User:DressyPear4/AdicionaNosEntrePares

From OpenStreetMap Wiki
Jump to navigation Jump to search

Adicionar nós entre pares de nós

Para divisão de um polígono/linha em distâncias exatamente iguais (75%,50%,25%...)

Como funciona?

  • Selecione uma linha ou polígono
  • Escolha a quantidade desejada
  • Novos nós serão adicionados
    • Selecione uma geometria e dois nós para adicionar os novos nós apenas entre esse seguimento

Demonstração

Imagem.gif, clique para visualizar.

Código

from org.openstreetmap.josm.gui import MainApplication, Notification
from org.openstreetmap.josm.data.osm import Node, Way
from org.openstreetmap.josm.command import SequenceCommand, AddCommand, ChangeNodesCommand
from org.openstreetmap.josm.data.projection import ProjectionRegistry
from org.openstreetmap.josm.data.coor import EastNorth
from org.openstreetmap.josm.data import UndoRedoHandler
from javax.swing import JOptionPane, JPanel, UIManager, JLabel, JSpinner, SpinnerNumberModel
from java.awt import GridLayout

def main():
    layer = MainApplication.getLayerManager().getEditLayer()
    if layer is None or not hasattr(layer, "data"):
        Notification(u"Nenhuma camada de edição ativa")\
        .setIcon(UIManager.getIcon("OptionPane.errorIcon"))\
        .show()
        return

    ds = layer.data
    selection = ds.getSelected()

    selected_ways = [item for item in selection if isinstance(item, Way)]
    selected_nodes = [item for item in selection if isinstance(item, Node)]

    if len(selected_ways) != 1:
        Notification(u"Selecione exatamente uma linha (e opcionalmente dois nós dela)")\
        .setIcon(UIManager.getIcon("OptionPane.informationIcon"))\
        .show()
        return

    if len(selected_nodes) not in (0, 2):
        Notification (u"Selecione exatamente dois nós do caminho como referência")\
        .setIcon(UIManager.getIcon("OptionPane.informationIcon"))\
        .show()
        return

    way = selected_ways[0]
    way_nodes = list(way.getNodes())
    is_closed = way.isClosed()

    if is_closed and len(way_nodes) > 1 and way_nodes[0] == way_nodes[-1]:
        way_nodes = way_nodes[:-1]

    modo_trecho = False
    if len(selected_nodes) == 2:
        if all(n in way_nodes for n in selected_nodes):
            modo_trecho = True
        else:
            Notification(u"Os dois nós selecionados devem pertencer a linha")\
            .setIcon(UIManager.getIcon("OptionPane.informationIcon"))\
            .show()
            return

    total_segmentos = len(way_nodes) if is_closed else len(way_nodes) - 1

    panel = JPanel(GridLayout(0, 1))
    panel.add(JLabel("<html>Total de segmentos da linha: {}<br>"
                     u"Informe o número de nós a serem<br>adicionados entre cada par</html>".format(total_segmentos)))
    spinner = JSpinner(SpinnerNumberModel(1, 1, 100, 1))
    panel.add(spinner)

    result = JOptionPane.showConfirmDialog(None, panel, u"Adicionar nós", JOptionPane.OK_CANCEL_OPTION)
    if result != JOptionPane.OK_OPTION:
        return

    num_nodes = spinner.getValue()
    projection = ProjectionRegistry.getProjection()
    commands = []
    updated_nodes = []
    nos_adicionados = 0

    if modo_trecho:
        n1, n2 = selected_nodes
        i1 = way_nodes.index(n1)
        i2 = way_nodes.index(n2)

        if i1 == i2:
            Notification(u"Os nós selecionados não formam um trecho válido.")\
            .setIcon(UIManager.getIcon("OptionPane.warningIcon"))\
            .show()
            return

        total = len(way_nodes)
        caminho1, caminho2 = [], []
        idx = i1
        while idx != i2:
            caminho1.append(idx)
            idx = (idx + 1) % total
        caminho1_len = len(caminho1)

        idx = i2
        while idx != i1:
            caminho2.append(idx)
            idx = (idx + 1) % total
        caminho2_len = len(caminho2)

        indices_validos = caminho1 if (is_closed and caminho1_len <= caminho2_len) else caminho2
        if not is_closed:
            if i1 > i2:
                i1, i2 = i2, i1
            indices_validos = list(range(i1, i2))

        for i in range(len(way_nodes)):
            updated_nodes.append(way_nodes[i])
            if i in indices_validos:
                node_start = way_nodes[i]
                node_end = way_nodes[(i + 1) % len(way_nodes)]
                en_start = node_start.getEastNorth()
                en_end = node_end.getEastNorth()

                dx = (en_end.east() - en_start.east()) / (num_nodes + 1)
                dy = (en_end.north() - en_start.north()) / (num_nodes + 1)

                for j in range(1, num_nodes + 1):
                    x = en_start.east() + dx * j
                    y = en_start.north() + dy * j
                    latlon = projection.eastNorth2latlon(EastNorth(x, y))
                    new_node = Node(latlon)
                    new_node.setModified(True)
                    commands.append(AddCommand(ds, new_node))
                    updated_nodes.append(new_node)
                    nos_adicionados += 1
    else:
        for i in range(len(way_nodes) - (0 if is_closed else 1)):
            node_start = way_nodes[i]
            updated_nodes.append(node_start)

            node_end = way_nodes[(i + 1) % len(way_nodes)] if is_closed else way_nodes[i + 1]
            en_start = node_start.getEastNorth()
            en_end = node_end.getEastNorth()

            dx = (en_end.east() - en_start.east()) / (num_nodes + 1)
            dy = (en_end.north() - en_start.north()) / (num_nodes + 1)

            for j in range(1, num_nodes + 1):
                x = en_start.east() + dx * j
                y = en_start.north() + dy * j
                latlon = projection.eastNorth2latlon(EastNorth(x, y))
                new_node = Node(latlon)
                new_node.setModified(True)
                commands.append(AddCommand(ds, new_node))
                updated_nodes.append(new_node)
                nos_adicionados += 1

        if not is_closed:
            updated_nodes.append(way_nodes[-1])

    if is_closed and updated_nodes[0] != updated_nodes[-1]:
        updated_nodes.append(updated_nodes[0])

    commands.append(ChangeNodesCommand(way, updated_nodes))
    UndoRedoHandler.getInstance().add(SequenceCommand("Inserir nos", commands))

    total_final = len(updated_nodes) - (1 if is_closed else 0)
    Notification(
    u"<html><span style='white-space:nowrap;'>Nós adicionados:&nbsp;{}\nTotal de nós agora:&nbsp;{}</span></html>"
    .format(nos_adicionados, total_final)
    ).setIcon(UIManager.getIcon("OptionPane.informationIcon")).show()


main()