Ich wäre versucht, dies mit Engeln zu tun, fast wie eine Sichtlinie. Wenn beim Iterieren der Scheitelpunkte in der Form die Winkel zwischen dem Ursprungsscheitelpunkt und dem Zielscheitelpunkt in einer konsistenten Richtung fortgesetzt werden, sind alle Punkte Kandidaten für das Antipodal. Wenn ein Winkel die Richtung wechselt, wird dieser Punkt durch den vorherigen Punkt ausgeblendet oder ausgeblendet. Wenn es durch den vorherigen Punkt ausgeblendet wird, muss der Punkt übersprungen werden. Wenn der vorherige Punkt ausgeblendet wird, müssen die vorherigen Punkte aus der Kandidatenliste entfernt werden.
- Erstellen Sie eine PolygonCandidates-Liste
- Für jeden Scheitelpunkt (Punkt k)
- Neue Liste für Kandidaten erstellen (Punkt, Winkel)
- Fügen Sie den aktuellen Scheitelpunkt zur Kandidatenliste hinzu (Punkt k)
- Iterieren Sie im Uhrzeigersinn um das Polygon für jeden verbleibenden Scheitelpunkt (Punkt i).
- Wenn sich der Winkel zum aktuellen Punkt (von Punkt k zu Punkt i) im Uhrzeigersinn fortsetzt, fügen Sie den Punkt hinzu
- Wenn sich der Winkel zum aktuellen Punkt gegen den Uhrzeigersinn fortsetzt
- Wenn die beiden vorherigen Kandidatenpunkte plus der aktuelle Punkt eine Rechtskurve bilden.
- Entfernen Sie den letzten Punkt in der Liste, bis der aktuelle Winkel und der letzte Kandidatenlistenwinkel gegen den Uhrzeigersinn liegen.
- Fügen Sie den aktuellen Punkt zur Kandidatenliste hinzu
- Fügen Sie alle bis auf die ersten beiden und letzten Kandidatenpunkte zu einer PolygonCandidates-Liste hinzu
- Suchen Sie den am weitesten entfernten Punkt in der Liste der PolygonCandidates.
Ich bin mir nicht sicher, was ich mit Fällen tun soll, in denen der Ursprung und zwei andere Eckpunkte alle entlang derselben Linie liegen. In diesem Fall wäre der Winkel der gleiche. Wenn Sie ein Polygon mit Löchern hatten, konnten Sie den minimalen / maximalen Winkel jedes Lochs ermitteln und alle Kandidatenpunkte entfernen, die innerhalb dieses Bereichs liegen.
Der Hauptvorteil dieses Ansatzes besteht darin, dass Sie nicht auf den Linienschnittpunkt zwischen dem aktuellen Liniensegment und allen Polygonkanten testen müssen.
Das funktioniert ... denke ich. Ich habe den obigen Pseudocode und die Python aktualisiert, um das Lesen zu erleichtern.
Dies sollte die letzte Bearbeitung sein. Im folgenden Beispiel sollte der größte Anitpole für eine bestimmte Geometrie gefunden werden. Ich habe den Scrip so geändert, dass Punkte und Vektoren verwendet werden, um das Lesen zu erleichtern.
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)])