C-7 点、线、向量的问题

拓扑部分

  • 所谓拓扑,其实就是抛去几何数值属性之后几何体留下的性质。比如长方体有八个顶点,那么无论这个长方体的长宽高是多少,其始终有八个顶点,这就是拓扑属性。当然八个顶点的连接关系也满足一定的拓扑条件。
  • 我在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;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值