mirror of
https://github.com/wxWidgets/Phoenix.git
synced 2025-07-20 20:21:09 +02:00
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/
252 lines
7.8 KiB
Python
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()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|