2 # Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Art Haas
4 # This file is part of PythonCAD.
6 # PythonCAD is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # PythonCAD is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with PythonCAD; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 from PythonCAD
.Generic
import util
29 from PythonCAD
.Generic
import color
30 from PythonCAD
.Generic
import linetype
31 from PythonCAD
.Generic
import style
32 from PythonCAD
.Generic
.point
import Point
33 from PythonCAD
.Generic
.segment
import Segment
34 from PythonCAD
.Generic
.circle
import Circle
35 from PythonCAD
.Generic
.arc
import Arc
36 from PythonCAD
.Generic
.leader
import Leader
37 from PythonCAD
.Generic
.polyline
import Polyline
38 from PythonCAD
.Generic
.hcline
import HCLine
39 from PythonCAD
.Generic
.vcline
import VCLine
40 from PythonCAD
.Generic
.acline
import ACLine
41 from PythonCAD
.Generic
.cline
import CLine
42 from PythonCAD
.Generic
.ccircle
import CCircle
43 from PythonCAD
.Generic
.text
import TextStyle
, TextBlock
44 from PythonCAD
.Generic
import dimension
45 from PythonCAD
.Generic
.layer
import Layer
46 from PythonCAD
.Generic
import tangent
49 """A generic tool object.
51 This class is meant to be a base class for tools. A Tool
52 instance the following attributes:
54 list: A list the tool can use to store objects
55 handlers: A dictionary used to store functions
57 A Tool object has the following methods:
59 {set/get/del/has}Handler(): Store/retrive/delete/test a handler for an event.
60 clearHandlers(): Unset all the handlers in the tool.
61 reset(): Restore the tool to a a default state.
62 initialize(): Retore the tool to its original state.
63 {set/get}Filter(): Set/Get a filtering procedure for object testing.
64 {set/get}Location(): Store/retrieve an image-based coordinate pair.
65 {set/get}CurrentPoint(): Store/retrieve a screen-based coordinate pair.
66 clearCurrentPoint(): Set the screen-based coordinate to None.
67 create(): Instantiate the object the tool is designed to create.
70 """Instantiate a Tool.
74 super(Tool
, self
).__init
__()
79 self
.__location
= None
80 self
.__curpoint
= None
82 self
.__xpts
= array
.array('d')
83 self
.__ypts
= array
.array('d')
87 """Return the number of objects in the list via len().
89 return len(self
.__objlist
)
92 """Make the Tool iterable.
94 return iter(self
.__objlist
)
97 """Return the Tool's object list.
101 return self
.__objlist
103 list = property(getList
, None, None, "Tool object list.")
106 """Restore the Tool to its initial state.
110 This function purges the Tool's object list and handler dictionary.
112 del self
.__objlist
[:]
113 self
.__handlers
.clear()
114 self
.__location
= None
115 self
.__curpoint
= None
121 def initialize(self
):
124 def setHandler(self
, key
, func
):
125 """Set a handler for the Tool.
127 setHandler(key, func)
129 There are two arguments for this function:
131 key: A string used to identify a particular action
132 func: A function object
134 There are no restrictions on what the function 'func' does,
135 the argument count, etc. Any call to setHandler() with
136 a key that is already stored replaces the old 'func' argument
137 with the new one. The function argument may be None, and
138 the key argument must be a string.
141 raise ValueError, "Key value cannot be None."
142 if not isinstance(key
, str):
143 raise TypeError, "Invalid key type: " + `
type(key
)`
144 if func
and not isinstance(func
, types
.FunctionType
):
145 raise TypeError, "Invalid function type: " + `
type(func
)`
146 self
.__handlers
[key
] = func
148 def getHandler(self
, key
):
149 """Return the function for a particular key.
153 Given argument 'key', the function associated with it is
154 returned. A KeyError is raised if the argument 'key' had
155 not be used to store a function.
157 if not isinstance(key
, str):
158 raise TypeError, "Invalid key type: " + `
type(key
)`
159 if not self
.__handlers
.has_key(key
):
160 raise KeyError, "Invalid key '%s'" % key
161 return self
.__handlers
[key
]
163 def delHandler(self
, key
):
164 """Delete the handler associated with a particular key
168 The argument 'key' should be a string.
170 if self
.__handlers
.has_key(key
):
171 del self
.__handlers
[key
]
173 def hasHandler(self
, key
):
174 """Check if there is a handler stored for a given key.
178 The 'key' argument must be a string. The function returns 1
179 if there is a handler for that key, 0 otherwise.
182 if not isinstance(_k
, str):
183 raise TypeError, "Invalid key type: " + `
type(key
)`
184 return self
.__handlers
.has_key(_k
)
186 def clearHandlers(self
):
187 """Unset all the handlers for the tool.
191 This function does not alter the Tool's object list.
193 self
.__handlers
.clear()
195 def setObjtype(self
, objtype
):
196 """Store the type of objects on which the tool operates.
200 Argument 'objtype' can be a single type, a tuple of types, or 'None'.
202 if not isinstance(objtype
, (tuple, types
.NoneType
, types
.TypeType
)):
203 raise TypeError, "Invalid objtype: " + `
type(objtype
)`
204 if objtype
is not None:
205 if isinstance(objtype
, tuple):
207 if not isinstance(_obj
, types
.TypeType
):
208 raise TypeError, "Invalid objtype: " + `
type(_obj
)`
209 self
.__objtype
= objtype
211 def getObjtype(self
):
212 """Return the type of object on which the tool operates.
216 This method returns the value set in a setObjtype(), or None if
217 no object types have been specified.
219 return self
.__objtype
221 def setFilter(self
, proc
):
222 """Store a procedure used to examine selected objects.
226 Argument 'proc' must be a callable procedure.
228 if not callable(proc
):
229 raise TypeError, "Invalid filter procedure: " + `
type(proc
)`
233 """Return a stored procedure.
237 This method returns the procedure stored vai setFilter() or None.
241 def pushObject(self
, obj
):
242 """Add an object to the Tool's object list.
246 self
.__objlist
.append(obj
)
249 """Remove the last object on the Tool's object list.
253 If the object list is empty, this function returns None.
256 if len(self
.__objlist
):
257 _obj
= self
.__objlist
.pop()
260 def delObjects(self
):
261 """Remove all objects from the Tool's object list.
265 This function does not alter the Tool's handlers.
267 del self
.__objlist
[:]
269 def getObject(self
, idx
):
270 """Access an object in the tool.
274 The argument 'idx' is the index into the list of
277 return self
.__objlist
[idx
]
279 def setLocation(self
, x
, y
):
280 """Store an x/y location in the tool.
284 Store an x-y coordinate in the tool. Both arguments
287 _x
= util
.get_float(x
)
288 _y
= util
.get_float(y
)
289 self
.__location
= (_x
,_y
)
291 def getLocation(self
):
292 """Return the stored location in the tool
296 return self
.__location
298 def clearLocation(self
):
299 """Reset the location to an empty value.
303 self
.__location
= None
305 def setCurrentPoint(self
, x
, y
):
306 """Set the tool's current point.
310 Store an x-y coordinate in the tool. Both arguments
314 if not isinstance(_x
, int):
317 if not isinstance(_y
, int):
319 self
.__curpoint
= (_x
, _y
)
321 def getCurrentPoint(self
):
322 """Return the tool's current point value.
326 return self
.__curpoint
328 def clearCurrentPoint(self
):
329 """Reset the current point to an empty value
333 self
.__curpoint
= None
335 def create(self
, image
):
336 """Create an object the tool is designed to construct.
340 The argument 'image' is an image in which the newly created object
341 will be added. In the Tool class, this method does nothing. It is
342 meant to be overriden in classed using the Tool class as a base
348 # The ZoomTool, PasteTool, SelectTool, and DeselectTool classes are
349 # subclasses of the Tool class but with no additional functionality (yet)
351 class ZoomTool(Tool
):
354 class PasteTool(Tool
):
357 class SelectTool(Tool
):
360 class DeselectTool(Tool
):
363 class PointTool(Tool
):
364 """A specialized tool for drawing Point objects.
366 The PointTool class is derived from the Tool class, so it
367 shares the methods and attributes of that class. The PointTool
368 class has the following additional methods:
370 {get/set}Point(): Get/Set a x/y coordinate in the tool.
373 super(PointTool
, self
).__init
__()
376 def setPoint(self
, x
, y
):
377 """Store an x/y coordinate in the tool
381 Arguments 'x' and 'y' should be floats.
383 _x
= util
.get_float(x
)
384 _y
= util
.get_float(y
)
385 self
.__point
= (_x
, _y
)
388 """Get the stored x/y coordinates from the tool.
392 This method returns a tuple containing the values passed in
393 with the setPoint() method, or None if that method has not
399 """Restore the tool to its initial state.
403 This method extends Tool::reset().
405 super(PointTool
, self
).reset()
408 def create(self
, image
):
409 """Create a new Point and add it to the image.
413 This method overrides the Tool::create() method.
415 if self
.__point
is not None:
416 _active_layer
= image
.getActiveLayer()
417 _x
, _y
= self
.__point
419 _active_layer
.addObject(_p
)
422 class SegmentTool(Tool
):
423 """A Specialized tool for drawing Segment objects.
425 The SegmentTool class is derived from the Tool class, so
426 it shares the attributes and methods of that class. The
427 SegmentTool class has the following additional methods:
429 {get/set}FirstPoint(): Get/Set the first point of the Segment.
430 {get/set}SecondPoint(): Get/Set the second point of the Segment.
433 super(SegmentTool
, self
).__init
__()
434 self
.__first
_point
= None
435 self
.__second
_point
= None
437 def setFirstPoint(self
, x
, y
):
438 """Store the first point of the Segment.
442 Arguments 'x' and 'y' should be floats.
444 _x
= util
.get_float(x
)
445 _y
= util
.get_float(y
)
446 self
.__first
_point
= (_x
, _y
)
448 def getFirstPoint(self
):
449 """Get the first point of the Segment.
453 This method returns a tuple holding the coordinates stored
454 by invoking the setFirstPoint() method, or None if that method
455 has not been invoked.
457 return self
.__first
_point
459 def setSecondPoint(self
, x
, y
):
460 """Store the second point of the Segment.
464 Arguments 'x' and 'y' should be floats. If the
465 tool has not had the first point set with setFirstPoint(),
466 a ValueError exception is raised.
468 if self
.__first
_point
is None:
469 raise ValueError, "SegmentTool first point is not set."
470 _x
= util
.get_float(x
)
471 _y
= util
.get_float(y
)
472 self
.__second
_point
= (_x
, _y
)
474 def getSecondPoint(self
):
475 """Get the second point of the Segment.
479 This method returns a tuple holding the coordinates stored
480 by invoking the setSecondPoint() method, or None if that method
481 has not been invoked.
483 return self
.__second
_point
486 """Restore the tool to its initial state.
490 This method extends Tool::reset().
492 super(SegmentTool
, self
).reset()
493 self
.__first
_point
= None
494 self
.__second
_point
= None
496 def create(self
, image
):
497 """Create a new Segment and add it to the image.
501 This method overrides the Tool::create() method.
503 if (self
.__first
_point
is not None and
504 self
.__second
_point
is not None):
505 _active_layer
= image
.getActiveLayer()
506 _x1
, _y1
= self
.__first
_point
507 _x2
, _y2
= self
.__second
_point
508 _pts
= _active_layer
.find('point', _x1
, _y1
)
510 _p1
= Point(_x1
, _y1
)
511 _active_layer
.addObject(_p1
)
514 _pts
= _active_layer
.find('point', _x2
, _y2
)
516 _p2
= Point(_x2
, _y2
)
517 _active_layer
.addObject(_p2
)
520 _s
= image
.getOption('LINE_STYLE')
521 _seg
= Segment(_p1
, _p2
, _s
)
522 _l
= image
.getOption('LINE_TYPE')
523 if _l
!= _s
.getLinetype():
525 _c
= image
.getOption('LINE_COLOR')
526 if _c
!= _s
.getColor():
528 _t
= image
.getOption('LINE_THICKNESS')
529 if abs(_t
- _s
.getThickness()) > 1e-10:
530 _seg
.setThickness(_t
)
531 _active_layer
.addObject(_seg
)
534 class RectangleTool(SegmentTool
):
535 """A Specialized tool for drawing rectangles.
537 The RectangleTool is derived from the SegmentTool, so it
538 shares all the methods and attributes of that class. A
539 RectangleTool creates four Segments in the shape of
540 a rectangle in the image.
543 super(RectangleTool
, self
).__init
__()
545 def create(self
, image
):
546 """Create Segments and add them to the image.
550 This method overrides the SegmentTool::create() method.
552 _p1
= self
.getFirstPoint()
553 _p2
= self
.getSecondPoint()
554 if _p1
is not None and _p2
is not None:
557 _active_layer
= image
.getActiveLayer()
558 _pts
= _active_layer
.find('point', _x1
, _y1
)
560 _p1
= Point(_x1
, _y1
)
561 _active_layer
.addObject(_p1
)
564 _pts
= _active_layer
.find('point', _x1
, _y2
)
566 _p2
= Point(_x1
, _y2
)
567 _active_layer
.addObject(_p2
)
570 _pts
= _active_layer
.find('point', _x2
, _y2
)
572 _p3
= Point(_x2
, _y2
)
573 _active_layer
.addObject(_p3
)
576 _pts
= _active_layer
.find('point', _x2
, _y1
)
578 _p4
= Point(_x2
, _y1
)
579 _active_layer
.addObject(_p4
)
582 _s
= image
.getOption('LINE_STYLE')
583 _l
= image
.getOption('LINE_TYPE')
584 if _l
== _s
.getLinetype():
586 _c
= image
.getOption('LINE_COLOR')
587 if _c
== _s
.getColor():
589 _t
= image
.getOption('LINE_THICKNESS')
590 if abs(_t
- _s
.getThickness()) < 1e-10:
592 _seg
= Segment(_p1
, _p2
, _s
, linetype
=_l
, color
=_c
, thickness
=_t
)
593 _active_layer
.addObject(_seg
)
594 _seg
= Segment(_p2
, _p3
, _s
, linetype
=_l
, color
=_c
, thickness
=_t
)
595 _active_layer
.addObject(_seg
)
596 _seg
= Segment(_p3
, _p4
, _s
, linetype
=_l
, color
=_c
, thickness
=_t
)
597 _active_layer
.addObject(_seg
)
598 _seg
= Segment(_p4
, _p1
, _s
, linetype
=_l
, color
=_c
, thickness
=_t
)
599 _active_layer
.addObject(_seg
)
602 class CircleTool(Tool
):
603 """A Specialized tool for drawing Circle objects.
605 The CircleTool is derived from the Tool class, so it shares
606 all the methods and attributes of that class. The CircleTool
607 class has the following addtional methods:
609 {set/get}Center(): Set/Get the center point location of the circle.
610 {set/get}Radius(): Set/Get the radius of the circle.
613 super(CircleTool
, self
).__init
__()
617 def setCenter(self
, x
, y
):
618 """Set the center point location of the circle.
622 The arguments 'x' and 'y' give the location for the center
625 _x
= util
.get_float(x
)
626 _y
= util
.get_float(y
)
627 self
.__center
= (_x
, _y
)
630 """Get the center point location of the circle.
634 This method returns the coordinates stored with the setCenter()
635 method, or None if that method has not been called.
639 def setRadius(self
, radius
):
640 """Set the radius of the circle.
644 The argument 'radius' must be a float value greater than 0.0
646 _r
= util
.get_float(radius
)
648 raise ValueError, "Invalid radius: %g" % _r
652 """Get the radius of the circle.
656 This method returns the value specified from the setRadius()
657 call, or None if that method has not been invoked.
662 """Restore the tool to its initial state.
666 This method extends Tool::reset().
668 super(CircleTool
, self
).reset()
672 def create(self
, image
):
673 """Create a new Circle and add it to the image.
677 This method overrides the Tool::create() method.
679 if (self
.__center
is not None and
680 self
.__radius
is not None):
681 _active_layer
= image
.getActiveLayer()
682 _x
, _y
= self
.__center
684 _pts
= _active_layer
.find('point', _x
, _y
)
687 _active_layer
.addObject(_cp
)
690 _s
= image
.getOption('LINE_STYLE')
691 _circle
= Circle(_cp
, _r
, _s
)
692 _l
= image
.getOption('LINE_TYPE')
693 if _l
!= _s
.getLinetype():
694 _circle
.setLinetype(_l
)
695 _c
= image
.getOption('LINE_COLOR')
696 if _c
!= _s
.getColor():
698 _t
= image
.getOption('LINE_THICKNESS')
699 if abs(_t
- _s
.getThickness()) > 1e-10:
700 _circle
.setThickness(_t
)
701 _active_layer
.addObject(_circle
)
704 class TwoPointCircleTool(CircleTool
):
705 """A specialized class for drawing Circles between two points.
707 The TwoPointCircleTool class is derived from the CircleTool
708 class, so it shares all the methods and attributes of that
709 class. The TwoPointCircleTool class has the following addtional
712 {set/get}FirstPoint(): Set/Get the first point used to define the circle.
713 {set/get}SecondPoint(): Set/Get the second point used to define the circle.
716 super(TwoPointCircleTool
, self
).__init
__()
717 self
.__first
_point
= None
718 self
.__second
_point
= None
720 def setFirstPoint(self
, x
, y
):
721 """Set the first point used to define the location of the circle.
725 Arguments 'x' and 'y' give the location of a point.
727 _x
= util
.get_float(x
)
728 _y
= util
.get_float(y
)
729 self
.__first
_point
= (_x
, _y
)
731 def getFirstPoint(self
):
732 """Get the first point used to define the location of the circle.
736 This method returns a tuple holding the values used when the
737 setFirstPoint() method was called, or None if that method has
740 return self
.__first
_point
742 def setSecondPoint(self
, x
, y
):
743 """Set the second point used to define the location of the circle.
747 Arguments 'x' and 'y' give the location of a point. Invoking
748 this method before the setFirstPoint() method will raise a
751 if self
.__first
_point
is None:
752 raise ValueError, "First point is not set"
753 _x
= util
.get_float(x
)
754 _y
= util
.get_float(y
)
755 _x1
, _y1
= self
.__first
_point
758 _radius
= math
.hypot((_x
- _x1
), (_y
- _y1
))/2.0
759 self
.setCenter(_xc
, _yc
)
760 self
.setRadius(_radius
)
761 self
.__second
_point
= (_x
, _y
)
763 def getSecondPoint(self
):
764 """Get the second point used to define the location of the circle.
768 This method returns a tuple holding the values used when the
769 setSecondPoint() method was called, or None if that method has
772 return self
.__second
_point
775 """Restore the tool to its initial state.
779 This method extends CircleTool::reset().
781 super(TwoPointCircleTool
, self
).reset()
782 self
.__first
_point
= None
783 self
.__second
_point
= None
785 class ArcTool(CircleTool
):
786 """A specialized tool for drawing Arc objects.
788 The ArcTool is Derived from the CircleTool class, so it shares
789 all the attributes and methods of that class. The ArcTool class
790 has the following addtional methods:
792 {set/get}StartAngle(): Set/Get the start angle of the arc
793 {set/get}EndAngle(): Set/Get the end angle of the arc.
796 super(ArcTool
, self
).__init
__()
797 self
.__start
_angle
= None
798 self
.__end
_angle
= None
800 def setStartAngle(self
, angle
):
801 """Set the start angle of the arc.
805 The argument 'angle' should be a float value between 0.0 and 360.0
807 _angle
= util
.make_c_angle(angle
)
808 self
.__start
_angle
= _angle
810 def getStartAngle(self
):
811 """Return the start angle of the arc.
815 This method returns the value defined in the previous setStartAngle()
816 call, or None if that method has not been called.
818 return self
.__start
_angle
820 def setEndAngle(self
, angle
):
821 """Set the start angle of the arc.
825 The argument 'angle' should be a float value between 0.0 and 360.0
827 _angle
= util
.make_c_angle(angle
)
828 self
.__end
_angle
= _angle
830 def getEndAngle(self
):
831 """Return the end angle of the arc.
835 This method returns the value defined in the previous setEndAngle()
836 call, or None if that method has not been called.
838 return self
.__end
_angle
841 """Restore the tool to its initial state.
845 This method extends CircleTool::reset().
847 super(ArcTool
, self
).reset()
848 self
.__start
_angle
= None
849 self
.__end
_angle
= None
851 def create(self
, image
):
852 """Create a new Arc and add it to the image.
856 This method overrides the CircleTool::create() method.
858 _center
= self
.getCenter()
859 _radius
= self
.getRadius()
860 _sa
= self
.__start
_angle
861 _ea
= self
.__end
_angle
862 if (_center
is not None and
863 _radius
is not None and
866 _active_layer
= image
.getActiveLayer()
868 _pts
= _active_layer
.find('point', _x
, _y
)
871 _active_layer
.addObject(_cp
)
874 _s
= image
.getOption('LINE_STYLE')
875 _arc
= Arc(_cp
, _radius
, _sa
, _ea
, _s
)
876 _l
= image
.getOption('LINE_TYPE')
877 if _l
!= _s
.getLinetype():
879 _c
= image
.getOption('LINE_COLOR')
880 if _c
!= _s
.getColor():
882 _t
= image
.getOption('LINE_THICKNESS')
883 if abs(_t
- _s
.getThickness()) > 1e-10:
884 _arc
.setThickness(_t
)
885 for _ep
in _arc
.getEndpoints():
887 _pts
= _active_layer
.find('point', _ex
, _ey
)
889 _lp
= Point(_ex
, _ey
)
890 _active_layer
.addObject(_lp
)
891 _active_layer
.addObject(_arc
)
895 # The ChamferTool and FilletTool class are subclasses of
896 # the Tool class but have no additional functionality (yet)
899 class ChamferTool(Tool
):
902 class FilletTool(Tool
):
905 class LeaderTool(Tool
):
906 """A specialized tool for drawing Leader objects.
908 The LeaderTool class is derived from the Tool class, so it
909 shares the methods and attributes of that class. The LeaderTool
910 class has the following addtional methods:
912 {set/get}FirstPoint(): Set/Get the first point of the Leader.
913 {set/get}MidPoint(): Set/Get the second point of the Leader.
914 {set/get}FinalPoint(): Set/Get the final point of the Leader.
917 super(LeaderTool
, self
).__init
__()
918 self
.__start
_point
= None
919 self
.__mid
_point
= None
920 self
.__end
_point
= None
922 def setFirstPoint(self
, x
, y
):
923 """Set the first point used to define the Leader.
927 Arguments 'x' and 'y' give the location of a point.
929 _x
= util
.get_float(x
)
930 _y
= util
.get_float(y
)
931 self
.__start
_point
= (_x
, _y
)
933 def getFirstPoint(self
):
934 """Get the first point used to define the Leader.
938 This method returns a tuple holding the values used when the
939 setFirstPoint() method was called, or None if that method has
942 return self
.__start
_point
944 def setMidPoint(self
, x
, y
):
945 """Set the second point used to define the Leader.
949 Arguments 'x' and 'y' give the location of a point. If the
950 first point has not been set this method raises a ValueError.
952 if self
.__start
_point
is None:
953 raise ValueError, "First point not set in LeaderTool."
954 _x
= util
.get_float(x
)
955 _y
= util
.get_float(y
)
956 self
.__mid
_point
= (_x
, _y
)
958 def getMidPoint(self
):
959 """Get the second point used to define the Leader.
963 This method returns a tuple holding the values used when the
964 setMidPoint() method was called, or None if that method has
967 return self
.__mid
_point
969 def setFinalPoint(self
, x
, y
):
970 """Set the first point used to final point of the Leader.
974 Arguments 'x' and 'y' give the location of a point. This method
975 raises an error if the first point or second point have not been
978 if self
.__start
_point
is None:
979 raise ValueError, "First point not set in LeaderTool."
980 if self
.__mid
_point
is None:
981 raise ValueError, "Second point not set in LeaderTool."
982 _x
= util
.get_float(x
)
983 _y
= util
.get_float(y
)
984 self
.__end
_point
= (_x
, _y
)
986 def getFinalPoint(self
):
987 """Get the third point used to define the Leader.
991 This method returns a tuple holding the values used when the
992 setFinalPoint() method was called, or None if that method has
995 return self
.__end
_point
998 """Restore the tool to its initial state.
1002 This method extends Tool::reset().
1004 super(LeaderTool
, self
).reset()
1005 self
.__start
_point
= None
1006 self
.__mid
_point
= None
1007 self
.__end
_point
= None
1009 def create(self
, image
):
1010 """Create a new Leader and add it to the image.
1014 This method overrides the Tool::create() method.
1016 if (self
.__start
_point
is not None and
1017 self
.__mid
_point
is not None and
1018 self
.__end
_point
is not None):
1019 _active_layer
= image
.getActiveLayer()
1020 _x1
, _y1
= self
.__start
_point
1021 _x2
, _y2
= self
.__mid
_point
1022 _x3
, _y3
= self
.__end
_point
1023 _pts
= _active_layer
.find('point', _x1
, _y1
)
1025 _p1
= Point(_x1
, _y1
)
1026 _active_layer
.addObject(_p1
)
1029 _pts
= _active_layer
.find('point', _x2
, _y2
)
1031 _p2
= Point(_x2
, _y2
)
1032 _active_layer
.addObject(_p2
)
1035 _pts
= _active_layer
.find('point', _x3
, _y3
)
1037 _p3
= Point(_x3
, _y3
)
1038 _active_layer
.addObject(_p3
)
1041 _size
= image
.getOption('LEADER_ARROW_SIZE')
1042 _s
= image
.getOption('LINE_STYLE')
1043 _leader
= Leader(_p1
, _p2
, _p3
, _size
, _s
)
1044 _l
= image
.getOption('LINE_TYPE')
1045 if _l
!= _s
.getLinetype():
1046 _leader
.setLinetype(_l
)
1047 _c
= image
.getOption('LINE_COLOR')
1048 if _c
!= _s
.getColor():
1049 _leader
.setColor(_c
)
1050 _t
= image
.getOption('LINE_THICKNESS')
1051 if abs(_t
- _s
.getThickness()) > 1e-10:
1052 _leader
.setThickness(_t
)
1053 _active_layer
.addObject(_leader
)
1056 class PolylineTool(Tool
):
1057 """A specialized tool for drawing Polyline objects.
1059 The PolylineTool class is derived from the Tool class, so it
1060 shares all the attributes and methods of that class. The PolylineTool
1061 class has the following addtional methods:
1063 storePoint(): Store a point used to define the Polyline.
1064 getPoint(): Retrieve a point used to define the Polyline.
1065 getLastPoint(): Retrieve the last point used to define the Polyline.
1066 getPoints(): Get the list of points that define the Polyline.
1069 super(PolylineTool
, self
).__init
__()
1073 return len(self
.__points
)
1075 def storePoint(self
, x
, y
):
1076 """Store a point that will define a Polyline.
1080 The arguments 'x' and 'y' should be float values. There is
1081 no limit as to how long a Polyline should be, so each invocation
1082 of this method appends the values to the list of stored points.
1084 _x
= util
.get_float(x
)
1085 _y
= util
.get_float(y
)
1086 self
.__points
.append((_x
, _y
))
1088 def getPoint(self
, i
):
1089 """Retrieve a point used to define a Polyline.
1093 Argument 'i' represents the index in the list of points that
1094 defines the polyline. Negative indicies will get points from
1095 last-to-first. Using an invalid index will raise an error.
1097 This method returns a tuple holding the x/y coordinates.
1099 return self
.__points
[i
]
1101 def getPoints(self
):
1102 """Get all the points that define the Polyline.
1106 This method returns a list of tuples holding the x/y coordinates
1107 of all the points that define the Polyline.
1109 return self
.__points
[:]
1112 """Restore the tool to its initial state.
1116 This method extends Tool::reset().
1118 super(PolylineTool
, self
).reset()
1119 del self
.__points
[:]
1121 def create(self
, image
):
1122 """Create a new Polyline and add it to the image.
1126 This method overrides the Tool::create() method.
1128 if len(self
.__points
):
1130 _active_layer
= image
.getActiveLayer()
1131 for _pt
in self
.__points
:
1133 _lpts
= _active_layer
.find('point', _x
, _y
)
1136 _active_layer
.addObject(_p
)
1139 _pts
.append(_lpts
[0])
1140 _s
= image
.getOption('LINE_STYLE')
1141 _pline
= Polyline(_pts
, _s
)
1142 _l
= image
.getOption('LINE_TYPE')
1143 if _l
!= _s
.getLinetype():
1144 _pline
.setLinetype(_l
)
1145 _c
= image
.getOption('LINE_COLOR')
1146 if _c
!= _s
.getColor():
1148 _t
= image
.getOption('LINE_THICKNESS')
1149 if abs(_t
- _s
.getThickness()) > 1e-10:
1150 _pline
.setThickness(_t
)
1151 _active_layer
.addObject(_pline
)
1154 class PolygonTool(Tool
):
1155 """A specialized to for creating Polygons from Segments.
1157 The PolygonTool will create an uniformly sized polygon from Segment
1158 entities. The minimum number of sides is three, creating an equilateral
1159 triangle. There is no maximum number of sides, though realistically any
1160 polygon with more than 20 or so sides is unlikely to be drawn. As
1161 the PolygonTool is derived from the Tool class, it shares all the attributes
1162 and method of that class. The PolygonTool has the following additional
1165 {get/set}SideCount(): Get/Set the number of sides in the polygon.
1166 {get/set}External() Get/Set if the polygon is drawn inside or outside a circle.
1167 {get/set}Center(): Get/Set the center location of the polygon.
1168 getCoords(): Get the coordinates of the polygon corners.
1171 super(PolygonTool
, self
).__init
__()
1172 self
.__nsides
= None
1173 self
.__increment
= None
1174 self
.__external
= False
1175 self
.__center
= None
1176 self
.__xpts
= array
.array("d")
1177 self
.__ypts
= array
.array("d")
1179 def setSideCount(self
, count
):
1180 """Set the number of sides of the polygon to create.
1184 Argument "count" should be an integer value greater than 2.
1187 if not isinstance(_count
, int):
1190 raise ValueError, "Invalid count: %d" % _count
1191 self
.__nsides
= _count
1192 self
.__increment
= (360.0/float(_count
)) * (math
.pi
/180.0)
1193 for _i
in range(_count
):
1194 self
.__xpts
.insert(_i
, 0.0)
1195 self
.__ypts
.insert(_i
, 0.0)
1197 def getSideCount(self
):
1198 """Get the number of sides of the polygon to be created.
1202 A ValueError exception is raised if the side count has not been
1203 set with setSideCount()
1205 if self
.__nsides
is None:
1206 raise ValueError, "No side count defined."
1207 return self
.__nsides
1209 def setExternal(self
):
1210 """Create the polygon on the outside of a reference circle.
1214 By default the polygon is drawing completely contained within a
1215 circle. Invoking this method will created the polygon so that all
1216 sides are outside the circle.
1218 self
.__external
= True
1220 def getExternal(self
):
1221 """Test if the polygon will be created outside a circle.
1225 If the setExternal() method has been called, this method will
1226 return True. By default this method will return False.
1228 return self
.__external
1230 def setCenter(self
, x
, y
):
1231 """Define the center of the polygon.
1235 Arguments 'x' and 'y' should be float values.
1237 _x
= util
.get_float(x
)
1238 _y
= util
.get_float(y
)
1239 self
.__center
= (_x
, _y
)
1241 def getCenter(self
):
1242 """Retrieve the center of the polygon to be created.
1246 This method returns a tuple holding two float values containing
1247 the 'x' and 'y' coordinates of the polygon center. A ValueError
1248 is raised if the center has not been set with a prior call to setCenter().
1250 if self
.__center
is None:
1251 raise ValueError, "Center is undefined."
1252 return self
.__center
1254 def getCoord(self
, i
):
1255 """Get one of the coordinates of the polygon corners.
1259 Argument "i" should be an integer value such that:
1261 0 <= i <= number of polygon sides
1267 def setLocation(self
, x
, y
):
1268 """Set the tool location.
1272 This method extends Tool::setLocation() and calculates the polygon
1275 super(PolygonTool
, self
).setLocation(x
, y
)
1276 _x
, _y
= self
.getLocation()
1277 _count
= self
.__nsides
1278 _inc
= self
.__increment
1283 _cx
, _cy
= self
.__center
1286 _angle
= math
.atan2(_ysep
, _xsep
) + _offset
1287 _rad
= math
.hypot(_xsep
, _ysep
)/math
.cos(_offset
)
1290 for _i
in range(_count
):
1291 _xp
[_i
] = _cx
+ (_rad
* math
.cos(_angle
))
1292 _yp
[_i
] = _cy
+ (_rad
* math
.sin(_angle
))
1293 _angle
= _angle
+ _inc
1295 def create(self
, image
):
1296 """Create a Polygon from Segments and add it to the image.
1300 This method overrides the Tool::create() method.
1302 if len(self
.__xpts
):
1303 _active_layer
= image
.getActiveLayer()
1304 _s
= image
.getOption('LINE_STYLE')
1305 _l
= image
.getOption('LINE_TYPE')
1306 if _l
== _s
.getLinetype():
1308 _c
= image
.getOption('LINE_COLOR')
1309 if _c
== _s
.getColor():
1311 _t
= image
.getOption('LINE_THICKNESS')
1312 if abs(_t
- _s
.getThickness()) < 1e-10:
1314 _count
= self
.__nsides
1320 # find starting point ...
1322 _pts
= _active_layer
.find('point', _x
, _y
)
1325 _active_layer
.addObject(_p0
)
1329 # make segments for all the points ...
1332 for _i
in range(1, _count
):
1335 _pts
= _active_layer
.find('point', _x
, _y
)
1338 _active_layer
.addObject(_pi
)
1341 _seg
= Segment(_p1
, _pi
, _s
, linetype
=_l
, color
=_c
, thickness
=_t
)
1342 _active_layer
.addObject(_seg
)
1345 # now add closing segment ...
1347 _seg
= Segment(_p1
, _p0
, _s
, linetype
=_l
, color
=_c
, thickness
=_t
)
1348 _active_layer
.addObject(_seg
)
1352 """Restore the PolygonTool to its original state.
1356 This method extends Tool::reset()
1358 super(PolygonTool
, self
).reset()
1359 # self.__nsides = None
1360 # self.__increment = None
1361 # self.__external = False # make this adjustable?
1362 self
.__center
= None
1363 for _i
in range(self
.__nsides
):
1364 self
.__xpts
[_i
] = 0.0
1365 self
.__ypts
[_i
] = 0.0
1367 class HCLineTool(PointTool
):
1368 """A specialized tool for drawing HCLine objects.
1370 The HCLineTool class is derived from the PointTool class
1371 so it shares all the attributes and methods of that class.
1373 There are no additional methods for this class.
1376 super(HCLineTool
, self
).__init
__()
1378 def create(self
, image
):
1379 """Create a new HCLine and add it to the image.
1383 This method overrides the Tool::create() method.
1385 _p
= self
.getPoint()
1387 _active_layer
= image
.getActiveLayer()
1389 _pts
= _active_layer
.find('point', _x
, _y
)
1392 _active_layer
.addObject(_pt
)
1396 _active_layer
.addObject(_hcl
)
1399 class VCLineTool(PointTool
):
1400 """A specialized tool for drawing VCLine objects.
1402 The VCLineTool class is derived from the PointTool class
1403 so it shares all the attributes and methods of that class.
1405 There are no additional methods for this class.
1408 super(VCLineTool
, self
).__init
__()
1410 def create(self
, image
):
1411 """Create a new VCLine and add it to the image.
1415 This method overrides the Tool::create() method.
1417 _p
= self
.getPoint()
1419 _active_layer
= image
.getActiveLayer()
1421 _pts
= _active_layer
.find('point', _x
, _y
)
1424 _active_layer
.addObject(_pt
)
1428 _active_layer
.addObject(_vcl
)
1431 class ACLineTool(PointTool
):
1432 """A specialized tool for drawing ACLine objects.
1434 The ACLineTool class is derived from the PointTool class
1435 so it shares all the attributes and methods of that class.
1436 The ACLineTool class has the following addtional methods:
1438 {set/get}Angle(): Set/Get the angle of the ACLine.
1441 super(ACLineTool
, self
).__init
__()
1444 def setLocation(self
, x
, y
):
1445 """Set the location of the Tool.
1449 This method extends the Tool::setLocation() method.
1451 super(ACLineTool
, self
).setLocation(x
, y
)
1452 _loc
= self
.getLocation()
1456 _x1
, _y1
= self
.getPoint()
1457 if abs(_y
- _y1
) < 1e-10: # horizontal
1459 elif abs(_x
- _x1
) < 1e-10: # vertical
1462 _slope
= 180.0/math
.pi
* math
.atan2((_y
- _y1
), (_x
- _x1
))
1463 self
.__angle
= util
.make_angle(_slope
)
1465 def setAngle(self
, angle
):
1466 """Set the angle for the ACLine.
1470 The argument 'angle' should be a float where -90.0 < angle < 90.0
1472 _angle
= util
.make_angle(angle
)
1473 self
.__angle
= _angle
1476 """Get the angle for the ACLine.
1480 This method returns a float.
1485 """Restore the tool to its initial state.
1489 This method extends PointTool::reset().
1491 super(ACLineTool
, self
).reset()
1494 def create(self
, image
):
1495 """Create a new ACLine and add it to the image.
1499 This method overrides the Tool::create() method.
1501 _p
= self
.getPoint()
1502 if (_p
is not None and
1503 self
.__angle
is not None):
1504 _active_layer
= image
.getActiveLayer()
1506 _pts
= _active_layer
.find('point', _x
, _y
)
1509 _active_layer
.addObject(_pt
)
1512 _acl
= ACLine(_pt
, self
.__angle
)
1513 _active_layer
.addObject(_acl
)
1516 class CLineTool(SegmentTool
):
1517 """A specialized tool for drawing CLine objects.
1519 The CLineTool class is derived from the SegmentTool class,
1520 so it shares all the attributes and methods of that class.
1522 There are no extra methods for the CLineTool class.
1525 super(CLineTool
, self
).__init
__()
1527 def create(self
, image
):
1528 """Create a new CLine and add it to the image.
1532 This method overrides the Tool::create() method.
1534 _p1
= self
.getFirstPoint()
1535 _p2
= self
.getSecondPoint()
1536 if _p1
is not None and _p2
is not None:
1537 _active_layer
= image
.getActiveLayer()
1540 _pts
= _active_layer
.find('point', _x1
, _y1
)
1542 _p1
= Point(_x1
, _y1
)
1543 _active_layer
.addObject(_p1
)
1546 _pts
= _active_layer
.find('point', _x2
, _y2
)
1548 _p2
= Point(_x2
, _y2
)
1549 _active_layer
.addObject(_p2
)
1552 _cline
= CLine(_p1
, _p2
)
1553 _active_layer
.addObject(_cline
)
1556 class CCircleTool(CircleTool
):
1557 """A specialized tool for drawing CCircle objects.
1559 The CCircleTool class is derived from the CircleTool class,
1560 so it shares all the attributes and methods of that class.
1562 There are no additional methods for the CCircleTool class.
1565 super(CCircleTool
, self
).__init
__()
1567 def create(self
, image
):
1568 """Create a new CCircle and add it to the image.
1572 This method overrides the Tool::create() method.
1574 _active_layer
= image
.getActiveLayer()
1575 _x
, _y
= self
.getCenter()
1576 _radius
= self
.getRadius()
1577 _pts
= _active_layer
.find('point', _x
, _y
)
1580 _active_layer
.addObject(_cp
)
1583 _ccircle
= CCircle(_cp
, _radius
)
1584 _active_layer
.addObject(_ccircle
)
1587 class TwoPointCCircleTool(TwoPointCircleTool
):
1588 """A specialized tool for drawing CCircle objects between two points.
1590 The TwoPointCCircleTool class is derived from the TwoPointCircleTool
1591 class, so it shares all the attributes and methods of that class.
1592 There are no additional methods for the TwoPointCCircleTool class.
1595 super(TwoPointCCircleTool
, self
).__init
__()
1597 def create(self
, image
):
1598 """Create a new CCircle and add it to the image.
1602 This method overrides the Tool::create() method.
1604 _center
= self
.getCenter()
1605 _radius
= self
.getRadius()
1606 if _center
is not None and _radius
is not None:
1607 _active_layer
= image
.getActiveLayer()
1609 _pts
= _active_layer
.find('point', _x
, _y
)
1612 _active_layer
.addObject(_cp
)
1615 _ccircle
= CCircle(_cp
, _radius
)
1616 _active_layer
.addObject(_ccircle
)
1620 # The PerpendicularCLineTool and TangentCLineTool classes are
1621 # subclasses of Tool without any additional functionality (yet)
1624 class PerpendicularCLineTool(Tool
):
1627 class TangentCLineTool(Tool
):
1630 class ParallelOffsetTool(Tool
):
1631 """A specialized tool for creating parallel construction lines.
1633 The ParallelOffsetTool will create a construction line parallel
1634 to another construction line a fixed distance from the original
1635 construction line. The type of the new construction line will match
1636 that of the original.
1638 The ParallelOffsetTool is derived from the Tool class, so it shares
1639 all the attributes and methods of that class. The ParallelOffsetTool
1640 has the following addtional methods:
1642 {set/get}Offset(): Set/Get the distance between the construction lines.
1643 {set/get}ConstructionLine(): Set/Get the original construction line
1644 {set/get}ReferencePoint(): Set/Get the point to define where the new
1645 construction line will go.
1649 super(ParallelOffsetTool
, self
).__init
__()
1651 self
.__offset
= None
1652 self
.__conline
= None
1654 def setOffset(self
, offset
):
1655 """Store the displacement in the tool.
1659 Argument 'offset' must be a float.
1661 _offset
= util
.get_float(offset
)
1662 self
.__offset
= _offset
1664 def getOffset(self
):
1665 """Return the stored offset from the tool.
1669 This method will raise a ValueError exception if the offset has
1670 not been set with setOffset()
1672 _offset
= self
.__offset
1674 raise ValueError, "Offset is not defined."
1677 def setConstructionLine(self
, conline
):
1678 """Store the reference construction line in the tool.
1680 setConstructionLine(conline)
1682 Argument 'conline' must be a VCLine, HCLine, ACLine, or CLine object.
1684 if not isinstance(conline
, (HCLine
, VCLine
, ACLine
, CLine
)):
1685 raise TypeError, "Invalid Construction line: " + `
type(conline
)`
1686 self
.__conline
= conline
1688 def getConstructionLine(self
):
1689 """Retrieve the stored construction line from the tool.
1691 getConstructionLine()
1693 A ValueError exception is raised if the construction line has not been
1694 set with the setConstructionLine() method.
1696 _conline
= self
.__conline
1697 if _conline
is None:
1698 raise ValueError, "Construction line is not defined."
1701 def setReferencePoint(self
, x
, y
):
1702 """Store the reference point for positioning the new construction line.
1704 setReferencePoint(x, y)
1706 Arguments 'x' and 'y' give the coordinates of a reference point
1707 used to determine where the new construction line will be placed.
1708 Both arguments should be floats.
1710 _x
= util
.get_float(x
)
1711 _y
= util
.get_float(y
)
1712 self
.__refpt
= (_x
, _y
)
1714 def getReferencePoint(self
):
1715 """Retreive the reference point from the tool.
1719 This method returns a tuple containing the values stored from
1720 the setReferencePoint() call. This method will raise a ValueError
1721 exception if the reference point has not been set.
1723 _refpt
= self
.__refpt
1725 raise ValueError, "No reference point defined."
1729 """Restore the tool to its initial state.
1733 This method extends Tool::reset().
1735 super(ParallelOffsetTool
, self
).reset()
1737 self
.__offset
= None
1738 self
.__conline
= None
1740 def create(self
, image
):
1741 """Create a parallel construction line in an image.
1745 This method overrides the Tool::create() method.
1747 _offset
= self
.__offset
1748 _conline
= self
.__conline
1749 _refpt
= self
.__refpt
1750 if (_offset
is not None and
1751 _conline
is not None and
1752 _refpt
is not None):
1753 _active_layer
= image
.getActiveLayer()
1755 _lp1
= _lp2
= _ncl
= None
1756 if isinstance(_conline
, HCLine
):
1757 _x
, _y
= _conline
.getLocation().getCoords()
1762 if len(_active_layer
.find('hcline', _yn
)) == 0:
1763 _pts
= _active_layer
.find('point', _x
, _yn
)
1765 _lp1
= Point(_x
, _yn
)
1769 elif isinstance(_conline
, VCLine
):
1770 _x
, _y
= _conline
.getLocation().getCoords()
1775 if len(_active_layer
.find('vcline', _xn
)) == 0:
1776 _pts
= _active_layer
.find('point', _xn
, _y
)
1778 _lp1
= Point(_xn
, _y
)
1782 elif isinstance(_conline
, ACLine
):
1783 _x
, _y
= _conline
.getLocation().getCoords()
1784 _angle
= _conline
.getAngle()
1785 if abs(_angle
) < 1e-10: # horizontal
1788 elif abs(abs(_angle
) - 90.0) < 1e-10: # vertical
1792 _slope
= math
.tan(_angle
* (math
.pi
/180.0))
1793 _yint
= _y
- (_slope
* _x
)
1798 # redefine angle from p1 to p2 ...
1799 _angle
= math
.atan2((_yint
- _y
), -_x
)
1801 _angle
= _angle
+ (2.0 * math
.pi
)
1802 _sqlen
= math
.hypot(_x
, (_y
- _yint
))
1803 _sn
= ((_y
- _ry
) * (0.0 - _x
)) - ((_x
- _rx
) * (_yint
- _y
))
1806 _perp
= _angle
+ (math
.pi
/2.0)
1808 _perp
= _angle
- (math
.pi
/2.0)
1809 _dx
= _offset
* math
.cos(_perp
)
1810 _dy
= _offset
* math
.sin(_perp
)
1811 _angle
= _conline
.getAngle() # reset variable
1814 if len(_active_layer
.find('acline', _xn
, _yn
, _angle
)) == 0:
1815 _pts
= _active_layer
.find('point', _xn
, _yn
)
1817 _lp1
= Point(_xn
, _yn
)
1820 _ncl
= ACLine(_lp1
, _angle
)
1821 elif isinstance(_conline
, CLine
):
1822 _p1
, _p2
= _conline
.getKeypoints()
1823 _x1
, _y1
= _p1
.getCoords()
1824 _x2
, _y2
= _p2
.getCoords()
1825 if abs(_x2
- _x1
) < 1e-10: # vertical
1828 elif abs(_y2
- _y1
) < 1e-10: # horizontal
1832 _angle
= math
.atan2((_y2
- _y1
), (_x2
- _x1
))
1834 _angle
= _angle
+ (2.0 * math
.pi
)
1835 _sqlen
= math
.hypot((_x2
- _x1
), (_y2
- _y1
))
1836 _sn
= ((_y1
- _ry
) * (_x2
- _x1
)) - ((_x1
- _rx
) * (_y2
- _y1
))
1839 _perp
= _angle
+ (math
.pi
/2.0)
1841 _perp
= _angle
- (math
.pi
/2.0)
1842 _dx
= math
.cos(_perp
) * _offset
1843 _dy
= math
.sin(_perp
) * _offset
1848 if len(_active_layer
.find('cline', _x1n
, _y1n
, _x2n
, _y2n
)) == 0:
1849 _pts
= _active_layer
.find('point', _x1n
, _y1n
)
1851 _lp1
= Point(_x1n
, _y1n
)
1854 _pts
= _active_layer
.find('point', _x2n
, _y2n
)
1856 _lp2
= Point(_x2n
, _y2n
)
1859 _ncl
= CLine(_lp1
, _lp2
)
1861 raise TypeError, "Invalid Construction line type: " + `
type(_conline
)`
1862 if _ncl
is not None:
1863 if _lp1
is not None and _lp1
.getParent() is None:
1864 _active_layer
.addObject(_lp1
)
1865 if _lp2
is not None and _lp2
.getParent() is None:
1866 _active_layer
.addObject(_lp2
)
1867 _active_layer
.addObject(_ncl
)
1870 class TangentCircleTool(Tool
):
1871 """A specialized class for creating tangent construction circles.
1873 This class is meant to be a base class for tools that create tangent
1874 construction circles. It is derived from the tool class so it shares
1875 all the attributes and methods of that class. This class has the
1876 following additional methods:
1878 {set/get}Center(): Set/Get the center of the tangent circle.
1879 {set/get}Radius(): Set/Get the radius of the tangent circle.
1880 {set/get}PixelRect(): Set/Get the screen rectangle for drawing the circle.
1883 super(TangentCircleTool
, self
).__init
__()
1884 self
.__center
= None
1885 self
.__radius
= None
1888 def setCenter(self
, x
, y
):
1889 """Store the tangent circle center point in the tool.
1893 Arguments 'x' and 'y' should be floats.
1895 _x
= util
.get_float(x
)
1896 _y
= util
.get_float(y
)
1897 self
.__center
= (_x
, _y
)
1899 def getCenter(self
):
1900 """Return the center of the tangent circle.
1904 This method returns a tuple holding two floats, the first
1905 is the 'x' coordinate of the center, the second is the 'y'
1906 coordinate. If the tool has not yet been invoked with a
1907 setLocation() call, this method returns None.
1909 return self
.__center
1911 def setRadius(self
, radius
):
1912 """Store the radius in the tool.
1916 Argument 'radius' should be a float.
1918 _radius
= util
.get_float(radius
)
1919 self
.__radius
= _radius
1921 def getRadius(self
):
1922 """Return the center of the tangent circle.
1926 This method returns a float giving the radius of the tangent
1927 circle, or None if the radius is not set.
1929 return self
.__radius
1931 def setPixelRect(self
, xmin
, ymin
, width
, height
):
1932 """Store the screen coordinates used to draw the circle.
1934 setPixelRect(xmin, ymin, width, height)
1936 All the arguments should be integer values.
1939 if not isinstance(_xmin
, int):
1942 if not isinstance(_ymin
, int):
1945 if not isinstance(_width
, int):
1946 _width
= int(_width
)
1948 if not isinstance(_height
, int):
1949 _height
= int(height
)
1950 self
.__rect
= (_xmin
, _ymin
, _width
, _height
)
1952 def getPixelRect(self
):
1953 """Return the screen boundary of the circle to draw
1957 This method will return a tuple holding four integer values:
1959 xmin, ymin, width, height
1961 If the rectangle has not been set by calling setPixelRect(), then
1962 this method will return None.
1967 """Restore the tool to its initial state.
1971 This method extends Tool::reset().
1973 super(TangentCircleTool
, self
).reset()
1974 self
.__center
= None
1975 self
.__radius
= None
1978 def create(self
, image
):
1979 """Create a new CCircle and add it to the image.
1983 This method overrides the Tool::create() method.
1985 _active_layer
= image
.getActiveLayer()
1986 _x
, _y
= self
.__center
1987 _radius
= self
.__radius
1988 _pts
= _active_layer
.find('point', _x
, _y
)
1991 _active_layer
.addObject(_cp
)
1994 _ccircle
= CCircle(_cp
, _radius
)
1995 _active_layer
.addObject(_ccircle
)
1998 class TangentCCircleTool(TangentCircleTool
):
1999 """A specialized tool for creating tangent construction circles.
2001 The TangentCCircleTool will create a construction circle tangent
2002 to a construction line or a construction circle.
2004 The TangentCCircleTool is derived from the TangentCircleTool class, so
2005 it shares all the attributes and methods of that class. The TangentCCircleTool
2006 has the following addtional methods:
2008 {set/get}ConstructionObject(): Set/Get the reference construction object.
2011 super(TangentCCircleTool
, self
).__init
__()
2012 self
.__conobj
= None
2014 def setConstructionLine(self
, conobj
):
2015 """Store the reference construction object in the tool.
2017 setConstructionLine(conobj)
2019 Argument 'conobj' must be a VCLine, HCLine, ACLine, CLine,
2022 if not isinstance(conobj
, (HCLine
, VCLine
, ACLine
, CLine
, CCircle
)):
2023 raise TypeError, "Invalid Construction entity type: " + `
type(conobj
)`
2024 self
.__conobj
= conobj
2026 def getConstructionLine(self
):
2027 """Retrieve the stored construction line from the tool.
2029 getConstructionLine()
2031 A ValueError exception is raised if the construction line has not been
2032 set with the setConstructionLine() method.
2034 _conobj
= self
.__conobj
2036 raise ValueError, "Construction object is not defined."
2039 def setLocation(self
, x
, y
):
2040 """Store an x/y coordinate pair in the tool.
2044 Arguments 'x' and 'y' should be floats. This method extends
2045 the TangentCircleTool::setLocation() methods.
2047 super(TangentCCircleTool
, self
).setLocation(x
, y
)
2048 _tx
, _ty
= self
.getLocation()
2049 _conobj
= self
.__conobj
2050 _cx
= _cy
= _radius
= None
2051 if isinstance(_conobj
, HCLine
):
2052 _x
, _y
= _conobj
.getLocation().getCoords()
2054 _cy
= (_ty
+ _y
)/2.0
2055 _radius
= abs(_ty
- _y
)/2.0
2056 elif isinstance(_conobj
, VCLine
):
2057 _x
, _y
= _conobj
.getLocation().getCoords()
2058 _cx
= (_tx
+ _x
)/2.0
2060 _radius
= abs(_tx
- _x
)/2.0
2061 elif isinstance(_conobj
, (ACLine
, CLine
)):
2062 _px
, _py
= _conobj
.getProjection(_tx
, _ty
)
2063 _cx
= (_tx
+ _px
)/2.0
2064 _cy
= (_ty
+ _py
)/2.0
2065 _radius
= math
.hypot((_tx
- _px
), (_ty
- _py
))/2.0
2066 elif isinstance(_conobj
, CCircle
):
2067 _ccx
, _ccy
= _conobj
.getCenter().getCoords()
2068 _rad
= _conobj
.getRadius()
2069 _sep
= math
.hypot((_tx
- _ccx
), (_ty
- _ccy
))
2072 _angle
= math
.atan2((_ty
- _ccy
), (_tx
- _ccx
))
2073 _px
= _ccx
+ (_rad
* math
.cos(_angle
))
2074 _py
= _ccy
+ (_rad
* math
.sin(_angle
))
2075 _cx
= (_tx
+ _px
)/2.0
2076 _cy
= (_ty
+ _py
)/2.0
2077 _radius
= math
.hypot((_tx
- _px
), (_ty
- _py
))/2.0
2079 raise TypeError, "Invalid construction entity type: " + `
type(_conobj
)`
2080 self
.setCenter(_cx
, _cy
)
2081 self
.setRadius(_radius
)
2083 class TwoPointTangentCCircleTool(TangentCircleTool
):
2084 """A specialized tool for creating tangent construction circles.
2086 The TwoPointTangentCCircleTool will create a construction circle tangent
2087 to two construction lines or a construction line and a construction
2088 circle if such a tangent circle can be created.
2090 The TwoPointTangentCCircleTool is derived from the TangentCircleTool
2091 class, so it shares all the attributes and methods of that class. This
2092 class also has the following addtional methods:
2094 {set/get}FirstConObject(): Set/Get the first construction object.
2095 {set/get}SecondConObject(): Set/Get the second constuction object.
2098 super(TwoPointTangentCCircleTool
, self
).__init
__()
2102 def setFirstConObject(self
, conobj
):
2103 """Store the first reference construction object in the tool.
2105 setFirstConObject(conobj)
2107 Argument 'conobj' must be a VCLine, HCLine, ACLine, CLine, or CCircle object.
2109 if not isinstance(conobj
, (HCLine
, VCLine
, ACLine
, CLine
, CCircle
)):
2110 raise TypeError, "Invalid Construction entity type: " + `
type(conobj
)`
2111 self
.__cobj
1 = conobj
2113 def getFirstConObject(self
):
2114 """Retreive the first construction object from the tool.
2120 def setSecondConObject(self
, conobj
):
2121 """Store the second reference construction object in the tool.
2123 setSecondConObject(conobj)
2125 Argument 'conobj' must be a VCLine, HCLine, ACLine, or a CLine object.
2126 Drawing a tangent circle against two CCircle objects is not yet supported.
2127 A ValueError exception will be raised if this method is called before the
2128 first construction object has been set.
2130 if self
.__cobj
1 is None:
2131 raise ValueError, "First construction object not set."
2132 if not isinstance(conobj
, (HCLine
, VCLine
, ACLine
, CLine
)):
2133 raise TypeError, "Invalid Construction line type: " + `
type(conobj
)`
2134 self
.__cobj
2 = conobj
2136 def getSecondConObject(self
):
2137 """Retreive the second construction object from the tool.
2139 getSecondConObject()
2144 """Restore the tool to its initial state.
2148 This method extends the TangentCircleTool::reset() method.
2150 super(TwoPointTangentCCircleTool
, self
).reset()
2154 def setLocation(self
, x
, y
):
2155 """Store an x/y coordinate pair in the tool.
2159 Arguments 'x' and 'y' should be floats. This method extends
2160 the TangentCircleTool::setLocation() methods.
2162 super(TwoPointTangentCCircleTool
, self
).setLocation(x
, y
)
2163 _tx
, _ty
= self
.getLocation()
2164 _obja
= self
.__cobj
1
2165 _objb
= self
.__cobj
2
2166 _tandata
= tangent
.calc_tangent_circle(_obja
, _objb
, _tx
, _ty
)
2167 if _tandata
is not None:
2168 _cx
, _cy
, _radius
= _tandata
2169 self
.setCenter(_cx
, _cy
)
2170 self
.setRadius(_radius
)
2173 class CCircleTangentLineTool(Tool
):
2174 """A specialized class for creating tangent lines to construction circles.
2176 This class is a specialized class that handles creating construction
2177 lines around circles. There can be at most four possible tangent lines.
2178 There are two tangent lines if the circles overlap, and no tangent
2179 lines if one circle is inside another. As this tool is derived from
2180 the Tool class it shares all the attributes and methods of that
2181 class. The CCircleTangentLineTool class has the following additional
2184 {get/set}FirstCCircle(): Get/Set the first CCircle in the tool.
2185 {get/set}SecondCCircle(): Get/Set the second CCircle in the tool.
2188 super(CCircleTangentLineTool
, self
).__init
__()
2193 def setFirstCCircle(self
, ccircle
):
2194 """Store the first construction circle in the tool.
2196 setFirstCCircle(ccircle)
2198 Argument 'ccircle' must be a CCircle object.
2200 if not isinstance(ccircle
, CCircle
):
2201 raise TypeError, "Invalid CCircle type: " + `
type(ccircle
)`
2202 self
.__circ
1 = ccircle
2204 def getFirstCCircle(self
):
2205 """Retreive the first construction circle from the tool.
2211 def setSecondCCircle(self
, ccircle
):
2212 """Store the second construction circle in the tool.
2214 setSecondCCircle(ccircle)
2216 Argument 'ccircle' must be a CCircle object. A ValueError exception will
2217 be raised if this method is called before the first construction circle
2220 if self
.__circ
1 is None:
2221 raise ValueError, "First construction circle not set."
2222 if not isinstance(ccircle
, CCircle
):
2223 raise TypeError, "Invalid CCircle type: " + `
type(ccircle
)`
2224 self
.__circ
2 = ccircle
2226 # calculate the tangent points if they exist
2230 _cx1
, _cy1
= _cc1
.getCenter().getCoords()
2231 _r1
= _cc1
.getRadius()
2232 _cx2
, _cy2
= _cc2
.getCenter().getCoords()
2233 _r2
= _cc2
.getRadius()
2234 _sep
= math
.hypot((_cx2
- _cx1
), (_cy2
- _cy1
))
2235 _angle
= math
.atan2((_cy2
- _cy1
), (_cx2
- _cx1
))
2236 _sine
= math
.sin(_angle
)
2237 _cosine
= math
.cos(_angle
)
2239 # tangent points are calculated as if the first circle
2240 # center is (0, 0) and both circle centers on the x-axis,
2241 # so the points need to be transformed to the correct coordinates
2243 _tanpts
= self
.__tanpts
2244 del _tanpts
[:] # make sure it is empty ...
2245 _tansets
= tangent
.calc_two_circle_tangents(_r1
, _r2
, _sep
)
2246 for _set
in _tansets
:
2247 _x1
, _y1
, _x2
, _y2
= _set
2248 _tx1
= ((_x1
* _cosine
) - (_y1
* _sine
)) + _cx1
2249 _ty1
= ((_x1
* _sine
) + (_y1
* _cosine
)) + _cy1
2250 _tx2
= ((_x2
* _cosine
) - (_y2
* _sine
)) + _cx1
2251 _ty2
= ((_x2
* _sine
) + (_y2
* _cosine
)) + _cy1
2252 _tanpts
.append((_tx1
, _ty1
, _tx2
, _ty2
))
2255 def getSecondCCircle(self
):
2256 """Retreive the second construction circle from the tool.
2262 def hasTangentPoints(self
):
2263 """Test if tangent points were found for the two circles.
2268 if len(self
.__tanpts
):
2272 def getTangentPoints(self
):
2273 """Return the tangent points calculated for two-circle tangency.
2277 This method returns a list of tuples holding four float values:
2281 A tangent line can be drawn between the two circles from (x1, y1) to (x2, y2).
2283 return self
.__tanpts
[:]
2285 def create(self
, image
):
2286 """Create the tangent line for two circles.
2290 _x
, _y
= self
.getLocation()
2291 _tanpts
= self
.__tanpts
2292 if not len(_tanpts
):
2293 raise ValueError, "No tangent points defined."
2294 _minsep
= _px1
= _py1
= _px2
= _py2
= None
2295 for _set
in _tanpts
:
2296 _x1
, _y1
, _x2
, _y2
= _set
2297 _sqlen
= pow((_x2
- _x1
), 2) + pow((_y2
- _y1
), 2)
2298 _rn
= ((_x
- _x1
) * (_x2
- _x1
)) + ((_y
- _y1
) * (_y2
- _y1
))
2300 _px
= _x1
+ _r
* (_x2
- _x1
)
2301 _py
= _y1
+ _r
* (_y2
- _y1
)
2302 _sep
= math
.hypot((_px
- _x
), (_py
- _y
))
2303 if _minsep
is None or _sep
< _minsep
:
2309 _active_layer
= image
.getActiveLayer()
2310 _pts
= _active_layer
.find('point', _px1
, _py1
)
2312 _p1
= Point(_px1
, _py1
)
2313 _active_layer
.addObject(_p1
)
2316 _pts
= _active_layer
.find('point', _px2
, _py2
)
2318 _p2
= Point(_px2
, _py2
)
2319 _active_layer
.addObject(_p2
)
2322 _active_layer
.addObject(CLine(_p1
, _p2
))
2325 """Restore the tool to its initial state.
2329 This method extends Tool::reset().
2331 super(CCircleTangentLineTool
, self
).reset()
2334 del self
.__tanpts
[:]
2336 class DimensionTool(Tool
):
2337 """A base class for tools creating Dimension objects.
2339 The DimensionTool class is meant to be a base class for classes
2340 that will create Dimension objects. The DimensionTool class is
2341 derived from the Tool class, so it shares all the attributes and
2342 methods of that class. The DimensionTool class has the following
2345 setDimension(): Store a dimension object in the tool
2346 getDimension(): Retrieve a stored dimension object.
2347 setDimPrefs(): Apply the current dimension preferences on a stored dimension.
2350 super(DimensionTool
, self
).__init
__()
2353 def _setDimension(self
, dim
):
2354 """Store a dimension in the tool.
2358 The argument 'dim' must be a Dimension object.
2360 if not isinstance(dim
, dimension
.Dimension
):
2361 raise TypeError, "Invalid Dimension type: " + `
type(dim
)`
2364 def getDimension(self
):
2365 """Retrieve the stored dimension object from the tool.
2369 This method returns the stored Dimension or None.
2373 def setDimPrefs(self
, image
):
2374 """Apply the current dimension options to the stored dimension.
2378 The argument 'image' is an image option in which the current dimension
2379 preferences are retrieved.
2383 raise ValueError, "No dimension stored in tool."
2384 _pds
= _dim
.getPrimaryDimstring()
2386 _pds
.setFamily(image
.getOption('DIM_PRIMARY_FONT_FAMILY'))
2387 _pds
.setWeight(image
.getOption('DIM_PRIMARY_FONT_WEIGHT'))
2388 _pds
.setStyle(image
.getOption('DIM_PRIMARY_FONT_STYLE'))
2389 _pds
.setColor(image
.getOption('DIM_PRIMARY_FONT_COLOR'))
2390 _pds
.setSize(image
.getOption('DIM_PRIMARY_TEXT_SIZE'))
2391 _pds
.setAlignment(image
.getOption('DIM_PRIMARY_TEXT_ALIGNMENT'))
2392 _pds
.setPrecision(image
.getOption('DIM_PRIMARY_PRECISION'))
2393 _pds
.setUnits(image
.getOption('DIM_PRIMARY_UNITS'))
2394 _pds
.setPrintZero(image
.getOption('DIM_PRIMARY_LEADING_ZERO'))
2395 _pds
.setPrintDecimal(image
.getOption('DIM_PRIMARY_TRAILING_DECIMAL'))
2397 _sds
= _dim
.getSecondaryDimstring()
2399 _sds
.setFamily(image
.getOption('DIM_SECONDARY_FONT_FAMILY'))
2400 _sds
.setWeight(image
.getOption('DIM_SECONDARY_FONT_WEIGHT'))
2401 _sds
.setStyle(image
.getOption('DIM_SECONDARY_FONT_STYLE'))
2402 _sds
.setColor(image
.getOption('DIM_SECONDARY_FONT_COLOR'))
2403 _sds
.setSize(image
.getOption('DIM_SECONDARY_TEXT_SIZE'))
2404 _sds
.setAlignment(image
.getOption('DIM_SECONDARY_TEXT_ALIGNMENT'))
2405 _sds
.setPrecision(image
.getOption('DIM_SECONDARY_PRECISION'))
2406 _sds
.setUnits(image
.getOption('DIM_SECONDARY_UNITS'))
2407 _sds
.setPrintZero(image
.getOption('DIM_SECONDARY_LEADING_ZERO'))
2408 _sds
.setPrintDecimal(image
.getOption('DIM_SECONDARY_TRAILING_DECIMAL'))
2410 _dim
.setOffset(image
.getOption('DIM_OFFSET'))
2411 _dim
.setExtension(image
.getOption('DIM_EXTENSION'))
2412 _dim
.setColor(image
.getOption('DIM_COLOR'))
2413 _dim
.setPosition(image
.getOption('DIM_POSITION'))
2414 _dim
.setEndpointType(image
.getOption('DIM_ENDPOINT'))
2415 _dim
.setEndpointSize(image
.getOption('DIM_ENDPOINT_SIZE'))
2416 _dim
.setDualDimMode(image
.getOption('DIM_DUAL_MODE'))
2419 """Restore the tool to its initial state.
2423 This method sets the DimensionTool dimension to None.
2425 super(DimensionTool
, self
).reset()
2428 class LinearDimensionTool(DimensionTool
):
2429 """A specialized tool for drawing LinearDimension objects.
2431 The LinearDimensionTool is derived from the DimensionTool and
2432 Tool, class, so it shares all the attributes and methods of those classes.
2433 The LinearDimensionTool class has the following addtional methods:
2435 {set/get}FirstPoint(): Set/Get the first point in the LinearDimension
2436 {set/get}SecondPoint(): Set/Get the second point in the LinearDimension.
2437 {set/get}DimPosition(): Set/Get the location of the dimension text.
2440 super(LinearDimensionTool
, self
).__init
__()
2443 self
.__position
= None
2445 def setFirstPoint(self
, p
):
2446 """Store the first point for the LinearDimension.
2450 The argument 'p' must be a Point instance.
2452 if not isinstance (p
, Point
):
2453 raise TypeError, "Invalid Point: " + `
type(p
)`
2454 if p
.getParent() is None:
2455 raise ValueError, "Point not found in a Layer."
2458 def getFirstPoint(self
):
2459 """Return the first point for the LinearDimension.
2463 This method returns a tuple of two objects: the first object
2464 is a Layer, the second object is a Point.
2468 def setSecondPoint(self
, p
):
2469 """Store the second point for the LinearDimension.
2473 The argument 'p' must be a Point instance.
2475 if self
.__p
1 is None:
2476 raise ValueError, "First point not set for LinearDimension."
2477 if not isinstance (p
, Point
):
2478 raise TypeError, "Invalid Point: " + `
type(p
)`
2479 if p
.getParent() is None:
2480 raise ValueError, "Point not found in a Layer."
2483 def getSecondPoint(self
):
2484 """Return the second point for the LinearDimension.
2488 This method returns a tuple of two objects: the first object
2489 is a Layer, the second object is a Point.
2493 def setDimPosition(self
, x
, y
):
2494 """Store the point where the dimension text will be located.
2496 setDimPosition(x, y)
2498 Arguments 'x' and 'y' should be float values.
2500 _x
= util
.get_float(x
)
2501 _y
= util
.get_float(y
)
2502 self
.__position
= (_x
, _y
)
2504 def getDimPosition(self
):
2505 """Retrieve where the dimension text should be placed.
2509 This method returns a tuple containing the x/y coodindates defined
2510 by the setDimPosition() call, or None if that method has not been invoked.
2512 return self
.__position
2515 """Restore the tool to its initial state.
2519 This method extends the reset() methods of its base classes.
2521 super(LinearDimensionTool
, self
).reset()
2524 self
.__position
= None
2526 def makeDimension(self
, image
):
2527 """Create a LinearDimension based on the stored tool values.
2529 makeDimension(image)
2531 The argument 'image' is an image object where the dimension will be used.
2535 _x
, _y
= self
.__position
2536 if (_p1
is not None and
2540 _ds
= image
.getOption('DIM_STYLE')
2541 _ldim
= dimension
.LinearDimension(_p1
, _p2
, _x
, _y
, _ds
)
2542 self
._setDimension
(_ldim
)
2543 self
.setDimPrefs(image
)
2545 def create(self
, image
):
2546 """Create a new LinearDimension and add it to the image.
2550 This method overrides the Tool::create() method.
2552 _ldim
= self
.getDimension()
2553 if _ldim
is not None:
2554 _pds
= _ldim
.getPrimaryDimstring()
2557 _pds
.setPrefix(image
.getOption('DIM_PRIMARY_PREFIX'))
2558 _pds
.setSuffix(image
.getOption('DIM_PRIMARY_SUFFIX'))
2561 _sds
= _ldim
.getSecondaryDimstring()
2564 _sds
.setPrefix(image
.getOption('DIM_SECONDARY_PREFIX'))
2565 _sds
.setSuffix(image
.getOption('DIM_SECONDARY_SUFFIX'))
2568 _ldim
.calcDimValues()
2569 image
.addObject(_ldim
)
2572 class HorizontalDimensionTool(LinearDimensionTool
):
2573 """A specialized tool for drawing HorizontalDimension objects.
2575 The HorizontalDimensionTool is derived from the LinearDimensionTool
2576 and the Tool classes, so it shares all the attributes and methods of
2579 There are no additional methods for the HorizontalDimension class.
2582 super(HorizontalDimensionTool
, self
).__init
__()
2584 def makeDimension(self
, image
):
2585 """Create a HorizontalDimension based on the stored tool values.
2587 makeDimension(image)
2589 The argument 'image' is an image object where the dimension willbe used.
2591 _p1
= self
.getFirstPoint()
2592 _p2
= self
.getSecondPoint()
2593 _x
, _y
= self
.getDimPosition()
2594 if (_p1
is not None and
2598 _ds
= image
.getOption('DIM_STYLE')
2599 _hdim
= dimension
.HorizontalDimension(_p1
, _p2
, _x
, _y
, _ds
)
2600 self
._setDimension
(_hdim
)
2601 self
.setDimPrefs(image
)
2603 def create(self
, image
):
2604 """Create a new HorizontalDimension and add it to the image.
2608 This method overrides the LinearDimensionTool::create() method.
2610 _hdim
= self
.getDimension()
2611 if _hdim
is not None:
2612 _pds
= _hdim
.getPrimaryDimstring()
2615 _pds
.setPrefix(image
.getOption('DIM_PRIMARY_PREFIX'))
2616 _pds
.setSuffix(image
.getOption('DIM_PRIMARY_SUFFIX'))
2619 _sds
= _hdim
.getSecondaryDimstring()
2622 _sds
.setPrefix(image
.getOption('DIM_SECONDARY_PREFIX'))
2623 _sds
.setSuffix(image
.getOption('DIM_SECONDARY_SUFFIX'))
2626 _hdim
.calcDimValues()
2627 image
.addObject(_hdim
)
2630 class VerticalDimensionTool(LinearDimensionTool
):
2631 """A specialized tool for drawing VerticalDimension objects.
2633 The VerticalalDimensionTool is derived from the LinearDimensionTool
2634 and the Tool classes, so it shares all the attributes and methods of
2637 There are no additional methods for the VerticalalDimension class.
2640 super(VerticalDimensionTool
, self
).__init
__()
2642 def makeDimension(self
, image
):
2643 """Create a VerticalDimension based on the stored tool values.
2645 makeDimension(image)
2647 The argument 'image' is an image object where the dimension will be used.
2649 _p1
= self
.getFirstPoint()
2650 _p2
= self
.getSecondPoint()
2651 _x
, _y
= self
.getDimPosition()
2652 if (_p1
is not None and
2656 _ds
= image
.getOption('DIM_STYLE')
2657 _vdim
= dimension
.VerticalDimension(_p1
, _p2
, _x
, _y
, _ds
)
2658 self
._setDimension
(_vdim
)
2659 self
.setDimPrefs(image
)
2661 def create(self
, image
):
2662 """Create a new VerticalDimension and add it to the image.
2666 This method overrides the LinearDimensionTool::create() method.
2668 _vdim
= self
.getDimension()
2669 if _vdim
is not None:
2670 _pds
= _vdim
.getPrimaryDimstring()
2673 _pds
.setPrefix(image
.getOption('DIM_PRIMARY_PREFIX'))
2674 _pds
.setSuffix(image
.getOption('DIM_PRIMARY_SUFFIX'))
2677 _sds
= _vdim
.getSecondaryDimstring()
2680 _sds
.setPrefix(image
.getOption('DIM_SECONDARY_PREFIX'))
2681 _sds
.setSuffix(image
.getOption('DIM_SECONDARY_SUFFIX'))
2684 _vdim
.calcDimValues()
2685 image
.addObject(_vdim
)
2688 class RadialDimensionTool(DimensionTool
):
2689 """A specialized tool for drawing RadialDimension objects.
2691 The RadialDimensionTool class is derived from the DimensionTool class
2692 and Tool class, so it shares all the attributes and methods of those
2693 classes. The RadialDimensionTool class has the following additional
2696 {set/get}DimObject(): Set/Get the circular object being dimensioned.
2697 {set/get}DimPosition(): Set/Get the location of the dimension text.
2700 super(RadialDimensionTool
, self
).__init
__()
2702 self
.__position
= None
2704 def setDimObject(self
, cobj
):
2705 """Store the Circle or Arc that the RadialDimension will describe.
2709 The argument 'cobj' must be either a Circle or Arc instance.
2711 if not isinstance (cobj
, (Circle
, Arc
)):
2712 raise TypeError, "Invalid Circle or Arc: " + `
type(cobj
)`
2713 if cobj
.getParent() is None:
2714 raise ValueError, "Circle/Arc not found in a Layer."
2717 def getDimObject(self
):
2718 """Return the object the RadialDimension will define.
2722 This method returns a tuple of two objects: the first object
2723 is a Layer, the second object is either a Circle or an Arc
2725 return self
.__cobj
.getParent(), self
.__cobj
2727 def setDimPosition(self
, x
, y
):
2728 """Store the point where the dimension text will be located.
2730 setDimPosition(x, y)
2732 Arguments 'x' and 'y' should be float values.
2734 _x
= util
.get_float(x
)
2735 _y
= util
.get_float(y
)
2736 self
.__position
= (_x
, _y
)
2738 def getDimPosition(self
):
2739 """Retrieve where the dimension text should be placed.
2743 This method returns a tuple containing the x/y coodindates defined
2744 by the setDimPosition() call, or None if that method has not been
2747 return self
.__position
2750 """Restore the tool to its initial state.
2754 This method extends the reset() methods of its base classes.
2756 super(RadialDimensionTool
, self
).reset()
2758 self
.__position
= None
2760 def makeDimension(self
, image
):
2761 """Create a RadialDimension based on the stored tool values.
2763 makeDimension(image)
2765 The argument 'image' is an image object where the dimension will
2769 _x
, _y
= self
.__position
2770 if (_cobj
is not None and
2773 _ds
= image
.getOption('DIM_STYLE')
2774 _rdim
= dimension
.RadialDimension(_cobj
, _x
, _y
, _ds
)
2775 self
._setDimension
(_rdim
)
2776 self
.setDimPrefs(image
)
2778 def create(self
, image
):
2779 """Create a new RadialDimension and add it to the image.
2783 This method overrides the Tool::create() method.
2785 _rdim
= self
.getDimension()
2786 if _rdim
is not None:
2787 _pds
= _rdim
.getPrimaryDimstring()
2790 _pds
.setPrefix(image
.getOption('RADIAL_DIM_PRIMARY_PREFIX'))
2791 _pds
.setSuffix(image
.getOption('RADIAL_DIM_PRIMARY_SUFFIX'))
2794 _sds
= _rdim
.getSecondaryDimstring()
2797 _sds
.setPrefix(image
.getOption('RADIAL_DIM_SECONDARY_PREFIX'))
2798 _sds
.setSuffix(image
.getOption('RADIAL_DIM_SECONDARY_SUFFIX'))
2801 _rdim
.setDiaMode(image
.getOption('RADIAL_DIM_DIA_MODE'))
2802 _rdim
.calcDimValues()
2803 image
.addObject(_rdim
)
2806 class AngularDimensionTool(LinearDimensionTool
):
2807 """A specialized tool for drawing AngularDimension objects.
2809 The AngularDimensionTool class is derived from the LinearDimensionTool
2810 class, so it shares all the attributes and methods of that class. The
2811 AngularDimensionTool class has the following additional methods:
2813 {set/get}VertexPoint(): Set/Get the vertex point used by the dimension
2816 super(AngularDimensionTool
, self
).__init
__()
2819 def setVertexPoint(self
, p
):
2820 """Store the vertex point for the AngularDimension.
2824 The argument 'p' must be a Point instance.
2826 if not isinstance (p
, Point
):
2827 raise TypeError, "Invalid Point: " + `
type(p
)`
2828 if p
.getParent() is None:
2829 raise ValueError, "Point not found in layer."
2832 def getVertexPoint(self
):
2833 """Return the vertex point for the AngularDimension.
2837 This method returns a tuple of two objects: the first object
2838 is a Layer, the second object is a Point.
2844 """Restore the tool to its initial state.
2848 This method extends LinearDimensionTool::reset().
2850 super(AngularDimensionTool
, self
).reset()
2853 def makeDimension(self
, image
):
2854 """Create an AngularDimension based on the stored tool values.
2856 makeDimension(image)
2858 The argument 'image' is an image object where the dimension will be used.
2861 _p1
= self
.getFirstPoint()
2862 _p2
= self
.getSecondPoint()
2863 _x
, _y
= self
.getDimPosition()
2864 if (_vp
is not None and
2869 _ds
= image
.getOption('DIM_STYLE')
2870 _adim
= dimension
.AngularDimension(_vp
, _p1
, _p2
, _x
, _y
, _ds
)
2871 self
._setDimension
(_adim
)
2872 self
.setDimPrefs(image
)
2874 def create(self
, image
):
2875 """Create a new AngularDimension and add it to the image.
2879 This method overrides the Tool::create() method.
2881 _adim
= self
.getDimension()
2882 if _adim
is not None:
2883 _pds
= _adim
.getPrimaryDimstring()
2886 _pds
.setPrefix(image
.getOption('ANGULAR_DIM_PRIMARY_PREFIX'))
2887 _pds
.setSuffix(image
.getOption('ANGULAR_DIM_PRIMARY_SUFFIX'))
2890 _sds
= _adim
.getSecondaryDimstring()
2893 _sds
.setPrefix(image
.getOption('ANGULAR_DIM_SECONDARY_PREFIX'))
2894 _sds
.setSuffix(image
.getOption('ANGULAR_DIM_SECONDARY_SUFFIX'))
2897 _adim
.calcDimValues()
2898 image
.addObject(_adim
)
2902 # printing/plotting tools
2905 class PlotTool(Tool
):
2906 """A tool for defining plot regions
2909 super(PlotTool
, self
).__init
__()
2914 """Restore the tool to its initial state.
2918 This method extends Tool::reset().
2920 super(PlotTool
, self
).reset()
2924 def setFirstCorner(self
, x
, y
):
2925 """Store the first corner of the plot region.
2927 setFirstCorner(x, y)
2929 Arguments 'x' and 'y' should be floats.
2931 _x
= util
.get_float(x
)
2932 _y
= util
.get_float(y
)
2933 self
.__c
1 = (_x
, _y
)
2935 def getFirstCorner(self
):
2936 """Return the first corner of the plot region.
2940 if self
.__c
1 is None:
2941 raise ValueError, "First corner not defined"
2944 def setSecondCorner(self
, x
, y
):
2945 """Store the second corner of the plot region.
2947 setSecondCorner(x, y)
2949 Arguments 'x' and 'y' should be floats.
2951 _x
= util
.get_float(x
)
2952 _y
= util
.get_float(y
)
2953 self
.__c
2 = (_x
, _y
)
2955 def getSecondCorner(self
):
2956 """Return the second corner of the plot region.
2960 if self
.__c
2 is None:
2961 raise ValueError, "Second corner not defined"
2965 # entity modification tools
2968 class RegionTool(Tool
):
2969 """A base class for a tool that can store a defined region.
2971 The RegionTool class is designed to be a base class for tools that
2972 need to store a rectangular region. The RegionTool class is derived
2973 from the Tool class, so it shares all the attributes and methods of
2974 that classs. The RegionTool class has the following additional methods:
2976 {set/get}Region(): Set/Get a stored rectangular region
2979 super(RegionTool
, self
).__init
__()
2980 self
.__region
= None
2982 def setRegion(self
, xmin
, ymin
, xmax
, ymax
):
2983 """Store a rectangular region in the RegionTool.
2985 setRegion(xmin, ymin, xmax, ymax)
2987 xmin: The minimum x-coordinate value
2988 ymin: The minimum y-coordinate value
2989 xmax: The maximum x-coordinate value
2990 ymax: The maximum y-coordinate value
2992 All the arguments should be floats. If xmax < xmin or ymax < ymin
2993 a ValueError exception is raised.
2995 _xmin
= util
.get_float(xmin
)
2996 _ymin
= util
.get_float(ymin
)
2997 _xmax
= util
.get_float(xmax
)
2999 raise ValueError, "Invalid values: xmax < xmin"
3000 _ymax
= util
.get_float(ymax
)
3002 raise ValueError, "Invalid values: ymax < ymin"
3003 self
.__region
= (_xmin
, _ymin
, _xmax
, _ymax
)
3005 def getRegion(self
):
3006 """Retrieve the stored rectangular region in the tool.
3010 This method returns a tuple containing four float values:
3012 (xmin, ymin, xmax, ymax)
3014 return self
.__region
3017 """Restore the tool to its initial state.
3021 This method resets the RegionTool region to None.
3023 super(RegionTool
, self
).reset()
3024 self
.__region
= None
3026 class MoveTool(RegionTool
):
3027 """A specialized class for moving objects.
3029 The MoveTool class is derived from the Tool and RegionTool classes,
3030 so it shares all the attributes and methods of those classes. The
3031 MoveTool class has the following additional methods:
3033 {set/get}Distance(): Set/Get the values to move objects.
3036 super(MoveTool
, self
).__init
__()
3037 self
.__distance
= None
3039 def setDistance(self
, x
, y
):
3040 """Store the distance to move objects in the tool.
3044 Arguments 'x' and 'y' should be floats, and represent the amount
3045 to move objects in the x-coordinate and y-coordinate axes.
3047 _x
= util
.get_float(x
)
3048 _y
= util
.get_float(y
)
3049 self
.__distance
= (_x
, _y
)
3051 def getDistance(self
):
3052 """Get the displacement stored in the tool.
3056 This method returns a tuple containing two float values.
3060 If this method is called before the setDistance() method is
3061 used, a ValueError exception is raised.
3063 if self
.__distance
is None:
3064 raise ValueError, "No distance stored in tool."
3065 return self
.__distance
3068 """Restore the tool to its initial state.
3072 This method extends the reset() method of its base classes
3074 super(MoveTool
, self
).reset()
3075 self
.__distance
= None
3077 class HorizontalMoveTool(MoveTool
):
3078 """A specialized class for moving objects horizontally.
3080 The HorizontalMoveTool is derived from the MoveTool class, so
3081 it shares all the attributes and methods of that class.
3083 There are no additional methods for this class.
3086 super(HorizontalMoveTool
, self
).__init
__()
3088 def setDistance(self
, x
, y
):
3089 """Store the distance to move objects in the tool.
3093 This method extends the MoveTool::setDistance() method by
3094 enforcing a y-axis displacement of 0.0
3096 _x
= util
.get_float(x
)
3097 super(HorizontalMoveTool
, self
).setDistance(_x
, 0.0)
3099 class VerticalMoveTool(MoveTool
):
3100 """A specialized class for moving objects vertically.
3102 The VerticalMoveTool is derived from the MoveTool class, so
3103 it shares all the attributes and methods of that class.
3105 There are no additional methods for this class.
3109 super(VerticalMoveTool
, self
).__init
__()
3111 def setDistance(self
, x
, y
):
3112 """Store the distance to move objects in the tool.
3116 This method extends the MoveTool::setDistance() method by
3117 enforcing an x-axis displacement of 0.0
3119 _y
= util
.get_float(y
)
3120 super(VerticalMoveTool
, self
).setDistance(0.0, _y
)
3122 class StretchTool(MoveTool
):
3123 """A specialized class for stretching objects
3125 The StretchTool class is derived from the MoveTool class, so
3126 it shares all the attributes and methods of that class.
3128 There are no additional methods for this class.
3131 super(StretchTool
, self
).__init
__()
3133 class HorizontalStretchTool(HorizontalMoveTool
):
3134 """A specialized class for stretching objects horizontally.
3136 The HorizontalStretchTool class is derived from the HorizontalMoveTool
3137 class, so it shares all the attributes and methods of that class.
3139 There are no additional methods for this class.
3142 super(HorizontalStretchTool
, self
).__init
__()
3144 class VerticalStretchTool(VerticalMoveTool
):
3145 """A specialized class for stretching objects horizontally.
3147 The VerticalStretchTool class is derived from the VerticalMoveTool
3148 class, so it shares all the attributes and methods of that class.
3150 There are no additional methods for this class.
3153 super(VerticalStretchTool
, self
).__init
__()
3155 class DeleteTool(RegionTool
):
3156 """A specialized class for deleting objects.
3158 The DeleteTool class is derived from the Tool and RegionTool classes,
3159 so it shares all the attributes and methods of those classes.
3161 There are no additional methods for this class.
3164 super(DeleteTool
, self
).__init
__()
3166 class SplitTool(RegionTool
):
3167 """A specialized class for splitting objects.
3169 The SplitTool class is derived from the Tool and RegionTool classes,
3170 so it shares all the attributes and methods of those classes.
3172 There are no additional methods for this class.
3175 super(SplitTool
, self
).__init
__()
3177 class MirrorTool(RegionTool
):
3178 """A specialized class for mirroring objects.
3180 The MirrorTool class is derived from the Tool and RegionTool classes,
3181 so it shares all the attributes and methods of those classes. The
3182 MirrorTool class has the following additional methods:
3184 {set/get}MirrorLine(): Set/Get the construction line used for mirroring
3187 super(MirrorTool
, self
).__init
__()
3188 self
.__mirrorline
= None
3190 def setMirrorLine(self
, mline
):
3191 """Store the mirroring construction line in the tool.
3193 setMirrorLine(mline)
3195 The argument 'mline' must be a construction line, otherwise
3196 a TypeError exception is raised.
3198 if not isinstance(mline
, (HCLine
, VCLine
, ACLine
, CLine
)):
3199 raise TypeError, "Invalid mirroring line type: " + `
type(mline
)`
3200 self
.__mirrorline
= mline
3202 def getMirrorLine(self
):
3203 """Retrieve the mirroring construction line from the tool.
3207 If the mirroring construction line has not been set, a ValueError
3208 exception is raised.
3210 if self
.__mirrorline
is None:
3211 raise ValueError, "No mirror line set."
3212 return self
.__mirrorline
3215 """Restore the tool to its initial state.
3219 This method extends the RegionTool::reset() method.
3221 super(MirrorTool
, self
).reset()
3222 self
.__mirrorline
= None
3225 # The TransferTool class is a subclass of the RegionTool
3226 # with no additional functionality (yet)
3229 class TransferTool(RegionTool
):
3232 class RotateTool(RegionTool
):
3233 """A specialized class for rotating objects.
3235 The RotateTool class is derived from the Tool and RegionTool classes,
3236 so it shares all the attributes and methods of those classes. The
3237 Rotateool class has the following additional methods:
3239 {set/get}RotationPoint(): Set/Get the point objects are rotated around
3240 {set/get}Angle(): Set/Get the angle of rotation
3243 super(RotateTool
, self
).__init
__()
3247 def setRotationPoint(self
, x
, y
):
3248 """Set the coordinates the entities will rotate around
3250 setRotationPoint(x, y)
3252 Arguments 'x' and 'y' should be floats
3254 _x
= util
.get_float(x
)
3255 _y
= util
.get_float(y
)
3256 self
.__rp
= (_x
, _y
)
3258 def getRotationPoint(self
):
3259 """Get the point objects will rotate around
3263 This method returns a tuple of two floats or None if the rotation
3264 point has not be defined with setRotationPoint()
3268 def setAngle(self
, angle
):
3269 """Set the angle of rotation.
3273 Argument 'angle' should be a float value. The value is normalized
3274 so that abs(angle) < 360.0.
3276 _a
= util
.get_float(angle
)
3277 self
.__angle
= math
.fmod(_a
, 360.0)
3280 """Get the angle of rotation.
3284 This method returns a float or None if the angle has not been
3290 """Restore the tool to its initial state.
3294 This method extends Tool::reset().
3296 super(RotateTool
, self
).reset()
3300 class GraphicObjectTool(RegionTool
):
3301 """A specialized class for changing attributes of GraphicObject instances.
3303 The GraphicObjectTool class is derived from the RegionTool class,
3304 so it shares all the attributes and methods of that class. The
3305 GraphicObjectTool class has the following additional methods:
3307 {set/get}Attribute(): Set/Get the desired attribute
3308 {set/get}Value(): Set/Get the new entity color.
3311 super(RegionTool
, self
).__init
__()
3315 def setAttribute(self
, attr
):
3316 """Define which attribute the tool is modifying.
3320 Argument 'attr' should be either 'setStyle', 'setLinetype', 'setColor',
3323 if not isinstance(attr
, str):
3324 raise TypeError, "Invalid attribute type: " + `
type(attr
)`
3325 if attr
not in ('setStyle', 'setLinetype', 'setColor', 'setThickness'):
3326 raise ValueError, "Invalid attribute: " + attr
3329 def getAttribute(self
):
3330 """Return the specified attribute.
3334 If called before invoking setAttribute(), this method raises a ValueError.
3336 if self
.__attr
is None:
3337 raise ValueError, "Tool attribute not defined."
3340 def setValue(self
, val
):
3341 """Store the new value of the entity attribute.
3345 Argument 'val' depends on the type of attribute defined for the
3346 tool. If no attribute is defined this method raises a ValueError.
3347 Invoking this method with 'None' as an argument sets the tool
3348 to restore the default attribute value.
3350 if self
.__attr
is None:
3351 raise ValueError, "Tool attribute not defined."
3355 if _a
== 'setStyle':
3356 if not isinstance(val
, style
.Style
):
3357 raise TypeError, "Invalid Style: " + `
type(val
)`
3359 elif _a
== 'setLinetype':
3360 if not isinstance(val
, linetype
.Linetype
):
3361 raise TypeError, "Invalid Linetype: " + `
type(val
)`
3363 elif _a
== 'setColor':
3364 if not isinstance(val
, color
.Color
):
3365 raise TypeError, "Invalid Color: " + `
type(val
)`
3367 elif _a
== 'setThickness':
3368 _val
= util
.get_float(val
)
3370 raise ValueError, "Invalid thickness: %g" % _val
3372 raise ValueError, "Unexpected attribute: " + _a
3376 """Get the stored attribute value.
3380 This method returns the value stored in setValue() or None.
3388 class ChangeStyleTool(GraphicObjectTool
):
3391 class ChangeLinetypeTool(GraphicObjectTool
):
3394 class ChangeColorTool(GraphicObjectTool
):
3397 class ChangeThicknessTool(GraphicObjectTool
):
3400 class TextTool(RegionTool
):
3401 """A specialized class for entering text.
3403 The TextTool class is derived from the Tool class, so it shares
3404 the attributes and methods of that class. The TextTool class also
3405 has the following additional methods:
3407 {set/get}Text(): Set/Get the text string in the tool.
3408 hasText(): Test if the tool has stored a text string
3409 {set/get}TextLocation(): Set/Get where the text is to be placed.
3410 {set/get}TextBlock(): Set/Get a TextBlock instance in the Tool
3411 {set/get}Bounds(): Set/Get the width and height of the text
3412 {set/get}PixelSize(): Set/Get the a rectangular region bounding the text.
3413 {set/get}Layout(): Set/Get the formatted text string display.
3414 {set/get/test}Attribute(): Set/Get/Test a TextBlock attribute
3415 {set/get}Value(): Set/Get the attribute value.
3418 super(TextTool
, self
).__init
__()
3420 self
.__location
= None
3421 self
.__tblock
= None
3424 self
.__bounds
= None
3425 self
.__pixel
_size
= None
3426 self
.__layout
= None
3428 def setText(self
, text
):
3429 """Store some text in the tool.
3433 The argument 'text' should be a unicode object.
3436 if not isinstance(_text
, unicode):
3437 _text
= unicode(text
)
3441 """Retrieve the stored text from the TextTool.
3445 If no text has been stored, this method raises a ValueError exception.
3447 if self
.__text
is None:
3448 raise ValueError, "No text stored in TextTool."
3452 """Test if the tool has stored a text string.
3456 return self
.__text
is not None
3458 def setTextLocation(self
, x
, y
):
3459 """Store the location where the text will be placed.
3461 setTextLocation(x, y)
3463 The arguments 'x' and 'y' should be float values.
3465 _x
, _y
= util
.make_coords(x
, y
)
3466 self
.__location
= (_x
, _y
)
3468 def getTextLocation(self
):
3469 """Retrieve the location where the text will be placed.
3473 This method returns a tuple holding two floats:
3478 A ValueError exception is raised if this method is called prior to
3479 setting the text location with setTextLocation().
3481 if self
.__location
is None:
3482 raise ValueError, "No text location defined."
3483 return self
.__location
3485 def testAttribute(self
, attr
):
3486 """Test that the given attribute is valid.
3490 Argument 'attr' should be one of the following: 'setAngle',
3491 'setAlignment', 'setFamily', 'setStyle', 'setWeight', 'setColor',
3494 if not isinstance(attr
, str):
3495 raise TypeError, "Invalid attribute type: " + `
type(attr
)`
3496 return attr
in ('setAngle', 'setAlignment', 'setFamily',
3497 'setStyle', 'setWeight', 'setColor', 'setSize')
3499 def setAttribute(self
, attr
):
3500 """Define which attribute the tool is modifying.
3504 Argument 'attr' should be one of the following: 'setAngle',
3505 'setAlignment', 'setFamily', 'setStyle', 'setWeight', 'setColor',
3508 if not self
.testAttribute(attr
):
3509 raise ValueError, "Invalid attribute: " + attr
3512 def getAttribute(self
):
3513 """Return the specified attribute.
3517 If called before invoking setAttribute(), this method raises a ValueError.
3519 if self
.__attr
is None:
3520 raise ValueError, "Tool attribute not defined."
3523 def testValue(self
, val
):
3524 """Test that the given value is valid for the preset attribute.
3528 Argument 'val' depends on what attribute has been set with via setAttribute().
3531 if _a
== 'setAngle':
3532 _val
= util
.getFloat(val
)
3533 elif _a
== 'setAlignment':
3534 if not isinstance(val
, int):
3535 raise TypeError, "Invalid alignment type: " + `
type(val
)`
3536 if (val
!= TextStyle
.ALIGN_LEFT
and
3537 val
!= TextStyle
.ALIGN_CENTER
and
3538 val
!= TextStyle
.ALIGN_RIGHT
):
3539 raise ValueError, "Invalid alignment value: %d" % val
3541 elif _a
== 'setColor':
3542 if not isinstance(val
, color
.Color
):
3543 raise TypeError, "Invalid Color: " + `
type(val
)`
3545 elif _a
== 'setFamily':
3546 if not isinstance(val
, types
.StringTypes
):
3547 raise TypeError, "Invalid family type: " + `
type(val
)`
3549 elif _a
== 'setStyle':
3550 if not isinstance(val
, int):
3551 raise TypeError, "Invalid style type: " + `
type(val
)`
3552 if (val
!= TextStyle
.FONT_NORMAL
and
3553 val
!= TextStyle
.FONT_OBLIQUE
and
3554 val
!= TextStyle
.FONT_ITALIC
):
3555 raise ValueError, "Invalid style value: %d" % val
3557 elif _a
== 'setWeight':
3558 if not isinstance(val
, int):
3559 raise TypeError, "Invalid weight type: " + `
type(val
)`
3560 if (val
!= TextStyle
.WEIGHT_NORMAL
and
3561 val
!= TextStyle
.WEIGHT_LIGHT
and
3562 val
!= TextStyle
.WEIGHT_BOLD
and
3563 val
!= TextStyle
.WEIGHT_HEAVY
):
3564 raise ValueError, "Invalid weight value: %d" % val
3566 elif _a
== 'setSize':
3567 _val
= util
.get_float(val
)
3569 raise ValueError, "Invalid size: %g" % _val
3571 raise ValueError, "Unexpected attribute: " + _a
3574 def setValue(self
, val
):
3575 """Store the new value of the entity attribute.
3579 Argument 'val' depends on the type of attribute defined for the
3580 tool. If no attribute is defined this method raises a ValueError.
3581 Invoking this method with 'None' as an argument sets the tool
3582 to restore the default attribute value.
3584 if self
.__attr
is None:
3585 raise ValueError, "Tool attribute not defined."
3588 _val
= self
.testValue(val
)
3592 """Get the stored attribute value.
3596 This method returns the value stored in setValue() or None.
3600 def getBounds(self
):
3601 """Return the width and height of the TextBlock.
3605 if self
.__bounds
is None:
3606 raise ValueError, "TextBlock bounds not defined."
3607 return self
.__bounds
3609 def setBounds(self
, width
, height
):
3610 """Set the width and height of the TextBlock.
3612 setBounds(width, height):
3614 Arguments 'width' and 'height' should be positive float values.
3616 _w
= util
.get_float(width
)
3618 raise ValueError, "Invalid width: %g" % _w
3619 _h
= util
.get_float(height
)
3621 raise ValueError, "Invalid height: %g" % _h
3622 self
.__bounds
= (_w
, _h
)
3624 def setPixelSize(self
, width
, height
):
3625 """Store a screen-size rectangular boundary for the text.
3627 setPixelSize(width, height)
3629 Arguments 'width' and 'height' should be positive integer values.
3631 This method is somewhat GTK specific ...
3634 if not isinstance(_width
, int):
3637 raise ValueError, "Invalid width: %d" % _width
3639 if not isinstance(_height
, int):
3640 _height
= int(height
)
3642 raise ValueError, "Invalid height: %d" % _height
3643 self
.__pixel
_size
= (_width
, _height
)
3645 def getPixelSize(self
):
3646 """Retrieve the stored rectangular region of text.
3650 A ValueError exception is raised if this method is called before
3651 the size has been set by setPixelSize()
3653 if self
.__pixel
_size
is None:
3654 raise ValueError, "Pixel size is not defined."
3655 return self
.__pixel
_size
3657 def setLayout(self
, layout
):
3658 """Store a formatted layout string for the text.
3662 This method is very GTK/Pango specific ...
3664 self
.__layout
= layout
3666 def getLayout(self
):
3667 """Retrieve the formatted layout for the text string.
3671 This method is very GTK/Pango specific ...
3673 return self
.__layout
3675 def setTextBlock(self
, tblock
):
3676 """Store a TextBlock instance within the Tool.
3678 setTextBlock(tblock)
3680 Argument 'tblock' must be a TextBlock.
3682 if not isinstance(tblock
, TextBlock
):
3683 raise TypeError, "Invalid TextBlock: " + `
type(tblock
)`
3684 self
.__tblock
= tblock
3686 def getTextBlock(self
):
3687 """Retrieve a stored TextBlock within the Tool.
3691 This method may return None if no TextBlock has been stored
3694 return self
.__tblock
3696 def create(self
, image
):
3697 """Create a new TextBlock and add it to the image.
3701 This method overrides the Tool::create() method.
3705 _text
= self
.getText()
3706 _x
, _y
= self
.getTextLocation()
3707 _ts
= image
.getOption('TEXT_STYLE')
3708 _tb
= TextBlock(_x
, _y
, _text
, _ts
)
3709 _f
= image
.getOption('FONT_FAMILY')
3710 if _f
!= _ts
.getFamily():
3712 _s
= image
.getOption('FONT_STYLE')
3713 if _s
!= _ts
.getStyle():
3715 _w
= image
.getOption('FONT_WEIGHT')
3716 if _w
!= _ts
.getWeight():
3718 _c
= image
.getOption('FONT_COLOR')
3719 if _c
!= _ts
.getColor():
3721 _sz
= image
.getOption('TEXT_SIZE')
3722 if abs(_sz
- _ts
.getSize()) > 1e-10:
3724 _a
= image
.getOption('TEXT_ANGLE')
3725 if abs(_a
- _ts
.getAngle()) > 1e-10:
3727 _al
= image
.getOption('TEXT_ALIGNMENT')
3728 if _al
!= _ts
.getAlignment():
3729 _tb
.setAlignment(_al
)
3730 image
.addObject(_tb
)
3734 """Restore the tool to its initial state.
3738 This method extends Tool::reset().
3740 super(TextTool
, self
).reset()
3742 self
.__location
= None
3743 self
.__tblock
= None
3744 self
.__bounds
= None
3745 self
.__pixel
_size
= None
3746 self
.__layout
= None
3748 class EditDimensionTool(RegionTool
):
3749 """A specialized class for changing attributes of Dimension instances.
3751 The EditDimensionTool class is derived from the RegionTool class,
3752 so it shares all the attributes and methods of that class. The
3753 EditDimensionTool class has the following additional methods:
3755 {set/get}Attribute(): Set/Get the desired attribute
3756 {set/get}Value(): Set/Get the new entity color.
3759 super(RegionTool
, self
).__init
__()
3763 def setAttribute(self
, attr
):
3764 """Define which attribute the tool is modifying.
3768 Argument 'attr' should be one of the following:
3770 'setEndpointType', 'setEndpointSize', 'setDualDimMode', 'setDualModeOffset',
3771 'setOffset', 'setExtension', 'setColor', 'setThickness', 'setScale'
3773 if not isinstance(attr
, str):
3774 raise TypeError, "Invalid attribute type: " + `
type(attr
)`
3775 if attr
not in ('setEndpointType', 'setEndpointSize',
3776 'setDualDimMode', 'setDualModeOffset',
3777 'setOffset', 'setExtension', 'setColor',
3778 'setThickness', 'setScale'):
3779 raise ValueError, "Invalid attribute: " + attr
3782 def getAttribute(self
):
3783 """Return the specified attribute.
3787 If called before invoking setAttribute(), this method raises a ValueError.
3789 if self
.__attr
is None:
3790 raise ValueError, "Tool attribute not defined."
3793 def setValue(self
, val
):
3794 """Store the new value of the entity attribute.
3798 Argument 'val' depends on the type of attribute defined for the
3799 tool. If no attribute is defined this method raises a ValueError.
3800 Invoking this method with 'None' as an argument sets the tool
3801 to restore the default attribute value.
3803 if self
.__attr
is None:
3804 raise ValueError, "Tool attribute not defined."
3808 if _a
== 'setEndpointType':
3809 if (val
!= dimension
.Dimension
.DIM_ENDPT_NONE
and
3810 val
!= dimension
.Dimension
.DIM_ENDPT_ARROW
and
3811 val
!= dimension
.Dimension
.DIM_ENDPT_FILLED_ARROW
and
3812 val
!= dimension
.Dimension
.DIM_ENDPT_SLASH
and
3813 val
!= dimension
.Dimension
.DIM_ENDPT_CIRCLE
):
3814 raise ValueError, "Invalid endpoint value: " + str(val
)
3816 elif _a
== 'setEndpointSize':
3817 _val
= util
.get_float(val
)
3819 raise ValueError, "Invalid endpoint size: %g" % _val
3821 elif _a
== 'setDualDimMode':
3822 util
.test_boolean(val
)
3824 elif _a
== 'setDualModeOffset':
3825 _val
= util
.get_float(val
)
3827 raise ValueError, "Invalid offset length: %g" % _val
3829 elif _a
== 'setOffset':
3830 _val
= util
.get_float(val
)
3832 raise ValueError, "Invalid offset length: %g" % _val
3834 elif _a
== 'setExtension':
3835 _val
= util
.get_float(val
)
3837 raise ValueError, "Invalid extension length: %g" % _val
3839 elif _a
== 'setColor':
3840 if not isinstance(val
, color
.Color
):
3841 raise TypeError, "Invalid Color: " + `
type(val
)`
3843 elif _a
== 'setThickness':
3844 _val
= util
.get_float(val
)
3846 raise ValueError, "Invalid thickness: %g" % _val
3847 elif _a
== 'setScale':
3848 _val
= util
.get_float(val
)
3850 raise ValueError, "Invalid scale: %g" % _val
3852 raise ValueError, "Unexpected attribute: " + _a
3856 """Get the stored attribute value.
3860 This method returns the value stored in setValue() or None.
3864 class EditDimStringTool(TextTool
):
3865 """A specialized class for modifying DimString instances in Dimensions.
3867 The EditDimStringTool class is derived from the TextTool class, so it
3868 shares the attributes and methods of that class. The TextTool class has
3869 the following additional methods:
3871 {set/get}Primary(): Set/Get the DimString on which the tool operates.
3874 super(EditDimStringTool
, self
).__init
__()
3877 def setPrimary(self
, flag
=True):
3878 """Set the tool to operate on the primary DimString
3882 Optional argument 'flag' should be a boolean. By default the
3883 tool will operate on the primary DimString of a Dimension. If
3884 argument 'flag' is False, the tool will operate on the secondary
3887 util
.test_boolean(flag
)
3890 def getPrimary(self
):
3891 """Test if the tool operates on the primary DimString
3895 This method returns a boolean
3899 def testAttribute(self
, attr
):
3900 """Test that the attribute is valid for the DimString entity.
3904 Argument 'attr' must be one of the following: 'setPrefix', 'setSuffix',
3905 'setUnits', 'setPrecision', 'setPrintZero', 'setPringDecimal', 'setFamily',
3906 'setStyle', 'setWeight', 'setSize', 'setAlignment', 'setColor', or
3909 if not isinstance(attr
, str):
3910 raise TypeError, "Invalid attribute type: " + `
type(attr
)`
3911 _res
= attr
in ('setPrefix', 'setSuffix', 'setUnits', 'setPrecision',
3912 'setPrintZero', 'setPrintDecimal')
3915 return super(EditDimStringTool
, self
).testAttribute(attr
)
3917 def testValue(self
, val
):
3918 """Test that the value is valid for a given DimString attribute.
3922 Argument 'val' depends on the attribute set for the EditDimString instance.
3924 _a
= self
.getAttribute()
3925 if _a
== 'setPrefix' or _a
== 'setSuffix':
3926 if not isinstance(val
, types
.StringTypes
):
3927 raise TypeError, "Invalid %s type: %s " % (_a
, `
type(val
)`
)
3929 if not isinstance(_val
, unicode):
3931 elif _a
== 'setPrecision':
3932 if not isinstance(val
, int):
3933 raise TypeError, "Invalid precision type: " + `
type(val
)`
3935 elif _a
== 'setPrintZero' or _a
== 'setPrintDecimal':
3937 util
.test_boolean(val
)
3939 raise TypeError, "Invalid %s type: %s " % (_a
, `
type(val
)`
)
3941 elif _a
== 'setUnits':
3942 _val
= val
# FIXME: needs error checking ...
3944 _val
= super(EditDimStringTool
, self
).testValue(val
)
3947 def setText(self
, txt
):
3956 def setTextLocation(self
, x
, y
):
3959 def getTextLocation(self
):
3962 def setBounds(self
, width
, height
):
3965 def getBounds(self
):
3968 def setPixelSize(self
, width
, height
):
3971 def getPixelSize(self
):
3974 def setLayout(self
, layout
):
3977 def getLayout(self
):