点的空间查询纠错
作者在两个星期前提出了以下问题,并做了解答,可是千算万算还是出错了,细究每一行代码才知道是之前的解决问题出错了。
问题回顾:点的空间查询
在做空间的点分类时,需要查询:(三维空间中)某一范围内到某条边两个端点p1、p2的距离小于这条边长l的所有点。因为边有方向,所以范围规定为:从p1的垂直平面和p2的垂直平面之间。
详情:p1(x0,y0,z0)、p2(x1,y1,z1)边长l,范围是如图所示阴影。
图1 求解范围:橙色
出错原因:
查找:√l 范围内的点 不只是绿色,还包括多余的点(深绿色),如图所示
图2 错误未考虑范围深绿色(已经考虑了嫩绿色)
作者思路:
因为我们只想要 橙色部分的点, 先扩大筛选范围根号l,是为了 先考虑蓝色区域 再根据到中心点距离小于半径 剩下的公共区域。
图3 多考虑根号l 是为了蓝色部分
可是,多出了上图的嫩绿色和深绿色 怎么办?
点的空间查询中已经解决了,嫩绿色,对于深绿色,作者的解法如下。
图4 钝角示意图
由图上可知,深绿色区域内,一定会形成钝角三角形,只要判断三个点围成的三角形是否是钝角三角形即可排除绿色区域。
由上我们就求出了,橙色区域的所有点。
该方法的C++实现为:
#include<Eigen/Dense>
#define M_PI 3.1415926
typedef Eigen::Vector3d Point;
//求角度
double getDegAngle(Point p1, Point p2, Point p3) {
Eigen::Vector3d v1 = p2 - p1;
Eigen::Vector3d v2 = p3 - p1;
//one method, radian_angle belong to 0~pi
//double radian_angle = atan2(v1.cross(v2).transpose() * (v1.cross(v2) / v1.cross(v2).norm()), v1.transpose() * v2);
//another method, radian_angle belong to 0~pi
double radian_angle = atan2(v1.cross(v2).norm(), v1.transpose() * v2);
if (v1.cross(v2).z() < 0) {
radian_angle = 2 * M_PI - radian_angle;
}
return radian_angle * 180 / M_PI;
}
//待求点p
Point_3 p;
std::vector<Point_3>ps;
//已知直线为line 两个端点为:line[0]、line[1]
std::list<Point_3> line;
//这条边的长度
float line_len = std::sqrt(std::abs(line[0].x() - line[1].x())*std::abs(line[0].x() - line[1].x()) + std::abs(line[0].y() - line[1].y())*std::abs(line[0].y() - line[1].y()) + std::abs(line[0].z() - line[1].z())*std::abs(line[0].z() - line[1].z()));
//计算p到点line[0]的距离
float r0= std::sqrt(std::abs(p.x() - line[0].x())*std::abs(p.x() - line[0].x()) + std::abs(p.y() - line[0].y())*std::abs(p.y() - line[0].y()) + std::abs(p.z() - line[0].z())*std::abs(p.z() - line[0].z()));
//计算p到点line[1]的距离
float r1 = std::sqrt(std::abs(p.x() - line[1].x())*std::abs(p.x() - line[1].x()) + std::abs(p.y() - line[1].y())*std::abs(p.y() - line[1].y()) + std::abs(p.z() - line[1].z())*std::abs(p.z() - line[1].z()));
if (r0 <= line_len*1.41421) {
//在球心为line[0]半径为√line_len半球内
if ( r1<= line_len*1.41421) {
//在球心为line[1]半径为√line_len半球内
if (r0<line_len|| r1<line_len) {
//在line[0]所在的l半球内或在line[1]所在的l半球内
//在line[0]所在的l半球内或在line[1]所在的l半球内
//因为区域内的点 围成的三角形应该是锐角,所以判断,R1和R2小于等于len
float angle1=getDegAngle(Point(line[1].x(), line[1].y(), line[1].z()), Point(line[0].x(), line[0].y(), line[0].z()), Point(p.x(), p.y(), p.z()));
float angle2 = getDegAngle( Point(line[0].x(), line[0].y(), line[0].z()), Point(line[1].x(), line[1].y(), line[1].z()), Point(p.x(), p.y(), p.z()));
if((angle1<=90||(angle1 >= 270&& angle1 <= 360))&& (angle2 <= 90 || (angle2 >= 270 && angle2 <= 360)))
{
std::cout<<p<<"is in area"<<std::endl;
ps.push_back(p);
}
}
}
}
该方法的优缺点:
优:只需要计算三个重要的数:line_len、r0、r1,剩下的就是比较
缺点:没有进行空间检索筛选,如果空间中涉及的点很多很多,需要从第一个点开始 到最后一个点查找,那么计算量会非常大,目前还没有直接从坐标入手考虑是否在范围内的方法。
注:萌新投稿,轻喷。有疑问,请私聊
下的就是比较
缺点:没有进行空间检索筛选,如果空间中涉及的点很多很多,需要从第一个点开始 到最后一个点查找,那么计算量会非常大,目前还没有直接从坐标入手考虑是否在范围内的方法。
注:萌新投稿,轻喷。有疑问,请私聊
更正完毕