Files
Phoenix/samples/floatcanvas/PolyEditor.py
Edouard Choinière 95cafd1a3f style: Normalise numpy imports with import numpy as np
The convention when importing numpy is to use `import numpy as np`

Fixes: unconventional-import-alias (ICN001)
Ruff rule: https://docs.astral.sh/ruff/rules/unconventional-import-alias/
2025-02-08 16:48:57 +00:00

252 lines
7.8 KiB
Python

#!/usr/bin/env python
"""
PolyEditor: a simple app for editing polygons
Used as a demo for FloatCanvas
"""
import numpy as np
import random
import numpy.random as RandomArray
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
# import a local copy:
#import sys
#sys.path.append("..")
#from floatcanvas import NavCanvas, FloatCanvas
import wx
class DrawFrame(wx.Frame):
"""
A frame used for the FloatCanvas Demo
"""
def __init__(self,parent, id,title,position,size):
wx.Frame.__init__(self,parent, id,title,position, size)
## Set up the MenuBar
MenuBar = wx.MenuBar()
FileMenu = wx.Menu()
exit = FileMenu.Append(wx.ID_EXIT, "", "Close Application")
self.Bind(wx.EVT_MENU, self.OnQuit, exit)
MenuBar.Append(FileMenu, "&File")
view_menu = wx.Menu()
zfit = view_menu.Append(wx.ID_ANY, "Zoom to &Fit", "Zoom to fit the window")
self.Bind(wx.EVT_MENU, self.ZoomToFit, zfit)
MenuBar.Append(view_menu, "&View")
help_menu = wx.Menu()
about = help_menu.Append(wx.ID_ABOUT, "",
"More information About this program")
self.Bind(wx.EVT_MENU, self.OnAbout, about)
MenuBar.Append(help_menu, "&Help")
self.SetMenuBar(MenuBar)
self.CreateStatusBar()
# Add the Canvas
self.Canvas = NavCanvas.NavCanvas(self,-1,(500,500),
Debug = 0,
BackgroundColor = "DARK SLATE BLUE"
).Canvas
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
self.Canvas.Bind(FloatCanvas.EVT_MOTION, self.OnMove)
self.Canvas.Bind(FloatCanvas.EVT_LEFT_UP, self.OnLeftUp)
self.Canvas.Bind(FloatCanvas.EVT_LEFT_DOWN, self.OnLeftClick)
self.ResetSelections()
return None
def ResetSelections(self):
self.SelectedPoly = None
self.SelectedPolyOrig = None
self.SelectedPoints = None
self.PointSelected = False
self.SelectedPointNeighbors = None
def OnAbout(self, event):
dlg = wx.MessageDialog(self, "This is a small program to demonstrate\n"
"the use of the FloatCanvas\n",
"About Me", wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
def ZoomToFit(self,event):
self.Canvas.ZoomToBB()
def Clear(self,event = None):
self.Canvas.ClearAll()
self.Canvas.SetProjectionFun(None)
self.Canvas.Draw()
def OnQuit(self,event):
self.Close(True)
def OnCloseWindow(self, event):
self.Destroy()
def OnMove(self, event):
"""
Updates the status bar with the world coordinates
And moves a point if there is one selected
"""
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
if self.PointSelected:
PolyPoints = self.SelectedPoly.Points
Index = self.SelectedPoints.Index
dc = wx.ClientDC(self.Canvas)
PixelCoords = event.GetPosition()
dc.SetPen(wx.Pen('WHITE', 2, wx.SHORT_DASH))
dc.SetLogicalFunction(wx.XOR)
if self.SelectedPointNeighbors is None:
self.SelectedPointNeighbors = np.zeros((3,2), np.float64)
#fixme: This feels very inelegant!
if Index == 0:
self.SelectedPointNeighbors[0] = self.SelectedPoly.Points[-1]
self.SelectedPointNeighbors[1:3] = self.SelectedPoly.Points[:2]
elif Index == len(self.SelectedPoly.Points)-1:
self.SelectedPointNeighbors[0:2] = self.SelectedPoly.Points[-2:]
self.SelectedPointNeighbors[2] = self.SelectedPoly.Points[0]
else:
self.SelectedPointNeighbors = self.SelectedPoly.Points[Index-1:Index+2]
self.SelectedPointNeighbors = self.Canvas.WorldToPixel(self.SelectedPointNeighbors)
else:
dc.DrawLines(self.SelectedPointNeighbors)
self.SelectedPointNeighbors[1] = PixelCoords
dc.DrawLines(self.SelectedPointNeighbors)
def OnLeftUp(self, event):
## if a point was selected, it's not anymore
if self.PointSelected:
self.SelectedPoly.Points[self.SelectedPoints.Index] = event.GetCoords()
self.SelectedPoly.SetPoints(self.SelectedPoly.Points, copy = False)
self.SelectedPoints.SetPoints(self.SelectedPoly.Points, copy = False)
self.PointSelected = False
self.SelectedPointNeighbors = None
self.Canvas.Draw()
def OnLeftClick(self,event):
## If a click happens outside the polygon, it's no longer selected
self.DeSelectPoly()
self.Canvas.Draw()
def Setup(self, event = None):
"Setting up with some random polygons"
wx.GetApp().Yield()
self.ResetSelections()
self.Canvas.ClearAll()
Range = (-10,10)
# Create a couple of random Polygons
for i, color in enumerate(("Light Blue", "Green", "Purple","Yellow")):
points = RandomArray.uniform(Range[0],Range[1],(6,2))
Poly = self.Canvas.AddPolygon(points,
LineWidth = 2,
LineColor = "Black",
FillColor = color,
FillStyle = 'Solid')
Poly.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.SelectPoly)
self.Canvas.ZoomToBB()
def SelectPoly(self, Object):
Canvas = self.Canvas
if Object is self.SelectedPolyOrig:
pass
else:
if self.SelectedPoly:
self.DeSelectPoly()
self.SelectedPolyOrig = Object
self.SelectedPoly = Canvas.AddPolygon(Object.Points,
LineWidth = 2,
LineColor = "Red",
FillColor = "Red",
FillStyle = "CrossHatch",
InForeground = True)
# Draw points on the Vertices of the Selected Poly:
self.SelectedPoints = Canvas.AddPointSet(Object.Points,
Diameter = 6,
Color = "Red",
InForeground = True)
self.SelectedPoints.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.SelectPointHit)
Canvas.Draw()
def DeSelectPoly(self):
Canvas = self.Canvas
if self.SelectedPolyOrig is not None:
self.SelectedPolyOrig.SetPoints(self.SelectedPoly.Points, copy = False)
self.Canvas.Draw(Force = True)
Canvas.RemoveObject(self.SelectedPoly)
Canvas.RemoveObject(self.SelectedPoints)
self.ResetSelections()
def SelectPointHit(self, PointSet):
PointSet.Index = PointSet.FindClosestPoint(PointSet.HitCoords)
print("point #%i hit"%PointSet.Index)
#Index = PointSet.Index
self.PointSelected = True
class PolyEditor(wx.App):
"""
A simple example of making editable shapes with FloatCanvas
"""
def OnInit(self):
frame = DrawFrame(None,
-1,
"FloatCanvas Demo App",
wx.DefaultPosition,
(700,700),
)
self.SetTopWindow(frame)
frame.Show()
frame.Setup()
return True
PolyEditor().MainLoop()