Khoảng cách đối cực (hoặc lấy đa giác hoặc đường kính đa giác) cho đa giác lõm


8

Tôi đang làm việc trên một số ví dụ lớp trong Python được triển khai trong ArcMap để tính khoảng cách đối cực trong một đa giác. Điều này khá thường xuyên đối với đa giác lồi, tuy nhiên, đối với đa giác lõm, tôi muốn loại trừ các giải pháp (được hình thành bởi một tia nối các điểm biên), không hoàn toàn nằm trong đa giác và không nằm trên ranh giới đa giác hoặc giao nhau. Tôi đã giải thích định nghĩa sai hay con thú này đi bằng một tên khác.

Hãy xem xét hai đa giác

pnts = [[0,0], [0,1], [1,4], [3,5], [5,4], [4,1], [0,0]] # một vòng khép kín lồi

pnts = [[0,0], [2,1], [1,4], [3,5], [5,4], [4,1], [0,0]] # một vòng khép kín đa giác lõm

Theo cách giải thích của tôi, điểm 0,0 không nên có khoảng cách đối cực liên kết với nó vì vectơ kết nối nó với các điểm khác là tự giao nhau với đa giác hoặc nằm trên ranh giới đa giác.

Nếu bất cứ ai có bất kỳ làm rõ về định nghĩa hoặc giải pháp tiềm năng, tôi sẽ đánh giá cao nó.

Một hình ảnh của đa giác lồi và các đường mong muốn (hiển thị màu đỏ) được đính kèm (các vectơ ví dụ từ điểm 0 chỉ được hiển thị).

Ví dụ khoảng cách Antipodal nội thất

Trong ví dụ lồi, điểm thứ nhất không có vectơ đối cực, tuy nhiên, điểm thứ hai thì có.

Ví dụ về Antipodal lõm

EDIT Tôi đã có một số tìm kiếm thành công bằng cách sử dụng "đa giác tìm nạp" hoặc "đường kính đa giác" trên web, tôi nghi ngờ rằng đây là những gì tôi đang theo đuổi.


1
Chào, Dân. Bạn đang sử dụng định nghĩa nào về "khoảng cách đối cực"? Một khả năng sẽ là điểm xa nhất được đo bằng cách di chuyển dọc theo ranh giới của đa giác, nhưng điều đó dường như không phù hợp với mô tả của bạn. Một định nghĩa khác là một điểm xa nhất mà việc đi lại có thể xảy ra ở bất cứ đâu trong hoặc ngoài đa giác. Tuy nhiên, một phần ba là điểm xa nhất mà việc đi lại chỉ được phép trong phạm vi bên trong và ranh giới của đa giác.
whuber

1
@whuber, tôi đang tìm một giải pháp chỉ đi trong đa giác không bao gồm các đoạn đường tạo thành ranh giới đa giác. Trong ví dụ lồi tôi đã đưa ra, chuyển động từ các điểm p0 đến p1 hoặc p0 đến p5 sẽ không được phép vì chúng là một phần của cạnh đa giác, tuy nhiên, p0 đến p2, p3, p4 sẽ là. Do đó, mối quan tâm của tôi rằng "phản đối" có thể không phải là thuật ngữ chính xác. Lưu ý, tôi chỉ quan tâm đến các đa giác lồi một phần không có lỗ tại thời điểm này. Nếu tôi bị mắc kẹt với các phân đoạn cạnh trong giải pháp, tôi luôn có thể loại bỏ chúng sau này.

1
Có một vấn đề tế nhị ở đây, Dan: mặc dù các phân đoạn như vậy có thể được loại trừ, tuy nhiên chúng cho bạn biết mức độ tối đa của tất cả các khoảng cách có thể sẽ là bao nhiêu (chúng chỉ ngăn chặn sự tối đa đó thực sự được nhận ra). Các giải pháp thực tế sẽ giữ bên trong các phân khúc đó nhưng vẫn cực kỳ gần với chúng. Do đó, đối với đa giác lồi, thuật toán rất đơn giản: tìm một đỉnh xa nhất từ ​​điểm bắt đầu (có thể có nhiều trong số chúng: tưởng tượng một hình bán nguyệt và bắt đầu từ tâm của vòng tròn ban đầu).
whuber

1
Tôi vẫn không hiểu định nghĩa của bạn, Dan, bởi vì không có "con đường dài nhất" trong bất kỳ đa giác nào: bạn có thể rắn xung quanh để tạo những con đường dài tùy ý. Có thể những gì bạn dự định là như sau: xác định khoảng cách giữa các điểm P và Q trong một đa giác (được kết nối) là cực đại của độ dài của tất cả các đường dẫn từ P đến Q nằm hoàn toàn trong đa giác. Sau đó, một "antipode" hợp lý cho một đa giác P được kết nối nhỏ gọn sẽ là bất kỳ điểm Q nào ở khoảng cách tối đa từ P. (Khi P là một đỉnh của một đa giác lồi, các antipode của nó một lần nữa là các đỉnh ở khoảng cách Euclide tối đa từ P.)
whuber

2
Điểm xa nhất được đặc trưng nghiêm ngặt bằng cách sử dụng định nghĩa "hợp lý" trong nhận xét trước của tôi. Lưu ý rằng trong việc tìm kiếm nó, bạn được phép giả định rằng bạn có thể đi dọc theo các cạnh. Trong hình thứ hai của bạn, E là đối cực với A và B; A là phản đối với C, D và E; và D và A đều đối nghịch với F. Sử dụng phép tương tự ca nô, trong đó phần bên trong của đa giác là một hồ nước, điểm P là đối cực với điểm xuất phát Q của bạn khi trong một cuộc đua ca nô từ Q chống lại một đối thủ nhắm đến P trước khi bạn đạt đến một số điểm P ', họ không có lợi thế hơn bạn cho dù P' ở đâu.
whuber

Câu trả lời:


4

Nếu tôi đang viết một thuật toán, tôi chỉ cần kiểm tra xem một đường giữa hai đỉnh trên đa giác có giao với bất kỳ đường nào tạo thành một trong các cạnh không. Đây là mã giả của tôi:

  1. Xác định tất cả các đỉnh, lưu trữ trong một danh sách
  2. Xác định tất cả các cạnh, lưu trữ trong một danh sách (có thể là các cặp từ 1, có lẽ)
  3. đối với mỗi đỉnh, lấy khoảng cách đến tất cả các đỉnh khác, ngoại trừ:
    1. loại trừ các đỉnh lân cận (có thể chia sẻ một cặp với đỉnh này trong 2)
    2. loại trừ bất kỳ dòng nào cắt bất kỳ dòng nào trong 2. sử dụng một cái gì đó từ đây .
  4. lưu trữ tất cả các khoảng cách valide với tham chiếu đến các đỉnh trong 1.

  5. làm những gì bạn muốn với kết quả, viết ra những dòng mới, lưu trữ dòng dài nhất cho mỗi đa giác ...

Bây giờ, tôi không chắc đây có phải là những gì bạn đang theo đuổi không, nhưng bạn chắc chắn có thể làm những điều trên trong ArcPy.

EDIT: Mã cho bước 2.2:

E = B-A = ( Bx-Ax, By-Ay )
F = D-C = ( Dx-Cx, Dy-Cy ) 
P = ( -Ey, Ex )
h = ( (A-C) * P ) / ( F * P )

Nếu h nằm trong khoảng từ 0 đến 1, các đường thẳng giao nhau, nếu không thì không. Nếu F * P bằng 0, tất nhiên bạn không thể thực hiện phép tính, nhưng trong trường hợp này, các đường thẳng song song và do đó chỉ giao nhau trong các trường hợp rõ ràng. Nếu h là 1, thì các dòng kết thúc tại cùng một điểm. Xử lý này như bạn muốn! (Tôi muốn nói rằng họ giao nhau, nó làm cho tôi dễ dàng hơn.)

Một ví dụ khác cho bước 2.2 từ đây: http://en.wikipedia.org/wiki/Line-line_intersection nhập mô tả hình ảnh ở đây

Trước tiên hãy kiểm tra mẫu số không bằng 0, có nghĩa là các đường thẳng song song.

Sau đó kiểm tra xem tọa độ tìm thấy ở trên không nằm ngoài hộp giới hạn của một trong hai dòng.

Đọc thêm: http://compgeom.cs.uiuc.edu/~jeffe/teaching/373/notes/x06-sweepline.pdf


Mã trên blog của tôi thực hiện mọi thứ trừ 3.2 và đưa kết quả trở lại chương trình gọi để tính toán thêm hoạt động tốt cho đa giác lồi. Tôi muốn một số tài liệu tham khảo nếu có thể và liệu số quanh co có hiệu quả để xác định giao lộ đường hay tôi nên đi một số tuyến đường khác.

2
Tôi đã thêm một ví dụ về tính toán giao cắt từ bài viết tôi liên kết đến. Tôi nghĩ rằng tôi sẽ không lo lắng về hiệu quả cho đến khi nó là một vấn đề! Làm cho một cái gì đó hoạt động, sau đó sửa chữa nó nếu nó không đủ tốt!
Alex Leith

Cảm ơn Alex, tôi sẽ kiểm tra xem ... hiệu quả không phải là vấn đề vì đây chỉ là một ví dụ không được chạy trên hàng ngàn đa giác

Mặc dù thật khó để nói câu trả lời này mô tả điều gì, nhưng dường như đó là kiểm tra xem một đa giác có lồi hay không. Điều đặc biệt khó hiểu là dường như sử dụng "dòng" thay cho "phân khúc dòng". Mã được cung cấp dường như không phải là một kiểm tra hợp lệ cho giao điểm của các đoạn
whuber

Hi whuber, điều này không kiểm tra phân khúc dòng. Ví dụ thứ hai tôi đã thêm có lẽ làm cho nó rõ ràng hơn, trong đó toán học tìm ra điểm giao nhau cho các đường vô hạn và sau đó bạn cần kiểm tra xem điểm giao nhau đó có nằm trong hộp giới hạn của một trong các đường không. Giống như tất cả toán học vectơ, chắc chắn có một thư viện thực hiện điều này, nhưng nó không phức tạp và tôi nghĩ cần thiết cho những gì OP muốn làm.
Alex Leith

3

Tôi sẽ bị cám dỗ để làm điều này bằng cách sử dụng các thiên thần, gần giống như đường ngắm. Nếu trong khi lặp lại các đỉnh trong hình dạng, các góc giữa đỉnh gốc và đỉnh đích tiếp tục theo một hướng nhất quán, thì tất cả các điểm đều là ứng cử viên cho phản đối. Nếu một góc chuyển hướng, thì điểm đó bị ẩn hoặc ẩn điểm trước đó. Nếu nó bị ẩn bởi điểm trước, điểm cần phải được bỏ qua. Nếu nó ẩn điểm trước đó, (các) điểm trước cần phải được xóa khỏi danh sách ứng cử viên.

  1. Tạo danh sách PolygonCandidates
  2. Đối với mỗi đỉnh (điểm k)
    1. Tạo danh sách mới cho các ứng cử viên (Điểm, Góc)
    2. Thêm đỉnh hiện tại vào danh sách ứng viên (điểm k)
    3. Lặp lại theo chiều kim đồng hồ xung quanh đa giác, cho mỗi đỉnh còn lại (điểm i)
      1. Nếu góc tới điểm hiện tại (từ điểm k đến điểm i) tiếp tục theo chiều kim đồng hồ 1. thêm điểm
      2. Nếu góc tới điểm hiện tại tiếp tục theo hướng ngược chiều kim đồng hồ
      3. Nếu hai điểm ứng cử viên trước, cộng với điểm hiện tại tạo thành một lượt rẽ phải.
      4. Xóa điểm cuối cùng trong danh sách cho đến góc hiện tại và góc danh sách ứng viên cuối cùng theo hướng ngược chiều kim đồng hồ.
      5. Thêm điểm hiện tại vào danh sách thí sinh
    4. Thêm tất cả trừ hai ứng cử viên đầu tiên và cuối cùng vào danh sách PolygonCandidates
  3. Tìm điểm xa nhất trong danh sách PolygonCandidates.

Tôi không biết phải làm gì với các trường hợp gốc tọa độ và hai đỉnh khác đều nằm trên cùng một đường thẳng. Trong trường hợp đó, góc sẽ giống nhau. Nếu bạn có một đa giác có lỗ, bạn có thể tìm góc tối thiểu / tối đa của mỗi lỗ và xóa bất kỳ điểm ứng cử viên nào nằm trong phạm vi đó.

Ưu điểm chính của phương pháp này là bạn không phải kiểm tra giao điểm giữa đường thẳng hiện tại và tất cả các cạnh đa giác.

Điều này hoạt động ... tôi nghĩ. Tôi đã cập nhật mã giả ở trên và python để dễ đọc hơn.


Đây phải là bản chỉnh sửa cuối cùng. Ví dụ dưới đây sẽ tìm thấy lỗ thông lớn nhất cho hình dạng đã cho. Tôi đã thay đổi tập lệnh để sử dụng Điểm và Vectơ, để thử và làm cho nó dễ đọc hơn.

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)])

Liệu thuật toán này thực sự hoạt động? Có lẽ bạn có thể minh họa nó bằng một ví dụ đơn giản, chẳng hạn như hình lục giác ((0,0), (- 2,0), (- 2,3), (2,2), (- 1,1), (4 , 0), (0,0))? Điều gì xảy ra khi bạn bắt đầu ở (0,0)? Và thuật toán này có ý định gì? Chẳng hạn, nó không tìm thấy đoạn đường dài nhất trong đa giác (có độ dài 1,2 * sqrt (26)).
whuber

Tuy nhiên, cảm ơn vì nhận xét Travis, điều này sẽ không hoạt động trong mọi trường hợp (xem ví dụ thân tàu lõm), từ isRightTurn (A, B, C) sẽ là sai và AC sẽ không phải là phân khúc ứng cử viên. Nếu B ở xa hơn về phía bắc, nó có thể hình dung tất cả một người cho một phân khúc AE, vì vậy tôi sẽ không muốn loại trừ hoàn toàn điểm A cho đến khi tất cả các điểm khác được kiểm tra.

@whuber, với hình dạng đó, tôi không thấy đoạn đường dài nhất là 1,2 * sqrt (26). Trừ khi tôi đã hoàn toàn bỏ lỡ những gì câu hỏi này là về. Nó sẽ không phải là sqrt (2), từ (0,0) -> (- 1,1) hoặc (-2,0) -> (- 1,1).
ngày

1
@DanPatterson, tôi có thể đã bỏ lỡ những gì bạn đang hỏi. Hiểu biết của tôi là: khoảng cách lớn nhất giữa một đỉnh đã cho và bất kỳ đỉnh nào khác, không giao với ranh giới của đa giác. Tôi đã cập nhật tập lệnh của mình để tìm khoảng cách tối đa của đa giác.
ngày

Đa giác lồi dường như không phải là một vấn đề với các ví dụ đơn giản mà người ta có thể tìm thấy trên web và trong các văn bản. Đường kính đa giác cho thân tàu lõm dường như có một số cách hiểu khác nhau và tìm nạp đa giác, bây giờ tôi bắt đầu nhận ra nó là một ấm cá khác. Trong mọi trường hợp, không giao nhau bất cứ điều gì, là những gì tôi đang theo đuổi. Mối quan tâm của tôi là thiếu các định nghĩa và ví dụ rõ ràng với các ví dụ thực tế. Tôi có thể bao quát những cái lồi, nhưng những cái lõm đang chứng tỏ có vấn đề và vượt ra ngoài chuyên môn toán học / tính toán của tôi như được hỗ trợ / làm nổi bật bởi một số đề xuất của Bill.

1

Có lẽ xem xét tam giác dữ liệu. Những dòng nào là phổ biến cho các cạnh đa giác sẽ dễ dàng thiết lập và những dòng còn lại có thể được so sánh để tìm ra dài nhất? Câu hỏi sau đó là thuật toán tam giác nào bạn cần.

Đó chỉ là một linh cảm nhưng tôi nghi ngờ (trớ trêu thay) tam giác "chất lượng thấp nhất" mà người ta có thể tạo phải chứa dòng bạn đang tìm kiếm, ví dụ như Hình 1 trong https://www.google.co.uk/url?sa=t&rct= j & q = & esrc = s & source = web & cd = 6 & ved = 0CEoQFjAF & url = http% 3,3%


Mã của tôi trên blog của tôi thực sự hiệu quả hơn, đó là thuật ngữ mà tôi cần làm rõ cũng như phải làm gì trong trường hợp vỏ tàu lõm.

Một hình tam giác vốn sẽ xử lý một thân tàu lõm (nhiều như nó sẽ không tạo ra bất kỳ cạnh tam giác nào vượt qua ranh giới đa giác)
AnserGIS
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.