Added a Python port of the OGL library, deprecated the C++ wrapped version.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@27447 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
%define DOCSTRING
|
%define DOCSTRING
|
||||||
"The Object Graphics Library provides for simple drawing and manipulation
|
"The Object Graphics Library provides for simple drawing and manipulation
|
||||||
of 2D objects."
|
of 2D objects. (This version is deprecated, please use wx.lib.ogl instead.)"
|
||||||
%enddef
|
%enddef
|
||||||
%module(docstring=DOCSTRING) ogl
|
%module(docstring=DOCSTRING) ogl
|
||||||
|
|
||||||
@@ -29,6 +29,12 @@ of 2D objects."
|
|||||||
%pythoncode { wx = _core }
|
%pythoncode { wx = _core }
|
||||||
%pythoncode { __docfilter__ = wx.__DocFilter(globals()) }
|
%pythoncode { __docfilter__ = wx.__DocFilter(globals()) }
|
||||||
|
|
||||||
|
%pythoncode {
|
||||||
|
import warnings
|
||||||
|
warnings.warn("This module is deprecated. Please use the wx.lib.ogl pacakge instead.",
|
||||||
|
DeprecationWarning, stacklevel=2)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MAKE_CONST_WXSTRING_NOSWIG(EmptyString);
|
MAKE_CONST_WXSTRING_NOSWIG(EmptyString);
|
||||||
|
|
||||||
|
@@ -30,7 +30,7 @@ import images
|
|||||||
|
|
||||||
_treeList = [
|
_treeList = [
|
||||||
# new stuff
|
# new stuff
|
||||||
('Recent Additions', [
|
('Recent Additions and Updates', [
|
||||||
'VListBox',
|
'VListBox',
|
||||||
'Listbook',
|
'Listbook',
|
||||||
'MaskedNumCtrl',
|
'MaskedNumCtrl',
|
||||||
|
@@ -1,15 +1,19 @@
|
|||||||
|
# -*- coding: iso-8859-1 -*-
|
||||||
# 11/20/2003 - Jeff Grimmett (grimmtooth@softhome.net)
|
# 11/20/2003 - Jeff Grimmett (grimmtooth@softhome.net)
|
||||||
#
|
#
|
||||||
# o Updated for wx namespace
|
# o Updated for wx namespace
|
||||||
#
|
#
|
||||||
|
# 20040508 - Pierre Hj<48>lm
|
||||||
|
#
|
||||||
|
# o Changed to use the python version of OGL
|
||||||
|
# o Added TextShape, CompositeShape and CompositeShape with divisions
|
||||||
|
#
|
||||||
|
|
||||||
import wx
|
import wx
|
||||||
import wx.ogl as ogl
|
import wx.lib.ogl as ogl
|
||||||
|
|
||||||
import images
|
import images
|
||||||
|
|
||||||
##wx.Trap()
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
class DiamondShape(ogl.PolygonShape):
|
class DiamondShape(ogl.PolygonShape):
|
||||||
@@ -20,13 +24,6 @@ class DiamondShape(ogl.PolygonShape):
|
|||||||
if h == 0.0:
|
if h == 0.0:
|
||||||
h = 60.0
|
h = 60.0
|
||||||
|
|
||||||
# Either ogl.RealPoints or 2-tuples of floats works.
|
|
||||||
|
|
||||||
#points = [ ogl.RealPoint(0.0, -h/2.0),
|
|
||||||
# ogl.RealPoint(w/2.0, 0.0),
|
|
||||||
# ogl.RealPoint(0.0, h/2.0),
|
|
||||||
# ogl.RealPoint(-w/2.0, 0.0),
|
|
||||||
# ]
|
|
||||||
points = [ (0.0, -h/2.0),
|
points = [ (0.0, -h/2.0),
|
||||||
(w/2.0, 0.0),
|
(w/2.0, 0.0),
|
||||||
(0.0, h/2.0),
|
(0.0, h/2.0),
|
||||||
@@ -44,6 +41,67 @@ class RoundedRectangleShape(ogl.RectangleShape):
|
|||||||
self.SetCornerRadius(-0.3)
|
self.SetCornerRadius(-0.3)
|
||||||
|
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CompositeDivisionShape(ogl.CompositeShape):
|
||||||
|
def __init__(self, canvas):
|
||||||
|
ogl.CompositeShape.__init__(self)
|
||||||
|
|
||||||
|
self.SetCanvas(canvas)
|
||||||
|
|
||||||
|
# create a division in the composite
|
||||||
|
self.MakeContainer()
|
||||||
|
|
||||||
|
# add a shape to the original division
|
||||||
|
shape2 = ogl.RectangleShape(40, 60)
|
||||||
|
self.GetDivisions()[0].AddChild(shape2)
|
||||||
|
|
||||||
|
# now divide the division so we get 2
|
||||||
|
self.GetDivisions()[0].Divide(wx.HORIZONTAL)
|
||||||
|
|
||||||
|
# and add a shape to the second division (and move it to the
|
||||||
|
# centre of the division)
|
||||||
|
shape3 = ogl.CircleShape(40)
|
||||||
|
shape3.SetBrush(wx.CYAN_BRUSH)
|
||||||
|
self.GetDivisions()[1].AddChild(shape3)
|
||||||
|
shape3.SetX(self.GetDivisions()[1].GetX())
|
||||||
|
|
||||||
|
for division in self.GetDivisions():
|
||||||
|
division.SetSensitivityFilter(0)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CompositeShape(ogl.CompositeShape):
|
||||||
|
def __init__(self, canvas):
|
||||||
|
ogl.CompositeShape.__init__(self)
|
||||||
|
|
||||||
|
self.SetCanvas(canvas)
|
||||||
|
|
||||||
|
constraining_shape = ogl.RectangleShape(120, 100)
|
||||||
|
constrained_shape1 = ogl.CircleShape(50)
|
||||||
|
constrained_shape2 = ogl.RectangleShape(80, 20)
|
||||||
|
|
||||||
|
constraining_shape.SetBrush(wx.BLUE_BRUSH)
|
||||||
|
constrained_shape2.SetBrush(wx.RED_BRUSH)
|
||||||
|
|
||||||
|
self.AddChild(constraining_shape)
|
||||||
|
self.AddChild(constrained_shape1)
|
||||||
|
self.AddChild(constrained_shape2)
|
||||||
|
|
||||||
|
constraint = ogl.Constraint(ogl.CONSTRAINT_MIDALIGNED_BOTTOM, constraining_shape, [constrained_shape1, constrained_shape2])
|
||||||
|
self.AddConstraint(constraint)
|
||||||
|
self.Recompute()
|
||||||
|
|
||||||
|
# If we don't do this, the shapes will be able to move on their
|
||||||
|
# own, instead of moving the composite
|
||||||
|
constraining_shape.SetDraggable(False)
|
||||||
|
constrained_shape1.SetDraggable(False)
|
||||||
|
constrained_shape2.SetDraggable(False)
|
||||||
|
|
||||||
|
# If we don't do this the shape will take all left-clicks for itself
|
||||||
|
constraining_shape.SetSensitivityFilter(0)
|
||||||
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
class DividedShape(ogl.DividedShape):
|
class DividedShape(ogl.DividedShape):
|
||||||
@@ -88,7 +146,7 @@ class DividedShape(ogl.DividedShape):
|
|||||||
|
|
||||||
def OnSizingEndDragLeft(self, pt, x, y, keys, attch):
|
def OnSizingEndDragLeft(self, pt, x, y, keys, attch):
|
||||||
print "***", self
|
print "***", self
|
||||||
self.base_OnSizingEndDragLeft(pt, x, y, keys, attch)
|
ogl.DividedShape.OnSizingEndDragLeft(self, pt, x, y, keys, attch)
|
||||||
self.SetRegionSizes()
|
self.SetRegionSizes()
|
||||||
self.ReformatRegions()
|
self.ReformatRegions()
|
||||||
self.GetCanvas().Refresh()
|
self.GetCanvas().Refresh()
|
||||||
@@ -103,15 +161,14 @@ class MyEvtHandler(ogl.ShapeEvtHandler):
|
|||||||
self.statbarFrame = frame
|
self.statbarFrame = frame
|
||||||
|
|
||||||
def UpdateStatusBar(self, shape):
|
def UpdateStatusBar(self, shape):
|
||||||
x,y = shape.GetX(), shape.GetY()
|
x, y = shape.GetX(), shape.GetY()
|
||||||
width, height = shape.GetBoundingBoxMax()
|
width, height = shape.GetBoundingBoxMax()
|
||||||
self.statbarFrame.SetStatusText("Pos: (%d,%d) Size: (%d, %d)" %
|
self.statbarFrame.SetStatusText("Pos: (%d, %d) Size: (%d, %d)" %
|
||||||
(x, y, width, height))
|
(x, y, width, height))
|
||||||
|
|
||||||
|
|
||||||
def OnLeftClick(self, x, y, keys = 0, attachment = 0):
|
def OnLeftClick(self, x, y, keys=0, attachment=0):
|
||||||
shape = self.GetShape()
|
shape = self.GetShape()
|
||||||
print shape.__class__, shape.GetClassName()
|
|
||||||
canvas = shape.GetCanvas()
|
canvas = shape.GetCanvas()
|
||||||
dc = wx.ClientDC(canvas)
|
dc = wx.ClientDC(canvas)
|
||||||
canvas.PrepareDC(dc)
|
canvas.PrepareDC(dc)
|
||||||
@@ -142,9 +199,9 @@ class MyEvtHandler(ogl.ShapeEvtHandler):
|
|||||||
self.UpdateStatusBar(shape)
|
self.UpdateStatusBar(shape)
|
||||||
|
|
||||||
|
|
||||||
def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
|
def OnEndDragLeft(self, x, y, keys=0, attachment=0):
|
||||||
shape = self.GetShape()
|
shape = self.GetShape()
|
||||||
self.base_OnEndDragLeft(x, y, keys, attachment)
|
ogl.ShapeEvtHandler.OnEndDragLeft(self, x, y, keys, attachment)
|
||||||
|
|
||||||
if not shape.Selected():
|
if not shape.Selected():
|
||||||
self.OnLeftClick(x, y, keys, attachment)
|
self.OnLeftClick(x, y, keys, attachment)
|
||||||
@@ -153,12 +210,12 @@ class MyEvtHandler(ogl.ShapeEvtHandler):
|
|||||||
|
|
||||||
|
|
||||||
def OnSizingEndDragLeft(self, pt, x, y, keys, attch):
|
def OnSizingEndDragLeft(self, pt, x, y, keys, attch):
|
||||||
self.base_OnSizingEndDragLeft(pt, x, y, keys, attch)
|
ogl.ShapeEvtHandler.OnSizingEndDragLeft(self, pt, x, y, keys, attch)
|
||||||
self.UpdateStatusBar(self.GetShape())
|
self.UpdateStatusBar(self.GetShape())
|
||||||
|
|
||||||
|
|
||||||
def OnMovePost(self, dc, x, y, oldX, oldY, display):
|
def OnMovePost(self, dc, x, y, oldX, oldY, display):
|
||||||
self.base_OnMovePost(dc, x, y, oldX, oldY, display)
|
ogl.ShapeEvtHandler.OnMovePost(self, dc, x, y, oldX, oldY, display)
|
||||||
self.UpdateStatusBar(self.GetShape())
|
self.UpdateStatusBar(self.GetShape())
|
||||||
|
|
||||||
|
|
||||||
@@ -188,29 +245,44 @@ class TestWindow(ogl.ShapeCanvas):
|
|||||||
rRectBrush = wx.Brush("MEDIUM TURQUOISE", wx.SOLID)
|
rRectBrush = wx.Brush("MEDIUM TURQUOISE", wx.SOLID)
|
||||||
dsBrush = wx.Brush("WHEAT", wx.SOLID)
|
dsBrush = wx.Brush("WHEAT", wx.SOLID)
|
||||||
|
|
||||||
|
self.MyAddShape(
|
||||||
|
CompositeDivisionShape(self),
|
||||||
|
310, 310, wx.BLACK_PEN, wx.BLUE_BRUSH, "Division"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.MyAddShape(
|
||||||
|
CompositeShape(self),
|
||||||
|
100, 260, wx.BLACK_PEN, wx.RED_BRUSH, "Composite"
|
||||||
|
)
|
||||||
|
|
||||||
self.MyAddShape(
|
self.MyAddShape(
|
||||||
ogl.CircleShape(80),
|
ogl.CircleShape(80),
|
||||||
100, 100, wx.Pen(wx.BLUE, 3), wx.GREEN_BRUSH, "Circle"
|
100, 100, wx.Pen(wx.BLUE, 3), wx.GREEN_BRUSH, "Circle"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.MyAddShape(
|
||||||
|
ogl.TextShape(45, 30),
|
||||||
|
205, 60, wx.GREEN_PEN, wx.LIGHT_GREY_BRUSH, "Text"
|
||||||
|
)
|
||||||
|
|
||||||
self.MyAddShape(
|
self.MyAddShape(
|
||||||
ogl.RectangleShape(85, 50),
|
ogl.RectangleShape(85, 50),
|
||||||
305, 60, wx.BLACK_PEN, wx.LIGHT_GREY_BRUSH, "Rectangle"
|
305, 60, wx.BLACK_PEN, wx.LIGHT_GREY_BRUSH, "Rectangle"
|
||||||
)
|
)
|
||||||
|
|
||||||
ds = self.MyAddShape(
|
ds = self.MyAddShape(
|
||||||
DividedShape(140, 150, self),
|
DividedShape(140, 150, self),
|
||||||
495, 145, wx.BLACK_PEN, dsBrush, ''
|
515, 145, wx.BLACK_PEN, dsBrush, ''
|
||||||
)
|
)
|
||||||
|
|
||||||
self.MyAddShape(
|
self.MyAddShape(
|
||||||
DiamondShape(90, 90),
|
DiamondShape(90, 90),
|
||||||
345, 235, wx.Pen(wx.BLUE, 3, wx.DOT), wx.RED_BRUSH, "Polygon"
|
445, 305, wx.Pen(wx.BLUE, 3, wx.DOT), wx.RED_BRUSH, "Polygon"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.MyAddShape(
|
self.MyAddShape(
|
||||||
RoundedRectangleShape(95,70),
|
RoundedRectangleShape(95, 70),
|
||||||
140, 255, wx.Pen(wx.RED, 2), rRectBrush, "Rounded Rect"
|
345, 145, wx.Pen(wx.RED, 2), rRectBrush, "Rounded Rect"
|
||||||
)
|
)
|
||||||
|
|
||||||
bmp = images.getTest2Bitmap()
|
bmp = images.getTest2Bitmap()
|
||||||
@@ -219,7 +291,7 @@ class TestWindow(ogl.ShapeCanvas):
|
|||||||
|
|
||||||
s = ogl.BitmapShape()
|
s = ogl.BitmapShape()
|
||||||
s.SetBitmap(bmp)
|
s.SetBitmap(bmp)
|
||||||
self.MyAddShape(s, 225, 150, None, None, "Bitmap")
|
self.MyAddShape(s, 225, 130, None, None, "Bitmap")
|
||||||
|
|
||||||
dc = wx.ClientDC(self)
|
dc = wx.ClientDC(self)
|
||||||
self.PrepareDC(dc)
|
self.PrepareDC(dc)
|
||||||
@@ -241,14 +313,15 @@ class TestWindow(ogl.ShapeCanvas):
|
|||||||
self.diagram.AddShape(line)
|
self.diagram.AddShape(line)
|
||||||
line.Show(True)
|
line.Show(True)
|
||||||
|
|
||||||
# for some reason, the shapes have to be moved for the line to show up...
|
|
||||||
fromShape.Move(dc, fromShape.GetX(), fromShape.GetY())
|
|
||||||
|
|
||||||
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
|
|
||||||
|
|
||||||
|
|
||||||
def MyAddShape(self, shape, x, y, pen, brush, text):
|
def MyAddShape(self, shape, x, y, pen, brush, text):
|
||||||
shape.SetDraggable(True, True)
|
# Composites have to be moved for all children to get in place
|
||||||
|
if isinstance(shape, ogl.CompositeShape):
|
||||||
|
dc = wx.ClientDC(self)
|
||||||
|
self.PrepareDC(dc)
|
||||||
|
shape.Move(dc, x, y)
|
||||||
|
else:
|
||||||
|
shape.SetDraggable(True, True)
|
||||||
shape.SetCanvas(self)
|
shape.SetCanvas(self)
|
||||||
shape.SetX(x)
|
shape.SetX(x)
|
||||||
shape.SetY(y)
|
shape.SetY(y)
|
||||||
@@ -268,16 +341,6 @@ class TestWindow(ogl.ShapeCanvas):
|
|||||||
return shape
|
return shape
|
||||||
|
|
||||||
|
|
||||||
def OnDestroy(self, evt):
|
|
||||||
# Do some cleanup
|
|
||||||
for shape in self.diagram.GetShapeList():
|
|
||||||
if shape.GetParent() == None:
|
|
||||||
shape.SetCanvas(None)
|
|
||||||
shape.Destroy()
|
|
||||||
|
|
||||||
self.diagram.Destroy()
|
|
||||||
|
|
||||||
|
|
||||||
def OnBeginDragLeft(self, x, y, keys):
|
def OnBeginDragLeft(self, x, y, keys):
|
||||||
self.log.write("OnBeginDragLeft: %s, %s, %s\n" % (x, y, keys))
|
self.log.write("OnBeginDragLeft: %s, %s, %s\n" % (x, y, keys))
|
||||||
|
|
||||||
@@ -298,25 +361,32 @@ def runTest(frame, nb, log):
|
|||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
# The OGL library holds some resources that need to be freed before
|
|
||||||
# the app shuts down.
|
|
||||||
class __Cleanup:
|
|
||||||
def __del__(self, cleanup=ogl.OGLCleanUp):
|
|
||||||
cleanup()
|
|
||||||
|
|
||||||
# When this module gets cleaned up by Python then __cu will be cleaned
|
overview = """<html><body>
|
||||||
# up and it's __dell__ is called, which will then call ogl.OGLCleanUp.
|
<h2>Object Graphics Library</h2>
|
||||||
__cu = __Cleanup()
|
|
||||||
|
|
||||||
|
|
||||||
overview = """\
|
|
||||||
The Object Graphics Library is a library supporting the creation and
|
The Object Graphics Library is a library supporting the creation and
|
||||||
manipulation of simple and complex graphic images on a canvas.
|
manipulation of simple and complex graphic images on a canvas.
|
||||||
|
|
||||||
|
<p>The OGL library was originally written in C++ and provided to
|
||||||
|
wxPython via an extension module wrapper as is most of the rest of
|
||||||
|
wxPython. The code has now been ported to Python (with many thanks to
|
||||||
|
Pierre Hj<48>lm!) in order to make it be more easily maintainable and
|
||||||
|
less likely to get rusty because nobody cares about the C++ lib any
|
||||||
|
more.
|
||||||
|
|
||||||
|
<p>The Python version should be mostly drop-in compatible with the
|
||||||
|
wrapped C++ version, except for the location of the package
|
||||||
|
(wx.lib.ogl instead of wx.ogl) and that the base class methods are
|
||||||
|
called the normal Python way (superclass.Method(self, ...)) instead of the
|
||||||
|
hacky way that had to be done to support overloaded methods with the
|
||||||
|
old SWIG (self.base_Method(...))
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys,os
|
import sys, os
|
||||||
import run
|
import run
|
||||||
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
|
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
|
||||||
|
|
||||||
|
@@ -71,6 +71,7 @@ wxPython/wx/lib/colourchooser
|
|||||||
wxPython/wx/lib/editor
|
wxPython/wx/lib/editor
|
||||||
wxPython/wx/lib/masked
|
wxPython/wx/lib/masked
|
||||||
wxPython/wx/lib/mixins
|
wxPython/wx/lib/mixins
|
||||||
|
wxPython/wx/lib/ogl
|
||||||
wxPython/wx/py
|
wxPython/wx/py
|
||||||
wxPython/wx/py/tests
|
wxPython/wx/py/tests
|
||||||
wxPython/wxPython
|
wxPython/wxPython
|
||||||
|
@@ -106,6 +106,8 @@ Source: "wx\lib\colourchooser\*.py"; DestDir: "{app}\wx\lib\colourchoo
|
|||||||
Source: "wx\lib\editor\*.py"; DestDir: "{app}\wx\lib\editor"; Components: core
|
Source: "wx\lib\editor\*.py"; DestDir: "{app}\wx\lib\editor"; Components: core
|
||||||
Source: "wx\lib\editor\*.txt"; DestDir: "{app}\wx\lib\editor"; Components: core
|
Source: "wx\lib\editor\*.txt"; DestDir: "{app}\wx\lib\editor"; Components: core
|
||||||
Source: "wx\lib\mixins\*.py"; DestDir: "{app}\wx\lib\mixins"; Components: core
|
Source: "wx\lib\mixins\*.py"; DestDir: "{app}\wx\lib\mixins"; Components: core
|
||||||
|
Source: "wx\lib\masked\*.py"; DestDir: "{app}\wx\lib\masked"; Components: core
|
||||||
|
Source: "wx\lib\ogl\*.py"; DestDir: "{app}\wx\lib\ogl"; Components: core
|
||||||
Source: "wx\py\*.py"; DestDir: "{app}\wx\py"; Components: core
|
Source: "wx\py\*.py"; DestDir: "{app}\wx\py"; Components: core
|
||||||
Source: "wx\py\*.txt"; DestDir: "{app}\wx\py"; Components: core
|
Source: "wx\py\*.txt"; DestDir: "{app}\wx\py"; Components: core
|
||||||
Source: "wx\py\*.ico"; DestDir: "{app}\wx\py"; Components: core
|
Source: "wx\py\*.ico"; DestDir: "{app}\wx\py"; Components: core
|
||||||
|
@@ -80,6 +80,17 @@ remaining compatible with "C".
|
|||||||
Switched gizmos.TreeListCtrl to the newer version of the code from the
|
Switched gizmos.TreeListCtrl to the newer version of the code from the
|
||||||
wxCode project.
|
wxCode project.
|
||||||
|
|
||||||
|
OGL is dead! LONG LIVE OGL! (Oops, sorry. A bit of my dramatic side
|
||||||
|
leaked out there...) The wx.ogl module has been deprecated in favor
|
||||||
|
of the new Python port of the OGL library located at wx.lib.ogl
|
||||||
|
contributed by Pierre Hj<48>lm. This will hopefully greatly extend the
|
||||||
|
life of OGL within wxPython by making it more easily maintainable and
|
||||||
|
less prone to getting rusty as there seems to be less and less
|
||||||
|
interest in maintaining the C++ version. At this point there are just
|
||||||
|
a couple minor known compatibility differences, please see the
|
||||||
|
MigrationGuide_ file for details.
|
||||||
|
|
||||||
|
.. _MigrationGuide: MigrationGuide.html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -3,10 +3,10 @@ wxPython 2.5 Migration Guide
|
|||||||
============================
|
============================
|
||||||
|
|
||||||
This document will help explain some of the major changes in wxPython
|
This document will help explain some of the major changes in wxPython
|
||||||
2.5 and let you know what you need to do to adapt your programs to
|
2.5 since the 2.4 series and let you know what you need to do to adapt
|
||||||
those changes. Be sure to also check in the CHANGES_ file like
|
your programs to those changes. Be sure to also check in the CHANGES_
|
||||||
usual to see info about the not so major changes and other things that
|
file like usual to see info about the not so major changes and other
|
||||||
have been added to wxPython.
|
things that have been added to wxPython.
|
||||||
|
|
||||||
.. _CHANGES: CHANGES.html
|
.. _CHANGES: CHANGES.html
|
||||||
|
|
||||||
@@ -20,8 +20,8 @@ The **wxWindows** project and library is now known as
|
|||||||
.. _here: http://www.wxwidgets.org/name.htm
|
.. _here: http://www.wxwidgets.org/name.htm
|
||||||
|
|
||||||
This won't really affect wxPython all that much, other than the fact
|
This won't really affect wxPython all that much, other than the fact
|
||||||
that the wxwindows.org domain name will be changing to wxwidgets.org,
|
that the wxwindows.org domain name has changed to wxwidgets.org,
|
||||||
so mail list, CVS, and etc. addresses will be changing. We're going
|
so mail list, CVS, and etc. addresses have also changed. We're going
|
||||||
to try and smooth the transition as much as possible, but I wanted you
|
to try and smooth the transition as much as possible, but I wanted you
|
||||||
all to be aware of this change if you run into any issues.
|
all to be aware of this change if you run into any issues.
|
||||||
|
|
||||||
@@ -585,6 +585,34 @@ provided by the makers of the ActiveX control that you are using.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
OGL is dead! LONG LIVE OGL!
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
The wx.ogl module has been deprecated in favor of the new Python port
|
||||||
|
of the OGL library located at wx.lib.ogl contributed by Pierre Hj<48>lm.
|
||||||
|
This will hopefully greatly extend the life of OGL within wxPython by
|
||||||
|
making it more easily maintainable and less prone to getting rusty as
|
||||||
|
there seems to be less and less interest in maintaining the C++
|
||||||
|
version.
|
||||||
|
|
||||||
|
There are only a few known compatibility issues at this time. First
|
||||||
|
is the location of OGL. The deprecated version is located in the
|
||||||
|
wx.ogl module, and the new version is in the wx.lib.ogl package. So
|
||||||
|
this just means that to start using the new version you need to adjust
|
||||||
|
your imports. So if your code currently has something like this::
|
||||||
|
|
||||||
|
import wx
|
||||||
|
import wx.ogl as ogl
|
||||||
|
|
||||||
|
Then just change it to this::
|
||||||
|
|
||||||
|
import wx
|
||||||
|
import wx.lib.ogl as ogl
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Obsolete Modules
|
Obsolete Modules
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
@@ -707,6 +707,7 @@ if __name__ == "__main__":
|
|||||||
'wx.lib.editor',
|
'wx.lib.editor',
|
||||||
'wx.lib.masked',
|
'wx.lib.masked',
|
||||||
'wx.lib.mixins',
|
'wx.lib.mixins',
|
||||||
|
'wx.lib.ogl',
|
||||||
'wx.py',
|
'wx.py',
|
||||||
'wx.tools',
|
'wx.tools',
|
||||||
'wx.tools.XRCed',
|
'wx.tools.XRCed',
|
||||||
|
14
wxPython/wx/lib/ogl/__init__.py
Normal file
14
wxPython/wx/lib/ogl/__init__.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
"""
|
||||||
|
The Object Graphics Library provides for simple drawing and manipulation
|
||||||
|
of 2D objects.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__all__ = ["basic", "diagram", "canvas", "lines", "bmpshape", "divided", "composit"]
|
||||||
|
|
||||||
|
from basic import *
|
||||||
|
from diagram import *
|
||||||
|
from canvas import *
|
||||||
|
from lines import *
|
||||||
|
from bmpshape import *
|
||||||
|
from divided import *
|
||||||
|
from composit import *
|
3173
wxPython/wx/lib/ogl/basic.py
Normal file
3173
wxPython/wx/lib/ogl/basic.py
Normal file
File diff suppressed because it is too large
Load Diff
66
wxPython/wx/lib/ogl/bmpshape.py
Normal file
66
wxPython/wx/lib/ogl/bmpshape.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# -*- coding: iso-8859-1 -*-
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# Name: bmpshape.py
|
||||||
|
# Purpose: Bitmap shape
|
||||||
|
#
|
||||||
|
# Author: Pierre Hj<48>lm (from C++ original by Julian Smart)
|
||||||
|
#
|
||||||
|
# Created: 20040508
|
||||||
|
# RCS-ID:
|
||||||
|
# Copyright: (c) 2004 Pierre Hj<48>lm - 1998 Julian Smart
|
||||||
|
# Licence: wxWindows license
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
|
from basic import RectangleShape
|
||||||
|
|
||||||
|
|
||||||
|
class BitmapShape(RectangleShape):
|
||||||
|
"""Draws a bitmap (non-resizable)."""
|
||||||
|
def __init__(self):
|
||||||
|
RectangleShape.__init__(self, 100, 50)
|
||||||
|
self._filename=""
|
||||||
|
|
||||||
|
def OnDraw(self, dc):
|
||||||
|
if not self._bitmap.Ok():
|
||||||
|
return
|
||||||
|
|
||||||
|
x = self._xpos-self._bitmap.GetWidth() / 2
|
||||||
|
y = self._ypos-self._bitmap.GetHeight() / 2
|
||||||
|
dc.DrawBitmap(self._bitmap, x, y, True)
|
||||||
|
|
||||||
|
def SetSize(self, w, h, recursive = True):
|
||||||
|
if self._bitmap.Ok():
|
||||||
|
w = self._bitmap.GetWidth()
|
||||||
|
h = self._bitmap.GetHeight()
|
||||||
|
|
||||||
|
self.SetAttachmentSize(w, h)
|
||||||
|
|
||||||
|
self._width = w
|
||||||
|
self._height = h
|
||||||
|
|
||||||
|
self.SetDefaultRegionSize()
|
||||||
|
|
||||||
|
def GetBitmap(self):
|
||||||
|
"""Return a the bitmap associated with this shape."""
|
||||||
|
return self._bitmap
|
||||||
|
|
||||||
|
def SetBitmap(self, bitmap):
|
||||||
|
"""Set the bitmap associated with this shape.
|
||||||
|
|
||||||
|
You can delete the bitmap from the calling application, since
|
||||||
|
reference counting will take care of holding on to the internal bitmap
|
||||||
|
data.
|
||||||
|
"""
|
||||||
|
self._bitmap = bitmap
|
||||||
|
if self._bitmap.Ok():
|
||||||
|
self.SetSize(self._bitmap.GetWidth(), self._bitmap.GetHeight())
|
||||||
|
|
||||||
|
def SetFilename(self, f):
|
||||||
|
"""Set the bitmap filename."""
|
||||||
|
self._filename = f
|
||||||
|
|
||||||
|
def GetFilename(self):
|
||||||
|
"""Return the bitmap filename."""
|
||||||
|
return self._filename
|
360
wxPython/wx/lib/ogl/canvas.py
Normal file
360
wxPython/wx/lib/ogl/canvas.py
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
# -*- coding: iso-8859-1 -*-
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# Name: canvas.py
|
||||||
|
# Purpose: The canvas class
|
||||||
|
#
|
||||||
|
# Author: Pierre Hj<48>lm (from C++ original by Julian Smart)
|
||||||
|
#
|
||||||
|
# Created: 20040508
|
||||||
|
# RCS-ID:
|
||||||
|
# Copyright: (c) 2004 Pierre Hj<48>lm - 1998 Julian Smart
|
||||||
|
# Licence: wxWindows license
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
|
import wx
|
||||||
|
from lines import LineShape
|
||||||
|
from composit import *
|
||||||
|
|
||||||
|
NoDragging, StartDraggingLeft, ContinueDraggingLeft, StartDraggingRight, ContinueDraggingRight = 0, 1, 2, 3, 4
|
||||||
|
|
||||||
|
KEY_SHIFT, KEY_CTRL = 1, 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Helper function: True if 'contains' wholly contains 'contained'.
|
||||||
|
def WhollyContains(contains, contained):
|
||||||
|
xp1, yp1 = contains.GetX(), contains.GetY()
|
||||||
|
xp2, yp2 = contained.GetX(), contained.GetY()
|
||||||
|
|
||||||
|
w1, h1 = contains.GetBoundingBoxMax()
|
||||||
|
w2, h2 = contained.GetBoundingBoxMax()
|
||||||
|
|
||||||
|
left1 = xp1-w1 / 2.0
|
||||||
|
top1 = yp1-h1 / 2.0
|
||||||
|
right1 = xp1 + w1 / 2.0
|
||||||
|
bottom1 = yp1 + h1 / 2.0
|
||||||
|
|
||||||
|
left2 = xp2-w2 / 2.0
|
||||||
|
top2 = yp2-h2 / 2.0
|
||||||
|
right2 = xp2 + w2 / 2.0
|
||||||
|
bottom2 = yp2 + h2 / 2.0
|
||||||
|
|
||||||
|
return ((left1 <= left2) and (top1 <= top2) and (right1 >= right2) and (bottom1 >= bottom2))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ShapeCanvas(wx.ScrolledWindow):
|
||||||
|
def __init__(self, parent = None, id=-1, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.BORDER, name="ShapeCanvas"):
|
||||||
|
wx.ScrolledWindow.__init__(self, parent, id, pos, size, style, name)
|
||||||
|
|
||||||
|
self._shapeDiagram = None
|
||||||
|
self._dragState = NoDragging
|
||||||
|
self._draggedShape = None
|
||||||
|
self._oldDragX = 0
|
||||||
|
self._oldDragY = 0
|
||||||
|
self._firstDragX = 0
|
||||||
|
self._firstDragY = 0
|
||||||
|
self._checkTolerance = True
|
||||||
|
|
||||||
|
wx.EVT_PAINT(self, self.OnPaint)
|
||||||
|
wx.EVT_MOUSE_EVENTS(self, self.OnMouseEvent)
|
||||||
|
|
||||||
|
def SetDiagram(self, diag):
|
||||||
|
self._shapeDiagram = diag
|
||||||
|
|
||||||
|
def GetDiagram(self):
|
||||||
|
return self._shapeDiagram
|
||||||
|
|
||||||
|
def OnPaint(self, evt):
|
||||||
|
dc = wx.PaintDC(self)
|
||||||
|
self.PrepareDC(dc)
|
||||||
|
|
||||||
|
dc.SetBackground(wx.Brush(self.GetBackgroundColour(), wx.SOLID))
|
||||||
|
dc.Clear()
|
||||||
|
|
||||||
|
if self.GetDiagram():
|
||||||
|
self.GetDiagram().Redraw(dc)
|
||||||
|
|
||||||
|
def OnMouseEvent(self, evt):
|
||||||
|
dc = wx.ClientDC(self)
|
||||||
|
self.PrepareDC(dc)
|
||||||
|
|
||||||
|
x, y = evt.GetLogicalPosition(dc)
|
||||||
|
|
||||||
|
keys = 0
|
||||||
|
if evt.ShiftDown():
|
||||||
|
keys |= KEY_SHIFT
|
||||||
|
if evt.ControlDown():
|
||||||
|
keys |= KEY_CTRL
|
||||||
|
|
||||||
|
dragging = evt.Dragging()
|
||||||
|
|
||||||
|
# Check if we're within the tolerance for mouse movements.
|
||||||
|
# If we're very close to the position we started dragging
|
||||||
|
# from, this may not be an intentional drag at all.
|
||||||
|
if dragging:
|
||||||
|
dx = abs(dc.LogicalToDeviceX(x-self._firstDragX))
|
||||||
|
dy = abs(dc.LogicalToDeviceY(y-self._firstDragY))
|
||||||
|
if self._checkTolerance and (dx <= self.GetDiagram().GetMouseTolerance()) and (dy <= self.GetDiagram().GetMouseTolerance()):
|
||||||
|
return
|
||||||
|
# If we've ignored the tolerance once, then ALWAYS ignore
|
||||||
|
# tolerance in this drag, even if we come back within
|
||||||
|
# the tolerance range.
|
||||||
|
self._checkTolerance = False
|
||||||
|
|
||||||
|
# Dragging - note that the effect of dragging is left entirely up
|
||||||
|
# to the object, so no movement is done unless explicitly done by
|
||||||
|
# object.
|
||||||
|
if dragging and self._draggedShape and self._dragState == StartDraggingLeft:
|
||||||
|
self._dragState = ContinueDraggingLeft
|
||||||
|
|
||||||
|
# If the object isn't m_draggable, transfer message to canvas
|
||||||
|
if self._draggedShape.Draggable():
|
||||||
|
self._draggedShape.GetEventHandler().OnBeginDragLeft(x, y, keys, self._draggedAttachment)
|
||||||
|
else:
|
||||||
|
self._draggedShape = None
|
||||||
|
self.OnBeginDragLeft(x, y, keys)
|
||||||
|
|
||||||
|
self._oldDragX, self._oldDragY = x, y
|
||||||
|
|
||||||
|
elif dragging and self._draggedShape and self._dragState == ContinueDraggingLeft:
|
||||||
|
# Continue dragging
|
||||||
|
self._draggedShape.GetEventHandler().OnDragLeft(False, self._oldDragX, self._oldDragY, keys, self._draggedAttachment)
|
||||||
|
self._draggedShape.GetEventHandler().OnDragLeft(True, x, y, keys, self._draggedAttachment)
|
||||||
|
self._oldDragX, self._oldDragY = x, y
|
||||||
|
|
||||||
|
elif evt.LeftUp and self._draggedShape and self._dragState == ContinueDraggingLeft:
|
||||||
|
self._dragState = NoDragging
|
||||||
|
self._checkTolerance = True
|
||||||
|
|
||||||
|
self._draggedShape.GetEventHandler().OnDragLeft(False, self._oldDragX, self._oldDragY, keys, self._draggedAttachment)
|
||||||
|
self._draggedShape.GetEventHandler().OnEndDragLeft(x, y, keys, self._draggedAttachment)
|
||||||
|
self._draggedShape = None
|
||||||
|
|
||||||
|
elif dragging and self._draggedShape and self._dragState == StartDraggingRight:
|
||||||
|
self._dragState = ContinueDraggingRight
|
||||||
|
if self._draggedShape.Draggable:
|
||||||
|
self._draggedShape.GetEventHandler().OnBeginDragRight(x, y, keys, self._draggedAttachment)
|
||||||
|
else:
|
||||||
|
self._draggedShape = None
|
||||||
|
self.OnBeginDragRight(x, y, keys)
|
||||||
|
self._oldDragX, self._oldDragY = x, y
|
||||||
|
|
||||||
|
elif dragging and self._draggedShape and self._dragState == ContinueDraggingRight:
|
||||||
|
# Continue dragging
|
||||||
|
self._draggedShape.GetEventHandler().OnDragRight(False, self._oldDragX, self._oldDragY, keys, self._draggedAttachment)
|
||||||
|
self._draggedShape.GetEventHandler().OnDragRight(True, x, y, keys, self._draggedAttachment)
|
||||||
|
self._oldDragX, self._oldDragY = x, y
|
||||||
|
|
||||||
|
elif evt.RightUp() and self._draggedShape and self._dragState == ContinueDraggingRight:
|
||||||
|
self._dragState = NoDragging
|
||||||
|
self._checkTolerance = True
|
||||||
|
|
||||||
|
self._draggedShape.GetEventHandler().OnDragRight(False, self._oldDragX, self._oldDragY, keys, self._draggedAttachment)
|
||||||
|
self._draggedShape.GetEventHandler().OnEndDragRight(x, y, keys, self._draggedAttachment)
|
||||||
|
self._draggedShape = None
|
||||||
|
|
||||||
|
# All following events sent to canvas, not object
|
||||||
|
elif dragging and not self._draggedShape and self._dragState == StartDraggingLeft:
|
||||||
|
self._dragState = ContinueDraggingLeft
|
||||||
|
self.OnBeginDragLeft(x, y, keys)
|
||||||
|
self._oldDragX, self._oldDragY = x, y
|
||||||
|
|
||||||
|
elif dragging and not self._draggedShape and self._dragState == ContinueDraggingLeft:
|
||||||
|
# Continue dragging
|
||||||
|
self.OnDragLeft(False, self._oldDragX, self._oldDragY, keys)
|
||||||
|
self.OnDragLeft(True, x, y, keys)
|
||||||
|
self._oldDragX, self._oldDragY = x, y
|
||||||
|
|
||||||
|
elif evt.LeftUp() and not self._draggedShape and self._dragState == ContinueDraggingLeft:
|
||||||
|
self._dragState = NoDragging
|
||||||
|
self._checkTolerance = True
|
||||||
|
|
||||||
|
self.OnDragLeft(False, self._oldDragX, self._oldDragY, keys)
|
||||||
|
self.OnEndDragLeft(x, y, keys)
|
||||||
|
self._draggedShape = None
|
||||||
|
|
||||||
|
elif dragging and not self._draggedShape and self._dragState == StartDraggingRight:
|
||||||
|
self._dragState = ContinueDraggingRight
|
||||||
|
self.OnBeginDragRight(x, y, keys)
|
||||||
|
self._oldDragX, self._oldDragY = x, y
|
||||||
|
|
||||||
|
elif dragging and not self._draggedShape and self._dragState == ContinueDraggingRight:
|
||||||
|
# Continue dragging
|
||||||
|
self.OnDragRight(False, self._oldDragX, self._oldDragY, keys)
|
||||||
|
self.OnDragRight(True, x, y, keys)
|
||||||
|
self._oldDragX, self._oldDragY = x, y
|
||||||
|
|
||||||
|
elif evt.RightUp() and not self._draggedShape and self._dragState == ContinueDraggingRight:
|
||||||
|
self._dragState = NoDragging
|
||||||
|
self._checkTolerance = True
|
||||||
|
|
||||||
|
self.OnDragRight(False, self._oldDragX, self._oldDragY, keys)
|
||||||
|
self.OnEndDragRight(x, y, keys)
|
||||||
|
self._draggedShape = None
|
||||||
|
|
||||||
|
# Non-dragging events
|
||||||
|
elif evt.IsButton():
|
||||||
|
self._checkTolerance = True
|
||||||
|
|
||||||
|
# Find the nearest object
|
||||||
|
attachment = 0
|
||||||
|
|
||||||
|
nearest_object, attachment = self.FindShape(x, y)
|
||||||
|
if nearest_object: # Object event
|
||||||
|
if evt.LeftDown():
|
||||||
|
self._draggedShape = nearest_object
|
||||||
|
self._draggedAttachment = attachment
|
||||||
|
self._dragState = StartDraggingLeft
|
||||||
|
self._firstDragX = x
|
||||||
|
self._firstDragY = y
|
||||||
|
|
||||||
|
elif evt.LeftUp():
|
||||||
|
# N.B. Only register a click if the same object was
|
||||||
|
# identified for down *and* up.
|
||||||
|
if nearest_object == self._draggedShape:
|
||||||
|
nearest_object.GetEventHandler().OnLeftClick(x, y, keys, attachment)
|
||||||
|
self._draggedShape = None
|
||||||
|
self._dragState = NoDragging
|
||||||
|
|
||||||
|
elif evt.LeftDClick():
|
||||||
|
nearest_object.GetEventHandler().OnLeftDoubleClick(x, y, keys, attachment)
|
||||||
|
self._draggedShape = None
|
||||||
|
self._dragState = NoDragging
|
||||||
|
|
||||||
|
elif evt.RightDown():
|
||||||
|
self._draggedShape = nearest_object
|
||||||
|
self._draggedAttachment = attachment
|
||||||
|
self._dragState = StartDraggingRight
|
||||||
|
self._firstDragX = x
|
||||||
|
self._firstDragY = y
|
||||||
|
|
||||||
|
elif evt.RightUp():
|
||||||
|
if nearest_object == self._draggedShape:
|
||||||
|
nearest_object.GetEventHandler().OnRightClick(x, y, keys, attachment)
|
||||||
|
self._draggedShape = None
|
||||||
|
self._dragState = NoDragging
|
||||||
|
|
||||||
|
else: # Canvas event
|
||||||
|
if evt.LeftDown():
|
||||||
|
self._draggedShape = None
|
||||||
|
self._dragState = StartDraggingLeft
|
||||||
|
self._firstDragX = x
|
||||||
|
self._firstDragY = y
|
||||||
|
|
||||||
|
elif evt.LeftUp():
|
||||||
|
self.OnLeftClick(x, y, keys)
|
||||||
|
self._draggedShape = None
|
||||||
|
self._dragState = NoDragging
|
||||||
|
|
||||||
|
elif evt.RightDown():
|
||||||
|
self._draggedShape = None
|
||||||
|
self._dragState = StartDraggingRight
|
||||||
|
self._firstDragX = x
|
||||||
|
self._firstDragY = y
|
||||||
|
|
||||||
|
elif evt.RightUp():
|
||||||
|
self.OnRightClick(x, y, keys)
|
||||||
|
self._draggedShape = None
|
||||||
|
self._dragState = NoDragging
|
||||||
|
|
||||||
|
def FindShape(self, x, y, info = None, notObject = None):
|
||||||
|
nearest = 100000.0
|
||||||
|
nearest_attachment = 0
|
||||||
|
nearest_object = None
|
||||||
|
|
||||||
|
# Go backward through the object list, since we want:
|
||||||
|
# (a) to have the control points drawn LAST to overlay
|
||||||
|
# the other objects
|
||||||
|
# (b) to find the control points FIRST if they exist
|
||||||
|
|
||||||
|
for object in self.GetDiagram().GetShapeList()[::-1]:
|
||||||
|
# First pass for lines, which might be inside a container, so we
|
||||||
|
# want lines to take priority over containers. This first loop
|
||||||
|
# could fail if we clickout side a line, so then we'll
|
||||||
|
# try other shapes.
|
||||||
|
if object.IsShown() and \
|
||||||
|
isinstance(object, LineShape) and \
|
||||||
|
object.HitTest(x, y) and \
|
||||||
|
((info == None) or isinstance(object, info)) and \
|
||||||
|
(not notObject or not notObject.HasDescendant(object)):
|
||||||
|
temp_attachment, dist = object.HitTest(x, y)
|
||||||
|
# A line is trickier to spot than a normal object.
|
||||||
|
# For a line, since it's the diagonal of the box
|
||||||
|
# we use for the hit test, we may have several
|
||||||
|
# lines in the box and therefore we need to be able
|
||||||
|
# to specify the nearest point to the centre of the line
|
||||||
|
# as our hit criterion, to give the user some room for
|
||||||
|
# manouevre.
|
||||||
|
if dist<nearest:
|
||||||
|
nearest = dist
|
||||||
|
nearest_object = object
|
||||||
|
nearest_attachment = temp_attachment
|
||||||
|
|
||||||
|
for object in self.GetDiagram().GetShapeList()[::-1]:
|
||||||
|
# On second pass, only ever consider non-composites or
|
||||||
|
# divisions. If children want to pass up control to
|
||||||
|
# the composite, that's up to them.
|
||||||
|
if (object.IsShown() and
|
||||||
|
(isinstance(object, DivisionShape) or
|
||||||
|
not isinstance(object, CompositeShape)) and
|
||||||
|
object.HitTest(x, y) and
|
||||||
|
(info == None or isinstance(object, info)) and
|
||||||
|
(not notObject or not notObject.HasDescendant(object))):
|
||||||
|
temp_attachment, dist = object.HitTest(x, y)
|
||||||
|
if not isinstance(object, LineShape):
|
||||||
|
# If we've hit a container, and we have already
|
||||||
|
# found a line in the first pass, then ignore
|
||||||
|
# the container in case the line is in the container.
|
||||||
|
# Check for division in case line straddles divisions
|
||||||
|
# (i.e. is not wholly contained).
|
||||||
|
if not nearest_object or not (isinstance(object, DivisionShape) or WhollyContains(object, nearest_object)):
|
||||||
|
nearest_object = object
|
||||||
|
nearest_attachment = temp_attachment
|
||||||
|
break
|
||||||
|
|
||||||
|
return nearest_object, nearest_attachment
|
||||||
|
|
||||||
|
def AddShape(self, object, addAfter = None):
|
||||||
|
self.GetDiagram().AddShape(object, addAfter)
|
||||||
|
|
||||||
|
def InsertShape(self, object):
|
||||||
|
self.GetDiagram().InsertShape(object)
|
||||||
|
|
||||||
|
def RemoveShape(self, object):
|
||||||
|
self.GetDiagram().RemoveShape(object)
|
||||||
|
|
||||||
|
def GetQuickEditMode(self):
|
||||||
|
return self.GetDiagram().GetQuickEditMode()
|
||||||
|
|
||||||
|
def Redraw(self, dc):
|
||||||
|
self.GetDiagram().Redraw(dc)
|
||||||
|
|
||||||
|
def Snap(self, x, y):
|
||||||
|
return self.GetDiagram().Snap(x, y)
|
||||||
|
|
||||||
|
def OnLeftClick(self, x, y, keys = 0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def OnRightClick(self, x, y, keys = 0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def OnDragLeft(self, draw, x, y, keys = 0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def OnBeginDragLeft(self, x, y, keys = 0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def OnEndDragLeft(self, x, y, keys = 0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def OnDragRight(self, draw, x, y, keys = 0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def OnBeginDragRight(self, x, y, keys = 0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def OnEndDragRight(self, x, y, keys = 0):
|
||||||
|
pass
|
1410
wxPython/wx/lib/ogl/composit.py
Normal file
1410
wxPython/wx/lib/ogl/composit.py
Normal file
File diff suppressed because it is too large
Load Diff
160
wxPython/wx/lib/ogl/diagram.py
Normal file
160
wxPython/wx/lib/ogl/diagram.py
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
# -*- coding: iso-8859-1 -*-
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# Name: diagram.py
|
||||||
|
# Purpose: Diagram class
|
||||||
|
#
|
||||||
|
# Author: Pierre Hj<48>lm (from C++ original by Julian Smart)
|
||||||
|
#
|
||||||
|
# Created: 20040508
|
||||||
|
# RCS-ID:
|
||||||
|
# Copyright: (c) 2004 Pierre Hj<48>lm - 1998 Julian Smart
|
||||||
|
# Licence: wxWindows license
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
|
import wx
|
||||||
|
|
||||||
|
DEFAULT_MOUSE_TOLERANCE = 3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Diagram(object):
|
||||||
|
"""Encapsulates an entire diagram, with methods for drawing. A diagram has
|
||||||
|
an associated ShapeCanvas.
|
||||||
|
|
||||||
|
Derived from:
|
||||||
|
Object
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self._diagramCanvas = None
|
||||||
|
self._quickEditMode = False
|
||||||
|
self._snapToGrid = True
|
||||||
|
self._gridSpacing = 5.0
|
||||||
|
self._shapeList = []
|
||||||
|
self._mouseTolerance = DEFAULT_MOUSE_TOLERANCE
|
||||||
|
|
||||||
|
def Redraw(self, dc):
|
||||||
|
"""Draw the shapes in the diagram on the specified device context."""
|
||||||
|
if self._shapeList:
|
||||||
|
if self.GetCanvas():
|
||||||
|
self.GetCanvas().SetCursor(wx.HOURGLASS_CURSOR)
|
||||||
|
for object in self._shapeList:
|
||||||
|
object.Draw(dc)
|
||||||
|
if self.GetCanvas():
|
||||||
|
self.GetCanvas().SetCursor(wx.STANDARD_CURSOR)
|
||||||
|
|
||||||
|
def Clear(self, dc):
|
||||||
|
"""Clear the specified device context."""
|
||||||
|
dc.Clear()
|
||||||
|
|
||||||
|
def AddShape(self, object, addAfter = None):
|
||||||
|
"""Adds a shape to the diagram. If addAfter is not None, the shape
|
||||||
|
will be added after addAfter.
|
||||||
|
"""
|
||||||
|
if not object in self._shapeList:
|
||||||
|
if addAfter:
|
||||||
|
self._shapeList.insert(self._shapeList.index(addAfter) + 1, object)
|
||||||
|
else:
|
||||||
|
self._shapeList.append(object)
|
||||||
|
|
||||||
|
object.SetCanvas(self.GetCanvas())
|
||||||
|
|
||||||
|
def InsertShape(self, object):
|
||||||
|
"""Insert a shape at the front of the shape list."""
|
||||||
|
self._shapeList.insert(0, object)
|
||||||
|
|
||||||
|
def RemoveShape(self, object):
|
||||||
|
"""Remove the shape from the diagram (non-recursively) but do not
|
||||||
|
delete it.
|
||||||
|
"""
|
||||||
|
if object in self._shapeList:
|
||||||
|
self._shapeList.remove(object)
|
||||||
|
|
||||||
|
def RemoveAllShapes(self):
|
||||||
|
"""Remove all shapes from the diagram but do not delete the shapes."""
|
||||||
|
self._shapeList = []
|
||||||
|
|
||||||
|
def DeleteAllShapes(self):
|
||||||
|
"""Remove and delete all shapes in the diagram."""
|
||||||
|
for shape in self._shapeList[:]:
|
||||||
|
if not shape.GetParent():
|
||||||
|
self.RemoveShape(shape)
|
||||||
|
|
||||||
|
def ShowAll(self, show):
|
||||||
|
"""Call Show for each shape in the diagram."""
|
||||||
|
for shape in self._shapeList:
|
||||||
|
shape.Show()
|
||||||
|
|
||||||
|
def DrawOutLine(self, dc, x1, y1, x2, y2):
|
||||||
|
"""Draw an outline rectangle on the current device context."""
|
||||||
|
dc.SetPen(wx.Pen(wx.Color(0, 0, 0), 1, wx.DOT))
|
||||||
|
dc.SetBrush(wx.TRANSPARENT_BRUSH)
|
||||||
|
|
||||||
|
dc.DrawLines([[x1, y1], [x2, y1], [x2, y2], [x1, y2], [x1, y1]])
|
||||||
|
|
||||||
|
def RecentreAll(self, dc):
|
||||||
|
"""Make sure all text that should be centred, is centred."""
|
||||||
|
for shape in self._shapeList:
|
||||||
|
shape.Recentre(dc)
|
||||||
|
|
||||||
|
def SetCanvas(self, canvas):
|
||||||
|
"""Set the canvas associated with this diagram."""
|
||||||
|
self._diagramCanvas = canvas
|
||||||
|
|
||||||
|
def GetCanvas(self):
|
||||||
|
"""Return the shape canvas associated with this diagram."""
|
||||||
|
return self._diagramCanvas
|
||||||
|
|
||||||
|
def FindShape(self, id):
|
||||||
|
"""Return the shape for the given identifier."""
|
||||||
|
for shape in self._shapeList:
|
||||||
|
if shape.GetId() == id:
|
||||||
|
return shape
|
||||||
|
return None
|
||||||
|
|
||||||
|
def Snap(self, x, y):
|
||||||
|
"""'Snaps' the coordinate to the nearest grid position, if
|
||||||
|
snap-to-grid is on."""
|
||||||
|
if self._snapToGrid:
|
||||||
|
return self._gridSpacing * int(x / self._gridSpacing + 0.5), self._gridSpacing * int(y / self._gridSpacing + 0.5)
|
||||||
|
return x, y
|
||||||
|
|
||||||
|
def GetGridSpacing(self):
|
||||||
|
"""Return the grid spacing."""
|
||||||
|
return self._gridSpacing
|
||||||
|
|
||||||
|
def GetSnapToGrid(self):
|
||||||
|
"""Return snap-to-grid mode."""
|
||||||
|
return self._snapToGrid
|
||||||
|
|
||||||
|
def SetQuickEditMode(self, mode):
|
||||||
|
"""Set quick-edit-mode on of off.
|
||||||
|
|
||||||
|
In this mode, refreshes are minimized, but the diagram may need
|
||||||
|
manual refreshing occasionally.
|
||||||
|
"""
|
||||||
|
self._quickEditMode = mode
|
||||||
|
|
||||||
|
def GetQuickEditMode(self):
|
||||||
|
"""Return quick edit mode."""
|
||||||
|
return self._quickEditMode
|
||||||
|
|
||||||
|
def SetMouseTolerance(self, tolerance):
|
||||||
|
"""Set the tolerance within which a mouse move is ignored.
|
||||||
|
|
||||||
|
The default is 3 pixels.
|
||||||
|
"""
|
||||||
|
self._mouseTolerance = tolerance
|
||||||
|
|
||||||
|
def GetMouseTolerance(self):
|
||||||
|
"""Return the tolerance within which a mouse move is ignored."""
|
||||||
|
return self._mouseTolerance
|
||||||
|
|
||||||
|
def GetShapeList(self):
|
||||||
|
"""Return the internal shape list."""
|
||||||
|
return self._shapeList
|
||||||
|
|
||||||
|
def GetCount(self):
|
||||||
|
"""Return the number of shapes in the diagram."""
|
||||||
|
return len(self._shapeList)
|
404
wxPython/wx/lib/ogl/divided.py
Normal file
404
wxPython/wx/lib/ogl/divided.py
Normal file
@@ -0,0 +1,404 @@
|
|||||||
|
# -*- coding: iso-8859-1 -*-
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# Name: divided.py
|
||||||
|
# Purpose: DividedShape class
|
||||||
|
#
|
||||||
|
# Author: Pierre Hj<48>lm (from C++ original by Julian Smart)
|
||||||
|
#
|
||||||
|
# Created: 20040508
|
||||||
|
# RCS-ID:
|
||||||
|
# Copyright: (c) 2004 Pierre Hj<48>lm - 1998 Julian Smart
|
||||||
|
# Licence: wxWindows license
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import wx
|
||||||
|
|
||||||
|
from basic import ControlPoint, RectangleShape, Shape
|
||||||
|
from oglmisc import *
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DividedShapeControlPoint(ControlPoint):
|
||||||
|
def __init__(self, the_canvas, object, region, size, the_m_xoffset, the_m_yoffset, the_type):
|
||||||
|
ControlPoint.__init__(self, the_canvas, object, size, the_m_xoffset, the_m_yoffset, the_type)
|
||||||
|
self.regionId = region
|
||||||
|
|
||||||
|
# Implement resizing of divided object division
|
||||||
|
def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
|
||||||
|
dc = wx.ClientDC(self.GetCanvas())
|
||||||
|
self.GetCanvas().PrepareDC(dc)
|
||||||
|
|
||||||
|
dc.SetLogicalFunction(OGLRBLF)
|
||||||
|
dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
|
||||||
|
dc.SetPen(dottedPen)
|
||||||
|
dc.SetBrush(wx.TRANSPARENT_BRUSH)
|
||||||
|
|
||||||
|
dividedObject = self._shape
|
||||||
|
x1 = dividedObject.GetX()-dividedObject.GetWidth() / 2
|
||||||
|
y1 = y
|
||||||
|
x2 = dividedObject.GetX() + dividedObject.GetWidth() / 2
|
||||||
|
y2 = y
|
||||||
|
|
||||||
|
dc.DrawLine(x1, y1, x2, y2)
|
||||||
|
|
||||||
|
def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
|
||||||
|
dc = wx.ClientDC(self.GetCanvas())
|
||||||
|
self.GetCanvas().PrepareDC(dc)
|
||||||
|
|
||||||
|
dc.SetLogicalFunction(OGLRBLF)
|
||||||
|
dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
|
||||||
|
dc.SetPen(dottedPen)
|
||||||
|
dc.SetBrush(wx.TRANSPARENT_BRUSH)
|
||||||
|
|
||||||
|
dividedObject = self._shape
|
||||||
|
|
||||||
|
x1 = dividedObject.GetX()-dividedObject.GetWidth() / 2
|
||||||
|
y1 = y
|
||||||
|
x2 = dividedObject.GetX() + dividedObject.GetWidth() / 2
|
||||||
|
y2 = y
|
||||||
|
|
||||||
|
dc.DrawLine(x1, y1, x2, y2)
|
||||||
|
self._canvas.CaptureMouse()
|
||||||
|
|
||||||
|
def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
|
||||||
|
dc = wx.ClientDC(self.GetCanvas())
|
||||||
|
self.GetCanvas().PrepareDC(dc)
|
||||||
|
|
||||||
|
dividedObject = self._shape
|
||||||
|
if not dividedObject.GetRegions()[self.regionId]:
|
||||||
|
return
|
||||||
|
|
||||||
|
thisRegion = dividedObject.GetRegions()[self.regionId]
|
||||||
|
nextRegion = None
|
||||||
|
|
||||||
|
dc.SetLogicalFunction(wx.COPY)
|
||||||
|
|
||||||
|
if self._canvas.HasCapture():
|
||||||
|
self._canvas.ReleaseMouse()
|
||||||
|
|
||||||
|
# Find the old top and bottom of this region,
|
||||||
|
# and calculate the new proportion for this region
|
||||||
|
# if legal.
|
||||||
|
currentY = dividedObject.GetY()-dividedObject.GetHeight() / 2
|
||||||
|
maxY = dividedObject.GetY() + dividedObject.GetHeight() / 2
|
||||||
|
|
||||||
|
# Save values
|
||||||
|
theRegionTop = 0
|
||||||
|
nextRegionBottom = 0
|
||||||
|
|
||||||
|
for i in range(len(dividedObject.GetRegions())):
|
||||||
|
region = dividedObject.GetRegions()[i]
|
||||||
|
proportion = region._regionProportionY
|
||||||
|
yy = currentY + dividedObject.GetHeight() * proportion
|
||||||
|
actualY = min(maxY, yy)
|
||||||
|
|
||||||
|
if region == thisRegion:
|
||||||
|
thisRegionTop = currentY
|
||||||
|
|
||||||
|
if i + 1<len(dividedObject.GetRegions()):
|
||||||
|
nextRegion = dividedObject.GetRegions()[i + 1]
|
||||||
|
if region == nextRegion:
|
||||||
|
nextRegionBottom = actualY
|
||||||
|
|
||||||
|
currentY = actualY
|
||||||
|
|
||||||
|
if not nextRegion:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check that we haven't gone above this region or below
|
||||||
|
# next region.
|
||||||
|
if y <= thisRegionTop or y >= nextRegionBottom:
|
||||||
|
return
|
||||||
|
|
||||||
|
dividedObject.EraseLinks(dc)
|
||||||
|
|
||||||
|
# Now calculate the new proportions of this region and the next region
|
||||||
|
thisProportion = (y-thisRegionTop) / dividedObject.GetHeight()
|
||||||
|
nextProportion = (nextRegionBottom-y) / dividedObject.GetHeight()
|
||||||
|
|
||||||
|
thisRegion.SetProportions(0, thisProportion)
|
||||||
|
nextRegion.SetProportions(0, nextProportion)
|
||||||
|
self._yoffset = y-dividedObject.GetY()
|
||||||
|
|
||||||
|
# Now reformat text
|
||||||
|
for i, region in enumerate(dividedObject.GetRegions()):
|
||||||
|
if region.GetText():
|
||||||
|
s = region.GetText()
|
||||||
|
dividedObject.FormatText(dc, s, i)
|
||||||
|
|
||||||
|
dividedObject.SetRegionSizes()
|
||||||
|
dividedObject.Draw(dc)
|
||||||
|
dividedObject.GetEventHandler().OnMoveLinks(dc)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DividedShape(RectangleShape):
|
||||||
|
"""A DividedShape is a rectangle with a number of vertical divisions.
|
||||||
|
Each division may have its text formatted with independent characteristics,
|
||||||
|
and the size of each division relative to the whole image may be specified.
|
||||||
|
|
||||||
|
Derived from:
|
||||||
|
RectangleShape
|
||||||
|
"""
|
||||||
|
def __init__(self, w, h):
|
||||||
|
RectangleShape.__init__(self, w, h)
|
||||||
|
self.ClearRegions()
|
||||||
|
|
||||||
|
def OnDraw(self, dc):
|
||||||
|
RectangleShape.OnDraw(self, dc)
|
||||||
|
|
||||||
|
def OnDrawContents(self, dc):
|
||||||
|
if self.GetRegions():
|
||||||
|
defaultProportion = 1 / len(self.GetRegions())
|
||||||
|
else:
|
||||||
|
defaultProportion = 0
|
||||||
|
currentY = self._ypos-self._height / 2
|
||||||
|
maxY = self._ypos + self._height / 2
|
||||||
|
|
||||||
|
leftX = self._xpos-self._width / 2
|
||||||
|
rightX = self._xpos + self._width / 2
|
||||||
|
|
||||||
|
if self._pen:
|
||||||
|
dc.SetPen(self._pen)
|
||||||
|
|
||||||
|
dc.SetTextForeground(self._textColour)
|
||||||
|
|
||||||
|
# For efficiency, don't do this under X - doesn't make
|
||||||
|
# any visible difference for our purposes.
|
||||||
|
if sys.platform[:3]=="win":
|
||||||
|
dc.SetTextBackground(self._brush.GetColour())
|
||||||
|
|
||||||
|
if self.GetDisableLabel():
|
||||||
|
return
|
||||||
|
|
||||||
|
xMargin = 2
|
||||||
|
yMargin = 2
|
||||||
|
|
||||||
|
dc.SetBackgroundMode(wx.TRANSPARENT)
|
||||||
|
|
||||||
|
for region in self.GetRegions():
|
||||||
|
dc.SetFont(region.GetFont())
|
||||||
|
dc.SetTextForeground(region.GetActualColourObject())
|
||||||
|
|
||||||
|
if region._regionProportionY<0:
|
||||||
|
proportion = defaultProportion
|
||||||
|
else:
|
||||||
|
proportion = region._regionProportionY
|
||||||
|
|
||||||
|
y = currentY + self._height * proportion
|
||||||
|
actualY = min(maxY, y)
|
||||||
|
|
||||||
|
centreX = self._xpos
|
||||||
|
centreY = currentY + (actualY-currentY) / 2
|
||||||
|
|
||||||
|
DrawFormattedText(dc, region._formattedText, centreX, centreY, self._width-2 * xMargin, actualY-currentY-2 * yMargin, region._formatMode)
|
||||||
|
|
||||||
|
if y <= maxY and region != self.GetRegions()[-1]:
|
||||||
|
regionPen = region.GetActualPen()
|
||||||
|
if regionPen:
|
||||||
|
dc.SetPen(regionPen)
|
||||||
|
dc.DrawLine(leftX, y, rightX, y)
|
||||||
|
|
||||||
|
currentY = actualY
|
||||||
|
|
||||||
|
def SetSize(self, w, h, recursive = True):
|
||||||
|
self.SetAttachmentSize(w, h)
|
||||||
|
self._width = w
|
||||||
|
self._height = h
|
||||||
|
self.SetRegionSizes()
|
||||||
|
|
||||||
|
def SetRegionSizes(self):
|
||||||
|
"""Set all region sizes according to proportions and this object
|
||||||
|
total size.
|
||||||
|
"""
|
||||||
|
if not self.GetRegions():
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.GetRegions():
|
||||||
|
defaultProportion = 1 / len(self.GetRegions())
|
||||||
|
else:
|
||||||
|
defaultProportion = 0
|
||||||
|
currentY = self._ypos-self._height / 2
|
||||||
|
maxY = self._ypos + self._height / 2
|
||||||
|
|
||||||
|
for region in self.GetRegions():
|
||||||
|
if region._regionProportionY <= 0:
|
||||||
|
proportion = defaultProportion
|
||||||
|
else:
|
||||||
|
proportion = region._regionProportionY
|
||||||
|
|
||||||
|
sizeY = proportion * self._height
|
||||||
|
y = currentY + sizeY
|
||||||
|
actualY = min(maxY, y)
|
||||||
|
|
||||||
|
centreY = currentY + (actualY-currentY) / 2
|
||||||
|
|
||||||
|
region.SetSize(self._width, sizeY)
|
||||||
|
region.SetPosition(0, centreY-self._ypos)
|
||||||
|
|
||||||
|
currentY = actualY
|
||||||
|
|
||||||
|
# Attachment points correspond to regions in the divided box
|
||||||
|
def GetAttachmentPosition(self, attachment, nth = 0, no_arcs = 1, line = None):
|
||||||
|
totalNumberAttachments = len(self.GetRegions()) * 2 + 2
|
||||||
|
if self.GetAttachmentMode() == ATTACHMENT_MODE_NONE or attachment >= totalNumberAttachments:
|
||||||
|
return Shape.GetAttachmentPosition(self, attachment, nth, no_arcs)
|
||||||
|
|
||||||
|
n = len(self.GetRegions())
|
||||||
|
isEnd = line and line.IsEnd(self)
|
||||||
|
|
||||||
|
left = self._xpos-self._width / 2
|
||||||
|
right = self._xpos + self._width / 2
|
||||||
|
top = self._ypos-self._height / 2
|
||||||
|
bottom = self._ypos + self._height / 2
|
||||||
|
|
||||||
|
# Zero is top, n + 1 is bottom
|
||||||
|
if attachment == 0:
|
||||||
|
y = top
|
||||||
|
if self._spaceAttachments:
|
||||||
|
if line and line.GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE:
|
||||||
|
# Align line according to the next handle along
|
||||||
|
point = line.GetNextControlPoint(self)
|
||||||
|
if point.x<left:
|
||||||
|
x = left
|
||||||
|
elif point.x>right:
|
||||||
|
x = right
|
||||||
|
else:
|
||||||
|
x = point.x
|
||||||
|
else:
|
||||||
|
x = left + (nth + 1) * self._width / (no_arcs + 1)
|
||||||
|
else:
|
||||||
|
x = self._xpos
|
||||||
|
elif attachment == n + 1:
|
||||||
|
y = bottom
|
||||||
|
if self._spaceAttachments:
|
||||||
|
if line and line.GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE:
|
||||||
|
# Align line according to the next handle along
|
||||||
|
point = line.GetNextControlPoint(self)
|
||||||
|
if point.x<left:
|
||||||
|
x = left
|
||||||
|
elif point.x>right:
|
||||||
|
x = right
|
||||||
|
else:
|
||||||
|
x = point.x
|
||||||
|
else:
|
||||||
|
x = left + (nth + 1) * self._width / (no_arcs + 1)
|
||||||
|
else:
|
||||||
|
x = self._xpos
|
||||||
|
else: # Left or right
|
||||||
|
isLeft = not attachment<(n + 1)
|
||||||
|
if isLeft:
|
||||||
|
i = totalNumberAttachments-attachment-1
|
||||||
|
else:
|
||||||
|
i = attachment-1
|
||||||
|
|
||||||
|
region = self.GetRegions()[i]
|
||||||
|
if region:
|
||||||
|
if isLeft:
|
||||||
|
x = left
|
||||||
|
else:
|
||||||
|
x = right
|
||||||
|
|
||||||
|
# Calculate top and bottom of region
|
||||||
|
top = self._ypos + region._y-region._height / 2
|
||||||
|
bottom = self._ypos + region._y + region._height / 2
|
||||||
|
|
||||||
|
# Assuming we can trust the absolute size and
|
||||||
|
# position of these regions
|
||||||
|
if self._spaceAttachments:
|
||||||
|
if line and line.GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE:
|
||||||
|
# Align line according to the next handle along
|
||||||
|
point = line.GetNextControlPoint(self)
|
||||||
|
if point.y<bottom:
|
||||||
|
y = bottom
|
||||||
|
elif point.y>top:
|
||||||
|
y = top
|
||||||
|
else:
|
||||||
|
y = point.y
|
||||||
|
else:
|
||||||
|
y = top + (nth + 1) * region._height / (no_arcs + 1)
|
||||||
|
else:
|
||||||
|
y = self._ypos + region._y
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
return x, y
|
||||||
|
|
||||||
|
def GetNumberOfAttachments(self):
|
||||||
|
# There are two attachments for each region (left and right),
|
||||||
|
# plus one on the top and one on the bottom.
|
||||||
|
n = len(self.GetRegions()) * 2 + 2
|
||||||
|
|
||||||
|
maxN = n-1
|
||||||
|
for point in self._attachmentPoints:
|
||||||
|
if point._id>maxN:
|
||||||
|
maxN = point._id
|
||||||
|
|
||||||
|
return maxN + 1
|
||||||
|
|
||||||
|
def AttachmentIsValid(self, attachment):
|
||||||
|
totalNumberAttachments = len(self.GetRegions()) * 2 + 2
|
||||||
|
if attachment >= totalNumberAttachments:
|
||||||
|
return Shape.AttachmentIsValid(self, attachment)
|
||||||
|
else:
|
||||||
|
return attachment >= 0
|
||||||
|
|
||||||
|
def MakeControlPoints(self):
|
||||||
|
RectangleShape.MakeControlPoints(self)
|
||||||
|
self.MakeMandatoryControlPoints()
|
||||||
|
|
||||||
|
def MakeMandatoryControlPoints(self):
|
||||||
|
currentY = self.GetY()-self._height / 2
|
||||||
|
maxY = self.GetY() + self._height / 2
|
||||||
|
|
||||||
|
for i, region in enumerate(self.GetRegions()):
|
||||||
|
proportion = region._regionProportionY
|
||||||
|
|
||||||
|
y = currentY + self._height * proportion
|
||||||
|
actualY = min(maxY, y)
|
||||||
|
|
||||||
|
if region != self.GetRegions()[-1]:
|
||||||
|
controlPoint = DividedShapeControlPoint(self._canvas, self, i, CONTROL_POINT_SIZE, 0, actualY-self.GetY(), 0)
|
||||||
|
self._canvas.AddShape(controlPoint)
|
||||||
|
self._controlPoints.append(controlPoint)
|
||||||
|
|
||||||
|
currentY = actualY
|
||||||
|
|
||||||
|
def ResetControlPoints(self):
|
||||||
|
# May only have the region handles, (n - 1) of them
|
||||||
|
if len(self._controlPoints)>len(self.GetRegions())-1:
|
||||||
|
RectangleShape.ResetControlPoints(self)
|
||||||
|
|
||||||
|
self.ResetMandatoryControlPoints()
|
||||||
|
|
||||||
|
def ResetMandatoryControlPoints(self):
|
||||||
|
currentY = self.GetY()-self._height / 2
|
||||||
|
maxY = self.GetY() + self._height / 2
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
for controlPoint in self._controlPoints:
|
||||||
|
if isinstance(controlPoint, DividedShapeControlPoint):
|
||||||
|
region = self.GetRegions()[i]
|
||||||
|
proportion = region._regionProportionY
|
||||||
|
|
||||||
|
y = currentY + self._height * proportion
|
||||||
|
actualY = min(maxY, y)
|
||||||
|
|
||||||
|
controlPoint._xoffset = 0
|
||||||
|
controlPoint._yoffset = actualY-self.GetY()
|
||||||
|
|
||||||
|
currentY = actualY
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
def EditRegions(self):
|
||||||
|
"""Edit the region colours and styles. Not implemented."""
|
||||||
|
print "EditRegions() is unimplemented"
|
||||||
|
|
||||||
|
def OnRightClick(self, x, y, keys = 0, attachment = 0):
|
||||||
|
if keys & KEY_CTRL:
|
||||||
|
self.EditRegions()
|
||||||
|
else:
|
||||||
|
RectangleShape.OnRightClick(self, x, y, keys, attachment)
|
1533
wxPython/wx/lib/ogl/lines.py
Normal file
1533
wxPython/wx/lib/ogl/lines.py
Normal file
File diff suppressed because it is too large
Load Diff
416
wxPython/wx/lib/ogl/oglmisc.py
Normal file
416
wxPython/wx/lib/ogl/oglmisc.py
Normal file
@@ -0,0 +1,416 @@
|
|||||||
|
# -*- coding: iso-8859-1 -*-
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# Name: oglmisc.py
|
||||||
|
# Purpose: Miscellaneous OGL support functions
|
||||||
|
#
|
||||||
|
# Author: Pierre Hj<48>lm (from C++ original by Julian Smart)
|
||||||
|
#
|
||||||
|
# Created: 20040508
|
||||||
|
# RCS-ID:
|
||||||
|
# Copyright: (c) 2004 Pierre Hj<48>lm - 1998 Julian Smart
|
||||||
|
# Licence: wxWindows license
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
from __future__ import division
|
||||||
|
from math import *
|
||||||
|
|
||||||
|
import wx
|
||||||
|
|
||||||
|
# Control point types
|
||||||
|
# Rectangle and most other shapes
|
||||||
|
CONTROL_POINT_VERTICAL = 1
|
||||||
|
CONTROL_POINT_HORIZONTAL = 2
|
||||||
|
CONTROL_POINT_DIAGONAL = 3
|
||||||
|
|
||||||
|
# Line
|
||||||
|
CONTROL_POINT_ENDPOINT_TO = 4
|
||||||
|
CONTROL_POINT_ENDPOINT_FROM = 5
|
||||||
|
CONTROL_POINT_LINE = 6
|
||||||
|
|
||||||
|
# Types of formatting: can be combined in a bit list
|
||||||
|
FORMAT_NONE = 0 # Left justification
|
||||||
|
FORMAT_CENTRE_HORIZ = 1 # Centre horizontally
|
||||||
|
FORMAT_CENTRE_VERT = 2 # Centre vertically
|
||||||
|
FORMAT_SIZE_TO_CONTENTS = 4 # Resize shape to contents
|
||||||
|
|
||||||
|
# Attachment modes
|
||||||
|
ATTACHMENT_MODE_NONE, ATTACHMENT_MODE_EDGE, ATTACHMENT_MODE_BRANCHING = 0, 1, 2
|
||||||
|
|
||||||
|
# Shadow mode
|
||||||
|
SHADOW_NONE, SHADOW_LEFT, SHADOW_RIGHT = 0, 1, 2
|
||||||
|
|
||||||
|
OP_CLICK_LEFT, OP_CLICK_RIGHT, OP_DRAG_LEFT, OP_DRAG_RIGHT = 1, 2, 4, 8
|
||||||
|
OP_ALL = OP_CLICK_LEFT | OP_CLICK_RIGHT | OP_DRAG_LEFT | OP_DRAG_RIGHT
|
||||||
|
|
||||||
|
# Sub-modes for branching attachment mode
|
||||||
|
BRANCHING_ATTACHMENT_NORMAL = 1
|
||||||
|
BRANCHING_ATTACHMENT_BLOB = 2
|
||||||
|
|
||||||
|
# logical function to use when drawing rubberband boxes, etc.
|
||||||
|
OGLRBLF = wx.INVERT
|
||||||
|
|
||||||
|
CONTROL_POINT_SIZE = 6
|
||||||
|
|
||||||
|
# Types of arrowhead
|
||||||
|
# (i) Built-in
|
||||||
|
ARROW_HOLLOW_CIRCLE = 1
|
||||||
|
ARROW_FILLED_CIRCLE = 2
|
||||||
|
ARROW_ARROW = 3
|
||||||
|
ARROW_SINGLE_OBLIQUE = 4
|
||||||
|
ARROW_DOUBLE_OBLIQUE = 5
|
||||||
|
# (ii) Custom
|
||||||
|
ARROW_METAFILE = 20
|
||||||
|
|
||||||
|
# Position of arrow on line
|
||||||
|
ARROW_POSITION_START = 0
|
||||||
|
ARROW_POSITION_END = 1
|
||||||
|
ARROW_POSITION_MIDDLE = 2
|
||||||
|
|
||||||
|
# Line alignment flags
|
||||||
|
# Vertical by default
|
||||||
|
LINE_ALIGNMENT_HORIZ = 1
|
||||||
|
LINE_ALIGNMENT_VERT = 0
|
||||||
|
LINE_ALIGNMENT_TO_NEXT_HANDLE = 2
|
||||||
|
LINE_ALIGNMENT_NONE = 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Format a string to a list of strings that fit in the given box.
|
||||||
|
# Interpret %n and 10 or 13 as a new line.
|
||||||
|
def FormatText(dc, text, width, height, formatMode):
|
||||||
|
i = 0
|
||||||
|
word=""
|
||||||
|
word_list = []
|
||||||
|
end_word = False
|
||||||
|
new_line = False
|
||||||
|
while i<len(text):
|
||||||
|
if text[i]=="%":
|
||||||
|
i += 1
|
||||||
|
if i == len(text):
|
||||||
|
word+="%"
|
||||||
|
else:
|
||||||
|
if text[i]=="n":
|
||||||
|
new_line = True
|
||||||
|
end_word = True
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
word+="%"+text[i]
|
||||||
|
i += 1
|
||||||
|
elif text[i] in ["\012","\015"]:
|
||||||
|
new_line = True
|
||||||
|
end_word = True
|
||||||
|
i += 1
|
||||||
|
elif text[i]==" ":
|
||||||
|
end_word = True
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
word += text[i]
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
if i == len(text):
|
||||||
|
end_word = True
|
||||||
|
|
||||||
|
if end_word:
|
||||||
|
word_list.append(word)
|
||||||
|
word=""
|
||||||
|
end_word = False
|
||||||
|
if new_line:
|
||||||
|
word_list.append(None)
|
||||||
|
new_line = False
|
||||||
|
|
||||||
|
# Now, make a list of strings which can fit in the box
|
||||||
|
string_list = []
|
||||||
|
buffer=""
|
||||||
|
for s in word_list:
|
||||||
|
oldBuffer = buffer
|
||||||
|
if s is None:
|
||||||
|
# FORCE NEW LINE
|
||||||
|
if len(buffer)>0:
|
||||||
|
string_list.append(buffer)
|
||||||
|
buffer=""
|
||||||
|
else:
|
||||||
|
if len(buffer):
|
||||||
|
buffer+=" "
|
||||||
|
buffer += s
|
||||||
|
x, y = dc.GetTextExtent(buffer)
|
||||||
|
|
||||||
|
# Don't fit within the bounding box if we're fitting
|
||||||
|
# shape to contents
|
||||||
|
if (x>width) and not (formatMode & FORMAT_SIZE_TO_CONTENTS):
|
||||||
|
# Deal with first word being wider than box
|
||||||
|
if len(oldBuffer):
|
||||||
|
string_list.append(oldBuffer)
|
||||||
|
buffer = s
|
||||||
|
if len(buffer):
|
||||||
|
string_list.append(buffer)
|
||||||
|
|
||||||
|
return string_list
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def GetCentredTextExtent(dc, text_list, xpos = 0, ypos = 0, width = 0, height = 0):
|
||||||
|
if not text_list:
|
||||||
|
return 0, 0
|
||||||
|
|
||||||
|
max_width = 0
|
||||||
|
for line in text_list:
|
||||||
|
current_width, char_height = dc.GetTextExtent(line)
|
||||||
|
if current_width>max_width:
|
||||||
|
max_width = current_width
|
||||||
|
|
||||||
|
return max_width, len(text_list) * char_height
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def CentreText(dc, text_list, xpos, ypos, width, height, formatMode):
|
||||||
|
if not text_list:
|
||||||
|
return
|
||||||
|
|
||||||
|
# First, get maximum dimensions of box enclosing text
|
||||||
|
char_height = 0
|
||||||
|
max_width = 0
|
||||||
|
current_width = 0
|
||||||
|
|
||||||
|
# Store text extents for speed
|
||||||
|
widths = []
|
||||||
|
for line in text_list:
|
||||||
|
current_width, char_height = dc.GetTextExtent(line.GetText())
|
||||||
|
widths.append(current_width)
|
||||||
|
if current_width>max_width:
|
||||||
|
max_width = current_width
|
||||||
|
|
||||||
|
max_height = len(text_list) * char_height
|
||||||
|
|
||||||
|
if formatMode & FORMAT_CENTRE_VERT:
|
||||||
|
if max_height<height:
|
||||||
|
yoffset = ypos - height / 2 + (height - max_height) / 2
|
||||||
|
else:
|
||||||
|
yoffset = ypos - height / 2
|
||||||
|
yOffset = ypos
|
||||||
|
else:
|
||||||
|
yoffset = 0.0
|
||||||
|
yOffset = 0.0
|
||||||
|
|
||||||
|
if formatMode & FORMAT_CENTRE_HORIZ:
|
||||||
|
xoffset = xpos - width / 2
|
||||||
|
xOffset = xpos
|
||||||
|
else:
|
||||||
|
xoffset = 0.0
|
||||||
|
xOffset = 0.0
|
||||||
|
|
||||||
|
for i, line in enumerate(text_list):
|
||||||
|
if formatMode & FORMAT_CENTRE_HORIZ and widths[i]<width:
|
||||||
|
x = (width - widths[i]) / 2 + xoffset
|
||||||
|
else:
|
||||||
|
x = xoffset
|
||||||
|
y = i * char_height + yoffset
|
||||||
|
|
||||||
|
line.SetX(x - xOffset)
|
||||||
|
line.SetY(y - yOffset)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def DrawFormattedText(dc, text_list, xpos, ypos, width, height, formatMode):
|
||||||
|
if formatMode & FORMAT_CENTRE_HORIZ:
|
||||||
|
xoffset = xpos
|
||||||
|
else:
|
||||||
|
xoffset = xpos - width / 2
|
||||||
|
|
||||||
|
if formatMode & FORMAT_CENTRE_VERT:
|
||||||
|
yoffset = ypos
|
||||||
|
else:
|
||||||
|
yoffset = ypos - height / 2
|
||||||
|
|
||||||
|
# +1 to allow for rounding errors
|
||||||
|
dc.SetClippingRegion(xpos - width / 2, ypos - height / 2, width + 1, height + 1)
|
||||||
|
|
||||||
|
for line in text_list:
|
||||||
|
dc.DrawText(line.GetText(), xoffset + line.GetX(), yoffset + line.GetY())
|
||||||
|
|
||||||
|
dc.DestroyClippingRegion()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def RoughlyEqual(val1, val2, tol = 0.00001):
|
||||||
|
return val1<(val2 + tol) and val1>(val2 - tol) and \
|
||||||
|
val2<(val1 + tol) and val2>(val1 - tol)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def FindEndForBox(width, height, x1, y1, x2, y2):
|
||||||
|
xvec = [x1 - width / 2, x1 - width / 2, x1 + width / 2, x1 + width / 2, x1 - width / 2]
|
||||||
|
yvec = [y1 - height / 2, y1 + height / 2, y1 + height / 2, y1 - height / 2, y1 - height / 2]
|
||||||
|
|
||||||
|
return FindEndForPolyline(xvec, yvec, x2, y2, x1, y1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def CheckLineIntersection(x1, y1, x2, y2, x3, y3, x4, y4):
|
||||||
|
denominator_term = (y4 - y3) * (x2 - x1) - (y2 - y1) * (x4 - x3)
|
||||||
|
numerator_term = (x3 - x1) * (y4 - y3) + (x4 - x3) * (y1 - y3)
|
||||||
|
|
||||||
|
length_ratio = 1.0
|
||||||
|
k_line = 1.0
|
||||||
|
|
||||||
|
# Check for parallel lines
|
||||||
|
if denominator_term<0.005 and denominator_term>-0.005:
|
||||||
|
line_constant=-1.0
|
||||||
|
else:
|
||||||
|
line_constant = float(numerator_term) / denominator_term
|
||||||
|
|
||||||
|
# Check for intersection
|
||||||
|
if line_constant<1.0 and line_constant>0.0:
|
||||||
|
# Now must check that other line hits
|
||||||
|
if (y4 - y3)<0.005 and (y4 - y3)>-0.005:
|
||||||
|
k_line = (x1 - x3 + line_constant * (x2 - x1)) / (x4 - x3)
|
||||||
|
else:
|
||||||
|
k_line = (y1 - y3 + line_constant * (y2 - y1)) / (y4 - y3)
|
||||||
|
if k_line >= 0 and k_line<1:
|
||||||
|
length_ratio = line_constant
|
||||||
|
else:
|
||||||
|
k_line = 1
|
||||||
|
|
||||||
|
return length_ratio, k_line
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def FindEndForPolyline(xvec, yvec, x1, y1, x2, y2):
|
||||||
|
lastx = xvec[0]
|
||||||
|
lasty = yvec[0]
|
||||||
|
|
||||||
|
min_ratio = 1.0
|
||||||
|
|
||||||
|
for i in range(1, len(xvec)):
|
||||||
|
line_ratio, other_ratio = CheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[i], yvec[i])
|
||||||
|
lastx = xvec[i]
|
||||||
|
lasty = yvec[i]
|
||||||
|
|
||||||
|
if line_ratio<min_ratio:
|
||||||
|
min_ratio = line_ratio
|
||||||
|
|
||||||
|
# Do last (implicit) line if last and first doubles are not identical
|
||||||
|
if not (xvec[0] == lastx and yvec[0] == lasty):
|
||||||
|
line_ratio, other_ratio = CheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[0], yvec[0])
|
||||||
|
if line_ratio<min_ratio:
|
||||||
|
min_ratio = line_ratio
|
||||||
|
|
||||||
|
return x1 + (x2 - x1) * min_ratio, y1 + (y2 - y1) * min_ratio
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def PolylineHitTest(xvec, yvec, x1, y1, x2, y2):
|
||||||
|
isAHit = False
|
||||||
|
lastx = xvec[0]
|
||||||
|
lasty = yvec[0]
|
||||||
|
|
||||||
|
min_ratio = 1.0
|
||||||
|
|
||||||
|
for i in range(1, len(xvec)):
|
||||||
|
line_ratio, other_ratio = CheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[i], yvec[i])
|
||||||
|
if line_ratio != 1.0:
|
||||||
|
isAHit = True
|
||||||
|
lastx = xvec[i]
|
||||||
|
lasty = yvec[i]
|
||||||
|
|
||||||
|
if line_ratio<min_ratio:
|
||||||
|
min_ratio = line_ratio
|
||||||
|
|
||||||
|
# Do last (implicit) line if last and first doubles are not identical
|
||||||
|
if not (xvec[0] == lastx and yvec[0] == lasty):
|
||||||
|
line_ratio, other_ratio = CheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[0], yvec[0])
|
||||||
|
if line_ratio != 1.0:
|
||||||
|
isAHit = True
|
||||||
|
|
||||||
|
return isAHit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def GraphicsStraightenLine(point1, point2):
|
||||||
|
dx = point2[0] - point1[0]
|
||||||
|
dy = point2[1] - point1[1]
|
||||||
|
|
||||||
|
if dx == 0:
|
||||||
|
return
|
||||||
|
elif abs(dy / dx)>1:
|
||||||
|
point2[0] = point1[0]
|
||||||
|
else:
|
||||||
|
point2[1] = point1[0]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def GetPointOnLine(x1, y1, x2, y2, length):
|
||||||
|
l = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
|
||||||
|
if l<0.01:
|
||||||
|
l = 0.01
|
||||||
|
|
||||||
|
i_bar = (x2 - x1) / l
|
||||||
|
j_bar = (y2 - y1) / l
|
||||||
|
|
||||||
|
return -length * i_bar + x2,-length * j_bar + y2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def GetArrowPoints(x1, y1, x2, y2, length, width):
|
||||||
|
l = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
|
||||||
|
|
||||||
|
if l<0.01:
|
||||||
|
l = 0.01
|
||||||
|
|
||||||
|
i_bar = (x2 - x1) / l
|
||||||
|
j_bar = (y2 - y1) / l
|
||||||
|
|
||||||
|
x3=-length * i_bar + x2
|
||||||
|
y3=-length * j_bar + y2
|
||||||
|
|
||||||
|
return x2, y2, width*-j_bar + x3, width * i_bar + y3,-width*-j_bar + x3,-width * i_bar + y3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def DrawArcToEllipse(x1, y1, width1, height1, x2, y2, x3, y3):
|
||||||
|
a1 = width1 / 2
|
||||||
|
b1 = height1 / 2
|
||||||
|
|
||||||
|
# Check that x2 != x3
|
||||||
|
if abs(x2 - x3)<0.05:
|
||||||
|
x4 = x2
|
||||||
|
if y3>y2:
|
||||||
|
y4 = y1 - sqrt((b1 * b1 - (((x2 - x1) * (x2 - x1)) * (b1 * b1) / (a1 * a1))))
|
||||||
|
else:
|
||||||
|
y4 = y1 + sqrt((b1 * b1 - (((x2 - x1) * (x2 - x1)) * (b1 * b1) / (a1 * a1))))
|
||||||
|
return x4, y4
|
||||||
|
|
||||||
|
# Calculate the x and y coordinates of the point where arc intersects ellipse
|
||||||
|
A = (1 / (a1 * a1))
|
||||||
|
B = ((y3 - y2) * (y3 - y2)) / ((x3 - x2) * (x3 - x2) * b1 * b1)
|
||||||
|
C = (2 * (y3 - y2) * (y2 - y1)) / ((x3 - x2) * b1 * b1)
|
||||||
|
D = ((y2 - y1) * (y2 - y1)) / (b1 * b1)
|
||||||
|
E = (A + B)
|
||||||
|
F = (C - (2 * A * x1) - (2 * B * x2))
|
||||||
|
G = ((A * x1 * x1) + (B * x2 * x2) - (C * x2) + D - 1)
|
||||||
|
H = ((y3 - y2) / (x32 - x2))
|
||||||
|
K = ((F * F) - (4 * E * G))
|
||||||
|
|
||||||
|
if K >= 0:
|
||||||
|
# In this case the line intersects the ellipse, so calculate intersection
|
||||||
|
if x2 >= x1:
|
||||||
|
ellipse1_x = ((F*-1) + sqrt(K)) / (2 * E)
|
||||||
|
ellipse1_y = ((H * (ellipse1_x - x2)) + y2)
|
||||||
|
else:
|
||||||
|
ellipse1_x = (((F*-1) - sqrt(K)) / (2 * E))
|
||||||
|
ellipse1_y = ((H * (ellipse1_x - x2)) + y2)
|
||||||
|
else:
|
||||||
|
# in this case, arc does not intersect ellipse, so just draw arc
|
||||||
|
ellipse1_x = x3
|
||||||
|
ellipse1_y = y3
|
||||||
|
|
||||||
|
return ellipse1_x, ellipse1_y
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def FindEndForCircle(radius, x1, y1, x2, y2):
|
||||||
|
H = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
|
||||||
|
|
||||||
|
if H == 0:
|
||||||
|
return x1, y1
|
||||||
|
else:
|
||||||
|
return radius * (x2 - x1) / H + x1, radius * (y2 - y1) / H + y1
|
Reference in New Issue
Block a user