Unindo linhas quando a direção não é conhecida

8

Estou lutando com esse problema. Eu tenho uma polilinha composta de vários segmentos. Cada segmento é composto de pontos, cada ponto identificado no espaço 3D por coordenadas e elevação. Juntos, se plotados, os segmentos formam uma linha mais ou menos contínua (pode haver quebras entre os segmentos), mas os segmentos em si não são consecutivos, nem os pontos de todos os segmentos seguem a mesma direção de deslocamento.
A questão é: como posso criar, usando Python, de preferência, uma única linha desses segmentos não consecutivos para que eu possa medir a distância entre os pontos e o comprimento total da linha.
Eu nem sei qual dos segmentos é o primeiro ou o último da linha, mas de alguma forma eu tenho que colocá-los na sequência correta e garantir que todos apontem na mesma direção para que eu possa medi-los.
Obrigado por qualquer ajuda. Ficarei feliz em fornecer informações, dados, etc. adicionais. Sublinho que não estou pedindo o código python real (não que eu o recusasse ...), apenas a estratégia. Prumo


fonte
Os segmentos na polilinha cruzam outros segmentos? Em caso afirmativo, há um requisito para interromper os segmentos nessas interseções?
precisa saber é o seguinte

Respostas:

6

Os segmentos podem ser usados ​​para formar um gráfico abstrato G no qual eles desempenham o papel de nós . Considere um nó que é o segmento (arco) do ponto P ao ponto Q, PQ. Seja R o ponto final mais próximo entre todos os outros pontos finais do segmento para P e S seja o outro ponto final do segmento de R. G então contém uma aresta do nó PQ ao nó RS e iremos rotular essa aresta com os pontos P e R.

Se queremos ter sucesso, G é um gráfico linear ou um único ciclo. Você pode detectar qual é qual armazenando os graus dos nós ao criar as arestas. (O grau de um nó conta as arestas que emanam desse nó.) Todos os nós, exceto possivelmente dois, devem ter o grau 2. Os outros dois devem ter o grau 2 (para um ciclo) ou o grau 1: isso os marca como as extremidades da polilinha. No primeiro caso, escolha qualquer nó para começar a construir a polilinha; no segundo caso, escolha uma das de grau 1. Qualquer outra combinação de graus é um erro.

A polilinha é inicializada no nó inicial (um arco). Observe uma das arestas e o incidente nesse nó: o outro nó informa qual arco deve ser processado a seguir e o rótulo indica quais vértices desses arcos devem ser unidos. (Junte-se aos vértices com um novo segmento de linha, se eles não têm coordenadas idênticas.) Atualize a crescente polilinha desta forma e, ao mesmo tempo, borda remove e do gráfico G . Continue até que ocorra um erro (e relate que as bordas não formam uma polilinha conectada sem ramificação) ou que todas as bordas são removidas. Se nenhum erro for gerado, imprima a polilinha que você criou.

Exemplo

Esboço dos arcos

Na figura, os arcos são AB, CD, EF e FG. Os nós do gráfico são, portanto, {AB, CD, EF, FG}. As bordas são AB - CD (rotulado com B e C), CD-EF (rotulado com E e F) e EF - FG (rotulado com F e F). Os graus de AB e FG são 1, enquanto os graus de CD e EF são 2. Aqui está um esquema do gráfico abstrato e seus rótulos de aresta:

O gráfico

Vamos começar arbitrariamente com FG, um dos nós de grau um. Por ter o grau 1, há uma aresta EF-FG conectada a ele, rotulada com F. Inicialize a polilinha com arco G -> F. Como o rótulo designa um ponto de extremidade comum de GF e EF, não precisamos fazer uma nova conexão. Remova a aresta EF - FG do gráfico e estenda a polilinha com EF através de G -> F -> E.

Essa remoção de aresta reduz o grau de EF de 2 para 1, deixando-o com uma única aresta para formar um CD marcado com E e D. Isso permite que você estenda a polilinha de E para D (com um novo segmento de linha) e depois arco CD: G -> F -> E -> D -> C. Da mesma maneira, após remover a borda ED - CD, você estenderá a polilinha ainda mais para sua forma final G -> F -> E -> D -> C -> B -> A. Você para porque todas as arestas foram removidas do gráfico: isso indica que o procedimento foi bem-sucedido.

whuber
fonte
Obrigado Whuber. Vou precisar de algum tempo para avaliar sua sugestão, mas já tenho algumas perguntas: você diz "Deixe R ser o ponto final mais próximo". Eu acredito que este é o cerne do problema. Existem três pontos de contato em potencial entre os segmentos, as coordenadas x, y e z. Mesmo se eliminarmos a coordenada z porque uma linha pode ser perfeitamente plana, isso ainda deixa duas opções. Lembre-se de que a solução precisa ser programada (em Python), nenhuma opção visual é possível.
Meu pensamento atual é usar o Matplotlib para plotar os segmentos, independentemente da sequência, que criariam a linha, mas os pontos precisariam ser recriados. Quão?
@Bob Encontrar o ponto mais próximo é uma operação GIS relativamente simples (mesmo em 3D). Cada segmento PQ possui dois pontos de extremidade P e Q. Primeiro, encontre o ponto mais próximo de P na coleção de pontos de extremidade de todos os segmentos (não incluindo o próprio PQ). É o ponto final, R, de algum segmento diferente RS. Crie a borda PQ -> RS rotulada por P e R. Repita a pesquisa em relação ao ponto final Q para obter a outra borda. Uma coisa que não notei: você precisa de um limite de tolerância; se o ponto mais próximo for maior que a tolerância, conclua que não há ponto mais próximo.
whuber
A dificuldade real em todo o procedimento é que a conexão de segmentos disjuntos pode potencialmente criar pequenas auto-interseções (dependendo de por que e como os pontos de extremidade do segmento não correspondem exatamente). Isso pode ser problemático para corrigir em geral. Se tais problemas ocorrerem, considere limpar a polilinha para eliminar essas falhas.
whuber
3

Seguindo a resposta do whuber, se você estiver procurando fazer isso no Python, consulte a biblioteca NetworkX que possui todo tipo de funcionalidade relacionada a gráficos, nós e arestas. Eu acho que são as funções da Traversal que implementam o que o whuber está descrevendo. Também inclui funcionalidade básica de desenho.

Depois de receber os pedidos de sua linha, você poderá facilmente construir geometrias no Shapely para fazer mais análises do tipo GIS ou exibir no MatPlotLib, exportar para GeoJSON etc.

geographika
fonte
2

Eu calcularia a distância entre cada segmento inicial e final e depois juntaria os com a menor distância entre eles?

johanvdw
fonte
Eu pensei nisso também. Não tenho certeza se funcionaria como uma solução geral.
George Silva
@ George Você está correto. Os problemas ocorrem em situações semelhantes à que eu descrevi em um comentário ao post do @ nathanvda. Você deseja usar distâncias de ponto a ponto a qualquer solução. A sugestão de @ johanvdw pode ser implementada se as distâncias forem entendidas nesse sentido; é análogo à técnica padrão para construir a árvore de abrangência mínima euclidiana de uma coleção de pontos.
whuber
Você está certo. Eu quis começar de extremidade do nó em vez do segmento.
Johanvdw 03/03
Isso é realmente o que eu mento bem :)
nathanvda
1

Você tem muitos segmentos, nenhuma ordem ou orientação específica. Você não sabe quais realmente tocam ou se sobrepõem e quais são apenas próximas.

Para cada segmento, apenas o ponto inicial e o ponto final são importantes. O objetivo é fazer uma grande polilinha, a orientação dessa polilinha não é importante, eu acho.

Nesse caso, eu faria algum tipo de conjunto / matriz de segmentos, começando com o primeiro, que é inteiramente aleatório.

No pseudocódigo, faça algo como

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

Algo parecido? Esse é um nível muito alto. Você precisará lidar com casos de fronteira. Suponho que você conheça ou possa ter a maior distância / distância possível, porque será necessário excluir de alguma forma os pontos encontrados: se o ponto mais próximo possível estiver na outra extremidade da polilinha, isso não é uma opção :) A maneira mais fácil de lidar com isso é definir uma distância de intervalo máxima. Isso também limitará o número de pontos que você terá que procurar para cada segmento.

[EDIT: detalhe o find_segment_closes_to]

Para deixar absolutamente claro como eu encontraria o segmento de fechamentos, escreverei primeiro uma abordagem muito grosseira:

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     

Essa é uma abordagem muito grosseira, que irá percorrer todos os segmentos e verificar cada ponto final mais próximo.

Idealmente, você teria alguma estrutura de dados na qual poderia solicitar todos os pontos de partida e pontos finais que estão dentro do alcance e encontrar apenas o ponto mais próximo entre eles.

Isso ajuda? Espero que você comece.

nathanvda
fonte
1
'find_segment_closest_to' produzirá resultados errados em alguns casos. Imagine uma polilinha que quase se fecha, mas não exatamente. Um vértice dessa polilinha pode estar extremamente próximo ao meio de outro de seus segmentos, mas não deve estar conectado a esse segmento. É por isso que um algoritmo correto se baseia em comparações ponto a ponto, não comparações ponto a segmento.
whuber
Sim, de fato: você deve observar apenas os pontos de início e de fim de um segmento. Talvez você tenha dito na sua solução quase a mesma coisa, mas achei muito difícil de ler e entender.
Nathanvda 3/03
Conhecer a linguagem e as técnicas básicas da teoria dos grafos é essencial se você quiser ler a literatura sobre algoritmos.
whuber
@whuber obrigado pela dica. Vou analisar isso.
Nathanvda 03/03