Ho un problema di geometria computazionale che ritengo dovrebbe avere una soluzione relativamente semplice, ma non riesco a capirlo.Determinare lo scafo non convesso della raccolta di segmenti di linea
Devo determinare il profilo non convesso di una regione definita da diversi segmenti di linea.
Sono a conoscenza di vari algoritmi di scafo non convesso (ad esempio forme alfa), ma non ho bisogno di un algoritmo completamente generale, in quanto i segmenti di linea definiscono una soluzione unica nella maggior parte dei casi.
Come ha sottolineato @ Jean-FrançoisCorbett, ci sono casi in cui ci sono più soluzioni. Ho chiaramente bisogno di pensare di più alla mia definizione.
Tuttavia, ciò che sto cercando di fare è di eseguire il reverse engineering e utilizzare un formato di file proprietario in modo da poter eseguire analisi di base sui dati raccolti da me stesso e da altri. Il formato del file è abbastanza semplice, ma determinare l'algoritmo che usano per definire il limite è considerevolmente più difficile.
Mettere in molti casi limite che si tradurrebbe in una soluzione non univoca fa sì che il software in questione si arresti senza preavviso o silenziosamente non riesca a leggere il file.
Pertanto, quando ci sono più soluzioni, sia la generazione di una delle soluzioni accettabili o la capacità di determinare che ci sono più soluzioni sarebbe accettabile.
Problema Definizione:
contorno del poligono non deve mai attraversare qualsiasi dei segmenti e dovrebbe essere formato da linee che uniscono tutti gli endpoint dei segmenti. Tutti i segmenti devono trovarsi interamente all'interno o lungo il confine del poligono. Nessun endpoint può essere utilizzato più di una volta nella struttura (ignorando "chiudendo" il poligono aggiungendo il primo punto alla fine per le librerie software che richiedono la chiusura di poligoni).
Nei casi in cui ci sono più soluzioni che soddisfano questi criteri, una di queste soluzioni sarebbe accettabile. (Sarebbe bello essere in grado di determinare quando la soluzione è non univoco, ma questo non è strettamente necessario.)
Esempi:
Per fare un esempio, ho qualcosa in questo senso :
E mi piacerebbe per delineare il seguente zona:
inoltre dovrebbe funzionare per segmenti non si intersecano. Per esempio.
credo (?) C'è una soluzione unica in entrambi i casi, in base ai criteri contorno in precedenza. (Modifica: Non c'è una soluzione unica in generale, come ha sottolineato @ Jean-FrançoisCorbett.Tuttavia, sono comunque interessato a un algoritmo che possa generare una delle soluzioni accettabili.)
Test Cases
Per un banco di prova, ecco il codice per generare le cifre di cui sopra. Sto usando Python qui, ma la domanda è indipendente dalla lingua.
import matplotlib.pyplot as plt
def main():
test1()
test2()
plt.show()
def test1():
"""Intersecting segments."""
segments = [[(1, 1), (1, 3)],
[(3.7, 1), (2, 4)],
[(2, 0), (3.7, 3)],
[(4, 0), (4, 4)],
[(4.3, 1), (4.3, 3)],
[(0, 2), (6, 3)]]
desired_outline = [segments[0][0], segments[5][0], segments[0][1],
segments[1][1], segments[2][1], segments[3][1],
segments[4][1], segments[5][1], segments[4][0],
segments[3][0], segments[1][0], segments[2][0],
segments[0][0]]
plot(segments, desired_outline)
def test2():
"""Non-intersecting segments."""
segments = [[(0, 1), (0, 3)],
[(1, 0), (1, 4)],
[(2, 1), (2, 3)],
[(3, 0), (3, 4)]]
desired_outline = [segments[0][0], segments[0][1], segments[1][1],
segments[2][1], segments[3][1], segments[3][0],
segments[2][0], segments[1][0], segments[0][0]]
plot(segments, desired_outline)
def plot(segments, desired_outline):
fig, ax = plt.subplots()
plot_segments(ax, segments)
ax.set_title('Segments')
fig, ax = plt.subplots()
ax.fill(*zip(*desired_outline), facecolor='gray')
plot_segments(ax, segments)
ax.set_title('Desired Outline')
def plot_segments(ax, segments):
for segment in segments:
ax.plot(*zip(*segment), marker='o', linestyle='-')
xmin, xmax, ymin, ymax = ax.axis()
ax.axis([xmin - 0.5, xmax + 0.5, ymin - 0.5, ymax + 0.5])
if __name__ == '__main__':
main()
Qualche idea?
Sto cominciando a sospettare che il software i cui risultati che sto cercando di riprodurre utilizza un algoritmo radiale-sweep in una sorta di "interno" sistema di coordinate (ad esempio un sistema di coordinate con x-prime
e y-prime
scalata e ruotata lungo la assi principali definiti dalla diffusione dei punti, il che rende il problema più "circolare"). Tuttavia, questo produce soluzioni in cui il contorno interseca segmenti di linea in molti casi. È abbastanza facile rilevare questo e forza bruta da lì, ma sicuramente c'è un modo migliore?
quando dici "le barre definiscono in modo univoco una soluzione" intendi che le barre devono trovarsi tutte all'interno del poligono finale? –
Sì! Avrei dovuto aggiungerlo alle informazioni. Grazie! –
Vedere il libro "Computational Geometry" di Mark de Berg e la libreria CGAL. Penso che troverete un algoritmo efficiente. – mitch