首页 > 其他分享 >线段上离p最近的点 - 投影方式

线段上离p最近的点 - 投影方式

时间:2023-12-21 23:46:40浏览次数:28  
标签:ab return 上离 线段 float 投影 flag Vector2

点到线段的最近距离

判断依据

1) 投影结果<0,则线段端点a离p最近

2) 投影结果>线段ab的长度,则线段端点b离p最近

3) 否则p在线段上的垂点为最近点

 

p与ab不共线时

1) p在线段两侧

2-a) p在线段内侧

2-b) p在线段内侧2

 

p与ab共线时

1) p在线段两侧

 

2-a) p在线段内侧

2-b) p在线段内侧

 

//线段上离p最近的点, flag: -1_表示最近点为a, 1_表示最近点为b, 0_表示最近点为线段中间的点
public static Vector2 GetSegmentClosestPoint(Vector2 a, Vector2 b, Vector2 p, out int flag)
{
    flag = 0;
    var ab = b - a;

    float abSqrLen = ab.sqrMagnitude;
    if (abSqrLen < float.Epsilon) //ab重合
        return a;

    var ap = p - a;
    // 计算投影长度,并单位化到[0, 1](需要额外除以ab的长度)。因此这里就直接除以长度的平方了。
    float proj = Vector2.Dot(ap, ab) / abSqrLen;
    if (proj < 0)
    {
        flag = -1;
        return a;
    }
    if (proj > 1)
    {
        flag = 1;
        return b;
    }

    return a + ab * proj;
}

求最近距离

//点到线段的距离, flag: -1_表示最近点为a, 1_表示最近点为b, 0_表示最近点为线段中间的点
public static float PointToSegmentDistance2(Vector2 a, Vector2 b, Vector2 p, out int flag)
{
    var c = GetSegmentClosestPoint(a, b, p, out flag);
    var pc = c - p;
    return pc.magnitude;
}

 

 

点与线段的位置关系

判断依据:投影结果<0或>线段ab的长度,则在线段的两侧;否则在线段内侧

//点与线段的位置关系: -1_外侧, 0_与端点重合, 1_内侧; isA: 是否点A那边的外侧或是否和点A重合
public static int GetPointSideOfSegment2(Vector2 p, Vector2 a, Vector2 b, out bool isA)
{
    isA = false;

    var ab = b - a;
    var ap = p - a;

    float abSqrLen = ab.sqrMagnitude;
    // 计算投影长度,并单位化到[0, 1](需要额外除以ab的长度)。因此这里就直接除以长度的平方了。
    float proj = Vector2.Dot(ap, ab) / abSqrLen;
    if (proj < 0)
    {
        isA = true;
        return -1;
    }
    if (proj > 1)
    {
        return -1;
    }

    //点和线段端点重合时
    float apSqrLen = ap.sqrMagnitude;
    if (apSqrLen < float.Epsilon)
    {
        isA = true;
        return 0;
    }

    var bp = p - b;
    float bpSqrLen = bp.sqrMagnitude;
    if (bpSqrLen < float.Epsilon)
        return 0;

    return 1;
}

 

标签:ab,return,上离,线段,float,投影,flag,Vector2
From: https://www.cnblogs.com/sailJs/p/17899822.html

相关文章

  • 吉司机线段树
    \(mxb\)为历史最大值,\(tg1,tg2,tg3,tg4\)分别对应最大值真实\(tag\),其他值真实\(tag\),最大值最大\(tag\),其它值最大\(tag\)#include<bits/stdc++.h>usingnamespacestd;#defineN500005#defineintlonglongintn,m;inta[N];structTREE{ intsum[N*4],mxb[N......
  • 线段树与历史最值和区间最值问题
    线段树与历史最值问题P4314CPU监控Description给定数组\(\{a_i\}\),维护以下操作。定义一个辅助数组\(\{b_i\}\),每次操作完后令\(b_i=\max(a_i,b_i)\)。查询\(\max_{i=l}^{r}a_i\)(区间最值)查询\(\max_{i=l}^{r}b_i\)(历史最值)\(\foralli\in[l,r]\),\(a_i\gets......
  • syoj.1827. 线段传送带题解
    前情提要-三分1827.线段传送带P2571[SCOI2010]传送带省流:三分套三分。在二维平面上有两个传送带,一个从A点到B点,一个从C点到D点,速度分别是p和q,在平面内其他点的速度为r。求A点到D点的最小速度。考虑从A到D的路程一定是\(AE+EF+FD\),即通过这两个点连......
  • 线段树详解
    定义什么是线段树线段树是一种二叉搜索树,每个节点都存储了一个区间的问题。能够解决的问题序列维护修改以及查询区间上的最值、求和等,修改和查询的时间复杂度为\(O\)(\(log\)\(n\))。与其他RMQ算法的区别算法适用范围优点缺点线段树动态可执行的操作......
  • 如何在 C# 中使用 投影(Projection)
    如何在C#中使用投影(Projection)一线码农 ​关注他 你浏览过TA的个人主页投影(Projection)是一种可以将查询结果进行 塑性 的一种操作,你可以使用 投影 将一个object转成仅包含你需要属性的新对象,这篇文章中,我们就一起看看如何使用投影功......
  • 简单线段树
    一、什么是线段树?线段树是怎样的树形结构?线段树是一种二叉搜索树,每个结点都存储了一个区间,也可以理解成一个线段,你要从这些线段上进行搜索操作得到你想要的答案。线段树能够解决什么样的问题?线段树的适用范围很广,可以在线维护修改以及查询区间上的最值,求和。......
  • CF1784C Monsters (hard version) 题解 线段树
    题目链接:https://codeforces.com/problemset/problem/1784/C题目大意:你面前有\(n\)只怪兽,每只怪兽都有一个初始血量,你可以进行两类操作:操作1:选择任意一个血量大于\(0\)的怪兽,并将它的血量降低\(1\);操作2:将所有存活的怪物的血量各自减去\(1\),如果存在怪物的血量恰好降为......
  • 线段树
    线段树什么是线段树线段树(英语:Segmenttree)是一种二叉树形数据结构,1977年由JonLouisBentley发明[1],用以存储区间或线段,并且允许快速查询结构内包含某一点的所有区间。一个包含n个区间的线段树,空间复杂度为O(n),查询的时间复杂度则为O(logn+k)},其中k是匹配条件的区间数量。此......
  • 【UVCAD】- 多段线教程,及与线段的区别
    【UVCAD】手机二维CAD建模,不止是看图UVCAD专注于二维(2D)的移动计算机辅助绘图(CAD)。UVCAD具有触摸优化的直观界面和工具。使用UVCAD,您可以在触摸屏上用手指或铅笔进行真正的2D绘图、2D建模和2D设计。对于需要易于使用的工具来更快、更精确地创建图纸的设计师和绘图员来说,UVC......
  • 刷题 ST表、单调栈、线段树->区间最值
    2023.12.13cf1904D2解题思路首先,a[i]大于b[i]时肯定不行,等于就满足了,直接过掉其次,要想使得a[i]等于b[i],就要在a[i]左右找最近的j使得a[j]=b[i](最近的最优,可证)k是i和j中间的一个数,想要满足题意,要满足以下两个条件(a[j]=b[i])1.ak<aj,即max(区间[i,j]中的ak)2.bk>bi,即min(区间......