User:DressyPear4/Solar
From OpenStreetMap Wiki
Jump to navigation
Jump to search
Solar (remove blocos intermediários)
Sempre uso este script em conjunto com o plugin Gridify. A combinação permite remover blocos intermediários com apenas um clique, ideal para fazendas solares ou condomínios onde as construções seguem padrões repetitivos.
Como funciona?
- Necessário um grupo de polígonos selecionados
- Para o caso em que os espaços têm a mesma largura dos polígonos, selecione;
- Remover blocos alternados
- Para o caso em que os espaços têm o dobro da largura dos polígonos, selecione;
- Remover dois a cada três blocos
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 DataSet, Way, Node
from org.openstreetmap.josm.command import DeleteCommand, SequenceCommand
from org.openstreetmap.josm.data.UndoRedoHandler import getInstance
from javax.swing import JOptionPane, JPanel, JLabel, JRadioButton, ButtonGroup, BoxLayout, Box, UIManager
def delete_blocks_and_disconnected_nodes():
layer = MainApplication.getLayerManager().getActiveLayer()
if not layer or not hasattr(layer, "data") or not isinstance(layer.data, DataSet):
Notification("Nenhuma camada de dados ativa encontrada!")\
.setIcon(UIManager.getIcon("OptionPane.errorIcon"))\
.show()
return
dataset = layer.data
selected = dataset.getSelectedWays()
ways = [w for w in selected if w.isClosed() and w.isUsable()]
if not ways:
Notification(u"Selecione ao menos um polígono fechado.")\
.setIcon(UIManager.getIcon("OptionPane.warningIcon"))\
.show()
return
ways.sort(key=lambda way: way.getNodes()[0].getCoor().x if way.getNodes() else float('inf'))
node_to_blocks = {}
for way in ways:
for node in way.getNodes():
node_to_blocks.setdefault(node, []).append(way)
processed_blocks = set()
connected_sequences = []
for way in ways:
if way in processed_blocks:
continue
sequence = []
to_process = [way]
while to_process:
current = to_process.pop()
if current in processed_blocks:
continue
sequence.append(current)
processed_blocks.add(current)
for node in current.getNodes():
for connected_way in node_to_blocks.get(node, []):
if connected_way not in processed_blocks:
to_process.append(connected_way)
if len(sequence) > 2:
connected_sequences.append(sequence)
# Criar painel customizado
panel = JPanel()
panel.setLayout(BoxLayout(panel, BoxLayout.Y_AXIS))
info = JLabel(u"<html><b>Escolha o método de remoção:</b><br>"
"<span style=\"color:#FF0000\">"
u"Bug quando 90°. Girar para resolver.</span></html>")
info.setAlignmentX(0.0)
panel.add(info)
panel.add(Box.createVerticalStrut(12)) # espaço
rb1 = JRadioButton(u"Remover dois a cada três blocos")
rb1.setSelected(True)
rb1.setAlignmentX(0.0)
rb2 = JRadioButton("Remover blocos alternados")
rb2.setAlignmentX(0.0)
group = ButtonGroup()
group.add(rb1)
group.add(rb2)
panel.add(rb1)
panel.add(rb2)
result = JOptionPane.showConfirmDialog(None, panel, u"Seleção de método",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE)
if result == JOptionPane.OK_OPTION:
if rb1.isSelected():
choice = 0
else:
choice = 1
else:
return
to_delete_blocks = []
if choice == 0: # Opcao 1
for sequence in connected_sequences:
for i, way in enumerate(sequence):
if (i % 3) in [1, 2]:
to_delete_blocks.append(way)
elif choice == 1: # Opcao 2
for sequence in connected_sequences:
for i in range(1, len(sequence) - 1, 2):
to_delete_blocks.append(sequence[i])
all_commands = []
for way in to_delete_blocks:
all_commands.append(DeleteCommand(dataset, way))
if all_commands:
sequence_blocks_cmd = SequenceCommand("Remover blocos selecionados", all_commands)
getInstance().add(sequence_blocks_cmd)
else:
sequence_blocks_cmd = None
to_delete_nodes = [
node for node in dataset.getNodes()
if not node.getReferrers() and not node.isDeleted() and node.getId() <= 0
]
node_commands = []
for node in to_delete_nodes:
try:
node_commands.append(DeleteCommand(dataset, node))
except:
pass
if node_commands:
sequence_nodes_cmd = SequenceCommand(u"Remover nós desconectados", node_commands)
getInstance().add(sequence_nodes_cmd)
total_blocks = len(to_delete_blocks)
total_nodes = len(to_delete_nodes)
Notification(
u"Removidos {} blocos e {} nós desconectados.".format(total_blocks, total_nodes))\
.setIcon(UIManager.getIcon("OptionPane.informationIcon"))\
.show()
# Executa a funcao
delete_blocks_and_disconnected_nodes()
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 DeleteCommand = Java.type("org.openstreetmap.josm.command.DeleteCommand");
const SequenceCommand = Java.type("org.openstreetmap.josm.command.SequenceCommand");
const UndoRedoHandler = Java.type("org.openstreetmap.josm.data.UndoRedoHandler");
const DataSet = Java.type("org.openstreetmap.josm.data.osm.DataSet");
const JOptionPane = Java.type("javax.swing.JOptionPane");
const JPanel = Java.type("javax.swing.JPanel");
const JLabel = Java.type("javax.swing.JLabel");
const JRadioButton = Java.type("javax.swing.JRadioButton");
const ButtonGroup = Java.type("javax.swing.ButtonGroup");
const BoxLayout = Java.type("javax.swing.BoxLayout");
const Box = Java.type("javax.swing.Box");
const UIManager = Java.type("javax.swing.UIManager");
const ArrayList = Java.type("java.util.ArrayList");
function deleteBlocksAndNodes() {
const layer = MainApplication.getLayerManager().getEditLayer();
if (!layer || !layer.data) {
new Notification("Nenhuma camada de dados ativa encontrada!")
.setIcon(UIManager.getIcon("OptionPane.errorIcon"))
.show();
return;
}
const dataset = layer.data;
const selectedWays = dataset.getSelectedWays();
const ways = [];
let iter = selectedWays.iterator();
while (iter.hasNext()) {
let w = iter.next();
if (w.isClosed() && w.isUsable()) {
ways.push(w);
}
}
if (ways.length < 3) {
new Notification("Selecione pelo menos 3 polígonos conectados.")
.setIcon(UIManager.getIcon("OptionPane.warningIcon"))
.show();
return;
}
ways.sort((a, b) => a.getNode(0).getCoor().lon() - b.getNode(0).getCoor().lon());
const nodeToBlocks = new Map();
ways.forEach(way => {
let nodes = way.getNodes();
for (let i = 0; i < nodes.size(); i++) {
let node = nodes.get(i);
if (!nodeToBlocks.has(node)) nodeToBlocks.set(node, []);
nodeToBlocks.get(node).push(way);
}
});
const processedBlocks = new Set();
const connectedSequences = [];
ways.forEach(way => {
if (processedBlocks.has(way)) return;
let sequence = [];
let toProcess = [way];
while (toProcess.length > 0) {
let current = toProcess.pop();
if (processedBlocks.has(current)) continue;
sequence.push(current);
processedBlocks.add(current);
let nodes = current.getNodes();
for (let i = 0; i < nodes.size(); i++) {
let node = nodes.get(i);
let connected = nodeToBlocks.get(node) || [];
connected.forEach(cw => {
if (!processedBlocks.has(cw)) toProcess.push(cw);
});
}
}
if (sequence.length >= 3) connectedSequences.push(sequence);
});
// Se após o agrupamento não houver sequências válidas
if (connectedSequences.length === 0) {
new Notification("Nenhuma sequência de 3 ou mais blocos conectada.")
.setIcon(UIManager.getIcon("OptionPane.warningIcon"))
.show();
return;
}
const panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
const info = new JLabel("<html><b>Escolha o método de remoção:</b><br>" +
"<span style='color:#FF0000'>Bug quando 90°. Girar para resolver.</span></html>");
panel.add(info);
panel.add(Box.createVerticalStrut(12));
const rb1 = new JRadioButton("Remover dois a cada três blocos", true);
const rb2 = new JRadioButton("Remover blocos alternados");
const group = new ButtonGroup();
group.add(rb1); group.add(rb2);
panel.add(rb1); panel.add(rb2);
const result = JOptionPane.showConfirmDialog(
MainApplication.getMainFrame(),
panel,
"Seleção de Método",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE
);
if (result !== JOptionPane.OK_OPTION) {
new Notification("Ação cancelada pelo usuário.")
.setIcon(UIManager.getIcon("OptionPane.informationIcon"))
.show();
return;
}
const toDeleteBlocks = [];
connectedSequences.forEach(sequence => {
if (rb1.isSelected()) {
sequence.forEach((way, i) => {
if ((i % 3) === 1 || (i % 3) === 2) toDeleteBlocks.push(way);
});
} else {
for (let i = 1; i < sequence.length - 1; i += 2) {
toDeleteBlocks.push(sequence[i]);
}
}
});
if (toDeleteBlocks.length > 0) {
let cmds = new ArrayList();
toDeleteBlocks.forEach(w => cmds.add(new DeleteCommand(w)));
UndoRedoHandler.getInstance().add(new SequenceCommand("Remover blocos selecionados", cmds));
}
const allNodes = dataset.getNodes().iterator();
const nodeCmds = new ArrayList();
while (allNodes.hasNext()) {
let node = allNodes.next();
if (node.getReferrers().isEmpty() && !node.isDeleted() && node.getId() <= 0) {
nodeCmds.add(new DeleteCommand(node));
}
}
if (!nodeCmds.isEmpty()) {
UndoRedoHandler.getInstance().add(new SequenceCommand("Limpar nós órfãos", nodeCmds));
}
new Notification("Sucesso: " + toDeleteBlocks.length + " blocos e " + nodeCmds.size() + " nós removidos.")
.setIcon(UIManager.getIcon("OptionPane.informationIcon"))
.show();
}
deleteBlocksAndNodes();