Estaría tentado a hacer esto usando ángeles, casi como una línea de visión. Si mientras itera los vértices en la forma, los ángulos entre el vértice de origen y el vértice de destino continúan en una dirección consistente, todos los puntos son candidatos para el antípoda. Si un ángulo cambia de dirección, ese punto está oculto u oculta el punto anterior. Si está oculto por el punto anterior, se debe omitir el punto. Si oculta el punto anterior, los puntos anteriores deben eliminarse de la lista de candidatos.
- Crear una lista de PolygonCandidates
- Para cada vértice (punto k)
- Crear una nueva lista de candidatos (punto, ángulo)
- Agregar el vértice actual a la lista de candidatos (punto k)
- Iterar en sentido horario alrededor del polígono, para cada vértice restante (punto i)
- Si el ángulo al punto actual (del punto k al punto i) continúa en el sentido de las agujas del reloj 1.agregue el punto
- Si el ángulo del punto actual continúa en sentido antihorario
- Si los dos puntos candidatos anteriores, más el punto actual, forman un giro a la derecha.
- Elimine el último punto de la lista hasta que el ángulo actual y el último ángulo de la lista de candidatos estén en sentido antihorario.
- Agregar el punto actual a la lista de candidatos
- Agregue todos menos los dos primeros, y el último candidato apunta a una lista de PolygonCandidates
- Encuentre el punto más alejado en la lista de PolygonCandidates.
No estoy seguro de qué hacer con los casos en que el origen y otros dos vértices caen en la misma línea. En ese caso, el ángulo sería el mismo. Si tuviera un polígono con agujeros, podría encontrar el ángulo mínimo / máximo de cada agujero y eliminar cualquier punto candidato que se encuentre dentro de ese rango.
La principal ventaja de este enfoque sería que no tiene que probar la intersección de línea entre el segmento de línea actual y todos los bordes del polígono.
Esto funciona ... creo. He actualizado el pseudocódigo anterior y el python para que sea más fácil de leer.
Esta debería ser la última edición. El siguiente ejemplo debería encontrar el mayor anitpole para una geometría dada. Modifiqué el script para que use Puntos y Vectores, para intentar que sea más fácil de leer.
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)])