Ben hit test (örneğin ) kullanmak için, çokgen algoritması içinde hızlı bir 2D nokta oluşturmaya çalışıyorum Polygon.contains(p:Point)
. Etkili teknikler için öneriler takdir edilecektir.
Ben hit test (örneğin ) kullanmak için, çokgen algoritması içinde hızlı bir 2D nokta oluşturmaya çalışıyorum Polygon.contains(p:Point)
. Etkili teknikler için öneriler takdir edilecektir.
Yanıtlar:
Grafikler için tamsayıları tercih etmemeyi tercih ederim. Birçok sistem UI boyama için tamsayılar kullanır (pikseller sonuçta ints'tur), ancak macOS örneğin her şey için kayan nokta kullanır. macOS yalnızca noktaları bilir ve bir nokta bir piksele çevrilebilir, ancak monitör çözünürlüğüne bağlı olarak başka bir şeye dönüşebilir. Retina ekranlarında yarım nokta (0.5 / 0.5) pikseldir. Yine de, macOS UI'lerinin diğer UI'lerden önemli ölçüde daha yavaş olduğunu hiç fark etmedim. Tüm 3B API'lerden sonra (OpenGL veya Direct3D) şamandıralarla çalışır ve modern grafik kütüphaneleri genellikle GPU hızlandırmadan yararlanır.
Şimdi hızın temel kaygınız olduğunu söylediniz, tamam, hadi hız için gidelim. Herhangi bir karmaşık algoritmayı çalıştırmadan önce basit bir test yapın. Bir oluşturma ekseniyle aynı hizada sınırlayıcı kutuÇokgeninizin etrafında . Bu çok kolay, hızlı ve zaten birçok hesaplamayı güvence altına alabilir. Bu nasıl çalışıyor? Poligonun tüm noktalarında tekrarlayın ve X ve Y'nin min / maks değerlerini bulun.
Mesela puanınız var (9/1), (4/3), (2/7), (8/2), (3/6)
. Bu, Xmin'in 2, Xmax'ın 9, Ymin'in 1 ve Ymax'ın 7 olduğu anlamına gelir. İki kenarlı (2/1) ve (9/7) dikdörtgenin dışındaki bir nokta çokgen içinde olamaz.
// p is your point, p.x is the x coord, p.y is the y coord
if (p.x < Xmin || p.x > Xmax || p.y < Ymin || p.y > Ymax) {
// Definitely not within the polygon!
}
Bu, herhangi bir nokta için yapılan ilk testtir. Gördüğünüz gibi, bu test ultra hızlı ama aynı zamanda çok kaba. Sınırlayıcı dikdörtgen içindeki noktaları işlemek için daha karmaşık bir algoritmaya ihtiyacımız var. Bunun nasıl hesaplanabileceğinin birkaç yolu vardır. Hangi yöntemin işe yaradığı da, çokgenin delikleri olabileceği veya her zaman katı olacağı gerçeğine bağlıdır. İşte katı olanların örnekleri (bir dışbükey, bir içbükey):
Ve işte bir deliği olan:
Yeşil olanın ortasında bir delik var!
Yukarıdaki üç vakayı da ele alabilen ve hala oldukça hızlı olan en kolay algoritmaya ray döküm denir . Algoritma fikri oldukça basittir: Çokgenin dışındaki herhangi bir yerden noktanıza sanal bir ışın çizin ve çokgenin bir tarafına ne sıklıkla çarptığını sayın. İsabet sayısı eşitse, çokgenin dışındadır, garipse, içeride.
Sarım sayısı algoritması çok yakın bir poligon hattı olmak noktaları için daha doğru ama çok yavaş da vardır, alternatif olabilir. Işın dökümü, sınırlı kayan nokta hassasiyeti ve yuvarlama sorunları nedeniyle çokgen tarafına çok yakın noktalar için başarısız olabilir, ancak gerçekte bu neredeyse bir sorun, sanki bir tarafa yakın bir nokta varmış gibi, zaten içeride mi yoksa hala dışarıda mı olduğunu görmek için görüntüleyicidir.
Hala yukarıdaki sınırlayıcı kutunuz var, hatırladınız mı? Sınırlayıcı kutunun dışında bir nokta seçin ve ışınınız için başlangıç noktası olarak kullanın. Örneğin nokta (Xmin - e/p.y)
çokgenin dışında.
Ama nedir e
? Eh, e
(aslında epsilon) sınırlayıcı kutusu bazı verir dolguyu . Dediğim gibi, çokgen çizgisine çok yakın başlarsak ışın izleme başarısız olur. Sınırlayıcı kutu çokgene eşit olabileceğinden (çokgen eksene hizalanmış bir dikdörtgense, sınırlayıcı kutu çokgenin kendisine eşittir!), Bunu güvenli hale getirmek için bazı dolgulara ihtiyacımız var, hepsi bu. Ne kadar büyük seçmelisin e
? Çok büyük değil. Çizim için kullandığınız koordinat sistemi ölçeğine bağlıdır. Piksel adım genişliğiniz 1,0 ise, yalnızca 1,0'ı seçin (ancak 0,1 de işe yarardı)
Işın başlangıç ve bitiş koordinatlarına sahip olduğumuza göre, sorun " çokgenin içindeki nokta " dan " ışının bir çokgen tarafıyla ne sıklıkla kesiştiğine " kayıyor . Bu nedenle, daha önce olduğu gibi çokgen noktalarıyla çalışamayız, şimdi gerçek taraflara ihtiyacımız var. Bir taraf daima iki nokta ile tanımlanır.
side 1: (X1/Y1)-(X2/Y2)
side 2: (X2/Y2)-(X3/Y3)
side 3: (X3/Y3)-(X4/Y4)
:
Işını her yönden test etmeniz gerekir. Işının bir vektör ve her iki tarafın da bir vektör olduğunu düşünün. Işın her iki tarafa tam olarak bir kez vurmalı ya da hiç vurmamalıdır. Aynı tarafa iki kez vuramaz. 2B uzayda iki çizgi, paralel olmadıkça her zaman tam olarak kesişir, bu durumda asla kesişmezler. Bununla birlikte, vektörler sınırlı bir uzunluğa sahip olduklarından, iki vektör paralel olmayabilir ve yine de birbirleriyle kesişemeyecek kadar kısa oldukları için asla kesişmeyebilirler.
// Test the ray against all sides
int intersections = 0;
for (side = 0; side < numberOfSides; side++) {
// Test if current side intersects with ray.
// If yes, intersections++;
}
if ((intersections & 1) == 1) {
// Inside of polygon
} else {
// Outside of polygon
}
Şimdiye kadar iyi, ama iki vektörün kesişip kesişmediğini nasıl test edersiniz? İşte bazı C kodu (test edilmemiştir), bu hile yapmalıdır:
#define NO 0
#define YES 1
#define COLLINEAR 2
int areIntersecting(
float v1x1, float v1y1, float v1x2, float v1y2,
float v2x1, float v2y1, float v2x2, float v2y2
) {
float d1, d2;
float a1, a2, b1, b2, c1, c2;
// Convert vector 1 to a line (line 1) of infinite length.
// We want the line in linear equation standard form: A*x + B*y + C = 0
// See: http://en.wikipedia.org/wiki/Linear_equation
a1 = v1y2 - v1y1;
b1 = v1x1 - v1x2;
c1 = (v1x2 * v1y1) - (v1x1 * v1y2);
// Every point (x,y), that solves the equation above, is on the line,
// every point that does not solve it, is not. The equation will have a
// positive result if it is on one side of the line and a negative one
// if is on the other side of it. We insert (x1,y1) and (x2,y2) of vector
// 2 into the equation above.
d1 = (a1 * v2x1) + (b1 * v2y1) + c1;
d2 = (a1 * v2x2) + (b1 * v2y2) + c1;
// If d1 and d2 both have the same sign, they are both on the same side
// of our line 1 and in that case no intersection is possible. Careful,
// 0 is a special case, that's why we don't test ">=" and "<=",
// but "<" and ">".
if (d1 > 0 && d2 > 0) return NO;
if (d1 < 0 && d2 < 0) return NO;
// The fact that vector 2 intersected the infinite line 1 above doesn't
// mean it also intersects the vector 1. Vector 1 is only a subset of that
// infinite line 1, so it may have intersected that line before the vector
// started or after it ended. To know for sure, we have to repeat the
// the same test the other way round. We start by calculating the
// infinite line 2 in linear equation standard form.
a2 = v2y2 - v2y1;
b2 = v2x1 - v2x2;
c2 = (v2x2 * v2y1) - (v2x1 * v2y2);
// Calculate d1 and d2 again, this time using points of vector 1.
d1 = (a2 * v1x1) + (b2 * v1y1) + c2;
d2 = (a2 * v1x2) + (b2 * v1y2) + c2;
// Again, if both have the same sign (and neither one is 0),
// no intersection is possible.
if (d1 > 0 && d2 > 0) return NO;
if (d1 < 0 && d2 < 0) return NO;
// If we get here, only two possibilities are left. Either the two
// vectors intersect in exactly one point or they are collinear, which
// means they intersect in any number of points from zero to infinite.
if ((a1 * b2) - (a2 * b1) == 0.0f) return COLLINEAR;
// If they are not collinear, they must intersect in exactly one point.
return YES;
}
Giriş değerleri, vektör 1 ( ve ) ve vektör 2 ( ve ) ' nin iki uç noktasıdır . 2 vektörünüz, 4 puanınız, 8 koordinatınız var. ve açıktır. kavşakları arttırır , hiçbir şey yapmaz.v1x1/v1y1
v1x2/v1y2
v2x1/v2y1
v2x2/v2y2
YES
NO
YES
NO
COLLINEAR ne olacak? Bu, her iki vektörün de pozisyona ve uzunluğa bağlı olarak aynı sonsuz çizgi üzerinde yattığı, hiç kesişmediği veya sonsuz sayıda noktada kesiştiği anlamına gelir. Bu davayı nasıl ele alacağımdan emin değilim, her iki durumda da kavşak olarak saymazdım. Bu durum pratikte kayan nokta yuvarlama hataları nedeniyle zaten oldukça nadirdir; daha iyi kod muhtemelen test etmeyecektir, == 0.0f
bunun yerine < epsilon
epsilon'un oldukça küçük bir sayı olduğu gibi bir şey için .
Çok sayıda noktayı test etmeniz gerekiyorsa, çokgen tarafların doğrusal denklem standart formlarını bellekte tutarak her şeyi biraz hızlandırabilirsiniz, böylece bunları her zaman yeniden hesaplamanız gerekmez. Bu, bellekte çokgen taraf başına üç kayan nokta değeri saklamak karşılığında her testte iki kayan nokta çarpımı ve üç kayan nokta çıkartması kaydedecektir. Bu tipik bir bellek vs hesaplama süresi değiş tokuş.
Son fakat en az değil: Sorunu çözmek için 3D donanım kullanabiliyorsanız, ilginç bir alternatif var. GPU'nun sizin için tüm işleri yapmasına izin verin. Ekran dışında bir boyama yüzeyi oluşturun. Tamamen siyah renkle doldurun. Şimdi, OpenGL veya Direct3D'nin çokgeninizi boyamasına izin verin (veya sadece noktaların içinde olup olmadığını test etmek istiyorsanız, çokgenlerinizi bile tümüyle boyayın, ancak hangisini umursamıyorsanız) ve çokgenleri farklı bir ile doldurun renk, örneğin beyaz. Bir noktanın çokgen içinde olup olmadığını kontrol etmek için, bu noktanın rengini çizim yüzeyinden alın. Bu sadece O (1) bellek getirmesidir.
Tabii ki bu yöntem sadece çizim yüzeyinizin büyük olması gerekmiyorsa kullanılabilir. GPU belleğine sığmıyorsa, bu yöntem CPU'da yapmaktan daha yavaştır. Büyük olması gerekiyorsa ve GPU'nuz modern gölgelendiricileri destekliyorsa, yine de GPU gölgelendirici olarak gösterilen ışın dökümünü uygulayarak GPU'yu kullanabilirsiniz, ki bu kesinlikle mümkündür. Daha fazla sayıda çokgen veya test edilecek çok sayıda nokta için, bu işe yarayacaktır, bazı GPU'ların 64 ila 256 noktayı paralel olarak test edebileceğini düşünün. Bununla birlikte, CPU'dan GPU'ya ve arkaya veri aktarmanın her zaman pahalı olduğunu unutmayın, bu nedenle noktaların veya çokgenlerin dinamik olduğu ve sık sık değişeceği birkaç basit poligona karşı birkaç noktayı test etmek için GPU yaklaşımı nadiren ödeme yapar kapatır.
Aşağıdaki kod parçası ( buradan alınan ) en iyi çözüm olduğunu düşünüyorum :
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
Hem kısa hem de verimlidir ve hem dışbükey hem de içbükey çokgenler için çalışır. Daha önce önerildiği gibi, önce sınırlayıcı dikdörtgeni kontrol etmeli ve çokgen deliklerini ayrı ayrı işlemelisiniz.
Bunun arkasındaki fikir oldukça basit. Yazar bunu şöyle anlatıyor:
Test noktasından yatay olarak yarı sonsuz bir ışın (artan x, sabit y) çalıştırıyorum ve kaç kenarı geçtiğini sayıyorum. Her geçişte, ışın iç ve dış arasında geçiş yapar. Buna Ürdün eğrisi teoremi denir.
Yatay değişken her kenardan geçtiğinde c değişkeni 0'dan 1'e ve 1'den 0'a geçer. Temel olarak, geçen kenar sayısının çift mi yoksa tek mi olduğunu takip ediyor. 0 eşittir ve 1 tek anlamına gelir.
verty[i]
ve verty[j]
her iki tarafındadır testy
, bu yüzden asla eşit olmazlar.
İşte bu RPI profesöründen gelen nirg tarafından verilen cevabın C # versiyonu . Bu RPI kaynağından kod kullanımının ilişkilendirme gerektirdiğini unutmayın.
Üst tarafa bir sınırlayıcı kutu denetimi eklendi. Ancak, James Brown'un işaret ettiği gibi, ana kod neredeyse sınırlayıcı kutunun kendisini kontrol ettiği kadar hızlıdır, bu nedenle kontrol ettiğiniz noktaların çoğunun sınırlayıcı kutunun içinde olması durumunda sınırlayıcı kutu kontrolü aslında genel işlemi yavaşlatabilir. . Böylece sınırlayıcı kutuyu kullanıma bırakabilirsiniz ya da bir alternatif, çok sık şekil değiştirmezlerse çokgenlerin sınırlayıcı kutularını önceden hesaplamak olabilir.
public bool IsPointInPolygon( Point p, Point[] polygon )
{
double minX = polygon[ 0 ].X;
double maxX = polygon[ 0 ].X;
double minY = polygon[ 0 ].Y;
double maxY = polygon[ 0 ].Y;
for ( int i = 1 ; i < polygon.Length ; i++ )
{
Point q = polygon[ i ];
minX = Math.Min( q.X, minX );
maxX = Math.Max( q.X, maxX );
minY = Math.Min( q.Y, minY );
maxY = Math.Max( q.Y, maxY );
}
if ( p.X < minX || p.X > maxX || p.Y < minY || p.Y > maxY )
{
return false;
}
// https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
bool inside = false;
for ( int i = 0, j = polygon.Length - 1 ; i < polygon.Length ; j = i++ )
{
if ( ( polygon[ i ].Y > p.Y ) != ( polygon[ j ].Y > p.Y ) &&
p.X < ( polygon[ j ].X - polygon[ i ].X ) * ( p.Y - polygon[ i ].Y ) / ( polygon[ j ].Y - polygon[ i ].Y ) + polygon[ i ].X )
{
inside = !inside;
}
}
return inside;
}
Nirg'ın yaklaşımına dayanan M. Katz'ın cevabının bir JavaScript varyantı:
function pointIsInPoly(p, polygon) {
var isInside = false;
var minX = polygon[0].x, maxX = polygon[0].x;
var minY = polygon[0].y, maxY = polygon[0].y;
for (var n = 1; n < polygon.length; n++) {
var q = polygon[n];
minX = Math.min(q.x, minX);
maxX = Math.max(q.x, maxX);
minY = Math.min(q.y, minY);
maxY = Math.max(q.y, maxY);
}
if (p.x < minX || p.x > maxX || p.y < minY || p.y > maxY) {
return false;
}
var i = 0, j = polygon.length - 1;
for (i, j; i < polygon.length; j = i++) {
if ( (polygon[i].y > p.y) != (polygon[j].y > p.y) &&
p.x < (polygon[j].x - polygon[i].x) * (p.y - polygon[i].y) / (polygon[j].y - polygon[i].y) + polygon[i].x ) {
isInside = !isInside;
}
}
return isInside;
}
P noktası ile çokgen apekslerinin her biri arasındaki açıların yönlendirilmiş toplamını hesaplayın. Toplam yönlendirilmiş açı 360 dereceyse, nokta içeridedir. Toplam 0 ise, nokta dışarıdadır.
Bu yöntemi daha çok seviyorum çünkü daha sağlam ve sayısal hassasiyete daha az bağımlı.
Kavşak sayısının eşitliğini hesaplayan yöntemler sınırlıdır, çünkü kavşak sayısının hesaplanması sırasında bir tepeye 'vurabilirsiniz'.
EDIT: Bu arada, bu yöntem içbükey ve dışbükey çokgenler ile çalışır.
EDIT: Geçenlerde konuyla ilgili bir Wikipedia makalesi buldum .
Bu soru çok ilginç. Bu yazının diğer cevaplarından farklı, uygulanabilir başka bir fikrim var. Fikir, hedefin içinde mi yoksa dışında mı olduğuna karar vermek için açıların toplamını kullanmaktır. Sargı numarası olarak bilinir .
X hedef nokta olsun. [0, 1, .... n] dizisi alanın tüm noktaları olsun. Hedef noktayı bir çizgiyle her kenarlık noktasına bağlayın. Hedef nokta bu alanın içindeyse. Tüm açıların toplamı 360 derece olacaktır. Aksi takdirde, açılar 360'tan az olacaktır.
Fikir hakkında temel bir fikir edinmek için bu resme bakın:
Algoritmam saat yönünde pozitif yön olduğunu varsayar. İşte potansiyel bir girdi:
[[-122.402015, 48.225216], [-117.032049, 48.999931], [-116.919132, 45.995175], [-124.079107, 46.267259], [-124.717175, 48.377557], [-122.92315, 47.047963], [-122.402015, 48.225216]]
Fikri uygulayan python kodu aşağıdadır:
def isInside(self, border, target):
degree = 0
for i in range(len(border) - 1):
a = border[i]
b = border[i + 1]
# calculate distance of vector
A = getDistance(a[0], a[1], b[0], b[1]);
B = getDistance(target[0], target[1], a[0], a[1])
C = getDistance(target[0], target[1], b[0], b[1])
# calculate direction of vector
ta_x = a[0] - target[0]
ta_y = a[1] - target[1]
tb_x = b[0] - target[0]
tb_y = b[1] - target[1]
cross = tb_y * ta_x - tb_x * ta_y
clockwise = cross < 0
# calculate sum of angles
if(clockwise):
degree = degree + math.degrees(math.acos((B * B + C * C - A * A) / (2.0 * B * C)))
else:
degree = degree - math.degrees(math.acos((B * B + C * C - A * A) / (2.0 * B * C)))
if(abs(round(degree) - 360) <= 3):
return True
return False
Eric Haines makale bobobobo bahsettiği gerçekten mükemmel. Algoritmaların performansını karşılaştıran tablolar özellikle ilginçtir; açı toplamı yöntemi diğerlerine göre gerçekten kötüdür. Ayrıca ilginç olan, çokgeni "giriş" ve "çıkış" sektörlerine daha da alt bölümlere ayırmak için bir arama ızgarası kullanmak gibi optimizasyonların, testi> 1000 tarafı olan çokgenlerde bile inanılmaz derecede hızlı hale getirebilmesidir.
Her neyse, ilk günler ama oyum "geçişler" yöntemine gidiyor, bu Mecki'nin sanırım açıkladığı gibi. Ancak en çok David Bourke tarafından tanımlanmış ve kodlanmış olarak buldum . Gerçek bir trigonometri gerekmediğini ve dışbükey ve içbükey için çalıştığını ve kenar sayısı arttıkça makul bir performans sergilediğini seviyorum.
Bu arada, Eric Haines'in makalesi için, çokgenleri rastgele test eden performans tablolarından biri.
number of edges per polygon
3 4 10 100 1000
MacMartin 2.9 3.2 5.9 50.6 485
Crossings 3.1 3.4 6.8 60.0 624
Triangle Fan+edge sort 1.1 1.8 6.5 77.6 787
Triangle Fan 1.2 2.1 7.3 85.4 865
Barycentric 2.1 3.8 13.8 160.7 1665
Angle Summation 56.2 70.4 153.6 1403.8 14693
Grid (100x100) 1.5 1.5 1.6 2.1 9.8
Grid (20x20) 1.7 1.7 1.9 5.7 42.2
Bins (100) 1.8 1.9 2.7 15.1 117
Bins (20) 2.1 2.2 3.7 26.3 278
Nirg tarafından cevap hızlı sürümü :
extension CGPoint {
func isInsidePolygon(vertices: [CGPoint]) -> Bool {
guard !vertices.isEmpty else { return false }
var j = vertices.last!, c = false
for i in vertices {
let a = (i.y > y) != (j.y > y)
let b = (x < (j.x - i.x) * (y - i.y) / (j.y - i.y) + i.x)
if a && b { c = !c }
j = i
}
return c
}
}
Nirg tarafından yayınlanan ve bobobobo tarafından düzenlenen çözüm gibi. Ben sadece javascript dostu ve kullanımı için biraz daha okunaklı yaptı:
function insidePoly(poly, pointx, pointy) {
var i, j;
var inside = false;
for (i = 0, j = poly.length - 1; i < poly.length; j = i++) {
if(((poly[i].y > pointy) != (poly[j].y > pointy)) && (pointx < (poly[j].x-poly[i].x) * (pointy-poly[i].y) / (poly[j].y-poly[i].y) + poly[i].x) ) inside = !inside;
}
return inside;
}
Michael Stonebraker altında bir araştırmacı olduğumda bu konuda biraz çalıştım - bilirsiniz, Ingres , PostgreSQL vb.
En hızlı yolun ilk önce sınırlayıcı bir kutu yapmak olduğunu fark ettik çünkü SUPER hızlı. Sınırlayıcı kutunun dışındaysa, dışarıdadır. Aksi takdirde, daha zor bir iş yaparsınız ...
Harika bir algoritma istiyorsanız, coğrafi çalışma için açık kaynak kodlu PostgreSQL kaynak koduna bakın ...
Ben işaret etmek istiyorum, biz asla sağ vs sol elini (herhangi bir "iç" vs "dış" sorun olarak ifade edilebilir herhangi bir fikir var ...
GÜNCELLEME
BKB'nin bağlantısı çok sayıda makul algoritma sağlamıştır. Dünya Bilimi sorunları üzerinde çalışıyordum ve bu nedenle enlem / boylamda çalışan bir çözüme ihtiyacım vardı ve kendine özgü bir el sorunu var - daha küçük alanın içindeki alan mı yoksa daha büyük alan mı? Cevap şudur: Verislerin "yönü" önemlidir - ya solak ya da sağlaktır ve bu şekilde her iki alanı da herhangi bir çokgenin "içinde" olarak belirtebilirsiniz. Bu nedenle, işim o sayfada numaralandırılmış üç numaralı çözümü kullandı.
Buna ek olarak, çalışmam "on line" testleri için ayrı fonksiyonlar kullandı.
Birisi sorduğundan beri: sınır sayısı kutu testlerinin en iyi olduğunu anladık, vertik sayısı bir sayının üzerine çıktığında - gerekirse daha uzun bir test yapmadan önce çok hızlı bir test yapın ... en büyük x, en küçük x, en büyük y ve en küçük y ve bir kutunun dört noktasını yapmak için bir araya getirme ...
Takip edenler için bir başka ipucu: daha karmaşık ve "ışık kararan" tüm hesaplamalarımızı bir düzlemde bir düzlemde pozitif noktalarda yaptık ve daha sonra tekrar "gerçek" boylam / enlem haline yansıtıp olası hatalardan kaçındık 180 boylam çizgisini aştığında ve kutup bölgelerini işlerken etrafını sarar. Harika çalıştı!
David Segond'un cevabı hemen hemen standart genel cevaptır ve Richard T'ler en yaygın optimizasyondur, ancak diğerleri de vardır. Diğer güçlü optimizasyonlar daha az genel çözümlere dayanmaktadır. Örneğin, aynı çokgeni çok sayıda nokta ile kontrol edecekseniz, çokgeni üçgenlemek çok sayıda hızlı TIN arama algoritması olduğu için işleri büyük ölçüde hızlandırabilir. Bir diğeri, çokgen ve noktaların düşük çözünürlükte sınırlı bir düzlemde olması, örneğin bir ekran görüntüsü olması durumunda, çokgeni belirli bir renkte bellek eşlemeli bir ekran arabelleğine boyayabilir ve belirli bir pikselin rengini kontrol edip çokgenlerde.
Birçok optimizasyon gibi, bunlar genel durumlardan ziyade spesifik vakalara dayanır ve tek kullanım yerine amortisman süresine göre fayda sağlar.
Bu alanda çalışarak, C 'ISBN 0-521-44034-3'te Joeseph O'Rourkes'in Hesaplama Geometrisinin çok yardımcı olduğunu gördüm.
Önemsiz çözüm, çokgeni üçgenlere bölmek ve burada açıklandığı gibi üçgenleri test etmek olacaktır.
Çokgeniniz CONVEX ise daha iyi bir yaklaşım olabilir. Çokgene sonsuz çizgi koleksiyonu olarak bakın. Her satır alanı ikiye böler. Her nokta için, çizginin bir tarafında mı yoksa diğer tarafında mı olduğunu söylemek kolaydır. Bir nokta tüm çizgilerin aynı tarafındaysa, poligonun içindedir.
Bunun eski olduğunu anlıyorum, ama burada herkes ilgilenirse Kakao'da uygulanan bir ışın döküm algoritması var. Bir şeyler yapmanın en etkili yolu olduğundan emin değilim, ama birisine yardımcı olabilir.
- (BOOL)shape:(NSBezierPath *)path containsPoint:(NSPoint)point
{
NSBezierPath *currentPath = [path bezierPathByFlatteningPath];
BOOL result;
float aggregateX = 0; //I use these to calculate the centroid of the shape
float aggregateY = 0;
NSPoint firstPoint[1];
[currentPath elementAtIndex:0 associatedPoints:firstPoint];
float olderX = firstPoint[0].x;
float olderY = firstPoint[0].y;
NSPoint interPoint;
int noOfIntersections = 0;
for (int n = 0; n < [currentPath elementCount]; n++) {
NSPoint points[1];
[currentPath elementAtIndex:n associatedPoints:points];
aggregateX += points[0].x;
aggregateY += points[0].y;
}
for (int n = 0; n < [currentPath elementCount]; n++) {
NSPoint points[1];
[currentPath elementAtIndex:n associatedPoints:points];
//line equations in Ax + By = C form
float _A_FOO = (aggregateY/[currentPath elementCount]) - point.y;
float _B_FOO = point.x - (aggregateX/[currentPath elementCount]);
float _C_FOO = (_A_FOO * point.x) + (_B_FOO * point.y);
float _A_BAR = olderY - points[0].y;
float _B_BAR = points[0].x - olderX;
float _C_BAR = (_A_BAR * olderX) + (_B_BAR * olderY);
float det = (_A_FOO * _B_BAR) - (_A_BAR * _B_FOO);
if (det != 0) {
//intersection points with the edges
float xIntersectionPoint = ((_B_BAR * _C_FOO) - (_B_FOO * _C_BAR)) / det;
float yIntersectionPoint = ((_A_FOO * _C_BAR) - (_A_BAR * _C_FOO)) / det;
interPoint = NSMakePoint(xIntersectionPoint, yIntersectionPoint);
if (olderX <= points[0].x) {
//doesn't matter in which direction the ray goes, so I send it right-ward.
if ((interPoint.x >= olderX && interPoint.x <= points[0].x) && (interPoint.x > point.x)) {
noOfIntersections++;
}
} else {
if ((interPoint.x >= points[0].x && interPoint.x <= olderX) && (interPoint.x > point.x)) {
noOfIntersections++;
}
}
}
olderX = points[0].x;
olderY = points[0].y;
}
if (noOfIntersections % 2 == 0) {
result = FALSE;
} else {
result = TRUE;
}
return result;
}
Test noktaları için örnek yöntemle nirg cevabının Obj-C versiyonu. Nirg'un yanıtı benim için iyi çalıştı.
- (BOOL)isPointInPolygon:(NSArray *)vertices point:(CGPoint)test {
NSUInteger nvert = [vertices count];
NSInteger i, j, c = 0;
CGPoint verti, vertj;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
verti = [(NSValue *)[vertices objectAtIndex:i] CGPointValue];
vertj = [(NSValue *)[vertices objectAtIndex:j] CGPointValue];
if (( (verti.y > test.y) != (vertj.y > test.y) ) &&
( test.x < ( vertj.x - verti.x ) * ( test.y - verti.y ) / ( vertj.y - verti.y ) + verti.x) )
c = !c;
}
return (c ? YES : NO);
}
- (void)testPoint {
NSArray *polygonVertices = [NSArray arrayWithObjects:
[NSValue valueWithCGPoint:CGPointMake(13.5, 41.5)],
[NSValue valueWithCGPoint:CGPointMake(42.5, 56.5)],
[NSValue valueWithCGPoint:CGPointMake(39.5, 69.5)],
[NSValue valueWithCGPoint:CGPointMake(42.5, 84.5)],
[NSValue valueWithCGPoint:CGPointMake(13.5, 100.0)],
[NSValue valueWithCGPoint:CGPointMake(6.0, 70.5)],
nil
];
CGPoint tappedPoint = CGPointMake(23.0, 70.0);
if ([self isPointInPolygon:polygonVertices point:tappedPoint]) {
NSLog(@"YES");
} else {
NSLog(@"NO");
}
}
CGPathContainsPoint()
arkadaşın.
CGPathContainsPoint()
Bir sorunun indüktif tanımından daha güzel bir şey yoktur. Burada eksiksizlik uğruna, ışın dökümü arkasındaki düşünceleri de netleştirebilecek bir prolog sürümü var. :
Http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html adresindeki basitlik algoritmasının simülasyonuna dayanmaktadır
Bazı yardımcılar şunları öngörüyor:
exor(A,B):- \+A,B;A,\+B.
in_range(Coordinate,CA,CB) :- exor((CA>Coordinate),(CB>Coordinate)).
inside(false).
inside(_,[_|[]]).
inside(X:Y, [X1:Y1,X2:Y2|R]) :- in_range(Y,Y1,Y2), X > ( ((X2-X1)*(Y-Y1))/(Y2-Y1) + X1),toggle_ray, inside(X:Y, [X2:Y2|R]); inside(X:Y, [X2:Y2|R]).
get_line(_,_,[]).
get_line([XA:YA,XB:YB],[X1:Y1,X2:Y2|R]):- [XA:YA,XB:YB]=[X1:Y1,X2:Y2]; get_line([XA:YA,XB:YB],[X2:Y2|R]).
2 nokta A ve B (Çizgi (A, B)) verilen bir çizginin denklemi:
(YB-YA)
Y - YA = ------- * (X - XA)
(XB-YB)
Hattın dönüş yönünün sınırlar için saat yönünde ve delikler için saat yönünün tersine ayarlanması önemlidir. Noktanın (X, Y), yani test edilen noktanın hattımızın sol yarım düzleminde olup olmadığını kontrol edeceğiz (bu bir zevk meselesi, aynı zamanda sağ taraf, aynı zamanda sınırların yönü de olabilir) bu durumda çizgiler değiştirilmelidir), bu, ışını noktadan sağa (veya sola) yansıtmak ve çizgiyle kesişmeyi kabul etmektir. Işını yatay yönde yansıtmayı seçtik (yine bir zevk meselesi, benzer kısıtlamalarla dikey olarak da yapılabilir), bu yüzden:
(XB-XA)
X < ------- * (Y - YA) + XA
(YB-YA)
Şimdi noktanın tüm düzlemde değil, yalnızca çizgi segmentinin sol (veya sağ) tarafında olup olmadığını bilmemiz gerekiyor, bu nedenle aramayı sadece bu segmentle sınırlamamız gerekiyor, ancak segmentin içinde olması kolay. çizgideki sadece bir nokta dikey eksende Y'den daha yüksek olabilir. Bu daha güçlü bir kısıtlama olduğundan, ilk kontrol edilmesi gerekir, bu yüzden önce sadece bu gereksinimi karşılayan satırları alırız ve ardından varlığını kontrol ederiz. Jordan Curve teoremi ile, bir çokgene yansıtılan herhangi bir ışın, eşit sayıda çizgide kesişmelidir. Böylece işimiz bitti, ışını sağa fırlatacağız ve sonra bir çizgiyle her kesiştiğinde, durumunu değiştireceğiz. Bununla birlikte, uygulamamızda verilen kısıtlamaları karşılayan çözüm torbasının uzunluğunu kontrol edip içselliğe karar vermekteyiz. çokgendeki her satır için bu yapılmalıdır.
is_left_half_plane(_,[],[],_).
is_left_half_plane(X:Y,[XA:YA,XB:YB], [[X1:Y1,X2:Y2]|R], Test) :- [XA:YA, XB:YB] = [X1:Y1, X2:Y2], call(Test, X , (((XB - XA) * (Y - YA)) / (YB - YA) + XA));
is_left_half_plane(X:Y, [XA:YA, XB:YB], R, Test).
in_y_range_at_poly(Y,[XA:YA,XB:YB],Polygon) :- get_line([XA:YA,XB:YB],Polygon), in_range(Y,YA,YB).
all_in_range(Coordinate,Polygon,Lines) :- aggregate(bag(Line), in_y_range_at_poly(Coordinate,Line,Polygon), Lines).
traverses_ray(X:Y, Lines, Count) :- aggregate(bag(Line), is_left_half_plane(X:Y, Line, Lines, <), IntersectingLines), length(IntersectingLines, Count).
% This is the entry point predicate
inside_poly(X:Y,Polygon,Answer) :- all_in_range(Y,Polygon,Lines), traverses_ray(X:Y, Lines, Count), (1 is mod(Count,2)->Answer=inside;Answer=outside).
Nirg'in cevabının C # sürümü burada: Sadece kodu paylaşacağım. Birini biraz zaman kurtarabilir.
public static bool IsPointInPolygon(IList<Point> polygon, Point testPoint) {
bool result = false;
int j = polygon.Count() - 1;
for (int i = 0; i < polygon.Count(); i++) {
if (polygon[i].Y < testPoint.Y && polygon[j].Y >= testPoint.Y || polygon[j].Y < testPoint.Y && polygon[i].Y >= testPoint.Y) {
if (polygon[i].X + (testPoint.Y - polygon[i].Y) / (polygon[j].Y - polygon[i].Y) * (polygon[j].X - polygon[i].X) < testPoint.X) {
result = !result;
}
}
j = i;
}
return result;
}
Java Sürümü:
public class Geocode {
private float latitude;
private float longitude;
public Geocode() {
}
public Geocode(float latitude, float longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
public float getLatitude() {
return latitude;
}
public void setLatitude(float latitude) {
this.latitude = latitude;
}
public float getLongitude() {
return longitude;
}
public void setLongitude(float longitude) {
this.longitude = longitude;
}
}
public class GeoPolygon {
private ArrayList<Geocode> points;
public GeoPolygon() {
this.points = new ArrayList<Geocode>();
}
public GeoPolygon(ArrayList<Geocode> points) {
this.points = points;
}
public GeoPolygon add(Geocode geo) {
points.add(geo);
return this;
}
public boolean inside(Geocode geo) {
int i, j;
boolean c = false;
for (i = 0, j = points.size() - 1; i < points.size(); j = i++) {
if (((points.get(i).getLongitude() > geo.getLongitude()) != (points.get(j).getLongitude() > geo.getLongitude())) &&
(geo.getLatitude() < (points.get(j).getLatitude() - points.get(i).getLatitude()) * (geo.getLongitude() - points.get(i).getLongitude()) / (points.get(j).getLongitude() - points.get(i).getLongitude()) + points.get(i).getLatitude()))
c = !c;
}
return c;
}
}
Net bağlantı noktası:.
static void Main(string[] args)
{
Console.Write("Hola");
List<double> vertx = new List<double>();
List<double> verty = new List<double>();
int i, j, c = 0;
vertx.Add(1);
vertx.Add(2);
vertx.Add(1);
vertx.Add(4);
vertx.Add(4);
vertx.Add(1);
verty.Add(1);
verty.Add(2);
verty.Add(4);
verty.Add(4);
verty.Add(1);
verty.Add(1);
int nvert = 6; //Vértices del poligono
double testx = 2;
double testy = 5;
for (i = 0, j = nvert - 1; i < nvert; j = i++)
{
if (((verty[i] > testy) != (verty[j] > testy)) &&
(testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]))
c = 1;
}
}
VBA SÜRÜMÜ:
Not: Poligonunuz bir harita içindeki bir alansa, Enlem / Boylam'ın X / Y (Latitude = Y, Boylam = X) yerine Y / X değerleri olduğunu unutmayın. Boylam bir ölçüm değildi.
SINIF MODÜLÜ: CPoint
Private pXValue As Double
Private pYValue As Double
'''''X Value Property'''''
Public Property Get X() As Double
X = pXValue
End Property
Public Property Let X(Value As Double)
pXValue = Value
End Property
'''''Y Value Property'''''
Public Property Get Y() As Double
Y = pYValue
End Property
Public Property Let Y(Value As Double)
pYValue = Value
End Property
MODÜL:
Public Function isPointInPolygon(p As CPoint, polygon() As CPoint) As Boolean
Dim i As Integer
Dim j As Integer
Dim q As Object
Dim minX As Double
Dim maxX As Double
Dim minY As Double
Dim maxY As Double
minX = polygon(0).X
maxX = polygon(0).X
minY = polygon(0).Y
maxY = polygon(0).Y
For i = 1 To UBound(polygon)
Set q = polygon(i)
minX = vbMin(q.X, minX)
maxX = vbMax(q.X, maxX)
minY = vbMin(q.Y, minY)
maxY = vbMax(q.Y, maxY)
Next i
If p.X < minX Or p.X > maxX Or p.Y < minY Or p.Y > maxY Then
isPointInPolygon = False
Exit Function
End If
' SOURCE: http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
isPointInPolygon = False
i = 0
j = UBound(polygon)
Do While i < UBound(polygon) + 1
If (polygon(i).Y > p.Y) Then
If (polygon(j).Y < p.Y) Then
If p.X < (polygon(j).X - polygon(i).X) * (p.Y - polygon(i).Y) / (polygon(j).Y - polygon(i).Y) + polygon(i).X Then
isPointInPolygon = True
Exit Function
End If
End If
ElseIf (polygon(i).Y < p.Y) Then
If (polygon(j).Y > p.Y) Then
If p.X < (polygon(j).X - polygon(i).X) * (p.Y - polygon(i).Y) / (polygon(j).Y - polygon(i).Y) + polygon(i).X Then
isPointInPolygon = True
Exit Function
End If
End If
End If
j = i
i = i + 1
Loop
End Function
Function vbMax(n1, n2) As Double
vbMax = IIf(n1 > n2, n1, n2)
End Function
Function vbMin(n1, n2) As Double
vbMin = IIf(n1 > n2, n2, n1)
End Function
Sub TestPointInPolygon()
Dim i As Integer
Dim InPolygon As Boolean
' MARKER Object
Dim p As CPoint
Set p = New CPoint
p.X = <ENTER X VALUE HERE>
p.Y = <ENTER Y VALUE HERE>
' POLYGON OBJECT
Dim polygon() As CPoint
ReDim polygon(<ENTER VALUE HERE>) 'Amount of vertices in polygon - 1
For i = 0 To <ENTER VALUE HERE> 'Same value as above
Set polygon(i) = New CPoint
polygon(i).X = <ASSIGN X VALUE HERE> 'Source a list of values that can be looped through
polgyon(i).Y = <ASSIGN Y VALUE HERE> 'Source a list of values that can be looped through
Next i
InPolygon = isPointInPolygon(p, polygon)
MsgBox InPolygon
End Sub
Nirg'in c ++ kodunun bir Python uygulamasını yaptım :
Girdiler
bounding_box_positions: filtrelenecek aday noktaları. (Uygulamamda sınırlayıcı kutudan oluşturuldu.
(Girdiler biçiminde dizilerini listeleri: [(xcord, ycord), ...]
)
İadeler
def polygon_ray_casting(self, bounding_points, bounding_box_positions):
# Arrays containing the x- and y-coordinates of the polygon's vertices.
vertx = [point[0] for point in bounding_points]
verty = [point[1] for point in bounding_points]
# Number of vertices in the polygon
nvert = len(bounding_points)
# Points that are inside
points_inside = []
# For every candidate position within the bounding box
for idx, pos in enumerate(bounding_box_positions):
testx, testy = (pos[0], pos[1])
c = 0
for i in range(0, nvert):
j = i - 1 if i != 0 else nvert - 1
if( ((verty[i] > testy ) != (verty[j] > testy)) and
(testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]) ):
c += 1
# If odd, that means that we are inside the polygon
if c % 2 == 1:
points_inside.append(pos)
return points_inside
Yine, fikir buradan alınır
Kimse bunu daha önce ortaya koymadı, ama bir veritabanı gerektiren pragmatistler için: MongoDB, bunu içeren Coğrafi sorgular için mükemmel bir desteğe sahip.
Aradığın şey:
db.neighborhoods.findOne ({geometry: {$ geoIntersects: {$ geometry: {type: "Point", koordinatlar: ["boylam", "enlem"]}}}}))
Neighborhoods
bir veya daha fazla poligonu standart GeoJson formatında saklayan koleksiyondur. Sorgu null değerini döndürürse kesişmez, aksi halde kesişir.
Burada çok iyi belgelenmiş: https://docs.mongodb.com/manual/tutorial/geospatial-tutorial/
330 düzensiz çokgen ızgarada sınıflandırılmış 6.000'den fazla noktanın performansı hiç optimizasyon olmadan bir dakikadan azdı ve belgeleri ilgili çokgenleri ile güncelleme süresi dahil.
C'de poligon testinde ışın dökümü kullanmayan bir nokta var. Üst üste binen alanlar (kendi kendine kesişimler) için çalışabilir, use_holes
tartışmaya bakın .
/* math lib (defined below) */
static float dot_v2v2(const float a[2], const float b[2]);
static float angle_signed_v2v2(const float v1[2], const float v2[2]);
static void copy_v2_v2(float r[2], const float a[2]);
/* intersection function */
bool isect_point_poly_v2(const float pt[2], const float verts[][2], const unsigned int nr,
const bool use_holes)
{
/* we do the angle rule, define that all added angles should be about zero or (2 * PI) */
float angletot = 0.0;
float fp1[2], fp2[2];
unsigned int i;
const float *p1, *p2;
p1 = verts[nr - 1];
/* first vector */
fp1[0] = p1[0] - pt[0];
fp1[1] = p1[1] - pt[1];
for (i = 0; i < nr; i++) {
p2 = verts[i];
/* second vector */
fp2[0] = p2[0] - pt[0];
fp2[1] = p2[1] - pt[1];
/* dot and angle and cross */
angletot += angle_signed_v2v2(fp1, fp2);
/* circulate */
copy_v2_v2(fp1, fp2);
p1 = p2;
}
angletot = fabsf(angletot);
if (use_holes) {
const float nested = floorf((angletot / (float)(M_PI * 2.0)) + 0.00001f);
angletot -= nested * (float)(M_PI * 2.0);
return (angletot > 4.0f) != ((int)nested % 2);
}
else {
return (angletot > 4.0f);
}
}
/* math lib */
static float dot_v2v2(const float a[2], const float b[2])
{
return a[0] * b[0] + a[1] * b[1];
}
static float angle_signed_v2v2(const float v1[2], const float v2[2])
{
const float perp_dot = (v1[1] * v2[0]) - (v1[0] * v2[1]);
return atan2f(perp_dot, dot_v2v2(v1, v2));
}
static void copy_v2_v2(float r[2], const float a[2])
{
r[0] = a[0];
r[1] = a[1];
}
Not: Bu, çok sayıda çağrı içerdiğinden, daha az optimal yöntemlerden biridir atan2f
, ancak bu iş parçacığını okuyan geliştiricilerin ilgisini çekebilir (testlerimde ~ 23x daha yavaş, çizgi kesişim yöntemini kullanarak).
Ray döküm algoritmasında aşağıdaki özel durumlarla başa çıkmak için :
Kontrol İster bir noktadır İçerisinde Karmaşık Bir Çokgeninizi Belirlenmesi . Makale, bunları çözmek için kolay bir yol sağlar, bu nedenle yukarıdaki durumlar için özel bir tedavi gerekmez.
Bunu, istenen noktayı çokgeninizin köşelerine bağlayarak oluşan alanın çokgenin kendisiyle aynı olup olmadığını kontrol ederek yapabilirsiniz.
Ya da noktanızdan kontrol noktanıza iki ardışık çokgen köşe çiftinin her birine kadar olan iç açıların toplamının 360'a kadar olup olmadığını kontrol edebilirsiniz, ancak ilk seçeneğin daha hızlı olduğunu hissediyorum, çünkü bölümleri veya hesaplamaları içermiyor trigonometrik fonksiyonların tersi.
Çokgeninizin içinde bir delik varsa ne olacağını bilmiyorum ama bana göre ana fikir bu duruma uyarlanabilir
Soruyu bir matematik topluluğuna da gönderebilirsiniz. Eminim bunu yapmanın bir milyon yolu vardır
Bir java-script kütüphanesi arıyorsanız Polygon sınıfı için bir noktanın içinde bulunup bulunmadığını tespit etmek için bir javascript google maps v3 uzantısı vardır.
var polygon = new google.maps.Polygon([], "#000000", 1, 1, "#336699", 0.3);
var isWithinPolygon = polygon.containsLatLng(40, -90);
Cevap, basit veya karmaşık çokgenlere sahip olup olmadığınıza bağlıdır. Basit çokgenlerin herhangi bir çizgi segmenti kesişimi olmamalıdır. Böylece delikleri olabilir ama çizgiler birbirini kesemez. Karmaşık bölgeler çizgi kesişimlerine sahip olabilir - böylece üst üste binen bölgelere veya tek bir noktadan birbirine temas eden bölgelere sahip olabilirler.
Basit çokgenler için en iyi algoritma Ray döküm (Geçiş sayısı) algoritmasıdır. Karmaşık çokgenler için, bu algoritma çakışan bölgelerin içindeki noktaları algılamaz. Bu yüzden karmaşık çokgenler için Sargı numarası algoritması kullanmanız gerekir.
İşte her iki algoritmanın C uygulaması ile mükemmel bir makale. Onları denedim ve iyi çalışıyorlar.
Nirg tarafından çözümün Scala versiyonu (sınırlayıcı dikdörtgen ön kontrolünün ayrı ayrı yapıldığını varsayar):
def inside(p: Point, polygon: Array[Point], bounds: Bounds): Boolean = {
val length = polygon.length
@tailrec
def oddIntersections(i: Int, j: Int, tracker: Boolean): Boolean = {
if (i == length)
tracker
else {
val intersects = (polygon(i).y > p.y) != (polygon(j).y > p.y) && p.x < (polygon(j).x - polygon(i).x) * (p.y - polygon(i).y) / (polygon(j).y - polygon(i).y) + polygon(i).x
oddIntersections(i + 1, i, if (intersects) !tracker else tracker)
}
}
oddIntersections(0, length - 1, tracker = false)
}
@Nirg answer'un golang sürümü (@@ m-katz tarafından C # kodundan esinlenilmiştir)
func isPointInPolygon(polygon []point, testp point) bool {
minX := polygon[0].X
maxX := polygon[0].X
minY := polygon[0].Y
maxY := polygon[0].Y
for _, p := range polygon {
minX = min(p.X, minX)
maxX = max(p.X, maxX)
minY = min(p.Y, minY)
maxY = max(p.Y, maxY)
}
if testp.X < minX || testp.X > maxX || testp.Y < minY || testp.Y > maxY {
return false
}
inside := false
j := len(polygon) - 1
for i := 0; i < len(polygon); i++ {
if (polygon[i].Y > testp.Y) != (polygon[j].Y > testp.Y) && testp.X < (polygon[j].X-polygon[i].X)*(testp.Y-polygon[i].Y)/(polygon[j].Y-polygon[i].Y)+polygon[i].X {
inside = !inside
}
j = i
}
return inside
}