FloatCanvas patch from Chris Barker.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@29711 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
try:
|
||||
from Numeric import array,asarray,Float,cos,pi,sum,minimum,maximum,Int32,zeros, ones, concatenate, sqrt, argmin, power, absolute
|
||||
from Numeric import array,asarray,Float,cos, sin, pi,sum,minimum,maximum,Int32,zeros, ones, concatenate, sqrt, argmin, power, absolute, matrixmultiply, transpose, sometrue
|
||||
except ImportError:
|
||||
from numarray import array, asarray, Float, cos, pi, sum, minimum, maximum, Int32, zeros, concatenate
|
||||
try:
|
||||
from numarray import array, asarray, Float, cos, sin, pi, sum, minimum, maximum, Int32, zeros, concatenate, matrixmultiply, transpose, sometrue
|
||||
except ImportError:
|
||||
raise ImportError("I could not import either Numeric or numarray")
|
||||
|
||||
from time import clock, sleep
|
||||
|
||||
@@ -17,10 +20,11 @@ global ScreenPPI
|
||||
|
||||
## a custom Exceptions:
|
||||
|
||||
class FloatCanvasException(Exception):
|
||||
class FloatCanvasError(Exception):
|
||||
pass
|
||||
|
||||
## Create all the mouse events
|
||||
# I don't see a need for these two, but maybe some day!
|
||||
#EVT_FC_ENTER_WINDOW = wx.NewEventType()
|
||||
#EVT_FC_LEAVE_WINDOW = wx.NewEventType()
|
||||
EVT_FC_LEFT_DOWN = wx.NewEventType()
|
||||
@@ -92,8 +96,9 @@ class _MouseEvent(wx.PyCommandEvent):
|
||||
self._NativeEvent = NativeEvent
|
||||
self.Coords = Coords
|
||||
|
||||
def SetCoords(self,Coords):
|
||||
self.Coords = Coords
|
||||
# I don't think this is used.
|
||||
# def SetCoords(self,Coords):
|
||||
# self.Coords = Coords
|
||||
|
||||
def GetCoords(self):
|
||||
return self.Coords
|
||||
@@ -294,7 +299,6 @@ class DrawObject:
|
||||
self._Canvas.MakeHitDict()
|
||||
self._Canvas.HitDict[Event][self.HitColor] = (self) # put the object in the hit dict, indexed by it's color
|
||||
|
||||
|
||||
def UnBindAll(self):
|
||||
## fixme: this only removes one from each list, there could be more.
|
||||
if self._Canvas.HitDict:
|
||||
@@ -421,6 +425,10 @@ class XYObjectMixin:
|
||||
self.XY = array( (x, y), Float)
|
||||
self.CalcBoundingBox()
|
||||
|
||||
def CalcBoundingBox(self):
|
||||
## This may get overwritten in some subclasses
|
||||
self.BoundingBox = array( (self.XY, self.XY), Float )
|
||||
|
||||
def SetPoint(self, xy):
|
||||
self.XY = array( xy, Float)
|
||||
self.XY.shape = (2,)
|
||||
@@ -601,6 +609,98 @@ class Line(DrawObject,PointsObjectMixin,LineOnlyMixin):
|
||||
HTdc.SetPen(self.HitPen)
|
||||
HTdc.DrawLines(Points)
|
||||
|
||||
class Arrow(DrawObject,XYObjectMixin,LineOnlyMixin):
|
||||
"""
|
||||
|
||||
Arrow(XY, # coords of origin of arrow (x,y)
|
||||
Length, # length of arrow in pixels
|
||||
theta, # angle of arrow in degrees: zero is straight up
|
||||
# angle is to the right
|
||||
LineColor = "Black",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 1,
|
||||
ArrowHeadSize = 4,
|
||||
ArrowHeadAngle = 45,
|
||||
InForeground = False):
|
||||
|
||||
It will draw an arrow , starting at the point, (X,Y) pointing in
|
||||
direction, theta.
|
||||
|
||||
|
||||
"""
|
||||
def __init__(self,
|
||||
XY,
|
||||
Length,
|
||||
Direction,
|
||||
LineColor = "Black",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 2, # pixels
|
||||
ArrowHeadSize = 8, # pixels
|
||||
ArrowHeadAngle = 30, # degrees
|
||||
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.Length = Length
|
||||
self.Direction = float(Direction)
|
||||
self.ArrowHeadSize = ArrowHeadSize
|
||||
self.ArrowHeadAngle = float(ArrowHeadAngle)
|
||||
|
||||
self.CalcArrowPoints()
|
||||
self.CalcBoundingBox()
|
||||
|
||||
self.LineColor = LineColor
|
||||
self.LineStyle = LineStyle
|
||||
self.LineWidth = LineWidth
|
||||
|
||||
self.SetPen(LineColor,LineStyle,LineWidth)
|
||||
|
||||
##fixme: How should the HitTest be drawn?
|
||||
self.HitLineWidth = max(LineWidth,self.MinHitLineWidth)
|
||||
|
||||
def SetDirection(self, Direction):
|
||||
self.Direction = float(Direction)
|
||||
self.CalcArrowPoints()
|
||||
|
||||
def SetLength(self, Length):
|
||||
self.Length = Length
|
||||
self.CalcArrowPoints()
|
||||
|
||||
def SetLengthDirection(self, Length, Direction):
|
||||
self.Direction = float(Direction)
|
||||
self.Length = Length
|
||||
self.CalcArrowPoints()
|
||||
|
||||
def SetLength(self, Length):
|
||||
self.Length = Length
|
||||
self.CalcArrowPoints()
|
||||
|
||||
def CalcArrowPoints(self):
|
||||
L = self.Length
|
||||
S = self.ArrowHeadSize
|
||||
phi = self.ArrowHeadAngle * pi / 360
|
||||
theta = (self.Direction-90.0) * pi / 180
|
||||
ArrowPoints = array( ( (0, L, L - S*cos(phi),L, L - S*cos(phi) ),
|
||||
(0, 0, S*sin(phi), 0, -S*sin(phi) ) ),
|
||||
Float )
|
||||
RotationMatrix = array( ( ( cos(theta), -sin(theta) ),
|
||||
( 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.
|
||||
@@ -755,8 +855,6 @@ class Point(DrawObject,XYObjectMixin,ColorOnlyMixin):
|
||||
def SetDiameter(self,Diameter):
|
||||
self.Diameter = Diameter
|
||||
|
||||
def CalcBoundingBox(self):
|
||||
self.BoundingBox = array( (self.XY, self.XY), Float )
|
||||
|
||||
def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
|
||||
dc.SetPen(self.Pen)
|
||||
@@ -821,9 +919,6 @@ class RectEllipse(DrawObject, XYObjectMixin,LineAndFillMixin):
|
||||
|
||||
|
||||
class Rectangle(RectEllipse):
|
||||
# def __init__(*args, **kwargs):
|
||||
# RectEllipse.__init__(*args, **kwargs)
|
||||
# raise "an error"
|
||||
|
||||
def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
|
||||
( XY, WH ) = self.SetUpDraw(dc,
|
||||
@@ -993,10 +1088,6 @@ class Text(DrawObject, TextObjectMixin):
|
||||
(self.TextWidth, self.TextHeight) = (None, None)
|
||||
self.ShiftFun = self.ShiftFunDict[Position]
|
||||
|
||||
def CalcBoundingBox(self):
|
||||
self.BoundingBox = array((self.XY, self.XY),Float)
|
||||
|
||||
|
||||
def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
|
||||
XY = WorldToPixel(self.XY)
|
||||
dc.SetFont(self.Font)
|
||||
@@ -1321,7 +1412,7 @@ class FloatCanvas(wx.Panel):
|
||||
elif ProjectionFun is None:
|
||||
self.ProjectionFun = lambda x=None: array( (1,1), Float)
|
||||
else:
|
||||
raise FloatCanvasException('Projectionfun must be either: "FlatEarth", None, or a function that takes the ViewPortCenter and returns a MapProjectionVector')
|
||||
raise FloatCanvasError('Projectionfun must be either: "FlatEarth", None, or a function that takes the ViewPortCenter and returns a MapProjectionVector')
|
||||
|
||||
def FlatEarthProjection(self,CenterPoint):
|
||||
return array((cos(pi*CenterPoint[1]/180),1),Float)
|
||||
@@ -1330,7 +1421,7 @@ class FloatCanvas(wx.Panel):
|
||||
if Mode in ["ZoomIn","ZoomOut","Move","Mouse",None]:
|
||||
self.GUIMode = Mode
|
||||
else:
|
||||
raise FloatCanvasException('"%s" is Not a valid Mode'%Mode)
|
||||
raise FloatCanvasError('"%s" is Not a valid Mode'%Mode)
|
||||
|
||||
def MakeHitDict(self):
|
||||
##fixme: Should this just be None if nothing has been bound?
|
||||
@@ -1465,7 +1556,8 @@ class FloatCanvas(wx.Panel):
|
||||
self._RaiseMouseEvent(event, EventType)
|
||||
|
||||
def WheelEvent(self,event):
|
||||
if self.GUIMode == "Mouse":
|
||||
##if self.GUIMode == "Mouse":
|
||||
## Why not always raise this?
|
||||
self._RaiseMouseEvent(event, EVT_FC_MOUSEWHEEL)
|
||||
|
||||
|
||||
@@ -1516,7 +1608,7 @@ class FloatCanvas(wx.Panel):
|
||||
StartMove = self.StartMove
|
||||
EndMove = array((event.GetX(),event.GetY()))
|
||||
if sum((StartMove-EndMove)**2) > 16:
|
||||
self.Move(StartMove-EndMove,'Pixel')
|
||||
self.MoveImage(StartMove-EndMove,'Pixel')
|
||||
self.StartMove = None
|
||||
elif self.GUIMode == "Mouse":
|
||||
EventType = EVT_FC_LEFT_UP
|
||||
@@ -1694,8 +1786,9 @@ class FloatCanvas(wx.Panel):
|
||||
animation, for instance.
|
||||
|
||||
"""
|
||||
#print "In Draw"
|
||||
if self.PanelSize < (1,1): # it's possible for this to get called before being properly initialized.
|
||||
# print "in Draw", self.PanelSize
|
||||
if sometrue(self.PanelSize < 1 ): # it's possible for this to get called before being properly initialized.
|
||||
# if self.PanelSize < (1,1): # it's possible for this to get called before being properly initialized.
|
||||
return
|
||||
if self.Debug: start = clock()
|
||||
ScreenDC = wx.ClientDC(self)
|
||||
@@ -1779,7 +1872,7 @@ class FloatCanvas(wx.Panel):
|
||||
## else:
|
||||
## return False
|
||||
|
||||
def Move(self,shift,CoordType):
|
||||
def MoveImage(self,shift,CoordType):
|
||||
"""
|
||||
move the image in the window.
|
||||
|
||||
@@ -1798,7 +1891,8 @@ class FloatCanvas(wx.Panel):
|
||||
|
||||
"""
|
||||
|
||||
shift = array(shift,Float)
|
||||
shift = asarray(shift,Float)
|
||||
#print "shifting by:", shift
|
||||
if CoordType == 'Panel':# convert from panel coordinates
|
||||
shift = shift * array((-1,1),Float) *self.PanelSize/self.TransformVector
|
||||
elif CoordType == 'Pixel': # convert from pixel coordinates
|
||||
@@ -1806,8 +1900,10 @@ class FloatCanvas(wx.Panel):
|
||||
elif CoordType == 'World': # No conversion
|
||||
pass
|
||||
else:
|
||||
raise FloatCanvasException('CoordType must be either "Panel", "Pixel", or "World"')
|
||||
|
||||
raise FloatCanvasError('CoordType must be either "Panel", "Pixel", or "World"')
|
||||
|
||||
#print "shifting by:", shift
|
||||
|
||||
self.ViewPortCenter = self.ViewPortCenter + shift
|
||||
self.MapProjectionVector = self.ProjectionFun(self.ViewPortCenter)
|
||||
self.TransformVector = array((self.Scale,-self.Scale),Float) * self.MapProjectionVector
|
||||
@@ -2010,7 +2106,7 @@ class FloatCanvas(wx.Panel):
|
||||
NumBetweenBlits = self.NumBetweenBlits # for speed
|
||||
for i, Object in enumerate(self._ShouldRedraw(DrawList, ViewPortBB)):
|
||||
Object._Draw(dc, WorldToPixel, ScaleWorldToPixel, HTdc)
|
||||
if i % NumBetweenBlits == 0:
|
||||
if i+1 % NumBetweenBlits == 0:
|
||||
Blit(0, 0, PanelSize0, PanelSize1, dc, 0, 0)
|
||||
dc.EndDrawing()
|
||||
|
||||
@@ -2035,7 +2131,7 @@ class FloatCanvas(wx.Panel):
|
||||
|
||||
def _makeFloatCanvasAddMethods(): ## lrk's code for doing this in module __init__
|
||||
classnames = ["Circle", "Ellipse", "Rectangle", "ScaledText", "Polygon",
|
||||
"Line", "Text", "PointSet","Point"]
|
||||
"Line", "Text", "PointSet","Point", "Arrow"]
|
||||
for classname in classnames:
|
||||
klass = globals()[classname]
|
||||
def getaddshapemethod(klass=klass):
|
||||
|
Reference in New Issue
Block a user