拓扑部分
- 所谓拓扑,其实就是抛去几何数值属性之后几何体留下的性质。比如长方体有八个顶点,那么无论这个长方体的长宽高是多少,其始终有八个顶点,这就是拓扑属性。当然八个顶点的连接关系也满足一定的拓扑条件。
- 我在Open CasCade的博客里也对拓扑属性做了一些描述,几何引擎肯定是会提供刻画拓扑属性的的接口的。在occ里是先定义几何属性,然后定义拓扑属性。将一系列具有几何属性的点,线,面按一定的拓扑关系连接在一起,最后形成一个TopoDs_Shape进行绘制,输出,求交等等一系列的后续操作。
- 这里我想先对一些比较经典的拓扑问题进行总结归纳,当然可能掺了一些几何。因为这两者都是一个物体上的重要的性质。
C-7 点、线、向量
- 罗列关于点、线、向量的问题,并解答
- 使用C++实现
点、线、向量的定义
- 点是三个浮点型
- 向量也是三个浮点型
- 线是两个点,或者一个点,一个向量。也就是六个浮点型。
- 代码如下
class Point {
public:
float x;
float y;
float z;
};
class vector {
public:
float x;
float y;
float z;
};
//这里用两个点来表示线,
//实际上无所谓,有了第二个点就有了方向向量
//反之有了方向向量,也就有了第二个点
class line {
public:
Point p0;
Point p1;
};
向量的叉乘
//只能是Point/Vector/Line三个类
template <typename T1, typename T2>
Vector cross(T1 a, T2 b) {
Vector result;
result.x = a.y * b.z - a.z * a.y;
result.y = a.z * b.x - a.x * b.z;
result.z = a.x * b.y - a.y * b.x;
return result;
}
求点到线的距离
- 求叉积就行了,叉乘所得的向量的模就是平行四边形的面积,用面积除以底边长度就是距离
- 这里还有一个求模长的函数
//只能是Point/Vector/Line三个类
template <typename T>
float abs(T a) {
return sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
}
float Point2LineDistance(Point p, Line l) {
Vector l_direction(l.p1.x - l.p0.x, l.p1.y - l.p0.y, l.p1.z - l.p0.z);
Point tempPoint(p.x - l.p0.x, p.y - l.p0.y, p.z - l.p0.z);
//叉乘所得的向量的模就是平行四边形的面积
//用面积除以底边长度就是距离
return abs(cross(tempPoint, l_direction)) / abs(l_direction);
}
给定一个二维点和一个二维向量,判断这个点是在该向量的左边还是右边
//左边还是右边
int leftorright(Point p,Vector v) {
//大于0 ,p就在向量v的右边
//小于0在左边
//等于0在上面
return cross(p, v).z;
}
问某一直线有没有经过一个特定的点
- 这个问题等同于:上一个问题或给定三个点能不能围成一个三角形?给定三个点是否共线?
两二维直线的交点
//两直线交点
Point IntersectionPoint_of_twoline(Line l1,Line l2){
Point p(FLT_MAX, FLT_MAX, 0);
float x,y,t0,t1;
if ((l1.p0.x - l1.p1.x) == 0 && (l2.p0.x - l2.p1.x) != 0) {
t1 = (l2.p0.y - l2.p1.y) / (l2.p0.x - l2.p1.x);
x = l1.p0.x;
y = t1 * (x - l2.p0.x) + l2.p0.y;
}else if ((l1.p0.x - l1.p1.x) != 0 && (l2.p0.x - l2.p1.x) == 0) {
t0 = (l1.p0.y - l1.p1.y) / (l1.p0.x - l1.p1.x);
x = l2.p0.x;
y = t0 * (x - l1.p0.x) + l1.p0.y;
}else {
t0 = (l1.p0.y - l1.p1.y) / (l1.p0.x - l1.p1.x);
t1 = (l2.p0.y - l2.p1.y) / (l2.p0.x - l2.p1.x);
if (t1 == t0) return p;
x = (t1 * l2.p0.x - t0 * l1.p0.x + l1.p0.y - l2.p0.y) / (t1 - t0);
y = t0 * (x - l1.p0.x) + l1.p0.y;
}
p.x = x;
p.y = y;
return p;
}
二维情况下,判断某个点是否在三角形内部
//如果在内部或在线上就返回1,否则返回0
//这里其实可以用上面那个判断左右的函数,其实就是判断p是否在三角形三条边的同一侧,要是在同一侧那么就是在三角形内部
bool inTriangle(Point p,Triangle t) {
if (cross(t.p0 - p, t.p0 - t.p1).z >= 0 && cross(t.p1 - p, t.p1 - t.p2).z >= 0 && cross(t.p2 - p, t.p2 - t.p0).z >=0) {
return 1;
}else if (cross(t.p0 - p, t.p0 - t.p1).z <= 0 && cross(t.p1 - p, t.p1 - t.p2).z <= 0 && cross(t.p2 - p, t.p2 - t.p0).z <= 0) {
return 1;
}else {
return 0;
}
}
完整代码
- 直接复制就能运行
- 没有用到第三方的函数库或者其他文件
#include <iostream>
#include<math.h>
class Point {
public:
float x;
float y;
float z;
Point() {};
Point(float _x, float _y, float _z) :x(_x), y(_y), z(_z) {}
void operator=(Point& p) {
this->x = p.x;
this->y = p.y;
this->z = p.z;
}
void print() {
std::cout << this->x << "," << this->y << "," << this->z << std::endl;
}
};
class Vector {
public:
float x;
float y;
float z;
Vector() {};
Vector(float _x, float _y, float _z) :x(_x), y(_y), z(_z) {}
void print() {
std::cout << this->x << "," << this->y << "," << this->z << std::endl;
}
};
//这里用两个点来表示线,
//实际上无所谓,有了第二个点就有了方向向量
//反之有了方向向量,也就有了第二个点
class Line {
public:
Point p0;
Point p1;
Line(Point _p0, Point _p1) {
p0 = _p0;
p1 = _p1;
}
void print() {
p0.print();
p1.print();
}
};
class Triangle {
public:
Point p0;
Point p1;
Point p2;
Triangle(Point _p0, Point _p1,Point _p2) {
p0 = _p0;
p1 = _p1;
p2 = _p2;
}
void print() {
p0.print();
p1.print();
p2.print();
}
};
Point operator-(Point& p1, Point& p2) {
Point tp(p1.x-p2.x, p1.y - p2.y, p1.z - p2.z);
return tp;
}
//只能是Point/Vector/Line三个类
template <typename T1, typename T2>
Vector cross(T1 a, T2 b) {
Vector result;
result.x = a.y * b.z - a.z * b.y;
result.y = a.z * b.x - a.x * b.z;
result.z = a.x * b.y - a.y * b.x;
return result;
}
template <typename T>
float abs(T a) {
return sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
}
//直线到点的距离
float Point2LineDistance(Point p, Line l) {
Vector l_direction(l.p1.x - l.p0.x, l.p1.y - l.p0.y, l.p1.z - l.p0.z);
Point tempPoint(p.x - l.p0.x, p.y - l.p0.y, p.z - l.p0.z);
//叉乘所得的向量的模就是平行四边形的面积
//用面积除以底边长度就是距离
return abs(cross(tempPoint, l_direction)) / abs(l_direction);
}
//左边还是右边
int leftorright(Point p,Vector v) {
//大于0 ,p就在向量v的右边
//小于0在左边
//等于0在上面
return cross(p, v).z;
}
//两直线交点
Point IntersectionPoint_of_twoline(Line l1,Line l2){
Point p(FLT_MAX, FLT_MAX, 0);
float x,y,t0,t1;
if ((l1.p0.x - l1.p1.x) == 0 && (l2.p0.x - l2.p1.x) != 0) {
t1 = (l2.p0.y - l2.p1.y) / (l2.p0.x - l2.p1.x);
x = l1.p0.x;
y = t1 * (x - l2.p0.x) + l2.p0.y;
}else if ((l1.p0.x - l1.p1.x) != 0 && (l2.p0.x - l2.p1.x) == 0) {
t0 = (l1.p0.y - l1.p1.y) / (l1.p0.x - l1.p1.x);
x = l2.p0.x;
y = t0 * (x - l1.p0.x) + l1.p0.y;
}else {
t0 = (l1.p0.y - l1.p1.y) / (l1.p0.x - l1.p1.x);
t1 = (l2.p0.y - l2.p1.y) / (l2.p0.x - l2.p1.x);
if (t1 == t0) return p;
x = (t1 * l2.p0.x - t0 * l1.p0.x + l1.p0.y - l2.p0.y) / (t1 - t0);
y = t0 * (x - l1.p0.x) + l1.p0.y;
}
p.x = x;
p.y = y;
return p;
}
bool inTriangle(Point p,Triangle t) {
if (cross(t.p0 - p, t.p0 - t.p1).z >= 0 && cross(t.p1 - p, t.p1 - t.p2).z >= 0 && cross(t.p2 - p, t.p2 - t.p0).z >=0) {
return 1;
}else if (cross(t.p0 - p, t.p0 - t.p1).z <= 0 && cross(t.p1 - p, t.p1 - t.p2).z <= 0 && cross(t.p2 - p, t.p2 - t.p0).z <= 0) {
return 1;
}else {
return 0;
}
}
int main()
{
std::cout << "开始程序" << std::endl;
std::cout << std::endl << "------------------------------------" << std::endl;
std::cout << "点到直线的距离" << std::endl << std::endl;
Point P(1, 1, 0);
Point B(0, 0, 0);
Point A(0, 0, 1);
std::cout << "点P的坐标" << std::endl;
P.print();
Line l(A, B);
std::cout << "直线经过的两个点的坐标" << std::endl;
l.print();
std::cout <<std::endl<< "P到直线的距离" << std::endl;
std::cout << Point2LineDistance(P, l)<<std::endl;
std::cout << std::endl << "------------------------------------" << std::endl;
std::cout << "判断左右" << std::endl << std::endl;
Point p(1, 1, 0);
Vector v(-1, 1, 0);
std::cout << "点p的坐标" << std::endl;
p.print();
std::cout << "向量v的坐标" << std::endl;
v.print();
std::cout << std::endl << "p在向量v的左边还是右边" << std::endl;
if (leftorright(p, v) > 0) std::cout << "在右边";
else if (leftorright(p, v) < 0) std::cout << "在左边";
else std::cout << "在上面";
std::cout << std::endl << "------------------------------------" << std::endl;
std::cout << "两直线的交点" << std::endl << std::endl;
Point a1(-9.5, -2.88, 0), b1(-2.816, 5.05165, 0);
Point a2(4.88, -4.62, 0), b2(6.88, -0.26413, 0);
Line l1(a1, b1);
Line l2(a2, b2);
std::cout << "直线1经过的两个点的坐标" << std::endl;
a1.print(); b1.print();
std::cout << "直线2经过的两个点的坐标" << std::endl;
a2.print(); b2.print();
Point IntersectionPoint = IntersectionPoint_of_twoline(l1, l2);
std::cout << std::endl << "直线经过的两个点的坐标两直线交点" << std::endl;
IntersectionPoint.print();
std::cout << std::endl << "------------------------------------" << std::endl;
std::cout << "点P是否在三角形内部" << std::endl << std::endl;
Point t0(0, 0, 0), t1(1, 0, 0), t2(0, 1, 0);
Triangle t(t0, t1, t2);
Point tp(0.5, 0.6, 0);
std::cout << "点P的坐标" << std::endl;
tp.print();
std::cout << "三角形的三个顶点的坐标" << std::endl;
t.print();
std::cout << std::endl << "P是否在三角形内部:";
if (inTriangle(tp, t)) std::cout << "在内部";
else std::cout << "不在内部";
return 0;
}