首页 > 其他分享 >空间判断点是否在线段上

空间判断点是否在线段上

时间:2023-05-21 21:05:35浏览次数:44  
标签:判断 线段 Vector2d LineSegment P1P2 lineSegment 空间 向量

空间判断点是否在线段上的原理以及实现

目录

  • 1. 概述
  • 2. 详论
  • 3. 参考

1. 概述

判断点是否在线段上的算法非常简单,有很多种实现方式,总结一下我自己的实现。

2. 详论

个人认为通过向量计算的方式是比较好的,因为可以保证在二维和三维的情况都成立。判断空间中点P是否在线段P1P2上,算法思想是分成两部分:

  1. 计算\(\vec{P1P2}\)与\(\vec{P1P}\)的向量叉积,可以判断是否存在一条直线上。原理是向量叉积的模(长度)表示两个向量组成的平面四边形的面积,如果叉积的模为0,说明两者共线,无法组成平行四边形。
  2. 计算向量点积,点积的几何意义是一个向量向另外一个向量的投影;如果满足如下公式,说明是在两个端点之间:

\[0<{\vec{P1P}}\cdot{\vec{P1P2}}<{||\vec{P1P2}||}^2 \]

具体的代码实现如下所示:

#include <Eigen/Eigen>
#include <iostream>

using namespace Eigen;
using namespace std;

using LineSegment = Vector2d[2];

const double epsilon = 0.000000001;

//判断点在线段上
bool PointInLine(const Vector2d& point, const LineSegment& lineSegment) {
  Vector3d P1P2;
  P1P2 << lineSegment[1] - lineSegment[0], 0;
  Vector3d P1P;
  P1P << point - lineSegment[0], 0;

  if (fabs((P1P2.cross(P1P)).norm()) > epsilon) {
    return false;
  }

  double dotProduct = P1P2.dot(P1P);
  if (dotProduct > 0 && dotProduct < P1P2.squaredNorm()) {
    return true;
  }

  return false;
}

int main() {
  // LineSegment lineSegment;
  // lineSegment[0] = Vector2d(0, 0);
  // lineSegment[1] = Vector2d(50, 100);
  // Vector2d c(25, 50);
  // Vector2d d(0, 8);

  LineSegment lineSegment;
  lineSegment[0] = Vector2d(2.6, 1.5);
  lineSegment[1] = Vector2d(24.5, 80.6);
  Vector2d ld = lineSegment[1] - lineSegment[0];
  Vector2d c = lineSegment[0] + 0.46 * ld;
  Vector2d d(0, 8);

  cout << PointInLine(c, lineSegment) << endl;
  // cout << PointInLine(d, lineSegment) << endl;
}

说明一下代码实现:

  1. 使用了Eigen中的矢量类,其实自己使用其他库的矢量类或者自己实现也是可以的。
  2. 内置浮点型的精度有限,因此设置epsilon作为容差。
  3. 由于是使用向量计算,因而是可以拓展到三维空间中使用的。

3. 参考

  1. 判断点是否在线段上
  2. How can you determine a point is between two other points on a line segment?



标签:判断,线段,Vector2d,LineSegment,P1P2,lineSegment,空间,向量
From: https://blog.51cto.com/u_15414551/6320192

相关文章

  • 【CSP 202303-4】星际网络Ⅱ 【离散化+线段树】
    题目链接http://118.190.20.162/view.page?gpid=T162题意一个网络地址由\(n\)(\(n\leq512\),且是16的倍数)位二进制位组成(形如xxxx:xxxx:....:xxxx),有若干用户需要申请一些网络地址。有三种操作:申请。给出一个用户编号,和要查询的地址区间[L,R],若全都没有被申请过,或者......
  • 空间站数据画图
    要求:打开ROOT文件,MakeClass生成两文件:(ams)zpw@dell:~/Files/0520_iss$rootISS_001223.root------------------------------------------------------------------|WelcometoROOT6.26/10https://root.cern||(c)1995-2021,TheR......
  • 电脑微信占用100多GB空间 解决办法来了:重回清爽流畅
    这几天微信吃内存的话题又上热搜了,作为一款10亿+用户的国民级APP,微信的真是让人又爱又恨,不用几乎不可能,用起来槽点又多,光是磁盘占用就是个头疼的问题。不论是工作还是日常沟通,微信里面的文件及语音、视频都会很多,时间长了就会占用大量空间,手机上占用100多GB很常见,电脑版微信同样......
  • 判断输入单词数
    #define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>intmain(){ charc,arr[50]; int i,num=1,word=1; printf("pleaseinputwords:\n"); gets(arr); for(i=0;(c=arr[i])!='\0';i++) if(c=='')num......
  • 线段树学习笔记
    让我们来一步一步理解! 1.向上更新voidpush_up(intrt){//向上更新sum[rt]=sum[rt<<1]+sum[rt<<1|1];} 2.向下更新voidpush_down(intrt,intm){if(add[rt]){//若有标记,则将标记向下移动一层add[rt<<1]+=add[rt];add[rt......
  • 炉火纯青:毫米波雷达开发手册之大话空间谱估计
    写在前面​ 深知新手在接触毫米波雷达板硬件时需要花费的沉没成本,因此在行将告别毫米波雷达之际,总结这两年以来在毫米波雷达上的一些经验和教训。​ 本文档用于为实现基于AWR1243BOOST等单板毫米波雷达开发提供参考指南与解决方案,主要包括硬件配置、基础参数、信号模型、应用DEM......
  • 判断移动端手指滑动
    话不多说codetimeconsttarget=document.getElementById('sidebar-open');letstartX,startY;functionhandleStart(e){startX=e.touches[0].clientX||e.clientX;startY=e.touches[0].clientY||e.clientY;}functionhandleEnd(e){const......
  • sql---判断语句
    将条件看做三种情况,分别处理SELECT CASE WHENid%2=1andid=(selectCOUNT(*)fromSeat)THENid WHENid%2=0THENid-1 Elseid+1 ENDASid,studentFROMSeatORDERBYid;别人的解法selectrank()over(orderby(id-1)^1)id,studentfromSeat#......
  • oracle 中的用户、表空间、数据模式光速入门
    oracle中没有limitROWNUM来处理的只能通过嵌套来处理SELECT*FROM(SELECTCOMP_LN.GIM_RENKOU.LASTUPTIMEFROMCOMP_LN.GIM_RENKOUORDERBYCOMP_LN.GIM_RENKOU.LASTUPTIMEDESC)WHEREROWNUM=1oracle首先连接的时候分为servicename和SID(SystemIdentifi......
  • golang 指针判断是否为空
    golang判断指针是否为空的方法:1、知道类型的情况下,自然是可以使用类型断言后判空。如ai,ok:=i.(*int),之后判断ai==nil。2、不知道是何种类型的指针,就只好借助反射了vi:=reflect.ValueOf(i),后使用vi.IsNil()来判断。但如果i里放到不是一个指针,调用IsNil会出异常,则可能要写......