📄 floatcanvas.py
字号:
( sin(theta), cos(theta) ) ),
Float
)
ArrowPoints = matrixmultiply(RotationMatrix, ArrowPoints)
self.ArrowPoints = transpose(ArrowPoints)
def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
dc.SetPen(self.Pen)
xy = WorldToPixel(self.XY)
ArrowPoints = xy + self.ArrowPoints
dc.DrawLines(ArrowPoints)
if HTdc and self.HitAble:
HTdc.SetPen(self.HitPen)
HTdc.DrawLines(ArrowPoints)
##class LineSet(DrawObject, ObjectSetMixin):
## """
## The LineSet class takes a list of 2-tuples, or a NX2 NumPy array of point coordinates.
## so that Points[N] = (x1,y1) and Points[N+1] = (x2,y2). N must be an even number!
## it creates a set of line segments, from (x1,y1) to (x2,y2)
## """
## def __init__(self,Points,LineColors,LineStyles,LineWidths,InForeground = False):
## DrawObject.__init__(self, InForeground)
## NumLines = len(Points) / 2
## ##fixme: there should be some error checking for everything being the right length.
## self.Points = array(Points,Float)
## self.BoundingBox = array(((min(self.Points[:,0]),min(self.Points[:,1])),(max(self.Points[:,0]),max(self.Points[:,1]))),Float)
## self.LineColors = LineColors
## self.LineStyles = LineStyles
## self.LineWidths = LineWidths
## self.SetPens(LineColors,LineStyles,LineWidths)
## #def _Draw(self,dc,WorldToPixel,ScaleWorldToPixel):
## def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
## Points = WorldToPixel(self.Points)
## Points.shape = (-1,4)
## dc.DrawLineList(Points,self.Pens)
class PointSet(DrawObject,PointsObjectMixin, ColorOnlyMixin):
"""
The PointSet class takes a list of 2-tuples, or a NX2 NumPy array of
point coordinates.
If Points is a sequence of tuples: Points[N][0] is the x-coordinate of
point N and Points[N][1] is the y-coordinate.
If Points is a NumPy array: Points[N,0] is the x-coordinate of point
N and Points[N,1] is the y-coordinate for arrays.
Each point will be drawn the same color and Diameter. The Diameter
is in screen pixels, not world coordinates.
The hit-test code does not distingish between the points, you will
only know that one of the points got hit, not which one. You can use
PointSet.FindClosestPoint(WorldPoint) to find out which one
In the case of points, the HitLineWidth is used as diameter.
"""
def __init__(self, Points, Color = "Black", Diameter = 1, InForeground = False):
DrawObject.__init__(self,InForeground)
self.Points = array(Points,Float)
self.Points.shape = (-1,2) # Make sure it is a NX2 array, even if there is only one point
self.CalcBoundingBox()
self.Diameter = Diameter
self.HitLineWidth = self.MinHitLineWidth
self.SetColor(Color)
def SetDiameter(self,Diameter):
self.Diameter = Diameter
def FindClosestPoint(self, XY):
"""
Returns the index of the closest point to the point, XY, given
in World coordinates. It's essentially random which you get if
there are more than one that are the same.
This can be used to figure out which point got hit in a mouse
binding callback, for instance. It's a lot faster that using a
lot of separate points.
"""
d = self.Points - XY
return argmin(hypot(d[:,0],d[:,1]))
def DrawD2(self, dc, Points):
# A Little optimization for a diameter2 - point
dc.DrawPointList(Points)
dc.DrawPointList(Points + (1,0))
dc.DrawPointList(Points + (0,1))
dc.DrawPointList(Points + (1,1))
def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
dc.SetPen(self.Pen)
Points = WorldToPixel(self.Points)
if self.Diameter <= 1:
dc.DrawPointList(Points)
elif self.Diameter <= 2:
self.DrawD2(dc, Points)
else:
dc.SetBrush(self.Brush)
radius = int(round(self.Diameter/2))
##fixme: I really should add a DrawCircleList to wxPython
if len(Points) > 100:
xy = Points
xywh = concatenate((xy-radius, ones(xy.shape) * self.Diameter ), 1 )
dc.DrawEllipseList(xywh)
else:
for xy in Points:
dc.DrawCircle(xy[0],xy[1], radius)
if HTdc and self.HitAble:
HTdc.SetPen(self.HitPen)
HTdc.SetBrush(self.HitBrush)
if self.Diameter <= 1:
HTdc.DrawPointList(Points)
elif self.Diameter <= 2:
self.DrawD2(HTdc, Points)
else:
if len(Points) > 100:
xy = Points
xywh = concatenate((xy-radius, ones(xy.shape) * self.Diameter ), 1 )
HTdc.DrawEllipseList(xywh)
else:
for xy in Points:
HTdc.DrawCircle(xy[0],xy[1], radius)
class Point(DrawObject,XYObjectMixin,ColorOnlyMixin):
"""
The Point class takes a 2-tuple, or a (2,) NumPy array of point
coordinates.
The Diameter is in screen points, not world coordinates, So the
Bounding box is just the point, and doesn't include the Diameter.
The HitLineWidth is used as diameter for the
Hit Test.
"""
def __init__(self, XY, Color = "Black", Diameter = 1, InForeground = False):
DrawObject.__init__(self, InForeground)
self.XY = array(XY, Float)
self.XY.shape = (2,) # Make sure it is a 1X2 array, even if there is only one point
self.CalcBoundingBox()
self.SetColor(Color)
self.Diameter = Diameter
self.HitLineWidth = self.MinHitLineWidth
def SetDiameter(self,Diameter):
self.Diameter = Diameter
def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
dc.SetPen(self.Pen)
xy = WorldToPixel(self.XY)
if self.Diameter <= 1:
dc.DrawPoint(xy[0], xy[1])
else:
dc.SetBrush(self.Brush)
radius = int(round(self.Diameter/2))
dc.DrawCircle(xy[0],xy[1], radius)
if HTdc and self.HitAble:
HTdc.SetPen(self.HitPen)
if self.Diameter <= 1:
HTdc.DrawPoint(xy[0], xy[1])
else:
HTdc.SetBrush(self.HitBrush)
HTdc.DrawCircle(xy[0],xy[1], radius)
class SquarePoint(DrawObject,XYObjectMixin,ColorOnlyMixin):
"""
The SquarePoint class takes a 2-tuple, or a (2,) NumPy array of point
coordinates. It produces a square dot, centered on Point
The Size is in screen points, not world coordinates, so the
Bounding box is just the point, and doesn't include the Size.
The HitLineWidth is used as diameter for the
Hit Test.
"""
def __init__(self, Point, Color = "Black", Size = 4, InForeground = False):
DrawObject.__init__(self, InForeground)
self.XY = array(Point, Float)
self.XY.shape = (2,) # Make sure it is a 1X2 array, even if there is only one point
self.CalcBoundingBox()
self.SetColor(Color)
self.Size = Size
self.HitLineWidth = self.MinHitLineWidth
def SetSize(self,Size):
self.Size = Size
def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
Size = self.Size
dc.SetPen(self.Pen)
xc,yc = WorldToPixel(self.XY)
if self.Size <= 1:
dc.DrawPoint(xc, yc)
else:
x = xc - Size/2.0
y = yc - Size/2.0
dc.SetBrush(self.Brush)
dc.DrawRectangle(x, y, Size, Size)
if HTdc and self.HitAble:
HTdc.SetPen(self.HitPen)
if self.Size <= 1:
HTdc.DrawPoint(xc, xc)
else:
HTdc.SetBrush(self.HitBrush)
HTdc.DrawRectangle(x, y, Size, Size)
class RectEllipse(DrawObject, XYObjectMixin, LineAndFillMixin):
def __init__(self, XY, WH,
LineColor = "Black",
LineStyle = "Solid",
LineWidth = 1,
FillColor = None,
FillStyle = "Solid",
InForeground = False):
DrawObject.__init__(self,InForeground)
self.XY = array( XY, Float)
self.XY.shape = (2,)
self.WH = array( WH, Float )
self.WH.shape = (2,)
self.BoundingBox = array((self.XY, (self.XY + self.WH)), Float)
self.LineColor = LineColor
self.LineStyle = LineStyle
self.LineWidth = LineWidth
self.FillColor = FillColor
self.FillStyle = FillStyle
self.HitLineWidth = max(LineWidth,self.MinHitLineWidth)
self.SetPen(LineColor,LineStyle,LineWidth)
self.SetBrush(FillColor,FillStyle)
def SetShape(self, XY, WH):
self.XY = array( XY, Float)
self.WH = array( WH, Float )
self.CalcBoundingBox()
def SetUpDraw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc):
dc.SetPen(self.Pen)
dc.SetBrush(self.Brush)
if HTdc and self.HitAble:
HTdc.SetPen(self.HitPen)
HTdc.SetBrush(self.HitBrush)
return ( WorldToPixel(self.XY),
ScaleWorldToPixel(self.WH) )
def CalcBoundingBox(self):
self.BoundingBox = array((self.XY, (self.XY + self.WH) ), Float)
self._Canvas.BoundingBoxDirty = True
class Rectangle(RectEllipse):
def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
( XY, WH ) = self.SetUpDraw(dc,
WorldToPixel,
ScaleWorldToPixel,
HTdc)
dc.DrawRectanglePointSize(XY, WH)
if HTdc and self.HitAble:
HTdc.DrawRectanglePointSize(XY, WH)
class Ellipse(RectEllipse):
def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
( XY, WH ) = self.SetUpDraw(dc,
WorldToPixel,
ScaleWorldToPixel,
HTdc)
dc.DrawEllipsePointSize(XY, WH)
if HTdc and self.HitAble:
HTdc.DrawEllipsePointSize(XY, WH)
class Circle(Ellipse):
def __init__(self, XY, Diameter, **kwargs):
self.Center = array(XY, Float)
Diameter = float(Diameter)
RectEllipse.__init__(self ,
self.Center - Diameter/2.0,
(Diameter, Diameter),
**kwargs)
def SetDiameter(self, Diameter):
Diameter = float(Diameter)
XY = self.Center - (Diameter/2.0)
self.SetShape(XY,
(Diameter, Diameter)
)
class TextObjectMixin(XYObjectMixin):
"""
A mix in class that holds attributes and methods that are needed by
the Text objects
"""
## I'm caching fonts, because on GTK, getting a new font can take a
## while. However, it gets cleared after every full draw as hanging
## on to a bunch of large fonts takes a massive amount of memory.
FontList = {}
LayoutFontSize = 12 # font size used for calculating layout
def SetFont(self, Size, Family, Style, Weight, Underline, FaceName):
self.Font = self.FontList.setdefault( (Size,
Family,
Style,
Weight,
Underline,
FaceName),
wx.Font(Size,
Family,
Style,
Weight,
Underline,
FaceName) )
return self.Font
def SetColor(self, Color):
self.Color = Color
def SetBackgroundColor(self, BackgroundColor):
self.BackgroundColor = BackgroundColor
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -