まるで視線のように、天使を使ってこれをやりたくなります。形状の頂点を反復している間、起点の頂点と終点の頂点の間の角度が一定の方向に続く場合、すべての点が正反対の候補になります。角度が方向を切り替えると、そのポイントは前のポイントによって非表示になるか、非表示になります。前のポイントによって非表示になっている場合は、そのポイントをスキップする必要があります。前のポイントを非表示にする場合は、前のポイントを候補リストから削除する必要があります。
- PolygonCandidatesリストを作成する
- 各頂点(ポイントk)
- 候補(ポイント、角度)の新しいリストを作成する
- 現在の頂点を候補リストに追加します(ポイントk)
- 残りの各頂点(点i)について、ポリゴンの周りを時計回りに反復します
- 現在の点に対する角度(点kから点iまで)が時計回りの方向に続く場合1.点を追加します
- 現在のポイントに対する角度が反時計回りに続いている場合
- 前の2つの候補ポイントと現在のポイントが右折した場合。
- 現在の角度と最後の候補リストの角度が反時計回りになるまで、リストの最後のポイントを削除します。
- 現在のポイントを候補リストに追加します
- 最初の2つと最後の候補点を除くすべてをPolygonCandidatesリストに追加する
- PolygonCandidatesリストで最も遠い点を見つけます。
原点と他の2つの頂点がすべて同じ線上にある場合の対処法がわかりません。その場合、角度は同じになります。穴のあるポリゴンがある場合は、各穴の最小/最大角度を見つけ、その範囲内にある候補点を削除できます。
このアプローチの主な利点は、現在のラインセグメントとすべてのポリゴンエッジ間のラインの交差をテストする必要がないことです。
これはうまくいくと思います。上記の疑似コードとpythonを読みやすくするために更新しました。
これが最後の編集です。以下の例は、与えられたジオメトリの最大のアニポールを見つけます。ポイントとベクターを使用するようにスクリプトを変更して、読みやすくしてみました。
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)])