Algoritmo per scoprire i punti di flesso per una polilinea


22

Sto cercando di scoprire i punti di flesso, cioè i punti in cui le curve in una linea iniziano e finiscono. Se guardi l'immagine, la linea verde può essere una strada o un ruscello e i punti neri sono i punti in cui iniziano e finiscono le curve. inserisci qui la descrizione dell'immagine

Quali sarebbero i passaggi di alto livello per automatizzare la generazione di questi punti? Ho un desktop ArcGIS e sono abbastanza utile con ArcObjects.


I dati di origine sono una polilinea composta da segmenti di linea e si desidera approssimarli con curve o contiene già segmenti di arco?
U2ros,

Attualmente è composto da segmenti di linea.
Devdatta Tengshe,

1
L'illustrazione in questa domanda è notevolmente simile a quella pubblicata su esri.com/news/arcuser/0110/turning.html .
whuber

@whuber: osservazione molto astuta. Era esattamente l'origine dati che avevo usato per creare l'immagine.
Devdatta Tengshe

Risposte:


15

Quando la curva è composta da segmenti di linea, tutti i punti interni di quei segmenti sono punti di flesso, il che non è interessante. Invece, la curva dovrebbe essere considerata come approssimata dai vertici di quei segmenti. Dividendo una curva due volte differenziabile a tratti attraverso quei segmenti, possiamo quindi calcolare la curvatura. Un punto di flesso, a rigor di termini, è quindi un luogo in cui la curvatura è zero.

Nell'esempio ci sono tratti allungati in cui la curvatura è quasi zero. Ciò suggerisce che i punti indicati dovrebbero approssimare le estremità di tali tratti di regioni a bassa curvatura.

Un algoritmo efficace splineerà quindi i vertici, calcolerà la curvatura lungo un denso insieme di punti intermedi, identificherà intervalli di curvatura quasi zero (usando una stima ragionevole di cosa significhi essere "vicino") e segnerà i punti finali di tali intervalli .

Ecco un Rcodice funzionante per illustrare queste idee. Cominciamo con una stringa di linea espressa come una sequenza di coordinate:

xy <- matrix(c(5,20, 3,18, 2,19, 1.5,16, 5.5,9, 4.5,8, 3.5,12, 2.5,11, 3.5,3, 
               2,3, 2,6, 0,6, 2.5,-4, 4,-5, 6.5,-2, 7.5,-2.5, 7.7,-3.5, 6.5,-8), ncol=2, byrow=TRUE)

Spline le x ed y coordinate separatamente per ottenere una parametrizzazione della curva. (Il parametro verrà chiamato time.)

n <- dim(xy)[1]
fx <- splinefun(1:n, xy[,1], method="natural")
fy <- splinefun(1:n, xy[,2], method="natural")

Interpolare le spline per la stampa e il calcolo:

time <- seq(1,n,length.out=511)
uv <- sapply(time, function(t) c(fx(t), fy(t)))

Abbiamo bisogno di una funzione per calcolare la curvatura di una curva parametrizzata. Deve stimare il primo e il secondo derivato della spline. Con molte spline (come spline cubiche) questo è un calcolo algebrico facile. Rfornisce automaticamente i primi tre derivati. (In altri ambienti, si potrebbe voler calcolare numericamente le derivate.)

curvature <- function(t, fx, fy) {
  # t is an argument to spline functions fx and fy.
  xp <- fx(t,1); yp <- fy(t,1)            # First derivatives
  xpp <- fx(t,2); ypp <- fy(t,2)          # Second derivatives
  v <- sqrt(xp^2 + yp^2)                  # Speed
  (xp*ypp - yp*xpp) / v^3                 # (Signed) curvature
  # (Left turns have positive curvature; right turns, negative.)
}

kappa <- abs(curvature(time, fx, fy))     # Absolute curvature of the data

Propongo di stimare una soglia per curvatura zero in termini di estensione della curva. Questo almeno è un buon punto di partenza; dovrebbe essere regolato in base alla tortuosità della curva (ovvero aumentata per curve più lunghe). Questo verrà successivamente utilizzato per colorare i grafici in base alla curvatura.

curvature.zero <- 2*pi / max(range(xy[,1]), range(xy[,2])) # A small threshold
i.col <- 1 + floor(127 * curvature.zero/(curvature.zero + kappa)) 
palette(terrain.colors(max(i.col)))                        # Colors

Ora che i vertici sono stati scanalati e la curvatura calcolata, resta solo da trovare i punti di flesso . Per mostrarli possiamo tracciare i vertici, tracciare la spline e segnare i punti di flesso su di essa.

plot(xy, asp=1, xlab="x",ylab="y", type="n")
tmp <- sapply(2:length(kappa), function(i) lines(rbind(uv[,i-1],uv[,i]), lwd=2, col=i.col[i]))
points(t(sapply(time[diff(kappa < curvature.zero/2) != 0], 
       function(t) c(fx(t), fy(t)))), pch=19, col="Black")
points(xy)

Tracciare

I punti aperti sono i vertici originali xye i punti neri sono i punti di flesso identificati automaticamente con questo algoritmo. Poiché la curvatura non può essere calcolata in modo affidabile ai punti finali della curva, tali punti non sono contrassegnati in modo speciale.


Forse la terminologia che ho usato era sbagliata. Quello che hai assunto è esattamente quello che volevo. La tua risposta sembra promettente e dovrò lavorare con R per elaborare il mio Shapefile.
Devdatta Tengshe,

3

È possibile utilizzare lo strumento Densify . In questo caso, si sceglie di densificare in base all'angolo, quindi selezionare l'angolo massimo accettato in linea retta. Quindi applicare la linea del risultato allo strumento Dividi linea ai vertici . Infine, elimina le linee che hanno shape_length minore della lunghezza minima della strada.

inserisci qui la descrizione dell'immagine

In questa immagine, vediamo tre passaggi:

1- Densifica la linea usando l'angolo. Ho usato 10 gradi come parametro e abbiamo usato la linea di divisione. Nella foto, la linea curva è nella sua fase iniziale.

arcpy.Densify_edit("line" , "ANGLE" , "","",10)
arcpy.SplitLine_management("line" , "line_split")

2- Selezionare i segmenti in cui shape_length non è ridondante. Come vediamo nella tabella, non ho selezionato quelle lunghezze ridondanti. Quindi, li seleziono in una nuova classe di funzionalità.

arcpy.Select_analysis("line_split" , "line_split_selected")

3- Abbiamo estratto i vertici situati nei bordi delle linee, che sono punti di flesso.

arcpy.FeatureVerticesToPoints_management("line_split_selected" , "line_split_pnt" , "DANGLE")

Ho gli stessi commenti e domande sulla tua altra risposta: è una bella idea, ma allo stesso tempo non è chiaro che produrrà il risultato desiderato, né come si dovrebbe scegliere l'angolo di soglia. Potresti fornire un'illustrazione dell'output in modo che i lettori possano valutare ciò che questa proposta fa davvero? Fornire esempi funzionanti è particolarmente importante quando si consiglia il software ESRI come parte di una soluzione, poiché i loro algoritmi di solito non sono documentati, rendendo impossibile sapere esattamente cosa stanno facendo.
whuber

per essere molto sicuro che sia una soluzione funzionante, devo testarlo, ma non posso provarlo, mi mancano i dati, quindi suppongo che gli strumenti proposti dall'ESRI funzioneranno come previsto, ma queste risposte devono essere testato ulteriormente.
geogeek,

potremmo nominarle idee e non risposte
geogeek,

1
Vorresti che li spostassi nei commenti, allora? A proposito, se vuoi testare i dati, potresti - per cominciare - usare le coordinate che ho pubblicato nella mia risposta, perché sono vicine all'illustrazione nella domanda. Ma perché non usare semplicemente i dati geografici che hai a portata di mano?
whuber

2
sì, davvero questa soluzione funziona meglio nell'estrarre solo linee rette.
geogeek,

1

Puoi utilizzare lo strumento Generalizza che ha l'offset massimo dalla linea originale come parametro, quindi puoi scegliere l'offset più adatto al tuo caso.

inserisci qui la descrizione dell'immagine

Se chiamiamo la linea originale "line_cur" e quella generalizzata "line_gen", allora potremmo tagliare "line_cur" con "line_gen". Il risultato sarà il segmento dritto di "line_cur". Quindi potremmo pulire alcuni segmenti molto brevi eliminandoli con una query sql che seleziona Shape_length maggiore della lunghezza minima della strada.


Questa è una bella idea Tuttavia, non è chiaro quanto funzionerebbe in pratica. Potresti forse mostrare un esempio che mostra i punti di flesso che si trovano?
whuber

ho fatto una modifica per includere un'immagine, l'immagine spiega come questo strumento potrebbe rendere una linea attaccata con segmenti dritti, quindi dobbiamo fare una clip alla vecchia linea, per estrarre solo i vecchi segmenti di linee rette
geogeek,

è qualcosa di non chiaro sono disponibile a rispondere alle tue domande?
geogeek,

Non vedo alcun punto di flesso identificato nell'illustrazione. Dove sarebbero esattamente? E come si dovrebbe scegliere la tolleranza per la generalizzazione?
whuber

ho bisogno di alcuni dati per eseguire il test, ma penso che dovremmo scegliere la tolleranza attraverso la sperimentazione
geogeek,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.