1. 程式人生 > >JS實現判斷點是否在多邊形內部(3)--迴轉數法實現

JS實現判斷點是否在多邊形內部(3)--迴轉數法實現

射線法是一種很簡單直觀的判斷平面內點是否在多邊形內的方法。除了射線法還有很多其他的方法,今天就再介紹一種通過迴轉數來判斷的方法。

平面中的閉合曲線關於一個點的迴轉數(又叫卷繞數),代表了曲線繞過該點的總次數。下面這張圖動態演示了迴轉數的概念:圖中紅色曲線關於點(人所在位置)的迴轉數為 2。

這裡寫圖片描述

迴轉數是拓撲學中的一個基本概念,具有很重要的性質和用途。本文並不打算在這一點上展開論述,這需要具備相當的數學知識,否則會非常乏味和難以理解。我們暫時只需要記住迴轉數的一個特性就行了:當迴轉數為 0 時,點在閉合曲線外部。

對於給定的點和多邊形,迴轉數應該怎麼計算呢?

  1. 用線段分別連線點和多邊形的全部頂點。

    這裡寫圖片描述

  2. 計算所有點與相鄰頂點連線的夾角。

    這裡寫圖片描述

  3. 計算所有夾角和。注意每個夾角都是有方向的,所以有可能是負值。

    這裡寫圖片描述

  4. 最後根據角度累加值計算迴轉數。看過本文開頭的介紹,很容易理解 360°(2π)相當於一次迴轉。

思路介紹完了,下面兩點是實現中需要留意的問題。

  1. JavaScript 的數只有 64 位雙精度浮點這一種。對於三角函式產生的無理數,浮點數計算不可避免會造成一些誤差,因此在最後計算迴轉數需要做取整操作。

  2. 通常情況下,平面直角座標系內一個角的取值範圍是 -π 到 π 這個區間,這也是 JavaScript 三角函式 Math.atan2() 返回值的範圍。但 JavaScript 並不能直接計算任意兩條線的夾角,我們只能先計算兩條線與 X 正軸夾角,再取兩者差值。這個差值的結果就有可能超出 -π 到 π 這個區間,因此我們還需要處理差值超出取值區間的情況。

程式碼實現:

  /**
   * @description 迴轉數法判斷點是否在多邊形內部
   * @param {Object} p 待判斷的點,格式:{ x: X座標, y: Y座標 }
   * @param {Array} poly 多邊形頂點,陣列成員的格式同 p
   * @return {String} 點 p 和多邊形 poly 的幾何關係
   */
  function windingNumber(p, poly) {
    var px = p.x,
        py = p.y,
        sum = 0

    for(var i = 0, l = poly.length, j = l - 1
; i < l; j = i, i++) { var sx = poly[i].x, sy = poly[i].y, tx = poly[j].x, ty = poly[j].y // 點與多邊形頂點重合或在多邊形的邊上 if((sx - px) * (px - tx) >= 0 && (sy - py) * (py - ty) >= 0 && (px - sx) * (ty - sy) === (py - sy) * (tx - sx)) { return 'on' } // 點與相鄰頂點連線的夾角 var angle = Math.atan2(sy - py, sx - px) - Math.atan2(ty - py, tx - px) // 確保夾角不超出取值範圍(-π 到 π) if(angle >= Math.PI) { angle = angle - Math.PI * 2 } else if(angle <= -Math.PI) { angle = angle + Math.PI * 2 } sum += angle } // 計算迴轉數並判斷點和多邊形的幾何關係 return Math.round(sum / Math.PI) === 0 ? 'out' : 'in' }

第一篇:射線法理論
第二篇:射線法實現
第三篇:迴轉數法實現

相關推薦

JS實現判斷是否在多邊形內部3--迴轉實現

射線法是一種很簡單直觀的判斷平面內點是否在多邊形內的方法。除了射線法還有很多其他的方法,今天就再介紹一種通過迴轉數來判斷的方法。 平面中的閉合曲線關於一個點的迴轉數(又叫卷繞數),代表了曲線繞過該點的總次數。下面這張圖動態演示了迴轉數的概念:圖中紅色曲線關

通過C++實現判斷多邊形的關係和兩點之間的距離

1.判斷兩點之間的距離 #include<math.h> //計算兩點之間的距離 double calculateDistence(double* p0,double* p){ double tempx = p[0] - p0[0];

js如何判斷一個物件是陣列函式

js如何判斷一個物件是陣列(函式) 1.typeof操作符  示例: // 數值 typeof 37 === 'number'; // 字串 typeof '' === 'string'; // 布林值 typeof true === 'boolean'; // Symbols typeo

如何設計一個單登錄系統3

抽象 pat resolve pro 業務 問題 resolv -c cli 在上一篇文章 如何設計一個單點登錄系統(2)? 中主要講解了可跨域SSO系統服務端,客戶端在登錄,登出過程中分別應該承擔的職責,本文將重點聊一下具體技術實現,源碼地址: https://githu

吳恩達深度學習筆記3-神經網路如何實現監督學習?

神經網路的監督學習(Supervised Learning with Neural Networks) 關於神經網路也有很多的種類,考慮到它們的使用效果,有些使用起來恰到好處,但事實表明,到目前幾乎所有由神經網路創造的經濟價值,本質上都離不開一種叫做監督學習的機器學習類別,讓我們舉例看看。

零基礎實現攝像頭的全平臺直播 公網直播的實現

接上回,我們實現內網直播,可以實現直播的web觀看,該篇博文我們將實現公網的直播。 由於通用最多都是 window系統,我們的軟體也是可以在Windows上執行,我們後面就以window為例進行操作 下載穿透軟體 下載地址:https://natapp.cn/#do

JDK動態代理3WeakCache快取的實現機制

上一篇我們分析了Proxy類的內部是怎樣產生代理類的,我們看到了Proxy內部用到了快取機制,如果根據提供的類載入器和介面陣列能在快取中找到代理類就直接返回該代理類,否則會呼叫ProxyClassFactory工廠去生成代理類。這裡用到的快取是二級快取,它的一級

ARKit從入門到精通3-ARKit自定義實現

1.1-建立一個簡單的工程 1.上一小節中介紹過,ARSCNView的英文UIView的子類的子類,所以從理論上來說,應用我們框架UIKit的英文可以載入AR場景的 0401.png 2.給介面新增一個按鈕開啟AR之旅,建立一個ARSCNViewController:繼承於UIViewCont

YAML的Java實現——JYAML基本原理與示例3YAML對檔案流的處理

請您先閱讀: 1. FileOutputStream 以流的方式,將資料寫入到YAML檔案中。 /* Output data structure into a YAML file as a

作業系統Linux--首次適應實現主存分配和回收

首次適應演算法:        從空閒分割槽表的第一個表目起查詢該表,把最先能夠滿足要求的空閒區分配給作業,這種方法目的在於減少查詢時間。為適應這種演算法,空閒分割槽表(空閒區鏈)中的空閒分割槽要按地址由低到高進行排序。該演算法優先使用低址部分空閒區,在低址空間造成許多小的

windows3修改視窗類實現文字的切換

【摘要】這節課的主要內容是將如何修改視窗類,也就是修改一個建立好的視窗類。本節課實現修改我們自己建立的視窗類,來達到閃爍的文字和視窗背景顏色的效果。當然也可以修改系統建立的視窗類。 修改視窗類,系統已經提供了API函式SetWindowLong。它可以修改已經建立的視窗的風

打造強大的BaseModel3:讓Model實現自動歸檔

本文是「打造強大的BaseModel」的篇三篇,第一篇文章請見此:讓Model自我描述 。第二篇文章請見此:讓Model自動轉換。相對於讓Model實現自我描述和自動轉換,讓Model實現自動歸檔會難一點(事實後來我發現一點也不難)。我相信能夠好好看完這三篇文章的人,絕對是有大

3C#for迴圈實現氣泡排序

class Program { static void Main(string[] args) { int[] a = { 15,17,3,4,4,19,6,7,11,9,10}; //

手動實現LinkedList,增加remove方法 3

package com.jianshun; public class Node { Node previous; //上一個節點 Node next; //下一個節點 Object element; //元素資料 public Node(Node previo

MapReduce初級案例3:使用MapReduce實現平均成績

當我們看到這個例子的時候,我們是否想過: mapreduce是否可以完成我們傳統開發中經常遇到的一些任務。例如排序、平均數、批量word轉換等。它和我們傳統開發有什麼不同。那麼我們可以帶著下面問題來閱讀:1.mapreduce是如何求平均值的?2.map在求平均值的作用是什

2015年大一下第11周專案4-、圓關係3直線與圓的交點

/* *Copyright (c) 2014,煙臺大學計算機學院 *All rights reserved. *檔名稱:Annpion.cpp *作者:王耀鵬 *完成日期:2015年5月21日 *版本號:v1.0 * *問題描述:以Point為基類,派生出一個Circle(

OpenCv造輪子 滑窗實現數碼管影象數字分割

因為做專案要用到這個方法,就用opencv+py實現了一下,很簡單,先灰度二值化影象,統計Y軸畫素點個數,滑窗檢測間斷點就可以: def split_by_pixel(img): img_gray = cv2.cvtColor(img,cv2.CO

如何編寫高質量的 JS 函式3 --函語言程式設計[理論篇]

 【編寫高質量函式系列】中, 《如何編寫高質量的 JS 函式(1) -- 敲山震虎篇》介紹了函式的執行機制,此篇將會從函式的命名、註釋和魯棒性方面,闡述如何通過 JavaScript 編寫高質量的函式。  《如何編寫高質量的 JS 函式(2)-- 命名/註釋/魯棒篇》從函式的命

SQL SERVER大話存儲結構3_據行的行結構

bits 基礎 就會 mar ant rain 版權 bpa 一個數 一行數據是如何來存儲的呢? 變長列與定長列,NULL與NOT NULL,實際是如何整理存放到 8k的數據頁上呢? 對表格進行增減列,修改長度,添加默認值等DDL S

c++ 函3的返回值

pty code else 傳參 man span 錯誤 turn nbsp 函數的返回和函數的傳參恰恰相反,它是通過返回值來初始化外層的臨時變量。 不要返回函數內部對象的引用或指針 const string &manip(){ string ret;