Algoritmo para descobrir pontos de inflexão para uma polilinha


22

Estou tentando descobrir os pontos de inflexão, ou seja, os pontos em que as curvas de uma linha começam e terminam. Se você olhar para a imagem, a linha verde pode ser uma estrada ou um riacho, e os pontos pretos são os pontos onde as curvas começam e terminam. insira a descrição da imagem aqui

Quais seriam as etapas de alto nível para automatizar a geração desses pontos? Eu tenho o ArcGIS desktop e sou bastante útil com o ArcObjects.


Os dados de origem são uma polilinha feita de segmentos de linha e você deseja aproximá-lo com curvas ou já possui segmentos de arco?
U2ros

Atualmente, é composto por segmentos de linha.
Devdatta Tengshe

1
A ilustração nesta pergunta se parece muito com uma publicada em esri.com/news/arcuser/0110/turning.html .
whuber

@ whuber: observação muito astuta. Essa era exatamente a fonte de dados que eu havia usado para criar a imagem.
Devdatta Tengshe

Respostas:


15

Quando a curva é composta por segmentos de linha, todos os pontos internos desses segmentos são pontos de inflexão, o que não é interessante. Em vez disso, a curva deve ser pensada como sendo aproximada pelos vértices desses segmentos. Ao dividir uma curva que pode ser diferenciada por duas vezes nesses segmentos, podemos calcular a curvatura. Um ponto de inflexão, a rigor, é então um lugar onde a curvatura é zero.

No exemplo, existem trechos longos, onde a curvatura é quase zero. Isso sugere que os pontos indicados devem aproximar as extremidades de tais trechos de regiões de baixa curvatura.

Um algoritmo eficaz, portanto, divide os vértices, calcula a curvatura ao longo de um conjunto denso de pontos intermediários, identifica faixas de curvatura quase zero (usando alguma estimativa razoável do que significa estar "próximo") e marca os pontos finais dessas faixas .

Aqui está o Rcódigo de trabalho para ilustrar essas idéias. Vamos começar com uma sequência de linhas expressa como uma sequência de coordenadas:

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)

Divine as coordenadas x e y separadamente para obter uma parametrização da curva. (O parâmetro será chamado time.)

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

Interpole os splines para plotagem e computação:

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

Precisamos de uma função para calcular a curvatura de uma curva parametrizada. Ele precisa estimar a primeira e a segunda derivada do spline. Com muitos splines (como splines cúbicos), esse é um cálculo algébrico fácil. Rfornece os três primeiros derivados automaticamente. (Em outros ambientes, pode-se querer calcular os derivados numericamente.)

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

Proponho estimar um limiar para a curvatura zero em termos da extensão da curva. Este pelo menos é um bom ponto de partida; deve ser ajustado de acordo com a tortuosidade da curva (ou seja, aumentada para curvas mais longas). Mais tarde, isso será usado para colorir as plotagens de acordo com a 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

Agora que os vértices foram estriados e a curvatura calculada, resta apenas encontrar os pontos de inflexão . Para mostrá-los, podemos plotar os vértices, plotar o spline e marcar os pontos de inflexão nele.

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)

Enredo

Os pontos em aberto são os vértices originais xye os pontos pretos são os pontos de inflexão identificados automaticamente com esse algoritmo. Como a curvatura não pode ser calculada com segurança nos pontos finais da curva, esses pontos não são especialmente marcados.


Talvez a terminologia que usei estivesse errada. O que você assumiu é exatamente o que eu queria. Sua resposta parece promissora e terei que trabalhar com R para processar meu Shapefile.
Devdatta Tengshe

3

Você pode usar a ferramenta Densify . Nesse caso, você escolhe densificar por ângulo. Em seguida, escolha o ângulo máximo aceito em uma linha reta. Em seguida, aplique à linha de resultado na ferramenta Dividir linha nos vértices . Por fim, exclua as linhas com comprimento_forma menor ao comprimento mínimo da estrada.

insira a descrição da imagem aqui

Nesta foto, vemos três etapas:

1- Densifique a linha usando o ângulo. Eu usei 10 graus como parâmetro e usamos splitline. Na figura, a linha curva está em sua fase inicial.

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

2- Selecione os segmentos nos quais o comprimento da forma não é redundante. Como podemos ver na tabela, não selecionei esses comprimentos redundantes. Depois, seleciono-os em uma nova classe de recurso.

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

3- Extraímos os vértices localizados nas bordas das linhas, que são pontos de inflexão.

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

Tenho os mesmos comentários e perguntas sobre a sua outra resposta: é uma boa idéia, mas ao mesmo tempo não está claro se ele produzirá o resultado desejado, nem como se deve escolher o ângulo do limiar. Você poderia fornecer uma ilustração do resultado para que os leitores possam avaliar o que essa proposta realmente faz? Fornecer exemplos trabalhados é especialmente importante ao recomendar o software ESRI como parte de uma solução, porque seus algoritmos geralmente não são documentados, tornando impossível saber exatamente o que eles estão fazendo.
whuber

para ter certeza de que é uma solução funcional, preciso testá-lo, mas não posso testá-lo, estou perdendo os dados, então suponho que as ferramentas propostas pela ESRI funcionem como o esperado, mas essas respostas precisam ser testado mais.
Geogeek

Poderíamos chamar-lhes idéias e não respostas
geogeek

1
Deseja que eu os coloque em comentários? BTW, se você quiser que os dados sejam testados, você pode - para começar - usar as coordenadas que eu postei na minha resposta, porque estão próximas da ilustração na pergunta. Mas por que não usar apenas dados geográficos úteis?
whuber

2
Sim, realmente esta solução está funcionando melhor para extrair apenas linhas retas.
Geogeek

1

Você pode usar a ferramenta Generalizar , que possui o deslocamento máximo da linha original como parâmetro, para poder escolher o deslocamento adequado ao seu caso.

insira a descrição da imagem aqui

Se nomearmos a linha original "line_cur" e a generalizada "line_gen", poderíamos recortar "line_cur" por "line_gen". O resultado será o segmento direto de "line_cur". Em seguida, poderíamos limpar um segmento muito curto, excluindo-o com uma consulta sql que seleciona o Comprimento da forma maior que o comprimento mínimo da estrada.


Esta é uma boa ideia. Não está claro como isso funcionaria na prática. Você poderia talvez mostrar um exemplo mostrando os pontos de inflexão encontrados?
whuber

Eu fiz uma edição para incluir uma imagem, a imagem explica como essa ferramenta pode fazer uma linha grudar nos segmentos retos, por isso temos que fazer um clipe na linha antiga, para extrair apenas os segmentos retos antigos
geogeek

algo não está claro, estou disponível para responder às suas perguntas?
Geogeek

Não vejo nenhum ponto de inflexão identificado na ilustração. Onde eles estariam exatamente? E como escolher a tolerância à generalização?
whuber

eu preciso de alguns dados para realizar o teste, mas eu acho que devemos escolher a tolerância pela experimentação
geogeek
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.