Nối dòng khi không biết hướng


8

Tôi đang vật lộn với vấn đề này. Tôi có một đa tuyến được tạo thành từ một số phân khúc. Mỗi phân đoạn được tạo thành từ các điểm, mỗi điểm được xác định trong không gian 3D theo tọa độ và độ cao. Cùng nhau, nếu được vẽ, các phân đoạn tạo thành một đường liên tục nhiều hơn hoặc ít hơn (có thể có các khoảng nghỉ giữa các phân đoạn), nhưng bản thân các phân đoạn không liên tiếp với nhau, cũng như các điểm của tất cả các phân khúc đều đi theo cùng một hướng di chuyển.
Câu hỏi là: làm thế nào tôi có thể tạo, tốt nhất là sử dụng Python, một dòng từ các phân đoạn không liên tiếp này để tôi có thể đo khoảng cách giữa các điểm và tổng chiều dài của dòng.
Tôi thậm chí không biết đoạn nào là đoạn đầu tiên hay đoạn cuối cùng trong dòng, nhưng bằng cách nào đó tôi phải đặt chúng theo đúng trình tự và đảm bảo tất cả chúng đều cùng hướng để tôi có thể đo chúng.
Cảm ơn vì sự trợ giúp. Tôi sẽ vui lòng cung cấp thêm thông tin, dữ liệu, v.v. Tôi nhấn mạnh rằng tôi không yêu cầu mã python thực tế (không phải là tôi sẽ từ chối nó ...), chỉ là chiến lược. Bob


Các phân đoạn trong đa tuyến có vượt qua các phân khúc khác không? Nếu vậy, có yêu cầu phá vỡ các đoạn tại các giao lộ này không?
Kirk Kuykendall

Câu trả lời:


6

Các phân đoạn có thể được sử dụng để tạo thành một biểu đồ trừu tượng G trong đó chúng đóng vai trò của các nút . Xét một nút là đoạn (cung) từ điểm P đến điểm Q, PQ. Đặt R là điểm cuối gần nhất trong số tất cả các điểm cuối phân đoạn khác với P và gọi S là điểm cuối khác của phân khúc R. G sau đó chứa một cạnh từ nút PQ đến nút RS và chúng ta sẽ gắn nhãn cạnh này với các điểm P và R.

Nếu chúng ta muốn thành công, thì G là một đồ thị tuyến tính hoặc một chu kỳ đơn. Bạn có thể phát hiện đó là bằng cách lưu trữ độ của các nút khi bạn tạo các cạnh. (Mức độ của một nút đếm các cạnh phát ra từ nút đó.) Tất cả các nút, ngoại trừ hai trong số chúng, phải có độ 2. Cả hai nút còn lại phải có độ 2 (cho một chu kỳ) hoặc độ 1: điều này đánh dấu chúng là các đầu của polyline. Trong trường hợp đầu tiên, chọn bất kỳ nút nào để bắt đầu xây dựng đa tuyến; trong trường hợp thứ hai, chọn một trong những mức độ 1. Bất kỳ sự kết hợp độ nào khác là một lỗi.

Đa tuyến được khởi tạo cho nút bắt đầu (một cung). Nhìn vào một trong các cạnh e trên nút này: nút khác của nó cho bạn biết cung nào sẽ xử lý tiếp theo và nhãn của nó cho bạn biết các đỉnh của các cung đó sẽ tham gia. (Tham gia vào các đỉnh với một đoạn thẳng mới nếu họ không có tọa độ giống hệt nhau.) Cập nhật polyline phát triển trong thời trang này và, đồng thời, loại bỏ cạnh e từ đồ thị G . Tiếp tục cho đến khi xảy ra lỗi (và báo cáo rằng các cạnh không tạo thành một đa tuyến được kết nối không phân nhánh) hoặc tất cả các cạnh được loại bỏ. Nếu không có lỗi nào được đưa ra, hãy xuất đa tuyến bạn đã tạo.

Thí dụ

Phác thảo các cung

Trong hình, các cung là AB, CD, EF và FG. Do đó, các nút của đồ thị là {AB, CD, EF, FG}. Các cạnh là AB - CD (được dán nhãn B và C), CD-EF (được gắn nhãn E và F) và EF - FG (được gắn nhãn F và F). Độ của AB và FG là 1 trong khi độ của CD và EF là 2. Dưới đây là sơ đồ của đồ thị trừu tượng và nhãn cạnh của nó:

Đồ thị

Chúng ta hãy tùy ý bắt đầu với FG, một trong các nút độ một. Bởi vì nó có độ 1, có một cạnh duy nhất EF - FG được kết nối với nó, được gắn nhãn F. Khởi tạo đa tuyến bằng cung G -> F. Vì nhãn chỉ định điểm cuối chung của GF và EF, chúng tôi không phải tạo kết nối mới. Xóa cạnh EF - FG khỏi biểu đồ và mở rộng đa tuyến bằng EF qua G -> F -> E.

Việc loại bỏ cạnh này làm giảm mức độ của EF từ 2 xuống 1, để lại nó với một cạnh duy nhất cho CD hình cung có nhãn E và D. Điều này cho bạn biết mở rộng đa tuyến từ E đến D (với một đoạn đường mới ở đó) và từ đó CD cung: G -> F -> E -> D -> C. Theo cách tương tự, sau khi loại bỏ cạnh ED - CD, bạn sẽ mở rộng đa tuyến hơn nữa đến dạng cuối cùng của nó G -> F -> E -> D -> C -> B -> A. Bạn dừng lại vì tất cả các cạnh đã bị xóa khỏi biểu đồ: điều này cho thấy thủ tục đã thành công.


Cảm ơn bạn Whuber. Tôi sẽ cần một chút thời gian để đánh giá đề xuất của bạn, nhưng tôi đã có một số câu hỏi: bạn nói "Hãy để R là điểm cuối gần nhất". Điều này tôi tin là mấu chốt của vấn đề. Có ba điểm tiếp xúc tiềm năng giữa các phân đoạn, tọa độ x, y và z. Ngay cả khi chúng ta loại bỏ tọa độ z vì một đường thẳng có thể hoàn toàn bằng phẳng, điều đó vẫn để lại hai sự lựa chọn. Hãy nhớ rằng giải pháp phải được lập trình (bằng Python), không có lựa chọn trực quan nào khả thi.

Suy nghĩ hiện tại của tôi là sử dụng Matplotlib để vẽ các phân đoạn bất kể trình tự, điều đó sẽ tạo ra dòng nhưng các điểm sẽ cần tạo lại. Làm sao?

@Bob Tìm điểm gần nhất là một hoạt động GIS tương đối đơn giản (ngay cả trong 3D). Mỗi phân đoạn PQ có hai điểm cuối P và Q. Trước tiên, hãy tìm điểm gần nhất với P trong số tập hợp các điểm cuối của tất cả các phân đoạn (không bao gồm chính PQ). Nó là điểm cuối, R, của một số phân khúc RS khác nhau. Tạo cạnh PQ -> RS được gắn nhãn bởi P và R. Lặp lại tìm kiếm liên quan đến điểm cuối Q để có được cạnh khác. Một điều tôi không lưu ý: bạn cần một ngưỡng chịu đựng; nếu điểm gần nhất lớn hơn dung sai, kết luận không có điểm gần nhất.
whuber

Khó khăn thực sự trong toàn bộ quy trình là việc kết nối các phân đoạn rời rạc có thể có khả năng tạo ra các giao điểm nhỏ (tùy thuộc vào lý do và cách các điểm cuối phân đoạn không khớp chính xác). Điều này có thể gây rắc rối để sửa chữa nói chung. Nếu những vấn đề như vậy xảy ra, hãy xem xét việc làm sạch polyline để loại bỏ những sai sót đó.
whuber

3

Theo dõi câu trả lời của người làm trắng, nếu bạn đang muốn thực hiện điều này trong Python thì hãy xem thư viện NetworkX có tất cả các loại chức năng liên quan đến biểu đồ, nút và cạnh. Tôi nghĩ rằng đó là các chức năng Traversal thực hiện những gì whuber đang mô tả. Nó cũng bao gồm chức năng vẽ cơ bản.

Khi bạn đã có đơn hàng của mình rồi, bạn có thể dễ dàng xây dựng hình học trong Shapely để thực hiện phân tích loại GIS hơn nữa hoặc hiển thị trong MatPlotLib, xuất sang GeoJSON, v.v.


2

Tôi sẽ tính khoảng cách giữa mỗi phân đoạn bắt đầu và phân khúc kết thúc, và sau đó tham gia những phân đoạn có khoảng cách ngắn nhất giữa chúng?


Tôi cũng nghĩ vậy. Tôi không chắc liệu nó có hoạt động như một giải pháp chung không.
George Silva

@George Bạn đúng rồi. Các vấn đề xảy ra trong các tình huống tương tự như tôi đã mô tả trong một nhận xét cho bài đăng của @ nathanvda. Bạn muốn sử dụng khoảng cách điểm cuối đến điểm cuối cho bất kỳ giải pháp nào. Đề xuất của @ johanvdw có thể được thực hiện nếu khoảng cách được hiểu theo nghĩa này; nó tương tự như kỹ thuật tiêu chuẩn để xây dựng cây bao trùm tối thiểu Euclide của một tập hợp các điểm.
whuber

Bạn đúng rồi. Tôi có nghĩa là nút bắt đầu để kết thúc nút thay vì phân khúc.
johanvdw

Đó thực sự là những gì tôi cũng nghĩ :)
nathanvda

1

Bạn có rất nhiều phân khúc, không có thứ tự hoặc định hướng cụ thể. Bạn không biết cái nào thực sự chạm hoặc chồng lên nhau, và cái nào chỉ đơn thuần là gần gũi.

Đối với mỗi phân khúc chỉ có điểm bắt đầu và điểm cuối là quan trọng. Mục tiêu là tạo ra một đa tuyến lớn, định hướng của đa tuyến đó không quan trọng, tôi đoán vậy.

Trong trường hợp đó tôi sẽ tạo một số loại tập hợp / mảng các phân đoạn, bắt đầu với phân đoạn đầu tiên, hoàn toàn ngẫu nhiên.

Trong mã giả làm một cái gì đó như

all_segments = set of all segments

# take the first segment out of set
new_polyline = all_segments.pop

until all_segments.empty?
  start_segm = find_segment_closest_to(new_polyline.start_point)
  remove_from_all_segments(start_segm)
  expand_polyline_at_begin(new_polyline, start_segm) 
  end_segm = find_segment_closest_to(new_polyline.end_point)
  expand_polyline_at_end(new_polyline, end_segm)
  remove_from_all_segments(end_segm)
end

Một cái gì đó như thế? Đó là một mức độ rất cao. Bạn sẽ cần phải xử lý các trường hợp ranh giới. Tôi đoán bạn biết hoặc có thể khoảng cách / khoảng cách lớn nhất có thể, bởi vì bạn sẽ cần phải loại trừ một số điểm được tìm thấy: nếu điểm gần nhất có thể nằm ở đầu kia của đa tuyến thì đó không phải là một lựa chọn :) Cách dễ nhất để xử lý đó là xác định khoảng cách tối đa. Điều này cũng sẽ giới hạn số điểm bạn sẽ phải xem xét cho từng phân khúc.

[EDIT: chi tiết find_segment_closes_to]

Để làm cho nó hoàn toàn rõ ràng làm thế nào tôi sẽ tìm thấy phân đoạn đóng, trước tiên tôi sẽ viết một cách tiếp cận rất thô thiển:

def find_segment_closes_to(point)
  closest_point = nothing
  closest_distance = MAX_GAP_RANGE
  all_segments.each do |segment|
    if distance(segment.end_point, point) < closest_distance
      closest_point = segment.end_point
      closest_segment = segment
      closest_distance = distance(segment.end_point, point)
   else if distance(segment.start_point, point) < closest_distance
      closest_point = segment.start_point
      closest_segment = segment
      closest_distance = distance(segment.start_point, point)
    end       
  end  
  # the closest segment
  return closest_segment
end     

Đây là một cách tiếp cận rất thô sơ, sẽ lặp đi lặp lại trên tất cả các phân khúc và kiểm tra từng điểm cuối gần nhất.

Lý tưởng nhất là bạn sẽ có một số cơ sở hạ tầng nơi bạn có thể yêu cầu tất cả các điểm bắt đầu và điểm cuối nằm trong phạm vi và chỉ tìm điểm gần nhất trong số đó.

cái đó có giúp ích không? Tôi hy vọng nó sẽ giúp bạn bắt đầu.


1
'find_seribution_closest_to' sẽ tạo ra kết quả sai trong một số trường hợp. Hãy tưởng tượng một polyline gần như tự đóng lại, nhưng không hoàn toàn. Một đỉnh của đa tuyến này có thể rất gần với giữa các phân đoạn khác của nó, nhưng nó không nên được kết nối với phân đoạn đó. Đây là lý do tại sao một thuật toán chính xác dựa vào so sánh điểm-điểm chứ không phải so sánh điểm-phân đoạn.
whuber

Đúng vậy: bạn chỉ nên nhìn vào điểm bắt đầu và điểm cuối của một đoạn. Có thể bạn nói trong giải pháp của bạn gần như giống nhau, nhưng tôi thấy nó rất khó đọc và hiểu.
nathanvda

Biết ngôn ngữ và các kỹ thuật cơ bản của lý thuyết đồ thị là điều cần thiết nếu bạn muốn có thể đọc tài liệu về các thuật toán.
whuber

@whuber cảm ơn bạn cho tiền boa. Tôi sẽ nhìn vào đó.
nathanvda
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.