1. 程式人生 > >計算幾何常用演算法及numpy模擬

計算幾何常用演算法及numpy模擬

在很久之前的一篇的文章點乘和叉乘及其物理意義(C++STL實現),我們用C++(STL)實現了對向量內積和叉積的定義與簡單計算,最後演示瞭如何用幾何的方法計算點到直線的距離計算任意三角形的面積等問題。把這些放在更大的範圍內,其實就是今天的主角,計算幾何(Computational geometry)

本文所有的模擬程式均在numpy(python第三方的科學計算庫)下進行:

import numpy as np

1. 向量減法

設二維向量 P=(x 1 ,y 1 ) Q=(x 2 ,y 2 ) 
則向量減法定義(對應位相減)為: PQ=(x 1 x 2 ,y 1 

y 2 ) 
顯然有性質 PQ=(QP) 
如不加說明,下面所有的都看作向量,兩點的減法就是向量相減;

def sub(p, q):
    return p-q
p, q = np.array([1, 2]), np.array([3, 5])
print(sub(p, q))
print(-sub(q, p))

2. 向量叉積

設向量P=(x 1 ,y 1 ),Q=(x 2 ,y 2 ) (本文以二維為例,可自然推廣到三維)
則向量叉積定義為: P×Q=x 1 y 2 x 2 y 1   得到的是一個標量
顯然有性質 P×Q=(Q×P),P×(

Q)=(P×Q) 
如不加說明,下面所有的點都看作向量,點的乘法看作向量叉積;

叉乘的重要性質:

若 P × Q > 0 , 則P 在Q的順時針方向
若 P × Q < 0 , 則P 在Q的逆時針方向(與性質1等價)
若 P × Q = 0 , 則P 與Q共線,但可能同向也可能反向

def cross_prod(p, q):
    assert len(p)==2 and len(q)==2
    return p[0]*q[1]-p[1]*q[0]
p, q = np.array([1, 0]), np.array([0, 1])
                        # p在q的順時針方向
print(cross_prod(p, q)) # 1>0 p, q = np.array([1, 2], [2, 4]) # p, q 同向 print(cross_prod(p, q)) # 0

3. 判斷點線上段上

設點為Q ,線段為P 1 P 2   ,判斷點Q 在該線段上的依據是:
(QP 1 )×(P 2 P 1 )=0 Q  在以 P 1 ,P 2   為對角頂點的矩形內;
這是叉積性質的直接應用,也即(QP 1 )×(P 2 P 1 )=0 ,則 QP 1  P 2 P 1  共線;

def is_point_on_line(q, p1, p2):
    return True if cross_prod(q-p1, p2-p1)==0 else False
p1, p2 = np.array([1, 0]), np.array([0, 1])
q = np.array([1/2, 1/2])
print(is_point_on_line(q, p1, p2))
                    # True
q = np.array([1/2, 1/3])
print(is_point_on_line(q, p1, p2))
                    # False

4. 判斷兩線段是否相交

我們分兩步確定兩條線段是否相交:

  1. 快速排斥試驗

    設以線段 P 1 P 2   為對角線的矩形為R , 設以線段 Q 1 Q 2   為對角線的矩形為T ,如果R T 不相交,顯然兩線段不會相交;

def rect_overlap(r1, r2):
    return not (((r1[1][0] < r2[0][0])|(r1[0][1] > r2[1][1]))
               |((r2[1][0] < r1[0][0])|(r2[0][1] > r1[1][1]))
  1. 跨立試驗

    如果兩線段相交,則兩線段必然相互跨立對方,如圖1所示。在圖1中,P 1 P 2  跨立Q 1 Q 2   ,則 向量 (P1Q1) (P 2 Q 1 ) 位於向量(Q 2 Q 1 )  的兩側,即(P1Q1)×(Q2Q1)(P2Q1)×(Q2Q1)<0  上式可改寫成 ( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0,
    當 ( P1 - Q1 ) × ( Q2 - Q1 ) = 0 時,說明 ( P1 - Q1 ) 和 ( Q2 - Q1 )共線,但是因為已經通過快速排斥試驗,所以 P1 一定線上段 Q1Q2上;同理,( Q2 - Q1 ) ×(P2 - Q1 ) = 0 說明 P2 一定線上段 Q1Q2上。 所以判斷P1P2跨立Q1Q2的依據是: ( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) ≥ 0 同理判斷Q1Q2跨立P1P2的依據是: ( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) ≥ 0至此已經完全解決判斷線段是否相交的問題。

def line_intersection(p1, p2, q1, q2):
    return False if not rect_overlap([p1, p2], [q1, q2]) else \             # 不相交直接返回
            (True if cross_prod(p1-q1, q2-q1)*cross_prod(q2-q1, p2-q1) >= 0 else False)

5. 判斷線段和直線是否相交

從標題即可看出,這裡的直線和線段是不相同的;
如果線段 P 1 P 2  和直線 Q 1 Q 2  相交,則 P 1 P 2  跨立 Q 1 Q 2  ,根據4的結論:

相關推薦

計算幾何常用演算法numpy模擬

在很久之前的一篇的文章點乘和叉乘及其物理意義(C++STL實現),我們用C++(STL)實現了對向量內積和叉積的定義與簡單計算,最後演示瞭如何用幾何的方法計算點到直線的距離,計算任意三角形的面積等問題。把這些放在更大的範圍內,其實就是今天的主角,計算幾何(Com

BZOJ 1100 POI2007 對稱軸osi 計算幾何+KMP演算法

題目大意:給定一個多邊形,求對稱軸數量 我X 這究竟是怎麼想到KMP的…… 首先 將邊字元化 即找到這個多邊形的中心 然後用與中心構成的三角形的邊-角-邊的方式表示這條邊 將邊順時針掃一遍 然後倍增至長度為2n-1 再逆時針掃一遍 逆時針掃的那遍在順時針那遍中出現的次數就是

計算幾何工具演算法-求任意多邊形的面積

題目描述: 給出n邊形的n個頂點座標,求這個n邊形的面積 題目分析: 如果在數學上,大概會把這個多邊形分成三角形(n-2)個三角形來求 但是這樣免不了繁瑣的演算法,程式設計複雜度和時間複雜度

關於計算幾何一些演算法

     其實也談不上推薦,只是自己做過的題目而已,甚至有的題目尚未AC,讓在掙扎中。之所以推薦計算幾何題,是因為,本人感覺ACM各種演算法中計算幾何算是比較實際的演算法,在很多領域有著重要的用途(例如本人的專業,GIS)。以後若有機會,我會補充、完善這個列表。 計算幾何題的特點與做題要領: 1.大部分不會很

ACM常用演算法練習

一.基本演算法:      (1)列舉. (poj1753,poj2965) (2)貪心(poj1328,poj2109,poj2586)      (3)遞迴和分治法.                  (4)遞推.      (5)構造法.(poj3295)             (6)模擬法.(poj

計算幾何-常用幾何函式(模板)

浮點誤差與精度問題 實數是用浮點數運算的,精度受到限制,特別是乘除法之後,誤差比較大。此時>=<是可能出現誤差的。我們可以認為非常接近0的實數都是0,寫一個實數的三出口函式。 程式碼:

深入淺出PID控制演算法(一)————連續控制系統的PID演算法MATLAB模擬

引言 PID是Proportional(比例)、Integral(積分)、Differential(微分)三者的縮寫。PID調節是連續控制系統中技術最成熟、應用最廣泛的調節方式。PID調節實質是根據輸入的偏差值,按照比例、積分、微分的函式關係進行運算,運

計算機幾何常用演算法

至此我們得出演算法如下:1、f 線端PQ的端點不都在多邊形內2、hen return false;3、點集pointSet初始化為空;4、for 多邊形的每條邊s5、do if 線段的某個端點在s上6、then 將該端點加入pointSet;7、else if s的某個端點線上段PQ上8、then 將該端點

Codeforces Round #558 (Div. 2)C(計算幾何,排列組合,模擬)

urn 計算 ont out turn long long using truct c++ #include<bits/stdc++.h>using namespace std;typedef struct{ double k,b;}node;node k[10

計算幾何基礎演算法幾何C++實現

This file is implementation of Common Common Computational Geometry Algorithms.Please please pay attention to input according to the specified data type.

2017級演算法模擬上機準備篇(計算幾何 初階_1)

平面最近點對/最遠點對 Bamboo之吃我一拳(單純的平面最近點對) 零崎的戰爭(兩個點集的平面最近點對) #include <iostream> #include <algorithm> #include <cmath> using namespace std

計算幾何與圖形學有關的幾種常用演算法(二)

3.6 用向量的叉積判斷直線段是否有交         向量叉積計算的另一個常用用途是直線段求交。求交演算法是計算機圖形學的核心演算法,也是體現速度和穩定性的重要標誌,高效並且穩定的求交演算法是任何一個CAD軟體都必需要重點關注的。求交包含兩層概念,一個是判斷是否相

算法系列之九:計算幾何與圖形學有關的幾種常用演算法(二)

3.6 用向量的叉積判斷直線段是否有交        向量叉積計算的另一個常用用途是直線段求交。求交演算法是計算機圖形學的核心演算法,也是體現速度和穩定性的重要標誌,高效並且穩定的求交演算法是任何一個CAD軟體都必需要重點關注的。求交包含兩層概念,一個是判斷是否相交,另一個是

計算幾何與圖形學有關的幾種常用演算法(一)

我的專業是計算機輔助設計(CAD),算是一半機械一半軟體,《計算機圖形學》是必修課,也是我最喜歡的課程。熱衷於用程式碼擺平一切的我幾乎將這本教科書上的每種演算法都實現了一遍,這種重複勞動雖然意義不大,但是收穫很多,特別是丟棄了多年的數學又重新回到了腦袋中,算是最大的收

計算幾何與圖形學有關的幾種常用演算法

我的專業是計算機輔助設計(CAD),算是一半機械一半軟體,《計算機圖形學》是必修課,也是我最喜歡的課程。熱衷於用程式碼擺平一切的我幾乎將這本教科書上的每種演算法都實現了一遍,這種重複勞動雖然意義不大,但是收穫很多,特別是丟棄了多年的數學又重新回到了腦袋中,算是最大的收穫吧

計算幾何演算法

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; /* 計算幾何 目錄 ㈠ 點的基本運算 1. 平面上兩點之間

POJ-2420 A Star not a Tree? 計算幾何 模擬退火

POJ-2420 A Star not a Tree? 題意: 給定n個點, 找到一個點p. 使得p到所有點的距離之和最小. 分析: 模擬退火隨機產生圓心座標, 跑一遍模擬退火就行, 這題n的範圍是100, 莫名其妙re, 開1000就ac了. 程式碼: #include

HDU-3644 A Chocolate Manufacturer's Problem 計算幾何 模擬退火

HDU-3644 A Chocolate Manufacturer’s Problem 題意: 給定一個多邊形, 判斷這個多邊形中是否可以放入一個半徑為r的圓. 分析: 發現不知從何入手時就開始模擬退火吧. 隨機找出圓心座標, 主要就是判斷某個點是否在多邊形內. 這題wa和tl

POJ-1379 Run Away 計算幾何 模擬退火

POJ-1379 Run Away 題意: 平面上給定n個點, 要求找到一個點使得到所有點的距離最大。 分析: 模擬退火, 計算到每個點的最小距離, 使得最小距離最大。 程式碼: #include <iostream> #include <cstring

計算幾何 平面最近點對 nlogn分治演算法 求平面中距離最近的兩點

本文全文原創 轉載請註明出處 http://blog.csdn.net/lytning/article/details/25370169 平面最近點對,即平面中距離最近的兩點 分治演算法: int SOLVE(int left,int right)//求解點集中區間[lef