主頁 > 移動端開發 > 線段與共享起點和終點相交

線段與共享起點和終點相交

2022-11-03 00:18:40 移動端開發

我正在嘗試通過查看它們是否會與串列中的任何現有線相交來測驗是否可以放置線。

public static bool onLine(Line l1, Vector2 p)
    {   //check whether p is on the line or not
        if (p.x <= Mathf.Max(l1.startingPoint.x, l1.endingPoint.x) && p.x <= Mathf.Min(l1.startingPoint.x, l1.endingPoint.x) &&
           (p.y <= Mathf.Max(l1.startingPoint.y, l1.endingPoint.y) && p.y <= Mathf.Min(l1.startingPoint.y, l1.endingPoint.y)))
            return true;

        return false;
    }

    public static int directionV2(Vector2 a, Vector2 b, Vector2 c)
    {
        float val = (b.y - a.y) * (c.x - b.x) - (b.x - a.x) * (c.y - b.y);
        if (val == 0)
            return 0;     //colinear
        else if (val < 0)
            return 2;    //anti-clockwise direction
        return 1;    //clockwise direction
    }

    public static bool isIntersect(Line l1, Line l2)
    {
        //four direction for two lines and points of other line
        int dir1 = directionV2(l1.startingPoint, l1.endingPoint, l2.startingPoint);
        int dir2 = directionV2(l1.startingPoint, l1.endingPoint, l2.endingPoint);
        int dir3 = directionV2(l2.startingPoint, l2.endingPoint, l1.startingPoint);
        int dir4 = directionV2(l2.startingPoint, l2.endingPoint, l1.endingPoint);

        if (dir1 != dir2 && dir3 != dir4)
            return true; //they are intersecting

        if (dir1 == 0 && onLine(l1, l2.startingPoint)) //when p2 of line2 are on the line1
            return true;

        if (dir2 == 0 && onLine(l1, l2.endingPoint)) //when p1 of line2 are on the line1
            return true;

        if (dir3 == 0 && onLine(l2, l1.startingPoint)) //when p2 of line1 are on the line2
            return true;

        if (dir4 == 0 && onLine(l2, l1.endingPoint)) //when p1 of line1 are on the line2
            return true;

        return false;
    }

    public struct Line
{
    public Vector2 startingPoint;
    public Vector2 endingPoint;

    public Line(Vector2 start, Vector2 end)
    {
        this.startingPoint = new Vector2(start.x, start.y);
        this.endingPoint = new Vector2(end.x, end.y);
    }
}

到目前為止,這是我通過其他帖子設法收集的內容,但我正在努力調整它以包括兩條線可以共享相同的起始位置而不會相交。

更新:我認為添加條件 l1.startingPoint != p && l1.endingPoint != p 將是解決方案。然而,代碼似乎仍在產生相交的線。我不確定我的解決方案是否錯誤,或者我是否在代碼的不同部分創建了問題。

更新更新:包含 Line 結構

任何幫助將不勝感激。

uj5u.com熱心網友回復:

兩條線段之間的相交測驗

線段與共享起點和終點相交

Segment A: [<1, 7>-<2, -1>]
Segment B: [<-2, 1>-<6, 4>]
Segments A, B intersect at <1.58209, 2.343284>.

線段與共享起點和終點相交

Segment A: [<1, 7>-<2, -1>]
Segment B: [<2, 2>-<6, 4>]
Segments A, B do not intersect.

概括

這個程序有兩個部分。

  1. 將線延伸到無窮遠,看看它們在哪里(以及是否)相交。

    • (a,b,c)使用帶有方程的坐標形成線條a*x b*y c=0這些是直線的齊次坐標。
    • 求兩條直線相交點的齊次坐標。
  2. 檢查交點是否包含在線段內。

    • 將點投影到線上。在這種情況下可以省略此步驟,因為根據定義,該點對兩條線是共同的。
    • t點沿距離A到的距離比B如果t=0那么該點在A,如果t=100%那么該點在B并且如果t=50%那么該點在 的中點AB該點包含在分段 ift>=0t<=1中。

注意命名法。線是無限的線,線段是定義在兩點之間的線。

細節

上述程序的關鍵是在LineeSegment.TryIntersect()方法內部實作。

程式

用于生成上述測驗的用途。GeometryTools是一個包含有用方法和值的靜態類。

class Program
{
    static void Main(string[] args)
    {
        var segA = new LineSegment(
            new Vector2(1, 7),
            new Vector2(2, -1));

        var segB = new LineSegment(
            new Vector2(-2, 1),
            new Vector2(6, 4));

        Console.WriteLine($"Segment A: {segA}");
        Console.WriteLine($"Segment B: {segB}");

        if (segA.TryIntersect(segB, out Vector2 point))
        {
            Console.WriteLine($"Segments A, B intersect at {point}.");
        }
        else
        {
            Console.WriteLine($"Segments A, B do not intersect.");
        }
    }
}

線段

上面的代碼依賴于LineSegment從兩點定義的類,以及TryIntersect()檢查兩條線段是否相交的函式。

public readonly struct LineSegment
{
    public LineSegment(Vector2 from, Vector2 to) : this()
    {
        From = from;
        To = to;
    }

    public Vector2 From { get; }
    public Vector2 To { get; }

    public float Length { get => Vector2.Distance(From, To); }
    public Vector2 Direction { get => Vector2.Normalize(To - From); }
    public Vector2 Normal { get => Vector2.Normalize(new Vector2(-(To.Y - From.Y), (To.X - From.X))); }

    public bool IsFinite
    {
        get => !float.IsNaN(From.X) && !float.IsNaN(From.Y)
            && !float.IsNaN(To.X) && !float.IsNaN(To.Y);
    }
    /// <summary>
    /// Check if a point is contained within the line segment
    /// </summary>
    /// <param name="target"></param>
    /// <returns></returns>
    public bool Contains(Vector2 target, bool inclusive = true)
    {
        if (TryJoin(From, To, out var line))
        {
            target = line.Project(target);
            Vector2 dir = Direction;
            float t = Vector2.Dot(dir, target - From) / Vector2.Dot(dir, To - From);
            return inclusive ? t >= 0 && t <= 1 : t > TINY && t < 1 - TINY;
        }
        return false;
    }
    /// <summary>
    /// Try to intersect two line segments
    /// </summary>
    /// <param name="other">The other line segment.</param>
    /// <param name="point">The intersection point.</param>
    /// <returns>True if they intersect, False otherwise</returns>
    public bool TryIntersect(LineSegment other, out Vector2 point, bool inclusive = true)
    {
        point = Vector2.Zero;

        if (GeometryTools.TryJoin(From, To, out InfiniteLine thisLine) 
            && GeometryTools.TryJoin(other.From, other.To, out InfiniteLine otherLine))
        {
            if (GeometryTools.TryMeet(thisLine, otherLine, out point))
            {
                return Contains(point, inclusive) && other.Contains(point, inclusive);
            }
        }
        return false;
    }
    public override string ToString() => $"[{From}-{To}]";
}

無限線

將無限線的引數和屬性分組到一個類中會很有幫助。

public readonly struct InfiniteLine
{
    /// <summary>
    /// The line at the horizon (not on the Eucledian plane).
    /// </summary>
    public static readonly InfiniteLine Horizon = new InfiniteLine(0, 0, 1);

    public InfiniteLine(float a, float b, float c) : this()
    {
        this.Coeff = (a, b, c);
        float m = (float)Math.Sqrt(a * a   b * b);
        this.IsFinite = m > GeometryTools.TINY;
    }
    /// <summary>
    /// The (a,b,c) coefficients define a line by the equation: <code>a*x b*y c=0</code>
    /// </summary>
    public (float a, float b, float c) Coeff { get; }

    /// <summary>
    /// True if line is in finite space, False if line is at horizon.
    /// </summary>
    public bool IsFinite { get; }

    /// <summary>
    /// Check if point belongs to the infinite line.
    /// </summary>
    /// <param name="point">The target point.</param>
    /// <returns>True if point is one the line.</returns>
    public bool Contains(Vector2 point)
    {
        return IsFinite 
            && Math.Abs(Coeff.a * point.X   Coeff.b * point.Y   Coeff.c) <= TINY;
    }

    /// <summary>
    /// Projects a target point onto the line.
    /// </summary>
    /// <param name="target">The target point.</param>
    /// <returns>The point on the line closest to the target.</returns>
    /// <remarks>If line is not finite the resulting point has NaN or Inf coordinates.</remarks>
    public Vector2 Project(Vector2 target)
    {
        (float a, float b, float c) = Coeff;
        float m2 = a * a   b * b;
        float px = b * (b * target.X - a * target.Y) - a * c;
        float py = a * (a * target.Y - b * target.X) - b * c;
        return new Vector2(px / m2, py / m2);
    }
    public override string ToString() => $"({Coeff.a})*x ({Coeff.b})*y ({Coeff.c})=0";
}

幾何工具

從兩點定義一條線(相遇)或從兩條線定義一個點(連接)的輔助函式。但在歐幾里得幾何中,這些操作可能會失敗(平行線或重合點),因此它們在這里被設計為相應地回傳true/false值。

public static class GeometryTools
{
    /// <summary>
    /// The value of 2^-19 is tiny
    /// </summary>
    public const float TINY = 1f / 524288;

    /// <summary>
    /// Try to join two points with an infinite line.
    /// </summary>
    /// <param name="A">The first point.</param>
    /// <param name="B">The second point.</param>
    /// <param name="line">The line joining the two points.</param>
    /// <returns>False if the two points are coincident, True otherwise.</returns>
    public static bool TryJoin(Vector2 A, Vector2 B, out InfiniteLine line)
    {
        float dx = B.X - A.X, dy = B.Y - A.Y;
        float m = A.X * B.Y - A.Y * B.X;
        line = new InfiniteLine(-dy, dx, m);
        return line.IsFinite;
    }
    /// <summary>
    /// Try to find the point where two infinite lines meet.
    /// </summary>
    /// <param name="L">The fist line.</param>
    /// <param name="M">The second line.</param>
    /// <param name="point">The point where the two lines meet.</param>
    /// <returns>False if the two lines are parallel, True othrwise.</returns>
    public static bool TryMeet(InfiniteLine L, InfiniteLine M, out Vector2 point)
    {
        (float a1, float b1, float c1) = L.Coeff;
        (float a2, float b2, float c2) = M.Coeff;
        float d = a1 * b2 - a2 * b1;
        if (d != 0)
        {
            point = new Vector2((b1 * c2 - b2 * c1) / d, (a2 * c1 - a1 * c2) / d);
            return true;
        }
        point = Vector2.Zero;
        return false;
    }
}

排除端點

如果默認情況下Contains()andTryIntersect()方法在計算中包括端點。但是通過將可選引數設定為inclusive = false您可以排除端點。

    static void Main(string[] args)
    {
        var segA = new LineSegment(
            new Vector2(1, 5),
            new Vector2(2, 2));

        var segB = new LineSegment(
            new Vector2(2, 2),
            new Vector2(6, 4));

        Console.WriteLine($"Segment A: {segA}");
        Console.WriteLine($"Segment B: {segB}");

        if (segA.TryIntersect(segB, out Vector2 point, false))
        {
            Console.WriteLine($"Segments A, B intersect at {point}.");
        }
        else
        {
            Console.WriteLine($"Segments A, B do not intersect.");
        }
    }
}

請參閱下面的示例

線段與共享起點和終點相交

帶輸出

Segment A: [<1, 5>-<2, 2>]
Segment B: [<2, 2>-<6, 4>]
Segments A, B do not intersect.

這意味著您可以使用它A.TryIntersect(B, out var point, false)來指定端點是否算作沖突。

上面的代碼遠沒有優化,因為它一遍又一遍地多次呼叫多個函式,而不是快取結果并使用它們。為了說明的目的,逐步解釋該程序。

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/525629.html

標籤:C#数学

上一篇:讀取一系列行的程式,每行都有正整數,并輸出第一行的總和,其中偶數個整數以3結尾

下一篇:有沒有辦法使用mingw編譯器工具創建僅資源的DLL?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more