Ideal para fazer a correção da inclinação de grupos de polígonos. Há uma diferença na função atual do JOSM, segurando ⇧ Shift+Ctrl+Click também faz o giro mas quando selecionado multiplos, é feito o giro sobre o pivô central de todo grupo, com o script cada geometria gira no seu próprio eixo.
Como funciona?
Selecione um ou mais polígonos
Selecione o grau de rotação
Escolha a direção de inclinação
Demonstração
Imagem.gif, clique para visualizar.
Código
fromorg.openstreetmap.josm.guiimportMainApplication,Notificationfromorg.openstreetmap.josm.data.osmimportWay,Nodefromorg.openstreetmap.josm.data.coorimportEastNorth,LatLonfromorg.openstreetmap.josm.data.projectionimportProjectionRegistryfromorg.openstreetmap.josm.commandimportChangeCommand,SequenceCommandfromorg.openstreetmap.josm.data.UndoRedoHandlerimportgetInstancefromjavax.swingimportJDialog,JPanel,JButton,JLabel,JOptionPane,BoxLayout,Timer,BorderFactory,JSpinner,SpinnerNumberModel,UIManagerfromjava.awtimportDimension,Component,eventfromjava.langimportMath# --------------------------# Funções auxiliares# --------------------------defget_centroid_en(way):proj=ProjectionRegistry.getProjection()en_list=[proj.latlon2eastNorth(n.getCoor())forninway.getNodes()ifn.isUsable()]ifnoten_list:returnNonesx,sy=0.0,0.0foreninen_list:sx+=en.east()sy+=en.north()returnEastNorth(sx/len(en_list),sy/len(en_list))defrotate_point(en,center,angle):dx,dy=en.east()-center.east(),en.north()-center.north()cos_a,sin_a=Math.cos(angle),Math.sin(angle)x_new=dx*cos_a-dy*sin_a+center.east()y_new=dx*sin_a+dy*cos_a+center.north()returnEastNorth(x_new,y_new)defrotate_way(way,angle):center=get_centroid_en(way)ifcenterisNone:return[]proj=ProjectionRegistry.getProjection()cmds=[]node_changes={}forninway.getNodes():ifnotn.isUsable():continueifninnode_changes:continueen=proj.latlon2eastNorth(n.getCoor())en_rot=rotate_point(en,center,angle)newCoor=proj.eastNorth2latlon(en_rot)n_new=Node(n)n_new.setCoor(newCoor)node_changes[n]=n_newcmds.append(ChangeCommand(n,n_new))returncmds# --------------------------# Painel de rotação# --------------------------classRotateDialog(JDialog):def__init__(self,ways):JDialog.__init__(self,MainApplication.getMainFrame(),u"Rotacionar Polígonos",True)self.ways=waysself.timer_delay=50self.total_angle_rad=0.0self.original_nodes={}forwinways:forninw.getNodes():ifn.isUsable()andnnotinself.original_nodes:self.original_nodes[n]=n.getCoor()self.spinner_model=SpinnerNumberModel(5,1,360,1)self.angle_spinner=JSpinner(self.spinner_model)self.timer=Timer(self.timer_delay,self.timer_action_listener)self.timer.setInitialDelay(200)panel=JPanel()panel.setLayout(BoxLayout(panel,BoxLayout.Y_AXIS))panel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10))lbl_angle=JLabel(u"Passo (graus):")lbl_angle.setAlignmentX(Component.CENTER_ALIGNMENT)self.angle_spinner.setAlignmentX(Component.CENTER_ALIGNMENT)panel.add(lbl_angle)panel.add(self.angle_spinner)panel.add(JLabel(u" "))btn_plus=JButton(u"(+) ⟲")btn_plus.setAlignmentX(Component.CENTER_ALIGNMENT)btn_plus.setMaximumSize(Dimension(250,40))btn_plus.addMouseListener(RotationMouseListener(self,1))btn_plus.addActionListener(lambdae:self.apply_rotation(self.get_rotation_angle_rad(1)))panel.add(btn_plus)panel.add(JLabel(u" "))btn_minus=JButton(u"(-) ⟳")btn_minus.setAlignmentX(Component.CENTER_ALIGNMENT)btn_minus.setMaximumSize(Dimension(250,40))btn_minus.addMouseListener(RotationMouseListener(self,-1))btn_minus.addActionListener(lambdae:self.apply_rotation(self.get_rotation_angle_rad(-1)))panel.add(btn_minus)panel.add(JLabel(u" "))btn_accept=JButton(u"Aceitar",UIManager.getIcon("OptionPane.okIcon"))btn_accept.setMaximumSize(Dimension(120,40))btn_accept.addActionListener(lambdae:self.accept_rotation())btn_cancel=JButton(u"Cancelar",UIManager.getIcon("OptionPane.noIcon"))btn_cancel.setMaximumSize(Dimension(120,40))btn_cancel.addActionListener(lambdae:self.cancel_rotation())button_panel=JPanel()button_panel.setLayout(BoxLayout(button_panel,BoxLayout.X_AXIS))button_panel.setAlignmentX(Component.CENTER_ALIGNMENT)button_panel.add(btn_accept)button_panel.add(JLabel(" "))# Espaço entre os botõesbutton_panel.add(btn_cancel)panel.add(button_panel)self.add(panel)self.pack()self.setResizable(False)self.setLocationRelativeTo(MainApplication.getMainFrame())self.addWindowListener(DialogWindowListener(self.timer))self.setVisible(True)deftimer_action_listener(self,e):angle_rad=float(self.timer.getActionCommand())ifangle_rad:try:self.apply_rotation(angle_rad)exceptException,ex:self.timer.stop()Notification(u"Erro ao aplicar rotação contínua: %s"%ex).setIcon(JOptionPane.ERROR_MESSAGE).show()defget_rotation_angle_rad(self,sign):angle_degrees=self.angle_spinner.getValue()angle_rad=Math.toRadians(angle_degrees)returnangle_rad*signdefapply_rotation(self,angle):cmds=[]forwinself.ways:cmds.extend(rotate_way(w,angle))ifcmds:seq=SequenceCommand(u"Rotacionar polígonos (%.2f°)"%Math.toDegrees(angle),cmds)getInstance().add(seq)self.total_angle_rad+=angledefaccept_rotation(self):ifabs(self.total_angle_rad)>1e-6:Notification(u"Girado com sucesso (%.2f°)"%Math.toDegrees(self.total_angle_rad)).setIcon(JOptionPane.INFORMATION_MESSAGE).show()else:Notification(u"Nenhuma rotação foi aplicada.").setIcon(JOptionPane.WARNING_MESSAGE).show()self.dispose()defcancel_rotation(self):cmds=[]forn,original_coorinself.original_nodes.items():n_new=Node(n)n_new.setCoor(original_coor)cmds.append(ChangeCommand(n,n_new))ifcmds:seq=SequenceCommand(u"Cancelar rotação",cmds)getInstance().add(seq)Notification(u"Rotação cancelada pelo usuário.").setIcon(JOptionPane.WARNING_MESSAGE).show()self.dispose()classRotationMouseListener(event.MouseAdapter):def__init__(self,dialog,sign):self.dialog=dialogself.sign=signdefmousePressed(self,e):angle_rad=self.dialog.get_rotation_angle_rad(self.sign)self.dialog.timer.setActionCommand(str(angle_rad))self.dialog.timer.start()defmouseReleased(self,e):self.dialog.timer.stop()classDialogWindowListener(event.WindowAdapter):def__init__(self,timer):self.timer=timerdefwindowClosing(self,e):self.timer.stop()# --------------------------# Função principal# --------------------------defrun_rotation_script():layer=MainApplication.getLayerManager().getEditLayer()ifnotlayer:Notification(u"Nenhuma camada de edição ativa.").setIcon(JOptionPane.ERROR_MESSAGE).show()returnsel=layer.data.getSelected()ways=[oforoinselifisinstance(o,Way)ando.isClosed()ando.isUsable()]ifnotways:Notification(u"Nenhum polígono selecionado.").setIcon(JOptionPane.WARNING_MESSAGE).show()returntry:RotateDialog(ways)exceptException,e:Notification(u"A interface de rotação encontrou um erro: %s"%e).setIcon(JOptionPane.ERROR_MESSAGE).show()# --------------------------# EXECUÇÃO# --------------------------run_rotation_script()