User:DressyPear4/DivideLinhaXNos
From OpenStreetMap Wiki
Jump to navigation
Jump to search
Dividir linha/polígono a cada X nós
Ideal para arquivos pegos de outras fontes usados para importação, o JOSM não permite que sejam enviadas geometrias com mais de 2000 nós. O script permite saber a quantidade de nós de cada linha e fazer uma divisão central ou em várias partes.
Como funciona?
- Selecionar uma linha ou polígono
- Escolher a quantidade de nós resultante em cada seguimento
- A quantidade de nós não deve ser maior ou igual à quantidade da linha original
Demonstração

Código
Python
Última atualização: 2026-03-11
from org.openstreetmap.josm.gui import MainApplication, Notification
from org.openstreetmap.josm.data.osm import Way, Relation, RelationMember
from org.openstreetmap.josm.data import UndoRedoHandler
from org.openstreetmap.josm.command import SequenceCommand, ChangeCommand, AddCommand, DeleteCommand
from javax.swing import JOptionPane, JPanel, JLabel, JSpinner, SpinnerNumberModel
from javax.swing import UIManager
from java.awt import GridLayout
from java.util import ArrayList
ds = MainApplication.getLayerManager().getEditDataSet()
if ds is None:
Notification(u"Nenhuma camada de edição ativa.")\
.setIcon(UIManager.getIcon("OptionPane.errorIcon"))\
.show()
else:
selected = list(ds.getSelected())
if len(selected) != 1 or not isinstance(selected[0], Way):
Notification(u"Selecione uma linha ou polígono para dividir!")\
.setIcon(UIManager.getIcon("OptionPane.informationIcon"))\
.show()
else:
way = selected[0]
total_nodes = len(way.getNodes())
panel = JPanel(GridLayout(3, 1))
panel.add(JLabel(u"A linha selecionada contém {} nós.".format(total_nodes)))
spinner = JSpinner(SpinnerNumberModel(100, 2, 1900, 100))
panel.add(spinner)
info_msg = u"<html><i><span style='color:red;'>ATENÇÃO! Se a linha é membro de uma relação,<br>os novos membros devem ser adicionados manualmente.</span></i></html>"
panel.add(JLabel(info_msg))
result = JOptionPane.showConfirmDialog(None, panel, u"Dividir linha a cada X nós",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE)
if result == JOptionPane.OK_OPTION:
step = spinner.getValue()
if step >= total_nodes:
Notification(u"O valor escolhido é maior ou igual ao número de nós. Nada será dividido.")\
.setIcon(UIManager.getIcon("OptionPane.warningIcon"))\
.show()
else:
nodes = list(way.getNodes())
new_ways = []
for i in range(0, total_nodes - 1, step):
part_nodes_py = nodes[i:i + step + 1]
if len(part_nodes_py) < 2:
continue
part_nodes_java = ArrayList()
for node in part_nodes_py:
part_nodes_java.add(node)
new_way = Way()
new_way.setNodes(part_nodes_java)
new_way.setKeys(way.getKeys())
new_ways.append(new_way)
if len(new_ways) == 0:
Notification("Nenhum segmento foi criado.")\
.setIcon(UIManager.getIcon("OptionPane.warningIcon"))\
.show()
else:
cmds = []
# Atualiza a way original com os primeiros nos
way_mod = Way(way)
way_mod.setNodes(new_ways[0].getNodes())
cmds.append(ChangeCommand(ds, way, way_mod))
for w in new_ways[1:]:
cmds.append(AddCommand(ds, w))
UndoRedoHandler.getInstance().add(SequenceCommand("Dividir linha em segmentos", cmds))
Notification("Linha dividida em {} segmentos.".format(len(new_ways)))\
.setIcon(UIManager.getIcon("OptionPane.informationIcon"))\
.show()
JavaScript
Última atualização: 2026-03-11
"use strict";
const MainApplication = Java.type("org.openstreetmap.josm.gui.MainApplication");
const Notification = Java.type("org.openstreetmap.josm.gui.Notification");
const Way = Java.type("org.openstreetmap.josm.data.osm.Way");
const AddCommand = Java.type("org.openstreetmap.josm.command.AddCommand");
const ChangeCommand = Java.type("org.openstreetmap.josm.command.ChangeCommand");
const SequenceCommand = Java.type("org.openstreetmap.josm.command.SequenceCommand");
const UndoRedoHandler = Java.type("org.openstreetmap.josm.data.UndoRedoHandler");
const UIManager = Java.type("javax.swing.UIManager");
const JOptionPane = Java.type("javax.swing.JOptionPane");
const JPanel = Java.type("javax.swing.JPanel");
const JLabel = Java.type("javax.swing.JLabel");
const JSpinner = Java.type("javax.swing.JSpinner");
const SpinnerNumberModel = Java.type("javax.swing.SpinnerNumberModel");
const GridLayout = Java.type("java.awt.GridLayout");
const ArrayList = Java.type("java.util.ArrayList");
function dividirLinhaPorNos() {
const layer = MainApplication.getLayerManager().getEditLayer();
if (!layer || !layer.data) {
new Notification("Nenhuma camada de edição ativa.")
.setIcon(UIManager.getIcon("OptionPane.errorIcon")).show();
return;
}
const ds = layer.data;
const selected = ds.getSelectedWays();
if (selected.size() !== 1) {
new Notification("Selecione uma linha ou polígono para dividir!")
.setIcon(UIManager.getIcon("OptionPane.informationIcon")).show();
return;
}
const way = selected.iterator().next();
const nodes = way.getNodes();
let totalNodes = nodes.size();
const ehFechado = way.isClosed();
const nósExibicao = ehFechado ? totalNodes - 1 : totalNodes;
// Painel de Configuração
const panel = new JPanel(new GridLayout(3, 1));
panel.add(new JLabel("A linha selecionada contém " + nósExibicao + " nós."));
const spinner = new JSpinner(new SpinnerNumberModel(100, 2, 1900, 100));
panel.add(spinner);
const infoMsg = "<html><i><span style='color:red;'>ATENÇÃO! Se a linha é membro de uma relação,<br>os novos membros devem ser adicionados manualmente.</span></i></html>";
panel.add(new JLabel(infoMsg));
const result = JOptionPane.showConfirmDialog(
MainApplication.getMainFrame(),
panel,
"Dividir linha a cada X nós",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE
);
if (result === JOptionPane.OK_OPTION) {
const step = spinner.getValue();
if (step >= nósExibicao && !ehFechado) {
new Notification("O valor escolhido é maior ou igual ao número de nós. Nada será dividido.")
.setIcon(UIManager.getIcon("OptionPane.warningIcon")).show();
return;
}
const newWays = [];
const nodesList = [];
for (let i = 0; i < totalNodes; i++) {
nodesList.push(nodes.get(i));
}
// Lógica de fatiamento
for (let i = 0; i < totalNodes - 1; i += step) {
let partNodes = nodesList.slice(i, i + step + 1);
// Se o segmento ficou com apenas 1 nó (pode acontecer no final), ignora
if (partNodes.length < 2) continue;
let javaNodes = new ArrayList();
partNodes.forEach(n => javaNodes.add(n));
let newPartWay = new Way();
newPartWay.setNodes(javaNodes);
newPartWay.setKeys(way.getKeys());
newWays.push(newPartWay);
}
if (newWays.length <= 1) {
new Notification("Nenhum segmento foi criado (valor do step maior que a linha).")
.setIcon(UIManager.getIcon("OptionPane.warningIcon")).show();
} else {
const cmds = new ArrayList();
// Atualiza a way original (preserva ID) com o primeiro segmento
let wayMod = new Way(way);
wayMod.setNodes(newWays[0].getNodes());
cmds.add(new ChangeCommand(way, wayMod));
// Adiciona os demais segmentos como novas ways
for (let i = 1; i < newWays.length; i++) {
cmds.add(new AddCommand(ds, newWays[i]));
}
UndoRedoHandler.getInstance().add(new SequenceCommand("Dividir linha em segmentos", cmds));
new Notification("Linha dividida em " + newWays.length + " segmentos.")
.setIcon(UIManager.getIcon("OptionPane.informationIcon")).show();
}
}
}
dividirLinhaPorNos();