User:DressyPear4/Estrela

From OpenStreetMap Wiki
Jump to navigation Jump to search

Criar uma estrela

Não é tão comum mas as vezes encontradas em praças como caminho de pedestres ou espelho de água de um chafariz

Como funciona?

  • Partindo do centro até uma das pontas desenhe uma linha com apenas dois nós
  • Escolha o número de pontas

Demonstração

Imagem.gif, clique para visualizar.

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, Node
from org.openstreetmap.josm.data.coor import LatLon
from org.openstreetmap.josm.command import AddCommand, DeleteCommand, SequenceCommand
from org.openstreetmap.josm.data.UndoRedoHandler import getInstance
from javax.swing import JOptionPane, JPanel, JLabel, JSpinner, SpinnerNumberModel, UIManager
from java.awt import GridBagLayout, GridBagConstraints, Insets, Dimension
from java.util import LinkedList
import math

def criar_estrela_nodes(cx, cy, raio_externo, num_pontas, angulo_rotacao):
    angulo_base = 2 * math.pi / (num_pontas * 2)
    coords = []

    for i in range(num_pontas * 2):
        angulo = i * angulo_base
        raio = raio_externo if i % 2 == 0 else raio_externo / 2.5
        dx = raio * math.cos(angulo)
        dy = raio * math.sin(angulo)

        # Aplica rotacao
        dx_rot = dx * math.cos(angulo_rotacao) - dy * math.sin(angulo_rotacao)
        dy_rot = dx * math.sin(angulo_rotacao) + dy * math.cos(angulo_rotacao)

        dlat = dy_rot / 111320.0
        dlon = dx_rot / (111320.0 * math.cos(math.radians(cx)))
        lat = cx + dlat
        lon = cy + dlon
        coords.append((lat, lon))

    return coords

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

    dataset = layer.data
    selecionados = dataset.getSelected()

    ways = [x for x in selecionados if isinstance(x, Way)]
    if len(ways) != 1:
        Notification(u"Selecione uma linha com dois nós.")\
        .setIcon(UIManager.getIcon("OptionPane.informationIcon"))\
        .show()
        return

    linha = ways[0]
    if len(linha.getNodes()) != 2:
        Notification(u"A linha deve conter exatamente dois nós.")\
        .setIcon(UIManager.getIcon("OptionPane.informationIcon"))\
        .show()
        return

    centro = linha.getNodes()[0]
    ponta = linha.getNodes()[1]

    cx = centro.getCoor().lat()
    cy = centro.getCoor().lon()
    px = ponta.getCoor().lat()
    py = ponta.getCoor().lon()

    dx = (py - cy) * 111320 * math.cos(math.radians((cx + px) / 2))
    dy = (px - cx) * 111320
    raio = math.hypot(dx, dy)

    # Calcular angulo de orientacao da linha
    delta_x = (py - cy) * math.cos(math.radians((cx + px) / 2))
    delta_y = (px - cx)
    angulo_rot = math.atan2(delta_y, delta_x)

    # Caixa de dialogo
    panel = JPanel()
    panel.setLayout(GridBagLayout())
    c = GridBagConstraints()
    c.insets = Insets(5, 5, 5, 5)

    c.gridx = 0
    c.gridy = 0
    c.anchor = GridBagConstraints.EAST
    panel.add(JLabel(u"Número de pontas:"), c)

    c.gridx = 1
    spinner_model = SpinnerNumberModel(5, 3, 25, 1)
    spinner = JSpinner(spinner_model)
    spinner.setPreferredSize(Dimension(80, 25))
    panel.add(spinner, c)

    resultado = JOptionPane.showConfirmDialog(None, panel, "Criar Estrela", JOptionPane.OK_CANCEL_OPTION)
    if resultado != JOptionPane.OK_OPTION:
        return

    num_pontas = spinner.getValue()
    coords = criar_estrela_nodes(cx, cy, raio, num_pontas, angulo_rot)

    comandos = []
    novos_nos = []

    for lat, lon in coords:
        n = Node(LatLon(lat, lon))
        comandos.append(AddCommand(dataset, n))
        novos_nos.append(n)

    # Fechar a estrela com o primeiro no
    novos_nos.append(novos_nos[0])

    estrela = Way()
    estrela.setNodes(LinkedList(novos_nos))
    comandos.append(AddCommand(dataset, estrela))

    # Remover a linha original e seus dois nos
    comandos.append(DeleteCommand(dataset, linha))
    comandos.append(DeleteCommand(dataset, linha.getNodes()))

    getInstance().add(SequenceCommand("Criar estrela", comandos))
    Notification("Estrela criada com sucesso.")\
    .setIcon(UIManager.getIcon("OptionPane.informationIcon"))\
    .show()

executar()

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 Node            = Java.type("org.openstreetmap.josm.data.osm.Node");
const Way             = Java.type("org.openstreetmap.josm.data.osm.Way");
const AddCommand      = Java.type("org.openstreetmap.josm.command.AddCommand");
const DeleteCommand   = Java.type("org.openstreetmap.josm.command.DeleteCommand");
const SequenceCommand = Java.type("org.openstreetmap.josm.command.SequenceCommand");
const LatLon          = Java.type("org.openstreetmap.josm.data.coor.LatLon");
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 GridBagLayout      = Java.type("java.awt.GridBagLayout");
const GridBagConstraints = Java.type("java.awt.GridBagConstraints");
const Insets             = Java.type("java.awt.Insets");
const Dimension          = Java.type("java.awt.Dimension");
const ArrayList          = Java.type("java.util.ArrayList");

function criarEstrela() {
    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 dataset = layer.data;
    const selecionados = dataset.getSelectedWays();

    if (selecionados.size() !== 1) {
        new Notification("Selecione uma linha com dois nós.")
            .setIcon(UIManager.getIcon("OptionPane.informationIcon"))
            .show();
        return;
    }

    const linha = selecionados.iterator().next();
    const linhaNos = linha.getNodes();

    if (linhaNos.size() !== 2) {
        new Notification("A linha deve conter exatamente dois nós.")
            .setIcon(UIManager.getIcon("OptionPane.informationIcon"))
            .show();
        return;
    }

    const centro = linhaNos.get(0);
    const ponta = linhaNos.get(1);

    const cx = centro.getCoor().lat();
    const cy = centro.getCoor().lon();
    const px = ponta.getCoor().lat();
    const py = ponta.getCoor().lon();

    // Cálculos Geodésicos (Métrica simples)
    const latRad = (cx + px) / 2 * Math.PI / 180.0;
    const dx = (py - cy) * 111320 * Math.cos(latRad);
    const dy = (px - cx) * 111320;
    const raio = Math.sqrt(dx * dx + dy * dy);

    // Calcular ângulo de orientação da linha
    const deltaX = (py - cy) * Math.cos(latRad);
    const deltaY = (px - cx);
    const anguloRot = Math.atan2(deltaY, deltaX);

    // Interface Gráfica
    const panel = new JPanel(new GridBagLayout());
    const gbc = new GridBagConstraints();
    gbc.insets = new Insets(5, 5, 5, 5);

    gbc.gridx = 0; gbc.gridy = 0;
    gbc.anchor = GridBagConstraints.EAST;
    panel.add(new JLabel("Número de pontas:"), gbc);

    gbc.gridx = 1;
    const spinnerModel = new SpinnerNumberModel(5, 3, 25, 1);
    const spinner = new JSpinner(spinnerModel);
    spinner.setPreferredSize(new Dimension(80, 25));
    panel.add(spinner, gbc);

    const resultado = JOptionPane.showConfirmDialog(
        MainApplication.getMainFrame(), 
        panel, 
        "Criar Estrela", 
        JOptionPane.OK_CANCEL_OPTION,
        JOptionPane.PLAIN_MESSAGE
    );

    if (resultado !== JOptionPane.OK_OPTION) return;

    const numPontas = spinner.getValue();
    const anguloBase = (2 * Math.PI) / (numPontas * 2);
    const comandos = new ArrayList();
    const novosNos = new ArrayList();

    for (let i = 0; i < numPontas * 2; i++) {
        let angulo = i * anguloBase;
        let r = (i % 2 === 0) ? raio : raio / 2.5;

        let dxLocal = r * Math.cos(angulo);
        let dyLocal = r * Math.sin(angulo);

        // Aplica rotação conforme a orientação da linha original
        let dxRot = dxLocal * Math.cos(anguloRot) - dyLocal * Math.sin(anguloRot);
        let dyRot = dxLocal * Math.sin(anguloRot) + dyLocal * Math.cos(anguloRot);

        let dlat = dyRot / 111320.0;
        let dlon = dxRot / (111320.0 * Math.cos(cx * Math.PI / 180.0));
        
        let node = new Node(new LatLon(cx + dlat, cy + dlon));
        comandos.add(new AddCommand(dataset, node));
        novosNos.add(node);
    }

    // Fechar a estrela
    novosNos.add(novosNos.get(0));

    const estrela = new Way();
    estrela.setNodes(novosNos);
    comandos.add(new AddCommand(dataset, estrela));

    // Remover a linha guia original e seus nós
    comandos.add(new DeleteCommand(dataset, linha));
    let itNos = linhaNos.iterator();
    while (itNos.hasNext()) {
        comandos.add(new DeleteCommand(dataset, itNos.next()));
    }

    UndoRedoHandler.getInstance().add(new SequenceCommand("Criar estrela", comandos));

    new Notification("Estrela criada com sucesso.")
        .setIcon(UIManager.getIcon("OptionPane.informationIcon"))
        .show();
}

criarEstrela();