Saya akan tergoda untuk melakukan ini menggunakan malaikat, hampir seperti saling berhadapan. Jika saat iterasi simpul dalam bentuk sudut antara titik asal dan titik tujuan terus dalam arah yang konsisten, semua poin adalah kandidat untuk antipodal. Jika suatu sudut berganti arah, maka titik itu disembunyikan oleh atau menyembunyikan titik sebelumnya. Jika disembunyikan oleh titik sebelumnya, titik harus dilewati. Jika menyembunyikan poin sebelumnya, poin sebelumnya harus dihapus dari daftar kandidat.
- Buat daftar PolygonCandidates
- Untuk setiap titik (titik k)
- Buat daftar baru untuk kandidat (Point, Angle)
- Tambahkan simpul saat ini ke daftar kandidat (titik k)
- Iterasi searah jarum jam di sekitar poligon, untuk setiap simpul yang tersisa (titik i)
- Jika sudut ke titik saat ini (dari titik k ke titik i) berlanjut searah jarum jam 1. tambahkan titik
- Jika sudut ke titik saat ini berlanjut dalam arah berlawanan arah jarum jam
- Jika dua kandidat poin sebelumnya, ditambah poin saat ini membentuk giliran kanan.
- Hapus titik terakhir dalam daftar sampai sudut saat ini dan sudut daftar kandidat terakhir dalam arah berlawanan arah.
- Tambahkan titik saat ini ke daftar kandidat
- Tambahkan semua kecuali dua yang pertama, dan kandidat poin terakhir ke daftar PolygonCandidates
- Temukan titik terjauh dalam daftar PolygonCandidates.
Saya tidak yakin apa yang harus dilakukan dengan kasus-kasus di mana asalnya, dan dua simpul lainnya semuanya berada di garis yang sama. Dalam hal ini, sudutnya akan sama. Jika Anda memiliki poligon berlubang, Anda bisa menemukan sudut min / maks dari setiap lubang, dan menghilangkan titik kandidat yang ada di dalam rentang itu.
Keuntungan utama dari pendekatan ini adalah Anda tidak perlu menguji untuk perpotongan garis antara segmen garis saat ini dan semua tepi poligon.
Ini berfungsi ... saya pikir. Saya telah memperbarui kode semu di atas dan python untuk membuatnya lebih mudah dibaca.
Ini harus menjadi suntingan terakhir. Contoh di bawah ini harus menemukan anitpole terbesar untuk geometri yang diberikan. Saya mengubah skrip sehingga menggunakan Poin dan Vektor, untuk mencoba dan membuatnya lebih mudah dibaca.
import math
from collections import namedtuple
Point = namedtuple("Point", "position x y")
Vector = namedtuple("Vector", "source dest angle")
def isClockwise(angle1, angle2):
diff = angle2 - angle1
#print(" angle1:%s angle2:%s diff: %s" % (angle1, angle2, diff))
if(diff > math.pi/2):
diff = diff - math.pi/2
elif (diff < -math.pi/2):
diff = diff + math.pi/2
#print(" diff:%s" % (diff))
if(diff > 0):
return False
return True
def getAngle(origin, point):
return math.atan2(point.y - origin.y, point.x-origin.x)
#returns a list of candidate vertcies. This will include the first, second, and second to last points
#the first and last points in the polygon must be the same
#k is the starting position, only vertices after this position will be evaluated
def getCandidates (k, polygon):
origin = polygon[k]
candidates = [Vector(k,k,0)]
prevAngle = 0;
currentAngle = 0;
for i in range(k + 1, len(polygon) - 1):
current = polygon[i]
#print("vertex i:%s x:%s y:%s " % (i, current.x, current.y))
if(i == k+1):
prevAngle = getAngle(origin, current)
candidates.append(Vector(k,i,prevAngle))
else:
currentAngle = getAngle(origin, current)
#print(" prevAngle:%s currentAngle:%s " % (prevAngle, currentAngle))
if isClockwise(prevAngle, currentAngle):
#print(" append")
candidates.append(Vector(k,i,currentAngle))
prevAngle = currentAngle
else:
#look at the angle between current, candidate-1 and candidate-2
if(i >= 2):
lastCandinate = polygon[candidates[len(candidates) - 1].dest]
secondLastCandidate = polygon[candidates[len(candidates) - 2].dest]
isleft = ((lastCandinate.x - secondLastCandidate.x)*(current.y - secondLastCandidate.y) - (lastCandinate.y - secondLastCandidate.y)*(current.x - secondLastCandidate.x)) > 0
#print(" test for what side of polygon %s" % (isleft))
if(i-k >= 2 and not isleft):
while isClockwise(currentAngle, candidates[len(candidates) - 1].angle):
#print(" remove %s" % (len(candidates) - 1))
candidates.pop()
#print(" append (after remove)")
candidates.append(Vector(k,i,currentAngle))
prevAngle = currentAngle
#for i in range(len(candidates)):
# print("candidate i:%s x:%s y:%s a:%s " % (candidates[i][0], candidates[i][1], candidates[i][2], candidates[i][3]))
return candidates
def calcDistance(point1, point2):
return math.sqrt(math.pow(point2.x - point1.x, 2) + math.pow(point2.y - point1.y, 2))
def findMaxDistance(polygon, candidates):
#ignore the first 2 and last result
maxDistance = 0
maxVector = Vector(0,0,0);
for i in range(len(candidates)):
currentDistance = calcDistance(polygon[candidates[i].source], polygon[candidates[i].dest])
if(currentDistance > maxDistance):
maxDistance = currentDistance
maxVector = candidates[i];
if(maxDistance > 0):
print ("The Antipodal distance is %s from %s to %s" % (maxDistance, polygon[candidates[i].source], polygon[candidates[i].dest]))
else:
print ("There is no Antipodal distance")
def getAntipodalDist(polygon):
polygonCandidates = []
for j in range(0, len(polygon) - 1):
candidates = getCandidates(j, polygon)
for i in range(2, len(candidates) - 1):
#print("candidate i:%s->%s x:%s y:%s " % (candidates[i].source, candidates[i].dest, candidates[i].x, candidates[i].y))
polygonCandidates.append(candidates[i])
for i in range(len(polygonCandidates)):
print("candidate i:%s->%s" % (polygonCandidates[i].source, polygonCandidates[i].dest))
findMaxDistance(polygon, polygonCandidates)
getAntipodalDist([Point(0,0,0),Point(1,-2,0),Point(2,-2,3),Point(3,2,2),Point(4,-1,1),Point(5,4,0),Point(6,0,0)])
getAntipodalDist([Point(0,0,0),Point(1,2,1),Point(2,1,4),Point(3,3,5),Point(4,5,4),Point(5,4,1),Point(6,0,0)])
getAntipodalDist([Point(0,0,0),Point(1,1,1),Point(2,2,1),Point(3,1,4),Point(4,3,5),Point(5,5,4),Point(6,4,1),Point(7,0,0)])
getAntipodalDist([Point(0,0,0),Point(1,-1,3),Point(2,1,4),Point(3,3,3),Point(4,2,0),Point(5,-2,-1),Point(6,0,0)])