JOSM já possui uma função para criar círculos, atalho ⇧ Shift+O.
Partindo do mesmo princípio, um código para criar uma elipse onde um círculo não seria adequado.
Como funciona?
Adicione uma linha com exatamente 3 nós
Selecione apenas os nós dessa linha
Escolha a quantidade de nós
Quanto maior a elipse, mais nós devem ser adicionados
Demonstração
Imagem.gif, clique para visualizar.
Código
fromorg.openstreetmap.josm.data.osmimportWay,Nodefromorg.openstreetmap.josm.guiimportMainApplication,Notificationfromorg.openstreetmap.josm.data.coorimportLatLonfromorg.openstreetmap.josm.commandimportAddCommand,SequenceCommand,DeleteCommandfromorg.openstreetmap.josm.dataimportUndoRedoHandlerfromjavax.swingimportJOptionPane,JPanel,JLabel,JSpinner,SpinnerNumberModel,UIManagerimportmathdefcriar_elipse_de_tres_pontos():layer=MainApplication.getLayerManager().getEditLayer()ifnotlayer:Notification(u"Nenhuma camada de edição ativa.")\
.setIcon(UIManager.getIcon("OptionPane.errorIcon"))\
.show()returnsel=layer.data.getSelectedNodes()iflen(sel)!=3:Notification(u"Selecione exatamente 3 nós.")\
.setIcon(UIManager.getIcon("OptionPane.informationIcon"))\
.show()return# Interface com spinnerpanel=JPanel()panel.add(JLabel(u"Número de pontos na elipse:"))spinner=JSpinner(SpinnerNumberModel(30,12,360,5))panel.add(spinner)option=JOptionPane.showConfirmDialog(None,panel,u"Parâmetros da Elipse",JOptionPane.OK_CANCEL_OPTION)ifoption!=JOptionPane.OK_OPTION:returnnum_pontos=spinner.getValue()n1,n2,n3=selp1=(n1.getCoor().lon(),n1.getCoor().lat())p2=(n2.getCoor().lon(),n2.getCoor().lat())p3=(n3.getCoor().lon(),n3.getCoor().lat())# Centro da elipsecx=(p1[0]+p3[0])/2cy=(p1[1]+p3[1])/2dx=p3[0]-p1[0]dy=p3[1]-p1[1]a=math.hypot(dx,dy)/2angle=math.atan2(dy,dx)defdist_perp(px,py,x1,y1,x2,y2):num=abs((x2-x1)*(y1-py)-(x1-px)*(y2-y1))den=math.hypot(x2-x1,y2-y1)returnnum/denb=dist_perp(p2[0],p2[1],p1[0],p1[1],p3[0],p3[1])pontos=[]foriinrange(num_pontos):t=2*math.pi*i/num_pontosex=a*math.cos(t)ey=b*math.sin(t)rx=ex*math.cos(angle)-ey*math.sin(angle)ry=ex*math.sin(angle)+ey*math.cos(angle)lon=cx+rxlat=cy+rypontos.append(Node(LatLon(lat,lon)))cmds=[]forninpontos:cmds.append(AddCommand(layer.data,n))way=Way()forninpontos:way.addNode(n)way.addNode(pontos[0])# Fecha a elipsecmds.append(AddCommand(layer.data,way))# Deletar caminho com exatamente os 3 nosforwinlayer.data.getWays():nodes=w.getNodes()ifall(ninnodesfornin[n1,n2,n3])andlen(nodes)==3:cmds.append(DeleteCommand(layer.data,w))# Deletar os nos selecionadoscmds.append(DeleteCommand(layer.data,sel))UndoRedoHandler.getInstance().add(SequenceCommand("Criar elipse",cmds))layer.data.setSelected(way)Notification(u"Elipse criada com sucesso!")\
.setIcon(UIManager.getIcon("OptionPane.informationIcon"))\
.show()criar_elipse_de_tres_pontos()