PythonCAD-DS1-R37/0000755000175000017500000000000011307677001013153 5ustar matteomatteoPythonCAD-DS1-R37/PKG-INFO0000644000175000017500000000040111307677001014243 0ustar matteomatteoMetadata-Version: 1.0 Name: PythonCAD Version: DS1-R37 Summary: CAD built from Python Home-page: http://www.pythoncad.org/ Author: Art Haas,Matteo Boscolo Author-email: ahaas@airmail.net,Euro_ii@libero.it License: GPL Description: UNKNOWN Platform: UNKNOWN PythonCAD-DS1-R37/INSTALL0000644000175000017500000000317011307666657014224 0ustar matteomatteoInstallation ============ The installation of PythonCAD is a two-step process. First, execute the setup.py script $ python setup.py install This command will install the files in the "Generic" and "Interface" directories into the Python library directory. You may need to be root to do this on your machine. Next, copy the file "gtkpycad.py" into one of the directories in your PATH. Commonly this will be "/usr/local/bin", or "/usr/bin". At this point you should be able to invoke the gtkpycad.py file at a prompt: $ gtkpycad.py After a few seconds, the application should start. Work has begun on making PythonCAD offer native language support. Translation files are in the 'po/' subdirectory. The '.po' file needs to be converted to a '.mo' file, a job for the 'msgfmt' program. Once the '.mo' file has been generated, it should be copied into the appropriate 'locale' directory for your system and the user environment adjusted to access the correct locale. For the time being the installation of these files requires much manual work; as more translations appear it is hoped the installation of the '.mo' files will become more automated. Problems ======== If something doesn't work, there are a couple of things to check. For the sake of a few examples, pretend that the python installation is in "/usr" and Python-2.2.X is installed, so the site-packages directory is "/usr/lib/python2.2/site-packages", and the python binary is "/usr/bin/python". Also pretend that the "gtkpycad.py" file is copied into "/usr/bin". Does "/usr/bin/gtkpycad.py" have the execute bits set? If not, do a "chmod a+x /usr/bin/gtkpycad.py" to set these bits. PythonCAD-DS1-R37/gtkpycad.py0000755000175000017500000002331111307666732015347 0ustar matteomatteo#!/usr/bin/env python # # Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # main routine to start GTK-based pycad # import getopt import sys import os import pygtk pygtk.require('2.0') import gtk import gettext gettext.install('PythonCAD') from PythonCAD.Generic import globals from PythonCAD.Generic import imageio from PythonCAD.Generic import fileio from PythonCAD.Generic import selections from PythonCAD.Generic import preferences from PythonCAD.Generic import color from PythonCAD.Generic import linetype from PythonCAD.Generic import style from PythonCAD.Generic import segment from PythonCAD.Generic import circle from PythonCAD.Generic import arc from PythonCAD.Generic import leader from PythonCAD.Generic import polyline from PythonCAD.Generic import segjoint from PythonCAD.Generic import conobject from PythonCAD.Generic import baseobject from PythonCAD.Generic import graphicobject from PythonCAD.Generic import dimension from PythonCAD.Generic import text from PythonCAD.Generic import units from PythonCAD.Interface.Gtk import gtkinit def _initialize_booleans(): globals.prefs['HIGHLIGHT_POINTS'] = True globals.prefs['AUTOSPLIT'] = False def _initialize_sizes(): globals.prefs['CHAMFER_LENGTH'] = 1.0 globals.prefs['FILLET_RADIUS'] = 1.0 globals.prefs['FILLET_TWO_TRIM_MODE'] = 'b' globals.prefs['UNITS'] = units.MILLIMETERS globals.prefs['LEADER_ARROW_SIZE'] = 1.0 def _initialize_image_colors(): _color = color.get_color(80, 140, 210) # blueish/purpleish globals.prefs['INACTIVE_LAYER_COLOR'] = _color _color = color.get_color(0, 0, 0) # black globals.prefs['BACKGROUND_COLOR'] = _color _color = color.get_color(255, 255, 0) # yellow globals.prefs['SINGLE_POINT_COLOR'] = _color _color = color.get_color(0, 255, 255) # cyan globals.prefs['MULTI_POINT_COLOR'] = _color def _initialize_styles(): _style = graphicobject.GraphicObject.getDefaultStyle() globals.prefs['LINE_STYLE'] = _style globals.prefs['LINE_COLOR'] = _style.getColor() globals.prefs['LINE_TYPE'] = _style.getLinetype() globals.prefs['LINE_THICKNESS'] = _style.getThickness() # # set this style as the class default for the "real" drawing entities # segment.Segment.setDefaultStyle(_style) circle.Circle.setDefaultStyle(_style) arc.Arc.setDefaultStyle(_style) leader.Leader.setDefaultStyle(_style) polyline.Polyline.setDefaultStyle(_style) segjoint.SegJoint.setDefaultStyle(_style) segjoint.Chamfer.setDefaultStyle(_style) segjoint.Fillet.setDefaultStyle(_style) # # define and set a construction line style # _color = color.get_color(0xff, 0, 0) # red _lt = linetype.Linetype(u'Construction Lines', [2, 2]) _style = style.Style(u'Construction Objects', _lt, _color, 0.0) conobject.ConstructionObject.setDefaultStyle(_style) # # define and add the default text style and use values in the # text style to define various global key/value pairs # _ts = text.TextBlock.getDefaultTextStyle() globals.prefs['TEXT_STYLE'] = _ts globals.prefs['FONT_COLOR'] = _ts.getColor() globals.prefs['FONT_WEIGHT'] = _ts.getWeight() globals.prefs['FONT_STYLE'] = _ts.getStyle() globals.prefs['FONT_FAMILY'] = _ts.getFamily() globals.prefs['TEXT_SIZE'] = _ts.getSize() globals.prefs['TEXT_ANGLE'] = _ts.getAngle() globals.prefs['TEXT_ALIGNMENT'] = _ts.getAlignment() # # define and add the default dimension style and use the # values in that style to define various global preference # key/value pairs # _ds = dimension.Dimension.getDefaultDimStyle() globals.dimstyles.append(_ds) globals.prefs['DIM_STYLE'] = _ds for _key in _ds.getOptions(): _value = _ds.getOption(_key) globals.prefs[_key] = _value def _initialize_linetypes(): _lt = linetype.Linetype(u'Solid') # solid globals.linetypes[_lt] = _lt _lt = linetype.Linetype(u'Dash1', [4, 1]) # dashed line globals.linetypes[_lt] = _lt _lt = linetype.Linetype(u'Dash2', [8, 2]) # dashed line globals.linetypes[_lt] = _lt _lt = linetype.Linetype(u'Dash3', [12, 2]) # dashed line globals.linetypes[_lt] = _lt _lt = linetype.Linetype(u'Dash4', [10, 2, 2, 2]) # dashed line globals.linetypes[_lt] = _lt _lt = linetype.Linetype(u'Dash5', [15, 5, 5, 5]) # dashed line globals.linetypes[_lt] = _lt def _initialize_colors(): _color = color.Color(255, 0, 0) # red globals.colors[_color] = _color _color = color.Color(0, 255, 0) # green globals.colors[_color] = _color _color = color.Color(0, 0, 255) # blue globals.colors[_color] = _color _color = color.Color(255, 0, 255) # violet globals.colors[_color] = _color _color = color.Color(255, 255, 0) # yellow globals.colors[_color] = _color _color = color.Color(0, 255, 255) # cyan globals.colors[_color] = _color _color = color.Color(255, 255, 255) # white globals.colors[_color] = _color _color = color.Color(0, 0, 0) # black globals.colors[_color] = _color def _inizialize_snap(): """ Inizialize Global Snap Erray """ globals.snapOption={'mid':True,'point':True,'end':True,'intersection':True, 'origin':False,'perpendicular':False,'tangent':False,'center':True} def _initialize_globals(): # # define globals # globals.imagelist = [] globals.prefs = {} globals.colors = baseobject.TypedDict(color.Color, color.Color) globals.linetypes = baseobject.TypedDict(linetype.Linetype, linetype.Linetype) globals.dimstyles = [] globals.selectobj = selections.Selection() _initialize_colors() _initialize_linetypes() _initialize_styles() _initialize_image_colors() _initialize_sizes() _initialize_booleans() _inizialize_snap() def main(): try: opts, args = getopt.getopt(sys.argv[1:], "hv", ["help", "version"]) except getopt.GetoptError, e: sys.stderr.write("Error: %s\n" % e) sys.exit(1) for o, a in opts: if o in ("-h", "--help"): sys.stdout.write("No help yet! Sorry ...\n") sys.exit() if o in ("-v", "--version"): sys.stdout.write("PythonCAD - DS1 - Release 37 Alfa \n") sys.exit() # # add graphic methods to classes # gtkinit.add_graphic_methods() # # load up global and user preferences # _initialize_globals() preferences.initialize_prefs() preferences.load_global_prefs() _user_flag = globals.prefs['USER_PREFS'] if _user_flag: preferences.load_user_prefs() # # open any drawings passed as arguments. This code needs # to be much more robust ... # assert 'BACKGROUND_COLOR' in globals.prefs, "BACKGROUND_COLOR missing" _background = globals.prefs['BACKGROUND_COLOR'] from PythonCAD.Interface.Gtk.gtkimage import GTKImage from PythonCAD.Generic.image import Image, ImageLog for _arg in args: if os.path.exists(_arg): sys.stdout.write("Opening '%s'\n" % _arg) try: _imfile = fileio.CompFile(_arg, "r") except IOError, _e: sys.stderr.write("Can't open '%s'! %s" % (_arg, _e)) continue _image = Image() try: try: imageio.load_image(_image, _imfile) finally: _imfile.close() _log = ImageLog(_image) _image.setLog(_log) _fname = os.path.realpath(_arg) _image.setFilename(_fname) _gtkimage = GTKImage(_image) _window = _gtkimage.getWindow() _window.set_title(os.path.basename(_fname)) globals.imagelist.append(_image) if _image.getOption('BACKGROUND_COLOR') == _background: _image.setOption('BACKGROUND_COLOR', _background) _window.show_all() _gtkimage.fitImage() except StandardError, _e: sys.stderr.write("Failed loading '%s'! %s" % (_arg, _e)) else: sys.stderr.write("Can't find file '%s' - Skipping ...\n" % _arg) if not len(globals.imagelist): _image = Image() _gtkimage = GTKImage(_image) _log = ImageLog(_image) _image.setLog(_log) globals.imagelist.append(_image) _image.setOption('BACKGROUND_COLOR', _background) _gtkimage.window.show_all() gtk.main() if __name__ == '__main__': _major, _minor, _micro = gtk.pygtk_version if ((_major < 2) and (_minor < 100) and # (_micro < 16)): print """ The PyGTK version you are using needs to be upgraded to a newer version. Changes in the PyGTK code have required the addition of some compatibility code in PythonCAD, but these changes are temporary and will be removed in a future PythonCAD release. Please upgrade your PyGTK module to version 1.99.16 (at least), or retrieve and build the PyGTK module from the CVS archive. """ main() PythonCAD-DS1-R37/gtkpycad.png0000644000175000017500000000110011307666732015470 0ustar matteomatteoPNG  IHDR00WsRGBbKGD pHYs  ~tIMEp*tOIDATh혱N0ҔcPG5Xydx@1;p!4?K;˝D"H$ju+Vb}UNHJXXg$#ªdζjɼם,j">,|%ȷ甸~& /b(qswOR, "(UI]; vzݦ EI1QxD:K$3+A2U}\Jh|g84+jmjϑ|UuN<9;h.CeV0Ok + ϠbEe\2Nq8]@g-GdI[EÌ6yl]Jmm/ p9 D.tNϱs'F,Mayfu.+YwOt H$Oϓ˫xdOIENDB`PythonCAD-DS1-R37/README0000644000175000017500000000724311307666657014060 0ustar matteomatteoIntroduction ============ PythonCAD is an open-source CAD package built designed around Python. As such, it aims to be a fully scriptable and customizable CAD program. It is initially designed to run under Linux, one of the BSD flavors, or Unix. Using an established, powerful, and expressive language like Python as the core of the program saves an enormous amount of work for developers and, for users who are already familiar with Python, you don't have to try and learn a new language if you want to extend or customize the code. If you've never written Python code before, there are extensive resources available for you. A good place to start is at the Python home page ... http://www.python.org Goals ===== The primary design goal is to provide a good CAD package. The open-source world has been moving steadily from providing superior tools for proprietary systems (i.e. GCC), to world-class operating systems (i.e. Linux), and has advanced remarkably in providing complete desktop environments (GNOME and KDE). It is hoped that PythonCAD will grow to be an excellent addition to the desktop programs now available for users of open-source software. A design goal with the program code is to keep the user interface completely separated from the back end or generic code. In doing so, it should be possible for developers to write code porting PythonCAD to their chosen interface with less work. The initial release is written using GTK-2.0 as the interface (utilizing the PyGTK library). The addition of a front end utilizing the Py-Objc bindings on Mac OS X and Cocoa demonstrates that this approach of separating the interface from the core program is a viable approach of application design. It is hoped that interfaces for GNOME, QT, KDE, and other packages will eventually be added to PythonCAD. A second code design goal is to write a powerful graphical program without writing much, if any, C or C++ code. The Python language frees the programmer from many of the difficulties that are associated with C (memory allocation, buffer handling, etc.) or C++ code (i.e. compiler and platform issues). No language is perfect, but it is hoped that PythonCAD can demonstrate that choosing Python as the primary language for development provides good performance, ease of maintenance, and a fun language to work with. Requirements ============ Python: Version 2.2 at a minimum, with the zlib module. At the time of the thirtieth release the final 2.2 based release is 2.2.3, the (final?) 2.3 release is 2.3.5, and the latest 2.4 release is 2.4.2. PythonCAD should run without problem in any of the releases. There are as yet no plans to raise the minimum Python release to the 2.3 series. PyGTK-2.0: Version 1.99.16 at least, with version 2.0 recommended. The PyGTK developers have released PyGTK-2.6, which has support for more features in the latest GTK code. The PyGTK-2.4 release as well as the PyGTK-2.2 release work also, but these releases are tied to older GTK releases and are consequently in maintenance mode (at best). GTK and its dependencies: It is strongly recommended to use the latest release of GTK, Pango, ATK, and Glib. At the thirtieth PythonCAD release, GTK is at version 2.8.16, Pango is version 1.12.0, ATK is release 1.11.3, and Glib is release 2.10.1. The fifteenth release of PythonCAD offered a native Cocoa interface utilizing the Py-Objc bridge for Mac OS X users. Unfortunately the developer maintaining the Cocoa interface is no longer able to do so, and current PythonCAD releases do not work with the Py-Objc bindings. Developers wishing to pick up this code and maintain it would be welcomed. License ======= PythonCAD is distributed under the terms of the GNU General Public License (GPL). PythonCAD-DS1-R37/pythoncad.xsd0000644000175000017500000003541511307666657015713 0ustar matteomatteo Schema for PythonCAD drawing files Author: Art Haas(ahaas@airmail.net) PythonCAD-DS1-R37/pythoncad.desktop0000644000175000017500000000025711307666732016554 0ustar matteomatteo[Desktop Entry] Name=PyCAD Comment=PythonCAD Icon=gtkpycad Exec=pythoncad Terminal=false Type=Application X-Desktop-File-Install-Version=0.3 Categories=Office;X-Red-Hat-Base; PythonCAD-DS1-R37/NEWS0000644000175000017500000002502611307674556013673 0ustar matteomatteoNEWS ==== Release DS1-R37, Sep 22, 2009: * New Mantainer Matteo Boscolo * New Repository in www.Sourceforge.net/projects/pythoncad * New Pan & Dynamic Zoom(Need to improve Performance ->R38) * New Snap System (With One shot snap :point/tangent/perpendicular/midpoint/endpoint) * New Dynamic Cursor shape changing with snap * New Fillet Two lines. * Fix wrong positions in copy&paste Command * New Abaut Dialog * Bug fixes and code improvements Release DS1-R36, May 12, 2007: * Windows preferences saved to "env['APPDATA']/PythonCAD" directory * Bug fixes and code improvements Release DS1-R35, December 19, 2006: * Global preferences now set via 'Edit'->'Preferences' menu, and the values are saved to $HOME/.pythoncad/prefs.py file. * Image preferences now adjustable via 'Draw'->'Set' menu commands * Bug fixes and code improvments Release DS1-R34, August 3, 2006: * Additional display speedups and redraw fixes * Entities can now be rotated around arbitrary points * Cairo drawing routines used for entity drawing if available * Bug fixes and code improvements Release DS1-R33, July 7, 2006: * Inclusion of 'gettext' module for Native Language Support * Reworked display code greatly improving interface responsiveness * Interface code now relies solely on messaging system for interaction with core interface-neutral code * Spanish translation provided by Miguel Angel Barcena Rodriguez * Bug fixes and code improvements Release DS1-R32, May 25, 2006: * Fix autosplitting code to not rely on initial setting in preferences file and not disable autosplitting on a layer after first execution where global AUTOSPLIT is False * Fix typo in new split code * Bug fixes Release DS1-R31, May 19, 2006: * Default style values for classes now settable at runtime * Entity splitting code reworked * Automatic entity splitting at newly added point now available * Bug fixes and code improvements Release DS1-R30, March 21, 2006: * Stop using weakref module in Subpart class * Rework again code for transferring entities between layers * Bug fixes and code improvements Release DS1-R29, March 3, 2006: * Simplified Dimension __init__() methods * Reworked entity deletion and transfer code * RadialDimension toggling of diameter display now available from menu * AngularDimension inversion now availabe from menu * Bug fixes and code improvements Release DS1-R28, February 2, 2006: * Reworked entity modification code allows for both 'select->act' and 'act->select' modes of operation. * Reworked entity movement code. * Attributes of Dimension DimString entities can be adjusted individually, plus the missing ability to adjust their color has been added. * Warning cleanup for running PythonCAD under recent PyGTK releases. * Bug fixes and code improvements Release DS1-R27, December 6, 2005: * Selecting an entity will cause it to be drawn in a special color. * Deselecting a selected entity action added to 'Edit' menu. * Bug fixes and code improvements. Release DS1-R26, October 21, 2005: * Horizontal and Vertical stretch now accept keyboard input to define the stretch distance * Dual x/y move operation accepts keyboard input to define distances * Dual x/y stretch operation added * PostScript output adjustments improving conformance to Adobe standards * Quadtree reworking to permit storage of equivalent entities * Menus have added mnemonics to permit menu selection via keyboard * Bug fixes and code improvements Release DS1-R25, May 26, 2005: * Fix several compatibility issues for running on older PyGTK releases * Clean up GTK event handling code to better match GTK expectations * Bug fixes and code improvements Release DS1-R24, April 29, 2005: * Entity drawing improvements via draw()/erase() methods * Use of gtk.Action and gtk.ActionGroup classes for building menus * Bug fixes and code improvements Release DS1-R23, March 18, 2005: * Improve scripting and entry box evaluation * Replace deprecated values from PyGTK * Bug fixes and code improvements Release DS1-R22, January 26, 2005: * Use new gtk.ComboBox and gtk.ColorDialog widgets if available. * Add missing ability to paste TextBlock objects * Bug fixes and code improvements Release DS1-R21, January 11, 2005: * File saving and restoration of locked and visibility status * Undo/Redo code improvements * Bug fixes and code improvements Release DS1-R20, December 21, 2004: * Numerous Undo/Redo improvements * Simplified and refined file storage code * Bug fixes and code improvements Release DS1-R19, November 13, 2004: * Fix file-save bug for drawings with text entities. * Add 'showpage' to PostScript output. Release DS1-R18, November 12, 2004: * Dimension printing improvements * Undo/Redo data storage improvements * Deleted entity re-creation improvements * Bug fixes and code improvements * RPM packaging contributions from D. Scott Barninger Release DS1-R17, October 3, 2004: * Printing!!! * Significant improvements in modifying entities * Undo/Redo improvements * Greatly improved text support * Significant code improvements in dimension and text code * Miscellaneous bug fixes and code improvements Release DS1-R16, June 16, 2004: * Fixes for Cocoa interface * Bug fix in SegJoints for Chamfers and Fillets Release DS1-R15, June 15, 2004: * Added Cocoa-based front end * Undo/Redo improvements * Layer addition and deletion bug fixes * Miscellaneous bug fixes Release DS1-R14, May 26, 2004: * Undo/Redo improvements * Fix file save bug regression * Fix broken handling of drawing tangent circles * Fix quadtree errors for angled construction lines * Miscelleanous bug fixes and code improvements Release DS1-R13, April 28, 2004: * Undo/Redo added * Many deprecated methods removed * Drawings are now stored with the background color and inactive layer color * Point colors can be adjusted * Bug fixes and code improvements Release DS1-R12, February 24, 2004: * Subpart classes now store weak references to objects * xrange() -> range() conversion * Many deprecated methods removed * Conversion of most entities to a new message-sending design similar to that of QT's signals/slots * New class hierarchy allows for entites to be locked and hidden * Quadtrees used for storing most entities in a drawing. * Bug fixes and code improvements. Release DS1-R11, December 30, 2003: * More Python 2.3 fixes * Reworked file saving to avoid using mutable objects as dictionary keys * Major improvements in with transferring objects between layers * Bug fixes and code improvments Release DS1-R10, October 14, 2003: * Python 2.3 fixes * Entity clipping changes * DWG reading code added - no reading of DWG files yet * Adding diameter display option for radial dimensions * Bug fixes and code improvemnts Release DS1-R9, July 29, 2003: * Rework internal option handling * Rework internal storage of colors, linetypes, linestyles * Tangent calculation fixes * Intersection fixes when testing for points * Fix improper user of mutable variables as hash keys. * Bug fixes and code improvements Release DS1-R8, June 24, 2003: * Intersection code changed to return intersection points as tuples. * Leader line arrow size and dimension endpoint size now settable through preference dialogs and preference file * Saving to existing files now shows a dialog to allow the operation to be cancelled. * Polygon drawing tool added. * Unified preferences dialog box and increased preference setting options and abilities. * Begin the rework of drawing options internal handling. * Bug fixes and code improvements Release DS1-R7, June 3, 2003: * Tangent Construction Circle creation: - Tangent to a single construction line or construction circle - Tangent to two construction lines or a construction line and construction circle * Tangent construction line creation between two construction circles * Parallel construction line creation simplified * First iteration of a command-line mode for working in a drawing * File format changes to make the files easier to understand * Large code cleanup by moving interface-neutral code to the "Generic" subdirectory * Many new methods added to drawing entities (i.e. layer.bindObject()) * Reworked object splitting code - polylines can now be split * Assorted bug fixes and code improvements Release DS1-R6, May 4, 2003: * Text can now be stored in a drawing * New Polyline entity available - this is essentially a set of connected Segment elements. * Mirroring objects around a construction line is now available. * Interface neutral code moved from Interface/Gtk to Generic. More of this should be done in upcoming releases. * Internal reworking of Tool objects, and the creation/modification of entities from the UI. The Tool changes should make the code clearer and simpler to write, as well as move more code from the interface specific directory to the generic directory. * Assorted bug fixes and code improvements Release DS1-R5, March 28, 2003: * The reading of a global and user preferences file is implemented * Many changes in anticipation of hatching - hatching itself is still not available though * Several new methods added for searching for objects at a specific location and of a specific size. * Dimension endpoint markers now displayed * Added leader lines * Filenames are now saved with a '.gz' to indicate they are gzipped * Added adjustable sizes to dimension end points * Assorted bug fixes and code improvements Release DS1-R4, February 24, 2003: * Split many Layer routines into smaller, private methods * Bugs found and fixed in Layer due to method splitting metioned above * Big improvements in drawing dimensions * Linear Dimensioning added * Angular Dimensioning added * Saved files now only contain used colors, linetypes, styles * Interactive feedback when creating dimensions and arcs * Assorted bug fixes and code improvements Release DS1-R3, January 30, 2003: * Added drawing tangent and perpendicular construction lines * Added splitting of segments, circles, and arcs * Line thickness is drawn for "real" entities * More code modified to current standards * Added more doc strings * Rewrote most of the intersection calculation code * Bug fixes and code improvements Release DS1-R2, January 11, 2003: * Add layer deletion and clearing. * Add setting current entity attributes from "Draw" menu. * Fix changing attributes from "Modify" menu. * Don't write empty placeholder tags in files. * Many doc strings added. * Modify a few routines to adhere to the current code standards. * Add the ability to transfer objects between layers. * Add a web page for keeping track of needed development features, enhancements, and wish list ideas. December 18, 2002: The first release! Basic drawing functionality works, rudimentary editing exists, and that's about it. PythonCAD-DS1-R37/COPYING0000644000175000017500000004313111307666657014227 0ustar matteomatteo GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. PythonCAD-DS1-R37/Mac_OS_X_Read_Me.txt0000644000175000017500000000142411307666657016700 0ustar matteomatteoTo run the OS X Native front-end as a double-clickable .app: 1) Download and install the Python-Objective C bridge. http://pyobjc.sf.net/ 2) Open a terminal window (in Applications->Utilities->Terminal) 3) Change to the directory where this readme file is located (ie, if it's on your desktop in a "PythonCad" folder, type 'cd ~/Desktop/PythonCad' in the Terminal. 4) Type "python buildapp.py --semi-standalone build" in the terminal window. 5) The PythonCad.app will be located in the newly created "build" directory. Drag it to wherever you usually keep your applications. I make no guarantee this will work on OS X 10.2. It might, it might not. If you can't get it to work, send an e-mail. If it doesn't work but you figure out how to fix it, send an-email. Enjoy. PythonCAD-DS1-R37/setup.py0000644000175000017500000000122211307676756014702 0ustar matteomatteo#!/usr/bin/env python # # Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Art Haas # Copyright (c) 2009 Matteo Boscolo # # Install pythoncad using the distutils method # from distutils.core import setup setup(name="PythonCAD", version="DS1-R37", description="CAD built from Python", author="Art Haas,Matteo Boscolo", author_email="ahaas@airmail.net,Euro_ii@libero.it", url="http://www.pythoncad.org/", license="GPL", packages=['PythonCAD', 'PythonCAD/Generic', 'PythonCAD/Interface', 'PythonCAD/Interface/Cocoa', 'PythonCAD/Interface/Gtk'], ) PythonCAD-DS1-R37/buildapp.py0000644000175000017500000000136611307666657015352 0ustar matteomatteofrom bundlebuilder import buildapp from plistlib import Plist, Dict plist = Plist( CFBundleDocumentTypes = [ Dict( CFBundleTypeExtensions = ["xml", "xml.gz", "*"], CFBundleTypeName = "XML File", CFBundleTypeRole = "Editor", NSDocumentClass = "ImageDocument", ), Dict( CFBundleTypeExtensions = ["dwg"], CFBundleTypeName = "DWG File", CFBundleTypeRole = "Viewer", NSDocumentClass = "ImageDocument", ), ] ) buildapp( mainprogram = "PythonCad.py", resources = ["PythonCAD/Interface/Cocoa/MainMenu.nib", "PythonCAD/Interface/Cocoa/ImageDocument.nib", "PythonCAD", "prefs.py"], nibname = "MainMenu", plist = plist, ) PythonCAD-DS1-R37/TODO0000644000175000017500000000343611307666657013670 0ustar matteomatteoThings to add to PythonCAD, shortcomings to address, feature requests, and reminders can go in this file. Development: * Replace GTKImage class with ImageView/ImageWindow classes. * Write the DWG/DXF->PythonCAD data conversion routines to utilize the DWG/DXF reading code so that files in those formats can be loaded within PythonCAD. * Enhance messaging system error handling - a tough problem currently "solved" by a try/except block that merely prints out the Exception * Consolidate various routines in the Image and Layer classes used for searching and testing entity existence. * Utilize the Entity parent/child relationship info in the Interface code more - a getParent() call will specify the Layer an entity is stored in, which could replace various find-and-test queries currently performed. * Rewrite entity moving routines to utilize the move() methods on the entities when possible. Also re-examine the issue of moving the users of a Point entity (i.e. if the center point of a circle is selected and moved, but the circle itself was not selected, should the circle be moved or not?) [DONE] * Make use of scaling - provide some sort of interface for adjusting the scale, use the scale value when calculating dimensions, etc. * Make the selection/modifications routines consistent with regard to the order of entity selection and operation - either select entities before executing an operation or select an operation to perform and then select entities on which to apply the action. [DONE, mostly] * Allow for the user preferences to be stored when the 'Preferences' dialog is adjusted. The current behavior regarding handling of the user preferences is not consistent with most other applications. Possibly split the preferences up to be those applicable to all Images and then an per-Image dialog? PythonCAD-DS1-R37/PythonCAD/0000755000175000017500000000000011307677001014744 5ustar matteomatteoPythonCAD-DS1-R37/PythonCAD/Interface/0000755000175000017500000000000011307677001016644 5ustar matteomatteoPythonCAD-DS1-R37/PythonCAD/Interface/Gtk/0000755000175000017500000000000011307677001017371 5ustar matteomatteoPythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkedit.py0000644000175000017500000004356011307666732021417 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # handle cut, copy, paste, selections, etc # import pygtk pygtk.require('2.0') import gtk from PythonCAD.Generic.point import Point from PythonCAD.Generic.segment import Segment from PythonCAD.Generic.circle import Circle from PythonCAD.Generic.arc import Arc from PythonCAD.Generic.hcline import HCLine from PythonCAD.Generic.vcline import VCLine from PythonCAD.Generic.acline import ACLine from PythonCAD.Generic.cline import CLine from PythonCAD.Generic.ccircle import CCircle from PythonCAD.Generic.dimension import LinearDimension from PythonCAD.Generic.dimension import HorizontalDimension from PythonCAD.Generic.dimension import VerticalDimension from PythonCAD.Generic.dimension import RadialDimension from PythonCAD.Generic.dimension import AngularDimension from PythonCAD.Generic.dimension import DimString from PythonCAD.Generic import text import PythonCAD.Generic.globals def select_region_end_cb(gtkimage, widget, event, tool): # print "called select_region_end_callback()" _image = gtkimage.getImage() _x2, _y2 = _image.getCurrentPoint() _y1 = tool.popObject() _x1 = tool.popObject() _xmin = min(_x1, _x2) _xmax = max(_x1, _x2) _ymin = min(_y1, _y2) _ymax = max(_y1, _y2) tool.delHandler("motion_notify") _active_layer = _image.getActiveLayer() _objs = _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax) if len(_objs): _image.sendMessage('group_action_started') try: for _obj in _objs: _image.selectObject(_obj) finally: _image.sendMessage('group_action_ended') gtkimage.setPrompt(_('Click on the items you want to select.')) select_mode_init(gtkimage) def select_motion_notify(gtkimage, widget, event, tool): _tx, _ty = tool.getLocation() _px, _py = gtkimage.coordToPixTransform(_tx, _ty) _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _cp = tool.getCurrentPoint() if _cp is not None: _xc, _yc = _cp _xmin = min(_xc, _px) _ymin = min(_yc, _py) _rw = abs(_xc - _px) _rh = abs(_yc - _py) widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _rw, _rh) tool.setCurrentPoint(_x, _y) _xmin = min(_x, _px) _ymin = min(_y, _py) _rw = abs(_x - _px) _rh = abs(_y - _py) widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _rw, _rh) return True def select_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() # print "x: %g; y: %g" % (_x, _y) _active_layer = _image.getActiveLayer() _pts = _active_layer.find('point', _x, _y, _tol) if len(_pts) > 0: _image.sendMessage('group_action_started') try: for _pt in _pts: _image.selectObject(_pt) finally: _image.sendMessage('group_action_ended') else: _objs = [] for _tb in _active_layer.getLayerEntities('text'): # print "testing tb: " + `_tb` _tx, _ty = _tb.getLocation() # print "tx: %g; ty: %g" % (_tx, _ty) _bounds = _tb.getBounds() if _bounds is not None: # print "has bounds ..." _w, _h = _bounds _align = _tb.getAlignment() if _align == text.TextStyle.ALIGN_LEFT: _txmin = _tx _txmax = _tx + _w elif _align == text.TextStyle.ALIGN_CENTER: _off = _w/2.0 _txmin = _tx - _off _txmax = _tx + _off elif _align == text.TextStyle.ALIGN_RIGHT: _txmin = _tx - _w _txmax = _tx else: raise ValueError, "Unexpected alignment: %d" % _align _tymin = _ty - _h _tymax = _ty # print "txmin: %g" % _txmin # print "tymin: %g" % _tymin # print "txmax: %g" % _txmax # print "tymax: %g" % _tymax if _txmin < _x < _txmax and _tymin < _y < _tymax: _objs.append(_tb) for _obj, _pt in _active_layer.mapPoint((_x, _y), _tol): _objs.append(_obj) if len(_objs): _image.sendMessage('group_action_started') try: for _obj in _objs: _image.selectObject(_obj) finally: _image.sendMessage('group_action_ended') else: # print "no objects ..." gtkimage.setPrompt(_('Click on another point to select the region.')) gc = gtkimage.getGC() gc.set_line_attributes(1, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) gc.set_function(gtk.gdk.INVERT) tool.setLocation(_x, _y) tool.pushObject(_x) tool.pushObject(_y) tool.setHandler("motion_notify", select_motion_notify) tool.setHandler("button_press", select_region_end_cb) def select_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the items you want to select.')) _tool = gtkimage.getImage().getTool() _tool.initialize() _tool.setHandler("button_press", select_button_press_cb) def deselect_region_end_cb(gtkimage, widget, event, tool): # print "called deselect_region_end_callback()" _image = gtkimage.getImage() _x2, _y2 = _image.getCurrentPoint() _y1 = tool.popObject() _x1 = tool.popObject() _xmin = min(_x1, _x2) _xmax = max(_x1, _x2) _ymin = min(_y1, _y2) _ymax = max(_y1, _y2) tool.delHandler("motion_notify") _active_layer = _image.getActiveLayer() _objs = _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax) if len(_objs): _sobjs = {} for _obj in _image.getSelectedObjects(False): if _obj.getParent() is _active_layer: _sobjs[id(_obj)] = True _image.sendMessage('group_action_started') try: for _obj in _objs: if id(_obj) in _sobjs: _image.deselectObject(_obj) finally: _image.sendMessage('group_action_ended') gtkimage.setPrompt(_('Click on the items you want to deselect.')) deselect_mode_init(gtkimage) def deselect_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() # print "x: %g; y: %g" % (_x, _y) _active_layer = _image.getActiveLayer() _objs = [] for _obj in _image.getSelectedObjects(False): if _obj.getParent() is _active_layer: if isinstance(_obj, Point): if abs(_obj.x - _x) < _tol and abs(_obj.y - _y) < _tol: _objs.append(_obj) elif isinstance(_obj, text.TextBlock): _tx, _ty = _obj.getLocation() _bounds = _obj.getBounds() if _bounds is not None: _w, _h = _bounds _align = _obj.getAlignment() if _align == text.TextStyle.ALIGN_LEFT: _txmin = _tx _txmax = _tx + _w elif _align == text.TextStyle.ALIGN_CENTER: _off = _w/2.0 _txmin = _tx - _off _txmax = _tx + _off elif _align == text.TextStyle.ALIGN_RIGHT: _txmin = _tx - _w _txmax = _tx else: raise ValueError, "Unexpected alignment: %d" % _align _tymin = _ty - _h _tymax = _ty if _txmin < _x < _txmax and _tymin < _y < _tymax: _objs.append(_obj) elif _obj.mapCoords(_x, _y, _tol) is not None: _objs.append(_obj) else: pass if len(_objs): _image.sendMessage('group_action_started') try: for _obj in _objs: _image.deselectObject(_obj) finally: _image.sendMessage('group_action_ended') else: gtkimage.setPrompt(_('Click on another point to select the region.')) gc = gtkimage.getGC() gc.set_line_attributes(1, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) gc.set_function(gtk.gdk.INVERT) tool.setLocation(_x, _y) tool.pushObject(_x) tool.pushObject(_y) tool.setHandler("motion_notify", select_motion_notify) tool.setHandler("button_press", deselect_region_end_cb) def deselect_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the items you want to deselect.')) _tool = gtkimage.getImage().getTool() _tool.initialize() _tool.setHandler("button_press", deselect_button_press_cb) def paste_button_press_cb(gtkimage, widget, event, tool): # print "called paste_button_press_cb()" _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() # print "x: %g; y: %g" % (_x, _y) _active_layer = _image.getActiveLayer() _objs = PythonCAD.Generic.globals.selectobj.getObjects() _objmap = {} _image.startAction() try: _midx, _midy = determine_center(_objs) _dx, _dy = _x - _midx, _y - _midy for _obj in _objs: if isinstance(_obj, Point): if not _objmap.has_key('point'): _objmap['point'] = {} _pt = Point(_obj.getx() + _dx, _obj.gety() + _dy) _ept = _active_layer.findObject(_pt) if _ept is None: _active_layer.addObject(_pt) _objmap['point'][_obj] = _pt else: _objmap['point'][_obj] = _ept elif isinstance(_obj, Segment): if not _objmap.has_key('segment'): _objmap['segment'] = {} _cseg = _obj.clone() _cseg.move(_dx, _dy) _eseg = _active_layer.findObject(_cseg) if _eseg is None: _p1, _p2 = _cseg.getEndpoints() _ep = _active_layer.findObject(_p1) if _ep is None: _active_layer.addObject(_p1) else: _cseg.setP1(_ep) _ep = _active_layer.findObject(_p2) if _ep is None: _active_layer.addObject(_p2) else: _cseg.setP2(_ep) _active_layer.addObject(_cseg) else: _objmap['segment'][_obj] = _eseg elif isinstance(_obj, (Circle, Arc, CCircle)): _cc = _obj.clone() _cc.move(_dx, _dy) _ec = _active_layer.findObject(_cc) if _ec is None: _cp = _cc.getCenter() _ep = _active_layer.findObject(_cp) if _ep is None: _active_layer.addObject(_cp) else: _cc.setLocation(_ep) _active_layer.addObject(_cc) elif isinstance(_obj, (HCLine, VCLine, ACLine)): _ccl = _obj.clone() _ccl.move(_dx, _dy) _ecl = _active_layer.findObject(_ccl) if _ecl is None: _lp = _ccl.getLocation() _ep = _active_layer.findObject(_lp) if _ep is None: _active_layer.addObject(_lp) else: _ccl.setLocation(_ep) _active_layer.addObject(_ccl) elif isinstance(_obj, CLine): _ccl = _obj.clone() _ccl.move(_dx, _dy) _ecl = _active_layer.findObject(_ccl) if _ecl is None: _p1, _p2 = _ccl.getKeypoints() _ep = _active_layer.findObject(_p1) if _ep is None: _active_layer.addObject(_p1) else: _ccl.setP1(_ep) _ep = _active_layer.findObject(_p2) if _ep is None: _active_layer.addObject(_p2) else: _ccl.setP2(_ep) _active_layer.addObject(_ccl) elif isinstance(_obj, LinearDimension): #these checks were wrongly placed and seem unecessary... #keep them here just in case... #if _active_layer.findObject(_obj) is None: #_l1, _l2 = _obj.getDimLayers() #if _image.hasLayer(_l1) and _image.hasLayer(_l2): _p1, _p2 = _obj.getDimPoints() dimpoint1 = Point(_p1.getx() + _dx, _p1.gety() + _dy) dimpoint2 = Point(_p2.getx() + _dx, _p2.gety() + _dy) dimx, dimy = _obj.getLocation() #check if points already exist in drawing _ep = _active_layer.findObject(dimpoint1) if _ep is None: _active_layer.addObject(dimpoint1) else: dimpoint1 = _ep _ep = _active_layer.findObject(dimpoint2) if _ep is None: _active_layer.addObject(dimpoint2) else: dimpoint2 = _ep _ds = _obj.getDimStyle() if isinstance(_obj, HorizontalDimension): _dtype = HorizontalDimension elif isinstance(_obj, VerticalDimension): _dtype = VerticalDimension else: _dtype = LinearDimension _dim = _dtype(dimpoint1, dimpoint2, dimx + _dx, dimy + _dy,_ds) _active_layer.addObject(_dim) elif isinstance(_obj, RadialDimension): if _active_layer.findObject(_obj) is None: _lyr = _obj.getDimLayer() if _image.hasLayer(_lyr): _dc = _obj.getDimCircle() _ds = _obj.getDimStyle() _dim = RadialDimension(_lyr, _dc, _x, _y, _ds) _active_layer.addObject(_dim) elif isinstance(_obj, AngularDimension): if _active_layer.findObject(_obj) is None: _cl, _l1, _l2 = _obj.getDimLayers() if (_image.hasLayer(_cl) and _image.hasLayer(_l1) and _image.hasLayer(_l2)): _cp, _p1, _p2 = _obj.getDimPoints() _ds = _obj.getDimStyle() _dim = AngularDimension(_cl, _cp, _l1, _p1, _l2, _p2, _x, _y, _ds) _active_layer.addObject(_dim) elif isinstance(_obj, text.TextBlock): _ntb = _obj.clone() _origpos = _obj.getLocation() _ntb.setLocation(_origpos[0] + _dx, _origpos[1] + _dy) _active_layer.addObject(_ntb) else: print "Unexpected type for pasting: " + `type(_obj)` finally: _image.endAction() def paste_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click where you want to paste the objects')) _tool = gtkimage.getImage().getTool() _tool.initialize() _tool.setHandler("button_press", paste_button_press_cb) def determine_center(_objectarray): #determine "center" of n points - simplest method: average values of #coordinates of center points of each object _sumx, _sumy, _objectnumber = 0, 0, 0 for _obj in _objectarray: _objectnumber += 1 if isinstance(_obj, Point): _sumx += _obj.getx() _sumy += _obj.gety() elif isinstance(_obj, Segment): _x, _y = _obj.getMiddlePoint() _sumx += _x _sumy += _y elif isinstance(_obj, (Circle, Arc, CCircle)): _center = _obj.getCenter() _sumx += _center.getx() _sumy += _center.gety() elif isinstance(_obj, (HCLine, VCLine, ACLine)): _center = _obj.getLocation() _sumx += _center.getx() _sumy += _center.gety() elif isinstance(_obj, CLine): _midpoint = _obj.getMiddlePoint() _sumx += _midpoint.getx() _sumy += _midpoint.gety() elif isinstance(_obj, LinearDimension): #linear dimensions don't count since they are connected to another #object _objectnumber -= 1 #elif isinstance(_obj, RadialDimension): #elif isinstance(_obj, AngularDimension): elif isinstance(_obj, text.TextBlock): _location = _obj.getLocation() _sumx += _location[0] _sumy += _location[1] elif isinstance(_obj, DimString): _objectnumber -= 1 else: print "Unexpected type for center determination: " + `type(_obj)` _objectnumber -= 1 return _sumx / _objectnumber, _sumy / _objectnumber PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkconobjs.py0000644000175000017500000006435711307666732022136 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2006, 2007 Art Haas # # 2009 Matteo Boscolo # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # the event handling bits for construction lines # and circles # import math import pygtk pygtk.require('2.0') import gtk from PythonCAD.Generic.point import Point from PythonCAD.Generic.segment import Segment from PythonCAD.Generic.circle import Circle from PythonCAD.Generic.arc import Arc from PythonCAD.Generic.hcline import HCLine from PythonCAD.Generic.vcline import VCLine from PythonCAD.Generic.acline import ACLine from PythonCAD.Generic.cline import CLine from PythonCAD.Generic.ccircle import CCircle from PythonCAD.Generic.color import Color from PythonCAD.Generic import util from PythonCAD.Interface.Gtk import gtkentities from PythonCAD.Generic import snap from PythonCAD.Generic.pyGeoLib import Vector # horizontal construction lines # def hcline_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setPoint,_tol,_snapArray) gtkentities.create_entity(gtkimage) def hcline_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _val = util.get_float(eval(_text, gtkimage.image.getImageVariables())) tool.setPoint(0.0, _val) gtkentities.create_entity(gtkimage) def hcline_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_("Click in the drawing area or enter 'y' coordinate:")) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", hcline_mode_init) _tool.setHandler("button_press", hcline_button_press_cb) _tool.setHandler("entry_event", hcline_entry_event_cb) # # vertical construction lines # def vcline_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setPoint,_tol,_snapArray) gtkentities.create_entity(gtkimage) def vcline_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _val = util.get_float(eval(_text, gtkimage.image.getImageVariables())) tool.setPoint(_val, 0.0) gtkentities.create_entity(gtkimage) def vcline_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_("Click in the drawing area or enter 'x' coordinate:")) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", vcline_mode_init) _tool.setHandler("button_press", vcline_button_press_cb) _tool.setHandler("entry_event", vcline_entry_event_cb) # # common functions for for acline, cline, and ccircle objects # def make_tuple(text, gdict): _tpl = eval(text, gdict) if not isinstance(_tpl, tuple): raise TypeError, "Invalid tuple: " + `type(_tpl)` if len(_tpl) != 2: raise ValueError, "Invalid tuple: " + str(_tpl) return _tpl # # angled construction lines # def acline_motion_notify_cb(gtkimage, widget, event, tool): _segs = [] _ax, _ay = tool.getPoint().point.getCoords() _pax, _pay = gtkimage.coordToPixTransform(_ax, _ay) _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _cp = tool.getCurrentPoint() if _cp is not None: _xc, _yc = _cp _segs.append((_pax, _pay, _xc, _yc)) _snapArray={'perpendicular':False,'tangent':False} snap.setDinamicSnap(gtkimage,tool.setLocation,_snapArray) tool.setCurrentPoint(_x, _y) _segs.append((_pax, _pay, _x, _y)) widget.window.draw_segments(_gc, _segs) return True def acline_entry_make_angle(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _angle = util.make_angle(eval(_text, gtkimage.image.getImageVariables())) tool.setAngle(_angle) gtkentities.create_entity(gtkimage) def acline_entry_make_pt(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) tool.setPoint(_x, _y) tool.setHandler("button_press", acline_second_button_press_cb) tool.setHandler("entry_event", acline_entry_make_angle) tool.setHandler("motion_notify", acline_motion_notify_cb) gtkimage.setPrompt(_('Enter the angle or click in the drawing area')) gtkimage.getGC().set_function(gtk.gdk.INVERT) def acline_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setLocation,_tol,_snapArray) gtkentities.create_entity(gtkimage) return True def acline_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setPoint,_tol,_snapArray) tool.setHandler("button_press", acline_second_button_press_cb) tool.setHandler("entry_event", acline_entry_make_angle) tool.setHandler("motion_notify", acline_motion_notify_cb) gtkimage.setPrompt(_('Enter the angle or click in the drawing area')) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True def acline_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter a Point')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", acline_mode_init) _tool.setHandler("button_press", acline_first_button_press_cb) _tool.setHandler("entry_event", acline_entry_make_pt) # # two point construction line # def cline_motion_notify_cb(gtkimage, widget, event, tool): _segs = [] _x1, _y1 = tool.getFirstPoint().point.getCoords() _px1, _py1 = gtkimage.coordToPixTransform(_x1, _y1) _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _cp = tool.getCurrentPoint() if _cp is not None: _xc, _yc = _cp _segs.append((_px1, _py1, _xc, _yc)) _snapArray={'perpendicular':False,'tangent':False} snap.setDinamicSnap(gtkimage,tool.setSecondPoint,_snapArray) tool.setCurrentPoint(_x, _y) _segs.append((_px1, _py1, _x, _y)) widget.window.draw_segments(_gc, _segs) return True def cline_second_entry_make_pt(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) tool.setSecondPoint(_x, _y) gtkentities.create_entity(gtkimage) def cline_first_entry_make_pt(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) tool.setFirstPoint(_x, _y) tool.setHandler("button_press", cline_second_button_press_cb) tool.setHandler("motion_notify", cline_motion_notify_cb) tool.setHandler("entry_event", cline_second_entry_make_pt) gtkimage.setPrompt(_('Enter the second Point or click in the drawing area')) gtkimage.getGC().set_function(gtk.gdk.INVERT) def cline_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setSecondPoint,_tol,_snapArray) gtkentities.create_entity(gtkimage) return True def cline_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setFirstPoint,_tol,_snapArray) tool.setHandler("button_press", cline_second_button_press_cb) tool.setHandler("entry_event", cline_second_entry_make_pt) tool.setHandler("motion_notify", cline_motion_notify_cb) gtkimage.setPrompt(_('Enter the second point or click in the drawing area')) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True def cline_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter a Point')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", cline_mode_init) _tool.setHandler("button_press", cline_first_button_press_cb) _tool.setHandler("entry_event", cline_first_entry_make_pt) # # construction circles # def ccircle_cpmode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter a Point')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", gtkentities.circle_center_button_press_cb) _tool.setHandler("entry_event", gtkentities.circle_point_entry_event_cb) _tool.setHandler("initialize", ccircle_cpmode_init) # # two-point construction circle # def ccircle_tpmode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter a Point')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", gtkentities.circle_tp_first_button_press_cb) _tool.setHandler("entry_event", gtkentities.circle_tp_first_entry_event_cb) _tool.setHandler("initialize", ccircle_tpmode_init) # # perpendicular construction line creation # def perp_cline_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _pt,_pc=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() _active_layer = _image.getActiveLayer() _hits = _active_layer.mapPoint((_pt,_pc), _tol, 1) if len(_hits): _obj, _lp = _hits[0] _pcl = None if isinstance(_obj, Segment): _p1, _p2 = _obj.getEndpoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() if abs(_p1x - _p2x) < 1e-10: # vertical _pcl = HCLine(_lp) elif abs(_p1y - _p2y) < 1e-10: # horizontal _pcl = VCLine(_lp) else: _slope = (180.0/math.pi) * math.atan2((_p2y - _p1y), (_p2x - _p1x)) + 90.0 _pcl = ACLine(_lp, _slope) elif isinstance(_obj, (Circle, Arc, CCircle)): _cp = _obj.getCenter() _pcl = CLine(_cp, _lp) elif isinstance(_obj, HCLine): _pcl = VCLine(_lp) elif isinstance(_obj, VCLine): _pcl = HCLine(_lp) elif isinstance(_obj, ACLine): _angle = _obj.getAngle() if abs(_angle) < 1e-10: # horizontal _pcl = VCLine(_lp) elif abs(abs(_angle) - 90.0) < 1e-10: # vertical _pcl = HCLine(_lp) else: _slope = _angle + 90.0 _pcl = ACLine(_lp, _slope) elif isinstance(_obj, CLine): _p1, _p2 = _obj.getKeypoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() if abs(_p1x - _p2x) < 1e-10: # vertical _pcl = HCLine(_lp) elif abs(_p1y - _p2y) < 1e-10: # horizontal _pcl = VCLine(_lp) else: _slope = (180.0/math.pi) * math.atan2((_p2y - _p1y), (_p2x - _p1x)) + 90.0 _pcl = ACLine(_lp, _slope) else: pass _image.startAction() try: if _lp.getParent() is None: _active_layer.addObject(_lp) if _pcl is not None: _active_layer.addObject(_pcl) finally: _image.endAction() return True def perpendicular_cline_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the object you want a perpendicular to')) _tool = gtkimage.getImage().getTool() _tool.initialize() _tool.setHandler("button_press", perp_cline_button_press_cb) # # tangent cline creation # def tangent_cline_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'tangent':False} _pt=snap.getOnlySnap(_image,_tol,_snapArray) if _pt is not None: _x, _y = _pt.point.getCoords() _layer = _image.getActiveLayer() _rtd = 180.0/math.pi _cobj = None _angle = None _circleEnt=_pt.entity if isinstance(_circleEnt,(CCircle,Circle,Arc)): _cp=_circleEnt.getCenter() _rad = _circleEnt.getRadius() _v=Vector(_cp,_pt.point).Mag() _v.Mult(_rad) _vectPoint=_v.Point() _x,_y=(_vectPoint+_cp) _cx,_cy=_cp.getCoords() if abs(math.hypot((_x - _cx), (_y - _cy)) - _rad) < 1e-10: _cobj = _circleEnt _angle = _rtd * math.atan2((_y - _cy), (_x - _cx)) if _angle < 0.0: _angle = _angle + 360.0 _pt=Point(_x,_y) if _cobj is not None: _image.startAction() try: if _pt: _layer.addObject(_pt) if (abs(_angle) < 1e-6 or abs(_angle - 180.0) < 1e-6 or abs(_angle - 360.0) < 1e-6): _tcl = VCLine(_pt) elif (abs(_angle - 90.0) < 1e-6 or abs(_angle - 270.0) < 1e-6): _tcl = HCLine(_pt) else: _slope = _angle + 90.0 _tcl = ACLine(_pt, _slope) _layer.addObject(_tcl) finally: _image.endAction() return True def tangent_cline_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the circle object you want a tangent to')) _tool = gtkimage.getImage().getTool() _tool.initialize() _tool.setHandler("button_press", tangent_cline_button_press_cb) # # parallel offset mode # def parallel_refpt_button_press_cb(gtkimage, widget, event, tool): _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() tool.setReferencePoint(_x, _y) _init_func = tool.getHandler("initialize") _image.startAction() try: tool.create(gtkimage.image) finally: _image.endAction() _init_func(gtkimage) return True def parallel_conline_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _objdict = _image.mapPoint(_x, _y, _tol, 1) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, (HCLine, VCLine, ACLine, CLine)): tool.setConstructionLine(_obj) tool.setHandler("button_press", parallel_refpt_button_press_cb) gtkimage.setPrompt(_('Click on the side to place the new construction line.')) def parallel_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _snp=snap.getSnapPoint(_image,_tol,_snapArray) _x,_y=_snp.point.getCoords() print "Debug: " + str(tool.getLocation()) _x1, _y1 = tool.getLocation() _offset = math.hypot((_x - _x1), (_y - _y1)) tool.setOffset(_offset) tool.setHandler("button_press", parallel_conline_button_press_cb) gtkimage.setPrompt(_('Click on the reference construction line.')) return True def parallel_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x1,_y1=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() tool.setLocation(_x1,_y1) tool.setHandler("button_press", parallel_second_button_press_cb) tool.delHandler("entry_event") gtkimage.setPrompt(_('Click another point to define the offset distance.')) return True def parallel_entry_event(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _dist = util.get_float(eval(_text, gtkimage.image.getImageVariables())) tool.setOffset(_dist) tool.delHandler("entry_event") tool.setHandler("button_press", parallel_conline_button_press_cb) gtkimage.setPrompt(_('Click on the reference construction line.')) def parallel_offset_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Enter the distance or click in the drawing area.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", parallel_offset_mode_init) _tool.setHandler("button_press", parallel_first_button_press_cb) _tool.setHandler("entry_event", parallel_entry_event) # # construction circle tangent to a construction line # def ccircle_single_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() tool.setLocation(_x, _y) gtkentities.create_entity(gtkimage) return True def ccircle_single_motion_notify_cb(gtkimage, widget, event, tool): _gc = gtkimage.getGC() _upp = gtkimage.getUnitsPerPixel() _rect = tool.getPixelRect() if _rect is not None: _xmin, _ymin, _width, _height = _rect widget.window.draw_arc(_gc, False, _xmin, _ymin, _width, _height, 0, 360*64) _ix, _iy = gtkimage.image.getCurrentPoint() tool.setLocation(_ix, _iy) _cx, _cy = tool.getCenter() _radius = tool.getRadius() _pcx, _pcy = gtkimage.coordToPixTransform(_cx, _cy) _pr = int(_radius/_upp) _xmin = _pcx - _pr _ymin = _pcy - _pr _width = _height = _pr * 2 tool.setPixelRect(_xmin, _ymin, _width, _height) widget.window.draw_arc(_gc, False, _xmin, _ymin, _width, _height, 0, 360*64) return True def ccircle_single_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'tangent':True} ent=snap.getOnlySnap(_image,_tol,_snapArray).entity if ent is not None: _active_layer = _image.getActiveLayer() if isinstance(ent, (HCLine, VCLine, ACLine, CLine, CCircle)): tool.setConstructionLine(ent) tool.setHandler("button_press", ccircle_single_second_button_press_cb) tool.setHandler("motion_notify", ccircle_single_motion_notify_cb) gtkimage.setPrompt(_('Click where the circle should be drawn.')) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True def tangent_ccircle_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the construction object used for tangency.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", tangent_ccircle_mode_init) _tool.setHandler("button_press", ccircle_single_first_button_press_cb) # # construction circle between two construction lines # def two_cline_set_circle_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() tool.setLocation(_x, _y) gtkentities.create_entity(gtkimage) def two_cline_motion_notify_cb(gtkimage, widget, event, tool): _gc = gtkimage.getGC() _upp = gtkimage.getUnitsPerPixel() _rect = tool.getPixelRect() if _rect is not None: _xmin, _ymin, _width, _height = _rect widget.window.draw_arc(_gc, False, _xmin, _ymin, _width, _height, 0, 360*64) _ix, _iy = gtkimage.image.getCurrentPoint() tool.setLocation(_ix, _iy) _radius = tool.getRadius() if _radius > 0.0: _cx, _cy = tool.getCenter() _pcx, _pcy = gtkimage.coordToPixTransform(_cx, _cy) _pr = int(_radius/_upp) _xmin = _pcx - _pr _ymin = _pcy - _pr _width = _height = _pr * 2 tool.setPixelRect(_xmin, _ymin, _width, _height) widget.window.draw_arc(_gc, False, _xmin, _ymin, _width, _height, 0, 360*64) return True def two_cline_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _objdict = _image.mapPoint(_x, _y, _tol, 1) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: _first_conobj = tool.getFirstConObject() for _obj, _pt in _objdict[_active_layer]: if _obj is _first_conobj: continue if isinstance(_obj, (HCLine, VCLine, ACLine, CLine)): tool.setHandler("button_press", two_cline_set_circle_cb) tool.setHandler("motion_notify", two_cline_motion_notify_cb) tool.setSecondConObject(_obj) gtkimage.setPrompt(_('Click where you want the tangent circle to be.')) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True def two_cline_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _objdict = _image.mapPoint(_x, _y, _tol, 1) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, (HCLine, VCLine, ACLine, CLine, CCircle)): tool.setHandler("button_press", two_cline_second_button_press_cb) tool.setFirstConObject(_obj) gtkimage.setPrompt(_('Click on the second construction line for tangency.')) return True def two_cline_tancc_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the first construction line or construction circle for tangency.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", two_cline_tancc_mode_init) _tool.setHandler("button_press", two_cline_first_button_press_cb) # # tangent lines around two circles # def two_ccircle_tangent_cb(gtkimage, widget, event, tool): _x, _y = gtkimage.image.getCurrentPoint() tool.setLocation(_x, _y) gtkentities.create_entity(gtkimage) def _draw_two_circle_tangents(gtkimage, tool): _tanpts = tool.getTangentPoints() assert len(_tanpts), "No tangent points defined!" _gc = gtkimage.getGC() _da = gtkimage.getDA() # # adjust the GC to draw the temporary segments in # a distinctive manner # _gc.set_line_attributes(1, gtk.gdk.LINE_DOUBLE_DASH, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) _gc.set_dashes(0, [3, 3]) _tempcolor = Color('#ffff99') # yellowish color _color = gtkimage.getColor(_tempcolor) _gc.set_foreground(_color) _gc.set_function(gtk.gdk.COPY) # _segs = [] for _set in _tanpts: _x1, _y1, _x2, _y2 = _set # print "x1: %g; y1: %g" % (_x1, _y1) # print "x2: %g; y2: %g" % (_x2, _y2) _px1, _py1 = gtkimage.coordToPixTransform(_x1, _y1) _px2, _py2 = gtkimage.coordToPixTransform(_x2, _y2) _segs.append((_px1, _py1, _px2, _py2)) _da.window.draw_segments(_gc, _segs) def two_circle_tangent_second_button_press_cb(gtkimage, widget, event, tool): # print "in second_button_press_cb() ..." _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _objdict = _image.mapPoint(_x, _y, _tol, 1) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, CCircle): tool.setHandler("button_press", two_circle_tangent_second_button_press_cb) tool.setSecondCCircle(_obj) if tool.hasTangentPoints(): _draw_two_circle_tangents(gtkimage, tool) gtkimage.setPrompt(_('Click on the segment to keep.')) tool.setHandler("button_press", two_ccircle_tangent_cb) else: tool.reset() two_circle_tangent_line_mode_init(gtkimage, tool) return True def two_circle_tangent_first_button_press_cb(gtkimage, widget, event, tool): # print "in first_button_press_cb() ..." _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _objdict = _image.mapPoint(_x, _y, _tol, 1) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, CCircle): tool.setHandler("button_press", two_circle_tangent_second_button_press_cb) tool.setFirstCCircle(_obj) gtkimage.setPrompt(_('Click on the second construction circle.')) return True def two_circle_tangent_line_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the first construction circle.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", two_circle_tangent_line_mode_init) _tool.setHandler("button_press", two_circle_tangent_first_button_press_cb) PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkimage.py0000644000175000017500000014673511307666732021564 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Art Haas # Copyright (c) 2009 Matteo Boscolo # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # the GTK code for displaying a drawing # from __future__ import division import math import types import warnings import pygtk pygtk.require('2.0') import gtk import gobject from PythonCAD.Interface.Gtk import gtkdimension from PythonCAD.Interface.Gtk import gtktext from PythonCAD.Interface.Gtk import gtkactions from PythonCAD.Generic.image import Image from PythonCAD.Generic.point import Point from PythonCAD.Generic.conobject import ConstructionObject from PythonCAD.Generic.color import Color from PythonCAD.Generic.layer import Layer from PythonCAD.Generic import tools from PythonCAD.Generic import globals from PythonCAD.Generic import keywords from PythonCAD.Generic import prompt from PythonCAD.Interface.Gtk import gtkshell # # Global variables # _debug = False ## SDB debug stuff globals.gtkcolors = {} globals.gtklinetypes = {} class GTKImage(object): """ The GTK wrapping around an Image The GTKImage class is derived from the Image class, so it shares all the attributes and methods of that class. The GTKImage class has the following addtional methods: close(): Close a GTKImage. getWindow(): Get the GTK Window used in the GTKImage. getEntry(): Get the GTK Entry used in the GTKImage. getDA(): Get the GTK Drawing Area used in the GTKImage. {get/set}Pixmap(): Get/Set the GTK Pixmap used in the GTKImage. {get/set}Prompt(): Get/Set the prompt. {get/set}Tool(): Get/Set the tool used for working in the GTKImage. {get/set}UnitsPerPixel(): Get/Set this display parameter. {get/set}View(): Get/Set the current view seen in the GTKImage. getTolerance(): Get the current drawing tolerance. {get/set}GC(): Get/Set the graphic context used in the GTKImage. {get/set}Point(): Get/Set the current coordinates of the tool. {get/set}Size(): Get/Set the size of the drawing area. pixToCoordTransform(): Convert pixels to x/y coordinates. coordToPixTransform(): Convert x/y coordinates to pixels. refresh(): Redraw the screen using the current pixmap. redraw(): Recalculate the visible entities and redraw the screen. addGroup(): Add a new ActionGroup to the GTKImage. getGroup(): Retrieve an ActionGroup from the GTKImage. deleteGroup(): Remove an ActionGroup from the GTKImage. """ # # class variables # from PythonCAD.Interface.Gtk import gtkentities from PythonCAD.Interface.Gtk import gtkconobjs from PythonCAD.Interface.Gtk import gtkmodify from PythonCAD.Interface.Gtk import gtkmirror from PythonCAD.Interface.Gtk import gtkprinting from PythonCAD.Interface.Gtk import gtkedit __inittool = { tools.PasteTool : gtkedit.paste_mode_init, tools.SelectTool : gtkedit.select_mode_init, tools.DeselectTool : gtkedit.deselect_mode_init, tools.PointTool : gtkentities.point_mode_init, tools.SegmentTool : gtkentities.segment_mode_init, tools.RectangleTool: gtkentities.rectangle_mode_init, tools.CircleTool : gtkentities.circle_center_mode_init, tools.TwoPointCircleTool : gtkentities.circle_tp_mode_init, tools.ArcTool : gtkentities.arc_center_mode_init, tools.ChamferTool : gtkentities.chamfer_mode_init, tools.FilletTool: gtkentities.fillet_mode_init, tools.FilletTwoLineTool: gtkentities.fillet_two_line_mode_init, tools.LeaderTool : gtkentities.leader_mode_init, tools.PolylineTool : gtkentities.polyline_mode_init, tools.PolygonTool : gtkentities.polygon_mode_init, tools.HCLineTool : gtkconobjs.hcline_mode_init, tools.VCLineTool : gtkconobjs.vcline_mode_init, tools.ACLineTool : gtkconobjs.acline_mode_init, tools.CLineTool : gtkconobjs.cline_mode_init, tools.PerpendicularCLineTool: gtkconobjs.perpendicular_cline_mode_init, tools.TangentCLineTool : gtkconobjs.tangent_cline_mode_init, tools.CCircleTangentLineTool : gtkconobjs.two_circle_tangent_line_mode_init, tools.ParallelOffsetTool : gtkconobjs.parallel_offset_mode_init, tools.CCircleTool : gtkconobjs.ccircle_cpmode_init, tools.TwoPointCCircleTool : gtkconobjs.ccircle_tpmode_init, tools.TangentCCircleTool : gtkconobjs.tangent_ccircle_mode_init, tools.TwoPointTangentCCircleTool : gtkconobjs.two_cline_tancc_mode_init, tools.TextTool : gtktext.text_add_init, tools.HorizontalMoveTool : gtkmodify.move_horizontal_init, tools.VerticalMoveTool : gtkmodify.move_vertical_init, tools.MoveTool : gtkmodify.move_twopoint_init, tools.HorizontalStretchTool : gtkmodify.stretch_horizontal_init, tools.VerticalStretchTool : gtkmodify.stretch_vertical_init, tools.StretchTool : gtkmodify.stretch_xy_init, tools.TransferTool : gtkmodify.transfer_object_init, tools.RotateTool : gtkmodify.rotate_init, tools.SplitTool : gtkmodify.split_object_init, tools.DeleteTool : gtkmodify.delete_mode_init, tools.MirrorTool : gtkmirror.mirror_mode_init, tools.ZoomTool : gtkmodify.zoom_init, tools.LinearDimensionTool : gtkdimension.linear_mode_init, tools.HorizontalDimensionTool : gtkdimension.horizontal_mode_init, tools.VerticalDimensionTool : gtkdimension.vertical_mode_init, tools.RadialDimensionTool : gtkdimension.radial_mode_init, tools.AngularDimensionTool : gtkdimension.angular_mode_init, tools.PlotTool : gtkprinting.plot_mode_init, tools.ZoomPan : gtkmodify.zoomPan_init, } def __init__(self, image): debug_print("Initialized another GTKImage class instance...") if not isinstance(image, Image): raise TypeError, "Invalid Image type: " + `type(image)` self.__image = image self.__window = gtk.Window() self.__window.set_title(image.filename) self.__window.set_icon_from_file("gtkpycad.png") self.__window.connect("destroy", self.__destroyEvent) self.__window.connect("event", self.__windowEvent) self.__window.connect("key_press_event", self.__keyPressEvent) # # Zooming Moving global Variable Definition # self.__StartZooming= False self.__StartMoving = False self.StopMove=False self._activateSnap=False _width = min(1024, int(0.8 * float(gtk.gdk.screen_width()))) _height = min(768, int(0.8 * float(gtk.gdk.screen_height()))) self.__window.set_default_size(_width, _height) main_vbox = gtk.VBox(False, 2) main_vbox.set_border_width(2) self.__window.add(main_vbox) # # accelerators # self.__accel = gtk.AccelGroup() self.__window.add_accel_group(self.__accel) # # menu bar # self.__mb = gtk.MenuBar() main_vbox.pack_start(self.__mb, False, False) # # action group dictionary # self.__groups = {} # # fixme - try to rework code to avoid this import ... # from PythonCAD.Interface.Gtk.gtkmenus import fill_menubar fill_menubar(self.__mb, self) # # drawing window has Horizontal Pane: # left side: stuff for layer display # right side: drawing area # pane = gtk.HPaned() main_vbox.pack_start(pane) frame1 = gtk.Frame() pane.pack1(frame1, True, False) pane.set_position(100) # # layer display stuff # _ld = gtkshell.LayerDisplay(self.__image, self.__window) frame1.add(_ld.getWindow()) self.__layerdisplay = _ld # # drawing area # self.__disp_width = None self.__disp_height = None self.__units_per_pixel = 1.0 self.__da = gtk.DrawingArea() black = gtk.gdk.color_parse('black') self.__da.modify_fg(gtk.STATE_NORMAL, black) self.__da.modify_bg(gtk.STATE_NORMAL, black) pane.pack2(self.__da, True, False) self.__da.set_flags(gtk.CAN_FOCUS) self.__da.connect("event", self.__daEvent) self.__da.connect("expose_event", self.__exposeEvent) self.__da.connect("realize", self.__realizeEvent) self.__da.connect("configure_event", self.__configureEvent) # self.__da.connect("focus_in_event", self.__focusInEvent) # self.__da.connect("focus_out_event", self.__focusOutEvent) self.__da.set_events(gtk.gdk.EXPOSURE_MASK | gtk.gdk.LEAVE_NOTIFY_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.ENTER_NOTIFY_MASK| gtk.gdk.LEAVE_NOTIFY_MASK| gtk.gdk.KEY_PRESS_MASK | gtk.gdk.KEY_RELEASE_MASK | gtk.gdk.FOCUS_CHANGE_MASK | gtk.gdk.POINTER_MOTION_MASK) lower_hbox = gtk.HBox(False, 2) main_vbox.pack_start(lower_hbox, False, False) self.__prompt = gtk.Label(_('Enter Command:')) lower_hbox.pack_start(self.__prompt, False, False) # # where the action is taking place # self.__coords = gtk.Label('(0,0)') lower_hbox.pack_end(self.__coords, False, False) self.__image.setCurrentPoint(0.0, 0.0) # # command entry area # self.__entry = gtk.Entry() main_vbox.pack_start(self.__entry, False, False) self.__entry.connect("activate", self.__entryEvent) # # the Pixmap, GraphicContext, and CairoContext for the drawing # self.__pixmap = None self.__gc = None self.__ctx = None self.__refresh = True # # the viewable region and tolerance in the drawing # self.__xmin = None self.__ymin = None self.__xmax = None self.__ymax = None self.__tolerance = 1e-10 # # establish message connections # _image = self.__image _image.connect('selected_object', self.__selectedObject) _image.connect('deselected_object', self.__deselectedObject) _image.connect('option_changed', self.__optionChanged) _image.connect('current_point_changed', self.__currentPointChanged) _image.connect('active_layer_changed', self.__activeLayerChanged) _image.connect('added_child', self.__imageAddedChild) _image.connect('removed_child', self.__imageRemovedChild) _image.connect('group_action_started', self.__groupActionStarted) _image.connect('group_action_ended', self.__groupActionEnded) _image.connect('units_changed', self.__imageUnitsChanged) _image.connect('tool_changed', self.__imageToolChanged) _layers = [_image.getTopLayer()] while len(_layers): _layer = _layers.pop() _layer.connect('added_child', self.__layerAddedChild) _layer.connect('removed_child', self.__layerRemovedChild) for _child in _layer.getChildren(): _child.connect('refresh', self.__refreshObject) _child.connect('change_pending', self.__objChangePending) _child.connect('change_complete', self.__objChangeComplete) _layers.extend(_layer.getSublayers()) #------------------------------------------------------------------ def close(self): """Release the entites stored in the drawing. close() """ self.__layerdisplay.close() self.__layerdisplay = None _image = self.__image _image.close() _image.disconnect(self) _log = _image.getLog() if _log is not None: _log.detatch() _image.setLog(None) _image.finish() self.__window.destroy() self.__window = None self.__da = None self.__entry = None self.__accel = None self.__mb = None self.__pixmap = None self.__gc = None #------------------------------------------------------------------ def __destroyEvent(self, widget, data=None): """ Destroy event """ if self.__image.isSaved()== False: from PythonCAD.Interface.Gtk.gtkmenus import file_quit_cb file_quit_cb(None,self) self.close() for _i in xrange(len(globals.imagelist)): _gimage = globals.imagelist[_i] if self.__image is _gimage: del globals.imagelist[_i] if not len(globals.imagelist): gtk.main_quit() break return False #------------------------------------------------------------------ def __keyPressEvent(self, widget, event, data=None): #print "__keyPressEvent()" _entry = self.__entry if _entry.is_focus(): return False _tool = self.__image.getTool() if _tool is not None and _tool.hasHandler('entry_event'): _entry.grab_focus() return _entry.event(event) return False #------------------------------------------------------------------ def __windowEvent(self, widget, event, data=None): _type = event.type debug_print("__windowEvent: Event type: %d" % _type) if _type == gtk.gdk.BUTTON_PRESS: _button = event.button debug_print("BUTTON_PRESS: %d" % _button) elif _type == gtk.gdk.BUTTON_RELEASE: _button = event.button debug_print("BUTTON_RELEASE: %d" % _button) elif _type == gtk.gdk.KEY_PRESS: debug_print("KEY_PRESS") if event.keyval == gtk.keysyms.Escape: debug_print("Got escape key") self.reset() self._activateSnap=False return True elif _type == gtk.gdk.KEY_RELEASE: debug_print("KEY_RELEASE") else: pass return False #------------------------------------------------------------------ def __entryEvent(self, widget, data=None): # # The error handling in this function needs work, and probably # a rethink as how the commands are implemented is in order. Perhaps # the command set should be stored in the image's global dictionary? # debug_print("__entryEvent()") _entry = self.__entry _text = _entry.get_text().strip() if len(_text): _text = _text.lower() if _text == 'end' or _text == 'stop': _entry.delete_text(0,-1) self.reset() else: _tool = self.__image.getTool() if _tool is not None and _tool.hasHandler("entry_event"): _handler = _tool.getHandler("entry_event") try: _handler(self, widget, _tool) except StandardError, e: print "exception called: " + str(e) else: _cmds = keywords.defaultglobals _entry.delete_text(0,-1) # print "text is '%s'" % _text if _text in _cmds: # print "valid command" _opt = _cmds[_text] # print "opt: '%s'" % _opt _tooltype = prompt.lookup(_opt) # print "cmd: '%s'" % _cmd if _tooltype is not None: self.__image.setTool(_tooltype()) else: # print "Calling exec for '%s'" % _text # print "Command Error; See http://www.pythoncad.org/commands.html for reference page." try: exec _text in self.__image.getImageVariables() except: print "error executing '%s' " % _text # # set the focus back to the DisplayArea widget # self.__da.grab_focus() return False #------------------------------------------------------------------ def __exposeEvent(self, widget, event, data=None): # print "__exposeEvent()" _pixmap = self.__pixmap _x, _y, _w, _h = event.area _gc = widget.get_style().fg_gc[widget.state] widget.window.draw_drawable(_gc, _pixmap, _x, _y, _x, _y, _w, _h) return True #------------------------------------------------------------------ def __realizeEvent(self, widget, data=None): _win = widget.window _width, _height = _win.get_size() self.setSize(_width, _height) widget.set_size_request(100,100) _gc = _win.new_gc() _gc.set_exposures(True) self.setGC(_gc) #------------------------------------------------------------------ def __configureEvent(self, widget, event, data=None): _win = widget.window _width, _height = _win.get_size() _disp_width, _disp_height = self.getSize() if _disp_width != _width or _disp_height != _height: self.setSize(_width, _height) _pixmap = gtk.gdk.Pixmap(_win, _width, _height) _gc = widget.get_style().fg_gc[widget.state] _pixmap.draw_rectangle(_gc, True, 0, 0, _width, _height) self.setPixmap(_pixmap) if hasattr(_pixmap, 'cairo_create'): self.__ctx = _pixmap.cairo_create() _xmin = self.__xmin _ymin = self.__ymin if _xmin is None or _ymin is None: _xmin = 1.0 _ymin = 1.0 _upp = self.__units_per_pixel self.setView(_xmin, _ymin, _upp) return True #------------------------------------------------------------------ def __daEvent(self, widget, event, data=None): _rv = False _type = event.type debug_print("__daEvent(): Event type: %d" % _type) _tool = self.__image.getTool() if _type==31: debug_print("if 31") if event.direction == gtk.gdk.SCROLL_UP: debug_print("BUTTON_PRESSS CROLL_UP") self.ZoomIn() if event.direction == gtk.gdk.SCROLL_DOWN: debug_print("BUTTON_PRESSS SCROLL_DOWN") self.ZoomOut() if _type == 12: debug_print("if 12") if _type == gtk.gdk.BUTTON_PRESS: debug_print("gtk.gdk.BUTTON_PRESS") self.setToolpoint(event) _button = event.button if _button == 1: if _tool is not None and _tool.hasHandler("button_press"): _rv = _tool.getHandler("button_press")(self, widget, event, _tool) debug_print("__Move BUTTON_PRESS") self.__Move(widget, event) elif _type == gtk.gdk.BUTTON_RELEASE: debug_print("gtk.gdk.BUTTON_RELEASE") self.setToolpoint(event) _button = event.button if _button == 1: if _tool is not None and _tool.hasHandler("button_release"): _rv =_tool.getHandler("button_release")(self, widget, event, _tool) debug_print("__Move BUTTON_RELEASE") self.__Move(widget, event) elif _type == gtk.gdk.MOTION_NOTIFY: debug_print("gtk.gdk.MOTION_NOTIFY") self.setToolpoint(event) if _tool is not None and _tool.hasHandler("motion_notify"): _rv = _tool.getHandler('motion_notify')(self, widget, event, _tool) debug_print("__Move MOTION_NOTIFY") self.__MakeMove(widget,event) self.__ActiveSnapEvent(widget,event) elif _type == gtk.gdk.KEY_PRESS: debug_print("In __daEvent(), got key press!") _key = event.keyval if (_key == gtk.keysyms.Page_Up or _key == gtk.keysyms.Page_Down or _key == gtk.keysyms.Left or _key == gtk.keysyms.Right or _key == gtk.keysyms.Up or _key == gtk.keysyms.Down): debug_print("Got Arrow/PageUp/PageDown key") #KeyMoveDrawing(_key) # Matteo Boscolo 12-05-2009 pass # handle moving the drawing in some fashion ... elif _key == gtk.keysyms.Escape: debug_print("Got escape key") self.reset() _rv = True elif _tool is not None and _tool.hasHandler("key_press"): debug_print("gtk.gdk.MOTION_NOTIFY") _rv = _tool.getHandler("key_press")(self, widget, event, _tool) else: debug_print("ELSE") _entry = self.__entry _entry.grab_focus() if _key == gtk.keysyms.Tab: _rv = True else: _rv = _entry.event(event) elif _type == gtk.gdk.ENTER_NOTIFY: debug_print("gtk.gdk.ENTER_NOTIFY") self.setToolpoint(event) _rv = True elif _type == gtk.gdk.LEAVE_NOTIFY: debug_print("gtk.gdk.LEAVE_NOTIFY") self.setToolpoint(event) _rv = True else: debug_print("Got type %d" % _type) pass return _rv def KeyMoveDrawing(self,key): """Make A Move when the user press arrows keys""" self.__MovmentStep=10 #This mast be a global settings that the user can change actualStep=self.__MovmentStep actualX=self.__activeX actualY=self.__activeY newX=actualX newY=actualY if (key == gtk.keysyms.Page_Up): print("ZoomUp") if (key == gtk.keysyms.Page_Down): print("ZoomDown") if (key == gtk.keysyms.Left): newX=actualX-actualStep newY=actualY if (key == gtk.keysyms.Right): newX=actualX+actualStep newY=actualY if (key == gtk.keysyms.Up): newX=actualX newY=actualY+actualStep if (key == gtk.keysyms.Down): newX=actualX newY=actualY-actualStep self.MoveFromTo(actualX,actualY,newX,newY) #------------------------------------------------------------------ def __focusInEvent(self, widget, event, data=None): debug_print("in GTKImage::__focusInEvent()") return False #------------------------------------------------------------------ def __focusOutEvent(self, widget, event, data=None): debug_print("in GTKImage::__focusOutEvent()") return False #------------------------------------------------------------------ def __selectedObject(self, img, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _obj = args[0] if _debug: print "Selected object: " + `_obj` _parent = _obj.getParent() if _parent.isVisible() and _obj.isVisible(): _color = Color('#ff7733') # FIXME color should be adjustable _obj.draw(self, _color) self.__refresh = True #------------------------------------------------------------------ def __deselectedObject(self, img, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _obj = args[0] if _debug: print "Deselected object: " + `_obj` _parent = _obj.getParent() if _parent.isVisible() and _obj.isVisible(): _obj.draw(self) self.__refresh = True #------------------------------------------------------------------ def __optionChanged(self, img, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _opt = args[0] if _debug: print "Option changed: '%s'" % _opt if _opt == 'BACKGROUND_COLOR': _bc = self.__image.getOption('BACKGROUND_COLOR') _col = gtk.gdk.color_parse(str(_bc)) self.__da.modify_fg(gtk.STATE_NORMAL, _col) self.__da.modify_bg(gtk.STATE_NORMAL, _col) self.redraw() elif (_opt == 'HIGHLIGHT_POINTS' or _opt == 'INACTIVE_LAYER_COLOR' or _opt == 'SINGLE_POINT_COLOR' or _opt == 'MULTI_POINT_COLOR'): self.redraw() else: pass #------------------------------------------------------------------ def __currentPointChanged(self, img, *args): _x, _y = self.__image.getCurrentPoint() self.__coords.set_text("%.4f, %.4f" % (_x, _y)) #------------------------------------------------------------------ def __activeLayerChanged(self, img, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _prev_layer = args[0] self.drawLayer(_prev_layer) _active_layer = self.__image.getActiveLayer() self.drawLayer(_active_layer) self.refresh() # def getImage(self): """Return the Image being displayed. getImage() """ return self.__image image = property(getImage, None, None, "Displayed Image") #------------------------------------------------------------------ def getAccel(self): """Return the gtk.AccelGroup in the GTKImage. getAccel() """ return self.__accel accel = property(getAccel, None, None, "Accel group in the GTKImage.") #------------------------------------------------------------------ def getWindow(self): """Return a handle to the gtk.Window in the GTKImage. getWindow() """ return self.__window window = property(getWindow, None, None, "Main GTK Window for a GTKImage.") #------------------------------------------------------------------ def getEntry(self): """Return a handle to the gtk.Entry in the GTKImage. getEntry() """ return self.__entry entry = property(getEntry, None, None, "Entry box for a GTKImage.") #------------------------------------------------------------------ def getDA(self): """Return the gtk.DrawingArea in the GTKImage. getDA() """ return self.__da da = property(getDA, None, None, "DrawingArea for a GTKImage.") #------------------------------------------------------------------ def getPixmap(self): """Return the Pixmap for the GTKImage. getPixmap() """ return self.__pixmap #------------------------------------------------------------------ def setPixmap(self, pixmap): """Set the Pixmap for the GTKImage. setPixmap(pixmap) """ self.__pixmap = pixmap pixmap = property(getPixmap, setPixmap, None, "Pixmap for a GTKImage.") #------------------------------------------------------------------ def getPrompt(self): """Return the current prompt string. getPrompt() """ return self.__prompt.get_label() #------------------------------------------------------------------ def setPrompt(self, p): """Set the current prompt string. setPrompt(p) """ if not isinstance(p, types.StringTypes): raise TypeError, "Invalid prompt type: " + `type(p)` self.__prompt.set_text(p) prompt = property(getPrompt, setPrompt, None, "Prompt string.") #------------------------------------------------------------------ def setTool(self, tool): """Replace the tool in the image with a new Tool. setTool(tool) The argument 'tool' should be an instance of a Tool object. """ warnings.warn("Method setTool() is deprecated - use getImage().setTool()", stacklevel=2) self.__image.setTool(tool) #------------------------------------------------------------------ def getTool(self): """Return the current Tool used in the drawing. getTool() """ warnings.warn("Method getTool() is deprecated - use getImage().getTool()", stacklevel=2) return self.__image.getTool() tool = property(getTool, None, None, "Tool for adding/modifying entities.") #------------------------------------------------------------------ def getUnitsPerPixel(self): """Return the current value of units/pixel. getUnitsPerPixel() """ return self.__units_per_pixel #------------------------------------------------------------------ def setUnitsPerPixel(self, upp): """Set the current value of units/pixel. setUnitsPerPixel(upp) The argument 'upp' should be a positive float value. """ _upp = upp if not isinstance(_upp, float): _upp = float(upp) if _upp < 1e-10: raise ValueError, "Invalid scale value: %g" % _upp self.__units_per_pixel = _upp self.__tolerance = _upp * 5.0 #------------------------------------------------------------------ def setView(self, xmin, ymin, scale=None): """Set the current visible area in a drawing. setView(xmin, ymin[, scale]) xmin: Minimum visible x-coordinate ymin: Minimum visible y-coordinate The optional argument 'scale' defaults to the current value of units/pixel (set with getUnitsPerPixel() method.) This value must be a positive float. """ _xmin = xmin if not isinstance(_xmin, float): _xmin = float(xmin) _ymin = ymin if not isinstance(_ymin, float): _ymin = float(ymin) _scale = scale if _scale is None: _scale = self.__units_per_pixel if not isinstance(_scale, float): _scale = float(scale) if _scale < 1e-10: raise ValueError, "Invalid scale value: %g" % _scale _xmax = _xmin + (_scale * self.__disp_width) _ymax = _ymin + (_scale * self.__disp_height) _recalc = False if abs(_scale - self.__units_per_pixel) > 1e-10: self.__units_per_pixel = _scale _recalc = True self.__tolerance = self.__units_per_pixel * 5.0 self.__xmin = _xmin self.__ymin = _ymin self.__xmax = _xmax self.__ymax = _ymax if _recalc: self.calcTextWidths() self.redraw() def calcTextWidths(self): """Calculate the width of the text strings in the Image. calcTextWidths() """ _layers = [self.__image.getTopLayer()] while len(_layers): _layer = _layers.pop() for _tblock in _layer.getLayerEntities('text'): gtktext.set_textblock_bounds(self, _tblock) for _dim in _layer.getLayerEntities('linear_dimension'): _ds1, _ds2 = _dim.getDimstrings() gtktext.set_textblock_bounds(self, _ds1) if _dim.getDualDimMode(): gtktext.set_textblock_bounds(self, _ds2) for _dim in _layer.getLayerEntities('horizontal_dimension'): _ds1, _ds2 = _dim.getDimstrings() gtktext.set_textblock_bounds(self, _ds1) if _dim.getDualDimMode(): gtktext.set_textblock_bounds(self, _ds2) for _dim in _layer.getLayerEntities('vertical_dimension'): _ds1, _ds2 = _dim.getDimstrings() gtktext.set_textblock_bounds(self, _ds1) if _dim.getDualDimMode(): gtktext.set_textblock_bounds(self, _ds2) for _dim in _layer.getLayerEntities('radial_dimension'): _ds1, _ds2 = _dim.getDimstrings() gtktext.set_textblock_bounds(self, _ds1) if _dim.getDualDimMode(): gtktext.set_textblock_bounds(self, _ds2) for _dim in _layer.getLayerEntities('angular_dimension'): _ds1, _ds2 = _dim.getDimstrings() gtktext.set_textblock_bounds(self, _ds1) if _dim.getDualDimMode(): gtktext.set_textblock_bounds(self, _ds2) _layers.extend(_layer.getSublayers()) def getView(self): """Return the current visible area in a drawing. getView() This method returns a tuple with four float values: (xmin, ymin, xmax, ymax) If the view has never been set, each of these values will be None. """ return (self.__xmin, self.__ymin, self.__xmax, self.__ymax) view = property(getView, setView, None, "The visible area in a drawing.") def getTolerance(self): """Return the current drawing tolerance. getTolerance() """ return self.__tolerance tolerance = property(getTolerance, None, None, "Drawing tolerance.") def getGC(self): """Return the GraphicContext allocated for the GTKImage. getGC() """ return self.__gc def setGC(self, gc): """Set the GraphicContext for the GTKImage. setGC(gc) """ if not isinstance(gc, gtk.gdk.GC): raise TypeError, "Invalid GC object: " + `gc` if self.__gc is None: self.__gc = gc gc = property(getGC, None, None, "GraphicContext for the GTKImage.") def getCairoContext(self): """Return the CairoContext allocated for the GTKImage. getCairoContext() """ return self.__ctx ctx = property(getCairoContext, None, None, "CairoContext for the GTKImage.") def getSize(self): """Return the size of the DrawingArea window. getSize() """ return (self.__disp_width, self.__disp_height) def setSize(self, width, height): """Set the size of the DrawingArea window. setSize(width, height) """ _width = width if not isinstance(_width, int): _width = int(width) if _width < 0: raise ValueError, "Invalid drawing area width: %d" % _width _height = height if not isinstance(_height, int): _height = int(height) if _height < 0: raise ValueError, "Invalid drawing area height: %d" % _height self.__disp_width = _width self.__disp_height = _height def setToolpoint(self, event): _x = event.x _y = event.y _tx, _ty = self.pixToCoordTransform(_x, _y) self.__image.setCurrentPoint(_tx, _ty) def addGroup(self, group): """Add an ActionGroup to the GTKImage. addGroup(group) Argument 'group' must be either an instance of either gtk.Action gtk.stdAction. """ if not isinstance(group, gtk.ActionGroup): if not isinstance(gtkactions.stdActionGroup): raise TypeError, "Invalid group type: " + `type(group)` self.__groups[group.get_name()] = group def getGroup(self, name): """Return an ActionGroup stored in the GTKImage. getGroup(name) Argument 'name' should be the name of the ActionGroup. This method will return None if no group by that name is stored. """ return self.__groups.get(name) def deleteGroup(self, name): """Remove an ActionGroup stored in the GTKImage. deleteGroup(name) Argument 'name' should be the name of the ActionGroup to be removed. """ if name in self.__groups: del self.__groups[name] def pixToCoordTransform(self, xp, yp): """Convert from pixel coordinates to x-y coordinates. pixToCoordTransform(xp, yp) The function arguments are: xp: pixel x value yp: pixel y value The function returns a tuple holding two float values """ _upp = self.__units_per_pixel _xc = self.__xmin + (xp * _upp) _yc = self.__ymax - (yp * _upp) return (_xc, _yc) #------------------------------------------------------------------ def coordToPixTransform(self, xc, yc): """Convert from x-y coordinates to pixel coordinates coordToPixTransform(xc, yc) The function arguments are: xc: x coordinate yp: y coordinate The function returns a tuple holding two integer values """ _upp = self.__units_per_pixel _xp = int((xc - self.__xmin)/_upp) _yp = int((self.__ymax - yc)/_upp) return _xp, _yp #------------------------------------------------------------------ def getColor(self, c): """Return an allocated color for a given Color object. getColor(c) Argument 'c' must be a Color object. This method will return an allocated color. """ if not isinstance(c, Color): raise TypeError, "Invalid Color object: " + `type(c)` _color = globals.gtkcolors.get(c) if _color is None: # _r = int(round(65535.0 * (c.r/255.0))) # _g = int(round(65535.0 * (c.g/255.0))) # _b = int(round(65535.0 * (c.b/255.0))) # _color = self.__da.get_colormap().alloc_color(_r, _g, _b) _color = self.__da.get_colormap().alloc_color(str(c)) globals.gtkcolors[c] = _color return _color #------------------------------------------------------------------ def fitImage(self): """Redraw the image so all entities are visible in the window. fitImage() """ _fw = float(self.__disp_width) _fh = float(self.__disp_height) _xmin, _ymin, _xmax, _ymax = self.__image.getExtents() _xdiff = abs(_xmax - _xmin) _ydiff = abs(_ymax - _ymin) _xmid = (_xmin + _xmax)/2.0 _ymid = (_ymin + _ymax)/2.0 _xs = _xdiff/_fw _ys = _ydiff/_fh if _xs > _ys: _scale = _xs * 1.05 # make it a little larger else: _scale = _ys * 1.05 # make it a little larger _xm = _xmid - (_fw/2.0) * _scale _ym = _ymid - (_fh/2.0) * _scale self.setView(_xm, _ym, _scale) #------------------------------------------------------------------ def refresh(self): """This method does a screen refresh. refresh() If entities in the drawing have been added, removed, or modified, use the redraw() method. """ _da = self.__da if (_da.flags() & gtk.MAPPED): # print "refreshing ..." _gc = _da.get_style().fg_gc[gtk.STATE_NORMAL] _gc.set_function(gtk.gdk.COPY) _da.queue_draw() #------------------------------------------------------------------ def redraw(self): """ This method draws all the objects visible in the window. """ _da = self.__da if (_da.flags() & gtk.MAPPED): if _debug: print "Redrawing image" _xmin = self.__xmin _ymin = self.__ymin _xmax = self.__xmax _ymax = self.__ymax _gc = _da.get_style().fg_gc[gtk.STATE_NORMAL] self.__pixmap.draw_rectangle(_gc, True, 0, 0, self.__disp_width, self.__disp_height) _active_layer = self.__image.getActiveLayer() _layers = [self.__image.getTopLayer()] while (len(_layers)): _layer = _layers.pop() if _layer is not _active_layer: self.drawLayer(_layer) _layers.extend(_layer.getSublayers()) self.drawLayer(_active_layer) # # redraw selected entities # _color = Color('#ff7733') for _obj in self.__image.getSelectedObjects(False): _obj.draw(self, _color) self.refresh() #------------------------------------------------------------------ def drawLayer(self, l): if not isinstance(l, Layer): raise TypeError, "Invalid layer type: " + `type(l)` if l.getParent() is not self.__image: raise ValueError, "Layer not found in Image" if l.isVisible(): _col = self.__image.getOption('INACTIVE_LAYER_COLOR') if l is self.__image.getActiveLayer(): _col = None _cobjs = [] _objs = [] _pts = [] for _obj in l.objsInRegion(self.__xmin, self.__ymin, self.__xmax, self.__ymax): if _obj.isVisible(): if isinstance(_obj, Point): _pts.append(_obj) elif isinstance(_obj, ConstructionObject): _cobjs.append(_obj) else: _objs.append(_obj) for _obj in _cobjs: _obj.draw(self, _col) for _obj in _pts: _obj.draw(self, _col) for _obj in _objs: _obj.draw(self, _col) #------------------------------------------------------------------ def ZoomIn(self,scaleFactor=None): _xmin, _ymin, _xmax, _ymax = self.getView() if(scaleFactor==None): _scale = self.getUnitsPerPixel() else: _scale=scaleFactor _xdiff = abs(_xmax - _xmin) _ydiff = abs(_ymax - _ymin) _xmin = (_xmin + _xmax)/2.0 - _xdiff/4.0 _ymin = (_ymin + _ymax)/2.0 - _ydiff/4.0 self.setView(_xmin, _ymin, (_scale/2)) #------------------------------------------------------------------ def ZoomOut(self,scaleFactor=None): _xmin, _ymin, _xmax, _ymax = self.getView() if(scaleFactor==None): _scale = self.getUnitsPerPixel() else: _scale=scaleFactor _xdiff = abs(_xmax - _xmin) _ydiff = abs(_ymax - _ymin) _xmin = (_xmin + _xmax)/2.0 - _xdiff _ymin = (_ymin + _ymax)/2.0 - _ydiff self.setView(_xmin, _ymin, (_scale * 2)) #------------------------------------------------------------------ def reset(self): """ Set the image to an initial drawing state. """ _tool = self.__image.getTool() if _tool is None: # # If _tool is None, deselect any selected objects in view. # This way, if you are currently using a tool, then the # first time you hit escape, you just clear the tool. # The second time clears all selections. debug_print("Entered reset") if _tool is None: debug_print(".....This is second time to be in reset") self.__image.clearSelectedObjects() self.__image.setTool() self.redraw() self.setPrompt(_('Enter command')) # # Entity drawing operations # def __drawObject(self, obj, col=None): # print "__drawObject()" _col = col if self.__xmin is None: return _xmin, _ymin, _xmax, _ymax = self.getView() if obj.inRegion(_xmin, _ymin, _xmax, _ymax): _image = self.__image if _col is None: if obj.getParent() is not _image.getActiveLayer(): _col = _image.getOption('INACTIVE_LAYER_COLOR') obj.draw(self, _col) self.__refresh = True def __eraseObject(self, obj): # print "__eraseObject()" _xmin, _ymin, _xmax, _ymax = self.getView() if self.__xmin is None: return if obj.inRegion(_xmin, _ymin, _xmax, _ymax): obj.erase(self) self.__refresh = True def __imageAddedChild(self, obj, *args): # print "__imageAddedChild()" _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _layer = args[0] if not isinstance(_layer, Layer): raise TypeError, "Unexpected child type: " + `type(_layer)` _layer.connect('added_child', self.__layerAddedChild) _layer.connect('removed_child', self.__layerRemovedChild) def __layerAddedChild(self, obj, *args): # print "__layerAddedChild()" _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _child = args[0] # need some verification test here ... _child.connect('refresh', self.__refreshObject) _child.connect('change_pending', self.__objChangePending) _child.connect('change_complete', self.__objChangeComplete) if _child.isVisible() and obj.isVisible(): self.__drawObject(_child) def __imageRemovedChild(self, obj, *args): # print "__imageRemovedChild()" _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _layer = args[0] if not isinstance(_layer, Layer): raise TypeError, "Unexpected child type: " + `type(_layer)` _layer.disconnect(self) def __layerRemovedChild(self, obj, *args): # print "__layerRemovedChild()" _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _child = args[0] # need some verification test here ... if _child.isVisible() and obj.isVisible(): self.__eraseObject(_child) _child.disconnect(self) def __groupActionStarted(self, obj, *args): # print "__groupActionStarted()" self.__refresh = False def __groupActionEnded(self, obj, *args): # print "__groupActionEnded()" if self.__refresh: self.refresh() else: self.__refresh = True def __imageUnitsChanged(self, obj, *args): # print "__imageUnitsChanged()" self.redraw() def __imageToolChanged(self, obj, *args): _tool = self.__image.getTool() if _tool is not None: _init = GTKImage.__inittool.get(type(_tool)) if _init is not None: _init(self) def __objChangePending(self, obj, *args): # print "__objChangePending()" + `obj` _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _change = args[0] if (obj.isVisible() and obj.getParent().isVisible() and _change != 'added_user' and _change != 'removed_user'): self.__eraseObject(obj) def __objChangeComplete(self, obj, *args): # print "__objChangeComplete()" + `obj` if obj.isVisible() and obj.getParent().isVisible(): self.__drawObject(obj) def __refreshObject(self, obj, *args): # print "__refreshObject()" _col = None if not obj.isVisible() or not obj.getParent().isVisible(): _col = self.__image.getOption('BACKGROUND_COLOR') self.__drawObject(obj, _col) #++ Matteo Boscolo def __Move(self, widget, event): """ set the Global Variable for controlling the zoom and moving of the drawing """ if(self.StopMove): return _type = event.type _button = event.button if(_button==3): if(_type==4): self.__activeX=event.x self.__activeY=event.y self.__StartMoving = True if(_type==7): self.__StartMoving = False if(_button==2): if(_type==4): self.__StartZooming = True if(_type==7): self.__StartZooming= False def __MakeMove(self, widget, event): if(self.__StartZooming): ActiveScale = self.getUnitsPerPixel() midX=abs(self.__xmin-self.__xmax)/2 midY=abs(self.__ymin-self.__ymax)/2 if(self.__activeY>event.y): ActiveScale=ActiveScale*1.05 #self.setView(midX,midY,ActiveScale) self.ZoomScale(ActiveScale) elif(self.__activeYxTo): self.__xmin=self.__xmin+deltaX self.__xmax=self.__xmax+deltaX else: self.__xmin=self.__xmin-deltaX self.__xmax=self.__xmax-deltaX if(yFrom>yTo): self.__ymin=self.__ymin-deltaY self.__ymax=self.__ymax-deltaY else: self.__ymin=self.__ymin+deltaY self.__ymax=self.__ymax+deltaY self.redraw() def ZoomScale(self,scale): """ Make a drawing zoom of the scale quantity """ _fw = float(self.__disp_width) _fh = float(self.__disp_height) _xdiff = abs(self.__xmax-self.__xmin) _ydiff = abs(self.__ymax-self.__ymin) _xmid = (self.__xmin + self.__xmax)/2.0 _ymid = (self.__ymin + self.__ymax)/2.0 _xm = _xmid - (_fw/2.0) * scale _ym = _ymid - (_fh/2.0) * scale self.setView(_xm, _ym, scale) def StartPanImage(self): """ Start Pan Image """ self.StopMove=True self.__StartMoving=True def StopPanImage(self): """ Stop Pan Operation """ self.StopMove=False self.__StartMoving=False def isPan(self): """ Return the active pan status """ return self.StopMove def setCursor(self,drwArea,snObject): """ active Snap cursor shape """ _win=drwArea.get_parent_window() if snObject is None or snObject.entity is None: _snapCursor=gtk.gdk.Cursor(gtk.gdk.TOP_LEFT_ARROW) else: _snapCursor=snObject.cursor _win.set_cursor(_snapCursor) def __ActiveSnapEvent(self,drwArea,event): """ Snap Event """ cursor=None if(self._activateSnap): _sobj=self.__image.snapProvider.getSnap(self.__tolerance,globals.snapOption) self.setCursor(drwArea,_sobj) else: self.setCursor(drwArea,None) def activateSnap(self): """ Activate the snap functionality """ self._activateSnap=True #-- Matteo Boscolo #------------------------------------------------------------------ def debug_print(string): if _debug is True: print "SDB Debug: " + string PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkmenus.py0000644000175000017500000032013411307674165021613 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the termscl_bo of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # ################################################################ # # This file contains the GTK Menu building code # ################################################################ import os import stat import sys _debug = False if _debug: try: import gc gc.set_debug(gc.DEBUG_LEAK) except ImportError: pass import pygtk pygtk.require('2.0') import gtk import gtk.keysyms from PythonCAD.Interface.Gtk.gtkimage import GTKImage from PythonCAD.Interface.Gtk import gtkentities from PythonCAD.Interface.Gtk import gtkprefs from PythonCAD.Interface.Gtk import gtkmodify from PythonCAD.Interface.Gtk import gtktext from PythonCAD.Interface.Gtk import gtkprinting from PythonCAD.Interface.Gtk import gtkactions from PythonCAD.Generic import globals from PythonCAD.Generic import fileio from PythonCAD.Generic import imageio from PythonCAD.Generic import tools from PythonCAD.Generic import plotfile from PythonCAD.Generic import text from PythonCAD.Generic import graphicobject from PythonCAD.Generic import dimension from PythonCAD.Generic import extFormat from PythonCAD.Generic.image import Image from PythonCAD.Interface.Gtk import gtkdimprefs from PythonCAD.Interface.Gtk import gtktextprefs from PythonCAD.Interface.Gtk import gtkstyleprefs from PythonCAD.Interface.Gtk import gtkDialog if not hasattr(gtk, 'Action'): gtk.Action = gtkactions.stdAction gtk.ActionGroup = gtkactions.stdActionGroup select_menu = [ ('SelectAllPoints', 'point',_('_Points')), ('SelectAllSegments','segment',_('_Segments')), ('SelectAllCircles','circle',_('_Circles')), ('SelectAllArcs','arc',_('_Arcs')), ('SelectAllLeaders','leader',_('_Leaders')), ('SelectAllPolylines','polyline',_('_Polylines')), ('SelectAllChamfers','chamfer',_('Cha_mfers')), ('SelectAllFillets','fillet',_('_Fillets')), (None, None, None), ('SelectAllHCLines','hcline',_('_HCLines')), ('SelectAllVCLines','vcline',_('_VCLines')), ('SelectAllACLines','acline',_('_ACLines')), ('SelectAllCLines','cline',_('C_Lines')), ('SelectAllCCircles','ccircle',_('CCircles')), (None, None, None), ('SelectAllTextBlocks','textblock',_('TextBlocks')), (None, None, None), ('SelectAllLDims','linear_dimension',_('Linear Dim.')), ('SelectAllHDims','horizontal_dimension',_('Horiz. Dim.')), ('SelectAllVDims','vertical_dimension',_('Vert. Dim.')), ('SelectAllRDims','radial_dimension',_('Radial Dim.')), ('SelectAllADims','angular_dimension',_('Angular Dim.')), ] ############################################################################# # # callbacks for the menu items # ############################################################################# def file_new_cb(menuitem, data=None): _image = Image() _gtkimage = GTKImage(_image) _background = globals.prefs['BACKGROUND_COLOR'] _image.setOption('BACKGROUND_COLOR', _background) globals.imagelist.append(_image) _gtkimage.window.show_all() #------------------------------------------------------------ def file_open_cb(menuitem, gtkimage): _open = False _fname = None _dialog = gtk.FileChooserDialog(title=_('Open File ...'), buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_OK), action=gtk.FILE_CHOOSER_ACTION_OPEN) while not _open: _response = _dialog.run() if _response == gtk.RESPONSE_OK: _fname = _dialog.get_filename() if os.path.isdir(_fname): _fname += "/" _dialog.set_filename(_fname) _response = _dialog.run() else: _open = True else: break _dialog.destroy() if _open: _image = Image() try: _handle = fileio.CompFile(_fname, "r") try: imageio.load_image(_image, _handle) finally: _handle.close() except (IOError, OSError), e: _errmsg = "Error opening '%s' : %s'" % (_fname, e) _error_dialog(gtkimage, _errmsg) return except StandardError, e: _errmsg = "Non-system error opening '%s' : %s'" % (_fname, e) _error_dialog(gtkimage, _errmsg) return globals.imagelist.append(_image) _image.setFilename(_fname) _gtkimage = GTKImage(_image) _window = _gtkimage.getWindow() _window.set_title(os.path.basename(_fname)) _window.show_all() _gtkimage.fitImage() #------------------------------------------------------------ def file_close_cb(menuitem, gtkimage): """ Close the application """ for _i in xrange(len(globals.imagelist)): _image = globals.imagelist[_i] if _image is gtkimage.image: if _image.isSaved()==False: print "ask for saving" #implement it matteo boscolo _log = _image.getLog() if _log is not None: _log.detatch() del globals.imagelist[_i] gtkimage.window.destroy() if not len(globals.imagelist): gtk.main_quit() break #------------------------------------------------------------ def _error_dialog(gtkimage, errmsg): _window = gtkimage.getWindow() _dialog = gtk.MessageDialog( _window, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, errmsg) _dialog.run() _dialog.destroy() #------------------------------------------------------------ def _save_file(gtkimage, filename): _image = gtkimage.getImage() _image.save() #------------------------------------------------------------ def _writecopy(src, dst): if sys.platform == 'win32': _rmode = 'rb' _wmode = 'wb' else: _rmode = 'r' _wmode = 'w' _from = file(src, _rmode) try: _to = file(dst, _wmode) try: while True: _data = _from.read(8192) if _data == '': break _to.write(_data) finally: _to.close() finally: _from.close() #------------------------------------------------------------ def _save_file_by_copy(gtkimage, filename): _image = gtkimage.getImage() _abs = os.path.abspath(filename) _bname = os.path.basename(_abs) if _bname.endswith('.gz'): _bname = _bname[:-3] _newfile = _abs + '.new' _handle = fileio.CompFile(_newfile, "w", truename=_bname) try: imageio.save_image(_image, _handle) finally: _handle.close() _backup = _abs + '~' if os.path.exists(_abs): _writecopy(_abs, _backup) try: _writecopy(_newfile, _abs) except: _writecopy(_backup, _abs) raise os.unlink(_newfile) if _image.getFilename() is None: _image.setFilename(_abs) #------------------------------------------------------------ def _get_filename_and_save(gtkimage, fname=None): _window = gtkimage.getWindow() _fname = fname if _fname is None: _fname = _window.get_title() _dialog = gtk.FileChooserDialog(title=_('Save As ...'), buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_OK), action=gtk.FILE_CHOOSER_ACTION_SAVE) _dialog.set_filename(_fname) _response = _dialog.run() _save = False if _response == gtk.RESPONSE_OK: _save = True _fname = _dialog.get_filename() if _fname == "": _fname = 'Untitled.xml' if not _fname.endswith('.xml.gz'): if not _fname.endswith('.xml'): _fname = _fname + '.xml' # # if the filename already exists see that the user # really wants to overwrite it ... # # test for the filename + '.gz' # if _fname.endswith('.xml.gz'): _gzfile = _fname else: _gzfile = _fname + '.gz' if os.path.exists(_gzfile): _save = False _dialog2 = gtk.Dialog(_('Overwrite Existing File'), _window, gtk.DIALOG_MODAL, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 10) _hbox.set_border_width(10) _dialog2.vbox.pack_start(_hbox, False, False, 0) _stock = gtk.image_new_from_stock(gtk.STOCK_DIALOG_QUESTION, gtk.ICON_SIZE_DIALOG) _hbox.pack_start(_stock, False, False, 0) _label = gtk.Label(_('File already exists. Delete it?')) _hbox.pack_start(_label, False, False, 0) _dialog2.show_all() _response = _dialog2.run() if _response == gtk.RESPONSE_OK: _save = True _dialog2.destroy() _dialog.destroy() if _save: # print "name: " + _gzfile gtkimage.image.setFilename(_gzfile) _window.set_title(os.path.basename(_gzfile)) try: _save_file(gtkimage, _gzfile) except (IOError, OSError), _e: _errmsg = "Error saving '%s' : %s'" % (_gzfile, _e) _error_dialog(gtkimage, _errmsg) except StandardError, _e: _errmsg = "Non-system error saving '%s' : %s'" % (_gzfile, _e) _error_dialog(gtkimage, _errmsg) #------------------------------------------------------------ def file_save_cb(menuitem, gtkimage): _fname = gtkimage.image.getFilename() if _fname is None: _get_filename_and_save(gtkimage) else: try: _save_file(gtkimage, _fname) except (IOError, OSError), _e: _errmsg = "Error saving '%s' : %s'" % (_fname, _e) _error_dialog(gtkimage, _errmsg) except StandardError, _e: _errmsg = "Non-system error saving '%s' : %s'" % (_fname, _e) _error_dialog(gtkimage, _errmsg) #------------------------------------------------------------ def file_save_as_cb(menuitem, gtkimage): _fname = gtkimage.image.getFilename() if _fname is None: _fname = gtkimage.getWindow().get_title() _get_filename_and_save(gtkimage, _fname) #------------------------------------------------------------ def file_save_layer_cb(menuitem, gtkimage): # print "called file_save_layer_cb()" active = gtkimage.image.getActiveLayer() layer_name = active.getName() dialog = gtk.FileSelection("Save Layer As ...") dialog.set_transient_for(gtkimage.getWindow()) dialog.set_filename(layer_name) response = dialog.run() if response == gtk.RESPONSE_OK: fname = dialog.get_filename() print "Saving layer as '%s'" % fname # # fixme - add the layer saving code ... # dialog.destroy() #------------------------------------------------------------ def file_print_screen_cb(menuitem, gtkimage): _plot = plotfile.Plot(gtkimage.image) _xmin, _ymin, _xmax, _ymax = gtkimage.getView() _plot.setBounds(_xmin, _ymin, _xmax, _ymax) gtkprinting.print_dialog(gtkimage, _plot) #------------------------------------------------------------ def file_print_cb(menuitem, gtkimage): _tool = tools.PlotTool() gtkimage.getImage().setTool(_tool) #------------------------------------------------------------ def file_quit_cb(menuitem, gtkimage): _image=gtkimage.getImage() if _image.isSaved()==False: _res=gtkDialog._yesno_dialog(gtkimage,"File Unsaved, Wold You Like To Save ?") if gtk.RESPONSE_ACCEPT == _res: file_save_cb(None, gtkimage) gtk.main_quit() #------------------------------------------------------------ def _select_all_cb(menuitem, gtkimage): _group = gtkimage.getGroup('Edit') if _group is not None: _layer = gtkimage.image.getActiveLayer() for _action, _entity, _menuitem in select_menu: if _action is None: continue _act = _group.get_action(_action) if _act is not None: _act.set_property('sensitive', _layer.getEntityCount(_entity) > 0) #------------------------------------------------------------ def edit_undo_cb(menuitem, gtkimage): gtkimage.image.doUndo() gtkimage.redraw() #------------------------------------------------------------ def edit_redo_cb(menuitem, gtkimage): gtkimage.image.doRedo() gtkimage.redraw() #------------------------------------------------------------ def edit_copy_cb(menuitem, gtkimage): for _obj in gtkimage.image.getSelectedObjects(): if _obj.getParent() is not None: globals.selectobj.storeObject(_obj) #------------------------------------------------------------ def edit_cut_cb(menuitem, gtkimage): _image = gtkimage.getImage() _image.startAction() try: for _obj in _image.getSelectedObjects(): globals.selectobj.storeObject(_obj) # # check that the object parent is not None - if it # is then the object was deleted as a result of the # deletion of an earlier object (i.e. dimension) # _layer = _obj.getParent() if _layer is not None: _layer.delObject(_obj) finally: _image.endAction() #------------------------------------------------------------ def edit_paste_cb(menuitem, gtkimage): _tool = tools.PasteTool() gtkimage.getImage().setTool(_tool) #------------------------------------------------------------ def edit_select_cb(menuitem, gtkimage): _tool = tools.SelectTool() gtkimage.getImage().setTool(_tool) #------------------------------------------------------------ def edit_deselect_cb(menuitem, gtkimage): _tool = tools.DeselectTool() gtkimage.getImage().setTool(_tool) #------------------------------------------------------------ def select_all_objects_cb(menuitem, ge): _gtkimage, _entity = ge _image = _gtkimage.getImage() _active_layer = _image.getActiveLayer() _image.sendMessage('group_action_started') try: for _obj in _active_layer.getLayerEntities(_entity): _image.selectObject(_obj) finally: _image.sendMessage('group_action_ended') def units_cb(menuitem, gtkimage): gtkentities.set_units_dialog(gtkimage) def toggle_cb(menuitem, gtkimage): gtkentities.set_toggle_dialog(gtkimage) def prefs_cb(menuitem, gtkimage): gtkprefs.prefs_dialog(gtkimage) def colors_cb(menuitem, gtkimage): gtkentities.set_colors_dialog(gtkimage) def sizes_cb(menuitem, gtkimage): gtkentities.set_sizes_dialog(gtkimage) def style_cb(menuitem, gtkimage): gtkstyleprefs.style_dialog(gtkimage, globals.prefs['STYLES'], globals.prefs['LINETYPES']) def textstyle_cb(menuitem, gtkimage): gtkimage.activateSnap() gtktextprefs.textstyle_dialog(gtkimage, globals.prefs['TEXTSTYLES']) def dimstyle_cb(menuitem, gtkimage): gtkimage.activateSnap() gtkdimprefs.dimstyle_dialog(gtkimage, globals.prefs['DIMSTYLES']) def draw_point_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.PointTool() gtkimage.getImage().setTool(_tool) def draw_segment_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.SegmentTool() gtkimage.getImage().setTool(_tool) def draw_rectangle_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.RectangleTool() gtkimage.getImage().setTool(_tool) def draw_circle_center_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.CircleTool() gtkimage.getImage().setTool(_tool) def draw_circle_tp_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.TwoPointCircleTool() gtkimage.getImage().setTool(_tool) def draw_arc_center_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.ArcTool() gtkimage.getImage().setTool(_tool) def draw_hcl_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.HCLineTool() gtkimage.getImage().setTool(_tool) def draw_vcl_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.VCLineTool() gtkimage.getImage().setTool(_tool) def draw_acl_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.ACLineTool() gtkimage.getImage().setTool(_tool) def draw_cl_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.CLineTool() gtkimage.getImage().setTool(_tool) def draw_perpendicular_cline_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.PerpendicularCLineTool() gtkimage.getImage().setTool(_tool) def draw_tangent_cline_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.TangentCLineTool() gtkimage.getImage().setTool(_tool) def draw_tangent_two_ccircles_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.CCircleTangentLineTool() gtkimage.getImage().setTool(_tool) def draw_poffset_cline_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.ParallelOffsetTool() gtkimage.getImage().setTool(_tool) def draw_ccirc_cp_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.CCircleTool() gtkimage.getImage().setTool(_tool) def draw_ccirc_tp_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.TwoPointCCircleTool() gtkimage.getImage().setTool(_tool) def draw_tangent_single_conobj_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.TangentCCircleTool() gtkimage.getImage().setTool(_tool) def draw_tangent_two_conobjs_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.TwoPointTangentCCircleTool() gtkimage.getImage().setTool(_tool) def draw_chamfer_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.ChamferTool() gtkimage.getImage().setTool(_tool) def draw_fillet_cb(menuitem, gtkimage): """ Start Point fillet comand """ gtkimage.activateSnap() _tool = tools.FilletTool() gtkimage.getImage().setTool(_tool) def draw_fillet_two_cb(menuitem, gtkimage): """ Start two line fillet comand """ _tool = tools.FilletTwoLineTool() gtkimage.getImage().setTool(_tool) def draw_leader_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.LeaderTool() gtkimage.getImage().setTool(_tool) def draw_polyline_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.PolylineTool() gtkimage.getImage().setTool(_tool) def _get_polygon_side_count(gtkimage): gtkimage.activateSnap() _sides = 0 _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Polygon Sides'), _window, gtk.DIALOG_MODAL, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 10) _hbox.set_border_width(10) _dialog.vbox.pack_start(_hbox, False, False, 0) _stock = gtk.image_new_from_stock(gtk.STOCK_DIALOG_QUESTION, gtk.ICON_SIZE_DIALOG) _hbox.pack_start(_stock, False, False, 0) _label = gtk.Label(_('Number of sides:')) _hbox.pack_start(_label, False, False, 0) _adj = gtk.Adjustment(3, 3, 3600, 1, 1, 1) # arbitrary max ... _sb = gtk.SpinButton(_adj) _sb.set_numeric(True) _hbox.pack_start(_sb, True, True, 0) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: _sides = _sb.get_value() _dialog.destroy() return _sides def draw_polygon_cb(menuitem, gtkimage): gtkimage.activateSnap() _sides = _get_polygon_side_count(gtkimage) if _sides > 0: _tool = tools.PolygonTool() _tool.setSideCount(_sides) gtkimage.getImage().setTool(_tool) def draw_ext_polygon_cb(menuitem, gtkimage): gtkimage.activateSnap() _sides = _get_polygon_side_count(gtkimage) if _sides > 0: _tool = tools.PolygonTool() _tool.setExternal() _tool.setSideCount(_sides) gtkimage.getImage().setTool(_tool) def draw_set_style_cb(menuitem, gtkimage): gtkentities.set_active_style(gtkimage) def draw_set_linetype_cb(menuitem, gtkimage): gtkentities.set_active_linetype(gtkimage) def draw_set_color_cb(menuitem, gtkimage): gtkentities.set_active_color(gtkimage) def draw_set_thickness_cb(menuitem, gtkimage): gtkentities.set_line_thickness(gtkimage) def draw_text_cb(menuitem, gtkimage): gtkimage.activateSnap() _text = gtktext.text_add_dialog(gtkimage) if _text is not None: _tool = tools.TextTool() _tool.setText(_text) gtkimage.getImage().setTool(_tool) def move_horizontal_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.HorizontalMoveTool() gtkimage.getImage().setTool(_tool) def move_vertical_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.VerticalMoveTool() gtkimage.getImage().setTool(_tool) def move_twopoint_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.MoveTool() gtkimage.getImage().setTool(_tool) def stretch_horiz_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.HorizontalStretchTool() gtkimage.getImage().setTool(_tool) def stretch_vert_cb(menuitem, gtkimage): _tool = tools.VerticalStretchTool() gtkimage.getImage().setTool(_tool) def stretch_twopoint_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.StretchTool() gtkimage.getImage().setTool(_tool) def transfer_object_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.TransferTool() gtkimage.getImage().setTool(_tool) def rotate_object_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.RotateTool() gtkimage.getImage().setTool(_tool) def split_object_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.SplitTool() gtkimage.getImage().setTool(_tool) def mirror_object_cb(menuitem, gtkimage): gtkimage.activateSnap() _tool = tools.MirrorTool() gtkimage.getImage().setTool(_tool) def delete_cb(menuitem, gtkimage): _tool = tools.DeleteTool() gtkimage.getImage().setTool(_tool) def change_style_cb(menuitem, gtkimage): _st = gtkmodify.change_style_dialog(gtkimage) if _st is not None: _tool = tools.GraphicObjectTool() _tool.setAttribute('setStyle') _tool.setValue(_st) _tool.setObjtype(graphicobject.GraphicObject) gtkimage.getImage().setTool(_tool) gtkmodify.change_style_init(gtkimage) def change_color_cb(menuitem, gtkimage): _color = gtkmodify.change_color_dialog(gtkimage) if _color is not None: _tool = tools.GraphicObjectTool() _tool.setAttribute('setColor') _tool.setValue(_color) _tool.setObjtype(graphicobject.GraphicObject) gtkimage.getImage().setTool(_tool) gtkmodify.change_color_init(gtkimage) def change_linetype_cb(menuitem, gtkimage): _lt = gtkmodify.change_linetype_dialog(gtkimage) if _lt is not None: _tool = tools.GraphicObjectTool() _tool.setAttribute('setLinetype') _tool.setValue(_lt) _tool.setObjtype(graphicobject.GraphicObject) gtkimage.getImage().setTool(_tool) gtkmodify.change_linetype_init(gtkimage) def change_thickness_cb(menuitem, gtkimage): _t = gtkmodify.change_thickness_dialog(gtkimage) if _t is not None: _tool = tools.GraphicObjectTool() _tool.setAttribute('setThickness') _tool.setValue(_t) _tool.setObjtype(graphicobject.GraphicObject) gtkimage.getImage().setTool(_tool) gtkmodify.change_thickness_init(gtkimage) def change_textblock_style_cb(menuitem, gtkimage): _st = gtkmodify.change_textblock_style_dialog(gtkimage, 'FONT_STYLE') if _st is not None: _tool = tools.TextTool() _tool.setAttribute('setStyle') _tool.setValue(_st) _tool.setObjtype(text.TextBlock) gtkimage.getImage().setTool(_tool) gtkmodify.change_textblock_style_init(gtkimage) def change_textblock_weight_cb(menuitem, gtkimage): _w = gtkmodify.change_textblock_weight_dialog(gtkimage, 'FONT_WEIGHT') if _w is not None: _tool = tools.TextTool() _tool.setAttribute('setWeight') _tool.setValue(_w) _tool.setObjtype(text.TextBlock) gtkimage.getImage().setTool(_tool) gtkmodify.change_textblock_weight_init(gtkimage) def change_textblock_alignment_cb(menuitem, gtkimage): _align = gtkmodify.change_textblock_alignment_dialog(gtkimage, 'TEXT_ALIGNMENT') if _align is not None: _tool = tools.TextTool() _tool.setAttribute('setAlignment') _tool.setValue(_align) _tool.setObjtype(text.TextBlock) gtkimage.getImage().setTool(_tool) gtkmodify.change_textblock_alignment_init(gtkimage) def change_textblock_size_cb(menuitem, gtkimage): _size = gtkmodify.change_textblock_size_dialog(gtkimage, 'TEXT_SIZE') if _size is not None: _tool = tools.TextTool() _tool.setAttribute('setSize') _tool.setValue(_size) _tool.setObjtype(text.TextBlock) gtkimage.getImage().setTool(_tool) gtkmodify.change_textblock_size_init(gtkimage) def change_textblock_family_cb(menuitem, gtkimage): _family = gtkmodify.change_textblock_family_dialog(gtkimage, 'FONT_FAMILY') if _family is not None: _tool = tools.TextTool() _tool.setAttribute('setFamily') _tool.setValue(_family) _tool.setObjtype(text.TextBlock) gtkimage.getImage().setTool(_tool) gtkmodify.change_textblock_family_init(gtkimage) def change_textblock_color_cb(menuitem, gtkimage): _color = gtkmodify.change_textblock_color_dialog(gtkimage, 'FONT_COLOR') if _color is not None: _tool = tools.TextTool() _tool.setAttribute('setColor') _tool.setValue(_color) _tool.setObjtype(text.TextBlock) gtkimage.getImage().setTool(_tool) gtkmodify.change_textblock_color_init(gtkimage) def change_dim_endpoint_cb(menuitem, gtkimage): _et = gtkmodify.change_dim_endpoint_dialog(gtkimage) if _et is not None: _tool = tools.EditDimensionTool() _tool.setAttribute('setEndpointType') _tool.setValue(_et) _tool.setObjtype(dimension.Dimension) gtkimage.getImage().setTool(_tool) gtkmodify.change_dim_endpoint_init(gtkimage) def change_dim_endpoint_size_cb(menuitem, gtkimage): _es = gtkmodify.change_dim_endpoint_size_dialog(gtkimage) if _es is not None: _tool = tools.EditDimensionTool() _tool.setAttribute('setEndpointSize') _tool.setValue(_es) _tool.setObjtype(dimension.Dimension) gtkimage.getImage().setTool(_tool) gtkmodify.change_dim_endpoint_size_init(gtkimage) def change_dim_offset_cb(menuitem, gtkimage): _offset = gtkmodify.change_dim_offset_dialog(gtkimage) if _offset is not None: _tool = tools.EditDimensionTool() _tool.setAttribute('setOffset') _tool.setValue(_offset) _tool.setObjtype(dimension.Dimension) gtkimage.getImage().setTool(_tool) gtkmodify.change_dim_offset_init(gtkimage) def change_dim_extension_cb(menuitem, gtkimage): _ext = gtkmodify.change_dim_extension_dialog(gtkimage) if _ext is not None: _tool = tools.EditDimensionTool() _tool.setAttribute('setExtension') _tool.setValue(_ext) _tool.setObjtype(dimension.Dimension) gtkimage.getImage().setTool(_tool) gtkmodify.change_dim_extension_init(gtkimage) def change_dim_dual_mode_cb(menuitem, gtkimage): _ddm = gtkmodify.change_dim_dual_mode_dialog(gtkimage) if _ddm is not None: _tool = tools.EditDimensionTool() _tool.setAttribute('setDualDimMode') _tool.setValue(_ddm) _tool.setObjtype(dimension.Dimension) gtkimage.getImage().setTool(_tool) gtkmodify.change_dim_dual_mode_init(gtkimage) def change_dim_dual_mode_offset_cb(menuitem, gtkimage): _dmo = gtkmodify.change_dim_dual_mode_offset_dialog(gtkimage) if _dmo is not None: _tool = tools.EditDimensionTool() _tool.setAttribute('setDualModeOffset') _tool.setValue(_dmo) _tool.setObjtype(dimension.Dimension) gtkimage.getImage().setTool(_tool) gtkmodify.change_dim_dual_mode_offset_init(gtkimage) def change_dim_thickness_cb(menuitem, gtkimage): _t = gtkmodify.change_dim_thickness_dialog(gtkimage) if _t is not None: _tool = tools.EditDimensionTool() _tool.setAttribute('setThickness') _tool.setValue(_t) _tool.setObjtype(dimension.Dimension) gtkimage.getImage().setTool(_tool) gtkmodify.change_dim_thickness_init(gtkimage) def change_dim_color_cb(menuitem, gtkimage): _color = gtkmodify.change_dim_color_dialog(gtkimage) if _color is not None: _tool = tools.EditDimensionTool() _tool.setAttribute('setColor') _tool.setValue(_color) _tool.setObjtype(dimension.Dimension) gtkimage.getImage().setTool(_tool) gtkmodify.change_dim_color_init(gtkimage) def _change_dimstring_style_cb(gtkimage, val, flag): _tool = tools.EditDimStringTool() _tool.setAttribute('setStyle') _tool.setValue(val) _tool.setPrimary(flag) _tool.setObjtype(dimension.DimString) gtkimage.getImage().setTool(_tool) gtkmodify.change_dimstr_style_init(gtkimage) def change_dim_primary_style_cb(menuitem, gtkimage): _st = gtkmodify.change_textblock_style_dialog(gtkimage, 'DIM_PRIMARY_FONT_STYLE') if _st is not None: _change_dimstring_style_cb(gtkimage, _st, True) def change_dim_secondary_style_cb(menuitem, gtkimage): _st = gtkmodify.change_textblock_style_dialog(gtkimage, 'DIM_SECONDARY_FONT_STYLE') if _st is not None: _change_dimstring_style_cb(gtkimage, _st, False) def _change_dimstring_family_cb(gtkimage, val, flag): _tool = tools.EditDimStringTool() _tool.setAttribute('setFamily') _tool.setValue(val) _tool.setPrimary(flag) _tool.setObjtype(dimension.DimString) gtkimage.getImage().setTool(_tool) gtkmodify.change_dimstr_family_init(gtkimage) def change_dim_primary_family_cb(menuitem, gtkimage): _family = gtkmodify.change_textblock_family_dialog(gtkimage, 'DIM_PRIMARY_FONT_FAMILY') if _family is not None: _change_dimstring_family_cb(gtkimage, _family, True) def change_dim_secondary_family_cb(menuitem, gtkimage): _family = gtkmodify.change_textblock_family_dialog(gtkimage, 'DIM_SECONDARY_FONT_FAMILY') if _family is not None: _change_dimstring_family_cb(gtkimage, _family, False) def _change_dimstring_weight_cb(gtkimage, val, flag): _tool = tools.EditDimStringTool() _tool.setAttribute('setWeight') _tool.setValue(val) _tool.setPrimary(flag) _tool.setObjtype(dimension.DimString) gtkimage.getImage().setTool(_tool) gtkmodify.change_dimstr_weight_init(gtkimage) def change_dim_primary_weight_cb(menuitem, gtkimage): _weight = gtkmodify.change_textblock_weight_dialog(gtkimage, 'DIM_PRIMARY_FONT_WEIGHT') if _weight is not None: _change_dimstring_weight_cb(gtkimage, _weight, True) def change_dim_secondary_weight_cb(menuitem, gtkimage): _weight = gtkmodify.change_textblock_weight_dialog(gtkimage, 'DIM_SECONDARY_FONT_WEIGHT') if _weight is not None: _change_dimstring_weight_cb(gtkimage, _weight, False) def _change_dimstring_size_cb(gtkimage, val, flag): _tool = tools.EditDimStringTool() _tool.setAttribute('setSize') _tool.setValue(val) _tool.setPrimary(flag) _tool.setObjtype(dimension.DimString) gtkimage.getImage().setTool(_tool) gtkmodify.change_dimstr_size_init(gtkimage) def change_dim_primary_size_cb(menuitem, gtkimage): _size = gtkmodify.change_textblock_size_dialog(gtkimage, 'DIM_PRIMARY_TEXT_SIZE') if _size is not None: _change_dimstring_size_cb(gtkimage, _size, True) def change_dim_secondary_size_cb(menuitem, gtkimage): _size = gtkmodify.change_textblock_size_dialog(gtkimage, 'DIM_SECONDARY_TEXT_SIZE') if _size is not None: _change_dimstring_size_cb(gtkimage, _size, False) def _change_dimstring_color_cb(gtkimage, val, flag): _tool = tools.EditDimStringTool() _tool.setAttribute('setColor') _tool.setValue(val) _tool.setPrimary(flag) _tool.setObjtype(dimension.DimString) gtkimage.getImage().setTool(_tool) gtkmodify.change_dimstr_color_init(gtkimage) def change_dim_primary_color_cb(menuitem, gtkimage): _color = gtkmodify.change_textblock_color_dialog(gtkimage, 'DIM_PRIMARY_FONT_COLOR') if _color is not None: _change_dimstring_color_cb(gtkimage, _color, True) def change_dim_secondary_color_cb(menuitem, gtkimage): _color = gtkmodify.change_textblock_color_dialog(gtkimage, 'DIM_SECONDARY_FONT_COLOR') if _color is not None: _change_dimstring_color_cb(gtkimage, _color, False) def _change_dimstring_alignment_cb(gtkimage, val, flag): _tool = tools.EditDimStringTool() _tool.setAttribute('setAlignment') _tool.setValue(val) _tool.setPrimary(flag) _tool.setObjtype(dimension.DimString) gtkimage.getImage().setTool(_tool) gtkmodify.change_dimstr_alignment_init(gtkimage) def change_dim_primary_alignment_cb(menuitem, gtkimage): _align = gtkmodify.change_textblock_alignment_dialog(gtkimage, 'DIM_PRIMARY_TEXT_ALIGNMENT') if _align is not None: _change_dimstring_alignment_cb(gtkimage, _align, True) def change_dim_secondary_alignment_cb(menuitem, gtkimage): _align = gtkmodify.change_textblock_alignment_dialog(gtkimage, 'DIM_SECONDARY_TEXT_ALIGNMENT') if _align is not None: _change_dimstring_alignment_cb(gtkimage, _align, False) def _change_dimstring_prefix_cb(gtkimage, val, flag): _tool = tools.EditDimStringTool() _tool.setAttribute('setPrefix') _tool.setValue(val) _tool.setPrimary(flag) _tool.setObjtype(dimension.DimString) gtkimage.getImage().setTool(_tool) def change_ldim_pds_prefix_cb(menuitem, gtkimage): _text = gtkmodify.change_dimstr_prefix_dialog(gtkimage, 'DIM_PRIMARY_PREFIX') if _text is not None: _change_dimstring_prefix_cb(gtkimage, _text, True) gtkmodify.change_ldimstr_prefix_init(gtkimage) def change_ldim_sds_prefix_cb(menuitem, gtkimage): _text = gtkmodify.change_dimstr_prefix_dialog(gtkimage, 'DIM_SECONDARY_PREFIX') if _text is not None: _change_dimstring_prefix_cb(gtkimage, _text, False) gtkmodify.change_ldimstr_prefix_init(gtkimage) def change_rdim_pds_prefix_cb(menuitem, gtkimage): _text = gtkmodify.change_dimstr_prefix_dialog(gtkimage, 'RADIAL_DIM_PRIMARY_PREFIX') if _text is not None: _change_dimstring_prefix_cb(gtkimage, _text, True) gtkmodify.change_rdimstr_prefix_init(gtkimage) def change_rdim_sds_prefix_cb(menuitem, gtkimage): _text = gtkmodify.change_dimstr_prefix_dialog(gtkimage, 'RADIAL_DIM_SECONDARY_PREFIX') if _text is not None: _change_dimstring_prefix_cb(gtkimage, _text, False) gtkmodify.change_rdimstr_prefix_init(gtkimage) def change_adim_pds_prefix_cb(menuitem, gtkimage): _text = gtkmodify.change_dimstr_prefix_dialog(gtkimage, 'ANGULAR_DIM_PRIMARY_PREFIX') if _text is not None: _change_dimstring_prefix_cb(gtkimage, _text, True) gtkmodify.change_adimstr_prefix_init(gtkimage) def change_adim_sds_prefix_cb(menuitem, gtkimage): _text = gtkmodify.change_dimstr_prefix_dialog(gtkimage, 'ANGULAR_DIM_SECONDARY_PREFIX') if _text is not None: _change_dimstring_prefix_cb(gtkimage, _text, False) gtkmodify.change_adimstr_prefix_init(gtkimage) def _change_dimstring_suffix_cb(gtkimage, val, flag): _tool = tools.EditDimStringTool() _tool.setAttribute('setSuffix') _tool.setValue(val) _tool.setPrimary(flag) _tool.setObjtype(dimension.DimString) gtkimage.getImage().setTool(_tool) def change_ldim_pds_suffix_cb(menuitem, gtkimage): _text = gtkmodify.change_dimstr_suffix_dialog(gtkimage, 'DIM_PRIMARY_SUFFIX') if _text is not None: _change_dimstring_suffix_cb(gtkimage, _text, True) gtkmodify.change_ldimstr_suffix_init(gtkimage) def change_ldim_sds_suffix_cb(menuitem, gtkimage): _text = gtkmodify.change_dimstr_suffix_dialog(gtkimage, 'DIM_SECONDARY_SUFFIX') if _text is not None: _change_dimstring_suffix_cb(gtkimage, _text, False) gtkmodify.change_ldimstr_suffix_init(gtkimage) def change_rdim_pds_suffix_cb(menuitem, gtkimage): _text = gtkmodify.change_dimstr_suffix_dialog(gtkimage, 'RADIAL_DIM_PRIMARY_SUFFIX') if _text is not None: _change_dimstring_suffix_cb(gtkimage, _text, True) gtkmodify.change_rdimstr_suffix_init(gtkimage) def change_rdim_sds_suffix_cb(menuitem, gtkimage): _text = gtkmodify.change_dimstr_suffix_dialog(gtkimage, 'RADIAL_DIM_SECONDARY_SUFFIX') if _text is not None: _change_dimstring_suffix_cb(gtkimage, _text, False) gtkmodify.change_rdimstr_suffix_init(gtkimage) def change_adim_pds_suffix_cb(menuitem, gtkimage): _text = gtkmodify.change_dimstr_suffix_dialog(gtkimage, 'ANGULAR_DIM_PRIMARY_SUFFIX') if _text is not None: _change_dimstring_suffix_cb(gtkimage, _text, True) gtkmodify.change_adimstr_suffix_init(gtkimage) def change_adim_sds_suffix_cb(menuitem, gtkimage): _text = gtkmodify.change_dimstr_suffix_dialog(gtkimage, 'ANGULAR_DIM_SECONDARY_SUFFIX') if _text is not None: _change_dimstring_suffix_cb(gtkimage, _text, False) gtkmodify.change_adimstr_suffix_init(gtkimage) def _change_dimstring_precision_cb(gtkimage, val, flag): _tool = tools.EditDimStringTool() _tool.setAttribute('setPrecision') _tool.setValue(val) _tool.setPrimary(flag) _tool.setObjtype(dimension.DimString) gtkimage.getImage().setTool(_tool) gtkmodify.change_dimstr_precision_init(gtkimage) def change_dim_primary_precision_cb(menuitem, gtkimage): _prec = gtkmodify.change_dimstr_precision_dialog(gtkimage, 'DIM_PRIMARY_PRECISION') if _prec is not None: _change_dimstring_precision_cb(gtkimage, _prec, True) def change_dim_secondary_precision_cb(menuitem, gtkimage): _prec = gtkmodify.change_dimstr_precision_dialog(gtkimage, 'DIM_SECONDARY_PRECISION') if _prec is not None: _change_dimstring_precision_cb(gtkimage, _prec, False) def _change_dimstring_units_cb(gtkimage, val, flag): _tool = tools.EditDimStringTool() _tool.setAttribute('setUnits') _tool.setValue(val) _tool.setPrimary(flag) _tool.setObjtype(dimension.DimString) gtkimage.getImage().setTool(_tool) gtkmodify.change_dimstr_units_init(gtkimage) def change_dim_primary_units_cb(menuitem, gtkimage): _unit = gtkmodify.change_dimstr_units_dialog(gtkimage, 'DIM_PRIMARY_UNITS') if _unit is not None: _change_dimstring_units_cb(gtkimage, _unit, True) def change_dim_secondary_units_cb(menuitem, gtkimage): _unit = gtkmodify.change_dimstr_units_dialog(gtkimage, 'DIM_SECONDARY_UNITS') if _unit is not None: _change_dimstring_units_cb(gtkimage, _unit, False) def _change_dimstring_print_zero_cb(gtkimage, val, flag): _tool = tools.EditDimStringTool() _tool.setAttribute('setPrintZero') _tool.setValue(val) _tool.setPrimary(flag) _tool.setObjtype(dimension.DimString) gtkimage.getImage().setTool(_tool) gtkmodify.change_dimstr_print_zero_init(gtkimage) def change_dim_primary_print_zero_cb(menuitem, gtkimage): _flag = gtkmodify.change_dimstr_print_zero_dialog(gtkimage, 'DIM_PRIMARY_LEADING_ZERO') if _flag is not None: _change_dimstring_print_zero_cb(gtkimage, _flag, True) def change_dim_secondary_print_zero_cb(menuitem, gtkimage): _flag = gtkmodify.change_dimstr_print_zero_dialog(gtkimage, 'DIM_SECONDARY_LEADING_ZERO') if _flag is not None: _change_dimstring_print_zero_cb(gtkimage, _flag, False) def _change_dimstring_print_decimal_cb(gtkimage, val, flag): _tool = tools.EditDimStringTool() _tool.setAttribute('setPrintDecimal') _tool.setValue(val) _tool.setPrimary(flag) _tool.setObjtype(dimension.DimString) gtkimage.getImage().setTool(_tool) gtkmodify.change_dimstr_print_decimal_init(gtkimage) def change_dim_primary_print_decimal_cb(menuitem, gtkimage): _flag = gtkmodify.change_dimstr_print_decimal_dialog(gtkimage, 'DIM_PRIMARY_TRAILING_DECIMAL') if _flag is not None: _change_dimstring_print_decimal_cb(gtkimage, _flag, True) def change_dim_secondary_print_decimal_cb(menuitem, gtkimage): _flag = gtkmodify.change_dimstr_print_decimal_dialog(gtkimage, 'DIM_SECONDARY_TRAILING_DECIMAL') if _flag is not None: _change_dimstring_print_decimal_cb(gtkimage, _flag, False) def change_rdim_dia_mode_cb(menuitem, gtkimage): _tool = tools.EditDimensionTool() _tool.setObjtype(dimension.RadialDimension) gtkimage.getImage().setTool(_tool) gtkmodify.change_rdim_dia_mode_init(gtkimage) def change_adim_invert_cb(menuitem, gtkimage): _tool = tools.EditDimensionTool() _tool.setObjtype(dimension.AngularDimension) gtkimage.getImage().setTool(_tool) gtkmodify.invert_adim_init(gtkimage) def zoom_cb(menuitem, gtkimage): _tool = tools.ZoomTool() gtkimage.getImage().setTool(_tool) def zoom_in_cb(menuitem, gtkimage): #_xmin, _ymin, _xmax, _ymax = gtkimage.getView() #_scale = gtkimage.getUnitsPerPixel() #_xdiff = abs(_xmax - _xmin) #_ydiff = abs(_ymax - _ymin) #_xmin = (_xmin + _xmax)/2.0 - _xdiff/4.0 #_ymin = (_ymin + _ymax)/2.0 - _ydiff/4.0 #gtkimage.setView(_xmin, _ymin, (_scale/2.0)) ActiveScale = gtkimage.getUnitsPerPixel() ActiveScale = ActiveScale*0.5 #This Value here could be a global variable to put in the application option gtkimage.ZoomScale(ActiveScale) def zoom_out_cb(menuitem, gtkimage): #_xmin, _ymin, _xmax, _ymax = gtkimage.getView() #_scale = gtkimage.getUnitsPerPixel() #_xdiff = abs(_xmax - _xmin) #_ydiff = abs(_ymax - _ymin) #_xmin = (_xmin + _xmax)/2.0 - _xdiff #_ymin = (_ymin + _ymax)/2.0 - _ydiff #gtkimage.setView(_xmin, _ymin, (_scale * 2.0)) ActiveScale = gtkimage.getUnitsPerPixel() ActiveScale = ActiveScale*2 #This Value here could be a global variable to put in the application option gtkimage.ZoomScale(ActiveScale) def zoom_fit_cb(menuitem, gtkimage): gtkimage.fitImage() def zoom_pan_cb(menuitem, gtkimage): _tool = tools.ZoomPan() gtkimage.getImage().setTool(_tool) def oneShotMidSnap(menuitem, gtkimage): """ Activate one shot snap mid """ gtkimage.image.snapProvider.setOneTemporarySnap('mid') def oneShotEndSnap(menuitem, gtkimage): """ Activate one shot snap end """ gtkimage.image.snapProvider.setOneTemporarySnap('end') def oneShotIntersectionSnap(menuitem, gtkimage): """ Activate one shot snap intersection """ gtkimage.image.snapProvider.setOneTemporarySnap('intersection') def oneShotOriginSnap(menuitem, gtkimage): """ Activate one shot snap origin """ gtkimage.image.snapProvider.setOneTemporarySnap('origin') def oneShotPerpendicularSnap(menuitem, gtkimage): """ Activate one shot snap Perpendicular """ gtkimage.image.snapProvider.setOneTemporarySnap('perpendicular') def oneShotTangentSnap(menuitem, gtkimage): """ Activate one shot snap Tangent """ gtkimage.image.snapProvider.setOneTemporarySnap('tangent') def oneShotPointSnap(menuitem, gtkimage): """ Activate one shot snap Point """ gtkimage.image.snapProvider.setOneTemporarySnap('point') def oneShutCenterSnap(menuitem, gtkimage): """ Activate one shut snap Center """ gtkimage.image.snapProvider.setOneTemporarySnap('center') def dimension_linear_cb(menuitem, gtkimage): _tool = tools.LinearDimensionTool() gtkimage.getImage().setTool(_tool) def dimension_horizontal_cb(menuitem, gtkimage): _tool = tools.HorizontalDimensionTool() gtkimage.getImage().setTool(_tool) def dimension_vertical_cb(menuitem, gtkimage): _tool = tools.VerticalDimensionTool() gtkimage.getImage().setTool(_tool) def dimension_radial_cb(menuitem, gtkimage): _tool = tools.RadialDimensionTool() gtkimage.getImage().setTool(_tool) def dimension_angular_cb(menuitem, gtkimage): _tool = tools.AngularDimensionTool() gtkimage.getImage().setTool(_tool) def get_focus_widget_cb(menuitem, gtkimage): _widget = gtkimage.getWindow().get_focus() print "Focus widget: " + str(_widget) def get_undo_stack_cb(menuitem, gtkimage): _layer = gtkimage.image.getActiveLayer() _log = _layer.getLog() if _log is not None: _log.printUndoData() def get_redo_stack_cb(menuitem, gtkimage): _layer = gtkimage.image.getActiveLayer() _log = _layer.getLog() if _log is not None: _log.printRedoData() def get_image_undo_cb(menuitem, gtkimage): gtkimage.image.printStack(True) def get_image_redo_cb(menuitem, gtkimage): gtkimage.image.printStack(False) def collect_garbage_cb(menuitem, gtkimage): if 'gc' in sys.modules: _lost = gc.collect() print "%d lost objects: " % _lost def _debug_cb(action, *args): print "_debug_cb()" print "action: " + `action` print "args: " + str(args) _group = action.get_property('action-group') if _group is not None: for _act in _group.list_actions(): _name = _act.get_name() print "Action name: %s" % _name def _std_cb(action, *args): print "_std_cb()" _name = action.get_name() print "Action name: %s" % _name def _add_accelerators(action, menuitem, accelgroup): _path = action.get_accel_path() if _path is not None: _data = gtk.accel_map_lookup_entry(_path) if _data is not None: _k, _m = _data if gtk.accelerator_valid(_k, _m): menuitem.add_accelerator('activate', accelgroup, _k, _m, gtk.ACCEL_VISIBLE) def show_abaut_cb(menuitem, gtkimage): """ CallBack action for the about menu """ import PythonCAD.Interface.Gtk.gtkDialog as dialog dialog.abautDialog() ############################################################################# # # Menu item definitions -- These define the individual menu items, # and the actions taken (callbacks invoked) when they are selected. # ############################################################################# ###################### File menu ########################## def _file_menu_init(menuitem, gtkimage): _group = gtkimage.getGroup('File') if _group is not None: _act = _group.get_action('SaveLayerAs') if _act is not None: _act.set_property('sensitive', False) #------------------------------------------------------------ def _make_file_menu(actiongroup, gtkimage): _accel = gtkimage.accel _menu = gtk.Menu() # _act = gtk.Action('New', _('_New'), None, gtk.STOCK_NEW) _act.connect('activate', file_new_cb) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, None) _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # _act = gtk.Action('Open', _('_Open'), None, gtk.STOCK_OPEN) _act.connect('activate', file_open_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, None) _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # _act = gtk.Action('Close', _('_Close'), None, gtk.STOCK_CLOSE) _act.connect('activate', file_close_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, None) _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('Save', _('_Save'), None, gtk.STOCK_SAVE) _act.connect('activate', file_save_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, None) _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # _act = gtk.Action('SaveAs', _('Save _As ...'), None, None) _act.connect('activate', file_save_as_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('SaveLayerAs', _('Save _Layer As ...'), None, None) _act.connect('activate', file_save_layer_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('PrintScreen', _('Print Screen'), None, None) _act.connect('activate', file_print_screen_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('Print', _('_Print'), None, gtk.STOCK_PRINT) _act.connect('activate', file_print_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, 'P') _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # _act = gtk.Action('Quit', _('_Quit'), None, gtk.STOCK_QUIT) _act.connect('activate', file_quit_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, None) _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # return _menu ####################### Edit menu ########################### def _edit_menu_init(menuitem, gtkimage): _group = gtkimage.getGroup('Edit') if _group is not None: _image = gtkimage.getImage() _act = _group.get_action('Undo') if _act is not None: _act.set_property('sensitive', _image.canUndo()) _act = _group.get_action('Redo') if _act is not None: _act.set_property('sensitive', _image.canRedo()) _act = _group.get_action('Cut') if _act is not None: _act.set_property('sensitive', _image.hasSelection()) _act = _group.get_action('Copy') if _act is not None: _act.set_property('sensitive', _image.hasSelection()) _act = _group.get_action('Paste') if _act is not None: _act.set_property('sensitive', globals.selectobj.hasObjects()) _act = _group.get_action('Select') if _act is not None: _act.set_property('sensitive', _image.getActiveLayer().hasEntities()) _act = _group.get_action('SelectAll') if _act is not None: _act.set_property('sensitive', _image.getActiveLayer().hasEntities()) _act = _group.get_action('Deselect') if _act is not None: _act.set_property('sensitive', _image.hasSelection()) ############################################################################# # Edit -> select all submenu ############################################################################# def _make_select_all_menu(actiongroup, gtkimage): _accel = gtkimage.accel _menu = gtk.Menu() for _action, _entity, _menuitem in select_menu: if _action is not None: _act = gtk.Action(_action, _menuitem, None, None) _act.connect('activate', select_all_objects_cb, (gtkimage, _entity)) _act.set_accel_group(_accel) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) else: _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) return _menu ############################################################################# # Edit menu ############################################################################# def _make_edit_menu(actiongroup, gtkimage): _accel = gtkimage.accel _menu = gtk.Menu() # _act = gtk.Action('Undo', _('_Undo'), None, gtk.STOCK_UNDO) _act.connect('activate', edit_undo_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, 'Z') _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # _act = gtk.Action('Redo', _('_Redo'), None, gtk.STOCK_REDO) _act.connect('activate', edit_redo_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, 'Z') _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('Cut', _('Cut'), None, gtk.STOCK_CUT) _act.connect('activate', edit_cut_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, None) _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # _act = gtk.Action('Copy', _('Copy'), None, gtk.STOCK_COPY) _act.connect('activate', edit_copy_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, None) _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # _act = gtk.Action('Paste', _('Paste'), None, gtk.STOCK_PASTE) _act.connect('activate', edit_paste_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, None) _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # _act = gtk.Action('Select', _('_Select'), None, None) _act.connect('activate', edit_select_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('SelectAll', _('Select _All'), None, None) _act.connect('activate', _select_all_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action(_act) _item = _act.create_menu_item() _submenu = _make_select_all_menu(actiongroup, gtkimage) _item.set_submenu(_submenu) _menu.append(_item) # _act = gtk.Action('Deselect', _('_Deselect'), None, None) _act.connect('activate', edit_deselect_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('Prefs', _('_Preferences'), None, gtk.STOCK_PREFERENCES) _act.connect('activate', prefs_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, None) _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) return _menu ############################################################################# # Draw -> basic sub-menu ############################################################################# def _make_draw_basic_menu(actiongroup, gtkimage): # _accel = gtkimage.accel _menu = gtk.Menu() # _act = gtk.Action('Points', _('_Point'), None, None) _act.connect('activate', draw_point_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('Segments', _('_Segment'), None, None) _act.connect('activate', draw_segment_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('Rectangles', _('_Rectangle'), None, None) _act.connect('activate', draw_rectangle_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('Circles', _('_Circle'), None, None) _act.connect('activate', draw_circle_center_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('CirclesTwoPoints', _('Circle (_2 Pts)'), None, None) _act.connect('activate', draw_circle_tp_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('Arcs', _('_Arc'), None, None) _act.connect('activate', draw_arc_center_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # return _menu ############################################################################# # Draw -> lines sub-menu ############################################################################# def _make_draw_conlines_menu(actiongroup, gtkimage): _menu = gtk.Menu() # _act = gtk.Action('HCLines', _('_Horizontal'), None, None) _act.connect('activate', draw_hcl_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('VCLines', _('_Vertical'), None, None) _act.connect('activate', draw_vcl_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ACLines', _('_Angled'), None, None) _act.connect('activate', draw_acl_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('CLines', _('_Two-Point'), None, None) _act.connect('activate', draw_cl_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('PerpConLines', _('Per_pendicular'), None, None) _act.connect('activate', draw_perpendicular_cline_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ParallelConLines', _('Para_llel'), None, None) _act.connect('activate', draw_poffset_cline_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('TangentConLines', _('_Tangent'), None, None) _act.connect('activate', draw_tangent_cline_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('TangentTwoCirclesConLines', _('Tangent _2 Circ'), None, None) _act.connect('activate', draw_tangent_two_ccircles_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # return _menu ############################################################################# # Draw -> concentric circles sub-menu ############################################################################# def _make_draw_concircs_menu(actiongroup, gtkimage): _menu = gtk.Menu() # _act = gtk.Action('CCircles', _('_Center Pt.'), None, None) _act.connect('activate', draw_ccirc_cp_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('CCirclesTwoPoints', _('_Two Pts.'), None, None) _act.connect('activate', draw_ccirc_tp_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('CCircleTangentSingle', _('_Single Tangency'), None, None) _act.connect('activate', draw_tangent_single_conobj_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('CCircleTangentDual', _('_Dual Tangency'), None, None) _act.connect('activate', draw_tangent_two_conobjs_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # return _menu ############################################################################# # Draw set style sub-menu ############################################################################# def _make_draw_set_menu(actiongroup, gtkimage): _menu = gtk.Menu() # # _act = gtk.Action('SetStyle', _('_Style'), None, None) # _act.connect('activate', draw_set_style_cb, gtkimage) # actiongroup.add_action(_act) # _menu.append(_act.create_menu_item()) # # _act = gtk.Action('SetLinetype', _('_Linetype'), None, None) # _act.connect('activate', draw_set_linetype_cb, gtkimage) # actiongroup.add_action(_act) # _menu.append(_act.create_menu_item()) # # _act = gtk.Action('SetColor', _('_Color'), None, None) # _act.connect('activate', draw_set_color_cb, gtkimage) # actiongroup.add_action(_act) # _menu.append(_act.create_menu_item()) # # _act = gtk.Action('SetThickness', _('_Thickness'), None, None) # _act.connect('activate', draw_set_thickness_cb, gtkimage) # actiongroup.add_action(_act) # _menu.append(_act.create_menu_item()) # # _item = gtk.SeparatorMenuItem() # _item.show() # _menu.append(_item) # _act = gtk.Action('SetImageColors', _('_Colors'), None, None) _act.connect('activate', colors_cb, gtkimage) _item = _act.create_menu_item() _menu.append(_item) # _act = gtk.Action('SetImageSizes', _('_Sizes'), None, None) _act.connect('activate', sizes_cb, gtkimage) _item = _act.create_menu_item() _menu.append(_item) # _act = gtk.Action('SetGraphicsStyle', _('_Style'), None, None) _act.connect('activate', style_cb, gtkimage) _item = _act.create_menu_item() _menu.append(_item) # _act = gtk.Action('SetTextStyle', _('_TextStyle'), None, None) _act.connect('activate', textstyle_cb, gtkimage) _item = _act.create_menu_item() _menu.append(_item) # _act = gtk.Action('SetDimStyle', _('_DimStyle'), None, None) _act.connect('activate', dimstyle_cb, gtkimage) _item = _act.create_menu_item() _menu.append(_item) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('SetImageOps', _('_Display'), None, None) _act.connect('activate', toggle_cb, gtkimage) _item = _act.create_menu_item() _menu.append(_item) # _act = gtk.Action('SetImageUnits', _('_Units'), None, None) _act.connect('activate', units_cb, gtkimage) _item = _act.create_menu_item() _menu.append(_item) # return _menu ############################################################################# # Draw-> Fillet sub menu . . ############################################################################# def _make_draw_fillets_menu(actiongroup, gtkimage): _menu = gtk.Menu() # _act = gtk.Action('PointFillet', _('_Point..'), None, None) _act.connect('activate', draw_fillet_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('TwoLineFillet', _('_Two Line'), None, None) _act.connect('activate', draw_fillet_two_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) return _menu ############################################################################# # Draw . . . . ############################################################################# def _make_add_new_menu(actiongroup, gtkimage): # # These currently do nothing but are present to encourage # the development of code to make the ability to add and # save new styles and linetypes in drawings ... # _menu = gtk.Menu() # _act = gtk.Action('AddStyle', _('Style'), None, None) _act.set_property('sensitive', False) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('AddLinetype', _('Linetype'), None, None) _act.set_property('sensitive', False) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # return _menu ############################################################################# # Top level draw menu ############################################################################# def _make_draw_menu(actiongroup, gtkimage): _menu = gtk.Menu() # _act = gtk.Action('Basic', _('_Basic'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_draw_basic_menu(actiongroup, gtkimage)) _menu.append(_item) # _act = gtk.Action('ConLines', _('Con. _Lines'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_draw_conlines_menu(actiongroup, gtkimage)) _menu.append(_item) # _act = gtk.Action('ConCircs', _('Con. _Circs.'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_draw_concircs_menu(actiongroup, gtkimage)) _menu.append(_item) # _act = gtk.Action('Chamfers', _('Cha_mfer'), None, None) _act.connect('activate', draw_chamfer_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('Fillets', _('_Fillets'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_draw_fillets_menu(actiongroup, gtkimage)) _menu.append(_item) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('Leaders', _('Lea_der'), None, None) _act.connect('activate', draw_leader_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('Polylines', _('_Polyline'), None, None) _act.connect('activate', draw_polyline_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('InternalPolygon', _('Poly_gon (Int.)'), None, None) _act.connect('activate', draw_polygon_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ExternalPolygon', _('Polygon (E_xt.)'), None, None) _act.connect('activate', draw_ext_polygon_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('Textblocks', _('_Text'), None, None) _act.connect('activate', draw_text_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('SetProperties', _('_Set ...'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_draw_set_menu(actiongroup, gtkimage)) _menu.append(_item) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('AddNew', _('Add _New ...'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_add_new_menu(actiongroup, gtkimage)) _menu.append(_item) # return _menu ############################################################################# # Modify -> move sub-menu ############################################################################# def _make_modify_move_menu(actiongroup, gtkimage): _menu = gtk.Menu() # _act = gtk.Action('MoveHoriz', _('_Horizontal'), None, None) _act.connect('activate', move_horizontal_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('MoveVert', _('_Vertical'), None, None) _act.connect('activate', move_vertical_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('MoveTwoPt', _('_Two-Point Move'), None, None) _act.connect('activate', move_twopoint_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # return _menu ############################################################################# # Modify -> stretch sub-menu ############################################################################# def _make_modify_stretch_menu(actiongroup, gtkimage): _menu = gtk.Menu() # _act = gtk.Action('StretchHoriz', _('_Horizontal'), None, None) _act.connect('activate', stretch_horiz_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('StretchVert', _('_Vertical'), None, None) _act.connect('activate', stretch_vert_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('StretchTwoPt', _('_Two-Point Stretch'), None, None) _act.connect('activate', stretch_twopoint_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # return _menu ############################################################################# # Modify -> change sub-sub-menu ############################################################################# def _make_change_text_menu(actiongroup, gtkimage): _menu = gtk.Menu() # _act = gtk.Action('ChangeTextBlockFamily', _('_Family'), None, None) _act.connect('activate', change_textblock_family_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeTextBlockWeight', _('_Weight'), None, None) _act.connect('activate', change_textblock_weight_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeTextBlockStyle', _('_Style'), None, None) _act.connect('activate', change_textblock_style_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeTextBlockColor', _('_Color'), None, None) _act.connect('activate', change_textblock_color_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeTextBlockSize', _('Si_ze'), None, None) _act.connect('activate', change_textblock_size_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeTextBlockAlignment', _('_Alignment'), None, None) _act.connect('activate', change_textblock_alignment_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # return _menu ############################################################################# # Modify -> change -> Dimension -> Primary DimString sub-sub-menu ############################################################################# def _make_change_primary_dimstring_menu(actiongroup, gtkimage): _menu = gtk.Menu() # _act = gtk.Action('ChangePDimStringFamily', _('Family'), None, None) _act.connect('activate', change_dim_primary_family_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangePDimStringWeight', _('Weight'), None, None) _act.connect('activate', change_dim_primary_weight_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangePDimStringStyle', _('Style'), None, None) _act.connect('activate', change_dim_primary_style_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangePDimStringSize', _('Size'), None, None) _act.connect('activate', change_dim_primary_size_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangePDimStringColor', _('Color'), None, None) _act.connect('activate', change_dim_primary_color_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangePDimStringAlignment', _('Alignment'), None, None) _act.connect('activate', change_dim_primary_alignment_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangePDimStringPrefix', _('Prefix'), None, None) _act.connect('activate', change_ldim_pds_prefix_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangePDimStringSuffix', _('Suffix'), None, None) _act.connect('activate', change_ldim_pds_suffix_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangePDimStringPrecision', _('Precision'), None, None) _act.connect('activate', change_dim_primary_precision_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangePDimStringUnits', _('Units'), None, None) _act.connect('activate', change_dim_primary_units_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangePDimStringPrintZero', _('Print Zero'), None, None) _act.connect('activate', change_dim_primary_print_zero_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangePDimStringPrintDecimal', _('Print Decimal'), None, None) _act.connect('activate', change_dim_primary_print_decimal_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # return _menu ############################################################################# # Modify -> change -> Dimension -> Secondary DimString sub-sub-menu ############################################################################# def _make_change_secondary_dimstring_menu(actiongroup, gtkimage): _menu = gtk.Menu() # _act = gtk.Action('ChangeSDimStringFamily', _('Family'), None, None) _act.connect('activate', change_dim_secondary_family_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeSDimStringWeight', _('Weight'), None, None) _act.connect('activate', change_dim_secondary_weight_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeSDimStringStyle', _('Style'), None, None) _act.connect('activate', change_dim_secondary_style_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeSDimStringSize', _('Size'), None, None) _act.connect('activate', change_dim_secondary_size_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeSDimStringColor', _('Color'), None, None) _act.connect('activate', change_dim_secondary_color_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeSDimStringAlignment', _('Alignment'), None, None) _act.connect('activate', change_dim_secondary_alignment_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeSDimStringPrefix', _('Prefix'), None, None) _act.connect('activate', change_ldim_sds_prefix_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeSDimStringSuffix', _('Suffix'), None, None) _act.connect('activate', change_ldim_sds_suffix_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeSDimStringPrecision', _('Precision'), None, None) _act.connect('activate', change_dim_secondary_precision_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeSDimStringUnits', _('Units'), None, None) _act.connect('activate', change_dim_secondary_units_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeSDimStringPrintZero', _('Print Zero'), None, None) _act.connect('activate', change_dim_secondary_print_zero_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeSDimStringPrintDecimal', _('Print Decimal'), None, None) _act.connect('activate', change_dim_secondary_print_decimal_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # return _menu def _make_change_rdim_menu(actiongroup, gtkimage): _menu = gtk.Menu() # _act = gtk.Action('ChangeRDimPDSPrefix', _('Primary Prefix'), None, None) _act.connect('activate', change_rdim_pds_prefix_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeRDimPDSSuffix', _('Primary Suffix'), None, None) _act.connect('activate', change_rdim_pds_suffix_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('ChangeRDimSDSPrefix', _('Secondary Prefix'), None, None) _act.connect('activate', change_rdim_sds_prefix_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeRDimSDSSuffix', _('Secondary Suffix'), None, None) _act.connect('activate', change_rdim_sds_suffix_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('ChangeRDimDiaMode', _('Dia. Mode'), None, None) _act.connect('activate', change_rdim_dia_mode_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # return _menu def _make_change_adim_menu(actiongroup, gtkimage): _menu = gtk.Menu() # _act = gtk.Action('ChangeADimPDSPrefix', _('Primary Prefix'), None, None) _act.connect('activate', change_adim_pds_prefix_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeADimPDSSuffix', _('Primary Suffix'), None, None) _act.connect('activate', change_adim_pds_suffix_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('ChangeADimSDSPrefix', _('Secondary Prefix'), None, None) _act.connect('activate', change_adim_sds_prefix_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeADimSDSSuffix', _('Secondary Suffix'), None, None) _act.connect('activate', change_adim_sds_suffix_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('ChangeADimInvert', _('Invert'), None, None) _act.connect('activate', change_adim_invert_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # return _menu ############################################################################# # Modify -> change -> dimension sub-sub-menu ############################################################################# def _make_change_dimension_menu(actiongroup, gtkimage): _menu = gtk.Menu() # _act = gtk.Action('ChangeDimEndpointType', _('Endpoint _Type'), None, None) _act.connect('activate', change_dim_endpoint_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeDimEndpointSize', _('Endpoint _Size'), None, None) _act.connect('activate', change_dim_endpoint_size_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeDimOffset', _('_Offset Length'), None, None) _act.connect('activate', change_dim_offset_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeDimExtension', _('E_xtension Length'), None, None) _act.connect('activate', change_dim_extension_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeDimDualMode', _('_Dual Mode'), None, None) _act.connect('activate', change_dim_dual_mode_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeDimDualModeOffset', _('Dual Mode O_ffset'), None, None) _act.connect('activate', change_dim_dual_mode_offset_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeDimThickness', _('_Thickness'), None, None) _act.connect('activate', change_dim_thickness_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeDimColor', _('_Color'), None, None) _act.connect('activate', change_dim_color_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('ChangePDimStrMenu', _('_Primary DimString'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_change_primary_dimstring_menu(actiongroup, gtkimage)) _menu.append(_item) # _act = gtk.Action('ChangeSDimStrMenu', _('_Secondary DimString'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_change_secondary_dimstring_menu(actiongroup, gtkimage)) _menu.append(_item) # _act = gtk.Action('ChangeRDimMenu', _('RadialDim ...'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_change_rdim_menu(actiongroup, gtkimage)) _menu.append(_item) # _act = gtk.Action('ChangeADimMenu', _('AngularDim ...'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_change_adim_menu(actiongroup, gtkimage)) _menu.append(_item) # # _act = gtk.Action('ChangeDimPrimaryDS', '_Primary DimString', None, None) # _act.connect('activate', change_primary_dim_cb, gtkimage) # actiongroup.add_action(_act) # _menu.append(_act.create_menu_item()) # # _act = gtk.Action('ChangeDimSecondaryDS', '_Secondary DimString', None, None) # _act.connect('activate', change_secondary_dim_cb, gtkimage) # actiongroup.add_action(_act) # _menu.append(_act.create_menu_item()) # return _menu ############################################################################# # Modify -> change sub-menu ############################################################################# def _make_modify_change_menu(actiongroup, gtkimage): _menu = gtk.Menu() # _act = gtk.Action('ChangeStyle', _('_Style'), None, None) _act.connect('activate', change_style_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeLinetype', _('_Linetype'), None, None) _act.connect('activate', change_linetype_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeColor', _('_Color'), None, None) _act.connect('activate', change_color_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ChangeThickness', _('_Thickness'), None, None) _act.connect('activate', change_thickness_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('ChangeTextMenu', _('Text_Block ...'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_change_text_menu(actiongroup, gtkimage)) _menu.append(_item) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('ChangeDimMenu', _('_Dimension ...'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_change_dimension_menu(actiongroup, gtkimage)) _menu.append(_item) # return _menu ############################################################################# # Initialize Modify -> change sub menu ############################################################################# def _change_menu_init(menuitem, gtkimage): # print "_change_menu_init()" _group = gtkimage.getGroup('Modify') if _group is not None: _image = gtkimage.getImage() _objlist = [] _active = _image.getActiveLayer() _gflag = _tflag = _dflag = False for _obj in _image.getSelectedObjects(False): if isinstance(_obj, graphicobject.GraphicObject): _goflag = True continue if isinstance(_obj, text.TextBlock): _tflag = True continue if isinstance(_obj, dimension.Dimension): _dflag = True if _gflag and _tflag and _dflag: break if not _gflag or not _tflag or not _dflag: for _obj in _active.getChildren(): if not _gflag and isinstance(_obj, graphicobject.GraphicObject): _gflag = True continue if not _tflag and isinstance(_obj, text.TextBlock): _tflag = True continue if not _dflag and isinstance(_obj, dimension.Dimension): _dflag = True if _gflag and _tflag and _dflag: break _act = _group.get_action('ChangeStyle') if _act is not None: _act.set_property('sensitive', _gflag) _act = _group.get_action('ChangeLinetype') if _act is not None: _act.set_property('sensitive', _gflag) _act = _group.get_action('ChangeColor') if _act is not None: _act.set_property('sensitive', _gflag) _act = _group.get_action('ChangeThickness') if _act is not None: _act.set_property('sensitive', _gflag) _act = _group.get_action('ChangeTextMenu') if _act is not None: _act.set_property('sensitive', _tflag) _act = _group.get_action('ChangeDimMenu') if _act is not None: _act.set_property('sensitive', _dflag) ############################################################################# # Initialize top level modify menu -- this handles greying out non-active items. ############################################################################# def _modify_menu_init(menuitem, gtkimage): _group = gtkimage.getGroup('Modify') if _group is not None: _image = gtkimage.getImage() _active = _image.getActiveLayer() _act = _group.get_action('Move') if _act is not None: _act.set_property('sensitive', (_active.hasEntities() or _image.hasSelection())) _act = _group.get_action('Stretch') if _act is not None: _act.set_property('sensitive', _active.hasEntities()) _act = _group.get_action('Split') if _act is not None: _flag = ((_active.getEntityCount('segment') > 0) or (_active.getEntityCount('circle') > 0) or (_active.getEntityCount('arc') > 0) or (_active.getEntityCount('polyline') > 0)) _act.set_property('sensitive', _flag) _act = _group.get_action('Mirror') if _act is not None: _flag = ((_active.hasEntities() or _image.hasSelection()) and ((_active.getEntityCount('hcline') > 0) or (_active.getEntityCount('vcline') > 0) or (_active.getEntityCount('acline') > 0) or (_active.getEntityCount('cline') > 0))) _act.set_property('sensitive', _flag) _act = _group.get_action('Transfer') if _act is not None: _flag = False _layers = [_image.getTopLayer()] while len(_layers): _layer = _layers.pop() if _layer is not _active: _flag = _layer.hasEntities() if _flag: break _layers.extend(_layer.getSublayers()) _act.set_property('sensitive', _flag) _act = _group.get_action('Rotate') if _act is not None: _act.set_property('sensitive', (_active.hasEntities() or _image.hasSelection())) _act = _group.get_action('Delete') if _act is not None: _act.set_property('sensitive', _active.hasEntities()) _act = _group.get_action('Change') if _act is not None: _act.set_property('sensitive', (_image.hasSelection() or _active.hasEntities())) _act = _group.get_action('ZoomFit') if _act is not None: _act.set_property('sensitive', _active.hasEntities()) ############################################################################# # Top level modify menu ############################################################################# def _make_modify_menu(actiongroup, gtkimage): _accel = gtkimage.accel _menu = gtk.Menu() # _act = gtk.Action('Move', _('_Move ...'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_modify_move_menu(actiongroup, gtkimage)) _menu.append(_item) # _act = gtk.Action('Stretch', _('S_tretch ...'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_modify_stretch_menu(actiongroup, gtkimage)) _menu.append(_item) # _act = gtk.Action('Split', _('S_plit'), None, None) _act.connect('activate', split_object_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('Mirror', _('_Mirror'), None, None) _act.connect('activate', mirror_object_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('Transfer', _('Trans_fer'), None, None) _act.connect('activate', transfer_object_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('Rotate', _('_Rotate'), None, None) _act.connect('activate', rotate_object_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('Delete', _('_Delete'), None, None) _act.connect('activate', delete_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _item = gtk.SeparatorMenuItem() _item.show() _menu.append(_item) # _act = gtk.Action('Change', _('_Change'), None, None) _act.connect('activate', _change_menu_init, gtkimage) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_modify_change_menu(actiongroup, gtkimage)) _menu.append(_item) return _menu ############################################################################# # Initialize top level view menu -- this handles greying out non-active items. ############################################################################# def _view_menu_init(menuitem, gtkimage): _group = gtkimage.getGroup('View') if _group is not None: _image = gtkimage.getImage() _active = _image.getActiveLayer() _act = _group.get_action('ZoomFit') if _act is not None: _act.set_property('sensitive', _active.hasEntities()) ############################################################################# # Top level view menu ############################################################################# def _make_view_menu(actiongroup, gtkimage): _accel = gtkimage.accel _menu = gtk.Menu() # _act = gtk.Action('ZoomIn', _('_Zoom In'), None, gtk.STOCK_ZOOM_IN) _act.connect('activate', zoom_in_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, None) _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # _act = gtk.Action('ZoomOut', _('Zoom _Out'), None, gtk.STOCK_ZOOM_OUT) _act.connect('activate', zoom_out_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, None) _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # _act = gtk.Action('ZoomFit', _('Zoom _Fit'), None, gtk.STOCK_ZOOM_FIT) _act.connect('activate', zoom_fit_cb, gtkimage) _act.set_accel_group(_accel) actiongroup.add_action_with_accel(_act, None) _item = _act.create_menu_item() if isinstance(_act, gtkactions.stdAction): _add_accelerators(_act, _item, _accel) _menu.append(_item) # _act = gtk.Action('ZoomPan', _('Zoom _Pan'), None, None) _act.connect('activate', zoom_pan_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) # _act = gtk.Action('ZoomWindow', _('Zoom _Window'), None, None) _act.connect('activate', zoom_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) return _menu ############################################################################# # Initialize top level help menu -- this handles greying out non-active items. ############################################################################# def _help_menu_init(menuitem, gtkimage): return ############################################################################# # Top level help menu ############################################################################# def _make_help_menu(actiongroup, gtkimage): _group = gtkimage.getGroup('Help') _menu = gtk.Menu() # Abaut _act = gtk.Action('About', _('_About'), None, None) _act.connect('activate', show_abaut_cb, gtkimage) actiongroup.add_action(_act) _item = _act.create_menu_item() _menu.append(_item) return _menu ############################################################################# # Initialize top level snap menu -- this handles greying out non-active items. ############################################################################# def _snap_menu_init(menuitem, gtkimage): return ############################################################################# # Top level snap menu ############################################################################# def _make_snap_menu(actiongroup, gtkimage): _group = gtkimage.getGroup('Snap') _menu = gtk.Menu() # _act = gtk.Action('OneShotSnap', _('_One Shot Snap'), None, None) actiongroup.add_action(_act) _item = _act.create_menu_item() _item.set_submenu(_make_snap_oneshot_menu(actiongroup, gtkimage)) _menu.append(_item) return _menu def _make_snap_oneshot_menu(actiongroup, gtkimage): _group = gtkimage.getGroup('SnapOneShot') _menu = gtk.Menu() # _act = gtk.Action('MidPoint', _('_Mid Point'), None, None) _act.connect('activate', oneShotMidSnap, gtkimage) actiongroup.add_action(_act) _item = _act.create_menu_item() _menu.append(_item) # _act = gtk.Action('Point', _('_Point'), None, None) _act.connect('activate', oneShotPointSnap, gtkimage) actiongroup.add_action(_act) _item = _act.create_menu_item() _menu.append(_item) # _act = gtk.Action('Center', _('_Center'), None, None) _act.connect('activate', oneShutCenterSnap, gtkimage) actiongroup.add_action(_act) _item = _act.create_menu_item() _menu.append(_item) # _act = gtk.Action('EndPoint', _('_End Point'), None, None) _act.connect('activate', oneShotEndSnap, gtkimage) actiongroup.add_action(_act) _item = _act.create_menu_item() _menu.append(_item) # _act = gtk.Action('IntersectionPoint', _('_Intersection Point'), None, None) _act.connect('activate', oneShotIntersectionSnap, gtkimage) actiongroup.add_action(_act) _item = _act.create_menu_item() _menu.append(_item) # _act = gtk.Action('OriginPoint', _('_Origin Point'), None, None) _act.connect('activate', oneShotOriginSnap, gtkimage) actiongroup.add_action(_act) _item = _act.create_menu_item() _menu.append(_item) # _act = gtk.Action('PerpendicularPoint', _('_Perpendicular Point'), None, None) _act.connect('activate', oneShotPerpendicularSnap, gtkimage) actiongroup.add_action(_act) _item = _act.create_menu_item() _menu.append(_item) # _act = gtk.Action('TangentPoint', _('_Tangent Point'), None, None) _act.connect('activate', oneShotTangentSnap, gtkimage) actiongroup.add_action(_act) _item = _act.create_menu_item() _menu.append(_item) return _menu ############################################################################# # Init top level Dimensions menu ############################################################################# def _dimension_menu_init(menuitem, gtkimage): _group = gtkimage.getGroup('Dimension') if _group is not None: _ldim = _hdim = _vdim = _rdim = _adim = False _count = 0 _layers = [gtkimage.image.getTopLayer()] for _layer in _layers: _pc = _layer.getEntityCount('point') if _pc > 0: _count = _count + _pc if _count > 1: _ldim = _hdim = _vdim = True if _count > 2: _adim = True if _layer.getEntityCount('circle') > 0: _rdim = True if _layer.getEntityCount('arc') > 0: _rdim = _adim = True if _ldim and _hdim and _vdim and _rdim and _adim: break _layers.extend(_layer.getSublayers()) _act = _group.get_action('Linear') if _act is not None: _act.set_property('sensitive', _ldim) _act = _group.get_action('Horizontal') if _act is not None: _act.set_property('sensitive', _hdim) _act = _group.get_action('Vertical') if _act is not None: _act.set_property('sensitive', _vdim) _act = _group.get_action('Radial') if _act is not None: _act.set_property('sensitive', _rdim) _act = _group.get_action('Angular') if _act is not None: _act.set_property('sensitive', _adim) ############################################################################# # Top level Dimensions menu ############################################################################# def _make_dimension_menu(actiongroup, gtkimage): _accel = gtkimage.accel _menu = gtk.Menu() _act = gtk.Action('Linear', _('_Linear'), None, None) _act.connect('activate', dimension_linear_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) _act = gtk.Action('Horizontal', _('_Horizontal'), None, None) _act.connect('activate', dimension_horizontal_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) _act = gtk.Action('Vertical', _('_Vertical'), None, None) _act.connect('activate', dimension_vertical_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) _act = gtk.Action('Radial', _('_Radial'), None, None) _act.connect('activate', dimension_radial_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) _act = gtk.Action('Angular', _('_Angular'), None, None) _act.connect('activate', dimension_angular_cb, gtkimage) actiongroup.add_action(_act) _menu.append(_act.create_menu_item()) return _menu ############################################################################# # Fill out top menubar with menu items. ############################################################################# def fill_menubar(mb, gtkimage): if not isinstance(mb, gtk.MenuBar): raise TypeError, "Invalid gtk.MenuBar object: " + `mb` # File menu _group = gtk.ActionGroup('File') gtkimage.addGroup(_group) _act = gtk.Action('FileMenu', _('_File'), None, None) _group.add_action(_act) _item = gtk.MenuItem() _act.connect_proxy(_item) _act.connect('activate', _file_menu_init, gtkimage) _menu = _make_file_menu(_group, gtkimage) _item.set_submenu(_menu) mb.append(_item) # Edit menu _group = gtk.ActionGroup('Edit') gtkimage.addGroup(_group) _act = gtk.Action('EditMenu', _('_Edit'), None, None) _group.add_action(_act) _item = gtk.MenuItem() _act.connect_proxy(_item) _act.connect('activate', _edit_menu_init, gtkimage) _menu = _make_edit_menu(_group, gtkimage) _item.set_submenu(_menu) mb.append(_item) # Draw menu _group = gtk.ActionGroup('Draw') gtkimage.addGroup(_group) _act = gtk.Action('DrawMenu', _('_Draw'), None, None) _group.add_action(_act) _item = gtk.MenuItem() _act.connect_proxy(_item) _menu = _make_draw_menu(_group, gtkimage) _item.set_submenu(_menu) mb.append(_item) # Modifying _group = gtk.ActionGroup('Modify') gtkimage.addGroup(_group) _act = gtk.Action('ModifyMenu', _('_Modify'), None, None) _group.add_action(_act) _item = gtk.MenuItem() _act.connect_proxy(_item) _act.connect('activate', _modify_menu_init, gtkimage) _menu = _make_modify_menu(_group, gtkimage) _item.set_submenu(_menu) mb.append(_item) # View _group = gtk.ActionGroup('View') gtkimage.addGroup(_group) _act = gtk.Action('ViewMenu', _('_View'), None, None) _group.add_action(_act) _item = gtk.MenuItem() _act.connect_proxy(_item) _act.connect('activate', _view_menu_init, gtkimage) _menu = _make_view_menu(_group, gtkimage) _item.set_submenu(_menu) mb.append(_item) # Snap _group = gtk.ActionGroup('Snap') gtkimage.addGroup(_group) _act = gtk.Action('SnapMenu', _('_Snap'), None, None) _group.add_action(_act) _item = gtk.MenuItem() _act.connect_proxy(_item) _act.connect('activate', _snap_menu_init, gtkimage) _menu = _make_snap_oneshot_menu(_group, gtkimage) _item.set_submenu(_menu) mb.append(_item) # Dimensioning _group = gtk.ActionGroup('Dimension') gtkimage.addGroup(_group) _act = gtk.Action('DimensionMenu', _('Dime_nsions'), None, None) _group.add_action(_act) _item = gtk.MenuItem() _act.connect_proxy(_item) _act.connect('activate', _dimension_menu_init, gtkimage) _menu = _make_dimension_menu(_group, gtkimage) _item.set_submenu(_menu) mb.append(_item) # Help _group = gtk.ActionGroup('Help') gtkimage.addGroup(_group) _act = gtk.Action('HelpMenu', _('_Help'), None, None) _group.add_action(_act) _item = gtk.MenuItem() _act.connect_proxy(_item) _act.connect('activate', _help_menu_init, gtkimage) _menu = _make_help_menu(_group, gtkimage) _item.set_submenu(_menu) mb.append(_item) PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkprinting.py0000644000175000017500000002542711307666732022326 0ustar matteomatteo# # Copyright (c) 2004, 2006, 2007 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # code for setting printing parameters # import pygtk pygtk.require('2.0') import gtk import os import tempfile from PythonCAD.Generic.plotfile import Plot from PythonCAD.Generic.printing import PSPlot def _toggle_widgets_on(widget): widget.set_sensitive(True) def _toggle_widgets_off(widget): widget.set_sensitive(False) def _print_rb_cb(button, hbox): if button.get_active(): hbox.foreach(_toggle_widgets_on) else: hbox.foreach(_toggle_widgets_off) return True def _error_dialog(gtkimage, errmsg): _window = gtkimage.getWindow() _dialog = gtk.MessageDialog(_window, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, errmsg) _dialog.run() _dialog.destroy() def print_dialog(gtkimage, plot): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Printing Preferences'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _vbox = _dialog.vbox # _psplot = PSPlot(plot) # # options for all plots # _frame = gtk.Frame(_('Plot Options')) _fvbox = gtk.VBox(False, 5) _fvbox.set_border_width(5) _frame.add(_fvbox) _ccb = gtk.CheckButton(_('Print in Color')) _fvbox.pack_start(_ccb, False, False, 5) _icb = gtk.CheckButton(_('Print White as Black')) _fvbox.pack_start(_icb, False, False, 5) _lcb = gtk.CheckButton(_('Print in Landscape Mode')) _fvbox.pack_start(_lcb, False, False, 5) _hbox = gtk.HBox(False, 5) _fvbox.pack_start(_hbox, True, True, 5) _label = gtk.Label(_('Paper Size:')) _hbox.pack_start(_label, False, False, 5) _papersizes = _psplot.getPaperSizes() _papersizes.sort() if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _size_widget = gtk.combo_box_new_text() for _size in _papersizes: _size_widget.append_text(_size) _size_widget.set_active(0) # perhaps a global preferences value? else: _menu = gtk.Menu() for _size in _papersizes: _item = gtk.MenuItem(_size) _menu.append(_item) _size_widget = gtk.OptionMenu() _size_widget.set_menu(_menu) _size_widget.set_history(0) # perhaps a global preference value? _hbox.pack_start(_size_widget, False, False, 5) _vbox.pack_start(_frame, False, False, 5) # # _label_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _frame = gtk.Frame(_('Print Destination')) _fvbox = gtk.VBox(False, 5) _fvbox.set_border_width(5) _frame.add(_fvbox) # _phbox = gtk.HBox(False, 5) _label = gtk.Label(_('Printer:')) _label_size_group.add_widget(_label) _phbox.pack_start(_label, False, False, 5) _print_entry = gtk.Entry() _print_entry.set_text("lp") _phbox.pack_start(_print_entry, False, False, 5) _fvbox.pack_start(_phbox, False, False, 5) # _fhbox = gtk.HBox(False, 5) _label = gtk.Label(_('File:')) _label_size_group.add_widget(_label) _label.set_sensitive(False) _fhbox.pack_start(_label, False, False, 5) _file_entry = gtk.Entry() _file_entry.set_sensitive(False) _fhbox.pack_start(_file_entry, False, False, 5) _fvbox.pack_start(_fhbox, False, False, 5) # _hbox = gtk.HBox(False, 5) _label = gtk.Label(_('Send print to ...')) _label_size_group.add_widget(_label) _hbox.pack_start(_label, False, False, 5) _prb = gtk.RadioButton() _prb.set_label(_('Printer')) _prb.set_mode(True) _prb.connect("toggled", _print_rb_cb, _phbox) _hbox.pack_start(_prb, False, False, 5) _frb = gtk.RadioButton(_prb) _frb.set_label(_('File')) _frb.set_mode(True) _frb.connect("toggled", _print_rb_cb, _fhbox) _hbox.pack_start(_frb, False, False, 5) _fvbox.pack_start(_hbox, False, False, 5) # _vbox.pack_start(_frame, False, False, 5) _dialog.show_all() while True: _response = _dialog.run() if _response == gtk.RESPONSE_OK: plot.setColorMode(_ccb.get_active()) plot.invertWhite(_icb.get_active()) plot.setLandscapeMode(_lcb.get_active()) plot.getPlotData() if hasattr(gtk, 'ComboBox') and isinstance(_size_widget, gtk.ComboBox): _idx = _size_widget.get_active() elif isinstance(_size_widget, gtk.OptionMenu): _idx = _sizewidget.get_history() else: raise TypeError, "Unexpected size_widget: " + `type(_size_widget)` _psplot.setSize(_papersizes[_idx]) if _prb.get_active(): # send job out try: _f = tempfile.NamedTemporaryFile() _fname = _f.name try: try: _psplot.write(_f) _cmd = "%s %s" %(_print_entry.get_text(), _fname) try: _res = os.system(_cmd) if _res == 0: break else: _msg = "Non-zero exit status from '%s': %d" % (_cmd, _res) _error_dialog(gtkimage, _msg) except StandardError, _err: _msg = "Error executing command '%s': %s" % (_cmd, _err) _error_dialog(gtkimage, _msg) except StandardError, _err: _msg = "Error writing '%s': %s" % (_fname, _err) _error_dialog(gtkimage, _msg) finally: _f.close() except StandardError, _err: _msg = "Error creating temporary file %s" % _err _error_dialog(gtkimage, _msg) else: _fname = _file_entry.get_text() try: _f = file(_fname, "w") try: _psplot.write(_f) finally: _f.close() break except StandardError, _err: _msg = "Error writing to %s: %s" % (_fname, _err) _error_dialog(gtkimage, _msg) else: break _psplot.finish() _dialog.destroy() def _show_print_dialog(gtkimage, tool=None): _plot = Plot(gtkimage.image) _tool = gtkimage.getImage().getTool() _x1, _y1 = _tool.getFirstCorner() _x2, _y2 = _tool.getSecondCorner() _xmin = min(_x1, _x2) _ymin = min(_y1, _y2) _xmax = max(_x1, _x2) _ymax = max(_y1, _y2) _plot.setBounds(_xmin, _ymin, _xmax, _ymax) _tool.reset() plot_mode_init(gtkimage) gtkimage.refresh() print_dialog(gtkimage, _plot) def plot_motion_notify(gtkimage, widget, event, tool): _tx, _ty = tool.getFirstCorner() _px, _py = gtkimage.coordToPixTransform(_tx, _ty) _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _cp = tool.getCurrentPoint() if _cp is not None: _xc, _yc = _cp _xmin = min(_xc, _px) _ymin = min(_yc, _py) _rw = abs(_xc - _px) _rh = abs(_yc - _py) widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _rw, _rh) tool.setCurrentPoint(_x, _y) _xmin = min(_x, _px) _ymin = min(_y, _py) _rw = abs(_x - _px) _rh = abs(_y - _py) widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _rw, _rh) return True def _make_tuple(text, gdict): _tpl = eval(text, gdict) if not isinstance(_tpl, tuple): raise TypeError, "Invalid tuple: " + `type(_tpl)` if len(_tpl) != 2: raise ValueError, "Invalid tuple: " + str(_tpl) return _tpl def plot_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _x, _y = _image.getClosestPoint(_x, _y, tolerance=_tol) tool.setSecondCorner(_x, _y) _show_print_dialog(gtkimage, tool) return True def plot_second_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = _make_tuple(_text, gtkimage.image.getImageVariables()) tool.setSecondCorner(_x, _y) _show_print_dialog(gtkimage, tool) def plot_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _x, _y = _image.getClosestPoint(_x, _y, tolerance=_tol) tool.setFirstCorner(_x, _y) gtkimage.setPrompt(_('Click in the drawing area or enter another point')) tool.setHandler("button_press", plot_second_button_press_cb) tool.setHandler("entry_event", plot_second_entry_event_cb) tool.setHandler("motion_notify", plot_motion_notify) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True def plot_first_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = _make_tuple(_text, gtkimage.image.getImageVariables()) tool.setFirstCorner(_x, _y) gtkimage.setPrompt(_('Click in the drawing area or enter another point')) tool.setHandler("button_press", plot_second_button_press_cb) tool.setHandler("entry_event", plot_second_entry_event_cb) tool.setHandler("motion_notify", plot_motion_notify) gtkimage.getGC().set_function(gtk.gdk.INVERT) def plot_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter a point')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", plot_mode_init) _tool.setHandler("button_press", plot_first_button_press_cb) _tool.setHandler("entry_event", plot_first_entry_event_cb) PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkprefs.py0000644000175000017500000031714211307666732021611 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # code for setting the preferences of an image # import pygtk pygtk.require('2.0') import gtk import gobject import sys from PythonCAD.Generic import globals from PythonCAD.Generic.text import TextStyle from PythonCAD.Generic import units from PythonCAD.Generic.image import Image from PythonCAD.Generic.color import get_color from PythonCAD.Generic import preferences from PythonCAD.Generic.dimension import Dimension _font_styles = TextStyle.getStyleStrings() _font_weights = TextStyle.getWeightStrings() _text_align = TextStyle.getAlignmentStrings() _dim_endpoints = Dimension.getEndpointTypeStrings() _dim_positions = Dimension.getPositionStrings() ################################################################ # # New and improved preferences code ... # ################################################################ class Prefstate(object): """A class for storing and retriving preference values. The Prefstate class stores references to the widgets used in making the preference dialog screens. When the dialog is closed the widgets stored in the Prefstate class are examined for their values if the user wants to set new preference values. The Prefstate class has the following methods: {set/get}TreeView(): Set/Get a gtk.TreeView for the Prefstate instance. {set/get}HBox(): Set/Get a gtk.HBox for the Prefstate instance. {set/get}Container(): Set/Get a reference to a gtk.Container instance. {set/get}PrefKey(): Set/Get a key used for storing preference widget sets. {set/get}Widget(): Set/Get a keyed reference to a widget. hasWidgetKey(): Test if a key is used to store a widget reference. getWidgetKeys(): Return the keys used to refer to stored widgets. {set/get}Image(): Set/Get the Image used for preference adjustment. {set/get}Window(): Set/Get the gtk.Window displaying the preference dialog. {set/get}Families(): Set/Get the font families for text selection screens clear(): Clear all storage of widgets """ def __init__(self): self.__tree_view = None self.__hbox = None self.__prefkeys = {} self.__prefkey = None self.__widgets = {} self.__image = None self.__window = None self.__families = None def setTreeView(self, treeview): """Store a reference to a TreeView widget. setTreeView(treeview) The argument 'treeview' must be a gtk.TreeView instance. """ if not isinstance(treeview, gtk.TreeView): raise TypeError, "Invalid TreeView: " + `type(treeview)` self.__tree_view = treeview def getTreeView(self): """Return the stored TreeView widget. getTreeView() If no gtk.TreeView has been stored this method returns None. """ return self.__tree_view def setHBox(self, hbox): """Store a reference to a gtk.HBox widget. setHBox(hbox) The argument 'hbox' must be a gtk.HBox instance. """ if not isinstance(hbox, gtk.HBox): raise TypeError, "Invalid HBox: " + `type(hbox)` self.__hbox = hbox def getHBox(self): """Return the stored gtk.HBox. getHBox() If no gtk.HBox has been stored this method returns None. """ return self.__hbox def setContainer(self, key, container): """Store a keyed reference to a gtk.Container instance. setContainer(key, container) Argument 'key' is a text string, and the container must be an instance of gtk.Container. """ if not isinstance(container, gtk.Container): raise TypeError, "Invalid container: " + `type(container)` self.__prefkeys[key] = container def getContainer(self, key): """Retrieve the gtk.Container referenced by a key. getContainer(key) If the key has been used to store a gtk.Container instance, the stored container is returned. If not, None is returned. """ if key in self.__prefkeys: _container = self.__prefkeys[key] else: _container = None return _container def setPrefKey(self, key): """Store a key representing a screenful of preference widgets. setPrefKey(key) Argument 'key' should be a string. """ if key not in self.__prefkeys: raise ValueError, "No container stored for key." self.__prefkey = key def getPrefKey(self): """Return the current key giving the preference widget screen. getPrefKey() This method returns the key last set by setPrefKey(). If that method has not been invoked None is returned. """ return self.__prefkey def delPrefKey(self): self.__prefkey = None def setWidget(self, key, widget): """Store a widget reference in the Prefstate. setWidget(key, widget) Argument 'key' should be a string. Argument 'widget' must be an instance of gtk.Widget. Trying to use the same key twice will raise a ValueError exception. """ if not isinstance(widget, gtk.Widget): raise TypeError, "Invalid widget: " + `type(widget)` if key in self.__widgets: raise ValueError, "Duplicate key: " + key self.__widgets[key] = widget def getWidget(self, key): """Return the widget associated with a key getWidget(key) Argument 'key' should be a string. Using a key that has not been used with setWidget() results in a KeyError exception. """ return self.__widgets[key] def hasWidgetKey(self, key): """Test if a key is used for widget association. hasWidgetKey(key) This method returns True if the key has already been used to store a widget. """ return key in self.__widgets def getWidgetKeys(self): """Return all the keys used to store widgets. getWidgetKeys() This method returns a list of strings. """ return self.__widgets.keys() def setImage(self, image): """Store a reference to the image used for preference adjustment. setImage(image) Argument 'image' must be an instance of image.Image. """ if not isinstance(image, Image): raise TypeError, "Invalid image: " + `type(image)` self.__image = image def getImage(self): """Retrieve the image used for this Prefstate instance. getImage() This method raises a ValueError exception if it is called before setImage(). """ if self.__image is None: raise ValueError, "Image not set." return self.__image def setWindow(self, window): """Store a reference to a gtk.Window. setWindow(window) Argument 'window' must be an instance of gtk.Window. """ if not isinstance(window, gtk.Window): raise TypeError, "Invalid window: " + `type(window)` self.__window = window def getWindow(self): """Return the stored window for the Prefstate instance. getWindow() This method raises a ValueError exception if it is invoked before setWindow() has been called. """ if self.__window is None: raise ValueError, "Window not set." return self.__window def setFamilies(self, families): """Store a list of font families. setFamilies(families) Argument 'families' should be a list. """ if not isinstance(families, list): raise TypeError, "Invalid families list: " + `type(families)` self.__families = families def getFamilies(self): """Return the list of families stored in the Prefstate instance. getFamilies() If setFamilies() has not been called, this method returns None """ return self.__families def clear(self): """Release all widget references. clear() This method should only be called once the usage of a Prefstate instance is completed. """ self.__tree_view = None self.__hbox = None self.__prefkeys.clear() self.__prefkey = None self.__widgets.clear() self.__image = None self.__window = None self.__families = None def entry_activate(entry): _text = entry.get_text() entry.delete_text(0, -1) if len(_text): if _text == '-' or _text == '+': sys.stderr.write("Incomplete value: '%s'\n" % _text) else: try: _value = float(_text) print "value: %g" % _value except: sys.stderr.write("Invalid float: '%s'\n" % _text) else: sys.stderr.write("Empty entry box.") # # use focus-out events to reset the value in entry boxes # to their previous value if the entry box text is invalid # def _leader_entry_focus_out(entry, event, prefstate): _text = entry.get_text() if _text == '' or _text == '+': entry.delete_text(0, -1) _size = "%f" % globals.prefs['LEADER_ARROW_SIZE'] entry.set_text(_size) return False def _dim_offset_entry_focus_out(entry, event, prefstate): _text = entry.get_text() if _text == '' or _text == '+': entry.delete_text(0, -1) _size = "%f" % globals.prefs['DIM_OFFSET'] entry.set_text(_size) return False def _dim_marker_entry_focus_out(entry, event, prefstate): _text = entry.get_text() if _text == '' or _text == '+': entry.delete_text(0, -1) _size = "%f" % globals.prefs['DIM_ENDPOINT_SIZE'] entry.set_text(_size) return False def _dim_extlen_entry_focus_out(entry, event, prefstate): _text = entry.get_text() if _text == '' or _text == '+': entry.delete_text(0, -1) _size = "%f" % globals.prefs['DIM_EXTENSION'] entry.set_text(_size) return False def _thickness_entry_focus_out(entry, event, prefstate): _text = entry.get_text() if _text == '' or _text == '+': entry.delete_text(0, -1) _size = "%f" % globals.prefs['LINE_THICKNESS'] entry.set_text(_size) return False def _chamfer_entry_focus_out(entry, event, prefstate): _text = entry.get_text() if _text == '' or _text == '+': entry.delete_text(0, -1) _size = "%f" % globals.prefs['CHAMFER_LENGTH'] entry.set_text(_size) return False def _fillet_entry_focus_out(entry, event, prefstate): _text = entry.get_text() if _text == '' or _text == '+': entry.delete_text(0, -1) _size = "%f" % globals.prefs['FILLET_RADIUS'] entry.set_text(_size) return False def _textsize_entry_focus_out(entry, event, prefstate): _text = entry.get_text() if _text == '' or _text == '+': entry.delete_text(0, -1) _size = "%f" % globals.prefs['TEXT_SIZE'] entry.set_text(_size) return False def _dim_primary_textsize_entry_focus_out(entry, event, prefstate): _text = entry.get_text() if _text == '' or _text == '+': entry.delete_text(0, -1) _size = "%f" % globals.prefs['DIM_PRIMARY_TEXT_SIZE'] entry.set_text(_size) return False def _dim_secondary_textsize_entry_focus_out(entry, event, prefstate): _text = entry.get_text() if _text == '' or _text == '+': entry.delete_text(0, -1) _size = "%f" % globals.prefs['DIM_SECONDARY_TEXT_SIZE'] entry.set_text(_size) return False def entry_focus_out(entry, event): _text = entry.get_text() if _text == '-' or _text == '+': entry.delete_text(0, -1) return False # # color change button handlers # def _get_rgb_values(color): if not isinstance(color, gtk.gdk.Color): raise TypeError, "Unexpected color type: " + `type(color)` _r = int(round((color.red/65535.0) * 255.0)) _g = int(round((color.green/65535.0) * 255.0)) _b = int(round((color.blue/65535.0) * 255.0)) return _r, _g, _b def _select_background_color(button): _da = button.get_child().get_child() _color = _da.get_style().bg[gtk.STATE_NORMAL] _dialog = gtk.ColorSelectionDialog(_('Choose New Color')) _colorsel = _dialog.colorsel _colorsel.set_previous_color(_color) _colorsel.set_current_color(_color) _colorsel.set_has_palette(True) _response = _dialog.run() if _response == gtk.RESPONSE_OK: _r, _g, _b = _get_rgb_values(_colorsel.get_current_color()) _str = "#%02x%02x%02x" % (_r, _g, _b) _color = gtk.gdk.color_parse(_str) _da.modify_bg(gtk.STATE_NORMAL, _color) _dialog.destroy() def _select_dimbar_color(button): _da = button.get_child().get_child() _color = _da.get_style().bg[gtk.STATE_NORMAL] _dialog = gtk.ColorSelectionDialog(_('Set Dimension Bar Color')) _colorsel = _dialog.colorsel _colorsel.set_previous_color(_color) _colorsel.set_current_color(_color) _colorsel.set_has_palette(True) _response = _dialog.run() if _response == gtk.RESPONSE_OK: _r, _g, _b = _get_rgb_values(_colorsel.get_current_color()) _str = "#%02x%02x%02x" % (_r, _g, _b) _color = gtk.gdk.color_parse(_str) _da.modify_bg(gtk.STATE_NORMAL, _color) _dialog.destroy() def _select_font_color(button): _da = button.get_child().get_child() _color = _da.get_style().bg[gtk.STATE_NORMAL] _dialog = gtk.ColorSelectionDialog(_('Set Font Color')) _colorsel = _dialog.colorsel _colorsel.set_previous_color(_color) _colorsel.set_current_color(_color) _colorsel.set_has_palette(True) _response = _dialog.run() if _response == gtk.RESPONSE_OK: _r, _g, _b = _get_rgb_values(_colorsel.get_current_color()) _str = "#%02x%02x%02x" % (_r, _g, _b) _color = gtk.gdk.color_parse(_str) _da.modify_bg(gtk.STATE_NORMAL, _color) _dialog.destroy() # def _toggle_widgets_on(widget, checkbox): if widget is not checkbox: widget.set_sensitive(True) def _toggle_widgets_off(widget, checkbox): if widget is not checkbox: widget.set_sensitive(False) def _toggle_secondary_dim_opts(checkbox, vbox): if checkbox.get_active(): vbox.foreach(_toggle_widgets_on, checkbox) else: vbox.foreach(_toggle_widgets_off, checkbox) def move_cursor(entry): entry.set_position(-1) return False def entry_insert_text(entry, new_text, new_text_length, position): if (new_text.isdigit() or new_text == '.' or new_text == '+'): _string = entry.get_text() + new_text[:new_text_length] _hid = entry.get_data('handlerid') _move = True entry.handler_block(_hid) try: _pos = entry.get_position() if _string == '+': _pos = entry.insert_text(new_text, _pos) else: try: _val = float(_string) _pos = entry.insert_text(new_text, _pos) except StandardError, e: _move = False sys.stdout.write("exception: '%s'\n" % e) finally: entry.handler_unblock(_hid) if _move: if hasattr(gobject, 'idle_add'): gobject.idle_add(move_cursor, entry) else: gtk.idle_add(move_cursor, entry) entry.stop_emission("insert-text") def tree_select_cb(selection, prefstate): if selection is not None: _model, _iter = selection.get_selected() if _iter is not None: _hbox = prefstate.getHBox() _prefkey = prefstate.getPrefKey() if _prefkey is not None: _old_container = prefstate.getContainer(_prefkey) assert _old_container is not None, "No container: " + _prefkey _pstring = _model.get_value(_iter, 1) # print "second field: '%s'" % _pstring _new_container = prefstate.getContainer(_pstring) if _new_container is None: if _pstring == 'dimensions': _new_container = _make_dimension_opts(prefstate) elif _pstring == 'linear': _new_container = _make_linear_opts(prefstate) elif _pstring == 'radial': _new_container = _make_radial_opts(prefstate) elif _pstring == 'angular': _new_container = _make_angular_opts(prefstate) elif _pstring == 'basic': _new_container = _make_basic_opts(prefstate) elif _pstring == 'sizes': _new_container = _make_size_opts(prefstate) elif _pstring == 'chamfers': _new_container = None elif _pstring == 'fillets': _new_container = None elif _pstring == 'text': _new_container = _make_text_opts(prefstate) elif _pstring == 'primary': _new_container = _make_primary_opts(prefstate) elif _pstring == 'secondary': _new_container = _make_secondary_opts(prefstate) elif _pstring == 'snap': _new_container = _make_snap_opts(prefstate) else: print "unexpected string: '%s'" % _pstring if _new_container is not None: _frame = None if _pstring == 'linear': _frame = prefstate.getWidget('LINEAR_SECONDARY_FRAME') elif _pstring == 'radial': _frame = prefstate.getWidget('RADIAL_SECONDARY_FRAME') elif _pstring == 'angular': _frame = prefstate.getWidget('ANGULAR_SECONDARY_FRAME') else: pass if _frame is not None: _flag = True if prefstate.hasWidgetKey('DIM_DUAL_MODE'): _cb = prefstate.getWidget('DIM_DUAL_MODE') _flag = _cb.get_active() if _flag: _frame.foreach(_toggle_widgets_on, _frame) else: _frame.foreach(_toggle_widgets_off, _frame) if _prefkey is not None: _old_container.hide_all() _hbox.remove(_old_container) _new_container.show_all() prefstate.setContainer(_pstring, _new_container) prefstate.setPrefKey(_pstring) _hbox.pack_start(_new_container, True, True, 5) # # the second time a new container is shown it may not # redraw completely - why? # _hbox.show_all() def _make_dimension_opts(prefstate): _vbox = gtk.VBox(False, 5) _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_IN) _text = "%s" % _('General Dimension Options') _label = gtk.Label(_text) _label.set_use_markup(True) _frame.add(_label) _vbox.pack_start(_frame, False, False, 5) _size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) # # options for dimension bars # _frame = gtk.Frame(_('Dimension Bar Options')) _table = gtk.Table(5, 2, False) _table.set_border_width(5) _table.set_row_spacings(5) _table.set_col_spacings(5) _frame.add(_table) _label = gtk.Label(_('Offset length:')) _table.attach(_label, 0, 1, 0, 1, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _length = "%f" % globals.prefs['DIM_OFFSET'] _entry.set_text(_length) if not prefstate.hasWidgetKey('DIM_OFFSET'): prefstate.setWidget('DIM_OFFSET', _entry) _entry.connect("activate", entry_activate) _entry.connect("focus-out-event", _dim_offset_entry_focus_out, prefstate) _handlerid = _entry.connect("insert-text", entry_insert_text) _entry.set_data('handlerid', _handlerid) _size_group.add_widget(_entry) _table.attach(_entry, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _thbox = gtk.HBox(False) _thbox.set_border_width(2) _label = gtk.Label(_('The offset length is the distance between the dimension point and the start of the dimension bar.')) _thbox.pack_start(_label, False, False) _label.set_line_wrap(True) _table.attach(_thbox, 0, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) # _label = gtk.Label(_('Extension length:')) _table.attach(_label, 0, 1, 2, 3, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _length = "%f" % globals.prefs['DIM_EXTENSION'] _entry.set_text(_length) if not prefstate.hasWidgetKey('DIM_EXTENSION'): prefstate.setWidget('DIM_EXTENSION', _entry) _entry.connect("activate", entry_activate) _entry.connect("focus-out-event", _dim_extlen_entry_focus_out, prefstate) _handlerid = _entry.connect("insert-text", entry_insert_text) _entry.set_data('handlerid', _handlerid) _size_group.add_widget(_entry) _table.attach(_entry, 1, 2, 2, 3, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _thbox = gtk.HBox(False) _thbox.set_border_width(2) _label = gtk.Label(_('The extension length is the distance the dimension bars extend beyond the dimension crossbar/crossarc.')) _label.set_line_wrap(True) _thbox.pack_start(_label, False, False) _table.attach(_thbox, 0, 2, 3, 4, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _fhbox = gtk.HBox(False, 5) _label = gtk.Label(_('Dimension bar color:')) _fhbox.pack_start(_label, False, False, 5) _color = globals.prefs['DIM_COLOR'] _gtkcolor = gtk.gdk.color_parse(str(_color)) if hasattr(gtk, 'ColorButton'): _button = gtk.ColorButton(color=_gtkcolor) _button.set_title(_('Select Dimension Color')) if not prefstate.hasWidgetKey('DIM_COLOR'): prefstate.setWidget('DIM_COLOR', _button) else: _button = gtk.Button() _bframe = gtk.Frame() _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT) _bframe.set_border_width(5) _button.add(_bframe) _da = gtk.DrawingArea() _da.set_size_request(20, 10) _da.modify_bg(gtk.STATE_NORMAL, _gtkcolor) if not prefstate.hasWidgetKey('DIM_COLOR'): prefstate.setWidget('DIM_COLOR', _da) _button.connect("clicked", _select_dimbar_color) _bframe.add(_da) _fhbox.pack_start(_button, False, False, 5) _table.attach(_fhbox, 0, 2, 4, 5, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _vbox.pack_start(_frame, False, False, 5) # # options for dimension text position # _frame = gtk.Frame(_('Dimension Text Position')) _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _frame.add(_fhbox) _label = gtk.Label(_('Text Location at crossbar:')) _fhbox.pack_start(_label, False, False, 5) _idx = 0 _cur_pos = globals.prefs['DIM_POSITION'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_dim_positions)): _name = _dim_positions[_i] if _cur_pos == Dimension.getPositionFromString(_name): _idx = _i _widget.append_text(_name) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_dim_positions)): _name = _dim_positions[_i] if _cur_pos == Dimension.getPositionFromString(_name): _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('DIM_POSITION'): prefstate.setWidget('DIM_POSITION', _widget) _fhbox.pack_start(_widget, False, False, 0) _vbox.pack_start(_frame, False, False, 5) # # options for dimension crossbar/crossarc markers # _frame = gtk.Frame(_('Dimension Crossbar Markers')) _table = gtk.Table(2, 2, False) _table.set_border_width(5) _table.set_row_spacings(5) _table.set_col_spacings(5) _frame.add(_table) _label = gtk.Label(_('Dimension marker:')) _table.attach(_label, 0, 1, 0, 1, gtk.FILL, gtk.FILL, 2, 2) _idx = 0 _endpt = globals.prefs['DIM_ENDPOINT'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_dim_endpoints)): _name = _dim_endpoints[_i] if _endpt == Dimension.getEndpointTypeFromString(_name): _idx = _i _widget.append_text(_name) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_dim_endpoints)): _name = _dim_endpoints[_i] if _endpt == Dimension.getEndpointTypeFromString(_name): _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('DIM_ENDPOINT'): prefstate.setWidget('DIM_ENDPOINT', _widget) _table.attach(_widget, 1, 2, 0, 1, gtk.FILL, gtk.FILL, 2, 2) # _label = gtk.Label(_('Marker size:')) _table.attach(_label, 0, 1, 1, 2, gtk.FILL, gtk.FILL, 2, 2) _entry = gtk.Entry() _size = "%f" % globals.prefs['DIM_ENDPOINT_SIZE'] _entry.set_text(_size) if not prefstate.hasWidgetKey('DIM_ENDPOINT_SIZE'): prefstate.setWidget('DIM_ENDPOINT_SIZE', _entry) _entry.connect("activate", entry_activate) _entry.connect("focus-out-event", _dim_marker_entry_focus_out, prefstate) _handlerid = _entry.connect("insert-text", entry_insert_text) _entry.set_data('handlerid', _handlerid) _size_group.add_widget(_entry) _table.attach(_entry, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 2, 2) _vbox.pack_start(_frame, False, False, 5) return _vbox def _make_primary_opts(prefstate): _vbox = gtk.VBox(False, 2) _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_IN) _text = "%s" % _('Primary Dimension Options') _label = gtk.Label(_text) _label.set_use_markup(True) _frame.add(_label) _vbox.pack_start(_frame, False, False, 5) _frame = gtk.Frame(_('Units')) _frame.set_border_width(2) _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(2) _frame.add(_fhbox) _label = gtk.Label(_('Primary dimension units:')) _fhbox.pack_start(_label, False, False, 5) _idx = 0 _units = units.get_all_units() _cur_unit = globals.prefs['DIM_PRIMARY_UNITS'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_units)): if _i == _cur_unit: _idx = _i _widget.append_text(_units[_i]) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_units)): if _i == _cur_unit: _idx = _i _item = gtk.MenuItem(_units[_i]) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('DIM_PRIMARY_UNITS'): prefstate.setWidget('DIM_PRIMARY_UNITS', _widget) _fhbox.pack_start(_widget, False, False, 5) _vbox.pack_start(_frame, False, False, 5) # _label_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _menu_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) # _frame = gtk.Frame(_('Font Properties')) _frame.set_border_width(2) _fvbox = gtk.VBox(False, 5) _fvbox.set_border_width(2) _frame.add(_fvbox) _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Family:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _families = prefstate.getFamilies() if _families is None: _families = [] _window = prefstate.getWindow() for _family in _window.get_pango_context().list_families(): _families.append(_family.get_name()) _families.sort() prefstate.setFamilies(_families) _idx = 0 _family = globals.prefs['DIM_PRIMARY_FONT_FAMILY'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_families)): _f = _families[_i] if _family == _f: _idx = _i _widget.append_text(_f) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_families)): _f = _families[_i] if _family == _f: _idx = _i _item = gtk.MenuItem(_f) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('DIM_PRIMARY_FONT_FAMILY'): prefstate.setWidget('DIM_PRIMARY_FONT_FAMILY', _widget) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Style:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _idx = 0 _style = globals.prefs['DIM_PRIMARY_FONT_STYLE'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_font_styles)): _name = _font_styles[_i] if _style == TextStyle.getStyleFromString(_name): _idx = _i _widget.append_text(_name) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_font_styles)): _name = _font_styles[_i] if _style == TextStyle.getStyleFromString(_name): _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('DIM_PRIMARY_FONT_STYLE'): prefstate.setWidget('DIM_PRIMARY_FONT_STYLE', _widget) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Weight:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _idx = 0 _weight = globals.prefs['DIM_PRIMARY_FONT_WEIGHT'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_font_weights)): _name = _font_weights[_i] if _weight == TextStyle.getWeightFromString(_name): _idx = _i _widget.append_text(_name) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_font_weights)): _name =_font_weights[_i] if _weight == TextStyle.getWeightFromString(_name): _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('DIM_PRIMARY_FONT_WEIGHT'): prefstate.setWidget('DIM_PRIMARY_FONT_WEIGHT', _widget) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Alignment:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _idx = 0 _align = globals.prefs['DIM_PRIMARY_TEXT_ALIGNMENT'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_text_align)): _name = _text_align[_i] if _align == TextStyle.getAlignmentFromString(_name): _idx = _i _widget.append_text(_name) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_text_align)): _name = _text_align[_i] if _align == TextStyle.getAlignmentFromString(_name): _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('DIM_PRIMARY_TEXT_ALIGNMENT'): prefstate.setWidget('DIM_PRIMARY_TEXT_ALIGNMENT', _widget) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Size:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _entry = gtk.Entry() _size = "%f" % globals.prefs['DIM_PRIMARY_TEXT_SIZE'] _entry.set_text(_size) if not prefstate.hasWidgetKey('DIM_PRIMARY_TEXT_SIZE'): prefstate.setWidget('DIM_PRIMARY_TEXT_SIZE', _entry) _entry.connect("activate", entry_activate) _entry.connect("focus-out-event", _dim_primary_textsize_entry_focus_out, prefstate) _handlerid = _entry.connect("insert-text", entry_insert_text) _entry.set_data('handlerid', _handlerid) # _entry_size_group.add_widget(_entry) _fhbox.pack_start(_entry, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(2) _label = gtk.Label(_('Color:')) _fhbox.pack_start(_label, False, False, 5) _color = globals.prefs['DIM_PRIMARY_FONT_COLOR'] _gtkcolor = gtk.gdk.color_parse(str(_color)) if hasattr(gtk, 'ColorButton'): _button = gtk.ColorButton(color=_gtkcolor) _button.set_title(_('Select Primary Dimension Font Color')) if not prefstate.hasWidgetKey('DIM_PRIMARY_FONT_COLOR'): prefstate.setWidget('DIM_PRIMARY_FONT_COLOR', _button) else: _button = gtk.Button() _bframe = gtk.Frame() _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT) _bframe.set_border_width(5) _button.add(_bframe) _da = gtk.DrawingArea() _da.set_size_request(20, 10) _da.modify_bg(gtk.STATE_NORMAL, _gtkcolor) if not prefstate.hasWidgetKey('DIM_PRIMARY_FONT_COLOR'): prefstate.setWidget('DIM_PRIMARY_FONT_COLOR', _da) _button.connect("clicked", _select_font_color) _bframe.add(_da) _fhbox.pack_start(_button, False, False, 5) _fvbox.pack_start(_fhbox, True, True, 5) _vbox.pack_start(_frame, False, False, 5) # _frame = gtk.Frame(_('Format Options')) _frame.set_border_width(2) _table = gtk.Table(3, 1, False) _table.set_border_width(5) _table.set_row_spacings(5) _table.set_col_spacings(5) _frame.add(_table) _cb = gtk.CheckButton(_('Print leading 0')) _state = globals.prefs['DIM_PRIMARY_LEADING_ZERO'] _cb.set_active(_state) if not prefstate.hasWidgetKey('DIM_PRIMARY_LEADING_ZERO'): prefstate.setWidget('DIM_PRIMARY_LEADING_ZERO', _cb) _table.attach(_cb, 0, 1, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _cb = gtk.CheckButton(_('Print trailing decimal point')) _state = globals.prefs['DIM_PRIMARY_TRAILING_DECIMAL'] _cb.set_active(_state) if not prefstate.hasWidgetKey('DIM_PRIMARY_TRAILING_DECIMAL'): prefstate.setWidget('DIM_PRIMARY_TRAILING_DECIMAL', _cb) _table.attach(_cb, 0, 1, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _thbox = gtk.HBox(False, 5) _label = gtk.Label(_('Display precision:')) _thbox.pack_start(_label, False, False, 5) _prec = globals.prefs['DIM_PRIMARY_PRECISION'] _adj = gtk.Adjustment(_prec, 0, 15, 1, 1, 1) _sb = gtk.SpinButton(_adj) _sb.set_digits(0) _sb.set_numeric(True) if not prefstate.hasWidgetKey('DIM_PRIMARY_PRECISION'): prefstate.setWidget('DIM_PRIMARY_PRECISION', _sb) _thbox.pack_start(_sb, False, False, 5) _table.attach(_thbox, 0, 1, 2, 3, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _vbox.pack_start(_frame, False, False, 5) return _vbox def _make_snap_opts(prefstate): """ Populate the left side of pref panel """ _vbox = gtk.VBox(False, 2) _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_IN) # # Headers # _text = "%s" % _('Snap Options') _label = gtk.Label(_text) _label.set_use_markup(True) _frame.add(_label) _vbox.pack_start(_frame, False, True, 5) # # Create Snap option Container # _snapFrame = gtk.Frame("Snap") _snapFrame.set_shadow_type(gtk.SHADOW_IN) verticalBoxItem=len(globals.snapOption) snapFrameVbox = gtk.VBox(True, verticalBoxItem) # # Fill Up snap Options # for key in globals.snapOption.keys(): newButton=createButtonOption(key,globals.snapOption[key]) newButton.connect("clicked", changeSnapState, None) snapFrameVbox.add(newButton) # # Fill Up snap Functionality # _vbox.pack_start(snapFrameVbox, False, False, 5) _label.show() _frame.show() _vbox.show() return _vbox def changeSnapState(self, widget, data=None): """ Change the state of the Global variable button """ # todo capire come fare a cambiare # globals.snapOption # per il settaggio dei valori # ret=self.get_active() if self.get_label() in globals.snapOption: globals.snapOption[self.get_label()]=ret return def createButtonOption(key,state): """ Create a button that show the snap state """ button=gtk.ToggleButton(key) button.set_active(state) button.show() return button def _make_secondary_opts(prefstate): _vbox = gtk.VBox(False, 2) _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_IN) _text = "%s" % _('Secondary Dimension Options') _label = gtk.Label(_text) _label.set_use_markup(True) _frame.add(_label) _vbox.pack_start(_frame, True, True, 5) # # it would be good to allow the widgets to be used if # the check box is active ... # _cb = gtk.CheckButton(_('Display secondary dimension text')) _state = globals.prefs['DIM_DUAL_MODE'] _cb.set_active(_state) _cb.connect("toggled", _toggle_secondary_dim_opts, _vbox) if not prefstate.hasWidgetKey('DIM_DUAL_MODE'): prefstate.setWidget('DIM_DUAL_MODE', _cb) _vbox.pack_start(_cb, False, False, 5) _frame = gtk.Frame(_('Units')) _frame.set_border_width(2) _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(2) _frame.add(_fhbox) _label = gtk.Label(_('Secondary dimension units:')) _fhbox.pack_start(_label, False, False, 5) _idx = 0 _units = units.get_all_units() _cur_unit = globals.prefs['DIM_SECONDARY_UNITS'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_units)): if _i == _cur_unit: _idx = _i _widget.append_text(_units[_i]) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_units)): if _i == _cur_unit: _idx = _i _item = gtk.MenuItem(_units[_i]) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('DIM_SECONDARY_UNITS'): prefstate.setWidget('DIM_SECONDARY_UNITS', _widget) _fhbox.pack_start(_widget, False, False, 5) _vbox.pack_start(_frame, False, False, 5) # _label_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _menu_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) # _frame = gtk.Frame(_('Font Properties')) _frame.set_border_width(2) _fvbox = gtk.VBox(False, 5) _fvbox.set_border_width(2) _frame.add(_fvbox) _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Family:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _families = prefstate.getFamilies() if _families is None: _families = [] _window = prefstate.getWindow() for _family in _window.get_pango_context().list_families(): _families.append(_family.get_name()) _families.sort() prefstate.setFamilies(_families) _idx = 0 _family = globals.prefs['DIM_SECONDARY_FONT_FAMILY'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_families)): _f = _families[_i] if _family == _f: _idx = _i _widget.append_text(_f) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_families)): _f = _families[_i] if _family == _f: _idx = _i _item = gtk.MenuItem(_f) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('DIM_SECONDARY_FONT_FAMILY'): prefstate.setWidget('DIM_SECONDARY_FONT_FAMILY', _widget) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Style:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _idx = 0 _style = globals.prefs['DIM_SECONDARY_FONT_STYLE'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_font_styles)): _name = _font_styles[_i] if _style == TextStyle.getStyleFromString(_name): _idx = _i _widget.append_text(_name) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_font_styles)): _name = _font_styles[_i] if _style == TextStyle.getStyleFromString(_name): _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('DIM_SECONDARY_FONT_STYLE'): prefstate.setWidget('DIM_SECONDARY_FONT_STYLE', _widget) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Weight:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _idx = 0 _weight = globals.prefs['DIM_SECONDARY_FONT_WEIGHT'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_font_weights)): _name = _font_weights[_i] if _weight == TextStyle.getWeightFromString(_name): _idx = _i _widget.append_text(_name) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_font_weights)): _name = _font_weights[_i] if _weight == TextStyle.getWeightFromString(_name): _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('DIM_SECONDARY_FONT_WEIGHT'): prefstate.setWidget('DIM_SECONDARY_FONT_WEIGHT', _widget) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Alignment:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _idx = 0 _align = globals.prefs['DIM_SECONDARY_TEXT_ALIGNMENT'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_text_align)): _name = _text_align[_i] if _align == TextStyle.getAlignmentFromString(_name): _idx = _i _widget.append_text(_name) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_text_align)): _name = _text_align[_i] if _align == TextStyle.getAlignmentFromString(_name): _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('DIM_SECONDARY_TEXT_ALIGNMENT'): prefstate.setWidget('DIM_SECONDARY_TEXT_ALIGNMENT', _widget) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Size:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _entry = gtk.Entry() _size = "%f" % globals.prefs['DIM_SECONDARY_TEXT_SIZE'] _entry.set_text(_size) if not prefstate.hasWidgetKey('DIM_SECONDARY_TEXT_SIZE'): prefstate.setWidget('DIM_SECONDARY_TEXT_SIZE', _entry) _entry.connect("activate", entry_activate) _entry.connect("focus-out-event", _dim_secondary_textsize_entry_focus_out, prefstate) _handlerid = _entry.connect("insert-text", entry_insert_text) _entry.set_data('handlerid', _handlerid) # _entry_size_group.add_widget(_entry) _fhbox.pack_start(_entry, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(2) _label = gtk.Label(_('Color:')) _fhbox.pack_start(_label, False, False, 5) _color = globals.prefs['DIM_SECONDARY_FONT_COLOR'] _gtkcolor = gtk.gdk.color_parse(str(_color)) if hasattr(gtk, 'ColorButton'): _button = gtk.ColorButton(color=_gtkcolor) _button.set_title(_('Select Secondary Dimension Font Color')) if not prefstate.hasWidgetKey('DIM_SECONDARY_FONT_COLOR'): prefstate.setWidget('DIM_SECONDARY_FONT_COLOR', _button) else: _button = gtk.Button() _bframe = gtk.Frame() _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT) _bframe.set_border_width(5) _button.add(_bframe) _da = gtk.DrawingArea() _da.set_size_request(20, 10) _da.modify_bg(gtk.STATE_NORMAL, _gtkcolor) if not prefstate.hasWidgetKey('DIM_SECONDARY_FONT_COLOR'): prefstate.setWidget('DIM_SECONDARY_FONT_COLOR', _da) _button.connect("clicked", _select_font_color) _bframe.add(_da) _fhbox.pack_start(_button, False, False, 5) _fvbox.pack_start(_fhbox, True, True, 5) _vbox.pack_start(_frame, False, False, 5) _frame = gtk.Frame(_('Format Options')) _frame.set_border_width(2) _table = gtk.Table(3, 1, False) _table.set_border_width(5) _table.set_row_spacings(5) _table.set_col_spacings(5) _frame.add(_table) _cb = gtk.CheckButton(_('Print leading 0')) _state = globals.prefs['DIM_SECONDARY_LEADING_ZERO'] _cb.set_active(_state) if not prefstate.hasWidgetKey('DIM_SECONDARY_LEADING_ZERO'): prefstate.setWidget('DIM_SECONDARY_LEADING_ZERO', _cb) _table.attach(_cb, 0, 1, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _cb = gtk.CheckButton(_('Print trailing decimal point')) _state = globals.prefs['DIM_SECONDARY_TRAILING_DECIMAL'] _cb.set_active(_state) if not prefstate.hasWidgetKey('DIM_SECONDARY_TRAILING_DECIMAL'): prefstate.setWidget('DIM_SECONDARY_TRAILING_DECIMAL', _cb) _table.attach(_cb, 0, 1, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _thbox = gtk.HBox(False, 5) _label = gtk.Label(_('Display precision:')) _thbox.pack_start(_label, False, False, 5) _prec = globals.prefs['DIM_SECONDARY_PRECISION'] _adj = gtk.Adjustment(_prec, 0, 15, 1, 1, 1) _sb = gtk.SpinButton(_adj) _sb.set_digits(0) _sb.set_numeric(True) if not prefstate.hasWidgetKey('DIM_SECONDARY_PRECISION'): prefstate.setWidget('DIM_SECONDARY_PRECISION', _sb) _thbox.pack_start(_sb, False, False, 5) _table.attach(_thbox, 0, 1, 2, 3, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _vbox.pack_start(_frame, False, False, 5) _cb = prefstate.getWidget('DIM_DUAL_MODE') _cb.emit("toggled") return _vbox def _make_linear_opts(prefstate): _vbox = gtk.VBox(False, 5) _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_IN) _text = "%s" % _('Linear Dimension Options') _label = gtk.Label(_text) _label.set_use_markup(True) _frame.add(_label) _vbox.pack_start(_frame, False, False, 5) _size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _frame = gtk.Frame(_('Primary Dimension Text Options')) _table = gtk.Table(2, 2, False) _table.set_border_width(5) _table.set_row_spacings(5) _table.set_col_spacings(5) _frame.add(_table) _label = gtk.Label(_('Default prefix:')) _table.attach(_label, 0, 1, 0, 1, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _entry.set_text(globals.prefs['DIM_PRIMARY_PREFIX']) _size_group.add_widget(_entry) if not prefstate.hasWidgetKey('DIM_PRIMARY_PREFIX'): prefstate.setWidget('DIM_PRIMARY_PREFIX', _entry) _table.attach(_entry, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _label = gtk.Label(_('Default suffix:')) _table.attach(_label, 0, 1, 1, 2, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _entry.set_text(globals.prefs['DIM_PRIMARY_SUFFIX']) _size_group.add_widget(_entry) if not prefstate.hasWidgetKey('DIM_PRIMARY_SUFFIX'): prefstate.setWidget('DIM_PRIMARY_SUFFIX', _entry) _table.attach(_entry, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _vbox.pack_start(_frame, False, False, 5) _frame = gtk.Frame(_('Secondary Dimension Text Options')) _table = gtk.Table(2, 2, False) _table.set_border_width(5) _table.set_row_spacings(5) _table.set_col_spacings(5) _frame.add(_table) if not prefstate.hasWidgetKey('LINEAR_SECONDARY_FRAME'): prefstate.setWidget('LINEAR_SECONDARY_FRAME', _frame) _label = gtk.Label(_('Default prefix:')) _table.attach(_label, 0, 1, 0, 1, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _entry.set_text(globals.prefs['DIM_SECONDARY_PREFIX']) _size_group.add_widget(_entry) if not prefstate.hasWidgetKey('DIM_SECONDARY_PREFIX'): prefstate.setWidget('DIM_SECONDARY_PREFIX', _entry) _table.attach(_entry, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _label = gtk.Label(_('Default suffix:')) _table.attach(_label, 0, 1, 1, 2, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _entry.set_text(globals.prefs['DIM_SECONDARY_SUFFIX']) _size_group.add_widget(_entry) if not prefstate.hasWidgetKey('DIM_SECONDARY_SUFFIX'): prefstate.setWidget('DIM_SECONDARY_SUFFIX', _entry) _table.attach(_entry, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _vbox.pack_start(_frame, False, False, 5) return _vbox def _make_radial_opts(prefstate): _vbox = gtk.VBox(False, 5) _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_IN) _text = "%s" % _('Radial Dimension Options') _label = gtk.Label(_text) _label.set_use_markup(True) _frame.add(_label) _vbox.pack_start(_frame, False, False, 5) _size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _frame = gtk.Frame(_('Primary Dimension Text Options')) _table = gtk.Table(2, 2, False) _table.set_border_width(5) _table.set_row_spacings(5) _table.set_col_spacings(5) _frame.add(_table) _label = gtk.Label(_('Default prefix:')) _table.attach(_label, 0, 1, 0, 1, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _entry.set_text(globals.prefs['RADIAL_DIM_PRIMARY_PREFIX']) _size_group.add_widget(_entry) if not prefstate.hasWidgetKey('RADIAL_DIM_PRIMARY_PREFIX'): prefstate.setWidget('RADIAL_DIM_PRIMARY_PREFIX', _entry) _table.attach(_entry, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _label = gtk.Label(_('Default suffix:')) _table.attach(_label, 0, 1, 1, 2, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _entry.set_text(globals.prefs['RADIAL_DIM_PRIMARY_SUFFIX']) _size_group.add_widget(_entry) if not prefstate.hasWidgetKey('RADIAL_DIM_PRIMARY_SUFFIX'): prefstate.setWidget('RADIAL_DIM_PRIMARY_SUFFIX', _entry) _table.attach(_entry, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _vbox.pack_start(_frame, False, False, 5) _frame = gtk.Frame(_('Secondary Dimension Text Options')) _table = gtk.Table(2, 2, False) _table.set_border_width(5) _table.set_row_spacings(5) _table.set_col_spacings(5) _frame.add(_table) if not prefstate.hasWidgetKey('RADIAL_SECONDARY_FRAME'): prefstate.setWidget('RADIAL_SECONDARY_FRAME', _frame) _label = gtk.Label(_('Default prefix:')) _table.attach(_label, 0, 1, 0, 1, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _entry.set_text(globals.prefs['RADIAL_DIM_SECONDARY_PREFIX']) _size_group.add_widget(_entry) if not prefstate.hasWidgetKey('RADIAL_DIM_SECONDARY_PREFIX'): prefstate.setWidget('RADIAL_DIM_SECONDARY_PREFIX', _entry) _table.attach(_entry, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _label = gtk.Label(_('Default suffix:')) _table.attach(_label, 0, 1, 1, 2, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _entry.set_text(globals.prefs['RADIAL_DIM_SECONDARY_SUFFIX']) _size_group.add_widget(_entry) if not prefstate.hasWidgetKey('RADIAL_DIM_SECONDARY_SUFFIX'): prefstate.setWidget('RADIAL_DIM_SECONDARY_SUFFIX', _entry) _table.attach(_entry, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _vbox.pack_start(_frame, False, False, 5) _cb = gtk.CheckButton(_('Show diametrical dimension value')) _state = globals.prefs['RADIAL_DIM_DIA_MODE'] _cb.set_active(_state) if not prefstate.hasWidgetKey('RADIAL_DIM_DIA_MODE'): prefstate.setWidget('RADIAL_DIM_DIA_MODE', _cb) _vbox.pack_start(_cb, False, False, 5) return _vbox def _make_angular_opts(prefstate): _vbox = gtk.VBox(False, 5) _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_IN) _text = "%s" % _('Angular Dimension Options') _label = gtk.Label(_text) _label.set_use_markup(True) _frame.add(_label) _vbox.pack_start(_frame, False, False, 5) _size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _frame = gtk.Frame(_('Primary Dimension Text Options')) _table = gtk.Table(2, 2, False) _table.set_border_width(5) _table.set_row_spacings(5) _table.set_col_spacings(5) _frame.add(_table) _label = gtk.Label(_('Default prefix:')) _table.attach(_label, 0, 1, 0, 1, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _entry.set_text(globals.prefs['ANGULAR_DIM_PRIMARY_PREFIX']) _size_group.add_widget(_entry) if not prefstate.hasWidgetKey('ANGULAR_DIM_PRIMARY_PREFIX'): prefstate.setWidget('ANGULAR_DIM_PRIMARY_PREFIX', _entry) _table.attach(_entry, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _label = gtk.Label(_('Default suffix:')) _table.attach(_label, 0, 1, 1, 2, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _entry.set_text(globals.prefs['ANGULAR_DIM_PRIMARY_SUFFIX']) _size_group.add_widget(_entry) if not prefstate.hasWidgetKey('ANGULAR_DIM_PRIMARY_SUFFIX'): prefstate.setWidget('ANGULAR_DIM_PRIMARY_SUFFIX', _entry) _table.attach(_entry, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _vbox.pack_start(_frame, False, False, 5) _frame = gtk.Frame(_('Secondary Dimension Text Options')) _table = gtk.Table(2, 2, False) _table.set_border_width(5) _table.set_row_spacings(5) _table.set_col_spacings(5) _frame.add(_table) if not prefstate.hasWidgetKey('ANGULAR_SECONDARY_FRAME'): prefstate.setWidget('ANGULAR_SECONDARY_FRAME', _frame) _label = gtk.Label(_('Default prefix:')) _table.attach(_label, 0, 1, 0, 1, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _entry.set_text(globals.prefs['ANGULAR_DIM_SECONDARY_PREFIX']) _size_group.add_widget(_entry) if not prefstate.hasWidgetKey('ANGULAR_DIM_SECONDARY_PREFIX'): prefstate.setWidget('ANGULAR_DIM_SECONDARY_PREFIX', _entry) _table.attach(_entry, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _label = gtk.Label(_('Default suffix:')) _table.attach(_label, 0, 1, 1, 2, gtk.EXPAND, gtk.EXPAND, 2, 2) _entry = gtk.Entry() _entry.set_text(globals.prefs['ANGULAR_DIM_SECONDARY_SUFFIX']) _size_group.add_widget(_entry) if not prefstate.hasWidgetKey('ANGULAR_DIM_SECONDARY_SUFFIX'): prefstate.setWidget('ANGULAR_DIM_SECONDARY_SUFFIX', _entry) _table.attach(_entry, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _vbox.pack_start(_frame, False, False, 5) return _vbox def _make_basic_opts(prefstate): _vbox = gtk.VBox(False, 5) _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_IN) _text = "%s" % _('Basic Options') _label = gtk.Label(_text) _label.set_use_markup(True) _frame.add(_label) _vbox.pack_start(_frame, False, False, 5) _frame = gtk.Frame(_('Units')) _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _frame.add(_fhbox) _label = gtk.Label(_('Drawing units:')) _fhbox.pack_start(_label, False, False, 5) _unit_list = units.get_all_units() _cur_unit = globals.prefs['UNITS'] _idx = 0 if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_unit_list)): if _i == _cur_unit: _idx = _i _widget.append_text(_unit_list[_i]) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_unit_list)): if _i == _cur_unit: _idx = _i _item = gtk.MenuItem(_unit_list[_i]) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('DRAWING_UNITS'): prefstate.setWidget('DRAWING_UNITS', _widget) _fhbox.pack_start(_widget, False, False, 5) _vbox.pack_start(_frame, False, False, 5) _frame = gtk.Frame(_('Highlight Points')) _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _frame.add(_fhbox) _cb = gtk.CheckButton(_('Boxes are drawn around Point objects')) _state = globals.prefs['HIGHLIGHT_POINTS'] _cb.set_active(_state) if not prefstate.hasWidgetKey('HIGHLIGHT_POINTS'): prefstate.setWidget('HIGHLIGHT_POINTS', _cb) _fhbox.pack_start(_cb, False, False, 5) _vbox.pack_start(_frame, False, False, 5) _frame = gtk.Frame(_('Autosplitting')) _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _frame.add(_fhbox) _cb = gtk.CheckButton(_('New Points split existing entities')) _state = globals.prefs['AUTOSPLIT'] _cb.set_active(_state) if not prefstate.hasWidgetKey('AUTOSPLIT'): prefstate.setWidget('AUTOSPLIT', _cb) _fhbox.pack_start(_cb, False, False, 5) _vbox.pack_start(_frame, False, False, 5) _frame = gtk.Frame(_('Colors')) _table = gtk.Table(4, 2, False) _table.set_border_width(5) _table.set_row_spacings(5) _table.set_col_spacings(5) _frame.add(_table) _label = gtk.Label(_('Drawing area color:')) _table.attach(_label, 0, 1, 0, 1, gtk.FILL, gtk.FILL, 2, 2) _color = globals.prefs['BACKGROUND_COLOR'] _gtkcolor = gtk.gdk.color_parse(str(_color)) if hasattr(gtk, 'ColorButton'): _button = gtk.ColorButton(color=_gtkcolor) _button.set_title(_('Select Background Color')) if not prefstate.hasWidgetKey('BACKGROUND_COLOR'): prefstate.setWidget('BACKGROUND_COLOR', _button) else: _button = gtk.Button() _bframe = gtk.Frame() _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT) _bframe.set_border_width(5) _button.add(_bframe) _da = gtk.DrawingArea() _da.set_size_request(20, 10) _da.modify_bg(gtk.STATE_NORMAL, _gtkcolor) if not prefstate.hasWidgetKey('BACKGROUND_COLOR'): prefstate.setWidget('BACKGROUND_COLOR', _da) _bframe.add(_da) _button.connect("clicked", _select_background_color) _table.attach(_button, 1, 2, 0, 1, gtk.FILL, gtk.FILL, 2, 2) # _label = gtk.Label(_('Inactive layer color:')) _table.attach(_label, 0, 1, 1, 2, gtk.FILL, gtk.FILL, 2, 2) _color = globals.prefs['INACTIVE_LAYER_COLOR'] _gtkcolor = gtk.gdk.color_parse(str(_color)) if hasattr(gtk, 'ColorButton'): _button = gtk.ColorButton(color=_gtkcolor) _button.set_title(_('Select Inactive Layer Color')) if not prefstate.hasWidgetKey('INACTIVE_LAYER_COLOR'): prefstate.setWidget('INACTIVE_LAYER_COLOR', _button) else: _button = gtk.Button() _bframe = gtk.Frame() _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT) _bframe.set_border_width(5) _button.add(_bframe) _da = gtk.DrawingArea() _da.set_size_request(20, 10) _da.modify_bg(gtk.STATE_NORMAL, _gtkcolor) if not prefstate.hasWidgetKey('INACTIVE_LAYER_COLOR'): prefstate.setWidget('INACTIVE_LAYER_COLOR', _da) _bframe.add(_da) _button.connect("clicked", _select_background_color) _table.attach(_button, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 2, 2) # _label = gtk.Label(_('Single point color:')) _table.attach(_label, 0, 1, 2, 3, gtk.FILL, gtk.FILL, 2, 2) _color = globals.prefs['SINGLE_POINT_COLOR'] _gtkcolor = gtk.gdk.color_parse(str(_color)) if hasattr(gtk, 'ColorButton'): _button = gtk.ColorButton(color=_gtkcolor) _button.set_title(_('Select Single Use Point Outline Color')) if not prefstate.hasWidgetKey('SINGLE_POINT_COLOR'): prefstate.setWidget('SINGLE_POINT_COLOR', _button) else: _button = gtk.Button() _bframe = gtk.Frame() _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT) _bframe.set_border_width(5) _button.add(_bframe) _da = gtk.DrawingArea() _da.set_size_request(20, 10) _da.modify_bg(gtk.STATE_NORMAL, _gtkcolor) if not prefstate.hasWidgetKey('SINGLE_POINT_COLOR'): prefstate.setWidget('SINGLE_POINT_COLOR', _da) _bframe.add(_da) _button.connect("clicked", _select_background_color) _table.attach(_button, 1, 2, 2, 3, gtk.FILL, gtk.FILL, 2, 2) # _label = gtk.Label(_('Multi point color:')) _table.attach(_label, 0, 1, 3, 4, gtk.FILL, gtk.FILL, 2, 2) _color = globals.prefs['MULTI_POINT_COLOR'] _gtkcolor = gtk.gdk.color_parse(str(_color)) if hasattr(gtk, 'ColorButton'): _button = gtk.ColorButton(color=_gtkcolor) _button.set_title(_('Select Multi-Use Point Outline Color')) if not prefstate.hasWidgetKey('MULTI_POINT_COLOR'): prefstate.setWidget('MULTI_POINT_COLOR', _button) else: _button = gtk.Button() _bframe = gtk.Frame() _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT) _bframe.set_border_width(5) _button.add(_bframe) _da = gtk.DrawingArea() _da.set_size_request(20, 10) _da.modify_bg(gtk.STATE_NORMAL, _gtkcolor) if not prefstate.hasWidgetKey('MULTI_POINT_COLOR'): prefstate.setWidget('MULTI_POINT_COLOR', _da) _bframe.add(_da) _button.connect("clicked", _select_background_color) _table.attach(_button, 1, 2, 3, 4, gtk.FILL, gtk.FILL, 2, 2) _vbox.pack_start(_frame, False, False, 5) _size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _frame = gtk.Frame(_('Line Thickness')) _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _frame.add(_fhbox) _label = gtk.Label(_('Thickness:')) _fhbox.pack_start(_label, False, False, 5) _entry = gtk.Entry() _thickness = "%f" % globals.prefs['LINE_THICKNESS'] _entry.set_text(_thickness) if not prefstate.hasWidgetKey('LINE_THICKNESS'): prefstate.setWidget('LINE_THICKNESS', _entry) _entry.connect("activate", entry_activate) _entry.connect("focus-out-event", _thickness_entry_focus_out, prefstate) _handlerid = _entry.connect("insert-text", entry_insert_text) _entry.set_data('handlerid', _handlerid) _size_group.add_widget(_entry) _fhbox.pack_start(_entry, False, False, 5) _vbox.pack_start(_frame, False, False, 5) return _vbox def _make_size_opts(prefstate): _vbox = gtk.VBox(False, 5) _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_IN) _label_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _entry_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _text = "%s" % _('Size Options') _label = gtk.Label(_text) _label.set_use_markup(True) _frame.add(_label) _vbox.pack_start(_frame, False, False, 5) # # leader line arrow size # _frame = gtk.Frame(_('Leader Arrow Size')) _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _frame.add(_fhbox) _label = gtk.Label(_('Size:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _entry = gtk.Entry() _arrowsize = "%f" % globals.prefs['LEADER_ARROW_SIZE'] _entry.set_text(_arrowsize) if not prefstate.hasWidgetKey('LEADER_ARROW_SIZE'): prefstate.setWidget('LEADER_ARROW_SIZE', _entry) _entry.connect("activate", entry_activate) _entry.connect("focus-out-event", _leader_entry_focus_out, prefstate) _handlerid = _entry.connect("insert-text", entry_insert_text) _entry.set_data('handlerid', _handlerid) _entry_size_group.add_widget(_entry) _fhbox.pack_start(_entry, False, False, 5) _vbox.pack_start(_frame, False, False, 5) # # Chamfer length # _frame = gtk.Frame(_('Chamfer Length')) _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _frame.add(_fhbox) _label = gtk.Label(_('Length:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _entry = gtk.Entry() _length = "%f" % globals.prefs['CHAMFER_LENGTH'] _entry.set_text(_length) if not prefstate.hasWidgetKey('CHAMFER_LENGTH'): prefstate.setWidget('CHAMFER_LENGTH', _entry) _entry.connect("activate", entry_activate) _entry.connect("focus-out-event", _chamfer_entry_focus_out, prefstate) _handlerid = _entry.connect("insert-text", entry_insert_text) _entry.set_data('handlerid', _handlerid) _entry_size_group.add_widget(_entry) _fhbox.pack_start(_entry, False, False, 5) _vbox.pack_start(_frame, False, False, 5) # # Fillet radius # _frame = gtk.Frame(_('Fillet Radius')) _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _frame.add(_fhbox) _label = gtk.Label(_('Radius:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _entry = gtk.Entry() _radius = "%f" % globals.prefs['FILLET_RADIUS'] _entry.set_text(_radius) if not prefstate.hasWidgetKey('FILLET_RADIUS'): prefstate.setWidget('FILLET_RADIUS', _entry) _entry.connect("activate", entry_activate) _entry.connect("focus-out-event", _fillet_entry_focus_out, prefstate) _handlerid = _entry.connect("insert-text", entry_insert_text) _entry.set_data('handlerid', _handlerid) _entry_size_group.add_widget(_entry) _fhbox.pack_start(_entry, False, False, 5) _vbox.pack_start(_frame, False, False, 5) return _vbox def _make_text_opts(prefstate): _vbox = gtk.VBox(False, 5) _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_IN) _text = "%s" % _('Text Options') _label = gtk.Label(_text) _label.set_use_markup(True) _frame.add(_label) _vbox.pack_start(_frame, False, False, 5) _label_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _menu_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _frame = gtk.Frame(_('Font Properties')) _frame.set_border_width(5) _fvbox = gtk.VBox(False, 5) _frame.add(_fvbox) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Family:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _families = prefstate.getFamilies() if _families is None: _families = [] _window = prefstate.getWindow() for _family in _window.get_pango_context().list_families(): _families.append(_family.get_name()) _families.sort() prefstate.setFamilies(_families) _idx = 0 _family = globals.prefs['FONT_FAMILY'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_families)): _f = _families[_i] if _family == _f: _idx = _i _widget.append_text(_f) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_families)): _f = _families[_i] if _family == _f: _idx = _i _item = gtk.MenuItem(_f) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('FONT_FAMILY'): prefstate.setWidget('FONT_FAMILY', _widget) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Style:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _idx = 0 _style = globals.prefs['FONT_STYLE'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_font_styles)): _name = _font_styles[_i] if _style == TextStyle.getStyleFromString(_name): _idx = _i _widget.append_text(_name) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_font_styles)): _name = _font_styles[_i] if _style == TextStyle.getStyleFromString(_name): _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('FONT_STYLE'): prefstate.setWidget('FONT_STYLE', _widget) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Weight:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _idx = 0 _weight = globals.prefs['FONT_WEIGHT'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_font_weights)): _name = _font_weights[_i] if _weight == TextStyle.getWeightFromString(_name): _idx = _i _widget.append_text(_name) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_font_weights)): _name = _font_weights[_i] if _weight == TextStyle.getWeightFromString(_name): _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('FONT_WEIGHT'): prefstate.setWidget('FONT_WEIGHT', _widget) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Alignment:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _idx = 0 _align = globals.prefs['TEXT_ALIGNMENT'] if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_text_align)): _name = _text_align[_i] if _align == TextStyle.getAlignmentFromString(_name): _idx = _i _widget.append_text(_name) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_text_align)): _name = _text_align[_i] if _align == TextStyle.getAlignmentFromString(_name): _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) if not prefstate.hasWidgetKey('TEXT_ALIGNMENT'): prefstate.setWidget('TEXT_ALIGNMENT', _widget) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(2) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Color:')) _fhbox.pack_start(_label, False, False, 5) _color = globals.prefs['FONT_COLOR'] _gtkcolor = gtk.gdk.color_parse(str(_color)) if hasattr(gtk, 'ColorButton'): _button = gtk.ColorButton(color=_gtkcolor) _button.set_title(_('Select Font Color')) if not prefstate.hasWidgetKey('FONT_COLOR'): prefstate.setWidget('FONT_COLOR', _button) else: _button = gtk.Button() _bframe = gtk.Frame() _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT) _bframe.set_border_width(5) _button.add(_bframe) _da = gtk.DrawingArea() _da.set_size_request(20, 10) _da.modify_bg(gtk.STATE_NORMAL, _gtkcolor) if not prefstate.hasWidgetKey('FONT_COLOR'): prefstate.setWidget('FONT_COLOR', _da) _button.connect("clicked", _select_font_color) _bframe.add(_da) _fhbox.pack_start(_button, False, False, 5) # _fhbox = gtk.HBox(False, 5) _fhbox.set_border_width(5) _fvbox.pack_start(_fhbox, False, False, 5) _label = gtk.Label(_('Size:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 5) _entry = gtk.Entry() _size = "%f" % globals.prefs['TEXT_SIZE'] _entry.set_text(_size) if not prefstate.hasWidgetKey('TEXT_SIZE'): prefstate.setWidget('TEXT_SIZE', _entry) _entry.connect("activate", entry_activate) _entry.connect("focus-out-event", _textsize_entry_focus_out, prefstate) _handlerid = _entry.connect("insert-text", entry_insert_text) _entry.set_data('handlerid', _handlerid) # _entry_size_group.add_widget(_entry) _fhbox.pack_start(_entry, False, False, 5) _vbox.pack_start(_frame, False, False, 5) return _vbox def _make_pref_tree(hbox, prefstate): _sw = gtk.ScrolledWindow() _sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) _sw.set_size_request(120, 300) _tree_store = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING) _iter1 = _tree_store.append(None) _tree_store.set(_iter1, 0, _('Basic')) _tree_store.set(_iter1, 1, 'basic') _iter1 = _tree_store.append(None) _tree_store.set(_iter1, 0, _('Sized Objects')) _tree_store.set(_iter1, 1, 'sizes') _iter1 = _tree_store.append(None) _tree_store.set(_iter1, 0, _('Text')) _tree_store.set(_iter1, 1, 'text') #_tree_view = gtk.TreeView(_tree_store) _iter1 = _tree_store.append(None) # Snap _tree_store.set(_iter1, 0, _('Snap')) _tree_store.set(_iter1, 1, 'snap') _tree_view = gtk.TreeView(_tree_store) _iter1 = _tree_store.append(None) # Dimension _tree_store.set(_iter1, 0, _('Dimensions')) _tree_store.set(_iter1, 1, 'dimensions') _iter2 = _tree_store.append(_iter1) _tree_store.set(_iter2, 0, _('Primary')) _tree_store.set(_iter2, 1, 'primary') _iter2 = _tree_store.append(_iter1) _tree_store.set(_iter2, 0, _('Secondary')) _tree_store.set(_iter2, 1, 'secondary') _iter2 = _tree_store.append(_iter1) _tree_store.set(_iter2, 0, _('Linear')) _tree_store.set(_iter2, 1, 'linear') _iter2 = _tree_store.append(_iter1) _tree_store.set(_iter2, 0, _('Radial')) _tree_store.set(_iter2, 1, 'radial') _iter2 = _tree_store.append(_iter1) _tree_store.set(_iter2, 0, _('Angular')) _tree_store.set(_iter2, 1, 'angular') _tree_view.set_reorderable(False) # no drag-and-drop _select = _tree_view.get_selection() _select.set_mode(gtk.SELECTION_SINGLE) _select.connect("changed", tree_select_cb, prefstate) _renderer = gtk.CellRendererText() _column = gtk.TreeViewColumn(_("Options"), _renderer, text=0) _tree_view.append_column(_column) _sw.add(_tree_view) hbox.pack_start(_sw, False, False, 5) return _tree_view def _set_dim_offset(prefstate): _text = prefstate.getWidget('DIM_OFFSET').get_text() if len(_text) and _text != '+': globals.prefs['DIM_OFFSET'] = float(_text) def _set_dim_extension(prefstate): _text = prefstate.getWidget('DIM_EXTENSION').get_text() if len(_text) and _text != '+': globals.prefs['DIM_EXTENSION'] = float(_text) def _set_dim_color(prefstate): _widget = prefstate.getWidget('DIM_COLOR') if hasattr(gtk, 'ColorButton') and isinstance(_widget, gtk.ColorButton): _color = _widget.get_color() elif isinstance(_widget, gtk.DrawingArea): _color= _widget.get_style().bg[gtk.STATE_NORMAL] else: raise TypeError, "Unexpected widget for DIM_COLOR: " + `type(_widget)` _r, _g, _b = _get_rgb_values(_color) _dimcolor = get_color(_r, _g, _b) globals.prefs['DIM_EXTENSION'] = get_color(_r, _g, _b) def _set_background_color(prefstate): _widget = prefstate.getWidget('BACKGROUND_COLOR') if hasattr(gtk, 'ColorButton') and isinstance(_widget, gtk.ColorButton): _color = _widget.get_color() elif isinstance(_widget, gtk.DrawingArea): _color= _widget.get_style().bg[gtk.STATE_NORMAL] else: raise TypeError, "Unexpected widget for BACKGROUND_COLOR: " + `type(_widget)` _r, _g, _b = _get_rgb_values(_color) globals.prefs['BACKGROUND_COLOR'] = get_color(_r, _g, _b) def _set_inactive_layer_color(prefstate): _widget = prefstate.getWidget('INACTIVE_LAYER_COLOR') if hasattr(gtk, 'ColorButton') and isinstance(_widget, gtk.ColorButton): _color = _widget.get_color() elif isinstance(_widget, gtk.DrawingArea): _color= _widget.get_style().bg[gtk.STATE_NORMAL] else: raise TypeError, "Unexpected widget for INACTIVE_LAYER_COLOR: " + `type(_widget)` _r, _g, _b = _get_rgb_values(_color) globals.prefs['INACTIVE_LAYER_COLOR'] = get_color(_r, _g, _b) def _set_single_point_color(prefstate): _widget = prefstate.getWidget('SINGLE_POINT_COLOR') if hasattr(gtk, 'ColorButton') and isinstance(_widget, gtk.ColorButton): _color = _widget.get_color() elif isinstance(_widget, gtk.DrawingArea): _color= _widget.get_style().bg[gtk.STATE_NORMAL] else: raise TypeError, "Unexpected widget for SINGLE_POINT_COLOR: " + `type(_widget)` _r, _g, _b = _get_rgb_values(_color) globals.prefs['SINGLE_POINT_COLOR'] = get_color(_r, _g, _b) def _set_multi_point_color(prefstate): _widget = prefstate.getWidget('MULTI_POINT_COLOR') if hasattr(gtk, 'ColorButton') and isinstance(_widget, gtk.ColorButton): _color = _widget.get_color() elif isinstance(_widget, gtk.DrawingArea): _color= _widget.get_style().bg[gtk.STATE_NORMAL] else: raise TypeError, "Unexpected widget for MULTI_POINT_COLOR: " + `type(_widget)` _r, _g, _b = _get_rgb_values(_color) globals.prefs['MULTI_POINT_COLOR'] = get_color(_r, _g, _b) def _set_font_color(prefstate): _widget = prefstate.getWidget('FONT_COLOR') if hasattr(gtk, 'ColorButton') and isinstance(_widget, gtk.ColorButton): _color = _widget.get_color() elif isinstance(_widget, gtk.DrawingArea): _color= _widget.get_style().bg[gtk.STATE_NORMAL] else: raise TypeError, "Unexpected widget for FONT_COLOR: " + `type(_widget)` _r, _g, _b = _get_rgb_values(_color) globals.prefs['FONT_COLOR'] = get_color(_r, _g, _b) def _set_dim_primary_font_color(prefstate): _widget = prefstate.getWidget('DIM_PRIMARY_FONT_COLOR') if hasattr(gtk, 'ColorButton') and isinstance(_widget, gtk.ColorButton): _color = _widget.get_color() elif isinstance(_widget, gtk.DrawingArea): _color= _widget.get_style().bg[gtk.STATE_NORMAL] else: raise TypeError, "Unexpected widget for DIM_PRIMARY_FONT_COLOR: " + `type(_widget)` _r, _g, _b = _get_rgb_values(_color) globals.prefs['DIM_PRIMARY_FONT_COLOR'] = get_color(_r, _g, _b) def _set_dim_secondary_font_color(prefstate): _widget = prefstate.getWidget('DIM_SECONDARY_FONT_COLOR') if hasattr(gtk, 'ColorButton') and isinstance(_widget, gtk.ColorButton): _color = _widget.get_color() elif isinstance(_widget, gtk.DrawingArea): _color= _widget.get_style().bg[gtk.STATE_NORMAL] else: raise TypeError, "Unexpected widget for DIM_SECONDARY_FONT_COLOR: " + `type(_widget)` _r, _g, _b = _get_rgb_values(_color) globals.prefs['DIM_SECONDARY_FONT_COLOR'] = get_color(_r, _g, _b) def _set_line_thickness(prefstate): _text = prefstate.getWidget('LINE_THICKNESS').get_text() if len(_text) and _text != '+': globals.prefs['LINE_THICKNESS'] = float(_text) def _set_leader_arrow_size(prefstate): _text = prefstate.getWidget('LEADER_ARROW_SIZE').get_text() if len(_text) and _text != '+': globals.prefs['LEADER_ARROW_SIZE'] = float(_text) def _set_chamfer_length(prefstate): _text = prefstate.getWidget('CHAMFER_LENGTH').get_text() if len(_text) and _text != '+': globals.prefs['CHAMFER_LENGTH'] = float(_text) def _set_fillet_radius(prefstate): _text = prefstate.getWidget('FILLET_RADIUS').get_text() if len(_text) and _text != '+': globals.prefs['FILLET_RADIUS'] = float(_text) def _set_dim_endpoint_size(prefstate): _text = prefstate.getWidget('DIM_ENDPOINT_SIZE').get_text() if len(_text) and _text != '+': globals.prefs['DIM_ENDPOINT_SIZE'] = float(_text) def _set_text_size(prefstate): _text = prefstate.getWidget('TEXT_SIZE').get_text() if len(_text) and _text != '+': globals.prefs['TEXT_SIZE'] = float(_text) def _set_dim_primary_text_size(prefstate): _text = prefstate.getWidget('DIM_PRIMARY_TEXT_SIZE').get_text() if len(_text) and _text != '+': globals.prefs['DIM_PRIMARY_TEXT_SIZE'] = float(_text) def _set_dim_secondary_text_size(prefstate): _text = prefstate.getWidget('DIM_SECONDARY_TEXT_SIZE').get_text() if len(_text) and _text != '+': globals.prefs['DIM_SECONDARY_TEXT_SIZE'] = float(_text) def _set_dim_position_offset(prefstate): _text = prefstate.getWidget('DIM_POSITION_OFFSET').get_text() if len(_text) and _text != '+': globals.prefs['DIM_POSITION_OFFSET'] = float(_text) def _set_dim_dual_mode_offset(prefstate): _text = prefstate.getWidget('DIM_DUAL_MODE_OFFSET').get_text() if len(_text) and _text != '+': globals.prefs['DIM_DUAL_MODE_OFFSET'] = float(_text) def _set_dim_dual_mode(prefstate): _cb = prefstate.getWidget('DIM_DUAL_MODE') globals.prefs['DIM_DUAL_MODE'] = _cb.get_active() def _set_highlight_points(prefstate): _cb = prefstate.getWidget('HIGHLIGHT_POINTS') globals.prefs['HIGHLIGHT_POINTS'] = _cb.get_active() def _set_autosplit(prefstate): _cb = prefstate.getWidget('AUTOSPLIT') globals.prefs['AUTOSPLIT'] = _cb.get_active() def _set_dim_primary_leading_zero(prefstate): _cb = prefstate.getWidget('DIM_PRIMARY_LEADING_ZERO') globals.prefs['DIM_PRIMARY_LEADING_ZERO'] = _cb.get_active() def _set_dim_primary_trailing_decimal(prefstate): _cb = prefstate.getWidget('DIM_PRIMARY_TRAILING_DECIMAL') globals.prefs['DIM_PRIMARY_TRAILING_DECIMAL'] = _cb.get_active() def _set_dim_primary_precision(prefstate): _sb = prefstate.getWidget('DIM_PRIMARY_PRECISION') globals.prefs['DIM_PRIMARY_PRECISION'] = _sb.get_value_as_int() def _set_dim_secondary_leading_zero(prefstate): _cb = prefstate.getWidget('DIM_SECONDARY_LEADING_ZERO') globals.prefs['DIM_SECONDARY_LEADING_ZERO'] = _cb.get_active() def _set_dim_secondary_trailing_decimal(prefstate): _cb = prefstate.getWidget('DIM_SECONDARY_TRAILING_DECIMAL') globals.prefs['DIM_SECONDARY_TRAILING_DECIMAL'] = _cb.get_active() def _set_dim_secondary_precision(prefstate): _sb = prefstate.getWidget('DIM_SECONDARY_PRECISION') globals.prefs['DIM_SECONDARY_PRECISION'] = _sb.get_value_as_int() def _set_dim_primary_prefix(prefstate): _text = prefstate.getWidget('DIM_PRIMARY_PREFIX').get_text() globals.prefs['DIM_PRIMARY_PREFIX'] = unicode(_text) def _set_dim_primary_suffix(prefstate): _text = prefstate.getWidget('DIM_PRIMARY_SUFFIX').get_text() globals.prefs['DIM_PRIMARY_SUFFIX'] = unicode(_text) def _set_dim_secondary_prefix(prefstate): _text = prefstate.getWidget('DIM_SECONDARY_PREFIX').get_text() globals.prefs['DIM_SECONDARY_PREFIX' ] = unicode(_text) def _set_dim_secondary_suffix(prefstate): _text = prefstate.getWidget('DIM_SECONDARY_SUFFIX').get_text() globals.prefs['DIM_SECONDARY_SUFFIX'] = unicode(_text) def _set_radial_dim_primary_prefix(prefstate): _text = prefstate.getWidget('RADIAL_DIM_PRIMARY_PREFIX').get_text() globals.prefs['RADIAL_DIM_PRIMARY_PREFIX'] = unicode(_text) def _set_radial_dim_primary_suffix(prefstate): _text = prefstate.getWidget('RADIAL_DIM_PRIMARY_SUFFIX').get_text() globals.prefs['RADIAL_DIM_PRIMARY_SUFFIX'] = unicode(_text) def _set_radial_dim_secondary_prefix(prefstate): _text = prefstate.getWidget('RADIAL_DIM_SECONDARY_PREFIX').get_text() globals.prefs['RADIAL_DIM_SECONDARY_PREFIX'] = unicode(_text) def _set_radial_dim_secondary_suffix(prefstate): _text = prefstate.getWidget('RADIAL_DIM_SECONDARY_SUFFIX').get_text() globals.prefs['RADIAL_DIM_SECONDARY_SUFFIX'] = unicode(_text) def _set_radial_dim_dia_mode(prefstate): _cb = prefstate.getWidget('RADIAL_DIM_DIA_MODE') globals.prefs['RADIAL_DIM_DIA_MODE'] = _cb.get_active() def _set_angular_dim_primary_prefix(prefstate): _text = prefstate.getWidget('ANGULAR_DIM_PRIMARY_PREFIX').get_text() globals.prefs['ANGULAR_DIM_PRIMARY_PREFIX'] = unicode(_text) def _set_angular_dim_primary_suffix(prefstate): _text = prefstate.getWidget('ANGULAR_DIM_PRIMARY_SUFFIX').get_text() globals.prefs['ANGULAR_DIM_PRIMARY_SUFFIX'] = unicode(_text) def _set_angular_dim_secondary_prefix(prefstate): _text = prefstate.getWidget('ANGULAR_DIM_SECONDARY_PREFIX').get_text() globals.prefs['ANGULAR_DIM_SECONDARY_PREFIX'] = unicode(_text) def _set_angular_dim_secondary_suffix(prefstate): _text = prefstate.getWidget('ANGULAR_DIM_SECONDARY_SUFFIX').get_text() globals.prefs['ANGULAR_DIM_SECONDARY_SUFFIX'] = unicode(_text) def _set_drawing_units(prefstate): _widget = prefstate.getWidget('DRAWING_UNITS') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _unit = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _unit = _widget.get_history() else: raise TypeError, "Unexpected DRAWING_UNITS widget: " + `type(_widget)` globals.prefs['UNITS'] = _unit def _set_dim_primary_units(prefstate): _widget = prefstate.getWidget('DIM_PRIMARY_UNITS') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _unit = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _unit = _widget.get_history() else: raise TypeError, "Unexpected DIM_PRIMARY_UNITS widget: " + `type(_widget)` globals.prefs['DIM_PRIMARY_UNITS'] = _unit def _set_dim_secondary_units(prefstate): _widget = prefstate.getWidget('DIM_SECONDARY_UNITS') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _unit = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _unit = _widget.get_history() else: raise TypeError, "Unexpected DIM_SECONDARY_UNITS widget: " + `type(_widget)` globals.prefs['DIM_SECONDARY_UNITS'] = _unit def _set_dim_endpoint(prefstate): _widget = prefstate.getWidget('DIM_ENDPOINT') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected DIM_ENDPOINT widget: " + `type(_widget)` _endpoint = Dimension.getEndpointTypeFromString(_dim_endpoints[_idx]) globals.prefs['DIM_ENDPOINT'] = _endpoint def _set_dim_position(prefstate): _widget = prefstate.getWidget('DIM_POSITION') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected DIM_POSITION widget: " + `type(_widget)` _pos = Dimension.getPositionFromString(_dim_positions[_idx]) globals.prefs['DIM_POSITION'] = _pos def _set_font_family(prefstate): _widget = prefstate.getWidget('FONT_FAMILY') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected FONT_FAMILY widget: " + `type(_widget)` _families = prefstate.getFamilies() globals.prefs['FONT_FAMILY'] = _families[_idx] def _set_font_style(prefstate): _widget = prefstate.getWidget('FONT_STYLE') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected FONT_STYLE widget: " + `type(_widget)` _style = TextStyle.getStyleFromString(_font_styles[_idx]) globals.prefs['FONT_STYLE']= _style def _set_font_weight(prefstate): _widget = prefstate.getWidget('FONT_WEIGHT') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected FONT_WEIGHT widget: " + `type(_widget)` _weight = TextStyle.getWeightFromString(_font_weights[_idx]) globals.prefs['FONT_WEIGHT'] = _weight def _set_text_alignment(prefstate): _widget = prefstate.getWidget('TEXT_ALIGNMENT') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected TEXT_ALIGNMENT widget: " + `type(_widget)` _align = TextStyle.getAlignmentFromString(_text_align[_idx]) globals.prefs['TEXT_ALIGNMENT'] = _align def _set_dim_primary_font_family(prefstate): _widget = prefstate.getWidget('DIM_PRIMARY_FONT_FAMILY') _families = prefstate.getFamilies() if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected DIM_PRIMARY_FONT_FAMILY widget: " + `type(_widget)` globals.prefs['DIM_PRIMARY_FONT_FAMILY'] = _families[_idx] def _set_dim_primary_font_style(prefstate): _widget = prefstate.getWidget('DIM_PRIMARY_FONT_STYLE') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected DIM_PRIMARY_FONT_STYLE widget: " + `type(_widget)` _style = TextStyle.getStyleFromString(_font_styles[_idx]) globals.prefs['DIM_PRIMARY_FONT_STYLE'] = _style def _set_dim_primary_font_weight(prefstate): _widget = prefstate.getWidget('DIM_PRIMARY_FONT_WEIGHT') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected DIM_PRIMARY_FONT_WEIGHT widget: " + `type(_widget)` _weight = TextStyle.getWeightFromString(_font_weights[_idx]) globals.prefs['DIM_PRIMARY_FONT_WEIGHT'] = _weight def _set_dim_primary_text_alignment(prefstate): _widget = prefstate.getWidget('DIM_PRIMARY_TEXT_ALIGNMENT') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected DIM_PRIMARY_TEXT_ALIGNMENT widget: " + `type(_widget)` _align = TextStyle.getAlignmentFromString(_text_align[_idx]) globals.prefs['DIM_PRIMARY_TEXT_ALIGNMENT'] = _align def _set_dim_primary_font(prefstate): _fontsel = prefstate.getWidget('DIM_PRIMARY_FONT') _font = _fontsel.get_font_name() _family, _style, _weight, _stretch, _size = (None, None, None, None, None) globals.prefs['DIM_PRIMARY_FONT_FAMILY'] = _family globals.prefs['DIM_PRIMARY_TEXT_SIZE'] = float(_size) # fixme globals.prefs['DIM_PRIMARY_FONT_STYLE'] = _style globals.prefs['DIM_PRIMARY_FONT_WEIGHT'] = _weight def _set_dim_secondary_font_family(prefstate): _widget = prefstate.getWidget('DIM_SECONDARY_FONT_FAMILY') _families = prefstate.getFamilies() if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected DIM_SECONDARY_FONT_FAMILY widget: " + `type(_widget)` globals.prefs['DIM_SECONDARY_FONT_FAMILY'] = _families[_idx] def _set_dim_secondary_font_style(prefstate): _widget = prefstate.getWidget('DIM_SECONDARY_FONT_STYLE') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected DIM_SECONDARY_FONT_STYLE widget: " + `type(_widget)` _style = TextStyle.getStyleFromString(_font_styles[_idx]) globals.prefs['DIM_SECONDARY_FONT_STYLE'] = _style def _set_dim_secondary_font_weight(prefstate): _widget = prefstate.getWidget('DIM_SECONDARY_FONT_WEIGHT') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected DIM_SECONDARY_FONT_WEIGHT widget: " + `type(_widget)` _weight = TextStyle.getWeightFromString(_font_weights[_idx]) globals.prefs['DIM_SECONDARY_FONT_WEIGHT'] = _weight def _set_dim_secondary_text_alignment(prefstate): _widget = prefstate.getWidget('DIM_SECONDARY_TEXT_ALIGNMENT') if hasattr(gtk, 'ComboBox') and isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected DIM_SECONDARY_TEXT_ALIGNMENT widget: " + `type(_widget)` _align = TextStyle.getAlignmentFromString(_text_align[_idx]) globals.prefs['DIM_SECONDARY_TEXT_ALIGNMENT'] = _align def _set_dim_secondary_font(prefstate): _fontsel = prefstate.getWidget('DIM_SECONDARY_FONT') _font = _fontsel.get_font_name() _family, _style, _weight, _stretch, _size = (None, None, None, None, None) globals.prefs['DIM_SECONDARY_FONT_FAMILY'] = _family globals.prefs['DIM_SECONDARY_TEXT_SIZE'] = float(_size) # fixme globals.prefs['DIM_SECONDARY_FONT_STYLE'] = _style globals.prefs['DIM_SECONDARY_FONT_WEIGHT'] = _weight def _set_snap_option(prefstate): """ set Snap Option """ _keymap = { 'DIM_OFFSET' : _set_dim_offset, 'DIM_EXTENSION' : _set_dim_extension, 'DIM_COLOR' : _set_dim_color, 'BACKGROUND_COLOR' : _set_background_color, 'INACTIVE_LAYER_COLOR' : _set_inactive_layer_color, 'SINGLE_POINT_COLOR' : _set_single_point_color, 'MULTI_POINT_COLOR' : _set_multi_point_color, 'FONT_COLOR' : _set_font_color, 'DIM_PRIMARY_FONT_COLOR' : _set_dim_primary_font_color, 'DIM_SECONDARY_FONT_COLOR' : _set_dim_secondary_font_color, 'LINE_THICKNESS' : _set_line_thickness, 'LEADER_ARROW_SIZE' : _set_leader_arrow_size, 'CHAMFER_LENGTH' : _set_chamfer_length, 'FILLET_RADIUS' : _set_fillet_radius, 'HIGHLIGHT_POINTS' : _set_highlight_points, 'AUTOSPLIT' : _set_autosplit, 'DIM_PRIMARY_FONT_FAMILY' : _set_dim_primary_font_family, 'DIM_PRIMARY_FONT_STYLE' : _set_dim_primary_font_style, 'DIM_PRIMARY_FONT_WEIGHT' : _set_dim_primary_font_weight, 'DIM_PRIMARY_TEXT_SIZE' : _set_dim_primary_text_size, 'DIM_PRIMARY_TEXT_ALIGNMENT' : _set_dim_primary_text_alignment, 'DIM_PRIMARY_PRECISION' : _set_dim_primary_precision, 'DIM_PRIMARY_LEADING_ZERO' : _set_dim_primary_leading_zero, 'DIM_PRIMARY_TRAILING_DECIMAL' : _set_dim_primary_trailing_decimal, 'DIM_SECONDARY_FONT_FAMILY' : _set_dim_secondary_font_family, 'DIM_SECONDARY_FONT_STYLE' : _set_dim_secondary_font_style, 'DIM_SECONDARY_FONT_WEIGHT' : _set_dim_secondary_font_weight, 'DIM_SECONDARY_TEXT_SIZE' : _set_dim_secondary_text_size, 'DIM_SECONDARY_TEXT_ALIGNMENT' : _set_dim_secondary_text_alignment, 'DIM_SECONDARY_PRECISION' : _set_dim_secondary_precision, 'DIM_SECONDARY_LEADING_ZERO' : _set_dim_secondary_leading_zero, 'DIM_SECONDARY_TRAILING_DECIMAL' : _set_dim_secondary_trailing_decimal, 'DIM_PRIMARY_PREFIX' : _set_dim_primary_prefix, 'DIM_PRIMARY_SUFFIX' : _set_dim_primary_suffix, 'DIM_SECONDARY_PREFIX' : _set_dim_secondary_prefix, 'DIM_SECONDARY_SUFFIX' : _set_dim_secondary_suffix, 'RADIAL_DIM_PRIMARY_PREFIX' : _set_radial_dim_primary_prefix, 'RADIAL_DIM_PRIMARY_SUFFIX' : _set_radial_dim_primary_suffix, 'RADIAL_DIM_SECONDARY_PREFIX' : _set_radial_dim_secondary_prefix, 'RADIAL_DIM_SECONDARY_SUFFIX' : _set_radial_dim_secondary_suffix, 'RADIAL_DIM_DIA_MODE' : _set_radial_dim_dia_mode, 'ANGULAR_DIM_PRIMARY_PREFIX' : _set_angular_dim_primary_prefix, 'ANGULAR_DIM_PRIMARY_SUFFIX' : _set_angular_dim_primary_suffix, 'ANGULAR_DIM_SECONDARY_PREFIX' : _set_angular_dim_secondary_prefix, 'ANGULAR_DIM_SECONDARY_SUFFIX' : _set_angular_dim_secondary_suffix, 'DRAWING_UNITS' : _set_drawing_units, 'DIM_PRIMARY_UNITS' : _set_dim_primary_units, 'DIM_SECONDARY_UNITS' : _set_dim_secondary_units, 'FONT_FAMILY' : _set_font_family, 'FONT_STYLE' : _set_font_style, 'FONT_WEIGHT' : _set_font_weight, 'TEXT_SIZE' : _set_text_size, 'TEXT_ALIGNMENT' : _set_text_alignment, 'DIM_PRIMARY_FONT' : _set_dim_primary_font, 'DIM_SECONDARY_FONT' : _set_dim_secondary_font, 'DIM_ENDPOINT' : _set_dim_endpoint, 'DIM_ENDPOINT_SIZE' : _set_dim_endpoint_size, 'DIM_DUAL_MODE' : _set_dim_dual_mode, 'DIM_POSITION' : _set_dim_position, 'DIM_DUAL_MODE_OFFSET' : _set_dim_dual_mode_offset, 'DIM_POSITION_OFFSET' : _set_dim_position_offset, 'SNAP_OPTION' : _set_snap_option, } def apply_prefs(prefstate): """ apply preferences to from the dialog """ for _key in prefstate.getWidgetKeys(): # print "widget key: " + _key if _key in _keymap: _optfunc = _keymap[_key] _optfunc(prefstate) # else: # print "no function for " + _key def prefs_dialog(gtkimage): """ Create Preferences dialog """ _window = gtkimage.getWindow() _prefstate = Prefstate() _prefstate.setImage(gtkimage.image) _prefstate.setWindow(_window) _dialog = gtk.Dialog(_('Set Preferences'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 5) _prefstate.setHBox(_hbox) _hbox.set_border_width(5) _dialog.vbox.pack_start(_hbox, True, True) _tree_view = _make_pref_tree(_hbox, _prefstate) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: apply_prefs(_prefstate) preferences.save_user_prefs() _prefstate.clear() _dialog.destroy() PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkmirror.py0000644000175000017500000001153311307666732021777 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # functions for doing mirroring operations # import pygtk pygtk.require('2.0') import gtk from PythonCAD.Generic.hcline import HCLine from PythonCAD.Generic.acline import ACLine from PythonCAD.Generic.vcline import VCLine from PythonCAD.Generic.cline import CLine from PythonCAD.Generic import mirror def mirror_objects(gtkimage, tool, objs): _mline = tool.getMirrorLine() tool.reset() _prompt = _('Click on the mirroring construction line.') if len(objs): _image = gtkimage.getImage() _image.startAction() try: mirror.mirror_objects(_mline, objs) finally: _image.endAction() mirror_mode_init(gtkimage) else: gtkimage.refresh() _prompt = ('Click on an object to mirror') tool.setMirrorLine(_mline) tool.setHandler("button_press", first_button_press_cb) gtkimage.setPrompt(_prompt) def select_motion_notify(gtkimage, widget, event, tool): _tx, _ty = tool.getLocation() _px, _py = gtkimage.coordToPixTransform(_tx, _ty) _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _cp = tool.getCurrentPoint() if _cp is not None: _xc, _yc = _cp _xmin = min(_xc, _px) _ymin = min(_yc, _py) _rw = abs(_xc - _px) _rh = abs(_yc - _py) widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _rw, _rh) tool.setCurrentPoint(_x, _y) _xmin = min(_x, _px) _ymin = min(_y, _py) _rw = abs(_x - _px) _rh = abs(_y - _py) widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _rw, _rh) return True def second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _active_layer = _image.getActiveLayer() _pts = _active_layer.find('point', _x, _y) if len(_pts) > 0: _x, _y = _pts[0].getCoords() _x1, _y1 = tool.getLocation() _xmin = min(_x1, _x) _ymin = min(_y1, _y) _xmax = max(_x1, _x) _ymax = max(_y1, _y) _objs = _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax, True) mirror_objects(gtkimage, tool, _objs) return True def first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _objdict = _image.mapPoint(_x, _y, _tol) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: _objs = [] for _obj, _pt in _objdict[_active_layer]: _objs.append(_obj) mirror_objects(gtkimage, tool, _objs) else: _x, _y = _image.getClosestPoint(_x, _y, tolerance=_tol) tool.setLocation(_x, _y) tool.setHandler("motion_notify", select_motion_notify) tool.setHandler("button_press", second_button_press_cb) gtkimage.setPrompt(_('Enclose objects to mirror with the box')) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True def get_mirror_line_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _objdict = _image.mapPoint(_x, _y, _tol) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, (HCLine, VCLine, ACLine, CLine)): tool.setMirrorLine(_obj) if _image.hasSelection(): mirror_objects(gtkimage, tool, _image.getSelectedObjects()) else: tool.setHandler("button_press", first_button_press_cb) gtkimage.setPrompt(_('Click on an object to mirror')) break return True def mirror_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the mirroring construction line')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", get_mirror_line_cb) PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkdimension.py0000644000175000017500000004313411307666732022454 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2006, 2007 Art Haas # # 2009 Matteo Boscolo # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # gtk dimension code # import pygtk pygtk.require('2.0') import gtk import pango from PythonCAD.Generic.dimension import Dimension from PythonCAD.Interface.Gtk import gtktext from PythonCAD.Generic import snap # # linear dimension motion-notify handler # def dim_pts_motion_notify_cb(gtkimage, widget, event, tool): _tx, _ty = tool.getLocation() _px, _py = gtkimage.coordToPixTransform(_tx, _ty) _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _cp = tool.getCurrentPoint() _segs = [] if _cp is not None: _xc, _yc = _cp _segs.append((_px, _py, _xc, _yc)) tool.setCurrentPoint(_x, _y) _segs.append((_px, _py, _x, _y)) widget.window.draw_segments(_gc, _segs) return True def dim_txt_motion_notify_cb(gtkimage, widget, event, tool): _ix, _iy = gtkimage.image.getCurrentPoint() _gc = gtkimage.getGC() _ex = int(event.x) _ey = int(event.y) _cp = tool.getCurrentPoint() _dim = tool.getDimension() _bar1, _bar2 = _dim.getDimBars() _crossbar = _dim.getDimCrossbar() _segs = [] if _cp is not None: _ep1, _ep2 = _bar1.getEndpoints() _px1, _py1 = gtkimage.coordToPixTransform(_ep1[0], _ep1[1]) _px2, _py2 = gtkimage.coordToPixTransform(_ep2[0], _ep2[1]) _segs.append((_px1, _py1, _px2, _py2)) _ep1, _ep2 = _bar2.getEndpoints() _px1, _py1 = gtkimage.coordToPixTransform(_ep1[0], _ep1[1]) _px2, _py2 = gtkimage.coordToPixTransform(_ep2[0], _ep2[1]) _segs.append((_px1, _py1, _px2, _py2)) _ep1, _ep2 = _crossbar.getEndpoints() _px1, _py1 = gtkimage.coordToPixTransform(_ep1[0], _ep1[1]) _px2, _py2 = gtkimage.coordToPixTransform(_ep2[0], _ep2[1]) _segs.append((_px1, _py1, _px2, _py2)) tool.setCurrentPoint(_ex, _ey) _dim.setLocation(_ix, _iy) _dim.calcDimValues(False) _ep1, _ep2 = _bar1.getEndpoints() _px1, _py1 = gtkimage.coordToPixTransform(_ep1[0], _ep1[1]) _px2, _py2 = gtkimage.coordToPixTransform(_ep2[0], _ep2[1]) _segs.append((_px1, _py1, _px2, _py2)) _ep1, _ep2 = _bar2.getEndpoints() _px1, _py1 = gtkimage.coordToPixTransform(_ep1[0], _ep1[1]) _px2, _py2 = gtkimage.coordToPixTransform(_ep2[0], _ep2[1]) _segs.append((_px1, _py1, _px2, _py2)) _ep1, _ep2 = _crossbar.getEndpoints() _px1, _py1 = gtkimage.coordToPixTransform(_ep1[0], _ep1[1]) _px2, _py2 = gtkimage.coordToPixTransform(_ep2[0], _ep2[1]) _segs.append((_px1, _py1, _px2, _py2)) widget.window.draw_segments(_gc, _segs) return True def add_dimension(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _init_func = _tool.getHandler("initialize") _image = gtkimage.getImage() _image.startAction() try: _tool.create(_image) finally: _image.endAction() _init_func(gtkimage) def linear_text_button_press_cb(gtkimage, widget, event, tool): _x, _y = gtkimage.image.getCurrentPoint() _ldim = tool.getDimension() _ldim.setLocation(_x, _y) _ldim.calcDimValues() _ldim.reset() add_dimension(gtkimage) return True def linear_second_button_press_cb(gtkimage, widget, event, tool): _snapArray={'perpendicular':False,'tangent':False} _strPnt=snap.getSnapOnTruePoint(gtkimage,_snapArray) if _strPnt.point is not None: _x, _y = _strPnt.point.getCoords() tool.setSecondPoint(_strPnt.point) tool.setDimPosition(_x, _y) tool.clearCurrentPoint() tool.makeDimension(gtkimage.getImage()) # # set GraphicsContext to Dimension color # _gc = gtkimage.getGC() _gc.set_function(gtk.gdk.INVERT) _col = tool.getDimension().getColor() _gc.set_foreground(gtkimage.getColor(_col)) tool.setHandler("button_press", linear_text_button_press_cb) tool.setHandler("motion_notify", dim_txt_motion_notify_cb) gtkimage.setPrompt(_('Click where the dimension text should go.')) gtkimage.refresh() return True def linear_first_button_press_cb(gtkimage, widget, event, tool): _snapArray={'perpendicular':False,'tangent':False} _strPnt=snap.getSnapOnTruePoint(gtkimage,_snapArray) if _strPnt is not None: _x, _y =_strPnt.point.getCoords() tool.setLocation(_x, _y) tool.setFirstPoint(_strPnt.point) tool.setHandler("button_press", linear_second_button_press_cb) tool.setHandler("motion_notify", dim_pts_motion_notify_cb) gtkimage.setPrompt(_('Click on the second point for the dimension.')) gtkimage.getGC().set_function(gtk.gdk.INVERT) else: gtkimage.setPrompt(_('Click on the first point for the dimension.')) tool.setHandler("button_press", linear_first_button_press_cb) tool.setHandler("initialize", linear_mode_init) return True # # linear dimensions # def linear_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the first point for the dimension.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", linear_first_button_press_cb) _tool.setHandler("initialize", linear_mode_init) # # horizontal dimensions # def horizontal_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the first point for the dimension.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", linear_first_button_press_cb) _tool.setHandler("initialize", horizontal_mode_init) # # vertical dimensions # def vertical_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the first point for the dimension.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", linear_first_button_press_cb) _tool.setHandler("initialize", vertical_mode_init) # # radial dimensions # def radial_txt_motion_notify_cb(gtkimage, widget, event, tool): _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _rdim = tool.getDimension() _crossbar = _rdim.getDimCrossbar() _cp = tool.getCurrentPoint() _segs = [] if _cp is not None: _p1, _p2 = _crossbar.getEndpoints() _p0x, _p0y = gtkimage.coordToPixTransform(_p1[0], _p1[1]) _p1x, _p1y = gtkimage.coordToPixTransform(_p2[0], _p2[1]) _segs.append((_p0x, _p0y, _p1x, _p1y)) tool.setCurrentPoint(_x, _y) _ix, _iy = gtkimage.image.getCurrentPoint() _rdim.setLocation(_ix, _iy) _rdim.calcDimValues(False) _p1, _p2 = _crossbar.getEndpoints() _p0x, _p0y = gtkimage.coordToPixTransform(_p1[0], _p1[1]) _p1x, _p1y = gtkimage.coordToPixTransform(_p2[0], _p2[1]) _segs.append((_p0x, _p0y, _p1x, _p1y)) widget.window.draw_segments(_gc, _segs) return True def radial_text_button_press_cb(gtkimage, widget, event, tool): _x, _y = gtkimage.image.getCurrentPoint() _rdim = tool.getDimension() _rdim.setLocation(_x, _y) _rdim.calcDimValues() _rdim.reset() add_dimension(gtkimage) return True def radial_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _dc = None _layers = [_image.getTopLayer()] while(len(_layers)): _layer = _layers.pop() if _layer.isVisible(): _cobjs = (_layer.getLayerEntities("circle") + _layer.getLayerEntities("arc")) for _cobj in _cobjs: _mp = _cobj.mapCoords(_x, _y, _tol) if _mp is not None: _dc = _cobj break _layers.extend(_layer.getSublayers()) if _dc is not None: _x, _y = _mp tool.setDimObject(_dc) tool.setDimPosition(_x, _y) tool.makeDimension(_image) tool.setHandler("motion_notify", radial_txt_motion_notify_cb) tool.setHandler("button_press", radial_text_button_press_cb) gtkimage.setPrompt(_('Click where the dimension text should be placed.')) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True def radial_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on an arc or a circle to dimension.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", radial_mode_init) _tool.setHandler("button_press", radial_button_press_cb) # # angular dimensions # def adim_txt_motion_notify_cb(gtkimage, widget, event, tool): _ix, _iy = gtkimage.image.getCurrentPoint() _gc = gtkimage.getGC() _ex = int(event.x) _ey = int(event.y) _cp = tool.getCurrentPoint() _adim = tool.getDimension() _vx, _vy = _adim.getVertexPoint().getCoords() _px, _py = gtkimage.coordToPixTransform(_vx, _vy) _win = widget.window _bar1, _bar2 = _adim.getDimBars() _crossarc = _adim.getDimCrossarc() _segs = [] if _cp is not None: # # draw bars # _ep1, _ep2 = _bar1.getEndpoints() _p1x, _p1y = gtkimage.coordToPixTransform(_ep1[0], _ep1[1]) _p2x, _p2y = gtkimage.coordToPixTransform(_ep2[0], _ep2[1]) _segs.append((_p1x, _p1y, _p2x, _p2y)) _ep1, _ep2 = _bar2.getEndpoints() _p1x, _p1y = gtkimage.coordToPixTransform(_ep1[0], _ep1[1]) _p2x, _p2y = gtkimage.coordToPixTransform(_ep2[0], _ep2[1]) _segs.append((_p1x, _p1y, _p2x, _p2y)) _win.draw_segments(_gc, _segs) del _segs[:] # # draw arc # _sa = _crossarc.getStartAngle() _ea = _crossarc.getEndAngle() _rad = int(_crossarc.getRadius()/gtkimage.getUnitsPerPixel()) _pxmin = _px - _rad _pymin = _py - _rad _cw = _ch = _rad * 2 if _sa < _ea: _sweep = _ea - _sa else: _sweep = 360.0 - (_sa - _ea) _win.draw_arc(_gc, False, _pxmin, _pymin, _cw, _ch, int(_sa * 64), int(_sweep * 64)) tool.setCurrentPoint(_ex, _ey) _adim.setLocation(_ix, _iy) _adim.calcDimValues(False) # # draw bars # _ep1, _ep2 = _bar1.getEndpoints() _p1x, _p1y = gtkimage.coordToPixTransform(_ep1[0], _ep1[1]) _p2x, _p2y = gtkimage.coordToPixTransform(_ep2[0], _ep2[1]) _segs.append((_p1x, _p1y, _p2x, _p2y)) _ep1, _ep2 = _bar2.getEndpoints() _p1x, _p1y = gtkimage.coordToPixTransform(_ep1[0], _ep1[1]) _p2x, _p2y = gtkimage.coordToPixTransform(_ep2[0], _ep2[1]) _segs.append((_p1x, _p1y, _p2x, _p2y)) _win.draw_segments(_gc, _segs) # # draw arc # _sa = _crossarc.getStartAngle() _ea = _crossarc.getEndAngle() _rad = int(_crossarc.getRadius()/gtkimage.getUnitsPerPixel()) _pxmin = _px - _rad _pymin = _py - _rad _cw = _ch = _rad * 2 if _sa < _ea: _sweep = _ea - _sa else: _sweep = 360.0 - (_sa - _ea) _win.draw_arc(_gc, False, _pxmin, _pymin, _cw, _ch, int(_sa * 64), int(_sweep * 64)) return True def angular_pts_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _active_layer = _image.getActiveLayer() _pt = None _pts = _active_layer.find('point',_x, _y, _tol) if len(_pts) > 0: _pt = _pts[0] if _pt is None: _layers = [_image.getTopLayer()] while(len(_layers)): _layer = _layers.pop() if _layer is not _active_layer and _layer.isVisible(): _pts = _layer.find('point', _x, _y, _tol) if len(_pts) > 0: _pt = _pts[0] break _layers.extend(_layer.getSublayers()) if _pt is not None: _x, _y = _pt.getCoords() tool.storeCoords(_x, _y) if len(tool) == 2: tool.pushObject(_pt) else: from PythonCAD.Generic.dimension import AngularDimension _p1 = tool.popObject() _vp = tool.popObject() _ds = _image.getOption("DIM_STYLE") _adim = AngularDimension(_vp, _p1, _pt, _x, _y, _ds) tool.pushObject(_adim) return True def angular_text_button_press_cb(gtkimage, widget, event, tool): _x, _y = gtkimage.image.getCurrentPoint() _adim = tool.getDimension() _adim.setLocation(_x, _y) _adim.calcDimValues() _adim.reset() add_dimension(gtkimage) return True def angular_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _layers = [_image.getTopLayer()] while len(_layers): _layer = _layers.pop() if _layer.isVisible(): _pt = None _pts = _layer.find('point', _x, _y, _tol) if len(_pts) > 0: _pt = _pts[0] if _pt is not None: _x, _y = _pt.getCoords() tool.setLocation(_x, _y) tool.setSecondPoint(_pt) tool.setDimPosition(_x, _y) tool.makeDimension(_image) # # set GraphicsContext to Dimension color # _gc = gtkimage.getGC() _gc.set_function(gtk.gdk.INVERT) _col = tool.getDimension().getColor() _gc.set_foreground(gtkimage.getColor(_col)) tool.setHandler("button_press", angular_text_button_press_cb) tool.setHandler("motion_notify", adim_txt_motion_notify_cb) gtkimage.setPrompt(_('Click where the dimension text should be located.')) gtkimage.refresh() break _layers.extend(_layer.getSublayers()) return True def angular_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _layers = [_image.getTopLayer()] while len(_layers): _layer = _layers.pop() if _layer.isVisible(): _pt = None _pts = _layer.find('point', _x, _y, _tol) if len(_pts) > 0: _pt = _pts[0] if _pt is not None: _x, _y = _pt.getCoords() tool.setLocation(_x, _y) tool.setFirstPoint(_pt) tool.setHandler("button_press", angular_second_button_press_cb) gtkimage.setPrompt(_('Click on the second point for the dimension.')) break _layers.extend(_layer.getSublayers()) return True def _test_layer(l, x, y, tol): _pt = _arc = None _pts = l.find('point', x, y) if len(_pts) > 0: _pt = _pts[0] if _pt is None: _pts = l.find('point', x, y, tol) if len(_pts) > 0: _pt = _pts[0] if _pt is None: _arc_pt = None for _arc in l.getLayerEntities("arc"): _arc_pt = _arc.mapCoords(x, y, tol) if _arc_pt is not None: break if _arc_pt is None: _arc = None # no hits on any arcs ... return _pt, _arc def angular_initial_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _active_layer = _image.getActiveLayer() _pt, _arc = _test_layer(_active_layer, _x, _y, _tol) if _pt is None and _arc is None: _layers = [_image.getTopLayer()] while len(_layers): _layer = _layers.pop() if _layer is not _active_layer and _layer.isVisible(): _pt, _arc = _test_layer(_layer, _x, _y, _tol) if _pt is not None or _arc is not None: break _layers.extend(_layer.getSublayers()) if _pt is not None: tool.setVertexPoint(_pt) tool.setHandler("button_press", angular_first_button_press_cb) gtkimage.setPrompt(_('Click on the first endpoint for the dimension.')) elif _arc is not None: _cp = _arc.getCenter() tool.setVertexPoint(_cp) _ep1, _ep2 = _arc.getEndpoints() _ex, _ey = _ep1 _pts = _active_layer.find('point', _ex, _ey) assert len(_pts) > 0, "Missing arc first endpoint" tool.setFirstPoint(_pts[0]) _ex, _ey = _ep2 _pts = _active_layer.find('point', _ex, _ey) assert len(_pts) > 0, "Missing arc second endpoint" tool.setSecondPoint(_pts[0]) tool.setDimPosition(_x, _y) tool.makeDimension(_image) tool.setHandler("button_press", angular_text_button_press_cb) tool.setHandler("motion_notify", adim_txt_motion_notify_cb) gtkimage.getGC().set_function(gtk.gdk.INVERT) gtkimage.setPrompt(_('Click where the dimension text should be located.')) return True def angular_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the angle vertex point or an arc.')) _tool = gtkimage.getImage().getTool() _tool.initialize() _tool.setHandler("button_press", angular_initial_button_press_cb) _tool.setHandler("initialize", angular_mode_init) PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkDialog.py0000644000175000017500000001020711307674214021653 0ustar matteomatteo# # Copyright (c) 2009 Matteo Boscolo # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # code for dialogs # import pygtk pygtk.require('2.0') import gtk import gobject import sys import os ioDebug=True def _error_dialog(gtkimage, errmsg): """ Show an error dialog """ _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('PythonCad Error'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _label = gtk.Label(errmsg) _dialog.vbox.pack_start(_label, True, True, 0) _label.show() _dialog.show_all() _response = _dialog.run() _dialog.destroy() if ioDebug : for s in sys.exc_info(): print "Exception Error: %s"%str(s) def _message_dialog(gtkimage,label1,label2): """ Create a dialogo with two label to give more information at the user """ _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('PythonCad Message'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _label1 = gtk.Label(label1) _label2 = gtk.Label(label2) _dialog.vbox.pack_start(_label1, True, True, 0) _dialog.vbox.pack_start(_label2, True, True, 0) _label1.show() _label2.show() _dialog.show_all() _response = _dialog.run() _dialog.destroy() def _yesno_dialog(gtkimage,label): """ Create a dialogo with a label and a yes no button """ _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('PythonCad Message'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) _label = gtk.Label(label) _dialog.vbox.pack_start(_label, True, True, 0) _label.show() _dialog.show_all() _response = _dialog.run() _dialog.destroy() return _response def delete_event(widget, event, data=None): gtk.main_quit() return False def _help_dialog(gtkimage,Command): """ Show the help dialog for the specifie comand Need to be implemented 1) open a child windows that show html text 2) load the command file """ pass def abautDialog(): """ Show The application debug dialog """ _abautDialog=gtk.AboutDialog() _abautDialog.set_name("PythonCad") _abautDialog.set_program_name("PythonCad") _abautDialog.set_version("DS1-R37") _abautDialog.set_comments("CAD built from Python") _iconPath=os.path.join(os.getcwd(),"gtkpycad.png") _pixBuf=gtk.gdk.pixbuf_new_from_file(_iconPath) _abautDialog.set_logo(_pixBuf) _abautDialog.set_website("http://sourceforge.net/projects/pythoncad") _licMsg='PythonCAD is distributed in the hope that it will be useful, \n \ but WITHOUT ANY WARRANTY; without even the implied warranty of \n \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \n \ GNU General Public License for more details. \n \ You should have received a copy of the GNU General Public License \n \ along with PythonCAD; if not, write to the Free Software \n \ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA' _abautDialog.set_license(_licMsg) response = _abautDialog.run() _abautDialog.destroy() PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/__init__.py0000644000175000017500000000210511307666657021517 0ustar matteomatteo# # Copyright (c) 2002, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # define __all__ so that "from Interface/Gtk import *" works # __all__ = [ 'gtkactions', 'gtkconobjs', 'gtkdimension', 'gtkedit', 'gtkentities', 'gtkimage', 'gtkinit', 'gtkmenus', 'gtkmirror', 'gtkmodify', 'gtkprefs', 'gtkprinting', 'gtkshell', 'gtktext' ] PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkinit.py0000644000175000017500000015355711307666732021445 0ustar matteomatteo# # Copyright (c) 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # code for adding graphical methods to drawing entities # import types from math import pi _dtr = (pi/180.0) import pygtk pygtk.require('2.0') import gtk import pango from PythonCAD.Generic import color from PythonCAD.Generic import point from PythonCAD.Generic import segment from PythonCAD.Generic import circle from PythonCAD.Generic import arc from PythonCAD.Generic import leader from PythonCAD.Generic import polyline from PythonCAD.Generic import segjoint from PythonCAD.Generic import conobject from PythonCAD.Generic import hcline from PythonCAD.Generic import vcline from PythonCAD.Generic import acline from PythonCAD.Generic import cline from PythonCAD.Generic import ccircle from PythonCAD.Generic import text from PythonCAD.Generic import dimension from PythonCAD.Generic import layer from PythonCAD.Interface.Gtk import gtkimage def _set_gc_values(gc, dl, c, t): if dl is None: _lt = gtk.gdk.LINE_SOLID else: _lt = gtk.gdk.LINE_DOUBLE_DASH gc.set_dashes(0, dl) gc.set_foreground(c) _t = t if not isinstance(_t, int): _t = int(round(t)) if _t < 1: # no zero-pixel lines _t = 1 gc.set_function(gtk.gdk.COPY) gc.set_line_attributes(_t, _lt, gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_MITER) _point_color = color.Color(255, 255, 255) # white def _draw_point(self, gimage, col=None): _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _x, _y = self.getCoords() _px, _py = gimage.coordToPixTransform(_x, _y) _w, _h = gimage.getSize() if (((_px + 5) < 0) or ((_py + 5) < 0) or ((_px - 5) > _w) or ((_py - 5) > _h)): return if _col is None: _col = _point_color _pixmap = _gc = None _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) _ctx.move_to(_px, _py) _ctx.line_to(_px, _py) _ctx.stroke() _ctx.restore() else: _gc = gimage.getGC() _gc.set_foreground(gimage.getColor(_col)) _pixmap = gimage.getPixmap() _pixmap.draw_point(_gc, _px, _py) _image = gimage.getImage() if _image.getOption('HIGHLIGHT_POINTS'): _count = 0 for _user in self.getUsers(): if not isinstance(_user, dimension.Dimension): _count = _count + 1 if _count > 1: break if _count > 1: _col = _image.getOption('MULTI_POINT_COLOR') else: _col = _image.getOption('SINGLE_POINT_COLOR') if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) _ctx.rectangle((_px - 5), (_py - 5), 10, 10) _ctx.stroke() _ctx.restore() else: _set_gc_values(_gc, None, gimage.getColor(_col), 1) _pixmap.draw_rectangle(_gc, False, (_px - 5), (_py - 5), 10, 10) def _erase_point(self, gimage): _x, _y = self.getCoords() _px, _py = gimage.coordToPixTransform(_x, _y) _w, _h = gimage.getSize() if (((_px + 5) < 0) or ((_py + 5) < 0) or ((_px - 5) > _w) or ((_py - 5) > _h)): return _image = gimage.getImage() _col = _image.getOption('BACKGROUND_COLOR') _pixmap = _gc = None _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() if(_col!=None): _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) _ctx.move_to(_px, _py) _ctx.line_to(_px, _py) _ctx.stroke() _ctx.restore() else: _gc = gimage.getGC() _gc.set_foreground(gimage.getColor(_col)) _pixmap = gimage.getPixmap() _pixmap.draw_point(_gc, _px, _py) if _image.getOption('HIGHLIGHT_POINTS'): if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) _ctx.rectangle((_px - 5), (_py - 5), 10, 10) _ctx.stroke() _ctx.restore() else: _gc.set_function(gtk.gdk.COPY) _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_MITER) _pixmap.draw_rectangle(_gc, False, (_px - 5), (_py - 5), 10, 10) def _draw_segment(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _xmin, _ymin, _xmax, _ymax = gimage.getView() _coords = self.clipToRegion(_xmin, _ymin, _xmax, _ymax) if _coords is not None: _p1, _p2 = self.getEndpoints() _x1, _y1, _x2, _y2 = _coords _p1x, _p1y = gimage.coordToPixTransform(_x1, _y1) _p2x, _p2y = gimage.coordToPixTransform(_x2, _y2) if _col is None: _col = self.getColor() _dlist = self.getLinetype().getList() _lw = self.getThickness()/gimage.getUnitsPerPixel() _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _dlist is not None: _ctx.set_dash(_dlist) _ctx.set_line_width(_lw) _ctx.move_to(_p1x, _p1y) _ctx.line_to(_p2x, _p2y) _ctx.stroke() _ctx.restore() else: _gc = gimage.getGC() _set_gc_values(_gc, _dlist, gimage.getColor(_col), _lw) gimage.getPixmap().draw_line(_gc, _p1x, _p1y, _p2x, _p2y) def _erase_segment(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _draw_circle(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _cp = self.getCenter() _x, _y = _cp.getCoords() _r = self.getRadius() _px, _py = gimage.coordToPixTransform(_x, _y) _rx, _ry = gimage.coordToPixTransform((_x + _r), _y) _rad = _rx - _px if _col is None: _col = self.getColor() _dlist = self.getLinetype().getList() _lw = self.getThickness()/gimage.getUnitsPerPixel() _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _dlist is not None: _ctx.set_dash(_dlist) _ctx.set_line_width(_lw) _ctx.arc(_px, _py, _rad, 0, (2.0 * pi)) _ctx.stroke() _ctx.restore() else: _gc = gimage.getGC() _set_gc_values(_gc, _dlist, gimage.getColor(_col), _lw) _pxmin = _px - _rad _pymin = _py - _rad _cw = _ch = _rad * 2 gimage.getPixmap().draw_arc(_gc, False, _pxmin, _pymin, _cw, _ch, 0, (360*64)) def _erase_circle(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _draw_arc(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _layer = self.getParent() if _layer is None: raise RuntimeError, "No parent Layer for Arc" _cp = self.getCenter() _x, _y = _cp.getCoords() _r = self.getRadius() _sa = self.getStartAngle() _ea = self.getEndAngle() _px, _py = gimage.coordToPixTransform(_x, _y) _rx, _ry = gimage.coordToPixTransform((_x + _r), _y) _rad = _rx - _px if _col is None: _col = self.getColor() _dlist = self.getLinetype().getList() _lw = self.getThickness()/gimage.getUnitsPerPixel() _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _dlist is not None: _ctx.set_dash(_dlist) _ctx.set_line_width(_lw) _rsa = _sa * _dtr _rea = _ea * _dtr # # arc drawing relies on Cairo transformations # _ctx.scale(1.0, -1.0) _ctx.translate(_px, -(_py)) if abs(_sa - _ea) < 1e-10: _ctx.arc(0, 0, _rad, _rsa, (_rsa + (2.0 * pi))) else: _ctx.arc(0, 0, _rad, _rsa, _rea) _ctx.stroke() _ctx.restore() else: _gc = gimage.getGC() for _ep in self.getEndpoints(): _ex, _ey = _ep _pts = _layer.find('point', _ex, _ey) if len(_pts) == 0: raise RuntimeError, "No Arc endpoint at: " + str(_ep) _ept = None for _pt in _pts: for _user in _pt.getUsers(): if _user is self: _ept = _pt break if _ept is not None: break if abs(_sa - _ea) < 1e-10: break _pxmin = _px - _rad _pymin = _py - _rad _cw = _ch = _rad * 2 _set_gc_values(_gc, _dlist, gimage.getColor(_col), _lw) if abs(_sa - _ea) < 1e-10: _sweep = 360.0 elif _sa > _ea: _sweep = 360.0 - (_sa - _ea) else: _sweep = _ea - _sa gimage.getPixmap().draw_arc(_gc, False, _pxmin, _pymin, _cw, _ch, int(round(_sa * 64)), int(round(_sweep * 64))) def _erase_arc(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _draw_leader(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _p1, _p2, _p3 = self.getPoints() _p1x, _p1y = gimage.coordToPixTransform(_p1.x, _p1.y) _p2x, _p2y = gimage.coordToPixTransform(_p2.x, _p2.y) _p3x, _p3y = gimage.coordToPixTransform(_p3.x, _p3.y) _pts = self.getArrowPoints() _a1x, _a1y = gimage.coordToPixTransform(_pts[0], _pts[1]) _a2x, _a2y = gimage.coordToPixTransform(_pts[2], _pts[3]) if _col is None: _col = self.getColor() _dlist = self.getLinetype().getList() _lw = self.getThickness()/gimage.getUnitsPerPixel() _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _dlist is not None: _ctx.set_dash(_dlist) _ctx.set_line_width(_lw) _ctx.move_to(_p1x, _p1y) _ctx.line_to(_p2x, _p2y) _ctx.line_to(_p3x, _p3y) _ctx.stroke() _ctx.move_to(_p3x, _p3y) _ctx.line_to(_a1x, _a1y) _ctx.line_to(_a2x, _a2y) _ctx.close_path() _ctx.fill() _ctx.restore() else: _gc = gimage.getGC() _set_gc_values(_gc, _dlist, gimage.getColor(_col), _lw) _pixmap = gimage.getPixmap() _pts = [(_p1x, _p1y), (_p2x, _p2y), (_p3x, _p3y)] _pixmap.draw_lines(_gc, _pts) _apts = [(_p3x, _p3y), (_a1x, _a1y), (_a2x, _a2y)] _pixmap.draw_polygon(_gc, True, _apts) def _erase_leader(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _draw_polyline(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _pts = [] for _pt in self.getPoints(): _x, _y = _pt.getCoords() _px, _py = gimage.coordToPixTransform(_x, _y) _pts.append((_px, _py)) if _col is None: _col = self.getColor() _dlist = self.getLinetype().getList() _lw = self.getThickness()/gimage.getUnitsPerPixel() _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _dlist is not None: _ctx.set_dash(_dlist) _ctx.set_line_width(_lw) _px, _py = _pts[0] _ctx.move_to(_px, _py) for _px, _py in _pts[1:]: _ctx.line_to(_px, _py) _ctx.stroke() _ctx.restore() else: _gc = gimage.getGC() _set_gc_values(_gc, _dlist, gimage.getColor(_col), _lw) gimage.getPixmap().draw_lines(_gc, _pts) def _erase_polyline(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _draw_chamfer(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _p1, _p2 = self.getMovingPoints() _p1x, _p1y = gimage.coordToPixTransform(_p1.x, _p1.y) _p2x, _p2y = gimage.coordToPixTransform(_p2.x, _p2.y) if _col is None: _col = self.getColor() _dlist = self.getLinetype().getList() _lw = self.getThickness()/gimage.getUnitsPerPixel() _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _dlist is not None: _ctx.set_dash(_dlist) _ctx.set_line_width(_lw) _ctx.move_to(_p1x, _p1y) _ctx.line_to(_p2x, _p2y) _ctx.stroke() _ctx.restore() else: _gc = gimage.getGC() _set_gc_values(_gc, _dlist, gimage.getColor(_col), _lw) gimage.getPixmap().draw_line(_gc, _p1x, _p1y, _p2x, _p2y) def _erase_chamfer(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _draw_fillet(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` if _col is None: _col = self.getColor() _cx, _cy = self.getCenter() _pcx, _pcy = gimage.coordToPixTransform(_cx, _cy) _p1, _p2 = self.getMovingPoints() _p1x, _p1y = gimage.coordToPixTransform(_p1.x, _p1.y) _p2x, _p2y = gimage.coordToPixTransform(_p2.x, _p2.y) _r = self.getRadius() _rx, _ry = gimage.coordToPixTransform((_cx + _r), _cy) _pr = _rx - _pcx _sa1, _sa2 = self.getAngles() _amin = min(_sa1, _sa2) _amax = max(_sa1, _sa2) if _amax - _amin > 180.0: _a1 = _amax _a2 = _amin else: _a1 = _amin _a2 = _amax # print "a1: %g" % _a1 # print "a2: %g" % _a2 _dlist = self.getLinetype().getList() _lw = self.getThickness()/gimage.getUnitsPerPixel() _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _dlist is not None: _ctx.set_dash(_dlist) _ctx.set_line_width(_lw) _ra1 = _a1 * _dtr _ra2 = _a2 * _dtr # # arc drawing relies on Cairo transformations # _ctx.scale(1.0, -1.0) _ctx.translate(_pcx, -(_pcy)) _ctx.arc(0, 0, _pr, _ra1, _ra2) _ctx.stroke() _ctx.restore() else: _gc = gimage.getGC() _set_gc_values(_gc, _dlist, gimage.getColor(_col), _lw) _pxmin = _pcx - _pr _pymin = _pcy - _pr _cw = _ch = _pr * 2 if _a1 > _a2: _sweep = 360.0 - (_a1 - _a2) else: _sweep = _a2 - _a1 gimage.getPixmap().draw_arc(_gc, False, _pxmin, _pymin, _cw, _ch, int(round(_a1 * 64)), int(round(_sweep * 64))) def _erase_fillet(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _draw_hcline(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _lp = self.getLocation() _x, _y = _lp.getCoords() _px, _py = gimage.coordToPixTransform(_x, _y) if _col is None: _col = self.getColor() _dlist = self.getLinetype().getList() _w, _h = gimage.getSize() _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _dlist is not None: _ctx.set_dash(_dlist) _ctx.set_line_width(1.0) _ctx.move_to(0, _py) _ctx.line_to(_w, _py) _ctx.stroke() _ctx.restore() else: _gc = gimage.getGC() _set_gc_values(_gc, _dlist, gimage.getColor(_col), 1) gimage.getPixmap().draw_line(_gc, 0, _py, _w, _py) def _erase_hcline(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _draw_vcline(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _lp = self.getLocation() _x, _y = _lp.getCoords() _px, _py = gimage.coordToPixTransform(_x, _y) if _col is None: _col = self.getColor() _dlist = self.getLinetype().getList() _w, _h = gimage.getSize() _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _dlist is not None: _ctx.set_dash(_dlist) _ctx.set_line_width(1.0) _ctx.move_to(_px, 0) _ctx.line_to(_px, _h) _ctx.stroke() _ctx.restore() else: _gc = gimage.getGC() _set_gc_values(_gc, _dlist, gimage.getColor(_col), 1) gimage.getPixmap().draw_line(_gc, _px, 0, _px, _h) def _erase_vcline(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _draw_acline(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _xmin, _ymin, _xmax, _ymax = gimage.getView() _coords = self.clipToRegion(_xmin, _ymin, _xmax, _ymax) if _coords is not None: _lp = self.getLocation() _x1, _y1, _x2, _y2 = _coords _p1x, _p1y = gimage.coordToPixTransform(_x1, _y1) _p2x, _p2y = gimage.coordToPixTransform(_x2, _y2) _p1x, _p1y = gimage.coordToPixTransform(_x1, _y1) _p2x, _p2y = gimage.coordToPixTransform(_x2, _y2) if _col is None: _col = self.getColor() _dlist = self.getLinetype().getList() _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _dlist is not None: _ctx.set_dash(_dlist) _ctx.set_line_width(1.0) _ctx.move_to(_p1x, _p1y) _ctx.line_to(_p2x, _p2y) _ctx.stroke() _ctx.restore() else: _gc = gimage.getGC() _set_gc_values(_gc, _dlist, gimage.getColor(_col), 1) gimage.getPixmap().draw_line(_gc, _p1x, _p1y, _p2x, _p2y) def _erase_acline(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _draw_cline(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _xmin, _ymin, _xmax, _ymax = gimage.getView() _coords = self.clipToRegion(_xmin, _ymin, _xmax, _ymax) if _coords is not None: _p1, _p2 = self.getKeypoints() _x1, _y1, _x2, _y2 = _coords _p1x, _p1y = gimage.coordToPixTransform(_x1, _y1) _p2x, _p2y = gimage.coordToPixTransform(_x2, _y2) if _col is None: _col = self.getColor() _dlist = self.getLinetype().getList() _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _dlist is not None: _ctx.set_dash(_dlist) _ctx.set_line_width(1.0) _ctx.move_to(_p1x, _p1y) _ctx.line_to(_p2x, _p2y) _ctx.stroke() _ctx.restore() else: _gc = gimage.getGC() _set_gc_values(_gc, _dlist, gimage.getColor(_col), 1) gimage.getPixmap().draw_line(_gc, _p1x, _p1y, _p2x, _p2y) def _erase_cline(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _draw_ccircle(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _cp = self.getCenter() _x, _y = _cp.getCoords() _r = self.getRadius() _px, _py = gimage.coordToPixTransform(_x, _y) _rx, _ry = gimage.coordToPixTransform((_x + _r), _y) _rad = _rx - _px _dlist = self.getLinetype().getList() if _col is None: _col = self.getColor() _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _dlist is not None: _ctx.set_dash(_dlist) _ctx.set_line_width(1.0) _ctx.arc(_px, _py, _rad, 0, (2.0 * pi)) _ctx.stroke() _ctx.restore() else: _gc = gimage.getGC() _set_gc_values(_gc, _dlist, gimage.getColor(_col), 1) _cw = _ch = _rad * 2 _pxmin = _px - _rad _pymin = _py - _rad gimage.getPixmap().draw_arc(_gc, False, _pxmin, _pymin, _cw, _ch, 0, (360*64)) def _erase_ccircle(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _format_layout(self, gimage, layout): _fd = pango.FontDescription() _fd.set_family(self.getFamily()) _val = self.getStyle() if _val == text.TextStyle.FONT_NORMAL: _style = pango.STYLE_NORMAL elif _val == text.TextStyle.FONT_OBLIQUE: _style = pango.STYLE_OBLIQUE elif _val == text.TextStyle.FONT_ITALIC: _style = pango.STYLE_ITALIC else: raise ValueError, "Unexpected TextBlock font style: %d" % _val _fd.set_style(_style) _val = self.getWeight() if _val == text.TextStyle.WEIGHT_NORMAL: _weight = pango.WEIGHT_NORMAL elif _val == text.TextStyle.WEIGHT_LIGHT: _weight = pango.WEIGHT_LIGHT elif _val == text.TextStyle.WEIGHT_BOLD: _weight = pango.WEIGHT_BOLD elif _val == text.TextStyle.WEIGHT_HEAVY: _weight = pango.WEIGHT_HEAVY else: raise ValueError, "Unexpected TextBlock font weight: %d" % _val _fd.set_weight(_weight) _upp = gimage.getUnitsPerPixel() _sz = int(pango.SCALE * (self.getSize()/_upp)) if _sz < pango.SCALE: _sz = pango.SCALE # print "pango units text size: %d" % _sz _fd.set_size(_sz) # # todo: handle drawing rotated text # _align = self.getAlignment() if _align == text.TextStyle.ALIGN_LEFT: layout.set_alignment(pango.ALIGN_LEFT) elif _align == text.TextStyle.ALIGN_CENTER: layout.set_alignment(pango.ALIGN_CENTER) elif _align == text.TextStyle.ALIGN_RIGHT: layout.set_alignment(pango.ALIGN_RIGHT) else: raise ValueError, "Unexpected TextBlock alignment value: %d" % _align layout.set_font_description(_fd) if self.getLineCount() > 0: _w, _h = layout.get_pixel_size() self.setBounds((_w * _upp), (_h * _upp)) def _draw_textblock(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _text = self.getText() _ctx = gimage.getCairoContext() if _ctx is not None: _layout = _ctx.create_layout() _layout.set_text(_text) else: _layout = gimage.getDA().create_pango_layout(_text) self._formatLayout(gimage, _layout) _x, _y = self.getLocation() _px, _py = gimage.coordToPixTransform(_x, _y) if _col is None: _col = self.getColor() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) _ctx.move_to(_px, _py) _ctx.show_layout(_layout) _ctx.restore() else: _gc = gimage.getGC() _gc.set_foreground(gimage.getColor(_col)) _gc.set_function(gtk.gdk.COPY) gimage.getPixmap().draw_layout(_gc, _px, _py, _layout) _layout = None def _erase_textblock(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _draw_dimstrings(self, gimage, col=None): _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _da = gimage.getDA() # # fixme - calculating dimensions needs rework! # _image = gimage.getImage() _slen = _image.scaleLength(self.calculate()) _dims = self.getDimensions(_slen) _dx, _dy = self.getLocation() _ds1 = _ds2 = _l1 = _l2 = _x1 = _y1 = _x2 = _y2 = None if self.getDualDimMode(): _off = self.getDualModeOffset() _ds1 = self.getPrimaryDimstring() if _ctx is not None: _l1 = _ctx.create_layout() _l1.set_text(_ds1.getText()) else: _l1 = _da.create_pango_layout(_ds1.getText()) _ds1._formatLayout(gimage, _l1) _w1, _h1 = _ds1.getBounds() _ds1.setLocation((_dx - (_w1/2.0)), (_dy + _h1 + _off)) _x1, _y1 = _ds1.getLocation() _ds2 = self.getSecondaryDimstring() if _ctx is not None: _l2 = _ctx.create_layout() _l2.set_text(_ds2.getText()) else: _l2 = _da.create_pango_layout(_ds2.getText()) _ds2._formatLayout(gimage, _l2) _w2, _h2 = _ds2.getBounds() _ds2.setLocation((_dx - (_w2/2.0)), (_dy - _off)) _x2, _y2 = _ds2.getLocation() _brect = (min(_x1, _x2), # xmin _y1, # ymax max((_x1 + _w1), (_x2 + _w2)), # xmax (_y2 - _h2)) # ymin else: _ds1 = self.getPrimaryDimstring() if _ctx is not None: _l1 = _ctx.create_layout() _l1.set_text(_ds1.getText()) else: _l1 = _da.create_pango_layout(_ds1.getText()) _ds1._formatLayout(gimage, _l1) _w, _h = _ds1.getBounds() _ds1.setLocation((_dx - (_w/2.0)), (_dy + (_h/2.0))) _x1, _y1 = _ds1.getLocation() _brect = (_x1, _y1, (_x1 + _w), (_y1 - _h)) _bx1, _by1 = gimage.coordToPixTransform(_brect[0], _brect[1]) _bx2, _by2 = gimage.coordToPixTransform(_brect[2], _brect[3]) _pixmap = None _bgcol = _image.getOption('BACKGROUND_COLOR') #this is a string not an object print "Debug: _bhcol %s"%str(_bgcol) if _ctx is not None : _r, _g, _b = _bgcol.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) _ctx.rectangle((_bx1 - 2), (_by1 - 2), ((_bx2 - _bx1) + 4), ((_by2 - _by1) + 4)) _ctx.fill() else: _gc = gimage.getGC() _gc.set_function(gtk.gdk.COPY) _gc.set_foreground(gimage.getColor(_bgcol)) _pixmap = gimage.getPixmap() _pixmap.draw_rectangle(_gc, True, (_bx1 - 2), (_by1 - 2), ((_bx2 - _bx1) + 4), ((_by2 - _by1) + 4)) _col = col if _col is None: _col = _ds1.getColor() _px, _py = gimage.coordToPixTransform(_x1, _y1) if _ctx is not None: _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) _ctx.move_to(_px, _py) _ctx.show_layout(_l1) else: _gc.set_foreground(gimage.getColor(_col)) _px, _py = gimage.coordToPixTransform(_x1, _y1) _pixmap.draw_layout(_gc, _px, _py, _l1) if _ds2 is not None: _col = col if _col is None: _col = _ds2.getColor() if _ctx is not None: _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) _px, _py = gimage.coordToPixTransform(_x2, _y2) _ctx.move_to(_px, _py) _ctx.show_layout(_l2) else: _gc.set_foreground(gimage.getColor(_col)) _px, _py = gimage.coordToPixTransform(_x2, _y2) _pixmap.draw_layout(_gc, _px, _py, _l2) _col = col if _col is None: _col = self.getColor() _px1, _py1 = gimage.coordToPixTransform(_brect[0], _dy) _px2, _py2 = gimage.coordToPixTransform(_brect[2], _dy) if _ctx is not None: _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) _ctx.move_to(_px1, _py1) _ctx.line_to(_px2, _py2) _ctx.stroke() else: _gc.set_foreground(gimage.getColor(_col)) _pixmap.draw_line(_gc, _px1, _py1, _px2, _py2) _l2 = None _l1 = None if _ctx is not None: _ctx.restore() def _cairo_draw_arrow_endpt(ctx, gimage, cpts, mpts): # # crossbar/crossarc points # _cx, _cy = cpts[0] _cp1x, _cp1y = gimage.coordToPixTransform(_cx, _cy) _cx, _cy = cpts[1] _cp2x, _cp2y = gimage.coordToPixTransform(_cx, _cy) # # marker points # _mp = mpts[0] if _mp is not None: _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) ctx.move_to(_px, _py) ctx.line_to(_cp1x, _cp1y) _mp = mpts[1] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) ctx.move_to(_px, _py) ctx.line_to(_cp1x, _cp1y) _mp = mpts[2] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) ctx.move_to(_px, _py) ctx.line_to(_cp2x, _cp2y) _mp = mpts[3] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) ctx.move_to(_px, _py) ctx.line_to(_cp2x, _cp2y) ctx.stroke() def _cairo_draw_filled_arrow_endpt(ctx, gimage, cpts, mpts): # # crossbar/crossarc points # _cx, _cy = cpts[0] _cp1x, _cp1y = gimage.coordToPixTransform(_cx, _cy) _cx, _cy = cpts[1] _cp2x, _cp2y = gimage.coordToPixTransform(_cx, _cy) # # marker points # _mp = mpts[0] if _mp is not None: ctx.move_to(_cp1x, _cp1y) _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) ctx.line_to(_px, _py) _mp = mpts[1] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) ctx.line_to(_px, _py) ctx.close_path() ctx.fill() _mp = mpts[2] ctx.move_to(_cp2x, _cp2y) _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) ctx.line_to(_px, _py) _mp = mpts[3] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) ctx.line_to(_px, _py) ctx.close_path() ctx.fill() def _cairo_draw_slash_endpt(ctx, gimage, mpts): # # marker points # _mp = mpts[0] if _mp is not None: _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) ctx.move_to(_px, _py) _mp = mpts[1] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) ctx.line_to(_px, _py) _mp = mpts[2] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) ctx.move_to(_px, _py) _mp = mpts[3] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) ctx.line_to(_px, _py) ctx.stroke() def _cairo_draw_circle_endpt(ctx, gimage, cpts, size): # # crossbar/crossarc points # _cp = cpts[0] if _cp is not None: _cp1x, _cp1y = gimage.coordToPixTransform(_cp[0], _cp[1]) _cx, _cy = cpts[1] _cp2x, _cp2y = gimage.coordToPixTransform(_cx, _cy) # # circle # _r = size/2.0 _pw = int(round(_r/gimage.getUnitsPerPixel())) if _cp is not None: ctx.arc(_cp1x, _cp1y, _pw, 0, (2.0 * pi)) ctx.fill() ctx.arc(_cp2x, _cp2y, _pw, 0, (2.0 * pi)) ctx.fill() def _gdk_draw_arrow_endpt(gc, gimage, pixmap, cpts, mpts): # # crossbar/crossarc points # _cx, _cy = cpts[0] _cp1x, _cp1y = gimage.coordToPixTransform(_cx, _cy) _cx, _cy = cpts[1] _cp2x, _cp2y = gimage.coordToPixTransform(_cx, _cy) # # marker points # _segs = [] _mp = mpts[0] if _mp is not None: _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) _segs.append((_px, _py, _cp1x, _cp1y)) _mp = mpts[1] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) _segs.append((_px, _py, _cp1x, _cp1y)) _mp = mpts[2] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) _segs.append((_px, _py, _cp2x, _cp2y)) _mp = mpts[3] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) _segs.append((_px, _py, _cp2x, _cp2y)) pixmap.draw_segments(gc, _segs) def _gdk_draw_filled_arrow_endpt(gc, gimage, pixmap, cpts, mpts): # # crossbar/crossarc points # _cx, _cy = cpts[0] _cp1x, _cp1y = gimage.coordToPixTransform(_cx, _cy) _cx, _cy = cpts[1] _cp2x, _cp2y = gimage.coordToPixTransform(_cx, _cy) # # marker points # _mp = mpts[0] if _mp is not None: _p1 = [] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) _p1.append((_px, _py)) _mp = mpts[1] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) _p1.append((_px, _py)) _p1.append((_cp1x, _cp1y)) pixmap.draw_polygon(gc, True, _p1) _p2 = [] _mp = mpts[2] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) _p2.append((_px, _py)) _mp = mpts[3] _px, _py = gimage.coordToPixTransform(_mp[0], _mp[1]) _p2.append((_px, _py)) _p2.append((_cp2x, _cp2y)) pixmap.draw_polygon(gc, True, _p2) def _gdk_draw_slash_endpt(gc, gimage, pixmap, mpts): # # marker points # _segs = [] _mp = mpts[0] if _mp is not None: _px1, _py1 = gimage.coordToPixTransform(_mp[0], _mp[1]) _mp = mpts[1] _px2, _py2 = gimage.coordToPixTransform(_mp[0], _mp[1]) _segs.append((_px1, _py1, _px2, _py2)) _mp = mpts[2] _px1, _py1 = gimage.coordToPixTransform(_mp[0], _mp[1]) _mp = mpts[3] _px2, _py2 = gimage.coordToPixTransform(_mp[0], _mp[1]) _segs.append((_px1, _py1, _px2, _py2)) # pixmap.draw_segments(gc, _segs) def _gdk_draw_circle_endpt(gc, gimage, pixmap, cpts, size): # # crossbar/crossarc points # _cp = cpts[0] if _cp is not None: _cp1x, _cp1y = gimage.coordToPixTransform(_cp[0], _cp[1]) _cx, _cy = cpts[1] _cp2x, _cp2y = gimage.coordToPixTransform(_cx, _cy) # _r = size/2.0 _pw = int(round(_r/gimage.getUnitsPerPixel())) _cw = _ch = _pw * 2 if _cp is not None: _xm = _cp1x - _pw _ym = _cp1y - _pw pixmap.draw_arc(gc, True, _xm, _ym, _cw, _ch, 0, (360 * 64)) _xm = _cp2x - _pw _ym = _cp2y - _pw pixmap.draw_arc(gc, True, _xm, _ym, _cw, _ch, 0, (360 * 64)) def _draw_ldim(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _bar1, _bar2 = self.getDimBars() _cbar = self.getDimCrossbar() if _col is None: _col = self.getColor() _lw = self.getThickness()/gimage.getUnitsPerPixel() # # bars and crossbar coordinates # _tlist = [] _ep1, _ep2 = _bar1.getEndpoints() _px1, _py1 = gimage.coordToPixTransform(_ep1[0], _ep1[1]) _px2, _py2 = gimage.coordToPixTransform(_ep2[0], _ep2[1]) _tlist.append((_px1, _py1, _px2, _py2)) _ep1, _ep2 = _bar2.getEndpoints() _px1, _py1 = gimage.coordToPixTransform(_ep1[0], _ep1[1]) _px2, _py2 = gimage.coordToPixTransform(_ep2[0], _ep2[1]) _tlist.append((_px1, _py1, _px2, _py2)) _ep1, _ep2 = _cbar.getEndpoints() _px1, _py1 = gimage.coordToPixTransform(_ep1[0], _ep1[1]) _px2, _py2 = gimage.coordToPixTransform(_ep2[0], _ep2[1]) _tlist.append((_px1, _py1, _px2, _py2)) _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _lw < 1.0: _lw = 1.0 _ctx.set_line_width(_lw) _p1x, _p1y, _p2x, _p2y = _tlist[0] _ctx.move_to(_p1x, _p1y) _ctx.line_to(_p2x, _p2y) _p1x, _p1y, _p2x, _p2y = _tlist[1] _ctx.move_to(_p1x, _p1y) _ctx.line_to(_p2x, _p2y) _p1x, _p1y, _p2x, _p2y = _tlist[2] _ctx.move_to(_p1x, _p1y) _ctx.line_to(_p2x, _p2y) _ctx.stroke() else: _gc = gimage.getGC() _gc.set_function(gtk.gdk.COPY) _gc.set_foreground(gimage.getColor(_col)) _t = int(round(_lw)) if _t < 1: # no zero-pixel lines _t = 1 _gc.set_line_attributes(_t, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) _pixmap = gimage.getPixmap() _pixmap.draw_segments(_gc, _tlist) # # draw endpoints # _etype = self.getEndpointType() if _etype != dimension.Dimension.DIM_ENDPT_NONE: _cpts = _cbar.getCrossbarPoints() if (_etype == dimension.Dimension.DIM_ENDPT_ARROW or _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW or _etype == dimension.Dimension.DIM_ENDPT_SLASH): _mpts = _cbar.getMarkerPoints() if _etype == dimension.Dimension.DIM_ENDPT_ARROW: if _ctx is not None: _cairo_draw_arrow_endpt(_ctx, gimage, _cpts, _mpts) else: _gdk_draw_arrow_endpt(_gc, gimage, _pixmap, _cpts, _mpts) elif _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW: if _ctx is not None: _cairo_draw_filled_arrow_endpt(_ctx, gimage, _cpts, _mpts) else: _gdk_draw_filled_arrow_endpt(_gc, gimage, _pixmap, _cpts, _mpts) elif _etype == dimension.Dimension.DIM_ENDPT_SLASH: if _ctx is not None: _cairo_draw_slash_endpt(_ctx, gimage, _mpts) else: _gdk_draw_slash_endpt(_gc, gimage, _pixmap, _mpts) else: raise ValueError, "Unexpected end point type: %d" % _etype elif _etype == dimension.Dimension.DIM_ENDPT_CIRCLE: _size = self.getEndpointSize() if _ctx is not None: _cairo_draw_circle_endpt(_ctx, gimage, _cpts, _size) else: _gdk_draw_circle_endpt(_gc, gimage, _pixmap, _cpts, _size) else: raise ValueError, "Unexpected endpoint value: %d" % _etype self._drawDimStrings(gimage, col) if _ctx is not None: _ctx.restore() def _draw_rdim(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` if _col is None: _col = self.getColor() _lw = self.getThickness()/gimage.getUnitsPerPixel() # # Dimension bar # _cbar = self.getDimCrossbar() _ep1, _ep2 = _cbar.getEndpoints() _p1x, _p1y = gimage.coordToPixTransform(_ep1[0], _ep1[1]) _p2x, _p2y = gimage.coordToPixTransform(_ep2[0], _ep2[1]) _tlist = [] _tlist.append((_p1x, _p1y, _p2x, _p2y)) _dx, _dy = self.getLocation() _pdx, _pdy = gimage.coordToPixTransform(_dx, _dy) _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _lw < 1.0: _lw = 1.0 _ctx.set_line_width(_lw) _p1x, _p1y, _p2x, _p2y = _tlist[0] _ctx.move_to(_p1x, _p1y) _ctx.line_to(_p2x, _p2y) _ctx.stroke() else: _gc = gimage.getGC() _gc.set_function(gtk.gdk.COPY) _gc.set_foreground(gimage.getColor(_col)) _t = int(round(_lw)) if _t < 1: # no zero-pixel lines _t = 1 _gc.set_line_attributes(_t, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) gimage.getPixmap().draw_segments(_gc, _tlist) # # draw marker points # _etype = self.getEndpointType() if _etype != dimension.Dimension.DIM_ENDPT_NONE: _cpts = _cbar.getCrossbarPoints() _dia_mode = self.getDiaMode() if (_etype == dimension.Dimension.DIM_ENDPT_ARROW or _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW or _etype == dimension.Dimension.DIM_ENDPT_SLASH): _mpts = _cbar.getMarkerPoints() if _etype == dimension.Dimension.DIM_ENDPT_ARROW: if _dia_mode: _mpts[0] = None if _ctx is not None: _cairo_draw_arrow_endpt(_ctx, gimage, _cpts, _mpts) else: _gdk_draw_arrow_endpt(_gc, gimage, _pixmap, _cpts, _mpts) elif _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW: if _dia_mode: _mpts[0] = None if _ctx is not None: _cairo_draw_filled_arrow_endpt(_ctx, gimage, _cpts, _mpts) else: _gdk_draw_filled_arrow_endpt(_gc, gimage, _pixmap, _cpts, _mpts) elif _etype == dimension.Dimension.DIM_ENDPT_SLASH: if _dia_mode: _mpts[0] = None if _ctx is not None: _cairo_draw_slash_endpt(_ctx, gimage, _mpts) else: _gdk_draw_slash_endpt(_gc, gimage, _pixmap, _mpts) else: raise ValueError, "Unexpected end point type: %d" % _etype elif _etype == dimension.Dimension.DIM_ENDPT_CIRCLE: _size = self.getEndpointSize() if _dia_mode: _cpts[0] = None if _ctx is not None: _cairo_draw_circle_endpt(_ctx, gimage, _cpts, _size) else: _gdk_draw_circle_endpt(gc, gimage, _pixmap, _cpts, _size) else: raise ValueError, "Unexpected endpoint value: %d" % _etype self._drawDimStrings(gimage, col) if _ctx is not None: _ctx.restore() def _draw_adim(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _bar1, _bar2 = self.getDimBars() _carc = self.getDimCrossarc() if _col is None: _col = self.getColor() _lw = self.getThickness()/gimage.getUnitsPerPixel() _sa = _carc.getStartAngle() _ea = _carc.getEndAngle() _vx, _vy = self.getVertexPoint().getCoords() _pvx, _pvy = gimage.coordToPixTransform(_vx, _vy) _dx, _dy = self.getLocation() _pdx, _pdy = gimage.coordToPixTransform(_dx, _dy) _pr = int(_carc.getRadius()/gimage.getUnitsPerPixel()) # # bars and crossarc coords # _tlist = [] _ep1, _ep2 = _bar1.getEndpoints() _p1x, _p1y = gimage.coordToPixTransform(_ep1[0], _ep1[1]) _p2x, _p2y = gimage.coordToPixTransform(_ep2[0], _ep2[1]) _tlist.append((_p1x, _p1y, _p2x, _p2y)) _ep1, _ep2 = _bar2.getEndpoints() _p1x, _p1y = gimage.coordToPixTransform(_ep1[0], _ep1[1]) _p2x, _p2y = gimage.coordToPixTransform(_ep2[0], _ep2[1]) _tlist.append((_p1x, _p1y, _p2x, _p2y)) _ctx = gimage.getCairoContext() if _ctx is not None: _ctx.save() _r, _g, _b = _col.getColors() _ctx.set_source_rgb((_r/255.0), (_g/255.0), (_b/255.0)) if _lw < 1.0: _lw = 1.0 _ctx.set_line_width(_lw) # # arc drawing relies on Cairo transformations # _ctx.scale(1.0, -1.0) _ctx.translate(_pvx, -(_pvy)) _ctx.arc(0, 0, _pr, (_sa * _dtr), (_ea * _dtr)) _ctx.identity_matrix() # _p1x, _p1y, _p2x, _p2y = _tlist[0] _ctx.move_to(_p1x, _p1y) _ctx.line_to(_p2x, _p2y) _p1x, _p1y, _p2x, _p2y = _tlist[1] _ctx.move_to(_p1x, _p1y) _ctx.line_to(_p2x, _p2y) _ctx.stroke() else: _gc = gimage.getGC() _gc.set_function(gtk.gdk.COPY) _gc.set_foreground(gimage.getColor(_col)) _t = int(round(_lw)) if _t < 1: # no zero-pixel lines _t = 1 _gc.set_line_attributes(_t, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) _pixmap = gimage.getPixmap() _pixmap.draw_segments(_gc, _tlist) _pxmin = _pvx - _pr _pymin = _pvy - _pr _cw = _ch = _pr * 2 if _sa < _ea: _sweep = _ea - _sa else: _sweep = 360.0 - (_sa - _ea) _pixmap.draw_arc(_gc, False, _pxmin, _pymin, _cw, _ch, int(_sa * 64), int(_sweep * 64)) # # draw endpoints # _etype = self.getEndpointType() if _etype != dimension.Dimension.DIM_ENDPT_NONE: _cpts = _carc.getCrossbarPoints() if (_etype == dimension.Dimension.DIM_ENDPT_ARROW or _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW or _etype == dimension.Dimension.DIM_ENDPT_SLASH): _mpts = _carc.getMarkerPoints() if _etype == dimension.Dimension.DIM_ENDPT_ARROW: if _ctx is not None: _cairo_draw_arrow_endpt(_ctx, gimage, _cpts, _mpts) else: _gdk_draw_arrow_endpt(_gc, gimage, _pixmap, _cpts, _mpts) elif _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW: if _ctx is not None: _cairo_draw_filled_arrow_endpt(_ctx, gimage, _cpts, _mpts) else: _gdk_draw_filled_arrow_endpt(_gc, gimage, _pixmap, _cpts, _mpts) elif _etype == dimension.Dimension.DIM_ENDPT_SLASH: if _ctx is not None: _cairo_draw_slash_endpt(_ctx, gimage, _mpts) else: _gdk_draw_slash_endpt(_gc, gimage, _pixmap, _mpts) else: raise ValueError, "Unexpected end point type: %d" % _etype elif _etype == dimension.Dimension.DIM_ENDPT_CIRCLE: _size = self.getEndpointSize() if _ctx is not None: _cairo_draw_circle_endpt(_ctx, gimage, _cpts, _size) else: _gdk_draw_circle_endpt(gc, gimage, _pixmap, _cpts, _size) else: raise ValueError, "Unexpected endpoint value: %d" % _etype self._drawDimStrings(gimage, col) if _ctx is not None: _ctx.restore() def _erase_dim(self, gimage): pass # originally the erase_dim set the color of the dimansion equal to the background color #for deleting the dimansion. #but when we close the application we get an error #Adding pass to the erese_dim functions we not have any problems #self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) def _draw_layer(self, gimage, col=None): if not isinstance(gimage, gtkimage.GTKImage): raise TypeError, "Invalid GTKImage: " + `type(gimage)` _col = col if _col is not None and not isinstance(_col, color.Color): raise TypeError, "Invalid Color: " + `type(_col)` _image = gimage.getImage() if _col is None: if self.isVisible() and _image.getActiveLayer() is not self: _col = _image.getOption('INACTIVE_LAYER_COLOR') else: _col = _image.getOption('BACKGROUND_COLOR') for _obj in self.getLayerEntities('point'): if _obj.isVisible(): _obj.draw(gimage, _col) _ctypes = ['hcline', 'vcline', 'acline', 'cline', 'ccircle'] for _ctype in _ctypes: for _obj in self.getLayerEntities(_ctype): if _obj.isVisible(): _obj.draw(gimage, _col) _gtypes = ['segment', 'circle', 'arc', 'leader', 'polyline', 'chamfer', 'fillet', 'textblock', 'linear_dimension', 'horizontal_dimension', 'vertical_dimension', 'radial_dimension', 'angular_dimension'] for _gtype in _gtypes: for _obj in self.getLayerEntities(_gtype): if _obj.isVisible(): _obj.draw(gimage, _col) def _erase_layer(self, gimage): self.draw(gimage, gimage.image.getOption('BACKGROUND_COLOR')) for _pt in self.getLayerEntities('point'): _pt.erase(gimage) def add_graphic_methods(): _class = point.Point _class.draw = types.MethodType(_draw_point, None, _class) _class.erase = types.MethodType(_erase_point, None, _class) _class = segment.Segment _class.draw = types.MethodType(_draw_segment, None, _class) _class.erase = types.MethodType(_erase_segment, None, _class) _class = circle.Circle _class.draw = types.MethodType(_draw_circle, None, _class) _class.erase = types.MethodType(_erase_circle, None, _class) _class = arc.Arc _class.draw = types.MethodType(_draw_arc, None, _class) _class.erase = types.MethodType(_erase_arc, None, _class) _class = leader.Leader _class.draw = types.MethodType(_draw_leader, None, _class) _class.erase = types.MethodType(_erase_leader, None, _class) _class = polyline.Polyline _class.draw = types.MethodType(_draw_polyline, None, _class) _class.erase = types.MethodType(_erase_polyline, None, _class) _class = segjoint.Chamfer _class.draw = types.MethodType(_draw_chamfer, None, _class) _class.erase = types.MethodType(_erase_chamfer, None, _class) _class = segjoint.Fillet _class.draw = types.MethodType(_draw_fillet, None, _class) _class.erase = types.MethodType(_erase_fillet, None, _class) _class = hcline.HCLine _class.draw = types.MethodType(_draw_hcline, None, _class) _class.erase = types.MethodType(_erase_hcline, None, _class) _class = vcline.VCLine _class.draw = types.MethodType(_draw_vcline, None, _class) _class.erase = types.MethodType(_erase_vcline, None, _class) _class = acline.ACLine _class.draw = types.MethodType(_draw_acline, None, _class) _class.erase = types.MethodType(_erase_acline, None, _class) _class = cline.CLine _class.draw = types.MethodType(_draw_cline, None, _class) _class.erase = types.MethodType(_erase_cline, None, _class) _class = ccircle.CCircle _class.draw = types.MethodType(_draw_ccircle, None, _class) _class.erase = types.MethodType(_erase_ccircle, None, _class) _class = text.TextBlock _class._formatLayout = types.MethodType(_format_layout, None, _class) _class.draw = types.MethodType(_draw_textblock, None, _class) _class.erase = types.MethodType(_erase_textblock, None, _class) _class = dimension.LinearDimension _class.draw = types.MethodType(_draw_ldim, None, _class) _class = dimension.RadialDimension _class.draw = types.MethodType(_draw_rdim, None, _class) _class = dimension.AngularDimension _class.draw = types.MethodType(_draw_adim, None, _class) _class = dimension.Dimension _class.erase = types.MethodType(_erase_dim, None, _class) _class._drawDimStrings = types.MethodType(_draw_dimstrings, None, _class) _class = layer.Layer _class.draw = types.MethodType(_draw_layer, None, _class) _class.erase = types.MethodType(_erase_layer, None, _class) PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtktextprefs.py0000644000175000017500000006120511307666657022520 0ustar matteomatteo# # Copyright (c) 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 51 Franklin Stree, Fifth Floor, Boston, MA 02110-1301, # USA # # # code for displaying TextStyle values # import pygtk pygtk.require('2.0') import gtk import gobject import sys from PythonCAD.Generic import color from PythonCAD.Generic import units from PythonCAD.Generic import text from PythonCAD.Generic import image class GtkTextStyle(object): """ """ __font_styles = text.TextStyle.getStyleStrings() __font_weights = text.TextStyle.getWeightStrings() __text_align = text.TextStyle.getAlignmentStrings() __families = None def __init__(self, window, ts=None): if not isinstance(window, gtk.Window): raise TypeError, "Invalid window type: " + `type(window)` self.__window = window self.__widgets = {} self.__textstyles = [] self.__ts = None if ts is not None: self.setTextStyle(ts) def addTextStyle(self, ts): """Store a TextStyle in the GtkTextStyle addTextStyle(ts) Argument 'ts' must be a TextStyle instance. """ if not isinstance(ts, text.TextStyle): raise TypeError, "Invalid TextStyle: " + `type(ts)` self.__textstyles.append(ts) def getTextStyles(self): """Return the list of stored TextStyles. getTextStyles() This method returns a list of TextStyle instances stored with the addTextStyle() method. """ return self.__textstyles def setTextStyle(self, ts): """Set the TextStyle defining the various widget values. setTextStyle(ts) Argument 'ts' must be a TextStyle instance. """ if not isinstance(ts, text.TextStyle): raise TypeError, "Invalid TextStyle: " + `type(ts)` self.__ts = ts self.setValues() def getTextStyle(self): """Get the TextStyle used to define the widget values. getTextStyle() This method returns a TextStyle instance or None if no TextStyle has been stored in the GtkTextStyle instance. """ return self.__ts def __selectColor(button, s=None): _s = s if _s is None: _s = _('Select Color') _da = button.get_child().get_child() _color = _da.get_style().bg[gtk.STATE_NORMAL] _dialog = gtk.ColorSelectionDialog(_s) _colorsel = _dialog.colorsel _colorsel.set_previous_color(_color) _colorsel.set_current_color(_color) _colorsel.set_has_palette(True) _response = _dialog.run() if _response == gtk.RESPONSE_OK: _r, _g, _b = _get_rgb_values(_colorsel.get_current_color()) _str = "#%02x%02x%02x" % (_r, _g, _b) _color = gtk.gdk.color_parse(_str) _da.modify_bg(gtk.STATE_NORMAL, _color) _dialog.destroy() __selectColor = staticmethod(__selectColor) def __moveCursor(entry): entry.set_position(-1) return False __moveCursor = staticmethod(__moveCursor) def __entryActivate(entry): _text = entry.get_text() entry.delete_text(0, -1) if len(_text): if _text == '-' or _text == '+': sys.stderr.write("Incomplete value: '%s'\n" % _text) else: try: _value = float(_text) except: sys.stderr.write("Invalid float: '%s'\n" % _text) else: sys.stderr.write("Empty entry box.") __entryActivate = staticmethod(__entryActivate) def __entryFocusOut(entry, event, text=''): _text = entry.get_text() if _text == '' or _text == '+': _size = entry.get_data('size') _hid = entry.get_data('handlerid') entry.delete_text(0, -1) entry.handler_block(_hid) try: entry.set_text(_size) finally: entry.handler_unblock(_hid) return False __entryFocusOut = staticmethod(__entryFocusOut) def __entryInsertText(entry, new_text, new_text_length, position): if (new_text.isdigit() or new_text == '.' or new_text == '+'): _string = entry.get_text() + new_text[:new_text_length] _hid = entry.get_data('handlerid') _move = True entry.handler_block(_hid) try: _pos = entry.get_position() if _string == '+': _pos = entry.insert_text(new_text, _pos) else: try: _val = float(_string) except StandardError, e: _move = False else: _pos = entry.insert_text(new_text, _pos) finally: entry.handler_unblock(_hid) if _move: if hasattr(gobject, 'idle_add'): gobject.idle_add(GtkTextStyle.__moveCursor, entry) else: gtk.idle_add(GtkTextStyle.__moveCursor, entry) entry.stop_emission('insert-text') __entryInsertText = staticmethod(__entryInsertText) def __getColorDA(widgets, key, val, s=None): _widget = widgets.get(key) if _widget is None: _widget = gtk.Button() _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_ETCHED_OUT) _frame.set_border_width(5) _widget.add(_frame) _da = gtk.DrawingArea() _da.set_size_request(20, 10) _widget.connect('clicked', GtkTextStyle.__selectColor, s) _frame.add(_da) else: _da = _widget.get_child().get_child() _da.modify_bg(gtk.STATE_NORMAL, val) return _widget __getColorDA = staticmethod(__getColorDA) def __getColorButton(widgets, key, val, s): _widget = widgets.get(key) if _widget is None: _widget = gtk.ColorButton() _widget.set_title(s) _widget.set_color(gtk.gdk.color_parse(str(val))) return _widget __getColorButton = staticmethod(__getColorButton) def __getOptionMenu(widgets, key, val, entries): _widget = widgets.get(key) if _widget is None: _widget = gtk.OptionMenu() _menu = gtk.Menu() else: _menu = _widget.getMenu() for _child in _menu.get_children(): _menu.remove(_child) _idx = 0 for _i in range(len(entries)): _val = entries[_i] if _val == val: _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget.set_menu(_menu) _widget.set_history(_idx) return _widget __getOptionMenu = staticmethod(__getOptionMenu) def __getComboBox(widgets, key, val, entries): _widget = widgets.get(key) if _widget is None: _widget = gtk.combo_box_new_text() else: _model = _widget.get_model() if _model is not None: while len(_model): _widget.remove_text(0) _idx = 0 for _i in range(len(entries)): _val = entries[_i] if _val == val: _idx = _i _widget.append_text(_val) _widget.set_active(_idx) return _widget __getComboBox = staticmethod(__getComboBox) def setValues(self): """Store the TextStyle values in the interface widgets. setValues() """ _ts = self.__ts if _ts is None: raise RuntimeError, "No TextStyle defined for the GtkTextStyle instance." _widgets = self.__widgets # if GtkTextStyle.__families is None: _families = [] for _family in self.__window.get_pango_context().list_families(): _families.append(_family.get_name()) _families.sort() GtkTextStyle.__families = _families _val = _ts.getFamily() if hasattr(gtk, 'ComboBox'): _sm = GtkTextStyle.__getComboBox else: _sm = GtkTextStyle.__getOptionMenu _key = 'FONT_FAMILY' _widget = _sm(_widgets, _key, _val, GtkTextStyle.__families) if _key not in _widgets: _widgets[_key] = _widget # _val = _ts.getStyle() if hasattr(gtk, 'ComboBox'): _sm = GtkTextStyle.__getComboBox else: _sm = GtkTextStyle.__getOptionMenu _key = 'FONT_STYLE' _widget = _sm(_widgets, _key, _val, GtkTextStyle.__font_styles) if _key not in _widgets: _widgets[_key] = _widget # _val = _ts.getWeight() if hasattr(gtk, 'ComboBox'): _sm = GtkTextStyle.__getComboBox else: _sm = GtkTextStyle.__getOptionMenu _key = 'FONT_WEIGHT' _widget = _sm(_widgets, _key, _val, GtkTextStyle.__font_weights) if _key not in _widgets: _widgets[_key] = _widget # _val = _ts.getColor() _s = _('Select Font Color') if hasattr(gtk, 'ColorButton'): _sm = GtkTextStyle.__getColorButton else: _sm = GtkTextStyle.__getColorDA _key = 'FONT_COLOR' _widget = _sm(_widgets, _key, _val, _s) if _key not in _widgets: _widgets[_key] = _widget # # fixme - TEXT_ANGLE # _val = _ts.getAlignment() if hasattr(gtk, 'ComboBox'): _sm = GtkTextStyle.__getComboBox else: _sm = GtkTextStyle.__getOptionMenu _key = 'TEXT_ALIGNMENT' _widget = _sm(_widgets, _key, _val, GtkTextStyle.__text_align) if _key not in _widgets: _widgets[_key] = _widget # _key = 'TEXT_SIZE' _entry = _widgets.setdefault(_key, gtk.Entry()) _val = _ts.getSize() _size = "%f" % _val _entry.set_data('size', _size) _hid = _entry.get_data('handlerid') if _hid is not None: _entry.handler_block(_hid) try: _entry.set_text(_size) finally: _entry.handler_unblock(_hid) else: _entry.set_text(_size) _handlerid = _entry.connect('insert-text', GtkTextStyle.__entryInsertText) _entry.set_data('handlerid', _handlerid) _entry.connect('activate', GtkTextStyle.__entryActivate) _entry.connect('focus-out-event', GtkTextStyle.__entryFocusOut) if _key not in _widgets: _widgets[_key] = _entry def __getRGBValues(color): if not isinstance(color, gtk.gdk.Color): raise TypeError, "Unexpected color type: " + `type(color)` _r = int(round((color.red/65535.0) * 255.0)) _g = int(round((color.green/65535.0) * 255.0)) _b = int(round((color.blue/65535.0) * 255.0)) return _r, _g, _b __getRGBValues = staticmethod(__getRGBValues) def getValues(self): """Return the values stored in the widgets getValues() This method returns a list of tuples in the form (key, value), where 'key' is the TextStyle option and 'value' is the option value. """ _ts = self.__ts if _ts is None: raise RuntimeError, "No TextStyle defined for the GtkTextStyle instance." _values = [] _widgets = self.__widgets # _key = 'FONT_FAMILY' _widget = _widgets[_key] if hasattr(gtk, 'ComboBox'): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected widget for '%s': " + (_key, `type(_widget)`) _values.append((_key, GtkTextStyle.__families[_idx])) # _key = 'FONT_WEIGHT' _widget = _widgets[_key] if hasattr(gtk, 'ComboBox'): _value = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _value = _widget.get_history() else: raise TypeError, "Unexpected widget for '%s': " + (_key, `type(_widget)`) _values.append((_key, _value)) # _key = 'FONT_STYLE' _widget = _widgets[_key] if hasattr(gtk, 'ComboBox'): _value = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _value = _widget.get_history() else: raise TypeError, "Unexpected widget for '%s': " + (_key, `type(_widget)`) _values.append((_key, _value)) # _key = 'FONT_COLOR' _widget = _widgets[_key] if hasattr(gtk, 'ColorButton'): _color = _widget.get_color() elif isinstance(_widget, gtk.Button): _da = _widget.getChild().getChild() _color= _da.get_style().bg[gtk.STATE_NORMAL] else: raise TypeError, "Unexpected widget for '%s': " + (_key, `type(_widget)`) _values.append((_key, GtkTextStyle.__getRGBValues(_color))) # _key = 'TEXT_ALIGNMENT' _widget = _widgets[_key] if hasattr(gtk, 'ComboBox'): _value = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _value = _widget.get_history() else: raise TypeError, "Unexpected widget for '%s': " + (_key, `type(_widget)`) _values.append((_key, _value)) # _key = 'TEXT_SIZE' _widget = _widgets[_key] _text = _widget.get_text() if len(_text) and _text != '+': _value = float(_text) else: _value = _ts.getSize() _values.append((_key, _value)) # # fixme - TEXT_ANGLE # return _values def getWidget(self, key): """Return a widget associated with a TextStyle option. getWidget(key) Argument 'key' must be a valid TextStyle option key. This method returns a widget or None. """ if (key != 'FONT_FAMILY' and key != 'FONT_STYLE' and key != 'FONT_WEIGHT' and key != 'FONT_COLOR' and key != 'TEXT_SIZE' and key != 'TEXT_ALIGNMENT' and key != 'TEXT_ANGLE'): return ValueError, "Invalid TextStyle key: " + key return self.__widgets.get(key) def clear(self): """Clear out all values and widgets in the GtkTextStyle. clear() """ self.__window = None self.__widgets.clear() del self.__textstyles[:] self.__ts = None def setImageSettings(self, im): """Adjust the widgets values based on current Image values setImageSettings(im) Argument 'im' must be an Image instance. """ if not isinstance(im, image.Image): raise TypeError, "Invalid Image type: " + `type(im)` _widgets = self.__widgets _key = 'FONT_FAMILY' _ival = im.getOption(_key) if GtkTextStyle.__families is None: _families = [] for _family in self.__window.get_pango_context().list_families(): _families.append(_family.get_name()) _families.sort() GtkTextStyle.__families = _families if hasattr(gtk, 'ComboBox'): _sm = GtkTextStyle.__getComboBox else: _sm = GtkTextStyle.__getOptionMenu _widget = _sm(_widgets, _key, _ival, GtkTextStyle.__families) if _key not in _widgets: _widgets[_key] = _widget # _key = 'FONT_STYLE' _ival = im.getOption(_key) if hasattr(gtk, 'ComboBox'): _sm = GtkTextStyle.__getComboBox else: _sm = GtkTextStyle.__getOptionMenu _optlist = GtkTextStyle.__font_styles _widget = _sm(_widgets, _key, _ival, _optlist) _idx = 0 for _i in range(len(_optlist)): _val = text.TextStyle.getStyleFromString(_optlist[_i]) if _val == _ival: _idx = _i _widget.set_active(_idx) if _key not in _widgets: _widgets[_key] = _widget # _key = 'FONT_WEIGHT' _ival = im.getOption(_key) if hasattr(gtk, 'ComboBox'): _sm = GtkTextStyle.__getComboBox else: _sm = GtkTextStyle.__getOptionMenu _optlist = GtkTextStyle.__font_weights _widget = _sm(_widgets, _key, _ival, _optlist) _idx = 0 for _i in range(len(_optlist)): _val = text.TextStyle.getWeightFromString(_optlist[_i]) if _val == _ival: _idx = _i _widget.set_active(_idx) if _key not in _widgets: _widgets[_key] = _widget # _key = 'FONT_COLOR' _ival = im.getOption(_key) _s = _('Select Font Color') if hasattr(gtk, 'ColorButton'): _sm = GtkTextStyle.__getColorButton else: _sm = GtkTextStyle.__getColorDA _widget = _sm(_widgets, _key, _ival, _s) if _key not in _widgets: _widgets[_key] = _widget # # fixme - TEXT_ANGLE # _key = 'TEXT_ALIGNMENT' _ival = im.getOption(_key) if hasattr(gtk, 'ComboBox'): _sm = GtkTextStyle.__getComboBox else: _sm = GtkTextStyle.__getOptionMenu _optlist = GtkTextStyle.__text_align _widget = _sm(_widgets, _key, _ival, _optlist) _idx = 0 for _i in range(len(_optlist)): _val = text.TextStyle.getAlignmentFromString(_optlist[_i]) if _val == _ival: _idx = _i _widget.set_active(_idx) if _key not in _widgets: _widgets[_key] = _widget # _key = 'TEXT_SIZE' _entry = _widgets.setdefault(_key, gtk.Entry()) _ival = im.getOption(_key) _size = "%f" % _ival _entry.set_data('size', _size) _hid = _entry.get_data('handlerid') if _hid is not None: _entry.handler_block(_hid) try: _entry.set_text(_size) finally: _entry.handler_unblock(_hid) else: _entry.set_text(_size) _handlerid = _entry.connect('insert-text', GtkTextStyle.__entryInsertText) _entry.set_data('handlerid', _handlerid) _entry.connect('activate', GtkTextStyle.__entryActivate) _entry.connect('focus-out-event', GtkTextStyle.__entryFocusOut) if _key not in _widgets: _widgets[_key] = _entry def _widget_changed(widget, gts): if hasattr(gtk, 'ComboBox'): _idx = widget.get_active() else: _idx = widget.get_history() _textstyles = gts.getTextStyles() gts.setTextStyle(_textstyles[_idx]) def _fill_dialog(dvbox, gts): _lsg = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _msg = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) # _frame = gtk.Frame(_('Font Properties')) _frame.set_border_width(2) _vbox = gtk.VBox(False, 2) _vbox.set_border_width(2) _frame.add(_vbox) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, False, False, 2) _label = gtk.Label(_('Family:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = gts.getWidget('FONT_FAMILY') _msg.add_widget(_widget) _hbox.pack_start(_widget, False, False, 2) # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, False, False, 2) _label = gtk.Label(_('Style:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = gts.getWidget('FONT_STYLE') _msg.add_widget(_widget) _hbox.pack_start(_widget, False, False, 2) # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, False, False, 2) _label = gtk.Label(_('Weight:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = gts.getWidget('FONT_WEIGHT') _msg.add_widget(_widget) _hbox.pack_start(_widget, False, False, 2) # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, False, False, 2) _label = gtk.Label(_('Alignment:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = gts.getWidget('TEXT_ALIGNMENT') _msg.add_widget(_widget) _hbox.pack_start(_widget, False, False, 2) # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, False, False, 2) _label = gtk.Label(_('Size:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = gts.getWidget('TEXT_SIZE') _hbox.pack_start(_widget, False, False, 2) # # fixme - TEXT_ANGLE # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, True, True, 2) _label = gtk.Label(_('Color:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = gts.getWidget('FONT_COLOR') _hbox.pack_start(_widget, False, False, 2) # dvbox.pack_start(_frame, False, False, 2) def textstyle_dialog(gtkimage, textstyles): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('TextStyle Settings'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _image = gtkimage.getImage() _ts = _image.getOption('TEXT_STYLE') _hbox = gtk.HBox(False, 5) _hbox.set_border_width(5) _label = gtk.Label(_('Active TextStyle:')) _hbox.pack_start(_label, False, False, 5) _idx = 0 if hasattr(gtk, 'ComboBox'): _widget = gtk.combo_box_new_text() for _i in range(len(textstyles)): _textstyle = textstyles[_i] if (_ts is _textstyle or _ts == _textstyle): _idx = _i _widget.append_text(_textstyle.getName()) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(textstyles)): _textstyle = textstyles[_i] if (_ts is _textstyle or _ts == _textstyle): _idx = _i _item = gtk.MenuItem(_textstyle.getName()) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) _hbox.pack_start(_widget, False, False, 0) _dialog.vbox.pack_start(_hbox, True, True) # _gts = GtkTextStyle(_window) for _textstyle in textstyles: _gts.addTextStyle(_textstyle) _gts.setTextStyle(_ts) _gts.setImageSettings(_image) _fill_dialog(_dialog.vbox, _gts) _widget.connect('changed', _widget_changed, _gts) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: _nts = _gts.getTextStyle() if _nts != _ts: _image.setOption('TEXT_STYLE', _nts) for _opt, _val in _gts.getValues(): if _opt == 'FONT_FAMILY': if _val != _image.getOption(_opt): _image.setOption(_opt, _val) elif _opt == 'FONT_STYLE': if _val != _image.getOption(_opt): _image.setOption(_opt, _val) elif _opt == 'FONT_WEIGHT': if _val != _image.getOption(_opt): _image.setOption(_opt, _val) elif _opt == 'FONT_COLOR': if _val != _image.getOption(_opt).getColors(): _r, _g, _b = _val _image.setOption(_opt, color.Color(_r, _g, _b)) elif _opt == 'TEXT_SIZE': if abs(_val - _image.getOption(_opt)) > 1e-10: _image.setOption(_opt, _val) elif _opt == 'TEXT_ANGLE': if abs(_val - _image.getOption(_opt)) > 1e-10: _image.setOption(_opt, _val) elif _opt == 'TEXT_ALIGNMENT': if _val != _image.getOption(_opt): _image.setOption(_opt, _val) else: raise RuntimeError, "Unexpected TextStyle option '%s'" % _opt _gts.clear() _dialog.destroy() PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtktext.py0000644000175000017500000002303111307666732021445 0ustar matteomatteo# # Copyright (c) 2003, 2004, 2006, 2007 Art Haas # # 2009 Matteo Boscolo # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # GTK interface code for dealing with text entities # import pygtk pygtk.require('2.0') import gtk import pango import copy from PythonCAD.Generic.text import TextStyle, TextBlock from PythonCAD.Generic import snap def set_textblock_bounds(gtkimage, tblock): # print "set_textblock_bounds() ..." _text = tblock.getText() if len(_text) == 0: tblock.setBounds(0, 0) tblock.setFontScale(1/float(pango.SCALE)) return _family = tblock.getFamily() _style = tblock.getStyle() _weight = tblock.getWeight() _size = tblock.getSize() _da = gtkimage.getDA() _upp = gtkimage.getUnitsPerPixel() # # initial test layout ... # _layout = _da.create_pango_layout(_text) _fd = pango.FontDescription() _fd.set_family(_family) _fd.set_style(_style) _fd.set_weight(_weight) # # use an 18-point font as first size guess # _fs = 18 _fd.set_size(pango.SCALE * _fs) _layout.set_font_description(_fd) _nlines = _layout.get_line_count() # # the pixel height of the TextBlock # _th = _nlines * _size # print "TextBlock height: %g" % _th _ph = _th/_upp _iph = int(_ph) if _iph/_nlines < 3: # tiny text - use the 18-point values for boundary _w, _h = _layout.get_size() _tw = (_w * _th)/float(_h) tblock.setBounds(_tw, _th) tblock.setFontScale(1/float(pango.SCALE)) _layout = None return # print "TextBlock pixel height: %g [%d]" % (_ph, _iph) _w, _h = _layout.get_pixel_size() # print "first layout: w: %d; h: %d" % (_w, _h) _i = 0 if _h != _iph: # # loop until the layout pixel height equals the "correct" pixel height # _diff = abs(_h - _iph) _ofs = _fs _fs = (_fs * _ph)/float(_h) # print "adjusted font size: %g" % (_fs) while True: _layout = _da.create_pango_layout(_text) _fd = pango.FontDescription() _fd.set_family(_family) _fd.set_style(_style) _fd.set_weight(_weight) _fd.set_size(int(pango.SCALE * _fs)) _layout.set_font_description(_fd) _w, _h = _layout.get_pixel_size() # print "adjusted layout: w: %d; h: %d" % (_w, _h) # # tests to bail out # # all the inexact comparisons and iteration max # count text are arbitrary ... # if _h == _iph: # print "exact match" break if ((_iph > 10) and (abs(_iph - _h) < 2)): # print "within 2" break if ((_iph > 100) and (abs(_iph - _h) < 10)): # print "within 10" break if ((_iph > 1000) and (abs(_iph - _h) < 40)): # print "within 40" break if _i > 25: # print "25 iterations" break # # bah, another iteration # _d = abs(_h - _iph) if _d < _diff: _diff = _d _ofs = _fs _fs = (_fs * _ph)/float(_h) else: # split the difference in the changed font size # and try again, but do not reset the old font # size _fs = _ofs + ((_fs - _ofs)/2.0) # print "adjusted font size: %g" % (_fs) _i = _i + 1 # # with the layout sized "correctly", calculate the TextBlock width # _w, _h = _layout.get_size() _tw = (_w * _th)/float(_h) # print "TextBlock width: %g" % _tw tblock.setBounds(_tw, _th) tblock.setFontScale(_fs) _layout = None def _make_pango_layout(gtkimage, text, family, style, weight, size): _layout = gtkimage.getDA().create_pango_layout(text) _fd = pango.FontDescription() _fd.set_family(family) if style == TextStyle.FONT_NORMAL: _style = pango.STYLE_NORMAL elif style == TextStyle.FONT_OBLIQUE: _style = pango.STYLE_OBLIQUE elif style == TextStyle.FONT_ITALIC: _style = pango.STYLE_ITALIC else: raise ValueError, "Unexpected font style: %d" % style _fd.set_style(_style) if weight == TextStyle.WEIGHT_NORMAL: _weight = pango.WEIGHT_NORMAL elif weight == TextStyle.WEIGHT_LIGHT: _weight = pango.WEIGHT_LIGHT elif weight == TextStyle.WEIGHT_BOLD: _weight = pango.WEIGHT_BOLD elif weight == TextStyle.WEIGHT_HEAVY: _weight = pango.WEIGHT_HEAVY else: raise ValueError, "Unexpected font weight: %d" % weight _fd.set_weight(_weight) _sz = int(pango.SCALE * (size/gtkimage.getUnitsPerPixel())) if _sz < pango.SCALE: _sz = pango.SCALE _fd.set_size(_sz) _layout.set_font_description(_fd) return _layout def text_button_press(gtkimage, widget, event, tool): _image=gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _sn=snap.getSnapPoint(_image,gtkimage.getTolerance(),_snapArray) _x,_y=_sn.point.getCoords() tool.getTextBlock().setLocation(_x,_y) _tool=copy.copy(tool) _image.startAction() try: tool.create(_image) finally: _image.endAction() text_add_init(gtkimage,_tool) return True def text_motion_notify(gtkimage, widget, event, tool): _tblock = tool.getTextBlock() _tw, _th = tool.getPixelSize() _gc = gtkimage.getGC() _align = _tblock.getAlignment() if _align == TextStyle.ALIGN_LEFT: _xoff = 0 elif _align == TextStyle.ALIGN_CENTER: _xoff = _tw//2 elif _align == TextStyle.ALIGN_RIGHT: _xoff = _tw else: raise ValueError, "Unexpected alignment value: %d" % _align _cp = tool.getCurrentPoint() if _cp is not None: _xc, _yc = _cp _xc = _xc - _xoff widget.window.draw_rectangle(_gc, False, _xc, _yc, _tw, _th) _snapArray={'perpendicular':False,'tangent':False} _sn=snap.getSnapPoint(gtkimage.getImage(),gtkimage.getTolerance(),_snapArray) _x, _y=_sn.point.getCoords() _x = _x - _xoff _x,_y = gtkimage.coordToPixTransform(_x,_y) tool.setCurrentPoint(_x,_y) widget.window.draw_rectangle(_gc, False, _x, _y, _tw, _th) return True def text_add_init(gtkimage, tool=None): _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() if tool is not None: _image.setTool(tool) _tool = _image.getTool() _text = _tool.getText() _ts = _image.getOption('TEXT_STYLE') _tb = TextBlock(_x, _y, _text, _ts) _f = _image.getOption('FONT_FAMILY') if _f != _ts.getFamily(): _tb.setFamily(_f) _s = _image.getOption('FONT_STYLE') if _s != _ts.getStyle(): _tb.setStyle(_s) _w = _image.getOption('FONT_WEIGHT') if _w != _ts.getWeight(): _tb.setWeight(_w) _c = _image.getOption('FONT_COLOR') if _c != _ts.getColor(): _tb.setColor(_c) _sz = _image.getOption('TEXT_SIZE') if abs(_sz - _ts.getSize()) > 1e-10: _tb.setSize(_sz) _a = _image.getOption('TEXT_ANGLE') if abs(_a - _ts.getAngle()) > 1e-10: _tb.setAngle(_a) _al = _image.getOption('TEXT_ALIGNMENT') if _al != _ts.getAlignment(): _tb.setAlignment(_al) _tool.setTextBlock(_tb) _layout = _make_pango_layout(gtkimage, _text, _f, _s, _w, _sz) _tool.setLayout(_layout) _lw, _lh = _layout.get_pixel_size() _tool.setPixelSize(_lw, _lh) _upp = gtkimage.getUnitsPerPixel() # # the width and height calculations can be somewhat inaccurate # as the unitsPerPixel value gets large # _w = _lw * _upp _h = _lh * _upp _tool.setBounds(_w, _h) _tool.setHandler("motion_notify", text_motion_notify) _tool.setHandler("button_press", text_button_press) gtkimage.setPrompt(_('Click where to place the text')) _gc = gtkimage.getGC() _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) _gc.set_function(gtk.gdk.INVERT) def text_add_dialog(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Enter text'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _tb = gtk.TextBuffer() _tv = gtk.TextView(_tb) _sw = gtk.ScrolledWindow() _sw.set_size_request(400, 300) _sw.add_with_viewport(_tv) _dialog.vbox.pack_start(_sw, False, False, 0) _dialog.show_all() _text = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _start_iter, _end_iter = _tb.get_bounds() _text = _tb.get_text(_start_iter, _end_iter) _dialog.destroy() return _text PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkmodify.py0000644000175000017500000027143011307666732021760 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Art Haas # # 2009 Matteo Bosocolo # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # functions for doing modifications on drawing # entities # import pygtk pygtk.require('2.0') import gtk from math import atan2, pi from PythonCAD.Generic.dimension import Dimension from PythonCAD.Generic.dimension import LinearDimension from PythonCAD.Generic.dimension import HorizontalDimension from PythonCAD.Generic.dimension import VerticalDimension from PythonCAD.Generic.dimension import RadialDimension from PythonCAD.Generic.dimension import AngularDimension from PythonCAD.Generic import color from PythonCAD.Generic.graphicobject import GraphicObject from PythonCAD.Generic.segment import Segment from PythonCAD.Generic.circle import Circle from PythonCAD.Generic.arc import Arc from PythonCAD.Generic.polyline import Polyline from PythonCAD.Generic.text import TextStyle, TextBlock from PythonCAD.Generic.hcline import HCLine from PythonCAD.Generic.acline import ACLine from PythonCAD.Generic.vcline import VCLine from PythonCAD.Generic.cline import CLine from PythonCAD.Generic import util from PythonCAD.Generic import split from PythonCAD.Generic import snap import PythonCAD.Generic.units import PythonCAD.Generic.move import PythonCAD.Generic.transfer import PythonCAD.Generic.delete import PythonCAD.Generic.rotate # # common code # def select_motion_notify(gtkimage, widget, event, tool): """ Draw the rectangle selections """ _tx, _ty = tool.getLocation() _px, _py = gtkimage.coordToPixTransform(_tx, _ty) _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _cp = tool.getCurrentPoint() if _cp is not None: _xc, _yc = _cp _xmin = min(_xc, _px) _ymin = min(_yc, _py) _rw = abs(_xc - _px) _rh = abs(_yc - _py) widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _rw, _rh) tool.setCurrentPoint(_x, _y) _xmin = min(_x, _px) _ymin = min(_y, _py) _rw = abs(_x - _px) _rh = abs(_y - _py) widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _rw, _rh) return True # # move objects # def move_objects(gtkimage, objlist, tool): _init_func = tool.getHandler("initialize") _dx, _dy = tool.getDistance() _image = gtkimage.getImage() _image.startAction() try: PythonCAD.Generic.move.move_objects(objlist, _dx, _dy) finally: _image.endAction() gtkimage.setPrompt(_('Click in the drawing area or enter a distance.')) tool.reset() gtkimage.redraw() _init_func(gtkimage, tool) def move_button_press(gtkimage, tool): _image = gtkimage.getImage() _tol = gtkimage.getTolerance() _onlySnap={"Freepoint":True} _sp=snap.getOnlySnap(_image,_tol,_onlySnap) _x, _y = _sp.point.getCoords() # # need to find if the point is an intersection of drawing objects ... # tool.pushObject(_x) tool.pushObject(_y) return True def move_end_button_press_cb(gtkimage, widget, event, tool): _image = gtkimage.getImage() _tol = gtkimage.getTolerance() _onlySnap={"Freepoint":True} _sp=snap.getOnlySnap(_image,_tol,_onlySnap) _x2, _y2 = _sp.point.getCoords() _x1, _y1 = tool.getLocation() _xmin = min(_x1, _x2) _xmax = max(_x1, _x2) _ymin = min(_y1, _y2) _ymax = max(_y1, _y2) _active_layer = _image.getActiveLayer() _objlist = _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax) move_objects(gtkimage, _objlist, tool) return True def move_elem_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _onlySnap={"Freepoint":True} _sp=snap.getOnlySnap(_image,_tol,_onlySnap) _x,_y=_sp.point.getCoords() #_x, _y = _image.getCurrentPoint() _objdict = _image.mapPoint(_x, _y, _tol, None) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: _objs = [] for _obj, _pt in _objdict[_active_layer]: _objs.append(_obj) _dx, _dy = tool.getDistance() move_objects(gtkimage, _objs, tool) else: _onlySnap={"Freepoint":True} _sp=snap.getOnlySnap(_image,_tol,_onlySnap) _x,_y=_sp.point.getCoords() tool.setLocation(_x, _y) tool.setHandler("motion_notify", select_motion_notify) tool.setHandler("button_press", move_end_button_press_cb) gtkimage.setPrompt(_('Click the second point for defining the region')) _gc = gtkimage.getGC() _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) _gc.set_function(gtk.gdk.INVERT) return True # # move horizontal # def move_horizontal_entry_event(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _image = gtkimage.getImage() _dist = util.get_float(eval(_text, _image.getImageVariables())) tool.setDistance(_dist, 0.0) if _image.hasSelection(): move_objects(gtkimage, _image.getSelectedObjects(), tool) else: gtkimage.setPrompt(_('Click on the objects to move.')) tool.setHandler("button_press", move_elem_button_press_cb) tool.delHandler("entry_event") def move_horizontal_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() _x1, _y1 = tool.getLocation() tool.setDistance((_x - _x1), 0.0) if _image.hasSelection(): move_objects(gtkimage, _image.getSelectedObjects(), tool) else: tool.clearLocation() gtkimage.setPrompt(_('Select the objects to move.')) tool.setHandler("button_press", move_elem_button_press_cb) tool.delHandler("entry_event") return True def move_horizontal_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() tool.setLocation(_x, _y) gtkimage.setPrompt(_('Click another point to define the distance')) tool.setHandler("button_press", move_horizontal_second_button_press_cb) return True def move_horizontal_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter the distance.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", move_horizontal_first_button_press_cb) _tool.setHandler("entry_event", move_horizontal_entry_event) _tool.setHandler("initialize", move_horizontal_init) # # move vertical # def move_vertical_entry_event(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _image = gtkimage.getImage() _dist = util.get_float(eval(_text, _image.getImageVariables())) tool.setDistance(0.0, _dist) if _image.hasSelection(): move_objects(gtkimage, _image.getSelectedObjects(), tool) else: gtkimage.setPrompt(_('Click on the objects to move.')) tool.setHandler("button_press", move_elem_button_press_cb) tool.delHandler("entry_event") def move_vertical_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() _x1, _y1 = tool.getLocation() tool.setDistance(0.0, (_y - _y1)) if _image.hasSelection(): move_objects(gtkimage, _image.getSelectedObjects(), tool) else: tool.clearLocation() gtkimage.setPrompt(_('Select the objects to move.')) tool.setHandler("button_press", move_elem_button_press_cb) tool.delHandler("entry_event") return True def move_vertical_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() tool.setLocation(_x, _y) gtkimage.setPrompt(_('Click another point to define the distance')) tool.setHandler("button_press", move_vertical_second_button_press_cb) return True def move_vertical_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter the distance.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", move_vertical_first_button_press_cb) _tool.setHandler("entry_event", move_vertical_entry_event) _tool.setHandler("initialize", move_vertical_init) # # move based on two mouse clicks # def move_xy_entry_event(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _image = gtkimage.getImage() _x, _y = eval(_text, _image.getImageVariables()) tool.setDistance(util.get_float(_x), util.get_float(_y)) if _image.hasSelection(): move_objects(gtkimage, _image.getSelectedObjects(), tool) else: gtkimage.setPrompt(_('Click on the objects to move.')) tool.setHandler("button_press", move_elem_button_press_cb) tool.delHandler("entry_event") def move_xy_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() _x1, _y1 = tool.getLocation() tool.setDistance((_x - _x1), (_y - _y1)) if _image.hasSelection(): move_objects(gtkimage, _image.getSelectedObjects(), tool) else: tool.clearLocation() gtkimage.setPrompt(_('Select the objects to move.')) tool.setHandler("button_press", move_elem_button_press_cb) tool.delHandler("entry_event") return True def move_xy_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() tool.setLocation(_x, _y) gtkimage.setPrompt(_('Click another point to define the distance')) tool.setHandler("button_press", move_xy_second_button_press_cb) return True def move_twopoint_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter the x and y distances.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", move_xy_first_button_press_cb) _tool.setHandler("entry_event", move_xy_entry_event) _tool.setHandler("initialize", move_twopoint_init) # # delete objects # def delete_region_end_cb(gtkimage, widget, event, tool): _image = gtkimage.getImage() _x2, _y2 = _image.getCurrentPoint() _x1, _y1 = tool.getLocation() _xmin = min(_x1, _x2) _xmax = max(_x1, _x2) _ymin = min(_y1, _y2) _ymax = max(_y1, _y2) tool.delHandler("motion_notify") tool.setHandler("button_press", delete_button_press_cb) _active_layer = _image.getActiveLayer() _objs = _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax) if len(_objs): _image.startAction() try: PythonCAD.Generic.delete.delete_objects(_objs) finally: _image.endAction() tool.reset() delete_mode_init(gtkimage) gtkimage.redraw() def delete_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _active_layer = _image.getActiveLayer() _objs = _active_layer.mapPoint((_x, _y), _tol) if len(_objs): _dims = [] _image.startAction() try: for _obj in _objs: if isinstance(_obj, Dimension): _dims.append(_obj) elif isinstance(_obj, tuple): _entity, _pt = _obj _active_layer.delObject(_entity) else: raise TypeError, "Unhandled object: " + `_obj` for _dim in _dims: if _dim in _active_layer: # it may have been removed ... _active_layer.delObject(_dim) finally: _image.endAction() gtkimage.redraw() else: tool.setLocation(_x, _y) tool.setHandler("motion_notify", select_motion_notify) tool.setHandler("button_press", delete_region_end_cb) gtkimage.setPrompt(_('Click the second point for defining the region')) _gc = gtkimage.getGC() _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) _gc.set_function(gtk.gdk.INVERT) return True def delete_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the items you want to delete.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", delete_button_press_cb) _tool.setHandler("initialize", delete_mode_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = _image.getSelectedObjects() _image.startAction() try: PythonCAD.Generic.delete.delete_objects(_objs) finally: _image.endAction() # # stretch operations # def stretch_end_button_press_cb(gtkimage, widget, event, tool): _image = gtkimage.getImage() _x2, _y2 = _image.getCurrentPoint() _y1 = tool.popObject() _x1 = tool.popObject() _xmin = min(_x1, _x2) _xmax = max(_x1, _x2) _ymin = min(_y1, _y2) _ymax = max(_y1, _y2) tool.delHandler("motion_notify") _active_layer = _image.getActiveLayer() _dx, _dy = tool.getDistance() _image.startAction() try: for _pt in _active_layer.getLayerEntities("point"): if _pt.inRegion(_xmin, _ymin, _xmax, _ymax): _pt.move(_dx, _dy) finally: _image.endAction() gtkimage.redraw() tool.clearLocation() tool.clearCurrentPoint() tool.setHandler("button_press", stretch_elem_button_press_cb) return True def stretch_elem_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() _active_layer = _image.getActiveLayer() _pt = None _pts = _active_layer.find('point', _x, _y, _tol) if len(_pts): _dx, _dy = tool.getDistance() _image.startAction() try: for _pt in _pts: _pt.move(_dx, _dy) finally: _image.endAction() gtkimage.redraw() else: tool.pushObject(_x) tool.pushObject(_y) tool.setLocation(_x, _y) tool.setHandler("motion_notify", select_motion_notify) tool.setHandler("button_press", stretch_end_button_press_cb) gtkimage.setPrompt(_('Click the second point for defining the region')) _gc = gtkimage.getGC() _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) _gc.set_function(gtk.gdk.INVERT) return True # # stretch horizontal # def stretch_horiz_button_press_cb(gtkimage, widget, event, tool): if not len(tool): move_button_press(gtkimage, tool) gtkimage.setPrompt(_('Click a second point to indicate the horizontal distance')) else: _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(gtkimage.getImage(),gtkimage.getTolerance(),_snapArray).point.getCoords() # # see if the point is at an intersection of drawing objects ... # _y1 = tool.popObject() _x1 = tool.popObject() tool.setDistance((_x - _x1), 0.0) gtkimage.setPrompt(_('Select the points to move.')) tool.delHandler("entry_event") tool.setHandler("button_press", stretch_elem_button_press_cb) return True def stretch_horiz_entry_event(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _dist = util.get_float(eval(_text, gtkimage.image.getImageVariables())) tool.setDistance(_dist, 0.0) gtkimage.setPrompt(_('Select the points to move.')) tool.setHandler("button_press", stretch_elem_button_press_cb) tool.delHandler("entry_event") def stretch_horizontal_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on a point or enter the horizontal distance.')) _tool = gtkimage.getImage().getTool() _tool.initialize() _tool.setHandler("button_press", stretch_horiz_button_press_cb) _tool.setHandler("entry_event", stretch_horiz_entry_event) _tool.setHandler("initialize", stretch_horizontal_init) # # stretch vertical # def stretch_vert_button_press_cb(gtkimage, widget, event, tool): if not len(tool): move_button_press(gtkimage, tool) gtkimage.setPrompt(_('Click a second point to indicate the vertical distance')) else: _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(gtkimage.getImage(),gtkimage.getTolerance(),_snapArray).point.getCoords() # # see if the point is at an intersection of drawing objects ... # _y1 = tool.popObject() _x1 = tool.popObject() tool.setDistance(0.0, (_y - _y1)) gtkimage.setPrompt(_('Select the points to move.')) tool.delHandler("entry_event") tool.setHandler("button_press", stretch_elem_button_press_cb) return True def stretch_vert_entry_event(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _dist = util.get_float(eval(_text, gtkimage.image.getImageVariables())) tool.setDistance(0.0, _dist) gtkimage.setPrompt(_('Select the points to move.')) tool.setHandler("button_press", stretch_elem_button_press_cb) tool.delHandler("entry_event") def stretch_vertical_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter the distance.')) _tool = gtkimage.getImage().getTool() _tool.initialize() _tool.setHandler("button_press", stretch_vert_button_press_cb) _tool.setHandler("entry_event", stretch_vert_entry_event) _tool.setHandler("initialize", stretch_vertical_init) # # stretch x/y # def stretch_xy_entry_event(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = eval(_text, gtkimage.image.getImageVariables()) tool.setDistance(util.get_float(_x), util.get_float(_y)) gtkimage.setPrompt(_('Select the points to move.')) tool.setHandler("button_press", stretch_elem_button_press_cb) tool.delHandler("entry_event") def stretch_xy_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() _x1, _y1 = tool.getLocation() tool.setDistance((_x - _x1), (_y - _y1)) tool.clearLocation() gtkimage.setPrompt(_('Select the points to move.')) tool.setHandler("button_press", stretch_elem_button_press_cb) tool.delHandler("entry_event") return True def stretch_xy_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() tool.setLocation(_x, _y) gtkimage.setPrompt(_('Click another point to define the distance')) tool.setHandler("button_press", stretch_xy_second_button_press_cb) return True def stretch_xy_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter the x and y distances.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", stretch_xy_first_button_press_cb) _tool.setHandler("entry_event", stretch_xy_entry_event) _tool.setHandler("initialize", stretch_xy_init) # # rotate objects # def rotate_objects(gtkimage, objlist, tool): _init_func = tool.getHandler("initialize") _cx, _cy = tool.getRotationPoint() _angle = tool.getAngle() _image = gtkimage.getImage() _image.startAction() try: PythonCAD.Generic.rotate.rotate_objects(objlist, _cx, _cy, _angle) finally: _image.endAction() tool.reset() _init_func(gtkimage, tool) def rotate_end_button_press_cb(gtkimage, widget, event, tool): _image = gtkimage.getImage() _x2, _y2 = _image.getCurrentPoint() _x1, _y1 = tool.getLocation() _xmin = min(_x1, _x2) _xmax = max(_x1, _x2) _ymin = min(_y1, _y2) _ymax = max(_y1, _y2) _active_layer = _image.getActiveLayer() _objlist = _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax) rotate_objects(gtkimage, _objlist, tool) return True def rotate_elem_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _objdict = _image.mapPoint(_x, _y, _tol, None) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: _objs = [] for _obj, _pt in _objdict[_active_layer]: _objs.append(_obj) rotate_objects(gtkimage, _objs, tool) else: _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() tool.setLocation(_x, _y) tool.setHandler("motion_notify", select_motion_notify) tool.setHandler("button_press", rotate_end_button_press_cb) gtkimage.setPrompt(_('Click the second point for defining the region')) _gc = gtkimage.getGC() _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) _gc.set_function(gtk.gdk.INVERT) return True def rotate_angle_entry_event(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _angle = eval(_text, gtkimage.image.getImageVariables()) tool.setAngle(util.get_float(_angle)) gtkimage.setPrompt(_('Select the objects to rotate')) tool.delHandler("entry_event") tool.setHandler("button_press", rotate_elem_button_press_cb) def rotate_angle_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() _objdict = _image.mapPoint(_x, _y, _tol) _a2 = None if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, HCLine): _a2 = 0.0 elif isinstance(_obj, VCLine): _a2 = 90.0 elif isinstance(_obj, ACLine): _a2 = _obj.getAngle() elif isinstance(_obj, CLine): _p1, _p2 = _obj.getKeypoints() _a2 = atan2((_p2.y - _p1.y), (_p2.x - _p1.x)) * (180.0/pi) else: pass if _a2 is not None: break if _a2 is not None: _cl = tool.getObject(0) if isinstance(_cl, HCLine): _a1 = 0.0 elif isinstance(_cl, VCLine): _a1 = 90.0 elif isinstance(_cl, ACLine): _a1 = _cl.getAngle() elif isinstance(_cl, CLine): _p1, _p2 = _cl.getKeypoints() _a1 = atan2((_p2.y - _p1.y), (_p2.x - _p1.x)) * (180.0/pi) else: raise RuntimeError, "Unexpected conline type: " + `type(_cl)` _angle = _a2 - _a1 if abs(_angle) > 1e-10: tool.setAngle(_angle) gtkimage.setPrompt(_('Select the objects to rotate')) tool.delHandler("entry_event") tool.setHandler("button_press", rotate_elem_button_press_cb) return True def rotate_angle_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() _objdict = _image.mapPoint(_x, _y, _tol) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, (HCLine, VCLine, ACLine, CLine)): tool.pushObject(_obj) tool.setHandler("button_press", rotate_angle_second_button_press_cb) gtkimage.setPrompt(_('Click on another construction line to define the angle of rotation or enter the rotation angle.')) break return True def rotate_point_entry_event(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = eval(_text, gtkimage.image.getImageVariables()) tool.setRotationPoint(util.get_float(_x), util.get_float(_y)) gtkimage.setPrompt(_('Click on a construction line or enter the rotation angle.')) tool.setHandler("entry_event", rotate_angle_entry_event) tool.setHandler("button_press", rotate_angle_first_button_press_cb) def rotate_point_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _x,_y=snap.getSnapPoint(_image,_tol,_snapArray).point.getCoords() tool.setRotationPoint(_x, _y) gtkimage.setPrompt(_('Click on a construction line or enter the rotation angle')) tool.setHandler("button_press", rotate_angle_first_button_press_cb) tool.setHandler("entry_event", rotate_angle_entry_event) return True def rotate_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter the rotation center coordinates.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", rotate_point_button_press_cb) _tool.setHandler("entry_event", rotate_point_entry_event) _tool.setHandler("initialize", rotate_init) # # split objects into two pieces or at intersection points # def split_end_button_press_cb(gtkimage, widget, event, tool): _image = gtkimage.getImage() _x2, _y2 = getSnapPoint(_image,_image.get.getTolerance()).point.getCoords() _y1 = tool.popObject() _x1 = tool.popObject() _xmin = min(_x1, _x2) _xmax = max(_x1, _x2) _ymin = min(_y1, _y2) _ymax = max(_y1, _y2) tool.delHandler("motion_notify") _active_layer = _image.getActiveLayer() _objs = _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax, True) if len(_objs): _splitable = [] for _obj in _objs: if isinstance(_obj, (Segment, Circle, Arc, Polyline)): _splitable.append(_obj) if len(_splitable): _image.startAction() try: split.split_objects(_splitable) finally: _image.endAction() gtkimage.setPrompt(_('Click on the objects you want to split.')) tool.clearLocation() tool.clearCurrentPoint() tool.setHandler("button_press", split_object_button_press_cb) return True def split_object_button_press_cb(gtkimage, widget, event, tool): """ First callbeck for the split comand """ _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = snap.getSnapPoint(_image,_tol).point.getCoords() _active_layer = _image.getActiveLayer() _objlist = _active_layer.mapPoint((_x, _y), _tol, None) if len(_objlist): for _obj, _pt in _objlist: _px, _py = _pt.getCoords() if isinstance(_obj, Segment): _image.startAction() try: _segs = split.split_segment_at(_obj, _px, _py) if _segs is not None: _active_layer.delObject(_obj) _s1, _s2 = _segs _active_layer.addObject(_s1) _active_layer.addObject(_s2) finally: _image.endAction() elif isinstance(_obj, Arc): _image.startAction() try: _arcs = split.split_arc_at(_obj, _px, _py) if _arcs is not None: _active_layer.delObject(_obj) _a1, _a2 = _arcs _active_layer.addObject(_a1) _active_layer.addObject(_a2) finally: _image.endAction() elif isinstance(_obj, Circle): _image.startAction() try: _arc = split.split_circle_at(_obj, _px, _py) if _arc is not None: _active_layer.delObject(_obj) _active_layer.addObject(_arc) finally: _image.endAction() elif isinstance(_obj, Polyline): _image.startAction() try: if split.split_polyline_at(_obj, _px, _py): _obj.erase(gtkimage) _obj.draw(gtkimage) finally: _image.endAction() else: pass else: tool.pushObject(_x) tool.pushObject(_y) tool.setLocation(_x, _y) tool.setHandler("motion_notify", select_motion_notify) tool.setHandler("button_press", split_end_button_press_cb) gtkimage.setPrompt(_('Click the second point for defining the region')) _gc = gtkimage.getGC() _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) _gc.set_function(gtk.gdk.INVERT) return True def split_object_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the objects you want to split')) _tool = gtkimage.getImage().getTool() _tool.initialize() _tool.setHandler("initialize", split_object_init) _tool.setHandler("button_press", split_object_button_press_cb) _image = gtkimage.getImage() if _image.hasSelection(): _splitable = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, (Segment, Circle, Arc, Polyline)): _splitable.append(_obj) if len(_splitable): _image.startAction() try: split.split_objects(_splitable) finally: _image.endAction() # # transfer objects from one layer to another # def transfer_end_button_press_cb(gtkimage, widget, event, tool): _image = gtkimage.getImage() _x2, _y2 = _image.getCurrentPoint() _y1 = tool.popObject() _x1 = tool.popObject() _xmin = min(_x1, _x2) _xmax = max(_x1, _x2) _ymin = min(_y1, _y2) _ymax = max(_y1, _y2) tool.delHandler("motion_notify") _active_layer = _image.getActiveLayer() _layers = [_image.getTopLayer()] _objdict = {} while len(_layers): _layer = _layers.pop() if _layer is not _active_layer: if _layer.isVisible(): _objs = _layer.objsInRegion(_xmin, _ymin, _xmax, _ymax) if len(_objs): _objdict[_layer] = _objs _layers.extend(_layer.getSublayers()) if len(_objdict): _image.startAction() try: for _layer in _objdict: if _layer is not _active_layer: _objs = _objdict[_layer] PythonCAD.Generic.transfer.transfer_objects(_objs, _active_layer) finally: _image.endAction() tool.clearLocation() tool.clearCurrentPoint() tool.setHandler("button_press", transfer_object_button_press_cb) return True def transfer_object_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _active_layer = _image.getActiveLayer() _objdict = _image.mapPoint(_x, _y, _tol, None) if len(_objdict): _image.startAction() try: for _layer in _objdict: if _layer is not _active_layer: _objs = [] for _obj, _pt in _objdict[_layer]: _objs.append(_obj) PythonCAD.Generic.transfer.transfer_objects(_objs, _active_layer) finally: _image.endAction() else: tool.pushObject(_x) tool.pushObject(_y) tool.setLocation(_x, _y) tool.setHandler("motion_notify", select_motion_notify) tool.setHandler("button_press", transfer_end_button_press_cb) gtkimage.setPrompt(_('Click the second point for defining the region')) gc = gtkimage.getGC() gc.set_line_attributes(1, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) gc.set_function(gtk.gdk.INVERT) return True def transfer_object_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the objects you want to transfer to the active layer')) _tool = gtkimage.getImage().getTool() _tool.initialize() _tool.setHandler("button_press", transfer_object_button_press_cb) # # common attribute changing code # def _change_attribute(gtkimage, objlist, tool=None): _tool = gtkimage.getImage().getTool() _init = _tool.getHandler('initialize') _attr = _tool.getAttribute() _value = _tool.getValue() if len(objlist): _image = gtkimage.getImage() _image.startAction() try: for _obj in objlist: getattr(_obj, _attr)(_value) finally: _image.endAction() _tool.reset() _init(gtkimage, _tool) def change_attr_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _active_layer = _image.getActiveLayer() _pts = _active_layer.find('point', _x, _y) if len(_pts) > 0: _x, _y = _pts[0].getCoords() _x1, _y1 = tool.getLocation() _xmin = min(_x1, _x) _ymin = min(_y1, _y) _xmax = max(_x1, _x) _ymax = max(_y1, _y) _objs = [] _filter = tool.getFilter() _objtype = tool.getObjtype() for _obj in _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax): if _filter is not None: _fobj = _filter(tool, _obj) if _fobj is not None: _objs.append(_fobj) elif _objtype is not None: if isinstance(_obj, _objtype): _objs.append(_obj) else: _objs.append(_obj) _change_attribute(gtkimage, _objs, tool) return True def change_attr_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _objdict = _image.mapPoint(_x, _y, _tol, None) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: _objs = [] _objtype = tool.getObjtype() for _obj, _pt in _objdict[_active_layer]: if _objtype is None: _objs.append(_obj) else: if isinstance(_obj, _objtype): _objs.append(_obj) _change_attribute(gtkimage, _objs, tool) else: _x, _y = _image.getClosestPoint(_x, _y, tolerance=_tol) tool.setLocation(_x, _y) tool.setHandler("motion_notify", select_motion_notify) tool.setHandler("button_press", change_attr_second_button_press_cb) gtkimage.setPrompt(_('Click the second point for defining the region')) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True # # change color # def change_color_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_color_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, GraphicObject): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the items you want the color to change.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_color_dialog(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.ColorSelectionDialog(_('Set Active Color')) _dialog.set_transient_for(_window) _colorsel = _dialog.colorsel _image = gtkimage.getImage() _prev_color = _image.getOption('LINE_COLOR') _gtk_color = gtkimage.getColor(_prev_color) _colorsel.set_previous_color(_gtk_color) _colorsel.set_current_color(_gtk_color) _colorsel.set_has_palette(True) _color = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _gtk_color = _colorsel.get_current_color() _r = int(round((_gtk_color.red/65535.0) * 255.0)) _g = int(round((_gtk_color.green/65535.0) * 255.0)) _b = int(round((_gtk_color.blue/65535.0) * 255.0)) for _c in _image.getImageEntities('color'): if _c.r == _r and _c.g == _g and _c.b == _b: _color = _c break if _color is None: _color = color.Color(_r, _g, _b) _dialog.destroy() return _color # # change linetypes # def change_linetype_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_linetype_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, GraphicObject): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the items you want the linetype to change.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_linetype_dialog(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Linetype'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Linetype:')) _hbox.pack_start(_label, False, False, 0) _image = gtkimage.getImage() _clt = _image.getOption('LINE_TYPE') _linetypes = _image.getImageEntities('linetype') _idx = 0 if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_linetypes)): _lt = _linetypes[_i] if _lt is _clt: _idx = _i _widget.append_text(_lt.getName()) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_linetypes)): _lt = _linetypes[_i] if _lt is _clt: _idx = _i _item = gtk.MenuItem(_lt.getName()) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) _hbox.pack_start(_widget, True, True, 0) _dialog.show_all() _lt = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: if isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected widget: " + `type(_widget)` _lt = _linetypes[_idx] _dialog.destroy() return _lt # # change thickness # def change_thickness_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_thickness_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, GraphicObject): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the items you want the thickness to change.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_thickness_dialog(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Thickness'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Thickness:')) _hbox.pack_start(_label, False, False, 0) _thickness = gtkimage.image.getOption('LINE_THICKNESS') _adj = gtk.Adjustment(_thickness, 0.0001, 20.0, 0.1, 1.0, 1.0) _sb = gtk.SpinButton(_adj) _sb.set_digits(1) _sb.set_numeric(False) _hbox.pack_start(_sb, True, True, 0) _dialog.show_all() _t = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _t = float(_sb.get_value()) _dialog.destroy() return _t # # change the style # def change_style_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_style_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, GraphicObject): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the items you want the style to change.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_style_dialog(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Style'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Style:')) _image = gtkimage.getImage() _cst = _image.getOption('LINE_STYLE') _styles = _image.getImageEntities('style') _idx = 0 if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_styles)): _s = _styles[_i] if _s is _cst: _idx = _i _widget.append_text(_s.getName()) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_styles)): _s = _styles[_i] if _s is _cst: _idx = _i _item = gtk.MenuItem(_s.getName()) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) _hbox.pack_start(_label, False, False, 0) _hbox.pack_start(_widget, True, True, 0) _dialog.show_all() _s = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: if isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected widget: " + `type(_widget)` _s = _styles[_idx] _dialog.destroy() return _s # # Change TextBlock properties # def change_textblock_size_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_textblock_size_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, TextBlock): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the items you want the size to change.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_textblock_size_dialog(gtkimage, key): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Text Size'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Text Size:')) _hbox.pack_start(_label, False, False, 0) _size = gtkimage.image.getOption(key) _adj = gtk.Adjustment(_size, 0.0001, 400.0, 0.1, 1.0, 1.0) _sb = gtk.SpinButton(_adj) _sb.set_digits(1) _sb.set_numeric(False) _hbox.pack_start(_sb, True, True, 0) _dialog.show_all() _size = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _size = float(_sb.get_value()) _dialog.destroy() return _size def change_textblock_family_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_textblock_family_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, TextBlock): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the objects you want the family to change.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_textblock_family_dialog(gtkimage, key): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Font Family'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _families = [] for _family in _window.get_pango_context().list_families(): _families.append(_family.get_name()) _families.sort() _label = gtk.Label(_('Family:')) _family = gtkimage.image.getOption(key) _idx = 0 if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_families)): _f = _families[_i] if _f == _family: _idx = _i _widget.append_text(_f) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_families)): _f = _families[_i] if _f == _family: _idx = _i _item = gtk.MenuItem(_f) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) _hbox.pack_start(_label, False, False, 0) _hbox.pack_start(_widget, True, True, 0) _dialog.show_all() _family = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: if isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected widget: " + `type(_widget)` _family = _families[_idx] _dialog.destroy() return _family def change_textblock_weight_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_textblock_weight_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, TextBlock): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the objects you want the weight to change.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_textblock_weight_dialog(gtkimage, key): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Text Weight'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Text Weight:')) _weight = gtkimage.image.getOption(key) _idx = 0 if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() _widget.append_text(_('NORMAL')) if _weight == TextStyle.WEIGHT_NORMAL: _idx = 0 _widget.append_text(_('LIGHT')) if _weight == TextStyle.WEIGHT_LIGHT: _idx = 1 _widget.append_text(_('BOLD')) if _weight == TextStyle.WEIGHT_BOLD: _idx = 2 _widget.append_text(_('HEAVY')) if _weight == TextStyle.WEIGHT_HEAVY: _idx = 3 _widget.set_active(_idx) else: _menu = gtk.Menu() _item = gtk.MenuItem(_('NORMAL')) _menu.append(_item) if _weight == TextStyle.WEIGHT_NORMAL: _idx = 0 _item = gtk.MenuItem(_('LIGHT')) _menu.append(_item) if _weight == TextStyle.WEIGHT_LIGHT: _idx = 1 _item = gtk.MenuItem(_('BOLD')) _menu.append(_item) if _weight == TextStyle.WEIGHT_BOLD: _idx = 2 _item = gtk.MenuItem(_('HEAVY')) _menu.append(_item) if _weight == TextStyle.WEIGHT_HEAVY: _idx = 3 _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) _hbox.pack_start(_label, False, False, 0) _hbox.pack_start(_widget, True, True, 0) _dialog.show_all() _weight = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: if isinstance(_widget, gtk.ComboBox): _weight = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _weight = _widget.get_history() else: raise TypeError, "Unexpected widget: " + `type(_widget)` _dialog.destroy() return _weight def change_textblock_style_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_textblock_style_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, TextBlock): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the objects you want the style to change.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_textblock_style_dialog(gtkimage, key): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Text Style'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Text Style:')) _style = gtkimage.image.getOption(key) _idx = 0 if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() _widget.append_text(_('NORMAL')) if _style == TextStyle.FONT_NORMAL: _idx = 0 _widget.append_text(_('OBLIQUE')) if _style == TextStyle.FONT_OBLIQUE: _idx = 1 _widget.append_text(_('ITALIC')) if _style == TextStyle.FONT_ITALIC: _idx = 2 _widget.set_active(_idx) else: _menu = gtk.Menu() _item = gtk.MenuItem(_('NORMAL')) _menu.append(_item) if _style == TextStyle.FONT_NORMAL: _idx = 0 _item = gtk.MenuItem(_('OBLIQUE')) _menu.append(_item) if _style == TextStyle.FONT_OBLIQUE: _idx = 1 _item = gtk.MenuItem(_('ITALIC')) _menu.append(_item) if _style == TextStyle.FONT_ITALIC: _idx = 2 _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) _hbox.pack_start(_label, False, False, 0) _hbox.pack_start(_widget, True, True, 0) _dialog.show_all() _style = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: if isinstance(_widget, gtk.ComboBox): _style = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _style = _widget.get_history() else: raise TypeError, "Unexpected widget: " + `type(_widget)` _dialog.destroy() return _style def change_textblock_alignment_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_textblock_alignment_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, TextBlock): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the objects you want the alignment to change.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_textblock_alignment_dialog(gtkimage, key): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Text Alignment'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Text Alignment:')) _align = gtkimage.image.getOption(key) _idx = 0 if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() _widget.append_text(_('LEFT')) if _align == TextStyle.ALIGN_LEFT: _idx = 0 _widget.append_text(_('CENTER')) if _align == TextStyle.ALIGN_CENTER: _idx = 1 _widget.append_text(_('RIGHT')) if _align == TextStyle.ALIGN_RIGHT: _idx = 2 _widget.set_active(_idx) else: _menu = gtk.Menu() _item = gtk.MenuItem(_('LEFT')) _menu.append(_item) if _align == TextStyle.ALIGN_LEFT: _idx = 0 _item = gtk.MenuItem(_('CENTER')) _menu.append(_item) if _align == TextStyle.ALIGN_CENTER: _idx = 1 _item = gtk.MenuItem(_('RIGHT')) _menu.append(_item) if _align == TextStyle.ALIGN_RIGHT: _idx = 2 _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) _hbox.pack_start(_label, False, False, 0) _hbox.pack_start(_widget, True, True, 0) _dialog.show_all() _align = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: if isinstance(_widget, gtk.ComboBox): _align = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _align = _widget.get_history() else: raise TypeError, "Unexpected widget: " + `type(_widget)` _dialog.destroy() return _align def change_textblock_color_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_textblock_color_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, TextBlock): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the objects you want the color to change.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_textblock_color_dialog(gtkimage, key): _window = gtkimage.getWindow() _dialog = gtk.ColorSelectionDialog(_('Change Font Color')) _dialog.set_transient_for(_window) _colorsel = _dialog.colorsel _image = gtkimage.getImage() _color = _image.getOption(key) _gtk_color = gtkimage.getColor(_color) _colorsel.set_previous_color(_gtk_color) _colorsel.set_current_color(_gtk_color) _colorsel.set_has_palette(True) _color = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _gtk_color = _colorsel.get_current_color() _r = int(round((_gtk_color.red/65535.0) * 255.0)) _g = int(round((_gtk_color.green/65535.0) * 255.0)) _b = int(round((_gtk_color.blue/65535.0) * 255.0)) for _c in _image.getImageEntities('color'): if _c.r == _r and _c.g == _g and _c.b == _b: _color = _c break if _color is None: _color = color.Color(_r, _g, _b) _dialog.destroy() return _color # # Change Dimension Properties # def change_dim_offset_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dim_offset_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, Dimension): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the dimension you want the offset to change.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_dim_offset_dialog(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Offset Length'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Length:')) _hbox.pack_start(_label, False, False, 0) _offset = gtkimage.image.getOption('DIM_OFFSET') _adj = gtk.Adjustment(_offset, 0.01, 200.0, 0.1, 1.0, 1.0) _sb = gtk.SpinButton(_adj) _sb.set_digits(2) _sb.set_numeric(False) _hbox.pack_start(_sb, True, True, 0) _dialog.show_all() _offset = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _offset = float(_sb.get_value()) _dialog.destroy() return _offset def change_dim_extension_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dim_extension_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, Dimension): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the dimension you want the extension to change.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_dim_extension_dialog(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Extension Length'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Length:')) _hbox.pack_start(_label, False, False, 0) _extlen = gtkimage.image.getOption('DIM_EXTENSION') _adj = gtk.Adjustment(_extlen, 0.01, 200.0, 0.1, 1.0, 1.0) _sb = gtk.SpinButton(_adj) _sb.set_digits(2) _sb.set_numeric(False) _hbox.pack_start(_sb, True, True, 0) _dialog.show_all() _extlen = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _extlen = float(_sb.get_value()) _dialog.destroy() return _extlen def change_dim_endpoint_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dim_endpoint_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, Dimension): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the dimension you want the endpoint type to change.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_dim_endpoint_dialog(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Endpoint Markers'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Endpoints:')) _endpt = gtkimage.image.getOption('DIM_ENDPOINT') _idx = 0 if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() _widget.append_text(_('None')) if _endpt == Dimension.DIM_ENDPT_NONE: _idx = 0 _widget.append_text(_('Arrow')) if _endpt == Dimension.DIM_ENDPT_ARROW: _idx = 1 _widget.append_text(_('Filled Arrow')) if _endpt == Dimension.DIM_ENDPT_FILLED_ARROW: _idx = 2 _widget.append_text(_('Slash')) if _endpt == Dimension.DIM_ENDPT_SLASH: _idx = 3 _widget.append_text(_('Circle')) if _endpt == Dimension.DIM_ENDPT_CIRCLE: _idx = 4 _widget.set_active(_idx) else: _menu = gtk.Menu() _item = gtk.MenuItem(_('None')) _menu.append(_item) if _endpt == Dimension.DIM_ENDPT_NONE: _idx = 0 _item = gtk.MenuItem(_('Arrow')) _menu.append(_item) if _endpt == Dimension.DIM_ENDPT_ARROW: _idx = 1 _item = gtk.MenuItem(_('Filled Arrow')) _menu.append(_item) if _endpt == Dimension.DIM_ENDPT_FILLED_ARROW: _idx = 2 _item = gtk.MenuItem(_('Slash')) _menu.append(_item) if _endpt == Dimension.DIM_ENDPT_SLASH: _idx = 3 _item = gtk.MenuItem(_('Circle')) _menu.append(_item) if _endpt == Dimension.DIM_ENDPT_CIRCLE: _idx = 4 _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) _hbox.pack_start(_label, False, False, 0) _hbox.pack_start(_widget, True, True, 0) _dialog.show_all() _endpt = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: if isinstance(_widget, gtk.ComboBox): _endpt = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _endpt = _widget.get_history() else: raise TypeError, "Unexpected widget: " + `type(_widget)` _dialog.destroy() return _endpt def change_dim_endpoint_size_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dim_endpoint_size_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, Dimension): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the dimension you want the endpoint size to change.')) tool.setHandler("button_press", change_attr_first_button_press_cb) def change_dim_endpoint_size_dialog(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Endpoint Size'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Length:')) _hbox.pack_start(_label, False, False, 0) _size = gtkimage.image.getOption('DIM_ENDPOINT_SIZE') _adj = gtk.Adjustment(_size, 0.01, 200.0, 0.1, 1.0, 1.0) _sb = gtk.SpinButton(_adj) _sb.set_digits(2) _sb.set_numeric(False) _hbox.pack_start(_sb, True, True, 0) _dialog.show_all() _size = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _size = float(_sb.get_value()) _dialog.destroy() return _size def change_dim_dual_mode_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dim_dual_mode_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, Dimension): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the dimension you want to change the dual dimension display.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_dim_dual_mode_dialog(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Dual Mode'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _cb = gtk.CheckButton(_('Display Two Dimension Values')) _mode = gtkimage.image.getOption('DIM_DUAL_MODE') _cb.set_active(_mode) _hbox.pack_start(_cb, True, True, 0) _dialog.show_all() _mode = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _mode = _cb.get_active() _dialog.destroy() return _mode def change_dim_dual_mode_offset_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dim_dual_mode_offset_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, Dimension): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the dimension you want to change the dual dimension offset value.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_dim_dual_mode_offset_dialog(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Dual Mode Offset'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Length:')) _hbox.pack_start(_label, False, False, 0) _offset = gtkimage.image.getOption('DIM_DUAL_MODE_OFFSET') _adj = gtk.Adjustment(_offset, 0.01, 200.0, 0.1, 1.0, 1.0) _sb = gtk.SpinButton(_adj) _sb.set_digits(2) _sb.set_numeric(False) _hbox.pack_start(_sb, True, True, 0) _dialog.show_all() _offset = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _offset = float(_sb.get_value()) _dialog.destroy() return _offset def change_dim_thickness_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dim_thickness_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, Dimension): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the dimension you want to change the thickess.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_dim_thickness_dialog(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Dim Thickness'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Thickness:')) _hbox.pack_start(_label, False, False, 0) _t = gtkimage.image.getOption('DIM_THICKNESS') _adj = gtk.Adjustment(_t, 0.01, 200.0, 0.1, 1.0, 1.0) _sb = gtk.SpinButton(_adj) _sb.set_digits(2) _sb.set_numeric(False) _hbox.pack_start(_sb, True, True, 0) _dialog.show_all() _t = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _t = float(_sb.get_value()) _dialog.destroy() return _t def change_dim_color_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dim_color_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, Dimension): _objs.append(_obj) _change_attribute(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the dimension you want to change the color.')) _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_dim_color_dialog(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.ColorSelectionDialog(_('Change Dimension Color')) _dialog.set_transient_for(_window) _colorsel = _dialog.colorsel _image = gtkimage.getImage() _color = _image.getOption('DIM_COLOR') _gtk_color = gtkimage.getColor(_color) _colorsel.set_previous_color(_gtk_color) _colorsel.set_current_color(_gtk_color) _colorsel.set_has_palette(True) _color = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _gtk_color = _colorsel.get_current_color() _r = int(round((_gtk_color.red/65535.0) * 255.0)) _g = int(round((_gtk_color.green/65535.0) * 255.0)) _b = int(round((_gtk_color.blue/65535.0) * 255.0)) for _c in _image.getImageEntities('color'): if _c.r == _r and _c.g == _g and _c.b == _b: _color = _c break if _color is None: _color = color.Color(_r, _g, _b) _dialog.destroy() return _color # # Change DimString properties # def _dimstring_filter_proc(tool, obj): _ds = None if isinstance(obj, Dimension): if tool.getPrimary(): _ds = obj.getPrimaryDimstring() else: _ds = obj.getSecondaryDimstring() return _ds def _ldimstring_filter_proc(tool, obj): _ds = None if isinstance(obj, (LinearDimension, HorizontalDimension, VerticalDimension)): if tool.getPrimary(): _ds = obj.getPrimaryDimstring() else: _ds = obj.getSecondaryDimstring() return _ds def _rdimstring_filter_proc(tool, obj): _ds = None if isinstance(obj, RadialDimension): if tool.getPrimary(): _ds = obj.getPrimaryDimstring() else: _ds = obj.getSecondaryDimstring() return _ds def _adimstring_filter_proc(tool, obj): _ds = None if isinstance(obj, AngularDimension): if tool.getPrimary(): _ds = obj.getPrimaryDimstring() else: _ds = obj.getSecondaryDimstring() return _ds def change_dimstr_prefix_dialog(gtkimage, key): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Prefix'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Prefix:')) _hbox.pack_start(_label, True, True, 0) _prefix = gtkimage.image.getOption(key) _entry = gtk.Entry() _entry.set_text(_prefix) _hbox.pack_start(_entry, True, True, 0) _dialog.show_all() _prefix = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _prefix = _entry.get_text() _dialog.destroy() return _prefix def change_dimstr_suffix_dialog(gtkimage, key): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Suffix'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Suffix:')) _hbox.pack_start(_label, True, True, 0) _suffix = gtkimage.image.getOption(key) _entry = gtk.Entry() _entry.set_text(_suffix) _hbox.pack_start(_entry, True, True, 0) _dialog.show_all() _suffix = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _suffix = _entry.get_text() _dialog.destroy() return _suffix def change_dimstr_precision_dialog(gtkimage, key): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Precision'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Precision:')) _hbox.pack_start(_label, False, False, 0) _prec = gtkimage.image.getOption(key) _adj = gtk.Adjustment(_prec, 0, 15, 1, 1, 1) _sb = gtk.SpinButton(_adj) _sb.set_digits(0) _sb.set_numeric(True) _hbox.pack_start(_sb, True, True, 0) _dialog.show_all() _prec = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _prec = int(_sb.get_value()) _dialog.destroy() return _prec def change_dimstr_units_dialog(gtkimage, key): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Units'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Units')) _hbox.pack_start(_label, False, False, 0) _units = [(_('Millimeters'), PythonCAD.Generic.units.MILLIMETERS), (_('Micrometers'), PythonCAD.Generic.units.MICROMETERS), (_('Meters'), PythonCAD.Generic.units.METERS), (_('Kilometers'), PythonCAD.Generic.units.KILOMETERS), (_('Inches'), PythonCAD.Generic.units.INCHES), (_('Feet'), PythonCAD.Generic.units.FEET), (_('Yards'), PythonCAD.Generic.units.YARDS), (_('Miles'), PythonCAD.Generic.units.MILES), ] _unit = gtkimage.image.getOption(key) _idx = 0 if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _unit_widget = gtk.combo_box_new_text() for _i in range(len(_units)): _str, _val = _units[_i] if _unit == _val: _idx = _i _unit_widget.append_text(_str) _unit_widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_units)): _str, _val = _units[_i] if _unit == _val: _idx = _i _item = gtk.MenuItem(_str) _menu.append(_item) _unit_widget = gtk.OptionMenu() _unit_widget.set_menu(_menu) _unit_widget.set_history(_idx) _hbox.pack_start(_unit_widget, True, True, 0); _dialog.show_all() _unit = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _idx = _unit_widget.get_active() else: _idx = _unit_widget.get_history() _unit = _units[_idx][1] _dialog.destroy() return _unit def change_dimstr_print_decimal_dialog(gtkimage, key): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Print Decimal'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _cb = gtk.CheckButton(_('Print Trailing Decimal')) _mode = gtkimage.image.getOption(key) _cb.set_active(_mode) _hbox.pack_start(_cb, True, True, 0) _dialog.show_all() _mode = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _mode = _cb.get_active() _dialog.destroy() return _mode def change_dimstr_print_zero_dialog(gtkimage, key): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Change Print Zero'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _cb = gtk.CheckButton(_('Print Leading Zero')) _mode = gtkimage.image.getOption(key) _cb.set_active(_mode) _hbox.pack_start(_cb, True, True, 0) _dialog.show_all() _mode = None _response = _dialog.run() if _response == gtk.RESPONSE_OK: _mode = _cb.get_active() _dialog.destroy() return _mode def _change_dimstring_init(gtkimage, tool=None): _image = gtkimage.getImage() _tool = _image.getTool() if _image.hasSelection(): _primary = tool.getPrimary() _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, Dimension): if _primary: _objs.append(_obj.getPrimaryDimstring()) else: _objs.append(_obj.getSecondaryDimstring()) _change_attribute(gtkimage, _objs, _tool) else: _tool.setHandler("button_press", change_attr_first_button_press_cb) def change_dimstr_family_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the dimension you want to change the DimString family.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dimstr_family_init) _tool.setFilter(_dimstring_filter_proc) _change_dimstring_init(gtkimage) def change_dimstr_style_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the dimension you want to change the DimString style.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dimstr_style_init) _tool.setFilter(_dimstring_filter_proc) _change_dimstring_init(gtkimage) def change_dimstr_weight_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the dimension you want to change the DimString weight.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dimstr_weight_init) _tool.setFilter(_dimstring_filter_proc) _change_dimstring_init(gtkimage) def change_dimstr_alignment_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the dimension you want to change the DimString alignment.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dimstr_alignment_init) _tool.setFilter(_dimstring_filter_proc) _change_dimstring_init(gtkimage) def change_dimstr_size_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the dimension you want to change the DimString size.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dimstr_size_init) _tool.setFilter(_dimstring_filter_proc) _change_dimstring_init(gtkimage) def change_dimstr_color_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the dimension you want to change the DimString color.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dimstr_color_init) _tool.setFilter(_dimstring_filter_proc) _change_dimstring_init(gtkimage) def change_ldimstr_prefix_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the dimension you want to change the DimString prefix.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_ldimstr_prefix_init) _tool.setFilter(_ldimstring_filter_proc) _change_dimstring_init(gtkimage) def change_ldimstr_suffix_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the dimension you want to change the DimString suffix.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_ldimstr_suffix_init) _tool.setFilter(_ldimstring_filter_proc) _change_dimstring_init(gtkimage) def change_rdimstr_prefix_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the RadialDimension you want to change the DimString prefix.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_rdimstr_prefix_init) _tool.setFilter(_rdimstring_filter_proc) _change_dimstring_init(gtkimage) def change_rdimstr_suffix_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the RadialDimension you want to change the DimString suffix.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_rdimstr_suffix_init) _tool.setFilter(_rdimstring_filter_proc) _change_dimstring_init(gtkimage) def change_adimstr_prefix_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the AngularDimension you want to change the DimString prefix.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_adimstr_prefix_init) _tool.setFilter(_adimstring_filter_proc) _change_dimstring_init(gtkimage) def change_adimstr_suffix_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the AngularDimension you want to change the DimString suffix.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_adimstr_suffix_init) _tool.setFilter(_adimstring_filter_proc) _change_dimstring_init(gtkimage) def change_dimstr_precision_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the dimension you want to change the DimString precision.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dimstr_precision_init) _tool.setFilter(_dimstring_filter_proc) _change_dimstring_init(gtkimage) def change_dimstr_units_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the dimension you want to change the DimString units.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dimstr_units_init) _tool.setFilter(_dimstring_filter_proc) _change_dimstring_init(gtkimage) def change_dimstr_print_zero_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the dimension you want to change the DimString print leading zero flag.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dimstr_print_zero_init) _tool.setFilter(_dimstring_filter_proc) _change_dimstring_init(gtkimage) def change_dimstr_print_decimal_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click the dimension you want to change the DimString print trailing decimal flag.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_dimstr_print_decimal_init) _tool.setFilter(_dimstring_filter_proc) _change_dimstring_init(gtkimage) def _change_rdim_dia_mode(gtkimage, objlist, tool): _init = tool.getHandler('initialize') if len(objlist): _image = gtkimage.getImage() _image.startAction() try: for _obj in objlist: _mode = not _obj.getDiaMode() _obj.setDiaMode(_mode) finally: _image.endAction() tool.reset() _init(gtkimage) def _rdim_dia_mode_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _active_layer = _image.getActiveLayer() _pts = _active_layer.find('point', _x, _y) if len(_pts) > 0: _x, _y = _pts[0].getCoords() _x1, _y1 = tool.getLocation() _xmin = min(_x1, _x) _ymin = min(_y1, _y) _xmax = max(_x1, _x) _ymax = max(_y1, _y) _objs = [] for _obj in _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax): if isinstance(_obj, RadialDimension): _objs.append(_obj) _change_rdim_dia_mode(gtkimage, _objs, tool) return True def _rdim_dia_mode_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _objdict = _image.mapPoint(_x, _y, _tol, None) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: _objs = [] for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, RadialDimension): _objs.append(_obj) _change_rdim_dia_mode(gtkimage, _objs, tool) else: _x, _y = _image.getClosestPoint(_x, _y, tolerance=_tol) tool.setLocation(_x, _y) tool.setHandler("motion_notify", select_motion_notify) tool.setHandler("button_press", _rdim_dia_mode_second_button_press_cb) gtkimage.setPrompt(_('Click the second point for defining the region')) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True def change_rdim_dia_mode_init(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", change_rdim_dia_mode_init) _image = gtkimage.getImage() if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, RadialDimension): _objs.append(_obj) _change_rdim_dia_mode(gtkimage, _objs, tool) else: gtkimage.setPrompt(_('Click the RadialDimensions to toggle diameter dimension display')) _tool.setHandler("button_press", _rdim_dia_mode_first_button_press_cb) def _invert_adim(gtkimage, objlist, tool): _init = tool.getHandler('initialize') if len(objlist): _image = gtkimage.getImage() _image.startAction() try: for _obj in objlist: _obj.invert() finally: _image.endAction() tool.reset() _init(gtkimage) def _invert_adim_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _active_layer = _image.getActiveLayer() _pts = _active_layer.find('point', _x, _y) if len(_pts) > 0: _x, _y = _pts[0].getCoords() _x1, _y1 = tool.getLocation() _xmin = min(_x1, _x) _ymin = min(_y1, _y) _xmax = max(_x1, _x) _ymax = max(_y1, _y) _objs = [] for _obj in _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax): if isinstance(_obj, AngularDimension): _objs.append(_obj) _invert_adim(gtkimage, _objs, tool) return True def _invert_adim_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _objdict = _image.mapPoint(_x, _y, _tol, None) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: _objs = [] for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, AngularDimension): _objs.append(_obj) _invert_adim(gtkimage, _objs, tool) else: _x, _y = _image.getClosestPoint(_x, _y, tolerance=_tol) tool.setLocation(_x, _y) tool.setHandler("motion_notify", select_motion_notify) tool.setHandler("button_press", _invert_adim_second_button_press_cb) gtkimage.setPrompt(_('Click the second point for defining the region')) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True def invert_adim_init(gtkimage, tool=None): _image = gtkimage.getImage() _tool = _image.getTool() _tool.setHandler("initialize", invert_adim_init) if _image.hasSelection(): _objs = [] for _obj in _image.getSelectedObjects(): if isinstance(_obj, AngularDimension): _objs.append() _invert_adim(gtkimage, _objs, _tool) else: gtkimage.setPrompt(_('Click the AngularDimensions to be inverted')) _tool.setHandler("button_press", _invert_adim_first_button_press_cb) # # arbitrary zoom # def zoom_end_button_press_cb(gtkimage, widget, event, tool): _xp, _yp = gtkimage.image.getCurrentPoint() _x1, _y1 = tool.getLocation() _xmin = min(_xp, _x1) _ymin = min(_yp, _y1) _width, _height = gtkimage.getSize() _fw = float(_width) _fh = float(_height) _wpp = abs(_x1 - _xp)/_fw _hpp = abs(_y1 - _yp)/_fh if _wpp > _hpp: _scale = _wpp else: _scale = _hpp gtkimage.setView(_xmin, _ymin, _scale) zoom_init(gtkimage) return True def zoom_motion_notify(gtkimage, widget, event, tool): _tx, _ty = tool.getLocation() _px, _py = gtkimage.coordToPixTransform(_tx, _ty) # width, height = gtkimage.getSize() _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _cp = tool.getCurrentPoint() # # it would be nice to draw the rectangle in the current # shape of the window ... # if _cp is not None: _xc, _yc = _cp _xmin = min(_px, _xc) _ymin = min(_py, _yc) _rw = abs(_xc - _px) _rh = abs(_yc - _py) widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _rw, _rh) _xmin = min(_x, _px) _ymin = min(_y, _py) tool.setCurrentPoint(_x, _y) _rw = abs(_x - _px) _rh = abs(_y - _py) widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _rw, _rh) return True def zoom_button_press_cb(gtkimage, widget, event, tool): _x, _y = gtkimage.image.getCurrentPoint() tool.setLocation(_x, _y) tool.setHandler("motion_notify", zoom_motion_notify) tool.setHandler("button_press", zoom_end_button_press_cb) gtkimage.setPrompt(_('Click a second point to define the zoom window')) _gc = gtkimage.getGC() _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER) _gc.set_function(gtk.gdk.INVERT) return True def zoom_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the window.')) _tool = gtkimage.getImage().getTool() _tool.initialize() _tool.setHandler("button_press", zoom_button_press_cb) # # Pan Zoom # def zoomPan_init(gtkimage, tool=None): gtkimage.setPrompt(_('Press Left Mause Button To Make Pan')) _tool = gtkimage.getImage().getTool() _tool.initialize() _tool.setHandler("button_press", zoomPan_button_press_cb) def zoomPan_button_press_cb(gtkimage, widget, event, tool): gtkimage.setPrompt(_('Press Right Mause Button To Stop Pan')) if(gtkimage.isPan()): gtkimage.StopPanImage() else: gtkimage.StartPanImage() return True PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkshell.py0000644000175000017500000007440711307666657021613 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # the GTK code for displaying a drawing # import types import pygtk pygtk.require('2.0') import gtk import gobject from PythonCAD.Generic import image from PythonCAD.Generic import layer from PythonCAD.Generic import util _debug = False class LayerDisplay(object): def __init__(self, im, win): """ This class defines the layer display graphic on the left side of the window. The calling arg should be a member of the image class. """ if _debug is True: print "SDB debug: instantiated another LayerDisplay class instance" if not isinstance(im, image.Image): raise TypeError, "Invalid Image type: " + `type(im)` if not isinstance(win, gtk.Window): raise TypeError, "Invalid Window type: " + `type(win)` _sw = gtk.ScrolledWindow() _sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) _model = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT) # _model.connect("rows-reordered", self.__reordered) _iter = _model.append(None) _layer = im.getTopLayer() _layer.connect('visibility_changed', self.__layerVisibilityChanged) _layer.connect('name_changed', self.__layerNameChanged) _model.set(_iter, 0, _layer.getName()) _model.set(_iter, 1, _layer) _tv = gtk.TreeView(_model) _tv.set_reorderable(True) # drag-and-drop _tv.set_search_column(0) _tv.connect("button_press_event", self.__treeViewButtonPress) _select = _tv.get_selection() _select.set_mode(gtk.SELECTION_SINGLE) _select.connect("changed", self.__selectionChanged) _renderer = gtk.CellRendererText() # _renderer.set_property("editable", True) _renderer.connect("edited", self.__cellEdited) _column = gtk.TreeViewColumn(_('Layers'), _renderer, text=0) _tv.append_column(_column) _sw.add(_tv) self.__image = im self.__window = win self.__sw = _sw self.__model = _model self.__treeview = _tv self.__layer = None # # establish messages connections # im.connect('active_layer_changed', self.__activeLayerChanged) im.connect('added_child', self.__imageAddedChild) im.connect('removed_child', self.__imageRemovedChild) _layers = [im.getTopLayer()] while len(_layers): _layer = _layers.pop() self.__layer = _layer self.__model.foreach(self.__modelAddLayer) _layer.connect('visibility_changed', self.__layerVisibilityChanged) _layer.connect('name_changed', self.__layerNameChanged) _layers.extend(_layer.getSublayers()) def __treeViewButtonPress(self, widget, event, data=None): _button = event.button _x = int(event.x) _y = int(event.y) _rv = event.window is widget.get_bin_window() and _button == 3 if _rv: _menu = self.__makePopupMenu(widget, _x, _y) if _menu is not None: _menu.popup(None, None, None, _button, event.time) return _rv def __makePopupMenu(self, widget, x, y): # print "Entered LayerDisplay._makePopupMenu" _data = widget.get_path_at_pos(x, y) if _data is None: return None _path, _col, _cx, _cy = _data _model = widget.get_model() _iter = _model.get_iter(_path) _layer = _model.get_value(_iter, 1) # _menu = gtk.Menu() _item = gtk.MenuItem(_('Rename')) _item.connect("activate", self.__renameLayer) _menu.append(_item) if _layer.isVisible(): _item = gtk.MenuItem(_('Hide')) _flag = False else: _item = gtk.MenuItem(_('Show')) _flag = True _item.connect("activate", self.__setLayerVisibility, _flag) _menu.append(_item) _item = gtk.MenuItem(_('Add Child Layer')) _item.connect("activate", self.__addChildLayer) _menu.append(_item) if _layer.hasSublayers(): _item = gtk.MenuItem(_('Hide Children')) _item.connect("activate", self.__setChildrenVisibility, False) _menu.append(_item) _item = gtk.MenuItem(_('Show Children')) _item.connect("activate", self.__setChildrenVisibility, True) _menu.append(_item) else: if _layer.getParentLayer() is not None: if not _layer.hasSublayers(): _item = gtk.MenuItem(_('Delete')) _item.connect("activate", self.__deleteLayer) _menu.append(_item) _item = gtk.MenuItem(_('Clear Layer')) _item.connect("activate", self.__clearLayer) _menu.append(_item) _menu.show_all() self.__layer = _layer return _menu def __selectionChanged(self, selection, data=None): if selection is not None: _model, _iter = selection.get_selected() if _iter is not None: _layer = _model.get_value(_iter, 1) self.__image.setActiveLayer(_layer) def __cellEdited(self, cell_renderer, path, text): _model = self.__model _iter = _model.get_iter_from_string(path) _layer = _model.get_value(_iter, 1) _layer.setName(text) _model.set(_iter, 0, text) def __reordered(self, model, path, iter, new_order): print "in reordered()" print "model: " + `model` print "path: " + `path` print "iter: " + `iter` print "new_order: " + `new_order` def __modelFindLayer(self, iter=None): # print "_modelFindLayer() ..." _model = self.__model _iter = iter if _iter is None: _iter = _model.get_iter_first() _layer = self.__layer _path = None _mlayer = _model.get_value(_iter, 1) if _mlayer is _layer: _path = _model.get_path(_iter) else: if _model.iter_has_child(_iter): _child = _model.iter_children(_iter) while _child is not None: _path = self.__modelFindLayer(_child) if _path is not None: break _child = _model.iter_next(_child) return _path def __modelAddLayer(self, model, path, iter): # print "_modelAddLayer() ..." _layer = self.__layer _mlayer = model.get_value(iter, 1) _val = _mlayer is _layer.getParentLayer() if _val: _iter = model.append(iter) model.set(_iter, 0, _layer.getName()) model.set(_iter, 1, _layer) return _val def __imageAddedChild(self, obj, *args): # print "__imageAddedChild()" _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _newlayer = args[0] self.__layer = _newlayer self.__model.foreach(self.__modelAddLayer) _path = self.__modelFindLayer() if _path is None: raise ValueError, "Layer not found in model!" _ppath = _path[:-1] _tv = self.__treeview while len(_ppath): if not _tv.row_expanded(_ppath): _tv.expand_row(_ppath, False) _ppath = _ppath[:-1] _tv.get_selection().select_path(_path) _newlayer.connect('visibility_changed', self.__layerVisibilityChanged) _newlayer.connect('name_changed', self.__layerNameChanged) def __modelDeleteLayer(self, model, path, iter): # print "_modelDeleteLayer() ..." _mlayer = model.get_value(iter, 1) _val = _mlayer is self.__layer if _val: model.remove(iter) return _val def __imageRemovedChild(self, obj, *args): # print "__imageRemovedChild()" _path = self.__modelFindLayer() if _path is None: raise ValueError, "Layer not found in model!" _ppath = _path[:-1] _tv = self.__treeview while len(_ppath): if not _tv.row_expanded(_ppath): _tv.expand_row(_ppath, False) _ppath = _ppath[:-1] self.__model.foreach(self.__modelDeleteLayer) self.__layer.disconnect(self) _tv.get_selection().select_path(_path[:-1]) def __modelDisconnectLayer(self, model, path, iter): # print "__modelDisconnnectLayer() ..." _layer = model.get_value(iter, 1) _layer.disconnect(self) return False def __activeLayerChanged(self, obj, *args): # print "_activeLayerChanged()" self.__layer = obj.getActiveLayer() _path = self.__modelFindLayer() if _path is None: raise ValueError, "Layer not found in model!" _ppath = _path[:-1] _tv = self.__treeview while len(_ppath): if not _tv.row_expanded(_ppath): _tv.expand_row(_ppath, False) _ppath = _ppath[:-1] _tv.get_selection().select_path(_path) def __layerVisibilityChanged(self, obj, *args): # print "_layerVisibilityChanged()" for _obj in obj.getLayerEntities('point'): if _obj.isVisible(): _obj.sendMessage('refresh') _ctypes = ['hcline', 'vcline', 'acline', 'cline', 'ccircle'] for _ctype in _ctypes: for _obj in obj.getLayerEntities(_ctype): if _obj.isVisible(): _obj.sendMessage('refresh') _gtypes = ['segment', 'circle', 'arc', 'leader', 'polyline', 'chamfer', 'fillet', 'textblock', 'linear_dimension', 'horizontal_dimension', 'vertical_dimension', 'radial_dimension', 'angular_dimension'] for _gtype in _gtypes: for _obj in obj.getLayerEntities(_gtype): if _obj.isVisible(): _obj.sendMessage('refresh') def __modelRenameLayer(self, model, path, iter): _layer = self.__layer _mlayer = model.get_value(iter, 1) _val = _mlayer is _layer if _val: model.set(iter, 0, _layer.getName()) return _val def __layerNameChanged(self, obj, *args): self.__layer = obj self.__model.foreach(self.__modelRenameLayer) def __setLayerVisibility(self, menuitem, data=None): _image = self.__image _image.startAction() try: self.__layer.setVisibility(data) finally: _image.endAction() return False def __setChildrenVisibility(self, menuitem, data=None): _image = self.__image _image.startAction() try: _layers = self.__layer.getSublayers() while len(_layers): _layer = _layers.pop() _layer.setVisibility(data) _layers.extend(_layer.getSublayers()) finally: _image.endAction() return False def __deleteLayer(self, menuitem, data=None): _image = self.__image _layer = self.__layer _image.startAction() try: if _layer.hasChildren(): _layer.clear() _image.delLayer(_layer) _layer.finish() finally: _image.endAction() self.__layer = None return False def __clearLayer(self, menuitem, data=None): _image = self.__image _image.startAction() try: self.__layer.clear() finally: _image.endAction() return False def __addChildLayer(self, menuitem, data=None): if _debug is True: print "SDB Debug: entered LayerDisplay.addChildLayer()..." _window = self.__window _dialog = gtk.Dialog(_('Add New Child Layer'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Name:')) _hbox.pack_start(_label, False, False, 0) _entry = gtk.Entry() _entry.set_text(_('NewChildLayer')) _hbox.pack_start(_entry, True, True, 0) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: _name = _entry.get_text() if len(_name): _new_layer = layer.Layer(_name) _image = self.__image _image.startAction() try: _image.addChildLayer(_new_layer, self.__layer) finally: _image.endAction() _dialog.destroy() return False def __renameLayer(self, menuitem, data=None): if _debug is True: print "SDB debug: entered _renameLayer()" _layer = self.__layer _name = _layer.getName() _window = self.__window _dialog = gtk.Dialog(_('Rename Layer'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Name:')) _hbox.pack_start(_label, False, False, 0) _entry = gtk.Entry() _entry.set_text(_name) _hbox.pack_start(_entry, True, True, 0) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: _new_name = _entry.get_text() if len(_new_name): _image = self.__image _image.startAction() try: _layer.setName(_new_name) finally: _image.endAction() _dialog.destroy() return False def close(self): self.__model.foreach(self.__modelDisconnectLayer) self.__image.disconnect(self) self.__image = None self.__window = None self.__sw = None self.__model = None self.__treeview = None self.__layer = None def getWindow(self): return self.__sw class ImageView(object): def __init__(self, im, xmin=0.0, ymax=0.0, upp=1.0): if _debug is True: print "SDB debug: Created new ImageView class instance" if not isinstance(im, image.Image): raise TypeError, "Invalid Image type: " + `type(im)` _xmin = util.get_float(xmin) _ymax = util.get_float(ymax) _upp = util.get_float(upp) if not _upp > 0.0: raise ValueError, "Invalid units-per-pixel value: %g" % _upp self.__image = im self.__pixmap = None self.__gc = None self.__width = None self.__height = None _da = gtk.DrawingArea() _da.set_size_request(100, 100) _black = gtk.gdk.color_parse('black') _da.modify_fg(gtk.STATE_NORMAL, _black) _da.modify_bg(gtk.STATE_NORMAL, _black) _da.set_flags(gtk.CAN_FOCUS) _da.connect("expose_event", self.__exposeEvent) _da.connect("realize", self.__realizeEvent) _da.connect("configure_event", self.__configureEvent) _da.connect("key_press_event", self.__keyPressEvent) _da.connect("key_release_event", self.__keyPressEvent) _da.connect("enter_notify_event", self.__elNotifyEvent) _da.connect("leave_notify_event", self.__elNotifyEvent) _da.connect("focus_in_event", self.__focusChangedEvent) _da.connect("focus_out_event", self.__focusChangedEvent) _da.set_events(gtk.gdk.EXPOSURE_MASK | gtk.gdk.LEAVE_NOTIFY_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.ENTER_NOTIFY_MASK| gtk.gdk.LEAVE_NOTIFY_MASK| gtk.gdk.KEY_PRESS_MASK | gtk.gdk.KEY_RELEASE_MASK | gtk.gdk.FOCUS_CHANGE_MASK | gtk.gdk.POINTER_MOTION_MASK) self.__da = _da self.__xmin = _xmin self.__ymax = _ymax self.__upp = _upp self.__view = None im.connect('added_child', self.__imageAddedChild) im.connect('removed_child', self.__imageRemovedChild) im.connect('modified', self.__objModified) def __realizeEvent(self, widget, data=None): _win = widget.window _w, _h = _win.get_size() self.__width = _w self.__height = _h _gc = _win.new_gc() _gc.set_exposures(True) self.__gc = _gc def __exposeEvent(self, widget, event, data=None): _pixmap = self.__pixmap _x, _y, _w, _h = event.area _gc = widget.get_style().fg_gc[gtk.STATE_NORMAL] widget.window.draw_drawable(_gc, _pixmap, _x, _y, _x, _y, _w, _h) return True def __configureEvent(self, widget, event, data=None): _win = widget.window _w, _h = _win.get_size() if self.__width != _w or self.__height != _h: self.__view = None self.__width = _w self.__height = _h _pixmap = gtk.gdk.Pixmap(_win, _w, _h) _gc = widget.get_style().fg_gc[gtk.STATE_NORMAL] _pixmap.draw_rectangle(_gc, True, 0, 0, _w, _h) self.__pixmap = _pixmap return True def __focusChangedEvent(self, widget, event, data=None): return False def __buttonPressEvent(self, widget, event, data=None): _rv = False _tool = gtkimage.getTool() gtkimage.setToolpoint(event) if (event.button == 1 and _tool is not None and _tool.hasHandler('button_press')): _rv = _tool.getHandler('button_press')(gtkimage, widget, event, _tool) return _rv def __buttonReleaseEvent(self, widget, event, data=None): _rv = False _tool = gtkimage.getTool() gtkimage.setToolpoint(event) if (event.button == 1 and _tool is not None and _tool.hasHandler('button_release')): _rv = _tool.getHandler('button_release')(gtkimage, widget, event, _tool) return _rv def __keyPressEvent(self, widget, event, data=None): _key = event.keyval _rv = (_key == gtk.keysyms.Left or _key == gtk.keysyms.Right or _key == gtk.keysyms.Up or _key == gtk.keysyms.Down) if _rv: _mods = event.state & gtk.accelerator_get_default_mod_mask() _dx = _dy = None if (_key == gtk.keysyms.Left): _dx = -1.0 elif (_key == gtk.keysyms.Right): _dx = 1.0 elif (_key == gtk.keysyms.Up): _dy = 1.0 elif (_key == gtk.keysyms.Down): _dy = -1.0 else: raise ValueError, "Unexpected keyval: %d" % _key if (_mods == gtk.gdk.CONTROL_MASK): _scale = 0.25 elif (_mods == gtk.gdk.SHIFT_MASK): _scale = 0.5 elif (_mods == gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK): _scale = 1.0 else: _scale = 0.05 if not _rv: _tool = gtkimage.getTool() if _tool is not None and _tool.hasHandler('key_press'): _rv = _tool.getHandler('key_press')(gtkimage, widget, event, _tool) return _rv def __keyReleaseEvent(self, widget, event, data=None): _rv = False _tool = gtkimage.getTool() if _tool is not None and _tool.hasHandler('key_release'): _rv = _tool.getHandler('key_release')(gtkimage, widget, event, _tool) return _rv def __motionNotifyEvent(self, widget, event, data=None): _rv = False _tool = gtkimage.getTool() gtkimage.setToolpoint(event) if _tool is not None and _tool.hasHandler('motion_notify'): _rv = _tool.getHandler('motion_notify')(gtkimage, widget, event, _tool) return _rv def __elNotifyEvent(self, widget, event, data=None): gtkimage.setToolpoint(event) return True def __drawObject(self, obj, col=None): _col = col _xmin, _ymin, _xmax, _ymax = self.getView() if obj.inRegion(_xmin, _ymin, _xmax, _ymax): _image = self.__image if _col is None: if obj.getParent() is not _image.getActiveLayer(): _col = _image.getOption('INACTIVE_LAYER_COLOR') obj.draw(self, _col) def __imageAddedChild(self, obj, *args): # print "_imageAddedChild()" _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _layer = args[0] if not isinstance(_layer, layer.Layer): raise TypeError, "Unexpected child type: " + `type(_layer)` _layer.connect('added_child', self.__layerAddedChild) _layer.connect('removed_child', self.__layerRemovedChild) def __layerAddedChild(self, obj, *args): # print "__layerAddedChild()" _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _child = args[0] # need some verification test here ... _child.connect('modified', self.__objModified) _child.connect('visibility_changed', self.__objVisibilityChanged) _child.connect('refresh', self.__refreshObject) _child.connect('change_pending', self.__objChanging) if _child.isVisible() and obj.isVisible(): self.__drawObject(_child) def __imageRemovedChild(self, obj, *args): # print "__imageRemovedChild()" _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _layer = args[0] if not isinstance(_layer, layer.Layer): raise TypeError, "Unexpected child type: " + `type(_layer)` _layer.disconnect(self) def __layerRemovedChild(self, obj, *args): # print "__layerDeletedChild()" _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _child = args[0] # need some verification test here ... if _child.isVisible() and obj.isVisible(): _color = self.__image.getOption('BACKGROUND_COLOR') self.__drawObject(_child, _color) _child.disconnect(self) def __objModified(self, obj, *args): # print "__objModified()" if obj.isVisible() and obj.getParent().isVisible(): self.__drawObject(obj) def __objChanging(self, obj, *args): # print "__objChanging()" if obj.isVisible() and obj.getParent().isVisible(): self.__drawObject(obj, self.__image.getOption('BACKGROUND_COLOR')) def __objVisibilityChanged(self, obj, *args): # print "__objVisibilityChanged()" if obj.getParent().isVisible(): _col = None if not obj.isVisible(): _col = self.__image.getOption('BACKGROUND_COLOR') self.__drawObject(obj, _col) def __refreshObject(self, obj, *args): # print "__refreshObject()" _col = None if not obj.isVisible() or not obj.getParent().isVisible(): _col = self.__image.getOption('BACKGROUND_COLOR') self.__drawObject(obj, _col) def getView(self): """Get the region of space the ImageView draws getRegion() This method returns a tuple of four values: xmin, ymin, xmax, ymax """ if self.__view is None: _xmin = self.__xmin _ymax = self.__ymax _upp = self.__upp _w = self.__width _h = self.__height _xmax = _xmin + (_upp * _w) _ymin = _ymax - (_upp * _h) self.__view = (_xmin, _ymin, _xmax, _ymax) return self.__view def getPixmap(self): """Return the gtk.gdk.Pixmap for this ImageView. getPixmap() """ return self.__pixmap def getUnitsPerPixel(self): """Return the units-per-pixel scaling factor for the ImageView. getUnitsPerPixel() """ return self.__upp def setUnitsPerPixel(self, upp): """Set the units-per-pixel scaling factor for the ImageView. setUnitsPerPixel(upp) Argument 'upp' should be a float value greater """ _upp = util.get_float(upp) if not _upp > 0.0: raise ValueError, "Invalid units-per-pixel value: %g" % _upp self.__upp = _upp self.__view = None def pixelsToCoords(self, x, y): """Convert from pixel coordinates to x-y coordinates. pixelsToCoords(x, y) Arguments 'x' and 'y' should be positive integers. This method returns a tuple of two float values """ if not isinstance(x, int): raise TypeError, "Invalid 'x' type: " + `type(x)` if x < 0: raise ValueError, "Invalid 'x' value: %d" % x if not isinstance(y, int): raise TypeError, "Invalid 'y' type: " + `type(y)` if y < 0: raise ValueError, "Invalid 'y' value: %d" % y _upp = self.__upp _xc = self.__xmin + (x * _upp) _yc = self.__ymax - (y * _upp) return _xc, _yc def coordsToPixels(self, x, y): """Convert from x-y coordinates to pixel coordinates coordsToPixels(x, y) Arguments 'x' and 'y' should be float values. This method returns a tuple holding two integer values """ _x = util.get_float(x) _y = util.get_float(y) _upp = self.__upp _xp = int((x - self.__xmin)/_upp) _yp = int((self.__ymax - y)/_upp) return _xp, _yp def close(self): self.__image.disconnect(self) def redraw(self): """This method draws all the objects visible in the ImageView. redraw() """ _da = self.__da if (_da.flags() & gtk.MAPPED): _image = self.__image _w = self.__width _h = self.__height _gc = _da.get_style().fg_gc[gtk.STATE_NORMAL] self.__pixmap.draw_rectangle(_gc, True, 0, 0, _w, _h) _active = _image.getActiveLayer() _layers = [_image.getTopLayer()] while (len(_layers)): _layer = _layers.pop() if _layer is not _active: self.drawLayer(_layer) _layers.extend(_layer.getSublayers()) self.drawLayer(_active) _da.queue_draw() # generate an expose event def drawLayer(self, l): if not isinstance(l, layer.Layer): raise TypeError, "Invalid layer type: " + `type(l)` if l.getParent() is not self.__image: raise ValueError, "Layer not found in Image" if l.isVisible(): _xmin = self.__xmin _ymax = self.__ymax _upp = self.__upp _xmax = _xmin + (_upp * _w) _ymin = _ymax - (_upp * _h) _col = self.getOption('INACTIVE_LAYER_COLOR') if l is self.getActiveLayer(): _col = None _cobjs = [] _objs = [] _pts = [] for _obj in l.objsInRegion(_xmin, _ymin, _xmax, _ymax): if _obj.isVisible(): if isinstance(_obj, Point): _pts.append(_obj) elif isinstance(_obj, ConstructionObject): _cobjs.append(_obj) else: _objs.append(_obj) for _obj in _cobjs: _obj.draw(self, _col) for _obj in _pts: _obj.draw(self, _col) for _obj in _objs: _obj.draw(self, _col) class ImageWindow(object): def __init__(self, im): if _debug is True: print "SDB debug: instantiated another ImageWindow class instance" if not isinstance(im, image.Image): raise TypeError, "Invalid Image type: " + `type(im)` self.__image = im # # Display window # _window = gtk.Window() _window.set_title("Untitled") _window.connect("destroy", self._closeImage) _width = min(1024, int(0.8 * float(gtk.gdk.screen_width()))) _height = min(768, int(0.8 * float(gtk.gdk.screen_height()))) _window.set_default_size(_width, _height) # _vbox = gtk.VBox(False, 2) _vbox.set_border_width(2) _window.add(_vbox) self.__ldisp = LayerDisplay(im) def getImage(self): """Return the Image stored in the ImageDisplay. getImage() """ return self.__image image = property(getImage, None, None, "The Image used for visualizing.") def closeImage(self, widget): """Close a window containing a Image. closeImage() """ _image = self.__image _image.close() _image.disconnect(self) self.__ldisp(close) for _i in xrange(len(globals.imagelist)): _gimage = globals.imagelist[_i] if _image is _gimage: del globals.imagelist[_i] _gimage.window.destroy() if not len(globals.imagelist): gtk.main_quit() break return False PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkstyleprefs.py0000644000175000017500000005067011307666657022700 0ustar matteomatteo# # Copyright (c) 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 51 Franklin Stree, Fifth Floor, Boston, MA 02110-1301, # USA # # # code for displaying Style values # import pygtk pygtk.require('2.0') import gtk import gobject import sys from PythonCAD.Generic import style from PythonCAD.Generic import linetype from PythonCAD.Generic import color from PythonCAD.Generic import image class GtkStyle(object): """ """ def __init__(self, window, gs=None): if not isinstance(window, gtk.Window): raise TypeError, "Invalid window type: " + `type(window)` self.__window = window self.__widgets = {} self.__styles = [] self.__linetypes = [] self.__style = None if gs is not None: self.setStyle(gs) def addStyle(self, s): """Store a Style in the GtkStyle addStyle(s) Argument 's' must be a Style instance. """ if not isinstance(s, style.Style): raise TypeError, "Invalid Style: " + `type(s)` self.__styles.append(s) def addLinetype(self, l): """ """ if not isinstance(l, linetype.Linetype): raise TypeError, "Invalid Linetype: " + `type(l)` self.__linetypes.append(l) def getStyles(self): """Return the list of stored Styles. getStyles() This method returns a list of Style instances stored with the addStyle() method. """ return self.__styles def getLinetypes(self): """Return the list of stored Linetypes getLinetypes() This method returns a list of Linetype instances stored with the addLinetype() method. """ return self.__linetypes def setStyle(self, s): """Set the Style defining the various widget values. setTextStyle(ts) Argument 's' must be a Style instance. """ if not isinstance(s, style.Style): raise TypeError, "Invalid Style: " + `type(s)` self.__style = s self.setValues() def getStyle(self): """Get the Style used to define the widget values. getStyle() This method returns a Style instance or None if no Style has been stored in the GtkStyle instance. """ return self.__style def __selectColor(button, s=None): _s = s if _s is None: _s = _('Select Color') _da = button.get_child().get_child() _color = _da.get_style().bg[gtk.STATE_NORMAL] _dialog = gtk.ColorSelectionDialog(_s) _colorsel = _dialog.colorsel _colorsel.set_previous_color(_color) _colorsel.set_current_color(_color) _colorsel.set_has_palette(True) _response = _dialog.run() if _response == gtk.RESPONSE_OK: _r, _g, _b = _get_rgb_values(_colorsel.get_current_color()) _str = "#%02x%02x%02x" % (_r, _g, _b) _da.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(_str)) _dialog.destroy() __selectColor = staticmethod(__selectColor) def __moveCursor(entry): entry.set_position(-1) return False __moveCursor = staticmethod(__moveCursor) def __entryActivate(entry): _text = entry.get_text() entry.delete_text(0, -1) if len(_text): if _text == '-' or _text == '+': sys.stderr.write("Incomplete value: '%s'\n" % _text) else: try: _value = float(_text) except: sys.stderr.write("Invalid float: '%s'\n" % _text) else: sys.stderr.write("Empty entry box.") __entryActivate = staticmethod(__entryActivate) def __entryFocusOut(entry, event, text=''): _text = entry.get_text() if _text == '' or _text == '+': _thickness = entry.get_data('thickness') _hid = entry.get_data('handlerid') entry.delete_text(0, -1) entry.handler_block(_hid) try: entry.set_text(_thickness) finally: entry.handler_unblock(_hid) return False __entryFocusOut = staticmethod(__entryFocusOut) def __entryInsertText(entry, new_text, new_text_length, position): if (new_text.isdigit() or new_text == '.' or new_text == '+'): _string = entry.get_text() + new_text[:new_text_length] _hid = entry.get_data('handlerid') _move = True entry.handler_block(_hid) try: _pos = entry.get_position() if _string == '+': _pos = entry.insert_text(new_text, _pos) else: try: _val = float(_string) except StandardError, e: _move = False else: _pos = entry.insert_text(new_text, _pos) finally: entry.handler_unblock(_hid) if _move: if hasattr(gobject, 'idle_add'): gobject.idle_add(GtkStyle.__moveCursor, entry) else: gtk.idle_add(GtkStyle.__moveCursor, entry) entry.stop_emission("insert-text") __entryInsertText = staticmethod(__entryInsertText) def __getColorDA(widgets, key, val, s=None): _widget = widgets.get(key) if _widget is None: _widget = gtk.Button() _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_ETCHED_OUT) _frame.set_border_width(5) _widget.add(_frame) _da = gtk.DrawingArea() _da.set_size_request(20, 10) _widget.connect('clicked', GtkStyle.__selectColor, s) _frame.add(_da) else: _da = _widget.get_child().get_child() _da.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(str(val))) return _widget __getColorDA = staticmethod(__getColorDA) def __getColorButton(widgets, key, val, s): _widget = widgets.get(key) if _widget is None: _widget = gtk.ColorButton() _widget.set_title(s) _widget.set_color(gtk.gdk.color_parse(str(val))) return _widget __getColorButton = staticmethod(__getColorButton) def __getOptionMenu(widgets, key, val, entries): _widget = widgets.get(key) if _widget is None: _widget = gtk.OptionMenu() _menu = gtk.Menu() else: _menu = _widget.getMenu() for _child in _menu.get_children(): _menu.remove(_child) _idx = 0 for _i in range(len(entries)): _name, _val = entries[_i] if _val == val: _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget.set_menu(_menu) _widget.set_history(_idx) return _widget __getOptionMenu = staticmethod(__getOptionMenu) def __getComboBox(widgets, key, val, entries): _widget = widgets.get(key) if _widget is None: _widget = gtk.combo_box_new_text() else: _model = _widget.get_model() if _model is not None: while len(_model): _widget.remove_text(0) _idx = 0 for _i in range(len(entries)): _val = entries[_i] if _val == val: _idx = _i _widget.append_text(_val) _widget.set_active(_idx) return _widget __getComboBox = staticmethod(__getComboBox) def setValues(self): """Store the TextStyle values in the interface widgets. setValues() """ _s = self.__style if _s is None: raise RuntimeError, "No Style defined for the GtkStyle instance." _widgets = self.__widgets # _key = 'LINE_TYPE' _widget = _widgets.get(_key) _lt = _s.getLinetype() _ltname = _lt.getName() _lts = self.__linetypes if hasattr(gtk, 'ComboBox'): if _widget is None: _widget = gtk.combo_box_new_text() else: _model = _widget.get_model() if _model is not None: while len(_model): _widget.remove_text(0) _idx = 0 for _i in range(len(_lts)): _val = _lts[_i] _vname = _val.getName() if _vname == _ltname: _idx = _i _widget.append_text(_vname) _widget.set_active(_idx) else: if _widget is None: _widget = gtk.OptionMenu() _menu = gtk.Menu() else: _menu = _widget.getMenu() for _child in _menu.get_children(): _menu.remove(_child) _idx = 0 for _i in range(len(_lts)): _val = _lts[_i] _vname = _val.getName() if _vname == _ltname: _idx = _i _item = gtk.MenuItem(_vname) _menu.append(_item) _widget.set_menu(_menu) _widget.set_history(_idx) if _key not in _widgets: _widgets[_key] = _widget # _val = _s.getColor() _str = _('Select Color') if hasattr(gtk, 'ColorButton'): _sm = GtkStyle.__getColorButton else: _sm = GtkStyle.__getColorDA _key = 'LINE_COLOR' _widget = _sm(_widgets, _key, _val, _str) if _key not in _widgets: _widgets[_key] = _widget # _key = 'LINE_THICKNESS' _entry = _widgets.setdefault(_key, gtk.Entry()) _val = _s.getThickness() _size = "%f" % _val _entry.set_data('thickness', _val) _hid = _entry.get_data('handlerid') if _hid is not None: _entry.handler_block(_hid) try: _entry.set_text(_size) finally: _entry.handler_unblock(_hid) else: _entry.set_text(_size) _handlerid = _entry.connect('insert-text', GtkStyle.__entryInsertText) _entry.set_data('handlerid', _handlerid) _entry.connect('activate', GtkStyle.__entryActivate) _entry.connect('focus-out-event', GtkStyle.__entryFocusOut) if _key not in _widgets: _widgets[_key] = _entry def __getRGBValues(color): if not isinstance(color, gtk.gdk.Color): raise TypeError, "Unexpected color type: " + `type(color)` _r = int(round((color.red/65535.0) * 255.0)) _g = int(round((color.green/65535.0) * 255.0)) _b = int(round((color.blue/65535.0) * 255.0)) return _r, _g, _b __getRGBValues = staticmethod(__getRGBValues) def setImageSettings(self, im): """Store the Image settings of various Style values. setImageSettings(im) Argument 'im' must be and Image instance. """ if not isinstance(im, image.Image): raise TypeError, "Invalid Image type: " + `type(im)` _widgets = self.__widgets # _key = 'LINE_TYPE' _widget = _widgets.get(_key) _lt = im.getOption(_key) _ltname = _lt.getName() _lts = self.__linetypes if hasattr(gtk, 'ComboBox'): if _widget is None: _widget = gtk.combo_box_new_text() else: _model = _widget.get_model() if _model is not None: while len(_model): _widget.remove_text(0) _idx = 0 for _i in range(len(_lts)): _val = _lts[_i] _vname = _val.getName() if _vname == _ltname: _idx = _i _widget.append_text(_vname) _widget.set_active(_idx) else: if _widget is None: _widget = gtk.OptionMenu() _menu = gtk.Menu() else: _menu = _widget.getMenu() for _child in _menu.get_children(): _menu.remove(_child) _idx = 0 for _i in range(len(_lts)): _val = _lts[_i] _vname = _val.getName() if _vname == _ltname: _idx = _i _item = gtk.MenuItem(_vname) _menu.append(_item) _widget.set_menu(_menu) _widget.set_history(_idx) if _key not in _widgets: _widgets[_key] = _widget # _key = 'LINE_COLOR' _val = im.getOption(_key) _str = _('Select Color') if hasattr(gtk, 'ColorButton'): _sm = GtkStyle.__getColorButton else: _sm = GtkStyle.__getColorDA _widget = _sm(_widgets, _key, _val, _str) if _key not in _widgets: _widgets[_key] = _widget # _key = 'LINE_THICKNESS' _entry = _widgets.setdefault(_key, gtk.Entry()) _val = im.getOption(_key) _size = "%f" % _val _entry.set_data('thickness', _val) _hid = _entry.get_data('handlerid') if _hid is not None: _entry.handler_block(_hid) try: _entry.set_text(_size) finally: _entry.handler_unblock(_hid) else: _entry.set_text(_size) _handlerid = _entry.connect('insert-text', GtkStyle.__entryInsertText) _entry.set_data('handlerid', _handlerid) _entry.connect('activate', GtkStyle.__entryActivate) _entry.connect('focus-out-event', GtkStyle.__entryFocusOut) if _key not in _widgets: _widgets[_key] = _entry def getValues(self): """Return the values stored in the widgets getValues() This method returns a list of tuples in the form (key, value), where 'key' is the Style option and 'value' is the option value. """ _s = self.__style if _s is None: raise RuntimeError, "No Style defined for the GtkStyle instance." _values = [] _widgets = self.__widgets # _key = 'LINE_TYPE' _widget = _widgets[_key] if hasattr(gtk, 'ComboBox'): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected widget for '%s': " + (_key, `type(_widget)`) _values.append((_key, self.__linetypes[_idx])) # _key = 'LINE_COLOR' _widget = _widgets[_key] if hasattr(gtk, 'ColorButton'): _color = _widget.get_color() elif isinstance(_widget, gtk.Button): _da = _widget.getChild().getChild() _color= _da.get_style().bg[gtk.STATE_NORMAL] else: raise TypeError, "Unexpected widget for '%s': " + (_key, `type(_widget)`) _values.append((_key, GtkStyle.__getRGBValues(_color))) _key = 'LINE_THICKNESS' _widget = _widgets[_key] _text = _widget.get_text() if len(_text) and _text != '+': _value = float(_text) else: _value = _s.getThickness() _values.append((_key, _value)) return _values def getWidget(self, key): """Return a widget associated with a Style option. getWidget(key) Argument 'key' must be a valid Style option key. This method returns a widget or None. """ if (key != 'LINE_TYPE' and key != 'LINE_COLOR' and key != 'LINE_THICKNESS'): return ValueError, "Invalid Style key: " + key return self.__widgets.get(key) def clear(self): """Clear out all values and widgets in the GtkStyle. clear() """ self.__window = None self.__widgets.clear() del self.__styles[:] del self.__linetypes[:] self.__style = None def _widget_changed(widget, gs): if hasattr(gtk, 'ComboBox'): _idx = widget.get_active() else: _idx = widget.get_history() _styles = gs.getStyles() gs.setStyle(_styles[_idx]) def _fill_dialog(dvbox, gs): _lsg = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _frame = gtk.Frame(_('Graphic Properties')) _frame.set_border_width(2) _vbox = gtk.VBox(False, 2) _vbox.set_border_width(2) _frame.add(_vbox) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, False, False, 2) _label = gtk.Label(_('Linetype:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = gs.getWidget('LINE_TYPE') _hbox.pack_start(_widget, False, False, 2) # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, True, True, 2) _label = gtk.Label(_('Color:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = gs.getWidget('LINE_COLOR') _hbox.pack_start(_widget, False, False, 2) # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, False, False, 2) _label = gtk.Label(_('Thickness:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = gs.getWidget('LINE_THICKNESS') _hbox.pack_start(_widget, False, False, 2) # dvbox.pack_start(_frame, False, False, 2) def style_dialog(gtkimage, styles, linetypes): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Style Settings'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _image = gtkimage.getImage() _st = _image.getOption('LINE_STYLE') _hbox = gtk.HBox(False, 5) _hbox.set_border_width(5) _label = gtk.Label(_('Active Style:')) _hbox.pack_start(_label, False, False, 5) _idx = 0 if hasattr(gtk, 'ComboBox'): _widget = gtk.combo_box_new_text() for _i in range(len(styles)): _style = styles[_i] if (_st is _style or _st == _style): _idx = _i _widget.append_text(_style.getName()) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(styles)): _style = styles[_i] if (_st is _style or _st == _style): _idx = _i _item = gtk.MenuItem(_style.getName()) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) _hbox.pack_start(_widget, False, False, 0) _dialog.vbox.pack_start(_hbox, True, True) # _gs = GtkStyle(_window) for _style in styles: _gs.addStyle(_style) for _lt in linetypes: _gs.addLinetype(_lt) _gs.setStyle(_st) _gs.setImageSettings(_image) _fill_dialog(_dialog.vbox, _gs) _widget.connect('changed', _widget_changed, _gs) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: _nst = _gs.getStyle() if _nst != _st: _image.setOption('LINE_STYLE', _nst) for _opt, _val in _gs.getValues(): if _opt == 'LINE_TYPE': if _val != _image.getOption(_opt): _image.setOption(_opt, _val) elif _opt == 'LINE_COLOR': if _val != _image.getOption(_opt).getColors(): _r, _g, _b = _val _image.setOption(_opt, color.Color(_r, _g, _b)) elif _opt == 'LINE_THICKNESS': if abs(_val - _image.getOption(_opt)) > 1e-10: _image.setOption(_opt, _val) else: raise RuntimeError, "Unexpected TextStyle option '%s'" % _opt _gs.clear() _dialog.destroy() PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkactions.py0000644000175000017500000004516411307666657022142 0ustar matteomatteo# # Copyright (c) 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # GTK Menu building code # # In GTK 2.4 the Action and ActionGroup classes were added to simplify, # and enhance the UI code of GTK. Earlier releases had the ItemFactory # or just raw MenuBar, MenuItem, and Menu widgets. The code in # this file is meant to provide some functionality found in the gtk.Action # and gtk.ActionGroup classes so that PythonCAD can still run on PyGTK # releases prior to the support of the GTK Action and ActionGroup classes # # import pygtk pygtk.require('2.0') import gtk import gobject class stdActionGroup(gobject.GObject): __gproperties__ = { 'name' : (gobject.TYPE_STRING, 'Name', 'Name', '', gobject.PARAM_READWRITE), 'sensitive' : (gobject.TYPE_BOOLEAN, 'Sensitive', 'Sensitivity', True, gobject.PARAM_READWRITE), 'visible' : (gobject.TYPE_BOOLEAN, 'Visible', 'Visibility', True, gobject.PARAM_READWRITE), } __gsignals__ = { 'connect-proxy' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), 'disconnect-proxy' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), 'post-activate' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), 'pre-activate' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)) } def __init__(self, name): gobject.GObject.__init__(self) self.name = name self.__actions = {} self.sensitive = True self.visible = True def get_name(self): return self.name def get_sensitive(self): return self.sensitive def set_sensitive(self, sensitive): _s = self.sensitive if _s is not sensitive: self.sensitive = sensitive def get_visible(self): return self.visible def set_visible(self, visible): _v = self.visible if _v is not visible: self.visible = visible def get_action(self, action): return self.__actions.get(action) def list_actions(self): return self.__actions.values() def add_action(self, action): _name = action.get_name() action.set_property('action-group', self) self.__actions[_name] = action def add_action_with_accel(self, action, accel): # print "add_action_with_accel" _keyval = None _mods = None _name = action.get_name() _path = "/".join(['', self.name, _name]) if accel is None: # print "accel is None" _sid = action.get_property('stock-id') if _sid != '': # print "sid = '%s'" % _sid _data = gtk.stock_lookup(_sid) if _data is not None and _data[3] != 0: # print "data: " + str(_data) _mods = _data[2] _keyval = _data[3] else: _k, _m = gtk.accelerator_parse(accel) if gtk.accelerator_valid(_k, _m): _keyval = _k _mods = _m if _keyval is not None: # print "calling gtk.accel_map_change_entry()" # print "Path: " + _path # print "Key: " + str(_keyval) # print "Mods: " + str(_mods) if not gtk.accel_map_change_entry(_path, _keyval, _mods, True): print "Failed to change accel_map for '%s'" % _path action.set_accel_path(_path) self.add_action(action) def remove_action(self, action): _name = action.get_name() del self.__actions[_name] action.set_property('action-group', None) def do_get_property(self, property): if property.name == 'name': _val = self.name elif property.name == 'sensitive': _val = self.sensitive elif property.name == 'visible': _val = self.visible else: raise AttributeError, "Unknown property '%s'" % property return _val def do_set_property(self, property, value): if property.name == 'name': raise AttributeError, "Property 'name' cannot be changed." elif property.name == 'sensitive': self.set_sensitive(value) elif property.name == 'visible': self.set_visible(value) else: raise AttributeError, "Unknown property '%s'" % property if not hasattr(gtk, 'ActionGroup'): gobject.type_register(stdActionGroup) class stdAction(gobject.GObject): __gproperties__ = { 'action_group' : (gobject.TYPE_PYOBJECT, 'Action Group', 'Action Group', gobject.PARAM_READWRITE), 'hide_if_empty' : (gobject.TYPE_BOOLEAN, 'Hide', 'Hide', True, gobject.PARAM_READWRITE), 'is_important' : (gobject.TYPE_BOOLEAN, 'Importance', 'Importance', False, gobject.PARAM_READWRITE), 'label' : (gobject.TYPE_STRING, 'Label', 'Label', '', gobject.PARAM_READWRITE), 'name' : (gobject.TYPE_STRING, 'Name', 'Name', '', gobject.PARAM_READWRITE), 'sensitive' : (gobject.TYPE_BOOLEAN, 'Sensitive', 'Sensitivity', True, gobject.PARAM_READWRITE), 'short_label' : (gobject.TYPE_STRING, 'Short Label', 'Short Label', '', gobject.PARAM_READWRITE), 'stock_id' : (gobject.TYPE_STRING, 'Stock ID', 'Stock ID', '', gobject.PARAM_READWRITE), 'tooltip' : (gobject.TYPE_STRING, 'Tooltip', 'Tooltip', '', gobject.PARAM_READWRITE), 'visible' : (gobject.TYPE_BOOLEAN, 'Visible', 'Visibility', True, gobject.PARAM_READWRITE), 'visible_horizontal' : (gobject.TYPE_BOOLEAN, 'Visible Horizontal', 'Visible Horizontal', True, gobject.PARAM_READWRITE), 'visible_overflown' : (gobject.TYPE_BOOLEAN, 'Visible Overflown', 'Visible Overflown', True, gobject.PARAM_READWRITE), 'visible_vertical' : (gobject.TYPE_BOOLEAN, 'Visible Vertical', 'Visible Vertical', True, gobject.PARAM_READWRITE) } __gsignals__ = { 'activate' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()) } def __init__(self, name, label, tooltip, stock_id): gobject.GObject.__init__(self) self.name = name self.label = label self.tooltip = '' if tooltip is not None: self.tooltip = tooltip self.stock_id = '' if stock_id is not None: self.stock_id = stock_id self.action_group = None self.hide_if_empty = False self.is_important = True self.sensitive = True self.short_label = None self.visible = True self.visible_horizontal = True self.visible_overflown = True self.visible_vertical = True self.__lset = False # lab self.__slset = False self.__accelpath = None self.__accelgroup = None self.__accelcount = 0 self.__proxies = [] self.__hids = {} def get_name(self): return self.name def is_sensitive(self): return self.sensitive and (self.action_group is None or self.action_group.get_sensitive()) def get_sensitive(self): return self.sensitive def set_sensitive(self, sensitive): _s = self.sensitive if _s is not sensitive: self.sensitive = sensitive self.notify('sensitive') def is_visible(self): return self.visible and (self.action_group is None or self.action_group.get_visible()) def get_visible(self): return self.visible def set_visible(self, visible): _v = self.visible if _v is not visible: self.visible = visible self.notify('visible') def activate(self): # print "stdAction::activate()" if self.is_sensitive(): _group = self.action_group if _group is not None: _group.emit('pre-activate', self) self.emit('activate') if _group is not None: _group.emit('post-activate', self) def create_icon(self, size): _icon = None if self.stock_id != '': _icon = gtk.image_new_from_stock(self.stock_id, size) return _icon def create_menu_item(self): _item = gtk.ImageMenuItem() self.connect_proxy(_item) return _item def create_tool_item(self): return None def connect_proxy(self, widget): _pact = widget.get_data('gtk-action') if _pact is not None: _pact.disconnect_proxy(widget) _hids = self.__hids.setdefault(id(widget),[]) widget.set_data('gtk-action', self) self.__proxies.insert(0, widget) _hid = widget.connect('destroy', self._remove_proxy) _hids.append(_hid) _hid = self.connect_object('notify::sensitive', self._sync_sensitivity, widget) _hids.append(_hid) widget.set_sensitive(self.is_sensitive()) _hid = self.connect_object('notify::visible', self._sync_visibility, widget) _hids.append(_hid) if self.is_visible(): widget.show() else: widget.hide() if hasattr(widget, 'set_no_show_all'): widget.set_no_show_all(True) if isinstance(widget, gtk.MenuItem): if self.__accelpath is not None: self.connect_accelerator() widget.set_accel_path(self.__accelpath) _label = widget.child if _label is None: _label = gtk.AccelLabel('') _label.set_property('use_underline', True) _label.set_property('xalign', 0.0) _label.set_property('visible', True) _label.set_property('parent', widget) _label.set_accel_widget(widget) _label.set_label(self.label) _hid = self.connect_object('notify::label', self._sync_label, widget) _hids.append(_hid) if isinstance(widget, gtk.ImageMenuItem): _image = widget.get_image() if _image is not None and not isinstance(_image, gtk.Image): widget.set_image(None) _image = None if _image is None: _image = gtk.image_new_from_stock(self.stock_id, gtk.ICON_SIZE_MENU) widget.set_image(_image) _image.show() _image.set_from_stock(self.stock_id, gtk.ICON_SIZE_MENU) _hid = self.connect_object('notify::stock-id', self._sync_stock_id, widget) _hids.append(_hid) if widget.get_submenu() is None: _hid = widget.connect_object('activate', stdAction.activate, self) _hids.append(_hid) else: raise TypeError, "Unexpected proxy widget type: " + `type(widget)` if self.action_group is not None: self.action_group.emit('connect-proxy', self, widget) def disconnect_proxy(self, widget): if widget.get_data('gtk-action') is not self: raise ValueError, "Action not being proxied by widget: " + `widget` widget.set_data('gtk-action', None) _hids = self.__hids.get(id(widget)) if _hids is not None: for _hid in _hids: if self.handler_is_connected(_hid): self.disconnect(_hid) continue if widget.handler_is_connected(_hid): widget.disconnect(_hid) if self.action_group is not None: self.action_group.emit('disconnect-proxy', self, widget) def get_proxies(self): return self.__proxies[:] def _accel_cb(self, accelgroup, acceleratable, keyval, mod): # print "_accel_cb()" pass def connect_accelerator(self): # print "connect_accelerator()" if self.__accelgroup is not None and self.__accelpath is not None: _count = self.__accelcount if _count == 0: # print "calling accelgroup.connect_by_path()" # print "accelpath: " + self.__accelpath if hasattr(self.__accelgroup, 'connect_by_path'): self.__accelgroup.connect_by_path(self.__accelpath, self._accel_cb) _count = _count + 1 def disconnect_accelerator(self): # print "disconnect_accelerator()" if self.__accelgroup is not None and self.__accelpath is not None: _count = self.__accelcount _count = _count - 1 if _count > 0: self.__accelgroup.disconnect(self._accel_cb) def block_activate_from(self, widget): pass def unblock_activate_from(self, widget): pass def get_accel_path(self): return self.__accelpath def set_accel_path(self, path): self.__accelpath = path def set_accel_group(self, group): self.__accelgroup = group def do_get_property(self, property): if property.name == 'name': _val = self.name elif property.name == 'label': _val = self.label elif property.name == 'tooltip': _val = self.tooltip elif property.name == 'stock-id': _val = self.stock_id elif property.name == 'action-group': _val = self.action_group elif property.name == 'hide-if-empty': _val = self.hide_if_empty elif property.name == 'is-important': _val = self.is_important elif property.name == 'sensitive': _val = self.sensitive elif property.name == 'short-label': _val = self.short_label elif property.name == 'visible': _val = self.visible elif property.name == 'visible-horizontal': _val = self.visible_horizontal elif property.name == 'visible-overflown': _val = self.visible_overflown elif property.name == 'visible-vertical': _val = self.visible_vertical else: raise AttributeError, "Unknown property '%s'" % property return _val def do_set_property(self, property, value): if property.name == 'name': raise AttributeError, "Property 'name' cannot be changed." elif property.name == 'label': self.label = value self.__lset = self.label != '' if not self.__lset and self.stock_id != '': _item = gtk.stock_lookup(self.stock_id) if _item is not None: self.label = _item[2] if not self.__slset: self.short_label = self.label self.notify('short-label') elif property.name == 'tooltip': self.tooltip = value elif property.name == 'stock-id': self.stock_id = value if not self.__lset: _item = gtk.stock_lookup(self.stock_id) if _item is not None: self.label = _item[2] else: self.label = '' self.notify('label') if not self.__slset: self.short_label = self.label self.notify('short-label') elif property.name == 'action-group': self.action_group = value elif property.name == 'hide-if-empty': self.hide_if_empty = value elif property.name == 'is-important': self.is_important = value elif property.name == 'sensitive': self.set_sensitive(value) elif property.name == 'short-label': self.short_label = value self.__slset = self.short_label != '' if not self.__slset: self.__slset = self.label elif property.name == 'visible': self.set_visible(value) elif property.name == 'visible-horizontal': self.visible_horizontal = value elif property.name == 'visible-overflow': self.visible_overflown = value elif property.name == 'visible-vertical': self.visible_vertical = value else: raise AttributeError, "Unknown property '%s'" % property def do_activate(self): #print "do_activate()" pass def _remove_proxy(self, widget): for _p in self.__proxies[:]: if _p is widget: self.__proxies.remove(_p) break def _sync_sensitivity(self, widget, data=None): widget.set_sensitive(self.is_sensitive()) def _sync_visibility(self, widget, data=None): widget.set_visible(self.is_visible()) def _sync_label(self, widget, data=None): _label = widget.child if _label is not None and isinstance(_label, gtk.Label): _label.set_label(self.label) def _sync_stock_id(self, widget, data=None): _image = widget.get_image() if isinstance(_image, gtk.Image): _image.set_from_stock(self.stock_id, gtk.ICON_SIZE_MENU) if not hasattr(gtk, 'Action'): gobject.type_register(stdAction) PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkdimprefs.py0000644000175000017500000015233711307666657022314 0ustar matteomatteo# # Copyright (c) 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 51 Franklin Stree, Fifth Floor, Boston, MA 02110-1301, # USA # # # code for displaying DimStyle values # import pygtk pygtk.require('2.0') import gtk import gobject import sys from PythonCAD.Generic import color from PythonCAD.Generic import units from PythonCAD.Generic import text from PythonCAD.Generic import dimension from PythonCAD.Generic import image class GtkDimStyle(object): """ """ __keys = dimension.DimStyle.getDimStyleOptions() __font_styles = text.TextStyle.getStyleStrings() __font_weights = text.TextStyle.getWeightStrings() __text_align = text.TextStyle.getAlignmentStrings() __dim_positions = dimension.Dimension.getPositionStrings() __dim_endpoints = dimension.Dimension.getEndpointTypeStrings() __units = units.Unit.getUnitStrings() __families = None def __init__(self, window, ds=None): if not isinstance(window, gtk.Window): raise TypeError, "Invalid window type: " + `type(window)` self.__window = window self.__widgets = {} self.__notebook = gtk.Notebook() self.__dimstyles = [] self.__ds = None if ds is not None: self.setimStyle(ds) def getNotebook(self): """Get the gtk.Notebook widget in the GtkDimStyle. getNotebook() """ return self.__notebook notebook = property(getNotebook, None, None, "gtk.Notebook widget") def addDimStyle(self, ds): """Store a DimStyle in the GtkDimStyle addDimStyle(ds) Argument 'ds' must be a DimStyle instance. """ if not isinstance(ds, dimension.DimStyle): raise TypeError, "Invalid DimStyle: " + `type(ds)` self.__dimstyles.append(ds) def getDimStyles(self): """Return the list of stored DimStyles getDimStyles() This method returns a list of DimStyle instances stored with the addDimStyle() method. """ return self.__dimstyles def setDimStyle(self, ds): """Set the DimStyle defining the various widget values. setDimStyle(ds) Argument 'ds' must be a DimStyle instance. """ if not isinstance(ds, dimension.DimStyle): raise TypeError, "Invalid DimStyle: " + `type(ds)` self.__ds = ds for _key in GtkDimStyle.__keys: self.setValues(_key) if self.__notebook.get_current_page() == -1: self.__initNotebook() def getDimStyle(self): """Get the DimStyle used to define the widget values. getDimStyle() This method returns a DimStyle instance or None if no DimStyle has been stored in the GtkDimStyle instance. """ return self.__ds def __getCheckButton(widgets, key, s): return widgets.setdefault(key, gtk.CheckButton(s)) __getCheckButton = staticmethod(__getCheckButton) def __selectColor(button, s=None): _s = s if _s is None: _s = _('Select Color') _da = button.get_child().get_child() _color = _da.get_style().bg[gtk.STATE_NORMAL] _dialog = gtk.ColorSelectionDialog(_s) _colorsel = _dialog.colorsel _colorsel.set_previous_color(_color) _colorsel.set_current_color(_color) _colorsel.set_has_palette(True) _response = _dialog.run() if _response == gtk.RESPONSE_OK: _r, _g, _b = _get_rgb_values(_colorsel.get_current_color()) _str = "#%02x%02x%02x" % (_r, _g, _b) _color = gtk.gdk.color_parse(_str) _da.modify_bg(gtk.STATE_NORMAL, _color) _dialog.destroy() __selectColor = staticmethod(__selectColor) def __moveCursor(entry): entry.set_position(-1) return False __moveCursor = staticmethod(__moveCursor) def __entryActivate(entry): _text = entry.get_text() entry.delete_text(0, -1) if len(_text): if _text == '-' or _text == '+': sys.stderr.write("Incomplete value: '%s'\n" % _text) else: try: _value = float(_text) except: sys.stderr.write("Invalid float: '%s'\n" % _text) else: sys.stderr.write("Empty entry box.") __entryActivate = staticmethod(__entryActivate) def __entryFocusOut(entry, event, text=''): _text = entry.get_text() if _text == '' or _text == '+': _length = entry.get_data('length') _hid = entry.get_data('handlerid') entry.delete_text(0, -1) entry.handler_block(_hid) try: entry.set_text(_length) finally: entry.handler_unblock(_hid) return False __entryFocusOut = staticmethod(__entryFocusOut) def __entryInsertText(entry, new_text, new_text_length, position): if (new_text.isdigit() or new_text == '.' or new_text == '+'): _string = entry.get_text() + new_text[:new_text_length] _hid = entry.get_data('handlerid') _move = True entry.handler_block(_hid) try: _pos = entry.get_position() if _string == '+': _pos = entry.insert_text(new_text, _pos) else: try: _val = float(_string) except StandardError, e: _move = False else: _pos = entry.insert_text(new_text, _pos) finally: entry.handler_unblock(_hid) if _move: if hasattr(gobject, 'idle_add'): gobject.idle_add(GtkDimStyle.__moveCursor, entry) else: gtk.idle_add(GtkDimStyle.__moveCursor, entry) entry.stop_emission("insert-text") __entryInsertText = staticmethod(__entryInsertText) def __getColorDA(widgets, key, val, s=None): _widget = widgets.get(key) if _widget is None: _widget = gtk.Button() _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_ETCHED_OUT) _frame.set_border_width(5) _widget.add(_frame) _da = gtk.DrawingArea() _da.set_size_request(20, 10) _widget.connect('clicked', GtkDimStyle.__selectColor, s) _frame.add(_da) else: _da = _widget.get_child().get_child() _da.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(str(val))) return _widget __getColorDA = staticmethod(__getColorDA) def __getColorButton(widgets, key, val, s): _widget = widgets.get(key) if _widget is None: _widget = gtk.ColorButton() _widget.set_title(s) _widget.set_color(gtk.gdk.color_parse(str(val))) return _widget __getColorButton = staticmethod(__getColorButton) def __getOptionMenu(widgets, key, val, entries): _widget = widgets.get(key) if _widget is None: _widget = gtk.OptionMenu() _menu = gtk.Menu() else: _menu = _widget.getMenu() for _child in _menu.get_children(): _menu.remove(_child) _idx = 0 for _i in range(len(entries)): _val = entries[_i] if _val == val: _idx = _i _item = gtk.MenuItem(_name) _menu.append(_item) _widget.set_menu(_menu) _widget.set_history(_idx) return _widget __getOptionMenu = staticmethod(__getOptionMenu) def __getComboBox(widgets, key, val, entries): _widget = widgets.get(key) if _widget is None: _widget = gtk.combo_box_new_text() else: _model = _widget.get_model() if _model is not None: while len(_model): _widget.remove_text(0) _idx = 0 for _i in range(len(entries)): _val = entries[_i] if _val == val: _idx = _i _widget.append_text(_val) _widget.set_active(_idx) return _widget __getComboBox = staticmethod(__getComboBox) def __toggleSecondaryOpts(checkbox, widgets): _state = checkbox.get_active() for _key in GtkDimStyle.__keys: if (_key.startswith('DIM_SECONDARY') or _key.startswith('RADIAL_DIM_SECONDARY') or _key.startswith('ANGULAR_DIM_SECONDARY')): _widget = widgets.get(_key) if _widget is not None: _widget.set_sensitive(_state) __toggleSecondaryOpts = staticmethod(__toggleSecondaryOpts) def setValues(self, key): """Store the DimStyle values in the interface widgets. setValues(key) """ _ds = self.__ds if _ds is None: raise RuntimeError, "No DimStyle defined for the GtkDimStyle instance." _widgets = self.__widgets if (key == 'DIM_PRIMARY_FONT_FAMILY' or key == 'DIM_SECONDARY_FONT_FAMILY'): if GtkDimStyle.__families is None: _families = [] _window = self.__window for _family in _window.get_pango_context().list_families(): _families.append(_family.get_name()) _families.sort() GtkDimStyle.__families = _families _val = _ds.getValue(key) if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _widget = _sm(_widgets, key, _val, GtkDimStyle.__families) if key not in _widgets: _widgets[key] = _widget elif (key == 'DIM_PRIMARY_FONT_STYLE' or key == 'DIM_SECONDARY_FONT_STYLE'): _val = _ds.getValue(key) if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _widget = _sm(_widgets, key, _val, GtkDimStyle.__font_styles) if key not in _widgets: _widgets[key] = _widget elif (key == 'DIM_PRIMARY_FONT_WEIGHT' or key == 'DIM_SECONDARY_FONT_WEIGHT'): _val = _ds.getValue(key) if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _widget = _sm(_widgets, key, _val, GtkDimStyle.__font_weights) if key not in _widgets: _widgets[key] = _widget elif key == 'DIM_PRIMARY_FONT_COLOR': _color = _ds.getValue(key) _s = _('Select Primary Dimension Font Color') if hasattr(gtk, 'ColorButton'): _sm = GtkDimStyle.__getColorButton else: _sm = GtkDimStyle.__getColorDA _widget = _sm(_widgets, key, _color, _s) if key not in _widgets: _widgets[key] = _widget elif key == 'DIM_SECONDARY_FONT_COLOR': _color = _ds.getValue(key) _s = _('Select Secondary Dimension Font Color') if hasattr(gtk, 'ColorButton'): _sm = GtkDimStyle.__getColorButton else: _sm = GtkDimStyle.__getColorDA _widget = _sm(_widgets, key, _color, _s) if key not in _widgets: _widgets[key] = _widget elif (key == 'DIM_PRIMARY_TEXT_ANGLE' or key == 'DIM_SECONDARY_TEXT_ANGLE'): pass elif (key == 'DIM_PRIMARY_TEXT_ALIGNMENT' or key == 'DIM_SECONDARY_TEXT_ALIGNMENT'): _val = _ds.getValue(key) if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _widget = _sm(_widgets, key, _val, GtkDimStyle.__text_align) if key not in _widgets: _widgets[key] = _widget elif (key == 'DIM_PRIMARY_PREFIX' or key == 'DIM_SECONDARY_PREFIX' or key == 'DIM_PRIMARY_SUFFIX' or key == 'DIM_SECONDARY_SUFFIX' or key == 'RADIAL_DIM_PRIMARY_PREFIX' or key == 'RADIAL_DIM_SECONDARY_PREFIX' or key == 'RADIAL_DIM_PRIMARY_SUFFIX' or key == 'RADIAL_DIM_SECONDARY_SUFFIX' or key == 'ANGULAR_DIM_PRIMARY_PREFIX' or key == 'ANGULAR_DIM_SECONDARY_PREFIX' or key == 'ANGULAR_DIM_PRIMARY_SUFFIX' or key == 'ANGULAR_DIM_SECONDARY_SUFFIX'): _entry = _widgets.setdefault(key, gtk.Entry()) _entry.set_text(_ds.getValue(key)) if key not in _widgets: _widgets[key] = _entry elif (key == 'DIM_PRIMARY_PRECISION' or key == 'DIM_SECONDARY_PRECISION'): _widget = _widgets.get(key) _val = _ds.getValue(key) if _widget is None: _adj = gtk.Adjustment(_val, 0, 15, 1, 1, 1) _sb = gtk.SpinButton(_adj) _sb.set_digits(0) _sb.set_numeric(True) _widgets[key] = _sb else: _widget.set_value(_val) elif (key == 'DIM_PRIMARY_UNITS' or key == 'DIM_SECONDARY_UNITS'): _val = _ds.getValue(key) if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _widget = _sm(_widgets, key, _val, GtkDimStyle.__units) if key not in _widgets: _widgets[key] = _widget elif (key == 'DIM_PRIMARY_LEADING_ZERO' or key == 'DIM_SECONDARY_LEADING_ZERO'): _str = _('Print leading 0') _cb = GtkDimStyle.__getCheckButton(_widgets, key, _str) _cb.set_active(_ds.getValue(key)) if key not in _widgets: _widgets[key] = _cb elif (key == 'DIM_PRIMARY_TRAILING_DECIMAL' or key == 'DIM_SECONDARY_TRAILING_DECIMAL'): _str = _('Print trailing decimal point') _cb = GtkDimStyle.__getCheckButton(_widgets, key, _str) _cb.set_active(_ds.getValue(key)) if key not in _widgets: _widgets[key] = _cb elif (key == 'DIM_OFFSET' or key == 'DIM_EXTENSION' or key == 'DIM_ENDPOINT_SIZE' or key == 'DIM_THICKNESS' or key == 'DIM_PRIMARY_TEXT_SIZE' or key == 'DIM_SECONDARY_TEXT_SIZE'): _entry = _widgets.setdefault(key, gtk.Entry()) _length = "%f" % _ds.getValue(key) _entry.set_data('length', _length) _hid = _entry.get_data('handlerid') if _hid is not None: _entry.handler_block(_hid) try: _entry.set_text(_length) finally: _entry.handler_unblock(_hid) else: _entry.set_text(_length) _handlerid = _entry.connect("insert-text", GtkDimStyle.__entryInsertText) _entry.set_data('handlerid', _handlerid) _entry.connect("activate", GtkDimStyle.__entryActivate) _entry.connect("focus-out-event", GtkDimStyle.__entryFocusOut) if key not in _widgets: _widgets[key] = _entry elif (key == 'DIM_COLOR'): _color = _ds.getValue(key) _s = _('Select Dimension Color') if hasattr(gtk, 'ColorButton'): _sm = GtkDimStyle.__getColorButton else: _sm = GtkDimStyle.__getColorDA _widget = _sm(_widgets, key, _color, _s) if key not in _widgets: _widgets[key] = _widget elif (key == 'DIM_POSITION'): _val = _ds.getValue(key) if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _widget = _sm(_widgets, key, _val, GtkDimStyle.__dim_positions) if key not in _widgets: _widgets[key] = _widget elif (key == 'DIM_ENDPOINT'): _val = _ds.getValue(key) if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _widget = _sm(_widgets, key, _val, GtkDimStyle.__dim_endpoints) if key not in _widgets: _widgets[key] = _widget elif (key == 'DIM_DUAL_MODE'): _str = _('Display secondary dimension text') _cb = GtkDimStyle.__getCheckButton(_widgets, key, _str) _cb.set_active(_ds.getValue(key)) # _cb.connect('toggled', GtkDimStyle.__toggleSecondaryOpts, _widgets) if key not in _widgets: _widgets[key] = _cb elif (key == 'DIM_POSITION_OFFSET'): pass elif (key == 'DIM_DUAL_MODE_OFFSET'): pass elif (key == 'RADIAL_DIM_DIA_MODE'): _str = _('Show diameterical dimension value') _cb = GtkDimStyle.__getCheckButton(_widgets, key, _str) _cb.set_active(_ds.getValue(key)) if key not in _widgets: _widgets[key] = _cb else: raise ValueError, "Unexpected key: " + key def __getRGBValues(color): if not isinstance(color, gtk.gdk.Color): raise TypeError, "Unexpected color type: " + `type(color)` _r = int(round((color.red/65535.0) * 255.0)) _g = int(round((color.green/65535.0) * 255.0)) _b = int(round((color.blue/65535.0) * 255.0)) return _r, _g, _b __getRGBValues = staticmethod(__getRGBValues) def getValues(self): """Return the values stored in the widgets getValues() This method returns a list of tuples in the form (key, value), where 'key' is the DimStyle option and 'value' is the option value. """ _ds = self.__ds if _ds is None: raise RuntimeError, "No DimStyle defined for the GtkDimStyle instance." _values = [] _widgets = self.__widgets for _key in GtkDimStyle.__keys: _widget = _widgets.get(_key) if _widget is None: continue if (_key == 'DIM_PRIMARY_FONT_FAMILY' or _key == 'DIM_SECONDARY_FONT_FAMILY'): if hasattr(gtk, 'ComboBox'): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected widget for '%s': " + (_key, `type(_widget)`) _value = GtkDimStyle.__families[_idx] elif (_key == 'DIM_PRIMARY_FONT_STYLE' or _key == 'DIM_SECONDARY_FONT_STYLE' or _key == 'DIM_PRIMARY_FONT_WEIGHT' or _key == 'DIM_SECONDARY_FONT_WEIGHT' or _key == 'DIM_PRIMARY_TEXT_ALIGNMENT' or _key == 'DIM_SECONDARY_TEXT_ALIGNMENT' or _key == 'DIM_PRIMARY_UNITS' or _key == 'DIM_SECONDARY_UNITS' or _key == 'DIM_POSITION' or _key == 'DIM_ENDPOINT'): if hasattr(gtk, 'ComboBox'): _value = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _value = _widget.get_history() else: raise TypeError, "Unexpected widget for '%s': " + (_key, `type(_widget)`) elif (_key == 'DIM_PRIMARY_FONT_COLOR' or _key == 'DIM_SECONDARY_FONT_COLOR' or _key == 'DIM_COLOR'): if hasattr(gtk, 'ColorButton'): _color = _widget.get_color() elif isinstance(_widget, gtk.Button): _da = _widget.getChild().getChild() _color= _da.get_style().bg[gtk.STATE_NORMAL] else: raise TypeError, "Unexpected widget for '%s': " + (_key, `type(_widget)`) _value = GtkDimStyle.__getRGBValues(_color) elif (_key == 'DIM_PRIMARY_TEXT_ANGLE' or _key == 'DIM_SECONDARY_TEXT_ANGLE'): pass elif (_key == 'DIM_PRIMARY_PREFIX' or _key == 'DIM_SECONDARY_PREFIX' or _key == 'DIM_PRIMARY_SUFFIX' or _key == 'DIM_SECONDARY_SUFFIX' or _key == 'RADIAL_DIM_PRIMARY_PREFIX' or _key == 'RADIAL_DIM_SECONDARY_PREFIX' or _key == 'RADIAL_DIM_PRIMARY_SUFFIX' or _key == 'RADIAL_DIM_SECONDARY_SUFFIX' or _key == 'ANGULAR_DIM_PRIMARY_PREFIX' or _key == 'ANGULAR_DIM_SECONDARY_PREFIX' or _key == 'ANGULAR_DIM_PRIMARY_SUFFIX' or _key == 'ANGULAR_DIM_SECONDARY_SUFFIX'): _value = _widget.get_text() elif (_key == 'DIM_PRIMARY_PRECISION' or _key == 'DIM_SECONDARY_PRECISION'): _value = _widget.get_value_as_int() elif (_key == 'DIM_PRIMARY_LEADING_ZERO' or _key == 'DIM_SECONDARY_LEADING_ZERO' or _key == 'DIM_PRIMARY_TRAILING_DECIMAL' or _key == 'DIM_SECONDARY_TRAILING_DECIMAL' or _key == 'DIM_DUAL_MODE' or _key == 'RADIAL_DIM_DIA_MODE'): _value = _widget.get_active() elif (_key == 'DIM_OFFSET' or _key == 'DIM_EXTENSION' or _key == 'DIM_ENDPOINT_SIZE' or _key == 'DIM_THICKNESS' or _key == 'DIM_PRIMARY_TEXT_SIZE' or _key == 'DIM_SECONDARY_TEXT_SIZE'): _text = _widget.get_text() if len(_text) and _text != '+': _value = float(_text) else: _value = self.__ds.getOption(_key) elif (key == 'DIM_POSITION_OFFSET'): pass elif (key == 'DIM_DUAL_MODE_OFFSET'): pass else: raise ValueError, "Unexpected key: " + key _values.append((_key, _value)) return _values def getWidget(self, key): """Return a widget associated with a DimStyle option. getWidget(key) Argument 'key' must be a valid DimStyle option key. This method returns a widget or None. """ if key not in GtkDimStyle.__keys: return ValueError, "Invalid DimStyle key: " + key return self.__widgets.get(key) def __generalPage(self): """Populate the 'General' Notebook page __generalPage() This method is private to the GtkDimStyle class. """ _widgets = self.__widgets _vbox = gtk.VBox(False, 2) _size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _frame = gtk.Frame(_('Dimension Bar Options')) _table = gtk.Table(4, 2, False) _table.set_border_width(2) _table.set_row_spacings(2) _table.set_col_spacings(2) _frame.add(_table) _label = gtk.Label(_('Offset length:')) _table.attach(_label, 0, 1, 0, 1, gtk.EXPAND, gtk.EXPAND, 2, 2) _widget = _widgets.get('DIM_OFFSET') _size_group.add_widget(_widget) _table.attach(_widget, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _label = gtk.Label(_('Extension length:')) _table.attach(_label, 0, 1, 1, 2, gtk.EXPAND, gtk.EXPAND, 2, 2) _widget = _widgets.get('DIM_EXTENSION') _size_group.add_widget(_widget) _table.attach(_widget, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _hbox = gtk.HBox(False, 2) _label = gtk.Label(_('Dimension bar color:')) _hbox.pack_start(_label, False, False, 2) _widget = _widgets.get('DIM_COLOR') _hbox.pack_start(_widget, False, False, 2) _table.attach(_hbox, 0, 2, 2, 3, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _hbox = gtk.HBox(False, 2) _label = gtk.Label(_('Dimension bar thickness:')) _hbox.pack_start(_label, False, False, 2) _widget = _widgets.get('DIM_THICKNESS') _hbox.pack_start(_widget, False, False, 2) _table.attach(_hbox, 0, 2, 3, 4, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _vbox.pack_start(_frame, False, False, 2) # # options for dimension text position # _frame = gtk.Frame(_('Dimension Text Position')) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _frame.add(_hbox) _label = gtk.Label(_('Text Location at crossbar:')) _hbox.pack_start(_label, False, False, 2) _widget = _widgets.get('DIM_POSITION') _hbox.pack_start(_widget, False, False, 0) _vbox.pack_start(_frame, False, False, 2) # # options for dimension crossbar/crossarc markers # _frame = gtk.Frame(_('Dimension Crossbar Markers')) _table = gtk.Table(2, 2, False) _table.set_border_width(2) _table.set_row_spacings(2) _table.set_col_spacings(2) _frame.add(_table) _label = gtk.Label(_('Dimension marker:')) _table.attach(_label, 0, 1, 0, 1, gtk.FILL, gtk.FILL, 2, 2) _widget = _widgets.get('DIM_ENDPOINT') _table.attach(_widget, 1, 2, 0, 1, gtk.FILL, gtk.FILL, 2, 2) _label = gtk.Label(_('Marker size:')) _table.attach(_label, 0, 1, 1, 2, gtk.FILL, gtk.FILL, 2, 2) _widget = _widgets.get('DIM_ENDPOINT_SIZE') _size_group.add_widget(_widget) _table.attach(_widget, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 2, 2) _vbox.pack_start(_frame, False, False, 2) # _widget = _widgets.get('DIM_DUAL_MODE') _vbox.pack_start(_widget, False, False, 2) self.__notebook.append_page(_vbox, gtk.Label(_('General'))) def __psPage(self, pds=True): """Populate the Primary/Secondary DimString pages psPage([pds]) This method is private to the GtkDimString class. """ _widgets = self.__widgets _vbox = gtk.VBox(False, 2) _frame = gtk.Frame(_('Units')) _frame.set_border_width(2) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _frame.add(_hbox) _label = gtk.Label(_('Dimension units:')) _hbox.pack_start(_label, False, False, 2) if pds: _key = 'DIM_PRIMARY_UNITS' else: _key = 'DIM_SECONDARY_UNITS' _widget = _widgets.get(_key) _hbox.pack_start(_widget, False, False, 2) _vbox.pack_start(_frame, False, False, 2) # _label_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _menu_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) # _frame = gtk.Frame(_('Font Properties')) _frame.set_border_width(2) _fvbox = gtk.VBox(False, 2) _fvbox.set_border_width(2) _frame.add(_fvbox) _fhbox = gtk.HBox(False, 2) _fhbox.set_border_width(2) _fvbox.pack_start(_fhbox, False, False, 2) _label = gtk.Label(_('Family:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 2) if pds: _key = 'DIM_PRIMARY_FONT_FAMILY' else: _key = 'DIM_SECONDARY_FONT_FAMILY' _widget = _widgets.get(_key) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 2) # _fhbox = gtk.HBox(False, 2) _fhbox.set_border_width(2) _fvbox.pack_start(_fhbox, False, False, 2) _label = gtk.Label(_('Style:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 2) if pds: _key = 'DIM_PRIMARY_FONT_STYLE' else: _key = 'DIM_SECONDARY_FONT_STYLE' _widget = _widgets.get(_key) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 2) # _fhbox = gtk.HBox(False, 2) _fhbox.set_border_width(2) _fvbox.pack_start(_fhbox, False, False, 2) _label = gtk.Label(_('Weight:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 2) if pds: _key = 'DIM_PRIMARY_FONT_WEIGHT' else: _key = 'DIM_SECONDARY_FONT_WEIGHT' _widget = _widgets.get(_key) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 2) # _fhbox = gtk.HBox(False, 2) _fhbox.set_border_width(2) _fvbox.pack_start(_fhbox, False, False, 2) _label = gtk.Label(_('Alignment:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 2) if pds: _key = 'DIM_PRIMARY_TEXT_ALIGNMENT' else: _key = 'DIM_SECONDARY_TEXT_ALIGNMENT' _widget = _widgets.get(_key) _menu_size_group.add_widget(_widget) _fhbox.pack_start(_widget, False, False, 2) # _fhbox = gtk.HBox(False, 2) _fhbox.set_border_width(2) _fvbox.pack_start(_fhbox, False, False, 2) _label = gtk.Label(_('Size:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 2) if pds: _key = 'DIM_PRIMARY_TEXT_SIZE' else: _key = 'DIM_SECONDARY_TEXT_SIZE' _widget = _widgets.get(_key) _fhbox.pack_start(_widget, False, False, 2) # _fhbox = gtk.HBox(False, 2) _fhbox.set_border_width(2) _fvbox.pack_start(_fhbox, True, True, 2) _label = gtk.Label(_('Color:')) _label_size_group.add_widget(_label) _fhbox.pack_start(_label, False, False, 2) if pds: _key = 'DIM_PRIMARY_FONT_COLOR' else: _key = 'DIM_SECONDARY_FONT_COLOR' _widget = _widgets.get(_key) _fhbox.pack_start(_widget, False, False, 2) _vbox.pack_start(_frame, False, False, 2) # _frame = gtk.Frame(_('Format Options')) _frame.set_border_width(2) _table = gtk.Table(3, 1, False) _table.set_border_width(2) _table.set_row_spacings(2) _table.set_col_spacings(2) _frame.add(_table) if pds: _key = 'DIM_PRIMARY_LEADING_ZERO' else: _key = 'DIM_SECONDARY_LEADING_ZERO' _widget = _widgets.get(_key) _table.attach(_widget, 0, 1, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) if pds: _key = 'DIM_PRIMARY_TRAILING_DECIMAL' else: _key = 'DIM_SECONDARY_TRAILING_DECIMAL' _widget = _widgets.get(_key) _table.attach(_widget, 0, 1, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) # _thbox = gtk.HBox(False, 2) _label = gtk.Label(_('Display precision:')) _thbox.pack_start(_label, False, False, 2) if pds: _key = 'DIM_PRIMARY_PRECISION' else: _key = 'DIM_SECONDARY_PRECISION' _widget = _widgets.get(_key) _thbox.pack_start(_widget, False, False, 2) _table.attach(_thbox, 0, 1, 2, 3, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _vbox.pack_start(_frame, False, False, 2) if pds: _label = gtk.Label(_('Primary')) else: _label = gtk.Label(_('Secondary')) self.__notebook.append_page(_vbox, _label) def __dimPage(self, dstr): """Populate the Linear/Radial/Angular dimension pages __dimPage(dstr) This method is private to the GtkDimStyle class """ if (dstr != 'linear' and dstr != 'radial' and dstr != 'angular'): raise ValueError, "Unexpected argument: " + dstr _widgets = self.__widgets _vbox = gtk.VBox(False, 5) _size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _frame = gtk.Frame(_('Primary Dimension Text Options')) _table = gtk.Table(2, 2, False) _table.set_border_width(5) _table.set_row_spacings(5) _table.set_col_spacings(5) _frame.add(_table) _label = gtk.Label(_('Default prefix:')) _table.attach(_label, 0, 1, 0, 1, gtk.EXPAND, gtk.EXPAND, 2, 2) if dstr == 'linear': _key = 'DIM_PRIMARY_PREFIX' elif dstr == 'radial': _key = 'RADIAL_DIM_PRIMARY_PREFIX' else: _key = 'ANGULAR_DIM_PRIMARY_PREFIX' _widget = _widgets.get(_key) _size_group.add_widget(_widget) _table.attach(_widget, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _label = gtk.Label(_('Default suffix:')) _table.attach(_label, 0, 1, 1, 2, gtk.EXPAND, gtk.EXPAND, 2, 2) if dstr == 'linear': _key = 'DIM_PRIMARY_SUFFIX' elif dstr == 'radial': _key = 'RADIAL_DIM_PRIMARY_SUFFIX' else: _key = 'ANGULAR_DIM_PRIMARY_SUFFIX' _widget = _widgets.get(_key) _size_group.add_widget(_widget) _table.attach(_widget, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _vbox.pack_start(_frame, False, False, 5) # _frame = gtk.Frame(_('Secondary Dimension Text Options')) _table = gtk.Table(2, 2, False) _table.set_border_width(5) _table.set_row_spacings(5) _table.set_col_spacings(5) _frame.add(_table) _label = gtk.Label(_('Default prefix:')) _table.attach(_label, 0, 1, 0, 1, gtk.EXPAND, gtk.EXPAND, 2, 2) if dstr == 'linear': _key = 'DIM_SECONDARY_PREFIX' elif dstr == 'radial': _key = 'RADIAL_DIM_SECONDARY_PREFIX' else: _key = 'ANGULAR_DIM_SECONDARY_PREFIX' _widget = _widgets.get(_key) _size_group.add_widget(_widget) _table.attach(_widget, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _label = gtk.Label(_('Default suffix:')) _table.attach(_label, 0, 1, 1, 2, gtk.EXPAND, gtk.EXPAND, 2, 2) if dstr == 'linear': _key = 'DIM_SECONDARY_SUFFIX' elif dstr == 'radial': _key = 'RADIAL_DIM_SECONDARY_SUFFIX' else: _key = 'ANGULAR_DIM_SECONDARY_SUFFIX' _widget = _widgets.get(_key) _size_group.add_widget(_widget) _table.attach(_widget, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 2, 2) _vbox.pack_start(_frame, False, False, 5) if dstr == 'radial': _widget = _widgets.get('RADIAL_DIM_DIA_MODE') _vbox.pack_start(_widget, False, False, 5) if dstr == 'linear': _label = gtk.Label(_('Linear')) elif dstr == 'radial': _label = gtk.Label(_('Radial')) else: _label = gtk.Label(_('Angular')) self.__notebook.append_page(_vbox, _label) def __initNotebook(self): """Populate the gtk.Notebook with widgets. __initNotebook() This method is private to the GtkDimStyle class. """ self.__generalPage() self.__psPage() # Primary self.__psPage(False) # Secondary self.__dimPage('linear') self.__dimPage('radial') self.__dimPage('angular') def clear(self): """Clear out all values and widgets in the GtkDimStyle. clear() """ self.__window = None _nb = self.__notebook _nb.set_current_page(0) while _nb.get_current_page() != -1: _nb.remove_page(-1) self.__widgets.clear() del self.__dimstyles[:] self.__ds = None def setImageSettings(self, im): """Adjust the widgets values based on current Image values setImageSettings(im) Argument 'im' must be an Image instance. """ if not isinstance(im, image.Image): raise TypeError, "Invalid Image type: " + `type(im)` _widgets = self.__widgets for _key in GtkDimStyle.__keys: _ival = im.getOption(_key) if (_key == 'DIM_PRIMARY_FONT_FAMILY' or _key == 'DIM_SECONDARY_FONT_FAMILY'): if GtkDimStyle.__families is None: _families = [] _window = self.__window for _family in _window.get_pango_context().list_families(): _families.append(_family.get_name()) _families.sort() GtkDimStyle.__families = _families if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _widget = _sm(_widgets, _key, _ival, GtkDimStyle.__families) if _key not in _widgets: _widgets[_key] = _widget elif (_key == 'DIM_PRIMARY_FONT_STYLE' or _key == 'DIM_SECONDARY_FONT_STYLE'): if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _optlist = GtkDimStyle.__font_styles _widget = _sm(_widgets, _key, _ival, _optlist) _idx = 0 for _i in range(len(_optlist)): _val = text.TextStyle.getStyleFromString(_optlist[_i]) if _val == _ival: _idx = _i _widget.set_active(_idx) if _key not in _widgets: _widgets[_key] = _widget elif (_key == 'DIM_PRIMARY_FONT_WEIGHT' or _key == 'DIM_SECONDARY_FONT_WEIGHT'): if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _optlist = GtkDimStyle.__font_weights _widget = _sm(_widgets, _key, _ival, _optlist) _idx = 0 for _i in range(len(_optlist)): _val = text.TextStyle.getWeightFromString(_optlist[_i]) if _val == _ival: _idx = _i _widget.set_active(_idx) if _key not in _widgets: _widgets[_key] = _widget elif _key == 'DIM_PRIMARY_FONT_COLOR': _s = _('Select Primary Dimension Font Color') if hasattr(gtk, 'ColorButton'): _sm = GtkDimStyle.__getColorButton else: _sm = GtkDimStyle.__getColorDA _widget = _sm(_widgets, _key, _ival, _s) if _key not in _widgets: _widgets[_key] = _widget elif _key == 'DIM_SECONDARY_FONT_COLOR': _s = _('Select Secondary Dimension Font Color') if hasattr(gtk, 'ColorButton'): _sm = GtkDimStyle.__getColorButton else: _sm = GtkDimStyle.__getColorDA _widget = _sm(_widgets, _key, _ival, _s) if _key not in _widgets: _widgets[_key] = _widget elif (_key == 'DIM_PRIMARY_TEXT_ANGLE' or _key == 'DIM_SECONDARY_TEXT_ANGLE'): pass elif (_key == 'DIM_PRIMARY_TEXT_ALIGNMENT' or _key == 'DIM_SECONDARY_TEXT_ALIGNMENT'): if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _optlist = GtkDimStyle.__text_align _widget = _sm(_widgets, _key, _ival, _optlist) _idx = 0 for _i in range(len(_optlist)): _val = text.TextStyle.getAlignmentFromString(_optlist[_i]) if _val == _ival: _idx = _i _widget.set_active(_idx) if _key not in _widgets: _widgets[_key] = _widget elif (_key == 'DIM_PRIMARY_PREFIX' or _key == 'DIM_SECONDARY_PREFIX' or _key == 'DIM_PRIMARY_SUFFIX' or _key == 'DIM_SECONDARY_SUFFIX' or _key == 'RADIAL_DIM_PRIMARY_PREFIX' or _key == 'RADIAL_DIM_SECONDARY_PREFIX' or _key == 'RADIAL_DIM_PRIMARY_SUFFIX' or _key == 'RADIAL_DIM_SECONDARY_SUFFIX' or _key == 'ANGULAR_DIM_PRIMARY_PREFIX' or _key == 'ANGULAR_DIM_SECONDARY_PREFIX' or _key == 'ANGULAR_DIM_PRIMARY_SUFFIX' or _key == 'ANGULAR_DIM_SECONDARY_SUFFIX'): _entry = _widgets.setdefault(_key, gtk.Entry()) _entry.set_text(_ival) if _key not in _widgets: _widgets[_key] = _entry elif (_key == 'DIM_PRIMARY_PRECISION' or _key == 'DIM_SECONDARY_PRECISION'): _widget = _widgets.get(_key) if _widget is None: _adj = gtk.Adjustment(_ival, 0, 15, 1, 1, 1) _sb = gtk.SpinButton(_adj) _sb.set_digits(0) _sb.set_numeric(True) _widgets[_key] = _sb else: _widget.set_value(_ival) elif (_key == 'DIM_PRIMARY_UNITS' or _key == 'DIM_SECONDARY_UNITS'): if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _widget = _sm(_widgets, _key, _ival, GtkDimStyle.__units) if _key not in _widgets: _widgets[_key] = _widget elif (_key == 'DIM_PRIMARY_LEADING_ZERO' or _key == 'DIM_SECONDARY_LEADING_ZERO'): _str = _('Print leading 0') _cb = GtkDimStyle.__getCheckButton(_widgets, _key, _str) _cb.set_active(_ival) if _key not in _widgets: _widgets[_key] = _cb elif (_key == 'DIM_PRIMARY_TRAILING_DECIMAL' or _key == 'DIM_SECONDARY_TRAILING_DECIMAL'): _str = _('Print trailing decimal point') _cb = GtkDimStyle.__getCheckButton(_widgets, _key, _str) _cb.set_active(_ival) if _key not in _widgets: _widgets[_key] = _cb elif (_key == 'DIM_OFFSET' or _key == 'DIM_EXTENSION' or _key == 'DIM_ENDPOINT_SIZE' or _key == 'DIM_THICKNESS' or _key == 'DIM_PRIMARY_TEXT_SIZE' or _key == 'DIM_SECONDARY_TEXT_SIZE'): _entry = _widgets.setdefault(_key, gtk.Entry()) _length = "%f" % _ival _entry.set_data('length', _length) _hid = _entry.get_data('handlerid') if _hid is not None: _entry.handler_block(_hid) try: _entry.set_text(_length) finally: _entry.handler_unblock(_hid) else: _entry.set_text(_length) _handlerid = _entry.connect("insert-text", GtkDimStyle.__entryInsertText) _entry.set_data('handlerid', _handlerid) _entry.connect("activate", GtkDimStyle.__entryActivate) _entry.connect("focus-out-event", GtkDimStyle.__entryFocusOut) if _key not in _widgets: _widgets[_key] = _entry elif (_key == 'DIM_COLOR'): _color = _ival _s = _('Select Dimension Color') if hasattr(gtk, 'ColorButton'): _sm = GtkDimStyle.__getColorButton else: _sm = GtkDimStyle.__getColorDA _widget = _sm(_widgets, _key, _ival, _s) if _key not in _widgets: _widgets[_key] = _widget elif (_key == 'DIM_POSITION'): if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _optlist = GtkDimStyle.__dim_positions _widget = _sm(_widgets, _key, _ival, _optlist) _idx = 0 for _i in range(len(_optlist)): _val = dimension.Dimension.getPositionFromString(_optlist[_i]) if _val == _ival: _idx = _i _widget.set_active(_idx) if _key not in _widgets: _widgets[_key] = _widget elif (_key == 'DIM_ENDPOINT'): if hasattr(gtk, 'ComboBox'): _sm = GtkDimStyle.__getComboBox else: _sm = GtkDimStyle.__getOptionMenu _optlist = GtkDimStyle.__dim_endpoints _widget = _sm(_widgets, _key, _ival, _optlist) _idx = 0 for _i in range(len(_optlist)): _val = dimension.Dimension.getEndpointTypeFromString(_optlist[_i]) if _val == _ival: _idx = _i _widget.set_active(_idx) if _key not in _widgets: _widgets[_key] = _widget elif (_key == 'DIM_DUAL_MODE'): _str = _('Display secondary dimension text') _cb = GtkDimStyle.__getCheckButton(_widgets, _key, _str) _cb.set_active(_ival) if _key not in _widgets: _widgets[_key] = _cb elif (_key == 'DIM_POSITION_OFFSET'): pass elif (_key == 'DIM_DUAL_MODE_OFFSET'): pass elif (_key == 'RADIAL_DIM_DIA_MODE'): _str = _('Show diameterical dimension value') _cb = GtkDimStyle.__getCheckButton(_widgets, _key, _str) _cb.set_active(_ival) if _key not in _widgets: _widgets[_key] = _cb else: raise ValueError, "Unexpected key: " + _key def _widget_changed(widget, gds): if hasattr(gtk, 'ComboBox'): _idx = widget.get_active() else: _idx = widget.get_history() _dimstyles = gds.getDimStyles() gds.setDimStyle(_dimstyles[_idx]) def dimstyle_dialog(gtkimage, dimstyles): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('DimStyle Settings'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _image = gtkimage.getImage() _ds = _image.getOption('DIM_STYLE') _hbox = gtk.HBox(False, 5) _hbox.set_border_width(5) _label = gtk.Label(_('Active DimStyle:')) _hbox.pack_start(_label, False, False, 5) _idx = 0 if hasattr(gtk, 'ComboBox'): _widget = gtk.combo_box_new_text() for _i in range(len(dimstyles)): _dimstyle = dimstyles[_i] if (_ds is _dimstyle or _ds == _dimstyle): _idx = _i _widget.append_text(_dimstyle.getName()) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(dimstyles)): _dimstyle = dimstyles[_i] if (_ds is _dimstyle or _ds == _dimstyle): _idx = _i _item = gtk.MenuItem(_dimstyle.getName()) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) _hbox.pack_start(_widget, False, False, 0) _dialog.vbox.pack_start(_hbox, True, True) # _gds = GtkDimStyle(_window) for _dimstyle in dimstyles: _gds.addDimStyle(_dimstyle) _gds.setDimStyle(_ds) _gds.setImageSettings(_image) _dialog.vbox.pack_start(_gds.notebook, True, True) _widget.connect('changed', _widget_changed, _gds) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: _nds = _gds.getDimStyle() if _nds != _ds: _image.setOption('DIM_STYLE', _nds) for _opt, _val in _gds.getValues(): _set = False _cv = _image.getOption(_opt) if (_opt == 'DIM_PRIMARY_FONT_FAMILY' or _opt == 'DIM_SECONDARY_FONT_FAMILY' or _opt == 'DIM_PRIMARY_FONT_WEIGHT' or _opt == 'DIM_SECONDARY_FONT_WEIGHT' or _opt == 'DIM_PRIMARY_FONT_STYLE' or _opt == 'DIM_SECONDARY_FONT_STYLE' or _opt == 'DIM_PRIMARY_TEXT_ALIGNMENT' or _opt == 'DIM_SECONDARY_TEXT_ALIGNMENT' or _opt == 'DIM_PRIMARY_PREFIX' or _opt == 'DIM_SECONDARY_PREFIX' or _opt == 'DIM_PRIMARY_SUFFIX' or _opt == 'DIM_SECONDARY_SUFFIX' or _opt == 'DIM_PRIMARY_PRECISION' or _opt == 'DIM_SECONDARY_PRECISION' or _opt == 'DIM_PRIMARY_UNITS' or _opt == 'DIM_SECONDARY_UNITS' or _opt == 'DIM_POSITION' or _opt == 'DIM_ENDPOINT' or _opt == 'RADIAL_DIM_PRIMARY_PREFIX' or _opt == 'RADIAL_DIM_PRIMARY_SUFFIX' or _opt == 'RADIAL_DIM_SECONDARY_PREFIX' or _opt == 'RADIAL_DIM_SECONDARY_SUFFIX' or _opt == 'ANGULAR_DIM_PRIMARY_PREFIX' or _opt == 'ANGULAR_DIM_PRIMARY_SUFFIX' or _opt == 'ANGULAR_DIM_SECONDARY_PREFIX' or _opt == 'ANGULAR_DIM_SECONDARY_SUFFIX'): if _val != _cv: _set = True elif (_opt == 'DIM_PRIMARY_TEXT_SIZE' or _opt == 'DIM_SECONDARY_TEXT_SIZE' or _opt == 'DIM_OFFSET' or _opt == 'DIM_EXTENSION' or _opt == 'DIM_THICKNESS' or _opt == 'DIM_ENDPOINT_SIZE'): if abs(_val - _cv) > 1e-10: _set = True elif (_opt == 'DIM_PRIMARY_LEADING_ZERO' or _opt == 'DIM_SECONDARY_LEADING_ZERO' or _opt == 'DIM_PRIMARY_TRAILING_DECIMAL' or _opt == 'DIM_SECONDARY_TRAILING_DECIMAL' or _opt == 'DIM_DUAL_MODE' or _opt == 'RADIAL_DIM_DIA_MODE'): if ((_val is False and _cv is True) or (_val is True and _cv is False)): _set = True elif (_opt == 'DIM_COLOR' or _opt == 'DIM_PRIMARY_FONT_COLOR' or _opt == 'DIM_SECONDARY_FONT_COLOR'): if _val != _cv.getColors(): _r, _g, _b = _val _val = color.Color(_r, _g, _b) elif (_opt == 'DIM_PRIMARY_TEXT_ANGLE' or _opt == 'DIM_SECONDARY_TEXT_ANGLE' or _opt == 'DIM_POSITION_OFFSET' or _opt == 'DIM_DUAL_MODE_OFFSET'): pass else: raise RuntimeError, "Unexpected DimStyle option: '%s'" % _opt if _set: _image.setOption(_opt, _val) _dialog.destroy() _gds.clear() PythonCAD-DS1-R37/PythonCAD/Interface/Gtk/gtkentities.py0000644000175000017500000017425211307666732022321 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Art Haas # # 2009 Matteo Boscolo # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # menu functions for creating entities in drawing # like segments, circles, etc ... # from math import hypot, pi, atan2 import pygtk pygtk.require('2.0') import gtk import gobject import math import sys from PythonCAD.Generic import globals from PythonCAD.Generic.point import Point from PythonCAD.Generic.segment import Segment from PythonCAD.Generic.segjoint import Chamfer, Fillet from PythonCAD.Generic import color from PythonCAD.Generic import util from PythonCAD.Generic import units from PythonCAD.Interface.Gtk import gtkDialog from PythonCAD.Generic import tools from PythonCAD.Generic import snap def make_tuple(text, gdict): _tpl = eval(text, gdict) if not isinstance(_tpl, tuple): raise TypeError, "Invalid tuple: " + `type(_tpl)` if len(_tpl) != 2: raise ValueError, "Invalid tuple: " + str(_tpl) return _tpl def create_entity(gtkimage, tool=None): _tool = gtkimage.getImage().getTool() _init_func = _tool.getHandler("initialize") _image = gtkimage.getImage() _image.startAction() try: _tool.create(_image) finally: _image.endAction() _init_func(gtkimage) # # points # def point_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() snap.setSnap(_image,tool.setPoint,_tol) create_entity(gtkimage) return True def point_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) tool.setPoint(_x, _y) create_entity(gtkimage) def point_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter the point.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", point_mode_init) _tool.setHandler("button_press", point_button_press_cb) _tool.setHandler("entry_event", point_entry_event_cb) # # segments # def segment_motion_notify_cb(gtkimage, widget, event, tool): """ Segment notify motion event """ _segs = [] _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _x1, _y1 = tool.getFirstPoint().point.getCoords() _px1, _py1 = gtkimage.coordToPixTransform(_x1, _y1) # # manage horizontal vertical angle forced # _x,_y = gtkimage.pixToCoordTransform(_x,_y) _x,_y = trasformCoords(_x1, _y1,_x,_y,tool.direction) _x,_y = gtkimage.coordToPixTransform(_x, _y) _cp = tool.getCurrentPoint() if _cp is not None: # draw the old line _xc, _yc = _cp _segs.append((_px1, _py1, _xc, _yc)) tool.setCurrentPoint(_x, _y) _segs.append((_px1, _py1, _x, _y)) widget.window.draw_segments(_gc, _segs) return True def trasformCoords(x,y,x1,y1,angle): """ trasform the given cordinate with en angle useful in case you whont to force a segment to be in a partuicular direction """ _x=x1 _y=y1 if angle is not None: if angle == 90.0 or angle == 270.0: _x=x elif angle == 0.0 or angle == 180.0: _y=y else: _radDir=(math.pi*angle)/180 _tan=math.tan(_radDir)*abs(x-x1) if x>x1: _y=y-_tan _x=x-abs(x-x1) else: _y=y+_tan _x=x+abs(x-x1) return _x,_y def segment_set_direction(text,tool): """ parse the text and set the direction into the tool """ if isinstance(text,str) : if text.find(':') >0 : cmdArgs=text.split(':') if len(cmdArgs)==2: _firstArgs=cmdArgs[0].strip().lower() if _firstArgs == 'd' : _r = setSegmentDirection(tool,cmdArgs[1]) return _r return False def setSegmentDirection(tool,angle): """ set the segment direction """ if str(angle).strip().lower() == "n" : tool.direction=None return False else: tool.direction=angle return True def segment_second_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() if segment_set_direction(_text,tool): tool.setHandler("button_press", segment_second_button_press_cb) tool.setHandler("motion_notify", segment_motion_notify_cb) tool.setHandler("entry_event", segment_second_entry_event_cb) _dir=str(tool.direction) gtkimage.setPrompt(_('Segmend d ' + _dir + 'Enter the second Point or click in the drawing area')) _entry.delete_text(0, -1) gtkimage.redraw() return _entry.delete_text(0, -1) if len(_text): try: _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) except: if _text.strip()!="d:n" : gtkDialog._message_dialog(gtkimage,"Wrong comand","inser a touple of values x,y") return _str=snap.SnapPointStr("Freepoint",Point(_x, _y),None) tool.setSecondPoint(_str) create_entity(gtkimage) def segment_first_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) _str=snap.SnapPointStr("Freepoint",Point(_x, _y),None) tool.setFirstPoint(_str) tool.setHandler("button_press", segment_second_button_press_cb) tool.setHandler("motion_notify", segment_motion_notify_cb) tool.setHandler("entry_event", segment_second_entry_event_cb) gtkimage.setPrompt(_('Enter the second Point or click in the drawing area')) gtkimage.getGC().set_function(gtk.gdk.INVERT) def segment_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() snap.setSnap(_image,tool.setSecondPoint,_tol) if tool.direction is not None: _x,_y=tool.getFirstPoint().point.getCoords() _x1,_y1=tool.getSecondPoint().point.getCoords() _x1,_y1=trasformCoords(_x,_y,_x1,_y1,tool.direction) _strP=snap.SnapPointStr("Freepoint",Point(_x1,_y1),"None") tool.setSecondPoint(_strP) try: create_entity(gtkimage) tool.direction=None except: tool.setHandler("button_press", segment_second_button_press_cb) tool.setHandler("entry_event", segment_second_entry_event_cb) tool.setHandler("motion_notify", segment_motion_notify_cb) gtkimage.setPrompt(_('Enter the second point or click in the drawing area')) return True def segment_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() snap.setSnap(_image,tool.setFirstPoint,_tol) tool.setHandler("button_press", segment_second_button_press_cb) tool.setHandler("entry_event", segment_second_entry_event_cb) tool.setHandler("motion_notify", segment_motion_notify_cb) gtkimage.setPrompt(_('Enter the second point or click in the drawing area')) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True def segment_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter a point.')) _tool = gtkimage.getImage().getTool() _tool.direction=None _tool.setHandler("initialize", segment_mode_init) _tool.setHandler("button_press", segment_first_button_press_cb) _tool.setHandler("entry_event", segment_first_entry_event_cb) # # rectangles # def rectangle_motion_notify_cb(gtkimage, widget, event, tool): _x1, _y1 = tool.getFirstPoint().point.getCoords() _px, _py = gtkimage.coordToPixTransform(_x1, _y1) _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _cp = tool.getCurrentPoint() if _cp is not None: _xc, _yc = _cp _xmin = min(_px, _xc) _ymin = min(_py, _yc) _width = abs(_px - _xc) _height = abs(_py - _yc) widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _width, _height) tool.setCurrentPoint(_x, _y) _xmin = min(_px, _x) _ymin = min(_py, _y) _width = abs(_px - _x) _height = abs(_py - _y) widget.window.draw_rectangle(_gc, False, _xmin, _ymin, _width, _height) return True def rectangle_second_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) tool.setSecondPoint(_x, _y) create_entity(gtkimage) def rectangle_first_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) tool.setFirstPoint(_x, _y) tool.setHandler("button_press", rectangle_second_button_press_cb) tool.setHandler("entry_event", rectangle_second_entry_event_cb) tool.setHandler("motion_notify", rectangle_motion_notify_cb) gtkimage.setPrompt(_('Enter the second Point or click in the drawing area')) gtkimage.getGC().set_function(gtk.gdk.INVERT) def rectangle_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() snap.setSnap(_image,tool.setSecondPoint,_tol) create_entity(gtkimage) return True def rectangle_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() snap.setSnap(_image,tool.setFirstPoint,_tol) tool.setHandler("button_press", rectangle_second_button_press_cb) tool.setHandler("motion_notify", rectangle_motion_notify_cb) tool.setHandler("entry_event", rectangle_second_entry_event_cb) gtkimage.setPrompt(_('Enter the second point or click in the drawing area')) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True def rectangle_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter a point.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", rectangle_mode_init) _tool.setHandler("button_press", rectangle_first_button_press_cb) _tool.setHandler("entry_event", rectangle_first_entry_event_cb) # # circles # def circle_center_motion_notify_cb(gtkimage, widget, event, tool): _cx, _cy = tool.center.point.getCoords() _pcx, _pcy = gtkimage.coordToPixTransform(_cx, _cy) _upp = gtkimage.getUnitsPerPixel() _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _radius = tool.getRadius() if _radius is not None: _pr = int(_radius/_upp) _xmin = _pcx - _pr _ymin = _pcy - _pr _cw = _ch = _pr * 2 widget.window.draw_arc(_gc, False, _xmin, _ymin, _cw, _ch, 0, 360*64) _ix, _iy = gtkimage.image.getCurrentPoint() _radius = hypot((_cx - _ix),(_cy - _iy)) if _radius<0.0: print "Debug: R: "+ str(_radius) _radius=0.1 # Convention if radius is less the 0 i assume 0.1 tool.setRadius(_radius) _pr = int(_radius/_upp) _xmin = _pcx - _pr _ymin = _pcy - _pr _cw = _ch = _pr * 2 widget.window.draw_arc(_gc, False, _xmin, _ymin, _cw, _ch, 0, 360*64) return True def circle_radius_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _r = util.get_float(eval(_text, gtkimage.image.getImageVariables())) if not _r > 0.0: raise ValueError, "Invalid radius: %g" % _r tool.setRadius(_r) create_entity(gtkimage) def circle_point_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) tool.setCenter(_x, _y) tool.setHandler("button_press", circle_radius_button_press_cb) tool.setHandler("motion_notify", circle_center_motion_notify_cb) tool.setHandler("entry_event", circle_radius_entry_event_cb) gtkimage.setPrompt(_('Enter the radius or click in the drawing area')) gtkimage.getGC().set_function(gtk.gdk.INVERT) #stop snap object stopOneShutSnap(gtkimage) def circle_radius_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() snap.setSnap(_image,tool.setRadiusPoint,_tol) _x,_y=tool.radiusPoint.point.getCoords() _cx,_cy=tool.getCenter().point.getCoords() _radius = hypot((_cx - _x), (_cy - _y)) tool.setRadius(_radius) create_entity(gtkimage) return True def circle_center_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setCenter,_tol,_snapArray) tool.setHandler("button_press", circle_radius_button_press_cb) tool.setHandler("motion_notify", circle_center_motion_notify_cb) tool.setHandler("entry_event", circle_radius_entry_event_cb) gtkimage.setPrompt(_('Enter the radius or click in the drawing area')) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True def circle_center_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter a point.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", circle_center_button_press_cb) _tool.setHandler("entry_event", circle_point_entry_event_cb) _tool.setHandler("initialize", circle_center_mode_init) # # circle from two points # def circle_tp_motion_notify_cb(gtkimage, widget, event, tool): _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _radius = tool.getRadius() _upp = gtkimage.getUnitsPerPixel() if _radius is not None: _cx, _cy = tool.getCenter().point.getCoords() _pcx, _pcy = gtkimage.coordToPixTransform(_cx, _cy) _pr = int(_radius/_upp) _xmin = _pcx - _pr _ymin = _pcy - _pr _cw = _ch = _pr * 2 widget.window.draw_arc(_gc, False, _xmin, _ymin, _cw, _ch,0, 360*64) snap.setDinamicSnap(gtkimage,tool.setSecondPoint,None) _cx, _cy = tool.getCenter().point.getCoords() _pcx, _pcy = gtkimage.coordToPixTransform(_cx, _cy) _radius = tool.getRadius() _pr = int(_radius/_upp) _xmin = _pcx - _pr _ymin = _pcy - _pr _cw = _ch = _pr * 2 widget.window.draw_arc(_gc, False, _xmin, _ymin, _cw, _ch,0, 360*64) return True def circle_tp_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() #todo imlement the tangent snap for the two point circle _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setSecondPoint,_tol,_snapArray) create_entity(gtkimage) return True def circle_tp_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() #todo imlement the tangent snap for the two point circle _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setFirstPoint,_tol,_snapArray) tool.setHandler("button_press", circle_tp_second_button_press_cb) tool.setHandler("motion_notify", circle_tp_motion_notify_cb) tool.setHandler("entry_event", circle_tp_second_entry_event_cb) gtkimage.setPrompt(_('Enter the second point or click in the drawing area')) gtkimage.getGC().set_function(gtk.gdk.INVERT) return True def circle_tp_second_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) tool.setSecondPoint(_x, _y) create_entity(gtkimage) def circle_tp_first_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) tool.setFirstPoint(_x, _y) tool.setHandler("motion_notify", circle_tp_motion_notify_cb) tool.setHandler("entry_event", circle_tp_second_entry_event_cb) gtkimage.setPrompt(_('Enter another point or click in the drawing area')) gtkimage.getGC().set_function(gtk.gdk.INVERT) def circle_tp_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter a point.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", circle_tp_first_button_press_cb) _tool.setHandler("entry_event", circle_tp_first_entry_event_cb) _tool.setHandler("initialize", circle_tp_mode_init) # # arcs # def arc_center_end_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _snp=snap.getSnapPoint(_image,_tol,_snapArray) _x,_y=_snp.point.getCoords() _cx, _cy = tool.getCenter().point.getCoords() _angle = (180.0/pi) * atan2((_y - _cy),(_x - _cx)) if _angle < 0.0: _angle = _angle + 360.0 tool.setEndAngle(_angle) create_entity(gtkimage) return True def arc_angle_motion_notify_cb(gtkimage, widget, event, tool): _ix, _iy = gtkimage.image.getCurrentPoint() _cx, _cy = tool.getCenter().point.getCoords() # arc center _radius = tool.getRadius() _sa = tool.getStartAngle() _pcx, _pcy = gtkimage.coordToPixTransform(_cx, _cy) _upp = gtkimage.getUnitsPerPixel() _pr = int(_radius/_upp) _xmin = _pcx - _pr _ymin = _pcy - _pr _cw = _ch = _pr * 2 _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _ea = tool.getEndAngle() _win = widget.window if _ea is not None: if _sa < _ea: _sweep = _ea - _sa else: _sweep = 360.0 - (_sa - _ea) _win.draw_arc(_gc, False, _xmin, _ymin, _cw, _ch, int(_sa * 64), int(_sweep * 64)) _ea = (180.0/pi) * atan2((_iy - _cy), (_ix - _cx)) if _ea < 0.0: _ea = _ea + 360.0 tool.setEndAngle(_ea) if _sa < _ea: _sweep = _ea - _sa else: _sweep = 360.0 - (_sa - _ea) _win.draw_arc(_gc, False, _xmin, _ymin, _cw, _ch, int(_sa * 64), int(_sweep * 64)) return True def arc_start_angle_button_press_cb(gtkimage, widget, event, tool): _cx, _cy = tool.getCenter() _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _snp=snap.getSnapPoint(_image,_tol,_snapArray) _x,_y=_snp.point.getCoords() _angle = (180.0/pi) * atan2((_y - _cy), (_x - _cx)) if _angle < 0.0: _angle = _angle + 360.0 tool.setStartAngle(_angle) tool.setHandler("motion_notify", arc_angle_motion_notify_cb) tool.setHandler("entry_event", arc_center_ea_entry_event_cb) gtkimage.setPrompt(_('Enter the end angle of the arc.')) return True def arc_center_ea_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _angle = util.make_c_angle(eval(_text, gtkimage.image.getImageVariables())) tool.setEndAngle(_angle) create_entity(gtkimage) def arc_center_sa_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _angle = util.make_c_angle(eval(_text, gtkimage.image.getImageVariables())) tool.setStartAngle(_angle) tool.setHandler("motion_notify", arc_angle_motion_notify_cb) tool.setHandler("entry_event", arc_center_ea_entry_event_cb) gtkimage.setPrompt(_('Enter the end angle of the arc.')) def arc_center_radius_button_press_cb(gtkimage, widget, event, tool): _cx, _cy = tool.getCenter().point.getCoords() _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} _snp=snap.getSnapPoint(_image,_tol,_snapArray) _x,_y=_snp.point.getCoords() _radius = hypot((_x - _cx), (_y - _cy)) tool.setRadius(_radius) _angle = (180.0/pi) * atan2((_y - _cy), (_x - _cx)) if _angle < 0.0: _angle = _angle + 360.0 tool.setStartAngle(_angle) tool.delHandler("entry_event") tool.setHandler("motion_notify", arc_angle_motion_notify_cb) gtkimage.refresh() gtkimage.getGC().set_function(gtk.gdk.INVERT) tool.setHandler("button_press", arc_center_end_button_press_cb) gtkimage.setPrompt(_('Click in the drawing area to finish the arc')) return True def arc_center_radius_entry_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _r = util.get_float(eval(_text, gtkimage.image.getImageVariables())) if not _r > 0.0: raise ValueError, "Invalid radius: %g" % _r tool.setRadius(_r) tool.setHandler("entry_event", arc_center_sa_entry_event_cb) tool.setHandler("button_press", arc_start_angle_button_press_cb) gtkimage.setPrompt(_('Enter the start angle of the arc.')) def arc_radius_motion_notify_cb(gtkimage, widget, event, tool): _cx, _cy = tool.getCenter().point.getCoords() _pcx, _pcy = gtkimage.coordToPixTransform(_cx, _cy) _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _radius = tool.getRadius() _upp = gtkimage.getUnitsPerPixel() if _radius is not None: _pr = int(_radius/_upp) _xmin = _pcx - _pr _ymin = _pcy - _pr _cw = _ch = _pr * 2 widget.window.draw_arc(_gc, False, _xmin, _ymin, _cw, _ch, 0, 360*64) _ix, _iy = gtkimage.image.getCurrentPoint() _radius = hypot((_cx - _ix), (_cy - _iy)) tool.setRadius(_radius) _pr = int(_radius/_upp) _xmin = _pcx - _pr _ymin = _pcy - _pr _cw = _ch = _pr * 2 widget.window.draw_arc(_gc, False, _xmin, _ymin, _cw, _ch, 0, 360*64) return True def arc_center_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setCenter,_tol,_snapArray) gtkimage.getGC().set_function(gtk.gdk.INVERT) tool.setHandler("motion_notify", arc_radius_motion_notify_cb) tool.setHandler("entry_event", arc_center_radius_entry_cb) tool.setHandler("button_press", arc_center_radius_button_press_cb) gtkimage.setPrompt(_('Enter the radius or click in the drawing area')) return True def arc_center_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) tool.setCenter(_x, _y) gtkimage.getGC().set_function(gtk.gdk.INVERT) tool.setHandler("motion_notify", arc_radius_motion_notify_cb) tool.setHandler("button_press", arc_center_radius_button_press_cb) tool.setHandler("entry_event", arc_center_radius_entry_cb) gtkimage.setPrompt(_('Enter the arc radius or click in the drawing area')) def arc_center_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area or enter a point.')) _tool = gtkimage.getImage().getTool() _tool.setHandler("button_press", arc_center_button_press_cb) _tool.setHandler("entry_event", arc_center_entry_event_cb) _tool.setHandler("initialize", arc_center_mode_init) # # chamfers # def chamfer_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _pt, _new_pt = _image.findPoint(_x, _y, _tol) if _pt is not None and not _new_pt: _active_layer = _image.getActiveLayer() _users = _pt.getUsers() if len(_users) != 2: return _s1 = _s2 = None for _user in _users: if not isinstance(_user, Segment): return if _s1 is None: _s1 = _user else: _s2 = _user _len = _image.getOption('CHAMFER_LENGTH') _s = _image.getOption('LINE_STYLE') _l = _image.getOption('LINE_TYPE') _c = _image.getOption('LINE_COLOR') _t = _image.getOption('LINE_THICKNESS') # # the following is a work-around that needs to # eventually be replaced ... # _p1, _p2 = _s1.getEndpoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _slen = _s1.length() _factor = 2.0 _r = (_slen - (_len/_factor))/_slen _xn = _x1 + _r * (_x2 - _x1) _yn = _y1 + _r * (_y2 - _y1) _pts = _active_layer.find('point', _xn, _yn) while len(_pts) > 0: _factor = _factor + 1.0 if _factor > 1000: break _r = (_slen - (_len/_factor))/_slen _xn = _x1 + _r * (_x2 - _x1) _yn = _y1 + _r * (_y2 - _y1) _pts = _active_layer.find('point', _xn, _yn) if len(_pts) == 0: _image.startAction() try: _pc = Point(_xn, _yn) _active_layer.addObject(_pc) if _pt is _p1: _s1.setP1(_pc) elif _pt is _p2: _s1.setP2(_pc) else: raise ValueError, "Unexpected endpoint: " + str(_pc) _ptx, _pty = _pt.getCoords() _pc.setCoords(_ptx, _pty) _chamfer = Chamfer(_s1, _s2, _len, _s) if _l != _s.getLinetype(): _chamfer.setLinetype(_l) if _c != _s.getColor(): _chamfer.setColor(_c) if abs(_t - _s.getThickness()) > 1e-10: _chamfer.setThickness(_t) _active_layer.addObject(_chamfer) finally: _image.endAction() return True def chamfer_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click on the points where you want a chamfer.')) _tool = gtkimage.getImage().getTool() _tool.initialize() _tool.setHandler("button_press", chamfer_button_press_cb) # # fillet # def fillet_entry_event_cb(gtkimage, widget, tool): """ Manage the radius entered from the entry """ _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text)>3: if _text.find(':') >0 : cmdArgs=_text.split(':') if len(cmdArgs)==2: _firstArgs=cmdArgs[0].strip().lower() if _firstArgs == 'r' : setFilletRadius(gtkimage,tool,cmdArgs[1]) return elif _firstArgs == 'tm': setTrimMode(gtkimage,tool,cmdArgs[1]) return if _text.find('?') >= 0: gtkDialog._help_dialog(gtkimage,"FilletTwoPoint") return gtkDialog._error_dialog(gtkimage,"Wrong command") def setTrimMode(gtkimage,tool,mode): """ set the trim fillet mode """ _mode=mode.strip().lower() if _mode=='f' : tool.TrimMode="f" elif _mode=='s' : tool.TrimMode="s" elif _mode=='b' : tool.TrimMode="b" elif _mode=='n' : tool.TrimMode="n" else: gtkDialog._error_dialog(gtkimage,"Wrong command") return fillet_prompt_message(gtkimage,tool) def setFilletRadius(gtkimage,tool,radius): """ set the fillet radius in to the tool """ _r=radius.strip() rad=float(_r) tool.rad=rad fillet_prompt_message(gtkimage,tool) def fillet_prompt_message(gtkimage,tool,startMessage=None): """ set the fillet message """ if startMessage == None: _oldMsg=gtkimage.getPrompt() else: _oldMsg=startMessage if isinstance(tool,tools.FilletTool): _msg =_oldMsg.split('(')[0] + '( r: ' + str(tool.rad) + ' )' + _oldMsg.split(')')[1] if isinstance(tool,tools.FilletTwoLineTool): _msg=_oldMsg.split('(')[0] + '( r: ' + str(tool.rad) + ' tm: ' + str(tool.TrimMode) + ' )' + _oldMsg.split(')')[1] gtkimage.setPrompt(_msg) def fillet_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _x, _y = _image.getCurrentPoint() _pt, _new_pt = _image.findPoint(_x, _y, _tol) if _pt is not None and not _new_pt: _active_layer = _image.getActiveLayer() _users = _pt.getUsers() if len(_users) != 2: return _s1 = _s2 = None for _user in _users: if not isinstance(_user, Segment): return if _s1 is None: _s1 = _user else: _s2 = _user if(tool.rad!=None): _rad = tool.rad else: _rad = _image.getOption('FILLET_RADIUS') _s = _image.getOption('LINE_STYLE') _l = _image.getOption('LINE_TYPE') _c = _image.getOption('LINE_COLOR') _t = _image.getOption('LINE_THICKNESS') # # the following is a work-around that needs to # eventually be replaced ... # _p1, _p2 = _s1.getEndpoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _slen = _s1.length() _factor = 2.0 _r = 1.0 - (_slen/_factor) _xn = _x1 + _r * (_x2 - _x1) _yn = _y1 + _r * (_y2 - _y1) _pts = _active_layer.find('point', _xn, _yn) while len(_pts) > 0: _factor = _factor + 1.0 if _factor > 1000: break _r = 1.0 - (_slen/_factor) _xn = _x1 + _r * (_x2 - _x1) _yn = _y1 + _r * (_y2 - _y1) _pts = _active_layer.find('point', _xn, _yn) if len(_pts) == 0: _image.startAction() try: _pc = Point(_xn, _yn) _active_layer.addObject(_pc) if _pt is _p1: _s1.setP1(_pc) elif _pt is _p2: _s1.setP2(_pc) else: raise ValueError, "Unexpected endpoint: " + str(_pc) _ptx, _pty = _pt.getCoords() _pc.setCoords(_ptx, _pty) _fillet = Fillet(_s1, _s2, _rad, _s) if _l != _s.getLinetype(): _fillet.setLinetype(_l) if _c != _s.getColor(): _fillet.setColor(_c) if abs(_t - _s.getThickness()) > 1e-10: _fillet.setThickness(_t) _active_layer.addObject(_fillet) finally: _image.endAction() gtkimage.redraw() return True def fillet_mode_init(gtkimage, tool=None): """ Init function for the fillet comand """ _image = gtkimage.getImage() if tool!= None and tool.rad!=None: _rad = tool.rad else: _rad = _image.getOption('FILLET_RADIUS') _tool = gtkimage.getImage().getTool() _msg = 'Click on the points where you want a fillet( ) or enter the Radius.' _tool.initialize() _tool.rad=_rad fillet_prompt_message(gtkimage,_tool,_msg) _tool.setHandler("initialize", fillet_mode_init) _tool.setHandler("button_press", fillet_button_press_cb) _tool.setHandler("entry_event", fillet_entry_event_cb) # # Fillet two line # def fillet_two_button_second_press_cb(gtkimage, widget, event, tool): """ Second selection commad """ _image = gtkimage.getImage() _objs,pnt=snap.getSelections(gtkimage,Segment) if _objs!=None and pnt!=None: _image.startAction() try: tool.SecondLine=_objs tool.SecondPoint=pnt tool.Create(_image) except ValueError,err: _errmsg = "Fillet ValueError error: %s" % str(err) gtkDialog._error_dialog(gtkimage,_errmsg ) except: _errmsg = "Fillet error: %s" % str( sys.exc_info()[0]) gtkDialog._error_dialog(gtkimage,_errmsg ) for s in sys.exc_info(): print "Exception Error: %s"%str(s) finally: _image.endAction() gtkimage.redraw() fillet_two_line_mode_init(gtkimage,tool) def fillet_two_button_press_cb(gtkimage, widget, event, tool): """ First Entity selected """ _image = gtkimage.getImage() _objs,pnt=snap.getSelections(gtkimage,Segment) if _objs!=None and pnt!=None: _image.startAction() try: tool.FirstLine=_objs tool.FirstPoint=pnt if(tool.rad!=None): _rad = tool.rad _mod=tool.TrimMode else: _rad = _image.getOption('FILLET_RADIUS') _mod = _image.getOption('FILLET_TWO_TRIM_MODE') _msg = 'Click on the Second Entity ( ) or enter command options.' fillet_prompt_message(gtkimage,tool,_msg) tool.setHandler("button_press", fillet_two_button_second_press_cb) # finally: _image.endAction() def fillet_two_line_mode_init(gtkimage, tool=None): """ init function for the fillet two line comand """ _image = gtkimage.getImage() if tool !=None and tool.rad!=None: _rad = tool.rad _tool=tool else: _rad = _image.getOption('FILLET_RADIUS') _tool = gtkimage.getImage().getTool() _msg = 'Click on the first Entity ( ) or enter command options.' _tool.initialize() _tool.rad=_rad fillet_prompt_message(gtkimage,_tool,_msg) _tool.setHandler("initialize", fillet_two_line_mode_init) _tool.setHandler("button_press", fillet_two_button_press_cb) _tool.setHandler("entry_event", fillet_entry_event_cb) gtkimage._activateSnap=False # # leader lines # def leader_second_motion_notify_cb(gtkimage, widget, event, tool): _segs = [] _x2, _y2 = tool.getMidPoint().point.getCoords() _px2, _py2 = gtkimage.coordToPixTransform(_x2, _y2) _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _cp = tool.getCurrentPoint() if _cp is not None: _xc, _yc = _cp _segs.append((_px2, _py2, _xc, _yc)) tool.setCurrentPoint(_x, _y) _segs.append((_px2, _py2, _x, _y)) widget.window.draw_segments(_gc, _segs) return True def leader_first_motion_notify_cb(gtkimage, widget, event, tool): _segs = [] _x1, _y1 = tool.getFirstPoint().point.getCoords() _px1, _py1 = gtkimage.coordToPixTransform(_x1, _y1) _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _cp = tool.getCurrentPoint() if _cp is not None: _xc, _yc = _cp _segs.append((_px1, _py1, _xc, _yc)) tool.setCurrentPoint(_x, _y) _segs.append((_px1, _py1, _x, _y)) widget.window.draw_segments(_gc, _segs) def leader_final_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setFinalPoint,_tol,_snapArray) create_entity(gtkimage) gtkimage.setPrompt(_('Click in the drawing area to place the initial point')) return True def leader_second_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setMidPoint,_tol,_snapArray) tool.clearCurrentPoint() tool.setHandler("motion_notify", leader_second_motion_notify_cb) tool.setHandler("button_press", leader_final_button_press_cb) gtkimage.setPrompt(_('Click in the drawing area to place the final point')) return True def leader_first_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setFirstPoint,_tol,_snapArray) tool.setHandler("motion_notify", leader_first_motion_notify_cb) tool.setHandler("button_press", leader_second_button_press_cb) gtkimage.getGC().set_function(gtk.gdk.INVERT) gtkimage.setPrompt(_('Click in the drawing area to place the second point')) return True def leader_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area to enter the first point')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", leader_mode_init) _tool.setHandler("button_press", leader_first_button_press_cb) # # polylines # def polyline_motion_notify_cb(gtkimage, widget, event, tool): _segs = [] _x1, _y1 = tool.getPoint(-1).point.getCoords() _px1, _py1 = gtkimage.coordToPixTransform(_x1, _y1) _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _cp = tool.getCurrentPoint() if _cp is not None: _xc, _yc = _cp _segs.append((_px1, _py1, _xc, _yc)) tool.setCurrentPoint(_x, _y) _segs.append((_px1, _py1, _x, _y)) widget.window.draw_segments(_gc, _segs) return True def polyline_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() tool.clearCurrentPoint() snap.setSnap(_image,tool.storePoint,_tol,None) _state = event.state if ((_state & gtk.gdk.SHIFT_MASK) == gtk.gdk.SHIFT_MASK): create_entity(gtkimage) else: tool.setHandler("motion_notify", polyline_motion_notify_cb) gtkimage.getGC().set_function(gtk.gdk.INVERT) gtkimage.setPrompt(_('Click to place the next point. Shift-click to finish polyline')) return True def polyline_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): if _text == 'end': create_entity(gtkimage) else: _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) tool.setPoint(_x, _y) tool.setHandler("motion_notify", polyline_motion_notify_cb) gtkimage.getGC().set_function(gtk.gdk.INVERT) gtkimage.setPrompt(_('Click to place the next point. Shift-click to finish polyline.')) def polyline_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area to enter the first point')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", polyline_mode_init) _tool.setHandler("entry_event", polyline_entry_event_cb) _tool.setHandler("button_press", polyline_button_press_cb) # # polygons # def polygon_radius_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setLocation,_tol,_snapArray) create_entity(gtkimage) return True def polygon_radius_motion_notify_cb(gtkimage, widget, event, tool): _segs = [] _gc = gtkimage.getGC() _x = int(event.x) _y = int(event.y) _cp = tool.getCurrentPoint() _count = tool.getSideCount() if _cp is not None: _tx0, _ty0 = tool.getCoord(0) _px0, _py0 = gtkimage.coordToPixTransform(_tx0, _ty0) _px1 = _px0 _py1 = _py0 for _i in range(1, _count): _txi, _tyi = tool.getCoord(_i) _pxi, _pyi = gtkimage.coordToPixTransform(_txi, _tyi) _segs.append((_px1, _py1, _pxi, _pyi)) _px1 = _pxi _py1 = _pyi _segs.append((_px1, _py1, _px0, _py0)) tool.setCurrentPoint(_x, _y) _snapArray={'perpendicular':False,'tangent':False} snap.setDinamicSnap(gtkimage,tool.setLocation,_snapArray) _tx0, _ty0 = tool.getCoord(0) _px0, _py0 = gtkimage.coordToPixTransform(_tx0, _ty0) _px1 = _px0 _py1 = _py0 for _i in range(1, _count): _txi, _tyi = tool.getCoord(_i) _pxi, _pyi = gtkimage.coordToPixTransform(_txi, _tyi) _segs.append((_px1, _py1, _pxi, _pyi)) _px1 = _pxi _py1 = _pyi _segs.append((_px1, _py1, _px0, _py0)) widget.window.draw_segments(_gc, _segs) return True def polygon_center_button_press_cb(gtkimage, widget, event, tool): _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _snapArray={'perpendicular':False,'tangent':False} snap.setSnap(_image,tool.setCenter,_tol,_snapArray) tool.setHandler("motion_notify", polygon_radius_motion_notify_cb) tool.setHandler("button_press", polygon_radius_button_press_cb) gtkimage.getGC().set_function(gtk.gdk.INVERT) gtkimage.setPrompt(_('Click in the drawing area to place the second point')) return True def polygon_center_entry_event_cb(gtkimage, widget, tool): _entry = gtkimage.getEntry() _text = _entry.get_text() _entry.delete_text(0,-1) if len(_text): _x, _y = make_tuple(_text, gtkimage.image.getImageVariables()) tool.setCenter(_x, _y) tool.setHandler("motion_notify", polygon_radius_motion_notify_cb) gtkimage.getGC().set_function(gtk.gdk.INVERT) tool.setHandler("button_press", polygon_radius_button_press_cb) tool.delHandler("entry_event") # ??? gtkimage.setPrompt(_('Click in the drawing area to draw the polygon')) def polygon_mode_init(gtkimage, tool=None): gtkimage.setPrompt(_('Click in the drawing area to define the center')) _tool = gtkimage.getImage().getTool() _tool.setHandler("initialize", polygon_mode_init) _tool.setHandler("entry_event", polygon_center_entry_event_cb) _tool.setHandler("button_press", polygon_center_button_press_cb) # # set the active style # def set_active_style(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Set Active Style'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Style:')) _image = gtkimage.getImage() _cur_style = _image.getOption('LINE_STYLE') _styles = _image.getImageEntities("style") _idx = 0 if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_styles)): _s = _styles[_i] if _s is _cur_style: _idx = _i _widget.append_text(_s.getName()) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_styles)): _s = _styles[_i] if _s is _cur_style: _idx = _i _item = gtk.MenuItem(_s.getName()) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) _hbox.pack_start(_label, False, False, 0) _hbox.pack_start(_widget, True, True, 0) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: if isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected widget: " + `type(_widget)` _image.setOption('LINE_STYLE', _styles[_idx]) _dialog.destroy() # # set the current color # def set_active_color(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.ColorSelectionDialog(_('Set Active Color')) _dialog.set_transient_for(_window) _colorsel = _dialog.colorsel _image = gtkimage.getImage() _prev_color = _image.getOption('LINE_COLOR') _gtk_color = gtkimage.getColor(_prev_color) _colorsel.set_previous_color(_gtk_color) _colorsel.set_current_color(_gtk_color) _colorsel.set_has_palette(True) _response = _dialog.run() if _response == gtk.RESPONSE_OK: _gtk_color = _colorsel.get_current_color() _r = int(round((_gtk_color.red/65535.0) * 255.0)) _g = int(round((_gtk_color.green/65535.0) * 255.0)) _b = int(round((_gtk_color.blue/65535.0) * 255.0)) _color = None for _c in _image.getImageEntities('color'): if _c.r == _r and _c.g == _g and _c.b == _b: _color = _c break if _color is None: _color = color.Color(_r, _g, _b) _image.setOption('LINE_COLOR', _color) _dialog.destroy() # # set the current linetype # def set_active_linetype(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Set Active Linetype'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Linetype:')) _hbox.pack_start(_label, False, False, 0) _image = gtkimage.getImage() _cur_linetype = _image.getOption('LINE_TYPE') _linetypes = _image.getImageEntities("linetype") _idx = 0 if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_linetypes)): _lt = _linetypes[_i] if _lt is _cur_linetype: _idx = _i _widget.append_text(_lt.getName()) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_linetypes)): _lt = _linetypes[_i] if _lt is _cur_linetype: _idx = _i _item = gtk.MenuItem(_lt.getName()) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) _hbox.pack_start(_widget, True, True, 0) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: if isinstance(_widget, gtk.ComboBox): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected widget: " + `type(_widget)` _image.setOption('LINE_TYPE', _linetypes[_idx]) _dialog.destroy() # # set the current line thickness # def move_cursor(entry): entry.set_position(-1) return False def thickness_activate(entry): # this probably isn't a good choice ... entry.stop_emission("activate") def thickness_focus_out(entry, event): _text = entry.get_text() if _text == '-' or _text == '+': entry.delete_text(0, -1) return False def thickness_insert_text(entry, new_text, new_text_length, position): if (new_text.isdigit() or new_text == '.' or new_text == '+'): _string = entry.get_text() + new_text[:new_text_length] _hid = entry.get_data('handlerid') entry.handler_block(_hid) try: _pos = entry.get_position() if _string == '+': _pos = entry.insert_text(new_text, _pos) else: try: _val = float(_string) _pos = entry.insert_text(new_text, _pos) except StandardError, e: pass finally: entry.handler_unblock(_hid) if hasattr(gobject, 'idle_add'): gobject.idle_add(move_cursor, entry) else: gtk.idle_add(move_cursor, entry) entry.stop_emission("insert-text") def set_line_thickness(gtkimage): _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Set Line Thickness'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _dialog.vbox.pack_start(_hbox, False, False, 0) _label = gtk.Label(_('Thickness:')) _hbox.pack_start(_label, False, False, 0) _image = gtkimage.getImage() _thickness = "%g" % _image.getOption('LINE_THICKNESS') _entry = gtk.Entry() _entry.set_text(_thickness) _entry.connect("focus_out_event", thickness_focus_out) _entry.connect("activate", thickness_activate) _handlerid = _entry.connect("insert-text", thickness_insert_text) _entry.set_data('handlerid', _handlerid) _hbox.pack_start(_entry, True, True, 0) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: _text = _entry.get_text() _thickness = float(_text) _image.setOption('LINE_THICKNESS', _thickness) _dialog.destroy() # def _selectColor(button): _s = _('Select Color') _da = button.get_child().get_child() _color = _da.get_style().bg[gtk.STATE_NORMAL] _dialog = gtk.ColorSelectionDialog(_s) _colorsel = _dialog.colorsel _colorsel.set_previous_color(_color) _colorsel.set_current_color(_color) _colorsel.set_has_palette(True) _response = _dialog.run() if _response == gtk.RESPONSE_OK: _r, _g, _b = _get_rgb_values(_colorsel.get_current_color()) _str = "#%02x%02x%02x" % (_r, _g, _b) _color = gtk.gdk.color_parse(_str) _da.modify_bg(gtk.STATE_NORMAL, _color) _dialog.destroy() def _fill_color_dialog(dvbox, widgets): _lsg = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _frame = gtk.Frame(_('Color Settings')) _frame.set_border_width(2) _vbox = gtk.VBox(False, 2) _vbox.set_border_width(2) _frame.add(_vbox) # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, True, True, 2) _label = gtk.Label(_('Inactive Layer Color:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = widgets['INACTIVE_LAYER_COLOR'] _hbox.pack_start(_widget, False, False, 2) # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, True, True, 2) _label = gtk.Label(_('Background Color:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = widgets['BACKGROUND_COLOR'] _hbox.pack_start(_widget, False, False, 2) # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, True, True, 2) _label = gtk.Label(_('Single Point Color:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = widgets['SINGLE_POINT_COLOR'] _hbox.pack_start(_widget, False, False, 2) # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, True, True, 2) _label = gtk.Label(_('Multi-Point Color:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = widgets['MULTI_POINT_COLOR'] _hbox.pack_start(_widget, False, False, 2) # dvbox.pack_start(_frame, False, False, 2) def _selectColor(button): _s = _('Select Color') _da = button.get_child().get_child() _color = _da.get_style().bg[gtk.STATE_NORMAL] _dialog = gtk.ColorSelectionDialog(_s) _colorsel = _dialog.colorsel _colorsel.set_previous_color(_color) _colorsel.set_current_color(_color) _colorsel.set_has_palette(True) _response = _dialog.run() if _response == gtk.RESPONSE_OK: _r, _g, _b = _get_rgb_values(_colorsel.get_current_color()) _str = "#%02x%02x%02x" % (_r, _g, _b) _color = gtk.gdk.color_parse(_str) _da.modify_bg(gtk.STATE_NORMAL, _color) _dialog.destroy() def _get_color_da(): _widget = gtk.Button() _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_ETCHED_OUT) _frame.set_border_width(5) _widget.add(_frame) _da = gtk.DrawingArea() _da.set_size_request(20, 10) _widget.connect('clicked', _select_color) _frame.add(_da) return _widget def _get_widget(col): if hasattr(gtk, 'ColorButton'): _widget = gtk.ColorButton() _widget.set_color(col) else: _widget = _get_color_da() _widget.modify_bg(gtk.STATE_NORMAL, col) return _widget def _get_color_widgets(opts, im): _widgets = {} for _opt in opts: _color = gtk.gdk.color_parse(str(im.getOption(_opt))) _widgets[_opt] = _get_widget(_color) return _widgets def _get_color(widgets, key): _widget = widgets[key] if hasattr(gtk, 'ColorButton'): _color = _widget.get_color() elif isinstance(_widget, gtk.Button): _da = _widget.getChild().getChild() _color= _da.get_style().bg[gtk.STATE_NORMAL] else: raise TypeError, "Unexpected widget for '%s': " + (_key, `type(_widget)`) return _color def set_colors_dialog(gtkimage): _opts = ['INACTIVE_LAYER_COLOR', 'BACKGROUND_COLOR', 'SINGLE_POINT_COLOR', 'MULTI_POINT_COLOR'] _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Color Settings'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _image = gtkimage.getImage() _widgets = _get_color_widgets(_opts, _image) _fill_color_dialog(_dialog.vbox, _widgets) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: for _opt in _opts: _color = _get_color(_widgets, _opt) _r = int(round((_color.red/65535.0) * 255.0)) _g = int(round((_color.green/65535.0) * 255.0)) _b = int(round((_color.blue/65535.0) * 255.0)) if (_r, _g, _b) != _image.getOption(_opt).getColors(): _image.setOption(_opt, color.Color(_r, _g, _b)) _widgets.clear() _dialog.destroy() # def _size_move_cursor(entry): entry.set_position(-1) return False def _size_entry_activate(entry): _text = entry.get_text() entry.delete_text(0, -1) if len(_text): if _text == '-' or _text == '+': sys.stderr.write("Incomplete value: '%s'\n" % _text) else: try: _value = float(_text) except: sys.stderr.write("Invalid float: '%s'\n" % _text) else: sys.stderr.write("Empty entry box.") def _size_entry_focus_out(entry, event, text=''): _text = entry.get_text() if _text == '' or _text == '+': _size = entry.get_data('size') _hid = entry.get_data('handlerid') entry.delete_text(0, -1) entry.handler_block(_hid) try: entry.set_text(_size) finally: entry.handler_unblock(_hid) return False def _size_entry_insert_text(entry, new_text, new_text_length, position): if (new_text.isdigit() or new_text == '.' or new_text == '+'): _string = entry.get_text() + new_text[:new_text_length] _hid = entry.get_data('handlerid') _move = True entry.handler_block(_hid) try: _pos = entry.get_position() if _string == '+': _pos = entry.insert_text(new_text, _pos) else: try: _val = float(_string) except StandardError, e: _move = False else: _pos = entry.insert_text(new_text, _pos) finally: entry.handler_unblock(_hid) if _move: if hasattr(gobject, 'idle_add'): gobject.idle_add(_size_move_cursor, entry) else: gtk.idle_add(_size_move_cursor, entry) entry.stop_emission('insert-text') def _fill_size_dialog(dvbox, widgets): _lsg = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) _frame = gtk.Frame(_('Size Settings')) _frame.set_border_width(2) _vbox = gtk.VBox(False, 2) _vbox.set_border_width(2) _frame.add(_vbox) # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, True, True, 2) _label = gtk.Label(_('Chamfer length:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = widgets['CHAMFER_LENGTH'] _hbox.pack_start(_widget, False, False, 2) # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, True, True, 2) _label = gtk.Label(_('Fillet Radius:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = widgets['FILLET_RADIUS'] _hbox.pack_start(_widget, False, False, 2) # _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, True, True, 2) _label = gtk.Label(_('Leader Arrow Size:')) _lsg.add_widget(_label) _hbox.pack_start(_label, False, False, 2) _widget = widgets['LEADER_ARROW_SIZE'] _hbox.pack_start(_widget, False, False, 2) # dvbox.pack_start(_frame, False, False, 2) def set_sizes_dialog(gtkimage): _opts = ['CHAMFER_LENGTH', 'FILLET_RADIUS', 'LEADER_ARROW_SIZE'] _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Size Settings'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _image = gtkimage.getImage() _widgets = {} for _opt in _opts: _val = _image.getOption(_opt) _entry = gtk.Entry() _sval = "%f" % _val _entry.set_data('size', _sval) _entry.set_text(_sval) _handlerid = _entry.connect('insert-text', _size_entry_insert_text) _entry.set_data('handlerid', _handlerid) _entry.connect('activate', _size_entry_activate) _entry.connect('focus-out-event', _size_entry_focus_out) _widgets[_opt] = _entry _fill_size_dialog(_dialog.vbox, _widgets) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: for _opt in _opts: _text = _widgets[_opt].get_text() _ival = _image.getOption(_opt) if len(_text) and _text != '+': _value = float(_text) else: _value = _ival if abs(_value - _ival) > 1e-10: _image.setOption(_opt, _value) _widgets.clear() _dialog.destroy() # def set_toggle_dialog(gtkimage): _opts = ['AUTOSPLIT', 'HIGHLIGHT_POINTS'] _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Operation Settings'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _image = gtkimage.getImage() _widgets = {} for _opt in _opts: _val = _image.getOption(_opt) if _opt == 'AUTOSPLIT': _str = _('New Points split existing entities') else: _str = _('Boxes are drawn around Point objects') _cb = gtk.CheckButton(_str) _cb.set_active(_val) _widgets[_opt] = _cb _frame = gtk.Frame(_('Operation Settings')) _frame.set_border_width(2) _vbox = gtk.VBox(False, 2) _vbox.set_border_width(2) _frame.add(_vbox) _vbox.pack_start(_widgets['AUTOSPLIT'], True, True, 2) _vbox.pack_start(_widgets['HIGHLIGHT_POINTS'], True, True, 2) _dialog.vbox.pack_start(_frame, False, False, 2) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: for _opt in _opts: _val = _widgets[_opt].get_active() _image.setOption(_opt, _val) _widgets.clear() _dialog.destroy() def set_units_dialog(gtkimage): _units = units.Unit.getUnitStrings() _window = gtkimage.getWindow() _dialog = gtk.Dialog(_('Image Units'), _window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) _image = gtkimage.getImage() _unit = _image.getUnits() _idx = 0 if hasattr(gtk, 'ComboBox'): # PyGTK 2.4 _widget = gtk.combo_box_new_text() for _i in range(len(_units)): _ui = _units[_i] if _unit == units.Unit.getUnitFromString(_ui): _idx = _i _widget.append_text(_ui) _widget.set_active(_idx) else: _menu = gtk.Menu() for _i in range(len(_units)): _ui = _units[_i] if _unit is _units.Unit.getUnitFromString(_ui): _idx = _i _item = gtk.MenuItem(_ui) _menu.append(_item) _widget = gtk.OptionMenu() _widget.set_menu(_menu) _widget.set_history(_idx) _vbox = _dialog.vbox _vbox.set_border_width(5) _hbox = gtk.HBox(False, 2) _hbox.set_border_width(2) _vbox.pack_start(_hbox, True, True, 2) _label = gtk.Label(_('Units:')) _hbox.pack_start(_label, False, False, 2) _hbox.pack_start(_widget, False, False, 2) _dialog.show_all() _response = _dialog.run() if _response == gtk.RESPONSE_OK: if hasattr(gtk, 'ComboBox'): _idx = _widget.get_active() elif isinstance(_widget, gtk.OptionMenu): _idx = _widget.get_history() else: raise TypeError, "Unexpected widget " + `type(_widget)` _val = units.Unit.getUnitFromString(_units[_idx]) if _val != _unit: _image.setUnits(_val) _dialog.destroy() PythonCAD-DS1-R37/PythonCAD/Interface/__init__.py0000644000175000017500000000026311307666657020775 0ustar matteomatteo# # Copyright (c) 2002, Art Haas # # # don't define an __all__ variable - the value of importing # different front-end interfaces into a module seems very # low right now ... # PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/0000755000175000017500000000000011307677001017670 5ustar matteomatteoPythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/LayerView.py0000644000175000017500000000655611307666657022204 0ustar matteomatteo# # Copyright (c) 2002-2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Subclass of NSOutlineView, used to diplay layers in image # from PythonCAD.Interface.Cocoa import Globals import PythonCAD.Generic.layer from AppKit import NSOutlineView, NSMenu, NSMenuItem class LayerOutlineView(NSOutlineView): """ Subclass of NSOutlineView, used to display layers The purpose of the subclass is primarily to allow custom context menus for the layer items. """ def menuForEvent_(self, event): _point = self.convertPoint_fromView_(event.locationInWindow(), None) _index = self.rowAtPoint_(_point) if -1 == _index: return None if not self.isRowSelected_(_index): self.selectRow_byExtendingSelection_(_index, False) _item = self.itemAtRow_(_index) _layer = Globals.unwrap(_item) if not isinstance(_layer, PythonCAD.Generic.layer.Layer): raise TypeError, "Invalid Layer: " + `_layer` _menu = NSMenu.alloc().initWithTitle_("Context") _menuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("Rename", "EditLayerName:", "") _menu.addItem_(_menuItem) if _layer.isVisible(): _menuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("Hide", "HideLayer:", "") else: _menuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("Show", "ShowLayer:", "") _menuItem.setRepresentedObject_(_item) _menu.addItem_(_menuItem) _menuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("Add Child Layer", "AddChildLayer:", "") _menuItem.setRepresentedObject_(_item) _menu.addItem_(_menuItem) _menuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("Clear", "ClearLayer:", "") _menuItem.setRepresentedObject_(_item) _menu.addItem_(_menuItem) if _layer.hasChildren(): _menuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("Hide Children", "HideChildLayers:", "") _menuItem.setRepresentedObject_(_item) _menu.insertItem_atIndex_(_menuItem, 3) _menuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("Show Children", "ShowChildLayers:", "") _menuItem.setRepresentedObject_(_item) _menu.insertItem_atIndex_(_menuItem, 4) elif _layer.getParentLayer() is not None: _menuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("Delete", "DeleteLayer:", "") _menuItem.setRepresentedObject_(_item) _menu.addItem_(_menuItem) return _menu PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/CocoaPrompt.py0000644000175000017500000001332311307666657022511 0ustar matteomatteo# # Copyright (c) 2003 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # This code handles interpreting entries in the gtkimage.entry box # and calling the apprpriate internal command # # Author: David Broadwell ( dbroadwell@mindspring.com, 05/26/2003 ) # ''' 05/29/03 R2c Complete redesign, no longer does the internal name need to be a function, dropped prompt.py filesize from 9.8 to 5.3Kb! cleaned up the feywords file, no appreciable difference Used a dictionary instead of discreet functions for every entry and for R3, menus. ''' def lookup(text): """Interface to promptdef dictionary, returns code by keyword definition lookup(text) """ assert text in promptdefs, "No command for %s" % str(text) return promptdefs[text] promptdefs = { 'acline' : "NSApp.sendAction_to_from_(\"drawACLine:\", None, self)", 'arcc' : "NSApp.sendAction_to_from_(\"drawArc:\", None, self)", 'ccircen' : "NSApp.sendAction_to_from_(\"drawCCircleCenter:\", None, self)", 'ccir2p' : "NSApp.sendAction_to_from_(\"drawCCircle2Point:\", None, self)", 'chamfer' : "NSApp.sendAction_to_from_(\"drawChamfer:\", None, self)", 'close' : "NSApp.sendAction_to_from_(\"performClose:\", None, self)", 'circen' : "NSApp.sendAction_to_from_(\"drawCircleCentered:\", None, self)", 'cir2p' : "NSApp.sendAction_to_from_(\"drawCircle2Point:\", None, self)", 'cl' : "NSApp.sendAction_to_from_(\"draw2PointCLine:\", None, self)", 'cut' : "NSApp.sendAction_to_from_(\"cut:\", None, self)", 'copy' : "NSApp.sendAction_to_from_(\"copy:\", None, self)", 'delete' : "NSApp.sendAction_to_from_(\"delete:\", None, self)", 'dimpref' : "NSApp.sendAction_to_from_(\"dimension_prefs_cb(None)", 'fillet' : "NSApp.sendAction_to_from_(\"drawFillet:\", None, self)", 'hcline' : "NSApp.sendAction_to_from_(\"drawHCLine:\", None, self)", 'leader' : "NSApp.sendAction_to_from_(\"drawLeader:\", None, self)", 'mirror' : "NSApp.sendAction_to_from_(\"modifyMirror:\", None, self)", 'moveh' : "NSApp.sendAction_to_from_(\"modifyMoveHorizontal:\", None, self)", 'movev' : "NSApp.sendAction_to_from_(\"modifyMoveVertical:\", None, self)", 'move' : "NSApp.sendAction_to_from_(\"modifyMoveFree:\", None, self)", 'new' : "NSApp.sendAction_to_from_(\"newDocument:\", None, self)", 'opend' : "NSApp.sendAction_to_from_(\"openDocument:\", None, self)", 'paste' : "NSApp.sendAction_to_from_(\"paste:\", None, self)", 'pcline' : "NSApp.sendAction_to_from_(\"drawPerpendicularCLine:\", None, self)", 'point' : "NSApp.sendAction_to_from_(\"drawPoint:\", None, self)", 'polyline' : "NSApp.sendAction_to_from_(\"drawPolyline:\", None, self)", 'polygon' : "NSApp.sendAction_to_from_(\"drawPolygon:\", None, self)", 'polygonext' : "NSApp.sendAction_to_from_(\"drawPolygonExternal:\", None, self)", 'pref' : "NSApp.sendAction_to_from_(\"prefs_cb(None)", 'rect' : "NSApp.sendAction_to_from_(\"drawRect:\", None, self)", 'redraw' : "self.document().getDA().setNeedsDisplay_(True)", 'redo ' : "NSApp.delegate().redo_(None)", 'refresh' : "self.document().getDA().setNeedsDisplay_(True)", 'saa' : "NSApp.sendAction_to_from_(\"select_all_arcs_cb(None)", 'saacl' : "NSApp.sendAction_to_from_(\"select_all_aclines_cb(None)", 'sac' : "NSApp.sendAction_to_from_(\"select_all_circles_cb(None)", 'sacc' : "NSApp.sendAction_to_from_(\"select_all_ccircles_cb(None)", 'sacl' : "NSApp.sendAction_to_from_(\"select_all_clines_cb(None)", 'sahcl' : "NSApp.sendAction_to_from_(\"select_all_hclines_cb(None)", 'sap' : "NSApp.sendAction_to_from_(\"select_all_points_cb(None)", 'sas' : "NSApp.sendAction_to_from_(\"select_all_segments_cb(None)", 'savcl' : "NSApp.sendAction_to_from_(\"select_all_vclines_cb(None)", 'saveas' : "NSApp.sendAction_to_from_(\"saveDocumentAs:\", None, self)", 'saves' : "NSApp.sendAction_to_from_(\"saveDocument:\", None, self)", 'savel' : "NSApp.sendAction_to_from_(\"saveLayerAs:\", None, self)", 'segment' : "NSApp.sendAction_to_from_(\"drawSegment:\", None, self)", 'split' : "NSApp.sendAction_to_from_(\"modifySplit:\", None, self)", 'strh' : "NSApp.sendAction_to_from_(\"modifyStretchHorizontal:\", None, self)", 'strv' : "NSApp.sendAction_to_from_(\"modifyStretchVertical:\", None, self)", 'str' : "NSApp.sendAction_to_from_(\"modifyStretchFree:\", None, self)", 'tcline' : "NSApp.sendAction_to_from_(\"drawTanCLine:\", None, self)", 'text' : "NSApp.sendAction_to_from_(\"drawText:\", None, self)", 'transfer' : "NSApp.sendAction_to_from_(\"modifyTransfer:\", None, self)", 'undo' : "NSApp.delegate().undo_(None)", 'vcline' : "NSApp.sendAction_to_from_(\"drawVCLine:\", None, self)", 'quit' : "NSApp.sendAction_to_from_(\"terminate:\", None, self)", 'zoomd' : "NSApp.sendAction_to_from_(\"windowZoom:\", None, self)", 'zoomi' : "NSApp.sendAction_to_from_(\"windowZoomIn:\", None, self)", 'zoomo' : "NSApp.sendAction_to_from_(\"windowZoomOut:\", None, self)", 'zoomf' : "NSApp.sendAction_to_from_(\"windowZoomFit:\", None, self)" } PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/MainMenu.nib/0000755000175000017500000000000011307677001022150 5ustar matteomatteoPythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/MainMenu.nib/classes.nib0000644000175000017500000000417711307666657024327 0ustar matteomatteo{ IBClasses = ( { ACTIONS = { dimensionAngular = id; dimensionHorizontal = id; dimensionLinear = id; dimensionRadial = id; dimensionVertical = id; draw2PointCLine = id; drawACLine = id; drawArc = id; drawCCircle1Tan = id; drawCCircle2Point = id; drawCCircle2Tan = id; drawCCircleCenter = id; drawChamfer = id; drawCircle2Point = id; drawCircleCentered = id; drawFillet = id; drawHCLine = id; drawLeader = id; drawParallelCLine = id; drawPerpendicularCLine = id; drawPoint = id; drawPolygon = id; drawPolygonExternal = id; drawPolyline = id; drawRect = id; drawSegment = id; drawTan2CircleCLine = id; drawTanCLine = id; drawText = id; drawTextSheetCancel = id; drawTextSheetOK = id; drawVCLine = id; modifyMirror = id; modifyMoveFree = id; modifyMoveHorizontal = id; modifyMoveVertical = id; modifySplit = id; modifyStretchFree = id; modifyStretchHorizontal = id; modifyStretchVertical = id; modifyTransfer = id; redo = id; saveLayerAs = id; undo = id; windowZoom = id; windowZoomFit = id; windowZoomIn = id; windowZoomOut = id; }; CLASS = AppController; LANGUAGE = ObjC; OUTLETS = {polygonPanel = NSPanel; textSheet = NSWindow; }; SUPERCLASS = NSObject; }, {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; } ); IBVersion = 1; }PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/MainMenu.nib/keyedobjects.nib0000644000175000017500000007330611307666657025345 0ustar matteomatteobplist00 Y$archiverX$versionT$topX$objects_NSKeyedArchiver ]IB.objectdataR +/3:=?CG  !"$(,012479:<?CDEFILDMNQSTUX[\]^adefgjmnopsvwxy|    "%'(*-01247 9;>@ACFHJMPQRTXZ[]^_behijmopqtvwx{}~   #$%(+,-023479:;?VWXY[chpq  '*-124567:;>@ACDFGJTUVWX[aefuvw{~z  "#$'456()+,./121416F8;>ABCFHILNORTUVY[\]C_behijmopqtvwx{~3Q<>@BFGHIKNO=GRUGVWY\G]^`abcfGfgilGmqrstwGxy{|~vGGGGoGGGGGUGG   GG!G!"$%')+JL]NPQSUWX}Y[\]^_`bdefghijl[pqrtK                           ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~   U$null  !"#$%&'()*[NSNamesKeys[NSFramework_NSObjectsValues]NSNamesValues]NSConnections]NSFontManagerVNSRootYNSNextOid_NSVisibleWindows]NSObjectsKeys]NSClassesKeysZNSOidsKeys\NSOidsValuesV$class_NSClassesValues   w3X*,-Q+,-.[NSClassName012YNS.string]NSApplication4567X$classesZ$classname789_NSMutableStringXNSStringXNSObject45;<<9^NSCustomObject0>2_IBCocoaFramework@ABZNS.objects45DEEF9\NSMutableSetUNSSet@HgIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ #(.39=BGKPUZ_dhnsz~€ƀˀрրڀހ !%)-159>CGK  #'+06;@EINSWNSLabelXNSSource VNSMenu]NSMnemonicLocWNSTitleYNSOnImageZNSKeyEquiv\NSMixedImage_NSKeyEquivModMask  VNSName[NSMenuItems[XMinimizeQm,^NSResourceNameWNSImage_NSMenuCheckmark45٣9_NSCustomResource_%NSCustomResource,Ԁ_NSMenuMixedState459ZNSMenuItem02_performMiniaturize:459_NSNibControlConnector^NSNibConnectorƀ_Bring All to FrontP02_arrangeInFront:"ƀ !fPrint &Qp02Vprint:'$ƀ%&kPage Setup &QP02^runPageLayout:  -) ƀ*+,^PythonCad HelpQ?02YshowHelp:2/ƀ01 ZClear Menu0#2_clearRecentDocuments:%"&']NSDestination84)*+ƀ567-./^Quit PythonCadQq032Zterminate:%"56<:)8ŀ;_About PythonCad0;2_orderFrontStandardAboutPanel:%"=>A>)@AB?@[Hide OthersQh_hideOtherApplications:%"GHFC)JKƀDE^Hide PythonCadUhide:%"OPJH)RƀIXShow All_unhideAllApplications:VWOLYZƀMNUCloseQw]performClose:_`TQbcƀRSSNewQn\newDocument:hiYVklƀWXeOpen &Qo]openDocument:qr^[tuƀ\]TSaveQs]saveDocument:z{c`}~ƀabhSave As &QS_saveDocumentAs:geŀfVRevert_revertDocumentToSaved:miƀjkl_r`YUnderlineQu02Zunderline:roƀpqijWUse All02_useAllLigatures:%!ytƀuvZShow FontsQt,-x02_orderFrontFontPanel:}{ƀ|[Use Default02_useStandardLigatures:%!UNSTagVBiggerQ+[modifyFont:ŀƀˁno02Yunscript:%!ЀƀVItalicQi02]addFontTrait:%!ۀƀWSmallerQ-䀖ƀYZWTighten02_tightenKerning:ƀVLoosen02^loosenKerning:ƀYSubscript02Zsubscript:ƀULower02^lowerBaseline: ƀXUse None0 2_turnOffLigatures:%!ƀTBoldQb02BZCopy StyleQc0!2YcopyFont:#$&ƀURaise0)2^raiseBaseline:+,./ƀ[Show ColorsQC032_orderFrontColorPanel:568ƀ0:2_turnOffKerning:<=?ƀ[Superscript0B2\superscript:DEŀGƀ0I2_useStandardKerning:KLʀNOBȀ[Paste StyleQv0S2ZpasteFont:%UVW΀ЀYƀ_Save Layer As...,-\]AppController\saveLayerAs:%U`aՀcdƀӀfgvwVPointsZdrawPoint:%UklـcnƀXSegments\drawSegment:%Urs݀cuƀZRectanglesYdrawRect:%Uyzc|ƀ_Circle - Centered_drawCircleCentered:%Ucƀ_Circle - 2 Points_drawCircle2Point:%UcƀSArcXdrawArc:%UƀʁZHorizontal[drawHCLine:%UƀXVertical[drawVCLine:%UƀVAngled[drawACLine:%UƀYTwo-Point_draw2PointCLine:%Uƀ]Perpendicular_drawPerpendicularCLine:%UƁWTangent]drawTanCLine:%UƁ_Tangent - 2 Circles_drawTan2CircleCLine:%Uā Ɓ XParallel_drawParallelCLine:%Uˁ Ɓ с\Center Point_drawCCircleCenter:%UցƁ_drawCCircle2Point:%U܁Ɓ_Tangent - 1 Object_drawCCircle1Tan:%UƁ_Tangent - 2 Objects_drawCCircle2Tan:%U ƁWChamfer\drawChamfer:%U$"Ɓ#VFillet[drawFillet:%U(&Ɓ'VLeader[drawLeader:%U,*Ɓ+XPolyline]drawPolyline:%U  0. Ɓ/WPolygon\drawPolygon:%U42Ɓ3_Polygon - External_drawPolygonExternal:%U86Ɓ7TTextYdrawText:%U=:!"Ɓ;UL@ABCDEFGHIJKLMNOPQRSTU_NSWindowStyleMask_NSWindowBackingYNSMinSize]NSWindowTitle]NSWindowClass\NSWindowRect\NSScreenRectYNSMaxSize\NSWindowViewYNSWTFlags[NSViewClassNOMQxP_{{185, 501}, {236, 113}}UPanelWNSPanel0Z2TView\]^_`abZNSSubviews_NSNextResponderWNSFrameR@defgSy]i^jkRRlmno[NSSuperviewYNSEnabledVNSCellT xU_{{152, 45}, {43, 22}}rstuvwxyz{|}m~e[NSTextColor[NSFormatter_NSDrawsBackgroundYNSSupportZNSContents]NSControlView_NSPlaceholderString[NSCellFlags_NSBackgroundColor\NSCellFlags2t[XVowqAp@m^NS.mantissa.bo[NS.mantissa[NS.exponentYNS.length[NS.negativeZNS.compactO@6W459_NSDecimalNumberPlaceholderVNSSizeXNSfFlags"APYZ\LucidaGrande459VNSFontm``VNS.nil_NS.allowsfloatsWNS.zeroVNS.nanVNS.max_NS.positiveattrs\NS.localized_NS.negativeattrsVNS.min_NS.negativeformat[NS.rounding_NS.positiveformatZNS.decimal[NS.thousand_NS.hasthousandsgchk^j]\lmnQ0@WNS.keys`_bWNSColorUNSRGB\NSColorSpaceF1 0 0a45945ˢ9\NSDictionary8\NSAttributesefd@AA45Ԣ9_NSAttributedString88ׁiSNaNmOQ%mO"Bt(̿PQ.Q,45s9_NSNumberFormatterQ3[NSColorName]NSCatalogNamesrqVSystem_textBackgroundColorWNSWhiteB1ƁvuYtextColorB045k9_NSTextFieldCell\NSActionCell459[NSTextField\%NSTextFieldYNSControlVNSView[NSResponder]i^jkRRmnz{_{{17, 47}, {138, 13}}ruvwyz{f }|~_Number of Polygon Sides:  "A Ɓ\controlColorK0.66666669Ɓ_controlTextColor]i^jkRRm_{{200, 42}, {19, 28}}w y!{mg"#$"%&\NSAutorepeatWNSValueZNSMaxValueZNSMinValue[NSIncrement#@#@Y #?45())k9]NSStepperCell45+,,9YNSStepper45.//09^NSMutableArrayWNSArray_{{1, 1}, {236, 113}}4539_{{0, 0}, {1152, 746}}Z{213, 129}_{3.40282e+38, 3.40282e+38}458999_NSWindowTemplate\polygonPanel45<==9_NSNibOutletConnector%e?g_takeIntValueFrom:%UB><Xdelegate%eE><_initialFirstResponder%HI>U@ABCDEFGHIJKLMNOPQRTSށ݁߁px_{{556, 439}, {300, 227}}VWindowXNSWindow0Z2\]^Y`Zb@\]^_`]i^jkQQbmcd_{{14, 12}, {78, 32}}ghiuvwjklym{n~~o]pqrst_NSPeriodicInterval_NSAlternateImage_NSAlternateContents^NSButtonFlags2]NSButtonFlags_NSPeriodicDelay_NSKeyEquivalent@ȁROK0245xyyzk9\NSButtonCell]%NSButtonCell45|}}9XNSButton]i^jkQQmc_{{204, 12}, {82, 32}}ghiuvwjklym{n~~^pqrtVCancel02]i^jkQQmn_{{17, 194}, {80, 13}}ruvwyz{_ [Enter Text:\]i^QQ]NSNextKeyView[NSHScrollerXNSvFlagsXNSsFlags[NSVScroller]NSContentViewځӁ@\]i^``YNSBGColorYNSDocViewYNScvFlagsXNSCursorρ @]iG`[NSFrameSizeXNSMinize\NSSharedDataZNSDelegateYNSTVFlags_NSTextContaineŕ́Y{258, 14}WNSWidthZNSTextView_NSLayoutManagerYNSTCFlags"C`]NSTextStorageYNSLMFlags_NSTextContainers8`́0245Ĥ9_NSMutableAttributedString@459459z``_NSSelectedAttributesWNSFlags_NSInsertionColor_NSDefaultParagraphStyle_NSLinkAttributes_NSMarkedAttributes/Ł@âƁ_selectedTextBackgroundColorƁ_selectedTextColor@ȁɢƁ[NSUnderlineF0 0 1459_NSTextViewSharedData\{323, 1e+07}X{114, 8}459[%NSTextViewVNSText_{{1, 1}, {258, 124}}YNSHotSpot\NSCursorTypeЁW{4, -5}45 945   9ZNSClipView]i^``&`ZNSCurValueXNSTargetXNSActionց_{{-30, 1}, {15, 124}}\_doScroller:459ZNSScroller]i^``&` !YNSPercent"?rC_{{-100, -100}, {87, 18}}_{{20, 60}, {260, 126}}45%&&9\NSScrollView_{{1, 9}, {300, 227}}YtextSheet%U*]_drawTextSheetOK:%U-^_drawTextSheetCancel:%]0>`[nextKeyView%^3>]%5>^%7>H%U9:<=Ɓ?@VLinear_dimensionLinear:%UDE<GƁ_dimensionHorizontal:%UJK<MƁ_dimensionVertical:%UPQ<SƁVRadial_dimensionRadial:%UWX<ZƁWAngular_dimensionAngular:%U^>"%U`acdƁfgׁUSplit\modifySplit:%Ukl  cnƁ VMirror]modifyMirror:%UrscuƁXTransfer_modifyTransfer:%Uyz|}Ɓҁ_modifyMoveHorizontal:%U|Ɓ_modifyMoveVertical:%U|ƁTFree_modifyMoveFree:%U"Ɓ !_modifyStretchHorizontal:%U&$Ɓ%_modifyStretchVertical:%U*(Ɓ)_modifyStretchFree:/,Ɓ-.XColor...51Ɓ234ZSelect AllQa02ZselectAll::7Ɓ89SCutQx02Tcut:Ɂ?<Ɓ=>UPaste02Vpaste:%UҁDAƁBCTRedoQZUredo:ہHFƁGVDeleteWdelete:%UMJƁKLTUndoQzUundo:ROƁPQTCopy02Ucopy:WTƁUV\Deselect AllQA02@;`X,H      'LU 6<6 cg=a'aHcR):z !"#$>_<%W&l'()$6l*+Er,P|se-./s^{K0/E1z!`]234Q5QWi6}78f9:\sxqa{kāǁ́ρԁbfÁ܁ށpفcځ0=2TKern@?E645A9CDEYNSSubmenu]^TFont^submenuAction:0F2@J5$ 3,LLMmm\NSIsDisabled]NSIsSeparatorLMmmCPQdeCSTghXLigature0U2@XCZ[lmXBaseline0\2@_=$LMmmLMmm[_NSFontMenuCcdetuUBasic@halszC)jkyzXServicesnop|~}0l2@A__NSServicesMenuCuv[Open Recent0w2@z__NSRecentDocumentsMenu'}ƁC!TFile02@`i#Wr{WMmMm_Construction Circles@'ƁWCirclesMm'Ɓ_Horizontal DimensionsMmcƁ\Thickness...CcWStretch@0U2@6'/6LMmm^_NSWindowsMenuC!<ZDimensions@:EKQX02THelp@ C'YSelect...@-() *7:'Ɓ'ƁTArcs'ƁWLeaders'ƁYPolylines'ƁXPolygons'Ɓ_Vertical Dimensions'Ɓ_Linear Dimensions'Ɓ_Radial Dimensions'Ɓ_Angular DimensionsMm02TEdit@+ MmC! ؁ŁCہȁ_Construction Lines@C!́Cc|ЁTMove@zC!cՁVModify@ als49/2 LMcmmcƁXStyle...cƁ[Linetype...cƁLM)mmC!C!VFormat02@%,ƁƁƁYPythonCad@ 6.18H>P0'LM)mm) ƁlPreferences &LM)mmLM)mm\_NSAppleMenuMmCMmXMainMenu@&"C!)C! TDraw@#  [_NSMainMenu45&009@(;Q<5)'|!$'"'cc !"  "''!'!R`c!)!c)c!)<&<|"!c)Q!c'')c'<)cR')ccQ<))c"Qcc"H<ec')|Rc'@*;!Ui{#'^]"f6 gW!`` r!H<e1_@,;!-./012345678911:;<1=1>?@ABCDEFGHI   !"#$%&')0K2Q60M2Q10O2Q5020R2Q80T2R100V2Q7T1111YNSButton10Z2\File's Owner_NSTextField111111\NSCustomView0M202]NSScrollView20a2Q20c2Q90a202\Font ManagerYTextEntry\PolygonPanelS121k(45mnno9VNSNullW%NSNull@A;@A;@s;#_VWfRsYH`*yt' )<llor2.UaQ h"p%`XaJz>i${LnusE|+cQi1N_ cE3sO' =},ZKv{}6zb7R<6c jPe]HSPT5'Kzd/,4 8q(kr) W[:Uew!\0]aI|Q9~!6l^f$g "-#/&`M^W :6XLmxg@u;#vwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÁāŁƁǁȁɁʁˁ́́΁ρЁсҁӁԁՁցׁ؁فځہ܁݁ށ߁      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOP3I;+wQR /hj-agU*J KZ&(R5x{?1JN'H"jGc MS7@\[TL !VM'.H,VP'P6p0viQA|` d|8q] ^W N,D 9~y-#2:.0&kt~%OeX}g/K \Er#2_z%<So%OY8$p4zu$oIb:fWsF})45 9^NSIBObjectData#,1:LQVdf   S _ k }     # % ' ) , . 1 4 7 : = @ I U W Y b l z |      $ 1 7 @         ! # % ' ) + - / 1 3 5 7 9 ; = ? A C E G I K M O Q S U W Y [ ] _ a c e g i k m o q s u w z }       # + 4 6 8 : [ b p x  !);DK^r579NOXjwy{ !#,;HJLmoqs&7EGIjlnp/13TVX]ik  -:<>_aciky "$EGINP^kmo ;=?ARUX[egp{ "-/8:CZgik #%'HJLY\_hr )+-NPR_bemv "-:<>_agp )68:[]_jlu6CEGhjs .;=?`bdpr{  /13@CFMXikm)+?Ufhj  024ADGR^oqs  , . 8 K \ ^ ` ! !!!4!7!M!d!u!x!{!!!!!!!!!!"" """0"A"D"G"h"k"""""""""""###4#G#X#[#^###############$ $$$3$6$=$I$Z$]$`$$$$$$$$$$$$$%%#%&%;%R%c%f%i%%%%%%%%%%%%&&&&(&+&.&7&F&W&Z&]&~&&&&&&&&&&&&&&'0'D'V'`'n'|'''''''''''''''''(( ((( (1(<(N(V(Y([(^(a(j(q(t(w(z(((((((((() ))+)5)@)N)d)p)))))))))))))))****,*.*/*2*;*@*]*n*u*~**********+ ++++2+?+R+Y+m+y+++++++++++++++++++++++,,,,%,,,/,8,=,F,K,X,e,r,u,x,{,,,,,,,,,,--(-*-,-5-<-P-R-g-s-----------------...'.0.=.I.V.`.g.s...........// //$/'/*/7/D/P/e/h/{/////////0000#0&0+040=0F0T0]0h0r0{0000000011 11!1.171>1U1f1i1}1111111112222222 2#2(2+2F2M2V2_2p2s2v22222222222333*3@3O3]3o333333333333333334 444+4`4c4f4m4v44444445 55$5-565B5P5S5V5Y5\5_5b5e5h5q5x555555555555566#6,696D6N6`6c6f6i6l6o6r6u66666666666677777$7'7*737<7E7a7j7m7v7{77777778 88!8$8'8*878<8?8B8G8J8M8b8e888888888888888999$9-969C9O9V9m9z999999999999:: :::::!:9:F:O:Z:e:::::::::::;;;+;.;A;R;U;l;};;;;;;;;;;;<<<<<<< <3=A=b=e=m==============> > >>1>4>;>I>Z>]>`>>>>>>>>>>>>>?????@?C?Y?j?m?p?????????????@@(@+@.@O@R@k@|@@@@@@@@@@@AAAAAA!A$AEAHAKANA[A^AaAlAnAwAAAAAAAAAAAAAABBB BBB B1B4B7BXB[B^BcBeBkBxB{B~BBBBBBBBBBBBBC C CC0C3C6C;CDCJCWCZC]C~CCCCCCEE!E$E'E*E-E0E3E6E9ELILRLWL`LcLLLLLLLMMMM)M,M4MUMXMbMMMMMMMMNN"N%N9NZN]NrNNNNNNOOOOBOEOHO]OfOwOOOOOOOOOPPPP P)P>PgPPPPPPPPQQ:Q=Q@QiQlQoQvQQQQQQQQQR RR)RRRsRvRyRRRRSS?SBSESjSsS|SSSSSSSSSTT$T-T2T;UUVV VPVSVVVYV\V_VbVeVhVkVnVqVtVwVzV}VVVVVVVVVVVVVVVVVVVVVVVVVVVVWW WW,W9WBWKWYWbWdWmWoWxWWWWWWWWWWWWWWZ5Z>\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\]]]] ] ]]]]]]]!]$]']*]-]0]3]6]9]<]?]B]E]H]K]N]Q]T]W]Z]]]`]c]f]i]l]o]r]u]x]{]~]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]^^^^ ^^^^^^^ ^#^&^)^,^/^2^5^8^;^>^A^D^G^J^M^P^S^V^Y^\^_^b^e^h^k^n^q^t^w^z^}^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^____ _ _______"_%_(_+_._1_4_7_:_=_@_C_F_I_L_O_R_U_X_[_^_a_d_g_j_m_p_s_v_y_|____________________________________________```` ` ````````!`$`'`*`-`/`2`5`8`;`>`A`C`F`I`L`O`R`U`X`[`^`a`d`f`i`k`n`p`s`v`y`|``````````````````````````````````````````````aaaa a aaaaaaa!a#a&a)a,a/a2a5a8a:a=a@aBaEaHaKaNaQaTaWaZa]a_abadagajamaoarauawaza}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbb b bbbbbbb b"b%b(b+b.b1b4b7b9b;b>bAbDbGbJbMbPbSbVbYb\b^b`bcbfbhbkbnbqbsbubxb{b~bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccc ccccc! c0PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/MainMenu.nib/info.nib0000644000175000017500000000106311307666657023614 0ustar matteomatteo IBDocumentLocation 471 246 444 256 0 0 1152 746 IBEditorPositions 29 60 702 544 44 0 0 1152 746 IBFramework Version 349.0 IBOpenObjects 29 IBSystem Version 7F44 PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/Globals.py0000644000175000017500000000317311307666657021650 0ustar matteomatteo# # Copyright (c) 2002-2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Global strings/utility classes stored here # from Foundation import NSObject # Strings for Preferences WinFrameName = "CADWindow" LayerColumnName = "LayerName" LayerAddedNotification = "PCAddLayer" LayerDeletedNotification = "PCDelLayer" ToolChangedNotification ="PCToolChanged" # Class to keep weak referenced/non-retained objects # from causing crashes. WRAPPED ={} class ObjWrap(NSObject): """This class is here to wrap python objects as objective-c objects """ def init_(self, obj): self.obj = obj return self def wrap(item): if WRAPPED.has_key(item): return WRAPPED[item] else: WRAPPED[item] = ObjWrap.alloc().init_(item) return WRAPPED[item] def unwrap(item): if item is None: return item return item.obj def purge(item): if WRAPPED.has_key(item): del WRAPPED[item] PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/CocoaText.py0000644000175000017500000000524011307666657022153 0ustar matteomatteo# # Copyright (c) 2002-2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Handles creation of text entries # import objc import PythonCAD.Generic.tools import PythonCAD.Generic.text import CocoaEntities from AppKit import NSFontManager, NSItalicFontMask, NSTextView def textview_format_setup(doc, textview): textview.setString_("") _family = doc.getOption('FONT_FAMILY') _weight = doc.getOption('FONT_WEIGHT') _style = doc.getOption('FONT_STYLE') _size = doc.getOption('FONT_SIZE') _color = doc.getOption('FONT_COLOR') _fm = NSFontManager.sharedFontManager() _traits = 0 if PythonCAD.Generic.text.TextStyle.FONT_ITALIC == _style: _traits = _traits | NSItalicFontMask if PythonCAD.Generic.text.TextStyle.WEIGHT_LIGHT == _weight: _weight = 3 if PythonCAD.Generic.text.TextStyle.WEIGHT_NORMAL == _weight: _weight = 5 elif PythonCAD.Generic.text.TextStyle.WEIGHT_BOLD == _weight: _weight = 9 elif PythonCAD.Generic.text.TextStyle.WEIGHT_HEAVY == _weight: _weight = 11 _font = _fm.fontWithFamily_traits_weight_size_(_family, _traits, _weight, _size) if _font is None: return textview.setFont_(_font) def text_entered(doc, tool, textview): doc.setPrompt("Click where to place the text.") tool.setHandler("mouse_move", text_mouse_move_cb) tool.setHandler("left_button_press", text_left_button_press_cb) def text_mouse_move_cb(doc, np, tool): (_x, _y) = np _text = tool.getText() _style = doc.getOption('TEXT_STYLE') _tblock = PythonCAD.Generic.text.TextBlock(_text, _style) _tblock.setLocation(_x, _y) _da = doc.getDA() _da.setTempObject(_tblock) def text_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) tool.setTextLocation(_viewLoc.x, _viewLoc.y) tool.create(doc.getImage()) tool.reset() doc.setPrompt("Enter command:") PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/ImageWindowController.py0000644000175000017500000003414711307666657024550 0ustar matteomatteo# # Copyright (c) 2002-2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Cocoa CAD drawing window controller, delegate of split view # # P.L.V. nov 23 05 # import adjustment import string import PythonCAD.Generic.layer import PythonCAD.Generic.keywords import PythonCAD.Interface.Cocoa.CADView import PythonCAD.Interface.Cocoa.LayerView import PythonCAD.Interface.Cocoa.CocoaPrompt import PythonCAD.Interface.Cocoa.Globals import PythonCAD.Interface.Cocoa.AppController from PythonCAD.Interface.Cocoa.Globals import WinFrameName, LayerDeletedNotification, LayerAddedNotification, ToolChangedNotification from PyObjCTools import NibClassBuilder from AppKit import * from Foundation import NSNotificationCenter # # Define True & False in case this is Python < 2.2.1 # try: True, False except NameError: True, False = 1, 0 class ImageWindowController(NSWindowController, NSOutlineViewDataSource): """ Custom NSWindowController for ImageDocument window An ImageWindowController is a NSWindowController used to manage the NSWindow used by the ImageDocument class. It is the delegate of the NSSplitView & NSOutlineView (holding the layers), & NSWindow """ # # Beginning of Cocoa methods # def initWithWindowNibName_owner_(self, nib, owner): self = super(ImageWindowController, self).initWithWindowNibName_owner_(nib, owner) if (self): self.__outlineView = None self.__splitView = None return self def windowDidLoad(self): _doc = self.document() _sv = _doc.getSplitView() _ov = _doc.getOutlineView() _text = _doc.getEntry() _win = self.window() _text.setDelegate_(self) _sv.setDelegate_(self) _win.setDelegate_(self) _win.setFrameUsingName_(WinFrameName) _ov.setDataSource_(self) _ov.setDelegate_(self) _ov.sizeLastColumnToFit() _ov.setAutoresizesOutlineColumn_(True) _da = _doc.getDA() _scrv = _da.enclosingScrollView() _scrvSize = _scrv.contentSize() _scrv.setCopiesOnScroll_(False) _da.setFrameSize_(_scrvSize) # # ensure selected layer is active # _item = _ov.itemAtRow_(0) _ov.expandItem_expandChildren_(_item, True) _endRow = _ov.numberOfRows() - 1 _ov.selectRow_byExtendingSelection_(_endRow, False) _ov.selectRow_byExtendingSelection_(0, False) # # Register for notifications of changes to the document # _img = _doc.getImage() _obj = Globals.wrap(_img) _nc = NSNotificationCenter.defaultCenter() _nc.addObserver_selector_name_object_(self, "layerChanged:", LayerAddedNotification, _obj) _nc.addObserver_selector_name_object_(self, "layerChanged:", LayerDeletedNotification, _obj) _nc.addObserver_selector_name_object_(self, "toolChanged:", ToolChangedNotification, _doc) def windowDidResize_(self, note): _win = note.object() _win.saveFrameUsingName_(WinFrameName) def windowWillClose_(self, note): _nc = NSNotificationCenter.defaultCenter() _nc.removeObserver_(self) # # Beginning of Split View delegate methods # def splitView_resizeSubviewsWithOldSize_(self, splitView, oldSize): """Resize split view subviews after size change to oldSize splitView_resizeSubviewsWithOldSize_(self, splitView, oldSize) """ _ov = self.document().getOutlineView() _cadView = self.document().getDA() _subviewArray = splitView.subviews() for _count in range(_subviewArray.count()): _aView = _subviewArray.objectAtIndex_(_count) if (_ov.isDescendantOf_(_aView)): _ov = _aView elif (_cadView.isDescendantOf_(_aView)): _cadView = _aView _ovFrame = _ov.frame() _cadFrame = _cadView.frame() _splitSize = splitView.frame().size _extraWidth = splitView.dividerThickness() + _ovFrame.size.width _ovFrame.size.height = _splitSize.height _cadFrame.size.height = _splitSize.height if _extraWidth < _splitSize.width: _cadFrame.size.width = _splitSize.width - _extraWidth else: splitView.adjustSubviews() _ov.setFrame_(_ovFrame) _cadView.setFrame_(_cadFrame) # # End of Split View delegate methods # # # Beginning of Outline View delegate methods # def outlineViewSelectionDidChange_(self, note): _ov = note.object() _index = _ov.selectedRow() if -1 != _index: _item = _ov.itemAtRow_(_index) _layer = Globals.unwrap(_item) _doc = self.document() _doc.getImage().setActiveLayer(_layer) _doc.getDA().setNeedsDisplay_(True) def outlineViewItemDidCollapse_(self, note): _doc = self.document() _active_layer = _doc.getImage().getActiveLayer() _ov = note.object() _row = _ov.rowForItem_(Globals.wrap(_active_layer)) if -1 == _row: _item = note.userInfo()["NSObject"] _row = _ov.rowForItem_(_item) _ov.selectRow_byExtendingSelection_(_row, False) def outlineView_willDisplayCell_forTableColumn_item_(self, ov, cell, tc, item): _layer = Globals.unwrap(item) if _layer.isVisible(): _color = NSColor.blackColor() else: _color = NSColor.lightGrayColor() cell.setTextColor_(_color) # # Outline view data source methods # # # Beginning of OutlineView Data source methods # def outlineView_isItemExpandable_(self, outlineView, item): """ NSOutlineViewDataSource method for layer view outlineView_isItemExpandable_(outlineView, item) """ _item = Globals.unwrap(item) if _item is None: return True # Top Layer item is always displayed return _item.hasSublayers() def outlineView_numberOfChildrenOfItem_(self, outlineView, item): """ NSOutlineViewDataSource method for layer view outlineView_numberOfChildrenOfItem_(outlineView, item) """ _item = Globals.unwrap(item) if _item is None: return 1 # Top Layer item is first item in layer list return len(_item.getSublayers()) def outlineView_child_ofItem_(self, outlineView, itemIndex, item): """ NSOutlineViewDataSource method for layer view outlineView_child_ofItem_(outlineView, itemIndex, item) """ _item = Globals.unwrap(item) if _item is None: return Globals.wrap(self.document().getImage().getTopLayer()) _children = _item.getSublayers() return Globals.wrap(_children[itemIndex]) def outlineView_objectValueForTableColumn_byItem_(self, ov, tc, item): """ NSOutlineViewDataSource method for layer view outlineView_objectValueForTableColumn_byItem_(outlineView, tableColumn, item) """ if tc.identifier() != Globals.LayerColumnName: return None _item = Globals.unwrap(item) if _item is None: _item = self.document().getImage().getTopLayer() return _item.getName() def outlineView_setObjectValue_forTableColumn_byItem_(self, ov, val, tc, item): """ NSOutlineViewDataSource method for layer view outlineView_setObjectValue_forTableColumn_byItem_(outlineView, value, tableColumn, item) """ if tc.identifier() != Globals.LayerColumnName: return _layer = Globals.unwrap(item) if not isinstance(_layer, PythonCAD.Generic.layer.Layer): raise TypeError, "Invalid active Layer: " + `_layer` _layer.setName(val) def layerChanged_(self, note): _doc = self.document() _doc.getDA().setNeedsDisplay_(True) _dict = note.userInfo() _parent = Globals.wrap(_dict["parent"]) _ov = _doc.getOutlineView() _image = _doc.getImage() _l = _activeLayer = _image.getActiveLayer() # _ov.reloadItem_reloadChildren_(_parent, True) _ov.reloadData() _topLayer = _image.getTopLayer() _stack = [] while _l is not _topLayer: _l = _l.getParentLayer() _stack.append(_l) while len(_stack): _item = Globals.wrap(_stack.pop()) _ov.expandItem_(_item) _al = Globals.wrap(_activeLayer) _row = _ov.rowForItem_(_al) _ov.selectRow_byExtendingSelection_(_row, False) def toolChanged_(self, note): _sheet = self.window().attachedSheet() if _sheet is None: return _userinfo = note.userInfo() _tool = _userinfo["tool"] if not isinstance(_tool, PythonCAD.Generic.tools.TextTool): NSApplication.sharedApplication().endSheet_(_sheet) _sheet.orderOut_(_sheet) # # Layer context menu functions # def EditLayerName_(self, sender): _ov = self.document().getOutlineView() _row = _ov.selectedRow() _ov.editColumn_row_withEvent_select_(0, _row, None, True) def HideLayer_(self, sender): _layer = Globals.unwrap(sender.representedObject()) if not isinstance(_layer, PythonCAD.Generic.layer.Layer): raise TypeError, "Invalid Layer: " + `_layer` _layer.hide() _doc = self.document() _doc.getDA().setNeedsDisplay_(True) _doc.getOutlineView().setNeedsDisplay_(True) def ShowLayer_(self, sender): _layer = Globals.unwrap(sender.representedObject()) if not isinstance(_layer, PythonCAD.Generic.layer.Layer): raise TypeError, "Invalid Layer: " + `_layer` _layer.show() _doc = self.document() _doc.getDA().setNeedsDisplay_(True) _doc.getOutlineView().setNeedsDisplay_(True) def AddChildLayer_(self, sender): _layer = Globals.unwrap(sender.representedObject()) if not isinstance(_layer, PythonCAD.Generic.layer.Layer): raise TypeError, "Invalid Layer: " + `_layer` _doc = self.document() _doc.addChildLayer(_layer) def HideChildLayers_(self, sender): _layer = Globals.unwrap(sender.representedObject()) if not isinstance(_layer, PythonCAD.Generic.layer.Layer): raise TypeError, "Invalid Layer: " + `_layer` _children = _layer.getSublayers() while(len(_children)): _child = _children.pop() _child.hide() if _child.hasSublayers(): _children = _children + _child.getSublayers() _doc = self.document() _doc.getDA().setNeedsDisplay_(True) _doc.getOutlineView().setNeedsDisplay_(True) def ShowChildLayers_(self, sender): _layer = Globals.unwrap(sender.representedObject()) if not isinstance(_layer, PythonCAD.Generic.layer.Layer): raise TypeError, "Invalid Layer: " + `_layer` _children = _layer.getSublayers() while(len(_children)): _child = _children.pop() _child.show() if _child.hasSublayers(): _children = _children + _child.getSublayers() _doc = self.document() _doc.getDA().setNeedsDisplay_(True) _doc.getOutlineView().setNeedsDisplay_(True) def ClearLayer_(self, sender): _layer = Globals.unwrap(sender.representedObject()) if not isinstance(_layer, PythonCAD.Generic.layer.Layer): raise TypeError, "Invalid Layer: " + `_layer` _layer.clear() _doc = self.document() _doc.getDA().setNeedsDisplay_(True) def DeleteLayer_(self, sender): _layer = Globals.unwrap(sender.representedObject()) if not isinstance(_layer, PythonCAD.Generic.layer.Layer): raise TypeError, "Invalid Layer: " + `_layer` _doc = self.document() _doc.delLayer(_layer) # # End of Layer context menu functions # # # somebody entered something in the entry event # def controlTextDidEndEditing_(self, note): _doc = self.document() _tool = _doc.getTool() _field = note.object() _text = string.strip(string.lower(_field.stringValue())) _cmds = PythonCAD.Generic.keywords.defaultglobals if _text == 'end' or _text == 'stop': _doc.reset() elif _text in _cmds: _opt = _cmds[_text] _cmd = CocoaPrompt.lookup(_opt) NSApp = NSApplication.sharedApplication() try: eval(_cmd) except: NSBeep() elif _tool is not None and _tool.hasHandler("entry_event"): _handler = _tool.getHandler("entry_event") try: _handler(_doc, _text, _tool) except: NSBeep() # # Beginning of NSWindow delegate methods # # def windowWillResize_toSize_(self, win, size): # if not self.__inResize: # self.__inResize = True # _da = self.document().getDA() # _img = _da.getImageRep() # _iv = NSImageView.alloc().initWithFrame_(_da.frame()) # _iv.setImage_(_img) # self.__dasv = _da.enclosingScrollView() # _da.removeFromSuperviewWithoutNeedingDisplay() # self.__dasv.setDocumentView_(_iv) # return size # # End of NSWindow Delegate methods # # # End of Cocoa methods # PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/CADView.py0000644000175000017500000014447411307666657021521 0ustar matteomatteo# # Copyright (c) 2002-2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Cocoa CAD drawing view # from math import hypot, ceil from objc import nil from PyObjCTools import NibClassBuilder from Foundation import * from AppKit import * import PythonCAD.Generic.graphicobject import PythonCAD.Generic.layer import PythonCAD.Generic.globals import PythonCAD.Generic.segment import PythonCAD.Generic.circle import PythonCAD.Generic.arc import PythonCAD.Generic.hcline import PythonCAD.Generic.vcline import PythonCAD.Generic.acline import PythonCAD.Generic.cline import PythonCAD.Generic.ccircle import PythonCAD.Generic.conobject import PythonCAD.Generic.segjoint import PythonCAD.Generic.leader import PythonCAD.Generic.polyline import PythonCAD.Generic.text import PythonCAD.Generic.dimension import PythonCAD.Generic.tools import PythonCAD.Interface.Cocoa.Globals # import PythonCAD.Interface.Cocoa.ImageDocument # import PythonCAD.Interface.Cocoa.ImageWindowController # import PythonCAD.Interface.Cocoa.AppController # # Define True & False in case this is Python < 2.2.1 # try: True, False except NameError: True, False = 1, 0 # # Global variables # PythonCAD.Generic.globals.NSColors = {} PythonCAD.Generic.globals.NSFonts = {} NibClassBuilder.extractClasses("ImageDocument") class CADView(NibClassBuilder.AutoBaseClass, PythonCAD.Generic.message.Messenger): """ Custom NSView for visual display & editing of a PythonCad CAD image. A CADView is an NSView used for editing & display of a generic Image object. """ # # Beginning of Cocoa methods # def init(self): """ NSView override for cocoa initializer of CADView init() """ self = super(CADView, self).init() if (self): self.__mouseTrackTimer = None self.__document = None self.__tracking_rect = None self.__trans = None self.__x_scale = 1.0 self.__y_scale = 1.0 return self def awakeFromNib(self): """ NSView override for post-NIB loading initialization awakeFromNib(self) """ # # initialize variables # self.__mouseTrackTimer = None self.__document = None self.__tracking_rect = None self.__trans = None self.__temporaryObject = [] self.__temporaryPoint = NSMakePoint(0.0,0.0) self.__temporaryRect = NSMakeRect(0.0, 0.0, 0.0, 0.0) self.__x_scale = 1.0 self.__y_scale = 1.0 self.updateTrackingRect() self.setTransform() _cv = self.enclosingScrollView().contentView() # # register for frame updates # _nc = NSNotificationCenter.defaultCenter() _nc.addObserver_selector_name_object_(self, "frameChangeNotification:", "NSViewFrameDidChangeNotification", _cv) _nc.addObserver_selector_name_object_(self, "boundsChangeNotification:", "NSViewBoundsDidChangeNotification", self) _nc.addObserver_selector_name_object_(self, "windowCloseNotification:", "NSWindowWillCloseNotification", self.window()) def isOpaque(self): _bool = self.inLiveResize() if _bool: return False return True def getDocument(self): """ Gets ImageDocument displayed by this view getDocument() """ if self.__document is None: self.__document = self.window().windowController().document() return self.__document def setMouseTimer(self, timer): """ Sets timer for tracking mouse location setMouseTimer(timer) """ if (self.__mouseTrackTimer) is not None: self.__mouseTrackTimer.invalidate() self.__mouseTrackTimer = timer def setTrackingRect(self, rect): """ Sets up tracking rectange for mouse location setTrackingRect(rect) """ if (self.__tracking_rect) is not None: self.removeTrackingRect_(self.__tracking_rect) self.__tracking_rect = rect def windowCloseNotification_(self, note): _nc = NSNotificationCenter.defaultCenter() _nc.removeObserver_(self) self.setMouseTimer(None) def frameChangeNotification_(self, note): """ NSView message for changes in enclosing clip view frame size frameChangeNotification(note) """ # # if the area for the CADView is bigger than the CADview, # we make the CADView bigger. It might make sense later to # shrink the CADView IF we can do so without hiding any images # _cv = note.object() _cvsize = _cv.frame().size _mysize = self.frame().size _redraw = False if (_cvsize.width > _mysize.width): _mysize.width = _cvsize.width _redraw = True if (_cvsize.height > _mysize.height): _mysize.height = _cvsize.height _redraw = True if (_redraw): self.setFrameSize_(_mysize) self.setNeedsDisplay_(True) self.updateTrackingRect() PythonCAD.Generic.globals.NSFonts.clear() self.setTransform() def boundsChangeNotification_(self, note): """ NSView message for changes in bounds size boundsChangeNotification(note) """ self.setTransform() PythonCAD.Generic.globals.NSFonts.clear() def itemAddedNotification_(self, note): """ ImageDocument message for new item added to drawing itemAddedNotification(note) """ self.setNeedsDisplayInRect_(self._getTempRect()) self._clearTempItems() _info = note.userInfo() if not _info.has_key("layer"): return if not _info["layer"].isVisible(): return if _info.has_key("item") and self.canDraw(): _item = _info["item"] _objList = [_item] # # assume item added to active layer - might be a problem # self.lockFocus() _bounds = self.bounds() if isinstance(_item, PythonCAD.Generic.conobject.ConstructionObject): self._drawConstructionObjects(_objList, _bounds, True) elif isinstance(_item, PythonCAD.Generic.point.Point): if self.getDocument().getOption('HIGHLIGHT_POINTS'): self._drawPoints(_objList, _bounds) else: self._drawObjects(_objList, _bounds, True) self.unlockFocus() def itemDeletedNotification_(self, note): """ ImageDocument message for item deleted from drawing itemDeletedNotification(note) """ _info = note.userInfo() if not _info.has_key("layer"): return if not _info["layer"].isVisible(): return self.setNeedsDisplay_(True) def setTempPoint(self, point=NSMakePoint(0.0, 0.0)): self.__temporaryPoint = point def setTempObject(self, obj=None, flush=True): if obj is None: self.__temporaryObject = [] elif isinstance(obj, (PythonCAD.Generic.graphicobject.GraphicObject, PythonCAD.Generic.graphicobject.old_GraphicObject, PythonCAD.Generic.text.TextBlock, PythonCAD.Generic.dimension.Dimension)): if flush: self.__temporaryObject=[obj] else: self.__temporaryObject.append(obj) else: raise TypeError, "Invalid graphics object:" + `obj` def flushTempObjects(self): self.setNeedsDisplayInRect_(self._getTempRect()) self._clearTempItems() def _setTempRect(self, rect=NSMakeRect(0.0,0.0,0.0,0.0)): self.__temporaryRect = rect def _getTempRect(self): return self.__temporaryRect def _getTempObject(self): return self.__temporaryObject def _clearTempItems(self): self.setTempPoint() self._setTempRect() self.setTempObject(None) def getImageRep(self): _frame = self.frame() _img = NSImage.alloc().initWithSize_(_frame.size) _img.setScalesWhenResized_(False) _img.lockFocus() self.drawRect_(self.frame()) _img.unlockFocus() return _img # def viewWillStartLiveResize(self): # super(CADView, self).viewWillStartLiveResize() # _bounds = self.bounds() # _image = NSImage.alloc().initWithSize_(_bounds.size) # _image.setCachedSeparately_(True) # _image.lockFocus() # self.drawRect_(_bounds) # _image.unlockFocus() # self.__image = NSImageView.alloc().initWithFrame_(_bounds) # self.addSubview_(self.__image) # self.__image.setAutoresizingMask_(NSViewWidthSizable|NSViewHeightSizable) # self.__image.setBounds_(_bounds) # self.__image.setImage_(_image) def postLoadSetup(self): """ Called after window loaded to make sure things register correctly. Should be able to do this with built-in functions, but can't get it to work. """ _img = self.getDocument().getImage() _obj = PythonCAD.Interface.Cocoa.Globals.wrap(_img) _nc = NSNotificationCenter.defaultCenter() _nc.addObserver_selector_name_object_(self,"itemAddedNotification:","added_object", _obj) _nc.addObserver_selector_name_object_(self,"itemDeletedNotification:","deleted_object", _obj) def viewDidEndLiveResize(self): super(CADView, self).viewDidEndLiveResize() # self.__image.removeFromSuperviewWithoutNeedingDisplay() # del self.__image # self.__image = None # self.setNeedsDisplay_(True) self.updateTrackingRect() def updateTrackingRect(self): """ Sets tracking rectangle over frame boundary to track mouse updateTrackingRect() """ _point = self.getMouseLocation() _vis = self.visibleRect() _flag = self.mouse_inRect_(_point, _vis) _rect = self.addTrackingRect_owner_userData_assumeInside_(_vis, self, 0, _flag) self.setTrackingRect(_rect) def mouseEntered_(self, event): """ NSView override to announce mouse entered CADView. Use for location update. mouseEntered_(event) """ # fire timer every 0.1 sec to track mouse moves _timer = NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(0.1, self, "updateMouseLocation:", 0, True) self.setMouseTimer(_timer) def mouseExited_(self, event): """ NSView override to announce mouse exited CADView. Use for location update. mouseExited_(event) """ self.setMouseTimer(None) def mouseDown_(self, event): _doc = self.getDocument() _tool = _doc.getTool() if _tool is not None and _tool.hasHandler("left_button_press"): _handler = _tool.getHandler("left_button_press") _handler(_doc, event, _tool) def updateMouseLocation_(self, timer): """ timer callback that updates current mouse location in ImageDocument updateMouseLocation_(timer): """ _point = self.getMouseLocation() _doc = self.getDocument() _ox, _oy = _doc.getPoint() if (_ox == _point.x) and (_oy == _point.y): return _doc.setPoint(_point.x,_point.y) _tool = _doc.getTool() if _tool is not None and _tool.hasHandler("mouse_move"): _handler = _tool.getHandler("mouse_move") _handler(_doc, _point, _tool) _x = _y = _w = _h = None if isinstance(_tool, (PythonCAD.Generic.tools.TwoPointCircleTool, PythonCAD.Generic.tools.TangentCCircleTool, PythonCAD.Generic.tools.TwoPointTangentCCircleTool)): _r = _tool.getRadius() if _r is not None and _r > 0: _cx, _cy = _tool.getCenter() _w = _h = _r * 2.1 _x = _cx - _r * 1.05 _y = _cy - _r * 1.05 else: return elif isinstance(_tool, PythonCAD.Generic.tools.ArcTool): _r = _tool.getRadius() if _r is not None and _r > 0: _cx, _cy = _tool.getCenter() _w = _h = _r * 2.1 _x = _cx - _r * 1.05 _y = _cy - _r * 1.05 elif isinstance(_tool, PythonCAD.Generic.tools.CircleTool): _r = hypot((self.__temporaryPoint.x - _point.x), (self.__temporaryPoint.y - _point.y)) _w = _h = _r * 2.1 _x = self.__temporaryPoint.x - _r * 1.05 _y = self.__temporaryPoint.y - _r * 1.05 elif isinstance(_tool, PythonCAD.Generic.tools.CCircleTangentLineTool): _tanpts = _tool.getTangentPoints() _tanrect = NSMakeRect(0,0,0,0) for _set in _tanpts: _x1, _y1, _x2, _y2 = _set _wt = abs(_x2 - _x1) * 1.06 _ht = abs(_y2 - _y1) * 1.06 _xt = min(_x1, _x2) - _wt * 0.03 _yt = min(_y1, _y2) - _ht * 0.03 _setrect = NSMakeRect(_xt, _yt, _wt, _ht) _tanrect = NSUnionRect(_tanrect, _setrect) _x = NSMinX(_tanrect) _y = NSMinY(_tanrect) _w = NSWidth(_tanrect) _h = NSHeight(_tanrect) elif isinstance(_tool, PythonCAD.Generic.tools.PolygonTool): _count = _tool.getSideCount() (_xc, _yc) = _tool.getCoord(0) _x = _xmax = _xc _y = _ymax = _yc for _i in range(1, _count): (_xc, _yc) = _tool.getCoord(_i) _x = min(_x, _xc) _xmax = max(_xmax, _xc) _y = min(_y, _yc) _ymax = max(_ymax, _yc) _w = abs(_xmax - _x) * 1.06 _h = abs(_ymax - _y) * 1.06 _x = _x - _w*0.03 _y = _y - _h*0.03 elif isinstance(_tool, PythonCAD.Generic.tools.TextTool): _x = _point.x _y = _point.y _vis = self.visibleRect() _w = NSWidth(_vis)/10.0 _h = NSHeight(_vis)/10.0 elif isinstance(_tool, PythonCAD.Generic.tools.AngularDimensionTool): _l1, _fp = _tool.getFirstPoint() _l2, _sp = _tool.getSecondPoint() if (_fp is not None) and (_sp is not None): _l, _vp = _tool.getVertexPoint() _vx, _vy = _vp.getCoords() _rad = hypot((_vx - _point.x), (_vy - _point.y)) _dim = _tool.getDimension() _bar1, _bar2 = _dim.getDimBars() _ep1, _ep2 = _bar1.getEndpoints() _ep3, _ep4 = _bar2.getEndpoints() _x1, _y1 = _ep1 _x2, _y2 = _ep2 _x3, _y3 = _ep3 _x4, _y4 = _ep4 _x5 = _vx - _rad _x6 = _vx + _rad _y5 = _vy - _rad _y6 = _vy + _rad _xmax = max(_x1, _x2, _x3, _x4, _x5, _x6, _point.x) _ymax = max(_y1, _y2, _y3, _y4, _y5, _y6, _point.y) _xmin = min(_x1, _x2, _x3, _x4, _x5, _x6, _point.x) _ymin = min(_y1, _y2, _y3, _y4, _y5, _y6, _point.y) _w = abs(_xmax - _xmin) * 1.1 _h = abs(_ymax - _ymin) * 1.1 _x = _xmin - _w * 0.05 _y = _ymin - _h * 0.05 elif isinstance(_tool, PythonCAD.Generic.tools.LinearDimensionTool): _l1, _p1 = _tool.getFirstPoint() _l2, _p2 = _tool.getSecondPoint() if _p1 is not None and _p2 is not None: _dim = _tool.getDimension() _bar1, _bar2 = _dim.getDimBars() _crossbar = _dim.getDimCrossbar() # # draw dimension lines # _ep1, _ep2 = _bar1.getEndpoints() _ep3, _ep4 = _bar2.getEndpoints() _ep5, _ep6 = _crossbar.getEndpoints() _x1, _y1 = _ep1 _x2, _y2 = _ep2 _x3, _y3 = _ep3 _x4, _y4 = _ep4 _x5, _y5 = _ep5 _x6, _y6 = _ep6 _xmax = max(_x1, _x2, _x3, _x4, _x5, _x6, _point.x) _ymax = max(_y1, _y2, _y3, _y4, _y5, _y6, _point.y) _xmin = min(_x1, _x2, _x3, _x4, _x5, _x6, _point.x) _ymin = min(_y1, _y2, _y3, _y4, _y5, _y6, _point.y) _w = abs(_xmax - _xmin) * 1.1 _h = abs(_ymax - _ymin) * 1.1 if (_w < 50): _w = 50 if (_h < 30): _h = 30 _x = _xmin - _w * 0.05 _y = _ymin - _h * 0.05 elif isinstance(_tool, PythonCAD.Generic.tools.RadialDimensionTool): _rdim = _tool.getDimension() _cb = _rdim.getDimCrossbar() _ep1, _ep2 = _cb.getEndpoints() _x1, _y1 = _ep1 _x2, _y2 = _ep2 _xmax = max(_x1, _x2, _point.x) _ymax = max(_y1, _y2, _point.y) _xmin = min(_x1, _x2, _point.x) _ymin = min(_y1, _y2, _point.y) _w = abs(_xmax - _xmin) * 1.2 _h = abs(_ymax - _ymin) * 1.2 if (_w < 50): _w = 50 if (_h < 30): _h = 30 _x = _xmin - _w * 0.15 _y = _ymin - _h * 0.15 if (_x is None) or (_y is None) or (_w is None) or (_h is None): _w = abs(_point.x - self.__temporaryPoint.x) * 1.06 _h = abs(_point.y - self.__temporaryPoint.y) * 1.06 _x = min(_point.x, self.__temporaryPoint.x) - _w * 0.03 _y = min(_point.y, self.__temporaryPoint.y) - _h * 0.03 _rect = NSMakeRect(_x, _y, _w, _h) _trect = self._getTempRect() self.setNeedsDisplayInRect_(_trect) self.setNeedsDisplayInRect_(_rect) self._setTempRect(_rect) def getMouseLocation(self): """ Finds mouse location in view getMouseLocation() This function returns an NSPoint corresponding to mouse location in view's coordinate system. """ _mouseLoc = self.window().mouseLocationOutsideOfEventStream() return self.convertPoint_fromView_(_mouseLoc, None) def fitImage(self): """Redraw the image so all entities are visible in the window. fitImage() """ _clipView = self.enclosingScrollView().contentView() _conRect = _clipView.documentRect() _doc = self.getDocument() _xmin, _ymin, _xmax, _ymax = _doc.getImage().getExtents() _xdiff = abs(_xmax - _xmin) * 1.05 _ydiff = abs(_ymax - _ymin) * 1.05 _xs = _xdiff / NSWidth(_conRect) _ys = _ydiff / NSHeight(_conRect) _xmid = (_xmin + _xmax) * 0.5 _ymid = (_ymin + _ymax) * 0.5 if _xs > _ys: _width = _xdiff _height = NSHeight(_conRect) * _xs else: _height = _ydiff _width = NSWidth(_conRect) * _ys _nx = _xmid - _width * 0.5 _ny = _ymid - _height * 0.5 self.zoomToRect(((_nx, _ny), (_width, _height))) def zoomToRect(self, rect): _clipView = self.enclosingScrollView().contentView() (_nx, _ny), (_nw, _nh) = rect (_cx, _cy), (_cw, _ch) = _clipView.frame() (_fx, _fy), (_fw, _fh) = self.frame() (_vx, _vy), (_vw, _vh) = self.visibleRect() _wzoom = _vw / _nw _hzoom = _vh / _nh _zoom = min(_wzoom, _hzoom) _nfw = _fw * _zoom _nfh = _fh * _zoom if _nfw < _cw or _nfh < _ch: _nfw = _cw _nfh = _ch self.setFrameSize_((_nfw, _nfh)) (_bx, _by), (_bw, _bh) = self.bounds() self.setBoundsSize_((_bw / _zoom, _bh / _zoom)) self.scrollRectToVisible_(rect) self.setNeedsDisplay_(True) def drawRect_(self, rect): """ NSView override to draw image in view drawRect(rect) Drawing view clipped to passed in NSRect "rect" """ _doc = self.getDocument() _gc = NSGraphicsContext.currentContext() _gc.setShouldAntialias_(False) self._drawBackground(_doc, rect) _active_layer = _doc.getImage().getActiveLayer() _layers = [] _layers.append(_doc.getImage().getTopLayer()) while (len(_layers)): _layer = _layers.pop() if _layer is not _active_layer and _layer.isVisible(): self._drawLayer(_doc, _layer, rect) if _layer.hasSublayers(): _layers.extend(_layer.getSublayers()) if _active_layer.isVisible(): self._drawLayer(_doc, _active_layer, rect) def _drawBackground(self, doc, rect): """ draws background color of ImageDocument doc in NSRect rect _drawBackground(doc, rect) """ _color = doc.getOption('BACKGROUND_COLOR') _nscolor = self.getNSColor(_color) _nscolor.set() NSRectFill(rect) def _drawLayer(self, doc, layer, rect): """ draws Layer "layer" of ImageDocument "doc" in NSRect "rect" _drawLayer(doc, layer, rect) """ _size = self.pointSize() _bigRect = NSInsetRect(rect, -_size.width, -_size.height) (_xmin, _ymin, _xmax, _ymax) = self.rectToCoordTransform(_bigRect) _objs = layer.objsInRegion(_xmin, _ymin, _xmax, _ymax) _active_layer = doc.getImage().getActiveLayer() if _active_layer is layer: active = True _tempObj = self._getTempObject() if len(_tempObj) > 0: for _obj in _tempObj: _objs.append(_obj) else: active = False _conobjs = [] _vobjs = [] _pts = [] for _obj in _objs: if isinstance(_obj, PythonCAD.Generic.conobject.ConstructionObject): _conobjs.append(_obj) elif isinstance(_obj, PythonCAD.Generic.point.Point): _pts.append(_obj) else: _vobjs.append(_obj) _bounds = self.bounds() self._drawConstructionObjects(_conobjs, _bounds, active) if doc.getOption('HIGHLIGHT_POINTS'): self._drawPoints(_pts, _bounds) self._drawObjects(_vobjs, _bounds, active) def _drawConstructionObjects(self, objs, rect, active): # # style bits are the same for all construction objects, so all # in the same bezier path # _constyle = PythonCAD.Generic.conobject.ConstructionObject._ConstructionObject__defstyle _dashArray = _constyle.getLinetype().getList() if _dashArray is None: _dashArray = [2, 2] _scaledArray = [] for _num in _dashArray: _scaledArray.append(_num*self.__x_scale) _path = NSBezierPath.bezierPath() _path.setLineDash_count_phase_(_scaledArray, len(_scaledArray), 0.0) _path.setLineCapStyle_(NSButtLineCapStyle) _path.setLineJoinStyle_(NSMiterLineJoinStyle) _path.setLineWidth_(0.0) if active: _color = _constyle.getColor() else: _color = self.getDocument().getOption('INACTIVE_LAYER_COLOR') self.getNSColor(_color).set() (_xmin, _ymin, _xmax, _ymax) = self.rectToCoordTransform(rect) for _obj in objs: if isinstance(_obj, PythonCAD.Generic.hcline.HCLine): _x, _y = _obj.getLocation().getCoords() _tp = self.nudgePoint(rect, NSMakePoint(_x, _y)) _point = NSMakePoint(_xmin, _tp.y) _path.moveToPoint_(_point) _point = NSMakePoint(_xmax, _tp.y) _path.lineToPoint_(_point) elif isinstance(_obj, PythonCAD.Generic.vcline.VCLine): _x, _y = _obj.getLocation().getCoords() _tp = self.nudgePoint(rect, NSMakePoint(_x, _y)) _point = NSMakePoint(_tp.x, _ymin) _path.moveToPoint_(_point) _point = NSMakePoint(_tp.x, _ymax) _path.lineToPoint_(_point) elif isinstance(_obj, PythonCAD.Generic.acline.ACLine): _coords = _obj.clipToRegion(_xmin, _ymin, _xmax, _ymax) if _coords is not None: _x1, _y1, _x2, _y2 = _coords _tp1 = self.nudgePoint(rect, NSMakePoint(_x1, _y1)) _tp2 = self.nudgePoint(rect, NSMakePoint(_x2, _y2)) _path.moveToPoint_(_tp1) _path.lineToPoint_(_tp2) elif isinstance(_obj, PythonCAD.Generic.cline.CLine): _coords = _obj.clipToRegion(_xmin, _ymin, _xmax, _ymax) if _coords is not None: _x1, _y1, _x2, _y2 = _coords _tp1 = self.nudgePoint(rect, NSMakePoint(_x1, _y1)) _tp2 = self.nudgePoint(rect, NSMakePoint(_x2, _y2)) _path.moveToPoint_(_tp1) _path.lineToPoint_(_tp2) elif isinstance(_obj, PythonCAD.Generic.ccircle.CCircle): _x, _y = _obj.getCenter().getCoords() _radius = _obj.getRadius() _tp = self.nudgePoint(rect, NSMakePoint(_x - _radius, _y - _radius)) _rect = NSMakeRect(_tp.x, _tp.y, _radius*2.0, _radius*2.0) _path.appendBezierPathWithOvalInRect_(_rect) else: pass _path.stroke() def _drawPoints(self, pts, rect): _ptSize = self.pointSize() _xcorr = _ptSize.width * 0.5 _ycorr = _ptSize.height * 0.5 _pathSingle = NSBezierPath.bezierPath() _pathSingle.setLineCapStyle_(NSButtLineCapStyle) _pathSingle.setLineJoinStyle_(NSMiterLineJoinStyle) _pathSingle.setLineWidth_(0.0) _pathMulti = _pathSingle.copyWithZone_(None) for _pt in pts: _users = _pt.getUsers() _path = _pathSingle if len(_users) > 1: _nd = 0 for _uref in _users: _user = _uref() if not isinstance(_user, PythonCAD.Generic.dimension.Dimension): _nd = _nd + 1 if _nd > 1: _path = _pathMulti break _orig = NSMakePoint(_pt.x - _xcorr, _pt.y - _ycorr) _orig = self.nudgePoint(rect, _orig) _path.appendBezierPathWithRect_(NSMakeRect(_orig.x, _orig.y, _ptSize.width, _ptSize.height)) _color = self.getDocument().getOption('SINGLE_POINT_COLOR') self.getNSColor(_color).set() _pathSingle.stroke() _color = self.getDocument().getOption('MULTI_POINT_COLOR') self.getNSColor(_color).set() _pathMulti.stroke() def _drawObjects(self, objs, rect, active): # # set default color if inactive # if not active: _color = self.getDocument().getOption('INACTIVE_LAYER_COLOR') self.getNSColor(_color).set() (_xmin, _ymin, _xmax, _ymax) = self.rectToCoordTransform(rect) # # iterate through items & draw # for _obj in objs: if (isinstance(_obj, PythonCAD.Generic.graphicobject.GraphicObject) or isinstance(_obj, PythonCAD.Generic.graphicobject.old_GraphicObject)): # # setup path # _path = NSBezierPath.bezierPath() # # line type # _dashList = _obj.getLinetype().getList() if _dashList is None: _dashList = [1] _scaledList = [] for _num in _dashList: _scaledList.append(_num*self.__x_scale) _path.setLineDash_count_phase_(_scaledList, len(_scaledList), 0.0) # # line color # if active: _color = _obj.getColor() self.getNSColor(_color).set() # # line thickness, cap, join # _path.setLineWidth_(_obj.getThickness()) _path.setLineJoinStyle_(NSMiterLineJoinStyle) _path.setLineCapStyle_(NSRoundLineCapStyle) # # items # if isinstance(_obj, PythonCAD.Generic.segment.Segment): _coords = _obj.clipToRegion(_xmin, _ymin, _xmax, _ymax) if _coords is not None: _x1, _y1, _x2, _y2 = _coords _tp1 = self.nudgePoint(rect, NSMakePoint(_x1, _y1)) _tp2 = self.nudgePoint(rect, NSMakePoint(_x2, _y2)) _path.moveToPoint_(_tp1) _path.lineToPoint_(_tp2) _path.stroke() elif isinstance(_obj, PythonCAD.Generic.arc.Arc): _x, _y = _obj.getCenter().getCoords() _point = self.nudgePoint(rect, NSMakePoint(_x, _y)) _r = _obj.getRadius() _sa = _obj.getStartAngle() _ea = _obj.getEndAngle() _path.appendBezierPathWithArcWithCenter_radius_startAngle_endAngle_clockwise_(_point, _r, _sa, _ea, False) _path.stroke() elif isinstance(_obj, PythonCAD.Generic.circle.Circle): _x, _y = _obj.getCenter().getCoords() _radius = _obj.getRadius() _tp = self.nudgePoint(rect, NSMakePoint(_x - _radius, _y - _radius)) _rect = NSMakeRect(_tp.x, _tp.y, _radius*2.0, _radius*2.0) _path.appendBezierPathWithOvalInRect_(_rect) _path.stroke() elif isinstance(_obj, PythonCAD.Generic.segjoint.Chamfer): _p1, _p2 = _obj.getMovingPoints() _tp1 = self.nudgePoint(rect, NSMakePoint(_p1.x, _p1.y)) _tp2 = self.nudgePoint(rect, NSMakePoint(_p2.x, _p2.y)) _path.moveToPoint_(_tp1) _path.lineToPoint_(_tp2) _path.stroke() elif isinstance(_obj, PythonCAD.Generic.segjoint.Fillet): _x, _y = _obj.getCenter() _p = self.nudgePoint(rect, NSMakePoint(_x, _y)) _r = _obj.getRadius() _sa, _ea = _obj.getAngles() _path.appendBezierPathWithArcWithCenter_radius_startAngle_endAngle_clockwise_(_p, _r, _sa, _ea, False) _path.stroke() elif isinstance(_obj, PythonCAD.Generic.leader.Leader): _p1, _p2, _p3 = _obj.getPoints() _tp1 = self.nudgePoint(rect, NSMakePoint(_p1.x, _p1.y)) _tp2 = self.nudgePoint(rect, NSMakePoint(_p2.x, _p2.y)) _tp3 = self.nudgePoint(rect, NSMakePoint(_p3.x, _p3.y)) _path.moveToPoint_(_tp1) _path.lineToPoint_(_tp2) _path.lineToPoint_(_tp3) _path.stroke() _path.removeAllPoints() _apts = _obj.getArrowPoints() _ap1 = self.nudgePoint(rect, NSMakePoint(_apts[0], _apts[1])) _ap2 = self.nudgePoint(rect, NSMakePoint(_apts[2], _apts[3])) _path.moveToPoint_(_tp3) _path.lineToPoint_(_ap1) _path.lineToPoint_(_ap2) _path.closePath() _path.stroke() _path.fill() elif isinstance(_obj, PythonCAD.Generic.polyline.Polyline): for _pt in _obj.getPoints(): _x, _y = _pt.getCoords() _point = self.nudgePoint(rect, NSMakePoint(_x, _y)) try: _path.lineToPoint_(_point) except: # catches first point _path.moveToPoint_(_point) _path.stroke() elif isinstance(_obj, PythonCAD.Generic.text.TextBlock): self._drawText(_obj, rect) elif isinstance(_obj, PythonCAD.Generic.dimension.HorizontalDimension): self._drawLinearDimension(_obj, rect, active) elif isinstance(_obj, PythonCAD.Generic.dimension.VerticalDimension): self._drawLinearDimension(_obj, rect, active) elif isinstance(_obj, PythonCAD.Generic.dimension.LinearDimension): self._drawLinearDimension(_obj, rect, active) elif isinstance(_obj, PythonCAD.Generic.dimension.RadialDimension): self._drawRadialDimension(_obj, rect, active) elif isinstance(_obj, PythonCAD.Generic.dimension.AngularDimension): self._drawAngularDimension(_obj, rect, active) else: pass def _drawLinearDimension(self, dim, rect, active): _path = NSBezierPath.bezierPath() _path.setLineWidth_(0) _path.setLineJoinStyle_(NSMiterLineJoinStyle) _path.setLineCapStyle_(NSButtLineCapStyle) if active: _color = dim.getColor() self.getNSColor(_color).set() if dim.isModified(): dim.calcDimValues() dim.reset() _bar1, _bar2 = dim.getDimBars() _crossbar = dim.getDimCrossbar() # # draw dimension lines # _ep1, _ep2 = _bar1.getEndpoints() _tp1 = self.nudgePoint(rect, NSMakePoint(_ep1[0], _ep1[1])) _tp2 = self.nudgePoint(rect, NSMakePoint(_ep2[0], _ep2[1])) _path.moveToPoint_(_tp1) _path.lineToPoint_(_tp2) _ep1, _ep2 = _bar2.getEndpoints() _tp1 = self.nudgePoint(rect, NSMakePoint(_ep1[0], _ep1[1])) _tp2 = self.nudgePoint(rect, NSMakePoint(_ep2[0], _ep2[1])) _path.moveToPoint_(_tp1) _path.lineToPoint_(_tp2) _ep1, _ep2 = _crossbar.getEndpoints() _tp1 = self.nudgePoint(rect, NSMakePoint(_ep1[0], _ep1[1])) _tp2 = self.nudgePoint(rect, NSMakePoint(_ep2[0], _ep2[1])) _path.moveToPoint_(_tp1) _path.lineToPoint_(_tp2) _path.stroke() # # draw endpoints # _mpts = _crossbar.getCrossbarPoints() _mp = _mpts[0] _mp1 = NSMakePoint(_mp[0], _mp[1]) _mp = _mpts[1] _mp2 = NSMakePoint(_mp[0], _mp[1]) _etype = dim.getEndpointType() if (_etype == PythonCAD.Generic.dimension.Dimension.ARROW or _etype == PythonCAD.Generic.dimension.Dimension.FILLED_ARROW or _etype == PythonCAD.Generic.dimension.Dimension.SLASH): _epts = _crossbar.getMarkerPoints() assert len(_epts) == 4, "Bad marker point count: %d" % len(_epts) self._drawLineEndpoints(_etype, _epts[0:2], _mp1) self._drawLineEndpoints(_etype, _epts[2:4], _mp2) elif _etype == PythonCAD.Generic.dimension.Dimension.CIRCLE: _size = dim.getEndpointSize() self._drawCircleEndpoints(_mp1, _size) self._drawCircleEndpoints(_mp2, _size) else: pass self._drawDimensionText(dim) def _drawRadialDimension(self, dim, rect, active): _path = NSBezierPath.bezierPath() _path.setLineWidth_(0) _path.setLineJoinStyle_(NSMiterLineJoinStyle) _path.setLineCapStyle_(NSButtLineCapStyle) if active: _color = dim.getColor() self.getNSColor(_color).set() if dim.isModified(): dim.calcDimValues() dim.reset() # # draw line # _crossbar = dim.getDimCrossbar() _ep1, _ep2 = _crossbar.getEndpoints() _tp1 = self.nudgePoint(rect, NSMakePoint(_ep1[0], _ep1[1])) _tp2 = self.nudgePoint(rect, NSMakePoint(_ep2[0], _ep2[1])) _path.moveToPoint_(_tp1) _path.lineToPoint_(_tp2) _path.stroke() # # draw endpoints # _p1, _p2 = _crossbar.getCrossbarPoints() _mp1 = NSMakePoint(_p1[0], _p1[1]) _mp2 = NSMakePoint(_p2[0], _p2[1]) _etype = dim.getEndpointType() _dia_mode = dim.getDiaMode() if (_etype == PythonCAD.Generic.dimension.Dimension.ARROW or _etype == PythonCAD.Generic.dimension.Dimension.FILLED_ARROW or _etype == PythonCAD.Generic.dimension.Dimension.SLASH): _epts = _crossbar.getMarkerPoints() assert len(_epts) == 4, "Unexpect endpoint length: %d" % len(_epts) if _dia_mode: self._drawLineEndpoints(_etype, _epts[0:2], _mp1) self._drawLineEndpoints(_etype, _epts[2:4], _mp2) elif _etype == PythonCAD.Generic.dimension.Dimension.CIRCLE: _size = dim.getEndpointSize() if _dia_mode: self._drawCircleEndpoints(_mp1, _size) self._drawCircleEndpoints(_mp2, _size) else: pass self._drawDimensionText(dim) def _drawAngularDimension(self, dim, rect, active): _path = NSBezierPath.bezierPath() _path.setLineWidth_(0) _path.setLineJoinStyle_(NSMiterLineJoinStyle) _path.setLineCapStyle_(NSButtLineCapStyle) if active: _color = dim.getColor() self.getNSColor(_color).set() if dim.isModified(): dim.calcDimValues() dim.reset() _bar1, _bar2 = dim.getDimBars() _crossarc = dim.getDimCrossarc() # # draw dimension lines # _ep1, _ep2 = _bar1.getEndpoints() _tp1 = self.nudgePoint(rect, NSMakePoint(_ep1[0], _ep1[1])) _tp2 = self.nudgePoint(rect, NSMakePoint(_ep2[0], _ep2[1])) _path.moveToPoint_(_tp1) _path.lineToPoint_(_tp2) _ep1, _ep2 = _bar2.getEndpoints() _tp1 = self.nudgePoint(rect, NSMakePoint(_ep1[0], _ep1[1])) _tp2 = self.nudgePoint(rect, NSMakePoint(_ep2[0], _ep2[1])) _path.moveToPoint_(_tp1) _path.lineToPoint_(_tp2) _path.stroke() _path.removeAllPoints() # # draw dimension arc # _vx, _vy = dim.getVertexPoint().getCoords() _sa = _crossarc.getStartAngle() _ea = _crossarc.getEndAngle() _rad = _crossarc.getRadius() _point = self.nudgePoint(rect, NSMakePoint(_vx, _vy)) _path.appendBezierPathWithArcWithCenter_radius_startAngle_endAngle_clockwise_(_point, _rad, _sa, _ea, False) _path.stroke() # # draw endpoints # _p1, _p2 = _crossarc.getCrossbarPoints() _mp1 = NSMakePoint(_p1[0], _p1[1]) _mp2 = NSMakePoint(_p2[0], _p2[1]) _etype = dim.getEndpointType() if (_etype == PythonCAD.Generic.dimension.Dimension.ARROW or _etype == PythonCAD.Generic.dimension.Dimension.FILLED_ARROW or _etype == PythonCAD.Generic.dimension.Dimension.SLASH): _epts = _crossarc.getMarkerPoints() assert len(_epts) == 4, "Unexpect endpoint length: %d" % len(_epts) self._drawLineEndpoints(_etype, _epts[0:2], _mp1) self._drawLineEndpoints(_etype, _epts[2:4], _mp2) elif _etype == PythonCAD.Generic.dimension.Dimension.CIRCLE: _size = dim.getEndpointSize() self._drawCircleEndpoints(_mp1, _size) self._drawCircleEndpoints(_mp2, _size) else: pass self._drawDimensionText(dim) def _drawCircleEndpoints(self, mp, size): _path = NSBezierPath.bezierPath() _path.setLineWidth_(0) _path.setLineJoinStyle_(NSMiterLineJoinStyle) _path.setLineCapStyle_(NSButtLineCapStyle) _rad = size * 0.5 _rect = NSMakeRect(mp.x - _rad , mp.y - _rad, size, size) _path.appendBezierPathWithOvalInRect_(_rect) _path.stroke() _path.fill() def _drawLineEndpoints(self, etype, ep, mp): _path = NSBezierPath.bezierPath() _path.setLineWidth_(0) _path.setLineJoinStyle_(NSMiterLineJoinStyle) _path.setLineCapStyle_(NSButtLineCapStyle) if etype == PythonCAD.Generic.dimension.Dimension.ARROW: for _i in range(2): _ep = ep[_i] _tep = NSMakePoint(_ep[0], _ep[1]) _path.moveToPoint_(_tep) _path.lineToPoint_(mp) elif etype == PythonCAD.Generic.dimension.Dimension.FILLED_ARROW: _ep = ep[0] _tep = NSMakePoint(_ep[0], _ep[1]) _path.moveToPoint_(_tep) _ep = ep[1] _tep = NSMakePoint(_ep[0], _ep[1]) _path.lineToPoint_(_tep) _path.lineToPoint_(mp) _path.closePath() elif etype == PythonCAD.Generic.dimension.Dimension.SLASH: _ep = ep[0] _tep = NSMakePoint(_ep[0], _ep[1]) _path.moveToPoint_(_tep) _ep = ep[1] _tep = NSMakePoint(_ep[0], _ep[1]) _path.lineToPoint_(_tep) else: pass _path.stroke() _path.fill() def _drawText(self, obj, rect): _gc = NSGraphicsContext.currentContext() _gc.setShouldAntialias_(True) _attrs = self.formatDictionary(obj, False) _x, _y = obj.getLocation() _point = self.nudgePoint(rect, NSMakePoint(_x, _y)) _font = _attrs[NSFontAttributeName] _lineHeight = _font.defaultLineHeightForFont() _text = obj.getText().splitlines() for _str in _text: _as = NSAttributedString.alloc().initWithString_attributes_(_str, _attrs) _as.drawAtPoint_(_point) _point.y = _point.y - _lineHeight _gc.setShouldAntialias_(False) def _drawDimensionText(self, dim): _gc = NSGraphicsContext.currentContext() _gc.setShouldAntialias_(True) _x, _y = dim.getLocation() _dlen = dim.calculate() _hlen = self.getDocument().getImage().scaleLength(_dlen) _dims = dim.getDimensions(_hlen) _pds = dim.getPrimaryDimstring() _pdsAttr = self.formatDictionary(_pds, True) _dim1 = NSAttributedString.alloc().initWithString_attributes_(_dims[0], _pdsAttr) _dim1Size = _dim1.size() _dual_mode = dim.getDualDimMode() if _dual_mode: _sds = dim.getSecondaryDimstring() _sdsAttr = self.formatDictionary(_sds, True) _dim2 = NSAttributedString.alloc().initWithString_attributes_(_dims[1], _sdsAttr) _dim2Size = _dim2.size() _width = max(_dim1Size.width, _dim2Size.width) * 0.5 # sep line & fill _gc.saveGraphicsState() _ngc = NSGraphicsContext.currentContext() _color = self.getDocument().getOption('BACKGROUND_COLOR') self.getNSColor(_color).set() NSRectFill(NSMakeRect((_x - _width), (_y - 2), _width * 2.0, 5)) _ngc.restoreGraphicsState() _path = NSBezierPath.bezierPath() _path.setLineWidth_(0) _point = NSMakePoint((_x - _width), _y) _path.moveToPoint_(_point) _point = NSMakePoint((_x + _width), _y) _path.lineToPoint_(_point) _path.stroke() # prim dim _point = NSMakePoint((_x - _dim1Size.width * 0.5), (_y + 2)) # a little padding on the height _dim1.drawAtPoint_(_point) # sec dim _point = NSMakePoint((_x - _dim2Size.width * 0.5), (_y - _dim2Size.height - 2)) _dim2.drawAtPoint_(_point) else: _point = NSMakePoint((_x - _dim1Size.width*0.5), (_y - _dim1Size.height* 0.5)) _dim1.drawAtPoint_(_point) _gc.setShouldAntialias_(False) def pointSize(self): _defsize = NSMakeSize(10, 10) _size = self.getTransform().transformSize_(_defsize) return _size def formatDictionary(self, style, db): """ returns attribute dictionary for NSAttributedString formatDictionary(styleObj, drawsBackground): """ _fm = NSFontManager.sharedFontManager() _family = style.getFamily() _style = style.getStyle() _weight = style.getWeight() _size = ceil(style.getSize() * self.__y_scale) if _size < 2: _size = 2 _fontkey = str(_family)+str(_style)+str(_weight)+str(_size) if PythonCAD.Generic.globals.NSFonts.has_key(_fontkey): _font = PythonCAD.Generic.globals.NSFonts[_fontkey] else: _traits = 0 if PythonCAD.Generic.text.TextStyle.FONT_ITALIC == _style: _traits = _traits | NSItalicFontMask if PythonCAD.Generic.text.TextStyle.WEIGHT_LIGHT == _weight: _weight = 3 if PythonCAD.Generic.text.TextStyle.WEIGHT_NORMAL == _weight: _weight = 5 elif PythonCAD.Generic.text.TextStyle.WEIGHT_BOLD == _weight: _weight = 9 elif PythonCAD.Generic.text.TextStyle.WEIGHT_HEAVY == _weight: _weight = 11 _font = _fm.fontWithFamily_traits_weight_size_(_family, _traits, _weight, _size) if _font is None: _font = NSFont.userFixedPitchFontOfSize_(_size) if PythonCAD.Generic.text.TextSTyle.FONT_ITALIC == _style: _font = _fm.convertFont_toHaveTrait_(_font, NSItalicFontMask) if _weight > 5: _font = _fm.convertWeight_ofFont_(True, _font) elif _weight < 5: _font = _fm.convertWeight_ofFont_(False, _font) PythonCAD.Generic.globals.NSFonts[_fontkey] = _font _attrs = {} _attrs[NSFontAttributeName] = _font if _size < 4: _attrs[NSKernAttributeName] = 0.3 _color = style.getColor() _attrs[NSForegroundColorAttributeName] = self.getNSColor(_color) if db: _color = self.getDocument().getOption('BACKGROUND_COLOR') _attrs[NSBackgroundColorAttributeName] = self.getNSColor(_color) return _attrs def nudgePoint(self, rect, point): """ we give the points a nudge to get a single pixel line nudgePoint(point) Returns an NSPoint """ _nudge = self.__x_scale * 0.5 _xoffset = round((point.x - rect.origin.x)/self.__x_scale) point.x = rect.origin.x + self.__x_scale*_xoffset + _nudge _nudge = self.__y_scale * 0.5 _yoffset = round((point.y - rect.origin.y)/self.__y_scale) point.y = rect.origin.y + self.__y_scale*_yoffset + _nudge return point def translateSize(self, size): return self.__trans.transformSize_(size) def setTransform(self): _trans = NSAffineTransform.transform() _bounds = self.bounds() _frame = self.frame() _xs = _bounds.size.width / _frame.size.width _ys = _bounds.size.height / _frame.size.height # _xt = _bounds.origin.x * _xs # _yt = _bounds.origin.y * _ys # _trans.translateXBy_yBy_(_xt, _yt) _trans.scaleXBy_yBy_(_xs, _ys) self.__trans = _trans self.__x_scale = _xs self.__y_scale = _ys def getTransform(self): if self.__trans is None: self.setTransform() return self.__trans def rectToCoordTransform(self, rect): """ Converts NSRect rect into x-y coordinates of ImageDocument rectToCoordTransform(rect) returns (xmin, ymin, xmax, ymax) """ return (NSMinX(rect), NSMinY(rect), NSMaxX(rect), NSMaxY(rect)) def getNSColor(self, color): """Retrieves an NSColor for a Color object. getNSColor(color) Argument "color" must be a Color object. This method returns an equivalent NSColor object, allocating it if necessary """ if not isinstance(color, PythonCAD.Generic.color.Color): raise TypeError, "Invalid Color object: " + `color` if PythonCAD.Generic.globals.NSColors.has_key(color): _val = PythonCAD.Generic.globals.NSColors[color] else: (_r, _g, _b) = color.getColors() _val = NSColor.colorWithCalibratedRed_green_blue_alpha_(_r/255.0, _g/255.0, _b/255.0, 1.0) PythonCAD.Generic.globals.NSColors[color] = _val return _val PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/__init__.py0000644000175000017500000000202411307666657022016 0ustar matteomatteo# # Copyright (c) 2002-2004, Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # define __all__ so 'from Generic import *' works # __all__ = [ 'AppController', 'CADView', 'CocoaDimensions', 'CocoaEntities', 'CocoaConobjs', 'CocoaModify', 'Globals', 'ImageDocument', 'ImageWindowController', 'LayerView' ] PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/ImageDocument.nib/0000755000175000017500000000000011307677001023160 5ustar matteomatteoPythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/ImageDocument.nib/classes.nib0000644000175000017500000000130011307666657025320 0ustar matteomatteo{ IBClasses = ( {CLASS = CADView; LANGUAGE = ObjC; SUPERCLASS = NSView; }, {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = ImageDocument; LANGUAGE = ObjC; OUTLETS = { CADView = CADView; entryField = NSTextField; layerOutlineView = NSOutlineView; locationField = NSTextField; promptField = NSTextField; splitView = NSSplitView; }; SUPERCLASS = NSDocument; }, {CLASS = LayerOutlineView; LANGUAGE = ObjC; SUPERCLASS = NSOutlineView; } ); IBVersion = 1; }PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/ImageDocument.nib/keyedobjects.nib0000644000175000017500000001607311307666657026353 0ustar matteomatteobplist00 Y$archiverX$versionT$topX$objects_NSKeyedArchiver ]IB.objectdata +/067;?IP[bcrs{|     249;OPQRWZ[^bcfiyz  S ! "#%'>z?@ABCDEFGHIJKLU$null  !"#$%&'()*[NSNamesKeys[NSFramework_NSObjectsValues]NSNamesValues]NSConnections]NSFontManagerVNSRootYNSNextOid_NSVisibleWindows]NSObjectsKeys]NSClassesKeysZNSOidsKeys\NSOidsValuesV$class_NSClassesValuesJ,-.[NSClassName]ImageDocument1234X$classesZ$classname45^NSCustomObjectXNSObject_IBCocoaFramework89:ZNS.objects12<==>5\NSMutableSetUNSSet8@HABCDEFG +19^JKLMNO"]NSDestinationWNSLabelXNSSource QRSTUVVWXYZ_NSNextResponder[NSSuperviewWNSFrameYNSEnabledVNSCell  \Q]R^_`_aZNSSubviews[NSFrameSize_{{0, 2}, {371, 13}}defghijklmMnopq[NSTextColorYNSSupportZNSContents]NSControlView[NSCellFlags_NSBackgroundColor\NSCellFlags2@_PromptTextFieldtuvwxyzVNSSizeVNSNameXNSfFlags"A \LucidaGrande12}~~5VNSFontWNSColor[NSColorName\NSColorSpace]NSCatalogNameVSystem\controlColorWNSWhiteK0.66666669125_controlTextColorB012U5_NSTextFieldCell\NSActionCell125[NSTextField\%NSTextFieldYNSControlVNSView[NSResponder[promptField125_NSNibOutletConnector^NSNibConnectorJKLO"*QRSTUXYXNSvFlags !"\QS!a@_{{20, 20}, {881, 22}}defghijXnq_NSDrawsBackground($#qA%Ptuvxy"AP'&_textBackgroundColorB1)YtextColorZentryFieldJKLO",0QRSTUVVXYπ-._{{726, 2}, {158, 13}}defghijklnopӀ/@]LocationField]locationFieldJKLO"28]QR,[NSExtension64375\QRSp]NSNextKeyViewYNSBGColorYNSDocViewYNScvFlagstru fX{86, 60}WCADView125\NSCustomViewJKLO":_NSWindowStyleMask_NSWindowBackingYNSMinSize]NSWindowTitle]NSWindowClass\NSWindowRect\NSScreenRectYNSMaxSize\NSWindowViewYNSWTFlags[NSViewClass<=;px>_{{161, 57}, {921, 567}}VWindowXNSWindow YNS.stringTView?125_NSMutableStringXNSString8H_A\QRSX\NSIsVerticalB}~8HC\Q]R!"#$%&'()*+,-./*01\NSCornerView_NSHeaderClipView[NSHScrollerXNSsFlags[NSVScroller]NSContentView\NSScrollAmtsDpEOLk"gqOA A AA83H*/-,+\QRS56768FGdc8:H6<]QR=>?!@ABTCi,DE**FGH+IJKXLMN[NSRowHeight\NSHeaderView^NSTableColumns_NSIntercellSpacingWidth_NSIntercellSpacingHeight[NSGridColor_NSOriginalClassNameYNSTvFlags"AJKR"@@"@_I@bH_LayerOutlineView]NSOutlineViewZ{159, 478}S]QR6T,,UV[NSTableViewMN\QRSXF7FYnoY{159, 17}12\]]5_NSTableHeaderViewQRS_`aPQ_{{-32, -34}, {16, 17}}12dee5]_NSCornerView8gHhSSjklmnopq6rstuXXvwx\NSHeaderCellZNSMinWidthWNSWidth\NSIdentifier^NSIsResizeable\NSIsEditableZNSDataCellZNSMaxWidthU"A"C JT\"Dz]YLayerNamedefhij{|}~YWV[XVLayerstuvxy"A0K0.33333299Z_headerTextColor12U5_NSTableHeaderCelldeghijk6n1@125]NSTableColumn125^NSMutableArrayWNSArraya`YgridColorD0.5125^NSClassSwapper_{{1, 17}, {159, 478}}e_controlBackgroundColor125ZNSClipViewQRS`XNSTargetYNSPercentXNSActionhj"?wni_{{-100, -100}, {15, 463}}\_doScroller:125ZNSScrollerQRS$`l"?h#m_{{1, -30}, {144, 15}}8HF_{{1, 0}, {159, 17}}Z{161, 496}125\NSScrollView\QRS#$%&0s|y2v8H8H_{{1, 1}, {710, 494}}QRS`΀wx_{{-30, 1}, {15, 479}}QRS$`ZNSCurValue"?z{_{{1, -30}, {695, 15}}_{{170, 0}, {712, 496}}_{{20, 71}, {882, 496}}12ڤ5[NSSplitView\QRS&V\NSBorderType_NSTitlePosition[NSTitleCellYNSOffsets]NSTransparentYNSBoxType8HV8HMY{881, 16}125_{{20, 48}, {881, 16}}V{0, 0}defhijnotuvxyM0 0.80000001125UNSBox_{{1, 9}, {921, 567}}_{{0, 0}, {1152, 746}}Z{300, 222}_{3.40282e+38, 3.40282e+38}125_NSWindowTemplateVwindowJKL6O"_layerOutlineViewJKLO"YsplitView8  V6_Mh12 58 "_V6V8 h6"M8 ^NSTableColumn1_NSTextField1111111]NSScrollView3\File's Owner_NSTextField1111118: 8$ N8& C"6FMBEV_DGAh8( )*+,-./0123456789:;<=54* )# 12MNN5^NSIBObjectData#,1:LQVdf&2>P^lz  "09BMRaj}.@LT^egijln(579;=BDI[lsz'35>CXZ\o|/>OQSpy{} &(*@MPegq|   ! # % > J L N P R T } , @ R \ j x    # * < E N U W t   " / 1 3 5 7 9 ; > @ B U ^ i   + F R h r w y { } '09Mbdmo (3>@EJLNSU_|~38AFT]ds{'2S\foqsxz ,7@IV*/13Kd}!#%&(14=BLU\t{9BGZart!468:<>@BDFUjx "$&(*,.02468:<>@BDFHJLNPRTVXZ\^`inO}PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/ImageDocument.nib/info.nib0000644000175000017500000000060011307666657024620 0ustar matteomatteo IBDocumentLocation 151 374 356 240 0 0 1152 746 IBFramework Version 349.0 IBSystem Version 7F44 PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/CocoaEntities.py0000644000175000017500000007363011307666657023023 0ustar matteomatteo# # Copyright (c) 2002-2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Handles creation of drawing entities (circles, lines, chamfers, etc) # # P.L.V. nov 23 05 # import adjustment import string from math import hypot, pi, atan2 import objc from PythonCAD.Interface.Cocoa import Globals import PythonCAD.Interface.Cocoa.ImageDocument import PythonCAD.Generic.tools import PythonCAD.Generic.util from Foundation import * from AppKit import NSShiftKeyMask # # Helper functions # def make_tuple(text): try: _tpl = eval(text) except: raise StandardError, "Invalid point: " + text if not isinstance(_tpl, tuple): raise TypeError, "Invalid point: " + str(_tpl) if len(_tpl) != 2: raise ValueError, "Invalid point: " + str(_tpl) return _tpl def make_radius(text): try: _textrad = eval(text) except: raise ValueError, "Invalid radius: " + text _rad = _textrad if not isinstance(_rad, float): _rad = float(_textrad) if _rad < 1e-10: raise ValueError, "Invalid radius: %g" % _rad return _rad def make_angle(text): try: _textangle = eval(text) except: raise StandardError, "Invalid angle: " + text return PythonCAD.Generic.util.make_c_angle(_textangle) def create_entity(doc, tool): _init_func = tool.getHandler("initialize") _image = doc.getImage() _image.startAction() try: tool.create(_image) finally: _image.endAction() _init_func(doc, tool) Globals.s = None Globals.l = None Globals.c = None Globals.t = None # # Points # def point_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter the point as 'x, y'") tool.setHandler("initialize", point_mode_init) tool.setHandler("left_button_press", point_left_button_press_cb) tool.setHandler("entry_event", point_entry_event_cb) def point_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) tool.setPoint(_viewLoc.x, _viewLoc.y) create_entity(doc, tool) def point_entry_event_cb(doc, text, tool): if len(text): _x, _y = make_tuple(text) tool.setPoint(_x, _y) create_entity(doc, tool) # # Segments # def segment_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter the first point as 'x, y'") tool.setHandler("initialize", segment_mode_init) tool.setHandler("left_button_press", segment_first_left_button_press_cb) tool.setHandler("entry_event", segment_first_entry_event_cb) _image = doc.getImage() Globals.s = _image.getOption('LINE_STYLE') Globals.l = _image.getOption('LINE_TYPE') Globals.c = _image.getOption('LINE_COLOR') Globals.t = _image.getOption('LINE_THICKNESS') def segment_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) tool.setFirstPoint(_viewLoc.x, _viewLoc.y) _da.setTempPoint(_viewLoc) tool.setHandler("left_button_press", segment_second_left_button_press_cb) tool.setHandler("mouse_move", segment_mouse_move_cb) doc.setPrompt("Click in the drawing area or enter the second point as 'x, y'") def segment_mouse_move_cb(doc, np, tool): _p1 = tool.getFirstPoint() _p2 = (np.x, np.y) _seg = PythonCAD.Generic.segment.Segment(_p1, _p2, Globals.s, Globals.l, Globals.c, Globals.t) _da = doc.getDA() _da.setTempObject(_seg) def segment_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _sp = _da.convertPoint_fromView_(_loc, None) tool.setSecondPoint(_sp.x, _sp.y) create_entity(doc, tool) def segment_first_entry_event_cb(doc, text, tool): if len(text): _x, _y = make_tuple(text) tool.setFirstPoint(_x, _y) doc.getDA().setTempPoint(NSMakePoint(_x, _y)) tool.setHandler("left_button_press", segment_second_left_button_press_cb) tool.setHandler("mouse_move", segment_mouse_move_cb) tool.setHandler("entry_event", segment_second_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the second point as 'x, y'") def segment_second_entry_event_cb(doc, text, tool): if len(text): _x, _y = make_tuple(text) tool.setSecondPoint(_x, _y) create_entity(doc, tool) # # rectangles # def rectangle_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter a point as 'x, y'") tool.setHandler("initialize", rectangle_mode_init) tool.setHandler("left_button_press", rectangle_first_left_button_press_cb) tool.setHandler("entry_event", rectangle_first_entry_event_cb) _image = doc.getImage() Globals.s = _image.getOption('LINE_STYLE') Globals.l = _image.getOption('LINE_TYPE') Globals.c = _image.getOption('LINE_COLOR') Globals.t = _image.getOption('LINE_THICKNESS') def rectangle_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) tool.setFirstPoint(_viewLoc.x, _viewLoc.y) _da.setTempPoint(_viewLoc) tool.setHandler("left_button_press", rectangle_second_left_button_press_cb) tool.setHandler("mouse_move", rectangle_mouse_move_cb) tool.setHandler("entry_event", rectangle_second_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the second point as 'x, y'") def rectangle_mouse_move_cb(doc, np, tool): _p1 = tool.getFirstPoint() _p2 = (_p1[0],np.y) _p3 = (np.x, np.y) _p4 = (np.x,_p1[1]) _da = doc.getDA() _s1 = PythonCAD.Generic.segment.Segment(_p1, _p2, Globals.s, Globals.l, Globals.c, Globals.t) _s2 = PythonCAD.Generic.segment.Segment(_p2, _p3, Globals.s, Globals.l, Globals.c, Globals.t) _s3 = PythonCAD.Generic.segment.Segment(_p3, _p4, Globals.s, Globals.l, Globals.c, Globals.t) _s4 = PythonCAD.Generic.segment.Segment(_p4, _p1, Globals.s, Globals.l, Globals.c, Globals.t) _da = doc.getDA() _da.setTempObject(_s1) _da.setTempObject(_s2, False) _da.setTempObject(_s3, False) _da.setTempObject(_s4, False) def rectangle_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _sp = _da.convertPoint_fromView_(_loc, None) tool.setSecondPoint(_sp.x, _sp.y) create_entity(doc, tool) def rectangle_first_entry_event_cb(doc, text, tool): if len(text): _x, _y = make_tuple(text) tool.setFirstPoint(_x, _y) tool.setHandler("left_button_press", rectangle_second_left_button_press_cb) tool.setHandler("mouse_move", rectangle_mouse_move_cb) tool.setHandler("entry_event", rectangle_second_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the second point as 'x, y'") doc.getDA().setTempPoint(NSMakePoint(_x, _y)) def rectangle_second_entry_event_cb(doc, text, tool): if len(text): _x, _y = make_tuple(text) tool.setSecondPoint(_x, _y) create_entity(doc, tool) # # Circles # # center point def circle_center_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter a point as 'x, y'") tool.setHandler("initialize", circle_center_mode_init) tool.setHandler("left_button_press", circle_center_first_left_button_press_cb) tool.setHandler("entry_event", circle_point_entry_event_cb) _image = doc.getImage() Globals.s = _image.getOption('LINE_STYLE') Globals.l = _image.getOption('LINE_TYPE') Globals.c = _image.getOption('LINE_COLOR') Globals.t = _image.getOption('LINE_THICKNESS') def circle_center_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) tool.setCenter(_viewLoc.x, _viewLoc.y) tool.setHandler("left_button_press", circle_center_second_left_button_press_cb) tool.setHandler("mouse_move", circle_center_mouse_move_cb) tool.setHandler("entry_event", circle_radius_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the radius") _da.setTempPoint(_viewLoc) def circle_center_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _sp = _da.convertPoint_fromView_(_loc, None) _cx, _cy = tool.getCenter() _radius = hypot((_cx - _sp.x), (_cy - _sp.y)) tool.setRadius(_radius) create_entity(doc, tool) def circle_center_mouse_move_cb(doc, np, tool): _p1 = tool.getCenter() _r = hypot((_p1[0] - np.x), (_p1[1] - np.y)) if _r > 0.0: _circle = PythonCAD.Generic.circle.Circle(_p1, _r, Globals.s, Globals.l, Globals.c, Globals.t) _da = doc.getDA() _da.setTempObject(_circle) def circle_point_entry_event_cb(doc, text, tool): if len(text): _x, _y = make_tuple(text) tool.setCenter(_x, _y) tool.setHandler("left_button_press", circle_center_second_left_button_press_cb) tool.setHandler("mouse_move", circle_center_mouse_move_cb) tool.setHandler("entry_event", circle_radius_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the radius") doc.getDA().setTempPoint(NSMakePoint(_x, _y)) def circle_radius_entry_event_cb(doc, text, tool): if len(text): _r = make_radius(text) tool.setRadius(_r) create_entity(doc, tool) # 2 point def circle_tp_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter a point as 'x, y'") tool.setHandler("initialize", circle_tp_mode_init) tool.setHandler("left_button_press", circle_tp_first_left_button_press_cb) tool.setHandler("entry_event", circle_tp_first_entry_event_cb) _image = doc.getImage() Globals.s = _image.getOption('LINE_STYLE') Globals.l = _image.getOption('LINE_TYPE') Globals.c = _image.getOption('LINE_COLOR') Globals.t = _image.getOption('LINE_THICKNESS') def circle_tp_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _da.setTempPoint(_viewLoc) tool.setFirstPoint(_viewLoc.x, _viewLoc.y) tool.setHandler("left_button_press", circle_tp_second_left_button_press_cb) tool.setHandler("mouse_move", circle_tp_mouse_move_cb) tool.setHandler("entry_event", circle_tp_second_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the second point as 'x, y'") def circle_tp_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _sp = _da.convertPoint_fromView_(_loc, None) tool.setSecondPoint(_sp.x, _sp.y) create_entity(doc, tool) def circle_tp_mouse_move_cb(doc, np, tool): _x, _y = tool.getFirstPoint() _fp = NSMakePoint(_x, _y) if NSEqualPoints(_fp, np): return tool.setSecondPoint(np.x, np.y) _cp = tool.getCenter() _r = tool.getRadius() if _r is not None and _r > 0: _circle = PythonCAD.Generic.circle.Circle(_cp, _r, Globals.s, Globals.l, Globals.c, Globals.t) _da = doc.getDA() _da.setTempObject(_circle) def circle_tp_first_entry_event_cb(doc, text, tool): if len(text): _x, _y = make_tuple(text) tool.setFirstPoint(_x, _y) tool.setHandler("left_button_press", circle_tp_second_left_button_press_cb) tool.setHandler("mouse_move", circle_tp_mouse_move_cb) tool.setHandler("entry_event", circle_tp_second_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the second point as 'x, y'") doc.getDA().setTempPoint(NSMakePoint(_x, _y)) def circle_tp_second_entry_event_cb(doc, text, tool): if len(text): _x, _y = make_tuple(text) tool.setSecondPoint(_x, _y) create_entity(doc, tool) # # Arcs # def arc_center_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter a point as 'x, y'") tool.setHandler("initialize", arc_center_mode_init) tool.setHandler("left_button_press", arc_center_first_left_button_press_cb) tool.setHandler("entry_event", arc_center_entry_event_cb) _image = doc.getImage() Globals.s = _image.getOption('LINE_STYLE') Globals.l = _image.getOption('LINE_TYPE') Globals.c = _image.getOption('LINE_COLOR') Globals.t = _image.getOption('LINE_THICKNESS') def arc_center_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _da.setTempPoint(_viewLoc) tool.setCenter(_viewLoc.x, _viewLoc.y) tool.setHandler("left_button_press", arc_center_second_left_button_press_cb) tool.setHandler("mouse_move", arc_radius_mouse_move_cb) tool.setHandler("entry_event", arc_radius_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the radius") def arc_center_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _sp = _da.convertPoint_fromView_(_loc, None) _cx, _cy = tool.getCenter() _radius = hypot((_sp.x - _cx), (_sp.y - _cy)) if _radius > 0.0: tool.setRadius(_radius) _angle = (180.0/pi) * atan2((_sp.y - _cy), (_sp.x - _cx)) if _angle < 0.0: _angle = _angle + 360.0 tool.setStartAngle(_angle) tool.delHandler("entry_event") tool.setHandler("left_button_press", arc_center_third_left_button_press_cb) tool.setHandler("mouse_move", arc_angle_mouse_move_cb) doc.setPrompt("Click in the drawing area to finish the arc") def arc_center_third_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _tp = _da.convertPoint_fromView_(_loc, None) _cx, _cy = tool.getCenter() _angle = (180.0/pi) * atan2((_tp.y - _cy), (_tp.x - _cx)) if _angle < 0.0: _angle = _angle + 360.0 tool.setEndAngle(_angle) create_entity(doc, tool) def arc_start_angle_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _pt, _flag = _image.findPoint(_x, _y, _tol) if _pt is not None: _x, _y = _pt.getCoords() _cx, _cy = tool.getCenter() _angle = (180.0/pi) * atan2((_y - _cy), (_x - _cx)) if _angle < 0.0: _angle = _angle + 360.0 tool.setStartAngle(_angle) tool.setHandler("mouse_move", arc_angle_mouse_move_cb) tool.setHandler("left_button_press", arc_center_third_left_button_press_cb) tool.setHandler("entry_event", arc_end_angle_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the end angle of the arc") def arc_radius_mouse_move_cb(doc, np, tool): _p1 = tool.getCenter() _p2 = (np.x, np.y) _seg = PythonCAD.Generic.segment.Segment(_p1, _p2, Globals.s, Globals.l, Globals.c, Globals.t) _da = doc.getDA() _da.setTempObject(_seg) def arc_angle_mouse_move_cb(doc, np, tool): _cp = tool.getCenter() _cx, _cy = _cp _r = tool.getRadius() _sa = tool.getStartAngle() _ea = (180.0/pi) * atan2((np.y - _cy), (np.x - _cx)) if _ea < 0.0: _ea = _ea + 360.0 _arc = PythonCAD.Generic.arc.Arc(_cp, _r, _sa, _ea, Globals.s, Globals.l, Globals.c, Globals.t) _da = doc.getDA() _da.setTempObject(_arc) def arc_center_entry_event_cb(doc, text, tool): if len(text): _x, _y = make_tuple(text) tool.setCenter(_x, _y) tool.setHandler("left_button_press", arc_center_second_left_button_press_cb) tool.setHandler("mouse_move", arc_radius_mouse_move_cb) tool.setHandler("entry_event", arc_radius_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the radius") doc.getDA().setTempPoint(NSMakePoint(_x, _y)) def arc_radius_entry_event_cb(doc, text, tool): if len(text): _r = make_radius(text) tool.setRadius(_r) tool.delHandler("mouse_move") tool.setHandler("left_button_press", arc_start_angle_left_button_press_cb) tool.setHandler("entry_event", arc_start_angle_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the start angle of the arc") def arc_start_angle_entry_event_cb(doc, text, tool): if len(text): _angle = make_angle(text) tool.setStartAngle(_angle) tool.setHandler("mouse_move", arc_angle_mouse_move_cb) tool.setHandler("left_button_press", arc_center_third_left_button_press_cb) tool.setHandler("entry_event", arc_end_angle_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the end angle of the arc") def arc_end_angle_entry_event_cb(doc, text, tool): if len(text): _angle = make_angle(text) tool.setEndAngle(_angle) create_entity(doc, tool) # # Chamfers # def chamfer_mode_init(doc, tool): doc.setPrompt("Click on the points where you want a chamfer") tool.setHandler("initialize", chamfer_mode_init) tool.setHandler("left_button_press", chamfer_left_button_press_cb) def chamfer_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _pt, _new_pt = _image.findPoint(_viewLoc.x, _viewLoc.y, _tol) if _pt is not None and not _new_pt: _active_layer = _image.getActiveLayer() _urefs = _pt.getUsers() if len(_urefs) != 2: return _s1 = _s2 = None for _uref in _urefs: _user = _uref() if _user is None: return if not isinstance(_user, PythonCAD.Generic.segment.Segment): return if _s1 is None: _s1 = _user else: _s2 = _user _len = _image.getOption('CHAMFER_LENGTH') Globals.s = _image.getOption('LINE_STYLE') Globals.l = _image.getOption('LINE_TYPE') Globals.c = _image.getOption('LINE_COLOR') Globals.t = _image.getOption('LINE_THICKNESS') # # the following is a work-around that needs to # eventually be replaced ... # _p1, _p2 = _s1.getEndpoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _slen = _s1.length() _factor = 2.0 _r = (_slen - (_len/_factor))/_slen _xn = _x1 + _r * (_x2 - _x1) _yn = _y1 + _r * (_y2 - _y1) _pc = _active_layer.find('point', _xn, _yn) while _pc is not None: _factor = _factor + 1.0 if _factor > 1000: break _r = (_slen - (_len/_factor))/_slen _xn = _x1 + _r * (_x2 - _x1) _yn = _y1 + _r * (_y2 - _y1) _pc = _active_layer.find('point', _xn, _yn) if _pc is None: _pc = PythonCAD.Generic.point.Point(_xn, _yn) _image.addObject(_pc) if _pt is _p1: _s1.setP1(_pc) else: _s1.setP2(_pc) _ptx, _pty = _pt.getCoords() _pc.setx(_ptx) _pc.sety(_pty) _chamfer = PythonCAD.Generic.segjoint.Chamfer(_s1, _s2, _len, Globals.s, Globals.l, Globals.c, Globals.t) _image.addObject(_chamfer) # force a redraw of the segments, too. # _msgr = doc.getMessenger() # _msgr.added_object_event(_image,_active_layer,_s1) # _msgr.added_object_event(_image,_active_layer,_s2) # we have to call another function to generate # an event to flush out the notification system # and draw what we just added. This one works # ok, I guess. create_entity(doc, tool) return # # Fillets # def fillet_mode_init(doc, tool): doc.setPrompt("Click on the points where you want a fillet") tool.setHandler("initialize", fillet_mode_init) tool.setHandler("left_button_press", fillet_left_button_press_cb) def fillet_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _pt, _new_pt = _image.findPoint(_viewLoc.x, _viewLoc.y, _tol) if _pt is not None and not _new_pt: _active_layer = _image.getActiveLayer() _urefs = _pt.getUsers() if len(_urefs) != 2: return _s1 = _s2 = None for _uref in _urefs: _user = _uref() if _user is None: return if not isinstance(_user, PythonCAD.Generic.segment.Segment): return if _s1 is None: _s1 = _user else: _s2 = _user _rad = _image.getOption('FILLET_RADIUS') Globals.s = _image.getOption('LINE_STYLE') Globals.l = _image.getOption('LINE_TYPE') Globals.c = _image.getOption('LINE_COLOR') Globals.t = _image.getOption('LINE_THICKNESS') # # the following is a work-around that needs to # eventually be replaced ... # _p1, _p2 = _s1.getEndpoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _slen = _s1.length() _factor = 2.0 _r = 1.0 - (_slen/_factor) _xn = _x1 + _r * (_x2 - _x1) _yn = _y1 + _r * (_y2 - _y1) _pc = _active_layer.find('point', _xn, _yn) while _pc is not None: _factor = _factor + 1.0 if _factor > 1000: break _r = 1.0 - (_slen/_factor) _xn = _x1 + _r * (_x2 - _x1) _yn = _y1 + _r * (_y2 - _y1) _pc = _active_layer.find('point', _xn, _yn) if _pc is None: _pc = PythonCAD.Generic.point.Point(_xn, _yn) _image.addObject(_pc) if _pt is _p1: _s1.setP1(_pc) else: _s1.setP2(_pc) _ptx, _pty = _pt.getCoords() _pc.setx(_ptx) _pc.sety(_pty) _fillet = PythonCAD.Generic.segjoint.Fillet(_s1, _s2, _rad, Globals.s, Globals.l, Globals.c, Globals.t) _image.addObject(_fillet) # we have to call another function to generate # an event to flush out the notification system # and draw what we just added. This one works # ok, I guess. create_entity(doc, tool) return # # Leaders # def leader_mode_init(doc, tool): doc.setPrompt("Click in the drawing area to enter the first point") tool.setHandler("initialize", leader_mode_init) tool.setHandler("left_button_press", leader_first_left_button_press_cb) _image = doc.getImage() Globals.s = _image.getOption('LINE_STYLE') Globals.l = _image.getOption('LINE_TYPE') Globals.c = _image.getOption('LINE_COLOR') Globals.t = _image.getOption('LINE_THICKNESS') def leader_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _da.setTempPoint(_viewLoc) tool.setFirstPoint(_viewLoc.x, _viewLoc.y) tool.setHandler("mouse_move", leader_mouse_move_cb) tool.setHandler("left_button_press", leader_second_left_button_press_cb) doc.setPrompt("Click in the drawing area to place the second point") def leader_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _da.setTempPoint(_viewLoc) tool.setMidPoint(_viewLoc.x, _viewLoc.y) tool.setHandler("mouse_move", leader_mouse_move_cb) tool.setHandler("left_button_press", leader_third_left_button_press_cb) doc.setPrompt("Click in the drawing area to place the final point") def leader_third_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) tool.setFinalPoint(_viewLoc.x, _viewLoc.y) create_entity(doc, tool) def leader_mouse_move_cb(doc, np, tool): _x1, _y1 = tool.getFirstPoint() _da = doc.getDA() _p2 = tool.getMidPoint() _flag = True if _p2 is not None: _s1 = PythonCAD.Generic.segment.Segment((_x1, _y1), _p2, Globals.s, Globals.l, Globals.c, Globals.t) _da.setTempObject(_s1, _flag) _flag = False (_x1, _y1) = _p2 (_x2, _y2) = np _s1 = PythonCAD.Generic.segment.Segment((_x1, _y1), (_x2, _y2), Globals.s, Globals.l, Globals.c, Globals.t) _da.setTempObject(_s1, _flag) # # Polyline # def polyline_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter the first point as 'x, y'") tool.setHandler("initialize", polyline_mode_init) tool.setHandler("left_button_press", polyline_left_button_press_cb) tool.setHandler("entry_event", polyline_entry_event_cb) _image = doc.getImage() Globals.s = _image.getOption('LINE_STYLE') Globals.l = _image.getOption('LINE_TYPE') Globals.c = _image.getOption('LINE_COLOR') Globals.t = _image.getOption('LINE_THICKNESS') def polyline_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _da.setTempPoint(_viewLoc) tool.storePoint(_viewLoc.x, _viewLoc.y) if ((event.modifierFlags() & NSShiftKeyMask) != 0): create_entity(doc, tool) else: tool.setHandler("mouse_move", polyline_mouse_move_cb) doc.setPrompt("Click or enter as 'x, y' the next point. Shift-click or type 'last' to finish") def polyline_mouse_move_cb(doc, np, tool): _pts = tool.getPoints() (_x1, _y1) = _pts[0] _count = len(_pts) _da = doc.getDA() _flag = True for _i in range(1, _count): (_x2, _y2) = _pts[_i] _s1 = PythonCAD.Generic.segment.Segment((_x1, _y1), (_x2, _y2), Globals.s, Globals.l, Globals.c, Globals.t) _da.setTempObject(_s1, _flag) _flag = False _x1 = _x2 _y1 = _y2 (_x2, _y2) = np _s1 = PythonCAD.Generic.segment.Segment((_x1, _y1), (_x2, _y2), Globals.s, Globals.l, Globals.c, Globals.t) _da.setTempObject(_s1, _flag) def polyline_entry_event_cb(doc, text, tool): if len(text): if text == 'done': create_entity(doc, tool) else: _x, _y = make_tuple(text) tool.storePoint(_x, _y) tool.setHandler("mouse_move", polyline_mouse_move_cb) doc.setPrompt("Click or enter as 'x, y' the next point. Shift-click or type 'done' to finish") doc.getDA().setTempPoint(NSMakePoint(_x, _y)) # # Polygon & External Polygon # def polygon_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter a point as 'x, y'") tool.setHandler("initialize", polygon_mode_init) tool.setHandler("left_button_press", polygon_first_left_button_press_cb) tool.setHandler("entry_event", polygon_point_entry_event_cb) _image = doc.getImage() Globals.s = _image.getOption('LINE_STYLE') Globals.l = _image.getOption('LINE_TYPE') Globals.c = _image.getOption('LINE_COLOR') Globals.t = _image.getOption('LINE_THICKNESS') def polygon_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) tool.setCenter(_viewLoc.x, _viewLoc.y) tool.setHandler("left_button_press", polygon_second_left_button_press_cb) tool.setHandler("mouse_move", polygon_mouse_move_cb) tool.setHandler("entry_event", polygon_radius_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the apparent radius") _da.setTempPoint(_viewLoc) def polygon_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) (_cx, _cy) = tool.getCenter() if (_cx != _x) or (_cy != _y): tool.setLocation(_x, _y) create_entity(doc, tool) def polygon_mouse_move_cb(doc, np, tool): _segs = [] (_x, _y) = np tool.setLocation(_x, _y) _count = tool.getSideCount() _flag = True _da = doc.getDA() (_x0, _y0) = (_x1, _y1) = tool.getCoord(0) for _i in range(1, _count): (_x2, _y2) = tool.getCoord(_i) _s1 = PythonCAD.Generic.segment.Segment((_x1, _y1), (_x2, _y2), Globals.s, Globals.l, Globals.c, Globals.t) _da.setTempObject(_s1, _flag) _x1 = _x2 _y1 = _y2 _flag = False _s1 = PythonCAD.Generic.segment.Segment((_x0, _y0), (_x1, _y1), Globals.s, Globals.l, Globals.c, Globals.t) _da.setTempObject(_s1, False) def polygon_point_entry_event_cb(doc, text, tool): if len(text): _x, _y = make_tuple(text) tool.setCenter(_x, _y) tool.setHandler("left_button_press", polygon_second_left_button_press_cb) tool.setHandler("mouse_move", polygon_mouse_move_cb) tool.delHandler("entry_event") doc.setPrompt("Click in the drawing area to complete the polygon") doc.getDA().setTempPoint(NSMakePoint(_x, _y)) def polygon_radius_entry_event_cb(doc, text, tool): if len(text): _r = make_radius(text) (_cx, _cy) = tool.getCenter() tool.setLocation(_cx+_r, _cy) create_entity(doc, tool) PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/AppController.py0000644000175000017500000004572611307666657023063 0ustar matteomatteo# # Copyright (c) 2002-2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Application Controller Object (& app delegate) # # P.L.V. nov 23 05 # import adjustment from math import hypot, pi, atan2 import objc import PythonCAD.Generic.tools import PythonCAD.Interface.Cocoa.CocoaConobjs import PythonCAD.Interface.Cocoa.CocoaEntities import PythonCAD.Interface.Cocoa.CocoaModify import PythonCAD.Interface.Cocoa.CocoaText import PythonCAD.Interface.Cocoa.CocoaDimensions from PyObjCTools import NibClassBuilder from Foundation import * from AppKit import NSDocumentController, NSSavePanel, NSOKButton, NSCancelButton, NSPanel, NSWindowController, NSApplication, NSTextView # # Define True & False if this is Python < 2.2.1 # try: True, False except NameError: True, False = 1, 0 ZOOM = 2.0 NibClassBuilder.extractClasses("MainMenu") class AppController(NibClassBuilder.AutoBaseClass): """ PythonCad application menu controller Passes menu commands to the appropriate handlers """ # # File menu # def saveLayerAs_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return # this is odd _sp = NSSavePanel.savePanel() _sp.setTitle_("Save Layer") _sp.setRequiredFileType_("xml.gz") _layer = _doc.getImage().getActiveLayer() _win = _doc.windowForSheet() _name = _layer.getName() _sp.beginSheetForDirectory_file_modalForWindow_modalDelegate_didEndSelector_contextInfo_(None, _name, _win, self, "savePanelDidEnd:returnCode:contextInfo:", 0) def savePanelDidEnd_returnCode_contextInfo_(self, sp, code, info): if NSOKButton == code: print "wahoo, we're saving the layer!" elif NSCancelButton == code: print "funk that - don't save the layer" savePanelDidEnd_returnCode_contextInfo_ = objc.selector(savePanelDidEnd_returnCode_contextInfo_, signature="v@:@ii") # # Edit menu commands # def undo_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _doc.getImage().undo() _doc.getDA().setNeedsDisplay_(True) def redo_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _doc.getImage().redo() _doc.getDA().setNeedsDisplay_(True) # # Draw Basic Menu commands # def drawPoint_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.PointTool() _doc.setTool(_tool) CocoaEntities.point_mode_init(_doc, _tool) def drawRect_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.RectangleTool() _doc.setTool(_tool) CocoaEntities.rectangle_mode_init(_doc, _tool) def drawSegment_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.SegmentTool() _doc.setTool(_tool) CocoaEntities.segment_mode_init(_doc, _tool) def drawCircleCentered_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.CircleTool() _doc.setTool(_tool) CocoaEntities.circle_center_mode_init(_doc, _tool) def drawCircle2Point_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.TwoPointCircleTool() _doc.setTool(_tool) CocoaEntities.circle_tp_mode_init(_doc, _tool) def drawArc_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.ArcTool() _doc.setTool(_tool) CocoaEntities.arc_center_mode_init(_doc, _tool) # # Draw Construction Line commands # def drawHCLine_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.HCLineTool() _doc.setTool(_tool) CocoaConobjs.hcline_mode_init(_doc, _tool) def drawVCLine_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.VCLineTool() _doc.setTool(_tool) CocoaConobjs.vcline_mode_init(_doc, _tool) def drawACLine_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.ACLineTool() _doc.setTool(_tool) CocoaConobjs.acline_mode_init(_doc, _tool) def drawParallelCLine_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.ParallelOffsetTool() _doc.setTool(_tool) CocoaConobjs.cline_par_mode_init(_doc, _tool) def drawPerpendicularCLine_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.Tool() _doc.setTool(_tool) CocoaConobjs.cline_perp_mode_init(_doc, _tool) def drawTanCLine_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.Tool() _doc.setTool(_tool) CocoaConobjs.cline_tan_mode_init(_doc, _tool) def drawTan2CircleCLine_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.CCircleTangentLineTool() _doc.setTool(_tool) CocoaConobjs.cline_tan_2circ_mode_init(_doc, _tool) def draw2PointCLine_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.CLineTool() _doc.setTool(_tool) CocoaConobjs.cline_tp_mode_init(_doc, _tool) # # Draw construction circle commands # def drawCCircleCenter_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.CCircleTool() _doc.setTool(_tool) CocoaConobjs.ccircle_center_mode_init(_doc, _tool) def drawCCircle2Point_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.TwoPointCCircleTool() _doc.setTool(_tool) CocoaConobjs.ccircle_tp_mode_init(_doc, _tool) def drawCCircle1Tan_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.TangentCCircleTool() _doc.setTool(_tool) CocoaConobjs.ccircle_tan1_mode_init(_doc, _tool) def drawCCircle2Tan_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.TwoPointTangentCCircleTool() _doc.setTool(_tool) CocoaConobjs.ccircle_tan2_mode_init(_doc, _tool) # # Draw more complicated things commands # def drawChamfer_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.Tool() _doc.setTool(_tool) CocoaEntities.chamfer_mode_init(_doc, _tool) def drawFillet_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.Tool() _doc.setTool(_tool) CocoaEntities.fillet_mode_init(_doc, _tool) def drawLeader_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.LeaderTool() _doc.setTool(_tool) CocoaEntities.leader_mode_init(_doc, _tool) def drawPolyline_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.PolylineTool() _doc.setTool(_tool) CocoaEntities.polyline_mode_init(_doc, _tool) def drawPolygon_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.PolygonTool() _doc.setTool(_tool) self.openPolygonPanel() CocoaEntities.polygon_mode_init(_doc, _tool) def drawPolygonExternal_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.PolygonTool() _tool.setExternal() _doc.setTool(_tool) self.openPolygonPanel() CocoaEntities.polygon_mode_init(_doc, _tool) def drawText_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _win = _doc.windowForSheet() _app = NSApplication.sharedApplication() _app.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_(self.textSheet, _win, None, None, 0) _tool = tools.TextTool() _doc.setTool(_tool) _textview = self.textSheet.initialFirstResponder() if isinstance(_textview, NSTextView): CocoaText.textview_format_setup(_doc, _textview) def drawTextSheetOK_(self, sender): _win = sender.window() _app = NSApplication.sharedApplication() _app.endSheet_(_win) _win.orderOut_(_win) _textview = _win.initialFirstResponder() if not isinstance(_textview, NSTextView): return _text = _textview.string() if not len(_text) > 0: return _doc = self.getCurrentDocument() _tool = _doc.getTool() if not isinstance(_tool, tools.TextTool): return _tool.setText(_text) CocoaText.text_entered(_doc, _tool, _textview) def drawTextSheetCancel_(self, sender): _win = sender.window() _app = NSApplication.sharedApplication() _app.endSheet_(_win) _win.orderOut_(_win) _textview = _win.initialFirstResponder() if not isinstance(_textview, NSTextView): return _textview.setString_("") # # Format menu # # # Modify menu # def modifyMoveHorizontal_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.HorizontalMoveTool() _doc.setTool(_tool) CocoaModify.move_horizontal_init(_doc, _tool) def modifyMoveVertical_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.VerticalMoveTool() _doc.setTool(_tool) CocoaModify.move_vertical_init(_doc, _tool) def modifyMoveFree_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.MoveTool() _doc.setTool(_tool) CocoaModify.move_free_init(_doc, _tool) def modifyStretchHorizontal_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.HorizontalStretchTool() _doc.setTool(_tool) CocoaModify.stretch_horizontal_init(_doc, _tool) def modifyStretchVertical_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.VerticalStretchTool() _doc.setTool(_tool) CocoaModify.stretch_vertical_init(_doc, _tool) def modifyStretchFree_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.StretchTool() _doc.setTool(_tool) CocoaModify.stretch_free_init(_doc, _tool) def modifySplit_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.SplitTool() _doc.setTool(_tool) CocoaModify.split_init(_doc, _tool) def modifyMirror_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.MirrorTool() _doc.setTool(_tool) CocoaModify.mirror_init(_doc, _tool) def modifyTransfer_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.Tool() _doc.setTool(_tool) CocoaModify.transfer_init(_doc, _tool) # # Dimensions menu # def dimensionLinear_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.LinearDimensionTool() _doc.setTool(_tool) CocoaDimensions.ldim_mode_init(_doc, _tool) def dimensionHorizontal_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.HorizontalDimensionTool() _doc.setTool(_tool) CocoaDimensions.ldim_mode_init(_doc, _tool) def dimensionVertical_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.VerticalDimensionTool() _doc.setTool(_tool) CocoaDimensions.ldim_mode_init(_doc, _tool) def dimensionRadial_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.RadialDimensionTool() _doc.setTool(_tool) CocoaDimensions.radial_mode_init(_doc, _tool) def dimensionAngular_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.AngularDimensionTool() _doc.setTool(_tool) CocoaDimensions.angular_mode_init(_doc, _tool) # # Window menu # def windowZoom_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _tool = tools.RectangleTool() _doc.setTool(_tool) CocoaModify.zoom_mode_init(_doc, _tool) def windowZoomIn_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _da = _doc.getDA() _visRect = _da.visibleRect() _xinset = NSWidth(_visRect) / (ZOOM*2) _yinset = NSHeight(_visRect) / (ZOOM*2) _zoomRect = NSInsetRect(_visRect, _xinset, _yinset) _da.zoomToRect(_zoomRect) def windowZoomOut_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _da = _doc.getDA() _visRect = _da.visibleRect() _xinset = NSWidth(_visRect) / ZOOM _yinset = NSHeight(_visRect) / ZOOM _zoomRect = NSInsetRect(_visRect, -_xinset, -_yinset) _da.zoomToRect(_zoomRect) def windowZoomFit_(self, sender): _doc = self.getCurrentDocument() if _doc is None: return _da = _doc.getDA() _da.fitImage() # # etc # __polyPanelWindowController = None def openPolygonPanel(self): if self.__polyPanelWindowController is None: _wc = NSWindowController.alloc().initWithWindow_(self.polygonPanel) self.__polyPanelWindowController = _wc self.__polyPanelWindowController.showWindow_(self) def windowDidResignKey_(self, note): _win = note.object() if _win is self.polygonPanel: _doc = self.getCurrentDocument() if _doc is None: return _tool = _doc.getTool() if isinstance(_tool, tools.PolygonTool): _textField = _win.initialFirstResponder() _int = _textField.intValue() _tool.setSideCount(_int) def getCurrentDocument(self): _dc = NSDocumentController.sharedDocumentController() _doc = _dc.currentDocument() return _doc def validateMenuItem_(self, menuItem): _doc = self.getCurrentDocument() if _doc is None: return False _action = menuItem.action() _image = _doc.getImage() _layer = _image.getActiveLayer() # # checks # if (_action == "undo:"): return _image.canUndo() elif (_action == "redo:"): return _image.canRedo() elif ((_action == "drawParallelCLine:") or (_action == "modifyMirror:")): _objs = _layer.getChildren() for _obj in _objs: if isinstance(_obj, (Generic.hcline.HCLine, Generic.vcline.VCLine, Generic.acline.ACLine, Generic.cline.CLine)): return True return False elif (_action == "drawPerpendicularCLine:"): return _layer.hasChildren() elif (_action == "drawTanCLine:"): _circles = (_layer.getLayerEntities("circle") + _layer.getLayerEntities("ccircle") + _layer.getLayerEntities("arc")) if len(_circles) == 0: return False else: return True elif (_action == "drawTan2CircleCLine:"): _circles = _layer.getLayerEntities("ccircle") if len(_circles) < 2: return False return True elif (_action == "drawCCircle1Tan:"): _objs = _layer.getChildren() for _obj in _objs: if isinstance(_obj, Generic.conobject.ConstructionObject): return True return False elif (_action == "drawCCircle2Tan:"): _ccircles = len(_layer.getLayerEntities("ccircle")) _cobjs = len(_layer.getLayerEntities("hcline") + _layer.getLayerEntities("vcline") + _layer.getLayerEntities("acline") + _layer.getLayerEntities("cline")) if _cobjs == 0: return False elif (_ccircles + _cobjs) < 2: return False return True elif (_action == "modifyTransfer:"): _top = _image.getTopLayer() if len(_top.getSublayers()): return True return False elif (_action == "modifySplit:"): _objs = _layer.getChildren() for _obj in _objs: if isinstance(_obj, (Generic.segment.Segment, Generic.arc.Arc, Generic.circle.Circle, Generic.polyline.Polyline)): return True return False return True PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/CocoaConobjs.py0000644000175000017500000006153511307666657022635 0ustar matteomatteo# # Copyright (c) 2002-2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Handles creation of construction lines, circles, etc # # P.L.V. nov 23 05 # import adjustment from math import hypot, pi, atan2 from Foundation import * import PythonCAD.Interface.Cocoa.CocoaEntities import PythonCAD.Generic.cline import PythonCAD.Generic.acline import PythonCAD.Generic.conobject # # Horizontal/Vertical lines - could really be combined # def hcline_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter the first point as 'x, y'") tool.setHandler("initialize", hcline_mode_init) tool.setHandler("left_button_press", hcline_left_button_press_cb) tool.setHandler("entry_event", hcline_entry_event_cb) def hcline_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) tool.setPoint(_viewLoc.x, _viewLoc.y) CocoaEntities.create_entity(doc, tool) def hcline_entry_event_cb(doc, text, tool): if len(text): _x, _y = CocoaEntities.make_tuple(text) tool.setPoint(_x, _y) CocoaEntities.create_entity(doc, tool) def vcline_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter the first point as 'x, y'") tool.setHandler("initialize", vcline_mode_init) tool.setHandler("left_button_press", vcline_left_button_press_cb) tool.setHandler("entry_event", vcline_entry_event_cb) def vcline_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) tool.setPoint(_viewLoc.x, _viewLoc.y) CocoaEntities.create_entity(doc, tool) def vcline_entry_event_cb(doc, text, tool): if len(text): _x, _y = CocoaEntities.make_tuple(text) tool.setPoint(_x, _y) CocoaEntities.create_entity(doc, tool) # # Angled Construction line # def acline_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter the first point as 'x, y'") tool.setHandler("initialize", acline_mode_init) tool.setHandler("left_button_press", acline_first_left_button_press_cb) tool.setHandler("entry_event", acline_first_entry_event_cb) def acline_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _da.setTempPoint(_viewLoc) tool.setPoint(_viewLoc.x, _viewLoc.y) tool.setHandler("mouse_move", acline_mouse_move_cb) tool.setHandler("left_button_press", acline_second_left_button_press_cb) tool.setHandler("entry_event", acline_second_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the angle") def acline_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _sp = _da.convertPoint_fromView_(_loc, None) tool.setLocation(_sp.x, _sp.y) CocoaEntities.create_entity(doc, tool) def acline_mouse_move_cb(doc, np, tool): tool.setLocation(np.x, np.y) _p1 = tool.getPoint() _p2 = (np.x, np.y) _s = PythonCAD.Generic.conobject.ConstructionObject._ConstructionObject__defstyle _seg = PythonCAD.Generic.segment.Segment(_p1, _p2, _s) _da = doc.getDA() _da.setTempObject(_seg) def acline_first_entry_event_cb(doc, text, tool): if len(text): _x, _y = CocoaEntities.make_tuple(text) tool.setPoint(_x, _y) tool.setHandler("mouse_move", acline_mouse_move_cb) tool.setHandler("left_button_press", acline_second_left_button_press_cb) tool.setHandler("entry_event", acline_second_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the angle") doc.getDA().setTempPoint(NSMakePoint(_x, _y)) def acline_second_entry_event_cb(doc, text, tool): if len(text): _angle = CocoaEntities.make_angle(text) tool.setAngle(_angle) CocoaEntities.create_entity(doc, tool) # # two-point construction line # def cline_tp_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter the first point as 'x, y'") tool.setHandler("initialize", cline_tp_mode_init) tool.setHandler("left_button_press", cline_tp_first_left_button_press_cb) tool.setHandler("entry_event", cline_tp_first_entry_event_cb) def cline_tp_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _da.setTempPoint(_viewLoc) tool.setFirstPoint(_viewLoc.x, _viewLoc.y) tool.setHandler("mouse_move", cline_tp_mouse_move_cb) tool.setHandler("left_button_press", cline_tp_second_left_button_press_cb) tool.setHandler("entry_event", cline_tp_second_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the second point as 'x, y'") def cline_tp_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _sp = _da.convertPoint_fromView_(_loc, None) tool.setSecondPoint(_sp.x, _sp.y) CocoaEntities.create_entity(doc, tool) def cline_tp_mouse_move_cb(doc, np, tool): _p1 = tool.getFirstPoint() _p2 = (np.x, np.y) _s = PythonCAD.Generic.conobject.ConstructionObject._ConstructionObject__defstyle _seg = PythonCAD.Generic.segment.Segment(_p1, _p2, _s) _da = doc.getDA() _da.setTempObject(_seg) def cline_tp_first_entry_event_cb(doc, text, tool): if len(text): _x, _y = CocoaEntities.make_tuple(text) tool.setFirstPoint(_x, _y) tool.setHandler("mouse_move", cline_tp_mouse_move_cb) tool.setHandler("left_button_press", cline_tp_second_left_button_press_cb) tool.setHandler("entry_event", cline_tp_second_entry_event_cb) doc.setPrompt("Click in the drawing area or enter the second point as 'x, y'") doc.getDA().setTempPoint(NSMakePoint(_x, _y)) def cline_tp_second_entry_event_cb(doc, text, tool): if len(text): _x, _y = CocoaEntities.make_tuple(text) tool.setSecondPoint(_x, _y) CocoaEntities.create_entity(doc, tool) # # Parallel Construction Line # def cline_par_mode_init(doc, tool): doc.setPrompt("Click on the reference construction line") tool.setHandler("initialize", cline_par_mode_init) tool.setHandler("left_button_press", cline_par_first_left_button_press_cb) def cline_par_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _objdict = _image.mapPoint(_viewLoc.x, _viewLoc.y, _tol, 1) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: _objs = [] for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, (PythonCAD.Generic.hcline.HCLine, PythonCAD.Generic.vcline.VCLine, PythonCAD.Generic.acline.ACLine, PythonCAD.Generic.cline.CLine)): tool.setLocation(_viewLoc.x, _viewLoc.y) tool.setConstructionLine(_obj) tool.setHandler("left_button_press", cline_par_second_left_button_press_cb) tool.delHandler("entry_event") doc.setPrompt("Click in the drawing area to place the new construction line") def cline_par_second_left_button_press_cb(doc, event, tool): _x1, _y1 = tool.getLocation() _loc = event.locationInWindow() _da = doc.getDA() _sp = _da.convertPoint_fromView_(_loc, None) _x2, _y2 = _sp _offset = hypot((_x2 - _x1), (_y2 - _y1)) tool.setOffset(_offset) tool.setReferencePoint(_sp.x, _sp.y) CocoaEntities.create_entity(doc, tool) # # Perpendicular to object construction line # def cline_perp_mode_init(doc, tool): doc.setPrompt("Click on the object to which you want a perpendicular") tool.setHandler("initialize", cline_perp_mode_init) tool.setHandler("left_button_press", cline_perp_left_button_press_cb) def cline_perp_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _layer = _image.getActiveLayer() _hits = _layer.mapPoint((_viewLoc.x, _viewLoc.y), _tol, 1) if len(_hits): _obj, _pt = _hits[0] _lp = _layer.findObject(_pt) if _lp is None: _lp = _pt _image.addObject(_lp) if isinstance(_obj, PythonCAD.Generic.segment.Segment): _p1, _p2 = _obj.getEndpoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() if abs(_p1x - _p2x) < 1e-10: # vertical _image.addObject(PythonCAD.Generic.hcline.HCLine(_lp)) elif abs(_p1y - _p2y) < 1e-10: # horizontal _image.addObject(PythonCAD.Generic.vcline.VCLine(_lp)) else: _slope = (180.0/pi) * atan2((_p2y - _p1y), (_p2x - _p1x)) + 90.0 _image.addObject(PythonCAD.Generic.acline.ACLine(_lp, _slope)) elif isinstance(_obj, PythonCAD.Generic.circle.Circle): _cp = _obj.getCenter() _image.addObject(PythonCAD.Generic.cline.CLine(_cp, _lp)) elif isinstance(_obj, PythonCAD.Generic.hcline.HCLine): _image.addObject(PythonCAD.Generic.vcline.VCLine(_lp)) elif isinstance(_obj, PythonCAD.Generic.vcline.VCLine): _image.addObject(PythonCAD.Generic.hcline.HCLine(_lp)) elif isinstance(_obj, PythonCAD.Generic.acline.ACLine): _angle = _obj.getAngle() if abs(_angle) < 1e-10: # horizontal _image.addObject(PythonCAD.Generic.vcline.VCLine(_lp)) elif abs(abs(_angle) - 90.0) < 1e-10: # vertical _image.addObject(PythonCAD.Generic.hcline.HCLine(_lp)) else: _slope = _angle + 90.0 _image.addObject(PythonCAD.Generic.acline.ACLine(_lp, _slope)) elif isinstance(_obj, PythonCAD.Generic.cline.CLine): _p1, _p2 = _obj.getKeypoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() if abs(_p1x - _p2x) < 1e-10: # vertical _image.addObject(PythonCAD.Generic.hcline.HCLine(_lp)) elif abs(_p1y - _p2y) < 1e-10: # horizontal _image.addObject(PythonCAD.Generic.vcline.VCLine(_lp)) else: _slope = (180.0/pi) * atan2((_p2y - _p1y), (_p2x - _p1x)) + 90.0 _image.addObject(PythonCAD.Generic.acline.ACLine(_lp, _slope)) else: _image.delObject(_lp) return # we have to call another function to generate # an event to flush out the notification system # and draw what we just added. This one works # ok, I guess. CocoaEntities.create_entity(doc, tool) # # tangent to a circle construction line # def cline_tan_mode_init(doc, tool): doc.setPrompt("Click on the circle to which you want a tangent") tool.setHandler("initialize", cline_tan_mode_init) tool.setHandler("left_button_press", cline_tan_left_button_press_cb) def cline_tan_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _pt, _new_pt = _image.findPoint(_viewLoc.x, _viewLoc.y, _tol) if _pt is not None: _x, _y = _pt.getCoords() _layer = _image.getActiveLayer() _rtd = 180.0/pi # I think this is just supposed to be active layer _cobj = None _angle = None _circles = (_layer.getLayerEntities("circle") + _layer.getLayerEntities("ccircle")) for _circle in _circles: _cx, _cy = _circle.getCenter().getCoords() _rad = _circle.getRadius() if hypot((_x - _cx), (_y - _cy)) - _rad < 1e-10: _cobj = _circle _angle = _rtd * atan2((_y - _cy), (_x - _cx)) if _angle < 0.0: _angle = _angle + 360.0 break if _cobj is None: for _arc in _layer.getLayerEntities("arc"): _cx, _cy = _arc.getCenter().getCoords() _rad = _arc.getRadius() if hypot((_cx - _x), (_cy - _y)) - _rad < 1e-10: _angle = _rtd * atan2((_y - _cy), (_x - _cx)) if _angle < 0.0: _angle = _angle + 360.0 if _arc.throughAngle(_angle): _cobj = _arc break if _cobj is not None: if _new_pt: _image.addObject(_pt) if (abs(_angle) < 1e-6 or abs(_angle - 180.0) < 1e-6 or abs(_angle - 360.0) < 1e-6): _tcl = PythonCAD.Generic.vcline.VCLine(_pt) elif (abs(_angle - 90.0) < 1e-6 or abs(_angle - 270.0) < 1e-6): _tcl = PythonCAD.Generic.hcline.HCLine(_pt) else: _slope = _angle + 90.0 _tcl = PythonCAD.Generic.acline.ACLine(_pt, _slope) _image.addObject(_tcl) # we have to call another function to generate # an event to flush out the notification system # and draw what we just added. This one works # ok, I guess. CocoaEntities.create_entity(doc, tool) return # # tangent to two circle construction line # def cline_tan_2circ_mode_init(doc, tool): doc.setPrompt("Click on the first construction circle") tool.setHandler("initialize", cline_tan_2circ_mode_init) tool.setHandler("left_button_press", cline_tan_2circ_first_left_button_press_cb) def cline_tan_2circ_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _objdict = _image.mapPoint(_viewLoc.x, _viewLoc.y, _tol, 1) if len(_objdict): _layer = _image.getActiveLayer() if _layer in _objdict: _objs = [] for _obj, _pt in _objdict[_layer]: if isinstance(_obj, PythonCAD.Generic.ccircle.CCircle): tool.setFirstCCircle(_obj) tool.setHandler("left_button_press", cline_tan_2circ_second_left_button_press_cb) doc.setPrompt("Click on the second construction circle") def cline_tan_2circ_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _objdict = _image.mapPoint(_viewLoc.x, _viewLoc.y, _tol, 1) if len(_objdict): _layer = _image.getActiveLayer() if _layer in _objdict: _objs = [] for _obj, _pt in _objdict[_layer]: if isinstance(_obj, PythonCAD.Generic.ccircle.CCircle): _fc = tool.getFirstCCircle() if _obj is _fc: return tool.setSecondCCircle(_obj) if tool.hasTangentPoints(): _draw_two_circle_tangents(doc, tool) tool.setHandler("mouse_move", cline_tan_2circ_mouse_move_cb) tool.setHandler("left_button_press", cline_tan_2circ_third_left_button_press_cb) doc.setPrompt("Click on the segment to keep") else: tool.reset() cline_tan_2circ_mode_init(doc, tool) def _draw_two_circle_tangents(doc, tool): _tanpts = tool.getTangentPoints() assert len(_tanpts), "No tangent points defined!" _da = doc.getDA() _da.setTempObject() #clear it out # # Make an interesting line style - should be defined globally? # _styles = PythonCAD.Generic.globals.prefs['STYLES'] _s = None for _style in _styles: if _style.getName() == "Dashed Yellow Line": _s = _style break if _s is None: raise TypeError, "Style not found for dashed lines." for _set in _tanpts: _x1, _y1, _x2, _y2 = _set _p1 = (_x1, _y1) _p2 = (_x2, _y2) _seg = PythonCAD.Generic.segment.Segment(_p1, _p2, _s) _da.setTempObject(_seg, False) # dummy function just for update - needs to only be called once def cline_tan_2circ_mouse_move_cb(doc, np, tool): tool.delHandler("mouse_move") def cline_tan_2circ_third_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) tool.setLocation(_viewLoc.x, _viewLoc.y) CocoaEntities.create_entity(doc, tool) # there's got to be a better way to do this, # but I give up. Just redraw everything. _da.setNeedsDisplay_(True) # # Construction circle - center point # def ccircle_center_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter a point as 'x, y'") tool.setHandler("initialize", ccircle_center_mode_init) tool.setHandler("left_button_press", ccircle_center_first_left_button_press_cb) tool.setHandler("entry_event", ccircle_point_entry_event_cb) def ccircle_center_first_left_button_press_cb(doc, event, tool): CocoaEntities.circle_center_first_left_button_press_cb(doc, event, tool) tool.setHandler("mouse_move", ccircle_center_mouse_move_cb) def ccircle_center_mouse_move_cb(doc, np, tool): _p1 = tool.getCenter() _r = hypot((_p1[0] - np.x), (_p1[1] - np.y)) if _r > 0.0: _circle = PythonCAD.Generic.ccircle.CCircle(_p1, _r) _da = doc.getDA() _da.setTempObject(_circle) def ccircle_point_entry_event_cb(doc, text, tool): if len(text): CocoaEntities.circle_point_entry_event_cb(doc, text, tool) tool.setHandler("mouse_move", ccircle_center_mouse_move_cb) # # Construction circle - 2 point # def ccircle_tp_mode_init(doc, tool): doc.setPrompt("Click in the drawing area or enter a point as 'x, y'") tool.setHandler("initialize", ccircle_tp_mode_init) tool.setHandler("left_button_press", ccircle_tp_first_left_button_press_cb) tool.setHandler("entry_event", ccircle_tp_first_entry_event_cb) def ccircle_tp_first_left_button_press_cb(doc, event, tool): CocoaEntities.circle_tp_first_left_button_press_cb(doc, event, tool) tool.setHandler("mouse_move", ccircle_tp_mouse_move_cb) def ccircle_tp_mouse_move_cb(doc, np, tool): _x, _y = tool.getFirstPoint() _fp = NSMakePoint(_x, _y) if NSEqualPoints(_fp, np): return tool.setSecondPoint(np.x, np.y) _cp = tool.getCenter() _r = tool.getRadius() if _r is not None and _r > 0: _circle = PythonCAD.Generic.ccircle.CCircle(_cp, _r) _da = doc.getDA() _da.setTempObject(_circle) def ccircle_tp_first_entry_event_cb(doc, text, tool): if len(text): CocoaEntities.circle_tp_first_entry_event_cb(doc, text, tool) tool.setHandler("mouse_move", ccircle_tp_mouse_move_cb) # # Construction circle - tangent # def ccircle_tan1_mode_init(doc, tool): doc.setPrompt("Click on the construction object used for tangency") tool.setHandler("initialize", ccircle_tan1_mode_init) tool.setHandler("left_button_press", ccircle_tan1_first_left_button_press_cb) def ccircle_tan1_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _objdict = _image.mapPoint(_viewLoc.x, _viewLoc.y, _tol, 1) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: _objs = [] for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, (PythonCAD.Generic.hcline.HCLine, PythonCAD.Generic.vcline.VCLine, PythonCAD.Generic.acline.ACLine, PythonCAD.Generic.cline.CLine, PythonCAD.Generic.ccircle.CCircle)): tool.setConstructionLine(_obj) tool.setHandler("left_button_press", ccircle_final_left_button_press_cb) tool.setHandler("mouse_move", ccircle_tan1_mouse_move_cb) doc.setPrompt("Click in the drawing area to place the new construction line") def ccircle_final_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _pt, _flag = _image.findPoint(_viewLoc.x, _viewLoc.y, _tol) if _pt is not None: _x, _y = _pt.getCoords() _viewLoc = NSMakePoint(_x, _y) tool.setLocation(_viewLoc.x, _viewLoc.y) CocoaEntities.create_entity(doc, tool) def ccircle_tan1_mouse_move_cb(doc, np, tool): tool.setLocation(np.x, np.y) _cp = tool.getCenter() _r = tool.getRadius() if _r is not None and _r > 0: _circle = PythonCAD.Generic.ccircle.CCircle(_cp, _r) _da = doc.getDA() _da.setTempObject(_circle) # # Construction circle - 2 circle tangent # def ccircle_tan2_mode_init(doc, tool): doc.setPrompt("Click on the first construction line for tangency") tool.setHandler("initialize", ccircle_tan2_mode_init) tool.setHandler("left_button_press", ccircle_tan2_first_left_button_press_cb) def ccircle_tan2_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _objdict = _image.mapPoint(_viewLoc.x, _viewLoc.y, _tol, 1) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: _objs = [] for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, (PythonCAD.Generic.hcline.HCLine, PythonCAD.Generic.vcline.VCLine, PythonCAD.Generic.acline.ACLine, PythonCAD.Generic.cline.CLine, PythonCAD.Generic.ccircle.CCircle)): tool.setFirstConObject(_obj) tool.setHandler("left_button_press", ccircle_tan2_second_left_button_press_cb) doc.setPrompt("Click on the second construction line for tangency") def ccircle_tan2_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _objdict = _image.mapPoint(_viewLoc.x, _viewLoc.y, _tol, 1) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: _objs = [] for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, (PythonCAD.Generic.hcline.HCLine, PythonCAD.Generic.vcline.VCLine, PythonCAD.Generic.acline.ACLine, PythonCAD.Generic.cline.CLine)): tool.setSecondConObject(_obj) tool.setHandler("left_button_press", ccircle_final_left_button_press_cb) tool.setHandler("mouse_move", ccircle_tan2_mouse_move_cb) doc.setPrompt("Click where you want the tangent circle to be") def ccircle_tan2_mouse_move_cb(doc, np, tool): tool.setLocation(np.x, np.y) _cp = tool.getCenter() _r = tool.getRadius() if _r is not None and _r > 0: _circle = PythonCAD.Generic.ccircle.CCircle(_cp, _r) _da = doc.getDA() _da.setTempObject(_circle) PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/CocoaDimensions.py0000644000175000017500000002532411307666657023344 0ustar matteomatteo# # Copyright (c) 2002-2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Handles creation of dimensions # import PythonCAD.Generic.segment from PythonCAD.Interface.Cocoa import CocoaEntities # # Linear, Horizontal, Vertical dimensions all work the same way. # def ldim_mode_init(doc, tool): doc.setPrompt("Click on the first point for the dimension.") tool.setHandler("initialize", ldim_mode_init) tool.setHandler("left_button_press", ldim_first_left_button_press_cb) def ldim_first_mouse_move_cb(doc, np, tool): _l1, _p1 = tool.getFirstPoint() _p2 = (np.x, np.y) _seg = PythonCAD.Generic.segment.Segment(_p1, _p2) _da = doc.getDA() _da.setTempObject(_seg) def ldim_second_mouse_move_cb(doc, np, tool): _ldim = tool.getDimension() _ldim.setLocation(np.x, np.y) _ldim.calcDimValues() _da = doc.getDA() _da.setTempObject(_ldim) def ldim_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _layers = [_image.getTopLayer()] while len(_layers): _layer = _layers.pop() if _layer.isVisible(): _pt = _layer.find('point', _viewLoc.x, _viewLoc.y, _tol) if _pt is not None: _x, _y = _pt.getCoords() _da.setTempPoint(_viewLoc) tool.setLocation(_x, _y) tool.setFirstPoint(_layer, _pt) tool.setHandler("left_button_press", ldim_second_left_button_press_cb) tool.setHandler("mouse_move", ldim_first_mouse_move_cb) doc.setPrompt("Click on the second point for the dimension.") break _layers.extend(_layer.getSublayers()) def ldim_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _layers = [_image.getTopLayer()] while len(_layers): _layer = _layers.pop() if _layer.isVisible(): _pt = _layer.find('point', _viewLoc.x, _viewLoc.y, _tol) if _pt is not None: _x, _y = _pt.getCoords() tool.setSecondPoint(_layer, _pt) tool.setDimPosition(_x, _y) tool.clearCurrentPoint() tool.makeDimension(_image) tool.setHandler("left_button_press", ldim_third_left_button_press_cb) tool.setHandler("mouse_move", ldim_second_mouse_move_cb) doc.setPrompt("Click where the dimension text should be placed.") break _layers.extend(_layer.getSublayers()) def ldim_third_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _ldim = tool.getDimension() _ldim.setLocation(_viewLoc.x, _viewLoc.y) _ldim.calcDimValues() _ldim.reset() CocoaEntities.create_entity(doc, tool) # # Radial # def radial_mode_init(doc, tool): doc.setPrompt("Click on an arc or a circle to dimension.") tool.setHandler("initialize", radial_mode_init) tool.setHandler("left_button_press", radial_first_left_button_press_cb) def radial_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _layers = [_image.getTopLayer()] _dc = _dl = None while len(_layers): _layer = _layers.pop() if _layer.isVisible(): _cobjs = (_layer.getLayerEntities("circle") + _layer.getLayerEntities("arc")) for _cobj in _cobjs: _mp = _cobj.mapCoords(_viewLoc.x, _viewLoc.y, _tol) if _mp is not None: _dc = _cobj _dl = _layer break _layers.extend(_layer.getSublayers()) if _dc is not None: _x, _y = _mp tool.setDimObject(_dl, _dc) tool.setDimPosition(_x, _y) tool.makeDimension(_image) tool.setHandler("mouse_move", radial_mouse_move_cb) tool.setHandler("left_button_press", radial_second_left_button_press_cb) doc.setPrompt("Click where the dimension text should be placed.") def radial_mouse_move_cb(doc, np, tool): _rdim = tool.getDimension() _rdim.setLocation(np.x, np.y) _rdim.calcDimValues() _da = doc.getDA() _da.setTempObject(_rdim) def radial_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _ldim = tool.getDimension() _ldim.setLocation(_viewLoc.x, _viewLoc.y) _ldim.calcDimValues() _ldim.reset() CocoaEntities.create_entity(doc, tool) # # Angular # def angular_mode_init(doc, tool): doc.setPrompt("Click on the angle vertex point or an arc.") tool.setHandler("initialize", angular_mode_init) tool.setHandler("left_button_press", angular_first_left_button_press_cb) def angular_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _layers = [_image.getTopLayer()] _pt = _arc = None while len(_layers): _layer = _layers.pop() if _layer.isVisible(): _pt, _arc = _test_layer(_layer, _viewLoc.x, _viewLoc.y, _tol) if _pt is not None or _arc is not None: break _layers.extend(_layer.getSublayers()) if _pt is not None: tool.setVertexPoint(_layer, _pt) _da.setTempPoint(_viewLoc) tool.setHandler("left_button_press", angular_second_left_button_press_cb) tool.setHandler("mouse_move", angular_segment_mouse_move_cb) doc.setPrompt("Click on the first endpoint for the dimension.") elif _arc is not None: _cp = _arc.getCenter() tool.setVertexPoint(_layer, _cp) _ep1, _ep2 = _arc.getEndpoints() _ex, _ey = _ep1 _p1 = _layer.find('point', _ex, _ey) assert _p1 is not None, "Missing arc endpoint" tool.setFirstPoint(_layer, _p1) _ex, _ey = _ep2 _p2 = _layer.find('point', _ex, _ey) assert _p2 is not None, "Missing arc endpoint" tool.setSecondPoint(_layer, _p2) tool.setDimPosition(_viewLoc.x, _viewLoc.y) tool.makeDimension(_image) tool.setHandler("left_button_press", angular_fourth_left_button_press_cb) tool.setHandler("mouse_move", angular_text_mouse_move_cb) doc.setPrompt("Click where the dimension text should be located.") def angular_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _layers = [_image.getTopLayer()] while len(_layers): _layer = _layers.pop() if _layer.isVisible(): _pt = _layer.find('point', _x, _y, _tol) if _pt is not None: _x, _y = _pt.getCoords() tool.setLocation(_x, _y) tool.setFirstPoint(_layer, _pt) tool.setHandler("left_button_press", angular_third_left_button_press_cb) tool.setHandler("mouse_move", angular_segment_mouse_move_cb) doc.setPrompt("Click on the second endpoint for the dimension.") break _layers.extend(_layer.getSublayers()) def angular_third_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _layers = [_image.getTopLayer()] while len(_layers): _layer = _layers.pop() if _layer.isVisible(): _pt = _layer.find('point', _x, _y, _tol) if _pt is not None: _x, _y = _pt.getCoords() tool.setLocation(_x, _y) tool.setSecondPoint(_layer, _pt) tool.setDimPosition(_x, _y) tool.makeDimension(_image) tool.setHandler("left_button_press", angular_fourth_left_button_press_cb) tool.setHandler("mouse_move", angular_text_mouse_move_cb) doc.setPrompt("Click where the dimension text should be located.") break _layers.extend(_layer.getSublayers()) def angular_fourth_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) _adim = tool.getDimension() _adim.setLocation(_x, _y) _adim.calcDimValues() _adim.reset() CocoaEntities.create_entity(doc, tool) def angular_segment_mouse_move_cb(doc, np, tool): _l1, _p1 = tool.getVertexPoint() _l2, _p2 = tool.getFirstPoint() _da = doc.getDA() _flag = True if _p2 is not None: _seg = PythonCAD.Generic.segment.Segment(_p1, _p2) _da.setTempObject(_seg, _flag) _flag = False _p2 = (np.x, np.y) _seg = PythonCAD.Generic.segment.Segment(_p1, _p2) _da.setTempObject(_seg, _flag) def angular_text_mouse_move_cb(doc, np, tool): _adim = tool.getDimension() _adim.setLocation(np.x, np.y) _adim.calcDimValues() _da = doc.getDA() _da.setTempObject(_adim) def _test_layer(layer, x, y, tol): _arc = None _pt = layer.find('point', x, y) if _pt is None: _pt = layer.find('point', x, y, tol) if _pt is None: _arc_pt = None for _arc in layer.getLayerEntities("arc"): _arc_pt = _arc.mapCoords(x, y, tol) if _arc_pt is not None: break if _arc_pt is None: _arc = None # no hits on any arcs ... return _pt, _arc PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/ImageDocument.py0000644000175000017500000004052611307666657023011 0ustar matteomatteo# # Copyright (c) 2002-2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Cocoa wrapper for Image class - handles display of # drawing in a window, saving & loading of files # # P.L.V. nov 23 05 # import adjustment from __future__ import division import math import sys import types import PythonCAD.Generic.image import PythonCAD.Generic.imageio import PythonCAD.Generic.tools import PythonCAD.Generic.globals import PythonCAD.Generic.layer import PythonCAD.Generic.message import PythonCAD.Interface.Cocoa.Globals import PythonCAD.Interface.Cocoa.CADView from PythonCAD.Interface.Cocoa import ImageWindowController from PyObjCTools import NibClassBuilder from Foundation import NSLog, NSObject, NSString, NSNotificationCenter, NSNotificationQueue, NSNotification, NSPostWhenIdle, NSPostASAP, NSNotificationNoCoalescing from AppKit import NSOutlineViewDataSource, NSWindowController, NSChangeDone # # Define True & False if this is Python < 2.2.1 # try: True, False except NameError: True, False = 1, 0 NibClassBuilder.extractClasses("ImageDocument") class CocoaMessenger(PythonCAD.Generic.message.Messenger): """ Class converts PythonCAD messages into NSNotificationCenter messages """ def added_object_event(self, obj, *args): """ Notification of new point, line, etc. added to drawing. object is Image object, userinfo dict stores new object under key "item" """ _nq = NSNotificationQueue.defaultQueue() if len(args) != 2: raise ValueError, "Invalid number of new items in added_object_event" _info = {"layer" : args[0], "item": args[1]} _obj = Globals.wrap(obj) _note = NSNotification.notificationWithName_object_userInfo_("added_object", _obj, _info) _nq.enqueueNotification_postingStyle_coalesceMask_forModes_(_note, NSPostASAP, NSNotificationNoCoalescing, None) def deleted_object_event(self, obj, *args): """ Notification of point, line, etc. removed from a layer. object is Image object, userinfo dict stores object under key "item", layer it was removed from under "layer" """ _nq = NSNotificationQueue.defaultQueue() if len(args) != 2: raise ValueError, "Invalid number of items in deleted_object_event" _info = {"layer" : args[0], "item": args[1]} _obj = Globals.wrap(obj) _note = NSNotification.notificationWithName_object_userInfo_("deleted_object", _obj, _info) _nq.enqueueNotification_postingStyle_coalesceMask_forModes_(_note, NSPostASAP, NSNotificationNoCoalescing, None) def added_child_event(self, obj, *args): """ Notification of new layer added to drawing. object is Image object, userinfo dict stores new layer under key "layer", parent layer under key "parent" """ _nq = NSNotificationQueue.defaultQueue() if len(args) != 2: raise ValueError, "Invalid number of new items in added_layer_event" _info = {"layer" : args[0], "parent" : args[0].getParent()} _obj = Globals.wrap(obj) _note = NSNotification.notificationWithName_object_userInfo_(Globals.LayerAddedNotification, _obj, _info) _nq.enqueueNotification_postingStyle_coalesceMask_forModes_(_note, NSPostASAP, NSNotificationNoCoalescing, None) def removed_child_event(self, obj, *args): """ Notification of deletion of a layer. object is Image object, userinfo dict stores layer under key "layer", parent layer under key "parent" """ _nq = NSNotificationQueue.defaultQueue() if len(args) != 2: raise ValueError, "Invalid number of items in deleted_layer_event" _info = {"layer" : args[0], "parent" : args[0].getParent()} _obj = Globals.wrap(obj) _note = NSNotification.notificationWithName_object_userInfo_(Globals.LayerDeletedNotification, _obj, _info) _nq.enqueueNotification_postingStyle_coalesceMask_forModes_(_note, NSPostASAP, NSNotificationNoCoalescing, None) # class defined in ImageDocument.nib class ImageDocument(NibClassBuilder.AutoBaseClass): """Cocoa wrapper around an Image. The ImageDocument is an NSDocument which has as a member variable an instance of the Image class. It is the data source for the Outline view of the window. It has the following additional methods: getDA(): Get CADView holding the drawing area getOutlineView: Get NSOutlineView holding layer information getEntry(): Get NSTextField used for command entry getSplitView(): Get NSSplitView containing the CADView & Layer Outline View {get/set}Option(): Get/set option in generic Image object {get/set}Image(): Get generic Image object {get/set}Prompt(): Get/Set the prompt. {get/set}Tool(): Get/Set the tool used for working in the GTKImage. {get/set}UnitsPerPixel(): Get/Set this display parameter. {get/set}Point(): Get/Set the current coordinates of the tool. reset(): Sets the image to an initial drawing state """ # # Setup variables # __image = None # # Beginning of Cocoa methods # def init(self): """ NSDocument override for cocoa initializer of ImageDocument. init() """ self = super(ImageDocument, self).init() if (self): # # Set up messaging # self.setMessenger(CocoaMessenger()) # # Initialize image object # self.setImage(PythonCAD.Generic.image.Image()) # # tool setup & location # self.__tool = None self.__oldtool = PythonCAD.Generic.tools.Tool() self.__point_x = 0.0 self.__point_y = 0.0 # # viewable region # self.__disp_width = None self.__disp_height = None self.__xmin = None self.__ymin = None self.__xmax = None self.__ymax = None return self def windowNibName(self): """ NSDocument override to load ImageDocument nib windowNibName() """ return "ImageDocument" def makeWindowControllers(self): """ NSDocument override to manage custom NSWindowController makeWindowControllers() """ _nib = self.windowNibName() _wc = ImageWindowController.alloc().initWithWindowNibName_owner_(_nib,self) self.addWindowController_(_wc) def windowControllerDidLoadNib_(self, windowController): """ NSDocument override to do post-window appearance initialization windowControllerDidLoadNib(windowController) """ # # layer view setup # self.promptField.setStringValue_("Enter Command:") self.locationField.setStringValue_(self.getPoint()) self.getOutlineView().reloadData() _da = self.getDA() _img = self.getImage() if len(_img.getTopLayer().getChildren()) > 0: _da.fitImage() _da.postLoadSetup() def close(self): """ NSDocument override called when window is closing close() """ PythonCAD.Generic.image.Image.close(self.getImage()) super(ImageDocument, self).close() def setFileName_(self, name): """ NSDocument override to keep filename set correctly in Image setFileName(name) """ self.getImage().setFilename(name) super(ImageDocument, self).setFileName_(name) def prepareSavePanel_(self, savePanel): """ NSDocument override to specify required extensions, etc prepareSavePanel(savePanel) """ savePanel.setRequiredFileType_("xml.gz") return True def writeToFile_ofType_(self, path, tp): """ NSDocument override to write file to disk writeToFile_ofType_(path, filetype) """ try: PythonCAD.Generic.imageio.save_image(self.getImage(),path) except (IOError, OSError), e: sys.stderr.write("Error writing file: %s\n" % str(e)) return False except StandardError, e: sys.stderr.write("Error: %s\n" % str(e)) return False return True def readFromFile_ofType_(self, path, tp): """ NSDocument override to read file from disk readFromFile_ofType_(path, filetype) """ _image = PythonCAD.Generic.image.Image() try: _imagefile = PythonCAD.Generic.fileio.CompFile(path, "r") try: PythonCAD.Generic.imageio.load_image(_image, _imagefile) finally: _imagefile.close() except (IOError, OSError), e: sys.stderr.write("Can't open '%s': %s\n" % (_fname, e)) return False except StandardError, e: sys.stderr.write("Error: %s\n" % str(e)) return False self.setImage(_image) return True # # End of Cocoa methods # # # Beginning of PythonCad specific methods # def addChildLayer(self, layer): """Add a new Layer as a Child of the entered layer. # #addChildLayer(l) # #This method covers the image::addChildLayer() method. # """ new_layer = PythonCAD.Generic.layer.Layer("NewChildLayer") try: self.getImage().addChildLayer(new_layer, layer) except: #should do this better return self.updateChangeCount_(NSChangeDone) # _nc = NSNotificationCenter.defaultCenter() # _nc.postNotificationName_object_(Globals.LayerAddedNotification, self) def delLayer(self, layer): """Remove a Layer from the drawing. delLayer(l) This method covers the image::delLayer() method. """ try: self.getImage().delLayer(layer) except: #should do this better return self.updateChangeCount_(NSChangeDone) # _nc = NSNotificationCenter.defaultCenter() # _nc.postNotificationName_object_(Globals.LayerDeletedNotification, self) def getDA(self): """ Return the CADView for the Image getDA() """ return self.CADView da = property(getDA, None, None, "DrawingArea for a ImageDocument.") def getOutlineView(self): """ Return the NSOutlineView holding layers for the Image getOutlineView() """ return self.layerOutlineView outline_view = property(getOutlineView, None, None, "OutlineView for a ImageDocument.") def getEntry(self): """ Returns the NSTextField for command entry getEntry() """ return self.entryField entry = property(getEntry, None, None, "Entry box for a ImageDocument.") def getSplitView(self): """ Returns the NSSplitView containing the OutlineView & DA getSplitView() """ return self.splitView def getOption(self, key): """Cover method to return the value of an option set in the drawing. getOption(key) Return the value of the option associated with the string "key". If there is no option found for that key, return None. """ return self.getImage().getOption(key) def setOption(self, key, value): """Cover method to set values of an option in the drawing setOption(key, value) The "key" must be a string, and "value" can be anything. Using the same key twice will result on the second value overwriting the first. """ self.getImage().setOption(key, value) def getImage(self): """ Returns Generic PythonCad Image object associated with this document getImage() """ return self.__image image = property(getImage, None, None, "Generic Image object of ImageDocument") def setImage(self, image): """ Sets Generic PythondCad Image object associated with this document setImage(image) """ _curImg = self.getImage() if isinstance(_curImg, PythonCAD.Generic.image.Image): PythonCAD.Generic.image.Image.close(_curImg) self.__image = image _m = self.getMessenger() image.connect("added_object", _m.added_object_event) image.connect("deleted_object", _m.deleted_object_event) image.connect("added_child", _m.added_child_event) image.connect("removed_child", _m.removed_child_event) def getMessenger(self): """ Returns PythonCad to NSNotificationCenter translation object for this document getMessenger() """ return self.__messenger def setMessenger(self, m): """ Sets PythongCad to NSNotificationCenter translation object for this document setMessenger() """ if not isinstance(m, CocoaMessenger): raise TypeError, "Invalid messenger object!" self.__messenger = m def getPrompt(self): """Return the current prompt string. getPrompt() """ return self.promptField.stringValue() def setPrompt(self, prompt): """Set the current prompt string. setPrompt(prompt) """ if not isinstance(prompt, types.StringTypes): raise TypeError, "Invalid prompt: " + `prompt` self.promptField.setStringValue_(prompt) prompt = property(getPrompt, setPrompt, None, "Prompt string.") def setTool(self, tool): """Replace the tool in the image with a new Tool. setTool(tool) The argument "tool" should be an instance of a Tool object. """ if not isinstance(tool, PythonCAD.Generic.tools.Tool): raise TypeError, "Invalid tool: " + str(tool) self.__tool = tool _nc = NSNotificationCenter.defaultCenter() _nc.postNotificationName_object_userInfo_(Globals.ToolChangedNotification, self, {"tool" : tool}) def getTool(self): """Return the current Tool used in the drawing. getTool() """ return self.__tool tool = property(getTool, None, None, "Tool for adding/modifying entities.") def getPoint(self): """Get the current point where the tool is located. getPoint() This function returns a tuple with two floats (x,y) x: x-coordinate y: y-coordinate """ return (self.__point_x, self.__point_y) def setPoint(self, x, y): """Store the point where the tool currently is located at. setPoint(x,y) The x and y arguments should be floats. """ _x = x _y = y try: if not isinstance(_x, float): _x = float(x) if not isinstance(_y, float): _y = float(y) _str = "%.4f, %.4f" % (_x, _y) self.locationField.setStringValue_(_str) self.__point_x = _x self.__point_y = _y except: # need better error handling pass point = property(getPoint, setPoint, None, "Current tool location.") def reset(self): """Set the image to an initial drawing state. reset() """ self.__tool = None self.setPrompt("Enter command:") self.getEntry().setStringValue_("") _da = self.getDA() _da.setTempObject() _da.setNeedsDisplay_(True) def changeColor_(self, sender): """ Records new colors chosen from color picker. changeColor_(colorPicker) """ _nscolor = sender.color().colorUsingColorSpaceName_("NSCalibratedRGBColorSpace") (_r, _g, _b, _a) = _nscolor.getRed_green_blue_alpha_() _ir = int(_r*255) _ig = int(_g*255) _ib = int(_b*255) _color = PythonCAD.Generic.color.get_color(_ir, _ig, _ib) self.setOption('LINE_COLOR', _color) PythonCAD-DS1-R37/PythonCAD/Interface/Cocoa/CocoaModify.py0000644000175000017500000006332711307666657022470 0ustar matteomatteo# # Copyright (c) 2002-2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Handles modification of drawing entities and views # import string import objc import PythonCAD.Generic.segment import PythonCAD.Generic.split import PythonCAD.Generic.transfer import PythonCAD.Generic.mirror import PythonCAD.Generic.move from Foundation import NSMakePoint # # Generic code - select, make distances, etc # def select_mouse_move_cb(doc, np, tool): _p1 = tool.getLocation() _p2 = (_p1[0],np.y) _p3 = (np.x, np.y) _p4 = (np.x,_p1[1]) _da = doc.getDA() _s1 = PythonCAD.Generic.segment.Segment(_p1, _p2) _s2 = PythonCAD.Generic.segment.Segment(_p2, _p3) _s3 = PythonCAD.Generic.segment.Segment(_p3, _p4) _s4 = PythonCAD.Generic.segment.Segment(_p4, _p1) _da = doc.getDA() _da.setTempObject(_s1) _da.setTempObject(_s2, False) _da.setTempObject(_s3, False) _da.setTempObject(_s4, False) # # Split # def split_init(doc, tool): doc.setPrompt("Click on the objects you want to split") tool.setHandler("initialize", split_init) tool.setHandler("left_button_press", split_first_left_button_press_cb) def split_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) _da.setTempPoint(NSMakePoint(_x, _y)) _tol = _da.pointSize().width _image = doc.getImage() _active_layer = _image.getActiveLayer() _objlist = _active_layer.mapPoint((_x, _y), _tol, None) if len(_objlist): for _obj, _pt in _objlist: if isinstance(_obj, PythonCAD.Generic.segment.Segment): _p1, _p2 = _obj.getEndpoints() _lpt = _active_layer.find('point', _pt.x, _pt.y) if _lpt is None: _active_layer.addObject(_pt) _lpt = _pt _s1, _s2 = PythonCAD.Generic.split.split_segment(_obj, _pt) _image.startAction() try: _active_layer.addObject(_s1) _active_layer.addObject(_s2) _active_layer.delObject(_obj) finally: _image.endAction() elif isinstance(_obj, PythonCAD.Generic.arc.Arc): _arc1, _arc2 = PythonCAD.Generic.split.split_arc(_obj, _pt) _image.startAction() try: _active_layer.addObject(_arc1) _active_layer.addObject(_arc2) _active_layer.delObject(_obj) finally: _image.endAction() elif isinstance(_obj, PythonCAD.Generic.circle.Circle): _arc = PythonCAD.Generic.split.split_circle(_obj, _pt) _image.startAction() try: _active_layer.addObject(_arc) _active_layer.delObject(_obj) finally: _image.endAction() elif isinstance(_obj, PythonCAD.Generic.polyline.Polyline): _lpt = _active_layer.find('point', _pt.x, _pt.y) _image.startAction() try: if _lpt is None: _active_layer.addObject(_pt) _lpt = _pt PythonCAD.Generic.split.split_polyline(_obj, _lpt) finally: _image.endAction() else: pass else: tool.pushObject(_x) tool.pushObject(_y) tool.setLocation(_x, _y) tool.setHandler("mouse_move", select_mouse_move_cb) tool.setHandler("left_button_press", split_second_left_button_press_cb) def split_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x2, _y2) = _da.convertPoint_fromView_(_loc, None) _y1 = tool.popObject() _x1 = tool.popObject() _xmin = min(_x1, _x2) _xmax = max(_x1, _x2) _ymin = min(_y1, _y2) _ymax = max(_y1, _y2) _image = doc.getImage() _active_layer = _image.getActiveLayer() _objs = _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax, True) if len(_objs): _splitable = [] for _obj in _objs: if isinstance(_obj, (PythonCAD.Generic.segment.Segment, PythonCAD.Generic.circle.Circle, PythonCAD.Generic.arc.Arc, PythonCAD.Generic.polyline.Polyline)): _splitable.append(_obj) if len(_splitable): PythonCAD.Generic.split.split_objects(_active_layer, _splitable) tool.reset() split_init(doc, tool) # # Mirror # def mirror_init(doc, tool): doc.setPrompt("Click on the mirroring construction line") tool.setHandler("initialize", mirror_init) tool.setHandler("left_button_press", mirror_first_left_button_press_cb) def mirror_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _objdict = _image.mapPoint(_x, _y, _tol, None) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: for _obj, _pt in _objdict[_active_layer]: if isinstance(_obj, (PythonCAD.Generic.hcline.HCLine, PythonCAD.Generic.vcline.VCLine, PythonCAD.Generic.acline.ACLine, PythonCAD.Generic.cline.CLine)): tool.setHandler("left_button_press", mirror_second_left_button_press_cb) tool.setMirrorLine(_obj) doc.setPrompt("Click on or select the objects to mirror") break def mirror_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) _da.setTempPoint(NSMakePoint(_x, _y)) _tol = _da.pointSize().width _image = doc.getImage() _objdict = _image.mapPoint(_x, _y, _tol, None) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: _objs = [] for _obj, _pt in _objdict[_active_layer]: _objs.append(_obj) _mline = tool.getMirrorLine() mirror_objects(doc, tool, _objs) else: _p, _flag = _image.findPoint(_x, _y, _tol) if _p is not None: _x, _y = _p.getCoords() tool.setLocation(_x, _y) tool.setHandler("mouse_move", select_mouse_move_cb) tool.setHandler("left_button_press", mirror_third_left_button_press_cb) def mirror_third_left_button_press_cb(doc, event, tool): tool.delHandler("mouse_move") _loc = event.locationInWindow() _da = doc.getDA() (_x2, _y2) = _da.convertPoint_fromView_(_loc, None) _image = doc.getImage() _active_layer = _image.getActiveLayer() _p = _active_layer.find('point', _x2, _y2) if _p is not None: _x2, _y2 = _p.getCoords() _x1, _y1 = tool.getLocation() _xmin = min(_x1, _x2) _xmax = max(_x1, _x2) _ymin = min(_y1, _y2) _ymax = max(_y1, _y2) _objs = _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax, True) mirror_objects(doc, tool, _objs) def mirror_objects(doc, tool, objs): _mline = tool.getMirrorLine() _image = doc.getImage() _mobjs = PythonCAD.Generic.mirror.mirror_objects(_image, _mline, objs) tool.reset() doc.getDA().flushTempObjects() mirror_init(doc, tool) # # Transfer # def transfer_init(doc, tool): doc.setPrompt("Click on the objects you want to transfer to the active layer") tool.setHandler("initialize", transfer_init) tool.setHandler("left_button_press", transfer_first_left_button_press_cb) def transfer_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) _da.setTempPoint(NSMakePoint(_x, _y)) _tol = _da.pointSize().width _image = doc.getImage() _active_layer = _image.getActiveLayer() _objdict = _image.mapPoint(_x, _y, _tol, None) if len(_objdict): _image.startAction() try: for _layer in _objdict: if _layer is not _active_layer: _objs = [] for _obj, _pt in _objdict[_layer]: _objs.append(_obj) PythonCAD.Generic.transfer.transfer_objects(_objs, _layer, _active_layer) finally: _image.endAction() else: tool.pushObject(_x) tool.pushObject(_y) tool.setLocation(_x, _y) tool.setHandler("mouse_move", select_mouse_move_cb) tool.setHandler("left_button_press", transfer_second_left_button_press_cb) def transfer_second_left_button_press_cb(doc, event, tool): tool.delHandler("mouse_move") _loc = event.locationInWindow() _da = doc.getDA() (_x2, _y2) = _da.convertPoint_fromView_(_loc, None) _y1 = tool.popObject() _x1 = tool.popObject() _xmin = min(_x1, _x2) _xmax = max(_x1, _x2) _ymin = min(_y1, _y2) _ymax = max(_y1, _y2) _image = doc.getImage() _active_layer = _image.getActiveLayer() _layers = [_image.getTopLayer()] _objdict = {} while len(_layers): _layer = _layers.pop() if _layer is not _active_layer: if _layer.isVisible(): _objs = _layer.objsInRegion(_xmin, _ymin, _xmax, _ymax) if len(_objs): _objdict[_layer] = _objs _layers.extend(_layer.getSublayers()) if len(_objdict): _image.startAction() try: for _layer in _objdict: if _layer is not _active_layer: _objs = _objdict[_layer] PythonCAD.Generic.transfer.transfer_objects(_objs, _layer, _active_layer) finally: _image.endAction() else: doc.getDA().flushTempObjects() tool.reset() transfer_init(doc, tool) # # Move # # functions used by all the move code def move_objects(doc, objs, tool): _init_func = tool.getHandler("initialize") _image = doc.getImage() _active_layer = _image.getActiveLayer() _dx, _dy = tool.getDistance() _image.startAction() try: PythonCAD.Generic.move.move_objects(_active_layer, objs, _dx, _dy) finally: _image.endAction() doc.getDA().flushTempObjects() tool.reset() _init_func(doc, tool) def make_distance(text): try: _textrad = eval(text) except: raise ValueError, "Invalid distance: " + text if not isinstance(_textrad, float): _textrad = float(_textrad) return _textrad def move_select_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) _da.setTempPoint(NSMakePoint(_x, _y)) _tol = _da.pointSize().width _image = doc.getImage() _active_layer = _image.getActiveLayer() _objdict = _image.mapPoint(_x, _y, _tol, None) if len(_objdict): _active_layer = _image.getActiveLayer() if _active_layer in _objdict: _objs = [] for _obj, _pt in _objdict[_active_layer]: _objs.append(_obj) move_objects(doc, _objs, tool) else: _pt, _flag = _image.findPoint(_x, _y, _tol) if _pt is not None: _x, _y = _pt.getCoords() tool.setLocation(_x, _y) tool.setHandler("mouse_move", select_mouse_move_cb) tool.setHandler("left_button_press", move_select_second_left_button_press_cb) def move_select_second_left_button_press_cb(doc, event, tool): tool.delHandler("mouse_move") _loc = event.locationInWindow() _da = doc.getDA() (_x2, _y2) = _da.convertPoint_fromView_(_loc, None) _x1, _y1 = tool.getLocation() _xmin = min(_x1, _x2) _xmax = max(_x1, _x2) _ymin = min(_y1, _y2) _ymax = max(_y1, _y2) _image = doc.getImage() _active_layer = _image.getActiveLayer() _objs = _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax, True) move_objects(doc, _objs, tool) # other functions def move_horizontal_init(doc, tool): doc.setPrompt("Click in the drawing area or enter the horizontal distance") tool.setHandler("initialize", move_horizontal_init) tool.setHandler("entry_event", move_horizontal_entry_event_cb) tool.setHandler("left_button_press", move_horizontal_first_left_button_press_cb) def move_horizontal_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _pt, _flag = _image.findPoint(_x, _y, _tol) if _pt is not None: _x, _y = _pt.getCoords() tool.setLocation(_x, _y) tool.setHandler("left_button_press", move_horizontal_second_left_button_press_cb) doc.setPrompt("Click another point to define the distance") def move_horizontal_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x2, _y2) = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _pt, _flag = _image.findPoint(_x2, _y2, _tol) if _pt is not None: _x2, _y2 = _pt.getCoords() _x1, _y1 = tool.getLocation() tool.setDistance((_x2 - _x1), 0.0) tool.clearLocation() tool.delHandler("entry_event") tool.setHandler("left_button_press", move_select_first_left_button_press_cb) doc.setPrompt("Click on or select the objects to move") def move_horizontal_entry_event_cb(doc, text, tool): if len(text): _dist = make_distance(text) tool.setDistance(_dist, 0.0) doc.setPrompt("Click on or select the objects to move") tool.delHandler("entry_event") tool.setHandler("left_button_press", move_select_first_left_button_press_cb) def move_vertical_init(doc, tool): doc.setPrompt("Click in the drawing area or enter the vertical distance") tool.setHandler("initialize", move_vertical_init) tool.setHandler("entry_event", move_vertical_entry_event_cb) tool.setHandler("left_button_press", move_vertical_first_left_button_press_cb) def move_vertical_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _pt, _flag = _image.findPoint(_x, _y, _tol) if _pt is not None: _x, _y = _pt.getCoords() tool.setLocation(_x, _y) tool.setHandler("left_button_press", move_vertical_second_left_button_press_cb) doc.setPrompt("Click another point to define the distance") def move_vertical_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x2, _y2) = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _pt, _flag = _image.findPoint(_x2, _y2, _tol) if _pt is not None: _x2, _y2 = _pt.getCoords() _x1, _y1 = tool.getLocation() tool.setDistance(0.0, (_y2 - _y1)) tool.clearLocation() tool.delHandler("entry_event") tool.setHandler("left_button_press", move_select_first_left_button_press_cb) doc.setPrompt("Click on or select the objects to move") def move_vertical_entry_event_cb(doc, text, tool): if len(text): _dist = make_distance(text) tool.setDistance(0.0, _dist) doc.setPrompt("Click on or select the objects to move") tool.delHandler("entry_event") tool.setHandler("left_button_press", move_select_first_left_button_press_cb) def move_free_init(doc, tool): doc.setPrompt("Click in the drawing area or enter the distance to move as 'h, v'") tool.setHandler("initialize", move_free_init) tool.setHandler("left_button_press", move_free_first_left_button_press_cb) tool.setHandler("entry_event", move_free_entry_event_cb) def move_free_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _pt, _flag = _image.findPoint(_x, _y, _tol) if _pt is not None: _x, _y = _pt.getCoords() tool.setLocation(_x, _y) tool.setHandler("left_button_press", move_free_second_left_button_press_cb) doc.setPrompt("Click another point to define the distance") def move_free_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x2, _y2) = _da.convertPoint_fromView_(_loc, None) _tol = _da.pointSize().width _image = doc.getImage() _pt, _flag = _image.findPoint(_x2, _y2, _tol) if _pt is not None: _x2, _y2 = _pt.getCoords() _x1, _y1 = tool.getLocation() tool.setDistance((_x2 - _x1), (_y2 - _y1)) tool.clearLocation() tool.setHandler("left_button_press", move_select_first_left_button_press_cb) doc.setPrompt("Click on or select the objects to move") def move_free_entry_event_cb(doc, text, tool): if len(text): _str = string.split(text, ",") if len(_str) != 2: raise ValueError, "Invalid distance (must be h, v): " + text _hdist = make_distance(_str[0]) _vdist = make_distance(_str[1]) tool.setDistance(_hdist, _vdist) doc.setPrompt("Click on or select the objects to move") tool.delHandler("entry_event") tool.setHandler("left_button_press", move_select_first_left_button_press_cb) # # Stretch # def stretch_select_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) _da.setTempPoint(NSMakePoint(_x, _y)) _tol = _da.pointSize().width _image = doc.getImage() _active_layer = _image.getActiveLayer() _pt = _active_layer.find('point', _x, _y, _tol) if _pt is not None: _dx, _dy = tool.getDistance() _pt.move(_dx, _dy) # should do this better . . . _init_func = tool.getHandler("initialize") tool.reset() _init_func(doc, tool) doc.getDA().setNeedsDisplay_(True) else: tool.setLocation(_x, _y) tool.setHandler("mouse_move", select_mouse_move_cb) tool.setHandler("left_button_press", stretch_select_second_left_button_press_cb) def stretch_select_second_left_button_press_cb(doc, event, tool): tool.delHandler("mouse_move") _loc = event.locationInWindow() _da = doc.getDA() (_x2, _y2) = _da.convertPoint_fromView_(_loc, None) _x1, _y1 = tool.getLocation() _xmin = min(_x1, _x2) _xmax = max(_x1, _x2) _ymin = min(_y1, _y2) _ymax = max(_y1, _y2) _image = doc.getImage() _active_layer = _image.getActiveLayer() _dx, _dy = tool.getDistance() for _pt in _active_layer.getLayerEntities("point"): if _pt.x > _xmax: break if _pt.inRegion(_xmin, _ymin, _xmax, _ymax): _pt.move(_dx, _dy) # should do this better . . . _init_func = tool.getHandler("initialize") tool.reset() _init_func(doc, tool) _da = doc.getDA() _da.flushTempObjects() _da.setNeedsDisplay_(True) def stretch_horizontal_init(doc, tool): doc.setPrompt("Click in the drawing area or enter the horizontal distance") tool.setHandler("initialize", stretch_horizontal_init) tool.setHandler("entry_event", stretch_horizontal_entry_event_cb) tool.setHandler("left_button_press", stretch_horizontal_first_left_button_press_cb) def stretch_horizontal_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) tool.setLocation(_x, _y) tool.setHandler("left_button_press", stretch_horizontal_second_left_button_press_cb) doc.setPrompt("Click a second point to indicate the horizontal distance") def stretch_horizontal_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x2, _y2) = _da.convertPoint_fromView_(_loc, None) (_x1, _y1) = tool.getLocation() tool.setDistance((_x2 - _x1), 0.0) tool.setHandler("left_button_press", stretch_select_first_left_button_press_cb) tool.delHandler("entry_event") doc.setPrompt("Click on or select the objects to stretch") def stretch_horizontal_entry_event_cb(doc, text, tool): if len(text): _dist = make_distance(text) tool.setDistance(_dist, 0.0) tool.setHandler("left_button_press", stretch_select_first_left_button_press_cb) tool.delHandler("entry_event") doc.setPrompt("Click on or select the points to stretch") def stretch_vertical_init(doc, tool): doc.setPrompt("Click in the drawing area or enter the vertical distance") tool.setHandler("initialize", stretch_vertical_init) tool.setHandler("entry_event", stretch_vertical_entry_event_cb) tool.setHandler("left_button_press", stretch_vertical_first_left_button_press_cb) def stretch_vertical_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) tool.setLocation(_x, _y) tool.setHandler("left_button_press", stretch_vertical_second_left_button_press_cb) doc.setPrompt("Click a second point to indicate the vertical distance") def stretch_vertical_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x2, _y2) = _da.convertPoint_fromView_(_loc, None) (_x1, _y1) = tool.getLocation() tool.setDistance(0.0, (_y2 - _y1)) tool.setHandler("left_button_press", stretch_select_first_left_button_press_cb) tool.delHandler("entry_event") doc.setPrompt("Click on or select the points to stretch") def stretch_vertical_entry_event_cb(doc, text, tool): if len(text): _dist = make_distance(text) tool.setDistance(0.0, _dist) tool.setHandler("left_button_press", stretch_select_first_left_button_press_cb) tool.delHandler("entry_event") doc.setPrompt("Click on or select the points to stretch") def stretch_free_init(doc, tool): doc.setPrompt("Click in the drawing area or enter the distance to stretch as 'h, v'") tool.setHandler("initialize", stretch_free_init) tool.setHandler("entry_event", stretch_free_entry_event_cb) tool.setHandler("left_button_press", stretch_free_first_left_button_press_cb) def stretch_free_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x, _y) = _da.convertPoint_fromView_(_loc, None) tool.setLocation(_x, _y) tool.setHandler("left_button_press", stretch_free_second_left_button_press_cb) doc.setPrompt("Click a second point to indicate the vertical distance") def stretch_free_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x2, _y2) = _da.convertPoint_fromView_(_loc, None) (_x1, _y1) = tool.getLocation() tool.setDistance((_x2 - _x1), (_y2 - _y1)) tool.setHandler("left_button_press", stretch_select_first_left_button_press_cb) tool.delHandler("entry_event") doc.setPrompt("Click on or select the points to stretch") def stretch_free_entry_event_cb(doc, text, tool): if len(text): _str = string.split(text, ",") if len(_str) != 2: raise ValueError, "Invalid distance (must be h, v): " + text _hdist = make_distance(_str[0]) _vdist = make_distance(_str[1]) tool.setDistance(_hdist, _vdist) tool.setHandler("left_button_press", stretch_select_first_left_button_press_cb) tool.delHandler("entry_event") doc.setPrompt("Click on or select the points to stretch") # # Zoom stuff # def zoom_mode_init(doc, tool): doc.setPrompt("Click in the drawing area to set the zoom location") tool.setHandler("initialize", zoom_mode_init) tool.setHandler("left_button_press", zoom_first_left_button_press_cb) def zoom_first_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() _viewLoc = _da.convertPoint_fromView_(_loc, None) tool.setFirstPoint(_viewLoc.x, _viewLoc.y) tool.setLocation(_viewLoc.x, _viewLoc.y) _da.setTempPoint(_viewLoc) tool.setHandler("left_button_press", zoom_second_left_button_press_cb) tool.setHandler("mouse_move", select_mouse_move_cb) doc.setPrompt("Move the mouse to select the zoom location") def zoom_second_left_button_press_cb(doc, event, tool): _loc = event.locationInWindow() _da = doc.getDA() (_x2, _y2) = _da.convertPoint_fromView_(_loc, None) (_x1, _y1) = tool.getFirstPoint() _x = min(_x1, _x2) _y = min(_y1, _y2) _w = abs(_x2 - _x1) _h = abs(_y2 - _y1) _da.setTempObject() _da.zoomToRect(((_x, _y), (_w, _h))) tool.reset() zoom_mode_init(doc, tool) PythonCAD-DS1-R37/PythonCAD/__init__.py0000644000175000017500000000013411307666657017072 0ustar matteomatteo# # Copyright (c) 2004 Art Haas # # # this file is needed for Python's import mechanism # PythonCAD-DS1-R37/PythonCAD/Generic/0000755000175000017500000000000011307677001016320 5ustar matteomatteoPythonCAD-DS1-R37/PythonCAD/Generic/layer.py0000644000175000017500000041555011307666732020031 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # 2009 Matteo Boscolo # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # The Layer class # import sys import types from math import pi, atan2 from PythonCAD.Generic import color from PythonCAD.Generic import linetype from PythonCAD.Generic import style from PythonCAD.Generic import point from PythonCAD.Generic import segment from PythonCAD.Generic import circle from PythonCAD.Generic import arc from PythonCAD.Generic import hcline from PythonCAD.Generic import vcline from PythonCAD.Generic import acline from PythonCAD.Generic import cline from PythonCAD.Generic import ccircle from PythonCAD.Generic import segjoint from PythonCAD.Generic import leader from PythonCAD.Generic import polyline from PythonCAD.Generic import text from PythonCAD.Generic import dimension from PythonCAD.Generic import dimtrees from PythonCAD.Generic import tolerance from PythonCAD.Generic import entity from PythonCAD.Generic import logger from PythonCAD.Generic import graphicobject from PythonCAD.Generic import units from PythonCAD.Generic import util class Layer(entity.Entity): """ The Layer class. A Layer object holds all the various entities that can be in a drawing. Each layer can have sublayers, and there is no limit to the depth of the sublayering. A Layer object has several attributes: name: The Layer's name parent: The parent Layer of the Layer scale: The scale factor for object contained in the Layer A Layer object has the following methods: {get/set}Name(): Get/Set the Layer's name. {get/set}ParentLayer(): Get/Set the Layer's parent. {add/del}Sublayer(): Add/Remove a sublayer to this Layer. hasSublayers(): Test if this Layer has sublayers. getSublayers(): Return any sublayers of this Layer. {add/del}Object(): Store/Remove a Point, Segment, etc. in the Layer. {get/set}Autosplit(): Get/Set the autosplitting state of the Layer. findObject(): Return an object in the layer equivalent to a test object. find(): Search for an object within the Layer. getObject(): Return an object with a specified ID mapPoint(): See if a non-Point object in the layer crosses some location. hasEntities(): Test if the Layer contains any entities hasEntityType(): Test if the Layer contains a particular entity type. getLayerEntities(): Return all the instances of an entity within the Layer. getBoundary(): Find the maximum and minimum coordinates of the Layer. objsInRegion(): Return all the objects in the Layer that can be seen within some view. {get/set}DeletedEntityData(): Get/Set the deleted entity values in the Layer """ __messages = { 'name_changed' : True, 'scale_changed' : True, 'added_sublayer' : True, 'deleted_sublayer' : True, } def __init__(self, name=None, **kw): """ Initializee a Layer. Layer([name) Argument name is optional. The name should be a unicode string if specified, otherwise a default name of 'Layer' is given. """ _n = name if _n is None: _n = u'Layer' if not isinstance(_n, types.StringTypes): raise TypeError, "Invalid layer name type: " + `type(name)` if isinstance(name, str): _n = unicode(name) super(Layer, self).__init__(**kw) self.__name = _n self.__points = point.PointQuadtree() self.__segments = segment.SegmentQuadtree() self.__circles = circle.CircleQuadtree() self.__arcs = arc.ArcQuadtree() self.__hclines = hcline.HCLineQuadtree() self.__vclines = vcline.VCLineQuadtree() self.__aclines = acline.ACLineQuadtree() self.__clines = cline.CLineQuadtree() self.__ccircles = ccircle.CCircleQuadtree() self.__chamfers = [] # should be Quadtree self.__fillets = [] # should be Quadtree self.__leaders = leader.LeaderQuadtree() self.__polylines = polyline.PolylineQuadtree() self.__textblocks = [] # should be Quadtree self.__ldims = dimtrees.LDimQuadtree() self.__hdims = dimtrees.HDimQuadtree() self.__vdims = dimtrees.VDimQuadtree() self.__rdims = dimtrees.RDimQuadtree() self.__adims = dimtrees.ADimQuadtree() self.__scale = 1.0 self.__parent_layer = None self.__sublayers = None self.__asplit = True # # self.__objects keeps a reference to all objects stored in the layer # self.__objects = {} self.__objids = {} self.__logs = {} def __str__(self): _p = self.__parent_layer if _p is None: _s = "Layer: %s [No Parent Layer]" % self.__name else: _s = "Layer: %s; Parent Layer: %s" % (self.__name, _p.getName()) return _s def __contains__(self, obj): """ Find an object in the Layer. This method permits the use of 'in' for test conditions. if obj in layer: .... This function tests for Point, Segment, Circle, etc. It returns True if there is an equivalent object held in the Layer. Otherwise the function returns False. """ _seen = False if id(obj) in self.__objects: _seen = True if not _seen: if isinstance(obj, point.Point): _x, _y = obj.getCoords() _seen = (len((self.__points.find(_x, _y))) > 0) elif isinstance(obj, segment.Segment): _p1, _p2 = obj.getEndpoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _seen = (len(self.__segments.find(_x1, _y1, _x2, _y2)) > 0) elif isinstance(obj, arc.Arc): _x, _y = obj.getCenter().getCoords() _r = obj.getRadius() _sa = obj.getStartAngle() _ea = obj.getEndAngle() _seen = (len(self.__arcs.find(_x, _y, _r, _sa, _ea)) > 0) elif isinstance(obj, circle.Circle): _x, _y = obj.getCenter().getCoords() _r = obj.getRadius() _seen = (len(self.__circles.find(_x, _y, _r)) > 0) elif isinstance(obj, hcline.HCLine): _y = obj.getLocation().y _seen = (len(self.__hclines.find(_y)) > 0) elif isinstance(obj, vcline.VCLine): _x = obj.getLocation().x _seen = (len(self.__vclines.find(_x)) > 0) elif isinstance(obj, acline.ACLine): _x, _y = obj.getLocation().getCoords() _angle = obj.getAngle() _seen = (len(self.__aclines.find(_x, _y, _angle)) > 0) elif isinstance(obj, cline.CLine): _p1, _p2 = obj.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _seen = (len(self.__clines.find(_x1, _y1, _x2, _y2)) > 0) elif isinstance(obj, ccircle.CCircle): _x, _y = obj.getCenter().getCoords() _r = obj.getRadius() _seen = (len(self.__ccircles.find(_x, _y, _r)) > 0) elif isinstance(obj, segjoint.Fillet): _seen = obj in self.__fillets elif isinstance(obj, segjoint.Chamfer): _seen = obj in self.__chamfers elif isinstance(obj, leader.Leader): _p1, _p2, _p3 = obj.getPoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _x3, _y3 = _p3.getCoords() _seen = (len(self.__leaders.find(_x1, _y1, _x2, _y2, _x3, _y3)) > 0) elif isinstance(obj, polyline.Polyline): _coords = [] for _pt in obj.getPoints(): _coords.extend(_pt.getCoords()) _seen = (len(self.__polylines.find(_coords)) > 0) elif isinstance(obj, text.TextBlock): _seen = obj in self.__textblocks elif isinstance(obj, dimension.HorizontalDimension): _p1, _p2 = obj.getDimPoints() _seen = (len(self.__hdims.find(_p1, _p2)) > 0) elif isinstance(obj, dimension.VerticalDimension): _p1, _p2 = obj.getDimPoints() _seen = (len(self.__vdims.find(_p1, _p2)) > 0) elif isinstance(obj, dimension.LinearDimension): _p1, _p2 = obj.getDimPoints() _seen = (len(self.__ldims.find(_p1, _p2)) > 0) elif isinstance(obj, dimension.RadialDimension): _c1 = obj.getDimCircle() _seen = (len(self.__rdims.find(_c1)) > 0) elif isinstance(obj, dimension.AngularDimension): _vp, _p1, _p2 = obj.getDimPoints() _dims = self.__adims.find(_vp, _p1, _p2) _seen = len(_dims) > 0 else: raise TypeError, "Invalid type for in operation: " + `type(obj)` return _seen def finish(self): self.__name = None self.__points = None self.__segments = None self.__circles = None self.__arcs = None self.__hclines = None self.__vclines = None self.__aclines = None self.__clines = None self.__ccircles = None self.__chamfers = None self.__fillets = None self.__leaders = None self.__polylines = None self.__textblocks = None self.__ldims = None self.__hdims = None self.__vdims = None self.__rdims = None self.__adims = None super(Layer, self).finish() def clear(self): """ Remove all the entities stored in this layer """ if self.isLocked(): raise RuntimeError, "Clearing layer not allowed - layer locked." for _obj in self.__adims.getObjects(): self.delObject(_obj) for _obj in self.__rdims.getObjects(): self.delObject(_obj) for _obj in self.__vdims.getObjects(): self.delObject(_obj) for _obj in self.__hdims.getObjects(): self.delObject(_obj) for _obj in self.__ldims.getObjects(): self.delObject(_obj) for _obj in self.__textblocks: self.delObject(_obj) for _obj in self.__polylines.getObjects(): self.delObject(_obj) for _obj in self.__leaders.getObjects(): self.delObject(_obj) for _obj in self.__chamfers: self.delObject(_obj) for _obj in self.__fillets: self.delObject(_obj) for _obj in self.__ccircles.getObjects(): self.delObject(_obj) for _obj in self.__clines.getObjects(): self.delObject(_obj) for _obj in self.__aclines.getObjects(): self.delObject(_obj) for _obj in self.__vclines.getObjects(): self.delObject(_obj) for _obj in self.__hclines.getObjects(): self.delObject(_obj) for _obj in self.__arcs.getObjects(): self.delObject(_obj) for _obj in self.__circles.getObjects(): self.delObject(_obj) for _obj in self.__segments.getObjects(): self.delObject(_obj) for _obj in self.__points.getObjects(): self.delObject(_obj) self.setScale(1.0) def getName(self): """ Return the name of the Layer. """ return self.__name def setName(self, name): """ Set the name of the Layer. The name must be a string, and cannot be None. """ _n = name if _n is None: raise ValueError, "Layers must have a name." if not isinstance(_n, types.StringTypes): raise TypeError, "Invalid name type: " + `type(_n)` if isinstance(_n, str): _n = unicode(_n) _on = self.__name if _on != _n: self.startChange('name_changed') self.__name = _n self.endChange('name_changed') self.sendMessage('name_changed', _on) self.modified() name = property(getName, setName, None, "Layer name.") def getValues(self): """ Return values comprising the Layer. This method extends the Entity::getValues() method. """ _data = super(Layer, self).getValues() _data.setValue('type', 'layer') _pid = None if self.__parent_layer is not None: _pid = self.__parent_layer.getID() _data.setValue('parent_layer', _pid) _data.setValue('name', self.__name) _data.setValue('scale', self.__scale) return _data def setDeletedEntityData(self, data): """ Fill in the deleted entity data. Argument 'data' must be a dictionary with the keys being entity id values (integers) and the dictionary values as Logger instances. """ if not isinstance(data, dict): raise TypeError, "Invalid dictionary type: " + `type(data)` if len(self.__logs) != 0: raise ValueError, "Deleted data already stored" for _key in data: if not isinstance(_key, int): raise TypeError, "Invalid entity id type: " + `type(_key)` _val = data[_key] if not isinstance(_val, logger.Logger): raise TypeError, "Invalid entity log type: " + `type(_val)` self.__logs[_key] = _val def getDeletedEntityData(self): """ Return the stored log data for deleted entities. This method returns a dictionary. """ return self.__logs.copy() def __splitObject(self, obj, pt): """ Split a Segment/Circle/Arc/Polyline on a Point in the Layer. Argument 'obj' must be a Segment, Circle, Arc, or Polyline, and argument 'pt' must be Point. Both arguments must be in stored in the Layer, and the point must lie on the entity to be split. This method is private to the Layer. """ if self.isLocked(): raise RuntimeError, "Splitting entity not allowed - layer locked." if not isinstance(obj, (segment.Segment, circle.Circle, arc.Arc, polyline.Polyline)): raise TypeError, "Invalid object: " + `type(obj)` if obj.getParent() is not self: raise ValueError, "Object not in layer: " + `obj` if not isinstance(pt, point.Point): raise TypeError, "Invalid point: " + `type(pt)` if pt.getParent() is not self: raise ValueError, "Point not in layer: " + `pt` _x, _y = pt.getCoords() _mp = obj.mapCoords(_x, _y) if _mp is None: raise RuntimeError, "Point not on object: " + `pt` _split = False _objs = [] if isinstance(obj, segment.Segment): _p1, _p2 = obj.getEndpoints() if _p1 != pt and _p2 != pt: _split = True _s = obj.getStyle() _l = obj.getLinetype() _c = obj.getColor() _t = obj.getThickness() _seg = segment.Segment(_p1, pt, _s, _l, _c, _t) self.addObject(_seg) _objs.append(_seg) _seg = segment.Segment(pt, _p2, _s, _l, _c, _t) self.addObject(_seg) _objs.append(_seg) elif isinstance(obj, (circle.Circle, arc.Arc)): _cp = obj.getCenter() _r = obj.getRadius() _s = obj.getStyle() _l = obj.getLinetype() _c = obj.getColor() _t = obj.getThickness() _angle = (180.0/pi) * atan2((_y - _cp.y),(_x - _cp.x)) if _angle < 0.0: _angle = _angle + 360.0 if isinstance(obj, circle.Circle): _split = True _arc = arc.Arc(_cp, _r, _angle, _angle, _s, _l, _c, _t) self.addObject(_arc) _objs.append(_arc) else: _ep1, _ep2 = obj.getEndpoints() if pt != _ep1 and pt != _ep2: _split = True _sa = obj.getStartAngle() _ea = obj.getEndAngle() _arc = arc.Arc(_cp, _r, _sa, _angle, _s, _l, _c, _t) self.addObject(_arc) _objs.append(_arc) _arc = arc.Arc(_cp, _r, _angle, _ea, _s, _l, _c, _t) self.addObject(_arc) _objs.append(_arc) elif isinstance(obj, polyline.Polyline): _pts = obj.getPoints() for _i in range(len(_pts) - 1): _p1x, _p1y = _pts[_i].getCoords() _p2x, _p2y = _pts[_i + 1].getCoords() _p = util.map_coords(_x, _y, _p1x, _p1y, _p2x, _p2y) if _p is None: continue _px, _py = _p if ((abs(_px - _p1x) < 1e-10 and abs(_py - _p1y) < 1e-10) or (abs(_px - _p2x) < 1e-10 and abs(_py - _p2y) < 1e-10)): continue _split = True obj.addPoint((_i + 1), pt) break else: raise TypeError, "Unexpected type: " + `type(obj)` return (_split, _objs) def setAutosplit(self, autoSplit): """ Set the autosplit state of the Layer. Argument 'autoSplit' must be a Boolean. """ util.test_boolean(autoSplit) self.__asplit = autoSplit def getAutosplit(self): """ Retrieve the autosplit state of the Layer. This method returns a Boolean. """ return self.__asplit def addObject(self, obj): """ Add an object to this Layer. The object should be a Point, Segment, Arc, Circle, HCLine, VCLine, ACLine, CLine, CCircle, TextBlock, Chamfer, Fillet, Leader, Polyline, or Dimension. Anything else raises a TypeError exception. """ if self.isLocked(): raise RuntimeError, "Adding entity not allowed - layer locked." if id(obj) in self.__objects: return if isinstance(obj, point.Point): _res = self.__addPoint(obj) elif isinstance(obj, segment.Segment): _res = self.__addSegment(obj) elif isinstance(obj, arc.Arc): _res = self.__addArc(obj) elif isinstance(obj, circle.Circle): _res = self.__addCircle(obj) elif isinstance(obj, hcline.HCLine): _res = self.__addHCLine(obj) elif isinstance(obj, vcline.VCLine): _res = self.__addVCLine(obj) elif isinstance(obj, acline.ACLine): _res = self.__addACLine(obj) elif isinstance(obj, ccircle.CCircle): _res = self.__addCCircle(obj) elif isinstance(obj, cline.CLine): _res = self.__addCLine(obj) elif isinstance(obj, segjoint.Chamfer): _res = self.__addChamfer(obj) elif isinstance(obj, segjoint.Fillet): _res = self.__addFillet(obj) elif isinstance(obj, leader.Leader): _res = self.__addLeader(obj) elif isinstance(obj, polyline.Polyline): _res = self.__addPolyline(obj) elif isinstance(obj, text.TextBlock): _res = self.__addTextBlock(obj) elif isinstance(obj, dimension.AngularDimension): _res = self.__addAngularDimension(obj) elif isinstance(obj, dimension.RadialDimension): _res = self.__addRadialDimension(obj) elif isinstance(obj, dimension.HorizontalDimension): _res = self.__addHorizontalDimension(obj) elif isinstance(obj, dimension.VerticalDimension): _res = self.__addVerticalDimension(obj) elif isinstance(obj, dimension.LinearDimension): _res = self.__addLinearDimension(obj) else: raise TypeError, "Invalid object type for storage: " + `type(obj)` if _res: # # call setParent() before connecting to layer log (if # it exists) so that the log will not recieve a 'modified' # message ... # self.__objects[id(obj)] = obj _oid = obj.getID() self.__objids[_oid] = obj obj.setParent(self) _log = obj.getLog() if _log is not None: # make this an error? _oldlog = self.__logs.get(_oid) if _oldlog is not None: # re-attach old log _log.transferData(_oldlog) del self.__logs[_oid] if isinstance(obj, dimension.Dimension): _ds1, _ds2 = obj.getDimstrings() _oid = _ds1.getID() _log = _ds1.getLog() if _log is not None: _oldlog = self.__logs.get(_oid) if _oldlog is not None: _log.transferData(_oldlog) del self.__logs[_oid] _oid = _ds2.getID() _log = _ds2.getLog() if _log is not None: _oldlog = self.__logs.get(_oid) if _oldlog is not None: _log.transferData(_oldlog) del self.__logs[_oid] # # Automatically split a segment, circle, arc, or # polyline if a point was added and the autosplit # flag is True # if (isinstance(obj, point.Point) and self.__asplit is True and not self.inUndo() and not self.inRedo()): _x, _y = obj.getCoords() _types = {'segment' : True, 'circle' : True, 'arc' : True, 'polyline' : True} _hits = self.mapCoords(_x, _y, types=_types) if len(_hits) > 0: for _mobj, _mpt in _hits: _split, _sobjs = self.__splitObject(_mobj, obj) if _split and len(_sobjs): self.delObject(_mobj) # # Reset the autosplit flag to True # self.__asplit = True def __addPoint(self, p): """ Add a Point object to the Layer. This method is private to the Layer object. """ self.__points.addObject(p) if p.getLog() is None: _log = point.PointLog(p) p.setLog(_log) return True def __addSegment(self, s): """ Add a Segment object to the Layer. This method is private to the Layer object. """ _p1, _p2 = s.getEndpoints() if id(_p1) not in self.__objects: raise ValueError, "Segment p1 Point not found in Layer." if id(_p2) not in self.__objects: raise ValueError, "Segment p2 Point not found in Layer." self.__segments.addObject(s) if s.getLog() is None: _log = segment.SegmentLog(s) s.setLog(_log) return True def __addCircle(self, c): """ Add a Circle object to the Layer. This method is private to the layer object. """ _cp = c.getCenter() if id(_cp) not in self.__objects: raise ValueError, "Circle center Point not found in Layer." self.__circles.addObject(c) if c.getLog() is None: _log = circle.CircleLog(c) c.setLog(_log) return True def __addArc(self, a): """ Add an Arc object to the Layer. This method is private to the Layer object. """ _cp = a.getCenter() if id(_cp) not in self.__objects: raise ValueError, "Arc center Point not found in Layer." self.__arcs.addObject(a) if a.getLog() is None: _log = arc.ArcLog(a) a.setLog(_log) for _ex, _ey in a.getEndpoints(): _pts = self.__points.find(_ex, _ey) if len(_pts) == 0: _lp = point.Point(_ex, _ey) self.addObject(_lp) else: _lp = _pts.pop() _max = _lp.countUsers() for _pt in _pts: _count = _pt.countUsers() if _count > _max: _max = _count _lp = _pt _lp.storeUser(a) if abs(a.getStartAngle() - a.getEndAngle()) < 1e-10: break return True def __addHCLine(self, hcl): """ Add an HCLine object to the Layer. This method is private to the Layer object. """ _lp = hcl.getLocation() if id(_lp) not in self.__objects: raise ValueError, "HCLine location Point not found in Layer." self.__hclines.addObject(hcl) if hcl.getLog() is None: _log = hcline.HCLineLog(hcl) hcl.setLog(_log) return True def __addVCLine(self, vcl): """ Add an VCLine object to the Layer. This method is private to the Layer object. """ _lp = vcl.getLocation() if id(_lp) not in self.__objects: raise ValueError, "VCLine location Point not found in Layer." self.__vclines.addObject(vcl) if vcl.getLog() is None: _log = vcline.VCLineLog(vcl) vcl.setLog(_log) return True def __addACLine(self, acl): """ Add an ACLine object to the Layer. This method is private to the Layer object. """ _lp = acl.getLocation() if id(_lp) not in self.__objects: raise ValueError, "ACLine location Point not found in Layer." self.__aclines.addObject(acl) if acl.getLog() is None: _log = acline.ACLineLog(acl) acl.setLog(_log) return True def __addCCircle(self, cc): """ Add an CCircle object to the Layer. This method is private to the Layer object. """ _cp = cc.getCenter() if id(_cp) not in self.__objects: raise ValueError, "CCircle center Point not found in Layer." self.__ccircles.addObject(cc) if cc.getLog() is None: _log = ccircle.CCircleLog(cc) cc.setLog(_log) return True def __addCLine(self, cl): """Add an CLine object to the Layer. _addCLine(cl) This method is private to the Layer object. """ _p1, _p2 = cl.getKeypoints() if id(_p1) not in self.__objects: raise ValueError, "CLine p1 Point not found in Layer." if id(_p2) not in self.__objects: raise ValueError, "CLine p2 Point not found in Layer." self.__clines.addObject(cl) if cl.getLog() is None: _log = cline.CLineLog(cl) cl.setLog(_log) return True def __addChamfer(self, ch): """Add a Chamfer object to the Layer. _addChamfer(ch) This method is private to the Layer object. """ _s1, _s2 = ch.getSegments() if id(_s1) not in self.__objects: raise ValueError, "Chamfer s1 Segment not found in Layer." if id(_s2) not in self.__objects: raise ValueError, "Chamfer s2 Segment not found in Layer." self.__chamfers.append(ch) if ch.getLog() is None: _log = segjoint.ChamferLog(ch) ch.setLog(_log) return True def __addFillet(self, f): """Add a Fillet object to the Layer. _addFillet(f) This method is private to the Layer object. """ _s1, _s2 = f.getSegments() if id(_s1) not in self.__objects: raise ValueError, "Fillet s1 Segment not found in Layer." if id(_s2) not in self.__objects: raise ValueError, "Fillet s2 Segment not found in Layer." self.__fillets.append(f) if f.getLog() is None: _log = segjoint.FilletLog(f) f.setLog(_log) return True def __addLeader(self, l): """Add a Leader object to the Layer. _addLeader(l) This method is private to the Layer object. """ _p1, _p2, _p3 = l.getPoints() if id(_p1) not in self.__objects: raise ValueError, "Leader p1 Point not found in Layer." if id(_p2) not in self.__objects: raise ValueError, "Leader p2 Point not found in Layer." if id(_p3) not in self.__objects: raise ValueError, "Leader p3 Point not found in Layer." self.__leaders.addObject(l) if l.getLog() is None: _log = leader.LeaderLog(l) l.setLog(_log) return True def __addPolyline(self, pl): """Add a Polyline object to the Layer. _addPolyline(pl) This method is private to the Layer object. """ for _pt in pl.getPoints(): if id(_pt) not in self.__objects: raise ValueError, "Polyline point not in layer: " + str(_pt) self.__polylines.addObject(pl) if pl.getLog() is None: _log = polyline.PolylineLog(pl) pl.setLog(_log) return True def __addTextBlock(self, tb): """Add a TextBlock object to the Layer. _addTextBlock(tb) The TextBlock object 'tb' is added to the layer if there is not already a TextBlock in the layer at the same location and with the same text. """ self.__textblocks.append(tb) if tb.getLog() is None: _log = text.TextBlockLog(tb) tb.setLog(_log) return True def __addAngularDimension(self, adim): """Add an AngularDimension object to the Layer. _addAngularDimension(adim) This method is private to the Layer object. """ _p1, _p2, _p3 = adim.getDimPoints() if _p1.getParent() is None: raise ValueError, "Dimension Point P1 not found in a Layer" if _p2.getParent() is None: raise ValueError, "Dimension Point P2 not found in a Layer!" if _p3.getParent() is None: raise ValueError, "Dimension Point P3 not found in a Layer!" self.__adims.addObject(adim) if adim.getLog() is None: _log = dimension.DimLog(adim) adim.setLog(_log) _ds1, _ds2 = adim.getDimstrings() _log = dimension.DimStringLog(_ds1) _ds1.setLog(_log) _log = dimension.DimStringLog(_ds2) _ds2.setLog(_log) return True def __addRadialDimension(self, rdim): """Add a RadialDimension object to the Layer. _addRadialDimension(rdim) This method is private to the Layer object. """ _dc = rdim.getDimCircle() if _dc.getParent() is None: raise ValueError, "RadialDimension circular object not found in a Layer" self.__rdims.addObject(rdim) if rdim.getLog() is None: _log = dimension.DimLog(rdim) rdim.setLog(_log) _ds1, _ds2 = rdim.getDimstrings() _log = dimension.DimStringLog(_ds1) _ds1.setLog(_log) _log = dimension.DimStringLog(_ds2) _ds2.setLog(_log) return True def __addHorizontalDimension(self, hdim): """Add a HorizontalDimension object to the Layer. _addHorizontalDimension(hdim) This method is private to the Layer object. """ _p1, _p2 = hdim.getDimPoints() if _p1.getParent() is None: raise ValueError, "HorizontalDimension Point P1 not found in layer" if _p1.getParent() is None: raise ValueError, "HorizontalDimension Point P2 not found in layer" self.__hdims.addObject(hdim) if hdim.getLog() is None: _log = dimension.DimLog(hdim) hdim.setLog(_log) _ds1, _ds2 = hdim.getDimstrings() _log = dimension.DimStringLog(_ds1) _ds1.setLog(_log) _log = dimension.DimStringLog(_ds2) _ds2.setLog(_log) return True def __addVerticalDimension(self, vdim): """Add a VerticalDimension object to the Layer. _addVerticalDimension(vdim) This method is private to the Layer object. """ _p1, _p2 = vdim.getDimPoints() if _p1.getParent() is None: raise ValueError, "VerticalDimension Point P1 not found in layer" if _p2.getParent() is None: raise ValueError, "VerticalDimension Point P2 not found in layer" self.__vdims.addObject(vdim) if vdim.getLog() is None: _log = dimension.DimLog(vdim) vdim.setLog(_log) _ds1, _ds2 = vdim.getDimstrings() _log = dimension.DimStringLog(_ds1) _ds1.setLog(_log) _log = dimension.DimStringLog(_ds2) _ds2.setLog(_log) return True def __addLinearDimension(self, ldim): """Add a LinearDimension object to the Layer. _addLinearDimension(ldim) This method is private to the Layer object. """ _p1, _p2 = ldim.getDimPoints() if _p1.getParent() is None: raise ValueError, "LinearDimension Point P1 not found in layer" if _p2.getParent() is None: raise ValueError, "LinearDimension Point P2 not found in layer" self.__ldims.addObject(ldim) if ldim.getLog() is None: _log = dimension.DimLog(ldim) ldim.setLog(_log) _ds1, _ds2 = ldim.getDimstrings() _log = dimension.DimStringLog(_ds1) _ds1.setLog(_log) _log = dimension.DimStringLog(_ds2) _ds2.setLog(_log) return True def delObject(self, obj): """Remove an object from this Layer. delObject(obj) The object should be a Point, Segment, Arc, Circle, HCLine, VCLine, ACLine, CLine, CCircle, Chamfer, Fillet, Leader, or Dimension. Anything else raises a TypeError exception. """ if self.isLocked(): raise RuntimeError, "Deleting entity not allowed - layer locked." if id(obj) not in self.__objects: raise ValueError, "Object not found in layer: " + `obj` if isinstance(obj, point.Point): self.__delPoint(obj) elif isinstance(obj, segment.Segment): self.__delSegment(obj) elif isinstance(obj, arc.Arc): self.__delArc(obj) elif isinstance(obj, circle.Circle): self.__delCircle(obj) elif isinstance(obj, hcline.HCLine): self.__delHCLine(obj) elif isinstance(obj, vcline.VCLine): self.__delVCLine(obj) elif isinstance(obj, acline.ACLine): self.__delACLine(obj) elif isinstance(obj, cline.CLine): self.__delCLine(obj) elif isinstance(obj, ccircle.CCircle): self.__delCCircle(obj) elif isinstance(obj, segjoint.Chamfer): self.__delChamfer(obj) elif isinstance(obj, segjoint.Fillet): self.__delFillet(obj) elif isinstance(obj, leader.Leader): self.__delLeader(obj) elif isinstance(obj, polyline.Polyline): self.__delPolyline(obj) elif isinstance(obj, text.TextBlock): self.__delTextBlock(obj) elif isinstance(obj, dimension.AngularDimension): self.__delAngularDimension(obj) elif isinstance(obj, dimension.RadialDimension): self.__delRadialDimension(obj) elif isinstance(obj, dimension.HorizontalDimension): self.__delHorizontalDimension(obj) elif isinstance(obj, dimension.VerticalDimension): self.__delVerticalDimension(obj) elif isinstance(obj, dimension.LinearDimension): self.__delLinearDimension(obj) else: raise TypeError, "Invalid object type for removal: " + `type(obj)` def __freeObj(self, obj): # # disconnect object before calling setParent() so that # the layer log will not recieve a 'modified' message # from the object ... # del self.__objects[id(obj)] _oid = obj.getID() del self.__objids[_oid] if isinstance(obj, dimension.Dimension): _ds1, _ds2 = obj.getDimstrings() _log = _ds1.getLog() if _log is not None: _oid = _ds1.getID() self.__logs[_oid] = _log _log = _ds2.getLog() if _log is not None: _oid = _ds2.getID() self.__logs[_oid] = _log _log = obj.getLog() if _log is not None: # store the object's log _log.detatch() self.__logs[_oid] = _log obj.setLog(None) _log = self.getLog() if _log is not None: obj.disconnect(_log) obj.setParent(None) def __delPoint(self, p): """Delete a Point from the Layer. _delPoint(p) This method is private to the Layer object. """ _delete = True _users = p.getUsers() for _user in _users: if not isinstance(_user, dimension.Dimension): _delete = False break if _delete: for _user in _users: _layer = _user.getParent() if _layer is self: if not self.inUndo() and not self.inRedo(): self.delObject(_user) else: p.disconnect(_user) p.freeUser(_user) elif _layer is not None: if not isinstance(_user, dimension.Dimension): raise RuntimeError, "Point " + `p` + " bound to non-layer object: " + `_user` if not self.inUndo() and not self.inRedo(): _layer.delObject(_user) else: p.disconnect(_user) p.freeUser(_user) else: pass self.__points.delObject(p) self.__freeObj(p) p.finish() def __delSegment(self, s): """Delete a Segment from the Layer. _delSegment(s) This method is private to the Layer object. """ for _user in s.getUsers(): # chamfers, fillets, or hatching _layer = _user.getParent() if _layer is self: if not self.inUndo() and not self.inRedo(): self.delObject(_user) # restore segments on ch/fl? else: s.freeUser(_user) s.disconnect(_user) elif _layer is not None: raise RuntimeError, "Segment " + `s` + " bound to non-layer object: " + `_user` else: pass _p1, _p2 = s.getEndpoints() assert id(_p1) in self.__objects, "Segment p1 Point not in objects" assert id(_p2) in self.__objects, "Segment p2 Point not in objects" self.__segments.delObject(s) self.__freeObj(s) s.finish() if not self.inUndo() and not self.inRedo(): self.delObject(_p1) # remove possibly unused point _p1 self.delObject(_p2) # remove possibly unused point _p2 def __delCircle(self, c): """Delete a Circle from the Layer. _delCircle(c) This method is private to the Layer object. """ assert not isinstance(c, arc.Arc), "Arc in _delCircle()" for _user in c.getUsers(): # dimensions or hatching _layer = _user.getParent() if _layer is self: if not self.inUndo() and not self.inRedo(): self.delObject(_user) else: c.freeUser(_user) c.disconnect(_user) elif _layer is not None: if not isinstance(_user, dimension.Dimension): raise RuntimeError, "Circle " + `c` + " bound to non-layer object: " + `_user` if not self.inUndo() and not self.inRedo(): _layer.delObject(_user) else: c.freeUser(_user) c.disconnect(_user) else: pass _cp = c.getCenter() assert id(_cp) in self.__objects, "Circle center point not in objects" self.__circles.delObject(c) self.__freeObj(c) c.finish() if not self.inUndo() and not self.inRedo(): self.delObject(_cp) # remove possibly unused point _cp def __delArc(self, a): """Delete an Arc from the Layer. _delArc(a) This method is private to the Layer object. """ for _user in a.getUsers(): # dimensions or hatching _layer = _user.getParent() if _layer is self: if not self.inUndo() and not self.inRedo(): self.delObject(_user) else: a.freeUser(_user) a.disconnect(_user) elif _layer is not None: if not isinstance(_user, dimension.Dimension): raise RuntimeError, "Arc " + `a` + " bound to non-layer object: " + `_user` if not self.inUndo() and not self.inRedo(): _layer.delObject(_user) else: a.freeUser(_user) a.disconnect(_user) else: pass _cp = a.getCenter() assert id(_cp) in self.__objects, "Arc center point not in objects" self.__arcs.delObject(a) self.__freeObj(a) for _ep in a.getEndpoints(): _pts = self.find('point', _ep[0], _ep[1]) _p = None for _pt in _pts: for _user in _pt.getUsers(): if _user is a: _p = _pt break if _p is not None: break assert _p is not None, "Arc endpoint not found in layer" assert id(_p) in self.__objects, "Arc endpoint not in objects" _p.disconnect(a) _p.freeUser(a) if not self.inUndo() and not self.inRedo(): self.delObject(_p) # remove possibly unused point _p if abs(a.getStartAngle() - a.getEndAngle()) < 1e-10: break a.finish() if not self.inUndo() and not self.inRedo(): self.delObject(_cp) # remove possibly unused point _cp def __delHCLine(self, hcl): """Remove a HCLine object from the Layer. _delHCLine(hcl) This method is private to the Layer object. """ _lp = hcl.getLocation() assert id(_lp) in self.__objects, "HCLine point not in objects" self.__hclines.delObject(hcl) self.__freeObj(hcl) hcl.finish() if not self.inUndo() and not self.inRedo(): self.delObject(_lp) # remove possibly unused point _lp def __delVCLine(self, vcl): """Remove a VCLine object from the Layer. _delVCLine(vcl) This method is private to the Layer object. """ _lp = vcl.getLocation() assert id(_lp) in self.__objects, "VCLine point not in objects" self.__vclines.delObject(vcl) self.__freeObj(vcl) vcl.finish() if not self.inUndo() and not self.inRedo(): self.delObject(_lp) # remove possibly unused point _lp def __delACLine(self, acl): """Remove an ACLine object from the Layer. _delACLine(acl) This method is private to the Layer object. """ _lp = acl.getLocation() assert id(_lp) in self.__objects, "ACLine point not in objects" self.__aclines.delObject(acl) self.__freeObj(acl) acl.finish() if not self.inUndo() and not self.inRedo(): self.delObject(_lp) # remove possibly unused point _lp def __delCLine(self, cl): """Delete a CLine from the Layer. _delCLine(cl) This method is private to the Layer object. """ _p1, _p2 = cl.getKeypoints() assert id(_p1) in self.__objects, "CLine point p1 not in objects" assert id(_p2) in self.__objects, "CLine point p2 not in objects" self.__clines.delObject(cl) self.__freeObj(cl) cl.finish() if not self.inUndo() and not self.inRedo(): self.delObject(_p1) # remove possibly unused point _p1 self.delObject(_p2) # remove possibly unused point _p2 def __delCCircle(self, cc): """Delete a CCircle from the Layer. _delCCircle(cc) This method is private to the Layer object. """ _cp = cc.getCenter() assert id(_cp) in self.__objects, "CCircle center point not in objects" self.__ccircles.delObject(cc) self.__freeObj(cc) cc.finish() if not self.inUndo() and not self.inRedo(): self.delObject(_cp) # remove possibly unused point _cp def __delChamfer(self, ch): """Remove a Chamfer from the Layer. _delChamfer(ch) This method is private to the Layer. """ _chamfers = self.__chamfers _idx = None for _i in range(len(_chamfers)): if ch is _chamfers[_i]: _idx = _i break assert _idx is not None, "lost chamfer from list" for _user in ch.getUsers(): # could be hatching ... _layer = _user.getParent() if _layer is self: if not self.inUndo() and not self.inRedo(): self.delObject(_user) else: ch.freeUser(_user) ch.disconnect(_user) elif _layer is not None: raise RuntimeError, "Chamfer " + `ch` + " bound to non-layer object: " + `_user` else: pass _s1, _s2 = ch.getSegments() assert id(_s1) in self.__objects, "Chamfer s1 segment not in objects" assert id(_s2) in self.__objects, "Chamfer s2 segment not in objects" del _chamfers[_idx] # restore the things the chamfer connects? self.__freeObj(ch) ch.finish() def __delFillet(self, fl): """Remove a Fillet from the Layer. _delFillet(fl) This method is private to the Layer. """ _fillets = self.__fillets _idx = None for _i in range(len(_fillets)): if fl is _fillets[_i]: _idx = _i break assert _idx is not None, "lost fillet from list" for _user in fl.getUsers(): # could be hatching ... _layer = _user.getParent() if _layer is self: if not self.inUndo() and not self.inRedo(): self.delObject(_user) else: fl.freeUser(_user) fl.disconnect(_user) elif _layer is not None: raise RuntimeError, "Fillet " + `fl` + " bound to non-layer object: " + `_user` else: pass _s1, _s2 = fl.getSegments() assert id(_s1) in self.__objects, "Fillet s1 segment not in objects" assert id(_s2) in self.__objects, "Fillet s2 segment not in objects" del _fillets[_idx] # restore the things the fillet connects? self.__freeObj(fl) fl.finish() def __delLeader(self, l): """Delete a Leader from the Layer. _delLeader(l, f) This method is private to the Layer object. """ _p1, _p2, _p3 = l.getPoints() assert id(_p1) in self.__objects, "Leader p1 Point not in objects" assert id(_p2) in self.__objects, "Leader p2 Point not in objects" assert id(_p3) in self.__objects, "Leader p3 Point not in objects" self.__leaders.delObject(l) self.__freeObj(l) l.finish() if not self.inUndo() and not self.inRedo(): self.delObject(_p1) # remove possibly unused point _p1 self.delObject(_p2) # remove possibly unused point _p2 self.delObject(_p3) # remove possibly unused point _p3 def __delPolyline(self, pl): """Delete a Polyline from the Layer. _delPolyline(pl, f) This method is private to the Layer object. """ for _user in pl.getUsers(): # could be hatching _layer = _user.getParent() if _layer is self: if not self.inUndo() and not self.inRedo(): self.delObject(_user) else: pl.freeUser(_user) pl.disconnect(_user) elif _layer is not None: raise RuntimeError, "Polyline " + `pl` + " bound to non-layer object: " + `_user` else: pass _pts = pl.getPoints() for _pt in _pts: assert id(_pt) in self.__objects, "Polyline point not in objects" self.__polylines.delObject(pl) self.__freeObj(pl) pl.finish() if not self.inUndo() and not self.inRedo(): for _pt in _pts: self.delObject(_pt) # remove possibly unused point _pt def __delTextBlock(self, tb): """Delete a TextBlock from the Layer. _delTextBlock(tb) This method is private to the Layer object. """ _tbs = self.__textblocks _idx = None for _i in range(len(_tbs)): if tb is _tbs[_i]: _idx = _i break assert _idx is not None, "lost textblock in list" del _tbs[_idx] self.__freeObj(tb) tb.finish() def __delAngularDimension(self, adim): """Delete an AngularDimension from the Layer. _delAngularDimension(adim, f) This method is private to the Layer object. """ _p1, _p2, _p3 = adim.getDimPoints() if _p1.getParent() is self: assert id(_p1) in self.__objects, "ADim P1 not in objects" if _p2.getParent() is self: assert id(_p2) in self.__objects, "ADim P2 not in objects" if _p3.getParent() is self: assert id(_p3) in self.__objects, "ADim P3 not in objects" self.__adims.delObject(adim) self.__freeObj(adim) adim.finish() def __delRadialDimension(self, rdim): """Delete a RadialDimension from the Layer. _delRadialDimension(rdim, f) This method is private to the Layer object. """ _circ = rdim.getDimCircle() if _circ.getParent() is self: assert id(_circ) in self.__objects, "RDim circle not in objects" self.__rdims.delObject(rdim) self.__freeObj(rdim) rdim.finish() def __delHorizontalDimension(self, hdim): """Delete an HorizontalDimension from the Layer. _delHorizontalDimension(hdim, f) This method is private to the Layer object. """ _p1, _p2 = hdim.getDimPoints() if _p1.getParent() is self: assert id(_p1) in self.__objects, "HDim P1 not in objects" if _p2.getParent() is self: assert id(_p2) in self.__objects, "HDim P2 not in objects" self.__hdims.delObject(hdim) self.__freeObj(hdim) hdim.finish() def __delVerticalDimension(self, vdim): """Delete an VerticalDimension from the Layer. _delVerticalDimension(vdim, f) This method is private to the Layer object. """ _p1, _p2 = vdim.getDimPoints() if _p1.getParent() is self: assert id(_p1) in self.__objects, "VDim P1 not in objects" if _p2.getParent() is self: assert id(_p2) in self.__objects, "VDim P2 not in objects" self.__vdims.delObject(vdim) self.__freeObj(vdim) vdim.finish() def __delLinearDimension(self, ldim): """Delete an LinearDimension from the Layer. _delLinearDimension(ldim, f) This method is private to the Layer object. """ _p1, _p2 = ldim.getDimPoints() if _p1.getParent() is self: assert id(_p1) in self.__objects, "LDim P1 not in objects" if _p2.getParent() is self: assert id(_p2) in self.__objects, "LDim P2 not in objects" self.__ldims.delObject(ldim) self.__freeObj(ldim) ldim.finish() def getObject(self, eid): """ Return an object of with a specified entity ID. Argument eid is an entity ID. """ return self.__objids.get(eid) def hasObject(self, eid): """ Argument eid is an entity ID. """ return eid in self.__objids def findObject(self, obj): """ Return an object in the layer that is equivalent to a test object. This method returns None if a suitable object is not found. """ _retobj = None if id(obj) in self.__objects: _retobj = obj else: _objs = [] if isinstance(obj, point.Point): _x, _y = obj.getCoords() _objs.extend(self.__points.find(_x, _y)) elif isinstance(obj, segment.Segment): _p1, _p2 = obj.getEndpoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _objs.extend(self.__segments.find(_x1, _y1, _x2, _y2)) elif isinstance(obj, arc.Arc): _x, _y = obj.getCenter().getCoords() _r = obj.getRadius() _sa = obj.getStartAngle() _ea = obj.getEndAngle() _objs.extend(self.__arcs.find(_x, _y, _r, _sa, _ea)) elif isinstance(obj, circle.Circle): _x, _y = obj.getCenter().getCoords() _r = obj.getRadius() _objs.extend(self.__circles.find(_x, _y, _r)) elif isinstance(obj, hcline.HCLine): _y = obj.getLocation().y _objs.extend(self.__hclines.find(_y)) elif isinstance(obj, vcline.VCLine): _x = obj.getLocation().x _objs.extend(self.__vclines.find(_x)) elif isinstance(obj, acline.ACLine): _x, _y = obj.getLocation().getCoords() _angle = obj.getAngle() _objs.extend(self.__aclines.find(_x, _y, _angle)) elif isinstance(obj, cline.CLine): _p1, _p2 = obj.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _objs.extend(self.__clines.find(_x1, _y1, _x2, _y2)) elif isinstance(obj, ccircle.CCircle): _x, _y = obj.getCenter().getCoords() _r = obj.getRadius() _objs.extend(self.__ccircles.find(_x, _y, _r)) elif isinstance(obj, segjoint.Fillet): for _f in self.__fillets: if _f is obj: _retobj = _f break elif isinstance(obj, segjoint.Chamfer): for _c in self.__chamfers: if _c == obj: _retobj = _f break elif isinstance(obj, leader.Leader): _p1, _p2, _p3 = obj.getPoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _x3, _y3 = _p3.getCoords() _objs.extend(self.__leaders.find(_x1, _y1, _x2, _y2, _x3, _y3)) elif isinstance(obj, polyline.Polyline): _coords = [] for _pt in obj.getPoints(): _coords.append(_pt.getCoords()) _objs.extend(self.__polylines.find(_coords)) elif isinstance(obj, text.TextBlock): for _tb in self.__textblocks: if _tb == obj: _retobj = _f break elif isinstance(obj, dimension.HorizontalDimension): _p1, _p2 = obj.getDimPoints() _objs.extend(self.__hdims.find(_p1, _p2)) elif isinstance(obj, dimension.VerticalDimension): _p1, _p2 = obj.getDimPoints() _objs.extend(self.__vdims.find(_p1, _p2)) elif isinstance(obj, dimension.LinearDimension): _p1, _p2 = obj.getDimPoints() _objs.extend(self.__ldims.find(_p1, _p2)) elif isinstance(obj, dimension.RadialDimension): _c1 = obj.getDimCircle() _objs.extend(self.__rdims.find(_c1)) elif isinstance(obj, dimension.AngularDimension): _vp, _p1, _p2 = obj.getDimPoints() _objs.extend(self.__adims.find(_vp, _p1, _p2)) else: raise TypeError, "Invalid object type: " + `type(obj)` if _retobj is not None: for _obj in _objs: if _obj is obj: _retobj = _obj break return _retobj def find(self, typestr, *args): """ Find an existing entity in the drawing. typestr: A string giving the type of entity to find *args: A variable number of arguments used for searching """ if not isinstance(typestr, str): raise TypeError, "Invalid type string: " + `type(typestr)` _objs = [] if typestr == 'point': _objs.extend(self.__points.find(*args)) elif typestr == 'segment': _objs.extend(self.__segments.find(*args)) elif typestr == 'circle': _objs.extend(self.__circles.find(*args)) elif typestr == 'arc': _objs.extend(self.__arcs.find(*args)) elif typestr == 'hcline': _objs.extend(self.__hclines.find(*args)) elif typestr == 'vcline': _objs.extend(self.__vclines.find(*args)) elif typestr == 'acline': _objs.extend(self.__aclines.find(*args)) elif typestr == 'cline': _objs.extend(self.__clines.find(*args)) elif typestr == 'ccircle': _objs.extend(self.__ccircles.find(*args)) elif typestr == 'leader': _objs.extend(self.__leaders.find(*args)) elif typestr == 'polyline': _objs.extend(self.__polylines.find(*args)) elif typestr == 'ldim': _objs.extend(self.__ldims.find(*args)) elif typestr == 'hdim': _objs.extend(self.__hdims.find(*args)) elif typestr == 'vdim': _objs.extend(self.__vdims.find(*args)) elif typestr == 'rdim': _objs.extend(self.__rdims.find(*args)) elif typestr == 'adim': _objs.extend(self.__adims.find(*args)) else: raise ValueError, "Unexpected type string '%s'" % typestr return _objs def mapPoint(self, p, tol=tolerance.TOL, count=2): """ Find a Point in the layer There is a single required argument: p: Either a Point object or a tuple of two-floats There are two optional arguments: tol: A float equal or greater than 0 for distance tolerance comparisons. count: An integer value indicating the largest number of objects to return. By default this value is 2. Setting 'count' to None or a negative value will result in the maximum number of objects being unlimited. This method tests the objects in the Layer to see if the Point can be mapped on to any of them. The returned list consists of tuples in the form: (obj, pt) Where 'obj' is the object the point was mapped to and 'pt' is the projected point on the object. """ _hits = [] _p = p if not isinstance(_p, point.Point): _p = point.Point(p) _t = tolerance.toltest(tol) _count = count if _count is None: _count = sys.maxint else: if not isinstance(_count, int): _count = int(count) if _count < 0: _count = sys.maxint if _count < 1: # bail out, but why set count to this value? return _hits _x, _y = _p.getCoords() _xmin = _x - _t _xmax = _x + _t _ymin = _y - _t _ymax = _y + _t # # scan for non-point objects first, then look at points, # because there will not be any way the same object can # be found in differnt trees/lists # for _obj in self.__segments.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__circles.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__arcs.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__hclines.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__vclines.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__aclines.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__ccircles.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__clines.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__leaders.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__polylines.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__ldims.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__hdims.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__vdims.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__rdims.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits for _obj in self.__adims.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pts = self.__points.find(_px, _py) if len(_pts) == 0: _pts.append(point.Point(_px, _py)) for _pt in _pts: _hits.append((_obj, _pt)) if len(_hits) == _count: return _hits # # scan for point, but do not append any object that # has already been added to the hit list # _objs = {} for _obj, _pt in _hits: _objs[id(_obj)] = True _pts = self.find('point', _x, _y, _t) if len(_pts) != 0: for _pt in _pts: assert id(_pt) in self.__objects, "Point not in objects" for _user in _pt.getUsers(): _uid = id(_user) if _uid not in _objs: _objs[_uid] = True _hits.append((_user, _pt)) if len(_hits) == _count: break return _hits def mapCoords(self, x, y, **kw): """ Find objects at coordinates in the Layer. Arguments 'x' and 'y' are mandatory and should be float values. Non-float values will be converted to that type if possible. There are several optional keyword arguments: tolerance: A float equal or greater than 0 for distance tolerance comparisons. count: An integer value indicating the largest number of objects to return. By default this value is the sys.maxint value, essentially making the count unlimited. types: A dictionary containing key/value pairs. If any key is given a value of 'True', only types for keys with 'True' values are examined. If any key is given a 'False' value, the type corresponding to that key is skipped. This method tests the objects in the Layer to see if the specified x/y coordiantes can can be mapped on to any of them. The returned list consists of tuples in the form:(obj, {var}) Where 'obj' is the object the point was mapped to and '{var}' is either an existing Point in the Layer or a tuple of the form (x, y) giving the coordinates where a new Point can be added. """ # # utility function for testing whether or not an entity type # is to be examined # def _test_entity(tdict, skip, etype): _rv = True if tdict is not None: if skip is True: if not tdict.has_key(etype) or tdict[etype] is not True: _rv = False else: if tdict.has_key(etype) and tdict[etype] is False: _rv = False return _rv _x = util.get_float(x) _y = util.get_float(y) _t = 1e-10 _types = None _skip = False _count = sys.maxint if 'tolerance' in kw: _val = util.get_float(kw['tolerance']) if _val < 0.0: raise ValueError, "Invalid negative tolerance: %f" % _val _t = _val if 'count' in kw: _val = kw['count'] if not isinstance(_val, int): _val = int(kw['count']) if _val < 0: raise ValueError, "Invalid negative entity count %d" % _val if 'types' in kw: _val = kw['types'] if not isinstance(_val, dict): raise TypeError, "Invalid 'types' dictionary: " + `type(_val)` for _k, _v in _val.items(): if not isinstance(_k, str): raise TypeError, "Invalid key %s type: %s " (str(_k), `type(_k)`) util.test_boolean(_v) if _skip is False and _v is True: _skip = True _types = _val _hits = [] if _count == 0: return _hits _xmin = _x - _t _xmax = _x + _t _ymin = _y - _t _ymax = _y + _t # # start testing entities # if _test_entity(_types, _skip, 'point'): _pts = self.__points.getInRegion(_xmin, _ymin, _xmax, _ymax) if len(_pts): _plist = [] for _pt in _pts: _sqlen = pow((_x - _pt.x), 2) + pow((_y - _pt.y), 2) _plist.append((_sqlen, _pt)) _plist.sort() # sorts tuples by first value! for _sqlen, _pt in _plist: _hits.append((_pt, _pt)) if len(_hits) == _count: return _hits # _users = {} # for _i in range(len(_pts)): # _pt = _pts[_i] # _count = _pt.countUsers() # _ulist = _users.setdefault(_count, []) # _ulist.append(_pt) # _counts = _users.keys() # _counts.sort(lambda _a, _b: cmp(_b, _a)) # largest to smallest # for _i in range(len(_counts)): # _count = _counts[_i] # for _pt in _users[_count]: # _hits.append((_pt, _pt)) # if len(_hits) == _count: # return _hits if _test_entity(_types, _skip, 'segment'): for _obj in self.__segments.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _p1, _p2 = _obj.getEndpoints() if ((abs(_px - _p1.x) < _t) and (abs(_py - _p1.y) < _t)): _hits.append((_obj, _p1)) elif ((abs(_px - _p2.x) < _t) and (abs(_py - _p2.y) < _t)): _hits.append((_obj, _p2)) else: _hits.append((_obj, (_px, _py))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'circle'): for _obj in self.__circles.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _hits.append((_obj, (_pt[0], _pt[1]))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'arc'): for _obj in self.__arcs.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _hits.append((_obj, (_pt[0], _pt[1]))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'hcline'): for _obj in self.__hclines.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _lp = _obj.getLocation() if ((abs(_px - _lp.x) < _t) and (abs(_py - _lp.y) < _t)): _hits.append((_obj, _lp)) else: _hits.append((_obj, (_px, _py))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'vcline'): for _obj in self.__vclines.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _lp = _obj.getLocation() if ((abs(_px - _lp.x) < _t) and (abs(_py - _lp.y) < _t)): _hits.append((_obj, _lp)) else: _hits.append((_obj, (_px, _py))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'acline'): for _obj in self.__aclines.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _lp = _obj.getLocation() if ((abs(_px - _lp.x) < _t) and (abs(_py - _lp.y) < _t)): _hits.append((_obj, _lp)) else: _hits.append((_obj, (_px, _py))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'ccircle'): for _obj in self.__ccircles.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _hits.append((_obj, (_pt[0], _pt[1]))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'cline'): for _obj in self.__clines.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _p1, _p2 = _obj.getKeypoints() if ((abs(_px - _p1.x) < _t) and (abs(_py - _p1.y) < _t)): _hits.append((_obj, _p1)) elif ((abs(_px - _p2.x) < _t) and (abs(_py - _p2.y) < _t)): _hits.append((_obj, _p2)) else: _hits.append((_obj, (_px, _py))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'leader'): for _obj in self.__leaders.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _p1, _p2, _p3 = _obj.getPoints() if ((abs(_px - _p1.x) < _t) and (abs(_py - _p1.y) < _t)): _hits.append((_obj, _p1)) elif ((abs(_px - _p2.x) < _t) and (abs(_py - _p2.y) < _t)): _hits.append((_obj, _p2)) elif ((abs(_px - _p3.x) < _t) and (abs(_py - _p3.y) < _t)): _hits.append((_obj, _p3)) else: _hits.append((_obj, (_px, _py))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'polyline'): for _obj in self.__polylines.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _pp = None for _tp in _obj.getPoints(): if ((abs(_px - _tp.x) < _t) and (abs(_py - _tp.y) < _t)): _pp = _tp break if _pp is not None: _hits.append((_obj, _pp)) else: _hits.append((_obj, (_px, _py))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'linear_dimension'): for _obj in self.__ldims.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _hits.append((_obj, (_pt[0], _pt[1]))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'horizontal_dimension'): for _obj in self.__hdims.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _hits.append((_obj, (_pt[0], _pt[1]))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'vertical_dimension'): for _obj in self.__vdims.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _hits.append((_obj, (_pt[0], _pt[1]))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'radial_dimension'): for _obj in self.__rdims.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _hits.append((_obj, (_pt[0], _pt[1]))) if len(_hits) == _count: return _hits if _test_entity(_types, _skip, 'angular_dimension'): for _obj in self.__adims.getInRegion(_xmin, _ymin, _xmax, _ymax): _pt = _obj.mapCoords(_x, _y, _t) if _pt is not None: _hits.append((_obj, (_pt[0], _pt[1]))) if len(_hits) == _count: return _hits return _hits def hasEntities(self): """ Test if the Layer has entities. This method returns a boolean """ if (self.__points or self.__segments or self.__circles or self.__arcs or self.__leaders or self.__polylines or self.__hclines or self.__vclines or self.__aclines or self.__clines or self.__ccircles or (len(self.__chamfers) > 0) or (len(self.__fillets) > 0) or (len(self.__textblocks) > 0) or self.__ldims or self.__hdims or self.__vdims or self.__rdims or self.__adims): return True return False def getEntityCount(self, etype): """ Return the number of an entity type stored in the Layer The argument 'etype' should be one of the following: point, segment, circle, arc, hcline, vcline, acline, cline, ccircle, chamfer, fillet, leader, polyline, textblock, linear_dimension, horizontal_dimenions, vertical_dimension, radial_dimension, or angular_dimension. """ if etype == "point": _res = len(self.__points) elif etype == "segment": _res = len(self.__segments) elif etype == "circle": _res = len(self.__circles) elif etype == "arc": _res = len(self.__arcs) elif etype == "leader": _res = len(self.__leaders) elif etype == "polyline": _res = len(self.__polylines) elif etype == "chamfer": _res = len(self.__chamfers) elif etype == "fillet": _res = len(self.__fillets) elif etype == "hcline": _res = len(self.__hclines) elif etype == "vcline": _res = len(self.__vclines) elif etype == "acline": _res = len(self.__aclines) elif etype == "cline": _res = len(self.__clines) elif etype == "ccircle": _res = len(self.__ccircles) elif etype == "text" or etype == 'textblock': _res = len(self.__textblocks) elif etype == "linear_dimension": _res = len(self.__ldims) elif etype == "horizontal_dimension": _res = len(self.__hdims) elif etype == "vertical_dimension": _res = len(self.__vdims) elif etype == "radial_dimension": _res = len(self.__rdims) elif etype == "angular_dimension": _res = len(self.__adims) else: raise ValueError, "Unexpected entity type string'%s'" % etype return _res def getLayerEntities(self, entity): """ Get all of a particular type of entity in the Layer. The argument 'entity' should be one of the following: point, segment, circle, arc, hcline, vcline, acline, cline, ccircle, chamfer, fillet, leader, polyline, textblock, linear_dimension, horizontal_dimenions, vertical_dimension, radial_dimension, or angular_dimension. """ if not isinstance(entity, str): raise TypeError, "Invalid entity type: " + `type(entity)` if entity == "point": _objs = self.__points.getObjects() elif entity == "segment": _objs = self.__segments.getObjects() elif entity == "circle": _objs = self.__circles.getObjects() elif entity == "arc": _objs = self.__arcs.getObjects() elif entity == "hcline": _objs = self.__hclines.getObjects() elif entity == "vcline": _objs = self.__vclines.getObjects() elif entity == "acline": _objs = self.__aclines.getObjects() elif entity == "cline": _objs = self.__clines.getObjects() elif entity == "ccircle": _objs = self.__ccircles.getObjects() elif entity == "chamfer": _objs = self.__chamfers[:] elif entity == "fillet": _objs = self.__fillets[:] elif entity == "leader": _objs = self.__leaders.getObjects() elif entity == "polyline": _objs = self.__polylines.getObjects() elif entity == "text" or entity == 'textblock': _objs = self.__textblocks[:] elif entity == "linear_dimension": _objs = self.__ldims.getObjects() elif entity == "horizontal_dimension": _objs = self.__hdims.getObjects() elif entity == "vertical_dimension": _objs = self.__vdims.getObjects() elif entity == "radial_dimension": _objs = self.__rdims.getObjects() elif entity == "angular_dimension": _objs = self.__adims.getObjects() else: raise ValueError, "Invalid layer entity '%s'" % entity return _objs def canParent(self, obj): """ Test if an Entity can be the parent of another Entity. This method overrides the Entity::canParent() method. A layer can be the parent of any object contained within itself. """ return isinstance(obj, (point.Point, segment.Segment, circle.Circle, arc.Arc, leader.Leader, polyline.Polyline, hcline.HCLine, vcline.VCLine, acline.ACLine, cline.CLine, segjoint.SegJoint, ccircle.CCircle, dimension.Dimension, dimension.DimString, # ??? text.TextBlock)) def setParentLayer(self, parent): """ Store the parent layer of a layer within itself. Argument 'parent' must be either another Layer or None. """ if parent is not None and not isinstance(parent, Layer): raise TypeError, "Invalid layer type: " + `type(parent)` _p = self.__parent_layer if _p is not parent: if _p is not None: _p.delSublayer(self) if parent is not None: parent.addSublayer(self) self.__parent_layer = parent self.sendMessage('reparented', _p) self.modified() def getParentLayer(self): return self.__parent_layer def addSublayer(self, l): if l is not None and not isinstance(l, Layer): raise TypeError, "Invalid layer type: " + `type(l)` if self.__sublayers is None: self.__sublayers = [] if l in self.__sublayers: raise ValueError, "Layer already a sublayer: " + `l` self.__sublayers.append(l) self.sendMessage('added_sublayer', l) self.modified() def delSublayer(self, l): if l is not None and not isinstance(l, Layer): raise TypeError, "Invalid layer type: " + `type(l)` if self.__sublayers is None: raise ValueError, "Layer has no sublayers: " + `self` if l not in self.__sublayers: raise ValueError, "Layer not a sublayer: " + `l` self.__sublayers.remove(l) if len(self.__sublayers) == 0: self.__sublayers = None self.sendMessage('deleted_sublayer', l) self.modified() def hasSublayers(self): return self.__sublayers is not None and len(self.__sublayers) > 0 def getSublayers(self): if self.__sublayers is not None: return self.__sublayers[:] return [] def getScale(self): """ Return the scale factor of the Layer. """ return self.__scale def setScale(self, scale): """ Set the scale factor for the Layer. The scale factor must be a positive float value greater than 0.0 """ _s = util.get_float(scale) if _s < 1e-10: raise ValueError, "Invalid scale factor: %g" % _s _os = self.__scale if abs(_os - _s) > 1e-10: self.startChange('scale_changed') self.__scale = _s self.endChange('scale_changed') self.sendMessage('scale_changed', _os) self.modified() scale = property(getScale, setScale, None, "Layer scale factor.") def getBoundary(self): """ Return the maximum and minimum values of the object in the Layer. The function returns a tuple holding four float values: (xmin, ymin, xmax, _ymax) A default value of (-1.0, -1.0, 1.0, 1.0) is returned for a Layer containing no objects. """ _xmin = None _ymin = None _xmax = None _ymax = None for _obj in self.__points.getObjects(): _x, _y = _obj.getCoords() if _xmin is None or _x < _xmin: _xmin = _x if _ymin is None or _y < _ymin: _ymin = _y if _xmax is None or _x > _xmax: _xmax = _x if _ymax is None or _y > _ymax: _ymax = _y for _obj in self.__arcs.getObjects(): _axmin, _aymin, _axmax, _aymax = _obj.getBounds() if _xmin is None or _axmin < _xmin: _xmin = _axmin if _ymin is None or _aymin < _ymin: _ymin = _aymin if _xmax is None or _axmax > _xmax: _xmax = _axmax if _ymax is None or _aymax > _ymax: _ymax = _aymax for _obj in self.__circles.getObjects() + self.__ccircles.getObjects(): _x, _y = _obj.getCenter().getCoords() _r = _obj.getRadius() _val = _x - _r if _xmin is None or _val < _xmin: _xmin = _val _val = _y - _r if _ymin is None or _val < _ymin: _ymin = _val _val = _x + _r if _xmax is None or _val > _xmax: _xmax = _val _val = _y + _r if _ymax is None or _val > _ymax: _ymax = _val _dims = (self.__ldims.getObjects() + self.__hdims.getObjects() + self.__vdims.getObjects() + self.__rdims.getObjects() + self.__adims.getObjects()) for _obj in _dims: _dxmin, _dymin, _dxmax, _dymax = _obj.getBounds() if _xmin is None or _dxmin < _xmin: _xmin = _dxmin if _ymin is None or _dymin < _ymin: _ymin = _dymin if _xmax is None or _dxmax > _xmax: _xmax = _dxmax if _ymax is None or _dymax > _ymax: _ymax = _dymax _ds1, _ds2 = _obj.getDimstrings() _x, _y = _ds1.getLocation() _bounds = _ds1.getBounds() if _bounds is not None: _w, _h = _bounds if _x < _xmin: _xmin = _x if (_y - _h) < _ymin: _ymin = (_y - _h) if (_x + _w) > _xmax: _xmax = (_x + _w) if _y > _ymax: _ymax = _y if _obj.getDualDimMode(): _x, _y = _ds2.getLocation() _bounds = _ds2.getBounds() if _bounds is not None: _w, _h = _bounds if _x < _xmin: _xmin = _x if (_y - _h) < _ymin: _ymin = (_y - _h) if (_x + _w) > _xmax: _xmax = (_x + _w) if _y > _ymax: _ymax = _y for _textblock in self.__textblocks: _x, _y = _textblock.getLocation() # upper left corner _w = _h = 0.0 _bounds = _textblock.getBounds() if _bounds is not None: _w, _h = _bounds _align = _textblock.getAlignment() if _align != text.TextStyle.ALIGN_LEFT: if _align == text.TextStyle.ALIGN_CENTER: _x = _x - _w/2.0 elif _align == text.TextStyle.ALIGN_RIGHT: _x = _x - _w if _xmin is None or _x < _xmin: _xmin = _x if _ymin is None or (_y - _h) < _ymin: _ymin = (_y - _h) if _xmax is None or (_x + _w) > _xmax: _xmax = (_x + _w) if _ymax is None or _y > _ymax: _ymax = _y if _xmin is None: _xmin = -1.0 if _ymin is None: _ymin = -1.0 if _xmax is None: _xmax = 1.0 if _ymax is None: _ymax = 1.0 return _xmin, _ymin, _xmax, _ymax def objsInRegion(self, xmin, ymin, xmax, ymax, fully=False): """ Return a all the objects in the Layer visible within the bounds. The function has four required arguments: xmin: The minimum x-value of the region ymin: The minimum y-value of the region xmax: The maximum x-value of the region ymax: The maximum y-value of the region There is a single optional argument: fully: A True/False value indicating if the object must be entirely within the region [fully=True], or can merely pass through [fully=False]. The default value is False. The function returns a list of objects. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if xmax < xmin: raise ValueError, "Value error: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Value error: ymax < ymin" util.test_boolean(fully) _objs = [] _objs.extend(self.__points.getInRegion(_xmin, _ymin, _xmax, _ymax)) _objs.extend(self.__segments.getInRegion(_xmin, _ymin, _xmax, _ymax)) _objs.extend(self.__circles.getInRegion(_xmin, _ymin, _xmax, _ymax)) _objs.extend(self.__arcs.getInRegion(_xmin, _ymin, _xmax, _ymax)) _objs.extend(self.__hclines.getInRegion(_xmin, _ymin, _xmax, _ymax)) _objs.extend(self.__vclines.getInRegion(_xmin, _ymin, _xmax, _ymax)) _objs.extend(self.__aclines.getInRegion(_xmin, _ymin, _xmax, _ymax)) _objs.extend(self.__clines.getInRegion(_xmin, _ymin, _xmax, _ymax)) _objs.extend(self.__ccircles.getInRegion(_xmin, _ymin, _xmax, _ymax)) for _obj in self.__chamfers: if _obj.inRegion(_xmin, _ymin, _xmax, _ymax): _objs.append(_obj) _objs.extend(self.__leaders.getInRegion(_xmin, _ymin, _xmax, _ymax)) _objs.extend(self.__polylines.getInRegion(_xmin, _ymin, _xmax, _ymax)) for _obj in self.__fillets: if _obj.inRegion(_xmin, _ymin, _xmax, _ymax): _objs.append(_obj) for _obj in self.__ldims.getInRegion(_xmin, _ymin, _xmax, _ymax): _objs.append(_obj) _ds1, _ds2 = _obj.getDimstrings() _objs.append(_ds1) if _obj.getDualDimMode(): _objs.append(_ds2) for _obj in self.__hdims.getInRegion(_xmin, _ymin, _xmax, _ymax): _objs.append(_obj) _ds1, _ds2 = _obj.getDimstrings() _objs.append(_ds1) if _obj.getDualDimMode(): _objs.append(_ds2) for _obj in self.__vdims.getInRegion(_xmin, _ymin, _xmax, _ymax): _objs.append(_obj) _ds1, _ds2 = _obj.getDimstrings() _objs.append(_ds1) if _obj.getDualDimMode(): _objs.append(_ds2) for _obj in self.__rdims.getInRegion(_xmin, _ymin, _xmax, _ymax): _objs.append(_obj) _ds1, _ds2 = _obj.getDimstrings() _objs.append(_ds1) if _obj.getDualDimMode(): _objs.append(_ds2) for _obj in self.__adims.getInRegion(_xmin, _ymin, _xmax, _ymax): _objs.append(_obj) _ds1, _ds2 = _obj.getDimstrings() _objs.append(_ds1) if _obj.getDualDimMode(): _objs.append(_ds2) for _obj in self.__textblocks: _x, _y = _obj.getLocation() _bounds = _obj.getBounds() if _bounds is not None: _w, _h = _bounds else: _w = _h = 0 _txmin = _x _txmax = _x + _w _tymin = _y - _h _tymax = _y if not ((_txmax < _xmin) or (_txmin > _xmax) or (_tymax < _ymin) or (_tymin > _ymax)): _objs.append(_obj) return _objs def sendsMessage(self, m): if m in Layer.__messages: return True return super(Layer, self).sendsMessage(m) def update(self): """ Check that the objects in this layer are stored correctly. This function checks that the objects held in this layer are kept in the proper order. Also, any duplicated objects that may have be created due to modifying entities in the layer are removed. """ raise RuntimeError, "Layer::update() called." # # Layer history class # class LayerLog(entity.EntityLog): def __init__(self, l): if not isinstance(l, Layer): raise TypeError, "Invalid layer type: " + `type(l)` super(LayerLog, self).__init__(l) l.connect('scale_changed', self.__scaleChanged) l.connect('name_changed', self.__nameChanged) l.connect('added_child', self.__addedChild) l.connect('removed_child', self.__removedChild) def __addedChild(self, l, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _obj = args[0] _vals = _obj.getValues() if not isinstance(_vals, entity.EntityData): raise TypeError, "Unexpected type for values: " + `type(_obj)` _vals.lock() self.saveUndoData('added_child', _vals) def __removedChild(self, l, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _obj = args[0] _vals = _obj.getValues() if not isinstance(_vals, entity.EntityData): raise TypeError, "Unexpected type for values: " + `type(_obj)` _vals.lock() self.saveUndoData('removed_child', _vals) def __nameChanged(self, l, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _name = args[0] if not isinstance(_name, types.StringTypes): raise TypeError, "Unexpected type for name: " + `type(_name)` self.saveUndoData('name_changed', _name) def __scaleChanged(self, l, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _scale = args[0] if not isinstance(_scale, float): raise TypeError, "Unexpected type for scale: " + `type(_scale)` if _scale < 1e-10: raise ValueError, "Invalid scale: %g" % _scale self.saveUndoData('scale_changed', _scale) def execute(self, undo, *args): # print "LayerLog::execute() ..." # print args util.test_boolean(undo) _alen = len(args) if len(args) == 0: raise ValueError, "No arguments to execute()" _l = self.getObject() _op = args[0] if _op == 'name_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _sdata = _l.getName() self.ignore(_op) try: _name = args[1] if undo: _l.startUndo() try: _l.setName(_name) finally: _l.endUndo() else: _l.startRedo() try: _l.setName(_name) finally: _l.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'scale_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _sdata = _l.getScale() self.ignore(_op) try: _scale = args[1] if undo: _l.startUndo() try: _l.setScale(_scale) finally: _l.endUndo() else: _l.startRedo() try: _l.setScale(_scale) finally: _l.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'added_child': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _vals = args[1] if not isinstance(_vals, entity.EntityData): raise TypeError, "Unexpected type for values: " + `type(_vals)` self.ignore('modified') try: if undo: _sdata = _vals self.ignore('removed_child') try: self.__delObject(undo, _vals) finally: self.receive('removed_child') else: _obj = self.__makeObject(_vals) self.ignore(_op) try: _l.startRedo() try: _l.addObject(_obj) finally: _l.endRedo() finally: self.receive(_op) _sdata = _obj.getValues() _sdata.lock() finally: self.receive('modified') self.saveData(undo, _op, _sdata) elif _op == 'removed_child': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _vals = args[1] if not isinstance(_vals, entity.EntityData): raise TypeError, "Unexpected type for values: " + `type(_vals)` self.ignore('modified') try: if undo: _obj = self.__makeObject(_vals) self.ignore('added_child') try: _l.startUndo() try: _l.addObject(_obj) finally: _l.endUndo() _sdata = _obj.getValues() _sdata.lock() finally: self.receive('added_child') else: _sdata = _vals self.ignore(_op) try: self.__delObject(undo, _vals) finally: self.receive(_op) finally: self.receive('modified') self.saveData(undo, _op, _sdata) else: super(LayerLog, self).execute(undo, *args) def __getImageColor(self, r, g, b): _image = self.getObject().getParent() _color = None if _image is not None: for _ic in _image.getImageEntities('color'): if _ic.r == r and _ic.g == g and _ic.b == b: _color = _ic break if _color is None: _color = color.Color(r, g, b) return _color def __makeImageColor(self, values): # print "LayerLog::__makeImageColor() ..." _image = self.getObject().getParent() _cdata = values.get('color') _color = None if _image is not None and _cdata is not None: # print "restoring image color: " + str(_cdata) _r, _g, _b = _cdata for _ic in _image.getImageEntities('color'): if _ic.r == _r and _ic.g == _g and _ic.b == _b: _color = _ic break if _color is None and _cdata is not None: # make one _r, _g, _b = _cdata _color = color.Color(_r, _g, _b) return _color def __makeGraphicLinetype(self, values): # print "LayerLog::__makeGraphicLinetype() ..." _image = self.getObject().getParent() _ltdata = values.get('linetype') _linetype = None if _image is not None and _ltdata is not None: # print "restoring graphic linetype: " + str(_ltdata) _name, _dlist = _ltdata for _ilt in _image.getImageEntities('linetype'): if ((_ilt.getName() == _name) and (_ilt.getList() == _dlist)): _linetype = _ilt break if _linetype is None and _ltdata is not None: # make one _name, _dlist = _ltdata _linetype = linetype.Linetype(_name, _dlist) return _linetype def __makeGraphicStyle(self, values): # print "LayerLog::__makeGraphicStyle() ..." _image = self.getObject().getParent() _sdata = values.get('style') _style = None if _image is not None and _sdata is not None: # print "restoring graphic style: " + str(_sdata) _name, _lt, _col, _th = _sdata _ln, _ld = _lt for _istyle in _image.getImageEntities('style'): if _istyle.getName() != _name: continue _ilt = _istyle.getLinetype() if ((_ilt.getName() != _ln) or (_ilt.getList() != _ld)): continue if _istyle.getColor().getColors() != _col: continue if abs(_istyle.getThickness() - _th) > 1e-10: continue _style = _istyle break if _style is None and _sdata is not None: # make one _name, _lt, _col, _th = _sdata _r, _g, _b = _col _color = self.__getImageColor(_r, _g, _b) _linetype = linetype.Linetype(_lt[0], _lt[1]) _style = style.Style(_name, _linetype, _color, _th) return _style def __resetGraphicValues(self, obj, values): # print "LayerLog::__resetGraphicValues() ..." _style = self.__makeGraphicStyle(values) if _style is not None: # print "resetting style ..." obj.setStyle(_style) _linetype = self.__makeGraphicLinetype(values) if _linetype is not None: # print "resetting linetype ..." obj.setLinetype(_linetype) _color = self.__makeImageColor(values) if _color is not None: # print "resetting color ..." obj.setColor(_color) _thickness = values.get('thickness') if _thickness is not None: # print "resetting thickness ..." obj.setThickness(_thickness) def __makeTextStyle(self, values): # print "LayerLog::__makeTextStyle() ..." _image = self.getObject().getParent() _tdata = values.get('textstyle') _textstyle = None if _image is not None and _tdata is not None: # print "restoring textstyle: " + str(_tdata) for _ts in _image.getImageEntities('textstyle'): # print "Comparing stored TextStyle: %s " % _ts.getName() if _ts.getName() != _tdata['name']: # print "name differs" continue if _ts.getFamily() != _tdata['family']: # print "family differs" continue if _ts.getStyle() != _tdata['style']: # print "style differs" continue _c = _ts.getColor() _r, _g, _b = _tdata['color'] if ((_c.r != _r) or (_c.g != _g) or (_c.b != _b)): # print "color differs" continue if abs(_ts.getSize() - _tdata['size']) > 1e-10: # print "size differs" continue if abs(_ts.getAngle() - _tdata['angle']) > 1e-10: # print "angle differs" continue if _ts.getAlignment() != _tdata['align']: # print "alignment differs" continue _textstyle = _ts break if _textstyle is None and _tdata is not None: # make one # print "Creating new TextStyle instance" _r, _g, _b = _tdata['color'] _color = self.__getImageColor(_r, _g, _b) _textstyle = text.TextStyle(_tdata['name'], family=_tdata['family'], style=_tdata['style'], weight=_tdata['weight'], color=_color, size=_tdata['size'], angle=_tdata['angle'], align=_tdata['align']) return _textstyle def __makeDimStyle(self, values): # print "LayerLog::__makeDimStyle() ..." _image = self.getObject().getParent() _dsdata = values.get('dimstyle') _dimstyle = None if _image is not None and _dsdata is not None: # print "restoring dimstylstyle: " + str(_tdata) _name = _dsdata['name'] _dscopy = {} for _key in _dsdata.keys(): if _key != 'name': _dscopy[_key] = _dsdata[_key] for _ds in _image.getImageEntities('dimstyle'): if _ds.getName() != _name: continue _keys = _ds.getKeys() _seen = True for _key in _keys: if _key not in _dscopy: _seen = False break if not _seen: continue for _key in _dscopy: if _key not in _keys: _seen = False break if not _seen: continue _hit = True for _key, _val in _dscopy.items(): _dsv = _ds.getValue(_key) if ((_key == 'DIM_COLOR') or (_key == 'DIM_PRIMARY_FONT_COLOR') or (_key == 'DIM_SECONDARY_FONT_COLOR')): if _dsv.getColors() != _val: _hit = False break else: if _dsv != _val: _hit = False break if not _hit: continue # print "hit on existing DimStyle ..." _dimstyle = _ds break if _dimstyle is None and _dsdata is not None: # make one # print "making new DimStyle ..." _name = _dsdata['name'] _vals = {} for _key in _dsdata.keys(): if _key != 'name': _val = _dsdata[_key] if ((_key == 'DIM_COLOR') or (_key == 'DIM_PRIMARY_FONT_COLOR') or (_key == 'DIM_SECONDARY_FONT_COLOR')): _r, _g, _b = _val _color = self.__getImageColor(_r, _g, _b) _vals[_key] = _color else: _vals[_key] = _val _dimstyle = dimension.DimStyle(_name, _vals) return _dimstyle def __makeDimString(self, values): # print "LayerLog::__makeDimString() ..." _textstyle = self.__makeTextStyle(values) _id = values.get('id') if _id is None: raise ValueError, "Lost 'id' for recreating DimString" _val = values.get('location') if _val is None: raise ValueError, "Lost 'location' value for DimString" _x, _y = _val _ds = dimension.DimString(_x, _y, textstyle=_textstyle, id=_id) # # TextBlock info # _val = values.get('family') if _val is not None: _ds.setFamily(_val) _val = values.get('style') if _val is not None: _ds.setStyle(_val) _val = values.get('weight') if _val is not None: _ds.setWeight(_val) _val = values.get('color') if _val is not None: _r, _g, _b = _val _ds.setColor(self.__getImageColor(_r, _g, _b)) _val = values.get('size') if _val is not None: _ds.setSize(_val) _val = values.get('angle') if _val is not None: _ds.setAngle(_val) _val = values.get('alignment') if _val is not None: _ds.setAlignment(_val) # # DimString info # _val = values.get('prefix') if _val is None: raise ValueError, "Lost 'prefix' value for DimString" _ds.setPrefix(_val) _val = values.get('suffix') if _val is None: raise ValueError, "Lost 'suffix' value for DimString" _ds.setSuffix(_val) _val = values.get('units') if _val is None: raise ValueError, "Lost 'units' value for DimString" if _val == 'millimeters': _unit = units.MILLIMETERS elif _val == 'micrometers': _unit = units.MICROMETERS elif _val == 'meters': _unit = units.METERS elif _val == 'kilometers': _unit = units.KILOMETERS elif _val == 'inches': _unit = units.INCHES elif _val == 'feet': _unit = units.FEET elif _val == 'yards': _unit = units.YARDS elif _val == 'miles': _unit = units.MILES else: raise ValueError, "Unexpected unit: %s" % _val _ds.setUnits(_unit) _val = values.get('precision') if _val is None: raise ValueError, "Lost 'precision' value for DimString" _ds.setPrecision(_val) _val = values.get('print_zero') if _val is None: raise ValueError, "Lost 'print_zero' value for DimString" _ds.setPrintZero(_val) _val = values.get('print_decimal') if _val is None: raise ValueError, "Lost 'print_decimal' value for DimString" _ds.setPrintDecimal(_val) return _ds def __adjustDimension(self, obj, values): # print "LayerLog::__adjustDimension() ..." _val = values.get('offset') if _val is not None: obj.setOffset(_val) _val = values.get('extension') if _val is not None: obj.setExtension(_val) _val = values.get('position') if _val is not None: obj.setPosition(_val) _val = values.get('eptype') if _val is not None: obj.setEndpointType(_val) _val = values.get('epsize') if _val is not None: obj.setEndpointSize(_val) _val = values.get('color') if _val is not None: _r, _g, _b = _val obj.setColor(self.__getImageColor(_r, _g, _b)) _val = values.get('dualmode') if _val is not None: obj.setDualDimMode(_val) _val = values.get('poffset') if _val is not None: obj.setPositionOffset(_val) _val = values.get('dmoffset') if _val is not None: obj.setDualModeOffset(_val) _val = values.get('thickness') if _val is not None: obj.setThickness(_val) def __makeObject(self, values): # print "LayerLog::__makeObject() ..." _type = values.get('type') if _type is None: _keys = values.keys() _keys.sort() for _key in _keys: print "key: %s: value: %s" % (_key, str(values.get(_key))) raise RuntimeError, "No type defined for these values" _id = values.get('id') if _id is None: raise ValueError, "Lost 'id' for recreating object" _l = self.getObject() _obj = None # if _type == 'point': _x = values.get('x') if _x is None: raise ValueError, "Lost 'x' value for Point" _y = values.get('y') if _y is None: raise ValueError, "Lost 'y' value for Point" _obj = point.Point(_x, _y, id=_id) elif _type == 'segment': _p1id = values.get('p1') if _p1id is None: raise ValueError, "Lost 'p1' value for Segment" _p1 = _l.getObject(_p1id) if _p1 is None or not isinstance(_p1, point.Point): raise ValueError, "Segment P1 point missing; id=%d" % _p1id _p2id = values.get('p2') if _p2id is None: raise ValueError, "Lost 'p2' value for Segment" _p2 = _l.getObject(_p2id) if _p2 is None or not isinstance(_p2, point.Point): raise ValueError, "Segment P2 point missing; id=%d" % _p2id _obj = segment.Segment(_p1, _p2, id=_id) self.__resetGraphicValues(_obj, values) elif _type == 'circle': _cid = values.get('center') if _cid is None: raise ValueError, "Lost 'center' value for Circle" _cp = _l.getObject(_cid) if _cp is None or not isinstance(_cp, point.Point): raise ValueError, "Circle center missing: id=%d" % _cid _r = values.get('radius') if _r is None: raise ValueError, "Lost 'radius' value for Circle" _obj = circle.Circle(_cp, _r, id=_id) self.__resetGraphicValues(_obj, values) elif _type == 'arc': _cid = values.get('center') if _cid is None: raise ValueError, "Lost 'center' value for Arc." _cp = _l.getObject(_cid) if _cp is None or not isinstance(_cp, point.Point): raise ValueError, "Arc center missing: id=%d" % _cid _r = values.get('radius') if _r is None: raise ValueError, "Lost 'radius' value for Arc." _sa = values.get('start_angle') if _sa is None: raise ValueError, "Lost 'start_angle' value for Arc." _ea = values.get('end_angle') if _ea is None: raise ValueError, "Lost 'end_angle' value for Arc." _obj = arc.Arc(_cp, _r, _sa, _ea, id=_id) self.__resetGraphicValues(_obj, values) elif _type == 'ellipse': raise TypeError, "Ellipse not yet handled ..." elif _type == 'leader': _p1id = values.get('p1') if _p1id is None: raise ValueError, "Lost 'p1' value for Leader." _p1 = _l.getObject(_p1id) if _p1 is None or not isinstance(_p1, point.Point): raise ValueError, "Leader P1 point missing: id=%d" % _p1id _p2id = values.get('p2') if _p2id is None: raise ValueError, "Lost 'p2' value for Leader." _p2 = _l.getObject(_p2id) if _p2 is None or not isinstance(_p2, point.Point): raise ValueError, "Leader P2 point missing: id=%d" % _p2id _p3id = values.get('p3') if _p3id is None: raise ValueError, "Lost 'p3' value for Leader." _p3 = _l.getObject(_p3id) if _p3 is None or not isinstance(_p3, point.Point): raise ValueError, "Leader P3 point missing: id=%d" % _p3id _size = values.get('size') if _size is None: raise ValueError, "Lost 'size' value for Leader." _obj = leader.Leader(_p1, _p2, _p3, _size, id=_id) self.__resetGraphicValues(_obj, values) elif _type == 'polyline': _pids = values.get('points') _pts = [] for _ptid in _pids: _p = _l.getObject(_ptid) if _p is None or not isinstance(_p, point.Point): raise ValueError, "Polyline point missing: id=%d" % _ptid _pts.append(_p) _obj = polyline.Polyline(_pts, id=_id) self.__resetGraphicValues(_obj, values) elif _type == 'textblock': _loc = values.get('location') if _loc is None: raise ValueError, "Lost 'location' value for TextBlock." _x, _y = _loc _text = values.get('text') if _text is None: raise ValueError, "Lost 'text' value for TextBlock." _tstyle = self.__makeTextStyle(values) _obj = text.TextBlock(_x, _y, _text, textstyle=_tstyle, id=_id) _val = values.get('family') if _val is not None: _obj.setFamily(_val) _val = values.get('style') if _val is not None: _obj.setStyle(_val) _val = values.get('weight') if _val is not None: _obj.setWeight(_val) _val = values.get('color') if _val is not None: _r, _g, _b = _val _obj.setColor(self.__getImageColor(_r, _g, _b)) _val = values.get('size') if _val is not None: _obj.setSize(_val) _val = values.get('angle') if _val is not None: _obj.setAngle(_val) _val = values.get('alignment') if _val is not None: _obj.setAlignment(_val) elif _type == 'hcline': _kid = values.get('keypoint') if _kid is None: raise ValueError, "Lost 'keypoint' value for HCLine." _p = _l.getObject(_kid) if _p is None or not isinstance(_p, point.Point): raise ValueError, "HCLine point missing: id=%d" % _kid _obj = hcline.HCLine(_p, id=_id) elif _type == 'vcline': _kid = values.get('keypoint') if _kid is None: raise ValueError, "Lost 'keypoint' value for VCLine." _p = _l.getObject(_kid) if _p is None or not isinstance(_p, point.Point): raise ValueError, "VCLine point missing: id=%d" % _kid _obj = vcline.VCLine(_p, id=_id) elif _type == 'acline': _kid = values.get('keypoint') if _kid is None: raise ValueError, "Lost 'keypoint' value for ACLine." _p = _l.getObject(_kid) if _p is None or not isinstance(_p, point.Point): raise ValueError, "ACLine point missing: id=%d" % _kid _angle = values.get('angle') if _angle is None: raise ValueError, "Lost 'angle' value for ACLine." _obj = acline.ACLine(_p, _angle, id=_id) elif _type == 'cline': _p1id = values.get('p1') if _p1id is None: raise ValueError, "Lost 'p1' value for CLine" _p1 = _l.getObject(_p1id) if _p1 is None or not isinstance(_p1, point.Point): raise ValueError, "CLine P1 point missing: id=%d" % _p1id _p2id = values.get('p2') if _p2id is None: raise ValueError, "Lost 'p2' value for CLine" _p2 = _l.getObject(_p2id) if _p2 is None or not isinstance(_p2, point.Point): raise ValueError, "CLine P2 point missing: id=%d" % _p2id _obj = cline.CLine(_p1, _p2, id=_id) elif _type == 'ccircle': _cid = values.get('center') if _cid is None: raise ValueError, "Lost 'center' value for CCircle" _cp = _l.getObject(_cid) if _cp is None or not isinstance(_cp, point.Point): raise ValueError, "CCircle center missing: id=%d" % _cid _r = values.get('radius') if _r is None: raise ValueError, "Lost 'radius' value for CCircle" _obj = ccircle.CCircle(_cp, _r, id=_id) elif _type == 'fillet': _s1id = values.get('s1') if _s1id is None: raise ValueError, "Lost 's1' value for Fillet" _s1 = _l.getObject(_s1id) if _s1 is None or not isinstance(_s1, segment.Segment): raise ValueError, "Fillet S1 segment missing: id=%d" % _s1id _s2id = values.get('s2') if _s2id is None: raise ValueError, "Lost 's2' value for Fillet" _s2 = _l.getObject(_s2id) if _s2 is None or not isinstance(_s2, segment.Segment): raise ValueError, "Fillet S2 segment missing: id=%d" % _s2id _r = values.get('radius') if _r is None: raise ValueError, "Lost 'radius' value for Fillet" _obj = segjoint.Fillet(_s1, _s2, _r, id=_id) elif _type == 'chamfer': _s1id = values.get('s1') if _s1id is None: raise ValueError, "Lost 's1' value for Chamfer" _s1 = _l.getObject(_s1id) if _s1 is None or not isinstance(_s1, segment.Segment): raise ValueError, "Fillet S1 segment missing: id=%d" % _s1id _s2id = values.get('s2') if _s2id is None: raise ValueError, "Lost 's2' value for Chamfer" _s2 = _l.getObject(_s2id) if _s2 is None or not isinstance(_s2, segment.Segment): raise ValueError, "Fillet S2 segment missing: id=%d" % _s2id _len = values.get('length') if _len is None: raise ValueError, "Lost 'length' value for Chamfer" _obj = segjoint.Chamfer(_s1, _s2, _len, id=_id) elif _type == 'ldim' or _type == 'hdim' or _type == 'vdim': _loc = values.get('location') if _loc is None: raise ValueError, "Lost 'location' value for L/H/V Dimension." _x, _y = _loc _l1id = values.get('l1') if _l1id is None: raise ValueError, "Lost 'l1' value for L/H/V Dimension." _p1id = values.get('p1') if _p1id is None: raise ValueError, "Lost 'p1' value for L/H/V Dimension." _l2id = values.get('l2') if _l2id is None: raise ValueError, "Lost 'l2' value for L/H/V Dimension." _p2id = values.get('p2') if _p2id is None: raise ValueError, "Lost 'p2' value for L/H/V Dimension." _l1 = _p1 = _l2 = _p2 = None _lid = _l.getID() _img = _l.getParent() if _img is None: raise ValueError, "Layer has no parent Image" if _l1id == _lid: _l1 = _l else: _l1 = _img.getObject(_l1id) if _l1 is None or not isinstance(_l1, Layer): raise ValueError, "Dimension L1 layer missing: id=%d" % _l1id _p1 = _l1.getObject(_p1id) if _p1 is None or not isinstance(_p1, point.Point): raise ValueError, "Dimension P1 point missing: id=%d" % _p1id if _l2id == _lid: _l2 = _l else: _l2 = _img.getObject(_l2id) if _l2 is None or not isinstance(_l2, Layer): raise ValueError, "Dimension L2 layer missing: id=%d" % _l2id _p2 = _l2.getObject(_p2id) if _p2 is None or not isinstance(_p2, point.Point): raise ValueError, "Dimension P2 point missing: id=%d" % _p2id _ds = self.__makeDimStyle(values) _dsdata = values.get('ds1') if _dsdata is None: raise ValueError, "Lost 'ds1' value for L/H/V Dimension." _ds1 = self.__makeDimString(_dsdata) _dsdata = values.get('ds2') if _dsdata is None: raise ValueError, "Lost 'ds2' value for L/H/V Dimension." _ds2 = self.__makeDimString(_dsdata) if _ds is None: _ds = _img.getOption('DIM_STYLE') if _type == 'ldim': _objtype = dimension.LinearDimension elif _type == 'hdim': _objtype = dimension.HorizontalDimension elif _type == 'vdim': _objtype = dimension.VerticalDimension else: raise ValueError, "Unexpected type: %s" % _type _obj = _objtype(_p1, _p2, _x, _y, _ds, ds1=_ds1, ds2=_ds2, id=_id) self.__adjustDimension(_obj, values) elif _type == 'rdim': _loc = values.get('location') if _loc is None: raise ValueError, "Lost 'location' value for RadialDimension." _x, _y = _loc _lid = values.get('layer') if _lid is None: raise ValueError, "Lost 'layer' value for RadialDimension." _cid = values.get('circle') if _cid is None: raise ValueError, "Lost 'circle' value for RadialDimension." _cl = _c = None _img = _l.getParent() if _img is None: raise ValueError, "Layer has no parent Image" if _lid == _l.getID(): _cl = _l else: _cl = _img.getObject(_lid) if _cl is None or not isinstance(_cl, Layer): raise ValueError, "Dimension Layer missing: id=%d" % _lid _c = _cl.getObject(_cid) if _c is None or not isinstance(_c, (circle.Circle, arc.Arc)): raise ValueError, "Dimension Circle/Arc missing: id=%d" % _cid _ds = self.__makeDimStyle(values) _dsdata = values.get('ds1') if _dsdata is None: raise ValueError, "Lost 'ds1' value for RadialDimension." _ds1 = self.__makeDimString(_dsdata) _dsdata = values.get('ds2') if _dsdata is None: raise ValueError, "Lost 'ds2' value for RadialDimension." _ds2 = self.__makeDimString(values.get('ds2')) _obj = dimension.RadialDimension(_c, _x, _y, _ds, ds1=_ds1, ds2=_ds2, id=_id) self.__adjustDimension(_obj, values) _mode = values.get('dia_mode') if _mode is None: raise ValueError, "Lost 'dia_mode' value for RadialDimension." _obj.setDiaMode(_mode) elif _type == 'adim': _x, _y = values.get('location') _vlid = values.get('vl') if _vlid is None: raise ValueError, "Lost 'vl' value for AngularDimension." _vpid = values.get('vp') if _vpid is None: raise ValueError, "Lost 'vp' value for AngularDimension." _l1id = values.get('l1') if _l1id is None: raise ValueError, "Lost 'l1' value for AngularDimension." _p1id = values.get('p1') if _p1id is None: raise ValueError, "Lost 'p1' value for AngularDimension." _l2id = values.get('l2') if _l2id is None: raise ValueError, "Lost 'l2' value for AngularDimension." _p2id = values.get('p2') if _p2id is None: raise ValueError, "Lost 'p2' value for AngularDimension." _vl = _vp = _l1 = _p1 = _l2 = _p2 = None _lid = _l.getID() _img = _l.getParent() if _img is None: raise ValueError, "Layer has no parent Image" if _vlid == _lid: _vl = _l else: _vl = _img.getObject(_vlid) if _vl is None or not isinstance(_vl, Layer): raise ValueError, "Dimension vertex layer missing: id=%d" % _vlid _vp = _vl.getObject(_vpid) if _vp is None or not isinstance(_vp, point.Point): raise ValueError, "Dimension vertex point missing: id=%d" % _vpid if _l1id == _lid: _l1 = _l else: _l1 = _img.getObject(_l1id) if _l1 is None or not isinstance(_l1, Layer): raise ValueError, "Dimension L1 layer missing: id=%d" % _l1id _p1 = _l1.getObject(_p1id) if _p1 is None or not isinstance(_p1, point.Point): raise ValueError, "Dimension P1 point missing: id=%d" % _p1id if _l2id == _lid: _l2 = _l else: _l2 = _img.getObject(_l2id) if _l2 is None or not isinstance(_l2, Layer): raise ValueError, "Dimension L2 layer missing: id=%d" % _l2id _p2 = _l2.getObject(_p2id) if _p2 is None or not isinstance(_p2, point.Point): raise ValueError, "Dimension P2 point missing: id=%d" % _p2id _ds = self.__makeDimStyle(values) _dsdata = values.get('ds1') if _dsdata is None: raise ValueError, "Lost 'ds1' value for AngularDimension." _ds1 = self.__makeDimString(_dsdata) _dsdata = values.get('ds2') if _dsdata is None: raise ValueError, "Lost 'ds2' value for AngularDimension." _ds2 = self.__makeDimString(values.get('ds2')) _obj = dimension.AngularDimension(_vp, _p1, _p2, _x, _y, _ds, ds1=_ds1, ds2=_ds2, id=_id) self.__adjustDimension(_obj, values) else: raise TypeError, "Unexpected type: %s" % _type return _obj def __delObject(self, undo, values): # print "LayerLog::__delObject() ..." _type = values.get('type') _id = values.get('id') # print "id: %d" % _id _l = self.getObject() _obj = _l.getObject(_id) if _obj is None: raise ValueError, "Missed object: %d, %s" % (_id, _type) # # layer still has to send messages out like 'removed_child' # if undo: _l.startUndo() try: _l.delObject(_obj) finally: _l.endUndo() else: _l.startRedo() try: _l.delObject(_obj) finally: _l.endRedo() PythonCAD-DS1-R37/PythonCAD/Generic/dwg15.py0000644000175000017500000060204211307666657017644 0ustar matteomatteo# # Copyright (c) 2003 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # read in an AutoCAD R15 DWG file # import struct import array from PythonCAD.Generic import dwgbase from PythonCAD.Generic import dwgutil def initialize_dwg(dwg): _handle = dwg.getHandle() _handle.seek(0, 0) _buf = _handle.read(6) if _buf != 'AC1015': raise ValueError, "File not R15 DWG format" _handle.seek(7, 1) # padding and a revisionbyte _offset = struct.unpack('h', _handle.read(2))[0] # big-endian size if _size == 2: # section is just CRC break _data.fromfile(_handle, _size) # # the spec says 'last_handle' and 'last_loc' are initialized outside # the outer for loop - postings on OpenDWG forum say these variables # must be initialized for each section # _last_handle = 0 _last_loc = 0 _bitpos = 0 _bitmax = (_size - 2) * 8 # remove two bytes for section CRC # # there should be something done with the CRC for section ... # while _bitpos < _bitmax: _bitpos, _hoffset = dwgutil.get_modular_char(_data, _bitpos) _last_handle = _last_handle + _hoffset _bitpos, _foffset = dwgutil.get_modular_char(_data, _bitpos) _last_loc = _last_loc + _foffset dwg.addEntityOffset(_last_handle, _last_loc) # # read the common parts at the start of many entities # def header_read(ent, data, offset): _bitpos = offset _mode = dwgutil.get_bits(data, 2, _bitpos) _bitpos = _bitpos + 2 ent.setMode(_mode) _bitpos, _rnum = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_rnum) _bitpos, _nolinks = dwgutil.test_bit(data, _bitpos) ent.setNoLinks(_nolinks) _bitpos, _color = dwgutil.get_bit_short(data, _bitpos) ent.setColor(_color) _bitpos, _ltscale = dwgutil.get_bit_double(data, _bitpos) ent.setLinetypeScale(_ltscale) _ltflag = dwgutil.get_bits(data, 2, _bitpos) _bitpos = _bitpos + 2 ent.setLinetypeFlags(_ltflag) _psflag = dwgutil.get_bits(data, 2, _bitpos) _bitpos = _bitpos + 2 ent.setPlotstyleFlags(_psflag) _bitpos, _invis = dwgutil.get_bit_short(data, _bitpos) ent.setInvisiblity(_invis) _bitpos, _weight = dwgutil.get_raw_char(data, _bitpos) ent.setLineweight(_weight) return _bitpos # # read the common parts ant the end of many entities # def tail_read(ent, data, offset): _bitpos = offset _sh = None if ent.getMode() == 0x0: _bitpos, _sh = dwgutil.get_handle(data, _bitpos) ent.setSubentity(_sh) for _i in range(ent.getNumReactors()): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _xh = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_xh) _bitpos, _lh = dwgutil.get_handle(data, _bitpos) ent.setLayer(_lh) if ent.getNoLinks() is False: _bitpos, _prev = dwgutil.get_handle(data, _bitpos) ent.setPrevious(_prev) _bitpos, _next = dwgutil.get_handle(data, _bitpos) ent.setNext(_next) if ent.getLinetypeFlags() == 0x3: _bitpos, _lth = dwgutil.get_handle(data, _bitpos) ent.setLinetype(_lth) if ent.getPlotstyleFlags() == 0x3: _bitpos, _pth = dwgutil.get_handle(data, _bitpos) ent.setPlotstyle(_pth) return _bitpos # # read the various entities stored in the DWG file # def text_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _dflag = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('data_flag', _dflag) if not (_dflag & 0x1): _bitpos, _elev = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _x1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y1 = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('insertion_point', (_x1, _y1)) if not (_dflag & 0x2): _bitpos, _x = dwgutil.get_default_double(data, _bitpos, _x1) _bitpos, _y = dwgutil.get_default_double(data, _bitpos, _y1) ent.setEntityData('alignment_point', (_x, _y)) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _x = _y = 0.0 _z = 1.0 else: _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _th = dwgutil.test_bit(data, _bitpos) if _flag: _th = 0.0 else: _bitpos, _th = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _th) if not (_dflag & 0x4): _bitpos, _oblique = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('oblique_angle', _oblique) if not (_dflag & 0x8): _bitpos, _rotation = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('rotation_angle', _rotation) _bitpos, _height = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('height', _height) if not (_dflag & 0x10): _bitpos, _width = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('width_factor', _width) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) if not (_dflag & 0x20): _bitpos, _gen = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('generation', _gen) if not (_dflag & 0x40): _bitpos, _halign = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('halign', _halign) if not (_dflag & 0x80): _bitpos, _valign = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('valign', _valign) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('style_handle', _handle) def attrib_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _dflag = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('data_flag', _dflag) if not (_dflag & 0x1): _bitpos, _elev = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _x1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y1 = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('insertion_point', (_x1, _y1)) if not (_dflag & 0x2): _bitpos, _x = dwgutil.get_default_double(data, _bitpos, _x1) _bitpos, _y = dwgutil.get_default_double(data, _bitpos, _y1) ent.setEntityData('alignment_point', (_x, _y)) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _x = _y = 0.0 _z = 1.0 else: _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _th = dwgutil.test_bit(data, _bitpos) if _flag: _th = 0.0 else: _bitpos, _th = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _th) if not (_dflag & 0x4): _bitpos, _oblique = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('oblique_angle', _oblique) if not (_dflag & 0x8): _bitpos, _rotation = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('rotation_angle', _rotation) _bitpos, _height = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('height', _height) if not (_dflag & 0x10): _bitpos, _width = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('width_factor', _width) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) if not (_dflag & 0x20): _bitpos, _gen = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('generation', _gen) if not (_dflag & 0x40): _bitpos, _halign = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('halign', _halign) if not (_dflag & 0x80): _bitpos, _valign = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('valign', _valign) _bitpos, _tag = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('tag', _tag) _bitpos, _fl = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('field_length', _fl) _bitpos, _flags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('style_handle', _handle) def attdef_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _dflag = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('data_flag', _dflag) if not (_dflag & 0x1): _bitpos, _elev = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _x1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y1 = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('insertion_point', (_x1, _y1)) if not (_dflag & 0x2): _bitpos, _x = dwgutil.get_default_double(data, _bitpos, _x1) _bitpos, _y = dwgutil.get_default_double(data, _bitpos, _y1) ent.setEntityData('alignment_point', (_x, _y)) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _x = _y = 0.0 _z = 1.0 else: _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _th = dwgutil.test_bit(data, _bitpos) if _flag: _th = 0.0 else: _bitpos, _th = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _th) if not (_dflag & 0x4): _bitpos, _oblique = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('oblique_angle', _oblique) if not (_dflag & 0x8): _bitpos, _rotation = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('rotation_angle', _rotation) _bitpos, _height = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('height', _height) if not (_dflag & 0x10): _bitpos, _width = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('width_factor', _width) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) if not (_dflag & 0x20): _bitpos, _gen = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('generation', _gen) if not (_dflag & 0x40): _bitpos, _halign = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('halign', _halign) if not (_dflag & 0x80): _bitpos, _valign = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('valign', _valign) _bitpos, _tag = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('tag', _tag) _bitpos, _fl = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('field_length', _fl) _bitpos, _flags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _prompt = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('prompt', _prompt) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('style_handle', _handle) def block_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos = tail_read(ent, data, _bitpos) def endblk_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos = tail_read(ent, data, _bitpos) def seqend_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos = tail_read(ent, data, _bitpos) def insert_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('insertion_point', (_x, _y, _z)) _dflag = dwgutil.get_bits(data, 2, _bitpos) _bitpos = _bitpos + 2 if _dflag == 0x0: _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_default_double(data, _bitpos, _x) _bitpos, _z = dwgutil.get_default_double(data, _bitpos, _x) elif _dflag == 0x1: _x = 1.0 _bitpos, _y = dwgutil.get_default_double(data, _bitpos, _x) _bitpos, _z = dwgutil.get_default_double(data, _bitpos, _x) elif _dflag == 0x2: _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _y = _z = _x else: _x = _y = _z = 1.0 ent.setEntityData('scale', (_x, _y, _z)) _bitpos, _rot = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('rotation', _rot) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _hasattr = dwgutil.test_bit(data, _bitpos) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('block_header_handle', _handle) if _hasattr: _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_attrib_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_attrib_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('seqend_handle', _handle) def minsert_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('insertion_point', (_x, _y, _z)) _dflag = dwgutil.get_bits(data, 2, _bitpos) _bitpos = _bitpos + 2 if _dflag == 0x0: _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_default_double(data, _bitpos, _x) _bitpos, _z = dwgutil.get_default_double(data, _bitpos, _x) elif _dflag == 0x1: _x = 1.0 _bitpos, _y = dwgutil.get_default_double(data, _bitpos, _x) _bitpos, _z = dwgutil.get_default_double(data, _bitpos, _x) elif _dflag == 0x2: _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _y = _z = _x else: _x = _y = _z = 1.0 ent.setEntityData('scale', (_x, _y, _z)) _bitpos, _rot = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('rotation', _rot) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _hasattr = dwgutil.test_bit(data, _bitpos) _bitpos, _nc = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('column_count', _nc) _bitpos, _nr = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('row_count', _nr) _bitpos, _colsp = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('column_spacing', _colsp) _bitpos, _rowsp = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('row_spacing', _rowsp) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('block_header_handle', _handle) if _hasattr: _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_attrib_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_attrib_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('seqend_handle', _handle) def vertex2d_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _flags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos, _sw = dwgutil.get_bit_double(data, _bitpos) if _sw < 0.0: _sw = _ew = abs(_sw) else: _bitpos, _ew = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('start_width', _sw) ent.setEntityData('end_width', _ew) _bitpos, _bulge = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('bulge', _bulge) _bitpos, _tandir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('tangent_dir', _tandir) _bitpos = tail_read(ent, data, _bitpos) def vertex3d_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _flags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def vertex_mesh_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _flags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def vertex_pface_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _flags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def vertex_pface_face_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _vi1 = dwgutil.get_bit_short(data, _bitpos) _bitpos, _vi2 = dwgutil.get_bit_short(data, _bitpos) _bitpos, _vi3 = dwgutil.get_bit_short(data, _bitpos) _bitpos, _vi4 = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('points', (_vi1, _vi2, _vi3, _vi4)) _bitpos = tail_read(ent, data, _bitpos) def polyline2d_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _flags = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _ctype = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('curve_type', _ctype) _bitpos, _sw = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('start_width', _sw) _bitpos, _ew = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('end_width', _ew) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _th = 0.0 else: _bitpos, _th = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _th) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _ex = _ey = 0.0 _ez = 1.0 else: _bitpos, _ex = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ey = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ez = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_ex, _ey, _ez)) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_vertext_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('seqend_handle', _handle) def polyline3d_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _sflags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('spline_flags', _sflags) _bitpos, _cflags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('closed_flags', _cflags) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('seqend_handle', _handle) def arc_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('center', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('radius', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _val = 0.0 else: _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _x = _y = 0.0 _z = 1.0 else: _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('start_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('end_angle', _val) _bitpos = tail_read(ent, data, _bitpos) def circle_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('center', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('radius', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _val = 0.0 else: _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _x = _y = 0.0 _z = 1.0 else: _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def line_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _zflag = dwgutil.test_bit(data, _bitpos) _bitpos, _x1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _x2 = dwgutil.get_default_double(data, _bitpos, _x1) _bitpos, _y1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y2 = dwgutil.get_default_double(data, _bitpos, _y1) if _zflag is False: _bitpos, _z1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _z2 = dwgutil.get_default_double(data, _bitpos, _z1) _p1 = (_x1, _y1, _z1) _p2 = (_x2, _y2, _z2) else: _p1 = (_x1, _y1) _p2 = (_x2, _y2) ent.setEntityData('p1', _p1) ent.setEntityData('p2', _p2) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _th = 0.0 else: _bitpos, _th = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _th) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _ex = _ey = 0.0 _ez = 1.0 else: _bitpos, _ex = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ey = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ez = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_ex, _ey, _ez)) _bitpos = tail_read(ent, data, _bitpos) def dimord_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _flags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _rot = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('rotation', _rot) _bitpos, _hdir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_dir', _hdir) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _ir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _ir) _bitpos, _ap = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('attachment_point', _ap) _bitpos, _lss = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('linespace_style', _lss) _bitpos, _lsf = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('linespace_factor', _lsf) _bitpos, _am = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('actual_measurement', _am) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('13-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('14-pt', (_x, _y, _z)) _bitpos, _flags2 = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags2', _flags) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def dimlin_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _flags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _rot = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('rotation', _rot) _bitpos, _hdir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_dir', _hdir) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _ir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _ir) _bitpos, _ap = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('attachment_point', _ap) _bitpos, _lss = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('linespace_style', _lss) _bitpos, _lsf = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('linespace_factor', _lsf) _bitpos, _am = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('actual_measurement', _am) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('13-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('14-pt', (_x, _y, _z)) _bitpos, _elr = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ext_rotation', _elr) _bitpos, _dr = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('dimension_rotation', _dr) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def dimalign_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _flags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _rot = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('rotation', _rot) _bitpos, _hdir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_dir', _hdir) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _ir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _ir) _bitpos, _ap = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('attachment_point', _ap) _bitpos, _lss = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('linespace_style', _lss) _bitpos, _lsf = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('linespace_factor', _lsf) _bitpos, _am = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('actual_measurement', _am) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('13-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('14-pt', (_x, _y, _z)) _bitpos, _elr = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ext_rotation', _elr) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def dimang3p_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _flags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _rot = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('text_rotation', _rot) _bitpos, _hdir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_dir', _hdir) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _ir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _ir) _bitpos, _ap = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('attachment_point', _ap) _bitpos, _lss = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('linespace_style', _lss) _bitpos, _lsf = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('linespace_factor', _lsf) _bitpos, _am = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('actual_measurement', _am) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('13-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('14-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('15-pt', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def dimang2l_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _flags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _rot = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('text_rotation', _rot) _bitpos, _hdir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_dir', _hdir) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _ir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _ir) _bitpos, _ap = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('attachment_point', _ap) _bitpos, _lss = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('linespace_style', _lss) _bitpos, _lsf = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('linespace_factor', _lsf) _bitpos, _am = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('actual_measurement', _am) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('16-pt', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('13-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('14-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('15-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def dimrad_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _flags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _rot = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('text_rotation', _rot) _bitpos, _hdir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_ir', _hdir) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _ir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _ir) _bitpos, _ap = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('attachment_point', _ap) _bitpos, _lss = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('linespace_style', _lss) _bitpos, _lsf = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('linespace_factor', _lsf) _bitpos, _am = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('actual_measurement', _am) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('15-pt', (_x, _y, _z)) _bitpos, _llen = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('leader_length', _llen) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def dimdia_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _flags = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _rot = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('text_rotation', _rot) _bitpos, _hdir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_dir', _hdir) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _ir = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _ir) _bitpos, _ap = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('attachment_point', _ap) _bitpos, _lss = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('linespace_style', _lss) _bitpos, _lsf = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('linespace_factor', _lsf) _bitpos, _am = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('actual_measurement', _am) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('15-pt', (_x, _y, _z)) _bitpos, _llen = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('leader_length', _llen) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def point_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _th = 0.0 else: _bitpos, _th = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _th) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _x = _y = 0.0 _z = 1.0 else: _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _xa = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('x_axis_angle', _xa) _bitpos = tail_read(ent, data, _bitpos) def face3d_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _nf = dwgutil.test_bit(data, _bitpos) # spec says RC, files say otherwise _bitpos, _zflag = dwgutil.test_bit(data, _bitpos) _bitpos, _cx = dwgutil.get_raw_double(data, _bitpos) _dcx = _cx _bitpos, _cy = dwgutil.get_raw_double(data, _bitpos) _dcy = _cy _cz = _dcz = 0.0 if _zflag is False: _bitpos, _cz = dwgutil.get_raw_double(data, _bitpos) _dcz = _cz _corner = (_cx, _cy, _cz) ent.setEntityData('corner1', _corner) _bitpos, _cx = dwgutil.get_default_double(data, _bitpos, _dcx) _dcx = _cx _bitpos, _cy = dwgutil.get_default_double(data, _bitpos, _dcy) _dcy = _cy _bitpos, _cz = dwgutil.get_default_double(data, _bitpos, _dcz) _dcz = _cz _corner = (_cx, _cy, _cz) ent.setEntityData('corner2', _corner) _bitpos, _cx = dwgutil.get_default_double(data, _bitpos, _dcx) _dcx = _cx _bitpos, _cy = dwgutil.get_default_double(data, _bitpos, _dcy) _dcy = _cy _bitpos, _cz = dwgutil.get_default_double(data, _bitpos, _dcz) _dcz = _cz _corner = (_cx, _cy, _cz) ent.setEntityData('corner3', _corner) _bitpos, _cx = dwgutil.get_default_double(data, _bitpos, _dcx) _bitpos, _cy = dwgutil.get_default_double(data, _bitpos, _dcy) _bitpos, _cz = dwgutil.get_default_double(data, _bitpos, _dcz) _corner = (_cx, _cy, _cz) ent.setEntityData('corner4', _corner) if _nf is False: _bitpos, _invis = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('flags', _invis) _bitpos = tail_read(ent, data, _bitpos) def pface_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _nv = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('vertex_count', _nv) _bitpos, _nf = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('face_count', _nf) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('seqend_handle', _handle) def mesh_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _flags = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _ctype = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('curve_type', _ctype) _bitpos, _mvc = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('m_vertices', _mvc) _bitpos, _nvc = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('n_vertices', _nvc) _bitpos, _md = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('m_density', _md) _bitpos, _nd = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('n_density', _md) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('seqend_handle', _handle) def solid_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _th = 0.0 else: _bitpos, _th = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _th) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner1', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner2', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner3', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner4', (_x, _y, _elev)) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _x = _y = 0.0 _z = 1.0 else: _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def trace_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _th = 0.0 else: _bitpos, _th = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _th) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner1', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner2', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner3', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner4', (_x, _y, _elev)) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) if _flag: _x = _y = 0.0 _z = 1.0 else: _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def shape_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('insertion_point', (_x, _y, _z)) _bitpos, _scale = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('scale', _scale) _bitpos, _rot = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('rotation', _rot) _bitpos, _width = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('width', _width) _bitpos, _ob = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('oblique', _ob) _bitpos, _th = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _th) _bitpos, _snum = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('shape_number', _snum) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('shapefile_handle', _handle) def viewport_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('center', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('width', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('height', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_target', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_direction', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_twist_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_height', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('lens_length', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('front_clip_z', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('back_clip_z', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('snap_angle', _val) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('view_center', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('snap_base', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('snap_spacing', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('grid_spacing', (_x, _y)) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('circle_zoom', _val) _bitpos, _flc = dwgutil.get_bit_long(data, _bitpos) _bitpos, _flags = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('status_flags', _flags) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('stylesheet', _text) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('render_mode', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('ucs_at_origin', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('ucs_per_viewport', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ucs_origin', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ucs_x_axis', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ucs_y_axis', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('ucs_ortho_view', _val) _bitpos = tail_read(ent, data, _bitpos) if _flc: _handles = [] for _i in range(_flc): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handles) ent.setEntityData('frozen_layer_handles', _handles) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('clip_boundary_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('viewport_ent_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('named_ucs_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('base_ucs_handle', _handle) def ellipse_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('center', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('major_axis_vector', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('axis_ratio', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('start_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('end_angle', _val) _bitpos = tail_read(ent, data, _bitpos) def spline_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _sc = dwgutil.get_bit_short(data, _bitpos) _bitpos, _deg = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('degree', _deg) _nknots = _nctlpts = _nfitpts = 0 _weight = False if _sc == 2: _bitpos, _ft = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('fit_tolerance', _ft) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('begin_tan_vector', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('end_tan_vector', (_x, _y, _z)) _bitpos, _nfitpts = dwgutil.get_bit_short(data, _bitpos) elif _sc == 1: _bitpos, _rat = dwgutil.test_bit(data, _bitpos) ent.setEntityData('rational', _rat) _bitpos, _closed = dwgutil.test_bit(data, _bitpos) ent.setEntityData('closed', _closed) _bitpos, _per = dwgutil.test_bit(data, _bitpos) ent.setEntityData('periodic', _per) _bitpos, _ktol = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('knot_tolerance', _ktol) _bitpos, _ctol = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('control_tolerance', _ctol) _bitpos, _nknots = dwgutil.get_bit_long(data, _bitpos) _bitpos, _nctlpts = dwgutil.get_bit_long(data, _bitpos) _bitpos, _weight = dwgutil.test_bit(data, _bitpos) else: raise ValueError, "Unexpected scenario: %d" % _sc if _nknots: _knotpts = [] for _i in range(_nknots): _bitpos, _knot = dwgutil.get_bit_double(data, _bitpos) _knotpts.append(_knot) ent.setEntityData('knot_points', _knotpts) if _nctlpts: _ctrlpts = [] _weights = [] for _i in range(_nctlpts): _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) _ctrlpts.append((_x, _y, _z)) if _weight: _bitpos, _w = dwgutil.get_bit_double(data, _bitpos) _weights.append(_w) ent.setEntityData('control_points', _ctrlpts) if _weight: ent.setEntityData('weights', _weights) if _nfitpts: _fitpts = [] for _i in range(_nfitpts): _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) _fitpts.append((_x, _y, _z)) ent.setEntityData('fit_points', _fitpts) _bitpos = tail_read(ent, data, _bitpos) def rsb_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _itype = dwgutil.get_bit_short(data, _bitpos) if (_itype == 64): _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) # print "unknown double: %g" % _val _bitpos, _cib = dwgutil.get_bit_long(data, _bitpos) _data = [] while (_cib != 0): _chars = [] for _i in range(_cib): _bitpos, _ch = dwgutil.get_raw_char(data, _bitpos) if (0x20 < _ch < 0x7e): _sat = 0x9f - _ch elif (_ch == ord("\t")): _sat = ord(" ") else: _sat = _ch _chars.append(_sat) _data.append("".join(_chars)) _bitpos, _cib = dwgutil.get_bit_long(data, _bitpos) else: raise ValueError, "Unexpected itemtype: %d" % _itype # # OpenDWG specs say there is stuff here but they haven't # figured it out, plus there is the tailing handles # skip this for now ... # _bitpos = tail_read(ent, data, _bitpos) def ray_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('vector', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def xline_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('vector', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def dict_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_short(data, _bitpos) _bitpos, _ni = dwgutil.get_bit_long(data, _bitpos) _bitpos, _cflag = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('cloning_flag', _cflag) _bitpos, _hoflag = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('hard_owner_flag', _hoflag) # ??? if _ni: _strings = [] for _i in range(_ni): _bitpos, _text = dwgutil.get_text_string(data, _bitpos) _strings.append(_text) ent.setEntityData('strings', _strings) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ni: _items = [] for _i in range(_ni): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _items.append(_handle) ent.setEntityData('items', _items) def mtext_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('insertion_point', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('x_axis_direction', (_x, _y, _z)) _bitpos, _width = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('width', _width) _bitpos, _height = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('height', _height) _bitpos, _att = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('attachment', _att) _bitpos, _dd = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('drawing_dir', _dd) # ??? _bitpos, _exh = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ext_height', _exh) _bitpos, _exw = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ext_width', _exw) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _lss = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('line_spacing_style', _lss) _bitpos, _lsf = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('line_spacing_factor:', _lsf) _bitpos, _val = dwgutil.test_bit(data, _bitpos) # print "unknown bit: " + str(_val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('style_handle', _handle) def leader_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _u = dwgutil.test_bit(data, _bitpos) # print "unknown bit: " + str(_u) _bitpos, _at = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('annotation_type', _at) _bitpos, _pt = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('path_type', _pt) _bitpos, _npts = dwgutil.get_bit_short(data, _bitpos) _points = [] for _i in range(_npts): _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) _points.append((_x, _y, _z)) ent.setEntityData('points', _points) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('end_pt_proj', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('x_direction', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('offset_block_ins_pt', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) # print "unknown: (%g,%g,%g)" % (_x, _y, _z) _bitpos, _bh = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('box_height', _bh) _bitpos, _bw = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('box_width', _bw) _bitpos, _hook = dwgutil.test_bit(data, _bitpos) ent.setEntityData('hooklineoxdir', _hook) # ??? _bitpos, _arrowon = dwgutil.test_bit(data, _bitpos) ent.setEntityData('arrowhead_on', _arrowon) _bitpos, _us = dwgutil.get_bit_short(data, _bitpos) # print "unknown short: %d" % _us _bitpos, _ub = dwgutil.test_bit(data, _bitpos) # print "unknown bit: " + str(_ub) _bitpos, _ub = dwgutil.test_bit(data, _bitpos) # print "unknown bit: " + str(_ub) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('associated_annotation_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) def tolerance_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('insertion_point', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('x_direction', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _ts = dwgutil.get_bit_short(data, _bitpos) # should this be text_string? ent.setEntityData('string', _ts) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) def mline_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _scale = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('scale', _scale) _bitpos, _just = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('justification', _just) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('base_point', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _oc = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('open_closed', _oc) _bitpos, _lis = dwgutil.get_raw_char(data, _bitpos) _bitpos, _nv = dwgutil.get_bit_short(data, _bitpos) _points = [] for _i in range(_nv): _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) _vertex = (_x, _y, _z) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) _vertex_dir = (_x, _y, _z) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) _miter_dir = (_x, _y, _z) _lines = [] for _j in range(_lis): _bitpos, _ns = dwgutil.get_bit_short(data, _bitpos) _segparms = [] for _k in range(_ns): _bitpos, _sp = dwgutil.get_bit_double(data, _bitpos) _segparms.append(_sp) _bitpos, _na = dwgutil.get_bit_short(data, _bitpos) _fillparms = [] for _k in range(_na): _bitpos, _afp = dwgutil.get_bit_double(data, _bitpos) _fillparms.append(_afp) _lines.append((_segparms, _fillparms)) _points.append((_vertex, _vertex_dir, _miter_dir, _lines)) ent.setEntityData('points', _points) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('mline_style_object_handle', _handle) def block_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _enum = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _enum: _handles = [] for _i in range(_enum): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('code_2_handles', _handles) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('*model_space_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('*paper_space_handle', _handle) def block_header_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _name = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _name) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _flag) # print "bitpos: %d" % _bitpos _bitpos, _xrefplus1 = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _xrefplus1) _bitpos, _xdep = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _xdep) _bitpos, _anon = dwgutil.test_bit(data, _bitpos) ent.setEntityData('anonymous', _anon) # print "bitpos: %d" % _bitpos _bitpos, _hasatts = dwgutil.test_bit(data, _bitpos) ent.setEntityData('has_attrs', _hasatts) _bitpos, _bxref = dwgutil.test_bit(data, _bitpos) ent.setEntityData('blk_is_xref', _bxref) _bitpos, _xover = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xrefoverlaid', _xover) # print "bitpos: %d" % _bitpos _bitpos, _loaded = dwgutil.test_bit(data, _bitpos) ent.setEntityData('loaded', _loaded) _bitpos, _bx = dwgutil.get_bit_double(data, _bitpos) _bitpos, _by = dwgutil.get_bit_double(data, _bitpos) _bitpos, _bz = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('base_point', (_bx, _by, _bz)) # print "bitpos: %d" % _bitpos _bitpos, _pname = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('xref_pname', _pname) # print "bitpos: %d" % _bitpos _icount = 0 while True: _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) if _val == 0: break _icount = _icount + 1 # print "insert count: %#x" % _icount # print "bitpos: %d" % _bitpos _bitpos, _desc = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('block_description', _desc) # print "bitpos: %d" % _bitpos _bitpos, _pdsize = dwgutil.get_bit_long(data, _bitpos) # print "preview data size: %d" % _pdsize # print "bitpos: %d" % _bitpos if _pdsize: _count = _pdsize * _icount _pdata = dwgutil.get_bits(data, _count, _bitpos) ent.setEntityData('preview_data', _pdata) _bitpos = _bitpos + _count _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('block_control_handle', _handle) # print "bitpos: %d" % _bitpos for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('block_entity_handle', _handle) if not _bxref and not _xover: _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_entity_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_entity_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('endblk_entity_handle', _handle) if _icount: _handles = [] for _i in range(_icount): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('insert_handles', _handles) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('layout_handle', _handle) def layer_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('code_2_handles', _handles) def layer_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _name = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _name) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _flag) _bitpos, _xrefplus1 = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _xrefplus1) _bitpos, _xdep = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _xdep) _bitpos, _flags = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _color = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('color', _color) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('layer_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('plotstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('linetype_handle', _handle) def shapefile_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('shapefile_handles', _handles) def shapefile_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _name = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _name) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _flag) _bitpos, _xrefplus1 = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _xrefplus1) _bitpos, _xdep = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _xdep) _bitpos, _vert = dwgutil.test_bit(data, _bitpos) ent.setEntityData('vertical', _vert) _bitpos, _sf = dwgutil.test_bit(data, _bitpos) ent.setEntityData('shape_file', _sf) _bitpos, _fh = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('fixed_height', _fh) _bitpos, _fw = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('fixed_width', _fw) _bitpos, _ob = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('oblique_angle', _ob) _bitpos, _gen = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('generation', _gen) _bitpos, _lh = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('last_height', _lh) _bitpos, _fn = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('font_name', _fn) _bitpos, _bfn = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('big_font_name', _bfn) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('shapefile_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) def linetype_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('entity_count', _ne) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('handles', _handles) def linetype_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _name = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _name) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _flag) _bitpos, _xrefplus1 = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _xrefplus1) _bitpos, _xdep = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _xdep) _bitpos, _desc = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('description', _desc) _bitpos, _pl = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('pattern_length', _pl) _bitpos, _align = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('alignment', _align) _bitpos, _nd = dwgutil.get_raw_char(data, _bitpos) if _nd: _dashes = [] for _i in range(_nd): _bitpos, _dl = dwgutil.get_bit_double(data, _bitpos) _bitpos, _cs = dwgutil.get_bit_short(data, _bitpos) _bitpos, _xo = dwgutil.get_raw_double(data, _bitpos) _bitpos, _yo = dwgutil.get_raw_double(data, _bitpos) _bitpos, _scale = dwgutil.get_bit_double(data, _bitpos) _bitpos, _rot = dwgutil.get_bit_double(data, _bitpos) _bitpos, _sf = dwgutil.get_bit_short(data, _bitpos) _dashes.append((_dl, _cs, _xo, _yo, _scale, _rot, _sf)) ent.setEntityData('dashes', _dashes) _strings = dwgutil.get_bits(data, 256, _bitpos) _bitpos = _bitpos + 256 ent.setEntityData('strings', _strings) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('linetype_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) def view_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('view_handles', _handles) def view_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _name = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _name) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _flag) _bitpos, _xrefplus1 = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _xrefplus1) _bitpos, _xdep = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _xdep) _bitpos, _vh = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_height', _vh) _bitpos, _vw = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_width', _vw) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('view_center', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('target', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_dir', (_x, _y, _z)) _bitpos, _ta = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('twist_angle', _ta) _bitpos, _ll = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('lens_length', _ll) _bitpos, _fc = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('front_clip', _fc) _bitpos, _bc = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('back_clip', _bc) _vm = dwgutil.get_bits(data, 4, _bitpos) _bitpos = _bitpos + 4 ent.setEntityData('view_control_flags', _vm) _bitpos, _rmode = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('render_mode', _rmode) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('pspace_flag', _flag) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('view_control_handle', _handle) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('associated_ucs', _val) if _val: _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ucs_origin', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ucs_x_axis', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ucs_y_axis', (_x, _y, _z)) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _ovtype = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('orthographic_view_type', _ovtype) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('base_ucs_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('named_ucs_handle', _handle) def ucs_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) # print "numentries: %d" % _ne _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('ucs_handles', _handles) def ucs_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _name = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _name) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _flag) _bitpos, _xrefplus1 = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _xrefplus1) _bitpos, _xdep = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _xdep) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('origin', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('x_direction', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('y_direction', (_x, _y, _z)) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _ovtype = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('orthographic_view_type', _ovtype) _bitpos, _otype = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('orthographic_type', _otype) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('ucs_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('base_ucs_handle',_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('unknown_handle', _handle) def vport_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('vport_handles', _handles) def vport_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _flag) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _flag) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_height', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('aspect_ratio', _val) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('view_center', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('target', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_dir', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('twist_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('lens_length', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('front_clip', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('back_clip', _val) _flags = dwgutil.get_bits(data, 4, _bitpos) _bitpos = _bitpos + 4 ent.setEntityData('vport_flags', _flags) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('render_mode', _val) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('lower_left', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('upper_right', (_x, _y)) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('ucsfollow', _flag) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('circle_zoom', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('fast_zoom', _flag) _flags = dwgutil.get_bits(data, 2, _bitpos) _bitpos = _bitpos + 2 ent.setEntityData('ucsicon', _flags) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('grid_status', _flag) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('grid_spacing', (_x, _y)) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('snap_status', _flag) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('snap_style', _flag) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('snap_isopair', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('snap_rotation', _val) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('snap_base', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('snap_spacing', (_x, _y)) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('unknown_bit', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('ucs_per_viewport', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('origin', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('x_direction', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('y_direction', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('orthographic_view_type', _val) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('vport_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('base_ucs_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('named_handle', _handle) def appid_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('appid_handles', _handles) def appid_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _name = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _name) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _flag) _bitpos, _xrefplus1 = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _xrefplus1) _bitpos, _xdep = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _xdep) _bitpos, _u = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('unknown_char', _u) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('appid_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) def dimstyle_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) # print "bitpos: %d" % _bitpos _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) # print "numentries: %d" % _ne # print "bitpos: %d" % _bitpos _bitpos, _nc5 = dwgutil.get_raw_char(data, _bitpos) # code 5 handles not in spec # print "bitpos: %d" % _bitpos _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) # print "bitpos: %d" % _bitpos _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) # print "bitpos: %d" % _bitpos if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('dimstyle_handles', _handles) # print "bitpos: %d" % _bitpos if _nc5: _handles = [] for _i in range(_nc5): # not in spec _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('code_5_handles', _handles) # print "bitpos: %d" % _bitpos def dimstyle_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _name = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _name) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _flag) _bitpos, _xrefplus1 = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _xrefplus1) _bitpos, _xdep = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _xdep) _bitpos, _string = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('DIMPOST', _string) _bitpos, _string = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('DIMAPOST', _string) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMSCALE', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMASZ', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMEXO', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMDLI', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMEXE', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMRND', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMDLE', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMTP', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMTM', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMTOL', _flag) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMLIM', _flag) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMTIH', _flag) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMTOH', _flag) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMSE1', _flag) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMSE2', _flag) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMTAD', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMZIN', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMAZIN', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMTXT', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMCEN', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMTSZ', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMALTF', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMLFAC', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMTVP', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMTFAC', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMGAP', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMALTRND', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMALT', _flag) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMALTD', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMTOFL', _flag) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMSAH', _flag) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMTIX', _flag) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMSOXD', _flag) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMCLRD', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMCLRE', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMCLRT', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMADEC', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMDEC', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMTDEC', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMALTU', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMALTTD', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMAUNIT', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMFRAC', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMLUNIT', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMDSEP', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMTMOVE', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMJUST', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMSD1', _flag) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMSD2', _flag) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMTOLJ', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMTZIN', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMALTZ', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMALTTZ', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMUPT', _flag) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMFIT', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMLWD', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMLWE', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('unknown', _flag) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('shapefile_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('leader_block_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimblk_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimblk1_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimblk2_handle', _handle) def vpentity_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) # print "numentries: %d" % _ne _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('vpentity_handles', _handles) def vpentity_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _name = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _name) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _flag) _bitpos, _xrefplus1 = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _xrefplus1) _bitpos, _xdep = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _xdep) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('1-flag', _flag) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('vpentity_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('next_vpentity_handle', _handle) def group_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _name = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _name) _bitpos, _unnamed = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('unnamed', _unnamed) _bitpos, _selectable = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('selectable', _selectable) _bitpos, _nh = dwgutil.get_bit_long(data, _bitpos) # print "numhandles: %d" % _nh _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _nh: _handles = [] for _i in range(_nh): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('entry_handles', _handles) def mlinestyle_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _name = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _name) _bitpos, _desc = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('description', _desc) _bitpos, _flags = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('flags', _flags) _bitpos, _fc = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('fill_color', _fc) _bitpos, _sa = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('start_angle', _sa) _bitpos, _ea = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('end_angle', _ea) _bitpos, _lc = dwgutil.get_raw_char(data, _bitpos) if _lc: _lines = [] for _i in range(_lc): _bitpos, _offset = dwgutil.get_bit_double(data, _bitpos) _bitpos, _color = dwgutil.get_bit_short(data, _bitpos) _bitpos, _ltindex = dwgutil.get_bit_short(data, _bitpos) _lines.append((_offset, _color, _ltindex)) ent.setEntityData('lines', _lines) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) def dictionaryvar_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _iv = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('intval', _iv) _bitpos, _s = dwgutil.get_text_string(data, _bitpos) # spec says bit_short ent.setEntityData('string', _s) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) def hatch_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('z_coord', _z) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _name = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _name) _bitpos, _sfill = dwgutil.test_bit(data, _bitpos) ent.setEntityData('solid_fill', _sfill) _bitpos, _assoc = dwgutil.test_bit(data, _bitpos) ent.setEntityData('associative', _assoc) _bitpos, _np = dwgutil.get_bit_long(data, _bitpos) # print "numpaths: %d" % _np _allbounds = 0 _pixel = 0 _paths = [] for _i in range(_np): _bitpos, _pf = dwgutil.get_bit_long(data, _bitpos) if _pf & 0x4: _pixel = _pixel + 1 if (_pf & 0x2): # POLYLINE _bitpos, _bulges = dwgutil.test_bit(data, _bitpos) _bitpos, _closed = dwgutil.test_bit(data, _bitpos) _bitpos, _nps = dwgutil.get_bit_long(data, _bitpos) _segs = [] for _j in range(_nps): _bitpos, _x1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y1 = dwgutil.get_raw_double(data, _bitpos) _bulge = None if (_bulges): _bitpos, _bulge = dwgutil.get_bit_double(data, _bitpos) _segs.append((_x1, _y1, _bulge)) _paths.append(('polyline', _segs)) else: _bitpos, _nps = dwgutil.get_bit_long(data, _bitpos) _segs = [] for _j in range(_nps): _bitpos, _pts = dwgutil.get_raw_char(data, _bitpos) if (_pts == 1): # LINE _bitpos, _x1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _x2 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y2 = dwgutil.get_raw_double(data, _bitpos) _segs.append(('line', _x1, _y1, _x2, _y2)) elif (_pts == 2): # CIRCULAR ARC _bitpos, _xc = dwgutil.get_raw_double(data, _bitpos) _bitpos, _yc = dwgutil.get_raw_double(data, _bitpos) _bitpos, _r = dwgutil.get_bit_double(data, _bitpos) _bitpos, _sa = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ea = dwgutil.get_bit_double(data, _bitpos) _bitpos, _isccw = dwgutil.test_bit(data, _bitpos) _segs.append(('arc', _xc, _yc, _r, _sa, _ea, _isccw)) elif (_pts == 3): # ELLIPTICAL ARC _bitpos, _xc = dwgutil.get_raw_double(data, _bitpos) _bitpos, _yc = dwgutil.get_raw_double(data, _bitpos) _bitpos, _xe = dwgutil.get_raw_double(data, _bitpos) _bitpos, _ye = dwgutil.get_raw_double(data, _bitpos) _bitpos, _ratio = dwgutil.get_bit_double(data, _bitpos) _bitpos, _sa = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ea = dwgutil.get_bit_double(data, _bitpos) _bitpos, _isccw = dwgutil.test_bit(data, _bitpos) _segs.append(('elliptical_arc', _xc, _yc, _xe, _ye, _ratio, _sa, _ea, _isccw)) elif (_pts == 4): # SPLINE _bitpos, _deg = dwgutil.get_bit_long(data, _bitpos) _bitpos, _israt = dwgutil.test_bit(data, _bitpos) _bitpos, _isper = dwgutil.test_bit(data, _bitpos) _bitpos, _nknots = dwgutil.get_bit_long(data, _bitpos) _bitpos, _nctlpts = dwgutil.get_bit_long(data, _bitpos) _knots = [] for _k in range(_nknots): _bitpos, _knot = dwgutil.get_bit_double(data, _bitpos) _knots.append(_knot) _ctlpts = [] for _k in range(_nctlpts): _bitpos, _x1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y1 = dwgutil.get_raw_double(data, _bitpos) _weight = None if (_israt): _bitpos, _weight = dwgutil.get_bit_double(data, _bitpos) _ctlpts.append((_x1, _y1, _weight)) _segs.append(('spline', _israt, _isper, _knots, _ctlpts)) else: raise ValueError, "Unexpected path type: %d" % _pts _paths.append(('stdpath', _segs)) _bitpos, _nbh = dwgutil.get_bit_long(data, _bitpos) _allbounds = _allbounds + _nbh _bitpos, _style = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('style', _style) _bitpos, _pattype = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('pattern_type', _pattype) if not _sfill: _bitpos, _angle = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('fill_angle', _angle) _bitpos, _sos = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('fill_scale_or_spacing', _sos) _bitpos, _dh = dwgutil.test_bit(data, _bitpos) ent.setEntityData('fill_doublehatch', _dh) _bitpos, _ndf = dwgutil.get_bit_short(data, _bitpos) _lines = [] for _i in range(_ndf): _bitpos, _angle = dwgutil.get_bit_double(data, _bitpos) _bitpos, _x1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ox = dwgutil.get_bit_double(data, _bitpos) _bitpos, _oy = dwgutil.get_bit_double(data, _bitpos) _bitpos, _nds = dwgutil.get_bit_short(data, _bitpos) _dashes = [] for _j in range(_nds): _bitpos, _dl = dwgutil.get_bit_double(data, _bitpos) _dashes.append(_dl) _lines.append((_angle, _x1, _y1, _ox, _oy, _dashes)) ent.setEntityData('fill_lines', _lines) if _pixel: _bitpos, _ps = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('pixel_size', _ps) _bitpos, _nsp = dwgutil.get_bit_long(data, _bitpos) if _nsp: _seedpts = [] for _i in range(_nsp): _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) _seedpts.append((_x, _y)) ent.setEntityData('seed_points', _seedpts) _bitpos = tail_read(ent, data, _bitpos) if _allbounds: _boundaries = [] for _i in range(_allbounds): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _boundaries.append(_handle) ent.setEntityData('boundary_handles', _boundaries) def idbuffer_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _u = dwgutil.get_raw_char(data, _bitpos) # print "unknown char: %#02x" % _u _bitpos, _nids = dwgutil.get_bit_long(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _nids: _handles = [] for _i in range(_nids): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('objid_handles', _handles) def image_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('class_version', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('pt0', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('uvec', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('vvec', (_x, _y, _z)) _bitpos, _val = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('height', _val) _bitpos, _val = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('width', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('display_props', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('clipping', _flag) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('brightness', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('contrast', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('fade', _val) _bitpos, _cbt = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('clip_type', _cbt) if (_cbt == 1): _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner1', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner2', (_x, _y)) else: _bitpos, _ncv = dwgutil.get_bit_long(data, _bitpos) _verts = [] for _i in range(_ncv): _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) _verts.append((_x, _y)) ent.setEntityData('vertices', _verts) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('imagedef_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('imagedef_reactor_handle', _handle) def imagedef_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _clsver = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('class_version', _clsver) _bitpos, _val = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('width', _val) _bitpos, _h = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('height', _val) _bitpos, _filepath = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('filepath', _filepath) _bitpos, _isloaded = dwgutil.test_bit(data, _bitpos) ent.setEntityData('is_loaded', _isloaded) _bitpos, _res = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('res_units', _res) _bitpos, _val = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('pixel_width', _val) _bitpos, _val = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('pixel_height', _val) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) def imagedefreactor_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _clsver = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('class version', _clsver) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) def layer_index_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ts1 = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('timestamp1', _ts1) _bitpos, _ts2 = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('timestamp2', _ts2) _bitpos, _ne = dwgutil.get_bit_long(data, _bitpos) if _ne: _indicies = [] for _i in range(_ne): _bitpos, _il = dwgutil.get_bit_long(data, _bitpos) _bitpos, _is = dwgutil.get_text_string(data, _bitpos) _indicies.append((_il, _is)) ent.setEntityData('index_handles', _indicies) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _entries = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _entries.append(_handle) ent.setEntityData('entry_handles', _entries) def layout_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _string = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('page_setup_name', _string) _bitpos, _string = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('printer_config', _string) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('plot_layout_flags', _val) _bitpos, _lm = dwgutil.get_bit_double(data, _bitpos) _bitpos, _bm = dwgutil.get_bit_double(data, _bitpos) _bitpos, _rm = dwgutil.get_bit_double(data, _bitpos) _bitpos, _tm = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('margins', (_lm, _bm, _rm, _tm)) _bitpos, _pw = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ph = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('paper_dim', (_pw, _ph)) _bitpos, _string = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('paper_size', _string) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('plot_origin', (_x, _y)) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('paper_units', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('plot_rotation', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('plot_type', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('window_min', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('window_max', (_x, _y)) _bitpos, _string = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('plot_view_name', _string) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('real_world_units', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('drawing_units', _val) _bitpos, _string = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('current_style_sheet', _string) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('scale_type', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('scale_factor', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('paper_image_origin', (_x, _y)) _bitpos, _string = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('layout_name', _string) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('tab_order', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('layout_flag', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ucs_origin', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('layout_minima', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('layout_maxima', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_point', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ucs_x_axis', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ucs_y_axis', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('orthoview_type', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extmin', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extmax', (_x, _y, _z)) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('paperspace_block_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_active_viewport_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('base_ucs_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('named_ucs_handle', _handle) def lwpline_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _flag = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('flag', _flag) _cw = 0.0 if (_flag & 0x4): _bitpos, _cw = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('const_width', _cw) _elev = 0.0 if (_flag & 0x8): _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _th = 0.0 if (_flag & 0x2): _bitpos, _th = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _th) _nx = _ny = _nz = 0.0 if (_flag & 0x1): _bitpos, _nx = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ny = dwgutil.get_bit_double(data, _bitpos) _bitpos, _nz = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('normal', (_nx, _ny, _nz)) _bitpos, _np = dwgutil.get_bit_long(data, _bitpos) _nb = 0 if (_flag & 0x10): _bitpos, _nb = dwgutil.get_bit_long(data, _bitpos) _nw = 0 if (_flag & 0x20): _bitpos, _nw = dwgutil.get_bit_long(data, _bitpos) _verticies = [] _bitpos, _vx = dwgutil.get_raw_double(data, _bitpos) _bitpos, _vy = dwgutil.get_raw_double(data, _bitpos) # print "first vertex: (%g,%g)" % (_vx, _vy) _verticies.append((_vx, _vy)) for _i in range((_np - 1)): _bitpos, _x = dwgutil.get_default_double(data, _bitpos, _vx) _bitpos, _y = dwgutil.get_default_double(data, _bitpos, _vy) _verticies.append((_x, _y)) _vx = _x _vy = _y ent.setEntityData('verticies', _verticies) if _nb: _bulges = [] for _i in range(_nb): _bitpos, _bulge = dwgutil.get_raw_double(data, _bitpos) _bulges.append(_bulge) ent.setEntityData('bulges', _bulges) if _nw: _widths = [] for _i in range(_nw): _bitpos, _sw = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ew = dwgutil.get_bit_double(data, _bitpos) _widths.append((_sw, _ew)) ent.setEntityData('widths', _widths) _bitpos = tail_read(ent, data, _bitpos) def rastervariables_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _clsver = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('class_version', _clsver) _bitpos, _df = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('dispfrm', _df) _bitpos, _dq = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('dispqual', _dq) _bitpos, _units = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('units', _units) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) def sortentstable_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_long(data, _bitpos) # print "numentries: %d" % _ne if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('sort_handles', _handles) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) # # the spec says there is an owner handle here # # _bitpos, _handle = dwgutil.get_handle(data, _bitpos) # print "owner handle: " + str(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('obj_handles', _handles) def spatial_filter_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _npts = dwgutil.get_bit_short(data, _bitpos) if _npts: _points = [] for _i in range(_npts): _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) _points.append((_x, _y)) ent.setEntityData('points', _points) _bitpos, _ex = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ey = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ez = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_ex, _ey, _ez)) _bitpos, _cx = dwgutil.get_bit_double(data, _bitpos) _bitpos, _cy = dwgutil.get_bit_double(data, _bitpos) _bitpos, _cz = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('clip_bound_origin', (_cx, _cy, _cz)) _bitpos, _db = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('disp_bound', _db) _bitpos, _fc = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('front_clip_on', _fc) _bitpos, _fd = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('front_dist', _fd) _bitpos, _bc = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('back_clip_on', _bc) _bitpos, _bd = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('back_dist', _bd) _invtr = array.array('d', 12 * [0.0]) for _i in range(12): _bitpos, _invtr[_i] = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('inv_array', _invtr) _clptr = array.array('d', 12 * [0.0]) for _i in range(12): _bitpos, _clptr[_i] = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('clip_array', _clptr) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) def spatial_index_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ts1 = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('timestamp1', _ts1) _bitpos, _ts2 = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('timestamp2', _ts2) # # fixme - lots of unknown stuff here # ... def xrecord_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ndb = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('data_bytes', _ndb) # # fixme - more stuff here ... # _objprops = [ (False, None), # Unused [0x00] (True, text_reader), # Text (True, attrib_reader), # Attrib (True, attdef_reader), # Attdef (True, block_reader), # Block (True, endblk_reader), # Endblk (True, seqend_reader), # Seqend (True, insert_reader), # Insert (True, minsert_reader), # Minsert [0x08] (False, None), # Skipped [0x09] (True, vertex2d_reader), # Vertex_2D (True, vertex3d_reader), # Vertex_3D (True, vertex_mesh_reader), # Vertex_mesh (True, vertex_pface_reader), # Vertex_pface (True, vertex_pface_face_reader), # Vertex_pface_face (True, polyline2d_reader), # Polyline_2D (True, polyline3d_reader), # Polyline_3D [0x10] (True, arc_reader), # Arc, (True, circle_reader), # Circle, (True, line_reader), # Line (True, dimord_reader), # Dimension_ord (True, dimlin_reader), # Dimension_lin (True, dimalign_reader), # Dimension_align (True, dimang3p_reader), # Dimension_angle_3pt (True, dimang2l_reader), # Dimension_angle_2ln [0x18] (True, dimrad_reader), # Dimension_radius (True, dimdia_reader), # Dimension_diameter (True, point_reader), # Point (True, face3d_reader), # Face3D (True, pface_reader), # Polyline_pface (True, mesh_reader), # Polyline_mesh (True, solid_reader), # Solid (True, trace_reader), # Trace [0x20] (True, shape_reader), # Shape (True, viewport_reader), # Viewport (True, ellipse_reader), # Ellipse (True, spline_reader), # Spline (True, rsb_reader), # Region (True, rsb_reader), # Solid3D (True, rsb_reader), # Body (True, ray_reader), # Ray [0x28] (True, xline_reader), # Xline (False, dict_reader), # Dictionary (False, None), # Skipped [0x2b] (True, mtext_reader), # Mtext (True, leader_reader), # Leader (True, tolerance_reader), # Tolerance (True, mline_reader), # Mline (False, block_control_reader), # Block control [0x30] (False, block_header_reader), # Block header (False, layer_control_reader), # Layer control (False, layer_reader), # Layer (False, shapefile_control_reader), # Style control (False, shapefile_reader), # Style (False, None), # Skipped [0x36] (False, None), # Skipped [0x37] (False, linetype_control_reader), # Linetype control [0x38] (False, linetype_reader), # Linetype (False, None), # Skipped [0x3a] (False, None), # Skipped [0x3b] (False, view_control_reader), # View control [0x3c] (False, view_reader), # View (False, ucs_control_reader), # UCS control, (False, ucs_reader), # UCS (False, vport_control_reader), # Vport control [0x40] (False, vport_reader), # Vport (False, appid_control_reader), # Appid control (False, appid_reader), # Appid (False, dimstyle_control_reader), # Dimstyle control (False, dimstyle_reader), # Dimstyle (False, vpentity_control_reader), # VP ENT HDR control (False, vpentity_reader), # VP ENT HDR (False, group_reader), # Group [0x48] (False, mlinestyle_reader), # Mlinestyle ] _vobjmap = { 'DICTIONARYVAR' : dictionaryvar_reader, 'HATCH' : hatch_reader, 'IDBUFFER' : idbuffer_reader, 'IMAGE' : image_reader, 'IMAGEDEF' : imagedef_reader, 'IMAGEDEFREACTOR' : imagedefreactor_reader, 'LAYER_INDEX' : layer_index_reader, 'LAYOUT' : layout_reader, 'LWPLINE' : lwpline_reader, # 'OLE2FRAME' : ole2frame_reader, 'RASTERVARIABLES' : rastervariables_reader, 'SORTENTSTABLE' : sortentstable_reader, 'SPATIAL_FILTER' : spatial_filter_reader, 'SPATIAL_INDEX' : spatial_index_reader, 'XRECORD' : xrecord_reader } def get_object(dwg, offset): _handle = dwg.getHandle() _handle.seek(offset, 0) _size = dwgutil.get_modular_short(_handle) _data = array.array('B') _data.fromfile(_handle, _size) _ent = dwgbase.dwgEntity() # _ent.setEntityData('bitstream', data) # save the bitstream data _bitpos = 0 _bitpos, _type = dwgutil.get_bit_short(_data, _bitpos) _ent.setType(_type) _bitpos, _objbsize = dwgutil.get_raw_long(_data, _bitpos) _ent.setEntityData('size_in_bits', _objbsize) _bitpos, _handle = dwgutil.get_handle(_data, _bitpos) _ent.setHandle(_handle) _bitpos, _extdata = dwgutil.read_extended_data(_data, _bitpos) _ent.setEntityData('extended_data', _extdata) # # use the objprops table to determine if the _entity # has a graphics bit and the appropriate bitstream # decoding function # _gflag = False _reader = None if _type < len(_objprops): _gflag, _reader = _objprops[_type] if _gflag: _bitpos, _val = dwgutil.test_bit(_data, _bitpos) if _val is True: _bitpos, _size = dwgutil.get_raw_long(_data, _bitpos) _bgsize = _size * 8 _gidata = dwgutil.get_bits(_data, _bgsize, _bitpos) _ent.setEntityData('graphic_data', _gidata) _bitpos = _bitpos + _bgsize if _reader is not None: _reader(_ent, _data, _bitpos) else: _stype = dwg.getDxfName(_type) if _stype is not None: if _stype == 'HATCH': # where is the data kept? _bitpos, _val = dwgutil.test_bit(_data, _bitpos) if _stype in _vobjmap: _vobjmap[_stype](_ent, _data, _bitpos) return _ent def read_second_header(handle, offset): # print "read_second_header() ..." handle.seek(offset, 0) _at = handle.tell() # print "offset at %d [%#x]" % (_at, _at) _s = array.array('B') _s.fromfile(handle, 16) if _s[0] != 0xd4: raise ValueError, "_s[0] != 0xd4" if _s[1] != 0x7b: raise ValueError, "_s[1] != 0x7b" if _s[2] != 0x21: raise ValueError, "_s[2] != 0x21" if _s[3] != 0xce: raise ValueError, "_s[3] != 0xce" if _s[4] != 0x28: raise ValueError, "_s[4] != 0x28" if _s[5] != 0x93: raise ValueError, "_s[5] != 0x93" if _s[6] != 0x9f: raise ValueError, "_s[6] != 0x9f" if _s[7] != 0xbf: raise ValueError, "_s[7] != 0xbf" if _s[8] != 0x53: raise ValueError, "_s[8] != 0x53" if _s[9] != 0x24: raise ValueError, "_s[9] != 0x24" if _s[10] != 0x40: raise ValueError, "_s[10] != 0x40" if _s[11] != 0x09: raise ValueError, "_s[11] != 0x09" if _s[12] != 0x12: raise ValueError, "_s[12] != 0x12" if _s[13] != 0x3c: raise ValueError, "_s[13] != 0x3c" if _s[14] != 0xaa: raise ValueError, "_s[14] != 0xaa" if _s[15] != 0x01: raise ValueError, "_s[15] != 0x01" # _at = handle.tell() # print "offset at %d [%#x]" % (_at, _at) _size = struct.unpack(' 90.0: _fa = fmod(_angle, 360.0) if abs(_fa) < 1e-10: _angle = 0.0 elif _fa > 0.0: if _fa > 270.0: _angle = _fa - 360.0 elif _fa > 90.0: _angle = _fa - 180.0 else: _angle = _fa else: if _fa < -270.0: _angle = _fa + 360.0 elif _fa < -90.0: _angle = _fa + 180.0 else: _angle = _fa return _angle def make_c_angle(angle): """Return an angle value such that 0 <= angle <= 360. make_c_angle(angle) The argument angle should be a float. """ _a = get_float(angle) if _a < 0.0: _a = fmod(_a, 360.0) + 360.0 elif _a > 360.0: _a = fmod(_a, 360.0) return _a def make_coords(x, y): """Check and convert x/y values to float values. make_coords(x, y) This routine is used to ensure the values are float values. """ _x = get_float(x) _y = get_float(y) return _x, _y def make_region(xmin, ymin, xmax, ymax): """Return a validated region defined by (xmin, ymin) to (xmax, ymax). make_region(xmin, ymin, xmax, ymax) This routine is used to ensure the values are floats and that xmin < xmax and ymin < ymax. """ _xmin = get_float(xmin) _ymin = get_float(ymin) _xmax = get_float(xmax) if _xmax < _xmin: raise ValueError, "Invalid values: xmax < xmin" _ymax = get_float(ymax) if _ymax < _ymin: raise ValueError, "Invalid values: ymax < ymin" return _xmin, _ymin, _xmax, _ymax def degrees(value): """Convert a value from radians to degrees. degrees(value) In Python 2.3 this is available as the math.degrees() function, but the value isn't scaled from -360.0 <= angle <= 360.0 """ _value = get_float(value) return fmod(_value, 360.0) def radians(value): """Convert a value from degrees to radians. radians(value) In Python 2.3 this is available ad the math.radians() function, but the value isn't scaled from -2*pi <= angle <= 2*pi """ _value = get_float(value) return fmod(_value, (2.0 * pi)) # # map x/y coordinates to a (x1, y1)->(x2, y2) segment # def map_coords(x, y, x1, y1, x2, y2, tol=tolerance.TOL): """ map_coords(x, y, x1, y1, x2, y2[, tol]) """ _x = get_float(x) _y = get_float(y) _x1 = get_float(x1) _y1 = get_float(y1) _x2 = get_float(x2) _y2 = get_float(y2) _t = tolerance.toltest(tol) if ((_x < min(_x1, _x2) - _t) or (_y < min(_y1, _y2) - _t) or (_x > max(_x1, _x2) + _t) or (_y > max(_y1, _y2) + _t)): return None _sqlen = pow((_x2 - _x1), 2) + pow((_y2 - _y1), 2) if _sqlen < 1e-10: # coincident points return None _r = ((_x - _x1)*(_x2 - _x1) + (_y - _y1)*(_y2 - _y1))/_sqlen if _r < 0.0: _r = 0.0 if _r > 1.0: _r = 1.0 _px = _x1 + _r * (_x2 - _x1) _py = _y1 + _r * (_y2 - _y1) if abs(_px - _x) < _t and abs(_py - _y) < _t: return _px, _py return None # # test if line segments are visible within a rectangular region # def in_region(x1, y1, x2, y2, xmin, ymin, xmax, ymax): """Test if a segment from (x1, y1)->(x2, y2) is in region. in_region(x1, y1, x2, y2, xmin, ymin, xmax, ymax) """ _x1 = get_float(x1) _y1 = get_float(y1) _x2 = get_float(x2) _y2 = get_float(y2) _xmin = get_float(xmin) _ymin = get_float(ymin) _xmax = get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" if not ((_x1 < _xmin) or (_x1 > _xmax) or (_y1 < _ymin) or (_y1 > _ymax)): return True if not ((_x2 < _xmin) or (_x2 > _xmax) or (_y2 < _ymin) or (_y2 > _ymax)): return True # # simple horizontal/vertical testing # if abs(_y2 - _y1) < 1e-10: # horizontal if not ((_y1 < _ymin) or (_y1 > _ymax)): if min(_x1, _x2) < _xmin and max(_x1, _x2) > _xmax: return True if abs(_x2 - _x1) < 1e-10: # vertical if not ((_x1 < _xmin) or (_x1 > _xmax)): if min(_y1, _y2) < _ymin and max(_y1, _y2) > _ymax: return True # # see if segment intersects an imaginary segment # from (xmin, ymax) to (xmax, ymin) # # p1 = (xmin, ymax) # p2 = (xmax, ymin) # p3 = (x1, y1) # p4 = (x2, y2) # _d = ((_xmax - _xmin)*(_y2 - _y1)) - ((_ymin - _ymax)*(_x2 - _x1)) if abs(_d) > 1e-10: _n = ((_ymax - _y1)*(_x2 - _x1)) - ((_xmin - _x1)*(_y2 - _y1)) _r = _n/_d if 0.0 < _r < 1.0: return True # # see if segment intersects an imaginary segment # from (xmin, ymin) to (xmax, ymax) # # p1 = (xmin, ymin) # p2 = (xmax, ymax) # p3 = (x1, y1) # p4 = (x2, y2) # _d = ((_xmax - _xmin)*(_y2 - _y1)) - ((_ymax - _ymin)*(_x2 - _x1)) if abs(_d) > 1e-10: _n = ((_ymin - _y1)*(_x2 - _x1)) - ((_xmin - _x1)*(_y2 - _y1)) _r = _n/_d if 0.0 < _r < 1.0: return True return False PythonCAD-DS1-R37/PythonCAD/Generic/acline.py0000644000175000017500000007114511307666657020154 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # single point construction lines at an arbitrary angle # from __future__ import generators import math from PythonCAD.Generic import conobject from PythonCAD.Generic import tolerance from PythonCAD.Generic import util from PythonCAD.Generic import point from PythonCAD.Generic import quadtree _dtr = math.pi/180.0 class ACLine(conobject.ConstructionObject): """A class for single point construction lines at a specified angle. A ACLine object is derived from an Spcline,so it has all that objects properties. There is one additional attribute for an ACLine: angle: A float value listing the angle at which this line rises or declines The limits of the float value: -90.0 < value < 90.0. Any values outside that range are adjusted to fall between those limits. A ACLine has the following addtional methods: {get/set}Angle(): Get/Set the angle of the ACLine. mapCoords(): Test if a coordinate pair is within some distance to an ACLine. inRegion(): Return whether or not a ACLine passes through a bounded region. clone(): Return an identical copy of an ACLine. """ __messages = { 'moved' : True, 'keypoint_changed' : True, 'rotated' : True } def __init__(self, p, a, **kw): """Initialize an ACLine object. ACLine(p, a) p: A Point object the line passes through a: The angle at which the line rises or declines """ _a = util.make_angle(a) _p = p if not isinstance(p, point.Point): _p = point.Point(p) super(ACLine, self).__init__(**kw) self.__keypoint = _p self.__angle = _a _p.storeUser(self) _p.connect('moved', self.__movePoint) _p.connect('change_pending', self.__pointChangePending) _p.connect('change_complete', self.__pointChangeComplete) def __eq__(self, obj): """Compare one ACLine to another for equality. """ if not isinstance(obj, ACLine): return False if obj is self: return True _as = self.__angle _ao = obj.getAngle() _xs, _ys = self.getLocation().getCoords() _xo, _yo = obj.getLocation().getCoords() _val = False if (self.isVertical() and obj.isVertical() and abs(_xs - _xo) < 1e-10): _val = True elif (self.isHorizontal() and obj.isHorizontal() and abs(_ys - _yo) < 1e-10): _val = True else: if abs(_as - _ao) < 1e-10: # same angle _ms = math.tan(_as * _dtr) _bs = _ys - (_ms * _xs) _y = (_ms * _xo) + _bs if abs(_y - _yo) < 1e-10: _val = True return _val def __ne__(self, obj): """Compare one ACLine to another for inequality. """ if not isinstance(obj, ACLine): return False if obj is self: return False _as = self.__angle _ao = obj.getAngle() _xs, _ys = self.getLocation().getCoords() _xo, _yo = obj.getLocation().getCoords() _val = True if (self.isVertical() and obj.isVertical() and abs(_xs - _xo) < 1e-10): _val = False elif (self.isHorizontal() and obj.isHorizontal() and abs(_ys - _yo) < 1e-10): _val = False else: if abs(_as - _ao) < 1e-10: # same angle _ms = math.tan(_as * _dtr) _bs = _ys - (_ms * _xs) _y = (_ms * _xo) + _bs if abs(_y - _yo) < 1e-10: _val = False return _val def __str__(self): _point = self.getLocation() _angle = self.__angle return "Angled construction line through %s at %g degrees" % (_point, _angle) def finish(self): self.__keypoint.disconnect(self) self.__keypoint.freeUser(self) self.__keypoint = self.__angle = None super(ACLine, self).finish() def getValues(self): _data = super(ACLine, self).getValues() _data.setValue('type', 'acline') _data.setValue('keypoint', self.__keypoint.getID()) _data.setValue('angle', self.__angle) return _data def getAngle(self): """Return the angle of the ACLine. getAngle() """ return self.__angle def setAngle(self, angle): """ setAngle(angle) The argument a should be a float representing the angle of the ACLine in degrees. """ if self.isLocked(): raise RuntimeError, "Setting angle not allowed - object locked." _a = util.make_angle(angle) _oa = self.__angle if abs(_a - _oa) > 1e-10: self.startChange('rotated') self.__angle = _a self.endChange('rotated') self.sendMessage('rotated', _oa) _x, _y = self.__keypoint.getCoords() self.sendMessage('moved', _x, _y, _oa) self.modified() angle = property(getAngle, setAngle, None, "Angle of inclination.") def isVertical(self): return abs(abs(self.__angle) - 90.0) < 1e-10 def isHorizontal(self): return abs(self.__angle) < 1e-10 def getLocation(self): return self.__keypoint def setLocation(self, p): if self.isLocked(): raise RuntimeError, "Setting keypoint not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Unexpected type for point: " + `type(p)` _kp = self.__keypoint if p is not _kp: _x, _y = _kp.getCoords() _kp.disconnect(self) _kp.freeUser(self) self.startChange('keypoint_changed') self.__keypoint = p self.endChange('keypoint_changed') self.sendMessage('keypoint_changed', _kp) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) p.storeUser(self) _px, _py = p.getCoords() if abs(_px - _x) > 1e-10 or abs(_py - _y) > 1e-10: self.sendMessage('moved', _x, _y, self.getAngle()) self.modified() def mapCoords(self, x, y, tol=tolerance.TOL): """Return the nearest Point on the ACLine to a coordinate pair. mapCoords(x, y[, tol]) The function has two required arguments: x: A Float value giving the x-coordinate y: A Float value giving the y-coordinate There is a single optional argument: tol: A float value equal or greater than 0.0 This function is used to map a possibly near-by coordinate pair to an actual Point on the ACLine. If the distance between the actual Point and the coordinates used as an argument is less than the tolerance, the actual Point is returned. Otherwise, this function returns None. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _xs, _ys = self.getLocation().getCoords() _angle = self.__angle # # the second point is 1 unit away - this simplifies things ... # if self.isHorizontal(): _x2 = _xs + 1.0 _y2 = _ys elif self.isVertical(): _x2 = _xs _y2 = _ys + 1.0 else: _x2 = _xs + math.cos(_angle * _dtr) _y2 = _ys + math.sin(_angle * _dtr) _r = ((_x - _xs)*(_x2 - _xs) + (_y - _ys)*(_y2 - _ys)) _px = _xs + (_r * (_x2 - _xs)) _py = _ys + (_r * (_y2 - _ys)) if abs(_px - _x) < _t and abs(_py - _y) < _t: return _px, _py return None def getProjection(self, x, y): """Find the projection point of some coordinates on the ACLine. getProjection(x, y) Arguments 'x' and 'y' should be float values. """ _x = util.get_float(x) _y = util.get_float(y) _x1, _y1 = self.getLocation().getCoords() _angle = self.__angle if self.isHorizontal(): _px = _x _py = _y1 elif self.isVertical(): _px = _x1 _py = _y else: _rangle = _angle * _dtr _dx = math.cos(_rangle) _dy = math.sin(_rangle) _sqlen = pow(_dx, 2) + pow(_dy, 2) _rn = ((_x - _x1) * _dx) + ((_y - _y1) * _dy) _r = _rn/_sqlen _px = _x1 + (_r * _dx) _py = _y1 + (_r * _dy) return _px, _py def inRegion(self, xmin, ymin, xmax, ymax, fully=False): """Return whether or not an ACLine passes through a region. inRegion(xmin, ymin, xmax, ymax) The first four arguments define the boundary. The method will return True if the ACLine passes through the boundary. Otherwise the function will return False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) if fully: return False _x, _y = self.getLocation().getCoords() _angle = self.__angle _val = False if _xmin < _x < _xmax and _ymin < _y < _ymax: _val = True elif self.isHorizontal() and _ymin < _y < _ymax: _val = True elif self.isVertical() and _xmin < _x < _xmax: _val = True else: # # the ACLine can be parameterized as # # x = u * (x2 - x1) + x1 # y = u * (y2 - y1) + y1 # # for u = 0, x => x1, y => y1 # for u = 1, x => x2, y => y2 # # if the ACLine passes through the region then there # will be valid u occuring at the region boundary # _rangle = _angle * _dtr _dx = math.cos(_rangle) _dy = math.sin(_rangle) # # x = xmin # _u = (_xmin - _x)/_dx _yt = (_u * _dy) + _y if (_ymin - 1e-10) < _yt < (_ymax + 1e-10): # catch endpoints _val = True if not _val: # # x = xmax # _u = (_xmax - _x)/_dx _yt = (_u * _dy) + _y if (_ymin - 1e-10) < _yt < (_ymax + 1e-10): # catch endpoints _val = True if not _val: # # y = ymin # # if this fails there is no way the ACLine can be in # region because it cannot pass through only one side # _u = (_ymin - _y)/_dy _xt = (_u * _dx) + _x if _xmin < _xt < _xmax: _val = True return _val def move(self, dx, dy): """Move an ACLine move(dx, dy) The first argument gives the x-coordinate displacement, and the second gives the y-coordinate displacement. Both values should be floats. """ if self.isLocked() or self.__keypoint.isLocked(): raise RuntimeError, "Moving ACLine not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _x, _y = self.__keypoint.getCoords() self.ignore('moved') try: self.__keypoint.move(_dx, _dy) finally: self.receive('moved') self.sendMessage('moved', _x, _y, self.getAngle()) def __pointChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.startChange('moved') def __pointChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.endChange('moved') def __movePoint(self, p, *args): _plen = len(args) if _plen < 2: raise ValueError, "Invalid argument count: %d" % _plen _x = util.get_float(args[0]) _y = util.get_float(args[1]) if p is not self.__keypoint: raise ValueError, "Invalid point for ACLine::movePoint()" + `p` _px, _py = p.getCoords() if abs(_px - _x) > 1e-10 or abs(_py - _y) > 1e-10: self.sendMessage('moved', _x, _y, self.getAngle()) def clipToRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _x, _y = self.getLocation().getCoords() _angle = self.__angle _coords = None if self.isVertical() and _xmin < _x < _xmax: _coords = (_x, _ymin, _x, _ymax) elif self.isHorizontal() and _ymin < _y < _ymax: _coords = (_xmin, _y, _xmax, _y) else: # # the ACLine can be parameterized as # # x = u * (x2 - x1) + x1 # y = u * (y2 - y1) + y1 # # for u = 0, x => x1, y => y1 # for u = 1, x => x2, y => y2 # # The following is the Liang-Barsky Algorithm # for segment clipping modified slightly for # construction lines # _rangle = _angle * _dtr _dx = math.cos(_rangle) _dy = math.sin(_rangle) _P = [-_dx, _dx, -_dy, _dy] _q = [(_x - _xmin), (_xmax - _x), (_y - _ymin), (_ymax - _y)] _u1 = None _u2 = None _valid = True for _i in range(4): _pi = _P[_i] _qi = _q[_i] if abs(_pi) < 1e-10: # this should be caught earlier ... if _qi < 0.0: _valid = False break else: _r = _qi/_pi if _pi < 0.0: if _u2 is not None and _r > _u2: _valid = False break if _u1 is None or _r > _u1: _u1 = _r else: if _u1 is not None and _r < _u1: _valid = False break if _u2 is None or _r < _u2: _u2 = _r if _valid: _coords = (((_u1 * _dx) + _x), ((_u1 * _dy) + _y), ((_u2 * _dx) + _x), ((_u2 * _dy) + _y)) return _coords def clone(self): """Create an identical copy of an ACLine. clone() """ return ACLine(self.__keypoint.clone(), self.__angle) def sendsMessage(self, m): if m in ACLine.__messages: return True return super(ACLine, self).sendsMessage(m) def intersect_region(acl, xmin, ymin, xmax, ymax): if not isinstance(acl, ACLine): raise TypeError, "Argument not an ACLine: " + `type(acl)` _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _x, _y = acl.getLocation().getCoords() _x1 = _y1 = _x2 = _y2 = None if acl.isVertical() and _xmin < _x < _xmax: _x1 = _x _y1 = _ymin _x2 = _x _y2 = _ymax elif acl.isHorizontal() and _ymin < _y < _ymax: _x1 = _xmin _y1 = _y _x2 = _xmax _y2 = _y else: _angle = acl.getAngle() _slope = math.tan(_angle * _dtr) _yint = _y - (_x * _slope) _xt = _x + math.cos(_angle * _dtr) _yt = _y + math.sin(_angle * _dtr) # # find y for x = xmin # _yt = (_slope * _xmin) + _yint if _ymin < _yt < _ymax: # print "hit at y for x=xmin" _x1 = _xmin _y1 = _yt # # find y for x = xmax # _yt = (_slope * _xmax) + _yint if _ymin < _yt < _ymax: # print "hit at y for x=xmax" if _x1 is None: _x1 = _xmax _y1 = _yt else: _x2 = _xmax _y2 = _yt if _x2 is None: # # find x for y = ymin # _xt = (_ymin - _yint)/_slope if _xmin < _xt < _xmax: # print "hit at x for y=ymin" if _x1 is None: _x1 = _xt _y1 = _ymin else: _x2 = _xt _y2 = _ymin if _x2 is None: # # find x for y = ymax # _xt = (_ymax - _yint)/_slope if _xmin < _xt < _xmax: # print "hit at x for y=ymax" if _x1 is None: _x1 = _xt _y1 = _ymax else: _x2 = _xt _y2 = _ymax return _x1, _y1, _x2, _y2 # # Quadtree ACLine storage # class ACLineQuadtree(quadtree.Quadtree): def __init__(self): super(ACLineQuadtree, self).__init__() def getNodes(self, *args): _alen = len(args) if _alen != 3: raise ValueError, "Expected 3 arguments, got %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _angle = util.get_float(args[2]) _v = abs(abs(_angle) - 90.0) < 1e-10 _h = abs(_angle) < 1e-10 _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if _node.hasSubnodes(): _ne = _nw = _sw = _se = False if _v: if _x < _xmin or _x > _xmax: continue _xmid = (_xmin + _xmax)/2.0 if _x < _xmid: # left of midpoint _nw = _sw = True else: _se = _ne = True elif _h: if _y < _ymin or _y > _ymax: continue _ymid = (_ymin + _ymax)/2.0 if _y < _ymid: # below midpoint _sw = _se = True else: _nw = _ne = True else: _ne = _nw = _sw = _se = True if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: yield _node def addObject(self, obj): if not isinstance(obj, ACLine): raise TypeError, "Argument not an ACLine: " + `type(obj)` if obj in self: return _x, _y = obj.getLocation().getCoords() _angle = obj.getAngle() _bounds = self.getTreeRoot().getBoundary() _xmin = _ymin = _xmax = _ymax = None _resize = False if _bounds is None: # first node in tree _resize = True _xmin = _x - 1.0 _ymin = _y - 1.0 _xmax = _x + 1.0 _ymax = _y + 1.0 else: _xmin, _ymin, _xmax, _ymax = _bounds if _x < _xmin: _xmin = _x - 1.0 _resize = True if _x > _xmax: _xmax = _x + 1.0 _resize = True if _y < _ymin: _ymin = _y - 1.0 _resize = True if _y > _ymax: _ymax = _y + 1.0 _resize = True if _resize: self.resize(_xmin, _ymin, _xmax, _ymax) for _node in self.getNodes(_x, _y, _angle): _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if obj.inRegion(_xmin, _ymin, _xmax, _ymax): _node.addObject(obj) super(ACLineQuadtree, self).addObject(obj) obj.connect('moved', self._moveACLine) def delObject(self, obj): if obj not in self: return _x, _y = obj.getLocation().getCoords() _angle = obj.getAngle() _pdict = {} for _node in self.getNodes(_x, _y, _angle): _node.delObject(obj) _parent = _node.getParent() if _parent is not None: _pid = id(_parent) if _pid not in _pdict: _pdict[_pid] = _parent super(ACLineQuadtree, self).delObject(obj) obj.disconnect(self) for _parent in _pdict.values(): self.purgeSubnodes(_parent) def find(self, *args): _alen = len(args) if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _angle = util.make_angle(args[2]) _t = tolerance.TOL if _alen > 3: _t = tolerance.toltest(args[3]) _xmin = _x - _t _xmax = _x + _t _ymin = _y - _t _ymax = _y + _t _aclines = [] for _acl in self.getInRegion(_xmin, _ymin, _xmax, _ymax): _ax, _ay = _acl.getLocation().getCoords() if ((abs(_ax - _x) < _t) and (abs(_ay - _y) < _t) and (abs(_acl.getAngle() - _angle) < 1e-10)): _aclines.append(_acl) return _aclines def _moveACLine(self, obj, *args): if obj not in self: raise ValueError, "ACLine not stored in Quadtree: " + `obj` _alen = len(args) if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _angle = util.get_float(args[2]) for _node in self.getNodes(_x, _y, _angle): _node.delObject(obj) # acline may not be in node super(ACLineQuadtree, self).delObject(obj) obj.disconnect(self) self.addObject(obj) def getClosest(self, x, y, tol=tolerance.TOL): _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _acline = _tsep = None _adict = {} _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) else: for _a in _node.getObjects(): _aid = id(_a) if _aid not in _adict: _ax, _ay = _a.getProjection(_x, _y) if abs(_ax - _x) < _t and abs(_ay - _y) < _t: _sep = math.hypot((_ax - _x), (_ay - _y)) if _tsep is None: _tsep = _sep _acline = _a else: if _sep < _tsep: _tsep = _sep _acline = _a return _acline def getInRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _acls = [] if not len(self): return _acls _nodes = [self.getTreeRoot()] _adict = {} while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) else: for _acl in _node.getObjects(): _aid = id(_acl) if _aid not in _adict: if _acl.inRegion(_xmin, _ymin, _xmax, _ymax): _acls.append(_acl) _adict[_aid] = True return _acls # # ACLine history class # class ACLineLog(conobject.ConstructionObjectLog): def __init__(self, a): if not isinstance(a, ACLine): raise TypeError, "Argument not an ACLine: " + `type(a)` super(ACLineLog, self).__init__(a) a.connect('keypoint_changed', self._keypointChange) a.connect('rotated', self._rotateACLine) def _rotateACLine(self, a, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _angle = args[0] if not isinstance(_angle, float): raise TypeError, "Unexpected type for angle: " + `type(_angle)` self.saveUndoData('rotated', _angle) def _keypointChange(self, a, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _old = args[0] if not isinstance(_old, point.Point): raise TypeError, "Argument not a Point: " + `type(_old)` self.saveUndoData('keypoint_changed', _old.getID()) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if _alen == 0: raise ValueError, "No arguments to execute()" _a = self.getObject() _p = _a.getLocation() _op = args[0] if _op == 'rotated': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _angle = args[1] if not isinstance(_angle, float): raise TypeError, "Unexpected type for angle: " + `type(_angle)` _sdata = _a.getAngle() self.ignore(_op) try: if undo: _a.startUndo() try: _a.setAngle(_angle) finally: _a.endUndo() else: _a.startRedo() try: _a.setAngle(_angle) finally: _a.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'keypoint_changed': if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _oid = args[1] _parent = _a.getParent() if _parent is None: raise ValueError, "ACLine has no parent - cannot undo" _pt = _parent.getObject(_oid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "Keypoint missing: id=%d" % _oid _sdata = _p.getID() self.ignore(_op) try: if undo: _a.startUndo() try: _a.setLocation(_pt) finally: _a.endUndo() else: _a.startRedo() try: _a.setLocation(_pt) finally: _a.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) else: super(ACLineLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/split.py0000644000175000017500000016117511307666657020057 0ustar matteomatteo# # Copyright (c) 2003, 2004, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # functions for splitting entities in a drawing import math from PythonCAD.Generic.layer import Layer from PythonCAD.Generic.point import Point from PythonCAD.Generic.segment import Segment from PythonCAD.Generic.circle import Circle from PythonCAD.Generic.arc import Arc from PythonCAD.Generic.polyline import Polyline from PythonCAD.Generic import util from PythonCAD.Generic import intersections _rtd = (180.0/math.pi) def _most_used(plist): _pmax = plist.pop() _max = _pmax.countUsers() for _pt in plist: _count = _pt.countUsers() if _count > _max: _max = _count _pmax = _pt return _pmax def _get_point(l, x, y): _pts = l.find('point', x, y) if len(_pts) == 0: _lp = Point(x, y) l.setAutosplit(False) l.addObject(_lp) else: _lp = _most_used(_pts) return _lp def split_segment_at(seg, x, y): if not isinstance(seg, Segment): raise TypeError, "Invalid Segment: " + `type(seg)` _x = util.get_float(x) _y = util.get_float(y) _layer = seg.getParent() if _layer is None: return None _p = seg.getProjection(_x, _y) if _p is None: return None _px, _py = _p if abs(_px - _x) > 1e-10 or abs(_py - _y) > 1e-10: return None _lp = _get_point(_layer, _px, _py) _p1, _p2 = seg.getEndpoints() if _lp == _p1 or _lp == _p2: return None _s = seg.getStyle() _l = seg.getLinetype() _c = seg.getColor() _t = seg.getThickness() _s1 = Segment(_p1, _lp, _s, _l, _c, _t) _s2 = Segment(_lp, _p2, _s, _l, _c, _t) return _s1, _s2 def split_circle_at(circ, x, y): if not isinstance(circ, Circle): raise TypeError, "Invalid Circle: " + `type(circ)` _x = util.get_float(x) _y = util.get_float(y) _layer = circ.getParent() if _layer is None: return None _p = circ.mapCoords(_x, _y) if _p is None: return None _px, _py = _p if abs(_px - _x) > 1e-10 or abs(_py - _y) > 1e-10: return None _lp = _get_point(_layer, _px, _py) _s = circ.getStyle() _cp = circ.getCenter() _angle = _rtd * math.atan2((_lp.y - _cp.y),(_lp.x - _cp.x)) _l = circ.getLinetype() _c = circ.getColor() _t = circ.getThickness() _arc = Arc(_cp, circ.getRadius(), _angle, _angle, _s, _l, _c, _t) return _arc def split_arc_at(arc, x, y): if not isinstance(arc, Arc): raise TypeError, "Invalid Arc: " + `type(arc)` _x = util.get_float(x) _y = util.get_float(y) _layer = arc.getParent() if _layer is None: return None _p = arc.mapCoords(_x, _y) if _p is None: return None _px, _py = _p if abs(_px - _x) > 1e-10 or abs(_py - _y) > 1e-10: return None _lp = _get_point(_layer, _px, _py) _s = arc.getStyle() _cp = arc.getCenter() _r = arc.getRadius() _sa = arc.getStartAngle() _ea = arc.getEndAngle() _angle = _rtd * math.atan2((_lp.y - _cp.y),(_lp.x - _cp.x)) _l = arc.getLinetype() _c = arc.getColor() _t = arc.getThickness() _a1 = Arc(_cp, _r, _sa, _angle, _s, _l, _c, _t) _a2 = Arc(_cp, _r, _angle, _ea, _s, _l, _c, _t) return _a1, _a2 def split_polyline_at(pl, x, y): if not isinstance(pl, Polyline): raise TypeError, "Invalid Polyline: " + `type(pl)` _x = util.get_float(x) _y = util.get_float(y) _layer = pl.getParent() if _layer is None: return False _pts = pl.getPoints() for _i in range(len(_pts) - 1): _p1x, _p1y = _pts[_i].getCoords() _p2x, _p2y = _pts[_i + 1].getCoords() _p = util.map_coords(_x, _y, _p1x, _p1y, _p2x, _p2y) if _p is None: continue _px, _py = _p if ((abs(_px - _p1x) < 1e-10 and abs(_py - _p1y) < 1e-10) or (abs(_px - _p2x) < 1e-10 and abs(_py - _p2y) < 1e-10)): continue _lp = _get_point(_layer, _px, _py) pl.addPoint((_i + 1), _lp) return True return False def split_segment(seg, pt): """Split a segment into two segments at a point. split_segment(seg, pt) seg: The segment to split pt: The point used to split the segment. There is presently no check to test that the point lies on the segment. """ if not isinstance(seg, Segment): raise TypeError, "Invalid Segment: " + `type(seg)` if not isinstance(pt, Point): raise TypeError, "Invalid Point: " + `type(pt)` _sp = seg.getParent() _pp = pt.getParent() if _sp is not None and _pp is not None and _sp is not _pp: raise RuntimeError, "Invalid Point for Segment splitting." _p1, _p2 = seg.getEndpoints() _s = seg.getStyle() _l = seg.getLinetype() _c = seg.getColor() _t = seg.getThickness() _s1 = Segment(_p1, pt, _s, _l, _c, _t) _s2 = Segment(pt, _p2, _s, _l, _c, _t) return _s1, _s2 def split_circle(circle, pt): """Split a circle into a single arc. split_circle(circle, pt) circle: The circle to split pt: The point used to determine the start/end angles of the arc. """ if not isinstance(circle, Circle): raise TypeError, "Invalid Circle: " + `type(circle)` if not isinstance(pt, Point): raise TypeError, "Invalid Point: " + `type(pt)` _cp = circle.getParent() _pp = pt.getParent() if _cp is not None and _pp is not None and _cp is not _pp: raise RuntimeError, "Invalid Point for Circle splitting." _cp = circle.getCenter() _rad = circle.getRadius() _cx, _cy = _cp.getCoords() _px, _py = pt.getCoords() _angle = _rtd * math.atan2((_py - _cy), (_px - _cx)) if _angle < 0.0: _angle = _angle + 360.0 return Arc(_cp, _rad, _angle, _angle, circle.getStyle(), circle.getLinetype(), circle.getColor(), circle.getThickness()) def split_arc(arc, pt): """Split an arc into two connected arcs. split_arc(arc, pt) arc: The arc to split. pt: The point used to determine the angle at which to split the arc. """ if not isinstance(arc, Arc): raise TypeError, "Invalid Arc: " + `type(arc)` if not isinstance(pt, Point): raise TypeError, "Invalid Point: " + `type(pt)` _ap = arc.getParent() _pp = pt.getParent() if _ap is not None and _pp is not None and _ap is not _pp: raise RuntimeError, "Invalid Point for Arc splitting." _cp = arc.getCenter() _cx, _cy = _cp.getCoords() _px, _py = pt.getCoords() _angle = _rtd * math.atan2((_py - _cy), (_px - _cx)) if _angle < 0.0: _angle = _angle + 360.0 if not arc.throughAngle(_angle): raise ValueError, "Arc does not exist at angle %g" % _angle _rad = arc.getRadius() _sa = arc.getStartAngle() _ea = arc.getEndAngle() _style = arc.getStyle() _linetype = arc.getLinetype() _color = arc.getColor() _thickness = arc.getThickness() _arc1 = Arc(_cp, _rad, _sa, _angle, _style, _linetype, _color, _thickness) _arc2 = Arc(_cp, _rad, _angle, _ea, _style, _linetype, _color, _thickness) return _arc1, _arc2 def split_polyline(polyline, pt): if not isinstance(polyline, Polyline): raise TypeError, "Invalid Polyline: " + `type(polyline)` if not isinstance(pt, Point): raise TypeError, "Invalid Point: " + `type(pt)` _plp = polyline.getParent() _pp = pt.getParent() if _plp is not None and _pp is not None and _plp is not _pp: raise RuntimeError, "Invalid Point for Polyline splitting." _px, _py = pt.getCoords() _count = len(polyline) for _i in range(_count - 1): _hit = False _p1x, _p1y = polyline.getPoint(_i).getCoords() _p2x, _p2y = polyline.getPoint(_i + 1).getCoords() if abs(_p2x - _p1x) < 1e-10: # vertical if (abs(_p2x - _px) < 1e-10 and min(_p1y, _p2y) < _py < max(_p1y, _p2y)): _hit = True elif abs(_p2y - _p1y) < 1e-10: # horizontal if (abs(_p2y - _py) < 1e-10 and min(_p1x, _p2x) < _px < max(_p1x, _p2x)): _hit = True else: _slope = (_p2y - _p1y)/(_p2x - _p1x) _yint = _p2y - (_slope * _p2x) _ytest = (_slope * _px) + _yint if abs(_ytest - _py) < 1e-10: _hit = True if _hit: polyline.addPoint((_i + 1), pt) break class SplitManager(object): def __init__(self, layer): if not isinstance(layer, Layer): raise TypeError, "Invalid Layer: " + `type(layer)` self.__layer = layer self.__segs = [] self.__circs = [] self.__arcs = [] self.__plines = [] self.__rects = {} def segBounds(s): if not isinstance(s, Segment): raise TypeError, "Invalid Segment: " + `type(s)` _p1, _p2 = s.getEndpoints() _x, _y = _p1.getCoords() _xmin = _xmax = _x _ymin = _ymax = _y _x, _y = _p2.getCoords() if _x < _xmin: _xmin = _x if _y < _ymin: _ymin = _y if _x > _xmax: _xmax = _x if _y > _ymax: _ymax = _y return _xmin, _ymin, _xmax, _ymax segBounds = staticmethod(segBounds) def circBounds(c): if not isinstance(c, Circle): raise TypeError, "Invalid Circle: " + `type(c)` _x, _y = c.getCenter().getCoords() _r = c.getRadius() return ((_x - _r), (_y - _r), (_x + _r), (_y + _r)) circBounds = staticmethod(circBounds) def canIntersect(r1, r2): if not isinstance(r1, tuple): raise TypeError, "Invalid R1 tuple: " + `type(r1)` if len(r1) != 4: raise ValueError, "R1 length error: " + str(r1) if not isinstance(r2, tuple): raise TypeError, "Invalid R2 tuple: " + `type(r2)` if len(r2) != 4: raise ValueError, "R2 length error: " + str(r2) return not ((r1[2] < r2[0]) or # r1 xmax < r2 xmin (r1[0] > r2[2]) or # r1 xmin > r2 xmax (r1[3] < r2[1]) or # r1 ymax < r2 ymin (r1[1] > r2[3])) # r1 ymin > r2 ymax canIntersect = staticmethod(canIntersect) def splitSegTwoPts(seg, pt1, pt2): _p1, _p2 = seg.getEndpoints() _s = seg.getStyle() _l = seg.getLinetype() _c = seg.getColor() _t = seg.getThickness() _s1 = Segment(_p1, pt1, _s, _l, _c, _t) _s2 = Segment(pt1, pt2, _s, _l, _c, _t) _s3 = Segment(pt2, _p2, _s, _l, _c, _t) return _s1, _s2, _s3 splitSegTwoPts = staticmethod(splitSegTwoPts) def splitCircTwoPts(circ, p1, p2): _cp = circ.getCenter() _r = circ.getRadius() _cx, _cy = _cp.getCoords() _px, _py = p1.getCoords() _a1 = _rtd * math.atan2((_py - _cy),(_px - _cx)) if _a1 < 0.0: _a1 = _a1 + 360.0 _px, _py = p2.getCoords() _a2 = _rtd * math.atan2((_py - _cy),(_px - _cx)) if _a2 < 0.0: _a2 = _a2 + 360.0 _s = circ.getStyle() _c = circ.getColor() _l = circ.getLinetype() _t = circ.getThickness() _arc1 = Arc(_cp, _r, _a1, _a2, _s, _l, _c, _t) _arc2 = Arc(_cp, _r, _a2, _a1, _s, _l, _c, _t) return _arc1, _arc2 splitCircTwoPts = staticmethod(splitCircTwoPts) def splitArcTwoPts(arc, p1, p2): _cp = arc.getCenter() _r = arc.getRadius() _sa = arc.getStartAngle() _ea = arc.getEndAngle() _cx, _cy = _cp.getCoords() _px, _py = p1.getCoords() _ap1 = _rtd * math.atan2((_py - _cy), (_px - _cx)) if _ap1 < 0.0: _ap1 = _ap1 + 360.0 _px, _py = p2.getCoords() _ap2 = _rtd * math.atan2((_py - _cy), (_px - _cx)) if _ap2 < 0.0: _ap2 = _ap2 + 360.0 if _sa < _ea: _a1 = min(_ap1, _ap2) _a2 = max(_ap1, _ap2) else: _d1 = _ap1 - _sa if _d1 < 0.0: _d1 = _ap1 + _sa _d2 = _ap2 - _sa if _d2 < 0.0: _d2 = _ap2 + _sa if _d1 < _d2: _a1 = _ap1 _a2 = _ap2 else: _a1 = _ap2 _a2 = _ap1 _s = arc.getStyle() _l = arc.getLinetype() _c = arc.getColor() _t = arc.getThickness() _arc1 = Arc(_cp, _r, _sa, _a1, _s, _l, _c, _t) _arc2 = Arc(_cp, _r, _a1, _a2, _s, _l, _c, _t) _arc3 = Arc(_cp, _r, _a2, _ea, _s, _l, _c, _t) return _arc1, _arc2, _arc3 splitArcTwoPts = staticmethod(splitArcTwoPts) def addObject(self, obj): if obj.getParent() is not self.__layer: raise ValueError, "Invalid object parent: " + `obj` _olist = None if isinstance(obj, Segment): _olist = self.__segs elif isinstance(obj, Circle): _olist = self.__circs elif isinstance(obj, Arc): _olist = self.__arcs elif isinstance(obj, Polyline): _olist = self.__plines else: raise TypeError, "Unexpected object: " + `type(obj)` _seen = False for _obj in _olist: if _obj is obj: _seen = True break if _seen: raise RuntimeError, "Object already stored: " + `obj` _olist.append(obj) def delObject(self, obj): _olist = None if isinstance(obj, Segment): _olist = self.__segs elif isinstance(obj, Circle): _olist = self.__circs elif isinstance(obj, Arc): _olist = self.__arcs elif isinstance(obj, Polyline): _olist= self.__plines else: raise TypeError, "Unexpected object: " + `type(obj)` for _i in range(len(_olist)): if _olist[_i] is obj: del _olist[_i] break def getSegments(self): return self.__segs def getCircles(self): return self.__circs def getArcs(self): return self.__arcs def getPolylines(self): return self.__plines def splitObjects(self): if len(self.__segs): self.__splitSegSeg() if len(self.__circs): self.__splitSegCircle() if len(self.__arcs): self.__splitSegArc() if len(self.__plines): self.__splitSegPolyline() if len(self.__circs): self.__splitCircCirc() if len(self.__circs) and len(self.__arcs): self.__splitCircArc() if len(self.__circs) and len(self.__plines): self.__splitCircPolyline() if len(self.__arcs): self.__splitArcArc() if len(self.__plines): self.__splitArcPolyline() if len(self.__plines): self.__splitPolyPoly() def __getPoint(self, x, y): _layer = self.__layer _pts = _layer.find('point', x, y) if len(_pts) == 0: _ip = Point(x, y) _layer.setAutosplit(False) _layer.addObject(_ip) else: _ip = _most_used(_pts) return _ip def __splitSegSeg(self): _layer = self.__layer _segs = self.__segs _rects = self.__rects _slist = [] _sdict = {} while len(_segs): _seg = _segs.pop() _slist.append(_seg) _segid = id(_seg) if _segid in _sdict and not _sdict[_segid]: continue _p1, _p2 = _seg.getEndpoints() if (_p1.getParent() is not _layer or _p2.getParent() is not _layer): raise RuntimeError, "Invalid Segment endpoints: " + `_seg` _sdict[_segid] = True _rseg = _rects.get(_segid) if _rseg is None: _rseg = SplitManager.segBounds(_seg) _rects[_segid] = _rseg for _s in _segs: _sid = id(_s) if _sid in _sdict and not _sdict[_sid]: continue _p3, _p4 = _s.getEndpoints() if (_p3.getParent() is not _layer or _p4.getParent() is not _layer): raise RuntimeError, "Invalid Segment endpoints: " + `_s` if _p1 == _p3 or _p1 == _p4 or _p2 == _p3 or _p2 == _p4: continue _rs = _rects.get(_sid) if _rs is None: _rs = SplitManager.segBounds(_s) _rects[_sid] = _rs if not SplitManager.canIntersect(_rseg, _rs): continue _ipts = intersections.find_intersections(_s, _seg) if len(_ipts): _x, _y = _ipts[0] _ip = self.__getPoint(_x, _y) if _ip != _p3 and _ip != _p4: _s1, _s2 = split_segment(_s, _ip) _segs.append(_s1) _segs.append(_s2) _sdict[_sid] = False if _ip != _p1 and _ip != _p2: _s1, _s2 = split_segment(_seg, _ip) _segs.append(_s1) _segs.append(_s2) _sdict[_segid] = False break _nseg = [] _dseg = [] for _seg in _slist: _status = _sdict.get(id(_seg)) if _status is None: raise RuntimeError, "No status for Segment: " + `_seg` elif _status: _nseg.append(_seg) else: _dseg.append(_seg) for _seg in _dseg: del self.__rects[id(_seg)] if _seg.getParent() is not None: _layer.delObject(_seg) else: _seg.finish() for _seg in _nseg: if _seg.getParent() is None: _layer.addObject(_seg) self.__segs = _nseg def __splitSegCircle(self): _segs = self.__segs _circs = self.__circs _layer = self.__layer _rects = self.__rects _slist = [] _alist = [] _odict = {} while len(_segs): _seg = _segs.pop() _slist.append(_seg) _sid = id(_seg) if _sid in _odict and not _odict[_sid]: continue _p1, _p2 = _seg.getEndpoints() if (_p1.getParent() is not _layer or _p2.getParent() is not _layer): raise RuntimeError, "Invalid Segment endpoints: " + `_seg` _odict[_sid] = True _rs = _rects.get(_sid) if _rs is None: _rs = SplitManager.segBounds(_seg) _rects[_sid] = _rs for _circ in _circs: _cid = id(_circ) if _cid in _odict and not _odict[_cid]: continue _odict[_cid] = True _rc = _rects.get(_cid) if _rc is None: _rc = SplitManager.circBounds(_circ) _rects[_cid] = _rc if not SplitManager.canIntersect(_rs, _rc): continue _ipts = intersections.find_intersections(_seg, _circ) if len(_ipts): _s1 = _s2 = _s3 = _a1 = _a2 = None _p1, _p2 = _seg.getEndpoints() _count = len(_ipts) if _count == 1: _x, _y = _ipts[0] _ip = self.__getPoint(_x, _y) _a1 = split_circle(_circ, _ip) if _ip != _p1 and _ip != _p2: _s1, _s2 = split_segment(_seg, _ip) elif _count == 2: _x, _y = _ipts[0] _ip1 = self.__getPoint(_x, _y) _x, _y = _ipts[1] _ip2 = self.__getPoint(_x, _y) _a1, _a2 = SplitManager.splitCircTwoPts(_circ, _ip1, _ip2) if (_ip1 != _p1 and _ip1 != _p2 and _ip2 != _p1 and _ip2 != _p2): if ((_p1 - _ip1) < (_p1 - _ip2)): _m1 = _ip1 _m2 = _ip2 else: _m1 = _ip2 _m2 = _ip1 _s1, _s2, _s3 = SplitManager.splitSegTwoPts(_seg, _m1, _m2) elif ((_ip1 == _p1 or _ip1 == _p2) and (_ip2 != _p1 and _ip2 != _p2)): _s1, _s2 = split_segment(_seg, _ip2) elif ((_ip2 == _p1 or _ip2 == _p2) and (_ip1 != _p1 and _ip1 != _p2)): _s1, _s2 = split_segment(_seg, _ip1) else: pass else: raise ValueError, "Unexpected count: %d" % _count # # if _a1 is not None the circle was split # if _a1 is not None: _odict[_cid] = False _alist.append(_a1) if _a2 is not None: _alist.append(_a2) # # if _s1 is not None the segment was split # if _s1 is not None: _odict[_sid] = False _segs.append(_s1) if _s2 is not None: _segs.append(_s2) if _s3 is not None: _segs.append(_s3) break # # handle circles # _dcirc = [] for _obj in _circs: _oid = id(_obj) _status = _odict.get(_oid) if _status is None: raise RuntimeError, "No status for Circle: " + `_obj` else: if not _status: _dcirc.append(_obj) for _obj in _dcirc: self.delObject(_obj) del self.__rects[id(_obj)] _layer.delObject(_obj) # # handle arcs # for _obj in _alist: _layer.addObject(_obj) self.addObject(_obj) # # handle segments # _nseg = [] _dseg = [] for _obj in _slist: _status = _odict.get(id(_obj)) if _status is None: raise RuntimeError, "No status for Segment: " + `_obj` elif _status: _nseg.append(_obj) else: _dseg.append(_obj) for _obj in _dseg: del self.__rects[id(_obj)] if _obj.getParent() is not None: _layer.delObject(_obj) else: _obj.finish() for _obj in _nseg: if _obj.getParent() is None: _layer.addObject(_obj) self.__segs = _nseg def __splitSegArc(self): _segs = self.__segs _arcs = self.__arcs _layer = self.__layer _rects = self.__rects _slist = [] _odict = {} while len(_segs): _seg = _segs.pop() _slist.append(_seg) _sid = id(_seg) if _sid in _odict and not _odict[_sid]: continue _p1, _p2 = _seg.getEndpoints() if (_p1.getParent() is not _layer or _p2.getParent() is not _layer): raise RuntimeError, "Invalid Segment endpoints: " + `_seg` _odict[_sid] = True _rs = _rects.get(_sid) if _rs is None: _rs = SplitManager.segBounds(_seg) _rects[_sid] = _rs for _arc in _arcs: _aid = id(_arc) if _aid in _odict and not _odict[_aid]: continue _odict[_aid] = True _ra = _rects.get(_aid) if _ra is None: _ra = _arc.getBounds() _rects[_aid] = _ra if not SplitManager.canIntersect(_rs, _ra): continue _ipts = intersections.find_intersections(_seg, _arc) if len(_ipts): _s1 = _s2 = _s3 = _a1 = _a2 = _a3 = None _p1, _p2 = _seg.getEndpoints() _ep1, _ep2 = _arc.getEndpoints() _count = len(_ipts) if _count == 1: _x, _y = _ipts[0] _ip = self.__getPoint(_x, _y) if _ip != _ep1 and _ip != _ep2: _a1, _a2 = split_arc(_arc, _ip) if _ip != _p1 and _ip != _p2: _s1, _s2 = split_segment(_seg, _ip) elif _count == 2: _x, _y = _ipts[0] _ip1 = self.__getPoint(_x, _y) _x, _y = _ipts[1] _ip2 = self.__getPoint(_x, _y) if (_ip1 != _ep1 and _ip1 != _ep2 and _ip2 != _ep1 and _ip2 != _ep2): _a1, _a2, _a3 = SplitManager.splitArcTwoPts(_arc, _ip1, _ip2) elif ((_ip1 == _ep1 or _ip1 == _ep2) and (_ip2 != _ep1 and _ip2 != _ep2)): _a1, _a2 = split_arc(_arc, _ip2) elif ((_ip2 == _ep1 or _ip2 == _ep2) and (_ip1 != _ep1 and _ip1 != _ep2)): _a1, _a2 = split_arc(_arc, _ip1) else: pass if (_ip1 != _p1 and _ip1 != _p2 and _ip2 != _p1 and _ip2 != _p2): if ((_p1 - _ip1) < (_p1 - _ip2)): _m1 = _ip1 _m2 = _ip2 else: _m1 = _ip2 _m2 = _ip1 _s1, _s2, _s3 = SplitManager.splitSegTwoPts(_seg, _m1, _m2) elif ((_ip1 == _p1 or _ip1 == _p2) and (_ip2 != _p1 and _ip2 != _p2)): _s1, _s2 = split_segment(_seg, _ip2) elif ((_ip2 == _p1 or _ip2 == _p2) and (_ip1 != _p1 and _ip1 != _p2)): _s1, _s2 = split_segment(_seg, _ip1) else: pass else: raise ValueError, "Unexpected count: %d" % _count # # if _a1 is not None the arc was split # if _a1 is not None: _odict[_aid] = False _arcs.append(_a1) if _a2 is not None: _arcs.append(_a2) if _a3 is not None: _arcs.append(_a3) # # if _s1 is not None the segment was split # if _s1 is not None: _odict[_sid] = False _segs.append(_s1) if _s2 is not None: _segs.append(_s2) if _s3 is not None: _segs.append(_s3) break # # handle arcs # _narc = [] _darc = [] for _obj in _arcs: _status = _odict.get(id(_obj)) if _status is None: raise RuntimeError, "No status for Arc: " + `_obj` elif _status: _narc.append(_obj) else: _darc.append(_obj) for _obj in _darc: del self.__rects[id(_obj)] if _obj.getParent() is not None: _layer.delObject(_obj) else: _obj.finish() for _obj in _narc: if _obj.getParent() is None: _layer.addObject(_obj) self.__arcs = _narc # # handle segments # _nseg = [] _dseg = [] for _obj in _slist: _status = _odict.get(id(_obj)) if _status is None: raise RuntimeError, "No status for Segment: " + `_obj` elif _status: _nseg.append(_obj) else: _dseg.append(_obj) for _obj in _dseg: del self.__rects[id(_obj)] if _obj.getParent() is not None: _layer.delObject(_obj) else: _obj.finish() for _obj in _nseg: if _obj.getParent() is None: _layer.addObject(_obj) self.__segs = _nseg def __splitSegPolyline(self): _segs = self.__segs _plines = self.__plines _layer = self.__layer _rects = self.__rects _slist = [] _odict = {} while len(_segs): _seg = _segs.pop() _slist.append(_seg) _sid = id(_seg) if _sid in _odict and not _odict[_sid]: continue _p1, _p2 = _seg.getEndpoints() if (_p1.getParent() is not _layer or _p2.getParent() is not _layer): raise RuntimeError, "Invalid Segment endpoints: " + `_seg` _odict[_sid] = True _rs = _rects.get(_sid) if _rs is None: _rs = SplitManager.segBounds(_seg) _rects[_sid] = _rs _ip = None for _pl in _plines: _pid = id(_pl) _rp = _rects.get(_pid) if _rp is None: _rp = _pl.getBounds() _rects[_pid] = _rp if not SplitManager.canIntersect(_rs, _rp): continue _pts = _pl.getPoints() _i = 0 while (_i < (len(_pts) - 1)): _lp1 = _pts[_i] _lp2 = _pts[_i + 1] if (_p1 == _lp1 or _p1 == _lp2 or _p2 == _lp1 or _p2 == _lp2): _i = _i + 1 continue _ts = Segment(_lp1, _lp2) _ipts = intersections.find_intersections(_seg, _ts) _ts.finish() if len(_ipts): _count = len(_ipts) if _count == 1: _x, _y = _ipts[0] _ip = self.__getPoint(_x, _y) _pl.addPoint((_i + 1), _ip) _pts = _pl.getPoints() if _ip != _p1 and _ip != _p2: _s1, _s2 = split_segment(_seg, _ip) _odict[_sid] = False _segs.append(_s1) _segs.append(_s2) else: _ip = None else: raise ValueError, "Unexpected count: %d" % _count _i = _i + 1 if _ip is not None: break if _ip is not None: break # # handle segments # _nseg = [] _dseg = [] for _obj in _slist: _status = _odict.get(id(_obj)) if _status is None: raise RuntimeError, "No status for Segment: " + `_obj` elif _status: _nseg.append(_obj) else: _dseg.append(_obj) for _obj in _dseg: del self.__rects[id(_obj)] if _obj.getParent() is not None: _layer.delObject(_obj) else: _obj.finish() for _obj in _nseg: if _obj.getParent() is None: _layer.addObject(_obj) self.__segs = _nseg def __splitCircCirc(self): _layer = self.__layer _circs = self.__circs _rects = self.__rects _olist = [] _cdict = {} while len(_circs): _circ = _circs.pop() _olist.append(_circ) _circid = id(_circ) if _circid in _cdict and not _cdict[_circid]: continue _cdict[_circid] = True _rcirc = _rects.get(_circid) if _rcirc is None: _rcirc = SplitManager.circBounds(_circ) _rects[_circid] = _rcirc for _c in _circs: _cid = id(_c) if _cid in _cdict and not _cdict[_cid]: continue _rc = _rects.get(_cid) if _rc is None: _rc = SplitManager.circBounds(_c) _rects[_cid] = _rc if not SplitManager.canIntersect(_rcirc, _rc): continue _ipts = intersections.find_intersections(_c, _circ) if len(_ipts): _count = len(_ipts) if _count == 1: _x, _y = _ipts[0] _ip = self.__getPoint(_x, _y) _arc = split_circle(_circ, _ip) _olist.append(_arc) _cdict[_circid] = False _arc = split_circle(_c, _ip) _olist.append(_arc) _cdict[_cid] = False elif _count == 2: _x, _y = _ipts[0] _ip1 = self.__getPoint(_x, _y) _x, _y = _ipts[1] _ip2 = self.__getPoint(_x, _y) _arc1, _arc2 = SplitManager.splitCircTwoPts(_circ, _ip1, _ip2) _cdict[_circid] = False _olist.append(_arc1) _olist.append(_arc2) _arc1, _arc2 = SplitManager.splitCircTwoPts(_c, _ip1, _ip2) _olist.append(_arc1) _olist.append(_arc2) _cdict[_cid] = False else: raise ValueError, "Unexpected count: %d" % _count break _alist = [] _dlist = [] for _obj in _olist: _status = _cdict.get(id(_obj)) if _status is None: _alist.append(_obj) elif _status: _circs.append(_obj) else: _dlist.append(_obj) for _obj in _dlist: self.delObject(_obj) del self.__rects[id(_obj)] _layer.delObject(_obj) for _obj in _alist: _layer.addObject(_obj) self.addObject(_obj) def __splitCircArc(self): _layer = self.__layer _circs = self.__circs _arcs = self.__arcs _rects = self.__rects _clist = [] _odict = {} while len(_circs): _circ = _circs.pop() _clist.append(_circ) _circid = id(_circ) if _circid in _odict and not _odict[_circid]: continue _odict[_circid] = True _rcirc = _rects.get(_circid) if _rcirc is None: _rcirc = SplitManager.circBounds(_circ) _rects[_circid] = _rcirc for _arc in _arcs: _arcid = id(_arc) if _arcid in _odict and not _odict[_arcid]: continue _odict[_arcid] = True _rarc = _rects.get(_arcid) if _rarc is None: _rarc = _arc.getBounds() _rects[_arcid] = _rarc if not SplitManager.canIntersect(_rcirc, _rarc): continue _ipts = intersections.find_intersections(_circ, _arc) if len(_ipts): _ep1, _ep2 = _arc.getEndpoints() _ca1 = _ca2 = _a1 = _a2 = _a3 = None _count = len(_ipts) if _count == 1: _x, _y = _ipts[0] _ip = self.__getPoint(_x, _y) _ca1 = split_circle(_circ, _ip) if _ip != _ep1 and _ip != _ep2: _a1, _a2 = split_arc(_arc, _ip) elif _count == 2: _x, _y = _ipts[0] _ip1 = self.__getPoint(_x, _y) _x, _y = _ipts[1] _ip2 = self.__getPoint(_x, _y) _ca1, _ca2 = SplitManager.splitCircTwoPts(_circ, _ip1, _ip2) if (_ip1 != _ep1 and _ip1 != _ep2 and _ip2 != _ep1 and _ip2 != _ep2): _a1, _a2, _a3 = SplitManager.splitArcTwoPts(_arc, _ip1, _ip2) elif ((_ip1 == _ep1 or _ip1 == _ep2) and (_ip2 != _ep1 and _ip2 != _ep2)): _a1, _a2 = split_arc(_arc, _ip2) elif ((_ip2 == _ep1 or _ip2 == _ep2) and (_ip1 !=_ep1 and _ip1 != _ep2)): _a1, _a2 = split_arc(_arc, _ip1) else: pass else: raise ValueError, "Unexpected count: %d" % _count # # if _a1 is not None then the arc was split # if _a1 is not None: _odict[_arcid] = False _arcs.append(_a1) if _a2 is not None: _arcs.append(_a2) if _a3 is not None: _arcs.append(_a3) # # if _ca1 is not none then the circle was split # if _ca1 is not None: _odict[_circid] = False _arcs.append(_ca1) if _ca2 is not None: _arcs.append(_ca2) break # # handle circles # _dlist = [] for _obj in _clist: _status = _odict.get(id(_obj)) if _status is None: raise RuntimeError, "No status for Circle: " + `_obj` elif _status: _circs.append(_obj) else: _dlist.append(_obj) for _obj in _dlist: self.delObject(_obj) del self.__rects[id(_obj)] _layer.delObject(_obj) # # handle arcs # _narc = [] _darc = [] for _obj in _arcs: _status = _odict.get(id(_obj)) # # states: # None - Arc untested - created during split of final circle # True - Arc survived all split attempts # False - Arc was split # if _status is None or _status: _narc.append(_obj) else: _darc.append(_obj) for _obj in _darc: del self.__rects[id(_obj)] if _obj.getParent() is not None: _layer.delObject(_obj) else: _obj.finish() for _obj in _narc: if _obj.getParent() is None: _layer.addObject(_obj) self.__arcs = _narc def __splitCircPolyline(self): _circs = self.__circs _plines = self.__plines _layer = self.__layer _rects = self.__rects _alist = [] _clist = [] _odict = {} while len(_circs): _circ = _circs.pop() _clist.append(_circ) _circid = id(_circ) if _circid in _odict and not _odict[_circid]: continue _odict[_circid] = True _rcirc = _rects.get(_circid) if _rcirc is None: _rcirc = SplitManager.circBounds(_circ) _rects[_circid] = _rcirc _hit = False for _pl in _plines: _pid = id(_pl) _rp = _rects.get(_pid) if _rp is None: _rp = _pl.getBounds() _rects[_pid] = _rp if not SplitManager.canIntersect(_rcirc, _rp): continue _pts = _pl.getPoints() for _i in range(len(_pts) - 1): _lp1 = _pts[_i] _lp2 = _pts[_i + 1] _seg = Segment(_lp1, _lp2) _ipts = intersections.find_intersections(_circ, _seg) _seg.finish() if len(_ipts): _a1 = _a2 = None _count = len(_ipts) if _count == 1: _x, _y = _ipts[0] _ip = self.__getPoint(_x, _y) _a1 = split_circle(_circ, _ip) if _ip != _lp1 and _ip != _lp2: _pl.addPoint((_i + 1), _ip) elif _count == 2: _x, _y = _ipts[0] _ip1 = self.__getPoint(_x, _y) _x, _y = _ipts[1] _ip2 = self.__getPoint(_x, _y) _a1, _a2 = SplitManager.splitCircTwoPts(_circ, _ip1, _ip2) if (_ip1 - _lp1) < (_ip2 - _lp1): _p1 = _ip1 _p2 = _ip2 else: _p1 = _ip2 _p2 = _ip1 if _p1 != _lp1 and _p1 != _lp2: _pl.addPoint((_i + 1), _p1) _i = _i + 1 if _p2 != _lp1 and _p2 != _lp2: _pl.addPoint((_i + 1), _p2) else: raise ValueError, "Unexpected count: %d" % _count # # if _a1 is not None the circle was split # if _a1 is not None: _odict[_circid] = False _alist.append(_a1) if _a2 is not None: _alist.append(_a2) _hit = True break if _hit: break # # handle circles # _dlist = [] for _obj in _clist: _status = _odict.get(id(_obj)) if _status is None: raise RuntimeError, "No status for Circle: " + `_obj` elif _status: _circs.append(_obj) else: _dlist.append(_obj) for _obj in _dlist: self.delObject(_obj) del self.__rects[id(_obj)] _layer.delObject(_obj) # # handle arcs # for _obj in _alist: _layer.addObject(_obj) self.addObject(_obj) def __splitArcArc(self): _arcs = self.__arcs _layer = self.__layer _rects = self.__rects _alist = [] _adict = {} while len(_arcs): _arc = _arcs.pop() _alist.append(_arc) _arcid = id(_arc) if _arcid in _adict and not _adict[_arcid]: continue _adict[_arcid] = True _rarc = _rects.get(_arcid) if _rarc is None: _rarc = _arc.getBounds() _rects[_arcid] = _rarc _ep1, _ep2 = _arc.getEndpoints() for _a in _arcs: _aid = id(_a) if _aid in _adict and not _adict[_aid]: continue _ra = _rects.get(_aid) if _ra is None: _ra = _a.getBounds() _rects[_aid] = _ra if not SplitManager.canIntersect(_rarc, _ra): continue _ep3, _ep4 = _a.getEndpoints() _ipts = intersections.find_intersections(_arc, _a) if len(_ipts): _a1 = _a2 = _a3 = _a4 = _a5 = _a6 = None _count = len(_ipts) if _count == 1: _x, _y = _ipts[0] _ip = self.__getPoint(_x, _y) if _ip != _ep1 and _ip != _ep2: _a1, _a2 = split_arc(_arc, _ip) if _ip != _ep3 and _ip != _ep4: _a4, _a5 = split_arc(_a, _ip) elif _count == 2: _x, _y = _ipts[0] _ip1 = self.__getPoint(_x, _y) _x, _y = _ipts[1] _ip2 = self.__getPoint(_x, _y) if (_ip1 != _ep1 and _ip1 != _ep2 and _ip2 != _ep1 and _ip2 != _ep2): _a1, _a2, _a3 = SplitManager.splitArcTwoPts(_arc, _ip1, _ip2) elif ((_ip1 == _ep1 or _ip1 == _ep2) and (_ip2 != _ep1 and _ip2 != _ep2)): _a1, _a2 = split_arc(_arc, _ip2) elif ((_ip2 == _ep1 or _ip2 == _ep2) and (_ip1 != _ep1 and _ip1 != _ep2)): _a1, _a2 = split_arc(_arc, _ip1) else: pass if (_ip1 != _ep3 and _ip1 != _ep4 and _ip2 != _ep3 and _ip2 != _ep4): _a4, _a5, _a6 = SplitManager.splitArcTwoPts(_a, _ip1, _ip2) elif ((_ip1 == _ep3 or _ip1 == _ep4) and (_ip2 != _ep3 and _ip2 != _ep4)): _a4, _a5 = split_arc(_a, _ip2) elif ((_ip2 == _ep3 or _ip2 == _ep4) and (_ip1 != _ep3 and _ip1 != _ep4)): _a4, _a5 = split_arc(_a, _ip1) else: pass else: raise ValueError, "Unexpected count: %d" % _count # # if _a4 is not None then _a was split # if _a4 is not None: _adict[_aid] = False _arcs.append(_a4) if _a5 is not None: _arcs.append(_a5) if _a6 is not None: _arcs.append(_a6) # # if _a1 is not None then _arc was split # if _a1 is not None: _adict[_arcid] = False _arcs.append(_a1) if _a2 is not None: _arcs.append(_a2) if _a3 is not None: _arcs.append(_a3) break _narc = [] _darc = [] for _arc in _alist: _status = _adict.get(id(_arc)) if _status is None: raise RuntimeError, "No status for Arc: " + `_arc` elif _status: _narc.append(_arc) else: _darc.append(_arc) for _arc in _darc: del self.__rects[id(_arc)] if _arc.getParent() is not None: _layer.delObject(_arc) else: _arc.finish() for _arc in _narc: if _arc.getParent() is None: _layer.addObject(_arc) self.__arcs = _narc def __splitArcPolyline(self): _arcs = self.__arcs _plines = self.__plines _layer = self.__layer _rects = self.__rects _alist = [] _adict = {} while len(_arcs): _arc = _arcs.pop() _alist.append(_arc) _arcid = id(_arc) if _arcid in _adict and not _adict[_arcid]: continue _adict[_arcid] = True _rarc = _rects.get(_arcid) if _rarc is None: _rarc = _arc.getBounds() _rects[_arcid] = _rarc _ep1, _ep2 = _arc.getEndpoints() _hit = False for _pl in _plines: _pid = id(_pl) _rp = _rects.get(_pid) if _rp is None: _rp = _pl.getBounds() _rects[_pid] = _rp if not SplitManager.canIntersect(_rarc, _rp): continue _pts = _pl.getPoints() for _i in range(len(_pts) - 1): _lp1 = _pts[_i] _lp2 = _pts[_i + 1] _seg = Segment(_lp1, _lp2) _ipts = intersections.find_intersections(_arc, _seg) _seg.finish() if len(_ipts): _a1 = _a2 = _a3 = None _count = len(_ipts) if _count == 1: _x, _y = _ipts[0] _ip = self.__getPoint(_x, _y) if _ip != _ep1 and _ip != _ep2: _a1, _a2 = split_arc(_arc, _ip) if _ip != _lp1 and _ip != _lp2: _pl.addPoint((_i + 1), _ip) elif _count == 2: _x, _y = _ipts[0] _ip1 = self.__getPoint(_x, _y) _x, _y = _ipts[1] _ip2 = self.__getPoint(_x, _y) if (_ip1 != _ep1 and _ip1 != _ep2 and _ip2 != _ep1 and _ip2 != _ep2): _a1, _a2, _a3 = SplitManager.splitArcTwoPts(_arc, _ip1, _ip2) elif ((_ip1 == _ep1 or _ip1 == _ep2) and (_ip2 != _ep1 and _ip2 != _ep2)): _a1, _a2 = split_arc(_arc, _ip2) elif ((_ip2 == _ep1 or _ip2 == _ep2) and (_ip1 != _ep1 and _ip1 != _ep2)): _a1, _a2 = split_arc(_arc, _ip1) else: pass if (_lp1 - _ip1) < (_lp1 -_ip2): _p1 = _ip1 _p2 = _ip2 else: _p1 = _ip2 _p2 = _ip1 if _p1 != _lp1 and _p1 != _lp2: _pl.addPoint((_i + 1), _p1) _i = _i + 1 if _p2 != _lp1 and _p2 != _lp2: _pl.addPoint((_i + 1), _p2) else: raise ValueError, "Unexpected count: %d" % _count # # if _a1 is not None then _arc was split # if _a1 is not None: _hit = True _adict[_arcid] = False _arcs.append(_a1) if _a2 is not None: _arcs.append(_a2) if _a3 is not None: _arcs.append(_a3) if _hit: break if _hit: break _narc = [] _darc = [] for _arc in _alist: _status = _adict.get(id(_arc)) if _status is None: raise RuntimeError, "No status for Arc: " + `_arc` elif _status: _narc.append(_arc) else: _darc.append(_arc) for _arc in _darc: del self.__rects[id(_arc)] if _arc.getParent() is not None: _layer.delObject(_arc) else: _arc.finish() for _arc in _narc: if _arc.getParent() is None: _layer.addObject(_arc) self.__arcs = _narc def __splitPolyPoly(self): _plines = self.__plines _rects = self.__rects _pdict = {} _zero = (0.0 - 1e-10) _one = (1.0 + 1e-10) while len(_plines): _pl = _plines.pop() _plid = id(_pl) if _plid in _pdict and not _pdict[_plid]: continue _pdict[_plid] = True _rpl = _rects.get(_plid) if _rpl is None: _rpl = _pl.getBounds() _rects[_plid] = _rpl _maxi = len(_pl) - 1 _ip = None for _p in _plines: _pid = id(_p) if _pid in _pdict and not _pdict[_pid]: continue _rp = _rects.get(_pid) if _rp is None: _rp = _p.getBounds() _rects[_pid] = _rp if not SplitManager.canIntersect(_rpl, _rp): continue for _i in range(_maxi): _p1 = _pl.getPoint(_i) _p2 = _pl.getPoint(_i + 1) _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _maxj = len(_p) - 1 for _j in range(_maxj): _p3 = _p.getPoint(_j) _p4 = _p.getPoint(_j + 1) if (_p1 == _p3 or _p1 == _p4 or _p2 == _p3 or _p2 == _p4): continue _d = intersections.denom(_p1, _p2, _p3, _p4) if abs(_d) > 1e-10: # NOT parallel _r = intersections.rnum(_p1, _p2, _p3, _p4)/_d _s = intersections.snum(_p1, _p2, _p3 ,_p4)/_d if (not (_r < _zero or _r > _one) and not (_s < _zero or _s > _one)): _xi = _x1 + _r * (_x2 - _x1) _yi = _y1 + _r * (_y2 - _y1) _ip = self.__getPoint(_xi, _yi) _pl.addPoint((_i + 1), _ip) _p.addPoint((_j + 1), _ip) if _ip is not None: break if _ip is not None: break if _ip is not None: break if _ip is not None: _plines.append(_pl) def split_objects(objlist): """Split a list of objects at their intersection points. split_objects(objlist): objlist: A list or tuple of objects to split """ if not isinstance(objlist, (list, tuple)): raise TypeError, "Invalid object list/tuple: " + `type(objlist)` _ldict = {} for _obj in objlist: _layer = _obj.getParent() if _layer is not None: _mgr = _ldict.setdefault(id(_layer), SplitManager(_layer)) _mgr.addObject(_obj) for _mgr in _ldict.values(): _mgr.splitObjects() PythonCAD-DS1-R37/PythonCAD/Generic/tolerance.py0000644000175000017500000001030511307666657020664 0ustar matteomatteo# # Copyright (c) 2002, 2003 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # this is a class that keeps a tolerance value. It should # be used as a class (static) variable for classes that # will compare instances with a tolerance # # a valid tolerance is a float value 0 or greater # TOL = 1e-10 class TolObject(object): """A class for maintaining a tolerance value. The tolerance value is a float that must be 0.0 or greater. Any class using this class as a base class will have a tolerance value unique to that class. There are two member functions: getTolerance(): return the current tolerance setTolerance(t): set the new tolerance """ def __init__(self, t=None): """Initialize a TolObject. TolObject(t) Optional argument t must be a float, and it must be greater than 0. A default tolerance is set if the function is called without arguments. """ if t is None: t = TOL tol = t if not isinstance(tol, float): tol = float(t) if tol < 0.0: raise ValueError, "Tolerance must be greater than 0: " + `tol` self.__tolerance = tol def setTolerance(self, t=None): """Set the tolerance value. setTolerance(t) Optional argument t must be a float, and it must be greater than 0. The default tolerance is reset if the function is called without arguments. This function returns the old tolerance value. """ old_tol = self.__tolerance if t is None: t = TOL tol = t if not isinstance(tol, float): tol = float(t) if tol < 0.0: raise ValueError, "Tolerance must be greater than 0: " + `tol` self.__tolerance = tol return old_tol def getTolerance(self): """Get the tolerance value. getTolerance() Return the current tolerance. """ return self.__tolerance tolerance = property(getTolerance, setTolerance, None, "Tolerance value") class StaticTolObject(object): """A class for maintaining a tolerance value. This class is meant to be a base-class for classes that wish to use a tolerance value for comparing one instance to another. There are two class methods: getTolerance(): return the current tolerance setTolerance(tol): set the new tolerance This class stores the tolerance value as a static class variable, so any classes using this class as a base class will share the same tolerance value. """ __tolerance = TOL def setTolerance(cls, t=None): """Set the tolerance value. Optional argument t must be a float, and itmust be greater than 0. The default tolerance is reset if the function is called without arguments. This function returns the old tolerance value. """ old_tol = cls.__tolerance if t is None: t = TOL _t = t if not isinstance(_t, float): _t = float(t) if _t < 0.0: raise ValueError, "Tolerance must be greater than 0: " + `_t` cls.__tolerance = _t return old_tol setTolerance = classmethod(setTolerance) def getTolerance(cls): """Get the tolerance value. Return the current tolerance. """ return cls.__tolerance getTolerance = classmethod(getTolerance) def toltest(tol): """Test that a tolerance value is valid. toltest(tol) The argument "tol" should be a float. """ _t = tol if not isinstance(_t, float): _t = float(tol) if _t < TOL: raise ValueError, "Invalid tolerance: %g" % _t return _t PythonCAD-DS1-R37/PythonCAD/Generic/tree.py0000644000175000017500000002727411307666657017664 0ustar matteomatteo# # Copyright (c) 2002, 2003 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # a class for maintaining a sorted list # # each list holds only a single type of object, and # the list is organized from smallest to largest # from PythonCAD.Generic import baseobject class TreeItem(baseobject.ModObject): """An object stored in a Tree. A TreeItem object is meant to be a base class for classes that will have instances stored in a Tree. TreeItem objects are derived from ModObjects, so they share the same attributes and methods as those objects. """ def __init__(self): """Initialize a TreeItem object. There are no arguments to this method. """ baseobject.ModObject.__init__(self) self.__tree = None # private to the TreeItem def _setTree(self, tree): """Store a reference to the Tree this TreeItem is stored within. _setTree(tree) A TreeItem object can only be kept in one Tree at a time. This routine is private to the TreeItem implementation. """ if tree is None: self.__tree = None else: if not isinstance(tree, Tree): raise TypeError, "Invalid Tree for storage: " + str(tree) if self.__tree is not None: raise ValueError, "TreeItem already claimed by a tree." self.__tree = tree def modified(self): """Set the modified flag value to True. modified() This method extends the ModObject::modified() method """ baseobject.ModObject.modified(self) if self.__tree is not None: self.__tree.markModified(self) class Tree(list): """A class for Trees. The Tree class is similar to a list, but it stores the objects in a sorted order. A Tree object can be iterated over, and there is a several method for scanning objects held in the tree. An object stored in the tree must be derived from the TreeItem class. A Tree has several methods: clear(): Remove all objects from the tree. store(obj): Store some object in the tree. remove(obj): Remove an object from the tree binscan(obj): Search the tree for the object using a binary search scan(obj): Search the tree for the object using a linear search. isModified(): An object stored in the Tree has its modified flag set to True getModified(): Return the objects in the Tree that are modified clean(): Sort the objects stored in the Tree, and remove any duplicates. Trees also have a modified __add__ method that allows you to add trees together, and a __contains__ method for doing "obj in tree" or "obj not in tree" operations. Also, a Tree supports indexed retrival similar to a list, but not allow indexed assignment or indexed deletion. """ def __init__(self, t): """Initialize a Tree. Tree(t) A Tree takes a single parameter t which is the type of object stored within the tree. Any Tree will only hold one type of object, and that object type cannot be None. """ if not issubclass(t, TreeItem): raise ValueError, "Invalid object for Tree storage: " + `t` list.__init__(self) self.__type = t self.__iter_index = 0 self.__modified = [] def __iter__(self): """Make a Tree iterable. """ if len(self.__modified): raise ValueError, "Tree in modified state." self.__iter_index = 0 return self def next(self): """This method is used for iteration. """ _index = self.__iter_index _next = _index + 1 if _next > len(self): raise StopIteration self.__iter_index = _next return self[_index] def __setitem__(self, index, value): raise StandardError, "Tree::__setitem__() is not supported." def __delitem__(self, index): raise StandardError, "Tree::__delitem__() is not supported." def __setslice__(self, i, j, vals): raise StandardError, "Tree::__setslice__() is not supported." def __delslice__(self, i, j): raise StandardError, "Tree::__delslice__() is not supported." def append(self, obj): raise StandardError, "Tree::append() is not supported." def insert(self, index, obj): raise StandardError, "Tree::insert() is not supported." def extend(self, objlist): raise StandardError, "Tree::extend() is not supported." def pop(self, idx=-1): raise StandardError, "Tree::pop() is not supported." def reverse(self): raise StandardError, "Tree::reverse() is not supported." def __contains__(self, obj): """Test if an object is in a Tree. This method uses a binary search to find if an object is in a Tree. It _should_ always be faster than a simple linear search from first object to the last. """ if not isinstance(obj, self.__type): raise TypeError, "Invalid object for inclusion test: " + `obj` if len(self.__modified): raise ValueError, "Tree in modified state." _lo = 0 _hi = len(self) _scanlist = [] _seen = False while _lo < _hi: _mid = (_hi+_lo)//2 if _mid in _scanlist: break _scanlist.append(_mid) _res = cmp(self[_mid], obj) if _res == -1: _lo = _mid + 1 elif _res == 1: _hi = _mid else: _seen = True break return _seen def clear(self): """Empty the Tree. clear() """ del self.__modified[:] list.__delslice__(self, 0, len(self)) def markModified(self, treeitem): """Store a reference to a modified TreeItem object. markModified(treeitem) This routine is private to the Tree implementation. """ self.__modified.append(treeitem) def store(self, obj): """Store an object in the Tree. store(obj) The object must be the same as was given when the tree was instantiated. A TypeError is raised if another object type is stored. The objects in the Tree are searched by using the cmp() function. Any class that will be stored in a Tree should provide a suitable __cmp__ method. """ if not isinstance(obj, self.__type): raise TypeError, "Invalid object for storage: " + `obj` obj._setTree(self) if len(self.__modified): raise ValueError, "Tree in modified state." _lo = 0 _hi = len(self) _scanlist = [] while _lo < _hi: _mid = (_hi+_lo)//2 if _mid in _scanlist: break _scanlist.append(_mid) _res = cmp(self[_mid], obj) if _res == -1: _lo = _mid + 1 elif _res == 1: _hi = _mid else: raise ValueError, "Equivalent object already in tree: " + `obj` list.insert(self, _lo, obj) assert _is_sorted(self), "Tree is not sorted: " + `self` def remove(self, obj): """Remove an object from a Tree. remove(obj) Delete the object from the Tree. """ if not isinstance(obj, self.__type): raise TypeError, "Invalid object for removal: " + `obj` if len(self.__modified): raise ValueError, "Tree in modified state." obj._setTree(None) _lo = 0 _hi = len(self) _scanlist = [] while _lo < _hi: _mid = (_hi+_lo)//2 if _mid in _scanlist: break _scanlist.append(_mid) _res = cmp(self[_mid], obj) if _res == -1: _lo = _mid + 1 elif _res == 1: _hi = _mid else: list.__delitem__(self, _mid) break def binscan(self, obj, tol=0): """Scan the Tree for the an object using a binary search. binscan(obj) This method looks for an object in a Tree utilizing a simple binary search. If the object is found within the tree, the index of the object is returned. Otherwise, the function returns None. """ if not isinstance(obj, self.__type): raise TypeError, "Invalid object for binscan: " + `obj` if len(self.__modified): raise ValueError, "Tree in modified state." _lo = 0 _hi = len(self) _scanlist = [] _ro = None while _lo < _hi: _mid = (_hi+_lo)//2 if _mid in _scanlist: break _scanlist.append(_mid) _res = cmp(self[_mid], obj) if _res == -1: _lo = _mid + 1 elif _res == 1: _hi = _mid else: _ro = self[_mid] break return _ro def scan(self, obj, tol=0): """Scan the Tree for the an object from first to last. scan(obj) This method looks for an object in a Tree from the first object to the last. It stops searching at the first instance which is greater than the object, or the first instance where one object is equal to the other. The function returns None if no object in the Tree is found equal to the object being compared against. """ if not isinstance(obj, self.__type): raise TypeError, "Invalid object for scan: " + `obj` if len(self.__modified): raise ValueError, "Tree in modified state." _ro = None for _sobj in self: _res = cmp(_sobj, obj) if _res == 1: break if _res == 0: _ro = _sobj break return _ro def isModified(self): """Returns True if an object in the tree has the modified flag to True. isModified() """ return len(self.__modified) != 0 def getModified(self): """Return any objects in the tree that have the modified flag to True. getModified() """ return self.__modified[:] def clean(self): """Sort the objects in the tree, and remove duplicated entities. clean() This function returns any duplicated entities found in the Tree. It is up to the caller to deal with any returned objects. """ _dups = [] if len(self.__modified): self.sort() _pobj = self[0] _dlist = [] for _i in range(1, len(self)): _obj = self[_i] if _obj == _pobj: _dlist.append(_i) else: _pobj = _obj if len(_dlist): _dlist.reverse() for _i in _dlist: _dups.append(self[_i]) list.__delitem__(self, _i) for _obj in self.__modified: if _obj not in _dups: _obj.reset() del self.__modified[:] return _dups # # this is a function used for assertion testing # def _is_sorted(tree): _res = True for _i in range(1, len(tree)): _tp = tree[_i-1] _ti = tree[_i] if _tp >= _ti: _res = False break return _res PythonCAD-DS1-R37/PythonCAD/Generic/pyGeoLib.py0000644000175000017500000001021311307666732020412 0ustar matteomatteo# # Copyright (c) 2009 Matteo Boscolo # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # This module provide class to manage geometrical vector operation # import math from PythonCAD.Generic import point class Vector: """ Provide a full 2d vector operation and definition """ def __init__(self,p1,p2): """ Default Constructor """ if(not isinstance(p1,point.Point)): raise TypeError,"Invalid Argument p1: Point Required" if(not isinstance(p2,point.Point)): raise TypeError,"Invalid Argument p2: Point Required" x,y=p1.getCoords() x1,y1=p2.getCoords() self.X=x1-x self.Y=y1-y def Mag(self): """ Get the versor """ if(self.X==0 or self.Y==0): if(self.X==0): x=0 if(self.Y>0): y=1 else: y=-1 else: y=0 if(self.X>0): x=1 else: x=-1 else: module=self.Norm() y=self.Y/module x=self.X/module p1=point.Point(0,0) p2=point.Point(x,y) retVector=Vector(p1,p2) return retVector def Norm(self): """ Get The Norm Of the vector """ return math.sqrt(pow(self.X,2)+pow(self.Y,2)) def __eq__(self,vector): """ the 2 vecror are equal """ if(not isinstance(vector,Vector)): raise TypeError,"Invalid Argument vector: Vector Required" if(self.Point()==vector.Point()): return True else: return False def Point(self): """ Return The Point """ return point.Point(self.X,self.Y) def Dot(self,vector): """ Compute The Dot Product """ if(not isinstance(vector,Vector)): raise TypeError,"Invalid Argument vector: Vector Required" v0=self.Point().getCoords() v1=vector.Point().getCoords() som=0 for a, b in zip(v0, v1): som+=a*b return som def Cross(self,vector): """ Compute The Cross Product """ if(not isinstance(vector,Vector)): raise TypeError,"Invalid Argument vector: Vector Required" x1,y1=self.Point().getCoords() x2,y2=vector.Point().getCoords() cros=x1*y2 - y1*x2 return cros def Ang(self,vector): """ Calculate the angle Between the two vector """ if(not isinstance(vector,Vector)): raise TypeError,"Invalid Argument vector: Vector Required" vself=self.Mag() vvector=vector.Mag() dot=vself.Dot(vvector) if(dot<-1): dot=-1 if(dot>1): dot=1 ang=math.acos(dot) return ang def Mult(self,scalar): """ Multiplae the vector for a scalar value """ self.X=scalar*self.X self.Y=scalar*self.Y def Map(self,x,y): """ Get a vector for the mapping point """ p0=point.Point(0,0) pPro=point.Point(x,y) vProj=Vector(p0,pPro) ang=self.Ang(vProj) vProjNorm=vProj.Norm() projectionUnitDistance=vProjNorm*math.cos(ang) vSelfMag=self.Mag() vSelfMag.Mult(projectionUnitDistance) return vSelfMag PythonCAD-DS1-R37/PythonCAD/Generic/tangent.py0000644000175000017500000006555011307666657020364 0ustar matteomatteo# # Copyright (c) 2003, 2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # functions for handling tangent circles on multiple objects # import math from PythonCAD.Generic import hcline from PythonCAD.Generic import vcline from PythonCAD.Generic import acline from PythonCAD.Generic import cline from PythonCAD.Generic import ccircle # # common constants # _dtr = math.pi/180.0 _piover2 = math.pi/2.0 # # find the projection point of point (x, y) on a line # from (x1, y1) to (x2, y2) # def _get_two_point_projection(x1, y1, x2, y2, x, y): _sqlen = pow((x2 - x1), 2) + pow((y2 - y1), 2) _rn = ((x - x1) * (x2 - x1)) + ((y - y1) * (y2 - y1)) _r = _rn/_sqlen _px = x1 + _r * (x2 - x1) _py = y1 + _r * (y2 - y1) return _px, _py # # find the projection point of point (x, y) on a line # defined by an angle and y intercept # def _get_angled_projection(angle, yint, x, y): _x1 = 0.0 _y1 = yint _x2 = _x1 + math.cos(angle) _y2 = _y1 + math.sin(angle) return _get_two_point_projection(_x1, _y1, _x2, _y2, x, y) def _two_line_tangent(x1, y1, x2, y2, x3, y3, x4, y4, x, y): # # this function calculates the apprpriate tangent circle # for two lines (x1, y1)->(x2, y2) and (x3, y3)->(x4, y4) # using a point (x, y) to determine which tangent circle # should be defined # # test if lines are parallel # _cx = _cy = _radius = None _denom = ((x2 - x1) * (y4 - y3)) - ((y2 - y1) * (x4 - x3)) # print "denom: %g" % _denom if abs(_denom) < 1e-10: # print "parallel ..." if abs(x2 - x1) < 1e-10: # both vertical if x < min(x1, x3) or x > max(x1, x3): return None _cx = (x3 + x1)/2.0 _cy = y _radius = abs(x3 - x1)/2.0 elif abs(y2 - y1) < 1e-10: # both horizontal if y < min(y1, y3) or y > max(y1, y3): return None _cx = x _cy = (y3 + y1)/2.0 _radius = abs(y3 - y1)/2.0 else: # both at equal angles _ax1, _ay1 = _get_two_point_projection(x1, y1, x2, y2, x, y) # print "ax1: %g; ay1: %g" % (_ax1, _ay1) _ax2, _ay2 = _get_two_point_projection(x3, y3, x4, y4, x, y) # print "ax2: %g; ay2: %g" % (_ax2, _ay2) if (x < min(_ax1, _ax2) or x > max(_ax1, _ax2) or y < min(_ay1, _ay2) or y > max(_ay1, _ay2)): return None _cx = (_ax1 + _ax2)/2.0 _cy = (_ay1 + _ay2)/2.0 _radius = math.hypot((_ax1 - _cx), (_ay1 - _cy)) return _cx, _cy, _radius # # the lines are not parallel, so we have to test for the # different combinations of horizontal/vertical/sloped lines ... # if abs(y2 - y1) < 1e-10: # horizontal line 1 # print "horizontal line 1 ..." if abs(y4 - y3) < 1e-10: # this should be handled above ... # print "horizontal line 2 ..." if y < min(y1, y3) or y > max(y1, y3): return None _cx = x _cy = (y1 + y3)/2.0 _radius = abs(_cy - y1) elif abs(x4 - x3) < 1e-10: # vertical line 2 # print "vertical line 2 ..." _a1 = math.pi/4.0 _a2 = -_a1 else: _angle = math.atan2((y4 - y3), (x4 - x3)) _a1 = _angle/2.0 if _a1 > 0.0: _a2 = _a1 - _piover2 else: _a2 = _a1 + _piover2 elif abs(x2 - x1) < 1e-10: # vertical line 1 # print "vertical line 1 ..." if abs(y4 - y3) < 1e-10: # horizontal line2 # print "horizontal line 2 ..." _a1 = math.pi/4.0 _a2 = -_a1 elif abs(x4 - x3) < 1e-10: # this should be handled above ... if x < min(x1, x3) or x > max(x1, x3): return None _cx = (x1 + x3)/2.0 _cy = y _radius = abs(_cx - x1) else: _angle = math.atan2((y4 - y3), (x4 - x3)) if _angle > 0.0: _a1 = (_angle + _piover2)/2.0 _a2 = _a1 - _piover2 else: _a1 = (_angle - _piover2)/2.0 _a2 = _a1 + _piover2 else: _angle1 = math.atan2((y2 - y1), (x2 - x1)) if abs(y4 - y3) < 1e-10: # horizontal line2 _a1 = _angle1/2.0 if _a1 > 0.0: _a2 = _a1 - _piover2 else: _a2 = _a1 + _piover2 elif abs(x4 - x3) < 1e-10: # vertical line2 if _angle1 > 0.0: _a1 = (_angle1 + _piover2)/2.0 _a2 = _a1 - _piover2 else: _a1 = (_angle1 - _piover2)/2.0 _a2 = _a1 + _piover2 else: _angle2 = math.atan2((y4 - y3), (x4 - x3)) _a1 = (_angle1 + _angle2)/2.0 if _a1 > 0.0: _a2 = _a1 - _piover2 else: _a2 = _a1 + _piover2 if _cx is not None and _cy is not None and _radius is not None: return _cx, _cy, _radius # # handle the general case of two lines at arbitrary angles # # print "arbitrary angles ..." # print "a1: %g" % (_a1/_dtr) # print "a2: %g" % (_a2/_dtr) _rn = ((y1 - y3) * (x4 - x3)) - ((x1 - x3) * (y4 - y3)) # print "rn: %g" % _rn _r = _rn/_denom # print "r: %g" % _r _ix = x1 + _r * (x2 - x1) _iy = y1 + _r * (y2 - y1) # print "ix: %g; iy: %g" % (_ix, _iy) _m1 = math.tan(_a1) _b1 = _iy - (_m1 * _ix) # print "line1: m: %g; b: %g" % (_m1, _b1) _m2 = math.tan(_a2) _b2 = _iy - (_m2 * _ix) # print "line2: m: %g; b: %g" % (_m2, _b2) _px1, _py1 = _get_angled_projection(_a1, _b1, x, y) # print "px1: %g; py1: %g" % (_px1, _py1) _sep1 = math.hypot((_px1 - x), (_py1 - y)) _px2, _py2 = _get_angled_projection(_a2, _b2, x, y) # print "px2: %g; py2: %g" % (_px2, _py2) _sep2 = math.hypot((_px2 - x), (_py2 - y)) if _sep1 < _sep2: _cx = _px1 _cy = _py1 else: _cx = _px2 _cy = _py2 _px, _py = _get_two_point_projection(x1, y1, x2, y2, _cx, _cy) _radius = math.hypot((_px - _cx), (_py - _cy)) return _cx, _cy, _radius # # horizontal construction line tangents # def _hcl_hcl_tangent(hcla, hclb, x, y): _hx1, _hy1 = hcla.getLocation().getCoords() _hx2, _hy2 = hclb.getLocation().getCoords() if y < min(_hy1, _hy2) or y > max(_hy1, _hy2): return None _cx = x _cy = (_hy1 + _hy2)/2.0 _radius = abs(_cy - _hy1) return _cx, _cy, _radius def _hcl_vcl_tangent(hcl, vcl, x, y): _hx, _hy = hcl.getLocation().getCoords() _hx2 = _hx + 1.0 _vx, _vy = vcl.getLocation().getCoords() _vy2 = _vy + 1.0 return _two_line_tangent(_hx, _hy, _hx2, _hy, _vx, _vy, _vx, _vy2, x, y) def _hcl_acl_tangent(hcl, acl, x, y): _hx, _hy = hcl.getLocation().getCoords() _hx2 = _hx + 1.0 _ax, _ay = acl.getLocation().getCoords() _angle = acl.getAngle() * _dtr _ax2 = _ax + math.cos(_angle) _ay2 = _ay + math.sin(_angle) return _two_line_tangent(_hx, _hy, _hx2, _hy, _ax, _ay, _ax2, _ay2, x, y) def _hcl_cl_tangent(hcl, cl, x, y): _hx, _hy = hcl.getLocation().getCoords() _hx2 = _hx + 1.0 _p1, _p2 = cl.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() return _two_line_tangent(_hx, _hy, _hx2, _hy, _x1, _y1, _x2, _y2, x, y) # # the HCLine-CCircle tangent circle problem has been generalized # to solve the {VCLine/ACLine/CLine}-CCircle tangent calculation # def _gen_cline_ccircle_tangent(radius, hy, x): # # center of ccircle : (0,0) # radius of ccircle : r # distance between ccircle and hcl: hy # x-coordinate of mouse: x # # center of tangent circle : (px, py) # # projection point on hcl: (px, hy) # # Projection point outside the radius of the circle gives: # # math.hypot((px - cx), (py - cy)) == math.hypot((px - px), (py - hy)) + r # # Projection point inside the radius of the circle gives: # # math.hypot((px - cx), (py - cy)) + rt = r # # rt == radius of tangent circle # # Distance from projection point to tangent circle center # # math.hypot((px - px), (py - hy)) = rt # # lots of algebra reduces to the following two cases # _cx = x if hy > 0.0: _num = pow(x, 2) - pow(hy, 2) - (2.0 * hy * radius) - pow(radius, 2) _den = (-2.0 * hy) - (2.0 * radius) else: _num = pow(x, 2) - pow(hy, 2) + (2.0 * hy * radius) - pow(radius, 2) _den = (2.0 * radius) - (2.0 * hy) # print "num: %g" % _num # print "den: %g" % _den _cy = _num/_den _radius = abs(_cy - hy) return _cx, _cy, _radius def _hcl_cc_tangent(hcl, cc, x, y): _hx, _hy = hcl.getLocation().getCoords() # print "hy: %g" % _hy _ccx, _ccy = cc.getCenter().getCoords() _rad = cc.getRadius() # # transform the coords into system where circle center is (0,0) # _sep = _hy - _ccy _xproj = x - _ccx _tcx, _tcy, _tcrad = _gen_cline_ccircle_tangent(_rad, _sep, _xproj) # # transform result back into real coordinates # _cx = _tcx + _ccx _cy = _tcy + _ccy return _cx, _cy, _tcrad # # vertical construction line # def _vcl_vcl_tangent(vcl1, vcl2, x, y): _vx1, _vy1 = vcl1.getLocation().getCoords() _vx2, _vy2 = vcl2.getLocation().getCoords() if x < min(_vx1, _vx2) or x > max(_vx1, _vx2): return None _cx = (_vx1 + _vx2)/2.0 _cy = y _radius = abs(_cx - _vx1) return _cx, _cy, _radius def _vcl_acl_tangent(vcl, acl, x, y): _vx, _vy = vcl.getLocation().getCoords() _vy2 = _vy + 1.0 _ax, _ay = acl.getLocation().getCoords() _angle = acl.getAngle() * _dtr _ax2 = _ax + math.cos(_angle) _ay2 = _ay + math.sin(_angle) return _two_line_tangent(_vx, _vy, _vx, _vy2, _ax, _ay, _ax2, _ay2, x, y) def _vcl_cl_tangent(hcl, cl, x, y): _vx, _vy = hcl.getLocation().getCoords() _vy2 = _vy + 1.0 _p1, _p2 = cl.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() return _two_line_tangent(_vx, _vy, _vx, _vy2, _x1, _y1, _x2, _y2, x, y) def _vcl_cc_tangent(vcl, cc, x, y): _vx, _vy = vcl.getLocation().getCoords() # print "vx: %g" % _vx _ccx, _ccy = cc.getCenter().getCoords() _rad = cc.getRadius() # # transform the coords into system where circle center is (0,0) and # rotate 90 degrees # _sep = _vx - _ccx _xproj = y - _ccy _tcx, _tcy, _tcrad = _gen_cline_ccircle_tangent(_rad, _sep, _xproj) # # transform result back into real coordinates # _cx = _tcy + _ccx _cy = _tcx + _ccy return _cx, _cy, _tcrad # # angular construction line # def _acl_acl_tangent(acl1, acl2, x, y): _ax1, _ay1 = acl1.getLocation().getCoords() _angle1 = acl1.getAngle() * _dtr _ax2 = _ax1 + math.cos(_angle1) _ay2 = _ay1 + math.sin(_angle1) _ax3, _ay3 = acl2.getLocation().getCoords() _angle2 = acl2.getAngle() * _dtr _ax4 = _ax3 + math.cos(_angle2) _ay4 = _ay3 + math.sin(_angle2) return _two_line_tangent(_ax1, _ay1, _ax2, _ay2, _ax3, _ay3, _ax4, _ay4, x, y) def _acl_cl_tangent(acl, cl, x, y): _ax1, _ay1 = acl.getLocation().getCoords() _angle = acl.getAngle() * _dtr _ax2 = _ax1 + math.cos(_angle) _ay2 = _ay1 + math.sin(_angle) _p1, _p2 = cl.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() return _two_line_tangent(_ax1, _ay1, _ax2, _ay2, _x1, _y1, _x2, _y2, x, y) def _acl_cc_tangent(acl, cc, x, y): _ax, _ay = acl.getLocation().getCoords() # print "ax: %g; ay: %g" % (_ax, _ay) _angle = acl.getAngle() _ccx, _ccy = cc.getCenter().getCoords() _rad = cc.getRadius() # # transform the coords into the system where the circle center is (0,0) # and rotate so the ACLine is horizontal # _apx, _apy = acl.getProjection(_ccx, _ccy) _sep = math.hypot((_apx - _ccx), (_apy - _ccy)) if abs(_angle) < 1e-10: # horizontal _sine = 0.0 if _apy > _ccy: # system rotated 0.0 _cosine = 1.0 else: # system rotated 180.0 _cosine = -1.0 elif abs(abs(_angle) - 90.0) < 1e-10: # vertical _cosine = 0.0 if _apx > _ccx: # system rotated 90.0 _sine = 1.0 else: # system rotated -90.0 _sine = -1.0 else: _angle = _piover2 - math.atan2((_apy - _ccy), (_apx - _ccx)) _sine = math.sin(_angle) _cosine = math.cos(_angle) # # transform (x, y) # _tx1 = x - _ccx _ty1 = y - _ccy # # transform by rotating through _negative_ angle to # map to horizontal line # _tx = (_tx1 * _cosine) - (_ty1 * _sine) _ty = (_tx1 * _sine) + (_ty1 * _cosine) _tcx, _tcy, _tcrad = _gen_cline_ccircle_tangent(_rad, _sep, _tx) # # transform result back into real coordinates # _cx = ((_tcx * _cosine) + (_tcy * _sine)) + _ccx _cy = (-(_tcx * _sine) + (_tcy * _cosine)) + _ccy return _cx, _cy, _tcrad # # two-point construction line # def _cl_cl_tangent(cl1, cl2, x, y): _p1, _p2 = cl1.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _p3, _p4 = cl2.getKeypoints() _x3, _y3 = _p3.getCoords() _x4, _y4 = _p4.getCoords() return _two_line_tangent(_x1, _y1, _x2, _y2, _x3, _y3, _x4, _y4, x, y) def _cl_cc_tangent(cl, cc, x, y): _p1, _p2 = cl.getKeypoints() _x1, _y1 = _p1.getCoords() # print "x1: %g; y1: %g" % (_x1, _y1) _x2, _y2 = _p2.getCoords() # print "x2: %g; y2: %g" % (_x2, _y2) _ccx, _ccy = cc.getCenter().getCoords() # print "ccx: %g; ccy: %g" % (_ccx, _ccy) _rad = cc.getRadius() # # transform the coords into the system where the circle center is (0,0) # and rotate so the CLine is horizontal # _apx, _apy = cl.getProjection(_ccx, _ccy) # print "apx: %g; apy: %g" % (_apx, _apy) _sep = math.hypot((_apx - _ccx), (_apy - _ccy)) # print "sep: %g" % _sep # # use the line (ccx, ccy) to (apx, apy) to determine the # angular rotation # if abs(_apx - _ccx) < 1e-10: # cline is horizontal _sine = 0.0 if _apy > _ccy: # system rotated 0.0 _cosine = 1.0 else: # system rotated 180.0 _cosine = -1.0 elif abs(_apy - _ccy) < 1e-10: # cline is vertical; system rotated -90.0 _cosine = 0.0 if _apx > _ccx: # system rotated 90.0 _sine = 1.0 else: # system rotated -90.0 _sine = -1.0 else: _angle = _piover2 - math.atan2((_apy - _ccy), (_apx - _ccx)) # print "angle: %g" % _angle _sine = math.sin(_angle) _cosine = math.cos(_angle) # print "sin(angle): %g" % _sine # print "cos(angle): %g" % _cosine # # transform (x, y) into _tx1 = x - _ccx _ty1 = y - _ccy # print "tx1: %g; ty1: %g" % (_tx1, _ty1) # # transform by rotating through angle to # map to horizontal line # _tx = (_tx1 * _cosine) - (_ty1 * _sine) _ty = (_tx1 * _sine) + (_ty1 * _cosine) # print "tx: %g; ty: %g" % (_tx, _ty) _tcx, _tcy, _tcrad = _gen_cline_ccircle_tangent(_rad, _sep, _tx) # # transform result back into real coordinates # # print "tcx: %g: tcy: %g" % (_tcx, _tcy) _cx = ((_tcx * _cosine) + (_tcy * _sine)) + _ccx _cy = (-(_tcx * _sine) + (_tcy * _cosine)) + _ccy # print "cx: %g; cy %g" % (_cx, _cy) return _cx, _cy, _tcrad def calc_tangent_circle(obja, objb, x, y): _x = x if not isinstance(_x, float): _x = float(x) _y = y if not isinstance(_y, float): _y = float(y) _tandata = None if isinstance(obja, hcline.HCLine): if isinstance(objb, hcline.HCLine): _tandata = _hcl_hcl_tangent(obja, objb, _x, _y) elif isinstance(objb, vcline.VCLine): _tandata = _hcl_vcl_tangent(obja, objb, _x, _y) elif isinstance(objb, acline.ACLine): _tandata = _hcl_acl_tangent(obja, objb, _x, _y) elif isinstance(objb, cline.CLine): _tandata = _hcl_cl_tangent(obja, objb, _x, _y) elif isinstance(objb, ccircle.CCircle): _tandata = _hcl_cc_tangent(obja, objb, _x, _y) elif isinstance(obja, vcline.VCLine): if isinstance(objb, hcline.HCLine): _tandata = _hcl_vcl_tangent(objb, obja, _x, _y) elif isinstance(objb, vcline.VCLine): _tandata = _vcl_vcl_tangent(obja, objb, _x, _y) elif isinstance(objb, acline.ACLine): _tandata = _vcl_acl_tangent(obja, objb, _x, _y) elif isinstance(objb, cline.CLine): _tandata = _vcl_cl_tangent(obja, objb, _x, _y) elif isinstance(objb, ccircle.CCircle): _tandata = _vcl_cc_tangent(obja, objb, _x, _y) elif isinstance(obja, acline.ACLine): if isinstance(objb, hcline.HCLine): _tandata = _hcl_acl_tangent(objb, obja, _x, _y) elif isinstance(objb, vcline.VCLine): _tandata = _vcl_acl_tangent(objb, obja, _x, _y) elif isinstance(objb, acline.ACLine): _tandata = _acl_acl_tangent(obja, objb, _x, _y) elif isinstance(objb, cline.CLine): _tandata = _acl_cl_tangent(obja, objb, _x, _y) elif isinstance(objb, ccircle.CCircle): _tandata = _acl_cc_tangent(obja, objb, _x, _y) elif isinstance(obja, cline.CLine): if isinstance(objb, hcline.HCLine): _tandata = _hcl_cl_tangent(objb, obja, _x, _y) elif isinstance(objb, vcline.VCLine): _tandata = _vcl_cl_tangent(objb, obja, _x, _y) elif isinstance(objb, acline.ACLine): _tandata = _acl_cl_tangent(objb, obja, _x, _y) elif isinstance(objb, cline.CLine): _tandata = _cl_cl_tangent(obja, objb, _x, _y) elif isinstance(objb, ccircle.CCircle): _cl_cc_tangent(obja, objb, _x, _y) elif isinstance(obja, ccircle.CCircle): if isinstance(objb, hcline.HCLine): _tandata = _hcl_cc_tangent(objb, obja, _x, _y) elif isinstance(objb, vcline.VCLine): _tandata = _vcl_cc_tangent(objb, obja, _x, _y) elif isinstance(objb, acline.ACLine): _tandata = _acl_cc_tangent(objb, obja, _x, _y) elif isinstance(objb, cline.CLine): _tandata = _cl_cc_tangent(objb, obja, _x, _y) else: pass # CCircle/CCircle tangent circles to do later ... return _tandata # # calculate the possible tangent lines between two circles # def _calc_values(ax, ay, bx, by, cx, cy): """This function was used for debugging""" _den = pow((bx - ax), 2) + pow((by - ay), 2) _num = ((cx - ax) * (bx - ax)) + ((cy - ay) * (by - ay)) _r = _num/_den # print "r: %g" % _r _num = ((ay - cy) * (bx - ax)) - ((ax - cx) * (by - ay)) _s = _num/_den # print "s: %g" % _s _sep = abs(_s) * math.sqrt(_den) # print "sep: %g" % _sep # return _r, _s, _sep def _calc_tangent_triangle(r1, r2, sep, ip): _sine = r1/abs(ip) # print "sin: %g" % _sine _angle = math.asin(_sine) # print "angle: %g" % (_angle * (180.0/math.pi)) _tan = math.tan(_angle) # print "tan(angle): %g" % _tan _cosine = math.cos(_angle) # print "cos(angle): %g" % _cosine _tanlen = r1/_tan # print "tanlen: %g" % _tanlen if ip < 0.0: # r1 < r2 and intersection point left of r1 assert abs(ip) > r1, "Expected ip beyond radius: %g < %g" % (ip, r1) _tx1 = ip + (_tanlen * _cosine) else: _tx1 = ip - (_tanlen * _cosine) # print "tx1: %g" % _tx1 _ty1 = _tanlen * _sine # print "ty1: %g" % _ty1 _dist = math.hypot(_tx1, _ty1) # print "dist: %g" % _dist assert abs(_dist - r1) < 1e-10, "Invalid tangent point for circle 1" _tanlen = r2/_tan # print "tanlen: %g" % _tanlen if ip < 0.0: # see above _tx2 = ip + (_tanlen * _cosine) _ty2 = _tanlen * _sine elif ip > (sep + r2): # only possible if r1 > r2 _tx2 = ip - (_tanlen * _cosine) _ty2 = _tanlen * _sine else: _tx2 = ip + (_tanlen * _cosine) _ty2 = -1.0 * _tanlen * _sine # print "tx2: %g" % _tx2 # print "ty2: %g" % _ty2 _dist = math.hypot((_tx2 - sep), _ty2) # print "dist: %g" % _dist assert abs(_dist - r2) < 1e-10, "Invalid tangent point for circle 2" return _tx1, _ty1, _tx2, _ty2 def calc_two_circle_tangents(r1, r2, sep): # print "in calc_two_circle_tangents() ..." _r1 = r1 if not isinstance(_r1, float): _r1 = float(r1) if not _r1 > 0.0: raise ValueError, "Invalid radius: %g" % _r1 _r2 = r2 if not isinstance(_r2, float): _r2 = float(r2) if not _r2 > 0.0: raise ValueError, "Invalid radius: %g" % _r2 _sep = sep if not isinstance(_sep, float): _sep = float(sep) _tangents = [] if (abs(_sep) + min(_r1, _r2)) > max(_r1, _r2): # small circle not within larger if abs(_r1 - _r2) < 1e-10: # print "same radii ..." _tangents.append((0.0, _r1, _sep, _r2)) _tangents.append((0.0, -_r1, _sep, -_r2)) if abs(_sep) > _r1 + _r2: _mid = _sep/2.0 _angle = math.asin(_r1/_mid) _tanlen = _r1/math.tan(_angle) _xt = _tanlen * math.cos(_angle) _yt = _tanlen * math.sin(_angle) _tx1 = _mid - _xt _ty1 = _yt _tx2 = _mid + _xt _ty2 = -_yt _tangents.append((_tx1, _ty1, _tx2, _ty2)) # _calc_values(_tx1, _ty1, _tx2, _ty2, 0.0, 0.0) # _calc_values(_tx1, _ty1, _tx2, _ty2, _sep, 0.0) _tangents.append((_tx1, -_ty1, _tx2, -_ty2)) # _calc_values(_tx1, -_ty1, _tx2, -_ty2, 0.0, 0.0) # _calc_values(_tx1, -_ty1, _tx2, -_ty2, _sep, 0.0) else: _alpha = pow((_r1/_r2), 2) # print "alpha: %g" % _alpha _a = (1.0 - _alpha) # print "a: %g" % _a _b = (2.0 * _alpha * _sep) # print "b: %g" % _b _c = (-1.0 * _alpha * pow(_sep, 2)) # print "c: %g" % _c _det = pow(_b, 2) - (4.0 * _a * _c) # print "det: %g" % _det if _det > 0.0: # can this ever be negative? # print "r1: %g" % _r1 # print "r2: %g" % _r2 # print "sep: %g" % _sep _denom = 2.0 * _a _det_sqrt = math.sqrt(_det) _num = (-1.0 * _b) + _det_sqrt _offset = _num/_denom # print "offset: %g" % _offset if (_r1 > _r2): # print "r1 > r2" if ((_offset > (_sep + _r2)) or ((_offset > _r1) and (_offset < (_sep - _r2)))): _tpts = _calc_tangent_triangle(_r1, _r2, _sep, _offset) _tangents.append(_tpts) _tx1, _ty1, _tx2, _ty2 = _tpts # _calc_values(_tx1, _ty1, _tx2, _ty2, 0.0, 0.0) # _calc_values(_tx1, _ty1, _tx2, _ty2, _sep, 0.0) # _calc_values(_tx2, _ty2, _tx1, _ty1, _sep, 0.0) # _calc_values(_tx2, _ty2, _tx1, _ty1, 0.0, 0.0) _tpts = (_tx1, - _ty1, _tx2, -_ty2) _tangents.append(_tpts) # _calc_values(_tx1, -_ty1, _tx2,-_ty2, 0.0, 0.0) # _calc_values(_tx1, -_ty1, _tx2, -_ty2, _sep, 0.0) # _calc_values(_tx2, -_ty2, _tx1, -_ty1, _sep, 0.0) # _calc_values(_tx2, -_ty2, _tx1, -_ty1, 0.0, 0.0) else: # _r1 < _r2 # print "r1 < r2" if ((_offset < -_r1) or ((_offset > _r1) and (_offset < (_sep - _r2)))): _tpts = _calc_tangent_triangle(_r1, _r2, _sep, _offset) _tangents.append(_tpts) _tx1, _ty1, _tx2, _ty2 = _tpts # _calc_values(_tx1, _ty1, _tx2, _ty2, 0.0, 0.0) # _calc_values(_tx1, _ty1, _tx2, _ty2, _sep, 0.0) # _calc_values(_tx2, _ty2, _tx1, _ty1, _sep, 0.0) # _calc_values(_tx2, _ty2, _tx1, _ty1, 0.0, 0.0) _tpts = (_tx1, - _ty1, _tx2, -_ty2) _tangents.append(_tpts) # _calc_values(_tx1, -_ty1, _tx2,-_ty2, 0.0, 0.0) # _calc_values(_tx1, -_ty1, _tx2, -_ty2, _sep, 0.0) # _calc_values(_tx2, -_ty2, _tx1, -_ty1, _sep, 0.0) # _calc_values(_tx2, -_ty2, _tx1, -_ty1, 0.0, 0.0) _num = (-1.0 * _b) - _det_sqrt _offset = _num/_denom # print "offset: %g" % _offset if (_r1 > _r2): # print "r1 > r2" if ((_offset > (_sep + _r2)) or ((_offset > _r1) and (_offset < (_sep - _r2)))): _tpts = _calc_tangent_triangle(_r1, _r2, _sep, _offset) _tangents.append(_tpts) _tx1, _ty1, _tx2, _ty2 = _tpts _tpts = (_tx1, - _ty1, _tx2, -_ty2) _tangents.append(_tpts) else: # _r1 < _r2 # print "r1 < r2" if ((_offset < -_r1) or ((_offset > _r1) and (_offset < (_sep - _r2)))): _tpts = _calc_tangent_triangle(_r1, _r2, _sep, _offset) _tangents.append(_tpts) _tx1, _ty1, _tx2, _ty2 = _tpts # _calc_values(_tx1, _ty1, _tx2, _ty2, 0.0, 0.0) # _calc_values(_tx1, _ty1, _tx2, _ty2, _sep, 0.0) # _calc_values(_tx2, _ty2, _tx1, _ty1, _sep, 0.0) # _calc_values(_tx2, _ty2, _tx1, _ty1, 0.0, 0.0) _tpts = (_tx1, - _ty1, _tx2, -_ty2) _tangents.append(_tpts) # _calc_values(_tx1, -_ty1, _tx2,-_ty2, 0.0, 0.0) # _calc_values(_tx1, -_ty1, _tx2, -_ty2, _sep, 0.0) # _calc_values(_tx2, -_ty2, _tx1, -_ty1, _sep, 0.0) # _calc_values(_tx2, -_ty2, _tx1, -_ty1, 0.0, 0.0) return _tangents PythonCAD-DS1-R37/PythonCAD/Generic/dwgbase.py0000644000175000017500000007133411307666657020335 0ustar matteomatteo# # Copyright (c) 2003 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # a class for reading (and hopefully eventually writing) DWG files # from __future__ import generators import types import sys class Dwg: """The class for revision-neutral handling of DWG files. The Dwg class is designed to provide a version-neutral interface for reading DWG files. A Dwg instance has the following methods: getHandle(): Get the opened file handle associated with the instance. {get/set}Version(): Get/Set the version of the underlying DWG file. {get/set}Offset(): Get/Set the offsets to sections with the DWG file. getOffsetKeys(): Retrieve the section names for which offsets are stored. setReader(): Set the function used for reading a particular DWG section. {get/set}Header(): Get/Set a header variable used in the DWG file. getHeaderKeys(): Get all the header variables in the DWG file. {get/set}Class(): Get/Set a class used in the DWG file. getClassKeys(): Get all the classes used in the DWG file. {get/set}Object(): Get/Set an entity stored in the DWG file. {get/set}ImageData(): Get/Set any bitmap image data in the DWG file. Older versions of the DWG format lack image data and header variables, and the presence of image data is optional. Also, the header data variables keys can be different from one release to another. """ def __init__(self, filename): """Initialize a Dwg instance. dwg = Dwg(filename) The one required argument is the path to a DWG file. """ _mode = 'r' if sys.platform == 'win32': _mode = 'rb' self.__fp = file(filename, _mode) self.__version = None self.__offsets = {} # file offsets self.__entities = [] # entity offset data self.__dxfnames = {} # class/dxfname map self.__readers = {} self.__headers = {} self.__classes = {} self.__objects = [] self.__wmfdata = None # not before R13 self.__bmpdata = None # not before R13 self.__index = 0 self.__len = 0 self.setVersion() def __del__(self): self.__fp.close() def getHandle(self): """Return the opened file handle associated with the DWG file. getHandle() """ return self.__fp def setVersion(self): """Store the version of the DWG file. setVersion() """ _fp = self.__fp _fp.seek(0, 0) _buf = _fp.read(6) if _buf == 'AC1009': _ver = 'R12' elif _buf == 'AC1010': # autocad 10? _ver = 'R12+' elif _buf == 'AC1012': import dwg1314 dwg1314.initialize_dwg(self) _ver = 'R13' elif _buf == 'AC1014': import dwg1314 dwg1314.initialize_dwg(self) _ver = 'R14' elif _buf == 'AC1015': import dwg15 dwg15.initialize_dwg(self) _ver = 'R15' else: _ver = None # unknown file - maybe raise an error? self.__fp.close() self.__version = _ver def getVersion(self): """Return the version of the DWG file in use. getVersion() """ if self.__version is None: self.setVersion() return self.__version def setOffset(self, key, value): """Store the offset to a section within the DWG file. setOffset(key, value) This method requires two arguments: key: A text string giving the section name. value: A tuple of two objects. Valid keys are one of the following: HEADERS, CLASSES, OBJECTS, IMAGES, UNKNOWN, R14DATA, R15REC5 The tuple is of the following format: (offset, size) offset: Offset in the file size: The size of the section; This argument can be 'None' """ if not isinstance(key, str): raise TypeError, "Invalid offset key: " + str(key) if not isinstance(value, tuple): raise TypeError, "Invalid offset tuple: " + str(value) if not len(value) == 2: raise ValueError, "Invalid offset tuple: " + str(value) if key in self.__offsets: raise ValueError, "Key already set: " + key if (key == 'HEADERS' or key == 'CLASSES' or key == 'OBJECTS' or key == 'IMAGES' or key == 'UNKNOWN' or key == 'R14DATA' or key == 'R14REC5'): self.__offsets[key] = value else: raise ValueError, "Unexpected offset key: " + key def getOffsetKeys(self): """Return the strings giving the sections for which offset data is stored. getOffsetKeys() This method returns the keys used in the setOffset() calls. The ordering of the keys is random. The offset data can be retrieved by calling the getOffset() method. """ return self.__offsets.keys() def getOffset(self, key): """Return the section data associated with a particular section key. getOffset(key) Argument 'key' should be a string returned from getOffsetKeys(). """ return self.__offsets[key] def setReader(self, key, value): """Store a function which reads a section of the DWG file. setReader(key, value) This function has two required arguments: key: A text string giving the reader type value: The function used to read the section of the DWG file. Valid keys are: HEADERS, CLASSES, OBJECTS, IMAGES """ if not isinstance(key, str): raise TypeError, "Invalid offset key: " + str(key) if not isinstance(value, types.FunctionType): raise TypeError, "Invalid reader for '%s': %s" % (key, str(value)) if (key == 'HEADERS' or key == 'CLASSES' or key == 'OBJECTS' or key == 'OFFSETS' or key == 'OBJECT' or key == 'IMAGES'): self.__readers[key] = value else: raise ValueError, "Unexpected reader key: " + key def getReader(self, key): """Return the function for reading a DWG file section. getReader(key) """ return self.__readers[key] def setHeader(self, key, value): """Store a header variable found in the DWG file. setHeader(key, value) This method has two arguments: key: The header variable value: Its value. The 'key' must be a string, and the value can be any type of Python object (string, int, double, tuple, etc...) """ if not isinstance(key, str): raise TypeError, "Invalid header key: " + str(key) self.__headers[key] = value def getHeaderKeys(self): """Return the various header variables found in the DWG file. getHeaderKeys() This method returns a list of strings, with each being one of the header variables found in the DWG file. The data associated with each header can be retrieved with the getHeader() method. """ if not len(self.__headers): if 'HEADERS' in self.__readers: _reader = self.__readers['HEADERS'] _reader(self) return self.__headers.keys() def getHeader(self, key): """Return the associated value for a particular header variable. getHeader(key) Argument 'key' should be one of the strings returned from getHeaderKeys() """ return self.__headers[key] def setDxfName(self, key, dxfname): """Store the mapping between the type number and DXF name. setDxfName(key, dxfname) Argument 'key' is an integer, and argument 'dxfname' is a string. This data is found in the class data section in R13, R14, and R15 DWG files. """ if not isinstance(key, int): raise TypeError, "Invalid dxfname key: " + str(key) if not isinstance(dxfname, str): raise TypeError, "Invalid dxfname: " + str(key) self.__dxfnames[key] = dxfname def getDxfName(self, key): """Return the dxfname for a given class key. getDxfName(key) Argument 'key' should be an integer. This method returns a string if there is a class for the key value. Otherwise this method returns None. """ if not isinstance(key, int): raise TypeError, "Invalid dxfname key: " + str(key) return self.__dxfnames.get(key) def setClass(self, key, value): """Store a class variable found in the DWG file. setClass(key, value) This method has two required arguments: key: An integer value value: A tuple The contents of the tuple are as follows: (appname, cplusplusname, dxfname, zombie, id) The tuple data comes from the R13/R14/R15 spec. """ if not isinstance(key, int): raise TypeError, "Non-integer class key: " + str(key) if not isinstance(value, tuple): raise TypeError, "Non-tuple class value: " + str(value) self.__classes[key] = value def getClassKeys(self): """Return the various classes found in the DWG file. getClassKeys() This method returns a list of class values. The data associated for each class can be obtained with getClass(). """ if not len(self.__classes): if 'CLASSES' in self.__readers: _reader = self.__readers['CLASSES'] _reader(self) return self.__classes.keys() def getClass(self, key): """Return the class data for a given class. getClass() This method returns a tuple holding the class data. """ return self.__classes.get(key) def addEntityOffset(self, handle, offset): """Store handle/offset data for an entity in the DWG file. addEntityOffset(handle, offset) """ self.__entities.append((handle, offset)) def getEntityOffset(self): """Return the list of handle/offset data for the DWG file entities. getEntityOffset() """ for _entdata in self.__entities: _id, _offset = _entdata yield _offset def setObject(self, obj): """Store an entity found within the DWG file. setObject(obj) Argument 'obj' must be an dwgEntity instance. """ if not isinstance(obj, dwgEntity): raise TypeError, "Invalid DWG object: " + str(obj) self.__objects.append(obj) def getObject(self): """Return a single object from the DWG file. getObject() This method can be called to extract the dwgEntity objects from the DWG file one object at a time. The first call gets the first entity, and each subsequent call retrieves the following entity. """ if not len(self.__classes): if 'CLASSES' in self.__readers: _reader = self.__readers['CLASSES'] _reader(self) if not len(self.__entities): if 'OFFSETS' in self.__readers: _reader = self.__readers['OFFSETS'] _reader(self) if 'OBJECT' not in self.__readers: raise StopIteration _reader = self.__readers['OBJECT'] for entdata in self.__entities: _id, _offset = entdata yield _reader(self, _offset) def rewind(self): if not len(self.__classes): if 'CLASSES' in self.__readers: _reader = self.__readers['CLASSES'] _reader(self) if not len(self.__entities): if 'OFFSETS' in self.__readers: _reader = self.__readers['OFFSETS'] _reader(self) self.__index = 0 self.__len = len(self.__entities) def next_object(self): if self.__index == self.__len: return _id, _offset = self.__entities[self.__index] _reader = self.__readers['OBJECT'] self.__index = self.__index + 1 return _reader(self, _offset) def getEntities(self): if not len(self.__classes): if 'CLASSES' in self.__readers: _reader = self.__readers['CLASSES'] _reader(self) if not len(self.__entities): if 'OFFSETS' in self.__readers: _reader = self.__readers['OFFSETS'] _reader(self) return self.__entities def getObjects(self): """Return all the stored objects found in the DWG file. getObjects() This method returns a list of dwgEntity objects. """ if not len(self.__classes): if 'CLASSES' in self.__readers: _reader = self.__readers['CLASSES'] _reader(self) if not len(self.__entities): if 'OFFSETS' in self.__readers: _reader = self.__readers['OFFSETS'] _reader(self) if not len(self.__objects): if 'OBJECTS' in self.__readers: _reader = self.__readers['OBJECTS'] _reader(self) return self.__objects[:] def setImageData(self, imagetype, data): """Store the bitmap image data found in the DWG file. setImageData(imagetype, data) This method has two required arguments: imagetype: A string - either 'BMP' or 'WMF' data: The image data The format in which the data is stored is not checked. The R13/R14/R15 readers use array.array instances for this. The image data is not found in R12 and earlier files. """ if not isinstance(imagetype, str): raise TypeError, "Invalid image type: " + str(imagetype) if imagetype == 'BMP': self.__bmpdata = data elif imagetype == 'WMF': self.__wmfdata = data else: raise ValueError, "Unexpected image type: " + imagetype def getImageData(self, imagetype): """Return the image data found in the DWG file. getImageData(imagetype) This method requires a single argument: imagetype: A string - either 'BMP' or 'WMF'. There is no image data in R12 and earlier files, and image data is optional in R13 and later files. If there is no image data this method returns None. """ if not isinstance(imagetype, str): raise TypeError, "Invalid image type: " + str(imagetype) if imagetype == 'BMP': return self.__bmpdata elif imagetype == 'WMF': return self.__wmfdata else: raise ValueError, "Unexpected image type: " + imagetype class dwgEntity: """A generic class for storing information about DWG objects. The dwgEntity class provides a revision neutral means of storing data found within the DWG file for all the drawing entities. Some entities are visible entities like lines, circles, and arcs, and others are non-graphical entities like tables. The dwgEntity class has the following methods: {get/set}Type(): Get/Set the entity type. {get/set}Handle(): Get/Set the entity handle (identifier). {get/set}EntityData(): Get/Set some information about a DWG entity. getEntityKeys(): Return the keys used for storing entity data. Each different type of DWG entity will have different keys stored, and the number of keys varies based on the entity and the ability to decode the information found in the DWG file itself. DWG entities in R13, R14, and R15 files have a large number of shared data attributes. The followin method are available for examining this information. Many of the following methods will only be useful when reading the entities from the DWG file itself. {get/set}Version(): Get/Set a DWG version in the entity {get/set}Mode(): Get/Set the entity mode. {get/set}NumReactors(): Get/Set the number of reactors. {get/set}NoLinks(): Get/Set the entity linkage flag. {get/set}IsLayerByLinetype(): ???? {get/set}Color(): Get/Set the entity color. {get/set}LinetypeScale(): Get/Set the linetype scale factor. {get/set}LinetypeFlags(): Get/Set the linetype flags. {get/set}PlotstyleFlags(): Get/Set the plotstyle flags. {get/set}Invisibility(): Get/Set the entity invisiblity flags. {get/set}Lineweight(): Get/Set the entity lineweight factor. {get/set}Subentity(): Get/Set the subentity flgas. addReactor(): Add a handle of a reactor object. getReactors(): Get all the reactors associated with an object. {get/set}Xdicobj(): ???? {get/set}Layer(): Get/Set the layer where the object is placed. {get/set}Linetype(): Get/Set the entity linetype getPrevious(): Get the previous entity in a entity chain. getNext(): Get the subsequent entity in an entity chain. {get/set}Plotstyle(): Get/Set the plotstyle flags. Some of the methods are particular to R13 and R14 files, and some are particular to R15 files. """ def __init__(self): """Initialize a dwgEntity instance. ent = dwgEntity() This method requires no arguments. """ self.__cdata = {} # "common" stuff for all entities self.__edata = {} # entity specfic data def getEntityKeys(self): """Return the keys used to store entity specific data. getEntityKeys() THis method returns an unsorted list of strings. The value associated with each key can be obtained by calling the getEntityData() method. """ return self.__edata.keys() def setEntityData(self, key, value): """Store entity specfic data in the dwgEntity. setEntityData(key, value) This method requires two arguments: key: A string used to describe the stored data. value: Any Python type. """ if not isinstance(key, str): raise TypeError, "Invalid entity data key: " + str(key) self.__edata[key] = value def getEntityData(self, key): """Retrieve the entity data value for a given key. getEntityData(key): Argument 'key' should be one of the keys returned from getEntityKeys(). """ return self.__edata[key] def setType(self, objtype): """Store the type of object in the dwgEntity instance. setType(objtype) Argument 'objtype' is an integer value corresponding to the entity type. The OpenDWG specs give this information in more detail. """ if not isinstance(objtype, int): raise TypeError, "Invalid object type: " + str(objtype) self.__cdata['TYPE'] = objtype def getType(self): """Return the type of object the dwgEntity represents. getType() This method returns an integer. See the OpenDWG specs for information to match this value to the entity type. """ return self.__cdata.get('TYPE') def setHandle(self, handle): """Set the handle (id) that the dwgEntity holds. setHandle(handle) Argument 'handle' is a tuple containing integer values. """ if not isinstance(handle, tuple): raise TypeError, "Invalid handle: " + str(handle) self.__cdata['HANDLE'] = handle def getHandle(self): """Return the handle (id) of the dwgEntity. getHandle() This method returns a tuple containing integers. """ return self.__cdata['HANDLE'] def setVersion(self, version): """Set a version string in the dwgEntity. setVersion(version) Argument 'version' must be a string. """ if not isinstance(version, str): raise TypeError, "Invalid version string: " + str(version) self.__cdata['VERSION'] = version def getVersion(self): """Retrieve the version string in the dwgEntity. getVersion() This method returns a string, or None if the setVersion() method has not been invoked on the instance. """ return self.__cdata.get('VERSION') def setMode(self, mode): """Set the mode of the entity. setMode(mode) Argument 'mode' must be an integer. """ if not isinstance(mode, int): raise TypeError, "Invalid mode: " + str(mode) self.__cdata['MODE'] = mode def getMode(self): """Return the mode of the entity. getMode() This method returns an integer value. """ return self.__cdata.get('MODE') def setNumReactors(self, nr): """Set the number of reactors of an entity. setNumReactors(nr) Argument 'nr' must be an integer. """ if not isinstance(nr, int): raise TypeError, "Invalind reactor count:" + str(nr) self.__cdata['NUMREACTORS'] = nr def getNumReactors(self): """Get the number of reactors of an entity. getNumReactors() This method returns an integer value. """ return self.__cdata.get('NUMREACTORS', 0) def setNoLinks(self, flag): """Set the 'nolinks' flag of an entity. setNoLinks(self, flag) Argument 'flag' can be either True, False, or an integer. If it is an integer, 0 is False, and all other values are True. """ if isinstance(flag, int): if flag == 0: _nlflag = False else: _nlflag = True elif flag is False: _nlflag = False elif flag is True: _nlflag = True else: raise TypeError, "Invalid type for flag: " + str(flag) self.__cdata['NOLINKS'] = _nlflag def getNoLinks(self): """Return the 'nolinks' flag of an entity. getNoLinks() """ return self.__cdata.get('NOLINKS') def setIsLayerByLinetype(self, flag): """Set a flag value. setIsLayerByLinetype(flag) Argument 'flag' can be either True, False, or an integer. If it is an integer, 0 is False, and all other values are True. """ if isinstance(flag, int): if flag == 0: _iflag = False else: _iflag = True elif flag is False: _iflag = False elif flag is True: _iflag = True else: raise TypeError, "Invalid type for flag: " + str(flag) self.__cdata['ILBT'] = _iflag def getIsLayerByLinetype(self): """Return the flag value. getIsLayerByLinetype() """ return self.__cdata.get('ILBT') def setColor(self, color): """Store the entity color in the dwgEntity object. setColor(color) Argument 'color' is an integer. """ if not isinstance(color, int): raise TypeError, "Invalid color: " + str(color) self.__cdata['COLOR'] = color def getColor(self): """Return the color of the entity. getColor() This method returns an integer giving the entity color. """ return self.__cdata.get('COLOR') def setLinetypeScale(self, scale): """Store the linetype scale factor of the DWG object. setLinetypeScale(scale) Argument 'scale' must be a float value. """ if not isinstance(scale, float): raise TypeError, "Invalid linetype scale: " + str(scale) self.__cdata['LTSCALE'] = scale def getLinetypeScale(self): """Return the linetype scale factor for the dwgEntity. getLinetypeScale() This method returns a float value. """ return self.__cdata.get('LTSCALE') def setLinetypeFlags(self, flags): """Set the linetype flags. setLinetypeFlags(flags) Argument 'flags' must be an integer. """ if not isinstance(flags, int): raise TypeError, "Invalid linetype flags: " + str(flags) self.__cdata['LTFLAGS'] = flags def getLinetypeFlags(self): """Return the linetype flags. getLinetypesFlags() """ return self.__cdata.get('LTFLAGS') def setPlotstyleFlags(self, flags): """Set the plotstyle flags. setPlotstyleFlags(flags) Argument 'flags' must be an integer. """ if not isinstance(flags, int): raise TypeError, "Invalid plotstyle flags: " + str(flags) self.__cdata['PSFLAGS'] = flags def getPlotstyleFlags(self): """Get the plotstyle flags. getPlotstyleFlags() """ return self.__cdata.get('PSFLAGS') def setInvisiblity(self, flag): """Set the invisiblity flag. setInvisiblity(flag) Argument 'flag' can be either True, False, or an integer. If it is an integer, 0 is False, and all other values are True. """ if isinstance(flag, int): if flag == 0: _iflag = False else: _iflag = True elif flag is False: _iflag = False elif flag is True: _iflag = True else: raise TypeError, "Invalid type for flag: " + str(flag) self.__cdata['INVIS'] = _iflag def getInvisibility(self): """Get the invisibility flag. getInvisibility() """ return self.__cdata.get('INVIS') def setLineweight(self, weight): """Set the line weight. setLineweight(weight) Argument 'weight' must be an integer. """ if not isinstance(weight, int): raise TypeError, "Invalid lineweight: " + str(weight) self.__cdata['LINEWEIGHT'] = weight def getLineweight(self): """Get the line weight. getLineweight() """ return self.__cdata.get('LINEWEIGHT') def setSubentity(self, handle): # code 3 handles """Set the subentity handle (id). setSubentity(handle) Argument 'handle' must be a tuple """ if not isinstance(handle, tuple): raise TypeError, "Invalid handle: " + str(handle) self.__cdata['SUBENTITY'] = handle def getSubentity(self): """Get the subentity handle. getSubentity """ return self.__cdata.get('SUBENTITY') def addReactor(self, handle): # code 4 handles """Add a reactor to an dwgEntity. addReactor(handle) Argument 'handle' must be a tuple. """ if not isinstance(handle, tuple): raise TypeError, "Invalid handle: " + str(handle) if 'REACTORS' not in self.__cdata: self.__cdata['REACTORS'] = [] self.__cdata['REACTORS'].append(handle) def getReactors(self): """Get all the reactors for a dwgEntity. getReactors() This method returns a list of tuples. """ _rlist = [] if 'REACTORS' in self.__cdata: _rlist.extend(self.__cdata['REACTORS'][:]) return _rlist def setXdicobj(self, handle): # code 3 handle if not isinstance(handle, tuple): raise TypeError, "Invalid handle: " + str(handle) self.__cdata['XDICOBJ'] = handle def getXdicobj(self): return self.__cdata.get('XDICOBJ') def setLayer(self, handle): # code 5 handle """Store the layer where the entity is held. setLayer(handle) Argument 'handle' is a tuple containing integers. """ if not isinstance(handle, tuple): raise TypeError, "Invalid handle: " + str(handle) self.__cdata['LAYER'] = handle def getLayer(self): """Return the layer handle to which this entity belongs. getLayer() This method returns a tuple. """ return self.__cdata.get('LAYER') def setLinetype(self, handle): # code 5 handle """Set the linetype handle for a dwgEntity. setLinetype(handle) Argument 'handle' must be a tuple. """ if not isinstance(handle, tuple): raise TypeError, "Invalid handle: " + str(handle) self.__cdata['LINETYPE'] = handle def getLinetype(self): """Get the linetype for a dwgEntity. getLinetype() """ return self.__cdata.get('LINETYPE') def setPrevious(self, handle): # code 4 handle """Set the previous entity handle for a dwgEntity. setPrevious(handle) Argument 'handle' must be a tuple. """ if not isinstance(handle, tuple): raise TypeError, "Invalid handle: " + str(handle) self.__cdata['PREV'] = handle def getPrevious(self): """Get the previous entity handle for a dwgEntity. getPrevious() """ return self.__cdata.get('PREV') def setNext(self, handle): # code 4 handle """Set the next entity handle for a dwgEntity. setNext(handle) Argument 'handle' must be a tuple. """ if not isinstance(handle, tuple): raise TypeError, "Invalid handle: " + str(handle) self.__cdata['NEXT'] = handle def getNext(self): """Get the next entity handle for a dwgEntity. getNext() """ return self.__cdata.get('NEXT') def setPlotstyle(self, handle): # code 5 handle """Set the plotstyle handle for an dwgEntity. setPlotstyle(handle) Argument 'handle' must be a tuple. """ if not isinstance(handle, tuple): raise TypeError, "Invalid handle: " + str(handle) self.__cdata['PLOTSTYLE'] = handle def getPlotstyle(self): """Get the plotstyle handle for a dwgEntity. getPlotstyle() """ return self.__cdata.get('PLOTSTYLE') PythonCAD-DS1-R37/PythonCAD/Generic/transfer.py0000644000175000017500000003251111307666657020537 0ustar matteomatteo# # Copyright (c) 2003, 2004, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # Transfer objects from one layer to another # from PythonCAD.Generic import point from PythonCAD.Generic import segment from PythonCAD.Generic import circle from PythonCAD.Generic import arc from PythonCAD.Generic import hcline from PythonCAD.Generic import vcline from PythonCAD.Generic import acline from PythonCAD.Generic import segjoint from PythonCAD.Generic import cline from PythonCAD.Generic import ccircle from PythonCAD.Generic import leader from PythonCAD.Generic import polyline from PythonCAD.Generic import text from PythonCAD.Generic import dimension from PythonCAD.Generic import layer def _dest_pt(lyr, pt): _x, _y = pt.getCoords() _pts = lyr.find('point', _x, _y) if len(_pts) == 0: _lpt = pt.clone() _lpt.setVisibility(False) lyr.addObject(_lpt) else: _lpt = _pts.pop() _max = _lpt.countUsers() for _pt in _pts: _count = _pt.countUsers() if _count > _max: _max = _count _lpt = _pt _lpt.setVisibility(False) return _lpt def _adjust_users(obj, cobjs): _oid = id(obj) for _user in obj.getUsers(): if isinstance(_user, dimension.Dimension): if isinstance(_user, dimension.LinearDimension): _p1, _p2 = _user.getDimPoints() if obj is _p1: _user.setP1(cobjs[_oid]) elif obj is _p2: _user.setP2(cobjs[_oid]) else: raise RuntimeError, "Point not in linear dimension: " + `_user` elif isinstance(_user, dimension.RadialDimension): _c = _user.getDimCircle() if obj is _c: _user.setDimCircle(cobjs[_oid]) else: raise RuntimeError, "Circle/Arc not in RadialDimension: " + `_user` elif isinstance(_user, dimension.AngularDimension): _vp, _p1, _p2 = _user.getDimPoints() if obj is _vp: _user.setVertexPoint(cobjs[_oid]) elif obj is _p1: _user.setP1(cobjs[_oid]) elif obj is _p2: _user.setP2(cobjs[_oid]) else: raise RuntimeError, "Point not in AngularDimension: " + `_user` else: raise TypeError, "Unexpected dimension type:" + `type(_user)` def transfer_objects(objlist, dest): """Transfer objects from one layer to another. transfer_objects(objlist, dest) objlist: A tuple/list of objects to transfer. dest: The Layer which will now contain the objects. """ if not isinstance(objlist, (tuple, list)): raise TypeError, "Invalid object list: " + `type(objlist)` if not isinstance(dest, layer.Layer): raise TypeError, "Invalid Layer type: " + `type(dest)` # # find the valid transferrable entities # _tlist = [] for _obj in objlist: if _obj.getParent() is not dest and dest.canParent(_obj): _tlist.append(_obj) # # add non-Dimension users of Point objects and # connected Segments on Chamfers and Fillets # _xferlist = [] _objdict = {} while len(_tlist) > 0: _obj = _tlist.pop() _xferlist.append(_obj) _objdict[id(_obj)] = True if isinstance(_obj, point.Point): for _user in _obj.getUsers(): if (not isinstance(_user, dimension.Dimension) and id(_user) not in _objdict): _tlist.append(_obj) elif isinstance(_obj, (segjoint.Chamfer, segjoint.Fillet)): _s1, _s2 = _obj.getSegments() if id(_s1) not in _objdict: _tlist.append(_s1) if id(_s2) not in _objdict: _tlist.append(_s2) else: pass # # clone objects # _cobjs = {} _dobjs = {} for _obj in _xferlist: _oid = id(_obj) if isinstance(_obj, point.Point): if _oid not in _cobjs: _cobjs[_oid] = _dest_pt(dest, _obj) if _oid not in _dobjs: _dobjs[_oid] = _obj elif isinstance(_obj, segment.Segment): _p1, _p2 = _obj.getEndpoints() _pid = id(_p1) if _pid not in _cobjs: _cobjs[_pid] = _dest_pt(dest, _p1) if _pid not in _dobjs: _dobjs[_pid] = _p1 _pid = id(_p2) if _pid not in _cobjs: _cobjs[_pid] = _dest_pt(dest, _p2) if _pid not in _dobjs: _dobjs[_pid] = _p2 _cobjs[_oid] = _obj.clone() elif isinstance(_obj, (circle.Circle, ccircle.CCircle)): _cp = _obj.getCenter() _pid = id(_cp) if _pid not in _cobjs: _cobjs[_pid] = _dest_pt(dest, _cp) if _pid not in _dobjs: _dobjs[_pid] = _cp _cobjs[_oid] = _obj.clone() if isinstance(_obj, circle.Circle) and _oid not in _dobjs: _dobjs[_oid] = _obj elif isinstance(_obj, arc.Arc): _cp = _obj.getCenter() _pid = id(_cp) if _pid not in _cobjs: _cobjs[_pid] = _dest_pt(dest, _cp) if _pid not in _dobjs: _dobjs[_pid] = _cp _cobjs[_oid] = _obj.clone() if _oid not in _dobjs: _dobjs[_oid] = _obj _layer = _obj.getParent() for _ep in _obj.getEndpoints(): _pts = layer.find('point', _ep[0], _ep[1]) if len(_pts) == 0: raise RuntimeError, "No points at arc endpoint: " + str(_ep) _ept = None for _pt in _pts: for _user in _pt.getUsers(): if _user is _obj: _ept = _pt break if _ept is None: raise RuntimeError, "No Arc endpoint at: " + str(_ep) _pid = id(_ept) if _pid not in _cobjs: _cobjs[_pid] = _dest_pt(dest, _ept) if _pid not in _dobjs: _dobjs[_pid] = _ept elif isinstance(_obj, leader.Leader): _p1, _p2, _p3 = _obj.getPoints() _pid = id(_p1) if _pid not in _cobjs: _cobjs[_pid] = _dest_pt(dest, _p1) if _pid not in _dobjs: _dobjs[_pid] = _p1 _pid = id(_p2) if _pid not in _cobjs: _cobjs[_pid] = _dest_pt(dest, _p2) if _pid not in _dobjs: _dobjs[_pid] = _p2 _pid = id(_p3) if _pid not in _cobjs: _cobjs[_pid] = _dest_pt(dest, _p3) if _pid not in _dobjs: _dobjs[_pid] = _p3 _cobjs[_oid] = _obj.clone() elif isinstance(_obj, polyline.Polyline): for _pt in _obj.getPoints(): _pid = id(_pt) if _pid not in _cobjs: _cobjs[_pid] = _dest_pt(dest, _pt) if _pid not in _dobjs: _dobjs[_pid] = _pt _cobjs[_oid] = _obj.clone() elif isinstance(_obj, (hcline.HCLine, vcline.VCLine, acline.ACLine)): _pt = _obj.getLocation() _pid = id(_pt) if _pid not in _cobjs: _cobjs[_pid] = _dest_pt(dest, _pt) if _pid not in _dobjs: _dobjs[_pid] = _pt _cobjs[_oid] = _obj.clone() elif isinstance(_obj, cline.CLine): _p1, _p2 = _obj.getKeypoints() _pid = id(_p1) if _pid not in _cobjs: _cobjs[_pid] = _dest_pt(dest, _p1) if _pid not in _dobjs: _dobjs[_pid] = _p1 _pid = id(_p2) if _pid not in _cobjs: _cobjs[_pid] = _dest_pt(dest, _p2) if _pid not in _dobjs: _dobjs[_pid] = _p2 _cobjs[_oid] = _obj.clone() elif isinstance(_obj, (segjoint.Chamfer, segjoint.Fillet)): pass elif isinstance(_obj, (text.TextBlock, dimension.LinearDimension, dimension.RadialDimension, dimension.AngularDimension)): _cobjs[id(_obj)] = _obj.clone() else: print "Skipping object type" + `type(_obj)` # # adjust cloned objects # _aobjs = [] for _obj in _xferlist: _cobj = _cobjs.get(id(_obj)) if isinstance(_obj, point.Point): continue elif isinstance(_obj, segment.Segment): _p1, _p2 = _obj.getEndpoints() _cobj.setP1(_cobjs[id(_p1)]) _cobj.setP2(_cobjs[id(_p2)]) elif isinstance(_obj, (circle.Circle, arc.Arc, ccircle.CCircle)): _cp = _obj.getCenter() _cobj.setCenter(_cobjs[id(_cp)]) if isinstance(_cobj, (circle.Circle, arc.Arc)): # # the following are hacks to handle the case where # a RadialDimension is attached to the Circle/Arc # # A RadialDimension in an Image (currently) cannot be # modified to point to a Circle/Arc without a parent # _obj.setVisibility(False) _cobj.setVisibility(False) dest.addObject(_cobj) elif isinstance(_obj, leader.Leader): _p1, _p2, _p3 = _obj.getPoints() _cobj.setP1(_cobjs[id(_p1)]) _cobj.setP2(_cobjs[id(_p2)]) _cobj.setP3(_cobjs[id(_p3)]) elif isinstance(_obj, polyline.Polyline): _pts = _obj.getPoints() for _i in range(len(_pts)): _pt = _pts[_i] _cobj.setPoint(_i, _cobjs[id(_pt)]) elif isinstance(_obj, (hcline.HCLine, vcline.VCLine, acline.ACLine)): _pt = _obj.getLocation() _cobj.setLocation(_cobjs[id(_pt)]) elif isinstance(_obj, cline.CLine): _p1, _p2 = _obj.getKeypoints() _cobj.setP1(_cobjs[id(_p1)]) _cobj.setP2(_cobjs[id(_p2)]) elif isinstance(_obj, (segjoint.Chamfer, segjoint.Fillet)): _s1, _s2 = _obj.getSegments() _cs1 = _cobjs[id(_s1)] _cs2 = _cobjs[id(_s2)] _s = _obj.getStyle() if isinstance(_obj, segjoint.Chamfer): _l = _obj.getLength() _cobj = segjoint.Chamfer(_cs1, _cs2, _l, _s) else: _r = _obj.getRadius() _cobj = segjoint.Fillet(_cs1, _cs2, _r, _s) _cobj.setColor(_obj.getColor()) _cobj.setLinetype(_obj.getLinetype()) _cobj.setThickness(_obj.getThickness()) elif isinstance(_obj, dimension.LinearDimension): _p1, _p2 = _obj.getDimPoints() _pid = id(_p1) if _pid in _cobjs: _cobj.setP1(_cobjs[_pid]) _pid = id(_p2) if _pid in _cobjs: _cobj.setP2(_cobjs[_pid]) elif isinstance(_obj, dimension.RadialDimension): _dc = _obj.getDimCircle() _dcid = id(_dc) if _dcid in _cobjs: _cobj.setDimCircle(_cobjs[_dcid]) elif isinstance(_obj, dimension.AngularDimension): _vp, _p1, _p2 = _obj.getDimPoints() _pid = id(_vp) if _pid in _cobjs: _cobj.setVertexPoint(_cobjs[_pid]) _pid = id(_p1) if _pid in _cobjs: _cobj.setP1(_cobjs[_pid]) _pid = id(_p2) if _pid in _cobjs: _cobj.setP2(_cobjs[_pid]) elif isinstance(_obj, text.TextBlock): pass else: print "Skipping object type " + `type(_obj)` continue _aobjs.append(_cobj) # # adjust dimensions # for _obj in _dobjs.values(): _adjust_users(_obj, _cobjs) # # delete the old objects # for _obj in _xferlist: _layer = _obj.getParent() if _layer is not None: _layer.delObject(_obj) # # set visibility of points in destination layer # for _obj in _cobjs.values(): if isinstance(_obj, point.Point): _obj.setVisibility(True) # # add the new objects # for _obj in _aobjs: if _obj.getParent() is None: dest.addObject(_obj) else: _obj.setVisibility(True) PythonCAD-DS1-R37/PythonCAD/Generic/printing.py0000644000175000017500000007653411307666657020562 0ustar matteomatteo# # Copyright (c) 2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import time from PythonCAD.Generic import plotfile from PythonCAD.Generic import units papersizes = { # see 'gs_statd.ps' from Ghostscript 'letter' : (612, 792), 'legal' : (612, 1008), 'tabloid' : (792, 1224), 'csheet' : (1224, 1584), 'dsheet' : (1584, 2448), 'esheet' : (2448, 3168), 'a0' : (2384, 3370), 'a1' : (1684, 2384), 'a2' : (1191, 1684), 'a3' : (842, 1191), 'a4' : (595, 842), 'a5' : (420, 595), 'b0' : (2835, 4008), 'b1' : (2004, 2835), 'b2' : (1417, 2004), 'b3' : (1001, 1417), 'b4' : (709, 1001), 'b5' : (499, 709), 'b6' : (354, 499), 'jisb0' : (2920, 4127), 'jisb1' : (2064, 2920), 'jisb2' : (1460, 2064), 'jisb3' : (1032, 1460), 'jisb4' : (729, 1032), 'jisb5' : (516, 729), 'jisb6' : (363, 516), 'c0' : (2599, 3677), 'c1' : (1837, 2599), 'c2' : (1298, 1837), 'c3' : (918, 1298), 'c4' : (649, 918), 'c5' : (459, 649), 'c6' : (323, 459), 'archE' : (2592, 3456), 'archD' : (1728, 2592), 'archC' : (1296, 1728), 'archB' : (864, 1296), 'archA' : (648, 864), } class PSPlot(object): """A class for generating PostScript output """ # # all papersizes below are defined for portrait printing # # some sizes taken from 'gs_statd.ps' Ghostscript file # __papersizes = { 'exact' : (0, 0), 'letter' : (612, 792), 'legal' : (612, 1008), 'tabloid' : (792, 1224), 'csheet' : (1224, 1584), 'dsheet' : (1584, 2448), 'esheet' : (2448, 3168), 'a0' : (2384, 3370), 'a1' : (1684, 2384), 'a2' : (1191, 1684), 'a3' : (842, 1191), 'a4' : (595, 842), 'a5' : (420, 595), 'b0' : (2835, 4008), 'b1' : (2004, 2835), 'b2' : (1417, 2004), 'b3' : (1001, 1417), 'b4' : (709, 1001), 'b5' : (499, 709), 'b6' : (354, 499), 'jisb0' : (2920, 4127), 'jisb1' : (2064, 2920), 'jisb2' : (1460, 2064), 'jisb3' : (1032, 1460), 'jisb4' : (729, 1032), 'jisb5' : (516, 729), 'jisb6' : (363, 516), 'c0' : (2599, 3677), 'c1' : (1837, 2599), 'c2' : (1298, 1837), 'c3' : (918, 1298), 'c4' : (649, 918), 'c5' : (459, 649), 'c6' : (323, 459), 'archE' : (2592, 3456), 'archD' : (1728, 2592), 'archC' : (1296, 1728), 'archB' : (864, 1296), 'archA' : (648, 864), } # # PostScript units are points : 72 points per inch # # note: 25.4 mm/inch __scale = { units.MILLIMETERS : '72 25.4 div', units.MICROMETERS : '72 25.4 1000 mul div', units.METERS : '72 25.4 1000 div div', units.KILOMETERS : '72 25.4 1000 1000 mul mul div', units.INCHES : '72', units.FEET : '72 12 mul', units.YARDS : '72 36 mul', units.MILES : '72 12 5280 mul mul' } def __init__(self, plot): if not isinstance(plot, plotfile.Plot): raise TypeError, "Invalid Plot object: " + `plot` self.__plot = plot self.__bounds = None self.__size = None self.__scale = None self.__factor = None def finish(self): self.__plot = None def _getBounds(self): if self.__bounds is not None: return _bounds = self.__plot.getBounds() if _bounds is None: raise ValueError, "Plot boundary not defined." self.__bounds = _bounds def setSize(self, size): if self.__size is not None: return if not isinstance(size, str): raise TypeError, "Invalid plot size string: " + `size` if size not in PSPlot.__papersizes: raise KeyError, "Invalid plot size: %s" % size self.__size = size def getPaperSizes(self): return PSPlot.__papersizes.keys() def getPaperSize(self): if self.__size is None: raise ValueError, "Paper size not defined." return PSPlot.__papersizes[self.__size] def _calcScale(self): if self.__scale is not None: return if self.__size is None: raise ValueError, "Paper size not defined." _plot = self.__plot _bounds = self.__bounds if _bounds is None: _bounds = _plot.getBounds() if _bounds is None: raise ValueError, "Plot boundary not defined." _xmin, _ymin, _xmax, _ymax = _bounds # print "xmin: %g" % _xmin # print "ymin: %g" % _ymin # print "xmax: %g" % _xmax # print "ymax: %g" % _ymax _w, _h = PSPlot.__papersizes[self.__size] if _plot.getLandscapeMode(): _w, _h = _h, _w # print "w: %d; h: %d" % (_w, _h) _units = _plot.getUnits() # print "units: %d" % _units if _units == units.MILLIMETERS: _fac = 72.0/25.4 elif _units == units.MICROMETERS: _fac = 72.0/(25.4 * 1000.0) elif _units == units.METERS: _fac = 72.0/(25.4/1000.0) elif _units == units.INCHES: _fac = 72.0 elif _units == units.FEET: _fac = 72.0 * 12 elif _units == units.YARDS: _fac = 72.0 * 36 elif _units == units.MILES: _fac = 72.0 * 12 * 5280 else: raise ValueError, "Unexpected unit: %s" % _units self.__factor = _fac # print "factor: %g" % _fac if _w == 0 and _h == 0: _ymin = 0 _xmin = 0 _s = 1 else: _xs = _fac * ((_xmax - _xmin)/float(_w)) _ys = _fac * ((_ymax - _ymin)/float(_h)) # print "xs: %g; ys: %g" % (_xs, _ys) _s = 1.0/max(_xs, _ys) self.__scale = _s # print "scale: %g" % self.__scale self.__matrix = ((_s * _fac), -(_xmin * _s * _fac), -(_ymin * _s * _fac)) # print "matrix: " + str(self.__matrix) def write(self, f): if False and not isinstance(f, file): raise TypeError, "Invalid file object: " + `f` if self.__size is None: raise ValueError, "Plot size not defined" self._getBounds() _xmin, _ymin, _xmax, _ymax = self.__bounds self._calcScale() _w, _h = PSPlot.__papersizes[self.__size] _plot = self.__plot if _plot.getLandscapeMode(): _w, _h = _h, _w # # header # f.write("%!PS-Adobe-1.0\n") f.write("%%Creator: PythonCAD\n") f.write("%%CreationDate: %s\n" % time.asctime()) f.write("%%BoundingBox: 0 0 %d %d\n" % (_w, _h)) f.write("%%EndComments\n") # add in Prologue _funcs = """% /m {transform round exch round exch itransform moveto} bind def /l {transform round exch round exch itransform lineto} bind def % /ljust { 0 begin /s exch def /y exch def /x exch def x y m s show end } def /ljust load 0 3 dict put % /cjust { 0 begin /s exch def /w exch def /y exch def /x exch def /dx {w s stringwidth pop 2 div sub} def x dx add y m s show end } def /cjust load 0 5 dict put % /rjust { 0 begin /s exch def /w exch def /y exch def /x exch def /dx {w s stringwidth pop sub} def x dx add y m s show end } def /rjust load 0 5 dict put """ f.write("%s" % _funcs) f.write("%\n% Plot specs\n%\n") f.write("%% (xmin, ymin): (%g, %g)\n" % (_xmin, _ymin)) f.write("%% (xmax, ymax): (%g, %g)\n" % (_xmax, _ymax)) f.write("%%\n%% unit scale factor: %g\n" % self.__factor) f.write("%% fit factor: %g\n" % self.__scale) f.write("%%EndProlog\n") f.write("%\n% Line defaults\n%\n") f.write("1 setlinecap\n") f.write("1 setlinejoin\n") if _plot.getLandscapeMode(): f.write("%\n% Landscape mode transformation\n%\n") f.write("90 rotate\n0 -%d translate\n" % _h) # # draw entities # if 'segments' in _plot: self._write_segments(f, _plot) if 'circles' in _plot: self._write_circles(f, _plot) if 'arcs' in _plot: self._write_arcs(f, _plot) if 'leaders' in _plot: self._write_leaders(f, _plot) if 'polylines' in _plot: self._write_polylines(f, _plot) if 'chamfers' in _plot: self._write_chamfers(f, _plot) if 'fillets' in _plot: self._write_fillets(f, _plot) if 'textblocks' in _plot: self._write_textblocks(f, _plot) if 'ldims' in _plot: self._write_ldims(f, _plot) if 'rdims' in _plot: self._write_rdims(f, _plot) if 'adims' in _plot: self._write_adims(f, _plot) f.write("showpage\n") f.flush() def _write_graphic_data(self, f, c, l, t): if c is not None: if not isinstance(c, tuple): raise TypeError, "Color argument not a tuple: " + str(c) if len(c) != 3: raise ValueError, "Unexpected color tuple length: " + str(c) if c[0] != 0 or c[1] != 0 or c[2] != 0: _r = c[0]/255.0 _g = c[1]/255.0 _b = c[2]/255.0 f.write("%.06f %.06f %.06f setrgbcolor\n" % (_r, _g, _b)) if l is not None: if not isinstance(l, list): raise TypeError, "Linetype argument not a list: " + str(l) f.write("[") for _i in l: if not isinstance(_i, int): raise TypeError, "Invalid dash list type: " + str(_i) f.write(" %d " % _i) f.write("] 0 setdash\n") _th = int(t * self.__factor * self.__scale) if _th < 1: _th = 1 f.write("%d setlinewidth\n" % _th) def _write_segments(self, f, plot): f.write("%\n% segments\n%\n") _sf, _dx, _dy = self.__matrix for _s in plot.getPlotEntities('segments'): _x1, _y1, _x2, _y2, _c, _lt, _t = _s f.write("%\n% data:\n") f.write("%% (x1, y1): (%g, %g)\n" % (_x1, _y1)) f.write("%% (x2, y2): (%g, %g)\n" % (_x2, _y2)) f.write("gsave\n") self._write_graphic_data(f, _c, _lt, _t) _xt = (_x1 * _sf) + _dx _yt = (_y1 * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _xt = (_x2 * _sf) + _dx _yt = (_y2 * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) f.write("stroke\ngrestore\n") def _write_circles(self, f, plot): f.write("%\n% circles\n%\n") _sf, _dx, _dy = self.__matrix for _c in plot.getPlotEntities('circles'): _x, _y, _r, _c, _lt, _t = _c f.write("%\n% data:\n") f.write("%% (xc, yc): (%g, %g)\n" % (_x, _y)) f.write("%% radius: %g\n" % _r) f.write("gsave\n") self._write_graphic_data(f, _c, _lt, _t) _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy _rt = _r * _sf f.write("%g %g %g 0 360 arc\n" % (_xt, _yt, _rt)) f.write("stroke\ngrestore\n") def _write_arcs(self, f, plot): f.write("%\n% arcs\n%\n") _sf, _dx, _dy = self.__matrix for _a in plot.getPlotEntities('arcs'): _x, _y, _r, _sa, _ea, _c, _lt, _t = _a f.write("%\n% data:\n") f.write("%% (xc, yc): (%g, %g)\n" % (_x, _y)) f.write("%% radius: %g\n" % _r) f.write("%% start angle: %g\n" % _sa) f.write("%% end angle: %g\n" % _ea) f.write("gsave\n") self._write_graphic_data(f, _c, _lt, _t) _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy _rt = _r * _sf f.write("%g %g %g %g %g arc\n" % (_xt, _yt, _rt, _sa, _ea)) f.write("stroke\ngrestore\n") def _write_leaders(self, f, plot): f.write("%\n% leaders\n%\n") _sf, _dx, _dy = self.__matrix for _l in plot.getPlotEntities('leaders'): _x1, _y1, _x2, _y2, _x3, _y3, _ax1, _ay1, _ax2, _ay2, _c, _lt, _t = _l f.write("%\n% data:\n") f.write("%% (x1, y1): (%g, %g)\n" % (_x1, _y1)) f.write("%% (x2, y2): (%g, %g)\n" % (_x2, _y2)) f.write("%% (x3, y3): (%g, %g)\n" % (_x3, _y3)) f.write("%\n% arrow pts:%\n") f.write("%% (x1, y1): (%g, %g)\n" % (_ax1, _ay1)) f.write("%% (x2, y2): (%g, %g)\n" % (_ax2, _ay2)) f.write("gsave\n") self._write_graphic_data(f, _c, _lt, _t) _xt = (_x1 * _sf) + _dx _yt = (_y1 * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _xt = (_x2 * _sf) + _dx _yt = (_y2 * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) _xt = (_x3 * _sf) + _dx _yt = (_y3 * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) f.write("currentpoint\nstroke\nmoveto\n") _xt = (_ax1 * _sf) + _dx _yt = (_ay1 * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) _xt = (_ax2 * _sf) + _dx _yt = (_ay2 * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) f.write("closepath\nfill\ngrestore\n") def _write_polylines(self, f, plot): f.write("%\n% polylines\n%\n") _sf, _dx, _dy = self.__matrix for _p in plot.getPlotEntities('polylines'): _pts, _c, _lt, _t = _p f.write("%\n% data:\n") f.write("%% length: %d\n" % len(_pts)) for _pt in _pts: f.write("%% (x, y): (%g, %g)\n" % (_pt[0], _pt[1])) f.write("gsave\n") self._write_graphic_data(f, _c, _lt, _t) _x, _y = _pts[0] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) for _t in _pts[1:]: _x, _y = _t _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) f.write("stroke\ngrestore\n") def _write_chamfers(self, f, plot): f.write("%\n% chamfers\n%\n") _sf, _dx, _dy = self.__matrix for _c in plot.getPlotEntities('chamfers'): _x1, _y1, _x2, _y2, _c, _lt, _t = _c f.write("%\n% data:\n") f.write("%% (x1, y1): (%g, %g)\n" % (_x1, _y1)) f.write("%% (x2, y2): (%g, %g)\n" % (_x2, _y2)) f.write("gsave\n") self._write_graphic_data(f, _c, _lt, _t) _xt = (_x1 * _sf) + _dx _yt = (_y1 * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _xt = (_x2 * _sf) + _dx _yt = (_y2 * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) f.write("stroke\ngrestore\n") def _write_fillets(self, f, plot): f.write("%\n% fillets\n%\n") _sf, _dx, _dy = self.__matrix for _f in plot.getPlotEntities('fillets'): _x, _y, _r, _sa, _ea, _c, _lt, _t = _f f.write("%\n% data:\n") f.write("%% (xc, yc): (%g, %g)\n" % (_x, _y)) f.write("%% radius: %g\n" % _r) f.write("%% start angle: %g\n" % _sa) f.write("%% end angle: %g\n" % _ea) f.write("gsave\n") self._write_graphic_data(f, _c, _lt, _t) _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy _rt = _r * _sf f.write("%g %g %g %g %g arc\n" % (_xt, _yt, _rt, _sa, _ea)) f.write("stroke\ngrestore\n") def _write_tblock(self, f, tbdata): _sf, _dx, _dy = self.__matrix _font = tbdata['font'] _size = tbdata['size'] _fontsize = _size * _sf f.write("/%s findfont %g scalefont setfont\n" % (_font, _fontsize)) _c = tbdata['color'] if _c is not None: if not isinstance(_c, tuple): raise TypeError, "Color argument not a tuple: " + str(_c) if len(_c) != 3: raise ValueError, "Unexpected color tuple length: " + str(_c) if _c[0] != 0 or _c[1] != 0 or _c[2] != 0: _r = _c[0]/255.0 _g = _c[1]/255.0 _b = _c[2]/255.0 f.write("%.06f %.06f %.06f setrgbcolor\n" % (_r, _g, _b)) _text = tbdata['text'] _align = tbdata['align'] _x, _y = tbdata['location'] _xt = (_x * _sf) + _dx _i = 1 if len(_text) == 1 or _align == 'left': for _t in _text: _yt = ((_y - (_i * _size)) * _sf) + _dy f.write("%g %g (%s) ljust\n" % (_xt, _yt, _t)) _i = _i + 1 else: _w, _h = tbdata['bounds'] _pw = _w * _sf # bounds width in points for _t in _text: _yt = ((_y - (_i * _size)) * _sf) + _dy if _align == 'center': f.write("%g %g %g (%s) cjust\n" % (_xt, _yt, _pw, _t)) else: f.write("%g %g %g (%s) rjust\n" % (_xt, _yt, _pw, _t)) _i = _i + 1 def _write_textblocks(self, f, plot): f.write("%\n% textblocks\n%\n") _sf, _dx, _dy = self.__matrix for _tbdata in plot.getPlotEntities('textblocks'): f.write("%\n% TextBlock:\n") f.write("%% (x, y): %s\n" % str(_tbdata['location'])) f.write("%% bounds: %s\n" % str(_tbdata['bounds'])) f.write("%% font: %s\n" % _tbdata['font']) f.write("%% color: %s\n" % str(_tbdata['color'])) f.write("%% alignment: %s\n" % _tbdata['align']) f.write("%% size: %g\n" % _tbdata['size']) f.write("%% text\n") for _t in _tbdata['text']: f.write("%%\t%s\n" % _t) f.write("%\n") f.write("gsave\n") self._write_tblock(f, _tbdata) f.write("grestore\n") def _write_dim_markers(self, f, mdata): _mtype = mdata['type'] _sf, _dx, _dy = self.__matrix if _mtype is not None: # # if 'rdim' is in the mdata dictionary, then the data # is for a RadialDimension and only the second marker # should be printed # _rdim = mdata.get('rdim') f.write("%%\n%% marker: %s\n" % _mtype) if _mtype == 'arrow': f.write("%% p1: %s\n" % str(mdata['p1'])) f.write("%% p2: %s\n" % str(mdata['p2'])) f.write("%% v1: %s\n" % str(mdata['v1'])) f.write("%% p3: %s\n" % str(mdata['p3'])) f.write("%% p4: %s\n" % str(mdata['p4'])) f.write("%% v2: %s\n" % str(mdata['v2'])) if _rdim is None: _x, _y = mdata['p1'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _x, _y = mdata['v1'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) _x, _y = mdata['p2'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\nstroke\n" % (_xt, _yt)) # _x, _y = mdata['p3'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _x, _y = mdata['v2'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) _x, _y = mdata['p4'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\nstroke\n" % (_xt, _yt)) elif _mtype == 'filled_arrow': f.write("%% p1: %s\n" % str(mdata['p1'])) f.write("%% p2: %s\n" % str(mdata['p2'])) f.write("%% v1: %s\n" % str(mdata['v1'])) f.write("%% p3: %s\n" % str(mdata['p3'])) f.write("%% p4: %s\n" % str(mdata['p4'])) f.write("%% v2: %s\n" % str(mdata['v2'])) if _rdim is None: _x, _y = mdata['p1'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _x, _y = mdata['p2'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) _x, _y = mdata['v1'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\nclosepath\nfill\n" % (_xt, _yt)) # _x, _y = mdata['p3'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _x, _y = mdata['p4'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) _x, _y = mdata['v2'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\nclosepath\nfill\n" % (_xt, _yt)) elif _mtype == 'slash': f.write("%% p1: %s\n" % str(mdata['p1'])) f.write("%% p2: %s\n" % str(mdata['p2'])) f.write("%% p3: %s\n" % str(mdata['p3'])) f.write("%% p4: %s\n" % str(mdata['p4'])) if _rdim is None: _x, _y = mdata['p1'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _x, _y = mdata['p2'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\nstroke\n" % (_xt, _yt)) # _x, _y = mdata['p3'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _x, _y = mdata['p4'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\nstroke\n" % (_xt, _yt)) elif _mtype == 'circle': f.write("%% radius: %g\n" % mdata['radius']) f.write("%% c1: %s\n" % str(mdata['c1'])) f.write("%% c2: %s\n" % str(mdata['c2'])) _r = mdata['radius'] if _rdim is None: _x, _y = mdata['c1'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy _rt = _r * _sf f.write("%g %g %g 0 360 arc\nfill\n" % (_xt, _yt, _rt)) # _x, _y = mdata['c2'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy _rt = _r * _sf f.write("%g %g %g 0 360 arc\nfill\n" % (_xt, _yt, _rt)) else: raise ValueError, "Unexpected marker type: %s" % _mtype def _write_dimstrings(self, f, dimdata): _sf, _dx, _dy = self.__matrix # # erase where the dim text will go # f.write("gsave\n") _tb1 = dimdata['ds1'] _tb2 = dimdata.get('ds2') _x, _y = _tb1['location'] _w, _h = _tb1['bounds'] if _tb2 is None: _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy _pw = _w * _sf _ph = _h * _sf f.write("%g %g m\n" % (_xt, _yt)) f.write("0 -%g rlineto\n" % _ph) f.write("%g 0 rlineto\n" % _pw) f.write("0 %g rlineto\n" % _ph) else: _x2, _y2 = _tb2['location'] _w2, _h2 = _tb2['bounds'] _xmin = min(_x, _x2) _xmax = max((_x + _w), (_x2 + _w2)) _ymin = _y2 - _h2 _ymax = _y _xt = (_xmin * _sf) + _dx _yt = (_ymin * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _xt = (_xmax * _sf) + _dx _yt = (_ymin * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) _xt = (_xmax * _sf) + _dx _yt = (_ymax * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) _xt = (_xmin * _sf) + _dx _yt = (_ymax * _sf) + _dy f.write("%g %g l\n" % (_xt, _yt)) f.write("closepath\n1 setgray fill\ngrestore\n") # # print ds1 dimension # f.write("%\n% DimString 1:\n") f.write("%% (x, y): %s\n" % str(_tb1['location'])) f.write("%% bounds: %s\n" % str(_tb1['bounds'])) f.write("%% font: %s\n" % _tb1['font']) f.write("%% color: %s\n" % str(_tb1['color'])) f.write("%% alignment: %s\n" % _tb1['align']) f.write("%% size: %g\n" % _tb1['size']) f.write("%% text\n") for _t in _tb1['text']: f.write("%%\t%s\n" % _t) f.write("gsave\n") self._write_tblock(f, _tb1) f.write("grestore\n") if _tb2 is not None: f.write("%\n% DimString 2:\n") f.write("%% (x, y): %s\n" % str(_tb2['location'])) f.write("%% bounds: %s\n" % str(_tb2['bounds'])) f.write("%% font: %s\n" % _tb2['font']) f.write("%% color: %s\n" % str(_tb2['color'])) f.write("%% alignment: %s\n" % _tb2['align']) f.write("%% size: %g\n" % _tb2['size']) f.write("%% text\n") for _t in _tb1['text']: f.write("%%\t%s\n" % _t) f.write("gsave\n") self._write_tblock(f, _tb2) f.write("grestore\n") def _write_ldims(self, f, plot): f.write("%\n% linear dimensions\n%\n") _sf, _dx, _dy = self.__matrix for _dimdata in plot.getPlotEntities('ldims'): f.write("%\n% data:\n") f.write("% first dimbar:\n") f.write("%% (x1, y1): %s\n" % str(_dimdata['ep1'])) f.write("%% (x2, y2): %s\n" % str(_dimdata['ep2'])) f.write("% second dimbar:\n") f.write("%% (x1, y1): %s\n" % str(_dimdata['ep3'])) f.write("%% (x2, y2): %s\n" % str(_dimdata['ep4'])) f.write("% crossbar:\n") f.write("%% (x1, y1): %s\n" % str(_dimdata['ep5'])) f.write("%% (x2, y2): %s\n" % str(_dimdata['ep6'])) f.write("gsave\n") _c = _dimdata['color'] _t = _dimdata['thickness'] self._write_graphic_data(f, _c, None, _t) _x, _y = _dimdata['ep1'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _x, _y = _dimdata['ep2'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\nstroke\n" % (_xt, _yt)) _x, _y = _dimdata['ep3'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _x, _y = _dimdata['ep4'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\nstroke\n" % (_xt, _yt)) _x, _y = _dimdata['ep5'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _x, _y = _dimdata['ep6'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\nstroke\n" % (_xt, _yt)) self._write_dim_markers(f, _dimdata['markers']) f.write("grestore\n") self._write_dimstrings(f, _dimdata) def _write_rdims(self, f, plot): f.write("%\n% radial dimensions\n%\n") _sf, _dx, _dy = self.__matrix for _dimdata in plot.getPlotEntities('rdims'): f.write("%\n% data:\n") f.write("% dimbar:\n") f.write("%% (x1, y1): %s)\n" % str(_dimdata['ep1'])) f.write("%% (x2, y2): %s)\n" % str(_dimdata['ep2'])) f.write("gsave\n") _c = _dimdata['color'] _t = _dimdata['thickness'] self._write_graphic_data(f, _c, None, _t) _x, _y = _dimdata['ep1'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _x, _y = _dimdata['ep2'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\nstroke\n" % (_xt, _yt)) self._write_dim_markers(f, _dimdata['markers']) f.write("grestore\n") self._write_dimstrings(f, _dimdata) def _write_adims(self, f, plot): f.write("%\n% angular dimensions\n%\n") _sf, _dx, _dy = self.__matrix for _dimdata in plot.getPlotEntities('adims'): f.write("%\n% data:\n") f.write("% first dimbar:\n") f.write("%% (x1, y1): %s\n" % str(_dimdata['ep1'])) f.write("%% (x2, y2): %s\n" % str(_dimdata['ep2'])) f.write("% second dimbar:\n") f.write("%% (x1, y1): %s\n" % str(_dimdata['ep3'])) f.write("%% (x2, y2): %s\n" % str(_dimdata['ep4'])) f.write("% crossarc:\n") f.write("%% (xc, yc): %s\n" % str(_dimdata['vp'])) f.write("%% radius: %g\n" % _dimdata['r']) f.write("%% start angle: %g\n" % _dimdata['sa']) f.write("%% end angle: %g\n" % _dimdata['ea']) f.write("gsave\n") _c = _dimdata['color'] _t = _dimdata['thickness'] self._write_graphic_data(f, _c, None, _t) _x, _y = _dimdata['ep1'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _x, _y = _dimdata['ep2'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\nstroke\n" % (_xt, _yt)) _x, _y = _dimdata['ep3'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g m\n" % (_xt, _yt)) _x, _y = _dimdata['ep4'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy f.write("%g %g l\nstroke\n" % (_xt, _yt)) _x, _y = _dimdata['vp'] _xt = (_x * _sf) + _dx _yt = (_y * _sf) + _dy _r = _dimdata['r'] _rt = _r * _sf _sa = _dimdata['sa'] _ea = _dimdata['ea'] f.write("%g %g %g %g %g arc\nstroke\n" % (_xt, _yt, _rt, _sa, _ea)) self._write_dim_markers(f, _dimdata['markers']) f.write("grestore\n") self._write_dimstrings(f, _dimdata) PythonCAD-DS1-R37/PythonCAD/Generic/units.py0000644000175000017500000002406211307666657020057 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # available units # import types import util MILLIMETERS = 0 MICROMETERS = 1 METERS = 2 KILOMETERS = 3 INCHES = 4 FEET = 5 YARDS = 6 MILES = 7 def get_all_units(): unitlist = [] unitlist.append(_('Millimeters')) unitlist.append(_('Micrometers')) unitlist.append(_('Meters')) unitlist.append(_('Kilometers')) unitlist.append(_('Inches')) unitlist.append(_('Feet')) unitlist.append(_('Yards')) unitlist.append(_('Miles')) return unitlist class Unit(object): """A class defining a unit for linear dimensions. The Unit class is used to establish what unit to assign distances between points. The class contains two methods used to scale distance value to and from an equivalent distance in millimeters. A Unit instance has the following methods: getStringUnit(): Get the instance unit string as a string value. setStringUnit(): Set the instance unit value based on a string {set/set}Unit(): Get/Set the instance unit. toMillimeters(): Convert a distance to millimeters fromMillimeters(): Convert a distance from millimeters The Unit class has the following classmethods: getUnitAsString(): Return a text string for a unit value. getUnitFromString(): Return a unit value for a given text string. getUnitStrings(): Return the available unit options as strings. getUnitValues(): Return the availbable unit values. """ MILLIMETERS = 0 MICROMETERS = 1 METERS = 2 KILOMETERS = 3 INCHES = 4 FEET = 5 YARDS = 6 MILES = 7 def __init__(self, unit=None): _unit = unit if _unit is None: _unit = Unit.MILLIMETERS if (_unit != Unit.MILLIMETERS and _unit != Unit.MICROMETERS and _unit != Unit.METERS and _unit != Unit.KILOMETERS and _unit != Unit.INCHES and _unit != Unit.FEET and _unit != Unit.YARDS and _unit != Unit.MILES): raise ValueError, "Invalid unit choice: " + str(unit) self.__unit = _unit def getUnitAsString(cls, u): """Return a text string for the unit value. getUnitAsString(u) This classmethod returns 'millimeters', 'micrometers', 'meters', 'kilometers', 'inches', 'feet', 'yards', or 'miles'. Passing an invalid unit value will raise a ValueError exception. """ if not isinstance(u, int): raise TypeError, "Invalid argument type: " + `type(u)` if u == Unit.MILLIMETERS: _str = 'millimeters' elif u == Unit.MICROMETERS: _str = 'micrometers' elif u == Unit.METERS: _str = 'meters' elif u == Unit.KILOMETERS: _str = 'kilometers' elif u == Unit.INCHES: _str = 'inches' elif u == Unit.FEET: _str = 'feet' elif u == Unit.YARDS: _str = 'yards' elif u == Unit.MILES: _str = 'miles' else: raise ValueError, "Unexpected unit value: %d" % u return _str getUnitAsString = classmethod(getUnitAsString) def getUnitFromString(cls, s): """Return a unit value for a given text string. getUnitFromString(s) This classmethod returns a value based on the string argument: 'millimeters' -> Unit.MILLIMETERS 'micrometers' -> Unit.MICROMETERS 'meters' -> Unit.METERS 'kilometers' -> Unit.KILOMETERS 'inches' -> Unit.INCHES 'feet' -> Unit.FEET 'yards' -> 'Unit.YARDS 'miles' -> Unit.MILES If the string is not listed above a ValueError execption is raised. """ if not isinstance(s, str): raise TypeError, "Invalid argument type: " + `type(s)` _ls = s.lower() if _ls == 'millimeters': _u = Unit.MILLIMETERS elif _ls == 'micrometers': _u = Unit.MICROMETERS elif _ls == 'meters': _u = Unit.METERS elif _ls == 'kilometers': _u = Unit.KILOMETERS elif _ls == 'inches': _u = Unit.INCHES elif _ls == 'feet': _u = Unit.FEET elif _ls == 'yards': _u = Unit.YARDS elif _ls == 'miles': _u = Unit.MILES else: raise ValueError, "Unexpected unit string: " + s return _u getUnitFromString = classmethod(getUnitFromString) def getUnitStrings(cls): """Return the available unit values as strings. getUnitStrings() This classmethod returns a list of strings. """ return [_('Millimeters'), _('Micrometers'), _('Meters'), _('Kilometers'), _('Inches'), _('Feet'), _('Yards'), _('Miles') ] getUnitStrings = classmethod(getUnitStrings) def getUnitValues(cls): """Return the available unit values. getUnitValues() This classmethod returns a list of unit values. """ return [Unit.MILLIMETERS, Unit.MICROMETERS, Unit.METERS, Unit.KILOMETERS, Unit.INCHES, Unit.FEET, Unit.YARDS, Unit.MILES ] getUnitValues = classmethod(getUnitValues) def getUnit(self): return self.__unit def getStringUnit(self): _u = self.__unit if _u == Unit.MILLIMETERS: _str = 'millimeters' elif _u == Unit.MICROMETERS: _str = 'micrometers' elif _u == Unit.METERS: _str = 'meters' elif _u == Unit.KILOMETERS: _str = 'kilometers' elif _u == Unit.INCHES: _str = 'inches' elif _u == Unit.FEET: _str = 'feet' elif _u == Unit.YARDS: _str = 'yards' elif _u == Unit.MILES: _str = 'miles' else: raise ValueError, "Unexpected unit: %d" % _u return _str def setStringUnit(self, unit): if not isinstance(unit, types.StringTypes): raise TypeError, "Unexpected unit string: " + str(unit) _ul = str(unit.lower()) if _ul == 'millimeters': _unit = MILLIMETERS elif _ul == 'micrometers': _unit = MICROMETERS elif _ul == 'meters': _unit = METERS elif _ul == 'kilometers': _unit = KILOMETERS elif _ul == 'inches': _unit = INCHES elif _ul == 'feet': _unit = FEET elif _ul == 'yards': _unit = YARDS elif _ul == 'miles': _unit = MILES else: raise ValueError, "Unexpected unit string: %s" % unit self.__unit = _unit def setUnit(self, unit): if (unit != Unit.MILLIMETERS and unit != Unit.MICROMETERS and unit != Unit.METERS and unit != Unit.KILOMETERS and unit != Unit.INCHES and unit != Unit.FEET and unit != Unit.YARDS and unit != Unit.MILES): raise ValueError, "Invalid unit choice: " + str(unit) self.__unit = unit unit = property(getUnit, setUnit, None, "Basic unit.") def toMillimeters(self, value): """Scale a value to the equivalent distance in millimeters. toMillimeters(value) """ _v = util.get_float(value) if self.__unit == Unit.MILLIMETERS: _sv = _v elif self.__unit == Unit.MICROMETERS: _sv = _v * 1e-3 elif self.__unit == Unit.METERS: _sv = _v * 1e3 elif self.__unit == Unit.KILOMETERS: _sv = _v * 1e6 elif self.__unit == Unit.INCHES: _sv = _v * 25.4 elif self.__unit == Unit.FEET: _sv = _v * 304.8 elif self.__unit == Unit.YARDS: _sv = _v * 914.4 elif self.__unit == Unit.MILES: _sv = _v * 1609344.4 else: raise ValueError, "Undefined unit value! " + str(self.__unit) return _sv def fromMillimeters(self, value): """Scale a value from an equivalent distance in millimeters. fromMillimeters(value) """ _v = util.get_float(value) if self.__unit == Unit.MILLIMETERS: _sv = _v elif self.__unit == Unit.MICROMETERS: _sv = _v * 1e3 elif self.__unit == Unit.METERS: _sv = _v * 1e-3 elif self.__unit == Unit.KILOMETERS: _sv = _v * 1e-6 elif self.__unit == Unit.INCHES: _sv = _v / 25.4 elif self.__unit == Unit.FEET: _sv = _v / 304.8 elif self.__unit == Unit.YARDS: _sv = _v / 914.4 elif self.__unit == Unit.MILES: _sv = _v / 1609344.4 else: raise ValueError, "Undefined unit value! " + str(self.__unit) return _sv def unit_string(value): """Return a text string for the integer unit value. unit_string(value) """ if value == MILLIMETERS: _str = 'millimeters' elif value == MICROMETERS: _str = 'micrometers' elif value == METERS: _str = 'meters' elif value == KILOMETERS: _str = 'kilometers' elif value == INCHES: _str = 'inches' elif value == FEET: _str = 'feet' elif value == YARDS: _str = 'yards' elif value == MILES: _str = 'miles' else: raise ValueError, "Unexpected unit: " + str(value) return _str PythonCAD-DS1-R37/PythonCAD/Generic/hatch.py0000644000175000017500000006034211307666657020005 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # hatching code # import math from PythonCAD.Generic import point from PythonCAD.Generic import segment from PythonCAD.Generic import circle from PythonCAD.Generic import arc from PythonCAD.Generic import segjoint from PythonCAD.Generic import layer from PythonCAD.Generic import util class Path(object): """The class for maintaining a list of objects defining a hatch border. A Path object contains one or more objects defining the boundary of a hatching. If the Path length is 1, the boundary is either a circle or an arc where the start angle and end angle are equal. There is no upper limit to the number of objects in the path. If a Path consists of Segments, Arcs, Chamfer, or Fillets, the Path can only be valid if starting at any point in any object in the Path the connections between the objects lead back to the starting point. A Path has the following methods: isExternal(): Check if the Path is an outer boundary isCircular(): Check if the Path is a Circle or closed Arc. getPath(): Return the objects comprising the Path inPath(): Test if a coordinate is inside a Path. """ def __init__(self, objs, external=True): """Initialize a Path. p = Path(objs[, external]) The required argument 'objs' is a list of objects defining the path. The valid objects are circles, arcs, segments, chamfers and fillets. The optional argument 'external' is by default True, meaning that this Path is an outer boundary. If the argument is False, then the Path represents an internal non-hatched area inside another Path. """ if not isinstance(objs, list): raise TypeError, "Unexpected list type: " + `type(objs)` if not len(objs): raise ValueError, "Invalid empty object list" for _obj in objs: _valid = False if (isinstance(_obj, segment.Segment) or isinstance(_obj, arc.Arc) or isinstance(_obj, circle.Circle) or isinstance(_obj, segjoint.Chamfer) or isinstance(_obj, segjoint.Fillet)): _valid = True if not _valid: raise TypeError, "Invalid object type in list: " + `type(_obj)` _circular = False if len(objs) == 1: _circular = True _obj = objs[0] _valid = False if isinstance(_obj, arc.Arc): _sa = _obj.getStartAngle() _ea = _obj.getEndAngle() if abs(_sa - _ea) < 1e-10: _valid = True if not _valid: raise ValueError, "Invalid single Arc path: " + str(_obj) elif isinstance(_obj, circle.Circle): pass else: raise TypeError, "Invalid single entity path: " + str(_obj) else: _valid = True for _obj in objs: if isinstance(_obj, circle.Circle): if not isinstance(_obj, arc.Arc): _valid = False break if not _valid: raise TypeError, "Circle found in multi-object path" _valid = True # _validate_path(objlist) if not _valid: raise ValueError, "Objlist objects do not make a closed path." util.test_boolean(external) self.__objs = objs[:] self.__circular = _circular self.__external = external def __len__(self): return len(self.__objs) def __str__(self): if self.__external: print "External Path: [" else: print "Internal Path: [" for _obj in self.__objs: print str(_obj) print "]" def isExternal(self): """Test if the Path is an external border. isExternal() """ return self.__external def isCircular(self): """Test if the Path is a Circle or closed Arc. isCircular() """ def getPath(self): """Return the objects defining the Path. getPath() This method returns a list of objects. """ return self.__objs[:] def inPath(self, x, y): """Test if a coordinate pair are inside a Path. inPath(x, y) This method has two required arguments: x: A float giving the 'x' coordinate. y: A float giving the 'y' coordinate. This method returns True if the Point is inside the Path, and False otherwise. """ _x = util.get_float(x) _y = util.get_float(y) _inside = False if self.__circular: assert len(self.__objs) == 1, "Invalid circular path length" _circ = self.__objs[0] _cx, _cy = _circ.getCenter().getCoords() _sep = math.hypot((_cx - _x), (_cy - _y)) if _sep < _circ.getRadius(): _inside = True else: _xp = 0.0 _yp = 0.0 _idx = None for _i in range(len(self.__objs)): _obj = self.__objs[_i] if isinstance(_obj, segment.Segment): _p1, _p2 = _obj.getEndpoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() elif isinstance(_obj, arc.Arc): _ep1, _ep2 = _obj.getEndpoints() _p1x, _p1y = _ep1 _p2x, _p2y = _ep2 elif isinstance(_obj, (segjoint.Chamfer, segjoint.Fillet)): _p1, _p2 = _obj.getMovingPoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _xdiff = _p2x - _p1x _ydiff = _p2y - _p1y _sqlen = pow(_xdiff, 2) + pow(_ydiff, 2) _r = ((_x - _p1x)*(_xdiff) + (_y - _p1y)*(_ydiff))/_sqlen if 0.0 < _r < 1.0: _s = ((_p1y - _y)*(_xdiff) - (_p1x - _x)*(_ydiff))/_sqlen if abs(_s) > 1e-10: _xp = _p1x + (_r * _xdiff) _yp = _p1y + (_r * _ydiff) _idx = _i break if _idx is not None: _count = 1 for _i in range(len(self.__objs)): if _i == _idx: continue _obj = self.__objs[_i] if isinstance(_obj, segment.Segment): _p1, _p2 = _obj.getEndpoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() elif isinstance(_obj, arc.Arc): _ep1, _ep2 = _obj.getEndpoints() _p1x, _p1y = _ep1 _p2x, _p2y = _ep2 elif isinstance(_obj, (segjoint.Chamfer, segjoint.Fillet)): _p1, _p2 = _obj.getMovingPoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _d = ((_p2x - _p1x)*(_yp - _y)) - ((_p2y - _p1y)*(_xp - _x)) if abs(_d) > 1e-10: _n = ((_p1y - _y)*(_xp - _x)) - ((_p1x - _x)*(_yp - _y)) _r = _n/_d if 0.0 < _r < 1.0: _count = _count + 1 if _count % 2: # need to test if point is in an arc ... _inside = True return _inside class HatchRegion(object): """The class defining a hatched area. A HatchRegion object consists of one Path object defining the external boundary of the hatching, and a list of zero or more Paths defining any areas inside the enclosing Path that are not hatched. """ def __init__(self, extpath, voids=[]): """Initialize a HatchRegion. h = HatchRegion(extpath[, voids]) The required argument 'extpath' is a Path object defining the external boundary of the hatching. The optional argument 'voids' is a list of Path objects defining areas within the external Path that are not to be hatched. A HatchRegion has the following methods: """ if not isinstance(extpath, Path): raise TypeError, "Invalid external path: " + `extpath` if not extpath.isExternal(): raise ValueError, "Path not defined to be an external path: " + `extpath` if not isinstance(voids, list): raise TypeError, "Invalid void list: " + `voids` for _void in voids: if not isinstance(_void, Path): raise TypeError, "Invalid path in void list: " + `_void` if _void.isExternal(): raise ValueError, "Void area defined as external: " + `_void` self.__ext_path = extpath self.__voids = voids[:] def getExternalPath(self): """Return the external Path for the HatchRegion. getExternalPath() """ return self.__ext_path def hasVoids(self): """Test if the HatchRegion has any internal non-hatched areas. hasVoids() """ return len(self.__voids) > 0 def getVoids(self): """Get any internal areas in the HatchRegion. getVoids() """ return self.__voids[:] def _seg_seg_touch(sega, segb): _touch = False _pa1, _pa2 = sega.getEndpoints() _pb1, _pb2 = segb.getEndpoints() if _pa1 is _pb1 or _pa1 is _pb2 or _pa2 is _pb1 or _pa2 is _pb2: _touch = True return _touch def _seg_arc_touch(seg, a): _touch = False _p1, _p2 = seg.getEndpoints() _ep1, _ep2 = a.getEndpoints() if _p1 == _ep1 or _p1 == _ep2 or _p2 == _ep1 or _p2 == _ep2: _touch = True return _touch def _arc_arc_touch(arca, arcb): _touch = False _aep1, _aep2 = arca.getEndpoints() _bep1, _bep2 = arcb.getEndpoints() if _aep1 == _bep1 or _aep1 == _bep2 or _aep2 == _bep1 or _aep2 == _bep2: _touch = True return _touch def _seg_joint_touch(seg, joint): _touch = False _s1, _s2 = joint.getSegments() if _s1 is seg or _s2 is seg: _touch = True return _touch def _old_validate_path(objlist): """Test if the objects in the objlist make a closed path. _validate_path(objlist) This function is private the the hatching code. """ if not isinstance(objlist, list): raise TypeError, "Invalid object list: " + `objlist` _startpt = None _nextpt = None _valid = False for _obj in objlist: print "testing object: " + `_obj` print "start: " + `_startpt` print "next: " + `_nextpt` if isinstance(_obj, segment.Segment): _p1, _p2 = _obj.getEndpoints() if _startpt is None: _startpt = _p1 _nextpt = _p2 else: if _nextpt == _p1: _nextpt = _p2 elif _nextpt == _p2: _nextpt = _p1 else: break elif isinstance(_obj, arc.Arc): _ep1, _ep2 = _obj.getEndpoints() if _startpt is None: _startpt = _ep1 _nextpt = _ep2 else: if _nextpt == _ep1: _nextpt = _ep2 elif _startpt == _ep2: _nextpt = _ep1 else: break elif isinstance(_obj, (segjoint.Chamfer, segjoint.Fillet)): _p1, _p2 = _obj.getMovingPoints() if _startpt is None: _startpt = _p1 _nextpt = _p2 else: if _nextpt == _p1: _nextpt = _p2 elif _nextpt == _p2: _nextpt = _p1 else: break else: raise TypeError, "Invalid object in path: " + `_obj` if _startpt == _nextpt: _valid = True return _valid def _can_touch(obja, objb): _touch = False if isinstance(obja, segment.Segment): if isinstance(objb, segment.Segment): _touch = _seg_seg_touch(obja, objb) elif isinstance(objb, arc.Arc): _touch = _seg_arc_touch(obja, objb) elif isinstance(objb, segjoint.SegJoint): _touch = _seg_joint_touch(obja, objb) elif isinstance(obja, arc.Arc): if isinstance(objb, segment.Segment): _touch = _seg_arc_touch(objb, obja) elif isinstance(objb, arc.Arc): _touch = _arc_arc_touch(obja, objb) elif isinstance(obja, segjoint.SegJoint): if isinstance(objb, segment.Segment): _touch = _seg_joint_touch(objb, obja) return _touch def _validate_path(lyr, objlist): """Test if the objects in the objlist make a closed path. _validate_path(objlist) This function is private the the hatching code. """ if not isinstance(objlist, list): raise TypeError, "Invalid object list: " + `objlist` for _obj in objlist: _lobj = lyr.findObject(_obj) if _lobj is not _obj: raise ValueError, "Object not in layer: " + `_obj` _valid = True for _i in range(len(objlist) - 1): _obja = objlist[_i] _objb = objlist[_i+1] if not _can_touch(_obja, _objb): _valid = False break if _valid: _valid = _can_touch(objlist[0], objlist[-1]) return _valid def point_boundaries(plist): _xmin = None _xmax = None _ymin = None _ymax = None _set = False if len(plist) > 1: for _pt in plist: _x, _y = _pt.getCoords() if not _set: _xmin = _x _xmax = _x _ymin = _y _ymax = _y else: if _x < _xmin: _xmin = _x if _x > _xmax: _xmax = _x if _y < _ymin: _ymin = _y if _y > _ymax: _ymax = _y return (_xmin, _ymin, _xmax, _ymax) def point_in_path(path): hits = 0 for seg in path: p1, p2 = seg.getEndpoints() p1x, p1y = p1.getEndpoints() p2x, p2y = p2.getEndpoints() xmin = min(p1x, p2x) xmax = max(p1x, p2x) ymin = min(p1y, p2y) ymax = max(p1y, p2y) # if hx < xmin or hx > max or hy > ymax: # continue hits = 1 - hits return hits def draw_path(path): if len(path): print "path: [" for seg in path: print seg print "]" def make_paths(pt, seg, sdict): paths = [] print "initial segment: " + str(seg) sp1, sp2 = seg.getEndpoints() if pt is sp1: sp = sp1 else: sp = sp2 print "start point: " + str(sp) segkeys = {} path = [] segkeys[seg] = pt path.append(seg) draw_path(path) paths.append(path) while(len(paths)): path = paths.pop() draw_path(path) seg = path[-1] print "path final segment: " + str(seg) # print "segkey: " + str(segkeys[seg]) p1, p2 = seg.getEndpoints() print "p1: " + str(p1) if p1 in sdict and segkeys[seg] is not p1: if p1 is sp: print "complete path:" draw_path(path) else: for p1seg in sdict[p1]: if p1seg not in path: segkeys[p1seg] = p1 path.append(p1seg) # print "new path:" draw_path(path) paths.append(path) print "p2: " + str(p2) if p2 in sdict and segkeys[seg] is not p2: if p2 is sp: print "complete path:" draw_path(path) else: for p2seg in sdict[p2]: if p2seg not in path: segkeys[p2seg] = p2 path.append(p2seg) # print "new_path:" draw_path(path) paths.append(path) def check_clist(ct, clist): xct, yct = ct.getCenter().getCoords() rct = ct.getRadius() add_flag = True i = 0 while (i < len(clist)): _c = clist[i] x, y = _c.getCenter().getCoords() r = _c.getRadius() sep = math.hypot((xct - x), (yct - y)) if sep < r: # ct center point inside _c if sep + rct < r: add_flag = False else: i = i + 1 elif sep < rct: # _c center point inside ct if sep + r < rct: del clist[i] else: i = i + 1 else: # two circle that may or may not overlap i = i + 1 if not add_flag: break return add_flag def get_contained_circles(l, c): clist = [] xc, yc = c.getCenter().getCoords() rc = c.getRadius() for _cir in l.getLayerEntities("circle"): if _cir is c: continue x, y = _cir.getCenter().getCoords() r = _cir.getCoords() sep = math.hypot((xc - x), (yc - y)) if sep + r < rc: if(check_clist(_cir, clist)): clist.append(_cir) return clist def make_hatch_area(lyr, x, y): _x = util.get_float(x) _y = util.get_float(y) if not isinstance(lyr, layer.Layer): raise TypeError, "Invalid layer: " + `lyr` # # see if we're in a circle # _circle = None for _c in lyr.getLayerEntities("circle"): _xc, _yc = _c.getCenter().getCoords() _r = _c.getRadius() _sep = math.hypot((_xc - _x), (_yc - _y)) if _sep < _r: if _circle is None: _circle = _c else: _rc = _circle.getRadius() if _r < _rc: _circle = _c # # get the eligible points in the layer and # store any circles that may be fully inside # the bounding circle # _pts = {} _circle_voids = [] if _circle is not None: _cx, _cy = _circle.getCenter().getCoords() _rad = _circle.getRadius() _xmin = _cx - _rad _ymin = _cy - _rad _xmax = _cx + _rad _ymax = _cy + _rad for _pt in lyr.getLayerEntities("point"): _x, _y = _pt.getCoords() if _x < _xmin or _y < _ymin or _y > _ymax: continue if _x > _xmax: break _sep = math.hypot((_cx - _x), (_cy - _y)) if _sep < _rad: _addpt = True if lyr.countUsers(_pt) == 1: _obj = lyr.usesObject(_pt) if not isinstance(_obj, circle.Circle): _addpt = False if _addpt: _pts[_pt] = True for _circ in lyr.getLayerEntities("circle"): if _circ is _circle: continue _tcx, _tcy = _circ.getCenter().getCoords() _tr = _circ.getRadius() if (_tcx + _tr) > _xmax: break if ((_tcx - _tr) < _xmin or (_tcy - _tr) < _ymin or (_tcy + _tr) > _ymax): continue _sepmax = math.hypot((_cx - _tcx), (_cy - _tcy)) + _tr if _sepmax < _rad: _circle_voids.append(_circ) else: for _pt in lyr.getLayerEntities("point"): _addpt = True if lyr.countUsers(_pt) == 1: _obj = lyr.usesObject(_pt) if not isinstance(_obj, circle.Circle): _addpt = False if _addpt: _pts[_pt] = True # # find the entites that can make closed paths # _objs = {} for _pt in _pts: for _user in lyr.usesObject(_pt): if isinstance(_user, (segment.Segment, arc.Arc, segjoint.Chamfer, segjoint.Fillet)): _objs[_user] = True if isinstance(_user, segment.Segment): for _seguser in lyr.usesObject(_user): _objs[_seguser] = True _paths = {} for _obj in _objs: _p1 = None _p2 = None if isinstance(_obj, segment.Segment): if _obj not in _paths: _paths[_obj] = [] for _user in lyr.usesObject(_obj): if isinstance(_user, (segjoint.Chamfer, segjoint.Fillet)): _paths[_obj].append(_user) _p1, _p2 = _obj.getEndpoints() elif isinstance(_obj, arc.Arc): _ep1, _ep2 = _obj.getEndpoints() for _pt in _pts: if _pt == _ep1: _p1 = _pt elif _p2 == _ep2: _p2 = _pt if _p1 is not None and _p2 is not None: break if _p1 is None or _p2 is None: continue # only one arc endpoint in list else: _s1, _s2 = _obj.getSegments() if _obj not in _paths: _paths[_obj] = [] _paths[_obj].append(_s1) _paths[_obj].append(_s2) if _p1 is not None: for _user in lyr.usesObject(_p1): if _user is not _obj: if isinstance(_user, (segment.Segment, arc.Arc)): _paths[_obj].append(_user) if _p2 is not None: for _user in lyr.usesObject(_p2): if _user is not _obj: if isinstance(_user, (segment.Segment, arc.Arc)): _paths[_obj].append(_user) # # remove any object that doesn't connect to another object # _objlist = _paths.keys() for _obj in _objlist: if len(_paths[_obj]) < 1: del _paths[_obj] # # try to make paths from the selected objects # _routes = {} _objlist = _paths.keys() _objcount = len(_objlist) for _obj in _objlist: _objpaths = [] _path = [_obj] for _fullpath in _make_paths(_paths, _objcount, _obj, _path): print "path: " + str(_fullpath) _valid = _validate_path(lyr, _fullpath) if _valid: _objpaths.append(_fullpath) else: print "invalid path" _routes[_obj] = _objpaths def _make_paths(pathdict, maxlen, tail, path): _paths = [] _pathlen = len(path) _head = None if _pathlen <= maxlen and tail in pathdict: if _pathlen: _head = path[0] for _next in pathdict[tail]: if _next is _head: _good = True if _pathlen == 2: if (isinstance(path[0], segment.Segment) and isinstance(path[1], segment.Segment)): _good = False if _good: _paths.append(path) elif _next not in path: _path = path + [_next] for _newpath in _make_paths(pathdict, maxlen, _next, _path): _paths.append(_newpath) else: pass return _paths hpx = 3.0 hpy = 4.0 def hatchtests(): p1 = point.Point(0,0) p2 = point.Point(10,0) p3 = point.Point(10,10) p4 = point.Point(0,10) s1 = segment.Segment(p1,p2) s2 = segment.Segment(p2,p3) s3 = segment.Segment(p3,p4) s4 = segment.Segment(p4,p1) l1 = layer.Layer('foo') l1.addObject(p1) l1.addObject(p2) l1.addObject(p3) l1.addObject(p4) l1.addObject(s1) l1.addObject(s2) l1.addObject(s3) l1.addObject(s4) # find_hatched_area(l1, hpx, hpy) p5 = point.Point(2.95, 3.95) l1.addObject(p5) c1 = circle.Circle(p5, 1) l1.addObject(c1) # find_hatched_area(l1, hpx, hpy) if __name__ == '__main__': hatchtests() PythonCAD-DS1-R37/PythonCAD/Generic/conobject.py0000644000175000017500000000630011307666657020656 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # construction line/circle base class # # These variables provide the defaults for # the construction line style attributes # from PythonCAD.Generic import graphicobject from PythonCAD.Generic import style from PythonCAD.Generic import linetype from PythonCAD.Generic import color from PythonCAD.Generic import tolerance from PythonCAD.Generic import point class ConstructionObject(graphicobject.GraphicObject): """A base class for construction lines and circles. This class is meant to provide the most basic bits for construction lines and circles. All construction lines and circles will share a common Style object style, meaning all instances will be drawn with the same linetype, have the same color, and be the same thickness. Construction entities should never be plotted out, however. """ # static class variables __defstyle = None def __init__(self, **kw): super(ConstructionObject, self).__init__(ConstructionObject.__defstyle, **kw) def getDefaultStyle(cls): if cls.__defstyle is None: _s = style.Style(u'Default Construction Object Style', linetype.Linetype(u'Construction Line', [2,2]), color.Color(255, 0, 0), 0.0) cls.__defstyle = _s return cls.__defstyle getDefaultStyle = classmethod(getDefaultStyle) def setDefaultStyle(cls, s): if not isinstance(s, style.Style): raise TypeError, "Invalid style: " + `type(s)` cls.__defstyle = s setDefaultStyle = classmethod(setDefaultStyle) def finish(self): super(ConstructionObject, self).finish() def getStyle(self): return self.getDefaultStyle() def setStyle(self, s): pass def getColor(self): return self.getDefaultStyle().getColor() def setColor(self, c): pass def getLinetype(self): return self.getDefaultStyle().getLinetype() def setLinetype(self, l): pass def getThickness(self): return self.getDefaultStyle().getThickness() def setThickness(self, t): pass # # ConstructionObject history class # class ConstructionObjectLog(graphicobject.GraphicObjectLog): def __init__(self, obj): if not isinstance(obj, ConstructionObject): raise TypeError, "Invalid ConstructionObject: " + `obj` super(ConstructionObjectLog, self).__init__(obj) PythonCAD-DS1-R37/PythonCAD/Generic/point.py0000644000175000017500000004115211307666732020037 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # classes for points # from __future__ import generators import math from PythonCAD.Generic import tolerance from PythonCAD.Generic import util from PythonCAD.Generic import baseobject from PythonCAD.Generic import quadtree from PythonCAD.Generic import entity class Point(baseobject.Subpart): """A 2-D point Class. A Point has the following attributes: x: x-coordinate y: y-coordinate A Point object has the following methods: {get/set}x(): Get/Set the x-coordinate of the Point. {get/set}y(): Get/Set the y-coordinate of the Point. {get/set}Coords(): Get/Set both the x and y coordinates of the Point. move(): Move a Point. clone(): Return an identical copy of a Point. inRegion(): Returns True if the point is in some area. """ __messages = { 'moved' : True, } # member functions def __init__(self, x, y=None, **kw): """ Initialize a Point. There are two ways to initialize a Point: Point(xc,yc) - Two arguments, with both arguments being floats Point((xc,yc)) - A single tuple containing two float objects """ super(Point, self).__init__(**kw) if isinstance(x, tuple): if y is not None: raise SyntaxError, "Invalid call to Point()" _x, _y = util.tuple_to_two_floats(x) elif y is not None: _x = util.get_float(x) _y = util.get_float(y) else: raise SyntaxError, "Invalid call to Point()." self.__x = _x self.__y = _y def __str__(self): return "(%g,%g)" % (self.__x, self.__y) def __sub__(self, p): """Return the separation between two points. This function permits the use of '-' to be an easy to read way to find the distance between two Point objects. """ if not isinstance(p, Point): raise TypeError, "Invalid type for Point subtraction: " + `type(p)` _px, _py = p.getCoords() return math.hypot((self.__x - _px), (self.__y - _py)) def __eq__(self, obj): """Compare a Point to either another Point or a tuple for equality. """ if not isinstance(obj, (Point,tuple)): return False if isinstance(obj, Point): if obj is self: return True _x, _y = obj.getCoords() else: _x, _y = util.tuple_to_two_floats(obj) if abs(self.__x - _x) < 1e-10 and abs(self.__y - _y) < 1e-10: return True return False def __ne__(self, obj): """ Compare a Point to either another Point or a tuple for inequality. """ if not isinstance(obj, (Point,tuple)): return True if isinstance(obj, Point): if obj is self: return False _x, _y = obj.getCoords() else: _x, _y = util.tuple_to_two_floats(obj) if abs(self.__x - _x) < 1e-10 and abs(self.__y - _y) < 1e-10: return False return True def __add__(self,obj): """ Add two Point """ if not isinstance(obj, Point): if isinstance(obj, tuple): x, y = util.tuple_to_two_floats(obj) else: raise TypeError,"Invalid Argument obj: Point or tuple Required" else: x,y = obj.getCoords() return self.__x+x,self.__y+y def finish(self): try: #Fix the setx to None exeption self.x = self.y = None super(Point, self).finish() except: return def getValues(self): """ Return values comprising the Point. getValues() This method extends the Subpart::getValues() method. """ _data = super(Point, self).getValues() _data.setValue('type', 'point') _data.setValue('x', self.__x) _data.setValue('y', self.__y) return _data def getx(self): """ Return the x-coordinate of a Point. getx() """ return self.__x def setx(self, val): """ Set the x-coordinate of a Point setx(val) The argument 'val' must be a float. """ if self.isLocked(): raise RuntimeError, "Coordinate change not allowed - object locked." _v = util.get_float(val) _x = self.__x if abs(_x - _v) > 1e-10: self.startChange('moved') self.__x = _v self.endChange('moved') self.sendMessage('moved', _x, self.__y) self.modified() x = property(getx, setx, None, "x-coordinate value") def gety(self): """Return the y-coordinate of a Point. gety() """ return self.__y def sety(self, val): """Set the y-coordinate of a Point sety(val) The argument 'val' must be a float. """ if self.isLocked(): raise RuntimeError, "Coordinate change not allowed - object locked." _v = util.get_float(val) _y = self.__y if abs(_y - _v) > 1e-10: self.startChange('moved') self.__y = _v self.endChange('moved') self.sendMessage('moved', self.__x, _y) self.modified() y = property(gety, sety, None, "y-coordinate value") def getCoords(self): """Return the x and y Point coordinates in a tuple. getCoords() """ return self.__x, self.__y def setCoords(self, x, y): """Set both the coordinates of a Point. setCoords(x, y) Arguments 'x' and 'y' should be float values. """ _x = util.get_float(x) _y = util.get_float(y) _sx = self.__x _sy = self.__y if abs(_sx - _x) > 1e-10 or abs(_sy - _y) > 1e-10: self.startChange('moved') self.__x = _x self.__y = _y self.endChange('moved') self.sendMessage('moved', _sx, _sy) self.modified() def move(self, dx, dy): """ Move a Point. The first argument gives the x-coordinate displacement, and the second gives the y-coordinate displacement. Both values should be floats. """ if self.isLocked(): raise RuntimeError, "Moving not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _x = self.__x _y = self.__y self.startChange('moved') self.__x = _x + _dx self.__y = _y + _dy self.endChange('moved') self.sendMessage('moved', _x, _y) self.modified() def clone(self): """ Create an identical copy of a Point. """ return Point(self.__x, self.__y) def inRegion(self, xmin, ymin, xmax, ymax, fully=True): """ Returns True if the Point is within the bounding values. inRegion(xmin, ymin, xmax, ymax) The four arguments define the boundary of an area, and the function returns True if the Point lies within that area. Otherwise, the function returns False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) _x = self.__x _y = self.__y return not ((_x < _xmin) or (_x > _xmax) or (_y < _ymin) or (_y > _ymax)) def sendsMessage(self, m): if m in Point.__messages: return True return super(Point, self).sendsMessage(m) def Dist(self,obj): """ Get The Distance From 2 Points """ if not isinstance(obj, Point): if isinstance(x, tuple): _x, _y = util.tuple_to_two_floats(obj) else: raise TypeError,"Invalid Argument point: Point or Tuple Required" else: x,y=obj.getCoords() xDist=x-self.__x yDist=y-self.__y return math.sqrt(pow(xDist,2)+pow(yDist,2)) # # Quadtree Point storage # class PointQuadtree(quadtree.Quadtree): def __init__(self): super(PointQuadtree, self).__init__() def getNodes(self, *args): _alen = len(args) if _alen != 2: raise ValueError, "Expected 2 arguments, got %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_x < _xmin) or (_y < _ymin) or (_x > _xmax) or (_y > _ymax)): continue if _node.hasSubnodes(): _xmid = (_xmin + _xmax)/2.0 _ymid = (_ymin + _ymax)/2.0 _ne = _nw = _sw = _se = False # # NE node (xmid,ymid) to (xmax,ymax) # if not ((_x < _xmid) or (_y < _ymid)): _ne = True # # NW node (xmin,ymid) to (xmid,ymax) # if not ((_x > _xmid) or (_y < _ymid)): _nw = True # # SW node (xmin,ymin) to (xmid,ymid) # if not ((_x > _xmid) or (_y > _ymid)): _sw = True # # SE node (xmid,ymin) to (xmax,ymid) # if not ((_x < _xmid) or (_y > _ymid)): _se = True if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: yield _node def addObject(self, obj): if not isinstance(obj, Point): raise TypeError, "Invalid Point object: " + `type(obj)` if obj in self: return _x, _y = obj.getCoords() _bounds = self.getTreeRoot().getBoundary() _xmin = _ymin = _xmax = _ymax = None _resize = False if _bounds is None: # first node in tree _resize = True _xmin = _x - 1.0 _ymin = _y - 1.0 _xmax = _x + 1.0 _ymax = _y + 1.0 else: _xmin, _ymin, _xmax, _ymax = _bounds if _x < _xmin: _xmin = _x - 1.0 _resize = True if _x > _xmax: _xmax = _x + 1.0 _resize = True if _y < _ymin: _ymin = _y - 1.0 _resize = True if _y > _ymax: _ymax = _y + 1.0 _resize = True if _resize: self.resize(_xmin, _ymin, _xmax, _ymax) for _node in self.getNodes(_x, _y): _node.addObject(obj) super(PointQuadtree, self).addObject(obj) obj.connect('moved', self._movePoint) def delObject(self, obj): if obj not in self: return _x, _y = obj.getCoords() for _node in self.getNodes(_x, _y): _node.delObject(obj) _parent = _node.getParent() if _parent is not None: self.purgeSubnodes(_parent) super(PointQuadtree, self).delObject(obj) obj.disconnect(self) def find(self, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _t = tolerance.TOL if _alen > 2 : _t = tolerance.toltest(args[2]) return self.getInRegion((_x - _t), (_y - _t), (_x + _t), (_y + _t)) def _movePoint(self, obj, *args): if obj not in self: raise ValueError, "Point not stored in Quadtree: " + `obj` _alen = len(args) if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) for _node in self.getNodes(_x, _y): _node.delObject(obj) super(PointQuadtree, self).delObject(obj) obj.disconnect(self) self.addObject(obj) def getClosest(self, x, y, tol=tolerance.TOL): return self.find(x, y, tol) def getInRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _pts = [] if not len(self): return _pts _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): for _subnode in _node.getSubnodes(): _sxmin, _symin, _sxmax, _symax = _subnode.getBoundary() if ((_sxmin > _xmax) or (_symin > _ymax) or (_sxmax < _xmin) or (_symax < _ymin)): continue _nodes.append(_subnode) else: for _pt in _node.getObjects(): if _pt.inRegion(_xmin, _ymin, _xmax, _ymax): _pts.append(_pt) return _pts # # Point history class # class PointLog(entity.EntityLog): def __init__(self, p): if not isinstance(p, Point): raise TypeError, "Invalid point: " + `type(p)` super(PointLog, self).__init__(p) p.connect('moved', self.__movePoint) def __movePoint(self, p, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = args[0] if not isinstance(_x, float): raise TypeError, "Unexpected type for 'x': " + `type(_x)` _y = args[1] if not isinstance(_y, float): raise TypeError, "Unexpected type for 'y': " + `type(_y)` self.saveUndoData('moved', _x, _y) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if _alen == 0: raise ValueError, "No arguments to execute()" _p = self.getObject() _op = args[0] if _op == 'moved': if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _x = args[1] if not isinstance(_x, float): raise TypeError, "Unexpected type for 'x': " + `type(_x)` _y = args[2] if not isinstance(_y, float): raise TypeError, "Unexpected type for 'y': " + `type(_y)` _px, _py = _p.getCoords() self.ignore(_op) try: if undo: _p.startUndo() try: _p.setCoords(_x, _y) finally: _p.endUndo() else: _p.startRedo() try: _p.setCoords(_x, _y) finally: _p.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _px, _py) else: super(PointLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/rotate.py0000644000175000017500000004172111307666657020214 0ustar matteomatteo# # Copyright (c) 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # code to handle rotating objects # from math import hypot, fmod, atan2, sin, cos, pi from PythonCAD.Generic.point import Point from PythonCAD.Generic.segment import Segment from PythonCAD.Generic.circle import Circle from PythonCAD.Generic.arc import Arc from PythonCAD.Generic.hcline import HCLine from PythonCAD.Generic.vcline import VCLine from PythonCAD.Generic.acline import ACLine from PythonCAD.Generic.segjoint import Chamfer, Fillet from PythonCAD.Generic.cline import CLine from PythonCAD.Generic.ccircle import CCircle from PythonCAD.Generic.leader import Leader from PythonCAD.Generic.polyline import Polyline from PythonCAD.Generic.text import TextBlock from PythonCAD.Generic.dimension import Dimension, DimString from PythonCAD.Generic.dimension import LinearDimension from PythonCAD.Generic.dimension import AngularDimension from PythonCAD.Generic import util _twopi = (2.0 * pi) _dtr = (pi/180.0) def _calc_coords(pt, cx, cy, ra): _px, _py = pt.getCoords() _r = hypot((_px - cx), (_py - cy)) _aorig = atan2((_py - cy), (_px - cx)) _anew = fmod((_aorig + ra), _twopi) _nx = cx + (_r * cos(_anew)) _ny = cy + (_r * sin(_anew)) return (_nx, _ny) def _xfrm_point(pt, objdict, cx, cy, ra): _layer = pt.getParent() _pid = id(pt) _np = None _x, _y = _calc_coords(pt, cx, cy, ra) if _can_move(pt, objdict) and objdict.get(_pid) is not False: pt.setCoords(_x, _y) else: _pts = _layer.find('point', _x, _y) if len(_pts) == 0: _np = Point(_x, _y) _layer.addObject(_np) else: _np = _most_used(_pts) return _np def _adjust_dimensions(op, np): _objs = 0 _dims = [] _reset = True for _user in op.getUsers(): if isinstance(_user, Dimension): _dims.append(_user) else: _objs = _objs + 1 if _objs > 1: _reset = False break if _reset: for _dim in _dims: if isinstance(_dim, LinearDimension): _p1, _p2 = _dim.getDimPoints() if _p1 is op: _user.setP1(np) elif _p2 is op: _user.setP2(np) elif isinstance(_dim, AngularDimension): _vp, _p1, _p2 = _dim.getDimPoints() if _vp is op: _user.setVertexPoint(np) elif _p1 is op: _user.setP1(np) elif _p2 is op: _user.setP2(np) else: raise TypeError, "Unknown dimension type: " + `type(_dim)` return _reset def _most_used(plist): _pmax = plist.pop() _max = _pmax.countUsers() for _pt in plist: _count = _pt.countUsers() if _count > _max: _max = _count _pmax = _pt return _pmax def _used_by(obj, plist): _objpt = None for _pt in plist: for _user in _pt.getUsers(): if _user is obj: _objpt = _pt break if _objpt is not None: break return _objpt def _can_move(obj, objdict): for _user in obj.getUsers(): if id(_user) not in objdict: return False return True def _rotate_acline(obj, objdict, cx, cy, ra): _layer = obj.getParent() if _layer is None: raise RuntimeError, "ACLine parent is None" _lp = obj.getLocation() if _lp.getParent() is not _layer: raise RuntimeError, "ACLine/Point parent object conflict!" _x, _y = _calc_coords(_lp, cx, cy, ra) _pts = _layer.find('point', _x, _y) if len(_pts) == 0: _np = Point(_x, _y) _layer.addObject(_np) else: _np = _most_used(_pts) _racl = (obj.getAngle() * _dtr) + ra obj.setLocation(_np) obj.setAngle(_racl/_dtr) if _adjust_dimension(_lp, _np): _layer.delObject(_lp) _pid = id(_lp) if objdict.get(_pid) is not False: objdict[_pid] = False def _rotate_vcline(obj, objdict, cx, cy, ra): _layer = obj.getParent() if _layer is None: raise RuntimeError, "VCLine parent is None" _lp = obj.getLocation() if _lp.getParent() is not _layer: raise RuntimeError, "VCLine/Point parent object conflict!" _x, _y = _calc_coords(_lp, cx, cy, ra) _pts = _layer.find('point', _x, _y) if len(_pts) == 0: _np = Point(_x, _y) _layer.addObject(_np) else: _np = _most_used(_pts) _da = ra/_dtr if abs(fmod(_da, 180)) < 1e-10: obj.setLocation(_np) if _adjust_dimension(_lp, _np): _layer.delObject(_lp) elif abs(fmod(_da, 90.0)) < 1e-10: _layer.addObject(HCLine(_np)) if _adjust_dimension(_lp, _np): _layer.delObject(obj) else: _layer.addObject(ACLine(_np, _da)) _layer.delObject(obj) _pid = id(_lp) if objdict.get(_pid) is not False: objdict[_pid] = False def _rotate_hcline(obj, objdict, cx, cy, ra): _layer = obj.getParent() if _layer is None: raise RuntimeError, "HCLine parent is None" _lp = obj.getLocation() if _lp.getParent() is not _layer: raise RuntimeError, "HCLine/Point parent object conflict!" _x, _y = _calc_coords(_lp, cx, cy, ra) _pts = _layer.find('point', _x, _y) if len(_pts) == 0: _np = Point(_x, _y) _layer.addObject(_np) else: _np = _most_used(_pts) _da = ra/_dtr if abs(fmod(_da, 180.0)) < 1e-10: obj.setLocation(_np) if _adjust_dimension(_lp, _np): _layer.delObject(_lp) elif abs(fmod(_da, 90.0)) < 1e-10: _layer.addObject(VCLine(_np)) if _adjust_dimension(_lp, _np): _layer.delObject(obj) else: _layer.addObject(ACLine(_np, _da)) _layer.delObject(obj) _pid = id(_lp) if objdict.get(_pid) is not False: objdict[_pid] = False def _rotate_polyline(obj, objdict, cx, cy, ra): _pts = obj.getPoints() _layer = obj.getParent() if _layer is None: raise RuntimeError, "Polyline parent is None" _move = True for _pt in _pts: if _pt.getParent() is not _layer: raise RuntimeError, "Polyline/point parent object conflict!" _move = (_can_move(_pt, objdict) and (objdict.get(id(_pt)) is not False)) if not _move: break if _move: for _pt in _pts: _x, _y = _calc_coords(_pt, cx, cy, ra) _pt.setCoords(_x, _y) _pid = id(_pt) objdict[_pid] = False else: for _i in range(len(_pts)): _pt = _pts[_i] if objdict.get(_pid) is True: _x, _y = _calc_coords(_pt, cx, cy, ra) _pts = _layer.find('point', _x, _y) if len(_pts) == 0: _np = Point(_x, _y) _layer.addObject(_np) else: _np = _most_used(_pts) obj.setPoint(_i, _np) objdict[_pid] = False _layer.delObject(_pt) def _rotate_leader(obj, objdict, cx, cy, ra): _layer = obj.getParent() if _layer is None: raise RuntimeError, "Leader parent is None" _p1, _p2, _p3 = obj.getPoints() if _p1.getParent() is not _layer: raise RuntimeError, "Leader/P1 parent object conflict!" if _p2.getParent() is not _layer: raise RuntimeError, "Leader/P2 parent object conflict!" if _p3.getParent() is not _layer: raise RuntimeError, "Leader/P3 parent object conflict!" _np = _xfrm_point(_p1, objdict, cx, cy, ra) if _np is not None: obj.setP1(_np) if _adjust_dimensions(_p1, _np): _layer.delObject(_p1) _np = _xfrm_point(_p2, objdict, cx, cy, ra) if _np is not None: obj.setP2(_np) if __adjust_dimensions(_p2, _np): _layer.delObject(_p2) _np = _xfrm_point(_p3, objdict, cx, cy, ra) if _np is not None: obj.setP3(_np) if __adjust_dimensions(_p3, _np): _layer.delObject(_p3) _pid = id(_p1) if objdict.get(_pid) is not False: objdict[_pid] = False _pid = id(_p2) if objdict.get(_pid) is not False: objdict[_pid] = False _pid = id(_p3) if objdict.get(_pid) is not False: objdict[_pid] = False def _adjust_endpoint(arc, pt, objdict, cx, cy, ra): _layer = arc.getParent() if pt.getParent() is not _layer: raise RuntimeError, "Arc/Endpoint parent object conflict!" _pid = id(pt) _users = [] for _user in pt.getUsers(): _users.append(_user) _np = None _x, _y = _calc_coords(pt, cx, cy, ra) if len(_users) == 1 and _users[0] is arc: if _can_move(pt, objdict) and objdict.get(_pid) is not False: pt.setCoords(_x, _y) else: _pts = _layer.find('point', _x, _y) if len(_pts) == 0: _np = Point(_x, _y) _layer.addObject(_np) else: _np = _most_used(_pts) else: pt.freeUser(arc) _pts = _layer.find('point', _x, _y) if len(_pts) == 0: _np = Point(_x, _y) _layer.addObject(_np) else: _np = _most_used(_pts) if _np is not None: _np.storeUser(arc) if _adjust_dimensions(pt, _np): _layer.delObject(pt) if objdict.get(_pid) is not False: objdict[_pid] = False def _rotate_arc(obj, objdict, cx, cy, ra): _layer = obj.getParent() if _layer is None: raise RuntimeError, "Arc parent is None" _cp = obj.getCenter() if _cp.getParent() is not _layer: raise RuntimeError, "Arc/center parent object conflict!" _ep1, _ep2 = obj.getEndpoints() _pts = _layer.find('point', _ep1[0], _ep1[1]) _ep = _used_by(obj, _pts) if _ep is None: raise RuntimeError, "Lost Arc first endpoint: " + str(_ep) _adjust_endpoint(obj, _ep, objdict, cx, cy, ra) _pts = _layer.find('point', _ep2[0], _ep2[1]) _ep = _used_by(obj, _pts) if _ep is None: raise RuntimeError, "Lost Arc second endpoint: " + str(_ep) _adjust_endpoint(obj, _ep, objdict, cx, cy, ra) _np = _xfrm_point(_cp, objdict, cx, cy, ra) if _np is not None: obj.setCenter(_np) if _adjust_dimensions(_cp, _np): _layer.delObject(_cp) _da = ra/_dtr obj.setStartAngle(obj.getStartAngle() + _da) obj.setEndAngle(obj.getEndAngle() + _da) _pid = id(_cp) if objdict.get(_pid) is not False: objdict[_pid] = False def _rotate_circ_ccirc(obj, objdict, cx, cy, ra): if isinstance(obj, Circle): _objtype = 'Circle' elif isinstance(obj, CCircle): _objtype = 'CCircle' else: raise TypeError, "Unexpected object type: " + `type(obj)` _layer = obj.getParent() if _layer is None: raise RuntimeError, "%s parent is None" % _objtype _cp = obj.getCenter() if _cp.getParent() is not _layer: raise RuntimeError, "%s/center parent object conflict!" % _objtype _np = _xfrm_point(_cp, objdict, cx, cy, ra) if _np is not None: obj.setCenter(_np) if _adjust_dimensions(_cp, _np): _layer.delObject(_cp) _pid = id(_cp) if objdict.get(_pid) is not False: objdict[_pid] = False def _rotate_seg_cline(obj, objdict, cx, cy, ra): if isinstance(obj, Segment): _p1, _p2 = obj.getEndpoints() _objtype = 'Segment' elif isinstance(obj, CLine): _p1, _p2 = obj.getKeypoints() _objtype = 'CLine' else: raise TypeError, "Unexpected object type: " + `type(obj)` _layer = obj.getParent() if _layer is None: raise RuntimeError, "%s parent is None" % _objtype if _p1.getParent() is not _layer: raise RuntimeError, "%s/P1 parent object conflict!" % _objtype if _p2.getParent() is not _layer: raise RuntimeError, "%s/P2 parent object conflict!" % _objtype _np = _xfrm_point(_p1, objdict, cx, cy, ra) if _np is not None: obj.setP1(_np) if _adjust_dimensions(_p1, _np): _layer.delObject(_p1) _np = _xfrm_point(_p2, objdict, cx, cy, ra) if _np is not None: obj.setP2(_np) if _adjust_dimensions(_p2, _np): _layer.delObject(_p2) _pid = id(_p1) if objdict.get(_pid) is not False: objdict[_pid] = False _pid = id(_p2) if objdict.get(_pid) is not False: objdict[_pid] = False def _adjust_point_users(pt, objdict, da): _layer = pt.getParent() for _user in pt.getUsers(): _uid = id(_user) if _uid in objdict: if isinstance(_user, HCLine) and _layer is not None: if abs(fmod(da, 180.0)) < 1e-10: objdict[_uid] = False elif abs(fmod(da, 90.0)) < 1e-10: _layer.addObject(VCLine(pt)) _layer.delObject(_user) del objdict[_uid] else: _layer.addObject(ACLine(pt, da)) _layer.delObject(_user) del objdict[_uid] elif isinstance(_user, VCLine) and _layer is not None: if abs(fmod(da, 180.0)) < 1e-10: objdict[_uid] = False elif abs(fmod(da, 90.0)) < 1e-10: _layer.addObject(HCLine(pt)) _layer.delObject(_user) del objdict[_uid] else: _layer.addObject(ACLine(pt, da)) _layer.delObject(_user) del objdict[_uid] elif isinstance(_user, ACLine) and _layer is not None: _user.setAngle(_user.getAngle() + da) objdict[_uid] = False else: if not isinstance(_user, Dimension): objdict[_uid] = False def rotate_objects(objs, cx, cy, angle): """Rotate a list of objects. rotate_objects(objs, cx, cy, angle) objs: A list or tuple containing the objects to move. cx: Rotation center point 'x' coordinate cy: Rotation center point 'y' coordinate angle: Angular amount of rotation """ if not isinstance(objs, (list, tuple)): raise TypeError, "Invalid object list/tuple: " + `type(objs)` _cx = util.get_float(cx) _cy = util.get_float(cy) _da = fmod(util.get_float(angle), 360.0) _ra = _da * _dtr # value in radians if abs(_ra) < 1e-10: return _objdict = {} _fillets = [] for _obj in objs: if not isinstance(_obj, DimString): _objdict[id(_obj)] = True for _obj in objs: _oid = id(_obj) if _oid not in _objdict: continue if _objdict[_oid]: if isinstance(_obj, Point): _x, _y = _calc_coords(_obj, _cx, _cy, _ra) _obj.setCoords(_x, _y) _adjust_point_users(_obj, _objdict, _da) elif isinstance(_obj, (Segment, CLine)): _rotate_seg_cline(_obj, _objdict, _cx, _cy, _ra) elif isinstance(_obj, (Circle, CCircle)): _rotate_circ_ccirc(_obj, _objdict, _cx, _cy, _ra) elif isinstance(_obj, Arc): _rotate_arc(_obj, _objdict, _cx, _cy, _ra) elif isinstance(_obj, Leader): _rotate_leader(_obj, _objdict, _cx, _cy, _ra) elif isinstance(_obj, Polyline): _rotate_polyline(_obj, _objdict, _cx, _cy, _ra) elif isinstance(_obj, (TextBlock, Dimension)) and False: _obj.move(_cx, _cy) elif isinstance(_obj, HCLine): _rotate_hcline(_obj, _objdict, _cx, _cy, _ra) elif isinstance(_obj, VCLine): _rotate_vcline(_obj, _objdict, _cx, _cy, _ra) elif isinstance(_obj, ACLine): _rotate_acline(_obj, _objdict, _cx, _cy, _ra) elif isinstance(_obj, (Chamfer, Fillet)) and False: _s1, _s2 = _obj.getSegments() if id(_s1) not in _objdict or id(_s2) not in _objdict: _layer = _obj.getParent() _layer.delObject(_obj) if isinstance(_obj, Fillet): _fillets.append(_obj) else: print "Unexpected entity type: " + `type(_obj)` _objdict[_oid] = False for _obj in _fillets: _obj._calculateCenter() # FIXME PythonCAD-DS1-R37/PythonCAD/Generic/color.py0000644000175000017500000001620611307666657020034 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # classes for colors # from PythonCAD.Generic import globals # # a seemingly good way to convert from string to integer # for a couple of common ways of expressing colors ... # def color_str_to_int(cstr): if cstr.startswith('0x') or cstr.startswith('0X'): _val = int(cstr, 16) elif cstr.startswith('#'): _val = int(cstr[1:], 16) else: _val = int(cstr) return _val class Color(object): """An object representing an RGB color. The class purpose is self evident. A Color object has three attributes: r: Red (0-255) g: Green (0-255) b: Blue (0-255) There is no alpha-channel attribute (yet)... A Color object has the following methods: getRed(): Get the Red value in the Color. getBlue(): Get the Blue value in the Color. getGreen(): Get the Green value in the Color. clone(): Return an identical copy of a Color. Once a color object is created, the values it contains may not be changed. """ def __init__(self, r=None, g=None, b=None): """Initialize a Color object. There are several ways to create a color object: Color(r,g,b) => r, g, and b values are all integers 0 <= value <= 255 Color(0xxxxx) => A hexidecimal value - it must begin with 0x. The color is computed as follows: r = (0xff0000 & value) >> 16 g = (0xff00 & value) >> 8 b = (0xff & value) Color('#hexvalue') => A string prefixed with '#', with the remaining characters representing a hexidecimal value. Color() => A default color with r = g = b = 255. """ _r = r _g = g _b = b if isinstance(_r, str): _val = color_str_to_int(_r) _r = (0xff0000 & _val) >> 16 _g = (0xff00 & _val) >> 8 _b = (0xff & _val) elif isinstance(_r, int) and _g is None and _b is None: _r = (0xff0000 & r) >> 16 _g = (0xff00 & r) >> 8 _b = (0xff & r) elif (isinstance(_r, int) and isinstance(_g, int) and isinstance(_b, int)): if _r < 0 or _r > 255: raise ValueError, "Invalid Red value: %d" % _r if _g < 0 or _g > 255: raise ValueError, "Invalid Green value: %d" % _g if _b < 0 or _b > 255: raise ValueError, "Invalid Blue value: %d" % _b elif _r is None and _g is None and _b is None: _r = 255 _g = 255 _b = 255 else: raise SyntaxError, "Invalid call to Color()." self.__color = (_r << 16) | (_g << 8) | _b def __eq__(self, obj): """Compare two Color objects for equivalence. """ if not isinstance(obj, Color): return False return self.getColors() == obj.getColors() def __ne__(self, obj): """Compare two Color objects for equivalence. """ if not isinstance(obj, Color): return True return self.getColors() != obj.getColors() def __cmp__(self, obj): """Compare two Color objects. The comparison is done based on the RGB values. red value of C1 < red value of C2 ==> return -1 red value of C1 > red value of C2 ==> return 1 Then green values are compared, then blue. If all values are equal, return 0. """ if not isinstance(obj, Color): raise TypeError, "Invalid object for color comparison: " + `obj` _val = self.__color _objval = hash(obj) return cmp(_val, _objval) def __hash__(self): """Return a hash value for the Color object. Providing this method means that Color objects can be used as keys in dictionaries. """ return self.__color def __repr__(self): _val = self.__color _r = (_val & 0xff0000) >> 16 _g = (_val & 0xff00) >> 8 _b = (_val & 0xff) return "Color(%d,%d,%d)" % (_r, _g, _b) def __str__(self): return "#%06x" % self.__color def getColors(self): """Return a three-item tuple with the values comprising this color. getColors() """ _val = self.__color _r = (_val & 0xff0000) >> 16 _g = (_val & 0xff00) >> 8 _b = (_val & 0xff) return _r, _g, _b def getRed(self): """Return the red value of the color. getRed() """ return (self.__color & 0xff0000) >> 16 r = property(getRed, None, None, "Red value of the color.") def getGreen(self): """Return the green value of the color. getGreen() """ return (self.__color & 0xff00) >> 8 g = property(getGreen, None, None, "Green value of the color.") def getBlue(self): """Return the blue value of the color. getBlue() """ return (self.__color & 0xff) b = property(getBlue, None, None, "Blue value of the color.") def clone(self): """Return a new Color object with the same color values. clone() """ _val = self.__color return Color(_val) # # ColorDict Class # # The ColorDict is built from the dict object. Using instances # of this class will guarantee than only Color objects will be # stored in the instance # class ColorDict(dict): def __init__(self): super(ColorDict, self).__init__() def __setitem__(self, key, value): if not isinstance(key, Color): raise TypeError, "ColorDict keys must be color objects: " + `key` if not isinstance(value, Color): raise TypeError, "ColorDict values must be Color objects: " + `value` super(ColorDict, self).__setitem__(key, value) # # find a Color object stored in the global color dictionary # or make a new one and store it # def get_color(r, g, b): if not isinstance(r, int): raise TypeError, "Invalid red value:" + `r` if r < 0 or r > 255: raise ValueError, "Invalid red value: %d" % r if not isinstance(g, int): raise TypeError, "Invalid green value:" + `g` if g < 0 or g > 255: raise ValueError, "Invalid green value: %d" % g if not isinstance(b, int): raise TypeError, "Invalid blue value:" + `b` if b < 0 or b > 255: raise ValueError, "Invalid blue value: %d" % b _color = Color(r, g, b) if _color in globals.colors: _color = globals.colors[_color] else: globals.colors[_color] = _color return _color PythonCAD-DS1-R37/PythonCAD/Generic/polyline.py0000644000175000017500000010263611307666657020554 0ustar matteomatteo# # Copyright (c) 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # classes for polyline objects # from __future__ import generators import math from PythonCAD.Generic import graphicobject from PythonCAD.Generic import tolerance from PythonCAD.Generic import style from PythonCAD.Generic import linetype from PythonCAD.Generic import color from PythonCAD.Generic import point from PythonCAD.Generic import util from PythonCAD.Generic import quadtree class Polyline(graphicobject.GraphicObject): """A class representing a polyline. A polyline is essentially a number of segments that connect end to end. A Polyline has the following methods: getPoints(): Return the points of the Polyline. {get/set}Point(): Get/Set one of the points of the Polyline addPoint(): Add a new point into the Polyline. delPoint(): Remove a point from the Polyline. move(): Move the Polyline. length(): Get the Polyline length. mapCoords(): Test if a coordinate pair is within some distance to a Polyline. inRegion(): Test if the Polyline is visible in some area. clone(): Make an identical copy of a Polyline. """ __defstyle = None __messages = { 'moved' : True, 'point_changed' : True, 'added_point' : True, 'deleted_point' : True, } def __init__(self, plist, st=None, lt=None, col=None, th=None, **kw): """Initialize a Polyline object. Polyline(plist) The argument 'plist' is a tuple or list containing Point objects. There should be two or more Points in the list. """ if not isinstance(plist, (tuple, list)): raise TypeError, "Invalid Point list/tuple: " + `type(plist)` _pts = [] _count = len(plist) if _count < 2: raise ValueError, "Invalid list count: %d" % _count for _i in range(_count): _obj = plist[_i] if not isinstance(_obj, point.Point): _obj = point.Point(plist[_i]) _pts.append(_obj) _plist = [] for _pt in _pts: try: # no exception means an equal point already found _i = _plist.index(_pt) _plist.append(_plist[_i]) except: # no equal point found _plist.append(_pt) if len(_plist) < 2: raise ValueError, "Invalid point list: " + str(plist) _st = st if _st is None: _st = self.getDefaultStyle() super(Polyline, self).__init__(_st, lt, col, th, **kw) self.__pts = _plist for _pt in _plist: _pt.connect('moved', self.__movePoint) _pt.connect('change_pending', self.__pointChangePending) _pt.connect('change_complete', self.__pointChangeComplete) _pt.storeUser(self) def __len__(self): return len(self.__pts) def __str__(self): return "Polyline" # fixme def __eq__(self, obj): """Compare two Polyline objects for equality. """ if not isinstance(obj, Polyline): return False if obj is self: return True _val = False _ppts = obj.getPoints() _pcount = len(_ppts) _spts = self.__pts _scount = len(_spts) if _pcount == _scount: _val = True for _i in range(_scount): if _ppts[_i] != _spts[_i]: _val = False break if not _val: # check reversed point list of second polyline _val = True _ppts.reverse() for _i in range(_scount): if _ppts[_i] != _spts[_i]: _val = False break return _val def __ne__(self, obj): """Compare two Polyline objects for inequality. """ if not isinstance(obj, Polyline): return True if obj is self: return False _val = True _ppts = obj.getPoints() _pcount = len(_ppts) _spts = self.__pts _scount = len(_spts) if _pcount == _scount: _val = False for _i in range(_scount): if _ppts[_i] != _spts[_i]: _val = True break if _val: # check reversed point list of second polyline _val = False _ppts.reverse() for _i in range(_scount): if _ppts[_i] != _spts[_i]: _val = True break return _val def getDefaultStyle(cls): if cls.__defstyle is None: _s = style.Style(u'Polyline Default Style', linetype.Linetype(u'Solid', None), color.Color(0xffffff), 1.0) cls.__defstyle = _s return cls.__defstyle getDefaultStyle = classmethod(getDefaultStyle) def setDefaultStyle(cls, s): if not isinstance(s, style.Style): raise TypeError, "Invalid style: " + `type(s)` cls.__defstyle = s setDefaultStyle = classmethod(setDefaultStyle) def finish(self): for _pt in self.__pts: _pt.disconnect(self) _pt.freeUser(self) self.__pts = None super(Polyline, self).finish() def setStyle(self, s): """Set the Style of the Polyline. setStyle(s) This method extends GraphicObject::setStyle(). """ _s = s if _s is None: _s = self.getDefaultStyle() super(Polyline, self).setStyle(_s) def getValues(self): """Return values comprising the Polyline. getValues() This method extends the GraphicObject::getValues() method. """ _data = super(Polyline, self).getValues() _data.setValue('type', 'polyline') _pts = [] for _pt in self.__pts: _pts.append(_pt.getID()) _data.setValue('points', _pts) return _data def getPoints(self): """Get the points of the Polyline. getPoints() This function returns a list containing all the Point objects that define the Polyline. """ return self.__pts[:] def getNumPoints(self): """Return the number of Point objects defining the Polyline. getNumPoints() """ return len(self) def getPoint(self, i): """Return a single Point object used for defining the Polyline. getPoint(i) The argument 'i' must be an integer, and its value represents the i'th Point used to define the Polyline. """ return self.__pts[i] def setPoint(self, i, p): """Set a Point of the Polyline. setPoint(i, p) The argument 'i' must be an integer, and its value represents the i'th Point used to define the Polyline. Argument 'p' must be a Point. """ if self.isLocked(): raise RuntimeError, "Setting point not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid Point for Polyline point: " + `type(p)` _pt = self.__pts[i] if _pt is not p: _pt.disconnect(self) _pt.freeUser(self) self.startChange('point_changed') self.__pts[i] = p self.endChange('point_changed') self.sendMessage('point_changed', _pt, p) p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) if abs(_pt.x - p.x) > 1e-10 or abs(_pt.y - p.y) > 1e-10: _pts = [] for _p in self.__pts: if _p is p: # the new point _pts.append((_pt.x, _pt.y)) else: # existing points _pts.append((_p.x, _p.y)) self.sendMessage('moved', _pts) self.modified() def addPoint(self, i, p): """Add a Point to the Polyline. addPoint(i, p) The argument 'i' must be an integer, and argument 'p' must be a Point. The Point is added into the list of points comprising the Polyline as the i'th point. """ if self.isLocked(): raise RuntimeError, "Adding point not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid Point for Polyline point: " + `type(p)` self.startChange('added_point') self.__pts.insert(i, p) self.endChange('added_point') self.sendMessage('added_point', i, p) p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) _pts = [] for _p in self.__pts: if _p is not p: # skip the new point _pts.append((_p.x, _p.y)) self.sendMessage('moved', _pts) self.modified() def delPoint(self, i): """Remove a Point from the Polyline. delPoint(i) The argument i represents the index of the point to remove from the list of points defining the Polyline. The point will be removed only if the polyline will still have at least two Points. """ if self.isLocked(): raise RuntimeError, "Deleting point not allowed - object locked." if len(self.__pts) > 2: _p = self.__pts[i] _pts = [] for _pt in self.__pts: _pts.append((_pt.x, _pt.y)) self.startChange('deleted_point') del self.__pts[i] self.endChange('deleted_point') _p.freeUser(self) _p.disconnect(self) self.sendMessage('deleted_point', i, _p) self.modified() def move(self, dx, dy): """Move a Polyline. move(dx, dy) The first argument gives the x-coordinate displacement, and the second gives the y-coordinate displacement. Both values should be floats. """ _locked = self.isLocked() if not _locked: for _pt in self.__pts: if _pt.isLocked(): _locked = True break if _locked: raise RuntimeError, "Moving polyline not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _coords = [] self.ignore('moved') try: for _pt in self.__pts: _coords.append(_pt.getCoords()) _pt.move(_dx, _dy) finally: self.receive('moved') self.sendMessage('moved', _coords) def length(self): """Return the length of the Polyline. length() The length is the sum of the lengths of all the sub-segments in the Polyline """ _length = 0.0 _pts = self.__pts _count = len(_pts) - 1 for _i in range(_count): _sublength = _pts[_i + 1] - _pts[_i] _length = _length + _sublength return _length def getBounds(self): """Return the bounding rectangle around a Polyline. getBounds() This method returns a tuple of four values: (xmin, ymin, xmax, ymax) """ _pts = self.__pts _pxmin = None _pymin = None _pxmax = None _pymax = None for _pt in _pts: _px, _py = _pt.getCoords() if _pxmin is None or _px < _pxmin: _pxmin = _px if _pymin is None or _py < _pymin: _pymin = _py if _pxmax is None or _px > _pxmax: _pxmax = _px if _pymax is None or _py > _pymax: _pymax = _py return _pxmin, _pymin, _pxmax, _pymax def mapCoords(self, x, y, tol=tolerance.TOL): """Return the nearest Point on the Polyline by the x/y coordinates. mapCoords(x, y[, tol]) The function has two required arguments: x: A Float value giving the 'x' coordinate y: A Float value giving the 'y' coordinate There is a single optional argument: tol: A float value equal or greater than 0.0 This function is used to map a possibly near-by coordinate pair to a Point object on the Polyline. If the distance between the actual Point and the coordinates used as an argument is less than the tolerance, the actual Point is returned. Otherwise, this method returns None. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _count = len(self.__pts) - 1 for _i in range(_count): _x1, _y1 = self.__pts[_i].getCoords() _x2, _y2 = self.__pts[_i + 1].getCoords() _pt = util.map_coords(_x, _y, _x1, _y1, _x2, _y2, _t) if _pt is not None: return _pt return None def inRegion(self, xmin, ymin, xmax, ymax, fully=False): """Return whether or not a Polyline exists within a region. isRegion(xmin, ymin, xmax, ymax[, fully]) The four arguments define the boundary of an area, and the method returns True if the Polyline lies within that area. If the optional argument 'fully' is used and is True, then both endpoints of the Polyline must lie within the boundary. Otherwise, the method returns False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) _pxmin, _pymin, _pxmax, _pymax = self.getBounds() if ((_pxmax < _xmin) or (_pxmin > _xmax) or (_pymax < _ymin) or (_pymin > _ymax)): return False if fully: if ((_pxmin > _xmin) and (_pymin > _ymin) and (_pxmax < _xmax) and (_pymax < _ymax)): return True return False _pts = self.__pts for _i in range(len(_pts) - 1): _x1, _y1 = _pts[_i].getCoords() _x2, _y2 = _pts[_i + 1].getCoords() if util.in_region(_x1, _y1, _x2, _y2, _xmin, _ymin, _xmax, _ymax): return True return False def __pointChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.startChange('moved') def __pointChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.endChange('moved') def __movePoint(self, p, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _seen = False _coords = [] for _pt in self.__pts: if p is _pt: _coords.append((_x, _y)) _seen = True else: _coords.append(_pt.getCoords()) if not _seen: raise ValueError, "Unexpected Polyline point: " + `p` self.sendMessage('moved', _coords) def clone(self): """Create an identical copy of a Polyline. clone() """ _cpts = [] for _pt in self.__pts: _cpts.append(_pt.clone()) _st = self.getStyle() _lt = self.getLinetype() _col = self.getColor() _th = self.getThickness() return Polyline(_cpts, _st, _lt, _col, _th) def sendsMessage(self, m): if m in Polyline.__messages: return True return super(Polyline, self).sendsMessage(m) # # Quadtree Polyline storage # class PolylineQuadtree(quadtree.Quadtree): def __init__(self): super(PolylineQuadtree, self).__init__() def getNodes(self, *args): _alen = len(args) if _alen != 4: raise ValueError, "Expected 4 arguments, got %d" % _alen _pxmin = util.get_float(args[0]) _pymin = util.get_float(args[1]) _pxmax = util.get_float(args[2]) if not _pxmax > _pxmin: raise ValueError, "xmax not greater than xmin" _pymax = util.get_float(args[3]) if not _pymax > _pymin: raise ValueError, "ymax not greater than ymin" _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_pxmin > _xmax) or (_pxmax < _xmin) or (_pymin > _ymax) or (_pymax < _ymin)): continue if _node.hasSubnodes(): _xmid = (_xmin + _xmax)/2.0 _ymid = (_ymin + _ymax)/2.0 _ne = _nw = _sw = _se = True if _pxmax < _xmid: # polyline on left side _ne = _se = False if _pxmin > _xmid: # polyline on right side _nw = _sw = False if _pymax < _ymid: # polyline below _nw = _ne = False if _pymin > _ymid: # polyline above _sw = _se = False if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: yield _node def addObject(self, obj): if not isinstance(obj, Polyline): raise TypeError, "Invalid Polyline object: " + `type(obj)` if obj in self: return _pxmin, _pymin, _pxmax, _pymax = obj.getBounds() _bounds = self.getTreeRoot().getBoundary() _xmin = _ymin = _xmax = _ymax = None _resize = False if _bounds is None: # first node in tree _resize = True _xmin = _pxmin - 1.0 _ymin = _pymin - 1.0 _xmax = _pxmax + 1.0 _ymax = _pymax + 1.0 else: _xmin, _ymin, _xmax, _ymax = _bounds if _pxmin < _xmin: _xmin = _pxmin - 1.0 _resize = True if _pxmax > _xmax: _xmax = _pxmax + 1.0 _resize = True if _pymin < _ymin: _ymin = _pymin - 1.0 _resize = True if _pymax > _ymax: _ymax = _pymax + 1.0 _resize = True if _resize: self.resize(_xmin, _ymin, _xmax, _ymax) for _node in self.getNodes(_pxmin, _pymin, _pxmax, _pymax): _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if obj.inRegion(_xmin, _ymin, _xmax, _ymax): _node.addObject(obj) super(PolylineQuadtree, self).addObject(obj) obj.connect('moved', self._movePolyline) def delObject(self, obj): if obj not in self: return _pxmin, _pymin, _pxmax, _pymax = obj.getBounds() _pdict = {} for _node in self.getNodes(_pxmin, _pymin, _pxmax, _pymax): _node.delObject(obj) # polyline may not be in the node ... _parent = _node.getParent() if _parent is not None: _pid = id(_parent) if _pid not in _pdict: _pdict[_pid] = _parent super(PolylineQuadtree, self).delObject(obj) obj.disconnect(self) for _parent in _pdict.values(): self.purgeSubnodes(_parent) def find(self, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if not isinstance(args[0], list): raise TypeError, "Invalid coordinate list: " + `type(args[0])` _coords = [] _xmin = _xmax = _ymin = _ymax = None for _arg in args[0]: if not isinstance(_arg, tuple): raise TypeError, "Invalid coordinate tuple: " + `type(_arg)` if len(_arg) != 2: raise ValueError, "Invalid coodinate tuple: " + str(_arg) _x = util.get_float(_arg[0]) _y = util.get_float(_arg[1]) _coords.append((_x, _y)) if _xmin is None or _x < _xmin: _xmin = _x if _xmax is None or _x > _xmax: _xmax= _x if _ymin is None or _y < _ymin: _ymin = _y if _ymax is None or _y > _ymax: _ymax = _y _t = tolerance.TOL if _alen > 1: _t = tolerance.toltest(args[1]) _xmin = _xmin - _t _ymin = _ymin - _t _xmax = _xmax + _t _ymax = _ymax + _t _plines = [] for _pline in self.getInRegion(_xmin, _ymin, _xmax, _ymax): _pts = _pline.getPoints() if len(_pts) != len(_coords): continue _hit = False for _i in range(len(_pts)): _px, _py = _pts[_i].getCoords() if ((abs(_px - _coords[_i][0]) > _t) or (abs(_py - _coords[_i][1]) > _t)): continue _hit = True if not _hit: _pts.reverse() for _i in range(len(_pts)): _px, _py = _pts[_i].getCoords() if ((abs(_px - _coords[_i][0]) > _t) or (abs(_py - _coords[_i][1]) > _t)): continue _hit = True if _hit: _plines.append(_pline) return _plines def _movePolyline(self, obj, *args): if obj not in self: raise ValueError, "Polyline not stored in Quadtree: " + `obj` _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if not isinstance(args[0], list): raise TypeError, "Invalid coordinate list: " + `type(args[0])` _pxmin = _pxmax = _pymin = _pymax = None for _arg in args[0]: if not isinstance(_arg, tuple): raise TypeError, "Invalid coordinate tuple: " + `type(_arg)` if len(_arg) != 2: raise ValueError, "Invalid coodinate tuple: " + str(_arg) _x = util.get_float(_arg[0]) _y = util.get_float(_arg[1]) if _pxmin is None or _x < _pxmin: _pxmin = _x if _pxmax is None or _x > _pxmax: _pxmax= _x if _pymin is None or _y < _pymin: _pymin = _y if _pymax is None or _y > _pymax: _pymax = _y for _node in self.getNodes(_pxmin, _pymin, _pxmax, _pymax): _node.delObject(obj) # polyline may not be in node ... super(PolylineQuadtree, self).delObject(obj) obj.disconnect(self) self.addObject(obj) def getClosest(self, x, y, tol=tolerance.TOL): _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _polyline = _tsep = None _bailout = False _pdict = {} _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_x < (_xmin - _t)) or (_x > (_xmax + _t)) or (_y < (_ymin - _t)) or (_y > (_ymax + _t))): continue if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) else: for _p in _node.getObjects(): _pid = id(_p) if _pid not in _pdict: for _pt in _p.getPoints(): _px, _py = _pt.getCoords() if ((abs(_px - _x) < 1e-10) and (abs(_py - _y) < 1e-10)): _polyline = _p _bailout = True break _pdict[_pid] = True if _bailout: break _pt = _p.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _sep = math.hypot((_px - _x), (_py - _y)) if _tsep is None: _tsep = _sep _polyline = _p else: if _sep < _tsep: _tsep = _sep _polyline = _p if _bailout: break return _polyline def getInRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _polylines = [] if not len(self): return _polylines _nodes = [self.getTreeRoot()] _pdict = {} while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): for _subnode in _node.getSubnodes(): _sxmin, _symin, _sxmax, _symax = _subnode.getBoundary() if ((_sxmin > _xmax) or (_symin > _ymax) or (_sxmax < _xmin) or (_symax < _ymin)): continue _nodes.append(_subnode) else: for _p in _node.getObjects(): _pid = id(_p) if _pid not in _pdict: if _p.inRegion(_xmin, _ymin, _xmax, _ymax): _polylines.append(_p) _pdict[_pid] = True return _polylines # # Polyline history class # class PolylineLog(graphicobject.GraphicObjectLog): def __init__(self, p): if not isinstance(p, Polyline): raise TypeError, "Invalid polyline: " + `type(p)` super(PolylineLog, self).__init__(p) p.connect('point_changed', self.__pointChanged) p.connect('added_point', self.__addedPoint) p.connect('deleted_point', self.__deletedPoint) def __pointChanged(self, p, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _old = args[0] if not isinstance(_old, point.Point): raise TypeError, "Invalid old endpoint: " + `type(_old)` _new = args[1] if not isinstance(_new, point.Point): raise TypeError, "Invalid new endpoint: " + `type(_new)` self.saveUndoData('point_changed', _old.getID(), _new.getID()) def __addedPoint(self, p, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _idx = args[0] if not isinstance(_idx, int): raise TypeError, "Invalid point index: " + `type(_idx)` _p = args[1] if not isinstance(_p, point.Point): raise TypeError, "Invalid point: " + `type(_p)` self.saveUndoData('added_point', _idx, _p.getID()) def __deletedPoint(self, p, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _idx = args[0] if not isinstance(_idx, int): raise TypeError, "Invalid point index: " + `type(_idx)` _p = args[1] if not isinstance(_p, point.Point): raise TypeError, "Invalid point: " + `type(_p)` self.saveUndoData('deleted_point', _idx, _p.getID()) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if _alen == 0: raise ValueError, "No arguments to execute()" _p = self.getObject() _op = args[0] _pts = _p.getPoints() if _op == 'point_changed': if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _oid = args[1] _nid = args[2] _parent = _p.getParent() if _parent is None: raise ValueError, "Polyline has no parent - cannot undo" self.ignore(_op) try: if undo: _setpt = _parent.getObject(_oid) if _setpt is None or not isinstance(_setpt, point.Point): raise ValueError, "Old endpoint missing: id=%d" % _oid _p.startUndo() try: _seen = False for _i in range(len(_pts)): _pt = _pts[_i] if _pt.getID() == _nid: _p.setPoint(_i, _setpt) _seen = True break if not _seen: raise ValueError, "Unexpected point ID: %d" % _nid finally: _p.endUndo() else: _setpt = _parent.getObject(_nid) if _setpt is None or not isinstance(_setpt, point.Point): raise ValueError, "New point missing: id=%d" % _nid _pts = _p.getPoints() _p.startRedo() try: _seen = False for _i in range(len(_pts)): _pt = _pts[_i] if _pt.getID() == _oid: _p.setPoint(_i, _setpt) _seen = True break if not _seen: raise ValueError, "Unexpected point ID: %d" % _nid finally: _p.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _oid, _nid) elif _op == 'added_point': if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _idx = args[1] _pid = args[2] self.ignore(_op) try: if undo: self.ignore('deleted_point') try: _p.startUndo() try: _p.delPoint(_idx) finally: _p.endUndo() finally: self.receive('deleted_point') else: _parent = _p.getParent() if _parent is None: raise ValueError, "Polyline has no parent - cannot undo" _pt = _parent.getObject(_pid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "Point missing: id=%d" % _pid _p.startRedo() try: _p.addPoint(_idx, _pt) finally: _p.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _idx, _pid) elif _op == 'deleted_point': if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _idx = args[1] _pid = args[2] self.ignore(_op) try: if undo: _parent = _p.getParent() if _parent is None: raise ValueError, "Polyline has no parent - cannot undo" _pt = _parent.getObject(_pid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "Point missing: id=%d" % _pid self.ignore('added_point') try: _p.startUndo() try: _p.addPoint(_idx, _pt) finally: _p.endUndo() finally: self.receive('added_point') else: _p.startRedo() try: _p.delPoint(_idx) finally: _p.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _idx, _pid) else: super(PolylineLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/message.py0000644000175000017500000001423411307666657020341 0ustar matteomatteo# # Copyright (c) 2004, 2005 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # A base class for objects that send messages # import types import traceback class Messenger(object): __messages = { 'connected' : True, 'disconnected' : True } def __init__(self): self.__connections = None self.__mdict = None self.__ignore = None self.__muted = False def finish(self): if self.__connections is not None: print "remaining connections for obj: " + `self` for _message in self.__connections: print "message: %s" % _message for _method in self.__connections[_message]: _obj = _method.im_self print "connected to obj: " + `_obj` def connect(self, message, method): if not self.sendsMessage(message): raise ValueError, "Unknown message : %s" % str(message) if not isinstance(method, types.MethodType): raise TypeError, "Invalid class method type: " + `type(method)` if method.im_self is None: raise ValueError, "Unbound method use invalid: %s" % str(method) if self.__connections is None: self.__connections = {} _methods = self.__connections.setdefault(message, []) _seen = False for _m in _methods: if _m is method: _seen = True break if not _seen: _methods.append(method) self.sendMessage('connected', method) def disconnect(self, obj, message=None): if self.__connections is not None: if message is None: _messages = self.__connections.keys() for _message in _messages: _methods = self.__connections[_message] for _method in _methods[:]: _obj = _method.im_self if _obj is obj: _methods.remove(_method) self.sendMessage('disconnected', obj) if len(_methods) == 0: del self.__connections[_message] else: if message in self.__connections: _methods = self.__connections[message] for _method in _methods[:]: _obj = _method.im_self if _obj is obj: _methods.remove(_method) self.sendMessage('disconnected', obj) break if len(_methods) == 0: del self.__connections[message] if len(self.__connections) == 0: self.__connections = None def sendsMessage(self, m): return m in Messenger.__messages def sendMessage(self, message, *args): if not isinstance(message, str): raise TypeError, "Invalid message type: " + `type(message)` if not self.__muted and self.__connections is not None: if self.__mdict is None or message not in self.__mdict: if message in self.__connections: _methods = self.__connections[message][:] # make a copy for _method in _methods: _obj = _method.im_self if (isinstance(_obj, Messenger) and _obj.ignores(message)): continue # # "handle" the exception - notice the quotes ... # try: _method(self, *args) except: traceback.print_exc() def muteMessage(self, message): if not isinstance(message, str): raise TypeError, "Invalid message type: " + `type(message)` if self.__mdict is None: self.__mdict = {} if message in self.__mdict: raise ValueError, "Message '%s' already blocked." % message self.__mdict[message] = True def unmuteMessage(self, message): if not isinstance(message, str): raise TypeError, "Invalid message type: " + `type(message)` if self.__mdict is not None: if message in self.__mdict: del self.__mdict[message] if len(self.__mdict) == 0: self.__mdict = None def mute(self): self.__muted = True def unmute(self): self.__muted = False def isMuted(self): return self.__muted is True def ignore(self, message): if not isinstance(message, str): raise TypeError, "Invalid message type: " + `type(message)` if self.__ignore is None: self.__ignore = {} if message in self.__ignore: raise RuntimeError, "Message '%s' already ignored." % message self.__ignore[message] = True def receive(self, message): if not isinstance(message, str): raise TypeError, "Invalid message type: " + `type(message)` if self.__ignore is not None: if message in self.__ignore: del self.__ignore[message] if len(self.__ignore) == 0: self.__ignore = None def ignores(self, message): return self.__ignore is not None and message in self.__ignore def receives(self, message): return self.__ignore is None or message not in self.__ignore PythonCAD-DS1-R37/PythonCAD/Generic/maptree.py0000644000175000017500000001265011307666657020352 0ustar matteomatteo# # Copyright (c) 2002, 2003 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # A PointMapTree and PointBMapTree extend a basic Tree # from PythonCAD.Generic import point from PythonCAD.Generic import util from PythonCAD.Generic import tolerance from PythonCAD.Generic import tree class PointMapTree(tree.Tree): """A Tree class that containing objects that have Point objects. The PointMapTree is based on the Tree class, so it shares all the functionality of that class. There is one extra method in the PointMapTree mapPoint(): Find objects in the tree that a Point could fall upon. Any class stored in this tree must provide a mapPoint() method. The format of that method is as follows: mapPoint(p[, tol]) p: Either a Point object or a two-float tuple Optional argument: tol: The tolerance used for testing the Point's proximity to the object. A class should also have a __cmp__ method that can handle an instance of the class being compared to a Point. """ def __init__(self, t): """Instantiate a PointMapTree. PointMapTree(t) This function has one required argument: t: The type of object stored in the tree. """ tree.Tree.__init__(self, t) def mapPoint(self, p, tol=tolerance.TOL, count=2): """See if an object in the PointMapTree exists at a Point. mapPoint(p [, tol, count]) This method has one required parameter: p: Either a Point object or a tuple of two-floats There are two optional arguments: tol: A float equal or greater than 0 used to decide if the point is close enough to the objects held in the Tree. count: An integer indicating the maximum number of objects to return. By default this value is 2. The function returns a list of at tuples, each of the form (obj, pt) obj: Object that the Point is mapped to pt: The projected Point on the object """ _p = p if not isinstance(_p, (point.Point, tuple)): raise TypeError, "Invalid type for searching in PointMapTree: " + `_p` if isinstance(_p, tuple): _x, _y = util.tuple_to_two_floats(_p) _p = point.Point(_x, _y) _t = tolerance.toltest(tol) _count = count if not isinstance(_count, int): _count = int(count) if _count < 0: raise ValueError, "Invalid count: %d" % _count _objlist = [] for _obj in self: _pt = _obj.mapPoint(_p, _t) if _pt is not None: _objlist.append((_obj, _pt)) if len(_objlist) == _count or cmp(_obj, _p) == 1: break return _objlist class PointBMapTree(PointMapTree): """A Tree class that containing objects that have Point objects. The PointBMapTree is based on the PointMapTree class, so it shares all the functionality of that class. The PointBMapTree uses a binary scan search on objects in the tree to find a particular object, where the PointMapTree uses a linear search. This implies that any PointBMapTree will only contain at most one object that a Point object may be mapped on to. """ def __init__(self, t): """Instantiate a PointBMapTree. PointBMapTree(t) This function has one required argument: t: The type of object stored in the tree. """ PointMapTree.__init__(self, t) def mapPoint(self, p, tol=tolerance.TOL): """See if an object in the PointBMapTree exists at a Point. mapPoint(p [, tol]) This method has one required parameter: p: Either a Point object or a tuple of two-floats There is a single optional argument: tol: A float equal or greater than 0 used to decide if the point is close enough to the objects held in the Tree. The function returns a list of at tuples, each of the form (obj, pt) obj: Object that the Point is mapped to pt: The projected Point on the object The list will contain at most two tuples. """ _p = p if not isinstance(_p, (point.Point, tuple)): raise TypeError, "Invalid type for searching in PointMapTree: " + `_p` if isinstance(_p, tuple): _x, _y = util.tuple_to_two_floats(_p) _p = point.Point(_x, _y) _t = tolerance.toltest(tol) _objlist = [] _scanlist = [] _lo = 0 _hi = len(self) while _lo < _hi: _mid = (_hi+_lo)//2 if _mid in _scanlist: break _scanlist.append(_mid) _obj = self[_mid] _res = cmp(_obj, _p) if _res == -1: _lo = _mid + 1 elif _res == 1: _hi = _mid else: _pt = _obj.mapPoint(_p, _t) if _pt is not None: _objlist.append((_obj, _pt)) break return _objlist PythonCAD-DS1-R37/PythonCAD/Generic/options.py0000644000175000017500000004744111307666732020410 0ustar matteomatteo# # Copyright (c) 2002, 2004, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # handle setting and retrieving of the various options # and preferences in an image # # none of these functions should be called directly - they # are all meant as private functions for an Image object import types from PythonCAD.Generic import units from PythonCAD.Generic import dimension from PythonCAD.Generic import text from PythonCAD.Generic import style from PythonCAD.Generic import color from PythonCAD.Generic import linetype # # generic type tests # def _test_boolean_value(key, value): if not (value is True or value is False): raise ValueError, "Invalid boolean for '%s'" + key def _test_int_value(key, value, min=None, max=None): if not isinstance(value, int): raise TypeError, "Integer required for '%s'" % key if min is not None: assert isinstance(min, int), "Invalid minimum value: " + str(min) if value < min: raise ValueError, "Invalid value: %d < %d (min)" % (value, min) if max is not None: assert isinstance(max, int), "Invalid maximum value: " + str(max) if value > max: raise ValueError, "Invalid value: %d > %d (max)" % (value, max) def _test_float_value(key, value, min=None, max=None): if not isinstance(value, float): raise TypeError, "Float required for '%s'" % key if min is not None: assert isinstance(min, float), "Invalid minimum value: " + str(min) if value < min: raise ValueError, "Invalid value: %g < %g (min)" % (value, min) if max is not None: assert isinstance(max, float), "Invalid maximum value: " + str(max) if value > max: raise ValueError, "Invalid value: %g > %g (max)" % (value, max) def _test_unicode_value(key, value): if not isinstance(value, unicode): raise TypeError, "Unicode string required for '%s'" % key def _test_color_value(key, value): if not isinstance(value, color.Color): raise TypeError, "Color object required for '%s'" % key def _test_linetype_value(key, value): if not isinstance(value, linetype.Linetype): raise TypeError, "Invalid line type for '%s'" % key def _test_linestyle_value(key, value): if not isinstance(value, style.Style): raise TypeError, "Invalid text style for '%s'" % key def _test_font_family(key, value): if not isinstance(value, types.StringTypes): raise TypeError, "String required for '%s'" % key if value == '': raise ValueError, "Non-null string required for '%s'" % key def _test_dimstyle(key, value): if not isinstance(value, dimension.DimStyle): raise TypeError, "Invalid DimStyle for '%s'" % key def _test_font_weight(key, value): if value not in text.TextStyle.getWeightValues(): raise ValueError, "Invalid font weight for '%s'" % key def _test_font_style(key, value): if value not in text.TextStyle.getStyleValues(): raise ValueError, "Invalid font style for '%s'" % key def _test_units(key, value): if value not in units.Unit.getUnitValues(): raise ValueError, "Invalid unit for '%s'" % key # # dimension related tests # def _set_dim_style(opt, ds): _test_dimstyle(opt, ds) def _set_dim_primary_font_family(opt, family): _test_font_family(opt, family) def _set_dim_primary_font_size(opt, size): _test_float_value(opt, size, min=0.0) def _set_dim_primary_text_size(opt, size): _test_float_value(opt, size, min=0.0) def _set_dim_primary_font_style(opt, st): _test_font_style(opt, st) def _set_dim_primary_font_weight(opt, weight): _test_font_weight(opt, weight) def _set_dim_primary_font_color(opt, col): _test_color_value(opt, col) def _set_dim_primary_prefix(opt, pfx): _test_unicode_value(opt, pfx) def _set_dim_primary_suffix(opt, pfx): _test_unicode_value(opt, pfx) def _set_dim_primary_units(opt, u): _test_units(opt, u) def _set_dim_primary_precision(opt, prec): _test_int_value(opt, prec, min=0, max=15) def _set_dim_primary_print_zero(opt, flag): _test_boolean_value(opt, flag) def _set_dim_primary_trail_decimal(opt, flag): _test_boolean_value(opt, flag) def _set_dim_secondary_font_family(opt, family): _test_font_family(opt, family) def _set_dim_secondary_font_size(opt, size): _test_float_value(opt, size, min=0.0) def _set_dim_secondary_text_size(opt, size): _test_float_value(opt, size, min=0.0) def _set_dim_secondary_font_style(opt, st): _test_font_style(opt, st) def _set_dim_secondary_font_weight(opt, weight): _test_font_weight(opt, weight) def _set_dim_secondary_font_color(opt, col): _test_color_value(opt, col) def _set_dim_secondary_prefix(opt, pfx): _test_unicode_value(opt, pfx) def _set_dim_secondary_suffix(opt, pfx): _test_unicode_value(opt, pfx) def _set_dim_secondary_units(opt, u): _test_units(opt, u) def _set_dim_secondary_precision(opt, prec): _test_int_value(opt, prec, min=0, max=15) def _set_dim_secondary_print_zero(opt, flag): _test_boolean_value(opt, flag) def _set_dim_secondary_trail_decimal(opt, flag): _test_boolean_value(opt, flag) def _set_dim_offset(opt, offset): _test_float_value(opt, offset, min=0.0) def _set_dim_extension(opt, ext): _test_float_value(opt, ext, min=0.0) def _set_dim_color(opt, col): _test_color_value(opt, col) def _set_dim_thickness(opt, ext): _test_float_value(opt, ext, min=0.0) def _set_dim_dual_mode(opt, mode): _test_boolean_value(opt, mode) def _set_dim_position_offset(opt, ext): _test_float_value(opt, ext, min=0.0) def _set_dim_dual_mode_offset(opt, ext): _test_float_value(opt, ext, min=0.0) def _set_dim_position(opt, pos): if pos not in dimension.Dimension.getPositionValues(): raise ValueError, "Invalid dimension position: " + str(pos) def _set_dim_endpoint(opt, ept): if ept not in dimension.Dimension.getEndpointTypeValues(): raise ValueError, "Invalid endpoint value: " + str(ept) def _set_dim_endpoint_size(opt, size): _test_float_value(opt, size, min=0.0) def _set_radial_dim_primary_prefix(opt, pfx): _test_unicode_value(opt, pfx) def _set_radial_dim_primary_suffix(opt, sfx): _test_unicode_value(opt, sfx) def _set_radial_dim_secondary_prefix(opt, sfx): _test_unicode_value(opt, sfx) def _set_radial_dim_secondary_suffix(opt, pfx): _test_unicode_value(opt, pfx) def _set_radial_dim_dia_mode(opt, flag): _test_boolean_value(opt, flag) def _set_angular_dim_primary_prefix(opt, pfx): _test_unicode_value(opt, pfx) def _set_angular_dim_primary_suffix(opt, sfx): _test_unicode_value(opt, sfx) def _set_angular_dim_secondary_prefix(opt, pfx): _test_unicode_value(opt, pfx) def _set_angular_dim_secondary_suffix(opt, sfx): _test_unicode_value(opt, sfx) def _set_angular_dim_small_angle_mode(opt, flag): _test_boolean_value(opt, flag) # # text related tests # def _set_text_style(opt, textstyle): if not isinstance(textstyle, text.TextStyle): raise TypeError, "Invalid text style: " + `textstyle` def _set_font_family(opt, family): _test_font_family(opt, family) def _set_font_style(opt, st): _test_font_style(opt, st) def _set_font_weight(opt, weight): _test_font_weight(opt, weight) def _set_font_size(opt, size): _test_float_value(opt, size, min=0.0) def _set_font_color(opt, col): _test_color_value(opt, col) def _set_text_size(opt, size): _test_float_value(opt, size, min=0.0) def _set_text_angle(opt, angle): _test_float_value(opt, angle) def _set_text_alignment(opt, align): if align not in text.TextStyle.getAlignmentValues(): raise ValueError, "Invalid text alignment: " + str(align) def _set_chamfer_length(opt, length): _test_float_value(opt, length, min=0.0) def _set_fillet_radius(opt, radius): _test_float_value(opt, radius) def _set_line_style(opt, st): _test_linestyle_value(opt, st) def _set_line_color(opt, col): _test_color_value(opt, col) def _set_line_type(opt, lt): _test_linetype_value(opt, lt) def _set_line_thickness(opt, thickness): _test_float_value(opt, thickness, min=0.0) def _set_units(opt, u): _test_units(opt, u) def _set_highlight_points(opt, flag): _test_boolean_value(opt, flag) def _set_inactive_layer_color(opt, col): _test_color_value(opt, col) def _set_background_color(opt, col): _test_color_value(opt, col) def _set_single_point_color(opt, col): _test_color_value(opt, col) def _set_multi_point_color(opt, col): _test_color_value(opt, col) def _set_autosplit(opt, col): _test_boolean_value(opt, col) def _leader_arrow_size(opt, size): _test_float_value(opt, size, min=0.0) # # the keys of this dictionary represent options that have # tests to validate the option value is suitable # _optdict = { 'DIM_STYLE' : _set_dim_style, 'DIM_PRIMARY_FONT_FAMILY' : _set_dim_primary_font_family, 'DIM_PRIMARY_FONT_SIZE' : _set_dim_primary_font_size, 'DIM_PRIMARY_TEXT_SIZE' : _set_dim_primary_text_size, 'DIM_PRIMARY_FONT_WEIGHT' : _set_dim_primary_font_weight, 'DIM_PRIMARY_FONT_STYLE' : _set_dim_primary_font_style, 'DIM_PRIMARY_FONT_COLOR' : _set_dim_primary_font_color, 'DIM_PRIMARY_TEXT_ANGLE' : _set_text_angle, 'DIM_PRIMARY_TEXT_ALIGNMENT' : _set_text_alignment, 'DIM_PRIMARY_PREFIX' : _set_dim_primary_prefix, 'DIM_PRIMARY_SUFFIX' : _set_dim_primary_suffix, 'DIM_PRIMARY_PRECISION' : _set_dim_primary_precision, 'DIM_PRIMARY_UNITS' : _set_dim_primary_units, 'DIM_PRIMARY_LEADING_ZERO' : _set_dim_primary_print_zero, 'DIM_PRIMARY_TRAILING_DECIMAL': _set_dim_primary_trail_decimal, 'DIM_SECONDARY_FONT_FAMILY' : _set_dim_secondary_font_family, 'DIM_SECONDARY_FONT_SIZE' : _set_dim_secondary_font_size, 'DIM_SECONDARY_TEXT_SIZE' : _set_dim_secondary_text_size, 'DIM_SECONDARY_FONT_WEIGHT' : _set_dim_secondary_font_weight, 'DIM_SECONDARY_FONT_STYLE' : _set_dim_secondary_font_style, 'DIM_SECONDARY_FONT_COLOR' : _set_dim_secondary_font_color, 'DIM_SECONDARY_TEXT_ANGLE' : _set_text_angle, 'DIM_SECONDARY_TEXT_ALIGNMENT' : _set_text_alignment, 'DIM_SECONDARY_PREFIX' : _set_dim_secondary_prefix, 'DIM_SECONDARY_SUFFIX' : _set_dim_secondary_suffix, 'DIM_SECONDARY_PRECISION' : _set_dim_secondary_precision, 'DIM_SECONDARY_UNITS' : _set_dim_secondary_units, 'DIM_SECONDARY_LEADING_ZERO' : _set_dim_secondary_print_zero, 'DIM_SECONDARY_TRAILING_DECIMAL': _set_dim_secondary_trail_decimal, 'DIM_OFFSET' : _set_dim_offset, 'DIM_EXTENSION': _set_dim_extension, 'DIM_COLOR' : _set_dim_color, 'DIM_THICKNESS' : _set_dim_thickness, 'DIM_POSITION': _set_dim_position, 'DIM_ENDPOINT': _set_dim_endpoint, 'DIM_ENDPOINT_SIZE' : _set_dim_endpoint_size, 'DIM_DUAL_MODE' : _set_dim_dual_mode, 'DIM_POSITION_OFFSET' : _set_dim_position_offset, 'DIM_DUAL_MODE_OFFSET' : _set_dim_dual_mode_offset, 'RADIAL_DIM_PRIMARY_PREFIX' : _set_radial_dim_primary_prefix, 'RADIAL_DIM_PRIMARY_SUFFIX' : _set_radial_dim_primary_suffix, 'RADIAL_DIM_SECONDARY_PREFIX' : _set_radial_dim_secondary_prefix, 'RADIAL_DIM_SECONDARY_SUFFIX' : _set_radial_dim_secondary_suffix, 'RADIAL_DIM_DIA_MODE' : _set_radial_dim_dia_mode, 'ANGULAR_DIM_PRIMARY_PREFIX' : _set_angular_dim_primary_prefix, 'ANGULAR_DIM_PRIMARY_SUFFIX' : _set_angular_dim_primary_suffix, 'ANGULAR_DIM_SECONDARY_PREFIX' : _set_angular_dim_secondary_prefix, 'ANGULAR_DIM_SECONDARY_SUFFIX' : _set_angular_dim_secondary_suffix, 'TEXT_STYLE' : _set_text_style, 'FONT_FAMILY' : _set_font_family, 'FONT_STYLE' : _set_font_style, 'FONT_WEIGHT' : _set_font_weight, 'FONT_SIZE' : _set_font_size, 'FONT_COLOR' : _set_font_color, 'TEXT_SIZE' : _set_text_size, 'TEXT_ANGLE' : _set_text_angle, 'TEXT_ALIGNMENT' : _set_text_alignment, 'CHAMFER_LENGTH' : _set_chamfer_length, 'FILLET_RADIUS' : _set_fillet_radius, 'UNITS' : _set_units, 'LINE_STYLE' : _set_line_style, 'LINE_COLOR' : _set_line_color, 'LINE_TYPE' : _set_line_type, 'LINE_THICKNESS': _set_line_thickness, 'HIGHLIGHT_POINTS' : _set_highlight_points, 'INACTIVE_LAYER_COLOR' : _set_inactive_layer_color, 'BACKGROUND_COLOR' : _set_background_color, 'SINGLE_POINT_COLOR' : _set_single_point_color, 'MULTI_POINT_COLOR' : _set_multi_point_color, 'AUTOSPLIT' : _set_autosplit, 'LEADER_ARROW_SIZE' : _leader_arrow_size, } # # the test_option() function will return True for tested # options that validate or for unknown options. Invalid # tested options will raise an exception that the caller # must handle # def test_option(opt, val): _valid = True if opt in _optdict: _optdict[opt](opt, val) return _valid class OptionManager(object): def isDimStyle(obj): return isinstance(obj, dimension.DimStyle) isDimStyle = staticmethod(isDimStyle) def isTextStyle(obj): return isinstance(obj, text.TextStyle) isTextStyle = staticmethod(isTextStyle) def isStyle(obj): return isinstance(obj, style.Style) isStyle = staticmethod(isStyle) def isLinetype(obj): return isinstance(obj, linetype.Linetype) isLinetype = staticmethod(isLinetype) def isStringType(obj): return isinstance(obj, types.StringTypes) isStringType = staticmethod(isStringType) def isInt(obj): return isinstance(obj, int) isInt = staticmethod(isInt) def isFloat(obj): return isinstance(obj, float) isFloat = staticmethod(isFloat) def isColor(obj): return isinstance(obj, color.Color) isColor = staticmethod(isColor) def isBoolean(obj): return ((hasattr(types, 'BooleanType') and isinstance(obj, types.BooleanType)) or (obj is True or obj is False)) isBoolean = staticmethod(isBoolean) def checkEndpointType(obj): return obj in dimension.Dimension.getEndpointTypeValues() checkEndpointType = staticmethod(checkEndpointType) def checkPosition(obj): return obj in dimension.Dimension.getPositionValues() checkPosition = staticmethod(checkPosition) def checkFontWeight(obj): return obj in text.TextStyle.getWeightValues() checkFontWeight = staticmethod(checkFontWeight) def checkFontStyle(obj): return obj in text.TextStyle.getStyleValues() checkFontStyle = staticmethod(checkFontStyle) def checkTextAlignment(obj): return obj in text.TextStyle.getAlignmentValues() checkTextAlignment = staticmethod(checkTextAlignment) def checkUnit(obj): return obj in units.Unit.getUnitValues() checkUnit = staticmethod(checkUnit) def checkPrecision(obj): return not (obj < 0 or obj > 15) checkPrecision = staticmethod(checkPrecision) def checkPositiveFloat(obj): return not obj < 0.0 checkPositiveFloat = staticmethod(checkPositiveFloat) __optdict = { 'DIM_STYLE' : ('isDimStyle', None), 'DIM_PRIMARY_FONT_FAMILY' : ('isStringType', None), 'DIM_PRIMARY_FONT_WEIGHT' : ('isInt', 'checkFontWeight'), 'DIM_PRIMARY_FONT_STYLE' : ('isInt', 'checkFontStyle'), 'DIM_PRIMARY_FONT_COLOR' : ('isColor', None), 'DIM_PRIMARY_TEXT_SIZE' : ('isFloat', 'checkPositiveFloat'), 'DIM_PRIMARY_TEXT_ANGLE' : ('isFloat', None), 'DIM_PRIMARY_TEXT_ALIGNMENT' : ('isInt', 'checkTextAlignment'), 'DIM_PRIMARY_PREFIX' : ('isStringType', None), 'DIM_PRIMARY_SUFFIX' : ('isStringType', None), 'DIM_PRIMARY_PRECISION' : ('isInt', 'checkPrecision'), 'DIM_PRIMARY_UNITS' : ('isInt', 'checkUnit'), 'DIM_PRIMARY_LEADING_ZERO' : ('isBoolean', None), 'DIM_PRIMARY_TRAILING_DECIMAL': ('isBoolean', None), 'DIM_SECONDARY_FONT_FAMILY' : ('isStringType', None), 'DIM_SECONDARY_FONT_WEIGHT' : ('isInt', 'checkFontWeight'), 'DIM_SECONDARY_FONT_STYLE' : ('isInt', 'checkFontStyle'), 'DIM_SECONDARY_FONT_COLOR' : ('isColor', None), 'DIM_SECONDARY_TEXT_SIZE' : ('isFloat', 'checkPositiveFloat'), 'DIM_SECONDARY_TEXT_ANGLE' : ('isFloat', None), 'DIM_SECONDARY_TEXT_ALIGNMENT' : ('isInt', 'checkTextAlignment'), 'DIM_SECONDARY_PREFIX' : ('isStringType', None), 'DIM_SECONDARY_SUFFIX' : ('isStringType', None), 'DIM_SECONDARY_PRECISION' : ('isInt', 'checkPrecision'), 'DIM_SECONDARY_UNITS' : ('isInt', 'checkUnit'), 'DIM_SECONDARY_LEADING_ZERO' : ('isBoolean', None), 'DIM_SECONDARY_TRAILING_DECIMAL': ('isBoolean', None), 'DIM_OFFSET' : ('isFloat', 'checkPositiveFloat'), 'DIM_EXTENSION': ('isFloat', 'checkPositiveFloat'), 'DIM_COLOR' : ('isColor', None), 'DIM_THICKNESS' : ('isFloat', 'checkPositiveFloat'), 'DIM_POSITION': ('isInt', 'checkPosition'), 'DIM_ENDPOINT': ('isInt', 'checkEndpointType'), 'DIM_ENDPOINT_SIZE' : ('isFloat', 'checkPositiveFloat'), 'DIM_DUAL_MODE' : ('isBoolean', None), 'DIM_POSITION_OFFSET' : ('isFloat', None), 'DIM_DUAL_MODE_OFFSET' : ('isFloat', None), 'RADIAL_DIM_PRIMARY_PREFIX' : ('isStringType', None), 'RADIAL_DIM_PRIMARY_SUFFIX' : ('isStringType', None), 'RADIAL_DIM_SECONDARY_PREFIX' : ('isStringType', None), 'RADIAL_DIM_SECONDARY_SUFFIX' : ('isStringType', None), 'RADIAL_DIM_DIA_MODE' : ('isBoolean', None), 'ANGULAR_DIM_PRIMARY_PREFIX' : ('isStringType', None), 'ANGULAR_DIM_PRIMARY_SUFFIX' : ('isStringType', None), 'ANGULAR_DIM_SECONDARY_PREFIX' : ('isStringType', None), 'ANGULAR_DIM_SECONDARY_SUFFIX' : ('isStringType', None), 'TEXT_STYLE' : ('isTextStyle', None), 'FONT_FAMILY' : ('isStringType', None), 'FONT_STYLE' : ('isInt', 'checkFontStyle'), 'FONT_WEIGHT' : ('isInt', 'checkFontWeight'), 'FONT_COLOR' : ('isColor', None), 'TEXT_SIZE' : ('isFloat', 'checkPositiveFloat'), 'TEXT_ANGLE' : ('isFloat', None), 'TEXT_ALIGNMENT' : ('isInt', 'checkTextAlignment'), 'CHAMFER_LENGTH' : ('isFloat', 'checkPositiveFloat'), 'FILLET_RADIUS' : ('isFloat', 'checkPositiveFloat'), 'FILLET_TWO_TRIM_MODE' : ('isStringType', None), 'UNITS' : ('isInt', 'checkUnit'), 'LINE_STYLE' : ('isStyle', None), 'LINE_COLOR' : ('isColor', None), 'LINE_TYPE' : ('isLinetype', None), 'LINE_THICKNESS': ('isFloat', 'checkPositiveFloat'), 'HIGHLIGHT_POINTS' : ('isBoolean', None), 'AUTOSPLIT' : ('isBoolean', None), 'INACTIVE_LAYER_COLOR' : ('isColor', None), 'BACKGROUND_COLOR' : ('isColor', None), 'SINGLE_POINT_COLOR' : ('isColor', None), 'MULTI_POINT_COLOR' : ('isColor', None), 'LEADER_ARROW_SIZE' : ('isFloat', 'checkPositiveFloat'), } def testOption(cls, opt, value): _tests = cls.__optdict.get(opt) if _tests is None: raise KeyError, "Unknown option: '%s'" % opt _ttest, _vtest = _tests if not (getattr(cls, _ttest))(value): raise TypeError, "Invalid type for option %s: '%s'" % (opt, `type(value)`) if _vtest is not None and not (getattr(cls, _vtest))(value): raise ValueError, "Invalid value for option %s: '%s'" % (opt, str(value)) testOption = classmethod(testOption) PythonCAD-DS1-R37/PythonCAD/Generic/graphicobject.py0000644000175000017500000004661711307666657021533 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # classes for graphic objects # from PythonCAD.Generic import style from PythonCAD.Generic import color from PythonCAD.Generic import linetype from PythonCAD.Generic import baseobject from PythonCAD.Generic import entity from PythonCAD.Generic import util class GraphicObject(baseobject.Subpart): """A class representing an object that is drawn. This class is meant to be a base class for things like line segments, circles, etc. The GraphicObject class has one attribute that cannot be None: style: The Style object There are three other attributes that override values in the style attribute: color: A Color object thickness: A positive float value linetype: A Linetype object A GraphicObject object has the following methods: {get/set}Style(): Get/Set the Style of a GraphicObject. {get/set}Color(): Get/Set the Color of a GraphicObject. {get/set}Thickness(): Get/Set the thickness of a GraphicObject. {get/set}Linetype(): Get/Set the Linetype of a GraphicObject. """ __messages = { 'style_changed' : True, 'color_changed' : True, 'linetype_changed' : True, 'thickness_changed' : True, } __defstyle = None def __init__(self, st=None, lt=None, col=None, t=None, **kw): """Initialize a GraphicObject. GraphicObject([st, lt, col, t]) Optional arguments: style: A style object that overrides the class default linetype: A Linetype object that overrides the value in the Style color: A Color object that overrides the value in the Style thickness: A positive float that overrides the value in the Style """ super(GraphicObject, self).__init__(**kw) _st = st if _st is None: _st = self.getDefaultStyle() if not isinstance(_st, style.Style): raise TypeError, "Invalid style type: " + `type(_st)` _col = _lt = _t = None if 'color' in kw: _col = kw['color'] if _col is None: _col = col if _col is not None: if not isinstance(_col, color.Color): _col = color.Color(_col) if _col == _st.getColor(): _col = None if 'linetype' in kw: _lt = kw['linetype'] if _lt is None: _lt = lt if _lt is not None: if not isinstance(_lt, linetype.Linetype): raise TypeError, "Invalid linetype type: " + `type(_lt)` if _lt == _st.getLinetype(): _lt = None if 'thickness' in kw: _t = kw['thickness'] if _t is None: _t = t if _t is not None: if not isinstance(_t, float): _t = util.get_float(_t) if _t < 0.0: raise ValueError, "Invalid thickness: %g" % _t if abs(_t - _st.getThickness()) < 1e-10: _t = None self.__style = _st self.__color = _col self.__linetype = _lt self.__thickness = _t def getDefaultStyle(cls): if cls.__defstyle is None: _s = style.Style(u'Default Style', linetype.Linetype(u'Solid', None), color.Color(0xffffff), 1.0) cls.__defstyle = _s return cls.__defstyle getDefaultStyle = classmethod(getDefaultStyle) def setDefaultStyle(cls, s): if not isinstance(s, style.Style): raise TypeError, "Invalid style: " + `type(s)` cls.__defstyle = s setDefaultStyle = classmethod(setDefaultStyle) def finish(self): self.__style = None self.__color = None self.__linetype = None self.__thickness = None super(GraphicObject, self).finish() def getStyle(self): """Get the Style of the GraphicObject. getStyle() Returns the current Style of an object. The values in the style may be overriden if any of the color, linetype, or thickness attributes are not None. """ return self.__style def setStyle(self, s): """Set the Style of the Object. setStyle(s) Setting the style of a GraphicObject unsets any overrides for the object. Setting the Style to None restores the default style. """ if self.isLocked(): raise RuntimeError, "Style change not allowed - objected locked." _s = s if _s is None: _s = self.getDefaultStyle() if not isinstance(_s, style.Style): raise TypeError, "Invalid style: " + `type(_s)` _cs = self.getStyle() if _cs != _s: _col = None if self.__color is not None: _col = self.__color _lt = None if self.__linetype is not None: _lt = self.__linetype _t = None if self.__thickness is not None: _t = self.__thickness self.startChange('style_changed') self.__style = _s self.__color = None self.__linetype = None self.__thickness = None self.endChange('style_changed') self.sendMessage('style_changed', _cs, _lt, _col, _t) self.modified() style = property(getStyle, setStyle, None, "Object Style.") def getColor(self): """Get the Color of the Object. getColor() """ _color = self.__color if _color is None: _color = self.__style.getColor() return _color def setColor(self, c=None): """Set the color of the object. setColor([c]) Setting the color overrides the value in the Style. Setting the color to None or invoking this method without arguments restores the color value defined in the Style. """ if self.isLocked(): raise RuntimeError, "Color change not allowed - object locked." _c = c if _c is not None: if not isinstance(_c, color.Color): _c = color.Color(c) _oc = self.getColor() if ((_c is None and self.__color is not None) or (_c is not None and _c != _oc)): self.startChange('color_changed') self.__color = _c self.endChange('color_changed') self.sendMessage('color_changed', _oc) self.modified() color = property(getColor, setColor, None, "Object color.") def getThickness(self): """Get the thickness of the GraphicObject. getThickness() """ _th = self.__thickness if _th is None: _th = self.__style.getThickness() return _th def setThickness(self, t=None): """Set the thickness of a object. setThickness([t]) Setting the thickness overrides the value in the Style. Setting the thickness to None, or invoking this method without an argument, restores the thickness value defined in the Style. """ if self.isLocked(): raise RuntimeError, "Thickness change not allowed - object locked." _t = t if _t is not None: _t = util.get_float(_t) if _t < 0.0: raise ValueError, "Invalid thickness: %g" % _t _ot = self.getThickness() if ((_t is None and self.__thickness is not None) or (_t is not None and abs(_t - _ot) > 1e-10)): self.startChange('thickness_changed') self.__thickness = _t self.endChange('thickness_changed') self.sendMessage('thickness_changed', _ot) self.modified() thickness = property(getThickness, setThickness, None, "Object thickness.") def getLinetype(self): """Get the Linetype of the object. getLinetype() """ _lt = self.__linetype if _lt is None: _lt = self.__style.getLinetype() return _lt def setLinetype(self, lt=None): """Set the Linetype of the GraphicObject. setLinetype([lt]) Setting the Linetype overrides the value in the Sytle. Setting the Linetype to None or invoking this method without arguments restores the linetype value defined in the Style. """ if self.isLocked(): raise RuntimeError, "Linetype change not allowed - object locked." _lt = lt if _lt is not None: if not isinstance(_lt, linetype.Linetype): raise TypeError, "Invalid linetype: " + `type(_lt)` _ol = self.getLinetype() if ((_lt is None and self.__linetype is not None) or (_lt is not None and _lt != _ol)): self.startChange('linetype_changed') self.__linetype = _lt self.endChange('linetype_changed') self.sendMessage('linetype_changed', _ol) self.modified() linetype = property(getLinetype, setLinetype, None, "Object Linetype.") def getGraphicValues(self): _l = _c = _t = None _s = self.__style.getStyleValues() if self.__linetype is not None: _name = self.__linetype.getName() _dash = self.__linetype.getList() _l = (_name, _dash) if self.__color is not None: _c = self.__color.getColors() if self.__thickness is not None: _t = self.__thickness return _s, _l, _c, _t def getValues(self): """Return values comprising the GraphicObject. getValues() This method extends the Subpart::getValues() method. """ _data = super(GraphicObject, self).getValues() _data.setValue('style', self.__style.getStyleValues()) if self.__color is not None: _data.setValue('color', self.__color.getColors()) if self.__linetype is not None: _lt = self.__linetype _data.setValue('linetype', (_lt.getName(), _lt.getList())) if self.__thickness is not None: _data.setValue('thickness', self.__thickness) return _data def sendsMessage(self, m): if m in GraphicObject.__messages: return True return super(GraphicObject, self).sendsMessage(m) # # GraphicObject history class # class GraphicObjectLog(entity.EntityLog): def __init__(self, obj): if not isinstance(obj, GraphicObject): raise TypeError, "Invalid GraphicObject: " + `type(obj)` super(GraphicObjectLog, self).__init__(obj) obj.connect('style_changed', self.__styleChanged) obj.connect('linetype_changed', self.__linetypeChanged) obj.connect('color_changed', self.__colorChanged) obj.connect('thickness_changed', self.__thicknessChanged) def __styleChanged(self, tb, *args): _alen = len(args) if _alen < 4: raise ValueError, "Invalid argument count: %d" % _alen _data = [] _style = args[0] if not isinstance(_style, style.Style): raise TypeError, "Invalid style type: " + `type(_style)` _data.append(_style.getStyleValues()) _lt = args[1] if _lt is None: _data.append(None) else: if not isinstance(_lt, linetype.Linetype): raise TypeError, "Invalid linetype type: " + `type(_lt)` _name = _lt.getName() _list = _lt.getList() _data.append((_name, _list)) _col = args[2] if _col is None: _data.append(None) else: if not isinstance(_col, color.Color): raise TypeError, "Invalid color type: " + `type(_col)` _data.append(_col.getColors()) _t = args[3] if _t is None: _data.append(None) else: if not isinstance(_t, float): raise TypeError, "Invalid thickness type: " + `type(_t)` _data.append(_t) self.saveUndoData('style_changed', tuple(_data)) def __linetypeChanged(self, tb, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _lt = args[0] if not isinstance(_lt, linetype.Linetype): raise TypeError, "Invalid linetype type: " + `type(_lt)` self.saveUndoData('linetype_changed', (_lt.getName(), _lt.getList())) def __colorChanged(self, tb, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _color = args[0] if not isinstance(_color, color.Color): raise TypeError, "Invalid color type: " + `type(_color)` self.saveUndoData('color_changed', _color.getColors()) def __thicknessChanged(self, tb, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _t = util.get_float(args[0]) if _t < 0.0: raise ValueError, "Invalid thickness: %g" % _t self.saveUndoData('thickness_changed', _t) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if len(args) == 0: raise ValueError, "No arguments to execute()" _obj = self.getObject() _op = args[0] _image = None _layer = _obj.getParent() if _layer is not None: _image = _layer.getParent() if _op == 'style_changed': if _image is None: raise RuntimeError, "Object not stored in an Image" if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _style = None _sv, _olt, _oc, _ot = args[1] _name, _ltdata, _col, _th = _sv for _s in _image.getImageEntities('style'): if _s.getName() != _name: continue _lt = _s.getLinetype() if (_lt.getName() != _ltdata[0] or _lt.getList() != _ltdata[1]): continue if _s.getColor().getColors() != _col: continue if abs(_s.getThickness() - _th) > 1e-10: continue _style = _s break _sdata = _obj.getGraphicValues() if _style is not None: self.ignore(_op) try: if undo: _obj.startUndo() try: _obj.setStyle(_style) finally: _obj.endUndo() else: _obj.startRedo() try: _obj.setStyle(_style) finally: _obj.endRedo() finally: self.receive(_op) # # restore values differing from the Style # if _olt is not None: _name, _list = _olt _lt = None for _l in _image.getImageEntities('linetype'): if (_l.getName() == _name and _l.getList() == _list): _lt = _l break _obj.mute() try: _obj.setLinetype(_lt) finally: _obj.unmute() if _oc is not None: _col = None for _c in _image.getImageEntities('color'): if _c.getColors() == _oc: _col = _c break _obj.mute() try: _obj.setColor(_col) finally: _obj.unmute() if _ot is not None: _obj.mute() try: _obj.setThickness(_ot) finally: _obj.unmute() self.saveData(undo, _op, _sdata) elif _op == 'linetype_changed': if _image is None: raise RuntimeError, "Object not stored in an Image" if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _lt = _obj.getLinetype() _sdata = (_lt.getName(), _lt.getList()) self.ignore(_op) try: _name, _list = args[1] _lt = None for _l in _image.getImageEntities('linetype'): if (_l.getName() == _name and _l.getList() == _list): _lt = _l break if undo: _obj.startUndo() try: _obj.setLinetype(_lt) finally: _obj.endUndo() else: _obj.startRedo() try: _obj.setLinetype(_lt) finally: _obj.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'color_changed': if _image is None: raise RuntimeError, "Object not stored in an Image" if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _sdata = _obj.getColor().getColors() self.ignore(_op) try: _col = None for _c in _image.getImageEntities('color'): if _c.getColors() == args[1]: _col = _c break if undo: _obj.startUndo() try: _obj.setColor(_col) finally: _obj.endUndo() else: _obj.startRedo() try: _obj.setColor(_col) finally: _obj.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'thickness_changed': if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _sdata = _obj.getThickness() self.ignore(_op) try: _t = args[1] if undo: _obj.startUndo() try: _obj.setThickness(_t) finally: _obj.endUndo() else: _obj.startRedo() try: _obj.setThickness(_t) finally: _obj.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) else: super(GraphicObjectLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/dimtrees.py0000644000175000017500000003601111307666657020526 0ustar matteomatteo# # Copyright (c) 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # quadtree storage for dimension objects # import math from PythonCAD.Generic import dimension from PythonCAD.Generic import quadtree from PythonCAD.Generic import point from PythonCAD.Generic import circle from PythonCAD.Generic import arc from PythonCAD.Generic import tolerance from PythonCAD.Generic import util # # Dimension storage # class DimQuadtree(quadtree.Quadtree): def __init__(self): super(DimQuadtree, self).__init__() def addObject(self, obj): if not isinstance(obj, dimension.Dimension): raise TypeError, "Invalid Dimension object: " + `obj` if obj in self: return _dxmin, _dymin, _dxmax, _dymax = obj.getBounds() _node = self.getTreeRoot() _bounds = _node.getBoundary() _xmin = _ymin = _xmax = _ymax = None _resize = False if _bounds is None: # first node in tree _resize = True _xmin = _dxmin - 1.0 _ymin = _dymin - 1.0 _xmax = _dxmax + 1.0 _ymax = _dymax + 1.0 else: _xmin, _ymin, _xmax, _ymax = _bounds if _dxmin < _xmin: _xmin = _dxmin - 1.0 _resize = True if _dxmax > _xmax: _xmax = _dxmax + 1.0 _resize = True if _dymin < _ymin: _ymin = _dymin - 1.0 _resize = True if _dymax > _ymax: _ymax = _dymax + 1.0 _resize = True if _resize: self.resize(_xmin, _ymin, _xmax, _ymax) _node = self.getTreeRoot() _nodes = [_node] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_dxmin > _xmax) or (_dymin > _ymax) or (_dxmax < _xmin) or (_dymax < _ymin)): continue if _node.hasSubnodes(): _xmid = (_xmin + _xmax)/2.0 _ymid = (_ymin + _ymax)/2.0 _ne = _nw = _sw = _se = True if _dxmax < _xmid: # dim on left side _ne = _se = False if _dxmin > _xmid: # dim on right side _nw = _sw = False if _dymax < _ymid: # dim below _nw = _ne = False if _dymin > _ymid: # dim above _sw = _se = False if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: if obj.inRegion(_xmin, _ymin, _xmax, _ymax): _node.addObject(obj) super(DimQuadtree, self).addObject(obj) obj.connect('moved', self._moveDim) def delObject(self, obj): if obj not in self: return _dxmin, _dymin, _dxmax, _dymax = obj.getBounds() _xmin = _ymin = _xmax = _ymax = None _pdict = {} _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_dxmin > _xmax) or (_dxmax < _xmin) or (_dymin > _ymax) or (_dymax < _ymin)): continue if _node.hasSubnodes(): _xmid = (_xmin + _xmax)/2.0 _ymid = (_ymin + _ymax)/2.0 _ne = _nw = _sw = _se = True if _dxmax < _xmid: # dim on left side _ne = _se = False if _dxmin > _xmid: # dim on right side _nw = _sw = False if _dymax < _ymid: # dim below _nw = _ne = False if _dymin > _ymid: # dim above _sw = _se = False if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: _node.delObject(obj) # dim may not be in the node ... _parent = _node.getParent() if _parent is not None: _pid = id(_parent) if _pid not in _pdict: _pdict[_pid] = _parent super(DimQuadtree, self).delObject(obj) obj.disconnect(self) for _parent in _pdict.values(): self.purgeSubnodes(_parent) def find(self, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _p1 = args[0] if not isinstance(_p1, point.Point): raise TypeError, "Invalid point: " + `type(_p1)` _p2 = args[1] if not isinstance(_p2, point.Point): raise TypeError, "Invalid point: " + `type(_p2)` _dims = [] if len(self) > 0: _l1 = _p1.getParent() _l2 = _p2.getParent() for _dim in self.getObjects(): _dp1, _dp2 = _dim.getDimPoints() _dl1 = _dp1.getParent() _dl2 = _dp2.getParent() if ((_l1 is _dl1) and (_p1 is _dp1) and (_l2 is _dl2) and (_p2 is _dp2)): _dims.append(_dim) if ((_l1 is _dl2) and (_p1 is _dp2) and (_l2 is _dl1) and (_p2 is _dp1)): _dims.append(_dim) return _dims def _moveDim(self, obj, *args): if obj not in self: raise ValueError, "Dimension not stored in Quadtree: " + `obj` _alen = len(args) if _alen < 4: raise ValueError, "Invalid argument count: %d" % _alen _dxmin = util.get_float(args[0]) _dymin = util.get_float(args[1]) _dxmax = util.get_float(args[2]) _dymax = util.get_float(args[3]) _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_dxmin > _xmax) or (_dxmax < _xmin) or (_dymin > _ymax) or (_dymax < _ymin)): continue if _node.hasSubnodes(): _xmid = (_xmin + _xmax)/2.0 _ymid = (_ymin + _ymax)/2.0 _ne = _nw = _sw = _se = True if _dxmax < _xmid: # dim on left side _ne = _se = False if _dxmin > _xmid: # dim on right side _nw = _sw = False if _dymax < _ymid: # dim below _nw = _ne = False if _dymin > _ymid: # dim above _sw = _se = False if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: _node.delObject(obj) # dim may not be in node ... super(DimQuadtree, self).delObject(obj) obj.disconnect(self) self.addObject(obj) def getClosest(self, x, y, tol=tolerance.TOL): _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _dim = _tsep = None _bailout = False _ddict = {} _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_x < (_xmin - _t)) or (_x > (_xmax + _t)) or (_y < (_ymin - _t)) or (_y > (_ymax + _t))): continue if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) else: for _d in _node.getObjects(): _did = id(_d) if _did not in _ddict: _pt = _d.mapCoords(_x, _y, _t) if _pt is not None: _px = _py = _pt _sep = math.hypot((_px - _x), (_py - _y)) if _tsep is None: _tsep = _sep _dim = _d else: if _sep < _tsep: _tsep = _sep _dim = _d if _dim is not None and _sep < 1e-10: _bailout = True break if _bailout: break return _dim def getInRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _dims = [] if not len(self): return _dims _nodes = [self.getTreeRoot()] _ddict = {} while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): for _subnode in _node.getSubnodes(): _sxmin, _symin, _sxmax, _symax = _subnode.getBoundary() if ((_sxmin > _xmax) or (_symin > _ymax) or (_sxmax < _xmin) or (_symax < _ymin)): continue _nodes.append(_subnode) else: for _dim in _node.getObjects(): _dimid = id(_dim) if _dimid not in _ddict: if _dim.inRegion(_xmin, _ymin, _xmax, _ymax): _dims.append(_dim) _ddict[_dimid] = True return _dims # # LinearDimension Quadtree # class LDimQuadtree(DimQuadtree): def __init__(self): super(LDimQuadtree, self).__init__() def addObject(self, obj): if not isinstance(obj, dimension.LinearDimension): raise TypeError, "Invalid LinearDimension object: " + `obj` super(LDimQuadtree, self).addObject(obj) # # HorizontalDimension Quadtree # class HDimQuadtree(DimQuadtree): def __init__(self): super(HDimQuadtree, self).__init__() def addObject(self, obj): if not isinstance(obj, dimension.HorizontalDimension): raise TypeError, "Invalid HorizontalDimension object: " + `obj` super(HDimQuadtree, self).addObject(obj) # # VerticalDimension Quadtree # class VDimQuadtree(DimQuadtree): def __init__(self): super(VDimQuadtree, self).__init__() def addObject(self, obj): if not isinstance(obj, dimension.VerticalDimension): raise TypeError, "Invalid VerticalDimension object: " + `obj` super(VDimQuadtree, self).addObject(obj) # # RadialDimension Quadtree # class RDimQuadtree(DimQuadtree): def __init__(self): super(RDimQuadtree, self).__init__() def addObject(self, obj): if not isinstance(obj, dimension.RadialDimension): raise TypeError, "Invalid RadalDimension object: " + `obj` super(RDimQuadtree, self).addObject(obj) def find(self, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _c1 = args[1] if not isinstance(_c1, (circle.Circle, arc.Arc)): raise TypeError, "Invalid circle/arc: " + `type(_c1)` _dims = [] if len(self) > 0: _l1 = _c1.getParent() for _rdim in self.getObjects(): _rc = _rdim.getDimCircle() _rl = _rc.getParent() if _rl is _l1 and _rc is _c1: _dims.append(_dim) return _dims # # AngularDimension Quadtree # class ADimQuadtree(DimQuadtree): def __init__(self): super(ADimQuadtree, self).__init__() def addObject(self, obj): if not isinstance(obj, dimension.AngularDimension): raise TypeError, "Invalid AngularDimension object: " + `obj` super(ADimQuadtree, self).addObject(obj) def find(self, *args): _alen = len(args) if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _vp = args[0] if not isinstance(_vp, point.Point): raise TypeError, "Invalid point: " + `type(_vp)` _p1 = args[1] if not isinstance(_p1, point.Point): raise TypeError, "Invalid point: " + `type(_p1)` _p2 = args[2] if not isinstance(_p2, point.Point): raise TypeError, "Invalid point: " + `type(_p2)` _dims = [] if len(self) > 0: _vl = _vp.getParent() _l1 = _p1.getParent() _l2 = _p2.getParent() for _adim in self.getObjects(): _avp, _ap1, _ap2 = _adim.getDimPoints() _avl = _avp.getParent() _al1 = _ap1.getParent() _al2 = _ap2.getParent() if ((_vl is _avl) and (_vp is _avp) and (_l1 is _al1) and (_p1 is _ap1) and (_l2 is _al2) and (_p2 is _ap2)): _dims.append(_dim) if ((_vl is _avl) and (_vp is _avp) and (_l1 is _al2) and (_p1 is _ap2) and (_l2 is _al1) and (_p2 is _ap1)): _dims.append(_dim) return _dims PythonCAD-DS1-R37/PythonCAD/Generic/logger.py0000644000175000017500000000756111307666657020201 0ustar matteomatteo# # Copyright (c) 2004, 2005 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # base class for entity history storage and undo/redo mechanisms # from PythonCAD.Generic import message class Logger(message.Messenger): def __init__(self): super(Logger, self).__init__() self.__undo = None self.__redo = None self.__inredo = False self.__undone = False def detatch(self): pass def saveUndoData(self, *data): if self.__undo is None: self.__undo = [] # print "saveUndoData: " + str(data) self.__undo.append(data) if self.__undone and not self.__inredo: self.__redo = None self.__undone = False def printUndoData(self): print "Undo stack ..." if self.__undo is None: print "None" else: for _d in self.__undo: print _d def getUndoData(self): _data = None if self.__undo is not None: _data = self.__undo.pop() if len(self.__undo) == 0: self.__undo = None return _data def undo(self): if self.__undo is not None: _data = self.__undo.pop() if len(self.__undo) == 0: self.__undo = None self.execute(True, *_data) self.__undone = True def saveRedoData(self, *data): if self.__redo is None: self.__redo = [] # print "saveRedoData: " + str(data) self.__redo.append(data) def getRedoData(self): _data = None if self.__redo is not None: _data = self.__redo.pop() if len(self.__redo) == 0: self.__redo = None return _data def printRedoData(self): print "Redo stack ..." if self.__redo is None: print "None" else: for _d in self.__redo: print _d def redo(self): if self.__redo is not None: _data = self.__redo.pop() if len(self.__redo) == 0: self.__redo = None self.__inredo = True try: self.execute(False, *_data) finally: self.__inredo = False def execute(self, undo, *args): pass def clear(self): self.__undo = None self.__redo = None def transferData(self, log): if not isinstance(log, Logger): raise TypeError, "Invalid Logger: " + `log` _undo = [] _redo = [] _data = log.getUndoData() while _data is not None: _undo.append(_data) _data = log.getUndoData() if len(_undo): if self.__undo is None: self.__undo = [] _undo.reverse() for _data in _undo: self.__undo.append(_data) _data = log.getRedoData() while _data is not None: _redo.append(_data) _data = log.getRedoData() if len(_redo): if self.__redo is None: self.__redo = [] _redo.reverse() for _data in _redo: self.__redo.append(_data) PythonCAD-DS1-R37/PythonCAD/Generic/extFormat.py0000644000175000017500000000432311307666732020656 0ustar matteomatteo# # Copyright (c) 2009 Matteo Boscolo # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the termscl_bo of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # import os.path class ExtFormat: """ This class provide base class for hendly different drawing format in pythoncad """ def __init__(self,gtkImage): """ Default Constructor """ self.__Tool=gtkImage.getTool() self.__GtkImage=gtkImage def openFile(self,fileName): """ Open a generic file """ path,exte=os.path.splitext( fileName ) if( exte.upper()==".dxf".upper()): dxf=Dxf(gtkImage,fileName) class DrawingFile: """ This Class provide base capability to read write a file """ def __init__(self,fileName): """ Base Constructor """ self.__fn=fileName self.__fb=None def ReadAsci(self): """ Read a generic file """ self.__fb=open(self.__fn,'r') def FileObject(self): """ Return the file opened """ if(self.__fb!=None): return self.__fb else: return None class Dxf(DrawingFile): """ this class provide dxf reading/writing capability """ def __init__(self,gtkImage): """ Default Constructor """ self.__gtkI=gtkImage def OpenFile(fileName): """ Open The file and create The entity in pythonCad """ self.ReadAsci(); fo=self.FileObject() if(fo!=None): "Implement here your methon" PythonCAD-DS1-R37/PythonCAD/Generic/delete.py0000644000175000017500000001113211307666657020151 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # Deleting objects # from PythonCAD.Generic.point import Point from PythonCAD.Generic.segment import Segment from PythonCAD.Generic.circle import Circle from PythonCAD.Generic.arc import Arc from PythonCAD.Generic.hcline import HCLine from PythonCAD.Generic.vcline import VCLine from PythonCAD.Generic.acline import ACLine from PythonCAD.Generic.segjoint import Chamfer, Fillet from PythonCAD.Generic.cline import CLine from PythonCAD.Generic.ccircle import CCircle from PythonCAD.Generic.leader import Leader from PythonCAD.Generic.polyline import Polyline from PythonCAD.Generic.text import TextBlock from PythonCAD.Generic.dimension import DimString from PythonCAD.Generic.layer import Layer def delete_objects(objlist): """Remove a list of objects from the parent Layer. delete_objects(objlist) The objlist argument must be either a tuple or list. """ if not isinstance(objlist, (list, tuple)): raise TypeError, "Invalid object list: " + `type(objlist)` _delobjs = [] for _obj in objlist: if not isinstance(_obj, DimString): _parent = _obj.getParent() if _parent is not None and isinstance(_parent, Layer): _delobjs.append(_obj) _objdict = {} for _obj in _delobjs: _objdict[id(_obj)] = True for _obj in _delobjs: if isinstance(_obj, Point): continue elif isinstance(_obj, Segment): _p1, _p2 = _obj.getEndpoints() _pid = id(_p1) if _pid in _objdict: _objdict[_pid] = False _pid = id(_p2) if _pid in _objdict: _objdict[_pid] = False elif isinstance(_obj, Arc): _cp = _obj.getCenter() _pid = id(_cp) if _pid in _objdict: _objdict[_pid] = False _parent = _obj.getParent() for _ep in _obj.getEndpoints(): _lp = None _pts = _parent.find('point', _ep[0], _ep[1]) for _pt in _pts: for _user in _pt.getUsers(): if _user is _obj: _lp = _pt break if _lp is None: raise RuntimeError, "Arc endpoint missing: " + str(_ep) _pid = id(_lp) if _pid in _objdict: _objdict[_pid] = False elif isinstance(_obj, (Circle, CCircle)): _cp = _obj.getCenter() _pid = id(_cp) if _pid in _objdict: _objdict[_pid] = False elif isinstance(_obj, (HCLine, VCLine, ACLine)): _lp = _obj.getLocation() _pid = id(_lp) if _pid in _objdict: _objdict[_pid] = False elif isinstance(_obj, CLine): _p1, _p2 = _obj.getKeypoints() _pid = id(_p1) if _pid in _objdict: _objdict[_pid] = False _pid = id(_p2) if _pid in _objdict: _objdict[_pid] = False elif isinstance(_obj, (Chamfer, Fillet)): continue # chamfers/fillets do not delete attached segments elif isinstance(_obj, (Leader, Polyline)): for _pt in _obj.getPoints(): _pid = id(_pt) if _pid in _objdict: _objdict[_pid] = False elif isinstance(_obj, TextBlock): continue else: pass for _obj in _delobjs: if _objdict[id(_obj)]: _parent = _obj.getParent() # # if the parent is None then the object has already been # deleted as a result of earlier deletions such as a # dimension being removed when the referenced points were # removed # if _parent is not None: _parent.delObject(_obj) PythonCAD-DS1-R37/PythonCAD/Generic/ccircle.py0000644000175000017500000006332311307666732020316 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # construction circle class # from __future__ import generators import math from PythonCAD.Generic import point from PythonCAD.Generic import conobject from PythonCAD.Generic import tolerance from PythonCAD.Generic import quadtree from PythonCAD.Generic import util from PythonCAD.Generic.pyGeoLib import Vector class CCircle(conobject.ConstructionObject): """A class for contruction circles A CCircle has two attributes: center: A Point object radius: The CCircle's radius A CCircle has the following methods: {get/set}Center(): Get/Set the center Point of a CCircle. {get/set}Radius(): Get/Set the radius of a CCircle. move(): Move the CCircle. circumference(): Get the CCircle's circumference. area(): Get the CCircle's area. mapCoords(): Find the nearest Point on the CCircle to a coordinate pair. inRegion(): Returns whether or not a CCircle can be seen in a bounded area. clone(): Return an indentical copy of a CCircle. """ __messages = { 'moved' : True, 'center_changed' : True, 'radius_changed' : True, } def __init__(self, center, radius, **kw): """Initialize a CCircle. CCircle(center, radius) The center should be a Point, or a two-entry tuple of floats, and the radius should be a float greater than 0. """ _cp = center if not isinstance(_cp, point.Point): _cp = point.Point(center) _r = util.get_float(radius) if not _r > 0.0: raise ValueError, "Invalid radius: %g" % _r super(CCircle, self).__init__(**kw) self.__radius = _r self.__center = _cp _cp.connect('moved', self.__movePoint) _cp.connect('change_pending', self.__pointChangePending) _cp.connect('change_complete', self.__pointChangeComplete) _cp.storeUser(self) def __eq__(self, obj): """Compare a CCircle to another for equality. """ if not isinstance(obj, CCircle): return False if obj is self: return True _val = False if self.__center == obj.getCenter(): if abs(self.__radius - obj.getRadius()) < 1e-10: _val = True return _val def __ne__(self, obj): """Compare a CCircle to another for inequality. """ if not isinstance(obj, CCircle): return True if obj is self: return False _val = True if self.__center == obj.getCenter(): if abs(self.__radius - obj.getRadius()) < 1e-10: _val = False return _val def finish(self): self.__center.disconnect(self) self.__center.freeUser(self) self.__center = self.__radius = None super(CCircle, self).finish() def getValues(self): _data = super(CCircle, self).getValues() _data.setValue('type', 'ccircle') _data.setValue('center', self.__center.getID()) _data.setValue('radius', self.__radius) return _data def getCenter(self): """Return the center Point of the CCircle. getCenter() """ return self.__center def setCenter(self, c): """Set the center Point of the CCircle. setCenter(c) The argument must be a Point or a tuple containing two float values. """ if self.isLocked(): raise RuntimeError, "Setting center not allowed - object locked." _cp = self.__center if not isinstance(c, point.Point): raise TypeError, "Invalid center point: " + `type(c)` if _cp is not c: _cp.disconnect(self) _cp.freeUser(self) self.startChange('center_changed') self.__center = c self.endChange('center_changed') self.sendMessage('center_changed', _cp) c.connect('moved', self.__movePoint) c.connect('change_pending', self.__pointChangePending) c.connect('change_complete', self.__pointChangeComplete) c.storeUser(self) if abs(_cp.x - c.x) > 1e-10 or abs(_cp.y - c.y) > 1e-10: self.sendMessage('moved', _cp.x, _cp.y, self.__radius) self.modified() center = property(getCenter, setCenter, None, "CCircle center") def getRadius(self): """Return the radius of the the CCircle. getRadius() """ return self.__radius def setRadius(self, radius): """Set the radius of the CCircle. setRadius(radius) The argument must be float value greater than 0. """ if self.isLocked(): raise RuntimeError, "Setting radius not allowed - object locked." _r = util.get_float(radius) if not _r > 0.0: raise ValueError, "Invalid radius: %g" % _r _cr = self.__radius if abs(_cr - _r) > 1e-10: self.startChange('radius_changed') self.__radius = _r self.endChange('radius_changed') self.sendMessage('radius_changed', _cr) _cx, _cy = self.__center.getCoords() self.sendMessage('moved', _cx, _cy, _cr) self.modified() radius = property(getRadius, setRadius, None, "CCircle radius") def move(self, dx, dy): """Move a CCircle. move(dx, dy) The first argument gives the x-coordinate displacement, and the second gives the y-coordinate displacement. Both values should be floats. """ if self.isLocked(): raise RuntimeError, "Setting radius not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _x, _y = self.__center.getCoords() self.ignore('moved') try: self.__center.move(_dx, _dy) finally: self.receive('moved') self.sendMessage('moved', _x, _y, self.__radius) def circumference(self): """Return the circumference of the CCircle. circumference() """ return 2.0 * math.pi * self.__radius def area(self): """Return the area enclosed by the CCircle. area() """ return math.pi * pow(self.__radius, 2) def mapCoords(self, x, y, tol=tolerance.TOL): """Return the nearest Point on the CCircle to a coordinate pair. mapCoords(x, y[, tol]) The function has two required arguments: x: A Float value giving the x-coordinate y: A Float value giving the y-coordinate There is a single optional argument: tol: A float value equal or greater than 0.0 This function is used to map a possibly near-by coordinate pair to an actual Point on the CCircle. If the distance between the actual Point and the coordinates used as an argument is less than the tolerance, the actual Point is returned. Otherwise, this function returns None. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _cx, _cy = self.__center.getCoords() _r = self.__radius _dist = math.hypot((_x - _cx), (_y - _cy)) if abs(_dist - _r) < _t: _angle = math.atan2((_y - _cy),(_x - _cx)) _xoff = _r * math.cos(_angle) _yoff = _r * math.sin(_angle) return (_cx + _xoff), (_cy + _yoff) return None def GetTangentPoint(self,x,y,outx,outy): """ Get the tangent from an axternal point args: x,y is a point near the circle xout,yout is a point far from the circle return: a tuple(x,y,x1,xy) that define the tangent line """ firstPoint=point.Point(x,y) fromPoint=point.Point(outx,outy) twoPointDistance=self.__center.Dist(fromPoint) if(twoPointDistancecy): #stupid situation rightAngle=-rightAngle posAngle=rightAngle+tgAngle negAngle=rightAngle-tgAngle #Compute the Positive Tangent xCord=math.cos(posAngle) yCord=math.sin(posAngle) dirPoint=point.Point(xCord,yCord)#Versor that point at the tangentPoint ver=Vector(originPoint,dirPoint) ver.Mult(tanMod) tangVectorPoint=ver.Point() posPoint=point.Point(tangVectorPoint+(outx,outy)) #Compute the Negative Tangent xCord=math.cos(negAngle) yCord=math.sin(negAngle) dirPoint=point.Point(xCord,yCord)#Versor that point at the tangentPoint ver=Vector(originPoint,dirPoint) ver.Mult(tanMod) tangVectorPoint=ver.Point() negPoint=point.Point(tangVectorPoint+(outx,outy)) if firstPoint.Dist(posPoint) _xmax) or ((_yc - _r) > _ymax) or ((_xc + _r) < _xmin) or ((_yc + _r) < _ymin)): return False _val = False _bits = 0 # # calculate distances from center to region boundary # if abs(_xc - _xmin) < _r: _bits = _bits | 1 # left edge if abs(_xc - _xmax) < _r: _bits = _bits | 2 # right edge if abs(_yc - _ymin) < _r: _bits = _bits | 4 # bottom edge if abs(_yc - _ymax) < _r: _bits = _bits | 8 # top edge if _bits == 0: # # if the ccircle center is in region then the entire # ccircle is visible since the distance from the center # to any edge is greater than the radius. If the center # is not in the region then the ccircle is not visible in # the region because the distance to any edge is greater # than the radius, and so one of the bits should have been # set ... # if ((_xmin < _xc < _xmax) and (_ymin < _yc < _ymax)): _val = True else: _val = True # # calculate distance to corners of region # if math.hypot((_xc - _xmin), (_yc - _ymax)) < _r: _bits = _bits | 0x10 # upper left if math.hypot((_xc - _xmax), (_yc - _ymin)) < _r: _bits = _bits | 0x20 # lower right if math.hypot((_xc - _xmin), (_yc - _ymin)) < _r: _bits = _bits | 0x40 # lower left if math.hypot((_xc - _xmax), (_yc - _ymax)) < _r: _bits = _bits | 0x80 # upper right # # if all bits are set then distance from ccircle center # to region endpoints is less than radius - ccircle # entirely outside the region # if _bits == 0xff or fully: _val = False return _val def __pointChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.startChange('moved') def __pointChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.endChange('moved') def __movePoint(self, p, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _cp = self.__center if p is not _cp: raise ValueError, "Point is not ccircle center: " + `p` _x, _y = _cp.getCoords() self.sendMessage('moved', _x, _y, self.__radius) def clone(self): """Create an identical copy of a CCircle clone() """ _cp = self.__center.clone() return CCircle(_cp, self.__radius) def sendsMessage(self, m): if m in CCircle.__messages: return True return super(CCircle, self).sendsMessage(m) # # Quadtree CCircle storage # class CCircleQuadtree(quadtree.Quadtree): def __init__(self): super(CCircleQuadtree, self).__init__() def getNodes(self, *args): _alen = len(args) if _alen != 3: raise ValueError, "Expected 3 arguments, got %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _r = util.get_float(args[2]) _cxmin = _x - _r _cxmax = _x + _r _cymin = _y - _r _cymax = _y + _r _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_cxmin > _xmax) or (_cxmax < _xmin) or (_cymin > _ymax) or (_cymax < _ymin)): continue if _node.hasSubnodes(): _xmid = (_xmin + _xmax)/2.0 _ymid = (_ymin + _ymax)/2.0 _ne = _nw = _sw = _se = True if _cxmax < _xmid: # circle on left side _ne = _se = False if _cxmin > _xmid: # circle on right side _nw = _sw = False if _cymax < _ymid: # circle below _nw = _ne = False if _cymin > _ymid: # circle above _sw = _se = False if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: yield _node def addObject(self, obj): if not isinstance(obj, CCircle): raise TypeError, "Invalid CCircle object: " + `type(obj)` if obj in self: return _x, _y = obj.getCenter().getCoords() _r = obj.getRadius() _node = self.getTreeRoot() _bounds = _node.getBoundary() _xmin = _ymin = _xmax = _ymax = None _cxmin = _x - _r _cxmax = _x + _r _cymin = _y - _r _cymax = _y + _r _resize = False if _bounds is None: # first node in tree _resize = True _xmin = _cxmin - 1.0 _ymin = _cymin - 1.0 _xmax = _cxmax + 1.0 _ymax = _cymax + 1.0 else: _xmin, _ymin, _xmax, _ymax = _bounds if _cxmin < _xmin: _xmin = _cxmin - 1.0 _resize = True if _cxmax > _xmax: _xmax = _cxmax + 1.0 _resize = True if _cymin < _ymin: _ymin = _cymin - 1.0 _resize = True if _cymax > _ymax: _ymax = _cymax + 1.0 _resize = True if _resize: self.resize(_xmin, _ymin, _xmax, _ymax) for _node in self.getNodes(_x, _y, _r): _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if obj.inRegion(_xmin, _ymin, _xmax, _ymax): _node.addObject(obj) super(CCircleQuadtree, self).addObject(obj) obj.connect('moved', self._moveCCircle) def delObject(self, obj): if obj not in self: return _x, _y = obj.getCenter().getCoords() _r = obj.getRadius() _pdict = {} for _node in self.getNodes(_x, _y, _r): _node.delObject(obj) # ccircle may not be in the node ... _parent = _node.getParent() if _parent is not None: _pid = id(_parent) if _pid not in _pdict: _pdict[_pid] = _parent super(CCircleQuadtree, self).delObject(obj) obj.disconnect(self) for _parent in _pdict.values(): self.purgeSubnodes(_parent) def find(self, *args): _alen = len(args) if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _r = util.get_float(args[2]) _t = tolerance.TOL if _alen > 3: _t = tolerance.toltest(args[4]) _xmin = _x - _r - _t _xmax = _x + _r + _t _ymin = _y - _r - _t _ymax = _y + _r + _t _ccircles = [] for _ccirc in self.getInRegion(_xmin, _ymin, _xmax, _ymax): _cx, _cy = _ccirc.getCenter().getCoords() if ((abs(_cx - _x) < _t) and (abs(_cy - _y) < _t) and (abs(_ccirc.getRadius() - _r) < _t)): _ccircles.append(_ccirc) return _ccircles def _moveCCircle(self, obj, *args): if obj not in self: raise ValueError, "CCircle not stored in Quadtree: " + `obj` _alen = len(args) if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _r = util.get_float(args[2]) for _node in self.getNodes(_x, _y, _r): _node.delObject(obj) # ccircle may not be in node ... super(CCircleQuadtree, self).delObject(obj) obj.disconnect(self) self.addObject(obj) def getClosest(self, x, y, tol=tolerance.TOL): _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _circ = _tsep = None _bailout = False _cdict = {} _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_x < (_xmin - _t)) or (_x > (_xmax + _t)) or (_y < (_ymin - _t)) or (_y > (_ymax + _t))): continue if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) else: for _c in _node.getObjects(): _cid = id(_c) if _cid not in _cdict: _cp = _c.mapCoords(_x, _y, _t) if _cp is not None: _cx, _cy = _cp _sep = math.hypot((_cx - _x), (_cy - _y)) if _tsep is None: _tsep = _sep _circ = _c else: if _sep < _tsep: _tsep = _sep _circ = _c if _sep < 1e-10 and _circ is not None: _bailout = True break if _bailout: break return _circ def getInRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _circs = [] if not len(self): return _circs _nodes = [self.getTreeRoot()] _cdict = {} while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): for _subnode in _node.getSubnodes(): _sxmin, _symin, _sxmax, _symax = _subnode.getBoundary() if ((_sxmin > _xmax) or (_symin > _ymax) or (_sxmax < _xmin) or (_symax < _ymin)): continue _nodes.append(_subnode) else: for _circ in _node.getObjects(): _cid = id(_circ) if _cid not in _cdict: if _circ.inRegion(_xmin, _ymin, _xmax, _ymax): _circs.append(_circ) _cdict[_cid] = True return _circs # # CCircle history class # class CCircleLog(conobject.ConstructionObjectLog): def __init__(self, c): if not isinstance(c, CCircle): raise TypeError, "Invalid CCircle object: " + `type(c)` super(CCircleLog, self).__init__(c) c.connect('center_changed' ,self._centerChange) c.connect('radius_changed', self._radiusChange) def _radiusChange(self, c, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _r = args[0] if not isinstance(_r, float): raise TypeError, "Unexpected type for radius: " + `type(_r)` self.saveUndoData('radius_changed', _r) def _centerChange(self, c, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _old = args[0] if not isinstance(_old, point.Point): raise TypeError, "Invalid old center point: " + `type(_old)` self.saveUndoData('center_changed', _old.getID()) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if _alen == 0: raise ValueError, "No arguments to execute()" _c = self.getObject() _cp = _c.getCenter() _op = args[0] if _op == 'radius_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _r = args[1] if not isinstance(_r, float): raise TypeError, "Unexpected type for radius: " + `type(_r)` _sdata = _c.getRadius() self.ignore(_op) try: if undo: _c.startUndo() try: _c.setRadius(_r) finally: _c.endUndo() else: _c.startRedo() try: _c.setRadius(_r) finally: _c.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'center_changed': if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _oid = args[1] _parent = _c.getParent() if _parent is None: raise ValueError, "CCircle has no parent - cannot undo" _pt = _parent.getObject(_oid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "Center point missing: id=%d" % _oid _sdata = _cp.getID() self.ignore(_op) try: if undo: _c.startUndo() try: _c.setCenter(_pt) finally: _c.endUndo() else: _c.startRedo() try: _c.setCenter(_pt) finally: _c.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) else: super(CCircleLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/text.py0000644000175000017500000016254411307666657017711 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # basic text functionality # import math import types from PythonCAD.Generic import color from PythonCAD.Generic import entity from PythonCAD.Generic import util def font_style_string(style): """Return a text string for the font style. font_style_string(style) """ if style == TextStyle.FONT_NORMAL: _str = 'normal' elif style == TextStyle.FONT_OBLIQUE: _str = 'oblique' elif style == TextStyle.FONT_ITALIC: _str = 'italic' else: raise ValueError, "Unknown font style: " + str(style) return _str def font_weight_string(weight): """Return a text string for the font weight. font_weight_string(weight) """ if weight == TextStyle.WEIGHT_NORMAL: _str = 'normal' elif weight == TextStyle.WEIGHT_LIGHT: _str = 'light' elif weight == TextStyle.WEIGHT_BOLD: _str = 'bold' elif weight == TextStyle.WEIGHT_HEAVY: _str = 'heavy' else: raise ValueError, "Unknown font weight: " + str(weight) return _str # # the font_prop_map and parse_font() should be moved as # they are GTK specific ... # font_prop_map = { 'Oblique' : 'style', 'Italic' : 'style', 'Ultra-Light' : 'weight', 'Light' : 'weight', 'Medium' : 'weight', 'Semi-Bold' : 'weight', 'Bold' : 'weight', 'Ultra-Bold' : 'weight', 'Heavy' : 'weight', 'Ultra-Condensed' : 'stretch', 'Extra-Condensed' : 'stretch', 'Condensed' : 'stretch', 'Semi-Condensed' : 'stretch', 'Semi-Expanded' : 'stretch', 'Expanded' : 'stretch', 'Extra-Expanded' : 'stretch', 'Ultra-Expanded' : 'stretch', } def parse_font(fontstr): _size = 12 _weight = 0 # NORMAL _style = 0 # NORMAL _stretch = 0# NORMAL _family = 'Sans' if fontstr != '': _fontlist = fontstr.split() _fontlist.reverse() if _fontlist[0].isdigit(): _sz = _fontlist.pop(0) _size = int(_sz) while (_fontlist[0] in font_prop_map): _prop = _fontlist.pop(0) _item = font_prop_map[_prop] # print "prop: " + _prop # print "item: " + _item if _item == 'style': if _prop == 'Oblique': _style = 1 elif _prop == 'Italic': _style = 2 else: _style = 0 # NORMAL # default elif _item == 'weight': if (_prop == 'Ultra-Light' or _prop == 'Light' or _prop == 'Medium'): _weight = 1 elif (_prop == 'Semi-Bold' or _prop == 'Bold'): _weight = 2 elif (_prop == 'Ultra-Bold' or _prop == 'Heavy'): _weight = 3 else: _weight = 0 # NORMAL elif _item == 'stretch': _stretch = _prop # fixme - add stretching bits else: raise ValueError, "Unknown font property: " + _item _fontlist.reverse() if len(_fontlist): _family = ' '.join(_fontlist) return (_family, _style, _weight, _stretch, _size) # # Style class for a text block # class TextStyle(object): """A class for describing text properties. A TextStyle object has the following attributes: family: The font family style: The font style weight: The font weight color: The font color alignment: Text positioning relative to the location angle: Angular position of the text A TextStyle object has the following methods: getFamily(): Get the font family. getStyle(): Get the font style. getWeight(): Get the font weight. getColor(): Get the font color. getSize(): Get the text size. getAngle(): Get the text angle getAlignment(): Get the text positioning. The TextStyle class has the following classmethods: getStyleAsString(): Get the font style in string form. getStyleFromString(): Get the font style value given a string argument getWeightAsString(): Get the font weight in string form. getWeightFromString(): Get the font weight value given a string argument getAlignmentAsString(): Get the text positioning in string form. getAlignmentFromString(): Get the text positioning value given a string. getStyleStrings(): Get the available font style values as strings. getStyleValues(): Get the available font style values. getWeightStrings(): Get the available font weight values as strings. getWeightValues(): Get the available font weight values. getAlignmentStrings(): Get the available text alignment values as strings. getAlignmentValues(): Get the available text alignment values. """ FONT_NORMAL = 0 FONT_OBLIQUE = 1 FONT_ITALIC = 2 WEIGHT_NORMAL = 0 WEIGHT_LIGHT = 1 WEIGHT_BOLD = 2 WEIGHT_HEAVY = 3 ALIGN_LEFT = 0 ALIGN_CENTER = 1 ALIGN_RIGHT = 2 __defcolor = color.Color(0xffffff) def __init__(self, name, **kw): """Initialize a TextStyle object. ts = TextStyle(name) The following are the defaults: family: Sans style: NORMAL weight: NORMAL color: White (#ffffff) size: 1.0 angle: 0.0 alignment: LEFT """ _name = name if not isinstance(_name, unicode): _name = unicode(name) _family = 'Sans' if 'family' in kw: _family = kw['family'] if not isinstance(_family, str): raise TypeError, "Invalid font family: " + str(_family) _style = TextStyle.FONT_NORMAL if 'style' in kw: _style = kw['style'] if not isinstance(_style, int): raise TypeError, "Invalid font style: " + str(_style) if (_style != TextStyle.FONT_NORMAL and _style != TextStyle.FONT_OBLIQUE and _style != TextStyle.FONT_ITALIC): raise ValueError, "Invalid font style value: %d" % _style _weight = TextStyle.WEIGHT_NORMAL if 'weight' in kw: _weight = kw['weight'] if not isinstance(_weight, int): raise TypeError, "Invalid font weight: " + str(_weight) if (_weight != TextStyle.WEIGHT_NORMAL and _weight != TextStyle.WEIGHT_LIGHT and _weight != TextStyle.WEIGHT_BOLD and _weight != TextStyle.WEIGHT_HEAVY): raise ValueError, "Invalid font weight value: %d" % _weight _color = TextStyle.__defcolor if 'color' in kw: _color = kw['color'] if not isinstance(_color, color.Color): raise TypeError, "Invalid color: " + str(_color) _size = 1.0 if 'size' in kw: _size = util.get_float(kw['size']) if _size < 0.0: raise ValueError, "Invalid text size: %g" % _size _angle = 0.0 if 'angle' in kw: _angle = util.get_float(kw['angle']) if _angle > 360.0 or _angle < -360.0: _angle = math.fmod(_angle, 360.0) _align = TextStyle.ALIGN_LEFT if 'align' in kw: _align = kw['align'] if not isinstance(_align, int): raise TypeError, "Invalid text alignment: " + str(_align) if (_align != TextStyle.ALIGN_LEFT and _align != TextStyle.ALIGN_CENTER and _align != TextStyle.ALIGN_RIGHT): raise ValueError, "Invalid text alignment value: %d" % _align super(TextStyle, self).__init__() self.__name = _name self.__family = _family self.__style = _style self.__weight = _weight self.__color = _color self.__size = _size self.__angle = _angle self.__alignment = _align def __eq__(self, obj): if not isinstance(obj, TextStyle): return False if obj is self: return True return (self.__name == obj.getName() and self.__family == obj.getFamily() and self.__style == obj.getStyle() and self.__weight == obj.getWeight() and self.__color == obj.getColor() and abs(self.__size - obj.getSize()) < 1e-10 and abs(self.__angle - obj.getAngle()) < 1e-10 and self.__alignment == obj.getAlignment()) def __ne__(self, obj): if not isinstance(obj, TextStyle): return True if obj is self: return False return (self.__name != obj.getName() or self.__family != obj.getFamily() or self.__style != obj.getStyle() or self.__weight != obj.getWeight() or self.__color != obj.getColor() or abs(self.__size - obj.getSize()) > 1e-10 or abs(self.__angle - obj.getAngle()) > 1e-10 or self.__alignment != obj.getAlignment()) def finish(self): """Finalization for TextStyle instances. """ self.__color = None def getValues(self): _vals = {} _vals['name'] = self.__name _vals['family'] = self.__family _vals['style'] = self.__style _vals['weight'] = self.__weight _vals['color'] = self.__color.getColors() _vals['size'] = self.__size _vals['angle'] = self.__angle _vals['align'] = self.__alignment return _vals def getName(self): """Retrieve the name of the TextStyle. getName() """ return self.__name name = property(getName, None, None, "TextStyle name.") def getFamily(self): """Return the font family. getFamily() """ return self.__family family = property(getFamily, None, None, "Text font family") def getStyle(self): """Return the font style. getStyle() """ return self.__style style = property(getStyle, None, None, "Text font style") def getStyleAsString(cls, s): """Return a text string for the font style. getStyleAsString(s) This classmethod returns 'normal', 'oblique', or 'italic' """ if not isinstance(s, int): raise TypeError, "Invalid argument type: " + `type(s)` if s == TextStyle.FONT_NORMAL: _str = 'normal' elif s == TextStyle.FONT_OBLIQUE: _str = 'oblique' elif s == TextStyle.FONT_ITALIC: _str = 'italic' else: raise ValueError, "Unexpected style value: %d" % s return _str getStyleAsString = classmethod(getStyleAsString) def getStyleFromString(cls, s): """Return a font style value based on a text string. getStyleFromString(s) This classmethod returns a value based on the string argument: 'normal' -> TextStyle.FONT_NORMAL 'oblique' -> TextStyle.FONT_OBLIQUE 'italic' -> TextStyle.FONT_ITALIC If the string is not listed above a ValueError execption is raised. """ if not isinstance(s, str): raise TypeError, "Invalid argument type: " + `type(s)` _ls = s.lower() if _ls == 'normal': _v = TextStyle.FONT_NORMAL elif _ls == 'oblique': _v = TextStyle.FONT_OBLIQUE elif _ls == 'italic': _v = TextStyle.FONT_ITALIC else: raise ValueError, "Unexpected style string: " + s return _v getStyleFromString = classmethod(getStyleFromString) def getStyleStrings(cls): """Return the font style values as strings. getStyleStrings() This classmethod returns a list of strings. """ return [_('Normal'), _('Oblique'), _('Italic') ] getStyleStrings = classmethod(getStyleStrings) def getStyleValues(cls): """Return the font style values. getStyleValues() This classmethod returns a list of values. """ return [TextStyle.FONT_NORMAL, TextStyle.FONT_OBLIQUE, TextStyle.FONT_ITALIC ] getStyleValues = classmethod(getStyleValues) def getWeight(self): """Return the font weight. getWeight() """ return self.__weight weight = property(getWeight, None, None, "Text font weight") def getWeightAsString(cls, w): """Return a text string for the font weight. getWeightAsString(w) This classmethod returns 'normal', 'light', 'bold', or 'heavy'. """ if not isinstance(w, int): raise TypeError, "Invalid argument type: " + `type(w)` if w == TextStyle.WEIGHT_NORMAL: _str = 'normal' elif w == TextStyle.WEIGHT_LIGHT: _str = 'light' elif w == TextStyle.WEIGHT_BOLD: _str = 'bold' elif w == TextStyle.WEIGHT_HEAVY: _str = 'heavy' else: raise ValueError, "Unexpected weight value: %d" % w return _str getWeightAsString = classmethod(getWeightAsString) def getWeightFromString(cls, s): """Return a font weight value for a given string argument. getWeightFromString(s) This classmethod returns a value based on the string argument: 'normal' -> TextStyle.WEIGHT_NORMAL 'light' -> TextStyle.WEIGHT_LIGHT 'bold' -> TextStyle.WEIGHT_BOLD 'heavy' -> TextStyle.WEIGHT_HEAVY If the string is not listed above a ValueError execption is raised. """ if not isinstance(s, str): raise TypeError, "Invalid argument type: " + `type(s)` _ls = s.lower() if _ls == 'normal': _v = TextStyle.WEIGHT_NORMAL elif _ls == 'light': _v = TextStyle.WEIGHT_LIGHT elif _ls == 'bold': _v = TextStyle.WEIGHT_BOLD elif _ls == 'heavy': _v = TextStyle.WEIGHT_HEAVY else: raise ValueError, "Unexpected weight string: " + s return _v getWeightFromString = classmethod(getWeightFromString) def getWeightStrings(cls): """Return the font weight values as strings. getWeightStrings() This classmethod returns a list of strings. """ return [_('Normal'), _('Light'), _('Bold'), _('Heavy') ] getWeightStrings = classmethod(getWeightStrings) def getWeightValues(cls): """Return the font weight values. getWeightValues() This classmethod returns a list of values. """ return [TextStyle.WEIGHT_NORMAL, TextStyle.WEIGHT_LIGHT, TextStyle.WEIGHT_BOLD, TextStyle.WEIGHT_HEAVY ] getWeightValues = classmethod(getWeightValues) def getColor(self): """Return the font color. getColor() """ return self.__color color = property(getColor, None, None, "Text color") def getSize(self): """Return the specified size. getSize() """ return self.__size size = property(getSize, None, None, "Text size.") def getAngle(self): """Return the angle at which the text is drawn. getAngle() This method returns an angle -360.0 < angle < 360.0. """ return self.__angle angle = property(getAngle, None, None, "Text angle.") def getAlignment(self): """Return the line justification setting. getAlignment() """ return self.__alignment alignment = property(getAlignment, None, "Text alignment.") def getAlignmentAsString(cls, a): """Return a text string for the text alignment. getAlignmentAsString(w) This classmethod returns 'left', 'center', or 'right' """ if not isinstance(a, int): raise TypeError, "Invalid argument type: " + `type(a)` if a == TextStyle.ALIGN_LEFT: _str = 'left' elif a == TextStyle.ALIGN_CENTER: _str = 'center' elif a == TextStyle.ALIGN_RIGHT: _str = 'right' else: raise ValueError, "Unexpected alignment value: %d" % a return _str getAlignmentAsString = classmethod(getAlignmentAsString) def getAlignmentFromString(cls, s): """Return a text alignment based on a string argument. getAlignmentFromString(s) This classmethod returns a value based on the string argument: 'left' -> TextStyle.ALIGN_LEFT 'center' -> TextStyle.ALIGN_CENTER 'right' -> TextStyle.ALIGN_RIGHT If the string is not listed above a ValueError execption is raised. """ if not isinstance(s, str): raise TypeError, "Invalid argument type: " + `type(s)` _ls = s.lower() if _ls == 'left': _v = TextStyle.ALIGN_LEFT elif _ls == 'center': _v = TextStyle.ALIGN_CENTER elif _ls == 'right': _v = TextStyle.ALIGN_RIGHT else: raise ValueError, "Unexpected alignment string: " + s return _v getAlignmentFromString = classmethod(getAlignmentFromString) def getAlignmentStrings(cls): """Return the text alignment values as strings. getAlignmentStrings() This classmethod returns a list of strings. """ return [_('Left'), _('Center'), _('Right') ] getAlignmentStrings = classmethod(getAlignmentStrings) def getAlignmentValues(cls): """Return the text alignment values. getAlignmentValues() This classmethod returns a list of values. """ return [TextStyle.ALIGN_LEFT, TextStyle.ALIGN_CENTER, TextStyle.ALIGN_RIGHT ] getAlignmentValues = classmethod(getAlignmentValues) # # TextBlock # class TextBlock(entity.Entity): """A class representing text in a drawing. A TextBlock instance has the following attributes: text: Text within the TextBlock location: Spatial location of the TextBlock family: The font family style: The font style weight: The font weight color: The font color size: Text size alignment: Text positioning at the location angle: Angular position of the text A TextBlock instance has the following methods: {get/set}TextStyle(): Get/Set the TextStyle for the TextBlock {get/set}Text(): Get/Set the text {get/set}Location(): Get/Set the TextBlock location {get/set}Family(): Get/Set the font family. {get/set}Style(): Get/Set the font style. {get/set}Weight(): Get/Set the font weight. {get/set}Color(): Get/Set the font color. {get/set}Size(): Get/Set the text size. {get/set}Angle(): Get/Set the text angle {get/set}Alignment(): Get/Set the text positioning {get/set}Bounds(): Get/Set the height and width of the TextBlock. {get/set}FontScale(): Get/Set a scale factor used for font display. getLineCount(): Get the number of lines stored in the TextBlock The TextBlock class has the following classmethods: {get/set}DefaultTextStyle(): Get/Set the default TextStyle for the class. """ __messages = { 'text_changed' : True, 'textstyle_changed' : True, 'font_family_changed' : True, 'font_style_changed' : True, 'font_weight_changed' : True, 'font_color_changed' : True, 'text_size_changed' : True, 'text_angle_changed' : True, 'text_alignment_changed' : True, 'moved' : True, } __defstyle = None def __init__(self, x, y, text, textstyle=None, **kw): """Initialize a TextBlock instance. TextBlock(x, y, text[, textstyle=None]) """ _x = util.get_float(x) _y = util.get_float(y) if not isinstance(text, types.StringTypes): raise TypeError, "Invalid text data: " + str(text) _tstyle = textstyle if _tstyle is None: _tstyle = self.getDefaultTextStyle() else: if not isinstance(_tstyle, TextStyle): raise TypeError, "Invalid TextStyle object: " + `_tstyle` _family = None if 'family' in kw: _family = kw['family'] if not isinstance(_family, types.StringTypes): raise TypeError, "Invalid font family: " + str(_family) if _family == _tstyle.getFamily(): _family = None _style = None if 'style' in kw: _style = kw['style'] if not isinstance(_style, int): raise TypeError, "Invalid font style: " + str(_style) if (_style != TextStyle.FONT_NORMAL and _style != TextStyle.FONT_OBLIQUE and _style != TextStyle.FONT_ITALIC): raise ValueError, "Invalid font style value: %d" % _style if _style == _tstyle.getStyle(): _style = None _weight = None if 'weight' in kw: _weight = kw['weight'] if not isinstance(_weight, int): raise TypeError, "Invalid font weight: " + str(_weight) if (_weight != TextStyle.WEIGHT_NORMAL and _weight != TextStyle.WEIGHT_LIGHT and _weight != TextStyle.WEIGHT_BOLD and _weight != TextStyle.WEIGHT_HEAVY): raise ValueError, "Invalid font weight value: %d" % _weight if _weight == _tstyle.getWeight(): _weight = None _color = None if 'color' in kw: _color = kw['color'] if not isinstance(_color, color.Color): raise TypeError, "Invalid font color: " + str(_color) if _color == _tstyle.getColor(): _color = None _size = None if 'size' in kw: _size = util.get_float(kw['size']) if _size < 0.0: raise ValueError, "Invalid text size: %g" % _size if abs(_size - _tstyle.getSize()) < 1e-10: _size = None _angle = None if 'angle' in kw: _angle = util.get_float(kw['angle']) if _angle > 360.0 or _angle < -360.0: _angle = math.fmod(_angle, 360.0) if abs(_angle - _tstyle.getAngle()) < 1e-10: _angle = None _align = None if 'align' in kw: _align = kw['align'] if not isinstance(_align, int): raise TypeError, "Invalid text alignment: " + str(_align) if (_align != TextStyle.ALIGN_LEFT and _align != TextStyle.ALIGN_CENTER and _align != TextStyle.ALIGN_RIGHT): raise ValueError, "Invalid text alignment value: %d" % _align if _align == _tstyle.getAlignment(): _align = None super(TextBlock, self).__init__(**kw) self.__location = (_x, _y) self.__text = text self.__tstyle = _tstyle self.__family = _family self.__style = _style self.__weight = _weight self.__color = _color self.__size = _size self.__angle = _angle self.__alignment = _align self.__bounds = None self.__scale = None def getDefaultTextStyle(cls): if cls.__defstyle is None: cls.__defstyle = TextStyle(u'Default Text Style', color=color.Color(0xffffff)) return cls.__defstyle getDefaultTextStyle = classmethod(getDefaultTextStyle) def setDefaultTextStyle(cls, s): if not isinstance(s, TextStyle): raise TypeError, "Invalid TextStyle: " + `type(s)` cls.__defstyle = s setDefaultTextStyle = classmethod(setDefaultTextStyle) def finish(self): """Finalization for TextBlock instances. finish() """ if self.__color is not None: self.__color = None super(TextBlock, self).finish() def getValues(self): """Return values comprising the TextBlock. getValues() This method extends the Entity::getValues() method. """ _data = super(TextBlock, self).getValues() _data.setValue('type', 'textblock') _data.setValue('location', self.__location) _data.setValue('text', self.__text) _data.setValue('textstyle', self.__tstyle.getValues()) if self.__family is not None: _data.setValue('family', self.__family) if self.__style is not None: _data.setValue('style', self.__style) if self.__weight is not None: _data.setValue('weight', self.__weight) if self.__color is not None: _data.setValue('color', self.__color.getColors()) if self.__size is not None: _data.setValue('size', self.__size) if self.__angle is not None: _data.setValue('angle', self.__angle) if self.__alignment is not None: _data.setValue('align', self.__alignment) return _data def getText(self): """Get the current text within the TextBlock. getText() """ return self.__text def setText(self, text): """Set the text within the TextBlock. setText(text) """ if not isinstance(text, types.StringTypes): raise TypeError, "Invalid text data: " + str(text) _ot = self.__text if _ot != text: self.startChange('text_changed') self.__text = text self.endChange('text_changed') if self.__bounds is not None: self.__bounds = None self.sendMessage('text_changed', _ot) self.modified() text = property(getText, setText, None, "TextBlock text.") def getLocation(self): """Return the TextBlock spatial position. getLocation() """ return self.__location def setLocation(self, x, y): """Store the spatial position of the TextBlock. setLocation(x, y) Arguments 'x' and 'y' should be float values. """ _x = util.get_float(x) _y = util.get_float(y) _ox, _oy = self.__location if abs(_ox - _x) > 1e-10 or abs(_oy - _y) > 1e-10: self.startChange('moved') self.__location = (_x, _y) self.endChange('moved') self.sendMessage('moved', _ox, _oy) self.modified() location = property(getLocation, None, None, "TextBlock location") def getTextStyle(self): """Return the TextStyle associated with this TextBlock. getTextStyle() """ return self.__tstyle def setTextStyle(self, textstyle=None): """Store the TextStyle associated with this TextBlock. setTextStyle([textstyle]) Optional argument 'textstyle' should be an TextStyle instance. If no argument is given the TextBlock will use a default TextStyle. The TextBlock will have all the text appearance and positioning attributes set the the values in the TextStyle. """ _ts = textstyle if _ts is None: _ts = self.getDefaultTextStyle() if not isinstance(_ts, TextStyle): raise TypeError, "Invalid text style: " + `_ts` _os = self.__tstyle if _os != _ts: _opts = {} if self.__family is not None: _opts['family'] = self.__family if self.__style is not None: _opts['style'] = self.__style if self.__weight is not None: _opts['weight'] = self.__weight if self.__color is not None: _opts['color'] = self.__color if self.__size is not None: _opts['size'] = self.__size if self.__angle is not None: _opts['angle'] = self.__angle if self.__alignment is not None: _opts['align'] = self.__alignment self.startChange('textstyle_changed') self.__tstyle = _ts self.endChange('textstyle_changed') # # call the methods with no arguments to set the values # given in the new TextStyle # self.setFamily() self.setStyle() self.setWeight() self.setColor() self.setSize() self.setAngle() self.setAlignment() self.sendMessage('textstyle_changed', _os, _opts) self.modified() def getFamily(self): """Return the font family. getFamily() """ _family = self.__family if _family is None: _family = self.__tstyle.getFamily() return _family def setFamily(self, family=None): """Set the font family. setFamily([family]) Optional argument 'family' should be a string giving the font family. Calling this method without an argument sets the font family to that defined in the TextStyle. """ if self.isLocked(): raise RuntimeError, "Setting family not allowed - object locked." _family = family if _family is not None: if not isinstance(family, types.StringTypes): raise TypeError, "Invalid family type: " + `type(family)` _f = self.getFamily() if ((_family is None and self.__family is not None) or (_family is not None and _family != _f)): self.startChange('font_family_changed') self.__family = _family self.endChange('font_family_changed') if self.__bounds is not None: self.__bounds = None self.sendMessage('font_family_changed', _f) self.modified() family = property(getFamily, setFamily, None, "Text object font family") def getStyle(self): """Return the font style. getStyle() """ _style = self.__style if _style is None: _style = self.__tstyle.getStyle() return _style def setStyle(self, style=None): """Set the font style. setStyle([style]) Optional argument 'style' should be one of the following: TextStyle.FONT_NORMAL TextStyle.FONT_OBLIQUE TextStyle.FONT_ITALIC Calling this method without an argument restores the font style to that defined in the TextStyle. """ if self.isLocked(): raise RuntimeError, "Setting style not allowed - object locked." _style = style if _style is not None: if not isinstance(_style, int): raise TypeError, "Invalid TextStyle font style type: " + `type(_style)` if (_style != TextStyle.FONT_NORMAL and _style != TextStyle.FONT_OBLIQUE and _style != TextStyle.FONT_ITALIC): raise ValueError, "Invalid font style: " + str(_style) _s = self.getStyle() if ((_style is None and self.__style is not None) or (_style is not None and _style != _s)): self.startChange('font_style_changed') self.__style = _style self.endChange('font_style_changed') if self.__bounds is not None: self.__bounds = None self.sendMessage('font_style_changed', _s) self.modified() style = property(getStyle, setStyle, None, "Text font style") def getWeight(self): """Return the font weight. getWeight() """ _weight = self.__weight if _weight is None: _weight = self.__tstyle.getWeight() return _weight def setWeight(self, weight=None): """Set the font weight. setWeight([weight]) Optional argument 'weight' should be one of the following values: TextStyle.WEIGHT_NORMAL TextStyle.WEIGHT_LIGHT TextStyle.WEIGHT_BOLD TextStyle.WEIGHT_HEAVY Calling this method without an argument restores the font weight to that defined in the TextStyle. """ if self.isLocked(): raise RuntimeError, "Setting weight not allowed - object locked." _weight = weight if _weight is not None: if not isinstance(_weight, int): raise TypeError, "Invalid TextStyle font weight type: " + `type(_weight)` if (_weight != TextStyle.WEIGHT_NORMAL and _weight != TextStyle.WEIGHT_LIGHT and _weight != TextStyle.WEIGHT_BOLD and _weight != TextStyle.WEIGHT_HEAVY): raise ValueError, "Invalid text weight: %d" % _weight _w = self.getWeight() if ((_weight is None and self.__weight is not None) or (_weight is not None and _weight != _w)): self.startChange('font_weight_changed') self.__weight = _weight self.endChange('font_weight_changed') if self.__bounds is not None: self.__bounds = None self.sendMessage('font_weight_changed', _w) self.modified() weight = property(getWeight, setWeight, None, "Text font weight") def getColor(self): """Return the font color. getColor() """ _color = self.__color if _color is None: _color = self.__tstyle.getColor() return _color def setColor(self, col=None): """Set the font color. setColor([col]) Optional argument 'col' should be a Color object. Calling this method without an argument restores the font color to that defined in the TextStyle. """ if self.isLocked(): raise RuntimeError, "Setting color not allowed - object locked." _col = col if _col is not None: if not isinstance(_col, color.Color): raise TypeError, "Invalid color type: " + `type(_col)` _c = self.getColor() if ((_col is None and self.__color is not None) or (_col is not None and _col != _c)): self.startChange('font_color_changed') self.__color = _col self.endChange('font_color_changed') self.sendMessage('font_color_changed', _c) self.modified() color = property(getColor, setColor, None, "Text color") def getSize(self): """Return the text size. getSize() """ _size = self.__size if _size is None: _size = self.__tstyle.getSize() return _size def setSize(self, size=None): """Set the size of the text. setSize([size]) Optionala rgument 'size' should be a float value greater than 0. Calling this method without an argument restores the text size to the value given in the TextStyle. """ if self.isLocked(): raise RuntimeError, "Setting size not allowed - object locked." _size = size if _size is not None: _size = util.get_float(_size) if _size < 0.0: raise ValueError, "Invalid size: %g" % _size _os = self.getSize() if ((_size is None and self.__size is not None) or (_size is not None and abs(_size - _os) > 1e-10)): self.startChange('text_size_changed') self.__size = _size self.endChange('text_size_changed') if self.__bounds is not None: self.__bounds = None self.sendMessage('text_size_changed', _os) self.modified() size = property(getSize, setSize, None, "Text size.") def getAngle(self): """Return the angle at which the text is drawn. getAngle() This method returns an angle -360.0 < angle < 360.0. """ _angle = self.__angle if _angle is None: _angle = self.__tstyle.getAngle() return _angle def setAngle(self, angle=None): """Set the angle at which the text block should be drawn. setAngle([angle]) Optional argument 'angle' should be a float value. Calling this method without arguments sets the angle to be the value defined in the TextStyle. """ if self.isLocked(): raise RuntimeError, "Setting angle not allowed - object locked." _angle = angle if _angle is not None: _angle = util.get_float(_angle) if _angle > 360.0 or _angle < -360.0: _angle = math.fmod(_angle, 360.0) _a = self.getAngle() if ((_angle is None and self.__angle is not None) or (_angle is not None and abs(_angle - _a) > 1e-10)): self.startChange('text_angle_changed') self.__angle = _angle self.endChange('text_angle_changed') self.sendMessage('text_angle_changed', _a) self.modified() angle = property(getAngle, setAngle, None, "Text angle.") def getAlignment(self): """Return the line justification setting. getAlignment() """ _align = self.__alignment if _align is None: _align = self.__tstyle.getAlignment() return _align def setAlignment(self, align=None): """Set left, center, or right line justification. setAlignment([align]) Optional argument 'align' should be one of TextStyle.ALIGN_LEFT TextStyle.ALIGN_CENTER TextStyle.ALIGN_RIGHT Calling this method without arguments sets the text alignment to be that given in the TextStyle. """ if self.isLocked(): raise RuntimeError, "Setting alignment not allowed - object locked." _align = align if _align is not None: if not isinstance(_align, int): raise TypeError, "Invalid TextStyle alignment type: " + `type(_align)` if (_align != TextStyle.ALIGN_LEFT and _align != TextStyle.ALIGN_CENTER and _align != TextStyle.ALIGN_RIGHT): raise ValueError, "Invalid text alignment value: %d" % _align _a = self.getAlignment() if ((_align is None and self.__alignment is not None) or (_align is not None and _align != _a)): self.startChange('text_alignment_changed') self.__alignment = _align self.endChange('text_alignment_changed') if self.__bounds is not None: self.__bounds = None self.sendMessage('text_alignment_changed', _a) self.modified() alignment = property(getAlignment, setAlignment, None, "Text alignment.") def move(self, dx, dy): """Move a TextBlock. move(dx, dy) The first argument gives the x-coordinate displacement, and the second gives the y-coordinate displacement. Both values should be floats. """ if self.isLocked(): raise RuntimeError, "Moving not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _x, _y = self.__location self.startChange('moved') self.__location = ((_x + _dx), (_y + _dy)) self.endChange('moved') self.sendMessage('moved', _x, _y) self.modified() def getLineCount(self): """Return the number of lines of text in the TextBlock getLineCount() """ # # ideally Python itself would provide a linecount() method # so the temporary list would not need to be created ... # return len(self.__text.splitlines()) def clone(self): """Return an identical copy of a TextBlock. clone() """ _x, _y = self.getLocation() _text = self.getText() _textstyle = self.getTextStyle() _tb = TextBlock(_x, _y, _text, _textstyle) _family = self.getFamily() if _family != _textstyle.getFamily(): _tb.setFamily(_family) _style = self.getStyle() if _style != _textstyle.getStyle(): _tb.setStyle(_style) _weight = self.getWeight() if _weight != _textstyle.getWeight(): _tb.setWeight(_weight) _color = self.getColor() if _color != _textstyle.getColor(): _tb.setColor(_color) _size = self.getSize() if abs(_size - _textstyle.getSize()) > 1e-10: _tb.setSize(_size) _angle = self.getAngle() if abs(_angle - _textstyle.getAngle()) > 1e-10: _tb.setAngle(_angle) _align = self.getAlignment() if _align != _textstyle.getAlignment(): _tb.setAlignment(_align) return _tb def getBounds(self): """Get the width and height of the TextBlock. getBounds() This method can return None if the boundary has not been calculated or the TextBlock has been changed. """ return self.__bounds def setBounds(self, width=None, height=None): """Set the width and height of the TextBlock. setBounds([width, height]) Arguments 'width' and 'height' should be positive float values if used. If both arguments are None, the boundary of the TextBlock is unset. """ _w = width _h = height if _w is None and _h is None: self.__bounds = None else: if _w is None: raise ValueError, "Width cannot be None" _w = util.get_float(_w) if _w < 0.0: raise ValueError, "Invalid width: %g" % _w if _h is None: raise ValueError, "Height cannot be None" _h = util.get_float(_h) if _h < 0.0: raise ValueError, "Invalid height: %g" % _w self.__bounds = (_w, _h) def inRegion (self, xmin, ymin, xmax, ymax, fully=True): """Returns True if the TextBlock is within the bounding values. inRegion(xmin, ymin, xmax, ymax) The four arguments define the boundary of an area, and the function returns True if the TextBlock lies within that area. Otherwise, the function returns False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) _x, _y = self.__location if self.__bounds is None: return not ((_x < _xmin) or (_x > _xmax) or (_y < _ymin) or (_y > _ymax)) else: _w, _h = self.__bounds _flag = True _align = self.getAlignment() if _align == TextStyle.ALIGN_LEFT: if ((_x > _xmax) or ((_x + _w) < _xmin)): _flag = False elif _align == TextStyle.ALIGN_CENTER: if (((_x - (_w/2.0)) > _xmax) or ((_x + (_w/2.0)) < _xmin)): _flag = False elif _align == TextStyle.ALIGN_RIGHT: if (((_x - _w) > _xmax) or (_x < _xmin)): _flag = False else: raise ValueError, "Unexpected alignment: %d" % _align if _flag: _flag = not ((_y < _ymin) or ((_y - _h) > _ymax)) return _flag def getFontScale(self): """Return the stored font scaling factor getFontScale() This method will raise a ValueError exception if there has not be a value stored with the setFontScale() call. """ if self.__scale is None: raise ValueError, "Scale not set." return self.__scale def setFontScale(self, scale): """Store a value used to scale the TextBlock font. setFontScale(scale) Argument 'scale' should be a positive float value. """ _s = util.get_float(scale) if not _s > 0.0: raise ValueError, "Invalid scale value: %g" % _s self.__scale = _s def sendsMessage(self, m): if m in TextBlock.__messages: return True return super(TextBlock, self).sendsMessage(m) # # TextBlock history class # class TextBlockLog(entity.EntityLog): __setops = { 'text_changed' : TextBlock.setText, 'font_family_changed' : TextBlock.setFamily, 'font_style_changed' : TextBlock.setStyle, 'font_color_changed' : TextBlock.setColor, 'font_weight_changed' : TextBlock.setWeight, 'text_size_changed' : TextBlock.setSize, 'text_angle_changed' : TextBlock.setAngle, 'text_alignment_changed' : TextBlock.setAlignment, } __getops = { 'text_changed' : TextBlock.getText, 'font_family_changed' : TextBlock.getFamily, 'font_style_changed' : TextBlock.getStyle, 'font_color_changed' : TextBlock.getColor, 'font_weight_changed' : TextBlock.getWeight, 'text_size_changed' : TextBlock.getSize, 'text_angle_changed' : TextBlock.getAngle, 'text_alignment_changed' : TextBlock.getAlignment, } def __init__(self, tblock): if not isinstance(tblock, TextBlock): raise TypeError, "Invalid TextBlock: " + `tblock` super(TextBlockLog, self).__init__(tblock) tblock.connect('textstyle_changed', self._textstyleChanged) tblock.connect('text_changed', self._textChanged) tblock.connect('font_family_changed', self._familyChanged) tblock.connect('font_style_changed', self._styleChanged) tblock.connect('font_color_changed', self._colorChanged) tblock.connect('font_weight_changed', self._weightChanged) tblock.connect('text_size_changed', self._sizeChanged) tblock.connect('text_angle_changed', self._angleChanged) tblock.connect('text_alignment_changed', self._alignmentChanged) tblock.connect('moved', self._moveText) def _textstyleChanged(self, tb, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _ts = args[0] if not isinstance(_ts, TextStyle): raise TypeError, "Invalid TextStyle type: " + `type(_ts)` _opts = args[1] if not isinstance(_opts, dict): raise TypeError, "Invalid option type: " + `type(_opts)` _data = {} _data['textstyle'] = _ts.getValues() for _k, _v in _opts: if _k == 'color': _data['color'] = _v.getColors() else: _data[_k] = _v self.saveUndoData('textstyle_changed', _data) def _textChanged(self, tb, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _text = args[0] if not isinstance(_text, types.StringTypes): raise TypeError, "Invalid text type: " + `type(_text)` self.saveUndoData('text_changed', _text) def _familyChanged(self, tb, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _family = args[0] if not isinstance(_family, types.StringTypes): raise TypeError, "Invalid family type: " + `type(_family)` self.saveUndoData('font_family_changed', _family) def _styleChanged(self, tb, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _style = args[0] if (_style != TextStyle.FONT_NORMAL and _style != TextStyle.FONT_OBLIQUE and _style != TextStyle.FONT_ITALIC): raise ValueError, "Invalid font style: " + str(_style) self.saveUndoData('font_style_changed', _style) def _colorChanged(self, tb, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _color = args[0] if not isinstance(_color, color.Color): raise TypeError, "Invalid color type: " + `type(_color)` self.saveUndoData('font_color_changed', _color.getColors()) def _weightChanged(self, tb, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _weight = args[0] if (_weight != TextStyle.WEIGHT_NORMAL and _weight != TextStyle.WEIGHT_LIGHT and _weight != TextStyle.WEIGHT_BOLD and _weight != TextStyle.WEIGHT_HEAVY): raise ValueError, "Invalid text weight: %d" % _weight self.saveUndoData('font_weight_changed', _weight) def _sizeChanged(self, tb, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _size = args[0] if not isinstance(_size, float): raise TypeError, "Unexpected size type: " + `type(_size)` if _size < 0.0: raise ValueError, "Invalid text size: %g" % _size self.saveUndoData('text_size_changed', _size) def _angleChanged(self, tb, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _angle = args[0] if not isinstance(_angle, float): raise TypeError, "Unexpected angle type: " + `type(_angle)` if _angle > 360.0 or _angle < -360.0: _angle = math.fmod(_angle, 360.0) self.saveUndoData('text_angle_changed', _angle) def _alignmentChanged(self, tb, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _align = args[0] if (_align != TextStyle.ALIGN_LEFT and _align != TextStyle.ALIGN_CENTER and _align != TextStyle.ALIGN_RIGHT): raise ValueError, "Invalid text alignment value: %d" % _align self.saveUndoData('text_alignment_changed', _align) def _moveText(self, tb, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = args[0] if not isinstance(_x, float): raise TypeError, "Unexpected type for x: " + `type(_x)` _y = args[1] if not isinstance(_y, float): raise TypeError, "Unexpected type for y: " + `type(_y)` self.saveUndoData('moved', _x, _y) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if len(args) == 0: raise ValueError, "No arguments to execute()" _tblock = self.getObject() _image = None _layer = _tblock.getParent() if _layer is not None: _image = _layer.getParent() _op = args[0] if (_op == 'text_changed' or _op == 'font_family_changed' or _op == 'font_style_changed' or _op == 'font_weight_changed' or _op == 'text_size_changed' or _op == 'text_angle_changed' or _op == 'text_alignment_changed'): if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _val = args[1] _get = TextBlockLog.__getops[_op] _sdata = _get(_tblock) self.ignore(_op) try: _set = TextBlockLog.__setops[_op] if undo: _tblock.startUndo() try: _set(_tblock, _val) finally: _tblock.endUndo() else: _tblock.startRedo() try: _set(_tblock, _val) finally: _tblock.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'moved': if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _x = args[1] if not isinstance(_x, float): raise TypeError, "Unexpected type for x: " + `type(_x)` _y = args[2] if not isinstance(_y, float): raise TypeError, "Unexpected type for y: " + `type(_y)` _tx, _ty = _tblock.getLocation() self.ignore(_op) try: if undo: _tblock.startUndo() try: _tblock.setLocation(_x, _y) finally: _tblock.endUndo() else: _tblock.startRedo() try: _tblock.setLocation(_x, _y) finally: _tblock.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _tx, _ty) elif _op == 'font_color_changed': if _image is None: raise RuntimeError, "TextBlock not stored in an Image" if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _sdata = _tblock.getColor().getColors() self.ignore(_op) try: _color = None for _c in _image.getImageEntities('color'): if _c.getColors() == args[1]: _color = _c break if undo: _tblock.startUndo() try: _tblock.setColor(_color) finally: _tblock.endUndo() else: _tblock.startRedo() try: _tblock.setColor(_color) finally: _tblock.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'textstyle_changed': if _image is None: raise RuntimeError, "TextBlock not stored in an Image" if _alen < 2: raise ValueError, "Invalid argument cound: %d" % _alen _data = args[1] _tsdata = _data['textstyle'] _sdata = {} _ts = _tblock.getTextStyle() _sdata['textstyle'] = _ts.getValues() _family = _tblock.getFamily() if _family != _ts.getFamily(): _sdata['family'] = _family _style = _tblock.getStyle() if _style != _ts.getStyle(): _sdata['style'] = _style _weight = _tblock.getWeight() if _weight != _ts.getWeight(): _sdata['weight'] = _weight _color = _tblock.getColor() if _color != _ts.getColor(): _sdata['color'] = _color.getColors() _size = _tblock.getSize() if abs(_size - _ts.getSize()) > 1e-10: _sdata['size'] = _size _angle = _tblock.getAngle() if abs(_angle - _ts.getAngle()) > 1e-10: _sdata['angle'] = _angle _align = _tblock.getAlignment() if _align != _ts.getAlignment(): _sdata['align'] = _align self.ignore(_op) try: _tstyle = None for _ts in _image.getImageEntities('textstyle'): if _ts.getName() != _tsdata['name']: continue if _ts.getFamily() != _tsdata['family']: continue if _ts.getStyle() != _tsdata['style']: continue if _ts.getWeight() != _tsdata['weight']: continue if _ts.getColor().getColors() != _tsdata['color']: continue if abs(_ts.getSize() - _tsdata['size']) > 1e-10: continue if abs(_ts.getAngle() - _tsdata['angle']) > 1e-10: continue if _ts.getAlignment() != _tsdata['align']: continue _tstyle = _ts break if undo: _tblock.startUndo() try: _tblock.setTextStyle(_tstyle) finally: _tblock.endUndo() else: _tblock.startRedo() try: _tblock.setTextStyle(_tstyle) finally: _tblock.endRedo() finally: self.receive(_op) # # restore values differing from the TextStyle # _tblock.mute() try: _family = _data.get('family') if _family is not None: _tblock.setFamily(_family) _style = _data.get('style') if _style is not None: _tblock.setStyle(_style) _weight = _data.get('weight') if _weight is not None: _tblock.setWeight(_weight) _color = _data.get('color') if _color is not None: _col = None for _c in _image.getImageEntities('color'): if _c.getColors() == _color: _col = _c break _tblock.setColor(_col) _size = _data.get('size') if _size is not None: _tblock.setSize(_size) _angle = _data.get('angle') if _angle is not None: _tblock.setAngle(_angle) _align = _data.get('align') if _align is not None: _tblock.setAlignment(_align) finally: _tblock.unmute() self.saveData(undo, _op, _sdata) else: super(TextBlockLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/dimension.py0000644000175000017500000056707311307666657020720 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # generic dimension classes # import math import sys import types from PythonCAD.Generic import text from PythonCAD.Generic import point from PythonCAD.Generic import circle from PythonCAD.Generic import arc from PythonCAD.Generic import color from PythonCAD.Generic import units from PythonCAD.Generic import util from PythonCAD.Generic import tolerance from PythonCAD.Generic import baseobject from PythonCAD.Generic import entity _dtr = math.pi/180.0 _rtd = 180.0/math.pi class DimString(text.TextBlock): """A class for the visual presentation of the dimensional value. The DimString class is used to present the numerical display for the dimension. A DimString object is derived from the text.TextBlock class, so it shares all of that classes methods and attributes. The DimString class has the following additional properties: prefix: A prefix prepended to the dimension text suffix: A suffix appended to the dimension text units: The units the dimension text will display precision: The displayed dimension precision print_zero: Displayed dimensions will have a leading 0 if needed print_decimal: Displayed dimensions will have a trailing decimal point The DimString class has the following additional methods: {get/set}Prefix(): Get/Set the text preceding the dimension value. {get/set}Suffix(): Get/Set the text following the dimension value. {get/set}Units(): Define what units the dimension will be in. {get/set}Precision(): Get/Set how many fractional digits are displayed. {get/set}PrintZero(): Get/Set whether or not a dimension less than one unit long should have a leading 0 printed {get/set}PrintDecimal(): Get/Set whether or not a dimension with 0 fractional digits prints out the decimal point. {get/set}Dimension(): Get/Set the dimension using the DimString The DimString class has the following classmethods: {get/set}DefaultTextStyle(): Get/Set the default TextStyle for the class. """ __defstyle = None __messages = { 'prefix_changed' : True, 'suffix_changed' : True, 'units_changed' : True, 'precision_changed' : True, 'print_zero_changed' : True, 'print_decimal_changed' : True, 'dimension_changed' : True, } def __init__(self, x, y, **kw): """Initialize a DimString object ds = DimString(x, y, **kw) Arguments 'x' and 'y' should be floats. Various keyword arguments can also be used: text: Displayed text textstyle: The default textstyle family: Font family style: Font style weight: Font weight color: Text color size: Text size angle: Text angle align: Text alignment prefix: Default prefix suffix: Default suffix units: Displayed units precision: Displayed precision of units print_zero: Boolean to print a leading '0' print_decimal: Boolean to print a leading '.' By default, a DimString object has the following values ... prefix: Empty string suffix: Empty string unit: Millimeters precision: 3 decimal places print zero: True print decimal: True """ _text = u'' if 'text' in kw: _text = kw['text'] _tstyle = self.getDefaultTextStyle() if 'textstyle' in kw: _tstyle = kw['textstyle'] del kw['textstyle'] _prefix = u'' if 'prefix' in kw: _prefix = kw['prefix'] if not isinstance(_prefix, types.StringTypes): raise TypeError, "Invalid prefix type: " + `type(_prefix)` _suffix = u'' if 'suffix' in kw: _suffix = kw['suffix'] if not isinstance(_suffix, types.StringTypes): raise TypeError, "Invalid suffix type: " + `type(_suffix)` _unit = units.MILLIMETERS if 'units' in kw: _unit = kw['units'] _prec = 3 if 'precision' in kw: _prec = kw['precision'] if not isinstance(_prec, int): raise TypeError, "Invalid precision type: " + `type(_prec)` if _prec < 0 or _prec > 15: raise ValueError, "Invalid precision: %d" % _prec _pz = True if 'print_zero' in kw: _pz = kw['print_zero'] util.test_boolean(_pz) _pd = True if 'print_decimal' in kw: _pd = kw['print_decimal'] util.test_boolean(_pd) super(DimString, self).__init__(x, y, _text, textstyle=_tstyle, **kw) self.__prefix = _prefix self.__suffix = _suffix self.__unit = units.Unit(_unit) self.__precision = _prec self.__print_zero = _pz self.__print_decimal = _pd self.__dim = None def getDefaultTextStyle(cls): if cls.__defstyle is None: _s = text.TextStyle(u'Default Dimension Text Style', color=color.Color(0xffffff), align=text.TextStyle.ALIGN_CENTER) cls.__defstyle = _s return cls.__defstyle getDefaultTextStyle = classmethod(getDefaultTextStyle) def setDefaultTextStyle(cls, s): if not isinstance(s, text.TextStyle): raise TypeError, "Invalid TextStyle: " + `type(s)` cls.__defstyle = s setDefaultTextStyle = classmethod(setDefaultTextStyle) def finish(self): """Finalization for DimString instances. finish() """ if self.__dim is not None: self.__dim = None super(DimString, self).finish() def getValues(self): """Return values comprising the DimString. getValues() This method extends the TextBlock::getValues() method. """ _data = super(DimString, self).getValues() _data.setValue('type', 'dimstring') _data.setValue('prefix', self.__prefix) _data.setValue('suffix', self.__suffix) _data.setValue('units', self.__unit.getStringUnit()) _data.setValue('precision', self.__precision) _data.setValue('print_zero', self.__print_zero) _data.setValue('print_decimal', self.__print_decimal) return _data def getParent(self): """Get the entity containing the DimString. getParent() This method overrides the Entity::getParent() call. """ _parent = None if self.__dim is not None: _parent = self.__dim.getParent() return _parent def setLocation(self, x, y): """Set the location of the DimString. setLocation(x, y) Arguments 'x' and 'y' should be floats. This method extends the TextBlock::setLocation() method. """ # # the DimString location is defined in relation to # the position defined by the Dimension::setLocation() # call, so don't bother sending out 'moved' or 'modified' # messages # self.mute() try: super(DimString, self).setLocation(x, y) finally: self.unmute() def getPrefix(self): """Return the prefix for the DimString object. getPrefix() """ return self.__prefix def setPrefix(self, prefix=None): """Set the prefix for the DimString object. setPrefix([prefix]) Invoking this method without arguments sets the prefix to an empty string, or to the DimStyle value in the associated Dimension if one is set for the DimString. When an argument is passed, the argument should be a Unicode string. """ if self.isLocked(): raise RuntimeError, "Setting prefix not allowed - object locked." _p = prefix if _p is None: _p = u'' if self.__dim is not None: _p = self.__dim.getStyleValue(self, 'prefix') if not isinstance(_p, unicode): _p = unicode(prefix) _op = self.__prefix if _op != _p: self.startChange('prefix_changed') self.__prefix = _p self.endChange('prefix_changed') self.setBounds() self.sendMessage('prefix_changed', _op) self.modified() prefix = property(getPrefix, setPrefix, None, 'Dimension string prefix') def getSuffix(self): """Return the suffix for the DimString object. getSuffix() """ return self.__suffix def setSuffix(self, suffix=None): """Set the suffix for the DimString object. setSuffix([suffix]) Invoking this method without arguments sets the suffix to an empty string, or to the DimStyle value in the associated Dimension if one is set for the DimString.. When an argument is passed, the argument should be a Unicode string. """ if self.isLocked(): raise RuntimeError, "Setting suffix not allowed - object locked." _s = suffix if _s is None: _s = u'' if self.__dim is not None: _s = self.__dim.getStyleValue(self, 'suffix') if not isinstance(_s, unicode): _s = unicode(suffix) _os = self.__suffix if _os != _s: self.startChange('suffix_changed') self.__suffix = _s self.endChange('suffix_changed') self.setBounds() self.sendMessage('suffix_changed', _os) self.modified() suffix = property(getSuffix, setSuffix, None, 'Dimension string suffix') def getPrecision(self): """Return the number of decimal points used for the DimString. getPrecision() """ return self.__precision def setPrecision(self, precision=None): """Set the number of decimal points used for the DimString. setPrecision([p]) The valid range of p is 0 <= p <= 15. Invoking this method without arguments sets the precision to 3, or to the DimStyle value in the associated Dimension if one is set for the DimString.. """ if self.isLocked(): raise RuntimeError, "Setting precision not allowed - object locked." _p = precision if _p is None: _p = 3 if self.__dim is not None: _p = self.__dim.getStyleValue(self, 'precision') if not isinstance(_p, int): raise TypeError, "Invalid precision type: " + `type(_p)` if _p < 0 or _p > 15: raise ValueError, "Invalid precision: %d" % _p _op = self.__precision if _op != _p: self.startChange('precision_changed') self.__precision = _p self.endChange('precision_changed') self.setBounds() self.sendMessage('precision_changed', _op) self.modified() precision = property(getPrecision, setPrecision, None, 'Dimension precision') def getUnits(self): """Return the current units used in the DimString(). getUnits() """ return self.__unit.getUnit() def setUnits(self, unit=None): """The the units for the DimString. setUnits([unit]) The value units are given in the units module. Invoking this method without arguments sets the units to millimeters, or to the DimStyle value of the associated Dimension if one is set for the DimString. """ _u = unit if _u is None: _u = units.MILLIMETERS if self.__dim is not None: _u = self.__dim.getStyleValue(self, 'units') _ou = self.__unit.getUnit() if _ou != _u: self.startChange('units_changed') self.__unit.setUnit(_u) self.endChange('units_changed') self.setBounds() self.sendMessage('units_changed', _ou) self.modified() units = property(getUnits, setUnits, None, 'Dimensional units.') def getPrintZero(self): """Return whether or not a leading 0 is printed for the DimString. getPrintZero() """ return self.__print_zero def setPrintZero(self, print_zero=None): """Set whether or not a leading 0 is printed for the DimString. setPrintZero([pz]) Invoking this method without arguments sets the value to True, or to the DimStyle value of the associated Dimension if one is set for the DimString. If called with an argument, the argument should be either True or False. """ _pz = print_zero if _pz is None: _pz = True if self.__dim is not None: _pz = self.__dim.getStyleValue(self, 'print_zero') util.test_boolean(_pz) _flag = self.__print_zero if _flag is not _pz: self.startChange('print_zero_changed') self.__print_zero = _pz self.endChange('print_zero_changed') self.setBounds() self.sendMessage('print_zero_changed', _flag) self.modified() print_zero = property(getPrintZero, setPrintZero, None, 'Print a leading 0 for decimal dimensions') def getPrintDecimal(self): """Return whether or not the DimString will print a trailing decimal. getPrintDecimal() """ return self.__print_decimal def setPrintDecimal(self, print_decimal=None): """Set whether or not the DimString will print a trailing decimal. setPrintDecimal([pd]) Invoking this method without arguments sets the value to True, or to the DimStyle value of the associated Dimension if one is set for the DimString. If called with an argument, the argument should be either True or False. """ _pd = print_decimal if _pd is None: _pd = True if self.__dim is not None: _pd = self.__dim.getStyleValue(self, 'print_decimal') util.test_boolean(_pd) _flag = self.__print_decimal if _flag is not _pd: self.startChange('print_decimal_changed') self.__print_decimal = _pd self.endChange('print_decimal_changed') self.setBounds() self.sendMessage('print_decimal_changed', _flag) self.modified() print_decimal = property(getPrintDecimal, setPrintDecimal, None, 'Print a decimal point after the dimension value') def getDimension(self): """Return the dimension using the Dimstring. getDimension() This method can return None if there is not Dimension association set for the DimString. """ return self.__dim def setDimension(self, dim, adjust): """Set the dimension using this DimString. setDimension(dim, adjust) Argument 'dim' must be a Dimension or None, and argument 'adjust' must be a Boolean. Argument 'adjust' is only used if a Dimension is passed for the first argument. """ _dim = dim if _dim is not None and not isinstance(_dim, Dimension): raise TypeError, "Invalid dimension: " + `type(_dim)` util.test_boolean(adjust) _d = self.__dim if _d is not _dim: self.startChange('dimension_changed') self.__dim = _dim self.endChange('dimension_changed') if _dim is not None and adjust: self.setPrefix() self.setSuffix() self.setPrecision() self.setUnits() self.setPrintZero() self.setPrintDecimal() self.setFamily() self.setStyle() self.setWeight() self.setColor() self.setSize() self.setAngle() self.setAlignment() self.sendMessage('dimension_changed', _d) self.modified() if self.__dim is not None: self.setParent(self.__dim.getParent()) # # extend the TextBlock set methods to use the values # found in a DimStyle if one is available # def setFamily(self, family=None): """Set the font family for the DimString. setFamily([family]) Calling this method without an argument will set the family to that given in the DimStyle of the associated Dimension if one is set for this DimString. """ _family = family if _family is None and self.__dim is not None: _family = self.__dim.getStyleValue(self, 'font_family') super(DimString, self).setFamily(_family) def setStyle(self, style=None): """Set the font style for the DimString. setStyle([style]) Calling this method without an argument will set the font style to that given in the DimStyle of the associated Dimension if one is set for this DimString. """ _style = style if _style is None and self.__dim is not None: _style = self.__dim.getStyleValue(self, 'font_style') super(DimString, self).setStyle(_style) def setWeight(self, weight=None): """Set the font weight for the DimString. setWeight([weight]) Calling this method without an argument will set the font weight to that given in the DimStyle of the associated Dimension if one is set for this DimString. """ _weight = weight if _weight is None and self.__dim is not None: _weight = self.__dim.getStyleValue(self, 'font_weight') super(DimString, self).setWeight(_weight) def setColor(self, color=None): """Set the font color for the DimString. setColor([color]) Calling this method without an argument will set the font color to that given in the DimStyle of the associated Dimension if one is set for this DimString. """ _color = color if _color is None and self.__dim is not None: _color = self.__dim.getStyleValue(self, 'color') super(DimString, self).setColor(_color) def setSize(self, size=None): """Set the text size for the DimString. setSize([size]) Calling this method without an argument will set the text size to that given in the DimStyle of the associated Dimension if one is set for this DimString. """ _size = size if _size is None and self.__dim is not None: _size = self.__dim.getStyleValue(self, 'size') super(DimString, self).setSize(_size) def setAngle(self, angle=None): """Set the text angle for the DimString. setAngle([angle]) Calling this method without an argument will set the text angle to that given in the DimStyle of the associated Dimension if one is set for this DimString. """ _angle = angle if _angle is None and self.__dim is not None: _angle = self.__dim.getStyleValue(self, 'angle') super(DimString, self).setAngle(_angle) def setAlignment(self, align=None): """Set the text alignment for the DimString. setAlignment([align]) Calling this method without an argument will set the text alignment to that given in the DimStyle of the associated Dimension if one is set for this DimString. """ _align = align if _align is None and self.__dim is not None: _align = self.__dim.getStyleValue(self, 'alignment') super(DimString, self).setAlignment(_align) def setText(self, text): """Set the text in the DimString. This method overrides the setText method in the TextBlock. """ pass def formatDimension(self, dist): """Return a formatted numerical value for a dimension. formatDimension(dist) The argument 'dist' should be a float value representing the distance in millimeters. The returned value will have the prefix prepended and suffix appended to the numerical value that has been formatted with the precision. """ _d = abs(util.get_float(dist)) _fmtstr = u"%%#.%df" % self.__precision _dstr = _fmtstr % self.__unit.fromMillimeters(_d) if _d < 1.0 and self.__print_zero is False: _dstr = _dstr[1:] if _dstr.endswith('.') and self.__print_decimal is False: _dstr = _dstr[:-1] _text = self.__prefix + _dstr + self.__suffix # # don't send out 'text_changed' or 'modified' messages # self.mute() try: super(DimString, self).setText(_text) finally: self.unmute() return _text def sendsMessage(self, m): if m in DimString.__messages: return True return super(DimString, self).sendsMessage(m) class DimBar(entity.Entity): """The class for the dimension bar. A dimension bar leads from the point the dimension references out to, and possibly beyond, the point where the dimension text bar the DimBar to another DimBar. Linear, horizontal, vertical, and angular dimension will have two dimension bars; radial dimensions have none. The DimBar class has the following methods: getEndpoints(): Get the x/y position of the DimBar start and end {get/set}FirstEndpoint(): Get/Set the starting x/y position of the DimBar. {get/set}SecondEndpoint(): Get/Set the ending x/y position of the DimBar. getAngle(): Get the angle at which the DimBar slopes getSinCosValues(): Get trig values used for transformation calculations. """ __messages = { 'attribute_changed' : True, } def __init__(self, x1=0.0, y1=0.0, x2=0.0, y2=0.0, **kw): """Initialize a DimBar. db = DimBar([x1, y1, x2, y2]) By default all the arguments are 0.0. Any arguments passed to this method should be float values. """ _x1 = util.get_float(x1) _y1 = util.get_float(y1) _x2 = util.get_float(x2) _y2 = util.get_float(y2) super(DimBar, self).__init__(**kw) self.__ex1 = _x1 self.__ey1 = _y1 self.__ex2 = _x2 self.__ey2 = _y2 def getEndpoints(self): """Return the coordinates of the DimBar endpoints. getEndpoints() This method returns two tuples, each containing two float values. The first tuple gives the x/y coordinates of the DimBar start, the second gives the coordinates of the DimBar end. """ _ep1 = (self.__ex1, self.__ey1) _ep2 = (self.__ex2, self.__ey2) return _ep1, _ep2 def setFirstEndpoint(self, x, y): """Set the starting coordinates for the DimBar setFirstEndpoint(x, y) Arguments x and y should be float values. """ if self.isLocked(): raise RuntimeError, "Setting endpoint not allowed - object locked." _x = util.get_float(x) _y = util.get_float(y) _sx = self.__ex1 _sy = self.__ey1 if abs(_sx - _x) > 1e-10 or abs(_sy - _y) > 1e-10: self.__ex1 = _x self.__ey1 = _y self.sendMessage('attribute_changed', 'endpoint', _sx, _sy, self.__ex2, self.__ey2) self.modified() def getFirstEndpoint(self): """Return the starting coordinates of the DimBar. getFirstEndpoint() This method returns a tuple giving the x/y coordinates. """ return self.__ex1, self.__ey1 def setSecondEndpoint(self, x, y): """Set the ending coordinates for the DimBar setSecondEndpoint(x, y) Arguments x and y should be float values. """ if self.isLocked(): raise RuntimeError, "Setting endpoint not allowed - object locked." _x = util.get_float(x) _y = util.get_float(y) _sx = self.__ex2 _sy = self.__ey2 if abs(_sx - _x) > 1e-10 or abs(_sy - _y) > 1e-10: self.__ex2 = _x self.__ey2 = _y self.sendMessage('attribute_changed', 'endpoint', self.__ex1, self.__ey1, _sx, _sy) self.modified() def getSecondEndpoint(self): """Return the ending coordinates of the DimBar. getSecondEndpoint() This method returns a tuple giving the x/y coordinates. """ return self.__ex2, self.__ey2 def getAngle(self): """Return the angle at which the DimBar lies. getAngle() This method returns a float value giving the angle of inclination of the DimBar. The value returned will be a positive value less than 360.0. """ _x1 = self.__ex1 _y1 = self.__ey1 _x2 = self.__ex2 _y2 = self.__ey2 if abs(_x2 - _x1) < 1e-10 and abs(_y2 - _y1) < 1e-10: raise ValueError, "Endpoints are equal" if abs(_x2 - _x1) < 1e-10: # vertical if _y2 > _y1: _angle = 90.0 else: _angle = 270.0 elif abs(_y2 - _y1) < 1e-10: # horizontal if _x2 > _x1: _angle = 0.0 else: _angle = 180.0 else: _angle = _rtd * math.atan2((_y2 - _y1), (_x2 - _x1)) if _angle < 0.0: _angle = _angle + 360.0 return _angle def getSinCosValues(self): """Return sin()/cos() values based on the DimBar slope getSinCosValues() This method returns a tuple of two floats. The first value is the sin() value, the second is the cos() value. """ _x1 = self.__ex1 _y1 = self.__ey1 _x2 = self.__ex2 _y2 = self.__ey2 if abs(_x2 - _x1) < 1e-10: # vertical _cosine = 0.0 if _y2 > _y1: _sine = 1.0 else: _sine = -1.0 elif abs(_y2 - _y1) < 1e-10: # horizontal _sine = 0.0 if _x2 > _x1: _cosine = 1.0 else: _cosine = -1.0 else: _angle = math.atan2((_y2 - _y1), (_x2 - _x1)) _sine = math.sin(_angle) _cosine = math.cos(_angle) return _sine, _cosine def sendsMessage(self, m): if m in DimBar.__messages: return True return super(DimBar, self).sendsMessage(m) class DimCrossbar(DimBar): """The class for the Dimension crossbar. The DimCrossbar class is drawn between two DimBar objects for horizontal, vertical, and generic linear dimensions. The dimension text is place over the DimCrossbar object. Arrow heads, circles, or slashes can be drawn at the intersection of the DimCrossbar and the DimBar if desired. These objects are called markers. The DimCrossbar class is derived from the DimBar class so it shares all the methods of that class. In addition the DimCrossbar class has the following methods: {set/get}FirstCrossbarPoint(): Set/Get the initial location of the crossbar. {set/get}SecondCrossbarPoint(): Set/Get the ending location of the crossbar. getCrossbarPoints(): Get the location of the crossbar endpoints. clearMarkerPoints(): Delete the stored coordintes of the dimension markers. storeMarkerPoint(): Save a coordinate pair of the dimension marker. getMarkerPoints(): Return the coordinates of the dimension marker. """ __messages = {} def __init__(self, **kw): """Initialize a DimCrossbar object. dcb = DimCrossbar() This method takes no arguments. """ super(DimCrossbar, self).__init__(**kw) self.__mx1 = 0.0 self.__my1 = 0.0 self.__mx2 = 0.0 self.__my2 = 0.0 self.__mpts = [] def setFirstCrossbarPoint(self, x, y): """Store the initial endpoint of the DimCrossbar. setFirstCrossbarPoint(x, y) Arguments x and y should be floats. """ if self.isLocked(): raise RuntimeError, "Setting crossbar point not allowed - object locked." _x = util.get_float(x) _y = util.get_float(y) _sx = self.__mx1 _sy = self.__my1 if abs(_sx - _x) > 1e-10 or abs(_sy - _y) > 1e-10: self.__mx1 = _x self.__my1 = _y self.sendMessage('attribute_changed', 'barpoint', _sx, _sy, self.__mx2, self.__my2) self.modified() def getFirstCrossbarPoint(self): """Return the initial coordinates of the DimCrossbar. getFirstCrossbarPoint() This method returns a tuple of two floats giving the x/y coordinates. """ return self.__mx1, self.__my1 def setSecondCrossbarPoint(self, x, y): """Store the terminal endpoint of the DimCrossbar. setSecondCrossbarPoint(x, y) Arguments 'x' and 'y' should be floats. """ if self.isLocked(): raise RuntimeError, "Setting crossbar point not allowed - object locked" _x = util.get_float(x) _y = util.get_float(y) _sx = self.__mx2 _sy = self.__my2 if abs(_sx - _x) > 1e-10 or abs(_sy - _y) > 1e-10: self.__mx2 = _x self.__my2 = _y self.sendMessage('attribute_changed', 'barpoint', self.__mx1, self.__my1, _sx, _sy) self.modified() def getSecondCrossbarPoint(self): """Return the terminal coordinates of the DimCrossbar. getSecondCrossbarPoint() This method returns a tuple of two floats giving the x/y coordinates. """ return self.__mx2, self.__my2 def getCrossbarPoints(self): """Return the endpoints of the DimCrossbar. getCrossbarPoints() This method returns two tuples, each tuple containing two float values giving the x/y coordinates. """ _mp1 = (self.__mx1, self.__my1) _mp2 = (self.__mx2, self.__my2) return _mp1, _mp2 def clearMarkerPoints(self): """Delete the stored location of any dimension markers. clearMarkerPoints() """ del self.__mpts[:] def storeMarkerPoint(self, x, y): """Save a coordinate pair of the current dimension marker. storeMarkerPoint(x, y) Arguments 'x' and 'y' should be floats. Each time this method is invoked the list of stored coordinates is appended with the values given as arguments. """ _x = util.get_float(x) _y = util.get_float(y) self.__mpts.append((_x, _y)) def getMarkerPoints(self): """Return the stored marker coordinates. getMarkerPoints() This method returns a list of coordinates stored with storeMarkerPoint(). Each item in the list is a tuple holding two float values - the x/y coordinate of the point. """ return self.__mpts[:] def sendsMessage(self, m): if m in DimCrossbar.__messages: return True return super(DimCrossbar, self).sendsMessage(m) class DimCrossarc(DimCrossbar): """The class for specialized crossbars for angular dimensions. The DimCrossarc class is meant to be used only with angular dimensions. As an angular dimension has two DimBar objects that are connected with an arc. The DimCrossarc class is derived from the DimCrossbar class so it shares all the methods of that class. The DimCrossarc class has the following additional methods: {get/set}Radius(): Get/Set the radius of the arc. {get/set}StartAngle(): Get/Set the arc starting angle. {get/set}EndAngle(): Get/Set the arc finishing angle. """ __messages = { 'arcpoint_changed' : True, 'radius_changed' : True, 'start_angle_changed' : True, 'end_angle_changed' : True, } def __init__(self, radius=0.0, start=0.0, end=0.0, **kw): """Initialize a DimCrossarc object. dca = DimCrossarc([radius, start, end]) By default the arguments are all 0.0. Any arguments passed to this method should be floats. """ super(DimCrossarc, self).__init__(**kw) _r = util.get_float(radius) if _r < 0.0: raise ValueError, "Invalid radius: %g" % _r _start = util.make_c_angle(start) _end = util.make_c_angle(end) self.__radius = _r self.__start = _start self.__end = _end def getRadius(self): """Return the radius of the arc. getRadius() This method returns a float value. """ return self.__radius def setRadius(self, radius): """Set the radius of the arc. setRadius(radius) Argument 'radius' should be a float value greater than 0.0. """ if self.isLocked(): raise RuntimeError, "Setting radius not allowed - object locked." _r = util.get_float(radius) if _r < 0.0: raise ValueError, "Invalid radius: %g" % _r _sr = self.__radius if abs(_sr - _r) > 1e-10: self.startChange('radius_changed') self.__radius = _r self.endChange('radius_changed') self.sendMessage('radius_changed', _sr) self.modified() def getStartAngle(self): """Return the arc starting angle. getStartAngle() This method returns a float. """ return self.__start def setStartAngle(self, angle): """Set the starting angle of the arc. setStartAngle(angle) Argument angle should be a float value. """ if self.isLocked(): raise RuntimeError, "Setting start angle not allowed - object locked." _sa = self.__start _angle = util.make_c_angle(angle) if abs(_sa - _angle) > 1e-10: self.startChange('start_angle_changed') self.__start = _angle self.endChange('start_angle_changed') self.sendMessage('start_angle_changed', _sa) self.modified() def getEndAngle(self): """Return the arc ending angle. getEndAngle() This method returns a float. """ return self.__end def setEndAngle(self, angle): """Set the ending angle of the arc. setEndAngle(angle) Argument angle should be a float value. """ if self.isLocked(): raise RuntimeError, "Setting end angle not allowed - object locked." _ea = self.__end _angle = util.make_c_angle(angle) if abs(_ea - _angle) > 1e-10: self.startChange('end_angle_changed') self.__end = _angle self.endChange('end_angle_changed') self.sendMessage('end_angle_changed', _ea) self.modified() def getAngle(self): pass # override the DimBar::getAngle() method def getSinCosValues(self): pass # override the DimBar::getSinCosValues() method def sendsMessage(self, m): if m in DimCrossarc.__messages: return True return super(DimCrossarc, self).sendsMessage(m) class Dimension(entity.Entity): """The base class for Dimensions A Dimension object is meant to be a base class for specialized dimensions. Every Dimension object holds two DimString objects, so any dimension can be displayed with two separate formatting options and units. A Dimension has the following methods {get/set}DimStyle(): Get/Set the DimStyle used for this Dimension. getPrimaryDimstring(): Return the DimString used for formatting the Primary dimension. getSecondaryDimstring(): Return the DimString used for formatting the Secondary dimension. {get/set}EndpointType(): Get/Set the type of endpoints used in the Dimension {get/set}EndpointSize(): Get/Set the size of the dimension endpoints {get/set}DualDimMode(): Get/Set whether or not to display both the Primary and Secondary DimString objects {get/set}Offset(): Get/Set how far from the dimension endpoints to draw dimension lines at the edges of the dimension. {get/set}Extension(): Get/Set how far past the dimension crossbar line to draw. {get/set}Position(): Get/Set where the dimensional values are placed on the dimension cross bar. {get/set}Color(): Get/Set the color used to draw the dimension lines. {get/set}Location(): Get/Set where to draw the dimensional values. {get/set}PositionOffset(): Get/Set the dimension text offset when the text is above or below the crossbar/crossarc {get/set}DualModeOffset(): Get/Set the text offset for spaceing the two dimension strings above and below the bar separating the two dimensions {get/set}Thickness(): Get/Set the Dimension thickness. {get/set}Scale(): Get/Set the Dimension scaling factor. getStyleValue(): Return the DimStyle value for some option getDimensions(): Return the formatted dimensional values in this Dimension. inRegion(): Return if the dimension is visible within some are. calcDimValues(): Calculate the dimension lines endpoints. mapCoords(): Return the coordinates on the dimension within some point. onDimension(): Test if an x/y coordinate pair hit the dimension lines. getBounds(): Return the minma and maximum locations of the dimension. The Dimension class has the following classmethods: {get/set}DefaultDimStyle(): Get/Set the default DimStyle for the class. getEndpointTypeAsString(): Return the endpoint type as a string for a value. getEndpointTypeFromString(): Return the endpoint type value given a string. getEndpointTypeStrings(): Get the endpoint types values as strings. getEndpointTypeValues(): Get the endpoint type values. getPositionAsString(): Return the text position as a string for a value. getPositionFromString(): Return the text postion value given a string. getPositionStrings(): Get the text position values as strings. getPositionValues(): Get the text position values. """ # # Endpoint # DIM_ENDPT_NONE= 0 DIM_ENDPT_ARROW = 1 DIM_ENDPT_FILLED_ARROW = 2 DIM_ENDPT_SLASH = 3 DIM_ENDPT_CIRCLE = 4 # # Dimension position on dimline # DIM_TEXT_POS_SPLIT = 0 DIM_TEXT_POS_ABOVE = 1 DIM_TEXT_POS_BELOW = 2 __defstyle = None __messages = { 'dimstyle_changed' : True, 'endpoint_type_changed' : True, 'endpoint_size_changed' : True, 'dual_mode_changed' : True, 'offset_changed' : True, 'extension_changed' : True, 'position_changed' : True, 'position_offset_changed' : True, 'dual_mode_offset_changed' : True, 'color_changed' : True, 'thickness_changed' : True, 'scale_changed' : True, 'location_changed' : True, 'dimstring_changed' : True, 'moved' : True, } def __init__(self, x, y, dimstyle=None, **kw): """Initialize a Dimension object dim = Dimension(x, y[, ds]) Arguments 'x' and 'y' should be float values. Optional argument 'ds' should be a DimStyle instance. A default DimStyle is used of the optional argument is not used. """ _x = util.get_float(x) _y = util.get_float(y) _ds = dimstyle if _ds is None: _ds = self.getDefaultDimStyle() if not isinstance(_ds, DimStyle): raise TypeError, "Invalid DimStyle type: " + `type(_ds)` _ddm = None if 'dual-mode' in kw: _ddm = kw['dual-mode'] if _ddm is not None: util.test_boolean(_ddm) if _ddm is _ds.getValue('DIM_DUAL_MODE'): _ddm = None _offset = None if 'offset' in kw: _offset = util.get_float(kw['offset']) if _offset is not None: if _offset < 0.0: raise ValueError, "Invalid dimension offset: %g" % _offset if abs(_offset - _ds.getValue('DIM_OFFSET')) < 1e-10: _offset = None _extlen = None if 'extlen' in kw: _extlen = util.get_float(kw['extlen']) if _extlen < 0.0: raise ValueError, "Invalid dimension extension: %g" % _extlen if abs(_extlen - _ds.getValue('DIM_EXTENSION')) < 1e-10: _extlen = None _textpos = None if 'textpos' in kw: _textpos = kw['textpos'] if (_textpos != Dimension.DIM_TEXT_POS_SPLIT and _textpos != Dimension.DIM_TEXT_POS_ABOVE and _textpos != Dimension.DIM_TEXT_POS_BELOW): raise ValueError, "Invalid dimension text position: '%s'" % str(_textpos) if _textpos == _ds.getValue('DIM_POSITION'): _textpos = None _poffset = None if 'poffset' in kw: _poffset = util.get_float(kw['poffset']) if _poffset < 0.0: raise ValueError, "Invalid text offset length %g" % _poffset if abs(_poffset - _ds.getValue('DIM_POSITION_OFFSET')) < 1e-10: _poffset = None _dmoffset = None if 'dmoffset' in kw: _dmoffset = util.get_float(kw['dmoffset']) if _dmoffset < 0.0: raise ValueError, "Invalid dual mode offset length %g" % _dmoffset if abs(_dmoffset - _ds.getValue('DIM_DUAL_MODE_OFFSET')) < 1e-10: _dmoffset = None _eptype = None if 'eptype' in kw: _eptype = kw['eptype'] if (_eptype != Dimension.DIM_ENDPT_NONE and _eptype != Dimension.DIM_ENDPT_ARROW and _eptype != Dimension.DIM_ENDPT_FILLED_ARROW and _eptype != Dimension.DIM_ENDPT_SLASH and _eptype != Dimension.DIM_ENDPT_CIRCLE): raise ValueError, "Invalid endpoint: '%s'" % str(_eptype) if _eptype == _ds.getValue('DIM_ENDPOINT'): _eptype = None _epsize = None if 'epsize' in kw: _epsize = util.get_float(kw['epsize']) if _epsize < 0.0: raise ValueError, "Invalid endpoint size %g" % _epsize if abs(_epsize - _ds.getValue('DIM_ENDPOINT_SIZE')) < 1e-10: _epsize = None _color = None if 'color' in kw: _color = kw['color'] if not isinstance(_color, color.Color): raise TypeError, "Invalid color type: " + `type(_color)` if _color == _ds.getValue('DIM_COLOR'): _color = None _thickness = None if 'thickness' in kw: _thickness = util.get_float(kw['thickness']) if _thickness < 0.0: raise ValueError, "Invalid thickness: %g" % _thickness if abs(_thickness - _ds.getValue('DIM_THICKNESS')) < 1e-10: _thickness = None _scale = 1.0 if 'scale' in kw: _scale = util.get_float(kw['scale']) if not _scale > 0.0: raise ValueError, "Invalid scale: %g" % _scale # # dimstrings # # the setDimension() call will adjust the values in the # new DimString instances if they get created # _ds1 = _ds2 = None _ds1adj = _ds2adj = True if 'ds1' in kw: _ds1 = kw['ds1'] if not isinstance(_ds1, DimString): raise TypeError, "Invalid DimString type: " + `type(_ds1)` _ds1adj = False if _ds1 is None: _ds1 = DimString(_x, _y) # if 'ds2' in kw: _ds2 = kw['ds2'] if not isinstance(_ds2, DimString): raise TypeError, "Invalid DimString type: " + `type(_ds2)` _ds2adj = False if _ds2 is None: _ds2 = DimString(_x, _y) # # finally ... # super(Dimension, self).__init__(**kw) self.__dimstyle = _ds self.__ddm = _ddm self.__offset = _offset self.__extlen = _extlen self.__textpos = _textpos self.__poffset = _poffset self.__dmoffset = _dmoffset self.__eptype = _eptype self.__epsize = _epsize self.__color = _color self.__thickness = _thickness self.__scale = _scale self.__dimloc = (_x, _y) self.__ds1 = _ds1 self.__ds2 = _ds2 self.__ds1.setDimension(self, _ds1adj) self.__ds2.setDimension(self, _ds2adj) _ds1.connect('change_pending', self.__dimstringChangePending) _ds1.connect('change_complete', self.__dimstringChangeComplete) _ds2.connect('change_pending', self.__dimstringChangePending) _ds2.connect('change_complete', self.__dimstringChangeComplete) def getDefaultDimStyle(cls): if cls.__defstyle is None: cls.__defstyle = DimStyle(u'Default DimStyle') return cls.__defstyle getDefaultDimStyle = classmethod(getDefaultDimStyle) def setDefaultDimStyle(cls, s): if not isinstance(s, DimStyle): raise TypeError, "Invalid DimStyle: " + `type(s)` cls.__defstyle = s setDefaultDimStyle = classmethod(setDefaultDimStyle) def finish(self): self.__ds1.disconnect(self) self.__ds2.disconnect(self) self.__ds1.finish() self.__ds2.finish() self.__ds1 = self.__ds2 = None super(Dimension, self).finish() def getValues(self): """Return values comprising the Dimension. getValues() This method extends the Entity::getValues() method. """ _data = super(Dimension, self).getValues() _data.setValue('location', self.__dimloc) if self.__offset is not None: _data.setValue('offset', self.__offset) if self.__extlen is not None: _data.setValue('extension', self.__extlen) if self.__textpos is not None: _data.setValue('position', self.__textpos) if self.__eptype is not None: _data.setValue('eptype', self.__eptype) if self.__epsize is not None: _data.setValue('epsize', self.__epsize) if self.__color is not None: _data.setValue('color', self.__color.getColors()) if self.__ddm is not None: _data.setValue('dualmode', self.__ddm) if self.__poffset is not None: _data.setValue('poffset', self.__poffset) if self.__dmoffset is not None: _data.setValue('dmoffset', self.__dmoffset) if self.__thickness is not None: _data.setValue('thickness', self.__thickness) _data.setValue('ds1', self.__ds1.getValues()) _data.setValue('ds2', self.__ds2.getValues()) _data.setValue('dimstyle', self.__dimstyle.getValues()) return _data def getDimStyle(self): """Return the DimStyle used in this Dimension. getDimStyle() """ return self.__dimstyle def setDimStyle(self, ds): """Set the DimStyle used for this Dimension. setDimStyle(ds) After setting the DimStyle, the values stored in it are applied to the DimensionObject. """ if self.isLocked(): raise RuntimeError, "Changing dimstyle not allowed - object locked." if not isinstance(ds, DimStyle): raise TypeError, "Invalid DimStyle type: " + `type(ds)` _sds = self.__dimstyle if ds is not _sds: _opts = self.getValues() self.startChange('dimstyle_changed') self.__dimstyle = ds self.endChange('dimstyle_changed') # # call the various methods without arguments # so the values given in the new DimStyle are used # self.setOffset() self.setExtension() self.setPosition() self.setEndpointType() self.setEndpointSize() self.setColor() self.setThickness() self.setDualDimMode() self.setPositionOffset() self.setDualModeOffset() # # set the values in the two DimString instances # _d = self.__ds1 _d.setPrefix(ds.getValue('DIM_PRIMARY_PREFIX')) _d.setSuffix(ds.getValue('DIM_PRIMARY_SUFFIX')) _d.setPrecision(ds.getValue('DIM_PRIMARY_PRECISION')) _d.setUnits(ds.getValue('DIM_PRIMARY_UNITS')) _d.setPrintZero(ds.getValue('DIM_PRIMARY_LEADING_ZERO')) _d.setPrintDecimal(ds.getValue('DIM_PRIMARY_TRAILING_DECIMAL')) _d.setFamily(ds.getValue('DIM_PRIMARY_FONT_FAMILY')) _d.setWeight(ds.getValue('DIM_PRIMARY_FONT_WEIGHT')) _d.setStyle(ds.getValue('DIM_PRIMARY_FONT_STYLE')) _d.setColor(ds.getValue('DIM_PRIMARY_FONT_COLOR')) _d.setSize(ds.getValue('DIM_PRIMARY_TEXT_SIZE')) _d.setAngle(ds.getValue('DIM_PRIMARY_TEXT_ANGLE')) _d.setAlignment(ds.getVaue('DIM_PRIMARY_TEXT_ALIGNMENT')) _d = self.__ds2 _d.setPrefix(ds.getValue('DIM_SECONDARY_PREFIX')) _d.setSuffix(ds.getValue('DIM_SECONDARY_SUFFIX')) _d.setPrecision(ds.getValue('DIM_SECONDARY_PRECISION')) _d.setUnits(ds.getValue('DIM_SECONDARY_UNITS')) _d.setPrintZero(ds.getValue('DIM_SECONDARY_LEADING_ZERO')) _d.setPrintDecimal(ds.getValue('DIM_SECONDARY_TRAILING_DECIMAL')) _d.setFamily(ds.getValue('DIM_SECONDARY_FONT_FAMILY')) _d.setWeight(ds.getValue('DIM_SECONDARY_FONT_WEIGHT')) _d.setStyle(ds.getValue('DIM_SECONDARY_FONT_STYLE')) _d.setColor(ds.getValue('DIM_SECONDARY_FONT_COLOR')) _d.setSize(ds.getValue('DIM_SECONDARY_TEXT_SIZE')) _d.setAngle(ds.getValue('DIM_SECONDARY_TEXT_ANGLE')) _d.setAlignment(ds.getVaue('DIM_SECONDARY_TEXT_ALIGNMENT')) self.sendMessage('dimstyle_changed', _sds, _opts) self.modified() dimstyle = property(getDimStyle, setDimStyle, None, "Dimension DimStyle object.") def getEndpointTypeAsString(cls, ep): """Return a text string for the dimension endpoint type. getEndpointTypeAsString(ep) This classmethod returns 'none', 'arrow', or 'filled-arrow', 'slash', or 'circle'. """ if not isinstance(ep, int): raise TypeError, "Invalid argument type: " + `type(ep)` if ep == Dimension.DIM_ENDPT_NONE: _str = 'none' elif ep == Dimension.DIM_ENDPT_ARROW: _str = 'arrow' elif ep == Dimension.DIM_ENDPT_FILLED_ARROW: _str = 'filled-arrow' elif ep == Dimension.DIM_ENDPT_SLASH: _str = 'slash' elif ep == Dimension.DIM_ENDPT_CIRCLE: _str = 'circle' else: raise ValueError, "Unexpected endpoint type value: %d" % ep return _str getEndpointTypeAsString = classmethod(getEndpointTypeAsString) def getEndpointTypeFromString(cls, s): """Return the dimension endpoint type given a string argument. getEndpointTypeFromString(ep) This classmethod returns a value based on the string argument: 'none' -> Dimension.DIM_ENDPT_NONE 'arrow' -> Dimension.DIM_ENDPT_ARROW 'filled-arrow' -> Dimension.DIM_ENDPT_FILLED_ARROW 'slash' -> Dimension.DIM_ENDPT_SLASH 'circle' -> Dimension.DIM_ENDPT_CIRCLE If the string is not listed above a ValueError execption is raised. """ if not isinstance(s, str): raise TypeError, "Invalid argument type: " + `type(s)` _ls = s.lower() if _ls == 'none': _v = Dimension.DIM_ENDPT_NONE elif _ls == 'arrow': _v = Dimension.DIM_ENDPT_ARROW elif (_ls == 'filled-arrow' or _ls == 'filled_arrow'): _v = Dimension.DIM_ENDPT_FILLED_ARROW elif _ls == 'slash': _v = Dimension.DIM_ENDPT_SLASH elif _ls == 'circle': _v = Dimension.DIM_ENDPT_CIRCLE else: raise ValueError, "Unexpected endpoint type string: " + s return _v getEndpointTypeFromString = classmethod(getEndpointTypeFromString) def getEndpointTypeStrings(cls): """Return the endpoint types as strings. getEndpointTypeStrings() This classmethod returns a list of strings. """ return [_('None'), _('Arrow'), _('Filled-Arrow'), _('Slash'), _('Circle') ] getEndpointTypeStrings = classmethod(getEndpointTypeStrings) def getEndpointTypeValues(cls): """Return the endpoint type values. getEndpointTypeValues() This classmethod returns a list of values. """ return [Dimension.DIM_ENDPT_NONE, Dimension.DIM_ENDPT_ARROW, Dimension.DIM_ENDPT_FILLED_ARROW, Dimension.DIM_ENDPT_SLASH, Dimension.DIM_ENDPT_CIRCLE ] getEndpointTypeValues = classmethod(getEndpointTypeValues) def getEndpointType(self): """Return what type of endpoints the Dimension uses. getEndpointType() """ _et = self.__eptype if _et is None: _et = self.__dimstyle.getValue('DIM_ENDPOINT') return _et def setEndpointType(self, eptype=None): """Set what type of endpoints the Dimension will use. setEndpointType([e]) The argument 'e' should be one of the following dimension.NO_ENDPOINT => no special marking at the dimension crossbar ends dimension.ARROW => an arrowhead at the dimension crossbar ends dimension.FILLED_ARROW => a filled arrohead at the dimension crossbar ends dimension.SLASH => a slash mark at the dimension crossbar ends dimension.CIRCLE => a filled circle at the dimension crossbar ends If this method is called without an argument, the endpoint type is set to that given in the DimStyle. """ if self.isLocked(): raise RuntimeError, "Changing endpoint type allowed - object locked." _ep = eptype if _ep is not None: if (_ep != Dimension.DIM_ENDPT_NONE and _ep != Dimension.DIM_ENDPT_ARROW and _ep != Dimension.DIM_ENDPT_FILLED_ARROW and _ep != Dimension.DIM_ENDPT_SLASH and _ep != Dimension.DIM_ENDPT_CIRCLE): raise ValueError, "Invalid endpoint value: '%s'" % str(_ep) _et = self.getEndpointType() if ((_ep is None and self.__eptype is not None) or (_ep is not None and _ep != _et)): self.startChange('endpoint_type_changed') self.__eptype = _ep self.endChange('endpoint_type_changed') self.calcDimValues() self.sendMessage('endpoint_type_changed', _et) self.modified() endpoint = property(getEndpointType, setEndpointType, None, "Dimension endpoint type.") def getEndpointSize(self): """Return the size of the Dimension endpoints. getEndpointSize() """ _es = self.__epsize if _es is None: _es = self.__dimstyle.getValue('DIM_ENDPOINT_SIZE') return _es def setEndpointSize(self, size=None): """Set the size of the Dimension endpoints. setEndpointSize([size]) Optional argument 'size' should be a float greater than or equal to 0.0. Calling this method without an argument sets the endpoint size to that given in the DimStle. """ if self.isLocked(): raise RuntimeError, "Changing endpoint type allowed - object locked." _size = size if _size is not None: _size = util.get_float(_size) if _size < 0.0: raise ValueError, "Invalid endpoint size: %g" % _size _es = self.getEndpointSize() if ((_size is None and self.__epsize is not None) or (_size is not None and abs(_size - _es) > 1e-10)): self.startChange('endpoint_size_changed') self.__epsize = _size self.endChange('endpoint_size_changed') self.calcDimValues() self.sendMessage('endpoint_size_changed', _es) self.modified() def getDimstrings(self): """Return both primary and secondry dimstrings. getDimstrings() """ return self.__ds1, self.__ds2 def getPrimaryDimstring(self): """ Return the DimString used for formatting the primary dimension. getPrimaryDimstring() """ return self.__ds1 def getSecondaryDimstring(self): """Return the DimString used for formatting the secondary dimension. getSecondaryDimstring() """ return self.__ds2 def getDualDimMode(self): """Return if the Dimension is displaying primary and secondary values. getDualDimMode(self) """ _mode = self.__ddm if _mode is None: _mode = self.__dimstyle.getValue('DIM_DUAL_MODE') return _mode def setDualDimMode(self, mode=None): """Set the Dimension to display both primary and secondary values. setDualDimMode([mode]) Optional argument 'mode' should be either True or False. Invoking this method without arguments will set the dual dimension value display mode to that given from the DimStyle """ if self.isLocked(): raise RuntimeError, "Changing dual mode not allowed - object locked." _mode = mode if _mode is not None: util.test_boolean(_mode) _ddm = self.getDualDimMode() if ((_mode is None and self.__ddm is not None) or (_mode is not None and _mode is not _ddm)): self.startChange('dual_mode_changed') self.__ddm = _mode self.endChange('dual_mode_changed') self.__ds1.setBounds() self.__ds2.setBounds() self.calcDimValues() self.sendMessage('dual_mode_changed', _ddm) self.modified() dual_mode = property(getDualDimMode, setDualDimMode, None, "Display both primary and secondary dimensions") def getOffset(self): """Return the current offset value for the Dimension. getOffset() """ _offset = self.__offset if _offset is None: _offset = self.__dimstyle.getValue('DIM_OFFSET') return _offset def setOffset(self, offset=None): """Set the offset value for the Dimension. setOffset([offset]) Optional argument 'offset' should be a positive float. Calling this method without arguments sets the value to that given in the DimStyle. """ if self.isLocked(): raise RuntimeError, "Setting offset not allowed - object locked." _o = offset if _o is not None: _o = util.get_float(_o) if _o < 0.0: raise ValueError, "Invalid dimension offset length: %g" % _o _off = self.getOffset() if ((_o is None and self.__offset is not None) or (_o is not None and abs(_o - _off) > 1e-10)): _dxmin, _dymin, _dxmax, _dymax = self.getBounds() self.startChange('offset_changed') self.__offset = _o self.endChange('offset_changed') self.calcDimValues() self.sendMessage('offset_changed', _off) self.sendMessage('moved', _dxmin, _dymin, _dxmax, _dymax) self.modified() offset = property(getOffset, setOffset, None, "Dimension offset.") def getExtension(self): """Get the extension length of the Dimension. getExtension() """ _ext = self.__extlen if _ext is None: _ext = self.__dimstyle.getValue('DIM_EXTENSION') return _ext def setExtension(self, ext=None): """Set the extension length of the Dimension. setExtension([ext]) Optional argument 'ext' should be a positive float value. Calling this method without arguments set the extension length to that given in the DimStyle. """ if self.isLocked(): raise RuntimeError, "Setting extension not allowed - object locked." _e = ext if _e is not None: _e = util.get_float(_e) if _e < 0.0: raise ValueError, "Invalid dimension extension length: %g" % _e _ext = self.getExtension() if ((_e is None and self.__extlen is not None) or (_e is not None and abs(_e - _ext) > 1e-10)): _dxmin, _dymin, _dxmax, _dymax = self.getBounds() self.startChange('extension_changed') self.__extlen = _e self.endChange('extension_changed') self.calcDimValues() self.sendMessage('extension_changed', _ext) self.sendMessage('moved', _dxmin, _dymin, _dxmax, _dymax) self.modified() extension = property(getExtension, setExtension, None, "Dimension extension length.") def getPositionAsString(cls, p): """Return a text string for the dimension text position. getPositionAsString(p) This classmethod returns 'split', 'above', or 'below' """ if not isinstance(p, int): raise TypeError, "Invalid argument type: " + `type(p)` if p == Dimension.DIM_TEXT_POS_SPLIT: _str = 'split' elif p == Dimension.DIM_TEXT_POS_ABOVE: _str = 'above' elif p == Dimension.DIM_TEXT_POS_BELOW: _str = 'below' else: raise ValueError, "Unexpected position value: %d" % p return _str getPositionAsString = classmethod(getPositionAsString) def getPositionFromString(cls, s): """Return the dimension text position given a string argument. getPositionFromString(s) This classmethod returns a value based on the string argument: 'split' -> Dimension.DIM_TEXT_POS_SPLIT 'above' -> Dimension.DIM_TEXT_POS_ABOVE 'below' -> Dimension.DIM_TEXT_POS_BELOW If the string is not listed above a ValueError execption is raised. """ if not isinstance(s, str): raise TypeError, "Invalid argument type: " + `type(s)` _ls = s.lower() if _ls == 'split': _v = Dimension.DIM_TEXT_POS_SPLIT elif _ls == 'above': _v = Dimension.DIM_TEXT_POS_ABOVE elif _ls == 'below': _v = Dimension.DIM_TEXT_POS_BELOW else: raise ValueError, "Unexpected position string: " + s return _v getPositionFromString = classmethod(getPositionFromString) def getPositionStrings(cls): """Return the position values as strings. getPositionStrings() This classmethod returns a list of strings. """ return [_('Split'), _('Above'), _('Below') ] getPositionStrings = classmethod(getPositionStrings) def getPositionValues(cls): """Return the position values. getPositionValues() This classmethod reutrns a list of values. """ return [Dimension.DIM_TEXT_POS_SPLIT, Dimension.DIM_TEXT_POS_ABOVE, Dimension.DIM_TEXT_POS_BELOW ] getPositionValues = classmethod(getPositionValues) def getPosition(self): """Return how the dimension text intersects the crossbar. getPosition() """ _pos = self.__textpos if _pos is None: _pos = self.__dimstyle.getValue('DIM_POSITION') return _pos def setPosition(self, pos=None): """Set where the dimension text should be placed at the crossbar. setPosition([pos]) Choices for optional argument 'pos' are: dimension.SPLIT => In the middle of the crossbar. dimension.ABOVE => Beyond the crossbar from the dimensioned objects. dimension.BELOW => Between the crossbar and the dimensioned objects. Calling this method without arguments sets the position to that given in the DimStyle. """ if self.isLocked(): raise RuntimeError, "Setting position not allowed - object locked." _pos = pos if (_pos != Dimension.DIM_TEXT_POS_SPLIT and _pos != Dimension.DIM_TEXT_POS_ABOVE and _pos != Dimension.DIM_TEXT_POS_BELOW): raise ValueError, "Invalid dimension text position: '%s'" % str(_pos) _dp = self.getPosition() if ((_pos is None and self.__textpos is not None) or (_pos is not None and _pos != _dp)): self.startChange('position_changed') self.__textpos = _pos self.endChange('position_changed') self.__ds1.setBounds() self.__ds2.setBounds() self.sendMessage('position_changed', _dp) self.modified() position = property(getPosition, setPosition, None, "Dimension text position") def getPositionOffset(self): """Get the offset for the dimension text and the crossbar/crossarc. getPositionOffset() """ _po = self.__poffset if _po is None: _po = self.__dimstyle.getValue('DIM_POSITION_OFFSET') return _po def setPositionOffset(self, offset=None): """Set the separation between the dimension text and the crossbar. setPositionOffset([offset]) If this method is called without arguments, the text offset length is set to the value given in the DimStyle. If the argument 'offset' is supplied, it should be a positive float value. """ if self.isLocked(): raise RuntimeError, "Setting text offset length not allowed - object locked." _o = offset if _o is not None: _o = util.get_float(_o) if _o < 0.0: raise ValueError, "Invalid text offset length: %g" % _o _to = self.getPositionOffset() if ((_o is None and self.__poffset is not None) or (_o is not None and abs(_o - _to) > 1e-10)): _dxmin, _dymin, _dxmax, _dymax = self.getBounds() self.startChange('position_offset_changed') self.__poffset = _o self.endChange('position_offset_changed') self.__ds1.setBounds() self.__ds2.setBounds() self.calcDimValues() self.sendMessage('position_offset_changed', _to) self.sendMessage('moved', _dxmin, _dymin, _dxmax, _dymax) self.modified() position_offset = property(getPositionOffset, setPositionOffset, None, "Text offset from crossbar/crossarc distance.") def getDualModeOffset(self): """Get the offset for the dimension text when displaying two dimensions. getDualModeOffset() """ _dmo = self.__dmoffset if _dmo is None: _dmo = self.__dimstyle.getValue('DIM_DUAL_MODE_OFFSET') return _dmo def setDualModeOffset(self, offset=None): """Set the separation between the dimensions and the dual mode dimension divider. setDualModeOffset([offset]) If this method is called without arguments, the dual mode offset length is set to the value given in the DimStyle. If the argument 'offset' is supplied, it should be a positive float value. """ if self.isLocked(): raise RuntimeError, "Setting dual mode offset length not allowed - object locked." _o = offset if _o is not None: _o = util.get_float(_o) if _o < 0.0: raise ValueError, "Invalid dual mode offset length: %g" % _o _dmo = self.getDualModeOffset() if ((_o is None and self.__dmoffset is not None) or (_o is not None and abs(_o - _dmo) > 1e-10)): _dxmin, _dymin, _dxmax, _dymax = self.getBounds() self.startChange('dual_mode_offset_changed') self.__dmoffset = _o self.endChange('dual_mode_offset_changed') self.__ds1.setBounds() self.__ds2.setBounds() self.calcDimValues() self.sendMessage('dual_mode_offset_changed', _dmo) self.sendMessage('moved', _dxmin, _dymin, _dxmax, _dymax) self.modified() dual_mode_offset = property(getDualModeOffset, setDualModeOffset, None, "Text offset from dimension splitting bar when displaying two dimensions.") def getColor(self): """Return the color of the dimension lines. getColor() """ _col = self.__color if _col is None: _col = self.__dimstyle.getValue('DIM_COLOR') return _col def setColor(self, c=None): """Set the color of the dimension lines. setColor([c]) Optional argument 'c' should be a Color instance. Calling this method without an argument sets the color to the value given in the DimStyle. """ if self.isLocked(): raise RuntimeError, "Setting object color not allowed - object locked." _c = c if _c is not None: if not isinstance(_c, color.Color): raise TypeError, "Invalid color type: " + `type(_c)` _oc = self.getColor() if ((_c is None and self.__color is not None) or (_c is not None and _c != _oc)): self.startChange('color_changed') self.__color = _c self.endChange('color_changed') self.sendMessage('color_changed', _oc) self.modified() color = property(getColor, setColor, None, "Dimension Color") def getThickness(self): """Return the thickness of the dimension bars. getThickness() This method returns a float. """ _t = self.__thickness if _t is None: _t = self.__dimstyle.getValue('DIM_THICKNESS') return _t def setThickness(self, thickness=None): """Set the thickness of the dimension bars. setThickness([thickness]) Optional argument 'thickness' should be a float value. Setting the thickness to 0 will display and print the lines with the thinnest value possible. Calling this method without arguments resets the thickness to the value defined in the DimStyle. """ if self.isLocked(): raise RuntimeError, "Setting thickness not allowed - object locked." _t = thickness if _t is not None: _t = util.get_float(_t) if _t < 0.0: raise ValueError, "Invalid thickness: %g" % _t _ot = self.getThickness() if ((_t is None and self.__thickness is not None) or (_t is not None and abs(_t - _ot) > 1e-10)): self.startChange('thickness_changed') self.__thickness = _t self.endChange('thickness_changed') self.sendMessage('thickness_changed', _ot) self.modified() thickness = property(getThickness, setThickness, None, "Dimension bar thickness.") def getScale(self): """Return the Dimension scale factor. getScale() """ return self.__scale def setScale(self, scale=None): """Set the Dimension scale factor. setScale([scale]) Optional argument 's' should be a float value greater than 0. If no argument is supplied the default scale factor of 1 is set. """ if self.isLocked(): raise RuntimeError, "Setting scale not allowed - object locked." _s = scale if _s is None: _s = 1.0 _s = util.get_float(_s) if not _s > 0.0: raise ValueError, "Invalid scale factor: %g" % _s _os = self.__scale if abs(_os - _s) > 1e-10: self.startChange('scale_changed') self.__scale = _s self.endChange('scale_changed') self.sendMessage('scale_changed', _os) self.modified() scale = property(getScale, setScale, None, "Dimension scale factor.") def getLocation(self): """Return the location of the dimensional text values. getLocation() """ return self.__dimloc def setLocation(self, x, y): """Set the location of the dimensional text values. setLocation(x, y) The 'x' and 'y' arguments should be float values. The text is centered around that point. """ if self.isLocked(): raise RuntimeError, "Setting location not allowed - object locked." _x = util.get_float(x) _y = util.get_float(y) _ox, _oy = self.__dimloc if abs(_ox - _x) > 1e-10 or abs(_oy - _y) > 1e-10: _dxmin, _dymin, _dxmax, _dymax = self.getBounds() self.startChange('location_changed') self.__dimloc = (_x, _y) self.endChange('location_changed') self.__ds1.setBounds() self.__ds2.setBounds() self.calcDimValues() self.sendMessage('location_changed', _ox, _oy) self.sendMessage('moved', _dxmin, _dymin, _dxmax, _dymax) self.modified() location = property(getLocation, setLocation, None, "Dimension location") def move(self, dx, dy): """Move a Dimension. move(dx, dy) The first argument gives the x-coordinate displacement, and the second gives the y-coordinate displacement. Both values should be floats. """ if self.isLocked(): raise RuntimeError, "Moving not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _dxmin, _dymin, _dxmax, _dymax = self.getBounds() _x, _y = self.__dimloc self.startChange('location_changed') self.__dimloc = ((_x + _dx), (_y + _dy)) self.endChange('location_changed') self.__ds1.setBounds() self.__ds2.setBounds() self.calcDimValues() self.sendMessage('location_changed', _x, _y) self.sendMessage('moved', _dxmin, _dymin, _dxmax, _dymax) self.modified() def getStyleValue(self, ds, opt): """Get the value in the DimStyle for some option getStyleValue(ds, opt) Argument 'ds' should be one of the DimString objects in the Dimension, and argument 'opt' should be a string. Valid choices for 'opt' are 'prefix', 'suffix', 'precision', 'units', 'print_zero', 'print_decimal', 'font_family', 'font_style', 'font_weight', 'size', 'color', 'angle', and 'alignment'. """ if not isinstance(ds, DimString): raise TypeError, "Invalid DimString type: " + `type(ds)` if not isinstance(opt, str): raise TypeError, "Invalid DimStyle option type: " + `type(opt)` _key = None if ds is self.__ds1: if opt == 'prefix': _key = 'DIM_PRIMARY_PREFIX' elif opt == 'suffix': _key = 'DIM_PRIMARY_SUFFIX' elif opt == 'precision': _key = 'DIM_PRIMARY_PRECISION' elif opt == 'units': _key = 'DIM_PRIMARY_UNITS' elif opt == 'print_zero': _key = 'DIM_PRIMARY_LEADING_ZERO' elif opt == 'print_decimal': _key = 'DIM_PRIMARY_TRAILING_DECIMAL' elif opt == 'font_family': _key = 'DIM_PRIMARY_FONT_FAMILY' elif opt == 'font_weight': _key = 'DIM_PRIMARY_FONT_WEIGHT' elif opt == 'font_style': _key = 'DIM_PRIMARY_FONT_STYLE' elif opt == 'size': _key = 'DIM_PRIMARY_TEXT_SIZE' elif opt == 'color': _key = 'DIM_PRIMARY_FONT_COLOR' elif opt == 'angle': _key = 'DIM_PRIMARY_TEXT_ANGLE' elif opt == 'alignment': _key = 'DIM_PRIMARY_TEXT_ALIGNMENT' else: raise ValueError, "Unexpected option: %s" % opt elif ds is self.__ds2: if opt == 'prefix': _key = 'DIM_SECONDARY_PREFIX' elif opt == 'suffix': _key = 'DIM_SECONDARY_SUFFIX' elif opt == 'precision': _key = 'DIM_SECONDARY_PRECISION' elif opt == 'units': _key = 'DIM_SECONDARY_UNITS' elif opt == 'print_zero': _key = 'DIM_SECONDARY_LEADING_ZERO' elif opt == 'print_decimal': _key = 'DIM_SECONDARY_TRAILING_DECIMAL' elif opt == 'font_family': _key = 'DIM_SECONDARY_FONT_FAMILY' elif opt == 'font_weight': _key = 'DIM_SECONDARY_FONT_WEIGHT' elif opt == 'font_style': _key = 'DIM_SECONDARY_FONT_STYLE' elif opt == 'size': _key = 'DIM_SECONDARY_TEXT_SIZE' elif opt == 'color': _key = 'DIM_SECONDARY_FONT_COLOR' elif opt == 'angle': _key = 'DIM_SECONDARY_TEXT_ANGLE' elif opt == 'alignment': _key = 'DIM_SECONDARY_TEXT_ALIGNMENT' else: raise ValueError, "Unexpected option: %s" % opt else: raise ValueError, "DimString not used in this Dimension: " + `ds` if _key is None: raise ValueError, "Unexpected option: %s" % opt return self.__dimstyle.getValue(_key) def getDimensions(self, dimlen): """Return the formatted dimensional values. getDimensions(dimlen) The argument 'dimlen' should be the length in millimeters. This method returns a list of the primary and secondary dimensional values. """ _dl = util.get_float(dimlen) dims = [] dims.append(self.__ds1.formatDimension(_dl)) dims.append(self.__ds2.formatDimension(_dl)) return dims def calcDimValues(self, allpts=True): """Recalculate the values for dimensional display calcDimValues([allpts]) This method is meant to be overriden by subclasses. """ pass def inRegion(self, xmin, ymin, xmax, ymax, fully=False): """Return whether or not a Dimension exists with a region. isRegion(xmin, ymin, xmax, ymax[, fully]) The first four arguments define the boundary. The optional fifth argument 'fully' indicates whether or not the Dimension must be completely contained within the region or just pass through it. This method should be overriden in classes derived from Dimension. """ return False def getBounds(self): """Return the minimal and maximal locations of the dimension getBounds() This method returns a tuple of four values - xmin, ymin, xmax, ymax. These values give the mimimum and maximum coordinates of the dimension object. This method should be overriden in classes derived from Dimension. """ _xmin = _ymin = -float(sys.maxint) _xmax = _ymax = float(sys.maxint) return _xmin, _ymin, _xmax, _ymax def copyDimValues(self, dim): """This method adjusts one Dimension to match another Dimension copyDimValues(dim) Argument 'dim' must be a Dimension instance """ if not isinstance(dim, Dimension): raise TypeError, "Invalid Dimension type: " + `type(dim)` self.setDimStyle(dim.getDimStyle()) self.setOffset(dim.getOffset()) self.setExtension(dim.getExtension()) self.setEndpointType(dim.getEndpointType()) self.setEndpointSize(dim.getEndpointSize()) self.setColor(dim.getColor()) self.setThickness(dim.getThickness()) self.setDualDimMode(dim.getDualDimMode()) self.setPositionOffset(dim.getPositionOffset()) self.setDualModeOffset(dim.getDualModeOffset()) # _ds1, _ds2 = dim.getDimstrings() # _ds = self.__ds1 _ds.setTextStyle(_ds1.getTextStyle()) _ds.setPrefix(_ds1.getPrefix()) _ds.setSuffix(_ds1.getSuffix()) _ds.setPrecision(_ds1.getPrecision()) _ds.setUnits(_ds1.getUnits()) _ds.setPrintZero(_ds1.getPrintZero()) _ds.setPrintDecimal(_ds1.getPrintDecimal()) _ds.setFamily(_ds1.getFamily()) _ds.setWeight(_ds1.getWeight()) _ds.setStyle(_ds1.getStyle()) _ds.setColor(_ds1.getColor()) _ds.setSize(_ds1.getSize()) _ds.setAngle(_ds1.getAngle()) _ds.setAlignment(_ds1.getAlignment()) # _ds = self.__ds2 _ds.setTextStyle(_ds2.getTextStyle()) _ds.setPrefix(_ds2.getPrefix()) _ds.setSuffix(_ds2.getSuffix()) _ds.setPrecision(_ds2.getPrecision()) _ds.setUnits(_ds2.getUnits()) _ds.setPrintZero(_ds2.getPrintZero()) _ds.setPrintDecimal(_ds2.getPrintDecimal()) _ds.setFamily(_ds2.getFamily()) _ds.setWeight(_ds2.getWeight()) _ds.setStyle(_ds2.getStyle()) _ds.setColor(_ds2.getColor()) _ds.setSize(_ds2.getSize()) _ds.setAngle(_ds2.getAngle()) _ds.setAlignment(_ds2.getAlignment()) def __dimstringChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _arg = args[0] if _arg == 'moved': self.startChange(_arg) elif (_arg == 'textstyle_changed' or _arg == 'font_family_changed' or _arg == 'font_style_changed' or _arg == 'font_weight_changed' or _arg == 'font_color_changed' or _arg == 'text_size_changed' or _arg == 'text_angle_changed' or _arg == 'text_alignment_changed' or _arg == 'prefix_changed' or _arg == 'suffix_changed' or _arg == 'units_changed' or _arg == 'precision_changed' or _arg == 'print_zero_changed' or _arg == 'print_decimal_changed'): self.startChange('dimstring_changed') else: pass def __dimstringChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _arg = args[0] if _arg == 'moved': self.endChanged(_arg) elif (_arg == 'textstyle_changed' or _arg == 'font_family_changed' or _arg == 'font_style_changed' or _arg == 'font_weight_changed' or _arg == 'font_color_changed' or _arg == 'text_size_changed' or _arg == 'text_angle_changed' or _arg == 'text_alignment_changed' or _arg == 'prefix_changed' or _arg == 'suffix_changed' or _arg == 'units_changed' or _arg == 'precision_changed' or _arg == 'print_zero_changed' or _arg == 'print_decimal_changed'): self.endChange('dimstring_changed') else: pass def sendsMessage(self, m): if m in Dimension.__messages: return True return super(Dimension, self).sendsMessage(m) # # class stuff for dimension styles # class DimStyle(object): """A class storing preferences for Dimensions The DimStyle class stores a set of dimension parameters that will be used when creating dimensions when the particular style is active. A DimStyle object has the following methods: getName(): Return the name of the DimStyle. getOption(): Return a single value in the DimStyle. getOptions(): Return all the options in the DimStyle. getValue(): Return the value of one of the DimStyle options. getOption() and getValue() are synonymous. The DimStyle class has the following classmethods: getDimStyleOptions(): Return the options defining a DimStyle. getDimStyleDefaultValue(): Return the default value for a DimStyle option. """ # # the default values for the DimStyle class # __deftextcolor = color.Color('#ffffff') __defdimcolor = color.Color(255,165,0) __defaults = { 'DIM_PRIMARY_FONT_FAMILY' : 'Sans', 'DIM_PRIMARY_TEXT_SIZE' : 1.0, 'DIM_PRIMARY_FONT_WEIGHT' : text.TextStyle.FONT_NORMAL, 'DIM_PRIMARY_FONT_STYLE' : text.TextStyle.FONT_NORMAL, 'DIM_PRIMARY_FONT_COLOR' : __deftextcolor, 'DIM_PRIMARY_TEXT_ANGLE' : 0.0, 'DIM_PRIMARY_TEXT_ALIGNMENT' : text.TextStyle.ALIGN_CENTER, 'DIM_PRIMARY_PREFIX' : u'', 'DIM_PRIMARY_SUFFIX' : u'', 'DIM_PRIMARY_PRECISION' : 3, 'DIM_PRIMARY_UNITS' : units.MILLIMETERS, 'DIM_PRIMARY_LEADING_ZERO' : True, 'DIM_PRIMARY_TRAILING_DECIMAL' : True, 'DIM_SECONDARY_FONT_FAMILY' : 'Sans', 'DIM_SECONDARY_TEXT_SIZE' : 1.0, 'DIM_SECONDARY_FONT_WEIGHT' : text.TextStyle.FONT_NORMAL, 'DIM_SECONDARY_FONT_STYLE' : text.TextStyle.FONT_NORMAL, 'DIM_SECONDARY_FONT_COLOR' : __deftextcolor, 'DIM_SECONDARY_TEXT_ANGLE' : 0.0, 'DIM_SECONDARY_TEXT_ALIGNMENT' : text.TextStyle.ALIGN_CENTER, 'DIM_SECONDARY_PREFIX' : u'', 'DIM_SECONDARY_SUFFIX' : u'', 'DIM_SECONDARY_PRECISION' : 3, 'DIM_SECONDARY_UNITS' : units.MILLIMETERS, 'DIM_SECONDARY_LEADING_ZERO' : True, 'DIM_SECONDARY_TRAILING_DECIMAL' : True, 'DIM_OFFSET' : 1.0, 'DIM_EXTENSION' : 1.0, 'DIM_COLOR' : __defdimcolor, 'DIM_THICKNESS' : 0.0, 'DIM_POSITION' : Dimension.DIM_TEXT_POS_SPLIT, 'DIM_ENDPOINT' : Dimension.DIM_ENDPT_NONE, 'DIM_ENDPOINT_SIZE' : 1.0, 'DIM_DUAL_MODE' : False, 'DIM_POSITION_OFFSET' : 0.0, 'DIM_DUAL_MODE_OFFSET' : 1.0, 'RADIAL_DIM_PRIMARY_PREFIX' : u'', 'RADIAL_DIM_PRIMARY_SUFFIX' : u'', 'RADIAL_DIM_SECONDARY_PREFIX' : u'', 'RADIAL_DIM_SECONDARY_SUFFIX' : u'', 'RADIAL_DIM_DIA_MODE' : False, 'ANGULAR_DIM_PRIMARY_PREFIX' : u'', 'ANGULAR_DIM_PRIMARY_SUFFIX' : u'', 'ANGULAR_DIM_SECONDARY_PREFIX' : u'', 'ANGULAR_DIM_SECONDARY_SUFFIX' : u'', } def __init__(self, name, keywords={}): """Instantiate a DimStyle object. ds = DimStyle(name, keywords) The argument 'name' should be a unicode name, and the 'keyword' argument should be a dict. The keys should be the same keywords used to set option values, such as DIM_OFFSET, DIM_EXTENSION, etc, and the value corresponding to each key should be set appropriately. """ super(DimStyle, self).__init__() _n = name if not isinstance(_n, types.StringTypes): raise TypeError, "Invalid DimStyle name type: "+ `type(_n)` if isinstance(_n, str): _n = unicode(_n) if not isinstance(keywords, dict): raise TypeError, "Invalid keywords argument type: " + `type(keywords)` from PythonCAD.Generic.options import test_option self.__opts = baseobject.ConstDict(str) self.__name = _n for _kw in keywords: if _kw not in DimStyle.__defaults: raise KeyError, "Unknown DimStyle keyword: " + _kw _val = keywords[_kw] _valid = test_option(_kw, _val) self.__opts[_kw] = _val def __eq__(self, obj): """Test a DimStyle object for equality with another DimStyle. """ if not isinstance(obj, DimStyle): return False if obj is self: return True if self.__name != obj.getName(): return False _val = True for _key in DimStyle.__defaults.keys(): _sv = self.getOption(_key) _ov = obj.getOption(_key) if ((_key == 'DIM_PRIMARY_TEXT_SIZE') or (_key == 'DIM_PRIMARY_TEXT_ANGLE') or (_key == 'DIM_SECONDARY_TEXT_SIZE') or (_key == 'DIM_SECONDARY_TEXT_ANGLE') or (_key == 'DIM_OFFSET') or (_key == 'DIM_EXTENSION') or (_key == 'DIM_THICKNESS') or (_key == 'DIM_ENDPOINT_SIZE') or (_key == 'DIM_POSITION_OFFSET') or (_key == 'DIM_DUAL_MODE_OFFSET')): if abs(_sv - _ov) > 1e-10: _val = False else: if _sv != _ov: _val = False if _val is False: break return _val def __ne__(self, obj): """Test a DimStyle object for inequality with another DimStyle. """ return not self == obj def getDimStyleOptions(cls): """Return the options used to define a DimStyle instance. getDimStyleOptions() This classmethod returns a list of strings. """ return cls.__defaults.keys() getDimStyleOptions = classmethod(getDimStyleOptions) def getDimStyleDefaultValue(cls, key): """Return the default value for a DimStyle option. getDimStyleValue(key) Argument 'key' must be one of the options given in getDimStyleOptions(). """ return cls.__defaults[key] getDimStyleDefaultValue = classmethod(getDimStyleDefaultValue) def getName(self): """Return the name of the DimStyle. getName() """ return self.__name name = property(getName, None, None, "DimStyle name.") def getKeys(self): """Return the non-default options within the DimStyle. getKeys() """ return self.__opts.keys() def getOptions(self): """Return all the options stored within the DimStyle. getOptions() """ _keys = self.__opts.keys() for _key in DimStyle.__defaults: if _key not in self.__opts: _keys.append(_key) return _keys def getOption(self, key): """Return the value of a particular option in the DimStyle. getOption(key) The key should be one of the strings returned from getOptions. If there is no value found in the DimStyle for the key, the value None is returned. """ if key in self.__opts: _val = self.__opts[key] elif key in DimStyle.__defaults: _val = DimStyle.__defaults[key] else: raise KeyError, "Unexpected DimStyle keyword: '%s'" % key return _val def getValue(self, key): """Return the value of a particular option in the DimStyle. getValue(key) The key should be one of the strings returned from getOptions. This method raises a KeyError exception if the key is not found. """ if key in self.__opts: _val = self.__opts[key] elif key in DimStyle.__defaults: _val = DimStyle.__defaults[key] else: raise KeyError, "Unexpected DimStyle keyword: '%s'" % key return _val def getValues(self): """Return values comprising the DimStyle. getValues() """ _vals = {} _vals['name'] = self.__name for _opt in self.__opts: _val = self.__opts[_opt] if ((_opt == 'DIM_PRIMARY_FONT_COLOR') or (_opt == 'DIM_SECONDARY_FONT_COLOR') or (_opt == 'DIM_COLOR')): _vals[_opt] = _val.getColors() else: _vals[_opt] = _val return _vals class LinearDimension(Dimension): """A class for Linear dimensions. The LinearDimension class is derived from the Dimension class, so it shares all of those methods and attributes. A LinearDimension should be used to display the absolute distance between two Point objects. A LinearDimension object has the following methods: {get/set}P1(): Get/Set the first Point for the LinearDimension. {get/set}P2(): Get/Set the second Point for the LinearDimension. getDimPoints(): Return the two Points used in this dimension. getDimLayers(): Return the two Layers holding the Points. getDimXPoints(): Get the x-coordinates of the dimension bar positions. getDimYPoints(): Get the y-coordinates of the dimension bar positions. getDimMarkerPoints(): Get the locaiton of the dimension endpoint markers. calcMarkerPoints(): Calculate the coordinates of any dimension marker objects. """ __messages = { 'point_changed' : True, } def __init__(self, p1, p2, x, y, ds=None, **kw): """Instantiate a LinearDimension object. ldim = LinearDimension(p1, p2, x, y, ds) p1: A Point contained in a Layer p2: A Point contained in a Layer x: The x-coordinate of the dimensional text y: The y-coordinate of the dimensional text ds: The DimStyle used for this Dimension. """ if not isinstance(p1, point.Point): raise TypeError, "Invalid point type: " + `type(p1)` if p1.getParent() is None: raise ValueError, "Point P1 not stored in a Layer!" if not isinstance(p2, point.Point): raise TypeError, "Invalid point type: " + `type(p2)` if p2.getParent() is None: raise ValueError, "Point P2 not stored in a Layer!" super(LinearDimension, self).__init__(x, y, ds, **kw) self.__p1 = p1 self.__p2 = p2 self.__bar1 = DimBar() self.__bar2 = DimBar() self.__crossbar = DimCrossbar() p1.storeUser(self) p1.connect('moved', self.__movePoint) p1.connect('change_pending', self.__pointChangePending) p1.connect('change_complete', self.__pointChangeComplete) p2.storeUser(self) p2.connect('moved', self.__movePoint) p2.connect('change_pending', self.__pointChangePending) p2.connect('change_complete', self.__pointChangeComplete) self.calcDimValues() def __eq__(self, ldim): """Test two LinearDimension objects for equality. """ if not isinstance(ldim, LinearDimension): return False _lp1 = self.__p1.getParent() _lp2 = self.__p2.getParent() _p1, _p2 = ldim.getDimPoints() _l1 = _p1.getParent() _l2 = _p2.getParent() if (_lp1 is _l1 and _lp2 is _l2 and self.__p1 == _p1 and self.__p2 == _p2): return True if (_lp1 is _l2 and _lp2 is _l1 and self.__p1 == _p2 and self.__p2 == _p1): return True return False def __ne__(self, ldim): """Test two LinearDimension objects for equality. """ if not isinstance(ldim, LinearDimension): return True _lp1 = self.__p1.getParent() _lp2 = self.__p2.getParent() _p1, _p2 = ldim.getDimPoints() _l1 = _p1.getParent() _p2 = self.__p2 _l2 = _p2.getParent() if (_lp1 is _l1 and _lp2 is _l2 and self.__p1 == _p1 and self.__p2 == _p2): return False if (_lp1 is _l2 and _lp2 is _l1 and self.__p1 == _p2 and self.__p2 == _p1): return False return True def finish(self): self.__p1.disconnect(self) self.__p1.freeUser(self) self.__p2.disconnect(self) self.__p2.freeUser(self) self.__bar1 = self.__bar2 = self.__crossbar = None self.__p1 = self.__p2 = None super(LinearDimension, self).finish() def getValues(self): """Return values comprising the LinearDimension. getValues() This method extends the Dimension::getValues() method. """ _data = super(LinearDimension, self).getValues() _data.setValue('type', 'ldim') _data.setValue('p1', self.__p1.getID()) _layer = self.__p1.getParent() _data.setValue('l1', _layer.getID()) _data.setValue('p2', self.__p2.getID()) _layer = self.__p2.getParent() _data.setValue('l2', _layer.getID()) return _data def getP1(self): """Return the first Point of a LinearDimension. getP1() """ return self.__p1 def setP1(self, p): """Set the first Point of a LinearDimension. setP1(p) There is one required argument for this method: p: A Point contained in a Layer """ if self.isLocked(): raise RuntimeError, "Setting point not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid point type: " + `type(p)` if p.getParent() is None: raise ValueError, "Point not stored in a Layer!" _pt = self.__p1 if _pt is not p: _pt.disconnect(self) _pt.freeUser(self) self.startChange('point_changed') self.__p1 = p self.endChange('point_changed') self.sendMessage('point_changed', _pt, p) p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) if abs(_pt.x - p.x) > 1e-10 or abs(_pt.y - p.y) > 1e-10: _dxmin, _dymin, _dxmax, _dymax = self.getBounds() self.calcDimValues() self.sendMessage('moved', _dxmin, _dymin, _dxmax, _dymax) self.modified() p1 = property(getP1, None, None, "Dimension first point.") def getP2(self): """Return the second point of a LinearDimension. getP2() """ return self.__p2 def setP2(self, p): """Set the second Point of a LinearDimension. setP2(p) There is one required argument for this method: p: A Point contained in a Layer """ if self.isLocked(): raise RuntimeError, "Setting point not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid point type: " + `type(p)` if p.getParent() is None: raise ValueError, "Point not stored in a Layer!" _pt = self.__p2 if _pt is not p: _pt.disconnect(self) _pt.freeUser(self) self.startChange('point_changed') self.__p2 = p self.endChange('point_changed') self.sendMessage('point_changed', _pt, p) p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) if abs(_pt.x - p.x) > 1e-10 or abs(_pt.y - p.y) > 1e-10: _dxmin, _dymin, _dxmax, _dymax = self.getBounds() self.calcDimValues() self.sendMessage('moved', _dxmin, _dymin, _dxmax, _dymax) self.modified() p2 = property(getP2, None, None, "Dimension second point.") def getDimPoints(self): """Return both points used in the LinearDimension. getDimPoints() The two points are returned in a tuple. """ return self.__p1, self.__p2 def getDimBars(self): """Return the dimension boundary bars. getDimBars() """ return self.__bar1, self.__bar2 def getDimCrossbar(self): """Return the dimension crossbar. getDimCrossbar() """ return self.__crossbar def getDimLayers(self): """Return both layers used in the LinearDimension. getDimLayers() The two layers are returned in a tuple. """ _l1 = self.__p1.getParent() _l2 = self.__p2.getParent() return _l1, _l2 def calculate(self): """Determine the length of this LinearDimension. calculate() """ return self.__p1 - self.__p2 def inRegion(self, xmin, ymin, xmax, ymax, fully=False): """Return whether or not a LinearDimension exists within a region. isRegion(xmin, ymin, xmax, ymax[, fully]) The four arguments define the boundary of an area, and the function returns True if the LinearDimension lies within that area. If the optional argument fully is used and is True, then the dimension points and the location of the dimension text must lie within the boundary. Otherwise, the function returns False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) _dxmin, _dymin, _dxmax, _dymax = self.getBounds() if ((_dxmin > _xmax) or (_dymin > _ymax) or (_dxmax < _xmin) or (_dymax < _ymin)): return False if fully: if ((_dxmin > _xmin) and (_dymin > _ymin) and (_dxmax < _xmax) and (_dymax < _ymax)): return True return False _dx, _dy = self.getLocation() if _xmin < _dx < _xmax and _ymin < _dy < _ymax: # dim text return True # # bar at p1 # _ep1, _ep2 = self.__bar1.getEndpoints() _x1, _y1 = _ep1 _x2, _y2 = _ep2 if util.in_region(_x1, _y1, _x2, _y2, _xmin, _ymin, _xmax, _ymax): return True # # bar at p2 # _ep1, _ep2 = self.__bar2.getEndpoints() _x1, _y1 = _ep1 _x2, _y2 = _ep2 if util.in_region(_x1, _y1, _x2, _y2, _xmin, _ymin, _xmax, _ymax): return True # # crossbar # _ep1, _ep2 = self.__crossbar.getEndpoints() _x1, _y1 = _ep1 _x2, _y2 = _ep2 return util.in_region(_x1, _y1, _x2, _y2, _xmin, _ymin, _xmax, _ymax) def calcDimValues(self, allpts=True): """Recalculate the values for dimensional display. calcDimValues([allpts]) This method calculates where the points for the dimension bars and crossbar are located. The argument 'allpts' is optional. By default it is True. If the argument is set to False, then the coordinates of the dimension marker points will not be calculated. """ _allpts = allpts util.test_boolean(_allpts) _p1, _p2 = self.getDimPoints() _bar1 = self.__bar1 _bar2 = self.__bar2 _crossbar = self.__crossbar _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _dx, _dy = self.getLocation() _offset = self.getOffset() _ext = self.getExtension() # # see comp.graphics.algorithms.faq section on calcuating # the distance between a point and line for info about # the following equations ... # _dpx = _p2x - _p1x _dpy = _p2y - _p1y _rnum = ((_dx - _p1x) * _dpx) + ((_dy - _p1y) * _dpy) _snum = ((_p1y - _dy) * _dpx) - ((_p1x - _dx) * _dpy) _den = pow(_dpx, 2) + pow(_dpy, 2) _r = _rnum/_den _s = _snum/_den _sep = abs(_s) * math.sqrt(_den) if abs(_dpx) < 1e-10: # vertical if _p2y > _p1y: _slope = math.pi/2.0 else: _slope = -math.pi/2.0 elif abs(_dpy) < 1e-10: # horizontal if _p2x > _p1x: _slope = 0.0 else: _slope = -math.pi else: _slope = math.atan2(_dpy, _dpx) if _s < 0.0: # dim point left of p1-p2 line _angle = _slope + (math.pi/2.0) else: # dim point right of p1-p2 line (or on it) _angle = _slope - (math.pi/2.0) _sin_angle = math.sin(_angle) _cos_angle = math.cos(_angle) _x = _p1x + (_offset * _cos_angle) _y = _p1y + (_offset * _sin_angle) _bar1.setFirstEndpoint(_x, _y) if _r < 0.0: _px = _p1x + (_r * _dpx) _py = _p1y + (_r * _dpy) _x = _px + (_sep * _cos_angle) _y = _py + (_sep * _sin_angle) else: _x = _p1x + (_sep * _cos_angle) _y = _p1y + (_sep * _sin_angle) _crossbar.setFirstEndpoint(_x, _y) _x = _p1x + (_sep * _cos_angle) _y = _p1y + (_sep * _sin_angle) _crossbar.setFirstCrossbarPoint(_x, _y) _x = _p1x + ((_sep + _ext) * _cos_angle) _y = _p1y + ((_sep + _ext) * _sin_angle) _bar1.setSecondEndpoint(_x, _y) _x = _p2x + (_offset * _cos_angle) _y = _p2y + (_offset * _sin_angle) _bar2.setFirstEndpoint(_x, _y) if _r > 1.0: _px = _p1x + (_r * _dpx) _py = _p1y + (_r * _dpy) _x = _px + (_sep * _cos_angle) _y = _py + (_sep * _sin_angle) else: _x = _p2x + (_sep * _cos_angle) _y = _p2y + (_sep * _sin_angle) _crossbar.setSecondEndpoint(_x, _y) _x = _p2x + (_sep * _cos_angle) _y = _p2y + (_sep * _sin_angle) _crossbar.setSecondCrossbarPoint(_x, _y) _x = _p2x + ((_sep + _ext) * _cos_angle) _y = _p2y + ((_sep + _ext) * _sin_angle) _bar2.setSecondEndpoint(_x, _y) if _allpts: self.calcMarkerPoints() def calcMarkerPoints(self): """Calculate and store the dimension endpoint markers coordinates. calcMarkerPoints() """ _type = self.getEndpointType() _crossbar = self.__crossbar _crossbar.clearMarkerPoints() if _type == Dimension.DIM_ENDPT_NONE or _type == Dimension.DIM_ENDPT_CIRCLE: return _size = self.getEndpointSize() _p1, _p2 = _crossbar.getCrossbarPoints() _x1, _y1 = _p1 _x2, _y2 = _p2 # print "x1: %g" % _x1 # print "y1: %g" % _y1 # print "x2: %g" % _x2 # print "y2: %g" % _y2 _sine, _cosine = _crossbar.getSinCosValues() if _type == Dimension.DIM_ENDPT_ARROW or _type == Dimension.DIM_ENDPT_FILLED_ARROW: _height = _size/5.0 # p1 -> (x,y) = (size, _height) _mx = (_cosine * _size - _sine * _height) + _x1 _my = (_sine * _size + _cosine * _height) + _y1 _crossbar.storeMarkerPoint(_mx, _my) # p2 -> (x,y) = (size, -_height) _mx = (_cosine * _size - _sine *(-_height)) + _x1 _my = (_sine * _size + _cosine *(-_height)) + _y1 _crossbar.storeMarkerPoint(_mx, _my) # p3 -> (x,y) = (-size, _height) _mx = (_cosine * (-_size) - _sine * _height) + _x2 _my = (_sine * (-_size) + _cosine * _height) + _y2 _crossbar.storeMarkerPoint(_mx, _my) # p4 -> (x,y) = (-size, -_height) _mx = (_cosine * (-_size) - _sine *(-_height)) + _x2 _my = (_sine * (-_size) + _cosine *(-_height)) + _y2 _crossbar.storeMarkerPoint(_mx, _my) elif _type == Dimension.DIM_ENDPT_SLASH: _angle = 30.0 * _dtr # slope of slash _height = 0.5 * _size * math.sin(_angle) _length = 0.5 * _size * math.cos(_angle) # p1 -> (x,y) = (-_length, -_height) _sx1 = (_cosine * (-_length) - _sine * (-_height)) _sy1 = (_sine * (-_length) + _cosine * (-_height)) # p2 -> (x,y) = (_length, _height) _sx2 = (_cosine * _length - _sine * _height) _sy2 = (_sine * _length + _cosine * _height) # # shift the calculate based on the location of the # marker point # _mx = _sx1 + _x2 _my = _sy1 + _y2 _crossbar.storeMarkerPoint(_mx, _my) _mx = _sx2 + _x2 _my = _sy2 + _y2 _crossbar.storeMarkerPoint(_mx, _my) _mx = _sx1 + _x1 _my = _sy1 + _y1 _crossbar.storeMarkerPoint(_mx, _my) _mx = _sx2 + _x1 _my = _sy2 + _y1 _crossbar.storeMarkerPoint(_mx, _my) else: raise ValueError, "Unexpected endpoint type: '%s'" % str(_type) def mapCoords(self, x, y, tol=tolerance.TOL): """Test an x/y coordinate pair if it could lay on the dimension. mapCoords(x, y[, tol]) This method has two required parameters: x: The x-coordinate y: The y-coordinate These should both be float values. There is an optional third parameter tol giving the maximum distance from the dimension bars that the x/y coordinates may lie. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _ep1, _ep2 = self.__bar1.getEndpoints() # # test p1 bar # _mp = util.map_coords(_x, _y, _ep1[0], _ep1[1], _ep2[0], _ep2[1], _t) if _mp is not None: return _mp # # test p2 bar # _ep1, _ep2 = self.__bar2.getEndpoints() _mp = util.map_coords(_x, _y, _ep1[0], _ep1[1], _ep2[0], _ep2[1], _t) if _mp is not None: return _mp # # test crossbar # _ep1, _ep2 = self.__crossbar.getEndpoints() return util.map_coords(_x, _y, _ep1[0], _ep1[1], _ep2[0], _ep2[1], _t) def onDimension(self, x, y, tol=tolerance.TOL): return self.mapCoords(x, y, tol) is not None def getBounds(self): """Return the minimal and maximal locations of the dimension getBounds() This method overrides the Dimension::getBounds() method """ _dx, _dy = self.getLocation() _dxpts = [] _dypts = [] _ep1, _ep2 = self.__bar1.getEndpoints() _dxpts.append(_ep1[0]) _dypts.append(_ep1[1]) _dxpts.append(_ep2[0]) _dypts.append(_ep2[1]) _ep1, _ep2 = self.__bar2.getEndpoints() _dxpts.append(_ep1[0]) _dypts.append(_ep1[1]) _dxpts.append(_ep2[0]) _dypts.append(_ep2[1]) _ep1, _ep2 = self.__crossbar.getEndpoints() _dxpts.append(_ep1[0]) _dypts.append(_ep1[1]) _dxpts.append(_ep2[0]) _dypts.append(_ep2[1]) _xmin = min(_dx, min(_dxpts)) _ymin = min(_dy, min(_dypts)) _xmax = max(_dx, max(_dxpts)) _ymax = max(_dy, max(_dypts)) return _xmin, _ymin, _xmax, _ymax def clone(self): _p1 = self.__p1 _p2 = self.__p2 _x, _y = self.getLocation() _ds = self.getDimStyle() _ldim = LinearDimension(_p1, _p2, _x, _y, _ds) _ldim.copyDimValues(self) return _ldim def __pointChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.startChange('moved') def __pointChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.endChange('moved') def __movePoint(self, p, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen if p is not self.__p1 and p is not self.__p2: raise ValueError, "Unexpected dimension point: " + `p` _dxmin, _dymin, _dxmax, _dymax = self.getBounds() self.calcDimValues(True) self.sendMessage('moved', _dxmin, _dymin, _dxmax, _dymax) def sendsMessage(self, m): if m in LinearDimension.__messages: return True return super(LinearDimension, self).sendsMessage(m) class HorizontalDimension(LinearDimension): """A class representing Horizontal dimensions. This class is derived from the LinearDimension class, so it shares all those attributes and methods of its parent. """ def __init__(self, p1, p2, x, y, ds=None, **kw): """Initialize a Horizontal Dimension. hdim = HorizontalDimension(p1, p2, x, y, ds) p1: A Point contained in a Layer p2: A Point contained in a Layer x: The x-coordinate of the dimensional text y: The y-coordinate of the dimensional text ds: The DimStyle used for this Dimension. """ super(HorizontalDimension, self).__init__(p1, p2, x, y, ds, **kw) def getValues(self): """Return values comprising the HorizontalDimension. getValues() This method extends the LinearDimension::getValues() method. """ _data = super(HorizontalDimension, self).getValues() _data.setValue('type', 'hdim') return _data def calculate(self): """Determine the length of this HorizontalDimension. calculate() """ _p1, _p2 = self.getDimPoints() return abs(_p1.x - _p2.x) def calcDimValues(self, allpts=True): """Recalculate the values for dimensional display. calcDimValues([allpts]) This method overrides the LinearDimension::calcDimValues() method. """ _allpts = allpts util.test_boolean(_allpts) _p1, _p2 = self.getDimPoints() _bar1, _bar2 = self.getDimBars() _crossbar = self.getDimCrossbar() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _dx, _dy = self.getLocation() _offset = self.getOffset() _ext = self.getExtension() _crossbar.setFirstEndpoint(_p1x, _dy) _crossbar.setSecondEndpoint(_p2x, _dy) if _dx < min(_p1x, _p2x) or _dx > max(_p1x, _p2x): if _p1x < _p2x: if _dx < _p1x: _crossbar.setFirstEndpoint(_dx, _dy) if _dx > _p2x: _crossbar.setSecondEndpoint(_dx, _dy) else: if _dx < _p2x: _crossbar.setSecondEndpoint(_dx, _dy) if _dx > _p1x: _crossbar.setFirstEndpoint(_dx, _dy) _crossbar.setFirstCrossbarPoint(_p1x, _dy) _crossbar.setSecondCrossbarPoint(_p2x, _dy) if _dy < min(_p1y, _p2y): _bar1.setFirstEndpoint(_p1x, (_p1y - _offset)) _bar1.setSecondEndpoint(_p1x, (_dy - _ext)) _bar2.setFirstEndpoint(_p2x, (_p2y - _offset)) _bar2.setSecondEndpoint(_p2x, (_dy - _ext)) elif _dy > max(_p1y, _p2y): _bar1.setFirstEndpoint(_p1x, (_p1y + _offset)) _bar1.setSecondEndpoint(_p1x, (_dy + _ext)) _bar2.setFirstEndpoint(_p2x, (_p2y + _offset)) _bar2.setSecondEndpoint(_p2x, (_dy + _ext)) else: if _dy > _p1y: _bar1.setFirstEndpoint(_p1x, (_p1y + _offset)) _bar1.setSecondEndpoint(_p1x, (_dy + _ext)) else: _bar1.setFirstEndpoint(_p1x, (_p1y - _offset)) _bar1.setSecondEndpoint(_p1x, (_dy - _ext)) if _dy > _p2y: _bar2.setFirstEndpoint(_p2x, (_p2y + _offset)) _bar2.setSecondEndpoint(_p2x, (_dy + _ext)) else: _bar2.setFirstEndpoint(_p2x, (_p2y - _offset)) _bar2.setSecondEndpoint(_p2x, (_dy - _ext)) if _allpts: self.calcMarkerPoints() def clone(self): _p1, _p2 = self.getDimPoints() _x, _y = self.getLocation() _ds = self.getDimStyle() _hdim = HorizontalDimension(_p1, _p2, _x, _y, _ds) _hdim.copyDimValues(self) return _hdim class VerticalDimension(LinearDimension): """A class representing Vertical dimensions. This class is derived from the LinearDimension class, so it shares all those attributes and methods of its parent. """ def __init__(self, p1, p2, x, y, ds=None, **kw): """Initialize a Vertical Dimension. vdim = VerticalDimension(p1, p2, x, y, ds) p1: A Point contained in a Layer p2: A Point contained in a Layer x: The x-coordinate of the dimensional text y: The y-coordinate of the dimensional text ds: The DimStyle used for this Dimension. """ super(VerticalDimension, self).__init__(p1, p2, x, y, ds, **kw) def getValues(self): """Return values comprising the VerticalDimension. getValues() This method extends the LinearDimension::getValues() method. """ _data = super(VerticalDimension, self).getValues() _data.setValue('type', 'vdim') return _data def calculate(self): """Determine the length of this VerticalDimension. calculate() """ _p1, _p2 = self.getDimPoints() return abs(_p1.y - _p2.y) def calcDimValues(self, allpts=True): """Recalculate the values for dimensional display. calcDimValues([allpts]) This method overrides the LinearDimension::calcDimValues() method. """ _allpts = allpts util.test_boolean(_allpts) _p1, _p2 = self.getDimPoints() _bar1, _bar2 = self.getDimBars() _crossbar = self.getDimCrossbar() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _dx, _dy = self.getLocation() _offset = self.getOffset() _ext = self.getExtension() _crossbar.setFirstEndpoint(_dx, _p1y) _crossbar.setSecondEndpoint(_dx, _p2y) if _dy < min(_p1y, _p2y) or _dy > max(_p1y, _p2y): if _p1y < _p2y: if _dy < _p1y: _crossbar.setFirstEndpoint(_dx, _dy) if _dy > _p2y: _crossbar.setSecondEndpoint(_dx, _dy) if _p2y < _p1y: if _dy < _p2y: _crossbar.setSecondEndpoint(_dx, _dy) if _dy > _p1y: _crossbar.setFirstEndpoint(_dx, _dy) _crossbar.setFirstCrossbarPoint(_dx, _p1y) _crossbar.setSecondCrossbarPoint(_dx, _p2y) if _dx < min(_p1x, _p2x): _bar1.setFirstEndpoint((_p1x - _offset), _p1y) _bar1.setSecondEndpoint((_dx - _ext), _p1y) _bar2.setFirstEndpoint((_p2x - _offset), _p2y) _bar2.setSecondEndpoint((_dx - _ext), _p2y) elif _dx > max(_p1x, _p2x): _bar1.setFirstEndpoint((_p1x + _offset), _p1y) _bar1.setSecondEndpoint((_dx + _ext), _p1y) _bar2.setFirstEndpoint((_p2x + _offset), _p2y) _bar2.setSecondEndpoint((_dx + _ext), _p2y) else: if _dx > _p1x: _bar1.setFirstEndpoint((_p1x + _offset), _p1y) _bar1.setSecondEndpoint((_dx + _ext), _p1y) else: _bar1.setFirstEndpoint((_p1x - _offset), _p1y) _bar1.setSecondEndpoint((_dx - _ext), _p1y) if _dx > _p2x: _bar2.setFirstEndpoint((_p2x + _offset), _p2y) _bar2.setSecondEndpoint((_dx + _ext), _p2y) else: _bar2.setFirstEndpoint((_p2x - _offset), _p2y) _bar2.setSecondEndpoint((_dx - _ext), _p2y) if _allpts: self.calcMarkerPoints() def clone(self): _p1, _p2 = self.getDimPoints() _x, _y = self.getLocation() _ds = self.getDimStyle() _vdim = VerticalDimension(_p1, _p2, _x, _y, _ds) _vdim.copyDimValues(self) return _vdim class RadialDimension(Dimension): """A class for Radial dimensions. The RadialDimension class is derived from the Dimension class, so it shares all of those methods and attributes. A RadialDimension should be used to display either the radius or diamter of a Circle object. A RadialDimension object has the following methods: {get/set}DimCircle(): Get/Set the measured circle object. getDimLayer(): Return the layer containing the measured circle. {get/set}DiaMode(): Get/Set if the RadialDimension should return diameters. getDimXPoints(): Get the x-coordinates of the dimension bar positions. getDimYPoints(): Get the y-coordinates of the dimension bar positions. getDimMarkerPoints(): Get the locaiton of the dimension endpoint markers. getDimCrossbar(): Get the DimCrossbar object of the RadialDimension. calcDimValues(): Calculate the endpoint of the dimension line. mapCoords(): Return coordinates on the dimension near some point. onDimension(): Test if an x/y coordinate pair fall on the dimension line. """ __messages = { 'dimobj_changed' : True, 'dia_mode_changed' : True, } def __init__(self, cir, x, y, ds=None, **kw): """Initialize a RadialDimension object. rdim = RadialDimension(cir, x, y, ds) cir: A Circle or Arc object x: The x-coordinate of the dimensional text y: The y-coordinate of the dimensional text ds: The DimStyle used for this Dimension. """ super(RadialDimension, self).__init__(x, y, ds, **kw) if not isinstance(cir, (circle.Circle, arc.Arc)): raise TypeError, "Invalid circle/arc type: " + `type(cir)` if cir.getParent() is None: raise ValueError, "Circle/Arc not found in Layer!" self.__circle = cir self.__crossbar = DimCrossbar() self.__dia_mode = False cir.storeUser(self) _ds = self.getDimStyle() _pds, _sds = self.getDimstrings() _pds.mute() try: _pds.setPrefix(_ds.getValue('RADIAL_DIM_PRIMARY_PREFIX')) _pds.setSuffix(_ds.getValue('RADIAL_DIM_PRIMARY_SUFFIX')) finally: _pds.unmute() _sds.mute() try: _sds.setPrefix(_ds.getValue('RADIAL_DIM_SECONDARY_PREFIX')) _sds.setSuffix(_ds.getValue('RADIAL_DIM_SECONDARY_SUFFIX')) finally: _sds.unmute() self.setDiaMode(_ds.getValue('RADIAL_DIM_DIA_MODE')) cir.connect('moved', self.__moveCircle) cir.connect('radius_changed', self.__radiusChanged) cir.connect('change_pending', self.__circleChangePending) cir.connect('change_complete', self.__circleChangeComplete) self.calcDimValues() def __eq__(self, rdim): """Compare two RadialDimensions for equality. """ if not isinstance(rdim, RadialDimension): return False _val = False _layer = self.__circle.getParent() _rc = rdim.getDimCircle() _rl = _rc.getParent() if _layer is _rl and self.__circle == _rc: _val = True return _val def __ne__(self, rdim): """Compare two RadialDimensions for inequality. """ if not isinstance(rdim, RadialDimension): return True _val = True _layer = self.__circle.getParent() _rc = rdim.getDimCircle() _rl = _rc.getParent() if _layer is _rl and self.__circle == _rc: _val = False return _val def finish(self): self.__circle.disconnect(self) self.__circle.freeUser(self) self.__circle = self.__crossbar = None super(RadialDimension, self).finish() def getValues(self): """Return values comprising the RadialDimension. getValues() This method extends the Dimension::getValues() method. """ _data = super(RadialDimension, self).getValues() _data.setValue('type', 'rdim') _data.setValue('circle', self.__circle.getID()) _layer = self.__circle.getParent() _data.setValue('layer', _layer.getID()) _data.setValue('dia_mode', self.__dia_mode) return _data def getDiaMode(self): """Return if the RadialDimension will return diametrical values. getDiaMode() This method returns True if the diameter value is returned, and False otherwise. """ return self.__dia_mode def setDiaMode(self, mode=False): """Set the RadialDimension to return diametrical values. setDiaMode([mode]) Calling this method without an argument sets the RadialDimension to return radial measurements. If the argument "mode" is supplied, it should be either True or False. If the RadialDimension is measuring an arc, the returned value will always be set to return a radius. """ util.test_boolean(mode) if not isinstance(self.__circle, arc.Arc): _m = self.__dia_mode if _m is not mode: self.startChange('dia_mode_changed') self.__dia_mode = mode self.endChange('dia_mode_changed') self.sendMessage('dia_mode_changed', _m) self.calcDimValues() self.modified() dia_mode = property(getDiaMode, setDiaMode, None, "Draw the Dimension as a diameter") def getDimLayer(self): """Return the Layer object holding the Circle for this RadialDimension. getDimLayer() """ return self.__circle.getParent() def getDimCircle(self): """Return the Circle object this RadialDimension is measuring. getDimCircle() """ return self.__circle def setDimCircle(self, c): """Set the Circle object measured by this RadialDimension. setDimCircle(c) The argument for this method is: c: A Circle/Arc contained in a Layer """ if self.isLocked(): raise RuntimeError, "Setting circle/arc not allowed - object locked." if not isinstance(c, (circle.Circle, arc.Arc)): raise TypeError, "Invalid circle/arc type: " + `type(c)` if c.getParent() is None: raise ValueError, "Circle/Arc not found in a Layer!" _circ = self.__circle if _circ is not c: _circ.disconnect(self) _circ.freeUser(self) self.startChange('dimobj_changed') self.__circle = c self.endChange('dimobj_changed') c.storeUser(self) self.sendMessage('dimobj_changed', _circ, c) c.connect('moved', self.__moveCircle) c.connect('radius_changed', self.__radiusChanged) c.connect('change_pending', self.__circleChangePending) c.connect('change_complete', self.__circleChangeComplete) self.calcDimValues() self.modified() circle = property(getDimCircle, None, None, "Radial dimension circle object.") def getDimCrossbar(self): """Get the DimCrossbar object used by the RadialDimension. getDimCrossbar() """ return self.__crossbar def calcDimValues(self, allpts=True): """Recalculate the values for dimensional display. calcDimValues([allpts]) The optional argument 'allpts' is by default True. Calling this method with the argument set to False will skip the calculation of any dimension endpoint marker points. """ _allpts = allpts util.test_boolean(_allpts) _c = self.__circle _dimbar = self.__crossbar _cx, _cy = _c.getCenter().getCoords() _rad = _c.getRadius() _dx, _dy = self.getLocation() _dia_mode = self.__dia_mode _sep = math.hypot((_dx - _cx), (_dy - _cy)) _angle = math.atan2((_dy - _cy), (_dx - _cx)) _sx = _rad * math.cos(_angle) _sy = _rad * math.sin(_angle) if isinstance(_c, arc.Arc): assert _dia_mode is False, "dia_mode for arc radial dimension" _sa = _c.getStartAngle() _ea = _c.getEndAngle() _angle = _rtd * _angle if _angle < 0.0: _angle = _angle + 360.0 if not _c.throughAngle(_angle): _ep1, _ep2 = _c.getEndpoints() if _angle < _sa: _sa = _dtr * _sa _sx = _rad * math.cos(_sa) _sy = _rad * math.sin(_sa) if _sep > _rad: _dx = _cx + (_sep * math.cos(_sa)) _dy = _cy + (_sep * math.sin(_sa)) if _angle > _ea: _ea = _dtr * _ea _sx = _rad * math.cos(_ea) _sy = _rad * math.sin(_ea) if _sep > _rad: _dx = _cx + (_sep * math.cos(_ea)) _dy = _cy + (_sep * math.sin(_ea)) if _dia_mode: _dimbar.setFirstEndpoint((_cx - _sx), (_cy - _sy)) _dimbar.setFirstCrossbarPoint((_cx - _sx), (_cy - _sy)) else: _dimbar.setFirstEndpoint(_cx, _cy) _dimbar.setFirstCrossbarPoint(_cx, _cy) if _sep > _rad: _dimbar.setSecondEndpoint(_dx, _dy) else: _dimbar.setSecondEndpoint((_cx + _sx), (_cy + _sy)) _dimbar.setSecondCrossbarPoint((_cx + _sx), (_cy + _sy)) if not _allpts: return # # calculate dimension endpoint marker coordinates # _type = self.getEndpointType() _dimbar.clearMarkerPoints() if _type == Dimension.DIM_ENDPT_NONE or _type == Dimension.DIM_ENDPT_CIRCLE: return _size = self.getEndpointSize() _x1, _y1 = _dimbar.getFirstCrossbarPoint() _x2, _y2 = _dimbar.getSecondCrossbarPoint() _sine, _cosine = _dimbar.getSinCosValues() if _type == Dimension.DIM_ENDPT_ARROW or _type == Dimension.DIM_ENDPT_FILLED_ARROW: _height = _size/5.0 # p1 -> (x,y) = (size, _height) _mx = (_cosine * _size - _sine * _height) + _x1 _my = (_sine * _size + _cosine * _height) + _y1 _dimbar.storeMarkerPoint(_mx, _my) # p2 -> (x,y) = (size, -_height) _mx = (_cosine * _size - _sine *(-_height)) + _x1 _my = (_sine * _size + _cosine *(-_height)) + _y1 _dimbar.storeMarkerPoint(_mx, _my) # p3 -> (x,y) = (-size, _height) _mx = (_cosine * (-_size) - _sine * _height) + _x2 _my = (_sine * (-_size) + _cosine * _height) + _y2 _dimbar.storeMarkerPoint(_mx, _my) # p4 -> (x,y) = (-size, -_height) _mx = (_cosine * (-_size) - _sine *(-_height)) + _x2 _my = (_sine * (-_size) + _cosine *(-_height)) + _y2 _dimbar.storeMarkerPoint(_mx, _my) elif _type == Dimension.DIM_ENDPT_SLASH: _angle = 30.0 * _dtr # slope of slash _height = 0.5 * _size * math.sin(_angle) _length = 0.5 * _size * math.cos(_angle) # p1 -> (x,y) = (-_length, -_height) _sx1 = (_cosine * (-_length) - _sine * (-_height)) _sy1 = (_sine * (-_length) + _cosine * (-_height)) # p2 -> (x,y) = (_length, _height) _sx2 = (_cosine * _length - _sine * _height) _sy2 = (_sine * _length + _cosine * _height) # # shift the calculate based on the location of the # marker point # _mx = _sx1 + _x1 _my = _sy1 + _y1 _dimbar.storeMarkerPoint(_mx, _my) _mx = _sx2 + _x1 _my = _sy2 + _y1 _dimbar.storeMarkerPoint(_mx, _my) _mx = _sx1 + _x2 _my = _sy1 + _y2 _dimbar.storeMarkerPoint(_mx, _my) _mx = _sx2 + _x2 _my = _sy2 + _y2 _dimbar.storeMarkerPoint(_mx, _my) else: raise ValueError, "Unexpected endpoint type: '%s'" % str(_type) def calculate(self): """Return the radius or diamter of this RadialDimension. calculate() By default, a RadialDimension will return the radius of the circle. The setDiaMode() method can be called to set the returned value to corresponed to a diameter. """ _val = self.__circle.getRadius() if self.__dia_mode is True: _val = _val * 2.0 return _val def inRegion(self, xmin, ymin, xmax, ymax, fully=False): """Return whether or not a RadialDimension exists within a region. isRegion(xmin, ymin, xmax, ymax[, fully]) The four arguments define the boundary of an area, and the function returns True if the RadialDimension lies within that area. If the optional argument 'fully' is used and is True, then the dimensioned circle and the location of the dimension text must lie within the boundary. Otherwise, the function returns False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) _dxmin, _dymin, _dxmax, _dymax = self.getBounds() if ((_dxmin > _xmax) or (_dymin > _ymax) or (_dxmax < _xmin) or (_dymax < _ymin)): return False if fully: if ((_dxmin > _xmin) and (_dymin > _ymin) and (_dxmax < _xmax) and (_dymax < _ymax)): return True return False _dx, _dy = self.getLocation() if _xmin < _dx < _xmax and _ymin < _dy < _ymax: # dim text return True _p1, _p2 = self.__crossbar.getEndpoints() _x1, _y1 = _p1 _x2, _y2 = _p2 return util.in_region(_x1, _y1, _x2, _y2, _xmin, _ymin, _xmax, _ymax) def mapCoords(self, x, y, tol=tolerance.TOL): """Test an x/y coordinate pair if it could lay on the dimension. mapCoords(x, y[, tol]) This method has two required parameters: x: The x-coordinate y: The y-coordinate These should both be float values. There is an optional third parameter, 'tol', giving the maximum distance from the dimension bars that the x/y coordinates may sit. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _p1, _p2 = self.__crossbar.getEndpoints() _x1, _y1 = _p1 _x2, _y2 = _p2 return util.map_coords(_x, _y, _x1, _y1, _x2, _y2, _t) def onDimension(self, x, y, tol=tolerance.TOL): return self.mapCoords(x, y, tol) is not None def getBounds(self): """Return the minimal and maximal locations of the dimension getBounds() This method overrides the Dimension::getBounds() method """ _p1, _p2 = self.__crossbar.getEndpoints() _x1, _y1 = _p1 _x2, _y2 = _p2 _xmin = min(_x1, _x2) _ymin = min(_y1, _y2) _xmax = max(_x1, _x2) _ymax = max(_y1, _y2) return _xmin, _ymin, _xmax, _ymax def clone(self): _c = self.__circle _x, _y = self.getLocation() _ds = self.getDimStyle() _rdim = RadialDimension(_c, _x, _y, _ds) _rdim.copyDimValues(self) _rdim.setDiaMode(self.getDiaMode()) return _rdim def __circleChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved' or args[0] =='radius_changed': self.startChange('moved') def __circleChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved' or args[0] =='radius_changed': self.endChange('moved') def __moveCircle(self, circ, *args): _alen = len(args) if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen if circ is not self.__circle: raise ValueError, "Unexpected sender: " + `circ` _dxmin, _dymin, _dxmax, _dymax = self.getBounds() self.calcDimValues() self.sendMessage('moved', _dxmin, _dymin, _dxmax, _dymax) def __radiusChanged(self, circ, *args): self.calcDimValues() def sendsMessage(self, m): if m in RadialDimension.__messages: return True return super(RadialDimension, self).sendsMessage(m) class AngularDimension(Dimension): """A class for Angular dimensions. The AngularDimension class is derived from the Dimension class, so it shares all of those methods and attributes. AngularDimension objects have the following methods: {get/set}VertexPoint(): Get/Set the vertex point for the AngularDimension. {get/set}P1(): Get/Set the first Point for the AngularDimension. {get/set}P2(): Get/Set the second Point for the AngularDimension. getDimPoints(): Return the two Points used in this dimension. getDimLayers(): Return the two Layers holding the Points. getDimXPoints(): Get the x-coordinates of the dimension bar positions. getDimYPoints(): Get the y-coordinates of the dimension bar positions. getDimAngles(): Get the angles at which the dimension bars should be drawn. getDimMarkerPoints(): Get the locaiton of the dimension endpoint markers. calcDimValues(): Calculate the endpoint of the dimension line. mapCoords(): Return coordinates on the dimension near some point. onDimension(): Test if an x/y coordinate pair fall on the dimension line. invert(): Switch the endpoints used to measure the dimension """ __messages = { 'point_changed' : True, 'inverted' : True, } def __init__(self, vp, p1, p2, x, y, ds=None, **kw): """Initialize an AngularDimension object. adim = AngularDimension(vp, p1, p2, x, y, ds) vp: A Point contained in a Layer p1: A Point contained in a Layer p2: A Point contained in a Layer x: The x-coordinate of the dimensional text y: The y-coordinate of the dimensional text ds: The DimStyle used for this Dimension. """ super(AngularDimension, self).__init__(x, y, ds, **kw) if not isinstance(vp, point.Point): raise TypeError, "Invalid point type: " + `type(vp)` if vp.getParent() is None: raise ValueError, "Vertex Point not found in a Layer!" if not isinstance(p1, point.Point): raise TypeError, "Invalid point type: " + `type(p1)` if p1.getParent() is None: raise ValueError, "Point P1 not found in a Layer!" if not isinstance(p2, point.Point): raise TypeError, "Invalid point type: " + `type(p2)` if p2.getParent() is None: raise ValueError, "Point P2 not found in a Layer!" self.__vp = vp self.__p1 = p1 self.__p2 = p2 self.__bar1 = DimBar() self.__bar2 = DimBar() self.__crossarc = DimCrossarc() _ds = self.getDimStyle() _pds, _sds = self.getDimstrings() _pds.mute() try: _pds.setPrefix(_ds.getValue('ANGULAR_DIM_PRIMARY_PREFIX')) _pds.setSuffix(_ds.getValue('ANGULAR_DIM_PRIMARY_SUFFIX')) finally: _pds.unmute() _sds.mute() try: _sds.setPrefix(_ds.getValue('ANGULAR_DIM_SECONDARY_PREFIX')) _sds.setSuffix(_ds.getValue('ANGULAR_DIM_SECONDARY_SUFFIX')) finally: _sds.unmute() vp.storeUser(self) vp.connect('moved', self.__movePoint) vp.connect('change_pending', self.__pointChangePending) vp.connect('change_complete', self.__pointChangeComplete) p1.storeUser(self) p1.connect('moved', self.__movePoint) p1.connect('change_pending', self.__pointChangePending) p1.connect('change_complete', self.__pointChangeComplete) p2.storeUser(self) p2.connect('moved', self.__movePoint) p2.connect('change_pending', self.__pointChangePending) p2.connect('change_complete', self.__pointChangeComplete) self.calcDimValues() def __eq__(self, adim): """Compare two AngularDimensions for equality. """ if not isinstance(adim, AngularDimension): return False _val = False _lvp = self.__vp.getParent() _lp1 = self.__p1.getParent() _lp2 = self.__p2.getParent() _vl, _l1, _l2 = adim.getDimLayers() _vp, _p1, _p2 = adim.getDimPoints() if (_lvp is _vl and self.__vp == _vp and _lp1 is _l1 and self.__p1 == _p1 and _lp2 is _l2 and self.__p2 == _p2): _val = True return _val def __ne__(self, adim): """Compare two AngularDimensions for inequality. """ if not isinstance(adim, AngularDimension): return True _val = True _lvp = self.__vp.getParent() _lp1 = self.__p1.getParent() _lp2 = self.__p2.getParent() _vl, _l1, _l2 = adim.getDimLayers() _vp, _p1, _p2 = adim.getDimPoints() if (_lvp is _vl and self.__vp == _vp and _lp1 is _l1 and self.__p1 == _p1 and _lp2 is _l2 and self.__p2 == _p2): _val = False return _val def finish(self): self.__vp.disconnect(self) self.__vp.freeUser(self) self.__p1.disconnect(self) self.__p1.freeUser(self) self.__p2.disconnect(self) self.__p2.freeUser(self) self.__bar1 = self.__bar2 = self.__crossarc = None self.__vp = self.__p1 = self.__p2 = None super(AngularDimension, self).finish() def getValues(self): """Return values comprising the AngularDimension. getValues() This method extends the Dimension::getValues() method. """ _data = super(AngularDimension, self).getValues() _data.setValue('type', 'adim') _data.setValue('vp', self.__vp.getID()) _layer = self.__vp.getParent() _data.setValue('vl', _layer.getID()) _data.setValue('p1', self.__p1.getID()) _layer = self.__p1.getParent() _data.setValue('l1', _layer.getID()) _data.setValue('p2', self.__p2.getID()) _layer = self.__p2.getParent() _data.setValue('l2', _layer.getID()) return _data def getDimLayers(self): """Return the layers used in an AngularDimension. getDimLayers() """ _vl = self.__vp.getParent() _l1 = self.__p1.getParent() _l2 = self.__p2.getParent() return _vl, _l1, _l2 def getDimPoints(self): """Return the points used in an AngularDimension. getDimPoints() """ return self.__vp, self.__p1, self.__p2 def getVertexPoint(self): """Return the vertex point used in an AngularDimension. getVertexPoint() """ return self.__vp def setVertexPoint(self, p): """Set the vertex point for an AngularDimension. setVertexPoint(p) There is one required argument for this method: p: A Point contained in Layer """ if self.isLocked(): raise RuntimeError, "Setting vertex point allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid point type: " + `type(p)` if p.getParent() is None: raise ValueError, "Point not found in a Layer!" _vp = self.__vp if _vp is not p: _vp.disconnect(self) _vp.freeUser(self) self.startChange('point_changed') self.__vp = p self.endChange('point_changed') p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) self.sendMessage('point_changed', _vp, p) self.calcDimValues() if abs(_vp.x - p.x) > 1e-10 or abs(_vp.y - p.y) > 1e-10: _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() _dx, _dy = self.getLocation() self.sendMessage('moved', _vp.x, _vp.y, _x1, _y1, _x2, _y2, _dx, _dy) self.modified() vp = property(getVertexPoint, None, None, "Angular Dimension vertex point.") def getP1(self): """Return the first angle point used in an AngularDimension. getP1() """ return self.__p1 def setP1(self, p): """Set the first Point for an AngularDimension. setP1(p) There is one required argument for this method: p: A Point contained in a Layer. """ if self.isLocked(): raise RuntimeError, "Setting vertex point allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid point type: " + `type(p)` if p.getParent() is None: raise ValueError, "Point not found in a Layer!" _p1 = self.__p1 if _p1 is not p: _p1.disconnect(self) _p1.freeUser(self) self.startChange('point_changed') self.__p1 = p self.endChange('point_changed') p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) self.sendMessage('point_changed', _p1, p) self.calcDimValues() if abs(_p1.x - p.x) > 1e-10 or abs(_p1.y - p.y) > 1e-10: _vx, _vy = self.__vp.getCoords() _x2, _y2 = self.__p2.getCoords() _dx, _dy = self.getLocation() self.sendMessage('moved', _vx, _vy, _p1.x, _p1.y, _x2, _y2, _dx, _dy) self.modified() p1 = property(getP1, None, None, "Dimension first point.") def getP2(self): """Return the second angle point used in an AngularDimension. getP2() """ return self.__p2 def setP2(self, p): """Set the second Point for an AngularDimension. setP2(p) There is one required argument for this method: l: The layer holding the Point p p: A point in Layer l """ if self.isLocked(): raise RuntimeError, "Setting vertex point allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid point type: " + `type(p)` if p.getParent() is None: raise ValueError, "Point not found in a Layer!" _p2 = self.__p2 if _p2 is not p: _p2.disconnect(self) _p2.freeUser(self) self.startChange('point_changed') self.__p2 = p self.endChange('point_changed') p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) self.sendMessage('point_changed', _p2, p) self.calcDimValues() if abs(_p2.x - p.x) > 1e-10 or abs(_p2.y - p.y) > 1e-10: _vx, _vy = self.__vp.getCoords() _x1, _y1 = self.__p1.getCoords() _dx, _dy = self.getLocation() self.sendMessage('moved', _vx, _vy, _x1, _y1, _p2.x, _p2.y, _dx, _dy) self.modified() p2 = property(getP2, None, None, "Dimension second point.") def getDimAngles(self): """Get the array of dimension bar angles. geDimAngles() """ _angle1 = self.__bar1.getAngle() _angle2 = self.__bar2.getAngle() return _angle1, _angle2 def getDimRadius(self): """Get the radius of the dimension crossarc. getDimRadius() """ return self.__crossarc.getRadius() def getDimBars(self): """Return the dimension boundary bars. getDimBars() """ return self.__bar1, self.__bar2 def getDimCrossarc(self): """Get the DimCrossarc object used by the AngularDimension. getDimCrossarc() """ return self.__crossarc def invert(self): """Switch the endpoints used in this object. invert() Invoking this method on an AngularDimension will result in it measuring the opposite angle than what it currently measures. """ _pt = self.__p1 self.startChange('inverted') self.__p1 = self.__p2 self.__p2 = _pt self.endChange('inverted') self.sendMessage('inverted') self.calcDimValues() self.modified() def calculate(self): """Find the value of the angle measured by this AngularDimension. calculate() """ _vx, _vy = self.__vp.getCoords() _p1x, _p1y = self.__p1.getCoords() _p2x, _p2y = self.__p2.getCoords() _a1 = _rtd * math.atan2((_p1y - _vy), (_p1x - _vx)) if _a1 < 0.0: _a1 = _a1 + 360.0 _a2 = _rtd * math.atan2((_p2y - _vy), (_p2x - _vx)) if _a2 < 0.0: _a2 = _a2 + 360.0 _val = _a2 - _a1 if _a1 > _a2: _val = _val + 360.0 return _val def inRegion(self, xmin, ymin, xmax, ymax, fully=False): """Return whether or not an AngularDimension exists within a region. isRegion(xmin, ymin, xmax, ymax[, fully]) The four arguments define the boundary of an area, and the function returns True if the RadialDimension lies within that area. If the optional argument 'fully' is used and is True, then the dimensioned circle and the location of the dimension text must lie within the boundary. Otherwise, the function returns False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) _vx, _vy = self.__vp.getCoords() _dx, _dy = self.getLocation() _pxmin, _pymin, _pxmax, _pymax = self.getBounds() _val = False if ((_pxmin > _xmax) or (_pymin > _ymax) or (_pxmax < _xmin) or (_pymax < _ymin)): return False if _xmin < _dx < _xmax and _ymin < _dy < _ymax: return True # # bar on vp-p1 line # _ep1, _ep2 = self.__bar1.getEndpoints() _ex1, _ey1 = _ep1 _ex2, _ey2 = _ep2 if util.in_region(_ex1, _ey1, _ex2, _ey2, _xmin, _ymin, _xmax, _ymax): return True # # bar at vp-p2 line # _ep1, _ep2 = self.__bar2.getEndpoints() _ex1, _ey1 = _ep1 _ex2, _ey2 = _ep2 if util.in_region(_ex1, _ey1, _ex2, _ey2, _xmin, _ymin, _xmax, _ymax): return True # # dimension crossarc # _val = False _r = self.__crossarc.getRadius() _d1 = math.hypot((_xmin - _vx), (_ymin - _vy)) _d2 = math.hypot((_xmin - _vx), (_ymax - _vy)) _d3 = math.hypot((_xmax - _vx), (_ymax - _vy)) _d4 = math.hypot((_xmax - _vx), (_ymin - _vy)) _dmin = min(_d1, _d2, _d3, _d4) _dmax = max(_d1, _d2, _d3, _d4) if _xmin < _vx < _xmax and _ymin < _vy < _ymax: _dmin = -1e-10 else: if _vx > _xmax and _ymin < _vy < _ymax: _dmin = _vx - _xmax elif _vx < _xmin and _ymin < _vy < _ymax: _dmin = _xmin - _vx elif _vy > _ymax and _xmin < _vx < _xmax: _dmin = _vy - _ymax elif _vy < _ymin and _xmin < _vx < _xmax: _dmin = _ymin - _vy if _dmin < _r < _dmax: _da = _rtd * math.atan2((_ymin - _vy), (_xmin - _vx)) if _da < 0.0: _da = _da + 360.0 _val = self._throughAngle(_da) if _val: return _val _da = _rtd * math.atan2((_ymin - _vy), (_xmax - _vx)) if _da < 0.0: _da = _da + 360.0 _val = self._throughAngle(_da) if _val: return _val _da = _rtd * math.atan2((_ymax - _vy), (_xmax - _vx)) if _da < 0.0: _da = _da + 360.0 _val = self._throughAngle(_da) if _val: return _val _da = _rtd * math.atan2((_ymax - _vy), (_xmin - _vx)) if _da < 0.0: _da = _da + 360.0 _val = self._throughAngle(_da) return _val def _throughAngle(self, angle): """Test if the angular crossarc exists at a certain angle. _throughAngle() This method is private to the AngularDimension class. """ _crossarc = self.__crossarc _sa = _crossarc.getStartAngle() _ea = _crossarc.getEndAngle() _val = True if abs(_sa - _ea) > 1e-10: if _sa > _ea: if angle > _ea and angle < _sa: _val = False else: if angle > _ea or angle < _sa: _val = False return _val def calcDimValues(self, allpts=True): """Recalculate the values for dimensional display. calcDimValues([allpts]) The optional argument 'allpts' is by default True. Calling this method with the argument set to False will skip the calculation of any dimension endpoint marker points. """ _allpts = allpts util.test_boolean(_allpts) _vx, _vy = self.__vp.getCoords() _p1x, _p1y = self.__p1.getCoords() _p2x, _p2y = self.__p2.getCoords() _dx, _dy = self.getLocation() _offset = self.getOffset() _ext = self.getExtension() _bar1 = self.__bar1 _bar2 = self.__bar2 _crossarc = self.__crossarc _dv1 = math.hypot((_p1x - _vx), (_p1y - _vy)) _dv2 = math.hypot((_p2x - _vx), (_p2y - _vy)) _ddp = math.hypot((_dx - _vx), (_dy - _vy)) _crossarc.setRadius(_ddp) # # first dimension bar # _angle = math.atan2((_p1y - _vy), (_p1x - _vx)) _sine = math.sin(_angle) _cosine = math.cos(_angle) _deg = _angle * _rtd if _deg < 0.0: _deg = _deg + 360.0 _crossarc.setStartAngle(_deg) _ex = _vx + (_ddp * _cosine) _ey = _vy + (_ddp * _sine) _crossarc.setFirstCrossbarPoint(_ex, _ey) _crossarc.setFirstEndpoint(_ex, _ey) if _ddp > _dv1: # dim point is radially further to vp than p1 _x1 = _p1x + (_offset * _cosine) _y1 = _p1y + (_offset * _sine) _x2 = _vx + ((_ddp + _ext) * _cosine) _y2 = _vy + ((_ddp + _ext) * _sine) else: # dim point is radially closer to vp than p1 _x1 = _p1x - (_offset * _cosine) _y1 = _p1y - (_offset * _sine) _x2 = _vx + ((_ddp - _ext) * _cosine) _y2 = _vy + ((_ddp - _ext) * _sine) _bar1.setFirstEndpoint(_x1, _y1) _bar1.setSecondEndpoint(_x2, _y2) # # second dimension bar # _angle = math.atan2((_p2y - _vy), (_p2x - _vx)) _sine = math.sin(_angle) _cosine = math.cos(_angle) _deg = _angle * _rtd if _deg < 0.0: _deg = _deg + 360.0 _crossarc.setEndAngle(_deg) _ex = _vx + (_ddp * _cosine) _ey = _vy + (_ddp * _sine) _crossarc.setSecondCrossbarPoint(_ex, _ey) _crossarc.setSecondEndpoint(_ex, _ey) if _ddp > _dv2: # dim point is radially further to vp than p2 _x1 = _p2x + (_offset * _cosine) _y1 = _p2y + (_offset * _sine) _x2 = _vx + ((_ddp + _ext) * _cosine) _y2 = _vy + ((_ddp + _ext) * _sine) else: # dim point is radially closers to vp than p2 _x1 = _p2x - (_offset * _cosine) _y1 = _p2y - (_offset * _sine) _x2 = _vx + ((_ddp - _ext) * _cosine) _y2 = _vy + ((_ddp - _ext) * _sine) _bar2.setFirstEndpoint(_x1, _y1) _bar2.setSecondEndpoint(_x2, _y2) # # test if the DimString lies outside the measured angle # and if it does adjust either the crossarc start or end angle # _deg = _rtd * math.atan2((_dy - _vy), (_dx - _vx)) if _deg < 0.0: _deg = _deg + 360.0 _csa = _crossarc.getStartAngle() _cea = _crossarc.getEndAngle() if ((_csa > _cea) and (_cea < _deg < _csa)): if abs(_csa - _deg) < abs(_deg - _cea): # closer to start _crossarc.setStartAngle(_deg) else: _crossarc.setEndAngle(_deg) elif ((_cea > _csa) and ((_csa > _deg) or (_cea < _deg))): if _deg > _cea: _a1 = _deg - _cea _a2 = 360.0 - _deg + _csa else: _a1 = 360.0 - _cea + _deg _a2 = _csa - _deg if abs(_a1) > abs(_a2): # closer to start _crossarc.setStartAngle(_deg) else: _crossarc.setEndAngle(_deg) else: pass if not _allpts: return # # calculate dimension endpoint marker coordinates # _type = self.getEndpointType() _crossarc.clearMarkerPoints() if _type == Dimension.DIM_ENDPT_NONE or _type == Dimension.DIM_ENDPT_CIRCLE: return _size = self.getEndpointSize() _a1 = _bar1.getAngle() - 90.0 _a2 = _bar2.getAngle() - 90.0 # print "a1: %g" % _a1 # print "a2: %g" % _a2 _mp1, _mp2 = _crossarc.getCrossbarPoints() _x1, _y1 = _mp1 _x2, _y2 = _mp2 # print "x1: %g" % _x1 # print "y1: %g" % _y1 # print "x2: %g" % _x2 # print "y2: %g" % _y2 _sin1 = math.sin(_dtr * _a1) _cos1 = math.cos(_dtr * _a1) _sin2 = math.sin(_dtr * _a2) _cos2 = math.cos(_dtr * _a2) if _type == Dimension.DIM_ENDPT_ARROW or _type == Dimension.DIM_ENDPT_FILLED_ARROW: _height = _size/5.0 # p1 -> (x,y) = (size, _height) _mx = (_cos1 * (-_size) - _sin1 * _height) + _x1 _my = (_sin1 * (-_size) + _cos1 * _height) + _y1 _crossarc.storeMarkerPoint(_mx, _my) # p2 -> (x,y) = (size, -_height) _mx = (_cos1 * (-_size) - _sin1 *(-_height)) + _x1 _my = (_sin1 * (-_size) + _cos1 *(-_height)) + _y1 _crossarc.storeMarkerPoint(_mx, _my) # p3 -> (x,y) = (size, _height) _mx = (_cos2 * _size - _sin2 * _height) + _x2 _my = (_sin2 * _size + _cos2 * _height) + _y2 _crossarc.storeMarkerPoint(_mx, _my) # p4 -> (x,y) = (size, -_height) _mx = (_cos2 * _size - _sin2 *(-_height)) + _x2 _my = (_sin2 * _size + _cos2 *(-_height)) + _y2 _crossarc.storeMarkerPoint(_mx, _my) elif _type == Dimension.DIM_ENDPT_SLASH: _angle = 30.0 * _dtr # slope of slash _height = 0.5 * _size * math.sin(_angle) _length = 0.5 * _size * math.cos(_angle) # p1 -> (x,y) = (-_length, -_height) _mx = (_cos1 * (-_length) - _sin1 * (-_height)) + _x1 _my = (_sin1 * (-_length) + _cos1 * (-_height)) + _y1 _crossarc.storeMarkerPoint(_mx, _my) # p2 -> (x,y) = (_length, _height) _mx = (_cos1 * _length - _sin1 * _height) + _x1 _my = (_sin1 * _length + _cos1 * _height) + _y1 _crossarc.storeMarkerPoint(_mx, _my) # p3 -> (x,y) = (-_length, -_height) _mx = (_cos2 * (-_length) - _sin2 * (-_height)) + _x2 _my = (_sin2 * (-_length) + _cos2 * (-_height)) + _y2 _crossarc.storeMarkerPoint(_mx, _my) # p4 -> (x,y) = (_length, _height) _mx = (_cos2 * _length - _sin2 * _height) + _x2 _my = (_sin2 * _length + _cos2 * _height) + _y2 _crossarc.storeMarkerPoint(_mx, _my) else: raise ValueError, "Unexpected endpoint type: '%s'" % str(_type) def mapCoords(self, x, y, tol=tolerance.TOL): """Test an x/y coordinate pair hit the dimension lines and arc. mapCoords(x, y[, tol]) This method has two required parameters: x: The x-coordinate y: The y-coordinate These should both be float values. There is an optional third parameter, 'tol', giving the maximum distance from the dimension bars that the x/y coordinates may sit. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) # # test vp-p1 bar # _ep1, _ep2 = self.__bar1.getEndpoints() _ex1, _ey1 = _ep1 _ex2, _ey2 = _ep2 _mp = util.map_coords(_x, _y, _ex1, _ey1, _ex2, _ey2, _t) if _mp is not None: return _mp # # test vp-p2 bar # _ep1, _ep2 = self.__bar2.getEndpoints() _mp = util.map_coords(_x, _y, _ex1, _ey1, _ex2, _ey2, _t) if _mp is not None: return _mp # # test the arc # _vx, _vy = self.__vp.getCoords() _psep = math.hypot((_vx - _x), (_vy - y)) _dx, _dy = self.getLocation() _dsep = math.hypot((_vx - _dx), (_vy - _dy)) if abs(_psep - _dsep) < _t: _crossarc = self.__crossarc _sa = _crossarc.getStartAngle() _ea = _crossarc.getEndAngle() _angle = _rtd * math.atan2((_y - _vy), (_x - _vx)) _val = True if abs(_sa - _ea) > 1e-10: if _sa < _ea: if _angle < _sa or _angle > _ea: _val = False else: if _angle > _ea or _angle < _sa: _val = False if _val: _xoff = _dsep * math.cos(_angle) _yoff = _dsep * math.sin(_angle) return (_vx + _xoff), (_vy + _yoff) return None def onDimension(self, x, y, tol=tolerance.TOL): return self.mapCoords(x, y, tol) is not None def getBounds(self): """Return the minimal and maximal locations of the dimension getBounds() This method overrides the Dimension::getBounds() method """ _vx, _vy = self.__vp.getCoords() _dx, _dy = self.getLocation() _dxpts = [] _dypts = [] _ep1, _ep2 = self.__bar1.getEndpoints() _dxpts.append(_ep1[0]) _dypts.append(_ep1[1]) _dxpts.append(_ep2[0]) _dypts.append(_ep2[1]) _ep1, _ep2 = self.__bar2.getEndpoints() _dxpts.append(_ep1[0]) _dypts.append(_ep1[1]) _dxpts.append(_ep2[0]) _dypts.append(_ep2[1]) _rad = self.__crossarc.getRadius() if self._throughAngle(0.0): _dxpts.append((_vx + _rad)) if self._throughAngle(90.0): _dypts.append((_vy + _rad)) if self._throughAngle(180.0): _dxpts.append((_vx - _rad)) if self._throughAngle(270.0): _dypts.append((_vy - _rad)) _xmin = min(_dx, min(_dxpts)) _ymin = min(_dy, min(_dypts)) _xmax = max(_dx, max(_dxpts)) _ymax = max(_dy, max(_dypts)) return _xmin, _ymin, _xmax, _ymax def clone(self): _vp = self.__vp _p1 = self.__p1 _p2 = self.__p2 _x, _y = self.getLocation() _ds = self.getDimStyle() _adim = AngularDimension(_vp, _p1, _p2, _x, _y, _ds) _adim.copyDimValues(self) return _adim def __movePoint(self, p, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen if ((p is not self.__vp) and (p is not self.__p1) and (p is not self.__p2)): raise ValueError, "Unexpected dimension point: " + `p` _dxmin, _dymin, _dxmax, _dymax = self.getBounds() self.calcDimValues() self.sendMessage('moved', _dxmin, _dymin, _dxmax, _dymax) def __pointChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.startChange('moved') def __pointChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.endChange('moved') def sendsMessage(self, m): if m in AngularDimension.__messages: return True return super(AngularDimension, self).sendsMessage(m) # # DimString history class # class DimStringLog(text.TextBlockLog): __setops = { 'prefix_changed' : DimString.setPrefix, 'suffix_changed' : DimString.setSuffix, 'units_changed' : DimString.setUnits, 'precision_changed' : DimString.setPrecision, 'print_zero_changed' : DimString.setPrintZero, 'print_decimal_changed' : DimString.setPrintDecimal, 'dimension_changed' : DimString.setDimension, } __getops = { 'prefix_changed' : DimString.getPrefix, 'suffix_changed' : DimString.getSuffix, 'units_changed' : DimString.getUnits, 'precision_changed' : DimString.getPrecision, 'print_zero_changed' : DimString.getPrintZero, 'print_decimal_changed' : DimString.getPrintDecimal, 'dimension_changed' : DimString.getDimension, } def __init__(self, obj): if not isinstance(obj, DimString): raise TypeError, "Invalid DimString type: " + `type(obj)` super(DimStringLog, self).__init__(obj) _ds = self.getObject() _ds.connect('prefix_changed', self._prefixChanged) _ds.connect('suffix_changed', self._suffixChanged) _ds.connect('units_changed', self._unitsChanged) _ds.connect('precision_changed', self._precisionChanged) _ds.connect('print_zero_changed', self._printZeroChanged) _ds.connect('print_decimal_changed', self._printDecimalChanged) _ds.connect('dimension_changed', self._dimensionChanged) def _prefixChanged(self, ds, *args): # print "prefixChanged() ..." _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _prefix = args[0] if not isinstance(_prefix, types.StringTypes): raise TypeError, "Invalid prefix type: " + `type(_prefix)` # print "old prefix: %s" % _prefix self.saveUndoData('prefix_changed', _prefix) def _suffixChanged(self, ds, *args): # print "suffixChanged() ..." _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _suffix = args[0] if not isinstance(_suffix, types.StringTypes): raise TypeError, "Invalid suffix type " + `type(_suffix)` # print "old suffix: %s" % _suffix self.saveUndoData('suffix_changed', _suffix) def _unitsChanged(self, ds, *args): # print "unitsChanged() ..." _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _units = args[0] if not isinstance(_units, int): raise TypeError, "Invalid unit type: " + `type(_units)` # print "old units: %d" % _units self.saveUndoData('units_changed', _units) def _precisionChanged(self, ds, *args): # print "precisionChanged() ..." _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _prec = args[0] if not isinstance(_prec, int): raise TypeError, "Invalid precision type: " + `type(_prec)` # print "old precision: %d" % _prec self.saveUndoData('precision_changed', _prec) def _printZeroChanged(self, ds, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _flag = args[0] util.test_boolean(_flag) self.saveUndoData('print_zero_changed', _flag) def _printDecimalChanged(self, ds, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _flag = args[0] util.test_boolean(_flag) self.saveUndoData('print_decimal_changed', _flag) def _dimensionChanged(self, ds, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _dim = args[0] if not isinstance(_dim, Dimension): raise TypeError, "Invalid dimension type: " + `type(_dim)` self.saveUndoData('dimension_changed', _dim.getID()) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if len(args) == 0: raise ValueError, "No arguments to execute()" _obj = self.getObject() _op = args[0] if (_op == 'prefix_changed' or _op == 'suffix_changed' or _op == 'units_changed' or _op == 'precision_changed' or _op == 'print_zero_changed' or _op == 'print_decimal_changed'): if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _val = args[1] _get = DimStringLog.__getops[_op] _sdata = _get(_obj) self.ignore(_op) try: _set = DimStringLog.__setops[_op] if undo: _obj.startUndo() try: _set(_obj, _val) finally: _obj.endUndo() else: _obj.startRedo() try: _set(_obj, _val) finally: _obj.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'dimension_changed': pass # fixme else: super(DimStringLog, self).execute(undo, *args) # # Dimension history class # class DimLog(entity.EntityLog): __setops = { 'offset_changed' : Dimension.setOffset, 'extension_changed' : Dimension.setExtension, 'endpoint_type_changed' : Dimension.setEndpointType, 'endpoint_size_changed' : Dimension.setEndpointSize, 'dual_mode_changed' : Dimension.setDualDimMode, 'dual_mode_offset_changed' : Dimension.setDualModeOffset, 'position_changed' : Dimension.setPosition, 'position_offset_changed' : Dimension.setPositionOffset, 'thickness_changed' : Dimension.setThickness, 'scale_changed' : Dimension.setScale, 'dia_mode_changed' : RadialDimension.setDiaMode, } __getops = { 'offset_changed' : Dimension.getOffset, 'extension_changed' : Dimension.getExtension, 'endpoint_type_changed' : Dimension.getEndpointType, 'endpoint_size_changed' : Dimension.getEndpointSize, 'dual_mode_changed' : Dimension.getDualDimMode, 'dual_mode_offset_changed' : Dimension.getDualModeOffset, 'position_changed' : Dimension.getPosition, 'position_offset_changed' : Dimension.getPositionOffset, 'thickness_changed' : Dimension.getThickness, 'scale_changed' : Dimension.getScale, 'dia_mode_changed' : RadialDimension.getDiaMode, } def __init__(self, dim): if not isinstance(dim, Dimension): raise TypeError, "Invalid dimension type: " + `type(dim)` super(DimLog, self).__init__(dim) _ds1, _ds2 = dim.getDimstrings() _ds1.connect('modified', self._dimstringChanged) _ds2.connect('modified', self._dimstringChanged) dim.connect('offset_changed', self._offsetChanged) dim.connect('extension_changed', self._extensionChanged) # dim.connect('dimstyle_changed', self._dimstyleChanged) dim.connect('endpoint_type_changed', self._endpointTypeChanged) dim.connect('endpoint_size_changed', self._endpointSizeChanged) dim.connect('dual_mode_changed', self._dualModeChanged) dim.connect('dual_mode_offset_changed', self._dualModeOffsetChanged) dim.connect('position_changed', self._positionChanged) dim.connect('position_offset_changed', self._positionOffsetChanged) dim.connect('color_changed', self._colorChanged) dim.connect('thickness_changed', self._thicknessChanged) dim.connect('scale_changed', self._scaleChanged) dim.connect('location_changed', self._locationChanged) if not isinstance(dim, RadialDimension): dim.connect('point_changed', self._pointChanged) if isinstance(dim, RadialDimension): dim.connect('dia_mode_changed', self._diaModeChanged) dim.connect('dimobj_changed', self._dimObjChanged) if isinstance(dim, AngularDimension): dim.connect('inverted', self._dimInverted) # dim.connect('moved', self._moveDim) def detatch(self): _dim = self.getObject() super(DimLog, self).detatch() _ds1, _ds2 = _dim.getDimstrings() _ds1.disconnect(self) _log = _ds1.getLog() if _log is not None: _log.detatch() _ds1.setLog(None) _ds2.disconnect(self) _log = _ds2.getLog() if _log is not None: _log.detatch() _ds2.setLog(None) def _moveDim(self, dim, *args): _alen = len(args) if _alen < 4: raise ValueError, "Invalid argument count: %d" % _alen _xmin = util.get_float(args[0]) _ymin = util.get_float(args[1]) _xmax = util.get_float(args[2]) _ymax = util.get_float(args[3]) self.saveUndoData('moved', _xmin, _ymin, _xmax, _ymax) def _dimstringChanged(self, dstr, *args): _dim = self.getObject() _ds1, _ds2 = _dim.getDimstrings() if dstr is _ds1: _dstr = 'ds1' elif dstr is _ds2: _dstr = 'ds2' else: raise ValueError, "Unexpected Dimstring: " + `dstr` self.saveUndoData('dimstring_changed', _dstr) _dim.modified() def _endpointTypeChanged(self, dim, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _ep = args[0] if (_ep != Dimension.DIM_ENDPT_NONE and _ep != Dimension.DIM_ENDPT_ARROW and _ep != Dimension.DIM_ENDPT_FILLED_ARROW and _ep != Dimension.DIM_ENDPT_SLASH and _ep != Dimension.DIM_ENDPT_CIRCLE): raise ValueError, "Invalid endpoint value: '%s'" % str(_ep) self.saveUndoData('endpoint_type_changed', _ep) def _endpointSizeChanged(self, dim, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _size = args[0] if not isinstance(_size, float): raise TypeError, "Unexpected type for size: " + `type(_size)` if _size < 0.0: raise ValueError, "Invalid endpoint size: %g" % _size self.saveUndoData('endpoint_size_changed', _size) def _dualModeChanged(self, dim, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _flag = args[0] util.test_boolean(_flag) self.saveUndoData('dual_mode_changed', _flag) def _dualModeOffsetChanged(self, dim, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _offset = args[0] if not isinstance(_offset, float): raise TypeError, "Unexpected type for flag: " + `type(_offset)` if _offset < 0.0: raise ValueError, "Invalid dual mode offset: %g" % _offset self.saveUndoData('dual_mode_offset_changed', _offset) def _positionChanged(self, dim, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _pos = args[0] if (_pos != Dimension.DIM_TEXT_POS_SPLIT and _pos != Dimension.DIM_TEXT_POS_ABOVE and _pos != Dimension.DIM_TEXT_POS_BELOW): raise ValueError, "Invalid position: '%s'" % str(_pos) self.saveUndoData('position_changed', _pos) def _positionOffsetChanged(self, dim, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _offset = args[0] if not isinstance(_offset, float): raise TypeError, "Unexpected type for offset: " + `type(_offset)` if _offset < 0.0: raise ValueError, "Invalid position offset: %g" % _offset self.saveUndoData('position_offset_changed', _offset) def _thicknessChanged(self, dim, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _t = args[0] if not isinstance(_t, float): raise TypeError, "Unexpected type for thickness" + `type(_t)` if _t < 0.0: raise ValueError, "Invalid thickness: %g" % _t self.saveUndoData('thickness_changed', _t) def _scaleChanged(self, dim, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _s = args[0] if not isinstance(_s, float): raise TypeError, "Unexpected type for scale" + `type(_s)` if not _s > 0.0: raise ValueError, "Invalid scale: %g" % _s self.saveUndoData('scale_changed', _s) def _colorChanged(self, dim, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _color = args[0] if not isinstance(_color, color.Color): raise TypeError, "Invalid color: " + str(_color) self.saveUndoData('color_changed', _color.getColors()) def _offsetChanged(self, dim, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _offset = args[0] if not isinstance(_offset, float): raise TypeError, "Unexpected type for offset: " + `type(_offset)` if _offset < 0.0: raise ValueError, "Invalid offset: %g" % _offset self.saveUndoData('offset_changed', _offset) def _extensionChanged(self, dim, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _extlen = args[0] if not isinstance(_extlen, float): raise TypeError, "Unexpected type for length: " + `type(_extlen)` if _extlen < 0.0: raise ValueError, "Invalid extension length: %g" % _extlen self.saveUndoData('extension_changed', _extlen) def _diaModeChanged(self, dim, *args): # RadialDimensions _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _flag = args[0] util.test_boolean(_flag) self.saveUndoData('dia_mode_changed', _flag) def _dimInverted(self, dim, *args): # AngularDimensions self.saveUndoData('inverted') def _dimstyleChanged(self, dim, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _ds = args[0] if not isinstance(_ds, DimStyle): raise TypeError, "Invalid DimStyle type: " + `type(_ds)` _opts = args[1] if not isinstance(_opts, dict): raise TypeError, "Invalid option type: " + `type(_opts)` _data = {} _data['dimstyle'] = _ds.getValues() _data.update(_opts) self.saveUndoData('dimstyle_changed', _data) def _locationChanged(self, dim, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = args[0] if not isinstance(_x, float): raise TypeError, "Unexpected type for x location" + `type(_x)` _y = args[1] if not isinstance(_y, float): raise TypeError, "Unexpected type for y location" + `type(_y)` self.saveUndoData('location_changed', _x, _y) def _pointChanged(self, dim, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _op = args[0] if not isinstance(_op, point.Point): raise TypeError, "Unexpected type for old point" + `type(_op)` _np = args[1] if not isinstance(_np, point.Point): raise TypeError, "Unexpected type for new point" + `type(_np)` _ol = _op.getParent() if _ol is None: raise RuntimeError, "Invalid Parent for replaced Point" + `_op` _olid = _ol.getID() _oid = _op.getID() _nl = _np.getParent() if _nl is None: raise RuntimeError, "Invalid Parent for new Point" + `_np` _nlid = _nl.getID() _nid = _np.getID() self.saveUndoData('point_changed', _olid, _oid, _nlid, _nid) def _dimObjChanged(self, dim, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _oo = args[0] if not isinstance(_oo, (circle.Circle, arc.Arc)): raise TypeError, "Unexpected type for old object" + `type(_oo)` _no = args[1] if not isinstance(_no, (circle.Circle, arc.Arc)): raise TypeError, "Unexpected type for new object" + `type(_no)` _ol = _oo.getParent() if _ol is None: raise RuntimeError, "Invalid Parent for replaced object" + `_oo` _olid = _ol.getID() _oid = _oo.getID() _nl = _no.getParent() if _nl is None: raise RuntimeError, "Invalid Parent for new object" + `_no` _nlid = _nl.getID() _nid = _no.getID() self.saveUndoData('dimobj_changed', _olid, _oid, _nlid, _nid) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if len(args) == 0: raise ValueError, "No arguments to execute()" _dim = self.getObject() _image = None _layer = _dim.getParent() if _layer is not None: _image = _layer.getParent() _op = args[0] if (_op == 'offset_changed' or _op == 'extension_changed' or _op == 'endpoint_type_changed' or _op == 'endpoint_size_changed' or _op == 'dual_mode_changed' or _op == 'dual_mode_offset_changed' or _op == 'dia_mode_changed' or _op == 'thickness_changed' or _op == 'scale_changed' or _op == 'position_changed' or _op == 'position_offset_changed'): if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _val = args[1] _get = DimLog.__getops[_op] _sdata = _get(_dim) self.ignore(_op) try: _set = DimLog.__setops[_op] if undo: _dim.startUndo() try: _set(_dim, _val) finally: _dim.endUndo() else: _dim.startRedo() try: _set(_dim, _val) finally: _dim.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'color_changed': if _image is None: raise RuntimeError, "Dimension not stored in an Image" if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _sdata = _dim.getColor().getColors() self.ignore(_op) try: _color = None for _c in _image.getImageEntities('color'): if _c.getColors() == args[1]: _color = _c break if undo: _dim.startUndo() try: _dim.setColor(_color) finally: _dim.endUndo() else: _dim.startRedo() try: _dim.setColor(_color) finally: _dim.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'location_changed': if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _x = args[1] if not isinstance(_x, float): raise TypeError, "Unexpected type for 'x': " + `type(_x)` _y = args[2] if not isinstance(_y, float): raise TypeError, "Unexpected type for 'y': " + `type(_y)` _dx, _dy = _dim.getLocation() self.ignore(_op) try: if undo: _dim.startUndo() try: _dim.setLocation(_x, _y) finally: _dim.endUndo() else: _dim.startRedo() try: _dim.setLocation(_x, _y) finally: _dim.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _dx, _dy) elif _op == 'point_changed': if _image is None: raise RuntimeError, "Dimension not stored in an Image" if _alen < 5: raise ValueError, "Invalid argument count: %d" % _alen _olid = args[1] _oid = args[2] _nlid = args[3] _nid = args[4] if undo: _lid = _olid else: _lid = _nlid _parent = None _layers = [_image.getTopLayer()] while len(_layers): _layer = _layers.pop() if _lid == _layer.getID(): _parent = _layer break _layers.extend(_layer.getSublayers()) if _parent is None: raise RuntimeError, "Parent layer of old point not found" self.ignore(_op) try: _vp = None _p1 = _dim.getP1() _p2 = _dim.getP2() if isinstance(_dim, AngularDimension): _vp = _dim.getVertexPoint() if undo: _pt = _parent.getObject(_oid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "Old endpoint missing: id=%d" % _oid _dim.startUndo() try: if _p1.getID() == _nid: _dim.setP1(_pt) elif _p2.getID() == _nid: _dim.setP2(_pt) elif _vp is not None and _vp.getID() == _nid: _dim.setVertexPoint(_pt) else: raise ValueError, "Unexpected point ID: %d" % _nid finally: _dim.endUndo() else: _pt = _parent.getObject(_nid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "New endpoint missing: id=%d" % _nid _dim.startRedo() try: if _p1.getID() == _oid: _dim.setP1(_pt) elif _p2.getID() == _oid: _dim.setP2(_pt) elif _vp is not None and _vp.getID() == _oid: _dim.setVertexPoint(_pt) else: raise ValueError, "Unexpected point ID: %d" % _oid finally: _dim.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _olid, _oid, _nlid, _nid) elif _op == 'dimobj_changed': if _image is None: raise RuntimeError, "Dimension not stored in an Image" if _alen < 5: raise ValueError, "Invalid argument count: %d" % _alen _olid = args[1] _oid = args[2] _nlid = args[3] _nid = args[4] if undo: _lid = _olid else: _lid = _nlid _parent = None _layers = [_image.getTopLayer()] while len(_layers): _layer = _layers.pop() if _lid == _layer.getID(): _parent = _layer break _layers.extend(_layer.getSublayers()) if _parent is None: raise RuntimeError, "Parent layer of old object not found" self.ignore(_op) try: if undo: _oo = _parent.getObject(_oid) if _oo is None or not isinstance(_oo, (circle.Circle, arc.Arc)): raise ValueError, "Old object missing: id=%d" % _oid _dim.startUndo() try: _dim.setDimCircle(_oo) finally: _dim.endUndo() else: _no = _parent.getObject(_nid) if _no is None or not isinstance(_no, (circle.Circle, arc.Arc)): raise ValueError, "New object missing: id=%d" % _nid _dim.startRedo() try: _dim.setDimCircle(_no) finally: _dim.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _olid, _oid, _nlid, _nid) elif _op == 'dimstring_changed': if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _dstr = args[1] _ds1, _ds2 = _dim.getDimstrings() self.ignore('modified') try: if _dstr == 'ds1': if undo: _ds1.undo() else: _ds1.redo() elif _dstr == 'ds2': if undo: _ds2.undo() else: _ds2.redo() else: raise ValueError, "Unexpected dimstring key: " + str(_dstr) finally: self.receive('modified') self.saveData(undo, _op, _dstr) if not undo: _dim.modified() elif _op == 'inverted': # AngularDimensions only self.ignore(_op) try: if undo: _dim.startUndo() try: _dim.invert() finally: _dim.endUndo() else: _dim.startRedo() try: _dim.invert() finally: _dim.endRedo() finally: self.receive(_op) self.saveData(undo, _op) else: super(DimLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/dwg12.py0000644000175000017500000011072611307666657017644 0ustar matteomatteo# # Copyright (c) 2003 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # read autocad r12 file format # import struct import array import sys r13 = False # ugh - global variable def dump_info(handle): global r13 handle.seek(0, 0) _version = handle.read(6) if _version != 'AC1009': if _version == 'AC1010': r13 = True else: print "unknown version" return handle.seek(6, 1) # skip rest of version (_b1, _w1, _w2, _w3, _b2) = struct.unpack(" 0): _xval = struct.unpack('B', handle.read(1))[0] _xlen = _xlen - 1 if _xval == 0: if _xlen < 1: break _val = struct.unpack('B', handle.read(1))[0] _xlen = _xlen - 1 if r13: # ugh if _xlen < 1: break _cp = struct.unpack('B', handle.read(1))[0] # code page? _xlen = _xlen - 1 if _xlen < _val: break _string = handle.read(_val) _data.append(_string) _xlen = _xlen - _val elif (_xval == 1 or _xval == 3 or _xval == 70): if _xlen < 2: break _val = struct.unpack(' 2) and (_kind != 22)): _z = struct.unpack(' _crcpos): print "at > crcpos" else: print "at == crcpos" _crc = struct.unpack(' _one): _plist.append((_xp, _yp)) else: if _dist < _r: _a = pow(_xdiff, 2) + pow(_ydiff, 2) _b = 2.0 * ((_xdiff * (x1 - _xc)) + (_ydiff * (y1 - _yc))) _c = (pow(_xc, 2) + pow(_yc, 2) + pow(x1, 2) + pow(y1, 2) - 2.0 * ((_xc*x1) + (_yc*y1)) - pow(_r,2)) _det = pow(_b, 2) - (4.0 * _a * _c) if _det > 1e-10: _dsq = math.sqrt(_det) _u = (-_b - _dsq)/(2.0 * _a) if skiptest or not (_u < _zero or _u > _one): _x = x1 + (_u * _xdiff) _y = y1 + (_u * _ydiff) _plist.append((_x, _y)) _u = (-_b + _dsq)/(2.0 * _a) if skiptest or not (_u < _zero or _u > _one): _x = x1 + (_u * _xdiff) _y = y1 + (_u * _ydiff) _plist.append((_x, _y)) return _plist # # intersection functions # def _null_intfunc(ipts, obja, objb): print "invoked _null_intfunc()" print "obja: " + `obja` print "objb: " + `objb` def _non_intersecting(ipts, obja, objb): pass # # segment - segment intersection # def _seg_seg_intersection(ipts, seg1, seg2): _p1, _p2 = seg1.getEndpoints() _p3, _p4 = seg2.getEndpoints() _xi = _yi = None if _p1 == _p3: _x, _y = _p4.getCoords() _proj = seg1.getProjection(_x, _y) if _proj is None: _xi, _yi = _p1.getCoords() else: _px, _py = _proj if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p1.getCoords() elif _p1 == _p4: _x, _y = _p3.getCoords() _proj = seg1.getProjection(_x, _y) if _proj is None: _xi, _yi = _p1.getCoords() else: _px, _py = _proj if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p1.getCoords() elif _p2 == _p3: _x, _y = _p4.getCoords() _proj = seg1.getProjection(_x, _y) if _proj is None: _xi, _yi = _p2.getCoords() else: _px, _py = _proj if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p2.getCoords() elif _p2 == _p4: _x, _y = _p3.getCoords() _proj = seg1.getProjection(_x, _y) if _proj is None: _xi, _yi = _p2.getCoords() else: _px, _py = _proj if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p2.getCoords() else: _d = denom(_p1, _p2, _p3, _p4) if abs(_d) > 1e-10: # NOT parallel _r = rnum(_p1, _p2, _p3, _p4)/_d _s = snum(_p1, _p2, _p3 ,_p4)/_d if (not (_r < _zero or _r > _one) and not (_s < _zero or _s > _one)): _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _xi = _p1x + _r * (_p2x - _p1x) _yi = _p1y + _r * (_p2y - _p1y) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # segment - circle intersection # def _seg_circ_intersection(ipts, obja, objb): if isinstance(obja, segment.Segment): _seg = obja _circ = objb else: _seg = objb _circ = obja assert not isinstance(_circ, arc.Arc), "Arc found!" _p1, _p2 = _seg.getEndpoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() for _ip in sc_intersection(_p1x, _p1y, _p2x, _p2y, _circ): ipts.append(_ip) # # segment - arc intersection # def _seg_arc_intersection(ipts, obja, objb): if isinstance(obja, segment.Segment): _seg = obja _arc = objb else: _seg = objb _arc = obja _p1, _p2 = _seg.getEndpoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _ax, _ay = _arc.getCenter().getCoords() for _ip in sc_intersection(_p1x, _p1y, _p2x, _p2y, _arc): _x, _y = _ip _angle = math.atan2((_y - _ay),(_x - _ax)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if _arc.throughAngle(_angle): ipts.append(_ip) # # segment - horizontal construction line intersection # def _seg_hcl_intersection(ipts, obja, objb): if isinstance(obja, segment.Segment): _seg = obja _hcl = objb else: _seg = objb _hcl = obja _p1, _p2 = _seg.getEndpoints() _hp = _hcl.getLocation() _hx, _hy = _hp.getCoords() _xi = _yi = None if _hp == _p1: _p2x, _p2y = _p2.getCoords() if abs(_hy - _p2y) > 1e-10: _xi, _yi = _p1.getCoords() elif _hp == _p2: _p1x, _p1y = _p1.getCoords() if abs(_hy - _p1y) > 1e-10: _xi, _yi = _p2.getCoords() else: _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _miny = min(_p1y, _p2y) _maxy = max(_p1y, _p2y) if abs(_p1y - _p2y) > 1e-10 and _miny < _hy < _maxy: _xi = _p1x + ((_hy - _p1y)*(_p2x - _p1x))/(_p2y - _p1y) _yi = _hy if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # segment - vertical construction line intersection # def _seg_vcl_intersection(ipts, obja, objb): if isinstance(obja, segment.Segment): _seg = obja _vcl = objb else: _seg = objb _vcl = obja _p1, _p2 = _seg.getEndpoints() _vp = _vcl.getLocation() _vx, _vy = _vp.getCoords() _xi = _yi = None if _vp == _p1: _p2x, _p2y = _p2.getCoords() if abs(_vx - _p2x) > 1e-10: _xi, _yi = _p1.getCoords() elif _vp == _p2: _p1x, _p1y = _p1.getCoords() if abs(_vx - _p1x) > 1e-10: _xi, _yi = _p2.getCoords() else: _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _vx, _vy = _vp.getCoords() _minx = min(_p1x, _p2x) _maxx = max(_p1x, _p2x) if abs(_p1x - _p2x) > 1e-10 and _minx < _vx < _maxx: _xi = _vx _yi = _p1y + ((_p2y - _p1y)*(_vx - _p1x))/(_p2x - _p1x) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # segment - angled construction line intersection # def _seg_acl_intersection(ipts, obja, objb): if isinstance(obja, segment.Segment): _seg = obja _acl = objb else: _seg = objb _acl = obja _p1, _p2 = _seg.getEndpoints() _ap = _acl.getLocation() _xi = _yi = None if _p1 == _ap: _x, _y = _p2.getCoords() _px, _py = _acl.getProjection(_x, _y) if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p1.getCoords() elif _p2 == _ap: _x, _y = _p1.getCoords() _px, _py = _acl.getProjection(_x, _y) if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p2.getCoords() else: _ax, _ay = _ap.getCoords() _angle = _acl.getAngle() * _dtr _xt = _ax + math.cos(_angle) _yt = _ay + math.sin(_angle) _tp = point.Point(_xt, _yt) _d = denom(_p1, _p2, _ap, _tp) if abs(_d) > 1e-10: # NOT parallel _r = rnum(_p1, _p2, _ap, _tp)/_d if not (_r < _zero or _r > _one): _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _xi = _p1x + _r * (_p2x - _p1x) _yi = _p1y + _r * (_p2y - _p1y) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # segment - 2-point construction line intersection # def _seg_cl_intersection(ipts, obja, objb): if isinstance(obja, segment.Segment): _seg = obja _cl = objb else: _seg = objb _cl = obja _p1, _p2 = _seg.getEndpoints() _p3, _p4 = _cl.getKeypoints() _xi = _yi = None if _p1 == _p3 or _p1 == _p4: _x, _y = _p2.getCoords() _px, _py = _cl.getProjection(_x, _y) if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p1.getCoords() elif _p2 == _p3 or _p2 == _p4: _x, _y = _p1.getCoords() _px, _py = _cl.getProjection(_x, _y) if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p2.getCoords() else: _d = denom(_p1, _p2, _p3, _p4) if abs(_d) > 1e-10: # NOT parallel _r = rnum(_p1, _p2, _p3, _p4)/_d if not (_r < _zero or _r > _one): _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _xi = _p1x + _r * (_p2x - _p1x) _yi = _p1y + _r * (_p2y - _p1y) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # circle - circle intersection # # see Paul Bourke's web pages for algorithm # def _circ_circ_intersection(ipts, circ1, circ2): _c1x, _c1y = circ1.getCenter().getCoords() _r1 = circ1.getRadius() _c2x, _c2y = circ2.getCenter().getCoords() _r2 = circ2.getRadius() _xdiff = _c2x - _c1x _ydiff = _c2y - _c1y if not (abs(_xdiff) < 1e-10 and abs(_ydiff) < 1e-10): # NOT concentric _sep = math.hypot(_xdiff, _ydiff) _maxsep = _r1 + _r2 + 1e-10 _minsep = abs(_r1 - _r2) - 1e-10 # print "sep: %g; maxsep: %g; minsep: %g" % (_sep, _maxsep, _minsep) if _minsep < _sep < _maxsep: _a = (pow(_r1, 2) - pow(_r2, 2) + pow(_sep, 2))/(2*_sep) _pcx = _c1x + _a * (_xdiff/_sep) _pcy = _c1y + _a * (_ydiff/_sep) # print "a: %g; pcx: %g; pcy: %g" % (_a, _pcx, _pcy) if abs(abs(_a) - _r1) < 1e-10: # single contact point ipts.append((_pcx, _pcy)) else: # two contact points _h = math.sqrt(pow(_r1, 2) - pow(_a, 2)) _x = _pcx + _h * (_ydiff/_sep) _y = _pcy - _h * (_xdiff/_sep) ipts.append((_x, _y)) _x = _pcx - _h * (_ydiff/_sep) _y = _pcy + _h * (_xdiff/_sep) ipts.append((_x, _y)) # # circle - arc intersection # def _circ_arc_intersection(ipts, obja, objb): if isinstance(obja, arc.Arc): _arc = obja _circ = objb else: _circ = obja _arc = objb _cp = _arc.getCenter() _r = _arc.getRadius() _tempcirc = circle.Circle(_cp, _r) _ipts = [] _circ_circ_intersection(_ipts, _circ, _tempcirc) if len(_ipts): # may have intersection points ... _cx, _cy = _cp.getCoords() for _ip in _ipts: _x, _y = _ip _angle = math.atan2((_y - _cy),(_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if _arc.throughAngle(_angle): ipts.append(_ip) _tempcirc.finish() # # circle - horizontal contruction line intersection # def _circ_hcl_intersection(ipts, obja, objb): if isinstance(obja, (circle.Circle, ccircle.CCircle)): _circ = obja _hcl = objb else: _circ = objb _hcl = obja _cp = _circ.getCenter() _r = _circ.getRadius() _hp = _hcl.getLocation() _hx, _hy = _hp.getCoords() if _hp == _cp: ipts.append(((_hx - _r), _hy)) ipts.append(((_hx + _r), _hy)) else: _cx, _cy = _circ.getCenter().getCoords() _ymin = _cy - _r _ymax = _cy + _r if abs(_ymin - _hy) < 1e-10: ipts.append((_cx, _ymin)) elif abs(_ymax - _hy) < 1e-10: ipts.append((_cx, _ymax)) elif _ymin < _hy < _ymax: _offset = math.sqrt(pow(_r, 2) - pow((_cy - _hy), 2)) ipts.append(((_cx - _offset), _hy)) ipts.append(((_cx + _offset), _hy)) else: pass # # circle - vertical contruction line intersection # def _circ_vcl_intersection(ipts, obja, objb): if isinstance(obja, (circle.Circle, ccircle.CCircle)): _circ = obja _vcl = objb else: _circ = objb _vcl = obja _cp = _circ.getCenter() _r = _circ.getRadius() _vp = _vcl.getLocation() _vx, _vy = _vp.getCoords() if _vp == _cp: ipts.append((_vx, (_vy - _r))) ipts.append((_vx, (_vy + _r))) else: _cx, _cy = _circ.getCenter().getCoords() _xmin = _cx - _r _xmax = _cx + _r if abs(_xmin - _vx) < 1e-10: ipts.append((_xmin, _cy)) elif abs(_xmax - _vx) < 1e-10: ipts.append((_xmax, _cy)) elif _xmin < _vx < _xmax: _offset = math.sqrt(pow(_r, 2) - pow((_vx - _cx), 2)) ipts.append((_vx, (_cy - _offset))) ipts.append((_vx, (_cy + _offset))) else: pass # # circle - angled construction line intersection # def _circ_acl_intersection(ipts, obja, objb): if isinstance(obja, (circle.Circle, ccircle.CCircle)): _circ = obja _acl = objb else: _circ = objb _acl = obja assert not isinstance(_circ, arc.Arc), "Arc found!" _p1x, _p1y = _acl.getLocation().getCoords() _angle = _acl.getAngle() * _dtr _xt = _p1x + math.cos(_angle) _yt = _p1y + math.sin(_angle) for _ip in sc_intersection(_p1x, _p1y, _xt, _yt, _circ, True): ipts.append(_ip) # # circle - 2-point construction line intersection # def _circ_cl_intersection(ipts, obja, objb): if isinstance(obja, (circle.Circle, ccircle.CCircle)): _circ = obja _cl = objb else: _circ = objb _cl = obja assert not isinstance(_circ, arc.Arc), "Arc found!" _p1, _p2 = _cl.getKeypoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() for _ip in sc_intersection(_p1x, _p1y, _p2x, _p2y, _circ, True): ipts.append(_ip) # # arc - arc intersection # def _arc_arc_intersection(ipts, arc1, arc2): _cp1 = arc1.getCenter() _r1 = arc1.getRadius() _tempcirc1 = circle.Circle(_cp1, _r1) _cp2 = arc2.getCenter() _r2 = arc2.getRadius() _tempcirc2 = circle.Circle(_cp2, _r2) _ipts = [] _circ_circ_intersection(_ipts, _tempcirc1, _tempcirc2) if len(_ipts): # may have intersection points ... for _ip in _ipts: _cx, _cy = _cp1.getCoords() _x, _y = _ip _angle = math.atan2((_y - _cy), (_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if arc1.throughAngle(_angle): _cx, _cy = _cp2.getCoords() _angle = math.atan2((_y - _cy), (_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if arc2.throughAngle(_angle): ipts.append(_ip) _tempcirc1.finish() _tempcirc2.finish() # # arc - horizontal construction line intersection # def _arc_hcl_intersection(ipts, obja, objb): if isinstance(obja, arc.Arc): _arc = obja _hcl = objb else: _arc = objb _hcl = obja _cp = _arc.getCenter() _r = _arc.getRadius() _tempcirc = circle.Circle(_cp, _r) _ipts = [] _circ_hcl_intersection(_ipts, _tempcirc, _hcl) if len(_ipts): # may have intersection points ... _cx, _cy = _cp.getCoords() for _ip in _ipts: _x, _y = _ip _angle = math.atan2((_y - _cy),(_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if _arc.throughAngle(_angle): ipts.append(_ip) _tempcirc.finish() # # arc - vertical construction line intersection # def _arc_vcl_intersection(ipts, obja, objb): if isinstance(obja, arc.Arc): _arc = obja _vcl = objb else: _arc = objb _vcl = obja _cp = _arc.getCenter() _r = _arc.getRadius() _tempcirc = circle.Circle(_cp, _r) _ipts = [] _circ_vcl_intersection(_ipts, _tempcirc, _vcl) if len(_ipts): # may have intersection points ... _cx, _cy = _cp.getCoords() for _ip in _ipts: _x, _y = _ip _angle = math.atan2((_y - _cy),(_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if _arc.throughAngle(_angle): ipts.append(_ip) _tempcirc.finish() # # arc - angled construction line intersection # def _arc_acl_intersection(ipts, obja, objb): if isinstance(obja, arc.Arc): _arc = obja _acl = objb else: _arc = objb _acl = obja _cp = _arc.getCenter() _r = _arc.getRadius() _tempcirc = circle.Circle(_cp, _r) _ipts = [] _circ_acl_intersection(_ipts, _tempcirc, _acl) if len(_ipts): # may have intersection points ... _cx, _cy = _cp.getCoords() for _ip in _ipts: _x, _y = _ip _angle = math.atan2((_y - _cy),(_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if _arc.throughAngle(_angle): ipts.append(_ip) _tempcirc.finish() # # arc - 2-point construction line intersection # def _arc_cl_intersection(ipts, obja, objb): if isinstance(obja, arc.Arc): _arc = obja _cl = objb else: _arc = objb _cl = obja _cp = _arc.getCenter() _r = _arc.getRadius() _tempcirc = circle.Circle(_cp, _r) _ipts = [] _circ_cl_intersection(_ipts, _tempcirc, _cl) if len(_ipts): # may have intersection points ... _cx, _cy = _cp.getCoords() for _ip in _ipts: _x, _y = _ip _angle = math.atan2((_y - _cy),(_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if _arc.throughAngle(_angle): ipts.append(_ip) _tempcirc.finish() # # horizontal construction line - vertical construction line intersection # def _hcl_vcl_intersection(ipts, obja, objb): if isinstance(obja, hcline.HCLine): _hcl = obja _vcl = objb else: _hcl = objb _vcl = obja _hx, _hy = _hcl.getLocation().getCoords() _vx, _vh = _vcl.getLocation().getCoords() ipts.append((_vx, _hy)) # # horizontal construction line - angled construction line intersection # def _hcl_acl_intersection(ipts, obja, objb): if isinstance(obja, hcline.HCLine): _hcl = obja _acl = objb else: _hcl = objb _acl = obja _angle = _acl.getAngle() if abs(_angle) > 1e-10: # acl is NOT horizontal _xi = _yi = None _hp = _hcl.getLocation() _ap = _acl.getLocation() if _hp == _ap: _xi, _yi = _hp.getCoords() else: _hx, _hy = _hp.getCoords() _yi = _hy _ax, _ay = _ap.getCoords() if abs(abs(_angle) - 90.0) < 1e-10: # acl is vertical _xi = _ax else: _slope = math.tan(_angle * _dtr) _yint = _ay - _slope*_ax _xi = (_hy - _yint)/_slope ipts.append((_xi, _yi)) # # horizontal construction line - 2-point construction line intersection # def _hcl_cl_intersection(ipts, obja, objb): if isinstance(obja, hcline.HCLine): _hcl = obja _cl = objb else: _hcl = objb _cl = obja _p1, _p2 = _cl.getKeypoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _ydiff = _p2y - _p1y if abs(_ydiff) > 1e-10: # cline is NOT horizontal _xi = _yi = None _hp = _hcl.getLocation() if _hp == _p1: _xi, _yi = _p1.getCoords() elif _hp == _p2: _xi, _yi = _p2.getCoords() else: _hx, _hy = _hp.getCoords() _yi = _hy _xdiff = _p2x - _p1x if abs(_xdiff) < 1e-10: # cline is vertical _xi = _p1x else: _slope = _ydiff/_xdiff _yint = _p1y - _slope*_p1x _xi = (_hy - _yint)/_slope ipts.append((_xi, _yi)) # # vertical construction line - angled construction line intersection # def _vcl_acl_intersection(ipts, obja, objb): if isinstance(obja, vcline.VCLine): _vcl = obja _acl = objb else: _vcl = objb _acl = obja _angle = _acl.getAngle() if abs(abs(_angle) - 90.0) > 1e-10: # acl is NOT vertical _vp = _vcl.getLocation() _ap = _acl.getLocation() if _vp == _ap: _xi, _yi = _vp.getCoords() else: _vx, _vy = _vp.getCoords() _xi = _vx _ax, _ay = _ap.getCoords() _slope = math.tan(_angle * _dtr) _yint = _ay - _slope*_ax _yi = _slope*_vx + _yint ipts.append((_xi, _yi)) # # vertical construction line - 2-point construction line intersection # def _vcl_cl_intersection(ipts, obja, objb): if isinstance(obja, vcline.VCLine): _vcl = obja _cl = objb else: _vcl = objb _cl = obja _p1, _p2 = _cl.getKeypoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _xdiff = _p2x - _p1x if abs(_xdiff) > 1e-10: # cline is NOT vertical _xi = _yi = None _vp = _vcl.getLocation() if _vp == _p1: _xi, _yi = _p1.getCoords() elif _vp == _p2: _xi, _yi = _p2.getCoords() else: _vx, _vy = _vp.getCoords() _xi = _vx _ydiff = _p2y - _p1y if abs(_ydiff) < 1e-10: # cline is horizontal _yi = _p1y else: _slope = _ydiff/_xdiff _yint = _p1y - _slope*_p1x _yi = _slope*_vx + _yint ipts.append((_xi, _yi)) # # angled construction line - angled construction line intersection # def _acl_acl_intersection(ipts, acl1, acl2): _ap1 = acl1.getLocation() _ap1x, _ap1y = _ap1.getCoords() _angle1 = acl1.getAngle() * _dtr _xt1 = _ap1x + math.cos(_angle1) _yt1 = _ap1y + math.sin(_angle1) _t1 = point.Point(_xt1, _yt1) _ap2 = acl2.getLocation() _ap2x, _ap2y = _ap2.getCoords() _angle2 = acl2.getAngle() * _dtr _xt2 = _ap2x + math.cos(_angle2) _yt2 = _ap2y + math.sin(_angle2) _t2 = point.Point(_xt2, _yt2) _d = denom(_ap1, _t1, _ap2, _t2) if abs(_d) > 1e-10: # NOT parallel _xi = _yi = None if _ap1 == _ap2: _xi, _yi = _ap1.getCoords() else: _rn = rnum(_ap1, _t1, _ap2, _t2) if abs(_rn) > 1e-10: # NOT colinear _r = _rn/_d _xi = _ap1x + _r * (_xt1 - _ap1x) _yi = _ap1y + _r * (_yt1 - _ap1y) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # angled construction line - 2-point construction line intersection # def _acl_cl_intersection(ipts, obja, objb): if isinstance(obja, acline.ACLine): _acl = obja _cl = objb else: _acl = objb _cl = obja _ap = _acl.getLocation() _apx, _apy = _ap.getCoords() _angle = _acl.getAngle() * _dtr _xt = _apx + math.cos(_angle) _yt = _apy + math.sin(_angle) _t1 = point.Point(_xt, _yt) _p1, _p2 = _cl.getKeypoints() _d = denom(_ap, _t1, _p1, _p2) if abs(_d) > 1e-10: # NOT parallel _xi = _yi = None if _ap == _p1: _xi, _yi = _p1.getCoords() elif _ap == _p2: _xi, _yi = _p2.getCoords() else: _rn = rnum(_ap, _t1, _p1, _p2) if abs(_rn) > 1e-10: # NOT colinear _r = _rn/_d _xi = _apx + _r * (_xt - _apx) _yi = _apy + _r * (_yt - _apy) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # 2-point construction line - 2-point construction line intersection # def _cl_cl_intersection(ipts, cl1, cl2): _p1, _p2 = cl1.getKeypoints() _p3, _p4 = cl2.getKeypoints() _d = denom(_p1, _p2, _p3, _p4) if abs(_d) > 1e-10: # NOT parallel _xi = _yi = None if _p1 == _p3 or _p2 == _p3: _xi, _yi = _p3.getCoords() elif _p1 == _p4 or _p2 == _p4: _xi, _yi = _p4.getCoords() else: _rn = rnum(_p1, _p2, _p3, _p4) if abs(_rn) > 1e-10: # NOT colinear _r = _rn/_d _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _xi = _p1x + _r * (_p2x - _p1x) _yi = _p1y + _r * (_p2y - _p1y) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # set segment intersecting function # def _segment_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_seg_intersection elif isinstance(objb, arc.Arc): _func = _seg_arc_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _seg_circ_intersection elif isinstance(objb, hcline.HCLine): _func = _seg_hcl_intersection elif isinstance(objb, vcline.VCLine): _func = _seg_vcl_intersection elif isinstance(objb, acline.ACLine): _func = _seg_acl_intersection elif isinstance(objb, cline.CLine): _func = _seg_cl_intersection else: _func = _null_intfunc return _func # # set circle intersecting function # def _circ_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_circ_intersection elif isinstance(objb, arc.Arc): _func = _circ_arc_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _circ_circ_intersection elif isinstance(objb, hcline.HCLine): _func = _circ_hcl_intersection elif isinstance(objb, vcline.VCLine): _func = _circ_vcl_intersection elif isinstance(objb, acline.ACLine): _func = _circ_acl_intersection elif isinstance(objb, cline.CLine): _func = _circ_cl_intersection else: _func = _null_intfunc return _func # # set arc intersecting function # def _arc_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_arc_intersection elif isinstance(objb, arc.Arc): _func = _arc_arc_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _circ_arc_intersection elif isinstance(objb, hcline.HCLine): _func = _arc_hcl_intersection elif isinstance(objb, vcline.VCLine): _func = _arc_vcl_intersection elif isinstance(objb, acline.ACLine): _func = _arc_acl_intersection elif isinstance(objb, cline.CLine): _func = _arc_cl_intersection else: _func = _null_intfunc return _func # # set hcline intersecting function # def _hcline_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_hcl_intersection elif isinstance(objb, arc.Arc): _func = _arc_hcl_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _circ_hcl_intersection elif isinstance(objb, hcline.HCLine): _func = _non_intersecting elif isinstance(objb, vcline.VCLine): _func =_hcl_vcl_intersection elif isinstance(objb, acline.ACLine): _func = _hcl_acl_intersection elif isinstance(objb, cline.CLine): _func = _hcl_cl_intersection else: _func = _null_intfunc return _func # # set vcline intersecting function # def _vcline_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_vcl_intersection elif isinstance(objb, arc.Arc): _func = _arc_vcl_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _circ_vcl_intersection elif isinstance(objb, hcline.HCLine): _func = _hcl_vcl_intersection elif isinstance(objb, vcline.VCLine): _func = _non_intersecting elif isinstance(objb, acline.ACLine): _func = _vcl_acl_intersection elif isinstance(objb, cline.CLine): _func = _vcl_cl_intersection return _func # # set acline intersecting function # def _acline_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_acl_intersection elif isinstance(objb, arc.Arc): _func = _arc_acl_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _circ_acl_intersection elif isinstance(objb, hcline.HCLine): _func = _hcl_acl_intersection elif isinstance(objb, vcline.VCLine): _func = _vcl_acl_intersection elif isinstance(objb, acline.ACLine): _func = _acl_acl_intersection elif isinstance(objb, cline.CLine): _func = _acl_cl_intersection else: _func = _null_intfunc return _func # # set cline intersecting function # def _cline_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_cl_intersection elif isinstance(objb, arc.Arc): _func = _arc_cl_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _circ_cl_intersection elif isinstance(objb, hcline.HCLine): _func = _hcl_cl_intersection elif isinstance(objb, vcline.VCLine): _func = _vcl_cl_intersection elif isinstance(objb, acline.ACLine): _func = _acl_cl_intersection elif isinstance(objb, cline.CLine): _func = _cl_cl_intersection else: _func = _null_intfunc return _func # # intersection functions for polylines # def _get_intfunc(obja, objb): if isinstance(obja, segment.Segment): _intfunc = _segment_intfuncs(objb) elif isinstance(obja, arc.Arc): _intfunc = _arc_intfuncs(objb) elif isinstance(obja, (circle.Circle, ccircle.CCircle)): _intfunc = _circ_intfuncs(objb) elif isinstance(obja, hcline.HCLine): _intfunc = _hcline_intfuncs(objb) elif isinstance(obja, vcline.VCLine): _intfunc = _vcline_intfuncs(objb) elif isinstance(obja, acline.ACLine): _intfunc = _acline_intfuncs(objb) elif isinstance(obja, cline.CLine): _intfunc = _cline_intfuncs(objb) else: _intfunc = _null_intfunc return _intfunc def find_intersections(obja, objb): _ipts = [] _intfunc = _get_intfunc(obja, objb) _intfunc(_ipts, obja, objb) return _ipts PythonCAD-DS1-R37/PythonCAD/Generic/hcline.py0000644000175000017500000003771011307666732020155 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # horizontal construction lines # from __future__ import generators from PythonCAD.Generic import conobject from PythonCAD.Generic import tolerance from PythonCAD.Generic import point from PythonCAD.Generic import quadtree from PythonCAD.Generic import util class HCLine(conobject.ConstructionObject): """A base class for horizontal construction lines. """ __messages = { 'moved' : True, 'keypoint_changed' : True } def __init__(self, p, **kw): """Instantiate an HCLine object. HCLine(p) """ _p = p if not isinstance(p, point.Point): _p = point.Point(p) super(HCLine, self).__init__(**kw) self.__keypoint = _p _p.storeUser(self) _p.connect('moved', self.__movePoint) _p.connect('change_pending', self.__pointChangePending) _p.connect('change_complete', self.__pointChangeComplete) def __eq__(self, obj): """Compare one HCLine to another for equality. """ if not isinstance(obj, HCLine): return False if obj is self: return True if abs(self.getLocation().y - obj.getLocation().y) < 1e-10: return True return False def __ne__(self, obj): """Compare one HCLine to another for inequality. """ if not isinstance(obj, HCLine): return True if obj is self: return False if abs(self.getLocation().y - obj.getLocation().y) < 1e-10: return False return True def __str__(self): _x, _y = self.getLocation().getCoords() return "Horizontal Construction Line at y = %g" % self.__keypoint.y def finish(self): self.__keypoint.disconnect(self) self.__keypoint.freeUser(self) self.__keypoint = None super(HCLine, self).finish() def getValues(self): _data = super(HCLine, self).getValues() _data.setValue('type', 'hcline') _data.setValue('keypoint', self.__keypoint.getID()) return _data def getLocation(self): return self.__keypoint def setLocation(self, p): if self.isLocked(): raise RuntimeError, "Setting keypoint not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid keypoint: " + `type(p)` _kp = self.__keypoint if p is not _kp: _y = _kp.y _kp.disconnect(self) _kp.freeUser(self) self.startChange('keypoint_changed') self.__keypoint = p self.endChange('keypoint_changed') self.sendMessage('keypoint_changed', _kp) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) p.storeUser(self) if abs(_y - p.y) > 1e-10: self.sendMessage('moved', p.x, _y) self.sendMessage('modified') def mapCoords(self, x, y, tol=tolerance.TOL): """Return the nearest Point on the HCLine to a coordinate pair. mapCoords(x, y[, tol]) The function has two required argument: x: A Float value giving the 'x' coordinate y: A Float value giving the 'y' coordinate There is a single optional argument: tol: A float value equal or greater than 0.0 This function is used to map a possibly near-by coordinate pair to an actual Point on the HCLine. If the distance between the actual Point and the coordinates used as an argument is less than the tolerance, the actual Point is returned. Otherwise, this function returns None. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _hy = self.__keypoint.y if abs(_hy - _y) < _t: return _x, _hy return None def inRegion(self, xmin, ymin, xmax, ymax, fully=False): """Return whether or not an HCLine passes through a region. inRegion(xmin, ymin, xmax, ymax) The first four arguments define the boundary. The method will return True if the HCLine falls between ymin and ymax. Otherwise the function will return False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) if fully: return False _y = self.__keypoint.y return not (_y < _ymin or _y > _ymax) def move(self, dx, dy): """Move a HCLine move(dx, dy) The first argument gives the x-coordinate displacement, and the second gives the y-coordinate displacement. Both values should be floats. """ if self.isLocked() or self.__keypoint.isLocked(): raise RuntimeError, "Moving HCLine not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _x, _y = self.__keypoint.getCoords() self.ignore('moved') try: self.__keypoint.move(_dx, _dy) finally: self.receive('moved') self.sendMessage('moved', _x, _y) def __pointChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.startChange('moved') def __pointChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.endChange('moved') def __movePoint(self, p, *args): _plen = len(args) if _plen < 2: raise ValueError, "Invalid argument count: %d" % _plen _x = util.get_float(args[0]) _y = util.get_float(args[1]) if p is not self.__keypoint: raise ValueError, "Invalid point for HCLine::movePoint()" + `p` if abs(p.y - _y) > 1e-10: self.sendMessage('moved', _x, _y) def clipToRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _y = self.__keypoint.y if _ymin < _y < _ymax: return _xmin, _y, _xmax, _y return None def clone(self): """Create an identical copy of an HCLine. clone() """ return HCLine(self.__keypoint.clone()) def sendsMessage(self, m): if m in HCLine.__messages: return True return super(HCLine, self).sendsMessage(m) def getProjection(self,x,y): """ Get the projection of the point in to the line """ HCLinePoint=self.getLocation() x1,y1=HCLinePoint.getCoords() x1=x return x1,y1 # # # def intersect_region(hcl, xmin, ymin, xmax, ymax): if not isinstance(hcl, HCLine): raise TypeError, "Invalid HCLine: " + `type(hcl)` _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _x, _y = hcl.getLocation().getCoords() _x1 = _y1 = _x2 = _y2 = None if _ymin < _y < _ymax: _x1 = _xmin _y1 = _y _x2 = _xmax _y2 = _y return _x1, _y1, _x2, _y2 # # Quadtree HCLine storage # class HCLineQuadtree(quadtree.Quadtree): def __init__(self): super(HCLineQuadtree, self).__init__() def getNodes(self, *args): _alen = len(args) if _alen != 1: raise ValueError, "Expected 1 arguments, got %d" % _alen _y = util.get_float(args[0]) _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _bounds = _node.getBoundary() _ymin = _bounds[1] _ymax = _bounds[3] if _y < _ymin or _y > _ymax: continue if _node.hasSubnodes(): _ymid = (_ymin + _ymax)/2.0 _ne = _nw = _sw = _se = True if _y < _ymid: # hcline below _nw = _ne = False if _y > _ymid: # hcline above _sw = _se = False if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: yield _node def addObject(self, obj): if not isinstance(obj, HCLine): raise TypeError, "Invalid HCLine object: " + `type(obj)` if obj in self: return _x, _y = obj.getLocation().getCoords() _bounds = self.getTreeRoot().getBoundary() _xmin = _ymin = _xmax = _ymax = None _resize = False if _bounds is None: # first node in tree _resize = True _xmin = _x - 1.0 _ymin = _y - 1.0 _xmax = _x + 1.0 _ymax = _y + 1.0 else: _xmin, _ymin, _xmax, _ymax = _bounds if _x < _xmin: _xmin = _x - 1.0 _resize = True if _x > _xmax: _xmax = _x + 1.0 _resize = True if _y < _ymin: _ymin = _y - 1.0 _resize = True if _y > _ymax: _ymax = _y + 1.0 _resize = True if _resize: self.resize(_xmin, _ymin, _xmax, _ymax) for _node in self.getNodes(_y): _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if obj.inRegion(_xmin, _ymin, _xmax, _ymax): _node.addObject(obj) super(HCLineQuadtree, self).addObject(obj) obj.connect('moved', self._moveHCLine) def delObject(self, obj): if obj not in self: return _pdict = {} _x, _y = obj.getLocation().getCoords() for _node in self.getNodes(_y): _node.delObject(obj) _parent = _node.getParent() if _parent is not None: _pid = id(_parent) if _pid not in _pdict: _pdict[_pid] = _parent super(HCLineQuadtree, self).delObject(obj) obj.disconnect(self) for _parent in _pdict.values(): self.purgeSubnodes(_parent) def find(self, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _y = util.get_float(args[0]) _t = tolerance.TOL if _alen > 1: _t = tolerance.toltest(args[1]) _hclines = [] _ymin = _y - _t _ymax = _y + _t return self.getInRegion(0, _ymin, 1, _ymax) # x values arbitrary def _moveHCLine(self, obj, *args): if obj not in self: raise ValueError, "HCLine not stored in Quadtree: " + `obj` _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) for _node in self.getNodes(_y): _node.delObject(obj) # hcline may not be in node super(HCLineQuadtree, self).delObject(obj) obj.disconnect(self) self.addObject(obj) def getClosest(self, x, y, tol=tolerance.TOL): return self.find(y, tol) def getInRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _hcls = [] if not len(self): return _hcls _nodes = [self.getTreeRoot()] _hdict = {} while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): for _subnode in _node.getSubnodes(): _bounds = _subnode.getBoundary() _bmin = _bounds[1] _bmax = _bounds[3] if ((_bmin > _ymax) or (_bmax < _ymin)): continue _nodes.append(_subnode) else: for _hcl in _node.getObjects(): _hid = id(_hcl) if _hid not in _hdict: if _hcl.inRegion(_xmin, _ymin, _xmax, _ymax): _hcls.append(_hcl) _hdict[_hid] = True return _hcls # # HCLine history class # class HCLineLog(conobject.ConstructionObjectLog): def __init__(self, h): if not isinstance(h, HCLine): raise TypeError, "Invalid HCLine: " + `type(h)` super(HCLineLog, self).__init__(h) h.connect('keypoint_changed', self._keypointChange) def _keypointChange(self, h, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _old = args[0] if not isinstance(_old, point.Point): raise TypeError, "Invalid old endpoint: " + `type(_old)` self.saveUndoData('keypoint_changed', _old.getID()) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if _alen == 0: raise ValueError, "No arguments to execute()" _h = self.getObject() _p = _h.getLocation() _op = args[0] if _op == 'keypoint_changed': if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _oid = args[1] _parent = _h.getParent() if _parent is None: raise ValueError, "HCLine has no parent - cannot undo" _pt = _parent.getObject(_oid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "Keypoint missing: id=%d" % _oid _sdata = _p.getID() self.ignore(_op) try: if undo: _h.startUndo() try: _h.setLocation(_pt) finally: _h.endUndo() else: _h.startRedo() try: _h.setLocation(_pt) finally: _h.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) else: super(HCLineLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/__init__.py0000644000175000017500000000324311307666657020452 0ustar matteomatteo# # Copyright (c) 2002, Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # define __all__ so 'from Generic import *' works # __all__ = [ 'acline', 'arc', 'baseobject', 'ccircle' 'circle', 'cline', 'color', 'conobject', 'delete', 'dimension', 'dimtrees', 'dim12', 'dim1314', 'dim15', 'dwgbase', 'dwgutil', 'dxf', 'ellipse', 'entity', 'fileio', 'globals', 'graphicobject', 'hatch', 'hcline', 'image', 'imageio', 'intersections' 'keywords' 'layer', 'leader', 'linetype', 'logger', 'maptree', 'message', 'mirror', 'move', 'nurbs', 'options', 'plotfile', 'point', 'polyline', 'preferences', 'printing', 'prompt', 'quadtree', 'segjoint', 'segment', 'selections', 'split', 'style', 'tangent', 'text', 'tolerance', 'tools', 'transfer', 'tree', 'units' 'util', 'vcline' ] PythonCAD-DS1-R37/PythonCAD/Generic/circle.py0000644000175000017500000021741311307666732020154 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # class stuff for circles # from __future__ import generators import math from PythonCAD.Generic import tolerance from PythonCAD.Generic import point from PythonCAD.Generic import graphicobject from PythonCAD.Generic import style from PythonCAD.Generic import linetype from PythonCAD.Generic import color from PythonCAD.Generic import quadtree from PythonCAD.Generic import util from PythonCAD.Generic import tangent from PythonCAD.Generic.pyGeoLib import Vector class Circle(graphicobject.GraphicObject): """A base-class for Circles and Arcs A Circle has two attributes: center: A Point object radius: The Circle's radius A Circle has the following methods: {get/set}Center(): Get/Set the center Point of a Circle. {get/set}Radius(): Get/Set the radius of a Circle. move(): Move the Circle. circumference(): Get the Circle's circumference. area(): Get the Circle's area. mapCoords(): Find the nearest Point on the Circle to a coordinate pair. inRegion(): Returns whether or not a Circle can be seen in a bounded area. clone(): Return an indentical copy of a Circle. """ __defstyle = None __messages = { 'moved' : True, 'center_changed' : True, 'radius_changed' : True, } def __init__(self, center, radius, st=None, lt=None, col=None, th=None, **kw): """Initialize a Circle. Circle(center, radius[, st, lt, col, th]) The center should be a Point, or a two-entry tuple of floats, and the radius should be a float greater than 0. """ _cp = center if not isinstance(_cp, point.Point): _cp = point.Point(center) _r = util.get_float(radius) if not _r > 0.0: raise ValueError, "Invalid radius: %g" % _r _st = st if _st is None: _st = self.getDefaultStyle() super(Circle, self).__init__(_st, lt, col, th, **kw) self.__radius = _r self.__center = _cp _cp.connect('moved', self.__movePoint) _cp.connect('change_pending', self.__pointChangePending) _cp.connect('change_complete', self.__pointChangeComplete) _cp.storeUser(self) def __eq__(self, obj): """Compare a Circle to another for equality. """ if not isinstance(obj, Circle): return False if obj is self: return True return (self.__center == obj.getCenter() and abs(self.__radius - obj.getRadius()) < 1e-10) def __ne__(self, obj): """Compare a Circle to another for inequality. """ if not isinstance(obj, Circle): return True if obj is self: return False return (self.__center != obj.getCenter() or abs(self.__radius - obj.getRadius()) > 1e-10) def getDefaultStyle(cls): if cls.__defstyle is None: _s = style.Style(u'Default Circle Style', linetype.Linetype(u'Solid', None), color.Color(0xffffff), 1.0) cls.__defstyle = _s return cls.__defstyle getDefaultStyle = classmethod(getDefaultStyle) def setDefaultStyle(cls, s): if not isinstance(s, style.Style): raise TypeError, "Invalid style: " + `type(s)` cls.__defstyle = s setDefaultStyle = classmethod(setDefaultStyle) def finish(self): self.__center.disconnect(self) self.__center.freeUser(self) self.__center = self.__radius = None super(Circle, self).finish() def setStyle(self, s): """Set the Style of the Circle. setStyle(s) This method extends GraphicObject::setStyle(). """ _s = s if _s is None: _s = self.getDefaultStyle() super(Circle, self).setStyle(_s) def getValues(self): """Return values comprising the Circle. getValues() This method extends the GraphicObject::getValues() method. """ _data = super(Circle, self).getValues() _data.setValue('type', 'circle') _data.setValue('center', self.__center.getID()) _data.setValue('radius', self.__radius) return _data def getCenter(self): """Return the center Point of the Circle. getCenter() """ return self.__center def setCenter(self, c): """Set the center Point of the Circle. setCenter(c) The argument must be a Point or a tuple containing two float values. """ if self.isLocked(): raise RuntimeError, "Setting center not allowed - object locked." _cp = self.__center if not isinstance(c, point.Point): raise TypeError, "Invalid center point: " + `type(c)` if _cp is not c: _cp.disconnect(self) _cp.freeUser(self) self.startChange('center_changed') self.__center = c self.endChange('center_changed') self.sendMessage('center_changed', _cp) c.connect('moved', self.__movePoint) c.connect('change_pending', self.__pointChangePending) c.connect('change_complete', self.__pointChangeComplete) c.storeUser(self) if abs(_cp.x - c.x) > 1e-10 or abs(_cp.y - c.y) > 1e-10: self.sendMessage('moved', _cp.x, _cp.y, self.__radius) self.modified() center = property(getCenter, setCenter, None, "Circle center") def getRadius(self): """Return the radius of the the Circle. getRadius() """ return self.__radius def setRadius(self, radius): """Set the radius of the Circle. setRadius(radius) The argument must be float value greater than 0. """ if self.isLocked(): raise RuntimeError, "Setting radius not allowed - object locked." _r = util.get_float(radius) if not _r > 0.0: raise ValueError, "Invalid radius: %g" % _r _cr = self.__radius if abs(_cr - _r) > 1e-10: self.startChange('radius_changed') self.__radius = _r self.endChange('radius_changed') self.sendMessage('radius_changed', _cr) _cx, _cy = self.__center.getCoords() self.sendMessage('moved', _cx, _cy, _cr) self.modified() radius = property(getRadius, setRadius, None, "Circle radius") def move(self, dx, dy): """Move a Circle. move(dx, dy) The first argument gives the x-coordinate displacement, and the second gives the y-coordinate displacement. Both values should be floats. """ if self.isLocked(): raise RuntimeError, "Setting radius not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _x, _y = self.__center.getCoords() self.ignore('moved') try: self.__center.move(_dx, _dy) finally: self.receive('moved') self.sendMessage('moved', _x, _y, self.__radius) def circumference(self): """Return the circumference of the Circle. circumference() """ return 2.0 * math.pi * self.__radius def area(self): """Return the area enclosed by the Circle. area() """ return math.pi * pow(self.__radius, 2) def GetTangentPoint(self,x,y,outx,outy): """ Get the tangent from an axternal point args: x,y is a point near the circle xout,yout is a point far from the circle return: a tuple(x,y,x1,xy) that define the tangent line """ firstPoint=point.Point(x,y) fromPoint=point.Point(outx,outy) twoPointDistance=self.__center.Dist(fromPoint) if(twoPointDistancecy): #stupid situation rightAngle=-rightAngle posAngle=rightAngle+tgAngle negAngle=rightAngle-tgAngle #Compute the Positive Tangent xCord=math.cos(posAngle) yCord=math.sin(posAngle) dirPoint=point.Point(xCord,yCord)#Versor that point at the tangentPoint ver=Vector(originPoint,dirPoint) ver.Mult(tanMod) tangVectorPoint=ver.Point() posPoint=point.Point(tangVectorPoint+(outx,outy)) #Compute the Negative Tangent xCord=math.cos(negAngle) yCord=math.sin(negAngle) dirPoint=point.Point(xCord,yCord)#Versor that point at the tangentPoint ver=Vector(originPoint,dirPoint) ver.Mult(tanMod) tangVectorPoint=ver.Point() negPoint=point.Point(tangVectorPoint+(outx,outy)) if(firstPoint.Dist(posPoint) _xmax) or ((_yc - _r) > _ymax) or ((_xc + _r) < _xmin) or ((_yc + _r) < _ymin)): return False _val = False _bits = 0 # # calculate distances from center to region boundary # if abs(_xc - _xmin) < _r: _bits = _bits | 1 # left edge if abs(_xc - _xmax) < _r: _bits = _bits | 2 # right edge if abs(_yc - _ymin) < _r: _bits = _bits | 4 # bottom edge if abs(_yc - _ymax) < _r: _bits = _bits | 8 # top edge if _bits == 0: # # circle must be visible - the center is in # the region and is more than the radius from # each edge # _val = True else: # # calculate distance to corners of region # if math.hypot((_xc - _xmin), (_yc - _ymax)) < _r: _bits = _bits | 0x10 # upper left if math.hypot((_xc - _xmax), (_yc - _ymin)) < _r: _bits = _bits | 0x20 # lower right if math.hypot((_xc - _xmin), (_yc - _ymin)) < _r: _bits = _bits | 0x40 # lower left if math.hypot((_xc - _xmax), (_yc - _ymax)) < _r: _bits = _bits | 0x80 # upper right # # if all bits are set then distance from circle center # to region endpoints is less than radius - circle # entirely outside the region # _val = not ((_bits == 0xff) or fully) return _val def __pointChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.startChange('moved') def __pointChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.endChange('moved') def __movePoint(self, p, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _cp = self.__center if p is not _cp: raise ValueError, "Point is not circle center: " + `p` _x, _y = _cp.getCoords() self.sendMessage('moved', _x, _y, self.__radius) def clone(self): """Create an identical copy of a Circle clone() """ _cp = self.__center.clone() _st = self.getStyle() _lt = self.getLinetype() _col = self.getColor() _th = self.getThickness() return Circle(_cp, self.__radius, _st, _lt, _col, _th) def sendsMessage(self, m): if m in Circle.__messages: return True return super(Circle, self).sendsMessage(m) def clipToRegion(self, xmin, ymin, xmax, ymax): """Return the portions of a circle visible in a region. clipToRegion(xmin, ymin, xmax, ymax) This method returns a list of tuples. Each tuple contains two float values representing arcs which are seen in the region. Each tuple has the start angle and end angle. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _xc, _yc = self.__center.getCoords() _r = self.__radius _bits = 0 _arcs = [] # # calculate distances from center to region boundaries # if abs(_xc - _xmin) < _r: _bits = _bits | 1 # left edge if abs(_xc - _xmax) < _r: _bits = _bits | 2 # right edge if abs(_yc - _ymin) < _r: _bits = _bits | 4 # bottom edge if abs(_yc - _ymax) < _r: _bits = _bits | 8 # top edge # # test if the circle is entirely contained or entirely # outside the region # # print "bits: %#02x" % _bits if _bits == 0: # # if the circle center is in region then the entire # circle is visible since the distance from the center # to any edge is greater than the radius. If the center # is not in the region then the circle is not visible in # the region because the distance to any edge is greater # than the radius, and so one of the bits should have been # set # if ((_xmin < _xc <_xmax) and (_ymin < _yc < _ymax)): print "circle completely inside region" _arcs.append((0.0, 360.0)) # fully in region else: # # calculate distance to corners of region # if math.hypot((_xc - _xmin), (_yc - _ymax)) < _r: _bits = _bits | 0x10 # upper left, NW corner if math.hypot((_xc - _xmax), (_yc - _ymin)) < _r: _bits = _bits | 0x20 # lower right, SE corner if math.hypot((_xc - _xmin), (_yc - _ymin)) < _r: _bits = _bits | 0x40 # lower left, SW corner if math.hypot((_xc - _xmax), (_yc - _ymax)) < _r: _bits = _bits | 0x80 # upper right, NE corner # # based on the bit pattern the various possible intersections # can be determined # # there is much room for optimization in here - many # of the distances from the center point to the region # edges and corners are calculated numerous times, the # square of these values are also repeatedly calculated ... # _rsqr = _r * _r # _rtd = 180.0/math.pi print "bits: %#02x" % _bits if _bits == 0x01: # circle crosses left edge twice print "circle crosses left edge twice" _yd = math.sqrt(_rsqr - pow((_xc - _xmin), 2)) _yt = _yc + _yd _yb = _yc - _yd print "yt: %g; yb: %g" % (_yt, _yb) assert _yt < _ymax, "ytop > ymax" assert _yb > _ymin, "ybot < ymin" if (_ymin < _yc < _ymax): # must be true _at = _calc_angle((_yt - _yc), (_xmin - _xc)) _ab = _calc_angle((_yb - _yc), (_xmin - _xc)) _arcs.append((_ab, ((360.0 - _ab) + _at))) if _xc > _xmin: # circle inside region print "circle center inside region" else: print "circle center outside" else: if _yc < _ymin: print "yc < ymin (%g < %g)" % (_yc, _ymin) elif _yc > _ymax: print "yc > ymax (%g > %g)" % (_yc, _ymax) else: print "unexpected y: (%g, %g, %g)" % (_ymin, _yc, _ymax) elif _bits == 0x02: # circle crosses right edge twice print "circle crosses right edge twice" _yd = math.sqrt(_rsqr - pow((_xc - _xmax), 2)) _yt = _yc + _yd _yb = _yc - _yd print "yt: %g; yb: %g" % (_yt, _yb) assert _yt < _ymax, "ytop > ymax" assert _yb > _ymin, "ybot < ymin" if (_ymin < _yc < _ymax): # must be true _at = _calc_angle((_yt - _yc), (_xmin - _xc)) _ab = _calc_angle((_yb - _yc), (_xmin - _xc)) _arcs.append((_at, (_ab - _at))) if _xc < _xmax: # circle inside region print "circle inside" else: print "circle outside" else: if _yc < _ymin: print "yc < ymin (%g < %g)" % (_yc, _ymin) elif _yc > _ymax: print "yc > ymax (%g > %g)" % (_yc, _ymax) else: print "unexpected y: (%g, %g, %g)" % (_ymin, _yc, _ymax) elif _bits == 0x04: # circle crosses bottom twice print "circle crosses bottom twice" _xd = math.sqrt(_rsqr - pow((_yc - _ymin), 2)) _xr = _xc + _xd _xl = _xc - _xd print "xl: %g; xr: %g" % (_xl, _xr) assert _xr < _xmax, "xright > xmax" assert _xl > _xmin, "xeft < xmin" if (_xmin < _xc < _xmax): # must be true _al = _calc_angle((_ymin - _yc), (_xl - _xc)) _ar = _calc_angle((_ymin - _yc), (_xr - _xc)) _arcs.append((_ar, (360.0 - _ar + _al))) if _yc > _ymin: # circle inside region print "circle inside" else: print "circle outside" else: if _xc < _xmin: print "xc < xmin (%g < %g)" % (_xc, _xmin) elif _yc > _ymax: print "xc > xmax (%g > %g)" % (_xc, _xmax) else: print "unexpected x: (%g, %g, %g)" % (_xmin, _xc, _xmax) elif _bits == 0x08: # circle crosses top twice print "circle crosses top twice" _xd = math.sqrt(_rsqr - pow((_yc - _ymax), 2)) _xr = _xc + _xd _xl = _xc - _xd print "xl: %g; xr: %g" % (_xl, _xr) assert _xr < _xmax, "xright > xmax" assert _xl > _xmin, "xeft < xmin" if (_xmin < _xc < _xmax): # must be true _al = _calc_angle((_ymax - _yc), (_xl - _xc)) _ar = _calc_angle((_ymax - _yc), (_xr - _xc)) _arcs.append((_al, (360.0 - _al + _ar))) if _yc < _ymax: # circle inside region print "circle inside" else: print "circle outside" else: if _xc < _xmin: print "xc < xmin (%g < %g)" % (_xc, _xmin) elif _yc > _ymax: print "xc > xmax (%g > %g)" % (_xc, _xmax) else: print "unexpected x: (%g, %g, %g)" % (_xmin, _xc, _xmax) elif _bits == 0x09: # circle crosses left and top twice print "circle crosses left and top twice" _xd = math.sqrt(_rsqr - pow((_yc - _ymax), 2)) _xr = _xc + _xd _xl = _xc - _xd _yd = math.sqrt(_rsqr - pow((_xc - _xmin), 2)) _yt = _yc + _yd _yb = _yc - _yd # top -> left _a1 = _calc_angle((_ymax - _yc), (_xl - _xc)) _a2 = _calc_angle((_yt - _yc), (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) # left -> top _a1 = _calc_angle((_yb - _yc), (_xmin - _xc)) _a2 = _calc_angle((_ymax - _yc), (_xr - _xc)) _arcs.append((_a1, (360.0 - _a1 + _a2))) if ((_xmin < _xc < _xmax) and (_ymin < _yc < _ymax)): print "circle inside" else: print "unexpected center for region: (%g, %g)" % (_xc, _yc) elif _bits == 0x0a: # circle crosses top and right twice print "circle crosses top and right twice" _xd = math.sqrt(_rsqr - pow((_yc - _ymax), 2)) _xr = _xc + _xd _xl = _xc - _xd _yd = math.sqrt(_rsqr - pow((_xc - _xmax), 2)) _yt = _yc + _yd _yb = _yc - _yd # top -> right _a1 = _calc_angle((_ymax - _yc), (_xl - _xc)) _a2 = _calc_angle((_yb - _yc), (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) # right -> top _a1 = _calc_angle((_yt - _yc), (_xmax - _xc)) _a2 = _calc_angle((_ymax - _yc), (_xr - _xc)) _arcs.append((_a1, (_a2 - _a1))) if ((_xmin < _xc < _xmax) and (_ymin < _yc < _ymax)): print "circle inside" else: print "unexpected center for region: (%g, %g)" % (_xc, _yc) elif _bits == 0x06: # circle crosses right and bottom twice print "circle crosses right and bottom twice" _xd = math.sqrt(_rsqr - pow((_yc - _ymin), 2)) _xr = _xc + _xd _xl = _xc - _xd _yd = math.sqrt(_rsqr - pow((_xc - _xmax), 2)) _yt = _yc + _yd _yb = _yc - _yd # right -> bottom _a1 = _calc_angle((_yt - _yc), (_xmax - _xc)) _a2 = _calc_angle((_ymin - _yc), (_xl - _xc)) _arcs.append((_a1, (_a2 - _a1))) # bottom -> right _a1 = _calc_angle((_ymin - _yc), (_xr - _xc)) _a2 = _calc_angle((_yb - _yc), (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) if ((_xmin < _xc < _xmax) and (_ymin < _yc < _ymax)): print "circle inside" else: print "unexpected center for region: (%g, %g)" % (_xc, _yc) elif _bits == 0x05: # circle crosses bottom and left twice print "circle crosses bottom and left twice" _xd = math.sqrt(_rsqr - pow((_yc - _ymin), 2)) _xr = _xc + _xd _xl = _xc - _xd _yd = math.sqrt(_rsqr - pow((_xc - _xmin), 2)) _yt = _yc + _yd _yb = _yc - _yd # left -> bottom _a1 = _calc_angle((_yb - _yc), (_xmin - _xc)) _a2 = _calc_angle((_ymin - _yc), (_xl - _xc)) _arcs.append((_a1, (_a2 - _a1))) # bottom -> left _a1 = _calc_angle((_ymin - _yc), (_xr - _xc)) _a2 = _calc_angle((_yt - _xc), (_xmin - _xc)) _arcs.append((_a1, (360.0 - _a1 + _a2))) if ((_xmin < _xc < _xmax) and (_ymin < _yc < _ymax)): print "circle inside" else: print "unexpected center for region: (%g, %g)" % (_xc, _yc) elif _bits == 0x0c: # circle crosses top and bottom twice print "circle crosses top and bottom twice" _xd = math.sqrt(_rsqr - pow((_yc - _ymax), 2)) _xtr = _xc + _xd _xtl = _xc - _xd _xd = math.sqrt(_rsqr - pow((_yc - _ymin), 2)) _xbr = _xc + _xd _xbl = _xc - _xd # top -> bottom _a1 = _calc_angle((_ymax - _yc), (_xtl - _xc)) _a2 = _calc_angle((_ymin - _yc), (_xbl - _xc)) _arcs.append((_a1, (_a2 - _a1))) # bottom -> top _a1 = _calc_angle((_ymin - _yc), (_xbr - _xc)) _a2 = _calc_angle((_ymax - _yc), (_xtr - _xc)) _arcs.append((_a1, (360.0 - _a1 + _a2))) if (_ymin < _yc < _ymax): # needed? print "circle inside region" elif _yc < _ymin: print "circle below region" else: print "circle above region" elif _bits == 0x03: # circle crosses left and right twice print "circle crosses left and right twice" _yd = math.sqrt(_rsqr - pow((_xc - _xmin), 2)) _ylt = _yc + _yd _ylb = _yc - _yd _yd = math.sqrt(_rsqr - pow((_xc - _xmax), 2)) _yrt = _yc + _yd _yrb = _yc - _yd # left -> right _a1 = _calc_angle((_ylb - _yc), (_xmin - _xc)) _a2 = _calc_angle((_yrb - _yc), (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) # right -> left _a1 = _calc_angle((_yrt - _yc), (_xmax - _xc)) _a2 = _calc_angle((_ylt - _yc), (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) if (_xmin < _xc < _xmax): print "circle inside region" elif _xc < _xmin: print "circle left of region" else: print "circle right of region" elif _bits == 0x0b: # circle through left, top, right twice print "circle through left & top & right twice" _xd = math.sqrt(_rsqr - pow((_yc - _ymax), 2)) _xtr = _xc + _xd _xtl = _xc - _xd _yd = math.sqrt(_rsqr - pow((_xc - _xmin), 2)) _ylt = _yc + _yd _ylb = _yc - _yd _yd = math.sqrt(_rsqr - pow((_xc - _xmax), 2)) _yrt = _yc + _yd _yrb = _yc - _yd # top -> left _a1 = _calc_angle((_ymax - _yc), (_xtl - _xc)) _a2 = _calc_angle((_ylt - _yc), (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) # left -> right _a1 = _calc_angle((_ylb - _yc), (_xmin - _xc)) _a2 = _calc_angle((_yrb - _yc), (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) # right > top _a1 = _calc_angle((_yrt - _yc), (_xmax - _xc)) _a2 = _calc_angle((_ymax - _yc), (_xtr - _xc)) _arcs.append((_a1, (_a2 - _a1))) if (_xmin < _xc < _xmax): print "circle inside region" elif _xc < _xmin: print "xc < xmin (%g, %g)" % (_xc, _xmin) else: print "xc > xmax (%g, %g)" % (_xc, _xmax) if _yc < _ymin: print "yc < ymin (%g, %g)" % (_yc, _ymin) else: if _yc > _ymax: print "yc > ymax (%g, %g)" % (_yc, _ymax) elif _bits == 0x0e: # circle through top, right, bottom twice print "circle through top & right & bottom twice" _xd = math.sqrt(_rsqr - pow((_yc - _ymax), 2)) _xtr = _xc + _xd _xtl = _xc - _xd _xd = math.sqrt(_rsqr - pow((_yc - _ymin), 2)) _xbr = _xc + _xd _xbl = _xc - _xd _yd = math.sqrt(_rsqr - pow((_xc - _xmax), 2)) _yrt = _yc + _yd _yrb = _yc - _yd # top -> bottom _a1 = _calc_angle((_ymax - _yc), (_xtl - _xc)) _a2 = _calc_angle((_ymin - _yc), (_xbl - _xc)) _arcs.append((_a1, (_a2 - _a1))) # bottom -> right _a1 = _calc_angle((_ymin - _yc), (_xbr - _xc)) _a2 = _calc_angle((_yrb - _yc), (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) # right -> top _a1 = _calc_angle((_yrt - _yc), (_xmax - _xc)) _a2 = _calc_angle((_ymax - _yc), (_xtr - _xc)) _arcs.append((_a1, (_a2 - _a1))) if (_ymin < _yc < _ymax): print "circle inside region" elif _yc < _ymin: print "yc < ymin (%g, %g)" % (_yc, _ymin) else: print "yc > ymax (%g, %g)" % (_yc, _ymax) if _xc < _xmin: print "xc < xmin (%g, %g)" % (_xc, _xmin) else: if _xc > _xmax: print "xc > xmax (%g, %g)" % (_xc, _xmax) elif _bits == 0x07: # circle though right, bottom, left twice print "circle through right & bottom & left twice" _xd = math.sqrt(_rsqr - pow((_yc - _ymin), 2)) _xbr = _xc + _xd _xbl = _xc - _xd _yd = math.sqrt(_rsqr - pow((_xc - _xmax), 2)) _yrt = _yc + _yd _yrb = _yc - _yd _yd = math.sqrt(_rsqr - pow((_xc - _xmin), 2)) _ylt = _yc + _yd _ylb = _yc - _yd # right -> left _a1 = _calc_angle((_yrt - _yc), (_xmax - _xc)) _a2 = _calc_angle((_ylt - _yc), (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) # left -> bottom _a1 = _calc_angle((_ylb - _yc), (_xmin - _xc)) _a2 = _calc_angle((_ymin - _yc), (_xbl - _xc)) _arcs.append((_a1, (_a2 - _a1))) # bottom -> right _a1 = _calc_angle((_ymin - _yc), (_xbr - _xc)) _a2 = _calc_angle((_yrb - _yc), (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) if (_xmin < _xc < _xmax): print "circle inside region" elif _xc < _xmin: print "xc < xmin (%g, %g)" % (_xc, _xmin) else: print "xc > xmax (%g, %g)" % (_xc, _xmax) if _yc < _ymin: print "yc < ymin (%g, %g)" % (_yc, _ymin) else: if _yc > _ymax: print "yc > ymax (%g, %g)" % (_yc, _ymax) elif _bits == 0x0d: # circle through bottom, left, top twice print "circle through bottom & left & top twice" _xd = math.sqrt(_rsqr - pow((_yc - _ymin), 2)) _xbr = _xc + _xd _xbl = _xc - _xd _xd = math.sqrt(_rsqr - pow((_yc - _ymax), 2)) _xtr = _xc + _xd _xtl = _xc - _xd _yd = math.sqrt(_rsqr - pow((_xc - _xmin), 2)) _ylt = _yc + _yd _ylb = _yc - _yd # bottom -> top _a1 = _calc_angle((_ymin - _yc), (_xbr - _xc)) _a2 = _calc_angle((_ymax - _yc), (_xtr - _xc)) _arcs.append((_a1, (360.0 - _a1 + _a2))) # top -> left _a1 = _calc_angle((_ymax - _yc), (_xtl - _xc)) _a2 = _calc_angle((_ylt - _yc), (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) # left -> bottom _a1 = _calc_angle((_ylb - _yc), (_xmin - _xc)) _a2 = _calc_angle((_ymin - _yc), (_xbl - _xc)) _arcs.append((_a1, (_a2 - _a1))) if (_ymin < _yc < _ymax): print "circle inside region" elif _yc < _ymin: print "yc < ymin (%g, %g)" % (_yc, _ymin) else: print "yc > ymax (%g, %g)" % (_yc, _ymax) if _xc < _xmin: print "xc < xmin (%g, %g)" % (_xc, _xmin) else: if _xc > _xmax: print "xc > xmax (%g, %g)" % (_xc, _xmax) elif _bits == 0x19: # circle through left, top, and NW corner print "circle through left and top with NW corner" _xd = math.sqrt(_rsqr - pow((_yc - _ymax), 2)) _yd = math.sqrt(_rsqr - pow((_xc - _xmin), 2)) _a1 = _calc_angle(-_yd, (_xmin - _xc)) _a2 = _calc_angle((_ymax - _yc), _xd) if _xc > _xmax: _arcs.append((_a1, (_a2 - _a1))) else: _arcs.append((_a1, (360.0 - _a1 + _a2))) if ((_xmin < _xc < _xmax) and (_ymin < _yc < _ymax)): print "circle inside region" else: print "circle outside region" elif _bits == 0x8a: # circle through right, top, and NE corner print "circle through right and top with NE corner" _xd = math.sqrt(_rsqr - pow((_yc - _ymax), 2)) _yd = math.sqrt(_rsqr - pow((_xc - _xmax), 2)) _a1 = _calc_angle((_ymax - _yc), -_xd) _a2 = _calc_angle(-_yd, (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) if ((_xmin < _xc < _xmax) and (_ymin < _yc < _ymax)): print "circle inside region" else: print "circle outside region" elif _bits == 0x26: # circle through right, bottom, and SE corner print "circle through right and bottom with SE corner" _xd = math.sqrt(_rsqr - pow((_yc - _ymin), 2)) _yd = math.sqrt(_rsqr - pow((_xc - _xmax), 2)) _a1 = _calc_angle(_yd, (_xmax - _xc)) _a2 = _calc_angle((_ymin - _yc), -_xd) _arcs.append((_a1, (_a2 - _a1))) if ((_xmin < _xc < _xmax) and (_ymin < _yc < _ymax)): print "circle inside region" else: print "circle outside region" elif _bits == 0x45: # circle through left, bottom, and SW corner print "circle through left and bottom with SW corner" _xd = math.sqrt(_rsqr - pow((_yc - _ymin), 2)) _yd = math.sqrt(_rsqr - pow((_xc - _xmax), 2)) _a1 = _calc_angle((_ymin - _yc), _xd) _a2 = _calc_angle(_yd, (_xmin - _xc)) if _xc < _xmin: _arcs.append((_a1, (_a2 - _a1))) else: _arcs.append((_a1, (360.0 - _a1 + _a2))) if ((_xmin < _xc < _xmax) and (_ymin < _yc < _ymax)): print "circle inside region" else: print "circle outside region" elif _bits == 0x9b: # circle through left, right, NE and NW corner print "circle through left and right with NE, NW corners" _yd = math.sqrt(_rsqr - pow((_xc - _xmin), 2)) _a1 = _calc_angle(-_yd, (_xmin - _xc)) _yd = math.sqrt(_rsqr - pow((_xc - _xmax), 2)) _a2 = _calc_angle(-_yd, (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) if _xc < _xmin: print "x < xmin (%g < %g)" % (_xc, _xmin) elif _xc > _xmax: print "x > xmax (%g > %g)" % (_xc, _xmax) else: if _yc < _ymax: print "circle center in region" else: print "circle center outside region" elif _bits == 0xae: # circle through top, botton, NE and SE corner print "circle through top and bottom with NE, SE corners" _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a1 = _calc_angle((_ymax - _yc), -_xd) _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a2 = _calc_angle((_ymin - _yc), -_xd) _arcs.append((_a1, (_a2 - _a1))) if _yc < _ymin: print "y < ymin (%g < %g)" % (_yc, _ymin) elif _yc > _ymax: print "y > ymax (%g > %g)" % (_yc, _ymax) else: if _xc < _xmax: print "circle center in region" else: print "circle center outside region" elif _bits == 0x67: # circle through left, right, SE and SW corner print "circle through left and right with SE, SW corners" _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a1 = _calc_angle(_yd, (_xmax - _xc)) _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a2 = _calc_angle(_yd, (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) if _xc < _xmin: print "x < xmin (%g < %g)" % (_xc, _xmin) elif _xc > _xmax: print "x > xmax (%g > %g)" % (_xc, _xmax) else: if _yc > _ymin: print "circle center inside region" else: print "circle center outside region" elif _bits == 0x5d: # circle through top, bottom, SW and NW corner _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a1 = _calc_angle((_ymin - _yc), _xd) _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a2 = _calc_angle((_ymax - _yc), _xd) if _xc > _xmin: _arcs.append((_a1, (_a2 - _a1))) else: _arcs.append((_a1, (360.0 - _a1 + _a2))) print "circle through top and bottom with SW, NW corners" if _yc < _ymin: print "y < ymin (%g < %g)" % (_yc, _ymin) elif _yc > _ymax: print "y > ymax (%g > %g)" % (_yc, _ymax) else: if _xc > _xmin: print "circle center inside region" else: print "circle center outside region" elif _bits == 0xbf: # circle center NE, crosses left and bottom print "circle center NE of region, crosses left and bottom" _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a1 = _calc_angle(-_yd, (_xmin - _xc)) _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a2 = _calc_angle((_ymin - _yc), -_xd) _arcs.append((_a1, (_a2 - _a1))) elif _bits == 0xef: # circle center SE, crosses left and top print "circle center SE of region, crosses left and top" _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a1 = _calc_angle((_ymax - _yc), -_xd) _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a2 = _calc_angle(_yd, (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) elif _bits == 0x7f: # circle center SW, crosses top and right print "circle center SW of region, crosses top and right" _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a1 = _calc_angle(_yd, (_xmax - _xc)) _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a2 = _calc_angle((_ymax - _yc), _xd) _arcs.append((_a1, (_a2 - _a1))) elif _bits == 0xdf: # circle center NW, crosses right and bottom print "circle center NW of region, crosses right and bottom" _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a1 = _calc_angle((_ymin - _yc), _xd) _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a2 = _calc_angle(-_yd, (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) elif _bits == 0x9f: # circle center N, crosses left, right, bottom print "circle center N, crosses left, right, and twice bottom" # left -> bottom _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a1 = _calc_angle(-_yd, (xmin - _xc)) _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a2 = _calc_angle((_ymin - _yc), -_xd) _arcs.append((_a1, (_a2 - _a1))) # bottom -> right; _xd now positive _a1 = _calc_angle((_ymin - _yc), _xd) _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a2 = _calc_angle(-_yd, (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) if _yc < _ymax: print "yc < ymax (%g < %g)" % (_yc, _ymax) if ((_xc < _xmin) or (_xc > _xmax)): print "xc: %g; xmin: %g; xmax: %g" % (_xc, _xmin, _xmax) elif _bits == 0xaf: # circle center W, crosses bottom, left, top print "circle center W, crosses bottom, top, and twice left" # top -> left _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a1 = _calc_angle((_ymax - _yc), -_xd) _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a2 = _calc_angle(_yd, (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) # left -> bottom; _yd now negative _a1 = _calc_angle(-_yd, (_xmin - _xc)) _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a2 = _calc_angle((_ymin - _yc), -_xd) _arcs.append((_a1, (_a2 - _a1))) if _xc < _xmax: print "xc < xmax (%g < %g)" % (_xc, _xmax) if ((_yc < _ymin) or (_yc > _ymax)): print "yc: %g; ymin: %g; ymax: %g" % (_yc, _ymin, _ymax) elif _bits == 0x6f: # circle center S, crosses left, top, right print "circle center S, crosses left, right, and twice top" # right -> top _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a1 = _calc_angle(_yd, (_xmax - _xc)) _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a2 = _calc_angle((_ymax - _yc), _xd) _arcs.append((_a1, (_a2 - _a1))) # top -> left; _xd now negative _a1 = _calc_angle((_ymax - _yc), -_xd) _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a2 = _calc_angle(_yd, (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) if _yc > _ymin: print "yc > ymin (%g > %g)" % (_yc, _ymin) if ((_xc < _xmin) or (_xc > _xmax)): print "xc: %g; xmin: %g; xmax: %g" % (_xc, _xmin, _xmax) elif _bits == 0x5f: # circle center E, crosses top, right, bottom print "circle center E, crosses top, bottom, and twice right" # bottom -> right _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a1 = _calc_angle((_ymin - _yc), _xd) _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a2 = _calc_angle(-_yd, (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) # right -> top, _yd now positive _a1 = _calc_angle(_yd, (_xmax - _xc)) _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a2 = _calc_angle((_ymax - _yc), _xd) _arcs.append((_a1, (_a2 - _a1))) if _xc > _xmin: print "xc > xmin (%g > %g)" % (_xc, _xmin) if ((_yc < _ymin) or (_yc > _ymax)): print "yc: %g; ymin: %g; ymax: %g" % (_yc, _ymin, _ymax) elif _bits == 0x1d: print "circle center N near NW, crosses T&L once, B twice" # left -> bottom _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a1 = _calc_angle(-_yd, (_xmin - _xc)) _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a2 = _calc_angle((_ymin - _yc), -_xd) _arcs.append((_a1, (_a2 - _a1))) # top -> bottom; _xd now positive _a1 = _calc_angle((_ymin - _yc), _xd) _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a2 = _calc_angle((_ymax - _yc), _xd) if _yc > _ymax: _arcs.append((_a1, (_a2 - _a1))) else: _arcs.append((_a1, (360.0 - _a1 + _a2))) if _xc < _xmin: print "x < xmin (%g < %g)" % (_xc, _xmin) if _yc < _ymax: print "y < ymax (%g < %g)" % (_yc, _ymax) elif _bits == 0x4d: print "circle center S near SW, crosses B&L once, T twice" # bottom -> top _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a1 = _calc_angle((_ymin - _yc), _xd) _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a2 = _calc_angle((_ymax - _yc), _xd) _arcs.append((_a1, (_a2 - _a1))) # top -> left, _xd now negative _a1 = _calc_angle((_ymax - _yc), -_xd) _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a2 = _calc_angle(_yd, (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) if _xc < _xmin: print "x < xmin (%g < %g)" % (_xc, _xmin) if _yc > _ymin: print "y > ymin (%g > %g)" % (_yc, _ymin) elif _bits == 0x2e: print "circle center S near SE, crosses B&R once, T twice" # right -> top _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a1 = _calc_angle(_yd, (_xmax - _xc)) _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a2 = _calc_angle((_ymax - _yc), _xd) _arcs.append((_a1, (_a2 - _a1))) # top -> bottom; _xd now negative _a1 = _calc_angle((_ymax - _yc), -_xd) _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a2 = _calc_angle((_ymin - _yc), -_xd) _arcs.append((_a1, (_a2 - _a1))) if _xc > _xmax: print "x > xmax (%g > %g)" % (_xc, _xmax) if _yc > _ymin: print "y > ymin (%g > %g)" % (_yc, _ymin) elif _bits == 0x8e: print "circle center N near NE, crosses T&R once, B twice" # top -> bottom _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a1 = _calc_angle((_ymax - _yc), -_xd) _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a2 = _calc_angle((_ymin - _yc), -_xd) _arcs.append((_a1, (_a2 - _a1))) # bottom -> right, _xd now positive _a1 = _calc_angle((_ymin - _yc), _xd) _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a2 = _calc_angle(-_yd, (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) if _xc > _xmax: print "x > xmax (%g > %g)" % (_xc, _xmax) if _yc < _ymax: print "y < ymax (%g < %g)" % (_yc, _ymax) elif _bits == 0x1b: print "circle center E near NW, crosses T&L once, R twice" # left -> right _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a1 = _calc_angle(-_yd, (_xmin - _xc)) _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a2 = _calc_angle(-_yd, (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) # right -> top; _yd now positive _a1 = _calc_angle(_yd, (_xmax - _xc)) _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a2 = _calc_angle((_ymax - _yc), _xd) _arcs.append((_a1, (_a2 - _a1))) if _yc > _ymax: print "y > ymax (%g > %g)" % (_yc, _ymax) if _xc > _xmin: print "x > xmin (%g > %g)" % (_xc, _xmin) elif _bits == 0x8b: print "circle center W near NE, crosses T&R once, L twice" # top -> left _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a1 = _calc_angle((_ymax - _yc), -_xd) _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a2 = _calc_angle(_yd, (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) # left -> right; _yd now negative _a1 = _calc_angle(-_yd, (_xmin - _xc)) _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a2 = _calc_angle(-_yd, (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) if _yc > _ymax: print "y > ymax (%g > %g)" % (_yc, _ymax) if _xc < _xmax: print "x < xmax (%g < %g)" % (_xc, _xmax) elif _bits == 0x27: print "circle center W near SE, crosses B&R once, L twice" # right -> left _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a1 = _calc_angle(_yd, (_xmax - _xc)) _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a2 = _calc_angle(_yd, (_xmin - _xc)) print "a1: %g; a2: %g" % (_a1, _a2) _arcs.append((_a1, (_a2 - _a1))) # left -> bottom; now _yd is negative _a1 = _calc_angle(-_yd, (_xmin - _xc)) _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a2 = _calc_angle((_ymin - _yc), -_xd) print "a1: %g; a2: %g" % (_a1, _a2) _arcs.append((_a1, (_a2 - _a1))) if _yc < _ymin: print "y < ymin (%g < %g)" % (_yc, _ymin) if _xc < _xmax: print "x < xmax (%g < %g)" % (_xc, _xmax) elif _bits == 0x47: print "circle center E near SW, crosses B&L once, R twice" # bottom -> right _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a1 = _calc_angle((_ymin - _yc), _xd) _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a2 = _calc_angle(-_yd, (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) # right -> left; now _yd is positive _a1 = _calc_angle(_yd, (_xmax - _xc)) _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a2 = _calc_angle(_yd, (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) if _yc < ymin: print "y < ymin (%g < %g)" % (_yc, _ymin) if _xc > _xmin: print "x > xmin (%g > %g)" % (_xc, _xmin) elif _bits == 0x1f: print "circle center NW, crosses L&T once, R&B twice" # right -> top _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a1 = _calc_angle(_yd, (_xmax - _xc)) _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a2 = _calc_angle((_ymax - _yc), _xd) _arcs.append((_a1, (_a2 - _a1))) # left -> bottom _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a1 = _calc_angle(-_yd, (_xmin - _xc)) _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a2 = _calc_angle((_ymin - _yc), -_xd) _arcs.append((_a1, (_a2 - _a1))) # bottom -> right; _xd now positive _a1 = _calc_angle((_ymin - _yc), _xd) _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a2 = _calc_angle(-_yd, (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) if ((_xmin < _xc < _xmax) and (_ymin < _yc < _ymax)): print "circle center in region" else: print "circle center out of region" elif _bits == 0x8f: print "circle center NE, crosses T&R once, B&L twice" # top -> left _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a1 = _calc_angle((_ymax - _yc), -_xd) _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a2 = _calc_angle(_yd, (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) # left -> bottom; _yd now negative _a1 = _calc_angle(-_yd, (_xmin - _xc)) _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a2 = _calc_angle((_ymin - _yc), -_xd) _arcs.append((_a1, (_a2 - _a1))) # bottom -> right; _xd now positive _a1 = _calc_angle((_ymin - _yc), _xd) _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a2 = _calc_angle(-_yd, (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) if ((_xmin < _xc < _xmax) and (_ymin < _yc < _ymax)): print "circle center in region" else: print "circle center out of region" elif _bits == 0x2f: print "circle center SE, crosses L&T twice, R&B once" # top -> left _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a1 = _calc_angle((_ymax - _yc), -_xd) _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a2 = _calc_angle(_yd, (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) # left -> bottom; _yd now negative _a1 = _calc_angle(-_yd, (_xmin - _xc)) _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a2 = _calc_angle((_ymin - _yc), -_xd) _arcs.append((_a1, (_a2 - _a1))) # right -> top _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a1 = _calc_angle(_yd, (_xmax - _xc)) _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a2 = _calc_angle((_ymax - _yc), _xd) _arcs.append((_a1, (_a2 - _a1))) if ((_xmin < _xc < _xmax) and (_ymin < _yc < _ymax)): print "circle center in region" else: print "circle center out of region" elif _bits == 0x4f: print "circle center SW, crosses T&R twice, B&L once" # bottom -> right _xd = math.sqrt(_rsqr - pow((_ymin - _yc), 2)) _a1 = _calc_angle((_ymin - _yc), _xd) _yd = math.sqrt(_rsqr - pow((_xmax - _xc), 2)) _a2 = _calc_angle(-_yd, (_xmax - _xc)) _arcs.append((_a1, (_a2 - _a1))) # right -> top; _yd now positive _a1 = _calc_angle(_yd, (_xmax - _xc)) _xd = math.sqrt(_rsqr - pow((_ymax - _yc), 2)) _a2 = _calc_angle((_ymax - _yc), _xd) _arcs.append((_a1, (_a2 - _a1))) # top -> left; _xd now negative _a1 = _calc_angle((_ymax - _yc), -_xd) _yd = math.sqrt(_rsqr - pow((_xmin - _xc), 2)) _a2 = _calc_angle(_yd, (_xmin - _xc)) _arcs.append((_a1, (_a2 - _a1))) if ((_xmin < _xc < _xmax) and (_ymin < _yc < _ymax)): print "circle center in region" else: print "circle center out of region" elif _bits == 0x0f: print "circle crosses all edges twice" _yld = math.sqrt(_rsqr - pow((_xc - _xmin), 2)) _yrd = math.sqrt(_rsqr - pow((_xc - _xmax), 2)) _xtd = math.sqrt(_rsqr - pow((_yc - _ymax), 2)) _xbd = math.sqrt(_rsqr - pow((_yc - _ymin), 2)) # right -> top _x1 = _xmax _y1 = _yc + _yrd _x2 = _xc + _xtd _y2 = _ymax _a1 = _calc_angle((_y1 - _yc), (_x1 - _xc)) _a2 = _calc_angle((_y2 - _yc), (_x2 - _xc)) _arcs.append((_a1, (_a2 - _a1))) # top -> left _x1 = _xc - _xtd _y1 = _ymax _x2 = _xmin _y2 = _yc + _yld _a1 = _calc_angle((_y1 - _yc), (_x1 - _xc)) _a2 = _calc_angle((_y2 - _yc), (_x2 - _xc)) _arcs.append((_a1, (_a2 - _a1))) # left -> bottom _x1 = _xmin _y1 = _yc - _yld _x2 = _xc - _xbd _y2 = _ymin _a1 = _calc_angle((_y1 - _yc), (_x1 - _xc)) _a2 = _calc_angle((_y2 - _yc), (_x2 - _xc)) _arcs.append((_a1, (_a2 - _a1))) # bottom -> right _x1 = _xc + _xbd _y1 = _ymin _x2 = _xmax _y2 = _yc - _yrd _a1 = _calc_angle((_y1 - _yc), (_x1 - _xc)) _a2 = _calc_angle((_y2 - _yc), (_x2 - _xc)) _arcs.append((_a1, (_a2 - _a1))) elif _bits == 0xff: print "circle outside region" else: print "Unexpected bit pattern: %#02x" % _bits return _arcs def _calc_angle(dy, dx): _angle = math.atan2(dy, dx) * (180.0/math.pi) if _angle < 0.0: _angle = _angle + 360.0 return _angle # # Quadtree Circle storage # class CircleQuadtree(quadtree.Quadtree): def __init__(self): super(CircleQuadtree, self).__init__() def getNodes(self, *args): _alen = len(args) if _alen != 3: raise ValueError, "Expected 3 arguments, got %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _r = util.get_float(args[2]) _cxmin = _x - _r _cxmax = _x + _r _cymin = _y - _r _cymax = _y + _r _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_cxmin > _xmax) or (_cxmax < _xmin) or (_cymin > _ymax) or (_cymax < _ymin)): continue if _node.hasSubnodes(): _xmid = (_xmin + _xmax)/2.0 _ymid = (_ymin + _ymax)/2.0 _ne = _nw = _sw = _se = True if _cxmax < _xmid: # circle on left side _ne = _se = False if _cxmin > _xmid: # circle on right side _nw = _sw = False if _cymax < _ymid: # circle below _nw = _ne = False if _cymin > _ymid: # circle above _sw = _se = False if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: yield _node def addObject(self, obj): if not isinstance(obj, Circle): raise TypeError, "Invalid Circle object: " + `type(obj)` if obj in self: return _x, _y = obj.getCenter().getCoords() _r = obj.getRadius() _bounds = self.getTreeRoot().getBoundary() _xmin = _ymin = _xmax = _ymax = None _cxmin = _x - _r _cxmax = _x + _r _cymin = _y - _r _cymax = _y + _r _resize = False if _bounds is None: # first node in tree _resize = True _xmin = _cxmin - 1.0 _ymin = _cymin - 1.0 _xmax = _cxmax + 1.0 _ymax = _cymax + 1.0 else: _xmin, _ymin, _xmax, _ymax = _bounds if _cxmin < _xmin: _xmin = _cxmin - 1.0 _resize = True if _cxmax > _xmax: _xmax = _cxmax + 1.0 _resize = True if _cymin < _ymin: _ymin = _cymin - 1.0 _resize = True if _cymax > _ymax: _ymax = _cymax + 1.0 _resize = True if _resize: self.resize(_xmin, _ymin, _xmax, _ymax) for _node in self.getNodes(_x, _y, _r): _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if obj.inRegion(_xmin, _ymin, _xmax, _ymax): _node.addObject(obj) super(CircleQuadtree, self).addObject(obj) obj.connect('moved', self._moveCircle) def delObject(self, obj): if obj not in self: return _x, _y = obj.getCenter().getCoords() _r = obj.getRadius() _pdict = {} for _node in self.getNodes(_x, _y, _r): _node.delObject(obj) # circle may not be in the node ... _parent = _node.getParent() if _parent is not None: _pid = id(_parent) if _pid not in _pdict: _pdict[_pid] = _parent super(CircleQuadtree, self).delObject(obj) obj.disconnect(self) for _parent in _pdict.values(): self.purgeSubnodes(_parent) def find(self, *args): _alen = len(args) if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _r = util.get_float(args[2]) _t = tolerance.TOL if _alen > 3: _t = tolerance.toltest(args[4]) _xmin = _x - _r - _t _xmax = _x + _r + _t _ymin = _y - _r - _t _ymax = _y + _r + _t _circs = [] for _circ in self.getInRegion(_xmin, _ymin, _xmax, _ymax): _cx, _cy = _circ.getCenter().getCoords() if ((abs(_cx - _x) < _t) and (abs(_cy - _y) < _t) and (abs(_circ.getRadius() - _r) < _t)): _circs.append(_circ) return _circs def _moveCircle(self, obj, *args): if obj not in self: raise ValueError, "Circle not stored in Quadtree: " + `obj` _alen = len(args) if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _r = util.get_float(args[2]) for _node in self.getNodes(_x, _y, _r): _node.delObject(obj) # circle may not be in node ... super(CircleQuadtree, self).delObject(obj) obj.disconnect(self) self.addObject(obj) def getClosest(self, x, y, tol=tolerance.TOL): _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _circ = _tsep = None _bailout = False _cdict = {} _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_x < (_xmin - _t)) or (_x > (_xmax + _t)) or (_y < (_ymin - _t)) or (_y > (_ymax + _t))): continue if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) else: for _c in _node.getObjects(): _cid = id(_c) if _cid not in _cdict: _cp = _c.mapCoords(_x, _y, _t) if _cp is not None: _cx, _cy = _cp _sep = math.hypot((_cx - _x), (_cy - _y)) if _tsep is None: _tsep = _sep _circ = _c else: if _sep < _tsep: _tsep = _sep _circ = _c if _sep < 1e-10 and _circ is not None: _bailout = True break if _bailout: break return _circ def getInRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _circs = [] if not len(self): return _circs _nodes = [self.getTreeRoot()] _cdict = {} while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): for _subnode in _node.getSubnodes(): _sxmin, _symin, _sxmax, _symax = _subnode.getBoundary() if ((_sxmin > _xmax) or (_symin > _ymax) or (_sxmax < _xmin) or (_symax < _ymin)): continue _nodes.append(_subnode) else: for _circ in _node.getObjects(): _cid = id(_circ) if _cid not in _cdict: if _circ.inRegion(_xmin, _ymin, _xmax, _ymax): _circs.append(_circ) _cdict[_cid] = True return _circs # # Circle history class # class CircleLog(graphicobject.GraphicObjectLog): def __init__(self, c): if not isinstance(c, Circle): raise TypeError, "Invalid circle: " + `type(c)` super(CircleLog, self).__init__(c) c.connect('center_changed', self.__centerChanged) c.connect('radius_changed', self.__radiusChanged) def __radiusChanged(self, c, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _r = args[0] if not isinstance(_r, float): raise TypeError, "Unxpected type for radius: " + `type(_r)` self.saveUndoData('radius_changed', _r) def __centerChanged(self, c, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _old = args[0] if not isinstance(_old, point.Point): raise TypeError, "Invalid old center point: " + `type(_old)` self.saveUndoData('center_changed', _old.getID()) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if _alen == 0: raise ValueError, "No arguments to execute()" _c = self.getObject() _cp = _c.getCenter() _op = args[0] if _op == 'radius_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _r = args[1] if not isinstance(_r, float): raise TypeError, "Unexpected type for radius: " + `type(_r)` _sdata = _c.getRadius() self.ignore(_op) try: if undo: _c.startUndo() try: _c.setRadius(_r) finally: _c.endUndo() else: _c.startRedo() try: _c.setRadius(_r) finally: _c.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'center_changed': if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _oid = args[1] _parent = _c.getParent() if _parent is None: raise ValueError, "Circle has no parent - cannot undo" _pt = _parent.getObject(_oid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "Center point missing: id=%d" % _oid _sdata = _cp.getID() self.ignore(_op) try: if undo: _c.startUndo() try: _c.setCenter(_pt) finally: _c.endUndo() else: _c.startRedo() try: _c.setCenter(_pt) finally: _c.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) else: super(CircleLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/snap.py0000644000175000017500000003574611307666732017663 0ustar matteomatteo# # Copyright (c) 2009 Matteo Boscolo # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # import math import types import warnings import pygtk pygtk.require('2.0') import gtk from PythonCAD.Generic import util from PythonCAD.Generic import intersections from PythonCAD.Generic.point import Point from PythonCAD.Generic.segment import Segment from PythonCAD.Generic.circle import Circle from PythonCAD.Generic.ccircle import CCircle from PythonCAD.Generic.arc import Arc from PythonCAD.Generic.cline import CLine from PythonCAD.Generic.hcline import HCLine from PythonCAD.Generic.vcline import VCLine from PythonCAD.Generic.acline import ACLine from PythonCAD.Generic import globals class SnapPointStr(object): """ this class provide a structure for cliched user point """ __snapKind=None __snapPoint=None __snapEnt=None __snapCursor=gtk.gdk.Cursor(gtk.gdk.X_CURSOR) def __init__(self,k,p,e): self.kind=k self.point=p self.entity=e def getKind(self): return self.__snapKind def setKind(self,k): self.__snapKind=k def getPoint(self): return self.__snapPoint def setPoint(self,p): if not isinstance(p,Point): raise TypeError, "Invalid Point type : " + `type(p)` self.__snapPoint=p def getEnt(self): return self.__snapEnt def setEnt(self,e): self.__snapEnt=e def getCursor(self): return self.__snapCursor def setCursor(self,c): self.__snapCursor=c kind=property(getKind,setKind,None,"Set/Get the kind of snap that is required") point=property(getPoint,setPoint,None,"Set/get the Point clicked that is required") entity=property(getEnt,setEnt,None,"Set/Get the Entity Clicked") cursor=property(getCursor,setCursor,None,"Define the Cursor") class SnapServices(object): """ Provide all snap functionality for the user """ def __init__(self,image): self.__image=image self.__topLayer=image.getTopLayer() self.__temporarySnap=None def getSnap(self,t,snapArray=None): """ return a snap snapPointStr clicked by the user """ if snapArray is None:_snapArray=globals.snapOption else:_snapArray=snapArray _currentX, _currentY = self.__image.getCurrentPoint() _mausePoint=Point(_currentX, _currentY) #print "Debug: Mouse Point %s"%str(_mausePoint) _mouseEnt = self.getEnt(_currentX,_currentY,t) retObj=SnapPointStr("Freepoint",Point(_currentX,_currentY),_mouseEnt) retObj.cursor=gtk.gdk.Cursor(gtk.gdk.TOP_LEFT_ARROW) if self.__temporarySnap is not None: _snapArray=self.__temporarySnap if 'mid' in _snapArray: if _snapArray['mid']: _midPnt=self.getMid(_currentX, _currentY,t) if _midPnt != None: retObj.point=_midPnt retObj.kind="Mid" retObj.cursor=gtk.gdk.Cursor(gtk.gdk.SB_H_DOUBLE_ARROW) if 'end' in _snapArray: if _snapArray['end']: _endPnt=self.getEndPoint(_currentX, _currentY,_mouseEnt) if _endPnt != None: if retObj.kind=="Freepoint": retObj.point=_endPnt retObj.kind="End" retObj.cursor=gtk.gdk.Cursor(gtk.gdk.DOTBOX) if _mausePoint.Dist(_endPnt)<_mausePoint.Dist(retObj.point): retObj.point=_endPnt retObj.kind="End" retObj.cursor=gtk.gdk.Cursor(gtk.gdk.DOTBOX) if 'intersection' in _snapArray: if _snapArray['intersection']: _intPnt=self.getIntersection(_currentX, _currentY,t) if _intPnt != None: if retObj.kind=="Freepoint": retObj.point=_intPnt retObj.kind="Mid" retObj.cursor=gtk.gdk.Cursor(gtk.gdk.X_CURSOR) if _mausePoint.Dist(_intPnt)<_mausePoint.Dist(retObj.point): retObj.point=_intPnt retObj.kind="Mid" retObj.cursor=gtk.gdk.Cursor(gtk.gdk.X_CURSOR) if 'point' in _snapArray: if _snapArray['point']: _pntPnt=self.getPoint(_currentX, _currentY,t) if _pntPnt != None: if retObj.kind=="Freepoint": retObj.point=_pntPnt retObj.kind="Point" retObj.cursor=gtk.gdk.Cursor(gtk.gdk.IRON_CROSS) if _mausePoint.Dist(_pntPnt)<_mausePoint.Dist(retObj.point): retObj.point=_pntPnt retObj.kind="Point" retObj.cursor=gtk.gdk.Cursor(gtk.gdk.IRON_CROSS) if 'origin' in _snapArray: if _snapArray['origin']: _oriPnt=Point(0.0,0.0) retObj.point=_oriPnt retObj.kind="Origin" retObj.cursor=gtk.gdk.Cursor(gtk.gdk.DOT) return retObj if 'perpendicular' in _snapArray: if _snapArray['perpendicular']: retObj.point=Point(_currentX, _currentY) retObj.kind="Perpendicular" retObj.cursor=gtk.gdk.Cursor(gtk.gdk.BOTTOM_TEE) return retObj if 'tangent' in _snapArray: if _snapArray['tangent']: retObj.point=Point(_currentX, _currentY) retObj.kind="Tangent" retObj.cursor=gtk.gdk.Cursor(gtk.gdk.EXCHANGE) return retObj if 'center' in _snapArray: if _snapArray['center']: _cenPnt=self.getCenter(_currentX, _currentY,t) if _cenPnt != (None,None): retObj.point=Point(_cenPnt) retObj.kind="Center" retObj.cursor=gtk.gdk.Cursor(gtk.gdk.CIRCLE) return retObj return retObj def getEnt(self,x,y,_t,types=None): """ Get The Entity Under the Mouse Pointer """ _objlist = [] _intlist = [] if types is not None: _types=types else: _types = {'point' : True, 'segment' : True, 'circle' : True, 'arc' : True, 'polyline' : True, 'hcline' : True, 'vcline' : True, 'acline' : True, 'cline' : True, 'ccircle' : True, } _layers = [self.__image.getActiveLayer()] while len(_layers): _layer = _layers.pop() _hits = _layer.mapCoords(x, y, tolerance=_t, types=_types) if len(_hits) > 0: for _obj, _pt in _hits: if(_obj is not None): return _obj return None def getMid(self,x,y,t): """" Calculate the mid point """ _types = {'segment' : True} _obj=self.getEnt(x,y,t,_types) if _obj is None: return None _ix,_iy=_obj.getMiddlePoint() return Point(_ix,_iy) def getEndPoint(self,x,y,entityHits): """ Get The Segment End Point nearest to the coord x,y """ nearestPoint = (None,None) if not entityHits is None: mousePoint=Point(x,y) if isinstance(entityHits,Segment): _op1, _op2 = entityHits.getEndpoints() if(mousePoint.Dist(_op1) 0: for _obj, _pt in _hits: for _tobj, _mp in _objlist: for _ix, _iy in intersections.find_intersections(_tobj, _obj): if ((abs(_ix - x) < t) and (abs(_iy - y) < t)): _sqlen = pow((x - _ix), 2) + pow((y - _iy), 2) _intlist.append((_sqlen, (_ix, _iy))) _objlist.append((_obj, _pt)) _layers.extend(_layer.getSublayers()) # # use the nearest intersection point if one is available # if len(_intlist): _intlist.sort() _cp = _intlist[0][1] if _cp is not None: return Point(_cp[0],_cp[1]) return None def getCenter(self,x,y,t): """ Get The Center point over the mouse """ _types = {'ccircle' : True ,'ccircle' : True ,'circle' : True ,'arc' : True ,'fillet':True} _obj=self.getEnt(x,y,t,_types) if _obj is None: return (None,None) _ix,_iy=_obj.getCenter().getCoords() return (_ix,_iy) def getPoint(self,x,y,t): """ Get The point over the mouse """ _types = {'point' : True} _obj=self.getEnt(x,y,t,_types) if _obj is None : return None _ix,_iy=_obj.getCoords() return Point(_ix,_iy) def setOneTemporarySnap(self,snap): """ Set only One snap snap mast be a string es: 'mid' """ _array={} _array[snap]=True self.__temporarySnap=_array def setTemporarySnapArray(self,snapArray): """ set to temporary snap array snapArray Mast be a dic es: {'mid':true,'end':false,....} """ if not isinstance(snapArray,dict): raise TypeError, "Unexpected type for snapArray: " + `type(snapArray)` self.__temporarySnap=snapArray def excludeSnapArray(self,excludeSnap): """ set the value of the exludeSnap to the global snap """ if not isinstance(excludeSnap,dict): raise TypeError, "Unexpected type for snapArray: " + `type(excludeSnap)` self.__temporarySnap = globals.snapOption.copy() for key in excludeSnap.keys(): self.__temporarySnap[key]=excludeSnap[key] def resetTemporatySnap(self): """ Reset the temporary snap array and restor the normal snap flow """ self.__temporarySnap=None def setSnap(image,toolFunction,tol,excludeSnap=None): """ set the snap to the toolFunctionMethod image : image or GTKImage toolFunction : function to be called for storing the data tol : tollerance culd be None if image is GTKImage excludeSnap : array of type {'end':False} """ _sPnt=getSnapPoint(image,tol,excludeSnap) toolFunction(_sPnt ) def setDinamicSnap(gtkimage,toolFunction,excludeSnap=None): """ set the dinamic snap for using withe preview douring motion functions """ _tol=gtkimage.getTolerance() _image=gtkimage.getImage() _sp=_image.snapProvider if excludeSnap is not None: _sp.excludeSnapArray(excludeSnap) _sPnt=_sp.getSnap(_tol) toolFunction(_sPnt ) def getSnapPoint(image,tol,excludeSnap=None): """ return the snap point clicked by the user image : image tol : tollerance culd be None if image is GTKImage excludeSnap : array of type {'end':False,.....} return: SnapPointStr """ _sp=image.snapProvider if excludeSnap is not None: _sp.excludeSnapArray(excludeSnap) _sPnt=_sp.getSnap(tol) _sp.resetTemporatySnap() return _sPnt def getOnlySnap(image,tol,onlySnapArray): """ set the dinamic snap to get only the onlySnapArray """ _sPnt=None _sp=image.snapProvider if onlySnapArray is not None: _sp.setTemporarySnapArray(onlySnapArray) _sPnt=_sp.getSnap(tol) _sp.resetTemporatySnap() return _sPnt def getSnapOnTruePoint(gtkimage,excludeArray): """ looking for real Entity Point Snap .. if it dose not find Return None On the str.Point """ _tol = gtkimage.getTolerance() _image = gtkimage.getImage() _sp=_image.snapProvider _strPnt=getSnapPoint(_image,_tol,excludeArray) _pt=getDrawedPoint(_image,_tol,_strPnt) if _pt is not None : _strPnt.point=_pt else: _active_layer = _image.getActiveLayer() _active_layer.addObject(_strPnt.point) return _strPnt def getDrawedPoint(image ,tol,strPoint): """ Looking in the drawing if the point exsists and get it none if no point is found """ if strPoint.kind=="Freepoint": return None _x, _y = strPoint.point.getCoords() _layers = [image.getTopLayer()] while len(_layers): _layer = _layers.pop() if _layer.isVisible(): _pt = None _pts = _layer.find('point', _x, _y, tol) if len(_pts) > 0: _pt = _pts[0] if _pt is not None: return _pt break _layers.extend(_layer.getSublayers()) return None def getSelections(gtkimage,objFilter): """ get the object preselected or selected """ _retVal=[] _tol = gtkimage.getTolerance() _image = gtkimage.getImage() if _image.hasSelection(): _objs= _image.getSelectedObjects() else: _x, _y = _image.getCurrentPoint() _active_layer = _image.getActiveLayer() objects=_active_layer.mapPoint((_x, _y), _tol) if len(objects): _mapObj ,point = objects[0] if isinstance(_mapObj,Segment): return _mapObj,point return None,NonePythonCAD-DS1-R37/PythonCAD/Generic/style.py0000644000175000017500000001377111307666657020062 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # classes for styles # import types from PythonCAD.Generic import color from PythonCAD.Generic import linetype from PythonCAD.Generic import util class Style(object): """A class storing a particular of Linetype, Color, and Thickness. A Style consists of four attributes: name: The Style name linetype: A Linetype object color: A Color object thickness: A positive float value giving the line thickness A Style has the following methods: getName(): Get the Style name. getColor(): Get the Style color. getLinetype(): Get the Style Linetype. getThickness(): Get the Style line thickness. clone(): Return an identical copy of the Style. Once a Style is created, the values in that object cannot be changed. """ __defcolor = color.Color(0xffffff) def __init__(self, name, lt=None, col=None, t=None): """Instatiate a Style object. Style(name [, lt, col, t]) name: A string giving the style a name Option arguments: lt: A Linetype object - defaults to a solid line Linetype col: A Color object - defaults to the default Color object t: A positive float value - defaults to 1.0 """ if not isinstance(name, types.StringTypes): raise TypeError, "Invalid Style name: " + `name` _n = name if not isinstance(_n, unicode): _n = unicode(name) _lt = lt if _lt is None: _lt = linetype.Linetype('Default_Solid', None) if not isinstance(_lt, linetype.Linetype): raise TypeError, "Invalid linetype: " + `_lt` _c = col if _c is None: _c = Style.__defcolor if not isinstance(_c, color.Color): _c = color.Color(color) _t = t if _t is None: _t = 1.0 _t = util.get_float(_t) if _t < 0.0: raise ValueError, "Invalid line thickness: %g" % _t self.__name = _n self.__linetype = _lt self.__color = _c self.__thickness = _t def __eq__(self, obj): """Compare a Style object to another Style for equality. Comparing two styles is really comparing that the linetypes are the same, then the colors are the same, and that the line thickness are the same (within a tiny tolerance). If all three are the same, the comparison returns True. Otherwise, the comparison returns False. """ if not isinstance(obj, Style): return False if obj is self: return True return (self.__name == obj.getName() and self.__linetype == obj.getLinetype() and self.__color == obj.getColor() and abs(self.__thickness - obj.getThickness()) < 1e-10) def __ne__(self, obj): """Compare a Style object to another Style for non-equality. Comparing two styles is really comparing that the linetypes are the same, then the colors are the same, and that the line thickness are the same (within a tiny tolerance). If all three are the same, the comparison returns False. Otherwise, the comparison returns True. """ return not self == obj def __hash__(self): """Return a hash value for the Style. Defining this method allows Styles to be stored in dictionaries. """ _val = hash(self.__color) _val = _val ^ hash(self.__linetype) _val = _val ^ hash(long(self.__thickness * 1e10)) return _val def getName(self): """Return the name of the Style. getName() """ return self.__name name = property(getName, None, None, "Style name.") def getLinetype(self): """Return the Linetype used by this Style. getLinetype() """ return self.__linetype linetype = property(getLinetype, None, None, "Style Linetype") def getColor(self): """Return the Color used by this Style. getColor() """ return self.__color color = property(getColor, None, None, "Style Color") def getThickness(self): """Return the line thickness used by this style. getThickness() """ return self.__thickness thickness = property(getThickness, None, None, "Style Thickness.") def getStyleValues(self): _n = self.__name _l = self.__linetype.getName(), self.__linetype.getList() _c = self.__color.getColors() _t = self.thickness return _n, _l, _c, _t def clone(self): """Return an identical copy of a Style. clone() """ _name = self.__name[:] _linetype = self.__linetype.clone() _color = self.__color.clone() _thickness = self.__thickness return Style(_name, _linetype, _color, _thickness) # # StyleDict Class # # The StyleDict is built from the dict object. Using instances # of this class will guarantee than only Style objects will be # stored in the instance # class StyleDict(dict): def __init__(self): super(StyleDict, self).__init__() def __setitem__(self, key, value): if not isinstance(key, Style): raise TypeError, "StyleDict keys must be Style objects: " + `key` if not isinstance(value, Style): raise TypeError, "StyleDict values must be Style objects: " + `value` super(StyleDict, self).__setitem__(key, value) PythonCAD-DS1-R37/PythonCAD/Generic/nurbs.py0000644000175000017500000001627511307666657020055 0ustar matteomatteo# # Copyright (c) 2003 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # NURBS curves import array class Nurb(object): def __init__(self, ctrlpts, knots, order): if not isinstance(ctrlpts, list): raise TypeError, "Invalid control point list: " + str(ctrlpts) if not isinstance(knots, list): raise TypeError, "Invalid knot list: " + str(knots) if not isinstance(order, int): raise TypeError, "Invalid order; " + str(order) if order < 2 or order > 16: # what is a good max value? raise ValueError, "Invalid order: %d" % order _ctrlpts = [] for _pt in ctrlpts: if not isinstance(_pt, tuple): raise TypeError, "Invalid control point: " + str(_pt) _len = len(_pt) if not (1 < _len < 4): raise ValueError, "Invalid tuple length: " + str(_pt) if _len == 2: _x, _y = _pt _w = 1.0 else: _x, _y, _w = _pt if not isinstance(_x, float): _x = float(_x) if not isinstance(_y, float): _y = float(_y) if not isinstance(_w, float): _w = float(_w) if not (_w > 0.0): raise ValueError, "Invalid weight: %g" % _w _ctrlpts.append((_x, _y, _w)) _knots = [] for _knot in knots: if not isinstance(_knot, float): _knot = float(_knot) if (_knot < 0.0 or _knot > 1.0): raise ValueError, "Invalid knot value: %g" % _knot for _val in _knots: if _knot < (_val - 1e-10): raise (ValueError, "Invalid decreasing knot: %g < %g" % (_knot, _val)) _knots.append(_knot) print "knots: " + str(_knots) print "ctrl: " + str(_ctrlpts) print "order: %d" % order _clen = len(_ctrlpts) if _clen < order: raise ValueError, "Order greater than number of control points." if len(_knots) != (_clen + order): raise ValueError, "Knot/Control Point/Order number error." self.__ctrlpts = _ctrlpts self.__knots = _knots self.__order = order def getControlPoints(self): return self.__ctrlpts[:] def getKnots(self): return self.__knots[:] def getOrder(self): return self.__order def calculate(self, count): if not isinstance(count, int): raise TypeError, "Invalid count: " + str(count) _cpts = self.__ctrlpts _knots = self.__knots _dt = 1.0/float(count) _p = self.__order - 1 _pts = [] for _c in range(count): _t = _c * _dt # print "time: %g" % _t _nx = _ny = _nw = 0.0 for _i in range(len(_cpts)): # print "using cpt %d" % _i _x, _y, _w = _cpts[_i] _Ni = self._N(_i, _p, _t) _nx = _nx + (_Ni * _x) _ny = _ny + (_Ni * _y) _nw = _nw + (_Ni * _w) # print "nw: %.3f" % _nw # print "nx: %.3f" % _nx # print "ny: %.3f" % _ny if abs(_nw) > 1e-10: _pts.append((_nx/_nw, _ny/_nw)) else: print "zero weight: %f, %f" % (_nx, _ny) return _pts def _N(self, i, p, t): # print "_N() ..." _flag = False if abs(t - 1.0) < 1e-10 and False: _flag = True if _flag: print "i: %d" % i print "p: %d" % p print "t: %.3f" % t _knots = self.__knots _ki = _knots[i] _kin = _knots[i + 1] if _flag: print "ki: %.3f" % _ki print "kin: %.3f" % _kin if p == 0: if ((_ki - 1e-10) < t < _kin): _val = 1.0 else: _val = 0.0 else: _kip = _knots[i + p] _kipn = _knots[i + p + 1] if _flag: print "kip: %.3f" % _kip print "kipn: %.3f" % _kipn _t1 = 0.0 _v1 = _kip - _ki if abs(_v1) > 1e-10: _v2 = t - _ki if abs(_v2) > 1e-10: _t1 = (_v2/_v1) * self._N(i, (p - 1), t) _t2 = 0.0 _v1 = _kipn - _kin if abs(_v1) > 1e-10: _v2 = _kipn - t if abs(_v2) > 1e-10: _t2 = (_v2/_v1) * self._N((i + 1), (p - 1), t) _val = _t1 + _t2 if _flag: print "val: %f" % _val return _val def writedata(self, count, fname): if not isinstance(count, int): raise TypeError, "Invalid count: " + str(count) _f = file(fname, "w") for _pt in self.calculate(count): _x, _y = _pt _f.write("%f %f\n" % (_x, _y)) _f.close() _f = file('control_points', "w") for _pt in self.getControlPoints(): _x, _y, _w = _pt # ignore weight _f.write("%f %f\n" % (_x, _y)) _f.close() _f = file('knots', "w") for _knot in self.getKnots(): _f.write("%f 0.0\n" % _knot) _f.close() def _NN(self, i, p, t): _cpts = self.__ctrlpts _cl = len(_cpts) _knots = self.__knots _kl = len(_knots) - 1 _val = _kl * [0.0] # # calculate values for 0 # for _i in range(_kl): if ((_knots[i] - 1e-10) < t < _knots[i + 1]): _val[_i] = 1.0 # # calculate values up to the degree # for _j in range(1, (p + 1)): for _i in range(_kl - _j): _ki = _knots[_i] _kin = _knots[_i + 1] _kip = _knots[_i + p] _kipn = _knots[_i + p + 1] _t1 = 0.0 _n = _val[_i] if abs(_n) > 1e-10: _v1 = _kip - _ki if abs(_v1) > 1e-10: _v2 = t - _ki if abs(_v2) > 1e-10: _t1 = (_v2/_v1) * _n _t2 = 0.0 _n = _val[_i + 1] if abs(_n) > 1e-10: _v1 = _kipn - _kin if abs(_v1) > 1e-10: _v2 = _kipn - t if abs(_v2) > 1e-10: _t2 = (_v2/_v1) * _n _val[_i] = _t1 + _t2 PythonCAD-DS1-R37/PythonCAD/Generic/globals.py0000644000175000017500000000146011307666657020335 0ustar matteomatteo# # Copyright (c) 2002, Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # a module for common global variables # pass PythonCAD-DS1-R37/PythonCAD/Generic/dwg1314.py0000644000175000017500000053304711307666657020017 0ustar matteomatteo# # Copyright (c) 2003 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # read in an AutoCAD dwg file # import struct import array import sys from PythonCAD.Generic import dwgbase from PythonCAD.Generic import dwgutil r14 = False # ugh, a global variable ... def dump_info(handle): global r14 _offsets = {} handle.seek(0, 0) # start of file _buf = handle.read(6) if _buf == 'AC1012': print "Autocad 13 format" elif _buf== 'AC1014': print "Autocad 14 format" r14 = True else: print "unknown format" return # print "offset at %#x" % handle.tell() _buf = array.array('B') _buf.fromfile(handle, 7) # if _buf[0] != 0: # print "buf[0] != 0" # if _buf[1] != 0: # print "buf[1] != 0" # if _buf[2] != 0: # print "buf[2] != 0" # if _buf[3] != 0: # print "buf[3] != 0" # if _buf[4] != 0: # print "buf[4] != 0" # if _buf[5] != 0: # ACADMAINTVER in Autocad 14 # print "buf[5] != 0" # if _buf[6] != 1: # print "buf[6] != 1" print "offset at %#x" % handle.tell() # # ub1 and ub2 are unknown bytes # _image_seeker, _ub1, _ub2 = struct.unpack(' %s" % (_key, str(_hmap[_key])) # # read class section # print "reading class data ..." _offset = _offsets['CLASS'] _size = _sizes['CLASS'] _class_data = read_class(handle, _offset, _size) print "class data offset: %d [%#x]" % (_offset, _offset) print "read %d bytes" % _size _cmap = decode_class_data(_class_data) # # read object section # print "reading object map data ..." _offset = _offsets['OBJECT_MAP'] _size = _sizes['OBJECT_MAP'] _sections = read_object_map(handle, _offset, _size) _objmap = decode_object_map(_sections) # # read the objects from the object map # _objects = read_objects(handle, _objmap, _cmap) # # read unknown section # print "reading unknown section ..." _offset = _offsets['R14_UNKNOWN'] _size = _sizes['R14_UNKNOWN'] # apparently always 53 ... handle.seek(_offset, 0) _unknown_data = handle.read(_size) # # read second header - apparently this starts immediately # following the unknown section ... # print "reading second header ..." _offset = handle.tell() _second_data = read_second_header(handle, _offset) _second_map = decode_second_header(_second_data) def initialize_dwg(dwg): _handle = dwg.getHandle() _handle.seek(0, 0) _buf = _handle.read(6) if _buf != 'AC1012': if _buf != 'AC1014': raise ValueError, "File not R13/R14 DWG format" _handle.seek(7, 1) # padding and a revision byte _offset = struct.unpack('h', _handle.read(2))[0] # big-endian size if _size == 2: # section is just CRC break _data.fromfile(_handle, _size) # # the spec says 'last_handle' and 'last_loc' are initialized outside # the outer for loop - postings on OpenDWG forum say these variables # must be initialized for each section # _last_handle = 0 _last_loc = 0 _bitpos = 0 _bitmax = (_size - 2) * 8 # remove two bytes for section CRC # # there should be something done with the CRC for section ... # while _bitpos < _bitmax: _bitpos, _hoffset = dwgutil.get_modular_char(_data, _bitpos) _last_handle = _last_handle + _hoffset _bitpos, _foffset = dwgutil.get_modular_char(_data, _bitpos) _last_loc = _last_loc + _foffset dwg.addEntityOffset(_last_handle, _last_loc) def r1314_read_objects(dwg): global r14 _version = dwg.getVersion() if _version == 'R14': r14 = True _handle = dwg.getHandle() _offset, _size = dwg.getOffset('OBJECTS') _sections = read_object_map(_handle, _offset, _size) _omap = decode_object_map(_sections) _classes = dwg.getClassKeys() _cmap = {} for _class in _classes: _cmap[_class] = dwg.getClass(_class) for _obj in read_objects(_handle, _omap, _cmap): dwg.setObject(_obj) def read_object_map(handle, offset, size): # print "read_object_map() ..." handle.seek(offset, 0) _at = handle.tell() # print "offset at %d [%#x]" % (_at, _at) _read = True _sections = [] while _read: # print "reading section ..." _secdata = array.array('B') _size = struct.unpack('>h', handle.read(2))[0] # print "section size: %d" % _size if _size == 2: _read = False _secdata.fromfile(handle, _size) _sections.append(_secdata) return _sections def decode_object_map(seclist): _map = {} # # the spec says 'last_handle' and 'last_loc' are initialized outside # the outer for loop - postings on OpenDWG forum say these variables # must be initialized for each section # _i = 0 for _sec in seclist: _last_handle = 0 _last_loc = 0 _bitpos = 0 _seclen = len(_sec) if _seclen == 2: # section of just CRC break _bitmax = (_seclen - 2) * 8 # remove two bytes for section CRC while _bitpos < _bitmax: # print "i: %d" % _i # print "bitpos: %d" % _bitpos _bitpos, _hoffset = dwgutil.get_modular_char(_sec, _bitpos) # print "hoffset: %d" % _hoffset _last_handle = _last_handle + _hoffset # print "last_handle: %d [%#x]" % (_last_handle, _last_handle) # print "bitpos: %d" % _bitpos _bitpos, _foffset = dwgutil.get_modular_char(_sec, _bitpos) # print "foffset: %d" % _foffset _last_loc = _last_loc + _foffset # print "last loc: %d [%#x]" % (_last_loc, _last_loc) _map[_i] = (_last_handle, _foffset, _last_loc) # print "object: %d; mapping: %s" % (_i, str(_map[_i])) # print "bitpos before incrementing i: %d" % _bitpos _i = _i + 1 return _map # # read the common parts at the start of an entity def header_read(ent, data, offset): _bitpos = offset _mode = dwgutil.get_bits(data, 2, _bitpos) _bitpos = _bitpos + 2 ent.setMode(_mode) _bitpos, _rnum = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_rnum) _bitpos, _islayer = dwgutil.test_bit(data, _bitpos) ent.setIsLayerByLinetype(_islayer) _bitpos, _nolinks = dwgutil.test_bit(data, _bitpos) ent.setNoLinks(_nolinks) _bitpos, _color = dwgutil.get_bit_short(data, _bitpos) ent.setColor(_color) _bitpos, _ltscale = dwgutil.get_bit_double(data, _bitpos) ent.setLinetypeScale(_ltscale) _bitpos, _invis = dwgutil.get_bit_short(data, _bitpos) ent.setInvisiblity(_invis) return _bitpos # # read the common parts at the end of many entities # def tail_read(ent, data, offset): _bitpos = offset if ent.getMode() == 0x0: _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setSubentity(_handle) for _i in range(ent.getNumReactors()): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setLayer(_handle) if ent.getIsLayerByLinetype() is False: _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setLinetype(_handle) if ent.getNoLinks() is False: _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setPrevious(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setNext(_handle) return _bitpos # # read the various entities stored in the DWG file # def text_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('insertion_point', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('alignment_point', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('oblique_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('rotation_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('height', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('width', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('generation', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('halign', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('valign', _val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('style_handle', _handle) def attrib_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('insertion_point', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('alignment_point', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('oblique_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('rotation_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('height', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('width', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('generation', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('halign', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('valign', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('tag', _text) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('field_length', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('style_handle', _handle) def attdef_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('insertion_point', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('alignment_point', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('oblique_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('rotation_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('height', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('width', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('generation', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('halign', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('valign', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('tag', _text) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('field_length', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('prompt', _text) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('style_handle', _handle) def block_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos = tail_read(ent, data, _bitpos) def endblk_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos = tail_read(ent, data, _bitpos) def seqend_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos = tail_read(ent, data, _bitpos) def insert_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('insertion_point', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('scale', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('rotation', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _hasattr = dwgutil.test_bit(data, _bitpos) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('block_header_handle', _handle) if _hasattr: _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_attrib_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_attrib_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('seqend_handle', _handle) def minsert_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('insertion_point', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('scale', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('rotation', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _hasattr = dwgutil.test_bit(data, _bitpos) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('column_count', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('row_count', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('column_spacing', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('row_spacing', _val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('block_header_handle', _handle) if _hasattr: _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_attrib_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_attrib_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('seqend_handle', _handle) def vertex2d_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos, _sw = dwgutil.get_bit_double(data, _bitpos) if _sw < 0.0: _sw = _ew = abs(_sw) else: _bitpos, _ew = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('start_width', _sw) ent.setEntityData('end_width', _ew) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('bulge', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('tangent_dir', _val) _bitpos = tail_read(ent, data, _bitpos) def vertex3d_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def vertex_mesh_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def vertex_pface_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def vertex_pface_face_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _v1 = dwgutil.get_bit_short(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_short(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_short(data, _bitpos) _bitpos, _v4 = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('points', (_v1, _v2, _v3, _v4)) _bitpos = tail_read(ent, data, _bitpos) def polyline2d_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('curve_type', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('start_width', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('end_width', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('seqend_handle', _handle) def polyline3d_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('spline_flags', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('closed_flags', _val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('seqend_handle', _handle) def arc_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('center', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('radius', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('start_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('end_angle', _val) _bitpos = tail_read(ent, data, _bitpos) def circle_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('center', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('radius', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def line_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('p1', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('p2', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def dimord_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('text_rotation', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_dir', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _val) _bitpos, _v1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_v1, _v2)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_v1, _v2, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('13-pt', (_v1, _v2, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('14-pt', (_v1, _v2, _v3)) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags2', _val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def dimlin_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('text_rotation', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_dir', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _val) _bitpos, _v1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_v1, _v2)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_v1, _v2, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('13-pt', (_v1, _v2, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('14-pt', (_v1, _v2, _v3)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ext_ln_rotation', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('dimension_rotation', _val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def dimalign_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('text_rotation', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_dir', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _val) _bitpos, _v1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_v1, _v2)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_v1, _v2, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('13-pt', (_v1, _v2, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('14-pt', (_v1, _v2, _v3)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ext_ln_rotation', _val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def dimang3p_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('text_rotation', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_dir', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _val) _bitpos, _v1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_v1, _v2)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_v1, _v2, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('13-pt', (_v1, _v2, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('14-pt', (_v1, _v2, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('15-pt', (_v1, _v2, _v3)) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def dimang2l_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('text_rotation', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_dir', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _val) _bitpos, _v1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_v1, _v2)) _bitpos, _v1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('16-pt', (_v1, _v2)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('13-pt', (_v1, _v2, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('14-pt', (_v1, _v3, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('15-pt', (_v1, _v2, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_v1, _v2, _v3)) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def dimrad_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('text_rotation', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_dir', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _val) _bitpos, _v1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_v1, _v2)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_v1, _v2, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('15-pt', (_v1, _v2, _v3)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('leader_length', _val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def dimdia_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('text_midpoint', (_x, _y)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('text_rotation', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('horiz_dir', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_scale', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ins_rotation', _val) _bitpos, _v1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('12-pt', (_v1, _v2)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('10-pt', (_v1, _v2, _v3)) _bitpos, _v1 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v2 = dwgutil.get_bit_double(data, _bitpos) _bitpos, _v3 = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('15-pt', (_v1, _v2, _v3)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('leader_length', _val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('anon_block_handle', _handle) def point_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('x_axis_angle', _val) _bitpos = tail_read(ent, data, _bitpos) def face3d_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('corner1', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('corner2', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('corner3', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('corner4', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('flags', _val) _bitpos = tail_read(ent, data, _bitpos) def pface_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('vertex_count', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('face_count', _val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('seqend_handle', _handle) def mesh_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('curve_type', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('m_verticies', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('n_verticies', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('m_density', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('n_density', _val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_vertex_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('seqend_handle', _handle) def solid_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner1', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner2', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner3', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner4', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def trace_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _bitpos, _elev = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _elev) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner1', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner2', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner3', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner4', (_x, _y, _elev)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def shape_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('insertion_point', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('scale', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('rotation', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('width', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('oblique', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('shape_number', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('shapefile_handle', _handle) def viewport_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('center', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('width', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('height', _val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('vport_entity_handle', _handle) def ellipse_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('center', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('major_axis_vector', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('axis_ratio', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('start_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('end_angle', _val) _bitpos = tail_read(ent, data, _bitpos) def spline_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _sc = dwgutil.get_bit_short(data, _bitpos) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('degree', _val) _nknots = _nctlpts = _nfitpts = 0 _weight = False if _sc == 2: _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('fit_tolerance', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('begin_tan_vector', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('end_tan_vector', (_x, _y, _z)) _bitpos, _nfitpts = dwgutil.get_bit_short(data, _bitpos) elif _sc == 1: _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('rational', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('closed', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('periodic', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('knot_tolerance', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('control_tolerance', _val) _bitpos, _nknots = dwgutil.get_bit_long(data, _bitpos) _bitpos, _nctlpts = dwgutil.get_bit_long(data, _bitpos) _bitpos, _weight = dwgutil.test_bit(data, _bitpos) else: raise ValueError, "Unexpected scenario: %d" % _sc if _nknots: _knots = [] for _i in range(_nknots): _bitpos, _knot = dwgutil.get_bit_double(data, _bitpos) _knots.append(_knot) ent.setEntityData('knot_points', _knots) if _nctlpts: _ctrlpts = [] _weights = [] for _i in range(_nctlpts): _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) _ctrlpts.append((_x, _y, _z)) if _weight: _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) _weights.append(_val) ent.setEntityData('control_points', _ctrlpts) ent.setEntityData('weights', _weights) if _nfitpts: _fitpts = [] for _i in range(_nfitpts): _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) _fitpts.append((_x, _y, _z)) ent.setEntityData('fit_points', _fitpts) _bitpos = tail_read(ent, data, _bitpos) def rsb_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _itype = dwgutil.get_bit_short(data, _bitpos) if (_itype == 64): _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) _bitpos, _cib = dwgutil.get_bit_long(data, _bitpos) _data = [] while (_cib != 0): _chars = [] for _i in range(_cib): _bitpos, _ch = dwgutil.get_raw_char(data, _bitpos) if (0x20 < _ch < 0x7e): _sat = 0x9f - _ch elif (_ch == ord("\t")): _sat = ord(" ") else: _sat = _ch _chars.append(_sat) _data.append("".join(_chars)) _bitpos, _cib = dwgutil.get_bit_long(data, _bitpos) else: raise ValueError, "Unexpected itemtype: %d" % _itype # # OpenDWG specs say there is stuff here but they haven't # figured it out, plus there is the tailing handles # skip this for now ... # _bitpos = tail_read(ent, data, _bitpos) def ray_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('vector', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def xline_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('point', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('vector', (_x, _y, _z)) _bitpos = tail_read(ent, data, _bitpos) def dict_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_short(data, _bitpos) _bitpos, _ni = dwgutil.get_bit_long(data, _bitpos) if ent.getVersion() == 'R14': _bitpos, _u = dwgutil.get_raw_char(data, _bitpos) if _ni: _strings = [] for _i in range(_ni): _bitpos, _text = dwgutil.get_text_string(data, _bitpos) _strings.append(_text) ent.setEntityData('strings', _strings) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ni: _items = [] for _i in range(_ni): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _items.append(_handle) ent.setEntityData('items', _items) def mtext_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('insertion_point', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('x_axis_dir', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('width', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('height', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('attachment', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('drawing_dir', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ext_height', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('ext_width', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('text', _text) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('style_handle', _handle) def leader_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.test_bit(data, _bitpos) # unknown _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('annotation_type', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('path_type', _val) _bitpos, _npts = dwgutil.get_bit_short(data, _bitpos) _points = [] for _i in range(_npts): _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) _points.append((_x, _y, _z)) ent.setEntityData('points', _points) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('end_pt_proj', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('x_direction', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('offset_block_insp_pt', (_x, _y, _z)) # # the following unknown is only in R14 ... # if ent.getVersion() == 'R14': _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('dimgap', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('box_height', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('box_width', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('hooklineoxdir', _val) # ??? _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('arrowhead_on', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('arrowhead_type', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('dimasz',_val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) # unknown _bitpos, _val = dwgutil.test_bit(data, _bitpos) # unknown _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) # unknown _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('by_block_color', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) # unknown _bitpos, _val = dwgutil.test_bit(data, _bitpos) # unknown _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('associated_annotation_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) def tolerance_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) # unknown _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('height', _val) _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('dimgap', _val) # maybe not??? _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('insertion_point', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('x_direction', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) # should this be text_string? ent.setEntityData('text', _val) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_handle', _handle) def mline_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('scale', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('justification', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('base_point', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('open_closed', _val) _bitpos, _lis = dwgutil.get_raw_char(data, _bitpos) _bitpos, _nv = dwgutil.get_bit_short(data, _bitpos) _points = [] for _i in range(_nv): _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) _vertex = (_x, _y, _z) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y= dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) _direction = (_x, _y, _z) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) _miter_dir = (_x, _y, _z) _lines = [] for _j in range(_lis): _bitpos, _ns = dwgutil.get_bit_short(data, _bitpos) _segparms = [] for _k in range(_ns): _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) _segparms.append(_val) _bitpos, _na = dwgutil.get_bit_short(data, _bitpos) _fillparms = [] for _k in range(_na): _bitpos, _afp = dwgutil.get_bit_double(data, _bitpos) _fillparms.append(_afp) _lines.append((_segparms, _fillparms)) _points.append((_vertex, _direction, _miter_dir, _lines)) ent.setEntityData('points', _points) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('mline_style_handle', _handle) def block_control_reader(ent, data, offset): _bitpos = offset _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_val) _bitpos, _enum = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _enum: _handles = [] for _i in range(_enum): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('code_2_handles', _handles) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('*model_space_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('*paper_space_handle', _handle) def block_header_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('anonymous', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('has_attrs', _val) _bitpos, _bxref = dwgutil.test_bit(data, _bitpos) ent.setEntityData('blk_is_xref', _bxref) _bitpos, _xover = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xrefoverlaid', _xover) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('base_point', (_x, _y, _z)) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('xref_pname', _text) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('block_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('block_handle', _handle) if not _bxref and not _xover: _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('first_entity_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('last_entity_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('endblk_handle', _handle) def layer_control_reader(ent, data, offset): _bitpos = offset _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_val) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('code_2_handles', _handles) def layer_reader(ent, data, offset): _bitpos = offset _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('frozen', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('on', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('frz_in_new', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('locked', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('color', _val) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('layer_control_handle', _handle) for _i in range(ent.getNumReactors()): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('linetype', _handle) def shapefile_control_reader(ent, data, offset): _bitpos = offset _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_val) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('shapefile_handles', _handles) def shapefile_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('vertical', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('shape_file', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('fixed_height', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('fixed_width', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('oblique_angle', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('generation', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('last_height', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('font_name', _text) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('big_font_name', _text) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('shapefile_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) def linetype_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('code_2_handles', _handles) def linetype_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('description', _text) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('pattern_length', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('alignment', _val) _bitpos, _nd = dwgutil.get_raw_char(data, _bitpos) if _nd: _dashes = [] for _i in range(_nd): _bitpos, _dl = dwgutil.get_bit_double(data, _bitpos) _bitpos, _cs = dwgutil.get_bit_short(data, _bitpos) _bitpos, _xo = dwgutil.get_raw_double(data, _bitpos) _bitpos, _yo = dwgutil.get_raw_double(data, _bitpos) _bitpos, _scale = dwgutil.get_bit_double(data, _bitpos) _bitpos, _rot = dwgutil.get_bit_double(data, _bitpos) _bitpos, _sf = dwgutil.get_bit_short(data, _bitpos) _dashes.append((_dl, _cs, _xo, _yo, _scale, _rot, _sf)) ent.setEntityData('dashes', _dashes) _strings = dwgutil.get_bits(data, 256, _bitpos) # unknown ? _bitpos = _bitpos + 256 _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('ltype_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) def view_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('view_handles', _handles) def view_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_height', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_width', _val) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('view_center', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('target', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_dir', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('twist_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('lens_length', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('front_clip', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('back_clip', _val) _val = dwgutil.get_bits(data, 4, _bitpos) _bitpos = _bitpos + 4 ent.setEntityData('view_control_flags', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('pspace_flag', _val) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('view_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) def ucs_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('ucs_handles', _handles) def ucs_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('origin', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('x_direction', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('y_direction', (_x, _y, _z)) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('ucs_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) def vport_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('vport_handles', _handles) def vport_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_height', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('aspect_ratio', _val) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('view_center', (_x, _y)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('target', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('view_dir', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('twist_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('lens_length', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('front_clip', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('back_clip', _val) _val = dwgutil.get_bits(data, 4, _bitpos) _bitpos = _bitpos + 4 ent.setEntityData('vport_flags', _val) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('lower_left', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('upper_right', (_x, _y)) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('ucsfollow', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('circle_zoom', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('fast_zoom', _val) _val = dwgutil.get_bits(data, 2, _bitpos) _bitpos = _bitpos + 2 ent.setEntityData('ucsicon', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('grid_status', _val) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('grid_spacing', (_x, _y)) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('snap_status', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('snap_style', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('snap_isopair', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('snap_rotation', _val) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('snap_base', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('snap_spacing', (_x, _y)) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('vport_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) def appid_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('appid_handles', _handles) def appid_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('appid_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) def dimstyle_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('dimstyle_handles', _handles) def dimstyle_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMTOL', _val) _bitpos, _flag = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMLIM', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMTIH', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMTOH', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMSE1', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMSE2', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMALT', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMTOFL', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMSAH', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMTIX', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMSOXD', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('DIMALTD', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('DIMZIN', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMSD1', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMSD2', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('DIMTOLJ', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('DIMJUST', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('DIMFIT', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('DIMUPT', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('DIMTZIN', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('DIMALTZ', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('DIMALTTZ', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('DIMTAD', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMUNIT', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMAUNIT', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMDEC', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMTDEC', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMALTU', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMALTTD', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMSCALE', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMASZ', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMEXO', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMDLI', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMEXE', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMAND', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMDLE', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMTP', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMTM', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMTXT', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMCEN', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMTSZ', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMALTF', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMLFAC', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMTVP', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMTFAC', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('DIMGAP', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('DIMPOST', _text) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('DIMAPOST', _text) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('DIMBLK', _text) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('DIMBLK1', _text) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('DIMBLK2', _text) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMCLAD', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMCLRE', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('DIMCLRT', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) # unknown _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('dimstyle_control_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('shapefile_handle', _handle) def vpentity_control_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_short(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('vpentity_handles', _handles) def vpentity_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('64-flag', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('xrefplus', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('xdep', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('1-flag', _val) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('vpentity_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('null_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('next_vpentity_handle', _handle) def group_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('unnamed', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('selectable', _val) _bitpos, _nh = dwgutil.get_bit_long(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _nh: _handles = [] for _i in range(_nh): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('entry_handles', _handles) def mlinestyle_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('description', _text) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('flags', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('fill_color', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('start_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('end_angle', _val) _bitpos, _lc = dwgutil.get_raw_char(data, _bitpos) if _lc: _lines = [] for _i in range(_lc): _bitpos, _offset = dwgutil.get_bit_double(data, _bitpos) _bitpos, _color = dwgutil.get_bit_short(data, _bitpos) _bitpos, _ltindex = dwgutil.get_bit_short(data, _bitpos) _lines.append((_offset, _color, _ltindex)) ent.setEntityData('lines', _lines) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) def dictionaryvar_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('intval', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) # spec says bit short _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) def hatch_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('z_coord', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('name', _text) _bitpos, _solid_fill = dwgutil.test_bit(data, _bitpos) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('associative', _val) _bitpos, _np = dwgutil.get_bit_long(data, _bitpos) _allbounds = 0 _pixel = 0 _paths = [] for _i in range(_np): _bitpos, _pf = dwgutil.get_bit_long(data, _bitpos) if _pf & 0x4: _pixel = _pixel + 1 if (_pf & 0x2): # POLYLINE _bitpos, _bulges = dwgutil.test_bit(data, _bitpos) _bitpos, _closed = dwgutil.test_bit(data, _bitpos) _bitpos, _nps = dwgutil.get_bit_long(data, _bitpos) _segs = [] for _j in range(_nps): _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) _bulge = None if (_bulges): _bitpos, _bulge = dwgutil.get_bit_double(data, _bitpos) _segs.append((_x, _y, _bulge)) _paths.append(('polyline', _segs)) else: _bitpos, _nps = dwgutil.get_bit_long(data, _bitpos) _segs = [] for _j in range(_nps): _bitpos, _pts = dwgutil.get_raw_char(data, _bitpos) if (_pts == 1): # LINE _bitpos, _x1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y1 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _x2 = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y2 = dwgutil.get_raw_double(data, _bitpos) _segs.append(('line', _x1, _y1, _x2, _y2)) elif (_pts == 2): # CIRCULAR ARC _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) _bitpos, _r = dwgutil.get_bit_double(data, _bitpos) _bitpos, _sa = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ea = dwgutil.get_bit_double(data, _bitpos) _bitpos, _isccw = dwgutil.test_bit(data, _bitpos) _segs.append(('arc', _x, _y, _r, _sa, _ea, _isccw)) elif (_pts == 3): # ELLIPTICAL ARC _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) _bitpos, _xe = dwgutil.get_raw_double(data, _bitpos) _bitpos, _ye = dwgutil.get_raw_double(data, _bitpos) _bitpos, _ratio = dwgutil.get_bit_double(data, _bitpos) _bitpos, _sa = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ea = dwgutil.get_bit_double(data, _bitpos) _bitpos, _isccw = dwgutil.test_bit(data, _bitpos) _segs.append(('elliptical_arc', _x, _y, _xe, _ye, _ratio, _sa, _ea, _isccw)) elif (_pts == 4): # SPLINE _bitpos, _deg = dwgutil.get_bit_long(data, _bitpos) _bitpos, _israt = dwgutil.test_bit(data, _bitpos) _bitpos, _isper = dwgutil.test_bit(data, _bitpos) _bitpos, _nknots = dwgutil.get_bit_long(data, _bitpos) _bitpos, _nctlpts = dwgutil.get_bit_long(data, _bitpos) _knots = [] for _k in range(_nknots): _bitpos, _knot = dwgutil.get_bit_double(data, _bitpos) _knots.append(_knot) _ctlpts = [] for _k in range(_nctlpts): _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) _weight = None if (_israt): _bitpos, _weight = dwgutil.get_bit_double(data, _bitpos) _ctlpts.append((_x, _y, _weight)) _segs.append(('spline', _israt, _isper, _knots, _ctlpts)) else: raise ValueError, "Unexpected path type: %d" % _pts _paths.append(('stdpath', _segs)) _bitpos, _nbh = dwgutil.get_bit_long(data, _bitpos) _allbounds = _allbounds + _nbh _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('style', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('pattern_type', _val) if not _solid_fill: _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('fill_angle', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('fill_scale_or_spacing', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('file_doublehatch', _val) _bitpos, _ndf = dwgutil.get_bit_short(data, _bitpos) _lines = [] for _i in range(_ndf): _bitpos, _angle = dwgutil.get_bit_double(data, _bitpos) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _xo = dwgutil.get_bit_double(data, _bitpos) _bitpos, _yo = dwgutil.get_bit_double(data, _bitpos) _bitpos, _nds = dwgutil.get_bit_short(data, _bitpos) _dashes = [] for _j in range(_nds): _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('dashlength', _val) _lines.append((_angle, _x, _y, _xo, _yo, _dashes)) ent.setEntityData('fill_lines', _lines) if _pixel: _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('pixel_size', _val) _bitpos, _nsp = dwgutil.get_bit_long(data, _bitpos) if _nsp: _points = [] for _i in range(_nsp): _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) _points.append((_x, _y)) ent.setEntityData('seed_points', _points) for _i in range(ent.getNumReactors()): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('layer_handle', _handle) if ent.getIsLayerByLinetype() is False: _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('linetype_handle', _handle) if ent.getNoLinks() is False: _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setPrevious(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setNext(_handle) _bounds = [] for _i in range(_allbounds): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _bounds.append(_handle) if len(_bounds): ent.setEntityData('boundary_handles', _bounds) def idbuffer_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) # unknown _bitpos, _nids = dwgutil.get_bit_long(data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _nids: _handles = [] for _i in range(_nids): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('objid_handles', _handles) def image_reader(ent, data, offset): _bitpos = offset _bitpos = header_read(ent, data, _bitpos) _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('class_version', _val) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('pt0', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('uvec', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('vvec', (_x, _y, _z)) _bitpos, _val = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('height', _val) _bitpos, _val = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('width', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('display_props', _val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('clipping', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('brightness', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('contrast', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('fade', _val) _bitpos, _cbt = dwgutil.get_bit_short(data, _bitpos) if (_cbt == 1): _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner1', (_x, _y)) _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('corner2', (_x, _y)) else: _bitpos, _ncv = dwgutil.get_bit_long(data, _bitpos) if _ncv: _verts = [] for _i in range(_ncv): _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) _verts.append((_x, _y)) ent.setEntityData('vertices', _verts) _bitpos = tail_read(ent, data, _bitpos) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('imagedef_handle', _handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('imagedef_reactor_handle', _handle) def imagedef_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('class_version', _val) _bitpos, _val = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('width', _val) _bitpos, _val = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('height', _val) _bitpos, _text = dwgutil.get_text_string(data, _bitpos) ent.setEntityData('filepath', _text) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setEntityData('is_loaded', _val) _bitpos, _val = dwgutil.get_raw_char(data, _bitpos) ent.setEntityData('res_units', _val) _bitpos, _val = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('pixel_width', _val) _bitpos, _ph = dwgutil.get_raw_double(data, _bitpos) ent.setEntityData('pixel_height', _val) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) def imagedefreactor_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('class_version', _val) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) def layer_index_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('timestamp1', _val) _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('timestamp2', _val) _bitpos, _ne = dwgutil.get_bit_long(data, _bitpos) if _ne: _indicies = [] for _i in range(_ne): _bitpos, _il = dwgutil.get_bit_long(data, _bitpos) _bitpos, _is = dwgutil.get_text_string(data, _bitpos) _indicies.append((_il, _is)) ent.setEntityData('index_handles', _indicies) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('entry_handles', _handles) def lwpline_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setIsLayerByLinetype(_val) _bitpos, _val = dwgutil.test_bit(data, _bitpos) ent.setNoLinks(_val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setColor(_val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setLinetypeScale(_val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setInvisiblity(_val) _bitpos, _flag = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('flag', _flag) _val = 0.0 if (_flag & 0x4): _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('const_width', _val) _val = 0.0 if (_flag & 0x8): _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('elevation', _val) _val = 0.0 if (_flag & 0x2): _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('thickness', _val) _x = _y = _z = 0.0 if (_flag & 0x1): _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('normal', (_x, _y, _z)) _bitpos, _np = dwgutil.get_bit_long(data, _bitpos) _nb = 0 if (_flag & 0x10): _bitpos, _nb = dwgutil.get_bit_long(data, _bitpos) _nw = 0 if (_flag & 0x20): _bitpos, _nw = dwgutil.get_bit_long(data, _bitpos) if _np: _points = [] for _i in range(_np): _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) _points.append((_x, _y)) ent.setEntityData('points', _points) if _nb: _bulges = [] for _i in range(_nb): _bitpos, _val = dwgutil.get_raw_double(data, _bitpos) _bulges.append(_val) ent.setEntityData('bulges', _bulges) if _nw: _widths = [] for _i in range(_nw): _bitpos, _sw = dwgutil.get_bit_double(data, _bitpos) _bitpos, _ew = dwgutil.get_bit_double(data, _bitpos) _widths.append((_sw, _ew)) ent.setEntityData('widths', _widths) _bitpos = tail_read(ent, data, _bitpos) def rastervariables_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('class_version', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('dispfrm', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('dispqual', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('units', _val) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) def sortentstable_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ne = dwgutil.get_bit_long(data, _bitpos) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('sort_handles', _handles) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactor(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) # # the spec says there is an owner handle here # # _bitpos, _handle = dwgutil.get_handle(data, _bitpos) # print "owner handle: " + str(_handle) if _ne: _handles = [] for _i in range(_ne): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) _handles.append(_handle) ent.setEntityData('obj_handles', _handles) def spatial_filter_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _npts = dwgutil.get_bit_short(data, _bitpos) if _npts: _points = [] for _i in range(_npts): _bitpos, _x = dwgutil.get_raw_double(data, _bitpos) _bitpos, _y = dwgutil.get_raw_double(data, _bitpos) _points.append((_x, _y)) ent.setEntityData('points', _points) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('extrusion', (_x, _y, _z)) _bitpos, _x = dwgutil.get_bit_double(data, _bitpos) _bitpos, _y = dwgutil.get_bit_double(data, _bitpos) _bitpos, _z = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('clip_bound_origin', (_x, _y, _z)) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('disp_bound', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('front_clip_on', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('front_dist', _val) _bitpos, _val = dwgutil.get_bit_short(data, _bitpos) ent.setEntityData('back_clip_on', _val) _bitpos, _val = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('back_dist', _val) _invtr = array.array('d', 12 * [0.0]) for _i in range(12): _bitpos, _invtr[_i] = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('inv_array', _invtr) _clptr = array.array('d', 12 * [0.0]) for _i in range(12): _bitpos, _clptr[_i] = dwgutil.get_bit_double(data, _bitpos) ent.setEntityData('clip_array', _clptr) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setEntityData('parent_handle', _handle) for _i in range(_nr): _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.addReactors(_handle) _bitpos, _handle = dwgutil.get_handle(data, _bitpos) ent.setXdicobj(_handle) def spatial_index_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('timestamp1', _val) _bitpos, _val = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('timestamp2', _val) # # fixme - lots of unknown stuff here # ... def xrecord_reader(ent, data, offset): _bitpos = offset _bitpos, _nr = dwgutil.get_bit_long(data, _bitpos) ent.setNumReactors(_nr) _bitpos, _ndb = dwgutil.get_bit_long(data, _bitpos) ent.setEntityData('data_bytes', _ndb) # # fixme - more stuff here ... # _objprops = [ (True, None), # Unused [0x00] (True, text_reader), # Text (True, attrib_reader), # Attrib (True, attdef_reader), # Attdef (True, block_reader), # Block (True, endblk_reader), # Endblk (True, seqend_reader), # Seqend (True, insert_reader), # Insert (True, minsert_reader), # Minsert [0x08] (False, None), # Skipped [0x09] (True, vertex2d_reader), # Vertex_2D (True, vertex3d_reader), # Vertex_3D (True, vertex_mesh_reader), # Vertex_mesh (True, vertex_pface_reader), # Vertex_pface (True, vertex_pface_face_reader), # Vertex_pface_face (True, polyline2d_reader), # Polyline_2D (True, polyline3d_reader), # Polyline_3D [0x10] (True, arc_reader), # Arc, (True, circle_reader), # Circle, (True, line_reader), # Line (True, dimord_reader), # Dimension_ord (True, dimlin_reader), # Dimension_lin (True, dimalign_reader), # Dimension_align (True, dimang3p_reader), # Dimension_angle_3pt (True, dimang2l_reader), # Dimension_angle_2ln [0x18] (True, dimrad_reader), # Dimension_radius (True, dimdia_reader), # Dimension_diameter (True, point_reader), # Point (True, face3d_reader), # Face3D (True, pface_reader), # Polyline_pface (True, mesh_reader), # Polyline_mesh (True, solid_reader), # Solid (True, trace_reader), # Trace [0x20] (True, shape_reader), # Shape (True, viewport_reader), # Viewport (True, ellipse_reader), # Ellipse (True, spline_reader), # Spline (True, rsb_reader), # Region (True, rsb_reader), # Solid3D (True, rsb_reader), # Body (True, ray_reader), # Ray [0x28] (True, xline_reader), # Xline (False, dict_reader), # Dictionary (False, None), # Skipped [0x2b] (True, mtext_reader), # Mtext (True, leader_reader), # Leader (True, tolerance_reader), # Tolerance (True, mline_reader), # Mline (False, block_control_reader), # Block control [0x30] (False, block_header_reader), # Block header (False, layer_control_reader), # Layer control (False, layer_reader), # Layer (False, shapefile_control_reader), # Style control (False, shapefile_reader), # Style (False, None), # Skipped [0x36] (False, None), # Skipped [0x37] (False, linetype_control_reader), # Linetype control [0x38] (False, linetype_reader), # Linetype (False, None), # Skipped [0x3a] (False, None), # Skipped [0x3b] (False, view_control_reader), # View control [0x3c] (False, view_reader), # View (False, ucs_control_reader), # UCS control, (False, ucs_reader), # UCS (False, vport_control_reader), # Vport control [0x40] (False, vport_reader), # Vport (False, appid_control_reader), # Appid control (False, appid_reader), # Appid (False, dimstyle_control_reader), # Dimstyle control (False, dimstyle_reader), # Dimstyle (False, vpentity_control_reader), # VP ENT HDR control (False, vpentity_reader), # VP ENT HDR (False, group_reader), # Group [0x48] (False, mlinestyle_reader), # Mlinestyle ] _vobjmap = { 'DICTIONARYVAR' : dictionaryvar_reader, 'HATCH' : hatch_reader, 'IDBUFFER' : idbuffer_reader, 'IMAGE' : image_reader, 'IMAGEDEF' : imagedef_reader, 'IMAGEDEFREACTOR' : imagedefreactor_reader, 'LAYER_INDEX' : layer_index_reader, 'LWPLINE' : lwpline_reader, # 'OLE2FRAME' : ole2frame_reader, 'RASTERVARIABLES' : rastervariables_reader, 'SORTENTSTABLE' : sortentstable_reader, 'SPATIAL_FILTER' : spatial_filter_reader, 'SPATIAL_INDEX' : spatial_index_reader, 'XRECORD' : xrecord_reader } def read_objects(handle, objmap, cmap): # print "read_objects() ..." # # use the classmap to tie the variable object numbers # to the type of object for use in the vobjmap dict _vmap = {} for _key in cmap.keys(): _type = cmap[_key][3] # classdxfclassname field _vmap[_key] = _type # print "mapping type %d to %s" % (_key, _type) _objkeys = objmap.keys() _objkeys.sort() _objlist = [] for _obj in _objkeys: _ent = dwgbase.dwgEntity() _last_handle, _foffset, _last_loc = objmap[_obj] handle.seek(_last_loc, 0) # use absolete offset _size = dwgbase.get_modular_short(handle) _data = array.array('B') _data.fromfile(handle, _size) # _ent.setEntityData('bitstream', _data) _bitpos = 0 _bitpos, _type = dwgutil.get_bit_short(_data, _bitpos) _ent.setType(_type) # print "bitpos: %d" % _bitpos _bitpos, _handle = dwgutil.get_handle(_data, _bitpos) _ent.setHandle(_handle) # print "bitpos: %d" % _bitpos _eexdata = [] while True: _bitpos, _exsize = dwgutil.get_bit_short(_data, _bitpos) # print "extended data size: %d" % _exsize if _exsize == 0: break # print "bitpos: %d" % _bitpos _bitpos, _handle = dwgutil.get_handle(_data, _bitpos) # print "eed handle: " + str(_handle) _count = 0 _eedata = [] while (_count < _exsize): # print "count: %d" % _count _bitpos, _cb = dwgutil.get_raw_char(_data, _bitpos) # print "code byte: %#x" % _cb _count = _count + 1 if _cb == 0x0: _bitpos, _slen = dwgutil.get_raw_char(_data, _bitpos) _bitpos, _cp = dwgutil.get_raw_short(_data, _bitpos) # print "code page: %d" % _cp _chars = [] for _i in range(_slen): _bitpos, _char = dwgutil.get_raw_char(_data, _bitpos) _chars.append(chr(_char)) _string = "".join(_chars) _eedata.append(_string) _count = _count + 3 + _slen elif _cb == 0x1: raise ValueError, "Invalid EEX code byte: 0x1" elif _cb == 0x2: _bitpos, _char = dwgutil.get_raw_char(_data, _bitpos) if _char == 0x0: _eedata.append("{") elif _char == 0x1: _eedata.append("}") else: raise ValueError, "Unexpected EEX char: %#02x" % _char _count = _count + 1 elif _cb == 0x3: # print "layer table reference" _chars = [] for _i in range(8): _bitpos, _char = dwgutil.get_raw_char(_data, _bitpos) _chars.append(_char) _eedata.append(_chars) _count = _count + 8 elif _cb == 0x4: # print "binary chunk" _bitpos, _len = dwgutil.get_raw_char(_data, _bitpos) _chars = [] for _i in range(_len): _bitpos, _char = dwgutil.get_raw_char(_data, _bitpos) _chars.append(_char) _eedata.append(_chars) _count = _count + 1 + _len elif _cb == 0x5: # print "entity handle reference" _chars = [] for _i in range(8): _bitpos, _char = dwgutil.get_raw_char(_data, _bitpos) _chars.append(_char) _eedata.append(_chars) _count = _count + 8 elif (0xa <= _cb <= 0xd): # print "three doubles" _bitpos, _d1 = dwgutil.get_raw_double(_data, _bitpos) _bitpos, _d2 = dwgutil.get_raw_double(_data, _bitpos) _bitpos, _d3 = dwgutil.get_raw_double(_data, _bitpos) _eedata.append((_d1, _d2, _d3)) _count = _count + 24 elif (0x28 <= _cb <= 0x2a): # print "one double" _bitpos, _d = dwgutil.get_raw_double(_data, _bitpos) _eedata.append(_d) _count = _count + 8 elif _cb == 0x46: # print "short int" _bitpos, _short = dwgutil.get_raw_short(_data, _bitpos) _eedata.append(_short) _count = _count + 2 elif _cb == 0x47: # print "long int" _bitpos, _long = dwgutil.get_raw_long(_data, _bitpos) _eedata.append(_long) print "long: %d" % _long _count = _count + 4 else: raise ValueError, "Unexpected code byte: %#02x" % _cb # # These objects may have the graphics bit # _gflag = False _reader = None if _type < len(_objflags): _gflag, _reader = _objflags[_type] if _gflag: _bitpos, _val = dwgutil.test_bit(_data, _bitpos) # print "graphic flag: " + str(_val) # print "bitpos: %d" % _bitpos if _val is True: _bitpos, _gsize = dwgutil.get_raw_long(_data, _bitpos) # print "graphic data bit size: %d" % _gsize # print "bitpos: %d" % _bitpos _bgsize = _gsize * 8 _gidata = dwgutil.get_bits(_data, _bgsize, _bitpos) _bitpos = _bitpos + _bgsize _ent.setEntityData('graphic_data', _gidata) _bitpos, _objbsize = dwgutil.get_raw_long(_data, _bitpos) # print "object data size in bits: %d" % _objbsize # print "bitpos: %d" % _bitpos if _reader is not None: _reader(_ent, _data, _bitpos) elif _type in _vmap: _stype = _vmap[_type] # print "type: %d => %s" % (_type, _stype) if _stype == 'HATCH': # where is the data kept? _bitpos, _val = dwgutil.test_bit(_data, _bitpos) # print "graphic flag: " + str(_val) if _stype in _vobjmap: _vobjmap[_stype](_ent, _data, _bitpos) else: # print "unhandled object type: %d" % _type pass _objlist.append(_ent) return _objlist def get_object(dwg, offset): _handle = dwg.getHandle() _handle.seek(offset, 0) _size = dwgutil.get_modular_short(_handle) _data = array.array('B') _data.fromfile(_handle, _size) _ent = dwgbase.dwgEntity() # _ent.setEntityData('bitstream', data) # save the bitstream data _ent.setVersion(dwg.getVersion()) _bitpos = 0 _bitpos, _type = dwgutil.get_bit_short(_data, _bitpos) _ent.setType(_type) _bitpos, _handle = dwgutil.get_handle(_data, _bitpos) _ent.setHandle(_handle) _bitpos, _extdata = dwgutil.read_extended_data(_data, _bitpos) _ent.setEntityData('extended_data', _extdata) # # use the objprops table to determine if the _entity # has a graphics bit and the appropriate bitstream # decoding function # _gflag = False _reader = None if _type < len(_objprops): _gflag, _reader = _objprops[_type] if _gflag: _bitpos, _val = dwgutil.test_bit(_data, _bitpos) if _val is True: _bitpos, _size = dwgutil.get_raw_long(_data, _bitpos) _bgsize = _size * 8 _gidata = dwgutil.get_bits(_data, _bgsize, _bitpos) _ent.setEntityData('graphic_data', _gidata) _bitpos = _bitpos + _bgsize _bitpos, _objbsize = dwgutil.get_raw_long(_data, _bitpos) _ent.setEntityData('size_in_bits', _objbsize) if _reader is not None: _reader(_ent, _data, _bitpos) else: _stype = dwg.getDxfName(_type) if _stype is not None: if _stype == 'HATCH': # where is the data kept? _bitpos, _val = dwgutil.test_bit(_data, _bitpos) if _stype in _vobjmap: _vobjmap[_stype](_ent, _data, _bitpos) return _ent def read_second_header(handle, offset): print "read_second_header() ..." handle.seek(offset, 0) _at = handle.tell() print "offset at %d [%#x]" % (_at, _at) _s = array.array('B') _s.fromfile(handle, 16) if _s[0] != 0xd4: raise ValueError, "_s[0] != 0xd4" if _s[1] != 0x7b: raise ValueError, "_s[1] != 0x7b" if _s[2] != 0x21: raise ValueError, "_s[2] != 0x21" if _s[3] != 0xce: raise ValueError, "_s[3] != 0xce" if _s[4] != 0x28: raise ValueError, "_s[4] != 0x28" if _s[5] != 0x93: raise ValueError, "_s[5] != 0x93" if _s[6] != 0x9f: raise ValueError, "_s[6] != 0x9f" if _s[7] != 0xbf: raise ValueError, "_s[7] != 0xbf" if _s[8] != 0x53: raise ValueError, "_s[8] != 0x53" if _s[9] != 0x24: raise ValueError, "_s[9] != 0x24" if _s[10] != 0x40: raise ValueError, "_s[10] != 0x40" if _s[11] != 0x09: raise ValueError, "_s[11] != 0x09" if _s[12] != 0x12: raise ValueError, "_s[12] != 0x12" if _s[13] != 0x3c: raise ValueError, "_s[13] != 0x3c" if _s[14] != 0xaa: raise ValueError, "_s[14] != 0xaa" if _s[15] != 0x01: raise ValueError, "_s[15] != 0x01" # _at = handle.tell() # print "offset at %d [%#x]" % (_at, _at) _size = struct.unpack(' _max: _max = _count _p = _pt return _p def _horizontal_mirror(hy, objlist): for _obj in objlist: _layer = _obj.getParent() if _layer is None: continue _mobj = None if isinstance(_obj, Point): _x, _y = _obj.getCoords() _ym = _y + (2.0 * (hy - _y)) _mp = _test_point(_layer, _x, _ym) elif isinstance(_obj, Segment): _p1, _p2 = _obj.getEndpoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() if ((abs(hy - _p1y) > 1e-10) or (abs(hy - _p2y) > 1e-10)): _y1m = _p1y + (2.0 * (hy - _p1y)) _mp1 = _test_point(_layer, _p1x, _y1m) _y2m = _p2y + (2.0 * (hy - _p2y)) _mp2 = _test_point(_layer, _p2x, _y2m) _mobj = _obj.clone() _mobj.setP1(_mp1) _mobj.setP2(_mp2) elif isinstance(_obj, Arc): _x, _y = _obj.getCenter().getCoords() _ym = _y + (2.0 * (hy - _y)) _mp = _test_point(_layer, _x, _ym) _mobj = _obj.clone() _mobj.setCenter(_mp) _mobj.setStartAngle(360.0 - _obj.getEndAngle()) _mobj.setEndAngle(360.0 - _obj.getStartAngle()) elif isinstance(_obj, (Circle, CCircle)): _x, _y = _obj.getCenter().getCoords() if abs(hy - _y) > 1e-10: _ym = _y + (2.0 * (hy - _y)) _mp = _test_point(_layer, _x, _ym) _mobj = _obj.clone() _mobj.setCenter(_mp) elif isinstance(_obj, HCLine): _x, _y = _obj.getLocation().getCoords() if abs(hy - _y) > 1e-10: _ym = _y + (2.0 * (hy - _y)) _mp = _test_point(_layer, _x, _ym) _mobj = _obj.clone() _mobj.setLocation(_mp) elif isinstance(_obj, VCLine): pass elif isinstance(_obj, ACLine): _angle = _obj.getAngle() if abs(abs(_angle) - 90.0) > 1e-10: # not vertical _x, _y = _obj.getLocation().getCoords() _ym = _y + (2.0 * (hy - _y)) _mp = _test_point(_layer, _x, _ym) _mobj = _obj.clone() if abs(_angle) > 1e-10: # not horizontal _mobj.setAngle(-1.0 * _angle) _mobj.setLocation(_mp) elif isinstance(_obj, CLine): _p1, _p2 = _obj.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() if abs(_x2 - _x1) > 1e-10: # not vertical _ym = _y1 + (2.0 * (hy - _y1)) _mp1 = _test_point(_layer, _x1, _ym) _ym = _y2 + (2.0 * (hy - _y2)) _mp2 = _test_point(_layer, _x2, _ym) _mobj = CLine(_mp1, _mp2) elif isinstance(_obj, Leader): _p1, _p2, _p3 = _obj.getPoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _p3x, _p3y = _p3.getCoords() if (abs(_p1y - hy) > 1e-10 or abs(_p2y - hy) > 1e-10 or abs(_p3y - hy) > 1e-10): _ym = _p1y + (2.0 * (hy - _p1y)) _mp1 = _test_point(_layer, _p1x, _ym) _ym = _p2y + (2.0 * (hy - _p2y)) _mp2 = _test_point(_layer, _p2x, _ym) _ym = _p3y + (2.0 * (hy - _p3y)) _mp3 = _test_point(_layer, _p3x, _ym) _mobj = _obj.clone() _mobj.setP1(_mp1) _mobj.setP2(_mp2) _mobj.setP3(_mp3) elif isinstance(_obj, Polyline): _mobj = _obj.clone() for _i in range(len(_mobj)): _pt = _mobj.getPoint(_i) _x, _y = _pt.getCoords() _ym = _y + (2.0 * (hy - _y)) _mp = _test_point(_layer, _x, _ym) _mobj.setPoint(_i, _mp) else: print "skipping obj: " + `_obj` if _mobj is not None: _layer.addObject(_mobj) def _vertical_mirror(vx, objlist): for _obj in objlist: _layer = _obj.getParent() if _layer is None: continue _mobj = None if isinstance(_obj, Point): _x, _y = _obj.getCoords() _xm = _x + (2.0 * (vx - _x)) _mp = _test_point(_layer, _xm, _y) elif isinstance(_obj, Segment): _p1, _p2 = _obj.getEndpoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() if ((abs(vx - _p1x) > 1e-10) or (abs(vx - _p2x) > 1e-10)): _x1m = _p1x + (2.0 * (vx - _p1x)) _mp1 = _test_point(_layer, _x1m, _p1y) _x2m = _p2x + (2.0 * (vx - _p2x)) _mp2 = _test_point(_layer, _x2m, _p2y) _mobj = _obj.clone() _mobj.setP1(_mp1) _mobj.setP2(_mp2) elif isinstance(_obj, Arc): _x, _y = _obj.getCenter().getCoords() _xm = _x + (2.0 * (vx - _x)) _mp = _test_point(_layer, _xm, _y) _mobj = _obj.clone() _mobj.setCenter(_mp) _mobj.setStartAngle(180.0 - _obj.getEndAngle()) _mobj.setEndAngle(180.0 - _obj.getStartAngle()) elif isinstance(_obj, (Circle, CCircle)): _x, _y = _obj.getCenter().getCoords() if abs(vx - _x) > 1e-10: _xm = _x + (2.0 * (vx - _x)) _mp = _test_point(_layer, _xm, _y) _mobj = _obj.clone() _mobj.setCenter(_mp) elif isinstance(_obj, HCLine): pass elif isinstance(_obj, VCLine): _x, _y = _obj.getLocation().getCoords() if abs(vx - _x) > 1e-10: _xm = _x + (2.0 * (vx - _x)) _mp = _test_point(_layer, _xm, _y) _mobj = _obj.clone() _mobj.setLocation(_mp) elif isinstance(_obj, ACLine): _angle = _obj.getAngle() if abs(_angle) > 1e-10: # not horizontal _x, _y = _obj.getLocation().getCoords() _xm = _x + (2.0 * (vx - _x)) _mp = _test_point(_layer, _xm, _y) _mobj = _obj.clone() if abs(abs(_angle) - 90.0) > 1e-10: # not vertical _mobj.setAngle(-1.0 * _angle) _mobj.setLocation(_mp) elif isinstance(_obj, CLine): _p1, _p2 = _obj.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() if abs(_y2 - _y1) > 1e-10: # not horizontal _xm = _x1 + (2.0 * (vx - _x1)) _mp1 = _test_point(_layer, _xm, _y1) _xm = _x2 + (2.0 * (vx - _x2)) _mp2 = _test_point(_layer, _xm, _y2) _mobj = CLine(_mp1, _mp2) elif isinstance(_obj, Leader): _p1, _p2, _p3 = _obj.getPoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _p3x, _p3y = _p3.getCoords() if (abs(_p1x - vx) > 1e-10 or abs(_p2x - vx) > 1e-10 or abs(_p3x - vx) > 1e-10): _xm = _p1x + (2.0 * (vx - _p1x)) _mp1 = _test_point(_layer, _xm, _p1y) _xm = _p2x + (2.0 * (vx - _p2x)) _mp2 = _test_point(_layer, _xm, _p2y) _xm = _p3x + (2.0 * (vx - _p3x)) _mp3 = _test_point(_layer, _xm, _p3y) _mobj = _obj.clone() _mobj.setP1(_mp1) _mobj.setP2(_mp2) _mobj.setP3(_mp3) elif isinstance(_obj, Polyline): _mobj = _obj.clone() for _i in range(len(_mobj)): _pt = _mobj.getPoint(_i) _x, _y = _pt.getCoords() _xm = _x + (2.0 * (vx - _x)) _mp = _test_point(_layer, _xm, _y) _mobj.setPoint(_i, _mp) else: print "skipping obj: " + `_obj` if _mobj is not None: _layer.addObject(_mobj) def _reflect_point(t1, t2, t3, yint, x, y): # # reflect point in coordinate frame with # origin at mirror line y-intersection, then # convert reflected point back to global # coordinates # _nx = (t1 * x) + (t3 * (y - yint)) _ny = (t3 * x) + (t2 * (y - yint)) + yint return _nx, _ny def _angled_mirror(slope, yint, objlist): _angle = math.atan(slope) # # linear algebra reflection matrix coefficients # if abs(abs(_angle) - 45.0) < 1e-10: _t1 = 0.0 _t2 = 0.0 _t3 = 1.0 else: _cosine = math.cos(_angle) _sine = math.sin(_angle) _t1 = (2.0 * _cosine * _cosine) - 1.0 _t2 = (2.0 * _sine * _sine) - 1.0 _t3 = 2.0 * _cosine * _sine for _obj in objlist: _layer = _obj.getParent() if _layer is None: continue _mobj = None if isinstance(_obj, Point): _x, _y = _obj.getCoords() _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _np = _test_point(_layer, _rx, _ry) elif isinstance(_obj, Segment): _p1, _p2 = _obj.getEndpoints() _x, _y = _p1.getCoords() _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _mp1 = _test_point(_layer, _rx, _ry) _x, _y = _p2.getCoords() _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _mp2 = _test_point(_layer, _rx, _ry) _mobj = _obj.clone() _mobj.setP1(_mp1) _mobj.setP2(_mp2) elif isinstance(_obj, Arc): _x, _y = _obj.getCenter().getCoords() _rcx, _rcy = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _mp = _test_point(_layer, _rcx, _rcy) _ep1, _ep2 = _obj.getEndpoints() _x, _y = _ep1 _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _rtd = 180.0/math.pi _ea = _rtd * math.atan2((_ry - _rcy), (_rx - _rcx)) if _ea < 0.0: _ea = _ea + 360.0 _x, _y = _ep2 _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _sa = _rtd * math.atan2((_ry - _rcy), (_rx - _rcx)) if _sa < 0.0: _sa = _sa + 360.0 _mobj = _obj.clone() _mobj.setCenter(_mp) _mobj.setStartAngle(_sa) _mobj.setEndAngle(_ea) elif isinstance(_obj, (Circle, CCircle)): _x, _y = _obj.getCenter().getCoords() _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _mp = _test_point(_layer, _rx, _ry) _mobj = _obj.clone() _mobj.setCenter(_mp) elif isinstance(_obj, HCLine): _x, _y = _obj.getLocation().getCoords() _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _mp = _test_point(_layer, _rx, _ry) if abs(abs(_angle) - 45.0) < 1e-10: _mobj = VCLine(_mp) else: _xi = (_y - yint)/slope _mang = 180.0/math.pi * math.atan2((_ry - _y), (_rx - _xi)) if _mang < 0.0: _mang = _mang + 360.0 _mobj = ACLine(_mp, _mang) elif isinstance(_obj, VCLine): _x, _y = _obj.getLocation().getCoords() _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _mp = _test_point(_layer, _rx, _ry) if abs(abs(_angle) - 45.0) < 1e-10: _mobj = HCLine(_mp) else: _yi = (slope * _x) + yint _mang = 180.0/math.pi * math.atan2((_ry - _yi), (_rx - _x)) if _mang < 0.0: _mang = _mang + 360.0 _mobj = ACLine(_mp, _mang) elif isinstance(_obj, ACLine): _at45 = False if abs(abs(_angle) - 45.0) < 1e-10: _at45 = True _x, _y = _obj.getLocation().getCoords() _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _mp = _test_point(_layer, _rx, _ry) _acl_angle = _obj.getAngle() if _at45 and abs(_acl_angle) < 1e-10: _mobj = VCLine(_mp) elif _at45 and abs(abs(_acl_angle) - 90.0) < 1e-10: _mobj = HCLine(_mp) else: if abs(_acl_angle) < 1e-10: # horizontal _xi = (_y - yint)/slope _yi = _y elif abs(abs(_acl_angle) - 90.0) < 1e-10: # vertical _xi = _x _yi = (slope * _x) + yint else: _asl = math.tan((math.pi/180.0) * _acl_angle) if abs(_asl - slope) < 1e-10: # parallel _mang = _acl_angle else: _ayi = _y - (_asl * _x) _xi = (_ayi - yint)/(slope - _asl) _yi = (slope * _xi) + yint _mang = 180.0/math.pi * math.atan2((_ry - _yi), (_rx - _xi)) if _mang < 0.0: _mang = _mang + 360.0 _mobj = ACLine(_mp, _mang) elif isinstance(_obj, CLine): _p1, _p2 = _obj.getKeypoints() _x, _y = _p1.getCoords() _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _mp1 = _test_point(_layer, _rx, _ry) _x, _y = _p2.getCoords() _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _mp2 = _test_point(_layer, _rx, _ry) _mobj = CLine(_mp1, _mp2) elif isinstance(_obj, Leader): _p1, _p2, _p3 = _obj.getPoints() _x, _y = _p1.getCoords() _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _mp1 = _test_point(_layer, _rx, _ry) _x, _y = _p2.getCoords() _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _mp2 = _test_point(_layer, _rx, _ry) _x, _y = _p3.getCoords() _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _mp3 = _test_point(_layer, _rx, _ry) _mobj = _obj.clone() _mobj.setP1(_mp1) _mobj.setP2(_mp2) _mobj.setP3(_mp3) elif isinstance(_obj, Polyline): _mpts = [] for _i in range(len(_obj)): _x, _y = _obj.getPoint(_i).getCoords() _rx, _ry = _reflect_point(_t1, _t2, _t3, yint, _x, _y) _mp = _test_point(_layer, _rx, _ry) _mpts.append(_mp) _s = _obj.getStyle() _mobj = Polyline(_mpts, _s) _l = _obj.getLinetype() if _l != _s.getLinetype(): _mobj.setLinetype(_l) _c = _obj.getColor() if _c != _s.getColor(): _mobj.setColor(_c) _t = _obj.getThickness() if abs(_t - _s.getThickness()) > 1e-10: _mobj.setThickness(_t) else: print "Skipping object: " + `_obj` if _mobj is not None: _layer.addObject(_mobj) def mirror_objects(mline, objlist): if not isinstance(mline, (HCLine, VCLine, ACLine, CLine)): raise TypeError, "Invalid mirror line type: " + `type(mline)` if not isinstance(objlist, (list, tuple)): raise TypeError, "Invalid object list: " + `type(objlist)` if isinstance(mline, HCLine): _x, _y = mline.getLocation().getCoords() _horizontal_mirror(_y, objlist) elif isinstance(mline, VCLine): _x, _y = mline.getLocation().getCoords() _vertical_mirror(_x, objlist) elif isinstance(mline, ACLine): _x, _y = mline.getLocation().getCoords() _angle = mline.getAngle() if abs(_angle) < 1e-10: # horizontal: _horizontal_mirror(_y, objlist) elif abs(abs(_angle) - 90.0) < 1e-10: # vertical _vertical_mirror(_x, objlist) else: _slope = math.tan(_angle * (math.pi/180.0)) _yint = _y - (_slope * _x) _angled_mirror(_slope, _yint, objlist) elif isinstance(mline, CLine): _p1, _p2 = mline.getKeypoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() if abs(_p2y - _p1y) < 1e-10: # horizontal _horizontal_mirror(_p1y, objlist) elif abs(_p2x - _p1x) < 1e-10: # vertical _vertical_mirror(_p1x, objlist) else: _slope = (_p2y - _p1y)/(_p2x - _p1x) _yint = _p1y - (_slope * _p1x) _angled_mirror(_slope, _yint, objlist) else: raise TypeError, "Unexpected mirror line type: " + `type(mline)` PythonCAD-DS1-R37/PythonCAD/Generic/quadtree.py0000644000175000017500000003420411307666657020526 0ustar matteomatteo# # Copyright (c) 2003, 2004, 2005 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # quadtree class definition # # TODO: Look at using weak references ... from __future__ import generators from PythonCAD.Generic import message class QTreeNode(message.Messenger): __messages = { 'subdivided' : True, 'reparented' : True, 'adjusted' : True, 'full' : True, } NENODE = 1 NWNODE = 2 SWNODE = 3 SENODE = 4 def __init__(self): super(QTreeNode, self).__init__() self.__subnodes = None self.__bounds = None self.__parent = None self.__threshold = 5 self.__objects = [] def __len__(self): return len(self.__objects) def setBoundary(self, xmin, ymin, xmax, ymax): if self.__subnodes is not None or self.__parent is not None: raise RuntimeError, "Node cannot have boundary changed." _xmin = xmin if not isinstance(_xmin, float): _xmin = float(xmin) _ymin = ymin if not isinstance(_ymin, float): _ymin = float(ymin) _xmax = xmax if not isinstance(_xmax, float): _xmax = float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = ymax if not isinstance(_ymax, float): _ymax = float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" self.__bounds = (_xmin, _ymin, _xmax, _ymax) def unsetBoundary(self): if self.__subnodes is not None or len(self.__objects) != 0: raise RuntimeError, "Node cannot have boundary changed." self.__bounds = None def getBoundary(self): return self.__bounds def setThreshold(self, count): _t = self.__threshold _count = count if not isinstance(_count, int): _count = int(count) if _count < 1: raise ValueError, "Invalid threshold: %d" % _count if _count != _t: self.__threshold = _count self.sendMessage('adjusted', _t) if len(self) > _count: self.sendMessage('full') def getThreshold(self): return self.__threshold def setParent(self, parent): _p = self.__parent if parent is not None and not isinstance(parent, QTreeNode): raise TypeError, "Invalid QTreeNode parent: " + `type(parent)` if parent is not _p: self.__parent = parent self.sendMessage('reparented', _p) def getParent(self): return self.__parent def addObject(self, obj): _seen = False for _obj in self.__objects: if _obj is obj: _seen = True break if not _seen: self.__objects.append(obj) if self.canSubdivide(): self.sendMessage('full') def getSubnode(self, subnode): if self.__subnodes is None: raise RuntimeError, "QTreeNode has no subnodes." _ne, _nw, _sw, _se = self.__subnodes if subnode == QTreeNode.NENODE: _sub = _ne elif subnode == QTreeNode.NWNODE: _sub = _nw elif subnode == QTreeNode.SWNODE: _sub = _sw elif subnode == QTreeNode.SENODE: _sub = _se else: raise ValueError, "Unknown subnode code: %d" % subnode return _sub def delObject(self, obj): for _i in range(len(self.__objects)): if obj is self.__objects[_i]: del self.__objects[_i] break def getObjects(self): return self.__objects[:] def delObjects(self): del self.__objects[:] def hasSubnodes(self): return self.__subnodes is not None def getSubnodes(self): return self.__subnodes def delSubnodes(self): if self.__subnodes is None: raise RuntimeError, "QTreeNode has no subnodes." for _subnode in self.__subnodes: _subnode.setParent(None) self.__subnodes = None def canSubdivide(self): if not len(self) > self.__threshold: return False _objs = self.__objects _flag = True for _obj in _objs: if not hasattr(_obj, '__eq__'): _flag = False break if not _flag: return len(self) > self.__threshold # # _test is an array of booleans: # _test[i] is True => object is unique # _test[i] is False => object is equal to another in list # # _test[0] is always True, so test from _test[1] to end # _test = [True] * len(_objs) _max = len(_test) for _i in range(_max - 1): if _test[_i]: # current object is unique ... for _j in range((_i + 1), _max): if _objs[_j] == _objs[_i]: _test[_j] = False return _test.count(True) > self.__threshold def subdivide(self): if len(self) < self.__threshold: return _xmin, _ymin, _xmax, _ymax = self.__bounds _xmid = (_xmin + _xmax)/2.0 _ymid = (_ymin + _ymax)/2.0 # # NE Node # _nenode = QTreeNode() _nenode.setBoundary(_xmid, _ymid, _xmax, _ymax) _nenode.setThreshold(self.__threshold) _nenode.setParent(self) # # NW Node # _nwnode = QTreeNode() _nwnode.setBoundary(_xmin, _ymid, _xmid, _ymax) _nwnode.setThreshold(self.__threshold) _nwnode.setParent(self) # # SW Node # _swnode = QTreeNode() _swnode.setBoundary(_xmin, _ymin, _xmid, _ymid) _swnode.setThreshold(self.__threshold) _swnode.setParent(self) # # SE Node # _senode = QTreeNode() _senode.setBoundary(_xmid, _ymin, _xmax, _ymid) _senode.setThreshold(self.__threshold) _senode.setParent(self) # self.__subnodes = (_nenode, _nwnode, _swnode, _senode) self.delObjects() self.sendMessage('subdivided') def sendsMessage(self, m): if m in QTreeNode.__messages: return True return super(QTreeNode, self).sendsMessage(m) class Quadtree(message.Messenger): __messages = { } def __init__(self): super(Quadtree, self).__init__() self.__objects = {} self.__queued = [] self.__splitnode = None self.__splitting = False self.__node = QTreeNode() self.__node.connect('full', self._splitTreeNode) def __nonzero__(self): return len(self.__objects) != 0 def __len__(self): return len(self.__objects) def __contains__(self, obj): _oid = id(obj) return _oid in self.__objects def getTreeRoot(self): return self.__node def getNodes(self, *args): _nodes = [self.__node] while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) else: yield _node def addObject(self, obj): _oid = id(obj) if _oid not in self.__objects: self.__objects[_oid] = obj if self.__splitnode is not None and not self.__splitting: self.__splitting = True _node = self.__splitnode _objs = _node.getObjects() _node.subdivide() for _subnode in _node.getSubnodes(): _subnode.connect('full', self._splitTreeNode) _root = self.__node self.__node = self.__splitnode try: for _obj in _objs: _oid = id(_obj) if _oid not in self.__objects: raise ValueError, "Lost object: " + str(_obj) del self.__objects[_oid] self.addObject(_obj) if _oid not in self.__objects: raise ValueError, "self.addObject() failed: " + str(_obj) finally: self.__node = _root self.__splitnode = None self.__splitting = False # set to False for Quadtree consistency testing if True or self.__splitnode is not None: return _objcount = len(self.__objects) _nodes = [self.__node] _nobj = {} while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) else: for _obj in _node.getObjects(): _oid = id(_obj) if _oid not in _nobj: _nobj[_oid] = True _nc = len(_nobj) if _nc > _objcount: print "Count inconsistency: %d > %d" % (_nc, _objcount) print "Quadtree objects:" for _obj in self.__objects.values(): print "obj: " + str(_obj) _bounds = self.__node.getBoundary() print "tree bounds: " + str(_bounds) _nodes = [self.__node] _nobj = {} while len(_nodes): _node = _nodes.pop() _bounds = _node.getBoundary() if _node.hasSubnodes(): print "Node with subnodes: " + str(_bounds) _nodes.extend(_node.getSubnodes()) else: print "Base node: " + str(_bounds) for _obj in _node.getObjects(): print "obj: " + str(_obj) _oid = id(_obj) if _oid not in _nobj: _nobj[_oid] = _obj if _oid not in self.__objects: print "###Object lost###" raise RuntimeError, "Inconsistent quadtree" def getObject(self, obj): _oid = id(obj) return self.__objects.get(_oid) # returns None if _oid not found def getObjects(self): return self.__objects.values() def delObject(self, obj): _oid = id(obj) if _oid in self.__objects: del self.__objects[_oid] def delObjects(self): _nodes = [self.__node] while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) _node.delSubnodes() else: for _obj in _node.getObjects(): _obj.disconnect(self) _node.delObjects() if _node.getParent() is not None: _node.setParent(None) _node.disconnect(self) self.__objects.clear() self.__node.unsetBoundary() def queueObject(self, obj): _oid = id(obj) if _oid in self.__objects: raise ValueError, "Object already stored in Quadtree: " + `obj` self.__queued.append(obj) def emptyQueue(self): _objs = self.__queued[:] del self.__queued[:] return _objs def find(self, *params): return [] def getClosest(self, x, y, tol): return None def getInRegion(self, xmin, ymin, xmax, ymax): return [] def resize(self, xmin, ymin, xmax, ymax): _xmin = xmin if not isinstance(_xmin, float): _xmin = float(xmin) _ymin = ymin if not isinstance(_ymin, float): _ymin = float(ymin) _xmax = xmax if not isinstance(_xmax, float): _xmax = float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = ymax if not isinstance(_ymax, float): _ymax = float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _root = self.__node if _root is not self.__splitnode: if not _root.hasSubnodes(): _root.setBoundary(_xmin, _ymin, _xmax, _ymax) else: _objs = self.__objects.values() self.delObjects() _root.setBoundary(_xmin, _ymin, _xmax, _ymax) for _obj in _objs: self.addObject(_obj) def _splitTreeNode(self, node, *args): if self.__splitnode is None: self.__splitnode = node def purgeSubnodes(self, node): if not isinstance(node, QTreeNode): raise TypeError, "Invalid node: " + `type(node)` _tmpnode = node _parent = node.getParent() while _parent is not None: _tmpnode = _parent _parent = _tmpnode.getParent() if self.__node is not _tmpnode: raise ValueError, "Node not in tree." if node.hasSubnodes(): _flag = True _count = 0 for _subnode in node.getSubnodes(): if _subnode.hasSubnodes(): _flag = False break _count = _count + len(_subnode) if _flag and _count < node.getThreshold(): _objs = [] for _subnode in node.getSubnodes(): _objs.extend(_subnode.getObjects()) node.delSubnodes() for _obj in _objs: Quadtree.delObject(self, _obj) self.addObject(_obj) def sendsMessage(self, m): if m in Quadtree.__messages: return True return super(Quadtree, self).sendsMessage(m) PythonCAD-DS1-R37/PythonCAD/Generic/image.py0000644000175000017500000021566111307674327017777 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # The class for a drawing # import sys import math import types import tempfile import stat import os from PythonCAD.Generic import fileio from PythonCAD.Generic import imageio from PythonCAD.Generic import globals from PythonCAD.Generic import layer from PythonCAD.Generic import graphicobject from PythonCAD.Generic import point from PythonCAD.Generic import style from PythonCAD.Generic import linetype from PythonCAD.Generic import tolerance from PythonCAD.Generic import intersections from PythonCAD.Generic import dimension from PythonCAD.Generic import color from PythonCAD.Generic import text from PythonCAD.Generic import units from PythonCAD.Generic import options from PythonCAD.Generic import baseobject from PythonCAD.Generic import entity from PythonCAD.Generic import logger from PythonCAD.Generic import util from PythonCAD.Generic import tools from PythonCAD.Generic import snap class Image(entity.Entity): """The class representing a CAD drawing. This class contains all the interface-neutral parts of a drawing. An image is essentially a collection of Layer objects, plus the bits needed to store the colors, linetypes, and styles used in a drawing. Each instance has several attributes: active_layer: The currently active Layer top_layer: The initial Layer in the Image scale: The scale factor of the Image The following methods are available for each instance: {get/set}Scale(): Get/Set the current scale factor. hasColor(): See if a color is already in use in the drawing. addColor(): Add a Color to the set available for objects in the drawing. hasLinetype(): See if a Linetype is found in the drawing. addLinetype(): Add a Linetype to the set available for objects in the drawing. hasStyle(): See if a Style is in the drawing. addStyle(): Add a Style to the set available for objects in the drawing. {get/set}ActiveLayer(): Get/Set the currently active Layer. addChildLayer(): Make one Layer object a child of another. addLayer(): Make one Layer object a child of the active Layer's parent. delLayer(): Remove a Layer from the image. findPoint(): Find a Point object in the drawing. mapPoint(): Find objects in the drawing where at some location. {get/set}CurrentPoint(): Get/Set a coordinate pair addObject(): Add an object to the drawing. delObject(): Delete an object from the drawing. getObject(): Return an object with a specific entity ID selectObject(): Store a references to an object in the drawing. deselectObject(): Release a reference to a stored object. getSelectedObjects(): Retrieve all the selected objects. clearSelectedObjects(): Release all references to selected objects. hasSelection(): Return whether the image has an active selection. getExtents(): Find the size of the drawing. {get/set}Option(): Retrieve/Store an option used in the drawing. {get/set}Filename(): Get/Set the filename for this image. getImageEntities(): Get all the instances of certain image-wide object. {get/set}Units(): Get/Set the basic length unit in the image. scaleLength(): Return a linear distance in millimeters. getClosestPoint(): Return the point/coordinates nearest to a given x/y pair. {start/end}Action(): Begin/End a sequence of actions to be treated as one event inAction(): Test if the Image is currently in a startAction()/endAction() block getAction(): Return the number of startAction()/endAction() blocks performed. {get/set}Tool(): Get/Set the active Tool used in the Image. """ __options = [ 'AUTOSPLIT', 'HIGHLIGHT_POINTS', 'LEADER_ARROW_SIZE', 'CHAMFER_LENGTH', 'FILLET_RADIUS', 'FILLET_TWO_TRIM_MODE', 'INACTIVE_LAYER_COLOR', 'BACKGROUND_COLOR', 'SINGLE_POINT_COLOR', 'MULTI_POINT_COLOR', 'UNITS', 'LINE_STYLE', 'LINE_TYPE', 'LINE_COLOR', 'LINE_THICKNESS', 'TEXT_STYLE', 'FONT_FAMILY', 'FONT_STYLE', 'FONT_WEIGHT', 'TEXT_SIZE', 'FONT_COLOR', 'TEXT_ANGLE', 'TEXT_ALIGNMENT', 'DIM_STYLE', 'DIM_PRIMARY_FONT_FAMILY', 'DIM_PRIMARY_FONT_STYLE', 'DIM_PRIMARY_FONT_WEIGHT', 'DIM_PRIMARY_FONT_COLOR', 'DIM_PRIMARY_TEXT_SIZE', 'DIM_PRIMARY_TEXT_ANGLE', 'DIM_PRIMARY_TEXT_ALIGNMENT', 'DIM_PRIMARY_PREFIX', 'DIM_PRIMARY_SUFFIX', 'DIM_PRIMARY_PRECISION', 'DIM_PRIMARY_UNITS', 'DIM_PRIMARY_LEADING_ZERO', 'DIM_PRIMARY_TRAILING_DECIMAL', 'DIM_SECONDARY_FONT_FAMILY', 'DIM_SECONDARY_FONT_WEIGHT', 'DIM_SECONDARY_FONT_STYLE', 'DIM_SECONDARY_FONT_COLOR', 'DIM_SECONDARY_TEXT_SIZE', 'DIM_SECONDARY_TEXT_ANGLE', 'DIM_SECONDARY_TEXT_ALIGNMENT', 'DIM_SECONDARY_PREFIX', 'DIM_SECONDARY_SUFFIX', 'DIM_SECONDARY_PRECISION', 'DIM_SECONDARY_UNITS', 'DIM_SECONDARY_LEADING_ZERO', 'DIM_SECONDARY_TRAILING_DECIMAL', 'DIM_OFFSET', 'DIM_EXTENSION', 'DIM_COLOR', 'DIM_THICKNESS', 'DIM_POSITION', 'DIM_POSITION_OFFSET', 'DIM_ENDPOINT', 'DIM_ENDPOINT_SIZE', 'DIM_DUAL_MODE', 'DIM_DUAL_MODE_OFFSET', 'RADIAL_DIM_PRIMARY_PREFIX', 'RADIAL_DIM_PRIMARY_SUFFIX', 'RADIAL_DIM_SECONDARY_PREFIX', 'RADIAL_DIM_SECONDARY_SUFFIX', 'RADIAL_DIM_DIA_MODE', 'ANGULAR_DIM_PRIMARY_PREFIX', 'ANGULAR_DIM_PRIMARY_SUFFIX', 'ANGULAR_DIM_SECONDARY_PREFIX', 'ANGULAR_DIM_SECONDARY_SUFFIX' ] __messages = { 'scale_changed' : True, 'units_changed' : True, 'tool_changed' : True, 'added_object' : True, 'deleted_object' : True, 'selected_object' : True, 'deselected_object' : True, 'active_layer_changed' : True, 'current_point_changed' : True, 'group_action_started' : True, 'group_action_ended' : True, 'option_changed' : True } def __init__(self, **kw): """ Instatiate a Image object. There are no parameters used to create the object. """ super(Image, self).__init__(**kw) self.__scale = 1.0 self.__cp = None self.__styles = [] self.__dimstyles = [] self.__textstyles = [] self.__linetypes = [] self.__colors = baseobject.TypedDict(keytype=color.Color) self.__units = units.Unit(units.MILLIMETERS) self.__options = baseobject.TypedDict(keytype=str) # miscellaneous options self.__fonts = baseobject.TypedDict(keytype=types.StringTypes) # font names self.__tool = None self.__selected = [] self.__filename = tempfile.mkdtemp(suffix='_temp', prefix='PyCad_') self.__vars = {} self.__busy = False self.__undo = [] self.__redo = [] self.__delhist = {} self.__logs = {} self.__action = 0L self.__closing = False # # add the initial layer # _top = layer.Layer(_(u'TopLayer')) _top.setParent(self) self.__top_layer = _top self.__active_layer = _top _top.connect('modified', self.__objectModified) _top.connect('added_child', self.__layerAddedChild) _top.connect('removed_child', self.__layerRemovedChild) _log = layer.LayerLog(_top) _top.setLog(_log) self.setDefaults() self.connect('modified', self.__objectModified) self.__vars['image'] = self # # Snap Obj # self.__snapProvider=snap.SnapServices(self) # #file status # self.__saved=False def isSaved(self): """ Sai if the file is saved """ return self.__saved def setSaved(self): """ force the file to be saved """ self.__saved=True def setUnsaved(self): """ force the file to be unsaved """ self.__saved=False def save(self,filename=None): if filename==None: filename=self.__filename _abs = os.path.abspath(filename) _bname = os.path.basename(_abs) if _bname.endswith('.gz'): _bname = _bname[:-3] _newfile = _abs + '.new' _handle = fileio.CompFile(_newfile, "w", truename=_bname) try: imageio.save_image(self, _handle) finally: _handle.close() self.setSaved() _backup = _abs + '~' if os.path.exists(_backup): os.unlink(_backup) _mode = None if os.path.exists(_abs): _st = os.stat(_abs) _mode = stat.S_IMODE(_st.st_mode) os.rename(_abs, _backup) try: os.rename(_newfile, _abs) except: os.rename(_backup, _abs) raise if _mode is not None and hasattr(os, 'chmod'): os.chmod(_abs, _mode) if self.getFilename() is None: self.setFilename(_abs) # # Snap method # def getSnapProvider(self): """ Return the snap Provider """ return self.__snapProvider # # Snap Property # snapProvider=property(getSnapProvider,None,None,"Provide the SnapServicesObject for snap operations") def __contains__(self, obj): """ Define if an object is in the Drawing. Defining this method allows the use of 'in' type test. """ _res = False if isinstance(obj, style.Style): _res = obj in self.__styles elif isinstance(obj, linetype.Linetype): _res = obj in self.__linetypes elif isinstance(obj, color.Color): _res = obj in self.__colors elif isinstance(obj, dimension.DimStyle): _res = obj in self.__dimstyles elif isinstance(obj, text.TextStyle): _res = obj in self.__textstyles else: _layers = [self.__top_layer] while (len(_layers)): _layer = _layers.pop() _res = obj in _layer if _res: break _layers.extend(_layer.getSublayers()) return _res def close(self): """Release all the entities stored in the drawing close() """ # print "in image::close()" self.__cp = None del self.__styles[:] del self.__dimstyles[:] del self.__textstyles[:] del self.__linetypes[:] self.__colors.clear() self.__options.clear() self.__fonts.clear() del self.__selected[:] self.__filename = None self.__vars.clear() del self.__undo[:] del self.__redo[:] self.__delhist.clear() self.__logs.clear() self.__closing = True _top = self.__top_layer _layers = [] _sublayers = [_top] while len(_sublayers): _layer = _sublayers.pop() _layers.append(_layer) _sublayers.extend(_layer.getSublayers()) _layers.reverse() for _layer in _layers: # print "closing layer " + _layer.getName() _layer.clear() self.delLayer(_layer) _layer.finish() self.disconnect(self) def addChildLayer(self, l, p=None): """Add a child Layer of the active Layer. addChildLayer(l [, p]) There is a one required argument: l: The child Layer There is one optional argument: p: The new parent Layer of the child The default parent is the currently active layer. The child layer cannot be a layer found when moving up from the new parent layer to the topmost layer. """ _child = l if not isinstance(_child, layer.Layer): raise TypeError, "Unexpected type for layer: " + `type(_child)` _pl = p if _pl is None: _pl = self.__active_layer if not isinstance(_pl, layer.Layer): raise TypeError, "Unexpected type for parent layer: " + `type(_pl)` if _pl.getParent() is not self: raise ValueError, "Parent layer not in Image." if _child is _pl: raise ValueError, "Child and parent layers identical." _tpl = _pl.getParentLayer() while _tpl is not None: if _tpl is _child: raise ValueError, "Child layer found in parent chain" _tpl = _tpl.getParentLayer() if not self.inUndo(): self.ignore('modified') try: _child.setParentLayer(_pl) finally: if not self.inUndo(): self.receive('modified') if _child.getParent() is not self: _child.setParent(self) # # restore the Layer log if possible # _cid = _child.getID() _log = _child.getLog() if _log is None: _log = layer.LayerLog(_child) _child.setLog(_log) _oldlog = self.__logs.get(_cid) if _oldlog is not None: # re-attach old log _log.transferData(_oldlog) del self.__logs[_cid] # # re-add deleted entity history # _data = self.__delhist.get(_cid) if _data is not None: _child.setDeletedEntityData(_data) del self.__delhist[_cid] _child.connect('modified', self.__objectModified) _child.connect('added_child', self.__layerAddedChild) _child.connect('removed_child', self.__layerRemovedChild) self.__active_layer = _child def addLayer(self, l): """Add a new Layer as a child of the active Layer's parent. addLayer(l) If the active layer is the topmost Layer in the drawing, the Layer is added as a child Layer to that Layer. Otherwise, the new layer is added and is a sibling to the active Layer. """ _layer = l if not isinstance(_layer, layer.Layer): raise TypeError, "Invalid Layer type: " + `type(_layer)` _pl = self.__active_layer.getParentLayer() if _pl is None: _pl = self.__top_layer self.addChildLayer(l, _pl) def delLayer(self, l): """Remove a Layer from the drawing. delLayer(l) A Layer object cannot be removed until its children are either deleted or moved to another Layer. The topmost Layer in a drawing cannot be deleted. """ _layer = l if not isinstance(_layer, layer.Layer): raise TypeError, "Invalid Layer type: " + `type(_layer)` if _layer.getParent() is not self: raise ValueError, "Layer not found in Image: " + _layer.getName() if (self.__closing or (_layer.getParentLayer() is not None and not _layer.hasSublayers())): if not self.__closing: # print "deleting layer ..." _lid = _layer.getID() _data = _layer.getDeletedEntityData() # # save the layer info so it can be reattched if # the layer deletion is undone # if len(_data): # print "has DeletedEntityData()" self.__delhist[_lid] = _data _log = _layer.getLog() if _log is not None: # print "Saving log file ..." _log.detatch() if not self.__closing: self.__logs[_lid] = _log _layer.setLog(None) # # stop listening for messages # _layer.disconnect(self) # # call setParent() before setParentLayer() so # the Layer's getValues() calls will have # the parent layer information # _layer.setParent(None) if not self.inUndo(): self.ignore('modified') try: _layer.setParentLayer(None) finally: if not self.inUndo(): self.receive('modified') def hasLayer(self, l): """Return whether or not a layer is in a drawing. hasLayer(l) """ _layer = l if not isinstance(_layer, layer.Layer): raise TypeError, "Invalid Layer type : " + `type(_layer)` _flag = False _l = _layer _p = _l.getParentLayer() while _p is not None: _l = _p _p = _p.getParentLayer() if _l is self.__top_layer: _flag = True _image = _layer.getParent() if ((_image is self and _flag is False) or (_image is not self and _flag is True)): raise ValueError, "Image/Layer parent inconsistency" return _flag def getActiveLayer(self): """ Return the active Layer in the drawing. The active Layer is the Layer to which any new objects will be stored. """ return self.__active_layer def setActiveLayer(self, l=None): """Set the active Layer in the Image. setActiveLayer(l) The the Layer 'l' to be the active Layer in the drawing. If the function is called without arguments, the topmost Layer in the drawing is set to the active layer. """ _layer = l if _layer is None: _layer = self.__top_layer if not isinstance(_layer, layer.Layer): raise TypeError, "Invalid Layer type: " + `type(_layer)` if _layer is not self.__top_layer: _l = _layer _p = _l.getParentLayer() while _p is not None: _l = _p _p = _p.getParentLayer() if _l is not self.__top_layer: raise ValueError, "Layer not found in image: " + `_layer` _parent = _layer.getParentLayer() if not _parent.hasSublayers(): raise ValueError, "Layer not in parent sublayer: " + `_layer` if _layer not in _parent.getSublayers(): raise ValueError, "Layer not in parent sublayers: " + `_layer` if _layer.getParent() is not self: raise ValueError, "Image/Layer parent inconsistency" _active = self.__active_layer if _layer is not _active: self.__active_layer = _layer self.sendMessage('active_layer_changed', _active) active_layer = property(getActiveLayer, setActiveLayer, None, "Image active Layer object.") def getTopLayer(self): """Return the top Layer of the image getTopLayer() """ return self.__top_layer top_layer = property(getTopLayer, None, None, "Image top Layer.") def getScale(self): """Return the image's scale factor. getScale() """ return self.__scale def setScale(self, scale): """Set the image's scale factor. setScale(scale) The scale must be a float greater than 0. """ _s = util.get_float(scale) if _s < 1e-10: raise ValueError, "Invalid scale factor: %g" % _s _os = self.__scale if abs(_os - _s) > 1e-10: self.__scale = _s self.sendMessage('scale_changed', _os) self.modified() scale = property(getScale, setScale, None, "Image scale factor.") def canParent(self, obj): """Test if an Entity can be the parent of another Entity. canParent(obj) This method overrides the Entity::canParent() method. An Image can be the parent of Layer entities only. """ return isinstance(obj, layer.Layer) def getImageEntities(self, entity): """Return all the entities of a particular type getImageEntities(entity) The argument 'entity' should be one of the following: color, linetype, style, font, dimstyle, or textstyle """ if entity == "color": _objs = self.__colors.keys() elif entity == "linetype": _objs = self.__linetypes[:] elif entity == "style": _objs = self.__styles[:] elif entity == "font": _objs = self.__fonts.keys() elif entity == "dimstyle": _objs = self.__dimstyles[:] elif entity == "textstyle": _objs = self.__textstyles[:] else: raise ValueError, "Invalid image entity: " + `entity` return _objs def addColor(self, c): """Add a Color object to the drawing. addColor(c) """ if not isinstance(c, color.Color): raise TypeError, "Invalid Color type: " + `type(c)` if c not in self.__colors: self.__colors[c] = True # maybe count entities ? def hasColor(self, c): """Check if a Color already exists in the drawing. hasColor(c) """ _c = c if not isinstance(_c, color.Color): _c = color.Color(c) return _c in self.__colors def addLinetype(self, lt): """Add a Linetype to the drawing. addLinetype(lt) """ if not isinstance(lt, linetype.Linetype): raise TypeError, "Invalid Linetype type: " + `type(lt)` if lt not in self.__linetypes: self.__linetypes.append(lt) def hasLinetype(self, lt): """Check if a Linetype already exists in the drawing. hasLinetype(lt) """ if not isinstance(lt, linetype.Linetype): raise TypeError, "Invalid Linetype type: " + `type(lt)` return lt in self.__linetypes def addStyle(self, s): """Add a Style to the drawing. addStyle(s) """ if not isinstance(s, style.Style): raise TypeError, "Invalid Style type: " + `type(s)` if s not in self.__styles: _col = s.getColor() if _col not in self.__colors: self.__colors[_col] = True _lt = s.getLinetype() if _lt not in self.__linetypes: self.__linetypes.append(_lt) self.__styles.append(s) def hasStyle(self, s): """Check if a Style already exists within the drawing. hasStyle(s) """ _s = s if not isinstance(_s, style.Style): _s = style.Style(s) return _s in self.__styles def addDimStyle(self, ds): """Add a DimStyle to the drawing addDimStyle(ds) """ if not isinstance(ds, dimension.DimStyle): raise TypeError, "Invalid DimStyle type: " + `type(ds)` if ds not in self.__dimstyles: _col = ds.getValue('DIM_COLOR') if _col is not None and _col not in self.__colors: self.__colors[_col] = True _col = ds.getValue('DIM_PRIMARY_FONT_COLOR') if _col is not None and _col not in self.__colors: self.__colors[_col] = True _col = ds.getValue('DIM_SECONDARY_FONT_COLOR') if _col is not None and _col not in self.__colors: self.__colors[_col] = True _family = ds.getValue('DIM_PRIMARY_FONT_FAMILY') if _family is not None and _family not in self.__fonts: self.__fonts[_family] = 1 _family = ds.getValue('DIM_SECONDARY_FONT_FAMILY') if _family is not None and _family not in self.__fonts: self.__fonts[_family] = 1 self.__dimstyles.append(ds) def hasDimStyle(self, ds): """Check if a DimStyle already exists within the drawing. hasDimStyle(ds) """ if not isinstance(ds, dimension.DimStyle): raise TypeError, "Invalid DimStyle type: " + `type(ds)` return ds in self.__dimstyles def addTextStyle(self, ts): """Add a TextStyle to the drawing. addTextStyle(ts) """ # print "Image::addTextStyle() ..." if not isinstance(ts, text.TextStyle): raise TypeError, "Invalid TextStyle type: " + `type(ts)` if ts not in self.__textstyles: # print "adding TextStyle: %s" % ts.getName() _color = ts.getColor() if _color not in self.__colors: self.__colors[_color] = True _family = ts.getFamily() if _family in self.__fonts: self.__fonts[_family] = 1 self.__textstyles.append(ts) def hasTextStyle(self, ts): """Return whether or not a TextStyle is already in an image. hasTextStyle(ts) """ if not isinstance(ts, text.TextStyle): raise TypeError, "Invalid TextStyle: " + str(ts) return ts in self.__textstyles def addFont(self, family): """Store the usage of a font in the image. addFont(family) Invoking this method does not set the current text font to the value used in this function. That must be done with setOption(). """ if not isinstance(family, types.StringTypes): raise TypeError, "Invalid font family type: " + `type(family)` self.__fonts[family] = 1 def getUnits(self): """Return the currently selected unit. getUnits() """ return self.__units.getUnit() def setUnits(self, unit): """Set the basic unit for the image. setUnits(unit) The available choices for the units are defined in the units.py file. """ _ou = self.__units.getUnit() self.__units.setUnit(unit) if unit != _ou: self.sendMessage('units_changed', _ou) self.modified() units = property(getUnits, setUnits, None, "Linear dimensional units for the image.") def scaleLength(self, l): """Convert some distance to a value in millimeters. scaleLength(l) The argument 'l' should be a float equal or greater than 0.0. """ _l = util.get_float(l) if _l < 0.0: raise ValueError, "Invalid scaling length: %g" % _l return self.__units.toMillimeters(_l) def getClosestPoint(self, x, y, **kw): """ Return a Point or (x, y) coordinate tuple in the Image. getClosestPoint(self, x, y [,**kw]) The function has two required arguments x: A float representing the x-coordinate y: A float representing the y-coordinate The accepted keyword arguements are: tolerance: The distance between the existing objects and the 'x' and 'y' arguments. The default value is 1e-10. This method returns a tuple of two values, one of which will be None. If an existing Point was found in the active layer, the first value in the tuple is the point, and the second value is None. If no point was found, the first value will be None and the second value will be a tuple of (x, y) coordinates where a new Point could be created. When the method returns the coordinate tuple, the location could be a projected point onto an Entity found in the Layer, or possibly the intersection of two or more entities, or simply a distinct point in the Layer if no nearby entities were found. """ raise "Function getClosestPoint banned " _t=5.0 if 'tolerance' in kw: _t=util.get_float(kw['tolerance']) _sobj=self.GetSnapObject() _ix, _iy,validate,cursor=_sobj.GetSnap(x,y,_t,None) _sobj.StopOneShutSnap() if(validate): return (_ix, _iy) return (x, y) def findPoint(self, x, y, tol=tolerance.TOL): """Return a Point object found at the x-y coordinates. findPoint(self, x, y [,tol]) The function has two required arguments x: A float representing the x-coordinate y: A float representing the y-coordinate The optional argument 'tol' gives a distance between the existing objects and the 'x' and 'y' arguments. The default value is 1e-10. This method returns a tuple of two objects, the first object is a Point object, and the second object is a boolean True/False value indicating if the point is an exisiting point in the active layer or a newly created point. If there were no Point objects found within the tolerance supplied, the Point object in the tuple is None. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _test_point = point.Point(_x, _y) _active_layer = self.__active_layer _new_pt = False _pt = None _pts = _active_layer.find('point', _x, _y, _t) if len(_pts) != 0: _pt = _pts[0] if _pt is None: _objs = [] _ptmap = {} _layers = [self.__top_layer] while len(_layers): _layer = _layers.pop() if _layer is not _active_layer: _pts = _layer.find('point', _x, _y, _t) if len(_pts) != 0: _pt = _pts[0].clone() _new_pt = True break _stop = False for _obj, _map_pt in _layer.mapPoint(_test_point, _t, None): if isinstance(_obj, dimension.Dimension): continue if len(_objs): for _tobj in _objs: _ints = intersections.find_intersections(_tobj, _obj) _count = len(_ints) if _count == 1: _stop = True _x, _y = _ints[0] _pt = point.Point(_x, _y) _new_pt = True break elif _count == 2: _stop = True _tx, _ty = _test_point.getCoords() _x1, _y1 = _ints[0] _d1 = math.hypot((_tx - _x1), (_ty - _y1)) _x2, _y2 = _ints[1] _d2 = math.hypot((_tx - _x2), (_ty - _y2)) if _d1 < _d2: _pt = point.Point(_x1, _y1) else: _pt = point.Point(_x2, _y2) _new_pt = True break else: pass # this should handle _count > 2 _ptmap[_obj] = _map_pt _objs.append(_obj) if _stop: break _layers.extend(_layer.getSublayers()) if _pt is None: # need to use one of the mapped points ... _min_sep = None _map_obj = None for _obj in _ptmap: _sep = _ptmap[_obj] - _test_point if _min_sep is None or _sep < _min_sep: _map_obj = _obj if _map_obj is not None: _pt = _ptmap[_map_obj] _new_pt = True return _pt, _new_pt def mapCoords(self, x, y, tol, count=None): """Return a set of Layers with objects found at the (x, y) location mapCoords(self, x, y, tol[, count]) This method has three required arguments: x: A float representing the x-coordinate y: A float representing the y-coordinate tol: A positive float giving the maximum distance between the x and y coordinates and the projected points of the objects There is a single optional argument: count: An integer value specifying the maximum number of objects to retrieve in any layer. By default the limit is the 'sys.maxint' value, essentially making the count unlimited. The function returns a list of tuples, where each tuple is of the form (layer, list). The 'list' in the tuple is itself a list of tuples consiting of an entity and either an existing Point in the layer or an x/y coordinate pair. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _count = count if _count is None: _count = sys.maxint if not isinstance(_count, int): _count = int(count) if _count < 0: raise ValueError, "Invalid negative entity count: %d" % _count _objlist = [] if _count == 0: return _objlist _active_layer = self.__active_layer _hits = _active_layer.mapCoords(_x, _y, tolerance=_t, count=_count) if len(_hits): _objlist.append((_active_layer, _hits)) else: _layers = [self.__top_layer] while len(_layers): _layer = _layers.pop() if _layer is not _active_layer: _hits = _layer.mapCoords(_x, _y, tolerance=_t, count=_count) if len(_hits): _objlist.append((_layer, _hits)) _layers.extend(_layer.getSublayers()) return _objlist def mapPoint(self, x, y, tol, count=2): """Return a set of Layers with objects found at the (x,y) location mapPoint(self, x, y, tol[, count]) This method has three required arguments: x: A float representing the x-coordinate y: A float representing the y-coordinate tol: A positive float giving the maximum distance between the x and y coordinates and the projected points of the objects There is a single optional argument: count: The maximum number of objects to retrieve in any layer. The default value of objects is 2. Setting 'count' to either None or a negative value will result in the maximum number of objects as unlimited. The function returns a dict object, with each key being a Layer object where some objects were found, and the value being a list of some tuples. Read the doc-string info for the layer::mapPoint() method for details regarding the tuple(s) in the list. If any objects in the currently active layer are identified, no other layers in the drawing will be examined. If there were no objects found within the tolerance supplied, the function returns an empty dict. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _count = count if _count is None: _count = sys.maxint else: if not isinstance(_count, int): _count = int(count) if _count < 0: # What if _count == 0 ??? _count = sys.maxint _tp = point.Point(_x, _y) _active_layer = self.__active_layer _objdict = {} _hits = _active_layer.mapPoint(_tp, _t, _count) if len(_hits): _objdict[_active_layer] = _hits else: _layers = [self.__top_layer] while len(_layers): _layer = _layers.pop() if _layer is not _active_layer: _hits = _layer.mapPoint(_tp, _t, _count) if len(_hits): _objdict[_layer] = _hits _layers.extend(_layer.getSublayers()) return _objdict def getCurrentPoint(self): """Get the current point defined for the Image. getCurrentPoint() This method returns a tuple containing two floats, or None if the point has not been defined """ return self.__cp def setCurrentPoint(self, x, y): """Set the current point. setCurrentPoint(x, y) Arguments 'x' and 'y' should be floats """ _x = util.get_float(x) _y = util.get_float(y) if self.__cp is not None: _cx, _cy = self.__cp if self.__cp is None or abs(_cx - _x) > 1e-10 or abs(_cy - _y) > 1e-10: self.__cp = (_x, _y) self.sendMessage('current_point_changed') current_point = property(getCurrentPoint, None, None, 'Current point') def __objectModified(self, obj, *args): # print "Image::objectModified()" # print "obj: " + `obj` if self.__closing: return if obj.inUndo(): raise RuntimeError, "Recieved 'modified' during undo: " + `obj` _oid = obj.getID() _pid = None _parent = obj.getParent() if _parent is None: if obj is not self: raise ValueError, "Invalid object without parent: " + `obj` else: _pid = _parent.getID() if _parent is self: if not isinstance(obj, layer.Layer): raise ValueError, "Non-layer with Image as parent: " + `obj` else: _layer = None for _child in self.getChildren(): _cid = _child.getID() if _cid == _pid: _layer = _child break if _layer is None: raise ValueError, "Parent %d not in Image children: %s" % (_pid, `_parent`) _lobj = _layer.getObject(_oid) if _lobj is not obj: raise ValueError, "Object %d not found in Layer: %s" % (_oid, `obj`) _i = self.__action # print "i: %d" % _i _undo = self.__undo # print "len(self.__undo): %d" % len(_undo) if len(_undo) == _i: _undo.insert(_i, [(_pid, _oid)]) else: _undo[_i].append((_pid, _oid)) if not self.__busy: self.__action = _i + 1 def __layerAddedChild(self, l, *args): # print "Image::layerAddedChild() ..." _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _obj = args[0] # print "obj: " + `_obj` _obj.connect('modified', self.__objectModified) if isinstance(_obj, graphicobject.GraphicObject): self.addStyle(_obj.getStyle()) self.addLinetype(_obj.getLinetype()) self.addColor(_obj.getColor()) _obj.connect('style_changed', self.__styleChanged) _obj.connect('color_changed', self.__colorChanged) _obj.connect('linetype_changed', self.__linetypeChanged) if isinstance(_obj, text.TextBlock): self.addColor(_obj.getColor()) self.addTextStyle(_obj.getTextStyle()) _obj.connect('font_color_changed', self.__colorChanged) _obj.connect('textstyle_changed', self.__textstyleChanged) if isinstance(_obj, dimension.Dimension): self.addDimStyle(_obj.getDimStyle()) self.addColor(_obj.getColor()) _obj.connect('dimstyle_changed', self.__dimstyleChanged) _obj.connect('color_changed', self.__colorChanged) _ds1, _ds2 = _obj.getDimstrings() self.addColor(_ds1.getColor()) self.addTextStyle(_ds1.getTextStyle()) _ds1.connect('font_color_changed', self.__colorChanged) _ds1.connect('textstyle_changed', self.__textstyleChanged) self.addColor(_ds2.getColor()) self.addTextStyle(_ds2.getTextStyle()) _ds2.connect('font_color_changed', self.__colorChanged) _ds2.connect('textstyle_changed', self.__textstyleChanged) self.sendMessage('added_object', l, _obj) # # If a Point was added set the Layer to the global AUTOSPLIT # option value unless the Layer has autosplitting set # if isinstance(_obj, point.Point) and l.getAutosplit(): l.setAutosplit(self.getOption('AUTOSPLIT')) def __layerRemovedChild(self, l, *args): # print "Image::layerRemovedChild() ..." _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _obj = args[0] # print "obj: " + `_obj` _obj.disconnect(self) if isinstance(_obj, dimension.Dimension): _ds1, _ds2 = _obj.getDimstrings() _ds1.disconnect(self) _ds2.disconnect(self) _objs = self.__selected for _i in range(len(_objs)): if _obj is _objs[_i]: del _objs[_i] break self.sendMessage('deleted_object', l, _obj) def __styleChanged(self, obj, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen self.addStyle(obj.getStyle()) def __colorChanged(self, obj, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen self.addColor(obj.getColor()) def __linetypeChanged(self, obj, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen self.addLinetype(obj.getLinetype()) def __textstyleChanged(self, obj, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen self.addTextStyle(obj.getTextstyle()) def __dimstyleChanged(self, obj, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen self.addDimStyle(obj.getDimStyle()) def printStack(self, undo): if undo: print "Image undo list:" _stack = self.__undo else: print "Image redo list:" _stack = self.__redo print "length: %d" % len(_stack) for _data in _stack: print _data def canUndo(self): return len(self.__undo) > 0 def canRedo(self): return len(self.__redo) > 0 def doUndo(self): # print "Image::doUndo() ..." if len(self.__undo): _act = self.__undo.pop() # print "Actions: " + str(_act) # print "undo length: %d" % len(self.__undo) self.__redo.append(_act[:]) self.__action = len(self.__undo) _act.reverse() self.ignore('modified') self.sendMessage('group_action_started') try: _sid = self.getID() _layers = {} for _pid, _oid in _act: # print "pid: " + str(_pid) # print "oid: %d" % _oid _obj = None if _pid is None: if _oid != _sid: raise ValueError, "Invalid orphan: %d" % _oid _obj = self if _obj is None and _pid == _sid: _obj = _layers.get(_oid) if _obj is None: for _layer in self.getChildren(): _lid = _layer.getID() _layers[_lid] = _layer if _lid == _oid: _obj = _layer break if _obj is None: raise ValueError, "Layer %d not found in Image" % _oid if _obj is None: _par = _layers.get(_pid) if _par is None: for _layer in self.getChildren(): _lid = _layer.getID() _layers[_lid] = _layer if _lid == _pid: _par = _layer break if _par is None: raise ValueError, "Parent layer not found: %d" % _pid _obj = _par.getObject(_oid) if _obj is None: raise ValueError, "Object %d not found in parent %d" % (_oid, _pid) # print "executing undo on obj: " + `_obj` _obj.undo() finally: self.sendMessage('group_action_ended') self.receive('modified') def doRedo(self): # print "Image::doRedo() ..." if len(self.__redo): _act = self.__redo.pop() self.__action = len(self.__undo) # # wrap all the redo() actions within a # startAction()/endAction block - this will # ensure that all the 'modified' messages the # redo operations generate will be stored in # in the undo list as a single set of operations # self.startAction() try: _sid = self.getID() _layers = {} for _pid, _oid in _act: _obj = None if _pid is None: if _oid != _sid: raise ValueError, "Invalid orphan: %d" % _oid _obj = self if _obj is None and _pid == _sid: _obj = _layers.get(_oid) if _obj is None: for _layer in self.getChildren(): _lid = _layer.getID() _layers[_lid] = _layer if _lid == _oid: _obj = _layer break if _obj is None: raise ValueError, "Layer %d not found in Image" % _oid if _obj is None: _par = _layers.get(_pid) if _par is None: for _layer in self.getChildren(): _lid = _layer.getID() _layers[_lid] = _layer if _lid == _pid: _par = _layer break if _par is None: raise ValueError, "Parent layer not found: %d" % _pid _obj = _par.getObject(_oid) if _obj is None: raise ValueError, "Object %d not found in parent %d" % (_oid, _pid) # print "executing redo on obj: " + `_obj` _obj.redo() finally: self.endAction() def addObject(self, obj, l=None): """Add an object to the Drawing. addObject(obj [, l]) Argument 'obj' is the entity to be added in the Image. Optional arguement 'l' is the Layer that will contain the object. If no layer is specfied then the object is placed in the active Layer. """ _layer = l if _layer is None: _layer = self.__active_layer _op = obj.getParent() if _op is not None: raise RuntimeError, "Object already in layer '%s'" % _op.getName() if not isinstance(_layer, layer.Layer): raise TypeError, "Invalid Layer: " + `type(_layer)` if _layer.getParent() is not self: raise RuntimeError, "Layer not found in Image." _layer.setAutosplit(self.getOption('AUTOSPLIT')) _layer.addObject(obj) def delObject(self, obj): """Remove an object from the Drawing. delObject(obj) Argument 'obj' must be an object stored in a Layer in the Image. """ _layer = obj.getParent() if _layer is None: raise RuntimeError, "Object not stored within a Layer." if _layer.getParent() is not self: raise RuntimeError, "Object parent Layer not found in Image." _layer.delObject(obj) def getObject(self, eid): """Retrieve an object with a specified ID. getObject(eid) Argument eid is an entity ID. If an object with an ID of that specified is found, the object is returned. Otherwise this method returns None. """ _layers = [self.__top_layer] while len(_layers): _layer = _layers.pop() if _layer.getID() == eid: return _layer _obj = _layer.getObject(eid) if _obj is not None: return _obj _layers.extend(_layer.getSublayers()) return None def startAction(self): """Set the Image to the point starting a sequence of operations. startAction() This method is called in conjunction with endAction() to store a sequence of operations on an Image as a single operation for undo/redo purposes. """ if self.__busy: raise ValueError, "Image already in busy state" self.__busy = True self.sendMessage('group_action_started') def endAction(self): """ Set the Image to the point completing a sequence of operations. This method is called in conjunction with startAction() to store a sequence of operations on an Image as a single operation for undo/redo purposes. """ if not self.__busy: raise ValueError, "Image not in busy state" self.__busy = False self.__action = len(self.__undo) self.sendMessage('group_action_ended') def inAction(self): """Test if the Image is with a startAction()/endAction() operation. inAction() This method returns a boolean. """ return self.__busy def getAction(self): return self.__action action = property(getAction, None, None, "Action value.") def selectObject(self, obj): """Store a reference to an object in the Image. selectObject(obj) The argument 'obj' is one of the objects stored in the Image. Storing an object with selectObject() is the means by which objects can be copied or modified. """ _parent = obj.getParent() if _parent is None: raise ValueError, "Object has no parent: " + `obj` if not isinstance(_parent, layer.Layer): raise TypeError, "Invalid object parent: " + `type(_parent)` if _parent.getParent() is not self: raise ValueError, "Object not in Image: " + `obj` _seen = False for _obj in self.__selected: if _obj is obj: _seen = True break if not _seen: self.__selected.append(obj) self.sendMessage('selected_object', obj) def deselectObject(self, obj): """Remove any occurance of an object in the Image. deselectObject(obj) If the object is not already selected a ValueError is returned. """ _parent = obj.getParent() if _parent is None: raise ValueError, "Object has no parent: " + `obj` if not isinstance(_parent, layer.Layer): raise TypeError, "Invalid object parent: " + `type(_parent)` if _parent.getParent() is not self: raise ValueError, "Object not in Image: " + `obj` _objs = self.__selected for _i in range(len(_objs)): if _objs[_i] is obj: del _objs[_i] self.sendMessage('deselected_object', obj) break def getSelectedObjects(self, delete=True): """Return all the currently selected objects. getSelectedObjects([delete]) Optional argument 'delete' defaults to True, so calling this method with no arguments will deselected all the selected objects. If the argument is False, the selected entities remain stored. """ util.test_boolean(delete) _objs = self.__selected[:] if delete: self.clearSelectedObjects() return _objs def clearSelectedObjects(self): """Empty the list list of selected objects. clearSelectedObjects() """ for _obj in self.__selected: self.sendMessage('deselected_object', _obj) del self.__selected[:] def hasSelection(self): """Return whether or not there are selected objects in the drawing. hasSelection() """ return len(self.__selected) > 0 def getImageVariables(self): """Get the dictionary storing the variables local to the image. getImageVariables() """ return self.__vars def getExtents(self): """Return the coordinates of a window holding the whole drawing getExtents() The function will return a tuple of the format: (xmin, ymin, xmax, ymax) Each value will be a float. """ _xmin = None _ymin = None _xmax = None _ymax = None _set = False _layers = [self.__top_layer] while (len(_layers)): _layer = _layers.pop() if _layer.isVisible(): _set = True _xmn, _ymn, _xmx, _ymx = _layer.getBoundary() if _xmin is None or _xmn < _xmin: _xmin = _xmn if _ymin is None or _ymn < _ymin: _ymin = _ymn if _xmax is None or _xmx > _xmax: _xmax = _xmx if _ymax is None or _ymx > _ymax: _ymax = _ymx _layers.extend(_layer.getSublayers()) if _set: # make sure the values are different if abs(_xmax - _xmin) < 1e-10: _xmin = _xmin - 1.0 _xmax = _xmax + 1.0 if abs(_ymax - _ymin) < 1e-10: _ymin = _ymin - 1.0 _ymax = _ymax + 1.0 else: _xmin = -1.0 _ymin = -1.0 _xmax = 1.0 _ymax = 1.0 return (_xmin, _ymin, _xmax, _ymax) def getOptions(cls): """Return the list of options that can be set in an Image. getOptions() This method returns a list of strings. """ return Image.__options[:] getOptions = classmethod(getOptions) def getOption(self, key): """Return the value of an option set in the drawing. getOption(key) Return the value of the option associated with the string 'key'. If there is no option found for that key, return None. """ if not isinstance(key, str): raise TypeError, "Invalid key type: " + `type(key)` if key not in Image.__options: raise ValueError, "Invalid option key: '%s'" % key return self.__options.get(key) def setOption(self, key, value): """Set an option in the drawing. setOption(key, value) Argument 'key' must be a string, and argument 'value' can any type of object. Using the same key twice will result on the second value overwriting the first. """ # # testOption will raise a exceptions for invalid values ... # if not isinstance(key, str): raise TypeError, "Invalid key type: " + `type(key)` options.OptionManager.testOption(key, value) if (key == 'LINE_COLOR' or key == 'FONT_COLOR' or key == 'BACKGROUND_COLOR' or key == 'INACTIVE_LAYER_COLOR' or key == 'SINGLE_POINT_COLOR' or key == 'MULTI_POINT_COLOR' or key == 'DIM_COLOR' or key == 'DIM_PRIMARY_FONT_COLOR' or key == 'DIM_SECONDARY_FONT_COLOR'): if value not in self.__colors: self.__colors[value] = True elif key == 'LINE_STYLE': self.setOption('LINE_COLOR', value.getColor()) self.setOption('LINE_TYPE', value.getLinetype()) self.setOption('LINE_THICKNESS', value.getThickness()) if value not in self.__styles: self.__styles.append(value) elif key == 'LINE_TYPE': if value not in self.__linetypes: self.__linetypes.append(value) elif key == 'DIM_STYLE': for _opt in value.getOptions(): _optval = value.getValue(_opt) self.setOption(_opt, _optval) if value not in self.__dimstyles: self.__dimstyles.append(value) elif key == 'TEXT_STYLE': self.setOption('FONT_COLOR', value.getColor()) self.setOption('FONT_WEIGHT', value.getWeight()) self.setOption('FONT_STYLE', value.getStyle()) self.setOption('FONT_FAMILY', value.getFamily()) self.setOption('TEXT_SIZE', value.getSize()) self.setOption('TEXT_ANGLE', value.getAngle()) self.setOption('TEXT_ALIGNMENT', value.getAlignment()) if value not in self.__textstyles: self.__textstyles.append(value) elif (key == 'FONT_FAMILY' or key == 'DIM_PRIMARY_FONT_FAMILY' or key == 'DIM_SECONDARY_FONT_FAMILY'): if value not in self.__fonts: self.__fonts[value] = True else: pass self.__options[key] = value self.sendMessage('option_changed', key, value) def setDefaults(self): """Set Image options to the current global settings. setDefaults() """ _gp = globals.prefs for _opt in Image.__options: self.setOption(_opt, _gp[_opt]) def setFilename(self, fname): """ Set the filename for this image. The filename will be where the system will save the data in this file. """ self.__filename = fname def getFilename(self): """ Return the filename for this image. """ return self.__filename filename = property(getFilename, setFilename, None, "Image filename.") def setTool(self, tool=None): """ Replace the Tool in the Image with a new Tool. The argument 'tool' should be an instance of a Tool object or 'None'. """ if tool is not None and not isinstance(tool, tools.Tool): raise TypeError, "Invalid tool: " + `type(tool)` _ot = self.__tool self.setUnsaved() #each time i set a tool i make some modification if (_ot is not tool): self.__tool = tool self.sendMessage('tool_changed') def getTool(self): """Return the current Tool used in the drawing. getTool() """ return self.__tool tool = property(getTool, setTool, None, "Tool for adding/modifying entities.") def sendsMessage(self, m): if m in Image.__messages: return True return super(Image, self).sendsMessage(m) # # provide some default colors, linetypes, and styles # for an image # def add_defaults(image): # # standard styles # _sstyle = globals.prefs['STANDARD_STYLE'] _dstyle = globals.prefs['DEFAULT_STYLE'] _set_style = False for _style in globals.prefs['STYLES']: image.addStyle(_style) if _style.getName() == _dstyle.getName(): image.setOption('LINE_STYLE', _style) _set_style = True if not _set_style: image.setOption('LINE_STYLE', _sstyle) # # standard colors # for _color in globals.prefs['COLORS']: image.addColor(_color) # # standard linetypes # for _linetype in globals.prefs['LINETYPES']: image.addLinetype(_linetype) # # standards styles # # solid = linetype.Linetype('Solid') # dash1 = linetype.Linetype('Dash1', [4,1]) # dash2 = linetype.Linetype('Dash2', [8,2]) # dash3 = linetype.Linetype('Dash3', [12,2]) # dash4 = linetype.Linetype('Dash4', [10,2,2,2]) # dash5 = linetype.Linetype('Dash5', [15,5,5,5]) # st = style.Style('Solid White Line', solid, white, 1) # image.addStyle(st) # image.setOption('LINE_STYLE', st) # st = style.Style('Solid Black Line', solid, black, 1) # image.addStyle(st) # st = style.Style('Dashed Red Line', dash1, red, 1) # image.addStyle(st) # st = style.Style('Dashed Green Line', dash1, green, 1) # image.addStyle(st) # st = style.Style('Dashed Blue Line', dash1, blue, 1) # image.addStyle(st) # st = style.Style('Dashed Yellow Line', dash2, yellow, 1) # image.addStyle(st) # st = style.Style('Dashed Violet Line', dash2, violet, 1) # image.addStyle(st) # st = style.Style('Dashed Cyan Line', dash2, cyan, 1) # image.addStyle(st) _ds = dimension.Dimension.getDefaultDimStyle() image.addDimStyle(_ds) _dstyle = globals.prefs['DEFAULT_DIMSTYLE'] _dname = None if _dstyle is not None: _dname = _dstyle.getName() _set_style = False for _dimstyle in globals.prefs['DIMSTYLES']: image.addDimStyle(_dimstyle) _name = _dimstyle.getName() if _dname is not None and _name == _dname: image.setOption('DIM_STYLE', _dimstyle) _set_style = True if not _set_style: # print "setting DIM_STYLE to default _ds ..." image.setOption('DIM_STYLE', _ds) # for _opt in _ds.getOptions(): # _val = str(_ds.getValue(_opt)) # print "opt: %s; value: %s" % (_opt, _val) # # FIXME: re-examine this once new text stuff is in place # # _ts = text.TextStyle('default') _ts = text.TextBlock.getDefaultTextStyle() image.addTextStyle(_ts) _tstyle = globals.prefs['DEFAULT_TEXTSTYLE'] _tname = None if _tstyle is not None: _tname = _tstyle.getName() _set_style = False for _textstyle in globals.prefs['TEXTSTYLES']: image.addTextStyle(_textstyle) _name = _textstyle.getName() if _tname is not None and _name == _tname: image.setOption('TEXT_STYLE', _textstyle) _set_style = True if not _set_style: image.setOption('TEXT_STYLE', _ts) # # these will override what the style has set # # image.setOption('FONT_FAMILY', globals.prefs['FONT_FAMILY']) # image.setOption('FONT_SIZE', globals.prefs['FONT_SIZE']) # image.setOption('FONT_STYLE', globals.prefs['FONT_STYLE']) # image.setOption('FONT_WEIGHT', globals.prefs['FONT_WEIGHT']) # _font_color = globals.prefs['FONT_COLOR'].clone() # image.setOption('FONT_COLOR', _font_color) # image.setOption('CHAMFER_LENGTH', globals.prefs['CHAMFER_LENGTH']) # image.setOption('FILLET_RADIUS', globals.prefs['FILLET_RADIUS']) image.setUnits(globals.prefs['UNITS']) # image.setOption('HIGHLIGHT_POINTS', globals.prefs['HIGHLIGHT_POINTS']) # image.setOption('INACTIVE_LAYER_COLOR', globals.prefs['INACTIVE_LAYER_COLOR']) # image.setOption('AUTOSPLIT', globals.prefs['AUTOSPLIT']) # image.setOption('LEADER_ARROW_SIZE', globals.prefs['LEADER_ARROW_SIZE']) # # Image history class # class ImageLog(entity.EntityLog): def __init__(self, image): if not isinstance(image, Image): raise TypeError, "Invalid Image: " + `image` super(ImageLog, self).__init__(image) image.connect('scale_changed', self.__scaleChanged) image.connect('units_changed', self.__unitsChanged) image.connect('added_child', self.__addedChild) image.connect('removed_child', self.__removedChild) def __scaleChanged(self, image, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _scale = args[0] if not isinstance(_scale, float): raise TypeError, "Unexpected type for scale: " + `type(_scale)` if _scale < 1e-10: raise ValueError, "Invalid scale: %g" % _scale self.saveUndoData('scale_changed', _scale) def __unitsChanged(self, image, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _units = args[0] # fixme - maybe add error checking ... self.saveUndoData('units_changed', _units) def __addedChild(self, image, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _obj = args[0] _vals = _obj.getValues() if not isinstance(_vals, entity.EntityData): raise TypeError, "non EntityData for obj: " + `_obj` _vals.lock() self.saveUndoData('added_child', _vals) def __removedChild(self, image, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _obj = args[0] _vals = _obj.getValues() if not isinstance(_vals, entity.EntityData): raise TypeError, "non EntityData for obj: " + `_obj` _vals.lock() self.saveUndoData('removed_child', _vals) def execute(self, undo, *args): # print "ImageLog::execute() ..." # print args util.test_boolean(undo) _alen = len(args) if len(args) == 0: raise ValueError, "No arguments to execute()" _img = self.getObject() _op = args[0] if _op == 'units_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _sdata = _img.getUnits() self.ignore(_op) try: _unit = args[1] if undo: _img.startUndo() try: _img.setUnits(_unit) finally: _img.endUndo() else: _img.startRedo() try: _img.setUnits(_unit) finally: _img.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'scale_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _sdata = _img.getScale() self.ignore(_op) try: _scale = args[1] if undo: _img.startUndo() try: _img.setScale(_scale) finally: _img.endUndo() else: _img.startRedo() try: _img.setScale(_scale) finally: _img.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'added_child': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _vals = args[1] if not isinstance(_vals, entity.EntityData): raise TypeError, "Invalid EntityData: " + `_vals` self.ignore('modified') try: if undo: _lid = _vals.get('id') _layer = None for _child in _img.getChildren(): if _child.getID() == _lid: _layer = _child break if _layer is None: raise ValueError, "Layer not found in Image" _sdata = _vals self.ignore('removed_child') try: _img.startUndo() try: _img.delLayer(_layer) finally: _img.endUndo() finally: self.receive('removed_child') else: _pid = _vals.get('parent_layer') _parent_layer = None for _child in _img.getChildren(): if _child.getID() == _pid: _parent_layer = _child break if _parent_layer is None: raise ValueError, "Parent layer not found in Image" _layer = self.__makeLayer(_vals) self.ignore(_op) try: _img.startRedo() try: _img.addChildLayer(_layer, _parent_layer) finally: _img.endRedo() _sdata = _layer.getValues() _sdata.lock() finally: self.receive(_op) finally: self.receive('modified') self.saveData(undo, _op, _sdata) elif _op == 'removed_child': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _vals = args[1] if not isinstance(_vals, entity.EntityData): raise TypeError, "Invalid EntityData: " + `_vals` self.ignore('modified') try: if undo: _pid = _vals.get('parent_layer') _parent_layer = None for _child in _img.getChildren(): if _child.getID() == _pid: _parent_layer = _child break if _parent_layer is None: raise ValueError, "Parent layer not found in Image" _layer = self.__makeLayer(_vals) self.ignore('added_child') try: _img.startUndo() try: _img.addChildLayer(_layer, _parent_layer) finally: _img.endUndo() _sdata = _layer.getValues() _sdata.lock() finally: self.receive('added_child') else: _lid = _vals.get('id') _layer = None for _child in _img.getChildren(): if _child.getID() == _lid: _layer = _child break if _layer is None: raise ValueError, "Layer not found in Image" _sdata = _vals self.ignore(_op) try: _img.startRedo() try: _img.delLayer(_layer) finally: _img.endRedo() finally: self.receive(_op) finally: self.receive('modified') self.saveData(undo, _op, _sdata) else: super(ImageLog, self).execute(undo, *args) def __makeLayer(self, values): _type = values.get('type') if _type != 'layer': _keys = values.keys() _keys.sort() for _key in _keys: print "key: %s: value: %s" % (_key, str(values.get(_key))) raise RuntimeError, "Invalid layer values" _id = values.get('id') if _id is None: raise ValueError, "Lost 'id' for recreating Layer" _name = values.get('name') if _name is None: raise ValueError, "Lost 'name' value for Layer" _scale = values.get('scale') if _scale is None: raise ValueError, "Lost 'scale' value for Layer" _layer = layer.Layer(_name, id=_id) _layer.setScale(_scale) return _layer PythonCAD-DS1-R37/PythonCAD/Generic/arc.py0000644000175000017500000011471011307666732017454 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # arc class # from __future__ import generators import math from PythonCAD.Generic import style from PythonCAD.Generic import util from PythonCAD.Generic import graphicobject from PythonCAD.Generic import linetype from PythonCAD.Generic import color from PythonCAD.Generic import point from PythonCAD.Generic import tolerance from PythonCAD.Generic import quadtree from PythonCAD.Generic.pyGeoLib import Vector _dtr = math.pi/180.0 _rtd = 180.0/math.pi class Arc(graphicobject.GraphicObject): """A class for Arcs. An Arc has four attributes: center: A Point object radius: The Arc's radius start_angle: The start angle end_angle: The end angle An Arc has the following methods: {get/set}Center(): Get/Set the center Point of an Arc. {get/set}Radius(): Get/Set the radius of an Arc. {get/set}StartAngle(): Get/Set the starting angle of an Arc. {get/set}EndAngle(): Get/Set the end angle of an arc move(): Move the Arc. length(): Return the length of an Arc. area(): Return the area of an Arc. mapPoint(): Find the nearest Point on the Arc to some other Point. mapCoords(): Find the nearest Point on the Arc to a coordinate pair. inRegion(): Returns whether or not a Arc can be seen in a bounded area. clone(): Return an indentical copy of a Arc. """ __defstyle = None __messages = { 'moved' : True, 'center_changed' : True, 'radius_changed' : True, 'start_angle_changed' : True, 'end_angle_changed' : True } def __init__(self, center, radius, start_angle, end_angle, st=None, lt=None, col=None, th=None, **kw): """Initialize a Arc. Arc(center, radius, start_angle, end_angle) The center should be a Point, or a two-entry tuple of floats, and the radius should be a float greater than 0. """ _cp = center if not isinstance(_cp, point.Point): _cp = point.Point(center) _r = util.get_float(radius) if not _r > 0.0: raise ValueError, "Invalid radius: %g" % _r _st = st _sa = util.make_c_angle(start_angle) _ea = util.make_c_angle(end_angle) if _st is None: _st = self.getDefaultStyle() super(Arc, self).__init__(_st, lt, col, th, **kw) self.__radius = _r self.__sa = _sa self.__ea = _ea self.__center = _cp _cp.connect('moved', self.__movePoint) _cp.connect('change_pending', self.__pointChangePending) _cp.connect('change_complete', self.__pointChangeComplete) _cp.storeUser(self) def __eq__(self, obj): """Compare a Arc to another for equality. """ if not isinstance(obj, Arc): return False if obj is self: return True return ((self.__center == obj.getCenter()) and (abs(self.__radius - obj.getRadius()) < 1e-10) and (abs(self.__sa - obj.getStartAngle()) < 1e-10) and (abs(self.__ea - obj.getEndAngle()) < 1e-10)) def __ne__(self, obj): """Compare a Arc to another for inequality. """ if not isinstance(obj, Arc): return True if obj is self: return False return ((self.__center != obj.getCenter()) or (abs(self.__radius - obj.getRadius()) > 1e-10) or (abs(self.__sa - obj.getStartAngle()) > 1e-10) or (abs(self.__ea - obj.getEndAngle()) > 1e-10)) def getDefaultStyle(cls): if cls.__defstyle is None: _s = style.Style(u'Default Arc Style', linetype.Linetype(u'Solid', None), color.Color(0xffffff), 1.0) cls.__defstyle = _s return cls.__defstyle getDefaultStyle = classmethod(getDefaultStyle) def setDefaultStyle(cls, s): if not isinstance(s, style.Style): raise TypeError, "Invalid style: " + `type(s)` cls.__defstyle = s setDefaultStyle = classmethod(setDefaultStyle) def finish(self): self.__center.disconnect(self) self.__center.freeUser(self) self.__center = self.__radius = self.__sa = self.__ea = None super(Arc, self).finish() def setStyle(self, s): """Set the Style of the Arc. setStyle(s) This method extends GraphicObject::setStyle(). """ _s = s if _s is None: _s = self.getDefaultStyle() super(Arc, self).setStyle(_s) def getValues(self): """Return values comprising the Arc. getValues() This method extends the GraphicObject::getValues() method. """ _data = super(Arc, self).getValues() _data.setValue('type', 'arc') _data.setValue('center', self.__center.getID()) _data.setValue('radius', self.__radius) _data.setValue('start_angle', self.__sa) _data.setValue('end_angle', self.__ea) return _data def getCenter(self): """Return the center Point of the Arc. getCenter() """ return self.__center def setCenter(self, c): """Set the center Point of the Arc. setCenter(c) The argument must be a Point or a tuple containing two float values. """ if self.isLocked(): raise RuntimeError, "Setting center not allowed - object locked." _cp = self.__center if not isinstance(c, point.Point): raise TypeError, "Invalid center point: " + `c` if _cp is not c: _cp.disconnect(self) _cp.freeUser(self) self.startChange('center_changed') self.__center = c self.endChange('center_changed') self.sendMessage('center_changed', _cp) c.connect('moved', self.__movePoint) c.connect('change_pending', self.__pointChangePending) c.connect('change_complete', self.__pointChangeComplete) c.storeUser(self) if abs(_cp.x - c.x) > 1e-10 or abs(_cp.y - c.y) > 1e-10: self.sendMessage('moved', _cp.x, _cp.y, self.__radius, self.__sa, self.__ea) self.modified() center = property(getCenter, setCenter, None, "Arc center") def getRadius(self): """Return the radius of the the Arc. getRadius() """ return self.__radius def setRadius(self, radius): """Set the radius of the Arc. setRadius(radius) The argument must be float value greater than 0. """ if self.isLocked(): raise RuntimeError, "Setting radius not allowed - object locked." _r = util.get_float(radius) if not _r > 0.0: raise ValueError, "Invalid radius: %g" % _r _cr = self.__radius if abs(_cr - _r) > 1e-10: self.startChange('radius_changed') self.__radius = _r self.endChange('radius_changed') self.sendMessage('radius_changed', _cr) _cx, _cy = self.__center.getCoords() self.sendMessage('moved', _cx, _cy, _cr, self.__sa, self.__ea) self.modified() radius = property(getRadius, setRadius, None, "Arc radius") def getStartAngle(self): """Return the start_angle for the Arc. getStartAngle() """ return self.__sa def setStartAngle(self, angle): """Set the start_angle for the Arc. setStartAngle(angle) The argument angle should be a float. """ if self.isLocked(): raise RuntimeError, "Setting start angle not allowed - object locked." _sa = self.__sa _angle = util.make_c_angle(angle) if abs(_sa - _angle) > 1e-10: self.startChange('start_angle_changed') self.__sa = _angle self.endChange('start_angle_changed') self.sendMessage('start_angle_changed', _sa) _cx, _cy = self.__center.getCoords() self.sendMessage('moved', _cx, _cy, self.__radius, _sa, self.__ea) self.modified() start_angle = property(getStartAngle, setStartAngle, None, "Start angle for the Arc.") def getEndAngle(self): """Return the end_angle for the Arc. getEndAngle() """ return self.__ea def setEndAngle(self, angle): """Set the end_angle for the Arc. setEndAngle(angle) The argument angle should be a float. """ if self.isLocked(): raise RuntimeError, "Setting end angle not allowed - object locked." _ea = self.__ea _angle = util.make_c_angle(angle) if abs(_ea - _angle) > 1e-10: self.startChange('end_angle_changed') self.__ea = _angle self.endChange('end_angle_changed') self.sendMessage('end_angle_changed', _ea) _cx, _cy = self.__center.getCoords() self.sendMessage('moved', _cx, _cy, self.__radius, self.__sa, _ea) self.modified() end_angle = property(getEndAngle, setEndAngle, None, "End angle for the Arc.") def getAngle(self): """Return the angular sweep of the Arc. getAngle() """ _sa = self.__sa _ea = self.__ea if abs(_ea - _sa) < 1e-10: _angle = 360.0 elif _ea > _sa: _angle = _ea - _sa else: _angle = 360.0 - _sa + _ea return _angle def throughAngle(self, angle): """Return True if an arc passes through some angle throughAngle(angle) The argument angle should be a float value. This method returns True if the arc exists at that angle, otherwise the method returns False. """ _angle = math.fmod(util.get_float(angle), 360.0) if _angle < 0.0: _angle = _angle + 360.0 _sa = self.__sa _ea = self.__ea _val = True if abs(_sa - _ea) > 1e-10: if _sa > _ea: if _angle > _ea and _angle < _sa: _val = False else: if _angle > _ea or _angle < _sa: _val = False return _val def getEndpoints(self): """Return where the two endpoints for the arc-segment lie. getEndpoints(self) This function returns two tuples, each containing the x-y coordinates of the arc endpoints. The first tuple corresponds to the endpoint at the start_angle, the second to the endpoint at the end_angle. """ _cx, _cy = self.__center.getCoords() _r = self.__radius _sa = self.__sa _sax = _cx + _r * math.cos(_sa * _dtr) _say = _cy + _r * math.sin(_sa * _dtr) _ea = self.__ea _eax = _cx + _r * math.cos(_ea * _dtr) _eay = _cy + _r * math.sin(_ea * _dtr) return (_sax, _say), (_eax, _eay) def length(self): """Return the length of the Arc. length() """ return 2.0 * math.pi * self.__radius * (self.getAngle()/360.0) def area(self): """Return the area enclosed by the Arc. area() """ return math.pi * pow(self.__radius, 2) * (self.getAngle()/360.0) def move(self, dx, dy): """Move a Arc. move(dx, dy) The first argument gives the x-coordinate displacement, and the second gives the y-coordinate displacement. Both values should be floats. """ if self.isLocked(): raise RuntimeError, "Setting radius not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _x, _y = self.__center.getCoords() self.ignore('moved') try: self.__center.move(_dx, _dy) finally: self.receive('moved') self.sendMessage('moved', _x, _y, self.__radius, self.__sa, self.__ea) def mapCoords(self, x, y, tol=tolerance.TOL): """Return the nearest Point on the Arc to a coordinate pair. mapCoords(x, y[, tol]) The function has two required arguments: x: A Float value giving the x-coordinate y: A Float value giving the y-coordinate There is a single optional argument: tol: A float value equal or greater than 0.0 This function is used to map a possibly near-by coordinate pair to an actual Point on the Arc. If the distance between the actual Point and the coordinates used as an argument is less than the tolerance, the actual Point is returned. Otherwise, this function returns None. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _cx, _cy = self.__center.getCoords() _r = self.__radius _dist = math.hypot((_x - _cx), (_y - _cy)) if abs(_dist - _r) < _t: _ra = math.atan2((_y - _cy), (_x - _cx)) _da = _ra * _rtd if _da < 0.0: _da = _da + 360.0 if self.throughAngle(_da): _xoff = _r * math.cos(_ra) _yoff = _r * math.sin(_ra) return (_cx + _xoff), (_cy + _yoff) return None def GetTangentPoint(self,x,y,outx,outy): """ Get the tangent from an axternal point args: x,y is a point near the circle xout,yout is a point far from the circle return: a tuple(x,y,x1,xy) that define the tangent line """ firstPoint=point.Point(x,y) fromPoint=point.Point(outx,outy) twoPointDistance=self.__center.Dist(fromPoint) if(twoPointDistancecy): #stupid situation rightAngle=-rightAngle posAngle=rightAngle+tgAngle negAngle=rightAngle-tgAngle #Compute the Positive Tangent xCord=math.cos(posAngle) yCord=math.sin(posAngle) dirPoint=point.Point(xCord,yCord)#Versor that point at the tangentPoint ver=Vector(originPoint,dirPoint) ver.Mult(tanMod) tangVectorPoint=ver.Point() posPoint=point.Point(tangVectorPoint+(outx,outy)) #Compute the Negative Tangent xCord=math.cos(negAngle) yCord=math.sin(negAngle) dirPoint=point.Point(xCord,yCord)#Versor that point at the tangentPoint ver=Vector(originPoint,dirPoint) ver.Mult(tanMod) tangVectorPoint=ver.Point() negPoint=point.Point(tangVectorPoint+(outx,outy)) if(firstPoint.Dist(posPoint) _xmax) or (_aymin > _ymax) or (_axmax < _xmin) or (_aymax < _ymin)): return False _val = False _bits = 0 # # calculate distances from center to region boundary # if abs(_xc - _xmin) < _r: _bits = _bits | 1 # left edge if abs(_xc - _xmax) < _r: _bits = _bits | 2 # right edge if abs(_yc - _ymin) < _r: _bits = _bits | 4 # bottom edge if abs(_yc - _ymax) < _r: _bits = _bits | 8 # top edge if _bits == 0: # # arc must be visible - the center is in # the region and is more than the radius from # each edge # _val = True else: # # calculate distance to corners of region # if math.hypot((_xc - _xmin), (_yc - _ymax)) < _r: _bits = _bits | 0x10 # upper left if math.hypot((_xc - _xmax), (_yc - _ymin)) < _r: _bits = _bits | 0x20 # lower right if math.hypot((_xc - _xmin), (_yc - _ymin)) < _r: _bits = _bits | 0x40 # lower left if math.hypot((_xc - _xmax), (_yc - _ymax)) < _r: _bits = _bits | 0x80 # upper right # # if all bits are set then distance from arc center # to region endpoints is less than radius - arc # entirely outside the region # _val = not ((_bits == 0xff) or fully) # # if the test value is still true, check that the # arc boundary can overlap with the region # if _val: _ep1, _ep2 = self.getEndpoints() _axmin = min(_xc, _ep1[0], _ep2[0]) if self.throughAngle(180.0): _axmin = _xc - _r if _axmin > _xmax: return False _aymin = min(_yc, _ep1[1], _ep2[1]) if self.throughAngle(270.0): _aymin = _yc - _r if _aymin > _ymax: return False _axmax = max(_xc, _ep1[0], _ep2[0]) if self.throughAngle(0.0): _axmax = _xc + _r if _axmax < _xmin: return False _aymax = max(_yc, _ep1[1], _ep2[1]) if self.throughAngle(90.0): _aymax = _yc + _r if _aymax < _ymin: return False return _val def getBounds(self): _ep1, _ep2 = self.getEndpoints() _xc, _yc = self.__center.getCoords() _r = self.__radius _xmin = min(_xc, _ep1[0], _ep2[0]) _ymin = min(_yc, _ep1[1], _ep2[1]) _xmax = max(_xc, _ep1[0], _ep2[0]) _ymax = max(_yc, _ep1[1], _ep2[1]) if self.throughAngle(0.0): _xmax = _xc + _r if self.throughAngle(90.0): _ymax = _yc + _r if self.throughAngle(180.0): _xmin = _xc - _r if self.throughAngle(270.0): _ymin = _yc - _r return _xmin, _ymin, _xmax, _ymax def __pointChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.startChange('moved') def __pointChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.endChange('moved') def __movePoint(self, p, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _cp = self.__center if p is not _cp: raise ValueError, "Point is not arc center: " + `p` _x, _y = _cp.getCoords() self.sendMessage('moved', _x, _y, self.__radius, self.__sa, self.__ea) def clone(self): """Create an identical copy of a Arc clone() """ _cp = self.__center.clone() _r = self.__radius _sa = self.__sa _ea = self.__ea _st = self.getStyle() _lt = self.getLinetype() _col = self.getColor() _th = self.getThickness() return Arc(_cp, _r, _sa, _ea, _st, _lt, _col, _th) def sendsMessage(self, m): if m in Arc.__messages: return True return super(Arc, self).sendsMessage(m) # # static functions for Arc class # def test_angle(s, e, a): """Returns if an angle lies between the start and end angle of an arc. test_angle(s, e, a) The arguments are: s: arc start angle e: arc end angle a: angle being tested """ _val = False if ((abs(e - s) < 1e-10) or ((s > e) and ((s <= a <= 360.0) or (0.0 <= a <= e))) or (s <= a <= e)): _val = True return _val test_angle = staticmethod(test_angle) # # Quadtree Arc storage # class ArcQuadtree(quadtree.Quadtree): def __init__(self): super(ArcQuadtree, self).__init__() def getNodes(self, *args): _alen = len(args) if _alen != 4: raise ValueError, "Expected 4 arguments, got %d" % _alen _axmin = util.get_float(args[0]) _aymin = util.get_float(args[1]) _axmax = util.get_float(args[2]) if not _axmax > _axmin: raise ValueError, "xmax not greater than xmin" _aymax = util.get_float(args[3]) if not _aymax > _aymin: raise ValueError, "ymax not greater than ymin" _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_axmin > _xmax) or (_axmax < _xmin) or (_aymin > _ymax) or (_aymax < _ymin)): continue if _node.hasSubnodes(): _xmid = (_xmin + _xmax)/2.0 _ymid = (_ymin + _ymax)/2.0 _ne = _nw = _sw = _se = True if _axmax < _xmid: # arc on left side _ne = _se = False if _axmin > _xmid: # arc on right side _nw = _sw = False if _aymax < _ymid: # arc below _nw = _ne = False if _aymin > _ymid: # arc above _sw = _se = False if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: yield _node def addObject(self, obj): if not isinstance(obj, Arc): raise TypeError, "Invalid Arc object: " + `obj` if obj in self: return _bounds = self.getTreeRoot().getBoundary() _xmin = _ymin = _xmax = _ymax = None _axmin, _aymin, _axmax, _aymax = obj.getBounds() _resize = False if _bounds is None: # first node in tree _resize = True _xmin = _axmin - 1.0 _ymin = _aymin - 1.0 _xmax = _axmax + 1.0 _ymax = _aymax + 1.0 else: _xmin, _ymin, _xmax, _ymax = _bounds if _axmin < _xmin: _xmin = _axmin - 1.0 _resize = True if _axmax > _xmax: _xmax = _axmax + 1.0 _resize = True if _aymin < _ymin: _ymin = _aymin - 1.0 _resize = True if _aymax > _ymax: _ymax = _aymax + 1.0 _resize = True if _resize: self.resize(_xmin, _ymin, _xmax, _ymax) for _node in self.getNodes(_axmin, _aymin, _axmax, _aymax): _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if obj.inRegion(_xmin, _ymin, _xmax, _ymax): _node.addObject(obj) super(ArcQuadtree, self).addObject(obj) obj.connect('moved', self._moveArc) def delObject(self, obj): if obj not in self: return _axmin, _aymin, _axmax, _aymax = obj.getBounds() _pdict = {} for _node in self.getNodes(_axmin, _aymin, _axmax, _aymax): _node.delObject(obj) # arc may not be in the node ... _parent = _node.getParent() if _parent is not None: _pid = id(_parent) if _pid not in _pdict: _pdict[_pid] = _parent super(ArcQuadtree, self).delObject(obj) obj.disconnect(self) for _parent in _pdict.values(): self.purgeSubnodes(_parent) def find(self, *args): _alen = len(args) if _alen < 5: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _r = util.get_float(args[2]) _sa = util.get_float(args[3]) _ea = util.get_float(args[4]) _t = tolerance.TOL if _alen > 5: _t = tolerance.toltest(args[5]) _axmin = _x - _r - _t _axmax = _x + _r + _t _aymin = _y - _r - _t _aymax = _y + _r + _t _arcs = [] for _arc in self.getInRegion(_axmin, _aymin, _axmax, _aymax): _cx, _cy = _arc.getCenter().getCoords() if ((abs(_cx - _x) < _t) and (abs(_cy - _y) < _t) and (abs(_arc.getRadius() - _r) < _t) and (abs(_arc.getStartAngle() - _sa) < 1e-10) and (abs(_arc.getEndAngle() - _ea) < 1e-10)): _arcs.append(_arc) return _arcs def _moveArc(self, obj, *args): if obj not in self: raise ValueError, "Arc not stored in Quadtree: " + `obj` _alen = len(args) if _alen < 5: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _r = util.get_float(args[2]) _sa = util.get_float(args[3]) _ea = util.get_float(args[4]) _sax = _x + _r * math.cos(_sa * _dtr) _say = _y + _r * math.sin(_sa * _dtr) _eax = _x + _r * math.cos(_ea * _dtr) _eay = _y + _r * math.sin(_ea * _dtr) _axmin = min(_x, _sax, _eax) if ((abs(_sa - 180.0) < 1e-10) or (abs(_ea - 180.0) < 1e-10) or ((_sa < _ea) and (_sa < 180.0 < _ea)) or ((_ea < _sa) and (_sa < 180.0))): _axmin = _x - _r _axmax = max(_x, _sax, _eax) if ((abs(_sa) < 1e-10) or (abs(_ea) < 1e-10) or ((_sa > _ea) and (_ea > 0.0))): _axmax = _x + _r _aymin = min(_y, _say, _eay) if ((abs(_sa - 270.0) < 1e-10) or (abs(_ea - 270.0) < 1e-10) or ((_sa < _ea) and (_sa < 270.0 < _ea)) or ((_ea < _sa) and (_sa < 270.0))): _aymin = _y - _r _aymax = max(_y, _say, _eay) if ((abs(_sa - 90.0) < 1e-10) or (abs(_ea - 90.0) < 1e-10) or ((_sa < _ea) and (_sa < 90.0 < _ea)) or ((_ea < _sa) and (_sa < 90.0))): _aymax = _y + _r for _node in self.getNodes(_axmin, _aymin, _axmax, _aymax): _node.delObject(obj) # arc may not be in node ... super(ArcQuadtree, self).delObject(obj) obj.disconnect(self) self.addObject(obj) def getClosest(self, x, y, tol=tolerance.TOL): _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _arc = _tsep = None _bailout = False _adict = {} _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_x < (_xmin - _t)) or (_x > (_xmax + _t)) or (_y < (_ymin - _t)) or (_y > (_ymax + _t))): continue if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) else: for _a in _node.getObjects(): _aid = id(_a) if _aid not in _adict: _ap = _a.mapCoords(_x, _y, _t) if _ap is not None: _ax, _ay = _ap _sep = math.hypot((_ax - _x), (_ay - _y)) if _tsep is None: _tsep = _sep _arc = _a else: if _sep < _tsep: _tsep = _sep _arc = _a if _sep < 1e-10 and _arc is not None: _bailout = True break if _bailout: break return _arc def getInRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _arcs = [] if not len(self): return _arcs _nodes = [self.getTreeRoot()] _adict = {} while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): for _subnode in _node.getSubnodes(): _sxmin, _symin, _sxmax, _symax = _subnode.getBoundary() if ((_sxmin > _xmax) or (_symin > _ymax) or (_sxmax < _xmin) or (_symax < _ymin)): continue _nodes.append(_subnode) else: for _arc in _node.getObjects(): _aid = id(_arc) if _aid not in _adict: if _arc.inRegion(_xmin, _ymin, _xmax, _ymax): _arcs.append(_arc) _adict[_aid] = True return _arcs # # Arc history class # class ArcLog(graphicobject.GraphicObjectLog): def __init__(self, a): if not isinstance(a, Arc): raise TypeError, "Invalid arc: " + `a` super(ArcLog, self).__init__(a) a.connect('center_changed' ,self.__centerChanged) a.connect('radius_changed', self.__radiusChanged) a.connect('start_angle_changed', self.__saChanged) a.connect('end_angle_changed', self.__eaChanged) def __radiusChanged(self, a, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _r = args[0] if not isinstance(_r, float): raise TypeError, "Unexpecte type for radius: " + `type(_r)` self.saveUndoData('radius_changed', _r) def __centerChanged(self, a, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _old = args[0] if not isinstance(_old, point.Point): raise TypeError, "Invalid old center point: " + `_old` self.saveUndoData('center_changed', _old.getID()) def __saChanged(self, a, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _sa = args[0] if not isinstance(_sa, float): raise TypeError, "Unexpected type for angle: " + `type(_sa)` self.saveUndoData('start_angle_changed', _sa) def __eaChanged(self, a, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _ea = args[0] if not isinstance(_ea, float): raise TypeError, "Unexpected type for angle: " + `type(_ea)` self.saveUndoData('end_angle_changed', _ea) def execute(self, undo, *args): # # fixme - deal with the endpoints ... # def _used_by(obj, plist): _objpt = None for _pt in plist: for _user in _pt.getUsers(): if _user is obj: _objpt = _pt break if _objpt is not None: break return _objpt def _most_used(plist): _pmax = plist.pop() _max = _pmax.countUsers() for _pt in plist: _count = _pt.countUsers() if _count > _max: _max = _count _pmax = _pt return _pmax util.test_boolean(undo) _alen = len(args) if _alen == 0: raise ValueError, "No arguments to execute()" _a = self.getObject() _cp = _a.getCenter() _op = args[0] if _op == 'center_changed': if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _oid = args[1] _parent = _a.getParent() if _parent is None: raise ValueError, "Arc has no parent - cannot undo" _pt = _parent.getObject(_oid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "Center point missing: id=%d" % _oid _ep1, _ep2 = _a.getEndpoints() _pts = _parent.find('point', _ep1[0], _ep1[1]) _ep = _used_by(_a, _pts) assert _ep is not None, "Arc endpoint not found in layer" _ep.freeUser(_a) _pts = _parent.find('point', _ep2[0], _ep2[1]) _ep = _used_by(_a, _pts) assert _ep is not None, "Arc endpoint not found in layer" _ep.freeUser(_a) _sdata = _cp.getID() self.ignore(_op) try: if undo: _a.startUndo() try: _a.setCenter(_pt) finally: _a.endUndo() else: _a.startRedo() try: _a.setCenter(_pt) finally: _a.endRedo() finally: self.receive(_op) _ep1, _ep2 = _a.getEndpoints() _pts = _parent.find('point', _ep1[0], _ep1[1]) _ep = _most_used(_pts) _ep.storeUser(_a) _pts = _parent.find('point', _ep2[0], _ep2[1]) _ep = _most_used(_pts) _ep.storeUser(_a) self.saveData(undo, _op, _sdata) elif _op == 'radius_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _r = args[1] if not isinstance(_r, float): raise TypeError, "Unexpected type for radius: " + `type(_r)` _sdata = _a.getRadius() self.ignore(_op) try: if undo: _a.startUndo() try: _a.setRadius(_r) finally: _a.endUndo() else: _a.startRedo() try: _a.setRadius(_r) finally: _a.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'start_angle_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _sa = args[1] if not isinstance(_sa, float): raise TypeError, "Unexpected type for angle: " + `type(_sa)` _sdata = _a.getStartAngle() self.ignore(_op) try: if undo: _a.startUndo() try: _a.setStartAngle(_sa) finally: _a.endUndo() else: _a.startRedo() try: _a.setStartAngle(_sa) finally: _a.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'end_angle_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _ea = args[1] if not isinstance(_ea, float): raise TypeError, "Unexpected type for angle: " + `type(_ea)` _sdata = _a.getEndAngle() self.ignore(_op) try: if undo: _a.startUndo() try: _a.setEndAngle(_ea) finally: _a.endUndo() else: _a.startRedo() try: _a.setEndAngle(_ea) finally: _a.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) else: super(ArcLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/keywords.py0000644000175000017500000000635011307666657020564 0ustar matteomatteo# # Copyright (c) 2003 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # This code sets the global entries for the gtkimage.entry box # commands text to 'defined' behavior for an application set # thus simulating a mainstream CAD package at the users need # # Author: David Broadwell ( dbroadwell@mindspring.com, 05/26/2003 ) # """ Defaultglobals is loaded by default, use it's pattern to make your own behave like the CAD you are familiar with. Please note the example below; exampledefinitions = { 'foobar' : "quit()", 'foo' : "segment()", 'X' : "quit()", 'O' : "opend()" } """ defaultglobals = { 'acline' : "acline", 'acl' : "acline", 'adim' : "adim", 'arc' : "arcc", 'ccir2' : "ccir2p", 'ccir' : "ccircen", 'chamfer' : "chamfer", 'cir2' : "cir2p", 'cir' : "circen", 'cl' : "cl", 'close' : "close", 'copy' : "copy", 'cut' : "cut", 'delete' : "delete", 'del' : "delete", 'deselect' : "deselect", 'dimpref' : "dimpref", 'exit' : "quit", 'fillet' : "fillet", 'hcline' : "hcline", 'hcl' : "hcline", 'hdim' : "hdim", 'ldim' : "ldim", 'leader' : "leader", 'lead' : "leader", 'mirror' : "mirror", 'mir' : "mirror", 'move' : "move", 'mv' : "move", 'moveh' : "moveh", 'movev' : "movev", 'new' : "new", 'opend' : "opend", 'paste' : "paste", 'pcline' : "pcline", 'point' : "point", 'polyline' : "polyline", 'pline' : "polyline", 'print' : "print", 'plot' : "print", 'pref' : "pref", 'quit' : "quit", 'rdim' : "rdim", 'rectangle' : "rect", 'rect' : "rect", 'redraw' : "redraw", 'refresh' : "refresh", 'r' : "refresh", 'saa' : "saa", 'saacl' : "saacl", 'sac' : "sac", 'sacc' : "sacc", 'sacl' : "sacl", 'sahcl' : "sahcl", 'sap' : "sap", 'sas' : "sas", 'savcl' : "savcl", 'saveas' : "saveas", 'savel' : "savel", 'saves' : "saves", 'select' : "select", 'sv' : "saves", 'segment' : "segment", 'seg' : "segment", 'l' : "segment", 'split' : "split", 'str' : "str", 'strh' : "strh", 'strv' : "strv", 'tcline' : "tcline", 'tcl' : "tcline", 'text' : "text", 'transfer' : "transfer", 'unselect' : "deselect", 'vcline' : "vcline", 'vcl' : "vcline", 'vdim' : "vdim", 'zoomd' : "zoomd", 'z' : "zoomd", 'zoomf' : "zoomf", 'zf' : "zoomf", 'zoomi' : "zoomi", 'zi' : "zoomi", 'zoomo' : "zoomo", 'zo' : "zoomo" } acadglobals = defaultglobals # me10globals = defaultglobals PythonCAD-DS1-R37/PythonCAD/Generic/imageio.py0000644000175000017500000036572011307666657020340 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # code for doing file saves/loads # import sys # # the 'import xml.dom' and 'import xml.parsers.expat' statements # are not directly necessary but adding them seems to fix some # Python XML parsing bugs. Very odd ... # import xml.dom import xml.dom.minidom import xml.parsers.expat from PythonCAD.Generic import layer from PythonCAD.Generic import color from PythonCAD.Generic import linetype from PythonCAD.Generic import style from PythonCAD.Generic import point from PythonCAD.Generic import segment from PythonCAD.Generic import circle from PythonCAD.Generic import arc from PythonCAD.Generic import hcline from PythonCAD.Generic import vcline from PythonCAD.Generic import acline from PythonCAD.Generic import cline from PythonCAD.Generic import ccircle from PythonCAD.Generic import units from PythonCAD.Generic import segjoint from PythonCAD.Generic import leader from PythonCAD.Generic import polyline from PythonCAD.Generic import text from PythonCAD.Generic import dimension from PythonCAD.Generic import fileio from PythonCAD.Generic import globals def _save_graph_bits(obj, node, doc, map): _st = obj.getStyle() assert _st in map, "Object %s style %s not in map!" % (str(obj), `_st`) _attr = doc.createAttributeNS("image", "style") node.setAttributeNodeNS(_attr) node.setAttributeNS("image", "style", `map[_st]`) _color = obj.getColor() if _color != _st.getColor(): assert _color in map, "Object %s color not in map!" % str(obj) _attr = doc.createAttributeNS("image", "color") node.setAttributeNodeNS(_attr) node.setAttributeNS("image", "color", `map[_color]`) _linetype = obj.getLinetype() if _linetype != _st.getLinetype(): assert _linetype in map, "Object %s linetype not in map!" % str(obj) _attr = doc.createAttributeNS("image", "linetype") node.setAttributeNodeNS(_attr) node.setAttributeNS("image", "linetype", `map[_linetype]`) _thickness = obj.getThickness() _tdiff = _thickness - _st.getThickness() if abs(_tdiff) > 1e-10: _attr = doc.createAttributeNS("image", "thickness") node.setAttributeNodeNS(_attr) node.setAttributeNS("image", "thickness", `_thickness`) def _save_state_bits(obj, node, doc): if not obj.isVisible(): _attr = doc.createAttributeNS("image", "visibility") node.setAttributeNodeNS(_attr) node.setAttributeNS("image", "visibility", "False") if obj.isLocked(): _attr = doc.createAttributeNS("image", "locked") node.setAttributeNodeNS(_attr) node.setAttributeNS("image", "locked", "True") def _save_leaders(lyr, node, doc, map): _leaders = lyr.getLayerEntities("leader") if len(_leaders): _leads = doc.createElementNS("image", "image:Leaders") node.appendChild(_leads) _i = 0 for _lead in _leaders: _p1, _p2, _p3 = _lead.getPoints() _i1 = id(_p1) _i2 = id(_p2) _i3 = id(_p3) assert _i1 in map, "Leader %s p1 not in map!" % str(_lead) assert _i2 in map, "Leader %s p2 not in map!" % str(_lead) assert _i3 in map, "Leader %s p3 not in map!" % str(_lead) _child = doc.createElementNS("image", "image:Leader") _leads.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "p1") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "p1", `map[_i1]`) _attr = doc.createAttributeNS("image", "p2") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "p2", `map[_i2]`) _attr = doc.createAttributeNS("image", "p3") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "p3", `map[_i3]`) _attr = doc.createAttributeNS("image", "size") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "size", `_lead.getArrowSize()`) _save_graph_bits(_lead, _child, doc, map) _save_state_bits(_lead, _child, doc) _i = _i + 1 def _save_polylines(lyr, node, doc, map): _polylines = lyr.getLayerEntities("polyline") if len(_polylines): _polys = doc.createElementNS("image", "image:Polylines") node.appendChild(_polys) _i = 0 for _polyline in _polylines: _pts = _polyline.getPoints() _mpts = [] for _pt in _pts: _ip = id(_pt) assert _ip in map, "Polyline point not in map: " + str(_pt) _mpts.append(map[_ip]) _child = doc.createElementNS("image", "image:Polyline") _polys.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "points") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "points", `_mpts`) _save_graph_bits(_polyline, _child, doc, map) _save_state_bits(_polyline, _child, doc) _i = _i + 1 def _save_textblocks(lyr, node, doc, map): _textblocks = lyr.getLayerEntities("text") if len(_textblocks): _tbs = doc.createElementNS("image", "image:TextBlocks") node.appendChild(_tbs) _i = 0 for _textblock in _textblocks: _x, _y = _textblock.getLocation() _text = _textblock.getText() _style = _textblock.getTextStyle() assert _style in map, "TextBlock textstyle not in map: " + `_style` _child = doc.createElementNS("image", "image:TextBlock") _tbs.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "x") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "x", `_x`) _attr = doc.createAttributeNS("image", "y") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "y", `_y`) _attr = doc.createAttributeNS("image", "tsid") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "tsid", `map[_style]`) _save_state_bits(_textblock, _child, doc) # # save any override values as attributes # _tbfamily = _textblock.getFamily() if _tbfamily != _style.getFamily(): assert _tbfamily in map, "Missing font family in map: " + _tbfamily _attr = doc.createAttributeNS("image", "fid") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "fid", `map[_tbfamily]`) _weight = _textblock.getWeight() if _weight != _style.getWeight(): _tbweight = text.font_weight_string(_weight) _attr = doc.createAttributeNS("image", "weight") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "weight", _tbweight) _st = _textblock.getStyle() if _st != _style.getStyle(): _tbstyle = text.font_style_string(_st) _attr = doc.createAttributeNS("image", "style") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "style", _tbstyle) _tbsize = _textblock.getSize() if _tbsize != _style.getSize(): _attr = doc.createAttributeNS("image", "size") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "size", `_tbsize`) _tbcolor = _textblock.getColor() if _tbcolor != _style.getColor(): assert _tbcolor in map, "Missing font color in map: " + str(_tbcolor) _attr = doc.createAttributeNS("image", "cid") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "cid", `map[_tbcolor]`) _tbangle = _textblock.getAngle() if abs(_tbangle - _style.getAngle()) > 1e-10: _attr = doc.createAttributeNS("image", "angle") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "angle", `_tbangle`) _tbalign = _textblock.getAlignment() if _tbalign != _style.getAlignment(): _attr = doc.createAttributeNS("image", "halign") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "halign", `_tbalign`) for _line in _text.splitlines(): _textline = doc.createElementNS("image", "image:TextLine") _child.appendChild(_textline) _attr = doc.createAttributeNS("image", "text") _textline.setAttributeNodeNS(_attr) _textline.setAttributeNS("image", "text", _line) # # I'd really rather not use an attribute to store # the text - using a TextNode would be better so # the file would look like the following: # # ... # blah blah blah # foo bar blah # ... # # minidom adds in newlines and spaces though # is there a known workaround or a magic call to # have it not do this? # # _textnode = doc.createTextNode(_line) # _textline.appendChild(_textnode) _i = _i + 1 def _save_chamfers(lyr, node, doc, map): _chamferlist = lyr.getLayerEntities("chamfer") if len(_chamferlist): _chs = doc.createElementNS("image", "image:Chamfers") node.appendChild(_chs) _i = 0 for _ch in _chamferlist: _s1, _s2 = _ch.getSegments() _i1 = id(_s1) _i2 = id(_s2) assert _i1 in map, "Chamfer %s seg1 not in map!" % `_ch` assert _i2 in map, "Chamfer %s seg2 not in map!" % `_ch` _child = doc.createElementNS("image", "image:Chamfer") _chs.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "s1") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "s1", `map[_i1]`) _attr = doc.createAttributeNS("image", "s2") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "s2", `map[_i2]`) _attr = doc.createAttributeNS("image", "length") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "length", `_ch.getLength()`) _save_graph_bits(_ch, _child, doc, map) _save_state_bits(_ch, _child, doc) _i = _i + 1 def _save_fillets(lyr, node, doc, map): _filletlist = lyr.getLayerEntities("fillet") if len(_filletlist): _flts = doc.createElementNS("image", "image:Fillets") node.appendChild(_flts) _i = 0 for _flt in _filletlist: _s1, _s2 = _flt.getSegments() _i1 = id(_s1) _i2 = id(_s2) assert _i1 in map, "Fillet %s seg1 not in map!" % `_flt` assert _i2 in map, "Fillet %s seg2 not in map!" % `_flt` _child = doc.createElementNS("image", "image:Fillet") _flts.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "_s1") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "s1", `map[_i1]`) _attr = doc.createAttributeNS("image", "s2") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "s2", `map[_i2]`) _attr = doc.createAttributeNS("image", "radius") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "radius", `_flt.getRadius()`) _save_graph_bits(_flt, _child, doc, map) _save_state_bits(_flt, _child, doc) _i = _i + 1 def _save_dim_override(node, doc, map, stkey, value): _child = doc.createElementNS("image", "image:DimOption") node.appendChild(_child) _attr = doc.createAttributeNS("image", "opt") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "opt", stkey) if (stkey == 'DIM_COLOR' or stkey == 'DIM_PRIMARY_FONT_COLOR' or stkey == 'DIM_SECONDARY_FONT_COLOR'): _attr = doc.createAttributeNS("image", "cid") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "cid", `map[value]`) elif (stkey == 'DIM_PRIMARY_FONT_FAMILY' or stkey == 'DIM_SECONDARY_FONT_FAMILY'): _attr = doc.createAttributeNS("image", "fid") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "fid", `map[value]`) else: _attr = doc.createAttributeNS("image", "val") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "val", str(value)) def _save_dim_common(dim, node, doc, map): _ds = dim.getDimStyle() _offset = dim.getOffset() if abs(_ds.getValue('DIM_OFFSET') - _offset) > 1e-10: _save_dim_override(node, doc, map, 'DIM_OFFSET', _offset) _ext = dim.getExtension() if abs(_ds.getValue('DIM_EXTENSION') - _ext) > 1e-10: _save_dim_override(node, doc, map, 'DIM_EXTENSION', _ext) _endpt = dim.getEndpointType() if _ds.getValue('DIM_ENDPOINT') != _endpt: _save_dim_override(node, doc, map, 'DIM_ENDPOINT', _endpt) _size = dim.getEndpointSize() if abs(_ds.getValue('DIM_ENDPOINT_SIZE') - _size) > 1e-10: _save_dim_override(node, doc, map, 'DIM_ENDPOINT_SIZE', _size) _color = dim.getColor() if _ds.getValue('DIM_COLOR') != _color: _save_dim_override(node, doc, map, 'DIM_COLOR', _color) _dual_mode = dim.getDualDimMode() if _ds.getValue('DIM_DUAL_MODE') != _dual_mode: _save_dim_override(node, doc, map, 'DIM_DUAL_MODE', _dual_mode) _poff = dim.getPositionOffset() if abs(_ds.getValue('DIM_POSITION_OFFSET') - _poff) > 1e-10: _save_dim_override(node, doc, map, 'DIM_POSITION_OFFSET', _poff) _dmo = dim.getDualModeOffset() if abs(_ds.getValue('DIM_DUAL_MODE_OFFSET') - _dmo) > 1e-10: _save_dim_override(node, doc, map, 'DIM_DUAL_MODE_OFFSET', _dmo) _t = dim.getThickness() if abs(_ds.getValue('DIM_THICKNESS') - _t) > 1e-10: _save_dim_override(node, doc, map, 'DIM_THICKNESS', _ext) # # primary dimension string # _pds = dim.getPrimaryDimstring() _prefix = _pds.getPrefix() if isinstance(dim, dimension.LinearDimension): if _ds.getValue('DIM_PRIMARY_PREFIX') != _prefix: _save_dim_override(node, doc, map, 'DIM_PRIMARY_PREFIX', _prefix) elif isinstance(dim, dimension.RadialDimension): if _ds.getValue('RADIAL_DIM_PRIMARY_PREFIX') != _prefix: _save_dim_override(node, doc, map, 'RADIAL_DIM_PRIMARY_PREFIX', _prefix) elif isinstance(dim, dimension.AngularDimension): if _ds.getValue('ANGULAR_DIM_PRIMARY_PREFIX') != _prefix: _save_dim_override(node, doc, map, 'ANGULAR_DIM_PRIMARY_PREFIX', _prefix) else: raise TypeError, "Unexpected dimension type: " + `dim` _suffix = _pds.getSuffix() if isinstance(dim, dimension.LinearDimension): if _ds.getValue('DIM_PRIMARY_SUFFIX') != _suffix: _save_dim_override(node, doc, map, 'DIM_PRIMARY_SUFFIX', _suffix) elif isinstance(dim, dimension.RadialDimension): if _ds.getValue('RADIAL_DIM_PRIMARY_SUFFIX') != _suffix: _save_dim_override(node, doc, map, 'RADIAL_DIM_PRIMARY_SUFFIX', _suffix) elif isinstance(dim, dimension.AngularDimension): if _ds.getValue('ANGULAR_DIM_PRIMARY_SUFFIX') != _suffix: _save_dim_override(node, doc, map, 'ANGULAR_DIM_PRIMARY_SUFFIX', _prefix) else: raise TypeError, "Unexpected dimension type: " + `dim` _unit = _pds.getUnits() if _ds.getValue('DIM_PRIMARY_UNITS') != _unit: _save_dim_override(node, doc, map, 'DIM_PRIMARY_UNITS', _unit) _precision = _pds.getPrecision() if _ds.getValue('DIM_PRIMARY_PRECISION') != _precision: _save_dim_override(node, doc, map, 'DIM_PRIMARY_PRECISION', _precision) _print_zero = _pds.getPrintZero() if _ds.getValue('DIM_PRIMARY_LEADING_ZERO') != _print_zero: _save_dim_override(node, doc, map, 'DIM_PRIMARY_LEADING_ZERO', _print_zero) _print_dec = _pds.getPrintDecimal() if _ds.getValue('DIM_PRIMARY_TRAILING_DECIMAL') != _print_dec: _save_dim_override(node, doc, map, 'DIM_PRIMARY_TRAILING_DECIMAL', _print_dec) _family = _pds.getFamily() if _ds.getValue('DIM_PRIMARY_FONT_FAMILY') != _family: assert _family in map, "Font family %s missing in map" % _family _save_dim_override(node, doc, map, 'DIM_PRIMARY_FONT_FAMILY', _family) _font_style = _pds.getStyle() if _ds.getValue('DIM_PRIMARY_FONT_STYLE') != _font_style: _save_dim_override(node, doc, map, 'DIM_PRIMARY_FONT_STYLE', _font_style) _weight = _pds.getWeight() if _ds.getValue('DIM_PRIMARY_FONT_WEIGHT') != _weight: _save_dim_override(node, doc, map, 'DIM_PRIMARY_FONT_WEIGHT', _weight) _font_color = _pds.getColor() if _ds.getValue('DIM_PRIMARY_FONT_COLOR') != _font_color: assert _font_color in map, "Font color missing in map: " + `_font_color` _save_dim_override(node, doc, map, 'DIM_PRIMARY_FONT_COLOR', _font_color) _size = _pds.getSize() if abs(_ds.getValue('DIM_PRIMARY_TEXT_SIZE') - _size) > 1e-10: _save_dim_override(node, doc, map, 'DIM_PRIMARY_TEXT_SIZE', _size) _angle = _pds.getAngle() if abs(_ds.getValue('DIM_PRIMARY_TEXT_ANGLE') - _angle) > 1e-10: _save_dim_override(node, doc, map, 'DIM_PRIMARY_TEXT_ANGLE', _angle) _align = _pds.getAlignment() if _ds.getValue('DIM_PRIMARY_TEXT_ALIGNMENT') != _align: _save_dim_override(node, doc, map, 'DIM_PRIMARY_TEXT_ALIGN', _align) # # secondary dimension string # _sds = dim.getSecondaryDimstring() _prefix = _sds.getPrefix() if isinstance(dim, dimension.LinearDimension): if _ds.getValue('DIM_SECONDARY_PREFIX') != _prefix: _save_dim_override(node, doc, map, 'DIM_SECONDARY_PREFIX', _prefix) elif isinstance(dim, dimension.RadialDimension): if _ds.getValue('RADIAL_DIM_SECONDARY_PREFIX') != _prefix: _save_dim_override(node, doc, map, 'RADIAL_DIM_SECONDARY_PREFIX', _prefix) elif isinstance(dim, dimension.AngularDimension): if _ds.getValue('ANGULAR_DIM_SECONDARY_PREFIX') != _prefix: _save_dim_override(node, doc, map, 'ANGULAR_DIM_SECONDARY_PREFIX', _prefix) else: raise TypeError, "Unexpected dimension type: " + `dim` _suffix = _sds.getSuffix() if isinstance(dim, dimension.LinearDimension): if _ds.getValue('DIM_SECONDARY_SUFFIX') != _suffix: _save_dim_override(node, doc, map, 'DIM_SECONDARY_SUFFIX', _suffix) elif isinstance(dim, dimension.RadialDimension): if _ds.getValue('RADIAL_DIM_SECONDARY_SUFFIX') != _suffix: _save_dim_override(node, doc, map, 'RADIAL_DIM_SECONDARY_SUFFIX', _suffix) elif isinstance(dim, dimension.AngularDimension): if _ds.getValue('ANGULAR_DIM_SECONDARY_SUFFIX') != _suffix: _save_dim_override(node, doc, map, 'ANGULAR_DIM_SECONDARY_SUFFIX', _prefix) else: raise TypeError, "Unexpected dimension type: " + `dim` _unit = _sds.getUnits() if _ds.getValue('DIM_SECONDARY_UNITS') != _unit: _save_dim_override(node, doc, map, 'DIM_SECONDARY_UNITS', _unit) _precision = _sds.getPrecision() if _ds.getValue('DIM_SECONDARY_PRECISION') != _precision: _save_dim_override(node, doc, map, 'DIM_SECONDARY_PRECISION', _precision) _print_zero = _sds.getPrintZero() if _ds.getValue('DIM_SECONDARY_LEADING_ZERO') != _print_zero: _save_dim_override(node, doc, map, 'DIM_SECONDARY_LEADING_ZERO', _print_zero) _print_dec = _sds.getPrintDecimal() if _ds.getValue('DIM_SECONDARY_TRAILING_DECIMAL') != _print_dec: _save_dim_override(node, doc, map, 'DIM_SECONDARY_TRAILING_DECIMAL', _print_dec) _family = _sds.getFamily() if _ds.getValue('DIM_SECONDARY_FONT_FAMILY') != _family: assert _family in map, "Font family %s missing in map" % _family _save_dim_override(node, doc, map, 'DIM_SECONDARY_FONT_FAMILY', _family) _font_style = _sds.getStyle() if _ds.getValue('DIM_SECONDARY_FONT_STYLE') != _font_style: _save_dim_override(node, doc, map, 'DIM_SECONDARY_FONT_STYLE', _font_style) _weight = _sds.getWeight() if _ds.getValue('DIM_SECONDARY_FONT_WEIGHT') != _weight: _save_dim_override(node, doc, map, 'DIM_SECONDARY_FONT_WEIGHT', _weight) _font_color = _sds.getColor() if _ds.getValue('DIM_SECONDARY_FONT_COLOR') != _font_color: assert _font_color in map, "Font color missing in map: " + `_font_color` _save_dim_override(node, doc, map, 'DIM_SECONDARY_FONT_COLOR', _font_color) _size = _sds.getSize() if abs(_ds.getValue('DIM_SECONDARY_TEXT_SIZE') - _size) > 1e-10: _save_dim_override(node, doc, map, 'DIM_SECONDARY_TEXT_SIZE', _size) _angle = _sds.getAngle() if abs(_ds.getValue('DIM_SECONDARY_TEXT_ANGLE') - _angle) > 1e-10: _save_dim_override(node, doc, map, 'DIM_SECONDARY_TEXT_ANGLE', _angle) _align = _sds.getAlignment() if _ds.getValue('DIM_SECONDARY_TEXT_ALIGNMENT') != _align: _save_dim_override(node, doc, map, 'DIM_SECONDARY_TEXT_ALIGN', _align) def _save_linear_dims(l, node, doc, map, entmap, dimtype): if dimtype == 'linear_dimension': _tag = 'image:LDims' elif dimtype == 'horizontal_dimension': _tag = 'image:HDims' elif dimtype == 'vertical_dimension': _tag = 'image:VDims' else: raise ValueError, "Unexpected linear dimension type: " + `dimtype` _ldimlist = l.getLayerEntities(dimtype) if len(_ldimlist): _item_tag = _tag[:-1] _block = doc.createElementNS("image", _tag) node.appendChild(_block) _i = 0 for _dim in _ldimlist: _p1, _p2 = _dim.getDimPoints() _l1 = _p1.getParent() if _l1 is None: raise ValueError, "Dimension P1 point not in a Layer" _l2 = _p2.getParent() if _l2 is None: raise ValueError, "Dimension P2 point not in a Layer" _x, _y = _dim.getLocation() _ds = _dim.getDimStyle() _child = doc.createElementNS("image", _item_tag) _block.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "l1") _child.setAttributeNodeNS(_attr) _il = id(_l1) if _il in map: _child.setAttributeNS("image", "l1", `map[_il]`) else: entmap.saveEntity(_child, 'l1', _l1) _attr = doc.createAttributeNS("image", "p1") _child.setAttributeNodeNS(_attr) _ip = id(_p1) if _ip in map: _child.setAttributeNS("image", "p1", `map[_ip]`) else: entmap.saveEntity(_child, 'p1', _p1) _attr = doc.createAttributeNS("image", "l2") _child.setAttributeNodeNS(_attr) _il = id(_l2) if _il in map: _child.setAttributeNS("image", "l2", `map[_il]`) else: entmap.saveEntity(_child, 'l2', _l2) _attr = doc.createAttributeNS("image", "p2") _child.setAttributeNodeNS(_attr) _ip = id(_p2) if _ip in map: _child.setAttributeNS("image", "p2", `map[_ip]`) else: entmap.saveEntity(_child, 'p2', _p2) _attr = doc.createAttributeNS("image", "x") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "x", `_x`) _attr = doc.createAttributeNS("image", "y") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "y", `_y`) _attr = doc.createAttributeNS("image", "ds") assert _ds in map, "Missing DimStyle in map: " + `_ds` _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "ds", `map[_ds]`) _save_dim_common(_dim, _child, doc, map) _save_state_bits(_dim, _child, doc) def _save_radial_dims(lyr, node, doc, map, entmap): _rdimlist = lyr.getLayerEntities("radial_dimension") if len(_rdimlist): _rdims = doc.createElementNS("image", "image:RDims") node.appendChild(_rdims) _i = 0 for _rdim in _rdimlist: _dc = _rdim.getDimCircle() _dl = _dc.getParent() if _dl is None: raise ValueError, "RadialDimension Circle/Arc not in a Layer" _x, _y = _rdim.getLocation() _ds = _rdim.getDimStyle() _child = doc.createElementNS("image", "image:RDim") _rdims.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "l") _child.setAttributeNodeNS(_attr) _il = id(_dl) if _il in map: _child.setAttributeNS("image", "l", `map[_il]`) else: entmap.saveEntity(_child, 'l', _dl) _attr = doc.createAttributeNS("image", "c") _child.setAttributeNodeNS(_attr) _ic = id(_dc) if _ic in map: _child.setAttributeNS("image", "c", `map[_ic]`) else: entmap.saveEntity(_child, 'c', _dc) _attr = doc.createAttributeNS("image", "x") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "x", `_x`) _attr = doc.createAttributeNS("image", "y") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "y", `_y`) _attr = doc.createAttributeNS("image", "ds") assert _ds in map, "Missing DimStyle in map: " + `_ds` _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "ds", `map[_ds]`) _save_dim_common(_rdim, _child, doc, map) _save_state_bits(_rdim, _child, doc) _dia_mode = _rdim.getDiaMode() if _ds.getValue('RADIAL_DIM_DIA_MODE') != _dia_mode: _opt = doc.createElementNS("image", "image:DimOption") _child.appendChild(_opt) _attr = doc.createAttributeNS("image", "opt") _opt.setAttributeNodeNS(_attr) _opt.setAttributeNS("image", "opt", 'RADIAL_DIM_DIA_MODE') _attr = doc.createAttributeNS("image", "val") _opt.setAttributeNodeNS(_attr) _opt.setAttributeNS("image", "val", `_dia_mode`) def _save_angular_dims(lyr, node, doc, map, entmap): _adimlist = lyr.getLayerEntities("angular_dimension") if len(_adimlist): _adims = doc.createElementNS("image", "image:ADims") node.appendChild(_adims) _i = 0 for _adim in _adimlist: _p1, _p2, _p3 = _adim.getDimPoints() _l1 = _p1.getParent() _l2 = _p2.getParent() _l3 = _p3.getParent() if _l1 is None: raise ValueError, "Dimension vertex point not in a Layer" _l2 = _p2.getParent() if _l2 is None: raise ValueError, "Dimension P1 point not in a Layer" _l3 = _p3.getParent() if _l3 is None: raise ValueError, "Dimension P2 point not in a Layer" _x, _y = _adim.getLocation() _ds = _adim.getDimStyle() _child = doc.createElementNS("image", "image:ADim") _adims.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "l1") _child.setAttributeNodeNS(_attr) _il = id(_l1) if _il in map: _child.setAttributeNS("image", "l1", `map[_il]`) else: entmap.saveEntity(_child, 'l1', _l1) _attr = doc.createAttributeNS("image", "p1") _child.setAttributeNodeNS(_attr) _ip = id(_p1) if _ip in map: _child.setAttributeNS("image", "p1", `map[_ip]`) else: entmap.saveEntity(_child, 'p1', _p1) _attr = doc.createAttributeNS("image", "l2") _child.setAttributeNodeNS(_attr) _il = id(_l2) if _il in map: _child.setAttributeNS("image", "l2", `map[_il]`) else: entmap.saveEntity(_child, 'l2', _l2) _attr = doc.createAttributeNS("image", "p2") _child.setAttributeNodeNS(_attr) _ip = id(_p2) if _ip in map: _child.setAttributeNS("image", "p2", `map[_ip]`) else: entmap.saveEntity(_child, 'p2', _p2) _attr = doc.createAttributeNS("image", "l3") _child.setAttributeNodeNS(_attr) _il = id(_l3) if _il in map: _child.setAttributeNS("image", "l3", `map[_il]`) else: entmap.saveEntity(_child, 'l3', _l3) _attr = doc.createAttributeNS("image", "p3") _child.setAttributeNodeNS(_attr) _ip = id(_p3) if _ip in map: _child.setAttributeNS("image", "p3", `map[_ip]`) else: entmap.saveEntity(_child, 'p3', _p3) _attr = doc.createAttributeNS("image", "x") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "x", `_x`) _attr = doc.createAttributeNS("image", "y") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "y", `_y`) _attr = doc.createAttributeNS("image", "ds") assert _ds in map, "Missing DimStyle in map: " + `_ds` _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "ds", `map[_ds]`) _save_dim_common(_adim, _child, doc, map) _save_state_bits(_adim, _child, doc) def _save_ccircles(lyr, node, doc, map): _cclist = lyr.getLayerEntities("ccircle") if len(_cclist): _ccircs = doc.createElementNS("image", "image:CCircles") node.appendChild(_ccircs) _i = 0 for _cc in _cclist: _cp = _cc.getCenter() _ic = id(_cp) assert _ic in map, "CCircle %s center not in map!" % str(_cc) _child = doc.createElementNS("image", "image:CCircle") _ccircs.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "cp") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "cp", `map[_ic]`) _attr = doc.createAttributeNS("image", "r") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "r", `_cc.getRadius()`) _save_state_bits(_cc, _child, doc) _i = _i + 1 def _save_clines(lyr, node, doc, map): _cllist = lyr.getLayerEntities("cline") if len(_cllist): _clines = doc.createElementNS("image", "image:CLines") node.appendChild(_clines) _i = 0 for _cl in _cllist: _p1, _p2 = _cl.getKeypoints() _i1 = id(_p1) _i2 = id(_p2) assert _i1 in map, "CLine %s p1 not in map!" % str(_cl) assert _i2 in map, "CLine %s p2 not in map!" % str(_cl) _child = doc.createElementNS("image", "image:CLine") _clines.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "p1") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "p1", `map[_i1]`) _attr = doc.createAttributeNS("image", "p2") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "p2", `map[_i2]`) _save_state_bits(_cl, _child, doc) _i = _i + 1 def _save_aclines(lyr, node, doc, map): _acllist = lyr.getLayerEntities("acline") if len(_acllist): _acls = doc.createElementNS("image", "image:ACLines") node.appendChild(_acls) _i = 0 for _acl in _acllist: _loc = _acl.getLocation() _il = id(_loc) assert _il in map, "ACline %s point not in map!" % str(_acl) _child = doc.createElementNS("image", "image:ACLine") _acls.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "angle") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "angle", `_acl.getAngle()`) _attr = doc.createAttributeNS("image", "location") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "location", `map[_il]`) _save_state_bits(_acl, _child, doc) _i = _i + 1 def _save_vclines(lyr, node, doc, map): _vcllist = lyr.getLayerEntities("vcline") if len(_vcllist): _vcls = doc.createElementNS("image", "image:VCLines") node.appendChild(_vcls) _i = 0 for _vcl in _vcllist: _loc = _vcl.getLocation() _il = id(_loc) assert _il in map, "VCline %s point not in map!" % str(_vcl) _child = doc.createElementNS("image", "image:VCLine") _vcls.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "location") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "location", `map[_il]`) _save_state_bits(_vcl, _child, doc) _i = _i + 1 def _save_hclines(lyr, node, doc, map): _hcllist = lyr.getLayerEntities("hcline") if len(_hcllist): _hcls = doc.createElementNS("image", "image:HCLines") node.appendChild(_hcls) _i = 0 for _hcl in _hcllist: _loc = _hcl.getLocation() _il = id(_loc) assert _il in map, "HCline %s point not in map!" % str(_hcl) _child = doc.createElementNS("image", "image:HCLine") _hcls.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "location") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "location", `map[_il]`) _save_state_bits(_hcl, _child, doc) _i = _i + 1 def _save_arcs(lyr, node, doc, map): _arclist = lyr.getLayerEntities("arc") if len(_arclist): _arcs = doc.createElementNS("image", "image:Arcs") node.appendChild(_arcs) _i = 0 for _arc in _arclist: _cp = _arc.getCenter() _ic = id(_cp) assert _ic in map, "Arc %s center not in map!" % str(_arc) _child = doc.createElementNS("image", "image:Arc") _arcs.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "cp") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "cp", `map[_ic]`) _attr = doc.createAttributeNS("image", "r") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "r", `_arc.getRadius()`) _attr = doc.createAttributeNS("image", "sa") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "sa", `_arc.getStartAngle()`) _attr = doc.createAttributeNS("image", "ea") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "ea", `_arc.getEndAngle()`) _save_graph_bits(_arc, _child, doc, map) _save_state_bits(_arc, _child, doc) if _arc.hasUsers(): map[id(_arc)] = _i _i = _i + 1 def _save_circles(lyr, node, doc, map): _circles = lyr.getLayerEntities("circle") if len(_circles): _circs = doc.createElementNS("image", "image:Circles") node.appendChild(_circs) _i = 0 for _circle in _circles: _cp = _circle.getCenter() _ic = id(_cp) assert _ic in map, "Circle %s center not in map!" % str(_circle) _child = doc.createElementNS("image", "image:Circle") _circs.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "cp") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "cp", `map[_ic]`) _attr = doc.createAttributeNS("image", "r") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "r", `_circle.getRadius()`) _save_graph_bits(_circle, _child, doc, map) _save_state_bits(_circle, _child, doc) if _circle.hasUsers(): map[id(_circle)] = _i _i = _i + 1 def _save_segments(lyr, node, doc, map): _segments = lyr.getLayerEntities("segment") if len(_segments): _segs = doc.createElementNS("image", "image:Segments") node.appendChild(_segs) _i = 0 for _seg in _segments: _p1, _p2 = _seg.getEndpoints() _i1 = id(_p1) _i2 = id(_p2) assert _i1 in map, "Segment %s p1 not in map!" % str(_seg) assert _i2 in map, "Segment %s p2 not in map!" % str(_seg) _child = doc.createElementNS("image", "image:Segment") _segs.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "p1") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "p1", `map[_i1]`) _attr = doc.createAttributeNS("image", "p2") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "p2", `map[_i2]`) _save_graph_bits(_seg, _child, doc, map) _save_state_bits(_seg, _child, doc) if _seg.hasUsers(): map[id(_seg)] = _i _i = _i + 1 def _save_points(lyr, node, doc, map): _points = lyr.getLayerEntities("point") if len(_points): _pts = doc.createElementNS("image", "image:Points") node.appendChild(_pts) _i = 0 for _pt in _points: _x, _y = _pt.getCoords() _child = doc.createElementNS("image", "image:Point") _pts.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "x") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "x", `_x`) _attr = doc.createAttributeNS("image", "y") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "y", `_y`) _save_state_bits(_pt, _child, doc) if _pt.hasUsers(): map[id(_pt)] = _i _i = _i + 1 def _make_xml_doc(): _newdoc = xml.dom.minidom.Document() _root = _newdoc.createElementNS("image", "image:Image") _newdoc.appendChild(_root) _attr = _newdoc.createAttributeNS("xmlns", "xmlns:image") _root.setAttributeNodeNS(_attr) _root.setAttributeNS("xmlns", "xmlns:image", "http://www.pythoncad.org") _attr = _newdoc.createAttributeNS("xmlns", "xmlns:xsi") _root.setAttributeNodeNS(_attr) _root.setAttributeNS("xmlns", "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") _attr = _newdoc.createAttributeNS("xsi", "xsi:schemaLocation") _root.setAttributeNodeNS(_attr) _root.setAttributeNS("xmlns", "xsi:schemaLocation", "http://www.pythoncad.org") return _newdoc def _save_dimstyles(attmap, node, doc, map): _dimstyles = doc.createElementNS("image", "image:DimStyles") node.appendChild(_dimstyles) _dslist = attmap['dimstyles'] _i = 0 for _ds in _dslist: _child = doc.createElementNS("image", "image:DimStyle") _dimstyles.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "name") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "name", _ds.getName()) _stkeys = _ds.getOptions() _stkeys.sort() for _stkey in _stkeys: _value = _ds.getValue(_stkey) _dsfield = doc.createElementNS("image", "image:DimOption") _child.appendChild(_dsfield) _attr = doc.createAttributeNS("image", "opt") _dsfield.setAttributeNodeNS(_attr) _dsfield.setAttributeNS("image", "opt", _stkey) if (_stkey == 'DIM_COLOR' or _stkey == 'DIM_PRIMARY_FONT_COLOR' or _stkey == 'DIM_SECONDARY_FONT_COLOR'): assert _value in map, "color %s not found in map!" % str(_value) _attr = doc.createAttributeNS("image", "cid") _dsfield.setAttributeNodeNS(_attr) _dsfield.setAttributeNS("image", "cid", `map[_value]`) elif (_stkey == 'DIM_PRIMARY_FONT_FAMILY' or _stkey == 'DIM_SECONDARY_FONT_FAMILY'): assert _value in map, "font %s not found in map!" % str(_value) _attr = doc.createAttributeNS("image", "fid") _dsfield.setAttributeNodeNS(_attr) _dsfield.setAttributeNS("image", "fid", `map[_value]`) elif (_stkey == 'DIM_PRIMARY_PREFIX' or _stkey == 'DIM_PRIMARY_SUFFIX' or _stkey == 'DIM_SECONDARY_PREFIX' or _stkey == 'DIM_SECONDARY_SUFFIX' or _stkey == 'RADIAL_DIM_PRIMARY_PREFIX' or _stkey == 'RADIAL_DIM_PRIMARY_SUFFIX' or _stkey == 'RADIAL_DIM_SECONDARY_PREFIX' or _stkey == 'RADIAL_DIM_SECONDARY_SUFFIX' or _stkey == 'ANGULAR_DIM_PRIMARY_PREFIX' or _stkey == 'ANGULAR_DIM_PRIMARY_SUFFIX' or _stkey == 'ANGULAR_DIM_SECONDARY_PREFIX' or _stkey == 'ANGULAR_DIM_SECONDARY_SUFFIX'): _attr = doc.createAttributeNS("image", "val") _dsfield.setAttributeNodeNS(_attr) _dsfield.setAttributeNS("image", "val", str(_value)) else: _attr = doc.createAttributeNS("image", "val") _dsfield.setAttributeNodeNS(_attr) _dsfield.setAttributeNS("image", "val", `_value`) map[_ds] = _i _i = _i + 1 def _save_textstyles(attmap, node, doc, map): _textstyles = doc.createElementNS("image", "image:TextStyles") node.appendChild(_textstyles) _tslist = attmap['textstyles'] _i = 0 for _ts in _tslist: _child = doc.createElementNS("image", "image:TextStyle") _textstyles.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "name") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "name", _ts.getName()) _family = _ts.getFamily() assert _family in map, "Missing font family in map: " + _family _attr = doc.createAttributeNS("image", "fid") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "fid", `map[_family]`) _weight = text.font_weight_string(_ts.getWeight()) _attr = doc.createAttributeNS("image", "weight") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "weight", _weight) _style = text.font_style_string(_ts.getStyle()) _attr = doc.createAttributeNS("image", "style") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "style", _style) _size = _ts.getSize() _attr = doc.createAttributeNS("image", "size") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "size", `_size`) _angle = _ts.getAngle() _attr = doc.createAttributeNS("image", "angle") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "angle", `_angle`) _align = _ts.getAlignment() _attr = doc.createAttributeNS("image", "halign") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "halign", `_align`) _color = _ts.getColor() assert _color in map, "Missing font color in map: " + str(_color) _attr = doc.createAttributeNS("image", "cid") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "cid", `map[_color]`) map[_ts] = _i _i = _i + 1 def _save_font_families(attmap, node, doc, map): _families = doc.createElementNS("image", "image:FontFamilies") node.appendChild(_families) _i = 0 _fontlist = attmap['fonts'] for _font in _fontlist: _child = doc.createElementNS("image", "image:FontFamily") _families.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "name") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "name", _font) map[_font] = _i _i = _i + 1 def _save_styles(attmap, node, doc, map): _styles = doc.createElementNS("image", "image:Styles") node.appendChild(_styles) _i = 0 _stylelist = attmap['styles'] for _style in _stylelist: _child = doc.createElementNS("image", "image:Style") _styles.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "name") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "name", _style.getName()) _color = _style.getColor() assert _color in map, "Color not found in map!" _attr = doc.createAttributeNS("image", "cid") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "cid", `map[_color]`) _linetype = _style.getLinetype() assert _linetype in map, "Linetype not found in map!" _attr = doc.createAttributeNS("image", "ltid") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "ltid", `map[_linetype]`) _attr = doc.createAttributeNS("image", "thickness") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "thickness", `_style.getThickness()`) map[_style] = _i _i = _i + 1 def _save_colors(attmap, node, doc, map): _colors = doc.createElementNS("image", "image:Colors") node.appendChild(_colors) _i = 0 _colorlist = attmap['colors'] for _color in _colorlist: _r, _g, _b = _color.getColors() _child = doc.createElementNS("image", "image:Color") _colors.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "r") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "r", `_r`) _attr = doc.createAttributeNS("image", "g") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "g", `_g`) _attr = doc.createAttributeNS("image", "b") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "b", `_b`) # # save color as hex string as well # # It may be better to save colors like ... # # #ffffff # _attr = doc.createAttributeNS("image", "color") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "color", str(_color)) map[_color] = _i _i = _i + 1 def _save_linetypes(attmap, node, doc, map): _linetypes = doc.createElementNS("image", "image:Linetypes") node.appendChild(_linetypes) _i = 0 _linetypelist = attmap['linetypes'] for _linetype in _linetypelist: _child = doc.createElementNS("image", "image:Linetype") _linetypes.appendChild(_child) _attr = doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = doc.createAttributeNS("image", "name") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "name", _linetype.getName()) _attr = doc.createAttributeNS("image", "pattern") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "pattern", `_linetype.getList()`) map[_linetype] = _i _i = _i + 1 def _save_units(image, node, doc): _uts = doc.createElementNS("image", "image:Units") node.appendChild(_uts) _attr = doc.createAttributeNS("image", "unit") _uts.setAttributeNodeNS(_attr) _ustr = units.unit_string(image.getUnits()) _uts.setAttributeNS("image", "unit", _ustr) def _save_globals(attmap, node, doc, map): # # for now, assumes globals are ONLY colors # _globals = doc.createElementNS("image", "image:Globals") node.appendChild(_globals) _globaldict = attmap['globals'] _keylist = _globaldict.keys() for _key in _keylist: _child = doc.createElementNS("image", "image:Global") _globals.appendChild(_child) _attr = doc.createAttributeNS("image", "key") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "key", _key) _val = _globaldict[_key] assert _val in map, "Color not found in map!" _attr = doc.createAttributeNS("image", "cid") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "cid", `map[_val]`) _entlist = [ 'segment', 'circle', 'arc', 'chamfer', 'fillet', 'leader', 'polyline', ] _conobjs = [ 'hcline', 'vcline', 'acline', 'cline', 'ccircle', ] _dimlist = [ 'linear_dimension', 'horizontal_dimension', 'vertical_dimension', 'radial_dimension', 'angular_dimension', ] def _get_image_attributes(image): _attmap = {} _styles = [] _attmap['styles'] = _styles _colors = [] _attmap['colors'] = _colors _linetypes = [] _attmap['linetypes'] = _linetypes _fonts = [] _attmap['fonts'] = _fonts _dimstyles = [] _attmap['dimstyles'] = _dimstyles _textstyles = [] _attmap['textstyles'] = _textstyles _globals = {} _attmap['globals'] = _globals # # Get global properties # for _key in ['BACKGROUND_COLOR', 'INACTIVE_LAYER_COLOR', 'SINGLE_POINT_COLOR', 'MULTI_POINT_COLOR']: _val = _globals[_key] = image.getOption(_key) if _val not in _colors: _colors.append(_val) _check_conobjs = True _layers = [image.getTopLayer()] while len(_layers): _layer = _layers.pop() for _ent in _entlist: for _obj in _layer.getLayerEntities(_ent): # # get style properties # _style = _obj.getStyle() if _style not in _styles: _styles.append(_style) _color = _style.getColor() # style color if _color not in _colors: _colors.append(_color) _linetype = _style.getLinetype() # style linetype if _linetype not in _linetypes: _linetypes.append(_linetype) # # object may have overridden style values # _color = _obj.getColor() if _color not in _colors: _colors.append(_color) _linetype = _obj.getLinetype() if _linetype not in _linetypes: _linetypes.append(_linetype) if _check_conobjs: for _conobj in _conobjs: for _obj in _layer.getLayerEntities(_conobj): _check_conobjs = False _style = _obj.getStyle() if _style not in _styles: _styles.append(_style) _color = _style.getColor() if _color not in _colors: _colors.append(_color) _linetype = _style.getLinetype() if _linetype not in _linetypes: _linetypes.append(_linetype) break if not _check_conobjs: break for _dim in _dimlist: for _obj in _layer.getLayerEntities(_dim): # # get style properties # _ds = _obj.getDimStyle() if _ds not in _dimstyles: _dimstyles.append(_ds) _color = _ds.getOption('DIM_COLOR') if _color not in _colors: _colors.append(_color) _color = _ds.getOption('DIM_PRIMARY_FONT_COLOR') if _color not in _colors: _colors.append(_color) _color = _ds.getOption('DIM_SECONDARY_FONT_COLOR') if _color not in _colors: _colors.append(_color) _font = _ds.getOption('DIM_PRIMARY_FONT_FAMILY') if _font not in _fonts: _fonts.append(_font) _font = _ds.getOption('DIM_SECONDARY_FONT_FAMILY') if _font not in _fonts: _fonts.append(_font) # # object may have overridden style values # _color = _obj.getColor() if _color not in _colors: # dimension bar colors _colors.append(_color) _pds = _obj.getPrimaryDimstring() _color = _pds.getColor() # primary dim text color if _color not in _colors: _colors.append(_color) _font = _pds.getFamily() # primary dim font if _font not in _fonts: _fonts.append(_font) _style = _pds.getTextStyle() if _style not in _textstyles: # print "Adding PDS textstyle: " + `_pds` # print "Dimension: " + `_obj` # print "TextStyle: " + `_style` _textstyles.append(_style) _sds = _obj.getSecondaryDimstring() _color = _sds.getColor() # secondary dim color if _color not in _colors: _colors.append(_color) _font = _sds.getFamily() # secondary dim font if _font not in _fonts: _fonts.append(_font) _style = _sds.getTextStyle() if _style not in _textstyles: # print "Adding SDS textstyle: " + `_sds` # print "Dimension: " + `_obj` # print "TextStyle: " + `_style` _textstyles.append(_style) for _textblock in _layer.getLayerEntities("textblock"): # print "Testing textblock: " + `_textblock` # print "Text: '%s'" % _textblock.getText() _style = _textblock.getTextStyle() # print "TextStyle: " + `_style` if _style not in _textstyles: # print "Adding TextBlock textstyle: " + `_textblock` # print "TextStyle: " + `_style` _textstyles.append(_style) _font = _style.getFamily() if _font not in _fonts: _fonts.append(_font) _color = _style.getColor() if _color not in _colors: _colors.append(_color) # # objects may have overridden the styles # _font = _textblock.getFamily() if _font not in _fonts: _fonts.append(_font) _color = _textblock.getColor() if _color not in _colors: _colors.append(_color) if _layer.hasSublayers(): _layers.extend(_layer.getSublayers()) _colors.sort() _styles.sort() _linetypes.sort() _fonts.sort() _dimstyles.sort() return _attmap class EntityMap(object): def __init__(self): self.__elements = {} self.__entities = {} def __nonzero__(self): return len(self.__elements) != 0 def saveEntity(self, elem, key, entity): _eid = id(elem) if _eid not in self.__elements: self.__elements[_eid] = elem if _eid not in self.__entities: self.__entities[_eid] = {} _edict = self.__entities[_eid] if key in _edict: raise KeyError, "Key '%s' already stored for element" % key _edict[key] = entity def getElements(self): return self.__elements.values() def getElementKeys(self, element): _eid = id(element) return self.__entities[_eid].keys() def getEntity(self, element, key): _eid = id(element) return self.__entities[_eid][key] def save_image(image, filehandle): """Save a file. save_image(image, filehandle) Argument 'image' should be an Image instance, and 'filehandle' should be an opened file, pipe, or writeable object. """ _map = {} _entmap = EntityMap() _doc = xml.dom.minidom.Document() try: _child = _doc.createElementNS("image", "image:Image") _doc.appendChild(_child) _attr = _doc.createAttributeNS("xmlns", "xmlns:image") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("xmlns", "xmlns:image", "http://www.pythoncad.org") _attr = _doc.createAttributeNS("xmlns", "xmlns:xsi") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("xmlns", "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") _attr = _doc.createAttributeNS("xsi", "xsi:schemaLocation") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("xmlns", "xsi:schemaLocation", "http://www.pythoncad.org") _root = _doc.documentElement # # to only save colors, linetypes, etc. actually used # in the drawing, the get_image_attributes() scans # the image and stores them and returns them in a # dictionary, then the image entities are written out. # this approach requires two passes over the image, and # it would be nice if these two passes could be combined # into a single pass. # _attmap = _get_image_attributes(image) _save_colors(_attmap, _root, _doc, _map) _save_linetypes(_attmap, _root, _doc, _map) _save_styles(_attmap, _root, _doc, _map) _save_font_families(_attmap, _root, _doc, _map) _save_dimstyles(_attmap, _root, _doc, _map) _save_textstyles(_attmap, _root, _doc, _map) _save_units(image, _root, _doc) _save_globals(_attmap, _root, _doc, _map) _lyrs = _doc.createElementNS("image", "image:Layers") _root.appendChild(_lyrs) _layers = [image.getTopLayer()] _i = 0 while len(_layers): _layer = _layers.pop() _map[id(_layer)] = _i _child = _doc.createElementNS("image", "image:Layer") _lyrs.appendChild(_child) _attr = _doc.createAttributeNS("image", "id") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "id", `_i`) _attr = _doc.createAttributeNS("image", "name") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "name", _layer.getName()) _attr = _doc.createAttributeNS("image", "scale") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "scale", `_layer.getScale()`) _parent = _layer.getParentLayer() if _parent is not None: _pid = id(_parent) assert _pid in _map, "Layer %s parent not in map!" % _layer.getName() _attr = _doc.createAttributeNS("image", "parent") _child.setAttributeNodeNS(_attr) _child.setAttributeNS("image", "parent", `_map[_pid]`) _save_points(_layer, _child, _doc, _map) _save_segments(_layer, _child, _doc, _map) _save_circles(_layer, _child, _doc, _map) _save_arcs(_layer, _child, _doc, _map) _save_hclines(_layer, _child, _doc, _map) _save_vclines(_layer, _child, _doc, _map) _save_aclines(_layer, _child, _doc, _map) _save_clines(_layer, _child, _doc, _map) _save_ccircles(_layer, _child, _doc, _map) _save_chamfers(_layer, _child, _doc, _map) _save_fillets(_layer, _child, _doc, _map) _save_leaders(_layer, _child, _doc, _map) _save_polylines(_layer, _child, _doc, _map) _save_textblocks(_layer, _child, _doc, _map) _save_linear_dims(_layer, _child, _doc, _map, _entmap, 'linear_dimension') _save_linear_dims(_layer, _child, _doc, _map, _entmap, 'horizontal_dimension') _save_linear_dims(_layer, _child, _doc, _map, _entmap, 'vertical_dimension') _save_radial_dims(_layer, _child, _doc, _map, _entmap) _save_angular_dims(_layer, _child, _doc, _map, _entmap) _save_state_bits(_layer, _child, _doc) _i = _i + 1 if _layer.hasSublayers(): _layers.extend(_layer.getSublayers()) if _entmap: for _elem in _entmap.getElements(): for _key in _entmap.getElementKeys(_elem): _obj = _entmap.getEntity(_elem, _key) _oid = id(_obj) assert _oid in _map, "Missing object in map: " + `_obj` #if _oid not in _map: # print "missing object in map:" # print "id(): " + `_oid` # print "obj: " + str(_obj) # raise KeyError, "Missing object key" _elem.setAttributeNS("image", _key, `_map[_oid]`) # # write it out # _doc.writexml(filehandle, " ", " ", "\n") finally: _doc.unlink() # # reload an image # class DimMap(object): def __init__(self): self.__layers = {} self.__dims = {} def __nonzero__(self): return len(self.__layers) != 0 def saveDim(self, lyr, dtype, dim): _lid = id(lyr) if _lid not in self.__layers: self.__layers[_lid] = lyr if _lid not in self.__dims: self.__dims[_lid] = {} _dtdict = self.__dims[_lid] if dtype not in _dtdict: _dtdict[dtype] = [] _dtdict[dtype].append(dim) def getLayers(self): return self.__layers.values() def getLayerDimTypes(self, lyr): _lid = id(lyr) return self.__dims[_lid].keys() def getLayerDims(self, lyr, key): _lid = id(lyr) return self.__dims[_lid][key][:] def _apply_dim_overrides(dim, overrides): # print "in _apply_dim_overrides()" for _key in overrides: _val = overrides[_key] if _key == 'DIM_OFFSET': dim.setOffset(_val) elif _key == 'DIM_EXTENSION': dim.setExtension(_val) elif _key == 'DIM_COLOR': dim.setColor(_val) elif _key == 'DIM_POSITION': dim.setPosition(_val) elif _key == 'DIM_ENDPOINT': dim.setEndpointType(_val) elif _key == 'DIM_ENDPOINT_SIZE': dim.setEndpointSize(_val) elif _key == 'DIM_DUAL_MODE': dim.setDualDimMode(_val) elif _key == 'DIM_POSITION_OFFSET': dim.setPositionOffset(_val) elif _key == 'DIM_DUAL_MODE_OFFSET': dim.setDualModeOffset(_val) elif _key == 'DIM_PRIMARY_FONT_FAMILY': dim.getPrimaryDimstring().setFamily(_val) elif _key == 'DIM_PRIMARY_FONT_WEIGHT': dim.getPrimaryDimstring().setWeight(_val) elif _key == 'DIM_PRIMARY_FONT_STYLE': dim.getPrimaryDimstring().setStyle(_val) elif _key == 'DIM_PRIMARY_FONT_COLOR': dim.getPrimaryDimstring().setColor(_val) elif (_key == 'DIM_PRIMARY_PREFIX' or _key == 'RADIAL_DIM_PRIMARY_PREFIX' or _key == 'ANGULAR_DIM_PRIMARY_PREFIX'): dim.getPrimaryDimstring().setPrefix(_val) elif (_key == 'DIM_PRIMARY_SUFFIX' or _key == 'RADIAL_DIM_PRIMARY_SUFFIX' or _key == 'ANGULAR_DIM_PRIMARY_SUFFIX'): dim.getPrimaryDimstring().setSuffix(_val) elif _key == 'DIM_PRIMARY_PRECISION': dim.getPrimaryDimstring().setPrecision(_val) elif _key == 'DIM_PRIMARY_UNITS': dim.getPrimaryDimstring().setUnits(_val) elif _key == 'DIM_PRIMARY_LEADING_ZERO': dim.getPrimaryDimstring().setPrintZero(_val) elif _key == 'DIM_PRIMARY_TRAILING_DECIMAL': dim.getPrimaryDimstring().setPrintDecimal(_val) elif _key == 'DIM_PRIMARY_TEXT_SIZE': dim.getPrimaryDimstring().setSize(_val) elif _key == 'DIM_PRIMARY_TEXT_ANGLE': dim.getPrimaryDimstring().setAngle(_val) elif _key == 'DIM_PRIMARY_TEXT_ALIGNMENT': dim.getPrimaryDimstring().setAlignment(_val) elif _key == 'DIM_SECONDARY_FONT_FAMILY': dim.getSecondaryDimstring().setFamily(_val) elif _key == 'DIM_SECONDARY_FONT_WEIGHT': dim.getSecondaryDimstring().setWeight(_val) elif _key == 'DIM_SECONDARY_FONT_STYLE': dim.getSecondaryDimstring().setStyle(_val) elif _key == 'DIM_SECONDARY_FONT_COLOR': dim.getSecondaryDimstring().setColor(_val) elif (_key == 'DIM_SECONDARY_PREFIX' or _key == 'RADIAL_DIM_SECONDARY_PREFIX' or _key == 'ANGULAR_DIM_SECONDARY_PREFIX'): dim.getSecondaryDimstring().setPrefix(_val) elif (_key == 'DIM_SECONDARY_SUFFIX' or _key == 'RADIAL_DIM_SECONDARY_SUFFIX' or _key == 'ANGULAR_DIM_SECONDARY_SUFFIX'): dim.getSecondaryDimstring().setSuffix(_val) elif _key == 'DIM_SECONDARY_PRECISION': dim.getSecondaryDimstring().setPrecision(_val) elif _key == 'DIM_SECONDARY_UNITS': dim.getSecondaryDimstring().setUnits(_val) elif _key == 'DIM_SECONDARY_LEADING_ZERO': dim.getSecondaryDimstring().setPrintZero(_val) elif _key == 'DIM_SECONDARY_TRAILING_DECIMAL': dim.getSecondaryDimstring().setPrintDecimal(_val) elif _key == 'DIM_SECONDARY_TEXT_SIZE': dim.getSecondaryDimstring().setSize(_val) elif _key == 'DIM_SECONDARY_TEXT_ANGLE': dim.getSecondaryDimstring().setAngle(_val) elif _key == 'DIM_SECONDARY_TEXT_ALIGNMENT': dim.getSecondaryDimstring().setAlignment(_val) elif _key == 'RADIAL_DIM_DIA_MODE': dim.setDiaMode(_val) else: pass # unused key ... def _load_dim_options(node, map): # print "in _load_dim_options()" _options = {} _child = node.firstChild while _child is not None: if _child.nodeType == xml.dom.Node.ELEMENT_NODE: if _child.nodeName == 'image:DimOption': _opt = str(_child.getAttribute('opt')) if (_opt == 'DIM_COLOR' or _opt == 'DIM_PRIMARY_FONT_COLOR' or _opt == 'DIM_SECONDARY_FONT_COLOR'): _cid = int(_child.getAttribute('cid')) assert _cid in map['color'], 'Color index %d missing' % _cid _val = map['color'][_cid] elif (_opt == 'DIM_PRIMARY_FONT_FAMILY' or _opt == 'DIM_SECONDARY_FONT_FAMILY'): _fid = int(_child.getAttribute('fid')) assert _fid in map['family'], 'Font index %d missing' % _fid _val = map['family'][_fid] elif (_opt == 'DIM_OFFSET' or _opt == 'DIM_ENDPOINT_SIZE' or _opt == 'DIM_EXTENSION' or _opt == 'DIM_PRIMARY_TEXT_SIZE' or _opt == 'DIM_SECONDARY_TEXT_SIZE' or _opt == 'DIM_DUAL_MODE_OFFSET' or _opt == 'DIM_POSITION_OFFSET' or _opt == 'DIM_THICKNESS' or _opt == 'DIM_PRIMARY_TEXT_ANGLE' or _opt == 'DIM_SECONDARY_TEXT_ANGLE'): _val = float(_child.getAttribute('val')) elif (_opt == 'DIM_PRIMARY_PRECISION' or _opt == 'DIM_SECONDARY_PRECISION' or _opt == 'DIM_PRIMARY_UNITS' or _opt == 'DIM_SECONDARY_UNITS' or _opt == 'DIM_PRIMARY_FONT_WEIGHT' or _opt == 'DIM_SECONDARY_FONT_WEIGHT' or _opt == 'DIM_PRIMARY_FONT_STYLE' or _opt == 'DIM_SECONDARY_FONT_STYLE' or _opt == 'DIM_POSITION' or _opt == 'DIM_ENDPOINT' or _opt == 'DIM_PRIMARY_TEXT_ALIGNMENT' or _opt == 'DIM_SECONDARY_TEXT_ALIGNMENT'): _val = int(_child.getAttribute('val')) elif (_opt == 'DIM_PRIMARY_LEADING_ZERO' or _opt == 'DIM_SECONDARY_LEADING_ZERO' or _opt == 'DIM_PRIMARY_TRAILING_DECIMAL' or _opt == 'DIM_SECONDARY_TRAILING_DECIMAL' or _opt == 'DIM_DUAL_MODE' or _opt == 'RADIAL_DIM_DIA_MODE'): _val = _child.getAttribute('val') if _val == 0 or _val == u'0' or _val == u'False': _val = False elif _val == 1 or _val == u'1' or _val == u'True': _val = True elif (_opt == 'ANGULAR_DIM_SMALL_ANGLE_MODE' or _opt == 'DIM_PRIMARY_FONT_SIZE' or _opt == 'DIM_SECONDARY_FONT_SIZE'): # obsolete _opt = None else: _val = _child.getAttribute('val') if _opt is not None: _options[_opt] = _val _child = _child.nextSibling return _options def _load_linear_dimensions(node, map): # print "in _load_linear_dimensions()" _dims = [] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and ((_child.nodeName == "image:LDim") or (_child.nodeName == "image:HDim") or (_child.nodeName == "image:VDim"))): _dimopts = {} _id = int(_child.getAttribute("id")) _dimopts['id'] = _id _ds = int(_child.getAttribute("ds")) _dimopts['ds'] = _ds assert _ds in map['dimstyle'], "Missing style %d in map" % _ds _l1 = int(_child.getAttribute("l1")) _dimopts['l1'] = _l1 _p1 = int(_child.getAttribute("p1")) _dimopts['p1'] = _p1 _l2 = int(_child.getAttribute("l2")) _dimopts['l2'] = _l2 _p2 = int(_child.getAttribute("p2")) _dimopts['p2'] = _p2 _x = float(_child.getAttribute("x")) _dimopts['x'] = _x _y = float(_child.getAttribute("y")) _dimopts['y'] = _y _overrides = _load_dim_options(_child, map) for _key in _overrides: _dimopts[_key] = _overrides[_key] _vis, _locked = _get_state_bits(_child) if not _vis: _dimopts['hidden'] = True if _locked: _dimopts['locked'] = True _dims.append(_dimopts) _child = _child.nextSibling return _dims def _load_radial_dimensions(node, map): # print "in _load_radial_dimensions()" _rdims = [] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:RDim")): _dimopts = {} _id = int(_child.getAttribute("id")) _dimopts['id'] = _id _ds = int(_child.getAttribute("ds")) assert _ds in map['dimstyle'], "Missing style %d in map" % _ds _dimopts['ds'] = _ds _l = int(_child.getAttribute("l")) _dimopts['l'] = _l _c = int(_child.getAttribute("c")) _dimopts['c'] = _c _x = float(_child.getAttribute("x")) _dimopts['x'] = _x _y = float(_child.getAttribute("y")) _dimopts['y'] = _y _overrides = _load_dim_options(_child, map) for _key in _overrides: _dimopts[_key] = _overrides[_key] _vis, _locked = _get_state_bits(_child) if not _vis: _dimopts['hidden'] = True if _locked: _dimopts['locked'] = True _rdims.append(_dimopts) _child = _child.nextSibling return _rdims def _load_angular_dimensions(node, map): # print "in _load_angular_dimensions()" _adims = [] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:ADim")): _dimopts = {} _id = int(_child.getAttribute("id")) _dimopts['id'] = _id _ds = int(_child.getAttribute("ds")) assert _ds in map['dimstyle'], "Missing style %d in map" % _ds _dimopts['ds'] = _ds _l1 = int(_child.getAttribute("l1")) _dimopts['l1'] = _l1 _p1 = int(_child.getAttribute("p1")) _dimopts['p1'] = _p1 _l2 = int(_child.getAttribute("l2")) _dimopts['l2'] = _l2 _p2 = int(_child.getAttribute("p2")) _dimopts['p2'] = _p2 _l3 = int(_child.getAttribute("l3")) _dimopts['l3'] = _l3 _p3 = int(_child.getAttribute("p3")) _dimopts['p3'] = _p3 _x = float(_child.getAttribute("x")) _dimopts['x'] = _x _y = float(_child.getAttribute("y")) _dimopts['y'] = _y _overrides = _load_dim_options(_child, map) for _key in _overrides: _dimopts[_key] = _overrides[_key] _vis, _locked = _get_state_bits(_child) if not _vis: _dimopts['hidden'] = True if _locked: _dimopts['locked'] = True _adims.append(_dimopts) _child = _child.nextSibling return _adims def _set_graphic_attrs(obj, node, map): _ltid = node.getAttribute("linetype") if _ltid != "": _ltid = int(_ltid) assert _ltid in map['linetype'], "Object linetype index %d not in map: %s" % (_ltid, str(obj)) _lt = map['linetype'][_ltid] obj.setLinetype(_lt) _cid = node.getAttribute("color") if _cid != "": _cid = int(_cid) assert _cid in map['color'], "Object color index %d not in map: %s" % (_cid, str(obj)) _c = map['color'][_cid] obj.setColor(_c) _th = node.getAttribute("thickness") if _th != "": _th = float(_th) obj.setThickness(_th) def _get_state_bits(node): _vis = True _locked = False _attr = node.getAttribute("visibility") if _attr != "": if _attr == 0 or _attr == u'0' or _attr == u'False': _vis = False _attr = node.getAttribute("locked") if _attr != "": if _attr == 1 or _attr == u'1' or _attr == u'True': _locked = True return _vis, _locked def _load_textblocks(image, node, map): _layer = image.getActiveLayer() _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:TextBlock")): # _id = int(_child.getAttribute("id")) _tsid = int(_child.getAttribute("tsid")) assert _tsid in map['textstyle'], "TextBlock textstyle id not in map: %d" % _tsid _style = map['textstyle'][_tsid] _x = float(_child.getAttribute("x")) _y = float(_child.getAttribute("y")) _text = u'' if _child.hasChildNodes(): _lines = [] _linenode = _child.firstChild while _linenode is not None: if ((_linenode.nodeType == xml.dom.Node.ELEMENT_NODE) and (_linenode.nodeName == "image:TextLine")): _text = _linenode.getAttribute("text") _lines.append(unicode(_text)) _linenode = _linenode.nextSibling # # this is lame ... # if sys.platform == 'mac': _sep = '\r' else: _sep = '\n' _text = _sep.join(_lines) _textblock = text.TextBlock(_x, _y, _text, _style) # # get any possibly overriden style values # _attr = _child.getAttribute("fid") if _attr != "": _fid = int(_attr) _family = map['family'][_fid] _textblock.setFamily(_family) _attr = _child.getAttribute("cid") if _attr != "": _cid = int(_attr) _color = map['color'][_cid] _textblock.setColor(_color) _attr = _child.getAttribute("weight") if _attr != "": _weight = text.TextStyle.WEIGHT_NORMAL if _attr == 'normal' or _attr == '0': _weight = text.TextStyle.WEIGHT_NORMAL elif _attr == 'light' or _attr == '1': _weight = text.TextStyle.WEIGHT_LIGHT elif _attr == 'bold' or _attr == '2': _weight = text.TextStyle.WEIGHT_BOLD elif _attr == 'heavy' or _attr == '3': _weight = text.TextStyle.WEIGHT_HEAVY else: sys.stderr.write("Unknown font weight '%s' - using NORMAL\n" % _attr) _textblock.setWeight(_weight) _attr = _child.getAttribute("style") if _attr != "": _style = text.TextStyle.FONT_NORMAL if _attr == 'normal' or _attr == '0': _style = text.TextStyle.FONT_NORMAL elif _attr == 'oblique' or _attr == '1': _style = text.TextStyle.FONT_OBLIQUE elif _attr == 'italic' or _attr == '2': _style = text.TextStyle.FONT_ITALIC else: sys.stderr.write("Unknown font style '%s' - using NORMAL\n" % _attr) _textblock.setStyle(_style) _attr = _child.getAttribute("size") if _attr != "": _size = float(_attr) _textblock.setSize(_size) _attr = _child.getAttribute("angle") if _attr != "": _angle = float(_attr) _textblock.setAngle(_angle) _attr = _child.getAttribute("halign") if _attr != "": _align = text.TextStyle.ALIGN_LEFT if _attr == 'left' or _attr == '0': _align = text.TextStyle.ALIGN_LEFT elif _attr == 'center' or _attr == '1': _align = text.TextStyle.ALIGN_CENTER elif _attr == 'right' or _attr == '2': _align = text.TextStyle.ALIGN_RIGHT else: sys.stderr.write("Unknown alignment %s - using ALIGN_LEFT\n" % _attr) _textblock.setAlignment(_align) _vis, _locked = _get_state_bits(_child) if not _vis: _textblock.setVisibility(False) if _locked: _locked.append(_textblock) _layer.addObject(_textblock) _child = _child.nextSibling def _load_leaders(image, node, map): _layer = image.getActiveLayer() _lid = id(_layer) _pmap = map[_lid]['point'] _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:Leader")): # _id = int(_child.getAttribute("id")) _pid = int(_child.getAttribute("p1")) assert _pid in _pmap, "Leader p1 index %d not in map!" % _pid _p1 = _pmap[_pid] _pid = int(_child.getAttribute("p2")) assert _pid in _pmap, "Leader p2 index %d not in map!" % _pid _p2 = _pmap[_pid] _pid = int(_child.getAttribute("p3")) assert _pid in _pmap, "Leader p3 index %d not in map!" % _pid _p3 = _pmap[_pid] _sid = int(_child.getAttribute("style")) _size = float(_child.getAttribute("size")) assert _sid in map['style'], "Leader style index %d not in map!" % _sid _style = map['style'][_sid] _leader = leader.Leader(_p1, _p2, _p3, _size, _style) _set_graphic_attrs(_leader, _child, map) _vis, _locked = _get_state_bits(_child) if not _vis: _leader.setVisibility(False) if _locked: _locked.append(_leader) _layer.addObject(_leader) _child = _child.nextSibling def _load_polylines(image, node, map): _layer = image.getActiveLayer() _lid = id(_layer) _pmap = map[_lid]['point'] _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:Polyline")): # _id = int(_child.getAttribute("id")) _mpts = eval(_child.getAttribute("points")) _pts = [] for _mpt in _mpts: assert _mpt in _pmap, "Polyline point %d not in map!" % _mpt _pts.append(_pmap[_mpt]) _sid = int(_child.getAttribute("style")) assert _sid in map['style'], "Polyline style index %d not in map!" % _sid _st = map['style'][_sid] _polyline = polyline.Polyline(_pts, _st) _set_graphic_attrs(_polyline, _child, map) _vis, _locked = _get_state_bits(_child) if not _vis: _polyline.setVisibility(False) if _locked: _locked.append(_polyline) _layer.addObject(_polyline) _child = _child.nextSibling def _load_fillets(image, node, map): _layer = image.getActiveLayer() _lid = id(_layer) _smap = map[_lid]['segment'] _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:Fillet")): # _id = int(_child.getAttribute("id")) _sid = int(_child.getAttribute("s1")) assert _sid in _smap, "Fillet segment s1 %d not in map!" % _sid _s1 = _smap[_sid] _sid = int(_child.getAttribute("s2")) assert _sid in _smap, "Fillet segment s2 %s not in map!" % _sid _s2 = _smap[_sid] _sid = int(_child.getAttribute("style")) assert _sid in map['style'], "Fillet style index %d not in map!" % _sid _style = map['style'][_sid] _radius = float(_child.getAttribute("radius")) _fillet = segjoint.Fillet(_s1, _s2, _radius, _style) _set_graphic_attrs(_fillet, _child, map) _vis, _locked = _get_state_bits(_child) if not _vis: _fillet.setVisibility(False) if _locked: _locked.append(_fillet) _layer.addObject(_fillet) _child = _child.nextSibling def _load_chamfers(image, node, map): _layer = image.getActiveLayer() _lid = id(_layer) _smap = map[_lid]['segment'] _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:Chamfer")): # _id = int(_child.getAttribute("id")) _sid = int(_child.getAttribute("s1")) assert _sid in _smap, "Chamfer segment s1 %d not in map!" % _sid _s1 = _smap[_sid] _sid = int(_child.getAttribute("s2")) assert _sid in _smap, "Chamfer segment s2 %s not in map!" % _sid _s2 = _smap[_sid] _sid = int(_child.getAttribute("style")) assert _sid in map['style'], "Chamfer style index %d not in map!" % _sid _style = map['style'][_sid] _length = float(_child.getAttribute("length")) _chamfer = segjoint.Chamfer(_s1, _s2, _length, _style) _set_graphic_attrs(_chamfer, _child, map) _vis, _locked = _get_state_bits(_child) if not _vis: _chamfer.setVisibility(False) if _locked: _locked.append(_chamfer) _layer.addObject(_chamfer) _child = _child.nextSibling def _load_ccircles(image, node, map): _layer = image.getActiveLayer() _lid = id(_layer) _pmap = map[_lid]['point'] _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:CCircle")): # _id = int(_child.getAttribute("id")) _cid = int(_child.getAttribute("cp")) assert _cid in _pmap, "CCircle center index %d not in map!" % _cid _cen = _pmap[_cid] _rad = float(_child.getAttribute("r")) _cc = ccircle.CCircle(_cen, _rad) _vis, _locked = _get_state_bits(_child) if not _vis: _cc.setVisibility(False) if _locked: _locked.append(_cc) _layer.addObject(_cc) _child = _child.nextSibling def _load_clines(image, node, map): _layer = image.getActiveLayer() _lid = id(_layer) _pmap = map[_lid]['point'] _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:CLine")): # _id = int(_child.getAttribute("id")) _pid = int(_child.getAttribute("p1")) assert _pid in _pmap, "CLine p1 index %d not in map!" % _pid _p1 = _pmap[_pid] _pid = int(_child.getAttribute("p2")) assert _pid in _pmap, "CLine p2 index %d not in map!" % _pid _p2 = _pmap[_pid] _cl = cline.CLine(_p1, _p2) _vis, _locked = _get_state_bits(_child) if not _vis: _cl.setVisibility(False) if _locked: _locked.append(_cl) _layer.addObject(_cl) _child = _child.nextSibling def _load_aclines(image, node, map): _layer = image.getActiveLayer() _lid = id(_layer) _pmap = map[_lid]['point'] _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:ACLine")): #_id = int(_child.getAttribute("id")) _pid = int(_child.getAttribute("location")) _angle = float(_child.getAttribute("angle")) assert _pid in _pmap, "ACLine location index %d not in map!" % _pid _loc = _pmap[_pid] _acl = acline.ACLine(_loc, _angle) _vis, _locked = _get_state_bits(_child) if not _vis: _acl.setVisibility(False) if _locked: _locked.append(_acl) _layer.addObject(_acl) _child = _child.nextSibling def _load_vclines(image, node, map): _layer = image.getActiveLayer() _lid = id(_layer) _pmap = map[_lid]['point'] _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:VCLine")): # _id = int(_child.getAttribute("id")) _pid = int(_child.getAttribute("location")) assert _pid in _pmap, "VCLine location index %d not in map!" % _pid _loc = _pmap[_pid] _vcl = vcline.VCLine(_loc) _vis, _locked = _get_state_bits(_child) if not _vis: _vcl.setVisibility(False) if _locked: _locked.append(_vcl) _layer.addObject(_vcl) _child = _child.nextSibling def _load_hclines(image, node, map): _layer = image.getActiveLayer() _lid = id(_layer) _pmap = map[_lid]['point'] _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:HCLine")): # _id = int(_child.getAttribute("id")) _pid = int(_child.getAttribute("location")) assert _pid in _pmap, "HCLine location index %d not in map!" % _pid _loc = _pmap[_pid] _hcl = hcline.HCLine(_loc) _vis, _locked = _get_state_bits(_child) if not _vis: _hcl.setVisibility(False) if _locked: _locked.append(_hcl) _layer.addObject(_hcl) _child = _child.nextSibling def _load_arcs(image, node, map): _layer = image.getActiveLayer() _lid = id(_layer) _pmap = map[_lid]['point'] _amap = {} map[_lid]['arc'] = _amap _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:Arc")): _id = int(_child.getAttribute("id")) _cid = int(_child.getAttribute("cp")) assert _cid in _pmap, "Arc center index %d not in map!" % _cid _cen = _pmap[_cid] _rad = float(_child.getAttribute("r")) _sa = float(_child.getAttribute("sa")) _ea = float(_child.getAttribute("ea")) _sid = int(_child.getAttribute("style")) assert _sid in map['style'], "Arc style index %d not in map!" % _sid _style = map['style'][_sid] _arc = arc.Arc(_cen, _rad, _sa, _ea, _style) _set_graphic_attrs(_arc, _child, map) _vis, _locked = _get_state_bits(_child) if not _vis: _arc.setVisibility(False) if _locked: _locked.append(_arc) _amap[_id] = _arc _layer.addObject(_arc) _child = _child.nextSibling def _load_circles(image, node, map): _layer = image.getActiveLayer() _lid = id(_layer) _pmap = map[_lid]['point'] _cmap = {} map[_lid]['circle'] = _cmap _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:Circle")): _id = int(_child.getAttribute("id")) _cid = int(_child.getAttribute("cp")) assert _cid in _pmap, "Circle center index %d not in map!" % _cid _cen = _pmap[_cid] _rad = float(_child.getAttribute("r")) _sid = int(_child.getAttribute("style")) assert _sid in map['style'], "Circle style index %d not in map!" % _sid _style = map['style'][_sid] _circle = circle.Circle(_cen, _rad, _style) _set_graphic_attrs(_circle, _child, map) _vis, _locked = _get_state_bits(_child) if not _vis: _circle.setVisibility(False) if _locked: _locked.append(_circle) _layer.addObject(_circle) _cmap[_id] = _circle _child = _child.nextSibling def _load_segments(image, node, map): _layer = image.getActiveLayer() _lid = id(_layer) _pmap = map[_lid]['point'] _smap = {} map[_lid]['segment'] = _smap _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:Segment")): _id = int(_child.getAttribute("id")) _pid = int(_child.getAttribute("p1")) assert _pid in _pmap, "Segment p1 index %d not in map!" % _pid _p1 = _pmap[_pid] _pid = int(_child.getAttribute("p2")) assert _pid in _pmap, "Segment p2 index %d not in map!" % _pid _p2 = _pmap[_pid] _sid = int(_child.getAttribute("style")) assert _sid in map['style'], "Segment style index %d not in map!" % _sid _style = map['style'][_sid] _seg = segment.Segment(_p1, _p2, _style) _set_graphic_attrs(_seg, _child, map) _vis, _locked = _get_state_bits(_child) if not _vis: _seg.setVisibility(False) if _locked: _locked.append(_seg) _layer.addObject(_seg) _smap[_id] = _seg _child = _child.nextSibling def _load_points(image, node, map): _layer = image.getActiveLayer() _lid = id(_layer) _pmap = {} map[_lid]['point'] = _pmap _locked = map['locked'] _child = node.firstChild while _child is not None: if ((_child.nodeType == xml.dom.Node.ELEMENT_NODE) and (_child.nodeName == "image:Point")): _id = int(_child.getAttribute("id")) _x = float(_child.getAttribute("x")) _y = float(_child.getAttribute("y")) _p = point.Point(_x, _y) _vis, _locked = _get_state_bits(_child) if not _vis: _p.setVisibility(False) if _locked: _locked.append(_p) _layer.addObject(_p) _pmap[_id] = _p _child = _child.nextSibling def _load_layer(image, node, map, dimmap): _layer = image.getActiveLayer() _lid = id(_layer) map[_lid] = {} _child = node.firstChild while _child is not None: if _child.nodeType == xml.dom.Node.ELEMENT_NODE: _name = _child.nodeName if _name == "image:Points": _load_points(image, _child, map) elif _name == "image:Segments": _load_segments(image, _child, map) elif _name == "image:Circles": _load_circles(image, _child, map) elif _name == "image:Arcs": _load_arcs(image, _child, map) elif _name == "image:HCLines": _load_hclines(image, _child, map) elif _name == "image:VCLines": _load_vclines(image, _child, map) elif _name == "image:ACLines": _load_aclines(image, _child, map) elif _name == "image:CLines": _load_clines(image, _child, map) elif _name == "image:CCircles": _load_ccircles(image, _child, map) elif _name == "image:Fillets": _load_fillets(image, _child, map) elif _name == "image:Chamfers": _load_chamfers(image, _child, map) elif _name == "image:Leaders": _load_leaders(image, _child, map) elif _name == "image:Polylines": _load_polylines(image, _child, map) elif _name == "image:TextBlocks": _load_textblocks(image, _child, map) elif _name == "image:LDims": for _dim in _load_linear_dimensions(_child, map): dimmap.saveDim(_layer, 'linear', _dim) elif _name == "image:HDims": for _dim in _load_linear_dimensions(_child, map): dimmap.saveDim(_layer, 'horizontal', _dim) elif _name == "image:VDims": for _dim in _load_linear_dimensions(_child, map): dimmap.saveDim(_layer, 'vertical', _dim) elif _name == "image:RDims": for _dim in _load_radial_dimensions(_child, map): dimmap.saveDim(_layer, 'radial', _dim) elif _name == "image:ADims": for _dim in _load_angular_dimensions(_child, map): dimmap.saveDim(_layer, 'angular', _dim) _child = _child.nextSibling def _add_linear_dimension(dim, map, dimtype, image, lyr): assert 'ds' in dim, "Dim missing key 'ds': " + `dim` _dsid = dim['ds'] assert _dsid in map['dimstyle'], "Missing dimstyle id %d" % _dsid _ds = map['dimstyle'][_dsid] del dim['ds'] assert 'l1' in dim, "Dim missing key 'l1': " + `dim` _lid = dim['l1'] del dim['l1'] assert _lid in map['layer'], "Missing layer id %d" % _lid _l1 = map['layer'][_lid] assert 'p1' in dim, "Dim missing key 'p1': " + `dim` _pid = dim['p1'] del dim['p1'] _lid = id(_l1) assert _pid in map[_lid]['point'], "Missing p1 key %d in map" % _pid _p1 = map[_lid]['point'][_pid] assert 'l2' in dim, "Dim missing key 'l2': " + `dim` _lid = dim['l2'] del dim['l2'] assert _lid in map['layer'], "Missing layer id %d" % _lid _l2 = map['layer'][_lid] assert 'p2' in dim, "Dim missing key 'p2': " + `dim` _pid = dim['p2'] del dim['p2'] _lid = id(_l2) assert _pid in map[_lid]['point'], "Missing p2 key %d in map" % _pid _p2 = map[_lid]['point'][_pid] assert 'x' in dim, "Dim missing key 'x': " + `dim` _x = dim['x'] del dim['x'] assert 'y' in dim, "Dim missing key 'y': " + `dim` _y = dim['y'] del dim['y'] _ldim = dimtype(_p1, _p2, _x, _y, _ds) if 'id' in dim: del dim['id'] # print "remaining keys ..." # for _key in dim: # print "key: %s" % _key # print "value: " + `dim[_key]` if len(dim): _apply_dim_overrides(_ldim, dim) if 'hidden' in dim: _ldim.setVisibility(False) if 'locked' in dim: _ldim.setLock(True) image.ignore('modified') try: image.addObject(_ldim, lyr) finally: image.receive('modified') _log = lyr.getLog() # fixme - this will go away if _log is not None: _log.clear() def _add_radial_dimension(dim, map, image, lyr): assert 'id' in dim, "Dim missing key 'id': " + `dim` assert 'ds' in dim, "Dim missing key 'ds': " + `dim` _dsid = dim['ds'] assert _dsid in map['dimstyle'], "Missing dimstyle id %d" % _dsid _ds = map['dimstyle'][_dsid] del dim['ds'] assert 'l' in dim, "Dim missing key 'l': " + `dim` _lid = dim['l'] del dim['l'] assert _lid in map['layer'], "Missing layer id %d" % _lid _cl = map['layer'][_lid] assert 'c' in dim, "Dim missing key 'c': " + `dim` _cid = dim['c'] del dim['c'] _lid = id(_cl) assert _cid in map[_lid]['circle'], "Missing circle key %d" % _cid _circ = map[_lid]['circle'][_cid] assert 'x' in dim, "Dim missing key 'x': " + `dim` _x = dim['x'] del dim['x'] assert 'y' in dim, "Dim missing key 'y': " + `dim` _y = dim['y'] del dim['y'] _rdim = dimension.RadialDimension(_circ, _x, _y, _ds) if 'id' in dim: del dim['id'] # print "remaining keys ..." # for _key in dim: # print "key: %s" % key # print "value: " + `dim[_key]` if len(dim): _apply_dim_overrides(_rdim, dim) if 'hidden' in dim: _rdim.setVisibility(False) if 'locked' in dim: _rdim.setLock(True) image.ignore('modified') try: image.addObject(_rdim, lyr) finally: image.receive('modified') _log = lyr.getLog() # fixme - this will go away if _log is not None: _log.clear() def _add_angular_dimension(dim, map, image, lyr): assert 'id' in dim, "Dim missing key 'id': " + `dim` assert 'ds' in dim, "Dim missing key 'ds': " + `dim` _dsid = dim['ds'] assert _dsid in map['dimstyle'], "Missing dimstyle id %d" % _dsid _ds = map['dimstyle'][_dsid] del dim['ds'] assert 'l1' in dim, "Dim missing key 'l1': " + `dim` _lid = dim['l1'] del dim['l1'] assert _lid in map['layer'], "Missing layer id %d" % _lid _l1 = map['layer'][_lid] assert 'p1' in dim, "Dim missing key 'p1': " + `dim` _pid = dim['p1'] del dim['p1'] _lid = id(_l1) assert _pid in map[_lid]['point'], "Missing p1 id %d" % _pid _p1 = map[_lid]['point'][_pid] assert 'l2' in dim, "Dim missing key 'l2': " + `dim` _lid = dim['l2'] del dim['l2'] assert _lid in map['layer'], "Missing layer id %d" % _lid _l2 = map['layer'][_lid] assert 'p2' in dim, "Dim missing key 'p2': " + `dim` _pid = dim['p2'] del dim['p2'] _lid = id(_l2) assert _pid in map[_lid]['point'], "Missing p2 id %d" % _pid _p2 = map[_lid]['point'][_pid] assert 'l3' in dim, "Dim missing key 'l3': " + `dim` _lid = dim['l3'] del dim['l3'] assert _lid in map['layer'], "Missing layer id %d" % _lid _l3 = map['layer'][_lid] assert 'p3' in dim, "Dim missing key 'p3': " + `dim` _pid = dim['p3'] del dim['p3'] _lid = id(_l3) assert _pid in map[_lid]['point'], "Missing p3 id %d" % _pid _p3 = map[_lid]['point'][_pid] assert 'x' in dim, "Dim missing key 'x': " + `dim` _x = dim['x'] del dim['x'] assert 'y' in dim, "Dim missing key 'y': " + `dim` _y = dim['y'] del dim['y'] _adim = dimension.AngularDimension(_p1, _p2, _p3, _x, _y, _ds) if 'id' in dim: del dim['id'] # print "remaining keys ..." # for _key in dim: # print "key: %s" % _key # print "value: " + `dim[_key]` if len(dim): _apply_dim_overrides(_adim, dim) if 'hidden' in dim: _adim.setVisibility(False) if 'locked' in dim: _adim.setLock(True) image.ignore('modified') try: image.addObject(_adim, lyr) finally: image.receive('modified') _log = lyr.getLog() # fixme - this will go away if _log is not None: _log.clear() def _load_layers(image, node, map): _lmap = {} map['layer'] = _lmap map['locked'] = [] _dimmap = DimMap() _child = node.firstChild while _child is not None: if _child.nodeType == xml.dom.Node.ELEMENT_NODE: if _child.nodeName == "image:Layer": _id = int(_child.getAttribute("id")) _name = str(_child.getAttribute("name")) _scale = float(_child.getAttribute("scale")) _pid = _child.getAttribute("parent") if _pid == "": # top layer created with image _layer = image.getTopLayer() _layer.setName(_name) else: _pid = int(_pid) assert _pid in _lmap, "Layer parent id %d missing in map!" % _pid _parent = _lmap[_pid] _layer = layer.Layer(_name) image.muteMessage('modified') try: image.addChildLayer(_layer, _parent) finally: image.unmuteMessage('modified') _layer.setScale(_scale) _vis, _locked = _get_state_bits(_child) if not _vis: _layer.setVisibility(False) if _locked: _locked.append(_layer) image.setActiveLayer(_layer) _lmap[_id] = _layer image.ignore('modified') try: _load_layer(image, _child, map, _dimmap) finally: image.receive('modified') _log = _layer.getLog() # fixme - this will go away if _log is not None: _log.clear() _child = _child.nextSibling if _dimmap: for _layer in _dimmap.getLayers(): for _dimtype in _dimmap.getLayerDimTypes(_layer): for _dim in _dimmap.getLayerDims(_layer, _dimtype): if _dimtype == 'linear': _add_linear_dimension(_dim, map, dimension.LinearDimension, image, _layer) elif _dimtype == 'horizontal': _add_linear_dimension(_dim, map, dimension.HorizontalDimension, image, _layer) elif _dimtype == 'vertical': _add_linear_dimension(_dim, map, dimension.VerticalDimension, image, _layer) elif _dimtype == 'radial': _add_radial_dimension(_dim, map, image, _layer) elif _dimtype == 'angular': _add_angular_dimension(_dim, map, image, _layer) else: raise TypeError, "Unknown dimension type %s" % _dimtype def _load_textstyles(image, node, map): map['textstyle'] = {} _gts = globals.prefs['TEXTSTYLES'] _child = node.firstChild while _child is not None: if _child.nodeType == xml.dom.Node.ELEMENT_NODE: if _child.nodeName == "image:TextStyle": _id = int(_child.getAttribute("id")) _name= _child.getAttribute("name") _cid = int(_child.getAttribute("cid")) assert _cid in map['color'], "Color ID missing from map: %d" % _cid _color = map['color'][_cid] _fid = int(_child.getAttribute("fid")) assert _fid in map['family'], "Font ID missing from map: %d" % _fid _family = map['family'][_fid] _attr = _child.getAttribute("weight") _weight = text.TextStyle.WEIGHT_NORMAL if _attr == 'normal' or _attr == '0': _weight = text.TextStyle.WEIGHT_NORMAL elif _attr == 'light' or _attr == '1': _weight = text.TextStyle.WEIGHT_LIGHT elif _attr == 'bold' or _attr == '2': _weight = text.TextStyle.WEIGHT_BOLD elif _attr == 'heavy' or _attr == '3': _weight = text.TextStyle.WEIGHT_HEAVY else: sys.stderr.write("Unknown font weight '%s' - using NORMAL\n" % _attr) # # size used to be integer in older TextStyles # _size = float(_child.getAttribute("size")) _attr = _child.getAttribute("style") _style = text.TextStyle.FONT_NORMAL if _attr == 'normal' or _attr == '0': _style = text.TextStyle.FONT_NORMAL elif _attr == 'oblique' or _attr == '1': _style = text.TextStyle.FONT_OBLIQUE elif _attr == 'italic' or _attr == '2': _style = text.TextStyle.FONT_ITALIC else: sys.stderr.write("Unknown font style '%s' - using NORMAL\n" % _attr) # # angle not present in older TextStyles # _angle = 0.0 _attr = _child.getAttribute("angle") if _attr != "": _angle = float(_attr) # # alignment not present in older TextStyles # _align = text.TextStyle.ALIGN_LEFT _attr = _child.getAttribute("halign") if _attr != "": if _attr == 'left' or _attr == '0': _align = text.TextStyle.ALIGN_LEFT elif _attr == 'center' or _attr == '1': _align = text.TextStyle.ALIGN_CENTER elif _attr == 'right' or _attr == '2': _align = text.TextStyle.ALIGN_RIGHT else: sys.stderr.write("Unknown alignment %s - using ALIGN_LEFT\n" % _attr) _textstyle = None for _ts in _gts: # print "Testing global TextStyle '%s'" % _ts.getName() if ((_ts.getName() == _name) and (_ts.getFamily() == _family) and (abs(_ts.getSize() - _size) < 1e-10) and (_ts.getStyle() == _style) and (_ts.getWeight() == _weight) and (_ts.getColor() == _color) and (abs(_ts.getAngle() - _angle) < 1e-10) and (_ts.getAlignment() == _align)): # print "TextStyle/global match" # print "Global TextStyle: " + `_ts` _textstyle = _ts break if _textstyle is None: # print "No matching TextStyle" # print "Name: %s" % _name # print "Family: %s" % _family # print "Size: %f" % _size # print "Style: %d" % _style # print "Weight: %d" % _weight # print "Angle: %f" % _angle # print "Align: %d" % _align # print "Color: %s" % str(_color) _textstyle = text.TextStyle(_name, family=_family, size=_size, style=_style, weight=_weight, color=_color, angle=_angle, align=_align) image.addTextStyle(_textstyle) map['textstyle'][_id] = _textstyle _child = _child.nextSibling def _load_dimstyles(image, node, map): map['dimstyle'] = {} _gds = globals.prefs['DIMSTYLES'] _dsk = dimension.DimStyle.getDimStyleOptions() _dds = dimension.Dimension.getDefaultDimStyle() _child = node.firstChild while _child is not None: if _child.nodeType == xml.dom.Node.ELEMENT_NODE: if _child.nodeName == "image:DimStyle": _id = int(_child.getAttribute("id")) _name = _child.getAttribute("name") _dsopts = _load_dim_options(_child, map) # print "print keys ..." # _dskeys = _dsopts.keys() # _dskeys.sort() # for key in dskeys: # print "key: " + key + "; value: " + `dsopts[key]` _dimstyle = None for _ds in _gds: _match = False if _name == _ds.getName(): _match = True for _k in _dsk: if _k in _dsopts: _v = _dsopts[_k] else: _v = _dds.getOption(_k) _dv = _ds.getOption(_k) if ((_k == 'DIM_PRIMARY_TEXT_SIZE') or (_k == 'DIM_PRIMARY_TEXT_ANGLE') or (_k == 'DIM_SECONDARY_TEXT_SIZE') or (_k == 'DIM_SECONDARY_TEXT_ANGLE') or (_k == 'DIM_OFFSET') or (_k == 'DIM_EXTENSION') or (_k == 'DIM_THICKNESS') or (_k == 'DIM_ENDPOINT_SIZE') or (_k == 'DIM_POSITION_OFFSET') or (_k == 'DIM_DUAL_MODE_OFFSET')): if abs(_v - _dv) > 1e-10: _match = False else: if _v != _dv: _match = False if not _match: break if _match: _dimstyle = _ds break if _dimstyle is None: _dimstyle = dimension.DimStyle(_name, _dsopts) image.addDimStyle(_dimstyle) map['dimstyle'][_id] = _dimstyle _child = _child.nextSibling def _load_font_families(image, node, map): map['family'] = {} _child = node.firstChild while _child is not None: if _child.nodeType == xml.dom.Node.ELEMENT_NODE: if _child.nodeName == "image:FontFamily": _id = int(_child.getAttribute("id")) _family = str(_child.getAttribute("name")) image.addFont(_family) map['family'][_id] = _family _child = _child.nextSibling def _load_styles(image, node, map): map['style'] = {} _gs = globals.prefs['STYLES'] _child = node.firstChild while _child is not None: if _child.nodeType == xml.dom.Node.ELEMENT_NODE: if _child.nodeName == "image:Style": _id = int(_child.getAttribute("id")) _cid = int(_child.getAttribute("cid")) assert _cid in map['color'], "Color index %d missing" % _cid _color = map['color'][_cid] _ltid = int(_child.getAttribute("ltid")) assert _ltid in map['linetype'], "Linetype index %d missing" % _ltid _lt = map['linetype'][_ltid] _name = _child.getAttribute("name") _th = float(_child.getAttribute("thickness")) _style = None for _st in _gs: if ((_name == _st.getName()) and (_color == _st.getColor()) and (_lt == _st.getLinetype()) and (abs(_th - _st.getThickness()) < 1e-10)): _style = _st break if _style is None: _style = style.Style(_name, _lt, _color, _th) image.addStyle(_style) map['style'][_id] = _style _child = _child.nextSibling def _load_globals(image, node, map): # # for now, assumes globals are ONLY colors # _child = node.firstChild while _child is not None: if _child.nodeType == xml.dom.Node.ELEMENT_NODE: if _child.nodeName == "image:Global": _key = str(_child.getAttribute("key")) _cid = int(_child.getAttribute("cid")) assert _cid in map['color'], "Color index %d missing" % _cid _color = map['color'][_cid] image.setOption(_key, _color) _child = _child.nextSibling def _load_linetypes(image, node, map): map['linetype'] = {} _glt = globals.prefs['LINETYPES'] _child = node.firstChild while _child is not None: if _child.nodeType == xml.dom.Node.ELEMENT_NODE: if _child.nodeName == "image:Linetype": _id = int(_child.getAttribute("id")) _name = _child.getAttribute("name") _attr = _child.getAttribute("pattern") _list = None if _attr != "None": _list = eval(_attr) # can this be done without eval()? _linetype = None for _lt in _glt: if _name == _lt.getName(): _dlist = _lt.getList() if ((_list is None and _dlist is None) or ((type(_list) == type(_dlist)) and (_list == _dlist))): _linetype = _lt break if _linetype is None: _linetype = linetype.Linetype(_name, _list) image.addLinetype(_linetype) map['linetype'][_id] = _linetype _child = _child.nextSibling def _load_colors(image, node, map): map['color'] = {} _gc = globals.prefs['COLORS'] _child = node.firstChild while _child is not None: if _child.nodeType == xml.dom.Node.ELEMENT_NODE: if _child.nodeName == "image:Color": _id = int(_child.getAttribute("id")) _r = int(_child.getAttribute("r")) _g = int(_child.getAttribute("g")) _b = int(_child.getAttribute("b")) _color = None for _c in _gc: if _r == _c.r and _g == _c.g and _b == _c.b: _color = _c break if _color is None: _color = color.Color(_r, _g, _b) image.addColor(_color) map['color'][_id] = _color _child = _child.nextSibling def load_image(image, filehandle): """Load an image from a filename or standard input load_image(image, filehandle) The argument image should be an empty image. The filehandle argument should be an opened file object that can be passed to the XML parser. """ _objmap = {} _doc = xml.dom.minidom.parse(filehandle) _root = _doc.documentElement if _root.nodeName != "image:Image": _doc.unlink() raise ValueError, "Expected 'image:Image' but got '%s' as document root!" % _root.name _child = _root.firstChild while _child.nodeType == xml.dom.Node.TEXT_NODE: _child = _child.nextSibling if _child.nodeName != "image:Colors": _doc.unlink() raise ValueError, "Expected 'image:Colors' but got '%s'" % _child.nodeName _load_colors(image, _child, _objmap) _child = _child.nextSibling while _child.nodeType == xml.dom.Node.TEXT_NODE: _child = _child.nextSibling if _child.nodeName != "image:Linetypes": raise ValueError, "Expected 'image:Linetypes' but got '%s'" % _child.nodeName _load_linetypes(image, _child, _objmap) _child = _child.nextSibling while _child.nodeType == xml.dom.Node.TEXT_NODE: _child = _child.nextSibling if _child.nodeName != "image:Styles": _doc.unlink() raise ValueError, "Expected 'image:Styles' but got '%s'" % _child.nodeName _load_styles(image, _child, _objmap) _child = _child.nextSibling while _child is not None: if _child.nodeType == xml.dom.Node.ELEMENT_NODE: _name = _child.nodeName if _name == "image:Units": _attr = _child.getAttribute("unit") if _attr == 'millimeters' or _attr == '0': _unit = units.MILLIMETERS elif _attr == 'micrometers' or _attr == '1': _unit = units.MICROMETERS elif _attr == 'meters' or _attr == '2': _unit = units.METERS elif _attr == 'kilometers' or _attr == '3': _unit = units.KILOMETERS elif _attr == 'inches' or _attr == '4': _unit = units.INCHES elif _attr == 'feet' or _attr == '5': _unit = units.FEET elif _attr == 'yards' or _attr == '6': _unit = units.YARDS elif _attr == 'miles' or _attr == '7': _unit = units.MILES else: sys.stderr.write("Unknown unit '%s' - using MILLIMETERS\n" % _attr) _unit = units.MILLIMETERS image.setUnits(_unit) elif _name == "image:FontFamilies": _load_font_families(image, _child, _objmap) elif _name == "image:DimStyles": _load_dimstyles(image, _child, _objmap) elif _name == "image:TextStyles": _load_textstyles(image, _child, _objmap) elif _name == "image:Globals": _load_globals(image, _child, _objmap) elif _name == "image:Layers": _load_layers(image, _child, _objmap) for _obj in _objmap['locked']: _obj.setLock(True) _child = _child.nextSibling _doc.unlink() PythonCAD-DS1-R37/PythonCAD/Generic/prompt.py0000644000175000017500000001173611307666657020242 0ustar matteomatteo# # Copyright (c) 2003 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # This code handles interpreting entries in the gtkimage.entry box # and calling the apprpriate internal command # # Author: David Broadwell ( dbroadwell@mindspring.com, 05/26/2003 ) # from PythonCAD.Generic import tools ''' defines the internal maping for a human name like circle() to an internal function, so that the config file can look all clean and pretty. AKA: evalkey interface Release 5/25/03 ''' ''' 05/29/03 R2c Complete redesign, no longer does the internal name need to be a function, dropped prompt.py filesize from 9.8 to 5.3Kb! cleaned up the feywords file, no appreciable difference Used a dictionary instead of discreet functions for every entry and for R3, menus. ''' ''' Previous versions of this file defined commands in terms of interface specific calls. The new takes advantage of the messaging system within PythonCAD and various improvements/cleanups in the core code. A command will be associated with a Tool subclass, and by installing the tool in an Image the messaging system will pass the information to the interface which can then install handlers as necessary. ''' def lookup(text): """ Interface to promptdef dictionary, returns code by keyword definition lookup(text) or 'None' if no Tool found for command. """ return promptdefs.get(text) promptdefs = { 'pcline' : tools.ParallelOffsetTool, 'tcline' : tools.TangentCLineTool, 'hcline' : tools.HCLineTool, 'vcline' : tools.VCLineTool, 'acline' : tools.ACLineTool, 'cl' : tools.CLineTool, 'point' : tools.PointTool, 'segment' : tools.SegmentTool, 'circen' : tools.CircleTool, 'cir2p' : tools.TwoPointCircleTool, 'ccircen' : tools.CCircleTool, 'ccir2p' : tools.TwoPointCCircleTool, 'arcc' : tools.ArcTool, 'rect' : tools.RectangleTool, 'leader' : tools.LeaderTool, 'polyline' : tools.PolylineTool, 'text' : tools.TextTool, 'transfer' : tools.TransferTool, 'split' : tools.SplitTool, 'mirror' : tools.MirrorTool, 'delete' : tools.DeleteTool, 'moveh' : tools.HorizontalMoveTool, 'movev' : tools.VerticalMoveTool, 'move' : tools.MoveTool, 'chamfer' : tools.ChamferTool, 'fillet' : tools.FilletTool, 'strh' : tools.HorizontalStretchTool, 'strv' : tools.VerticalStretchTool, 'str' : tools.StretchTool, 'adim' : tools.AngularDimensionTool, 'rdim' : tools.RadialDimensionTool, 'ldim' : tools.LinearDimensionTool, 'hdim' : tools.HorizontalDimensionTool, 'vdim' : tools.VerticalDimensionTool, # 'close' : "gtkmenus.file_close_cb('file_close',self)", # 'quit' : "gtkmenus.file_quit_cb('file_quit',self)", # 'new' : "gtkmenus.file_new_cb('file_new',self)", # 'opend' : "gtkmenus.file_open_cb('file_open',self)", # 'saves' : "gtkmenus.file_save_cb('file_save',self)", # 'saveas' : "gtkmenus.file_save_as_cb('file_save_as',self)", # 'savel' : "gtkmenus.file_save_layer_cb('file_save_layer',self)", # 'cut' : "gtkmenus.edit_cut_cb('edit_cut',self)", # 'copy' : "gtkmenus.edit_copy_cb('edit_copy',self)", 'paste' : tools.PasteTool, 'select' : tools.SelectTool, 'deselect' : tools.DeselectTool, # 'saa' : "gtkmenus.select_all_arcs_cb('select_all_arcs',self)", # 'sac' : "gtkmenus.select_all_circles_cb('select_all_circles',self)", # 'sacc' : "gtkmenus.select_all_ccircles_cb('select_all_ccircles',self)", # 'sacl' : "gtkmenus.select_all_clines_cb('select_all_clines',self)", # 'sahcl' : "gtkmenus.select_all_hclines_cb('select_all_hclines',self)", # 'savcl' : "gtkmenus.select_all_vclines_cb('select_all_vclines',self)", # 'saacl' : "gtkmenus.select_all_aclines_cb('select_all_aclines',self)", # 'sap' : "gtkmenus.select_all_points_cb('select_all_points',self)", # 'sas' : "gtkmenus.select_all_segments_cb('select_all_segments',self)", # 'redraw' : "self.redraw()", # 'refresh' : "self.refresh()", # 'pref' : "gtkmenus.prefs_cb('prefs',self)", # 'dimpref' : "gtkmenus.dimension_prefs_cb('dimension_prefs',self)", 'zoomd' : tools.ZoomTool, 'print' : tools.PlotTool, # 'zoomi' : "gtkmenus.zoom_in_cb('zoom_in',self)", # 'zoomo' : "gtkmenus.zoom_out_cb('zoom_out',self)", # 'zoomf' : "gtkmenus.zoom_fit_cb('zoom_fit',self)" } PythonCAD-DS1-R37/PythonCAD/Generic/dxf.py0000644000175000017500000002325011307666657017474 0ustar matteomatteo# # Copyright (c) 2003 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # simple DXF file reader # import sys def read_dxf(handle): handle.seek(0,0) while True: _code, _data = get_group(handle) if _code == 0 and _data == 'EOF': break if _code == 0 and _data == 'SECTION': _secdata = read_section(handle) def read_section(handle): _sdata = None while True: _code, _data = get_group(handle) if _code == 0 and _data == 'EOF': break if _code != 2: raise ValueError, "Expected code 2; got %d" % _code _sdata = None if _data == 'HEADER': _sdata = read_header(handle) print "HEADER data:" elif _data == 'CLASSES': _sdata = read_classes(handle) print "CLASSES data:" elif _data == 'TABLES': _sdata = read_tables(handle) print "TABLES data:" elif _data == 'BLOCKS': _sdata = read_blocks(handle) print "BLOCKS data:" elif _data == 'ENTITIES': _sdata = read_entities(handle) print "ENTITY data:" elif _data == 'OBJECTS': _sdata = read_objects(handle) print "OBJECTS data:" else: while True: _code, _data = get_group(handle) if _code == 0 and (_data == 'ENDSEC' or _data == 'EOF'): break if _sdata is not None: _keys = _sdata.keys() _keys.sort() for _key in _keys: print "%s -> %s" % (_key, str(_sdata[_key])) break return _sdata def read_header(handle): _hmap = {} _code, _data = get_group(handle) while True: if _code == 0 and (_data == 'EOF' or _data == 'ENDSEC'): break if _code != 9: raise ValueError, "Expected code 9; got %d" % _code while True: _var = _data[1:] _dlist = [] while True: _code, _data = get_group(handle) if _code == 0 or _code == 9: break _dlist.append(_data) if len(_dlist) == 1: _hmap[_var] = _dlist[0] else: _hmap[_var] = tuple(_dlist) if _code == 0: break return _hmap def read_classes(handle): _cmap = {} while True: _code, _r0 = get_group(handle) if _code != 0: raise ValueError, "Expected code 0, got %d" % _code if _r0 == 'EOF' or _r0 == 'ENDSEC': break _code, _r1 = get_group(handle) if _code != 1: raise ValueError, "Expected code 1, got %d" % _code _code, _r2 = get_group(handle) if _code != 2: raise ValueError, "Expected code 2, got %d" % _code _code, _r3 = get_group(handle) if _code != 3: raise ValueError, "Expected code 3, got %d" % _code _code, _r90 = get_group(handle) if _code != 90: raise ValueError, "Expected code 90, got %d" % _code _code, _r280 = get_group(handle) if _code != 280: raise ValueError, "Expected code 280, got %d" % _code _code, _r281 = get_group(handle) if _code != 281: raise ValueError, "Expected code 281, got %d" % _code _cmap[_r1] = (_r2, _r3, _r90, _r280, _r281) return _cmap def read_tables(handle): _tmap = {} while True: _code, _r0 = get_group(handle) if _code == 0 and (_r0 == 'EOF' or _r0 == 'ENDSEC'): break if _code == 0 and _r0 == 'TABLE': _code, _name = get_group(handle) if _code != 2: raise ValueError, "Expected code 2 for table name: %d" % _code _tdata = [] while True: _code, _val = get_group(handle) if _code == 0 and _val == 'ENDTAB': break _tdata.append((_code, _val)) _tmap[_name] = _tdata return _tmap def read_blocks(handle): _bmap = {} _i = 0 _code, _val = get_group(handle) while True: if _code != 0: raise ValueError, "Expected code 0; got %d" % _code if _val == 'EOF' or _val == 'ENDSEC': break if _val != 'BLOCK': raise ValueError, "Expected BLOCK, got " + str(_val) _bdata = [] while True: _code, _val = get_group(handle) if _code == 0 and _val == 'ENDBLK': break _bdata.append((_code, _val)) _ebdata = [] while True: _code, _val = get_group(handle) if _code == 0 and (_val == 'BLOCK' or _val == 'ENDSEC'): break _ebdata.append((_code, _val)) _bmap[_i] = _bdata + _ebdata _i = _i + 1 return _bmap def read_entities(handle): _emap = {} _i = 0 _code, _val = get_group(handle) while True: if _code != 0: raise ValueError, "Expected code 0; got %d" % _code if _val == 'EOF' or _val == 'ENDSEC': break _edata = [] _edata.append((_code, _val)) # entity type is _val while True: _code, _val = get_group(handle) if _code == 0: # either next entity or end of section break _edata.append((_code, _val)) _emap[_i] = _edata _i = _i + 1 return _emap def read_objects(handle): _omap = {} _i = 0 _code, _val = get_group(handle) while True: if _code != 0: raise ValueError, "Expected code 0: got %d" % _code if _val == 'EOF' or _val == 'ENDSEC': break _odata = [] _odata.append((_code, _val)) # object type is _val while True: _code, _val = get_group(handle) if _code == 0: # either next object or end of section break _odata.append((_code, _val)) _omap[_i] = _odata _i = _i + 1 return _omap def get_group(handle): _code = int(handle.readline()) _dfun = get_data_type(_code) _data = _dfun(handle.readline()) return _code, _data def string_data(text): return text.strip() def float_data(text): return float(text) def int_data(text): return int(text) def unicode_data(text): return unicode(text.strip()) def handle_data(text): return int(text.strip(), 16) # fixme def hex_data(text): return int(text.strip(), 16) # ??? def bin_data(text): _str = text.strip() _bytes = [] if not len(_str) % 2: # even length -> good data ... for _i in range(0, len(_str), 2): _bytes.append(chr(int(_str[_i:_i+2], 16))) return _bytes def bool_data(text): _btext = text.strip() if _btext == '0': _flag = False elif _btext == '1': _flag = True else: raise ValueError, "Unexpected boolean data string: %s" % _btext return _flag def get_data_type(code): if (0 <= code <= 9): _dfun = string_data elif (10 <= code <= 59): _dfun = float_data elif (60 <= code <= 79): _dfun = int_data # 16-bit int elif (90 <= code <= 99): _dfun = int_data # 32-bit int elif (code == 100): _dfun = unicode_data elif (code == 102): _dfun = unicode_data elif (code == 105): _dfun = handle_data elif (110 <= code <= 139): _dfun = float_data # not in dxf spec elif (140 <= code <= 149): # says 147 in dxf spec _dfun = float_data elif (170 <= code <= 179): # says 175 in dxf spec _dfun = int_data # 16-bit int elif (270 <= code <= 279): _dfun = int_data # not in dxf spec elif (280 <= code <= 289): _dfun = int_data # 8-bit int elif (290 <= code <= 299): _dfun = bool_data elif (300 <= code <= 309): _dfun = string_data elif (310 <= code <= 319): _dfun = bin_data elif (320 <= code <= 329): _dfun = handle_data elif (330 <= code <= 369): _dfun = hex_data elif (370 <= code <= 379): _dfun = int_data # 8-bit int elif (380 <= code <= 389): _dfun = int_data # 8-bit int elif (390 <= code <= 399): _dfun = handle_data elif (400 <= code <= 409): _dfun = int_data # 16-bit int elif (410 <= code <= 419): _dfun = string_data elif (code == 999): _dfun = string_data # comment elif (1000 <= code <= 1009): _dfun = string_data elif (1010 <= code <= 1059): _dfun = float_data elif (1060 <= code <= 1070): _dfun = int_data # 16-bit int elif (code == 1071): _dfun = int_data # 32-bit int else: raise ValueError, "Unexpected code: %d" % code return _dfun if __name__ == '__main__': if len(sys.argv) < 2: print "usage: dxf.py filename" sys.exit(1) try: _fh = file(sys.argv[1]) except: print "failed to open '%s'. Exiting ..." % sys.argv[1] sys.exit(1) read_dxf(_fh) _fh.close() PythonCAD-DS1-R37/PythonCAD/Generic/leader.py0000644000175000017500000010304411307666657020147 0ustar matteomatteo# # Copyright (c) 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # classes for leader lines # from __future__ import generators import math import array from PythonCAD.Generic import graphicobject from PythonCAD.Generic import tolerance from PythonCAD.Generic import style from PythonCAD.Generic import linetype from PythonCAD.Generic import color from PythonCAD.Generic import point from PythonCAD.Generic import util from PythonCAD.Generic import quadtree class Leader(graphicobject.GraphicObject): """A class representing a leader line. A leader line is usually used as a visual connector between some text and an entity in a drawing. Leader lines cannot be used to define an edge of some shape. A Leader object has the following attributes: p1: A Point object representing the first end point. p2: A Point object representing the leader mid point. p3: A Point object representing the final end point. arrowsize: The size of the arrow at the end of the leader line A Leader object has the following methods: getPoints(): Return the points defining the Leader {get/set}P1(): Get/Set the Leader first endpoint. {get/set}P2(): Get/Set the Leader midpoint {get/set}P3(): Get/Set the Leader final endpoint {get/set}ArrowSize(): Get/Set the Leader line arrow size. calcArrowPoints(): Calculate where the Leader arrow points are. getArrowPoints(): Return where the Leader arrow points are. move(): Move the Leader. mapCoords(): See if a point lies within some distance of a Leader. inRegion(): Test if the Leader is visible in some area. clone(): Make an identical copy of a Leader. """ __defstyle = None __messages = { 'moved' : True, 'point_changed' : True, 'size_changed' : True, } def __init__(self, p1, p2, p3, size=1.0, st=None, lt=None, col=None, th=None, **kw): """Initialize a Leader object. Leader(p1, p2, p3[, size, st, lt, col, th]) The following arguments are required: p1: Leader first endpoint - may be a Point or a two-item tuple of floats p2: Leader mid point - may be a Point or a two-item tuple of floats p3: Leader final endpoint - may be a Point or a two-item tuple of floats Argument size is optional. It gives the size of the arrow at the end of the leader line, and defaults to 1.0. """ _p1 = p1 if not isinstance(_p1, point.Point): _p1 = point.Point(p1) _p2 = p2 if not isinstance(_p2, point.Point): _p2 = point.Point(p2) if _p1 is _p2: raise ValueError, "Leader points p1 and p2 cannot be identical." _p3 = p3 if not isinstance(_p3, point.Point): _p3 = point.Point(_p3) if _p1 is _p3: raise ValueError, "Leader points p1 and p3 cannot be identical." if _p2 is _p3: raise ValueError, "Leader points p2 and p3 cannot be identical" _size = util.get_float(size) if _size < 0.0: raise ValueError, "Invalid arrow size: %g" % _size _st = st if _st is None: _st = self.getDefaultStyle() super(Leader, self).__init__(_st, lt, col, th, **kw) self.__p1 = _p1 _p1.connect('moved', self.__movePoint) _p1.connect('change_pending', self.__pointChangePending) _p1.connect('change_complete', self.__pointChangeComplete) _p1.storeUser(self) self.__p2 = _p2 _p2.connect('moved', self.__movePoint) _p2.connect('change_pending', self.__pointChangePending) _p2.connect('change_complete', self.__pointChangeComplete) _p2.storeUser(self) self.__p3 = _p3 _p3.connect('moved', self.__movePoint) _p3.connect('change_pending', self.__pointChangePending) _p3.connect('change_complete', self.__pointChangeComplete) _p3.storeUser(self) self.__size = _size self.__arrow_pts = array.array('d', [0.0, 0.0, 0.0, 0.0]) self.calcArrowPoints() def __str__(self): return "Leader: %s to %s to %s" % (self.__p1, self.__p2, self.__p3) def __eq__(self, obj): """Compare two leader lines for equality. """ if not isinstance(obj, Leader): return False if obj is self: return True _sp1 = self.__p1 _sp2 = self.__p2 _sp3 = self.__p3 _p1, _p2, _p3 = obj.getPoints() if (_sp1 == _p1 and _sp2 == _p2 and _sp3 == _p3): return True return False def __ne__(self, obj): """Compare two leader lines for inequality. """ if not isinstance(obj, Leader): return True if obj is self: return False _sp1 = self.__p1 _sp2 = self.__p2 _sp3 = self.__p3 _p1, _p2, _p3 = obj.getPoints() if (_sp1 == _p1 and _sp2 == _p2 and _sp3 == _p3): return False return True def getDefaultStyle(cls): if cls.__defstyle is None: _s = style.Style(u'Leader Default Style', linetype.Linetype(u'Solid', None), color.Color(0xffffff), 1.0) cls.__defstyle = _s return cls.__defstyle getDefaultStyle = classmethod(getDefaultStyle) def setDefaultStyle(cls, s): if not isinstance(s, style.Style): raise TypeError, "Invalid style: " + `type(s)` cls.__defstyle = s setDefaultStyle = classmethod(setDefaultStyle) def finish(self): self.__p1.disconnect(self) self.__p1.freeUser(self) self.__p2.disconnect(self) self.__p2.freeUser(self) self.__p3.disconnect(self) self.__p3.freeUser(self) self.__p1 = self.__p2 = self.__p3 = self.__size = None super(Leader, self).finish() def setStyle(self, s): """Set the Style of the Leader. setStyle(s) This method extends GraphicObject::setStyle(). """ _s = s if _s is None: _s = self.getDefaultStyle() super(Leader, self).setStyle(_s) def getValues(self): """Return values comprising the Arc. getValues() This method extends the GraphicObject::getValues() method. """ _data = super(Leader, self).getValues() _data.setValue('type', 'leader') _data.setValue('p1', self.__p1.getID()) _data.setValue('p2', self.__p2.getID()) _data.setValue('p3', self.__p3.getID()) _data.setValue('size', self.__size) return _data def getPoints(self): """Get the points defining the Leader. getPoints() This function returns a tuple containing the three Point objects that are the defining points of the Leader """ return self.__p1, self.__p2, self.__p3 def getP1(self): """Return the first endpoint Point of the Leader getP1() """ return self.__p1 def setP1(self, p): """Set the first endpoint Point of the Leader setP1(p) The argument 'p' should be a Point. """ if self.isLocked(): raise RuntimeError, "Setting points not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid P1 point: " + `type(p)` if p is self.__p2 or p is self.__p3: raise ValueError, "Leader points cannot be identical." _pt = self.__p1 if _pt is not p: _pt.disconnect(self) _pt.freeUser(self) self.startChange('point_changed') self.__p1 = p self.endChange('point_changed') self.sendMessage('point_changed', _pt, p) p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) if abs(_pt.x - p.x) > 1e-10 or abs(_pt.y - p.y) > 1e-10: _x2, _y2 = self.__p2.getCoords() _x3, _y3 = self.__p3.getCoords() self.sendMessage('moved', _pt.x, _pt.y, _x2, _y2, _x3, _y3) self.modified() p1 = property(getP1, setP1, None, "First endpoint of the Leader.") def getP2(self): """Return the midpoint Point of the Leader. getP2() """ return self.__p2 def setP2(self, p): """Set the midpoint Point of the Leader. setP2(p) The argument 'p' should be a Point. """ if self.isLocked(): raise RuntimeError, "Setting points not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid P2 point: " + `type(p)` if p is self.__p1 or p is self.__p3: raise ValueError, "Leader points cannot be identical." _pt = self.__p2 if _pt is not p: _pt.disconnect(self) _pt.freeUser(self) self.startChange('point_changed') self.__p2 = p self.endChange('point_changed') self.sendMessage('point_changed', _pt, p) p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) if abs(_pt.x - p.x) > 1e-10 or abs(_pt.y - p.y) > 1e-10: self.calcArrowPoints() _x1, _y1 = self.__p1.getCoords() _x3, _y3 = self.__p3.getCoords() self.sendMessage('moved', _x1, _y1, _pt.x, _pt.y, _x3, _y3) self.modified() p2 = property(getP2, setP2, None, "Leader midpoint.") def getP3(self): """Return the final Point of the Leader. getP3() """ return self.__p3 def setP3(self, p): """Set the final endpoint Point of the Leader. setP3(p) The argument 'p' should be a Point. """ if not isinstance(p, point.Point): raise TypeError, "Invalid Point for p3 endpoint: " + `p` if self.isLocked(): raise RuntimeError, "Setting points not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid P3 point: " + `type(p)` if p is self.__p1 or p is self.__p2: raise ValueError, "Leader points cannot be identical." _pt = self.__p3 if _pt is not p: _pt.disconnect(self) _pt.freeUser(self) self.startChange('point_changed') self.__p3 = p self.endChange('point_changed') self.sendMessage('point_changed', _pt, p) p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) if abs(_pt.x - p.x) > 1e-10 or abs(_pt.y - p.y) > 1e-10: self.calcArrowPoints() _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() self.sendMessage('moved', _x1, _y1, _x2, _y2, _pt.x, _pt.y) self.modified() p3 = property(getP3, setP3, None, "Third endpoint of the Leader.") def getArrowSize(self): """Return the size of the leader line arrow. getArrowSize() """ return self.__size def setArrowSize(self, size): """Set the size of the leader line arrow. setSize(size) Argument 'size' should be a float greater than or equal to 0.0. """ if self.isLocked(): raise RuntimeError, "Cannot change arrow size - object locked." _size = util.get_float(size) if _size < 0.0: raise ValueError, "Invalid arrow size: %g" % _size _os = self.__size if abs(_os - _size) > 1e-10: self.startChange('size_changed') self.__size = _size self.endChange('size_changed') self.calcArrowPoints() self.sendMessage('size_changed', _os) self.modified() arrowsize = property(getArrowSize, setArrowSize, None, "Leader line arrow size.") def calcArrowPoints(self): """Calculate where the Leader arrow points are. calcArrowPoints() """ _x1, _y1 = self.__p2.getCoords() _x2, _y2 = self.__p3.getCoords() if abs(_x2 - _x1) < 1e-10: # vertical _cosine = 0.0 if _y2 > _y1: _sine = 1.0 else: _sine = -1.0 elif abs(_y2 - _y1) < 1e-10: # horizontal _sine = 0.0 if _x2 > _x1: _cosine = 1.0 else: _cosine = -1.0 else: _angle = math.atan2((_y2 - _y1), (_x2 - _x1)) _sine = math.sin(_angle) _cosine = math.cos(_angle) _size = self.__size _height = _size/5.0 # p1 -> (x,y) = (-size, _height) self.__arrow_pts[0] = (_cosine * (-_size) - _sine * _height) + _x2 self.__arrow_pts[1] = (_sine * (-_size) + _cosine * _height) + _y2 # p2 -> (x,y) = (-size, -_height) self.__arrow_pts[2] = (_cosine * (-_size) - _sine *(-_height)) + _x2 self.__arrow_pts[3] = (_sine * (-_size) + _cosine *(-_height)) + _y2 def getArrowPoints(self): """Return the endpoints of the Leader arrow. getArrowPoints() This method returns an array holding four float values. """ return self.__arrow_pts def move(self, dx, dy): """Move a Leader. move(dx, dy) The first argument gives the x-coordinate displacement, and the second gives the y-coordinate displacement. Both values should be floats. """ if (self.isLocked() or self.__p1.isLocked() or self.__p2.isLocked() or self.__p3.isLocked()): raise RuntimeError, "Moving Leader not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() _x3, _y3 = self.__p3.getCoords() self.ignore('moved') try: self.__p1.move(_dx, _dy) self.__p2.move(_dx, _dy) self.__p3.move(_dx, _dy) finally: self.receive('moved') self.calcArrowPoints() self.sendMessage('moved', _x1, _y1, _x2, _y2, _x3, _y3) def mapCoords(self, x, y, tol=tolerance.TOL): """Return the nearest Point on the Leader to a coordinate pair. mapCoords(x, y[, tol]) The function has two required arguments: x: A Float value giving the 'x' coordinate y: A Float value giving the 'y' coordinate There is a single optional argument: tol: A float value equal or greater than 0.0 This function is used to map a possibly near-by coordinate pair to an actual Point on the Leader. If the distance between the actual Point and the coordinates used as an argument is less than the tolerance, the actual Point is returned. Otherwise, this function returns None. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() _x3, _y3 = self.__p3.getCoords() _pt = util.map_coords(_x, _y, _x1, _y1, _x2, _y2, _t) if _pt is None: _pt = util.map_coords(_x, _y, _x2, _y2, _x3, _y3, _t) if _pt is not None: return _pt return None def inRegion(self, xmin, ymin, xmax, ymax, fully=False): """Return whether or not a Leader exists within a region. isRegion(xmin, ymin, xmax, ymax[, fully]) The four arguments define the boundary of an area, and the method returns True if the Leader lies within that area. If the optional argument fully is used and is True, then all the Leader points must lie within the boundary. Otherwise, the method returns False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() _x3, _y3 = self.__p3.getCoords() _pxmin = min(_x1, _x2, _x3) _pymin = min(_y1, _y2, _y3) _pxmax = max(_x1, _x2, _x3) _pymax = max(_y1, _y2, _y3) if ((_pxmax < _xmin) or (_pymax < _ymin) or (_pxmin > _xmax) or (_pymin > _ymax)): return False if fully: if ((_pxmin > _xmin) and (_pymin > _ymin) and (_pxmax < _xmax) and (_pymax < _ymax)): return True return False if util.in_region(_x1, _y1, _x2, _y2, _xmin, _ymin, _xmax, _ymax): return True return util.in_region(_x2, _y2, _x3, _y3, _xmin, _ymin, _xmax, _ymax) def __pointChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.startChange('moved') def __pointChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': if p is self.__p2 or p is self.__p3: self.calcArrowPoints() self.endChange('moved') def __movePoint(self, p, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _p1 = self.__p1 _p2 = self.__p2 _p3 = self.__p3 if p is _p1: _x1 = _x _y1 = _y _x2, _y2 = _p2.getCoords() _x3, _y3 = _p3.getCoords() elif p is _p2: _x1, _y1 = _p1.getCoords() _x2 = _x _y2 = _y _x3, _y3 = _p3.getCoords() elif p is _p3: _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _x3 = _x _y3 = _y else: raise ValueError, "Unexpected Leader endpoint: " + `p` self.sendMessage('moved', _x1, _y1, _x2, _y2, _x3, _y3) def clone(self): """Create an identical copy of a Leader. clone() """ _cp1 = self.__p1.clone() _cp2 = self.__p2.clone() _cp3 = self.__p3.clone() _size = self.__size _st = self.getStyle() _lt = self.getLinetype() _col = self.getColor() _th = self.getThickness() return Leader(_cp1, _cp2, _cp3, _size, _st, _lt, _col, _th) def sendsMessage(self, m): if m in Leader.__messages: return True return super(Leader, self).sendsMessage(m) # # Quadtree Leader storage # class LeaderQuadtree(quadtree.Quadtree): def __init__(self): super(LeaderQuadtree, self).__init__() def getNodes(self, *args): _alen = len(args) if _alen != 4: raise ValueError, "Expected 4 arguments, got %d" % _alen _lxmin = util.get_float(args[0]) _lymin = util.get_float(args[1]) _lxmax = util.get_float(args[2]) if not _lxmax > _lxmin: raise ValueError, "xmax not greater than xmin" _lymax = util.get_float(args[3]) if not _lymax > _lymin: raise ValueError, "ymax not greater than ymin" _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_lxmin > _xmax) or (_lxmax < _xmin) or (_lymin > _ymax) or (_lymax < _ymin)): continue if _node.hasSubnodes(): _xmid = (_xmin + _xmax)/2.0 _ymid = (_ymin + _ymax)/2.0 _ne = _nw = _sw = _se = True if _lxmax < _xmid: # leader on left side _ne = _se = False if _lxmin > _xmid: # leader on right side _nw = _sw = False if _lymax < _ymid: # leader below _nw = _ne = False if _lymin > _ymid: # leader above _sw = _se = False if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: yield _node def addObject(self, obj): if not isinstance(obj, Leader): raise TypeError, "Invalid Leader object: " + `obj` if obj in self: return _p1, _p2, _p3 = obj.getPoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _x3, _y3 = _p3.getCoords() _bounds = self.getTreeRoot().getBoundary() _xmin = _ymin = _xmax = _ymax = None _lxmin = min(_x1, _x2, _x3) _lxmax = max(_x1, _x2, _x3) _lymin = min(_y1, _y2, _y3) _lymax = max(_y1, _y2, _y3) _resize = False if _bounds is None: # first node in tree _resize = True _xmin = _lxmin - 1.0 _ymin = _lymin - 1.0 _xmax = _lxmax + 1.0 _ymax = _lymax + 1.0 else: _xmin, _ymin, _xmax, _ymax = _bounds if _lxmin < _xmin: _xmin = _lxmin - 1.0 _resize = True if _lxmax > _xmax: _xmax = _lxmax + 1.0 _resize = True if _lymin < _ymin: _ymin = _lymin - 1.0 _resize = True if _lymax > _ymax: _ymax = _lymax + 1.0 _resize = True if _resize: self.resize(_xmin, _ymin, _xmax, _ymax) for _node in self.getNodes(_lxmin, _lymin, _lxmax, _lymax): _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if obj.inRegion(_xmin, _ymin, _xmax, _ymax): _node.addObject(obj) super(LeaderQuadtree, self).addObject(obj) obj.connect('moved', self._moveLeader) def delObject(self, obj): if obj not in self: return _p1, _p2, _p3 = obj.getPoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _x3, _y3 = _p3.getCoords() _lxmin = min(_x1, _x2, _x3) _lxmax = max(_x1, _x2, _x3) _lymin = min(_y1, _y2, _y3) _lymax = max(_y1, _y2, _y3) _pdict = {} for _node in self.getNodes(_lxmin, _lymin, _lxmax, _lymax): _node.delObject(obj) # leader may not be in the node ... _parent = _node.getParent() if _parent is not None: _pid = id(_parent) if _pid not in _pdict: _pdict[_pid] = _parent super(LeaderQuadtree, self).delObject(obj) obj.disconnect(self) for _parent in _pdict.values(): self.purgeSubnodes(_parent) def find(self, *args): _alen = len(args) if _alen < 6: raise ValueError, "Invalid argument count: %d" % _alen _x1 = util.get_float(args[0]) _y1 = util.get_float(args[1]) _x2 = util.get_float(args[2]) _y2 = util.get_float(args[3]) _x3 = util.get_float(args[4]) _y3 = util.get_float(args[5]) _t = tolerance.TOL if _alen > 6: _t = tolerance.toltest(args[6]) _xmin = min(_x1, _x2, _x3) - _t _xmax = max(_x1, _x2, _x3) + _t _ymin = min(_y1, _y2, _y3) - _t _ymax = max(_y1, _y2, _y3) + _t _leaders = [] for _leader in self.getInRegion(_xmin, _ymin, _xmax, _ymax): _p1, _p2, _p3 = _leader.getPoints() if ((abs(_p1.x - _x1) < _t) and (abs(_p1.y - _y1) < _t) and (abs(_p2.x - _x2) < _t) and (abs(_p2.y - _y2) < _t) and (abs(_p3.x - _x3) < _t) and (abs(_p3.y - _y3) < _t)): _leaders.append(_leader) return _leaders def _moveLeader(self, obj, *args): if obj not in self: raise ValueError, "Leader not stored in Quadtree: " + `obj` _alen = len(args) if _alen < 6: raise ValueError, "Invalid argument count: %d" % _alen _x1 = util.get_float(args[0]) _y1 = util.get_float(args[1]) _x2 = util.get_float(args[2]) _y2 = util.get_float(args[3]) _x3 = util.get_float(args[4]) _y3 = util.get_float(args[5]) _lxmin = min(_x1, _x2, _x3) _lxmax = max(_x1, _x2, _x3) _lymin = min(_y1, _y2, _y3) _lymax = max(_y1, _y2, _y3) for _node in self.getNodes(_lxmin, _lymin, _lxmax, _lymax): _node.delObject(obj) # leader may not be in node ... super(LeaderQuadtree, self).delObject(obj) obj.disconnect(self) self.addObject(obj) def getClosest(self, x, y, tol=tolerance.TOL): _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _leader = _tsep = None _bailout = False _ldict = {} _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_x < (_xmin - _t)) or (_x > (_xmax + _t)) or (_y < (_ymin - _t)) or (_y > (_ymax + _t))): continue if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) else: for _l in _node.getObjects(): _lid = id(_l) _p1, _p2, _p3 = _l.getPoints() if _lid not in _ldict: _px, _py = _p1.getCoords() if ((abs(_px - _x) < 1e-10) and (abs(_py - _y) < 1e-10)): _leader = _l _bailout = True break _px, _py = _p2.getCoords() if ((abs(_px - _x) < 1e-10) and (abs(_py - _y) < 1e-10)): _leader = _l _bailout = True break _px, _py = _p3.getCoords() if ((abs(_px - _x) < 1e-10) and (abs(_py - _y) < 1e-10)): _leader = _l _bailout = True break _ldict[_lid] = True _pt = _l.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _sep = math.hypot((_px - _x), (_py - _y)) if _tsep is None: _tsep = _sep _leader = _l else: if _sep < _tsep: _tsep = _sep _leader = _l if _bailout: break return _leader def getInRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _leaders = [] if not len(self): return _leaders _nodes = [self.getTreeRoot()] _ldict = {} while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): for _subnode in _node.getSubnodes(): _lxmin, _lymin, _lxmax, _lymax = _subnode.getBoundary() if ((_lxmin > _xmax) or (_lymin > _ymax) or (_lxmax < _xmin) or (_lymax < _ymin)): continue _nodes.append(_subnode) else: for _l in _node.getObjects(): _lid = id(_l) if _lid not in _ldict: if _l.inRegion(_xmin, _ymin, _xmax, _ymax): _leaders.append(_l) _ldict[_lid] = True return _leaders # # Leader history class # class LeaderLog(graphicobject.GraphicObjectLog): def __init__(self, l): if not isinstance(l, Leader): raise TypeError, "Invalid leader: " + `l` super(LeaderLog, self).__init__(l) l.connect('point_changed', self.__pointChanged) l.connect('size_changed', self.__sizeChanged) def __pointChanged(self, l, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _old = args[0] if not isinstance(_old, point.Point): raise TypeError, "Invalid old endpoint: " + `_old` _new = args[1] if not isinstance(_new, point.Point): raise TypeError, "Invalid new endpoint: " + `_new` self.saveUndoData('point_changed', _old.getID(), _new.getID()) def __sizeChanged(self, l, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _size = args[0] if not isinstance(_size, float): raise TypeError, "Unexpected type for size: " + `type(_size)` self.saveUndoData('size_changed', _size) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if _alen == 0: raise ValueError, "No arguments to execute()" _l = self.getObject() _op = args[0] if _op == 'point_changed': if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _oid = args[1] _nid = args[2] _p1, _p2, _p3 = _l.getPoints() _parent = _l.getParent() if _parent is None: raise ValueError, "Leader has no parent - cannot undo" self.ignore(_op) try: if undo: _pt = _parent.getObject(_oid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "Old point missing: id=%d" % _oid _l.startUndo() try: if _p1.getID() == _nid: _l.setP1(_pt) elif _p2.getID() == _nid: _l.setP2(_pt) elif _p3.getID() == _nid: _l.setP3(_pt) else: raise ValueError, "Unexpected point ID: %d" % _nid finally: _l.endUndo() else: _pt = _parent.getObject(_nid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "New point missing: id=%d" % _nid _l.startRedo() try: if _p1.getID() == _oid: _l.setP1(_pt) elif _p2.getID() == _oid: _l.setP2(_pt) elif _p3.getID() == _oid: _l.setP3(_pt) else: raise ValueError, "Unexpected point ID: %d" % _oid finally: _l.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _oid, _nid) elif _op == 'size_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _size = args[1] if not isinstance(_size, float): raise TypeError, "Unexpected type for size: " + `type(_size)` _sdata = _l.getArrowSize() self.ignore(_op) try: if undo: _l.startUndo() try: _l.setArrowSize(_size) finally: _l.endUndo() else: _l.startRedo() try: _l.setArrowSize(_size) finally: _l.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) else: super(LeaderLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/linetype.py0000644000175000017500000001712511307666657020550 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # linetype class # import types from sys import maxint from PythonCAD.Generic import globals class Linetype(object): """A class representing linetypes. This class provides the basis for solid and dashed lines. Dashed lines are more 'interesting' in the various ways the dashes can be drawn. A Linetype object has two attributes: name: A string describing this linetype dlist: A list of integers used for drawing dashed lines A solid line has a dlist attribute of None. A Linetype object has the following methods: getName(): Return the Linetype name getList(): Return the Linetype dashlist clone(): Make a copy of a Linetype object. """ def __init__(self, name, dashlist=None): """Initstantiate a Linetype object. Linetype(name, dashlist) The name should be a string representing what this linetype is called. The dashlist can be None (solid lines) or a list of integers which will be used to determine the on/off bits of a dashed line. The list must have at least two integers. """ _n = name if not isinstance(_n, types.StringTypes): raise TypeError, "Invalid Linetype name: " + `_n` if not isinstance(_n, unicode): _n = unicode(name) _l = dashlist if _l is not None: if not isinstance(_l, list): raise TypeError, "Second argument must be a list or None." _length = len(_l) if _length < 2: raise ValueError, "Dash list must hold at least two integers." _temp = [] for _i in range(_length): _item = _l[_i] if not isinstance(_item, int): _item = int(_l[_i]) if _item < 0: raise ValueError, "Invalid list value: %d" % _item _temp.append(_item) _l = _temp self.__name = _n if _l is None: self.__list = None else: self.__list = _l[:] def __str__(self): if self.__list is None: return "Solid Line: '%s'" % self.__name else: _str = "Dashed Line: '%s': " % self.__name return _str + `self.__list` def __eq__(self, obj): """Compare one Linetype to another for equality. The comparison examines the dash list - if both lists are None, or the same length and with identical values, the function returns True. Otherwise the function returns False. """ if not isinstance(obj, Linetype): return False if obj is self: return True _slist = self.__list _olist = obj.getList() return ((_slist is None and _olist is None) or ((type(_slist) == type(_olist)) and (_slist == _olist))) def __ne__(self, obj): """Compare one Linetype to another for non-equality. The comparison examines the dash list - if both lists are None, or the same length and with identical values, the function returns False. Otherwise the function returns True. """ return not self == obj def __hash__(self): """Provide a hash function for Linetypes. Defining this method allows Linetype objects to be stored as dictionary keys. """ _dashlist = self.__list _val = 0 # hash value for solid lines if _dashlist is not None: _val = hash_dashlist(_dashlist) return _val def getName(self): """Get the name of the Linetype. getName() """ return self.__name name = property(getName, None, None, "Linetype name.") def getList(self): """Get the list used for determining the dashed line pattern. getList() This function returns None for solid Linetypes. """ _list = None if self.__list is not None: _list = self.__list[:] return _list list = property(getList, None, None, "Linetype dash list.") def clone(self): """Make a copy of a Linetype clone() """ _name = self.__name[:] _dashlist = None if self.__list is not None: _dashlist = self.__list[:] return Linetype(_name, _dashlist) # # LinetypeDict Class # # The LinetypeDict is built from the dict object. Using instances # of this class will guarantee than only Linetype objects will be # stored in the instance # class LinetypeDict(dict): def __init__(self): super(LinetypeDict, self).__init__() def __setitem__(self, key, value): if not isinstance(key, Linetype): raise TypeError, "LinetypeDict keys must be Linetype objects: " + `key` if not isinstance(value, Linetype): raise TypeError, "LinetypeDict values must be Linetype objects: " + `value` super(LinetypeDict, self).__setitem__(key, value) # # the hash function for linetype dashlists # def hash_dashlist(dashlist): """The hashing function for linetype dashlists hash_dashlist(dashlist) Argument 'dashlist' should be a list containing two or more integer values. """ if not isinstance(dashlist, list): raise TypeError, "Invalid list: " + `dashlist` if len(dashlist) < 2: raise ValueError, "Invalid list length: " + str(dashlist) _dlist = [] for _obj in dashlist: if not isinstance(_obj, int): raise TypeError, "Invalid list item: " + `_obj` if _obj < 0: raise ValueError, "Invalid list value: %d" % _obj _dlist.append(_obj) _val = (0xffffff & _dlist[0]) << 6 for _i in _dlist: _val = c_mul(160073, _val) ^ ((_i << 5) | _i) # made this up _val = _val ^ len(_dlist) if _val == -1: _val = -2 return _val # # mulitplication used for hashing # # an eval-based routine came from http://effbot.org/zone/python-hash.htm, # but the move to Python 2.3 printed warnings when executing that code # due to changes in large hex values, so the code was re-written to # avoid the eval-loop and hackish long->str->int conversions ... # def c_mul(a, b): _lval = (long(a * b) & 0xffffffffL) - maxint return int(_lval) # # find an existing linetype in the global linetype dictionary # def get_linetype_by_dashes(dashlist): if dashlist is None: _key = 0 elif isinstance(dashlist, list): _key = hash_dashlist(dashlist) else: raise TypeError, "Invalid dashlist: " + `dashlist` for _k in globals.linetypes.keys(): if hash(_k) == _key: return _k raise ValueError, "No matching linetype found: " + str(dashlist) def get_linetype_by_name(name): if not isinstance(name, types.StringTypes): raise TypeError, "Invalid linetype name: " + str(name) _name = name if not isinstance(_name, unicode): _name = unicode(name) for _lt in globals.linetypes: if _lt.getName() == _name: return _lt return None PythonCAD-DS1-R37/PythonCAD/Generic/entity.py0000644000175000017500000005235211307666657020234 0ustar matteomatteo# # Copyright (c) 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # _The_ base class for all objects used in PythonCAD # import types from PythonCAD.Generic import message from PythonCAD.Generic import logger from PythonCAD.Generic import util class Entity(message.Messenger): """The base class for PythonCAD entities. An entity has the following properties: parent: The parent of an entity - another entity or None An entity has the following methods: {set/get}Lock(): Set/Get the locked state on an entity. isLocked(): Returns the locked state of an entity. isModified(): Returns the flag indicating the entity has been modified. modified()/reset(): Set/Unset a flag indicating the entity modified state. isVisible(): Returns the visibity of the entity. {set/get}Visibility(): Set/Get the visibility flag on an entity. {set/get}Parent(): Set/Get the parent entity of an entity. {add/del}Child(): Add/Remove a child entity to/from another entity. hasChild(): Test if one entity is a child of another. hasChildren(): Test if an entity has any children entities. getChildren(): Return a list of children entities for an entity. A few short aliases exist for some of these methods: lock(): Same as setLock(True) unlock(): Same as setLock(False) hide(): Same as setVisibility(True) show()/expose(): Same as setVisibility(False) The aliases may be removed at some point. """ __messages = { 'lock_changed' : True, 'modified' : True, 'reset' : True, # 'parent_changed' : True, 'visibility_changed' : True, 'refresh' : True, 'added_child' : True, 'removed_child' : True, 'change_pending' : True, 'change_complete' : True, } __idcount = 0 def __init__(self, **kw): _parent = _id = None if 'parent' in kw: _parent = kw['parent'] if _parent is not None and not isinstance(_parent, Entity): raise TypeError, "Unexpected parent type: " + `type(_parent)` if 'id' in kw: _id = kw['id'] if not isinstance(_id, int): raise TypeError, "Unexpected ID type: " + `type(_id)` if _id < 0 or _id >= Entity.__idcount: raise ValueError, "Invalid ID: %d" % _id if _id is None: _id = Entity.__idcount Entity.__idcount = Entity.__idcount + 1 super(Entity, self).__init__() self.__locked = False self.__modified = False self.__visible = True self.__parent = None self.__children = None self.__log = None self.__undoing = 0 # 1 => undo, -1 => redo self.__id = _id if _parent is not None: Entity.setParent(self, _parent) def finish(self): if self.__parent is not None: print "parent is not None: " + `self` print "parent: " + `self.__parent` if self.__children is not None: print "children is not None: " + `self` for _child in self.__children.values(): print "Child: " + `_child` super(Entity, self).finish() def getValues(self): """Return values comprising the Entity. getValues() This method returns an EntityData instance. """ _data = EntityData() _data.setValue('id', self.__id) _pid = None if self.__parent is not None: _pid = self.__parent.getID() _data.setValue('pid', _pid) return _data values = property(getValues, None, None, "Entity values") def getID(self): """Return the unique integer identifier for the entity. getID() """ return self.__id id = property(getID, None, None, "Entity ID") def isLocked(self): """Test if the entity has been locked. isLocked() This method returns a boolean. """ return self.__locked def lock(self): """Set the entity so that its attributes cannot be changed. lock() """ Entity.setLock(self, True) def unlock(self): """Set the entity so that its attributes can be changed. unlock() """ Entity.setLock(self, False) def getLock(self): """Return the locked status of an entity. getLock() """ return self.__locked def setLock(self, lock): """Set the locked status on an entity. setLock(lock) Argument 'lock' can be True or False. """ util.test_boolean(lock) _l = self.__locked if _l is not lock: self.__locked = lock self.sendMessage('lock_changed', _l) self.modified() def isModified(self): """Test if the entity has been altered in some form. isModified() This method returns a boolean. """ return self.__modified def startChange(self, msg): """Enter the modification state of an entity. startChange(msg) Argument 'msg' is the message the entity will send at the completion of the modification. """ if not self.sendsMessage(msg): raise ValueError, "Unknown message: %s" % msg self.sendMessage('change_pending', msg) def endChange(self, msg): """Complete the modification state of an entity. endChange(msg) This method is meant to complete the notification process begun by the startChange() method. """ if not self.sendsMessage(msg): raise ValueError, "Unknown message: %s" % msg self.sendMessage('change_complete', msg) def modified(self): """Indicate that the entity has been altered. modified() """ if not self.__modified: self.__modified = True self.sendMessage('modified') def reset(self): """Indicate that the entity is no longer altered. reset() """ if self.__modified: self.__modified = False self.sendMessage('reset') def isVisible(self): """Test to see if the entity can be seen. isVisible() This method returns a boolean. """ return self.__visible is True def getVisibility(self): """Return the visibility flag of an entity. getVisibility() """ return self.__visible def setVisibility(self, vis): """Set the visibility of the entity. setVisibility(vis) Argument 'vis' must be either True or False. """ util.test_boolean(vis) _v = self.__visible if _v is not vis: self.startChange('visibility_changed') self.__visible = vis self.endChange('visibility_changed') self.sendMessage('visibility_changed', _v) self.modified() def hide(self): """Mark the entity invisible. hide() """ Entity.setVisibility(self, False) def show(self): """Mark the entity as visible. show() """ Entity.setVisibility(self, True) def expose(self): """Mark the entity as visible. expose() This method is identical to show(). """ Entity.setVisibility(self, True) def canParent(self, obj): """Test if an Entity can be the parent of another Entity. canParent(obj) Subclasses should override this method if the ability to be the parent of another entity needs refinement. """ return True def setParent(self, parent): """Store the parent of the entity. setParent(parent) Argument 'parent' must be another entity, and the parent entity is tested to ensure that it can have children entities. """ if parent is not None: if not isinstance(parent, Entity): raise TypeError, "Unexpected parent type: " + `type(parent)` if not parent.canParent(self): raise ValueError, "Invalid parent for Entity: " + `parent` _oldparent = self.__parent if _oldparent is not parent: if _oldparent is not None: Entity.__delChild(_oldparent, self) self.__parent = parent if parent is not None: Entity.__addChild(parent, self) # # fixme - re-examine sending (or not) the 'parent_changed' # and 'modified' messages when this method is invoked as this # method invocation is often called as part of an add/delete # operation that and as such can be thought of as a "side-effect" # # self.sendMessage('parent_changed', _oldparent) # self.modified() def getParent(self): """Return the parent entity of an entity. getParent() This method returns an Entity instance, or None of no parent has been set. """ return self.__parent parent = property(getParent, setParent, None, "Parent of an Entity.") def __addChild(self, child): """Take an entity as a child. addChild(child) This method is private to the Entity class. """ if not isinstance(child, Entity): raise TypeError, "Unexpected child type: " + `type(child)` if child.getParent() is not self: raise ValueError, "Invalid parent: " + `child` if self.__children is None: self.__children = {} _cid = id(child) if _cid in self.__children: raise ValueError, "Child entity already stored: " + `child` self.__children[_cid] = child self.sendMessage('added_child', child) self.modified() def __delChild(self, child): """Remove an entity as a child. delChild(child) This method is private to the Entity class. """ if child.getParent() is not self: raise ValueError, "Invalid parent for child: " + `child` if self.__children is None: raise ValueError, "Entity has no children: " + `self` _cid = id(child) if _cid not in self.__children: raise ValueError, "Child entity not stored: " + `child` del self.__children[_cid] if len(self.__children) == 0: self.__children = None self.sendMessage('removed_child', child) self.modified() def hasChild(self, child): """Test if an entity is a stored as a child. hasChild(child) """ return self.__children is not None and id(child) in self.__children def hasChildren(self): """Test if an entity has children entities. hasChildren() This method returns a boolean. """ return self.__children is not None def getChildren(self): """Return any children entities of an entity. getChildren() This method returns a list of children entities. """ if self.__children is not None: return self.__children.values() return [] def sendsMessage(self, m): """Test if an entity can send a type of message. sendsMessage(m) Argument 'm' should be a string giving the message name. This method returns a boolean. """ if m in Entity.__messages: return True return super(Entity, self).sendsMessage(m) def clone(self): """Return an identical copy of an entity. clone() """ return Entity(parent=self.__parent) def inRegion(self, xmin, ymin, xmax, ymax, all=False): """Test if an entity is found in a spatial region. inRegion(xmin, ymin, xmax, ymax[, all]) Arguments 'xmin', 'ymin', 'xmax', and 'ymax' should all be floats. Argument 'all' is a boolean, with the default set to False. If 'all' is true, then the entire entity must lie within the boundary. """ return False def getLog(self): """Return the history log for an entity. getLog() This method returns a Logger instance, or None if no log has been assigned to the entity. """ return self.__log def setLog(self, log): """Assign a Logger instance to an entity. setLog(log) Argument 'log' should be a Logger instance, or None. """ if log is not None: if not isinstance(log, logger.Logger): raise TypeError, "Unexpected log type: " + `type(log)` if self.__log is not None: raise ValueError, "Entity already contains a log." self.__log = log def delLog(self): """Remove a Logger instance from an entity. delLog() """ if self.__log is not None: self.__log.clear() self.__log = None def undo(self): """Undo an action. undo() Using undo() requires a Logger instance to be assigned to the entity. """ if self.__log is not None: self.__log.undo() def startUndo(self, mute=False): """Store an indication that an undo operation is commencing. startUndo([mute]) Optional argument 'mute' must be a boolean. By default it is False, and when True the entity will be muted during the undo operation. """ _state = self.__undoing if _state != 0: if _state == -1: raise RuntimeError, "Object in redo state: " + `self` elif _state == 1: raise RuntimeError, "Object already in undo state: " + `self` else: raise ValueError, "Unexpected undo/redo state: %d" % _state if mute and False: self.mute() self.__undoing = 1 def endUndo(self): """Set the entity to the state of undo operation completion. endUndo() """ _state = self.__undoing if _state != 1: if _state == -1: raise RuntimeError, "Object in redo state: " + `self` elif _state == 0: raise RuntimeError, "Object not in undo state: " + `self` else: raise ValueError, "Unexpected undo/redo state: %d" % _state self.__undoing = 0 def inUndo(self): """Test if the entity is currently in an undo operation. inUndo() This method returns a boolean. """ return self.__undoing == 1 def redo(self): """Redo an action. redo() Using redo() requires a Logger instance to be assigned to the entity. """ if self.__log is not None: self.__log.redo() def startRedo(self): """Store an indication that an redo operation is commencing. startRedo() """ _state = self.__undoing if _state != 0: if _state == 1: raise RuntimeError, "Object in undo state: " + `self` elif _state == -1: raise RuntimeError, "Object already in redo state: " + `self` else: raise ValueError, "Unexpected undo/redo state: %d" % _state self.__undoing = -1 def endRedo(self): """Set the entity to the state of redo operation completion. endRedo() """ _state = self.__undoing if _state != -1: if _state == 1: raise RuntimeError, "Object in undo state: " + `self` elif _state == 0: raise RuntimeError, "Object not in redo state: " + `self` else: raise ValueError, "Unexpected undo/redo state: %d" % _state self.__undoing = 0 def inRedo(self): """Test if the entity is currently in a redo operation. inRedo() This method returns a boolean. """ return self.__undoing == -1 # # Entity history class # class EntityLog(logger.Logger): def __init__(self, obj): if not isinstance(obj, Entity): raise TypeError, "Unexpected entity type: " + `type(obj)` super(EntityLog, self).__init__() self.__obj = obj obj.connect('visibility_changed', self.__visibilityChanged) obj.connect('lock_changed', self.__lockChanged) # obj.connect('parent_changed', self.__parentChanged) def detatch(self): self.__obj.disconnect(self) self.__obj = None def getObject(self): """Return the object stored in the log. getEntity() """ return self.__obj def __visibilityChanged(self, obj, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _vis = args[0] util.test_boolean(_vis) self.saveUndoData('visibilty_changed', _vis) def __lockChanged(self, obj, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _lock = args[0] util.test_boolean(_lock) self.saveUndoData('lock_changed', _lock) def __parentChanged(self, obj, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _parent = args[0] if _parent is not None and not isinstance(_parent, Entity): raise TypeError, "Unexpected parent type: " + `type(_parent)` _pid = None if _parent is not None: _pid = _parent.getID() self.saveUndoData('parent_changed', _pid) def execute(self, undo, *args): # print "EntityLog::execute() ..." # print args util.test_boolean(undo) _alen = len(args) if len(args) == 0: raise ValueError, "No arguments to execute()" _obj = self.__obj _op = args[0] if _op == 'visibility_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _sdata = _obj.getVisibility() self.ignore(_op) try: _vis = args[1] if undo: _obj.startUndo() try: _obj.setVisibility(_vis) finally: _obj.endUndo() else: _obj.startRedo() try: _obj.setVisibility(_vis) finally: _obj.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) elif _op == 'lock_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _sdata = _obj.isLocked() self.ignore(_op) try: _lock = args[1] if undo: _obj.startUndo() try: _obj.setLock(_lock) finally: _obj.endUndo() else: _obj.startRedo() try: _obj.setLock(_lock) finally: _obj.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) else: raise ValueError, "Unexpected operation: %s" % _op def saveData(self, undo, op, *args): util.test_boolean(undo) if undo: self.saveRedoData(op, *args) else: self.saveUndoData(op, *args) # # property storage class # class EntityData(object): def __init__(self): self.__values = {} self.__locked = False def keys(self): return self.__values.keys() def values(self): return self.__values.values() def lock(self): self.__locked = True def unlock(self): self.__locked = False def isLocked(self): return self.__locked is True def setValue(self, key, value): if self.__locked: raise RuntimeError, "EntityData instance is locked: " + `self` if not isinstance(key, types.StringTypes): raise TypeError, "Invalid key type: " + `type(key)` if not EntityData._testValueType(self, value): raise TypeError, "Invalid value type: " + `type(value)` self.__values[key] = value def _testValueType(self, value): _pass = isinstance(value, (types.StringTypes, types.NoneType, int, float, EntityData)) if not _pass: if isinstance(value, (tuple, list)): for _v in value: _pass = EntityData._testValueType(self, _v) if not _pass: break elif isinstance(value, dict): for _k, _v in value.items(): _pass = isinstance(_k, types.StringTypes) if not _pass: break _pass = EntityData._testValueType(self, _v) if not _pass: break else: _pass = False return _pass def getValue(self, key): return self.__values[key] def get(self, key): return self.__values.get(key) PythonCAD-DS1-R37/PythonCAD/Generic/move.py0000644000175000017500000004566711307666657017701 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # code to handle moving objects # from PythonCAD.Generic.point import Point from PythonCAD.Generic.segment import Segment from PythonCAD.Generic.circle import Circle from PythonCAD.Generic.arc import Arc from PythonCAD.Generic.hcline import HCLine from PythonCAD.Generic.vcline import VCLine from PythonCAD.Generic.acline import ACLine from PythonCAD.Generic.segjoint import Chamfer, Fillet from PythonCAD.Generic.cline import CLine from PythonCAD.Generic.ccircle import CCircle from PythonCAD.Generic.leader import Leader from PythonCAD.Generic.polyline import Polyline from PythonCAD.Generic.text import TextBlock from PythonCAD.Generic.dimension import Dimension, DimString from PythonCAD.Generic.dimension import LinearDimension from PythonCAD.Generic.dimension import AngularDimension from PythonCAD.Generic import util def _adjust_dimensions(op, np): _users = op.getUsers() for _user in _users: if isinstance(_user, Dimension): if isinstance(_user, LinearDimension): _p1, _p2 = _user.getDimPoints() if _p1 is op: _user.setP1(np) elif _p2 is op: _user.setP2(np) elif isinstance(_user, AngularDimension): _vp, _p1, _p2 = _user.getDimPoints() if _vp is op: _user.setVertexPoint(np) elif _p1 is op: _user.setP1(np) elif _p2 is op: _user.setP2(np) else: raise TypeError, "Unknown dimension type: " + `type(_user)` def _most_used(plist): _pmax = plist.pop() _max = _pmax.countUsers() for _pt in plist: _count = _pt.countUsers() if _count > _max: _max = _count _pmax = _pt return _pmax def _used_by(obj, plist): _objpt = None for _pt in plist: for _user in _pt.getUsers(): if _user is obj: _objpt = _pt break if _objpt is not None: break return _objpt def _can_move(obj, objdict): for _user in obj.getUsers(): if id(_user) not in objdict: return False return True def _copy_spcline(obj, objdict, dx, dy): _lp = obj.getLocation() _pid = id(_lp) _layer = obj.getParent() _x, _y = _lp.getCoords() _nx = _x + dx _ny = _y + dy _pts = _layer.find('point', _nx, _ny) if len(_pts) == 0: _np = Point(_nx, _ny) _layer.addObject(_np) else: _np = _most_used(_pts) obj.setLocation(_np) _adjust_dimensions(_lp, _np) _layer.delObject(_lp) if objdict.get(_pid) is not False: objdict[_pid] = False def _move_spcline(obj, objdict, dx, dy): if isinstance(obj, HCLine): _objtype = 'HCLine' elif isinstance(obj, VCLine): _objtype = 'VCLine' elif isinstance(obj, ACLine): _objtype = 'ACLine' else: raise TypeError, "Unexpected object type: " + `type(obj)` _layer = obj.getParent() if _layer is None: raise RuntimeError, "%s parent is None" % _objtype _lp = obj.getLocation() if _lp.getParent() is not _layer: raise RuntimeError, "%s/point parent object conflict!" % _objtype if _can_move(_lp, objdict): _pid = id(_lp) if _pid in objdict: if objdict[_pid]: _lp.move(dx, dy) else: obj.move(dx, dy) if objdict.get(_pid) is not False: objdict[_pid] = False else: _copy_spcline(obj, objdict, dx, dy) def _copy_polyline(obj, objdict, dx, dy): _pts = obj.getPoints() _mp = {} for _pt in _pts: _pid = id(_pt) _mp[_pid] = False if _can_move(obj, objdict): for _pt in _pts: _pid = id(_pt) if _can_move(_pt, objdict) and objdict.get(_pid) is not False: _mp[_pid] = True _layer = obj.getParent() for _i in range(len(_pts)): _pt = _pts[_i] _pid = id(_pt) if _mp[_pid]: _pt.move(dx, dy) else: _x, _y = _pt.getCoords() _nx = _x + dx _ny = _y + dy _lpts = _layer.find('point', _nx, _ny) if len(_lpts) == 0: _np = Point(_nx, _ny) _layer.addObject(_np) else: _np = _most_used(_lpts) obj.setPoint(_i, _np) _adjust_dimensions(_pt, _np) _layer.delObject(_pt) if objdict.get(_pid) is not False: objdict[_pid] = False def _move_polyline(obj, objdict, dx, dy): _pts = obj.getPoints() _layer = obj.getParent() if _layer is None: raise RuntimeError, "Polyline parent is None" for _pt in _pts: if _pt.getParent() is not _layer: raise RuntimeError, "Polyline/point parent object conflict!" _use_move = _can_move(obj, objdict) if _use_move: for _pt in _pts: if not _can_move(_pt, objdict): _use_move = False break if _use_move: _objmove = True _seen = False _used = True for _pt in _pts: _pid = id(_pt) if _pid in objdict: _seen = True if not objdict[_pid]: _used = False if _seen and not _used: _objmove = False break if _objmove: obj.move(dx, dy) else: for _pt in _pts: _pid = id(_pt) if objdict.get(_pid) is not False: _pt.move(dx, dy) for _pt in _pts: _pid = id(_pt) if objdict.get(_pid) is not False: objdict[_pid] = False else: _copy_polyline(obj, objdict, dx, dy) def _copy_leader(obj, objdict, dx, dy): _p1, _p2, _p3 = obj.getPoints() _p1id = id(_p1) _p2id = id(_p2) _p3id = id(_p3) _layer = obj.getParent() if _can_move(_p1, objdict) and objdict.get(_p1id) is not False: _p1.move(dx, dy) else: _x, _y = _p1.getCoords() _nx = _x + dx _ny = _y + dy _pts = _layer.find('point', _nx, _ny) if len(_pts) == 0: _np = Point(_nx, _ny) _layer.addObject(_np) else: _np = _most_used(_pts) obj.setP1(_np) _adjust_dimensions(_p1, _np) _layer.delObject(_p1) if _can_move(_p2, objdict) and objdict.get(_p2id) is not False: _p2.move(dx, dy) else: _x, _y = _p2.getCoords() _nx = _x + dx _ny = _y + dy _pts = _layer.find('point', _nx, _ny) if len(_pts) == 0: _np = Point(_nx, _ny) _layer.addObject(_np) else: _np = _most_used(_pts) obj.setP2(_np) _adjust_dimensions(_p2, _np) _layer.delObject(_p2) if _can_move(_p3, objdict) and objdict.get(_p3id) is not False: _p3.move(dx, dy) else: _x, _y = _p3.getCoords() _nx = _x + dx _ny = _y + dy _pts = _layer.find('point', _nx, _ny) if len(_pts) == 0: _np = Point(_nx, _ny) _layer.addObject(_np) else: _np = _most_used(_pts) obj.setP3(_np) _adjust_dimensions(_p3, _np) _layer.delObject(_p3) if objdict.get(_p1id) is not False: objdict[_p1id] = False if objdict.get(_p2id) is not False: objdict[_p2id] = False if objdict.get(_p3id) is not False: objdict[_p3id] = False def _move_leader(obj, objdict, dx, dy): _p1, _p2, _p3 = obj.getPoints() _layer = obj.getParent() if _layer is None: raise RuntimeError, "Leader parent is None" if _p1.getParent() is not _layer: raise RuntimeError, "Leader/P1 parent object conflict!" if _p2.getParent() is not _layer: raise RuntimeError, "Leader/P2 parent object conflict!" if _p3.getParent() is not _layer: raise RuntimeError, "Leader/P3 parent object conflict!" if (_can_move(_p1, objdict) and _can_move(_p2, objdict) and _can_move(_p3, objdict)): _p1id = id(_p1) _p2id = id(_p2) _p3id = id(_p3) if (objdict.get(_p1id) is not False and objdict.get(_p2id) is not False and objdict.get(_p3id) is not False): obj.move(dx, dy) else: if objdict.get(_p1id) is not False: _p1.move(dx, dy) if objdict.get(_p2id) is not False: _p2.move(dx, dy) if objdict.get(_p3id) is not False: _p3.move(dx, dy) if objdict.get(_p1id) is not False: objdict[_p1id] = False if objdict.get(_p2id) is not False: objdict[_p2id] = False if objdict.get(_p3id) is not False: objdict[_p3id] = False else: _copy_leader(obj, objdict, dx, dy) def _adjust_endpoint(arc, pt, objdict, dx, dy): _layer = arc.getParent() if pt.getParent() is not _layer: raise RuntimeError, "Arc/Endpoint parent object conflict!" _pid = id(pt) _users = [] for _user in pt.getUsers(): _users.append(_user) if len(_users) == 1 and _users[0] is arc: if objdict.get(_pid) is not False: pt.move(dx, dy) else: pt.freeUser(arc) _x, _y = pt.getCoords() _nx = _x + dx _ny = _y + dy _pts = _layer.find('point', _nx, _ny) if len(_pts) == 0: _np = Point(_nx, _ny) _layer.addObject(_np) else: _np = _most_used(_pts) _np.storeUser(arc) _adjust_dimensions(pt, _np) _layer.delObject(pt) if objdict.get(_pid) is not False: objdict[_pid] = False def _copy_arc(obj, objdict, dx, dy): _cp = obj.getCenter() _pid = id(_cp) _layer = obj.getParent() _ep1, _ep2 = obj.getEndpoints() _pts = _layer.find('point', _ep1[0], _ep1[1]) _lp1 = _used_by(obj, _pts) if _lp1 is None: raise RuntimeError, "Lost Arc first endpoint: " + str(_ep1) _adjust_endpoint(obj, _lp1, objdict, dx, dy) _pts = _layer.find('point', _ep2[0], _ep2[1]) _lp2 = _used_by(obj, _pts) if _lp2 is None: raise RuntimeError, "Lost Arc second endpoint: " + str(_ep2) _adjust_endpoint(obj, _lp2, objdict, dx, dy) _x, _y = _cp.getCoords() _nx = _x + dx _ny = _y + dy _pts = _layer.find('point', _nx, _ny) if len(_pts) == 0: _np = Point(_nx, _ny) _layer.addObject(_np) else: _np = _most_used(_pts) obj.setCenter(_np) _adjust_dimensions(_cp, _np) _layer.delObject(_cp) if objdict.get(_pid) is not False: objdict[_pid] = False def _move_arc(obj, objdict, dx, dy): _layer = obj.getParent() if _layer is None: raise RuntimeError, "Arc parent is None" _cp = obj.getCenter() if _cp.getParent() is not _layer: raise RuntimeError, "Arc/center parent object conflict!" if _can_move(obj, objdict) and _can_move(_cp, objdict): _ep1, _ep2 = obj.getEndpoints() _pts = _layer.find('point', _ep1[0], _ep1[1]) _lp1 = _used_by(obj, _pts) if _lp1 is None: raise RuntimeError, "Lost Arc first endpoint: " + str(_ep1) _adjust_endpoint(obj, _lp1, objdict, dx, dy) _pts = _layer.find('point', _ep2[0], _ep2[1]) _lp2 = _used_by(obj, _pts) if _lp2 is None: raise RuntimeError, "Lost Arc second endpoint: " + str(_ep2) _adjust_endpoint(obj, _lp2, objdict, dx, dy) _pid = id(_cp) if _pid in objdict: if objdict[_pid]: _cp.move(dx, dy) else: obj.move(dx, dy) if objdict.get(_pid) is not False: objdict[_pid] = False else: _copy_arc(obj, objdict, dx, dy) def _copy_circ_ccirc(obj, objdict, dx, dy): _cp = obj.getCenter() _pid = id(_cp) _layer = obj.getParent() _x, _y = _cp.getCoords() _nx = _x + dx _ny = _y + dy _pts = _layer.find('point', _nx, _ny) if len(_pts) == 0: _np = Point(_nx, _ny) _layer.addObject(_np) else: _np = _most_used(_pts) obj.setCenter(_np) _adjust_dimensions(_cp, _np) _layer.delObject(_cp) if objdict.get(_pid) is not False: objdict[_pid] = False def _move_circle(obj, objdict, dx, dy): if isinstance(obj, Circle): _objtype = 'Circle' elif isinstance(obj, CCircle): _objtype = 'CCircle' else: raise TypeError, "Unexpected object type: " + `type(obj)` _layer = obj.getParent() if _layer is None: raise RuntimeError, "%s parent is None" % _objtype _cp = obj.getCenter() if _cp.getParent() is not _layer: raise RuntimeError, "%s/center parent object conflict!" % _objtype if _can_move(obj, objdict) and _can_move(_cp, objdict): _pid = id(_cp) if _pid in objdict: if objdict[_pid]: _cp.move(dx, dy) else: obj.move(dx, dy) if objdict.get(_pid) is not False: objdict[_pid] = False else: _copy_circ_ccirc(obj, objdict, dx, dy) def _copy_seg_cline(obj, objdict, dx, dy): if isinstance(obj, Segment): _p1, _p2 = obj.getEndpoints() elif isinstance(obj, CLine): _p1, _p2 = obj.getKeypoints() else: raise TypeError, "Unexpected object type: " + `type(obj)` _p1id = id(_p1) _p2id = id(_p2) _mp1 = _mp2 = False if _can_move(obj, objdict): _mp1 = _can_move(_p1, objdict) and objdict.get(_p1id) is not False _mp2 = _can_move(_p2, objdict) and objdict.get(_p2id) is not False _layer = obj.getParent() if _mp1: _p1.move(dx, dy) else: _x, _y = _p1.getCoords() _nx = _x + dx _ny = _y + dy _pts = _layer.find('point', _nx, _ny) if len(_pts) == 0: _np = Point(_nx, _ny) _layer.addObject(_np) else: _np = _most_used(_pts) obj.setP1(_np) _adjust_dimensions(_p1, _np) _layer.delObject(_p1) if _mp2: _p2.move(dx, dy) else: _x, _y = _p2.getCoords() _nx = _x + dx _ny = _y + dy _pts = _layer.find('point', _nx, _ny) if len(_pts) == 0: _np = Point(_nx, _ny) _layer.addObject(_np) else: _np = _most_used(_pts) obj.setP2(_np) _adjust_dimensions(_p2, _np) _layer.delObject(_p2) if objdict.get(_p1id) is not False: objdict[_p1id] = False if objdict.get(_p2id) is not False: objdict[_p2id] = False def _move_seg_cline(obj, objdict, dx, dy): if isinstance(obj, Segment): _p1, _p2 = obj.getEndpoints() _objtype = 'Segment' elif isinstance(obj, CLine): _p1, _p2 = obj.getKeypoints() _objtype = 'CLine' else: raise TypeError, "Unexpected object type: " + `type(obj)` _layer = obj.getParent() if _layer is None: raise RuntimeError, "%s parent is None" % _objtype if _p1.getParent() is not _layer: raise RuntimeError, "%s/P1 parent object conflict!" % _objtype if _p2.getParent() is not _layer: raise RuntimeError, "%s/P2 parent object conflict!" % _objtype if (_can_move(obj, objdict) and _can_move(_p1, objdict) and _can_move(_p2, objdict)): _p1id = id(_p1) _p2id = id(_p2) if (objdict.get(_p1id) is not False and objdict.get(_p2id) is not False): obj.move(dx, dy) else: if objdict.get(_p1id) is not False: _p1.move(dx, dy) if objdict.get(_p2id) is not False: _p2.move(dx, dy) if objdict.get(_p1id) is not False: objdict[_p1id] = False if objdict.get(_p2id) is not False: objdict[_p2id] = False else: _copy_seg_cline(obj, objdict, dx, dy) def move_objects(objs, dx, dy): """Move a list of objects. move_objects(objs, dx, dy) objs: A list or tuple containing the objects to move. dx: The displacement along the x-axis dy: The displacement along the y-axis """ if not isinstance(objs, (list, tuple)): raise TypeError, "Invalid object list/tuple: " + `type(objs)` _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _objdict = {} _fillets = [] for _obj in objs: if not isinstance(_obj, DimString): _objdict[id(_obj)] = True for _obj in objs: _oid = id(_obj) if _oid not in _objdict: continue if _objdict[_oid]: if isinstance(_obj, Point): _obj.move(_dx, _dy) for _user in _obj.getUsers(): _uid = id(_user) if (_uid in _objdict and not isinstance(_user, Dimension)): _objdict[_uid] = False elif isinstance(_obj, (Segment, CLine)): _move_seg_cline(_obj, _objdict, _dx, _dy) elif isinstance(_obj, (Circle, CCircle)): _move_circle(_obj, _objdict, _dx, _dy) elif isinstance(_obj, Arc): _move_arc(_obj, _objdict, _dx, _dy) elif isinstance(_obj, Leader): _move_leader(_obj, _objdict, _dx, _dy) elif isinstance(_obj, Polyline): _move_polyline(_obj, _objdict, _dx, _dy) elif isinstance(_obj, (TextBlock, Dimension)): _obj.move(_dx, _dy) elif isinstance(_obj, (HCLine, VCLine, ACLine)): _move_spcline(_obj, _objdict, _dx, _dy) elif isinstance(_obj, (Chamfer, Fillet)): _s1, _s2 = _obj.getSegments() if id(_s1) not in _objdict or id(_s2) not in _objdict: _layer = _obj.getParent() _layer.delObject(_obj) if isinstance(_obj, Fillet): _fillets.append(_obj) else: print "Unexpected entity type: " + `type(_obj)` _objdict[_oid] = False for _obj in _fillets: _obj._calculateCenter() # FIXME PythonCAD-DS1-R37/PythonCAD/Generic/bindump.py0000644000175000017500000000322211307666657020346 0ustar matteomatteo#!/usr/bin/python # # simply binary dump # import sys import array if len(sys.argv) < 4: print "bindump.py file offset count" sys.exit(1) else: try: _fname = file(sys.argv[1]) except: print "invalid file: " + sys.argv[1] sys.exit(1) try: _offset = int(sys.argv[2]) except: print "invalid offset: " + sys.argv[2] sys.exit(1) if _offset < 0: print "invalid offset: %d" % _offset sys.exit(1) try: _count = int(sys.argv[3]) except: print "invalid byte count: " + sys.argv[3] sys.exit(1) if _count < 0: print "invalid byte count: %d" % _count sys.exit(1) print "opening file: " + _fname.name print "offset: %d" % _offset print "count: %d" % _count try: _fname.seek(_offset, 0) except: _fname.close() print "invalid offset into file: %d" % _offset sys.exit(1) _data = array.array('B') try: _data.fromfile(_fname, _count) except: _fname.close() print "invalid read of %d bytes from file: %s" % (_count, _fname.name) sys.exit(1) _fname.close() _patterns = [ '0 0 0 0', # 0 '0 0 0 1', # 1 '0 0 1 0', # 2 '0 0 1 1', # 3 '0 1 0 0', # 4 '0 1 0 1', # 5 '0 1 1 0', # 6 '0 1 1 1', # 7 '1 0 0 0', # 8 '1 0 0 1', # 9 '1 0 1 0', # A '1 0 1 1', # B '1 1 0 0', # C '1 1 0 1', # D '1 1 1 0', # E '1 1 1 1' # F ] _i = 0 while (_i < _count): _bitoffset = _i * 8 _nib1 = _patterns[((_data[_i] & 0xf0) >> 4)] _nib2 = _patterns[(_data[_i] & 0x0f)] print "%d [%d]: 0x%02x %s %s" % (_i, _bitoffset, _data[_i], _nib1, _nib2) _i = _i + 1 PythonCAD-DS1-R37/PythonCAD/Generic/ellipse.py0000644000175000017500000003632611307666657020360 0ustar matteomatteo# # Copyright (c) 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # class stuff for ellipses # # Ellipse info: # http://mathworld.wolfram.com/Ellipse.html # http://astronomy.swin.edu.au/~pbourke/geometry/ellipsecirc/ # import math from PythonCAD.Generic import baseobject from PythonCAD.Generic import tolerance from PythonCAD.Generic import point from PythonCAD.Generic import graphicobject from PythonCAD.Generic import style from PythonCAD.Generic import linetype from PythonCAD.Generic import color from PythonCAD.Generic import util class Ellipse(graphicobject.GraphicObject): """A base class for Ellipses An ellipse has the following attributes: center: A _point object major_axis: minor_axis: angle: A float from -90.0 to 90.0 degrees """ __defstyle = None __messages = { 'center_changed' : True, 'major_axis_changed' : True, 'minor_axis_changed' : True, 'angle_changed' : True, 'moved' : True, } def __init__(self, center, major, minor, angle, st=None, lt=None, col=None, t=None, **kw): _cp = center if not isinstance(_cp, point._Point): _cp = point.Point(center) _major = util.get_float(major) if not _major > 0.0: raise ValueError, "Invalid major axis value: %g" % _major _minor = util.get_float(minor) if not _minor > 0.0: raise ValueError, "Invalid minor axis value: %g" % _minor if _minor > _major: raise ValueError, "Minor axis must be less than major axis" _angle = util.make_angle(angle) _st = st if _st is None: _st = self.getDefaultStyle() super(Ellipse, self).__init__(_st, lt, col, t, **kw) self.__center = _cp self.__major = _major self.__minor = _minor self.__angle = _angle _cp.storeUser(self) _cp.connect('moved', self.__movePoint) _cp.connect('change_pending', self.__pointChangePending) _cp.connect('change_complete', self.__pointChangeComplete) def __eq__(self, obj): """Compare one ellipse to another for equality. """ if not isinstance(obj, Ellipse): return False if obj is self: return True return (self.__center == obj.getCenter() and abs(self.__major - obj.getMajorAxis()) < 1e-10 and abs(self.__minor - obj.getMinorAxis()) < 1e-10 and abs(self.__angle - obj.getAngle()) < 1e-10) def __ne__(self, obj): """Compare one ellipse to another for equality. """ if not isinstance(obj, Ellipse): return True if obj is self: return False return (self.__center != obj.getCenter() or abs(self.__major - obj.getMajorAxis()) > 1e-10 or abs(self.__minor - obj.getMinorAxis()) > 1e-10 or abs(self.__angle - obj.getAngle()) > 1e-10) def getDefaultStyle(cls): if cls.__defstyle is None: _s = style.Style(u'Default Ellipse Style', linetype.Linetype(u'Solid', None), color.Color(0xffffff), 1.0) cls.__defstyle = _s return cls.__defstyle getDefaultStyle = classmethod(getDefaultStyle) def setDefaultStyle(cls, s): if not isinstance(s, style.Style): raise TypeError, "Invalid style: " + `type(s)` cls.__defstyle = s setDefaultStyle = classmethod(setDefaultStyle) def finish(self): self.__center.disconnect(self) self.__center.freeUser(self) self.__center = self.__major = self.__minor = self.__angle = None super(Ellipse, self).finish() def setStyle(self, s): """Set the Style of the Ellipse. setStyle(s) This method extends GraphicObject::setStyle(). """ _s = s if _s is None: _s = self.getDefaultStyle() super(Ellipse, self).setStyle(_s) def getValues(self): """Return values comprising the Ellipse. getValues() This method extends the GraphicObject::getValues() method. """ _data = super(Ellipse, self).getValues() _data.setValue('type', 'ellipse') _data.setValue('center', self.__center.getID()) _data.setValue('major', self.__major) _data.setValue('minor', self.__minor) _data.setValue('angle', self.__angle) return _data def getCenter(self): """Return the center _Point of the Ellipse. getCenter() """ return self.__center def setCenter(self, cp): """Set the center _Point of the Ellipse. setCenter(cp) The argument must be a _Point or a tuple containing two float values. """ if self.isLocked(): raise RuntimeError, "Setting center not allowed - object locked." if not isinstance(cp, point._Point): raise TypeError, "Invalid Point: " + `cp` _c = self.__center if _c is not cp: _c.disconnect(self) _c.freeUser(self) self.startChange('center_changed') self.__center = cp self.endChange('center_changed') self.sendMessage('center_changed', _c) cp.storeUser(self) cp.connect('moved', self.__movePoint) cp.connect('change_pending', self.__pointChangePending) cp.connect('change_complete', self.__pointChangeComplete) if abs(_c.x - cp.x) > 1e-10 or abs(_c.y - cp.y) > 1e-10: _x, _y = _c.getCoords() self.sendMessage('moved', _x, _y, self.__major, self.__minor, self.__angle) self.modified() center = property(getCenter, setCenter, None, "Ellipse center") def getMajorAxis(self): """Return the major axis value of the Ellipse. getMajorAxis() This method returns a float. """ return self.__major def setMajorAxis(self, val): """Set the major axis of the Ellipse. setMajorAxis(val) Argument 'val' must be a float value greater than 0. """ if self.isLocked(): raise RuntimeError, "Setting major axis not allowed - object locked." _val = util.get_float(val) if not _val > 0.0: raise ValueError, "Invalid major axis value: %g" % _val if _val < self.__minor: raise ValueError, "Major axis must be greater than minor axis." _maj = self.__major if abs(_val - _maj) > 1e-10: self.startChange('major_axis_changed') self.__major = _val self.endChange('major_axis_changed') self.sendMessage('major_axis_changed', _maj) _x, _y = self.__center.getCoords() self.sendMessage('moved', _x, _y, _maj, self.__minor, self.__angle) self.modified() major_axis = property(getMajorAxis, setMajorAxis, None, "Ellipse major axis") def getMinorAxis(self): """Return the minor axis value of the Ellipse. getMinorAxis() This method returns a float. """ return self.__minor def setMinorAxis(self, val): """Set the minor axis of the Ellipse. setMinorAxis(val) Argument 'val' must be a float value greater than 0. """ if self.isModified(): raise RuntimeError, "Setting minor axis not allowed - object locked." _val = util.get_float(val) if not _val > 0.0: raise ValueError, "Invalid minor axis value: %g" % _val if _val > self.__major: raise ValueError, "Minor axis must be less than major axis" _min = self.__minor if abs(_val - _min) > 1e-10: self.startChange('minor_axis_changed') self.__minor = _val self.endChange('minor_axis_changed') self.sendMessage('minor_axis_changed', _min) _x, _y = self.__center.getCoords() self.sendMessage('moved', _x, _y, self.__major, _min, self.__angle) self.modified() minor_axis = property(getMinorAxis, setMinorAxis, None, "Ellipse minor axis") def getAngle(self): """Return the Ellipse major axis angle. getAngle() This method returns a float value. """ return self.__angle def setAngle(self, angle): """Set the Ellipse major axis angle. setAngle(angle) Argument 'angle' should be a float. The value will be adjusted so the angle will be defined from 90.0 to -90.0. """ if self.isModified(): raise RuntimeError, "Setting angle not allowed - object locked." _angle = util.make_angle(angle) _a = self.__angle if abs(_a - _angle) > 1e-10: self.startChange('angle_changed') self.__angle = _angle self.endChange('angle_changed') self.sendMessage('angle_changed', _a) _x, _y = self.__center.getCoords() self.sendMessage('moved', _x, _y, self.__major, self.__minor, _angle) self.modified() angle = property(getAngle, setAngle, None, "Ellipse major axis angle") def move(self, dx, dy): """Move an Ellipse. move(dx, dy) Arguments 'dx' and 'dy' should be floats. """ if self.isLocked() or self.__center.isLocked(): raise RuntimeError, "Moving object not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _x, _y = self.__center.getCoords() self.ignore('moved') try: self.__center.move(_dx, _dy) finally: self.receive('moved') self.sendMessage('moved', _x, _y, self.__major, self.__minor, self.__angle) def rotate(self, angle): """Rotate an Ellipse rotate(angle) Argument 'angle' should be a float. """ if self.isLocked(): raise RuntimeError, "Rotating object not allowed - object locked." _angle = util.get_float(angle) if abs(_angle) > 1e-10: _cur = self.__angle _new = util.make_angle(_angle + _cur) self.startChange('angle_changed') self.__angle = _new self.endChange('angle_changed') self.sendMessage('angle_changed', _cur) _x, _y = self.__center.getCoords() self.sendMessage('moved', _x, _y, self.__major, self.__minor, _cur) self.modified() def eccentricity(self): """Return the eccecntricity of the Ellipse. eccentricity() This method returns a float value. """ _major = self.__major _minor = self.__minor if abs(_major - _minor) < 1e-10: # circular _e = 0.0 else: _e = math.sqrt(1.0 - ((_minor * _minor)/(_major * _major))) return _e def area(self): """Return the area of the Ellipse. area() This method returns a float value. """ return math.pi * self.__major * self.__minor def circumference(self): """Return the circumference of an ellipse. circumference() This method returns a float. The algorithm below is taken from http://astronomy.swin.edu.au/~pbourke/geometry/ellipsecirc/ Ramanujan, Second Approximation """ _a = self.__major _b = self.__minor _h = math.pow((_a - _b), 2)/math.pow((_a + _b), 2) _3h = 3.0 * _h return math.pi * (_a + _b) * (1.0 + _3h/(10.0 + math.sqrt(4.0 - _3h))) def mapCoords(self, x, y, tol=tolerance.TOL): """Return the nearest _Point on the Ellipse to a coordinate pair. mapCoords(x, y[, tol]) The function has two required arguments: x: A Float value giving the 'x' coordinate y: A Float value giving the 'y' coordinate There is a single optional argument: tol: A float value equal or greater than 0.0 This function is used to map a possibly near-by coordinate pair to an actual _Point on the Ellipse. If the distance between the actual _Point and the coordinates used as an argument is less than the tolerance, the actual _Point is returned. Otherwise, this function returns None. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _cx, _cy = self.__center.getCoords() _dist = math.hypot((_x - _cx), (_y - _cy)) _major = self.__major _minor = self.__minor _ep = None if abs(_major - _minor) < 1e-10: # circular _sep = _dist - _major if _sep < _t or abs(_sep - _t) < 1e-10: _angle = math.atan2((_y - _cy),(_x - _cx)) _px = _major * math.cos(_angle) _py = _major * math.sin(_angle) _ep = point._Point((_cx + _px), (_cy + _py)) else: if _dist < _major and _dist > _minor: _ecos = math.cos(self.__angle) _esin = math.sin(self.__angle) # FIXME ... return _ep def __pointChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.startChange('moved') def __pointChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.endChange('moved') def __movePoint(self, p, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) if p is not self.__center: raise ValueError, "Unexpected point in movePoint" + `p` self.sendMessage('moved', _x, _y, self.__major, self.__minor, self.__angle) self.modified() # # measure r from focus # # x = c + r*cos(theta) # y = r*sin(theta) # # c = sqrt(a^2 - b^2) # # r = a*(1-e)/(1 + e*cos(theta)) def clone(self): """Make a copy of an Ellipse. clone() This method returns a new Ellipse object """ _cp = self.__center.clone() _st = self.getStyle() _lt = self.getLinetype() _col = self.getColor() _th = self.getThickness() return Ellipse(_cp, self.__major, self.__minor, self.__angle, _st, _lt, _col, _th) def sendsMessage(self, m): if m in Ellipse.__messages: return True return super(Ellipse, self).sendsMessage(m) PythonCAD-DS1-R37/PythonCAD/Generic/segjoint.py0000644000175000017500000007556211307666732020544 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # code for chamfer and fillet objects # from math import hypot, pi, sin, cos, tan, atan2 from PythonCAD.Generic import baseobject from PythonCAD.Generic import graphicobject from PythonCAD.Generic import intersections from PythonCAD.Generic import segment from PythonCAD.Generic import style from PythonCAD.Generic import linetype from PythonCAD.Generic import color from PythonCAD.Generic import util _dtr = 180.0/pi class SegJoint(graphicobject.GraphicObject): """A base class for chamfers and fillets A SegJoint object has the following methods: validate(): Check the two segments can intersect. getSegments(): Get the two segments joined by the SegJoint object. getMovingPoints(): Get the segment points used by the SegJoint object. getFixedPoints(): Get the segment points not used by the SegJoint object. update(): Recheck the SegJoint's validity. getIntersection(): Get the intersection point of the joined segments. inRegion(): Determine if a SegJoint is located in some area. """ # # The default style for the Segjoint class # __defstyle = None def __init__(self, s1, s2, st=None, lt=None, col=None, t=None, **kw): if not isinstance(s1, segment.Segment): raise TypeError, "Invalid first Segment for SegJoint: " + `type(s1)` if not isinstance(s2, segment.Segment): raise TypeError, "Invalid second Segment for SegJoint: " + `type(s2)` _st = st if _st is None: _st = self.getDefaultStyle() super(SegJoint, self).__init__(_st, lt, col, t, **kw) self.__s1 = s1 self.__s2 = s2 self.__xi = None # segment intersection x-coordinate self.__yi = None # segment intersection y-coordinate self.__s1_float = None # s1 endpoint at joint self.__s1_fixed = None # s1 other endpoint self.__s2_float = None # s2 endpoint at joint self.__s2_fixed = None # s2 other endpoint SegJoint.validate(self) s1.storeUser(self) # s1.connect('moved', self._moveSegment) # s1.connect('change_pending', self._segmentChanging') s2.storeUser(self) # s2.connect('moved', self._moveSegment) # s2.connect('change_pending', self._segmentChanging') def getDefaultStyle(cls): if cls.__defstyle is None: _s = style.Style(u'Segjoint Default Style', linetype.Linetype(u'Solid', None), color.Color(0xffffff), 1.0) cls.__defstyle = _s return cls.__defstyle getDefaultStyle = classmethod(getDefaultStyle) def setDefaultStyle(cls, s): if not isinstance(s, style.Style): raise TypeError, "Invalid style: " + `type(s)` cls.__defstyle = s setDefaultStyle = classmethod(setDefaultStyle) def finish(self): self.__s1.disconnect(self) self.__s1.freeUser(self) self.__s2.disconnect(self) self.__s2.freeUser(self) self.__s1 = self.__s2 = None super(SegJoint, self).finish() def setStyle(self, s): """Set the Style of the SegJoint. setStyle(s) This method extends GraphicObject::setStyle(). """ _s = s if _s is None: _s = self.getDefaultStyle() super(SegJoint, self).setStyle(_s) def validate(self): """ Check that the two segments can intersect. """ _p1, _p2 = self.__s1.getEndpoints() _p3, _p4 = self.__s2.getEndpoints() if _p1 is _p3 or _p2 is _p3 or _p1 is _p4 or _p2 is _p4: raise ValueError, "Shared segment endpoints in s1 and s2" _denom = intersections.denom(_p1, _p2, _p3, _p4) if abs(_denom) < 1e-10: # parallel raise ValueError, "Segments are parallel" _rn = intersections.rnum(_p1, _p2, _p3, _p4) # print "rn: %g" % _rn _sn = intersections.snum(_p1, _p2, _p3, _p4) # print "sn: %g" % _sn _r = _rn/_denom _s = _sn/_denom if 0.0 < _r < 1.0 or 0.0 < _s < 1.0: raise ValueError, "Invalid segment intersection point" _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() self.__xi = _x1 + _r * (_x2 - _x1) # intersection "x" coordinate self.__yi = _y1 + _r * (_y2 - _y1) # intersection "y" coordinate # print "xi: %g; yi: %g" % (self.__xi, self.__yi) if _r < 1e-10: self.__s1_fixed = _p2 self.__s1_float = _p1 else: self.__s1_fixed = _p1 self.__s1_float = _p2 if _s < 1e-10: self.__s2_fixed = _p4 self.__s2_float = _p3 else: self.__s2_fixed = _p3 self.__s2_float = _p4 def getSegments(self): """Return the two segments joined by the SegJoint. getSegments() This method returns a tuple holding the two segments joined by the SegJoint. """ return self.__s1, self.__s2 def getMovingPoints(self): """Return the joined segment points used by the SegJoint. getMovingPoints() This method returns a tuple of two points, the first point is the used point on the SegJoint initial segment, and the second point is the used point on the SegJoint secondary segment. """ return self.__s1_float, self.__s2_float def getFixedPoints(self): """Return the joined segment points not used by the SegJoint. getFixedPoints() This method returns a tuple of two points, the first point is the unused point on the SegJoint initial segment, and the second point is the unused point on the SegJoint secondary segment. """ return self.__s1_fixed, self.__s2_fixed def update(self): """Revalidate the SegJoint if it is modified. update() """ if self.isModified(): self.validate() self.reset() def getIntersection(self): """Return the intersection points of the SegJoint segments. getIntersection() This method returns a tuple of two floats; the first is the intersection 'x' coordinate, and the second is the 'y' coordinate. """ self.update() return self.__xi, self.__yi def inRegion(self, xmin, ymin, xmax, ymax, fully=False): """Return whether or not a segjoint exists with a region. isRegion(xmin, ymin, xmax, ymax) The four arguments define the boundary of an area, and the function returns True if the joint lies within that area. Otherwise, the function returns False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) _mp1, _mp2 = self.getMovingPoints() _mx1, _my1 = _mp1.getCoords() _mx2, _my2 = _mp2.getCoords() _fxmin = min(_mx1, _mx2) _fymin = min(_my1, _my2) _fxmax = max(_mx1, _mx2) _fymax = max(_my1, _my2) if ((_fxmax < _xmin) or (_fymax < _ymin) or (_fxmin > _xmax) or (_fymin > _ymax)): return False if fully: if ((_fxmin > _xmin) and (_fymin > _ymin) and (_fxmax < _xmax) and (_fymax < _ymax)): return True return False return util.in_region(_mx1, _my1, _mx2, _my2, _xmin, _ymin, _xmax, _ymax) def _moveSegment(self, s, *args): _alen = len(args) if _alen < 4: raise ValueError, "Invalid argument count: %d" % _alen _x1 = util.get_float(args[0]) _y1 = util.get_float(args[1]) _x2 = util.get_float(args[2]) _y2 = util.get_float(args[3]) # # would it be better to resize the joint or to remove it? # we pass for now ... # if s is self.__s1: pass elif s is self.__s2: pass else: raise ValueError, "Unexpected segment in moveSegment" + `s` def getValues(self): """Return values comprising the SegJoint. getValues() This method extends the GraphicObject::getValues() method. """ _data = super(SegJoint, self).getValues() return _data class Chamfer(SegJoint): """A Chamfer class A chamfer is a small distance taken off a sharp corner in a drawing. For the chamfer to be valid, the chamfer length must be less than the length of either segment, and the two segments must be extendable so they could share a common endpoint. A Chamfer is derived from a SegJoint, so it shares all the methods and attributes of that class. A Chamfer has the following additional methods: {set/get}Length(): Set/Get the Chamfer length. A Chamfer has the following attributes: length: The Chamfer length. """ __defstyle = None __messages = { 'length_changed' : True, 'moved' : True } def __init__(self, s1, s2, l, st=None, lt=None, col=None, t=None, **kw): super(Chamfer, self).__init__(s1, s2, st, lt, col, t, **kw) _len = util.get_float(l) if _len < 0.0: raise ValueError, "Invalid chamfer length: %g" % _len if _len > s1.length(): raise ValueError, "Chamfer is longer than first Segment." if _len > s2.length(): raise ValueError, "Chamfer is longer than second Segment." _xi, _yi = SegJoint.getIntersection(self) # print "xi: %g; yi: %g" % (_xi, _yi) _sp1, _sp2 = SegJoint.getMovingPoints(self) _xp, _yp = _sp1.getCoords() _sep = hypot((_yp - _yi), (_xp - _xi)) if _sep > (_len + 1e-10): # print "sep: %g" % _sep # print "xp: %g; yp: %g" % (_xp, _yp) raise ValueError, "First segment too far from intersection point." _xp, _yp = _sp2.getCoords() _sep = hypot((_yp - _yi), (_xp - _xi)) if _sep > (_len + 1e-10): # print "sep: %g" % _sep # print "xp: %g; yp: %g" % (_xp, _yp) raise ValueError, "Second segment too far from intersection point." self.__length = _len self.ignore('moved') try: self._moveSegmentPoints(_len) finally: self.receive('moved') def finish(self): self.__length = None super(Chamfer, self).finish() def __eq__(self, obj): if not isinstance(obj, Chamfer): return False if obj is self: return True _s1, _s2 = self.getSegments() _os1, _os2 = obj.getSegments() return (((_s1 == _os1 and _s2 == _os2) or (_s1 == _os2 and _s2 == _os1)) and abs(self.__length - obj.getLength()) < 1e-10) def __ne__(self, obj): if not isinstance(obj, Chamfer): return True if obj is self: return False _s1, _s2 = self.getSegments() _os1, _os2 = obj.getSegments() return (((_s1 != _os1 or _s2 == _os2) and (_s1 != _os2 or _s2 == _os1)) or abs(self.__length - obj.getLength()) > 1e-10) def getDefaultStyle(cls): if cls.__defstyle is None: _s = style.Style(u'Chamfer Default Style', linetype.Linetype(u'Solid', None), color.Color(0xffffff), 1.0) cls.__defstyle = _s return cls.__defstyle getDefaultStyle = classmethod(getDefaultStyle) def setDefaultStyle(cls, s): if not isinstance(s, style.Style): raise TypeError, "Invalid style: " + `type(s)` cls.__defstyle = s setDefaultStyle = classmethod(setDefaultStyle) def getValues(self): """Return values comprising the Chamfer. getValues() This method extends the SegJoint::getValues() method. """ _data = super(Chamfer, self).getValues() _data.setValue('type', 'chamfer') _s1, _s2 = self.getSegments() _data.setValue('s1', _s1.getID()) _data.setValue('s2', _s2.getID()) _data.setValue('length', self.__length) return _data def getLength(self): """Return the Chamfer length. getLength() """ return self.__length def setLength(self, l): """Set the Chamfer length. setLength(l) The length should be a positive float value. """ _s1, _s2 = self.getSegments() if (self.isLocked() or _s1.isLocked() or _s2.isLocked()): raise RuntimeError, "Setting length not allowed - object locked." _l = util.get_float(l) if _l < 0.0: raise ValueError, "Invalid chamfer length: %g" % _l if _l > _s1.length(): raise ValueError, "Chamfer is larger than first Segment." if _l > _s2.length(): raise ValueError, "Chamfer is larger than second Segment." _ol = self.__length if abs(_l - _ol) > 1e-10: self.startChange('length_changed') self.__length = _l self.endChange('length_changed') self.sendMessage('length_changed', _ol) self._moveSegmentPoints(_l) self.modified() length = property(getLength, setLength, None, "Chamfer length.") def _moveSegmentPoints(self, dist): """Set the Chamfer endpoints at the correct location moveSegmentPoints(dist) The argument 'dist' is the chamfer length. This method is private the the Chamfer object. """ _d = util.get_float(dist) # # process segment 1 # _xi, _yi = self.getIntersection() # print "xi: %g; yi: %g" % (xi, yi) _mp1, _mp2 = self.getMovingPoints() _sp1, _sp2 = self.getFixedPoints() _sx, _sy = _sp1.getCoords() _slen = hypot((_yi - _sy), (_xi - _sx)) # print "slen: %g" % slen _newlen = (_slen - _d)/_slen # print "newlen: %g" % _newlen _xs, _ys = _sp1.getCoords() _xm, _ym = _mp1.getCoords() _xn = _xs + _newlen * (_xi - _xs) _yn = _ys + _newlen * (_yi - _ys) # print "xn: %g; yn: %g" % (_xn, _yn) _mp1.setCoords(_xn, _yn) # # process segment 2 # _sx, _sy = _sp2.getCoords() _slen = hypot((_yi - _sy), (_xi - _sx)) # print "slen: %g" % _slen _newlen = (_slen - _d)/_slen # print "newlen: %g" % _newlen _xs, _ys = _sp2.getCoords() _xm, _ym = _mp2.getCoords() _xn = _xs + _newlen * (_xi - _xs) _yn = _ys + _newlen * (_yi - _ys) # print "xn: %g; yn: %g" % (_xn, _yn) _mp2.setCoords(_xn, _yn) def clone(self): _s1, _s2 = self.getSegments() _l = self.__length _s = self.getStyle() _ch = Chamfer(_s1, _s2, _l, _s) _ch.setColor(self.getColor()) _ch.setLinetype(self.getLinetype()) _ch.setThickness(self.getThickness()) return _ch def sendsMessage(self, m): if m in Chamfer.__messages: return True return super(Chamfer, self).sendsMessage(m) # # Chamfer history class # class ChamferLog(graphicobject.GraphicObjectLog): def __init__(self, c): if not isinstance(c, Chamfer): raise TypeError, "Invalid chamfer: " + `type(c)` super(ChamferLog, self).__init__(c) c.connect('length_changed', self._lengthChange) def _lengthChange(self, c, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _l = args[0] if not isinstance(_l, float): raise TypeError, "Unexpected type for length: " + `type(_l)` self.saveUndoData('length_changed', _l) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if _alen == 0: raise ValueError, "No arguments to execute()" _c = self.getObject() _op = args[0] if _op == 'length_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _l = args[1] if not isinstance(_l, float): raise TypeError, "Unexpected type for length: " + `type(_l)` _sdata = _c.getLength() self.ignore(_op) try: if undo: _c.startUndo() try: _c.setLength(_l) finally: _c.endUndo() else: _c.startRedo() try: _c.setLength(_l) finally: _c.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) else: super(ChamferLog, self).execute(undo, *args) class Fillet(SegJoint): """ A fillet is a curved joining of two segments. For a filleted joint to be valid, the radius must fall within some distance determined by the segment endpoints and segment intersection point, and the two segments must be extendable so they can share a common endpoint. A Fillet is derived from a SegJoint, so it shares the methods and attributes of that class. """ __defstyle = None __messages = {'radius_changed' : True,'moved' : True} def __init__(self, s1, s2, r, st=None, lt=None, col=None, t=None, **kw): super(Fillet, self).__init__(s1, s2, st, lt, col, t, **kw) _r = util.get_float(r) if _r < 0.0: raise ValueError, "Invalid fillet radius: %g" % _r self._calculateLimits() _rmin, _rmax = self.getRadialLimits() if _r < _rmin or _r > _rmax: raise ValueError, "Invalid radius: %g" % _r self.__radius = _r self.__center = (0.0, 0.0) self._calculateCenter() self.ignore('moved') try: self._moveSegmentPoints() finally: self.receive('moved') def finish(self): self.__radius = self.__center = None super(Fillet, self).finish() def __eq__(self, obj): if not isinstance(obj, Fillet): return False if obj is self: return True _s1, _s2 = self.getSegments() _os1, _os2 = obj.getSegments() return (((_s1 == _os1 and _s2 == _os2) or (_s1 == _os2 and _s2 == _os1)) and abs(self.__radius - obj.getRadius()) < 1e-10) def __ne__(self, obj): if not isinstance(obj, Fillet): return True if obj is self: return False _s1, _s2 = self.getSegments() _os1, _os2 = obj.getSegments() return (((_s1 != _os1 or _s2 != _os2) and (_s1 != _os2 or _s2 != _os1)) or abs(self.__radius - obj.getRadius()) > 1e-10) def getDefaultStyle(cls): if cls.__defstyle is None: _s = style.Style(u'Fillet Default Style', linetype.Linetype(u'Solid', None), color.Color(0xffffff), 1.0) cls.__defstyle = _s return cls.__defstyle getDefaultStyle = classmethod(getDefaultStyle) def setDefaultStyle(cls, s): if not isinstance(s, style.Style): raise TypeError, "Invalid style: " + `type(s)` cls.__defstyle = s setDefaultStyle = classmethod(setDefaultStyle) def getValues(self): """Return values comprising the Fillet. getValues() This method extends the SegJoint::getValues() method. """ _data = super(Fillet, self).getValues() _data.setValue('type', 'fillet') _s1, _s2 = self.getSegments() _data.setValue('s1', _s1.getID()) _data.setValue('s2', _s2.getID()) _data.setValue('radius', self.__radius) return _data def getRadius(self): """Return the Fillet radius. getRadius() """ return self.__radius def setRadius(self, r): """Set the Fillet radius. setRadius(r) The radius should be a positive float value. """ _s1, _s2 = self.getSegments() if (self.isLocked() or _s1.isLocked() or _s2.isLocked()): raise RuntimeError, "Setting length not allowed - object locked." _r = util.get_float(r) if _r < 0.0: raise ValueError, "Invalid fillet radius: %g" % _r self._calculateLimits() _rmin, _rmax = self.getRadialLimits() if _r < _rmin or _r > _rmax: raise ValueError, "Invalid radius: %g" % _r _or = self.__radius if abs(_r - _or) > 1e-10: self.startChange('radius_changed') self.__radius = _r self.endChange('radius_changed') self._calculateCenter() self._moveSegmentPoints() self.sendMessage('radius_changed', _or) self.modified() radius = property(getRadius, setRadius, None, "Chamfer radius.") def _calculateCenter(self): """Find the center point of the radius _calculateCenter() This method is private to the Fillet object. """ _r = self.__radius _p1, _p3 = self.getMovingPoints() _p2, _p4 = self.getFixedPoints() _as1 = atan2((_p2.y - _p1.y), (_p2.x - _p1.x)) # _as1 in radians _as2 = atan2((_p4.y - _p3.y), (_p4.x - _p3.x)) # _as2 in radians if abs(abs(_as1) - pi) < 1e-10: if _as1 > 0.0 and _as2 < 0.0: _as1 = -pi if _as1 < 0.0 and _as2 > 0.0: _as1 = pi if abs(abs(_as2) - pi) < 1e-10: if _as2 > 0.0 and _as2 < 0.0: _as2 = -pi if _as2 < 0.0 and _as1 > 0.0: _as2 = pi _acl = (_as1 + _as2)/2.0 _acc = abs(_as1 - _as2)/2.0 if (_as1 > 0.0 and _as2 < 0.0) or (_as1 < 0.0 and _as2 > 0.0): _amin = min(_as1, _as2) _amax = max(_as1, _as2) #print "_amax: %g" % _amax #print "_amin: %g" % _amin if _amax - _amin > pi: # radians if _acl < 0.0: _acl = _acl + pi else: _acl = _acl - pi _acc = ((pi - _amax) + (_amin + pi))/2.0 #print "_acl: %g" % (_acl * _dtr) #print "_acc: %g" % (_acc * _dtr) _rc = hypot((_r/tan(_acc)), _r) #print "_rc: %g" % _rc _xi, _yi = self.getIntersection() _xc = _xi + _rc * cos(_acl) _yc = _yi + _rc * sin(_acl) self.__center = (_xc, _yc) #print "center: %s" % str(self.__center) def getCenter(self): """Return the center location of the Fillet. getCenter() This method returns a tuple of two floats; the first is the center 'x' coordinate, the second is the 'y' coordinate. """ return self.__center def _calculateLimits(self): """Determine the radial limits of the fillet. _calculateLimits() This method is private to the Fillet. """ _p1, _p3 = self.getMovingPoints() _p2, _p4 = self.getFixedPoints() _as1 = atan2((_p2.y - _p1.y), (_p2.x - _p1.x)) # radians _as2 = atan2((_p4.y - _p3.y), (_p4.x - _p3.x)) # radians if abs(abs(_as1) - pi) < 1e-10: if _as1 > 0.0 and _as2 < 0.0: _as1 = -pi if _as1 < 0.0 and _as2 > 0.0: _as1 = pi if abs(abs(_as2) - pi) < 1e-10: if _as2 > 0.0 and _as2 < 0.0: _as2 = -pi if _as2 < 0.0 and _as1 > 0.0: _as2 = pi #print "_as1: %g" % (_as1 * _dtr) #print "_as2: %g" % (_as2 * _dtr) _acl = (_as1 + _as2)/2.0 _acc = abs(_as1 - _as2)/2.0 if (_as1 > 0.0 and _as2 < 0.0) or (_as1 < 0.0 and _as2 > 0.0): _amin = min(_as1, _as2) _amax = max(_as1, _as2) #print "_amax: %g" % _amax #print "_amin: %g" % _amin if _amax - _amin > pi: # radians if _acl < 0.0: _acl = _acl + pi else: _acl = _acl - pi _acc = ((pi - _amax) + (_amin + pi))/2.0 #print "_acl: %g" % (_acl * _dtr) #print "_acc: %g" % (_acc * _dtr) _xi, _yi = self.getIntersection() _pf1, _pf2 = self.getFixedPoints() _d1 = hypot((_xi - _pf1.x), (_yi - _pf1.y)) _d2 = hypot((_xi - _pf2.x), (_yi - _pf2.y)) _c4 = min(_d1, _d2) self.__rmax = _c4 * tan(_acc) + 1e-10 #print "rmax: %g" % self.__rmax _pm1, _pm2 = self.getMovingPoints() _d1 = hypot((_xi - _pm1.x), (_yi - _pm1.y)) _d2 = hypot((_xi - _pm2.x), (_yi - _pm2.y)) _c4 = max(_d1, _d2) self.__rmin = _c4 * tan(_acc) - 1e-10 #print "rmin: %g" % self.__rmin def getRadialLimits(self): """Return the radial limits of the fillet. getRadialLimits() This method returns a tuple of two floats; the first is the minimal radius for the fillet between two segments, and the second is the maximum radius. """ return self.__rmin, self.__rmax def _moveSegmentPoints(self): """Position the segment endpoints used in the Fillet. _moveSegmentPoints() This method is private to the Fillet. """ _p1, _p3 = self.getMovingPoints() _p2, _p4 = self.getFixedPoints() _xc, _yc = self.__center # # segment 1 # _l = _p2 - _p1 _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _r = ((_xc - _x1)*(_x2 - _x1) + (_yc - _y1)*(_y2 - _y1))/pow(_l, 2) _px = _x1 + _r * (_x2 - _x1) _py = _y1 + _r * (_y2 - _y1) _p1.setCoords(_px, _py) # # segment 2 # _l = _p4 - _p3 _x1, _y1 = _p3.getCoords() _x2, _y2 = _p4.getCoords() _r = ((_xc - _x1)*(_x2 - _x1) + (_yc - _y1)*(_y2 - _y1))/pow(_l, 2) _px = _x1 + _r * (_x2 - _x1) _py = _y1 + _r * (_y2 - _y1) _p3.setCoords(_px, _py) def getAngles(self): """Return the angles that the fillet sweeps through. getAngles() This method returns a tuple of two floats, the first is the start angle of the fillet, and the second is the end angle. """ _ms1, _ms2 = self.getMovingPoints() _xc, _yc = self.__center _x, _y = _ms1.getCoords() _as1 = _dtr * atan2((_y - _yc), (_x - _xc)) if _as1 < 0.0: _as1 = _as1 + 360.0 _x, _y = _ms2.getCoords() _as2 = _dtr * atan2((_y - _yc), (_x - _xc)) if _as2 < 0.0: _as2 = _as2 + 360.0 return _as1, _as2 def inRegion(self, xmin, ymin, xmax, ymax, fully=False): """Return whether or not a fillet exists with a region. isRegion(xmin, ymin, xmax, ymax) The four arguments define the boundary of an area, and the function returns True if the joint lies within that area. Otherwise, the function returns False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) _mp1, _mp2 = self.getMovingPoints() _mx1, _my1 = _mp1.getCoords() _mx2, _my2 = _mp2.getCoords() _r = self.__radius _xc, _yc = self.__center _a1, _a2 = self.getAngles() _xl = [_mx1, _mx2, _xc] _yl = [_my1, _my2, _yc] if fully: if ((min(_xl) > _xmin) and (min(_yl) > _ymin) and (max(_xl) < _xmax) and (max(_yl) < _ymax)): return True return False # # fixme - need to use the arc and endpoints and not # a line connecting the endpoints ... # return util.in_region(_mx1, _my1, _mx2, _my2, _xmin, _ymin, _xmax, _ymax) def clone(self): _s1, _s2 = self.getSegments() _r = self.__radius _s = self.getStyle() _f = Fillet(_s1, _s2, _r, _s) _f.setColor(self.getColor()) _f.setLinetype(self.getLinetype()) _f.setThickness(self.getThickness()) return _f def sendsMessage(self, m): if m in Fillet.__messages: return True return super(Fillet, self).sendsMessage(m) # # Fillet history class # class FilletLog(graphicobject.GraphicObjectLog): def __init__(self, f): if not isinstance(f, Fillet): raise TypeError, "Invalid fillet: " + `type(f)` super(FilletLog, self).__init__(f) f.connect('radius_changed', self._radiusChange) def _radiusChange(self, f, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _r = args[0] if not isinstance(_r, float): raise TypeError, "Unexpected type for radius: " + `type(_r)` self.saveUndoData('radius_changed', _r) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if _alen == 0: raise ValueError, "No arguments to execute()" _f = self.getObject() _op = args[0] if _op == 'radius_changed': if len(args) < 2: raise ValueError, "Invalid argument count: %d" % _alen _r = args[1] if not isinstance(_r, float): raise TypeError, "Unexpected type for radius: " + `type(_r)` _sdata = _f.getRadius() self.ignore(_op) try: if undo: _f.startUndo() try: _f.setRadius(_r) finally: _f.endUndo() else: _f.startRedo() try: _f.setRadius(_r) finally: _f.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) else: super(FilletLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/cline.py0000644000175000017500000007571211307666732020011 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # a construction line defined by two points # from __future__ import generators import math from PythonCAD.Generic import conobject from PythonCAD.Generic import tolerance from PythonCAD.Generic import point from PythonCAD.Generic import quadtree from PythonCAD.Generic import util class CLine(conobject.ConstructionObject): """A class for construction lines defined by two distinct Points. A CLine object is derived from the conobject class, so it shares the functionality of that class. In addition, a CLine instance has two attributes: p1: A Point object representing the first keypoint p2: A Point object representing the second keypoint A CLine has the following methods: getKeypoints(): Return the two points the CLine is defined by. {get/set}P1: Get/Set the first keypoint of the CLine. {get/set}P2: Get/Set the second keypoint of the CLine. move(): Move a CLine mapCoords(): Return the nearest point on a CLine to a coordinate pair. inRegion(): Return whether the CLine passes through a bounded region. clone(): Return an identical copy of a CLine. """ __messages = { 'moved' : True, 'keypoint_changed' : True } def __init__(self, p1, p2, **kw): """Initialize a CLine object. CLine(p1, p2) Both arguments are Point objects that the CLine passes through. """ _p1 = p1 if not isinstance(_p1, point.Point): _p1 = point.Point(p1) _p2 = p2 if not isinstance(_p2, point.Point): _p2 = point.Point(p2) if _p1 is _p2: raise ValueError, "A CLine must have two different keypoints." super(CLine, self).__init__(**kw) self.__p1 = _p1 _p1.storeUser(self) _p1.connect('moved', self.__movePoint) _p1.connect('change_pending', self.__pointChangePending) _p1.connect('change_complete', self.__pointChangeComplete) self.__p2 = _p2 _p2.storeUser(self) _p2.connect('moved', self.__movePoint) _p2.connect('change_pending', self.__pointChangePending) _p2.connect('change_complete', self.__pointChangeComplete) def __eq__(self, obj): """Compare one CLine to another for equality. """ if not isinstance(obj, CLine): return False if obj is self: return True _sp1, _sp2 = self.getKeypoints() _op1, _op2 = obj.getKeypoints() _sv = abs(_sp1.x - _sp2.x) < 1e-10 _sh = abs(_sp1.y - _sp2.y) < 1e-10 _ov = abs(_op1.x - _op2.x) < 1e-10 _oh = abs(_op1.y - _op2.y) < 1e-10 _val = False if _sv and _ov: # both vertical if abs(_sp1.x - _op1.x) < 1e-10: _val = True elif _sh and _oh: # both horizontal if abs(_sp1.y - _op1.y) < 1e-10: _val = True else: if (not (_sv or _sh)) and (not (_ov or _oh)): _sx1, _sy1 = _sp1.getCoords() _sx2, _sy2 = _sp2.getCoords() _ox1, _oy1 = _op1.getCoords() _ox2, _oy2 = _op2.getCoords() _ms = (_sy2 - _sy1)/(_sx2 - _sx1) _bs = _sy1 - (_ms * _sx1) _ty = (_ms * _ox1) + _bs if abs(_ty - _oy1) < 1e-10: _ty = (_ms * _ox2) + _bs if abs(_ty - _oy2) < 1e-10: _val = True return _val def __ne__(self, obj): """Compare one CLine to another for inequality. """ if not isinstance(obj, CLine): return True if obj is self: return False _sp1, _sp2 = self.getKeypoints() _op1, _op2 = obj.getKeypoints() _sv = abs(_sp1.x - _sp2.x) < 1e-10 _sh = abs(_sp1.y - _sp2.y) < 1e-10 _ov = abs(_op1.x - _op2.x) < 1e-10 _oh = abs(_op1.y - _op2.y) < 1e-10 _val = True if _sv and _ov: # both vertical if abs(_sp1.x - _op1.x) < 1e-10: _val = False elif _sh and _oh: # both horizontal if abs(_sp1.y - _op1.y) < 1e-10: _val = False else: if (not (_sv or _sh)) and (not (_ov or _oh)): _sx1, _sy1 = _sp1.getCoords() _sx2, _sy2 = _sp2.getCoords() _ox1, _oy1 = _op1.getCoords() _ox2, _oy2 = _op2.getCoords() _ms = (_sy2 - _sy1)/(_sx2 - _sx1) _bs = _sy1 - (_ms * _sx1) _ty = (_ms * _ox1) + _bs if abs(_ty - _oy1) < 1e-10: _ty = (_ms * _ox2) + _bs if abs(_ty - _oy2) < 1e-10: _val = False return _val def __str__(self): return "Construction Line through %s and %s" % (self.__p1, self.__p2) def finish(self): self.__p1.disconnect(self) self.__p1.freeUser(self) self.__p2.disconnect(self) self.__p2.freeUser(self) self.__p1 = self.__p2 = None super(CLine, self).finish() def getValues(self): _data = super(CLine, self).getValues() _data.setValue('type', 'cline') _data.setValue('p1', self.__p1.getID()) _data.setValue('p2', self.__p2.getID()) return _data def getKeypoints(self): """Return the two keypoints of this CLine. getKeypoints() """ return self.__p1, self.__p2 def getP1(self): """Return the first keypoint Point of the CLine. getP1() """ return self.__p1 def setP1(self, p): """Set the first keypoint Point of the CLine. setP1(p) Argument 'p' must be a Point. """ if self.isLocked(): raise RuntimeError, "Setting keypoint not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid keypoint: " + `type(p)` if p is self.__p2 or p == self.__p2: raise ValueError, "CLines must have two different keypoints." _kp = self.__p1 if _kp is not p: _kp.disconnect(self) _kp.freeUser(self) self.startChange('keypoint_changed') self.__p1 = p self.endChange('keypoint_changed') self.sendMessage('keypoint_changed', _kp, p) p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) if abs(_kp.x - p.x) > 1e-10 or abs(_kp.y - p.y) > 1e-10: _x, _y = self.__p2.getCoords() self.sendMessage('moved', _kp.x, _kp.y, _x, _y) self.modified() p1 = property(getP1, setP1, None, "First keypoint of the CLine.") def getP2(self): """Return the second keypoint Point of the CLine. getP2() """ return self.__p2 def setP2(self, p): """Set the second keypoint Point of the CLine. setP2(p) Argument 'p' must be a Point. """ if self.isLocked(): raise RuntimeError, "Setting keypoint not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid keypoint: " + `type(p)` if p is self.__p1 or p == self.__p1: raise ValueError, "CLines must have two different keypoints." _kp = self.__p2 if _kp is not p: _kp.disconnect(self) _kp.freeUser(self) self.startChange('keypoint_changed') self.__p2 = p self.endChange('keypoint_changed') self.sendMessage('keypoint_changed', _kp, p) p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) if abs(_kp.x - p.x) > 1e-10 or abs(_kp.y - p.y) > 1e-10: _x, _y = self.__p1.getCoords() self.sendMessage('moved', _x, _y, _kp.x, _kp.y) self.modified() p2 = property(getP2, setP2, None, "Second keypoint of the CLine.") def move(self, dx, dy): """Move a CLine. move(dx, dy) The first argument gives the x-coordinate displacement, and the second gives the y-coordinate displacement. Both values should be floats. """ if self.isLocked() or self.__p1.isLocked() or self.__p2.isLocked(): raise RuntimeError, "Moving CLine not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() self.ignore('moved') try: self.__p1.move(_dx, _dy) self.__p2.move(_dx, _dy) finally: self.receive('moved') self.sendMessage('moved', _x1, _y1, _x2, _y2) def mapCoords(self, x, y, tol=tolerance.TOL): """Return the nearest Point on the CLine to a coordinate pair. mapCoords(x, y[, tol]) The function has two required arguments: x: A Float value giving the 'x' coordinate y: A Float value giving the 'y' coordinate There is a single optional argument: tol: A float value equal or greater than 0.0 This function is used to map a possibly near-by coordinate pair to a actual Point on the CLine. If the distance between the actual Point and the coordinates used as an argument is less than the tolerance, the actual Point is returned. Otherwise, this function returns None. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() _sqlen = pow((_x2 - _x1), 2) + pow((_y2 - _y1), 2) if _sqlen < 1e-10: # both points the same raise RuntimeError, "CLine points coincident." _r = ((_x - _x1)*(_x2 - _x1) + (_y - _y1)*(_y2 - _y1))/_sqlen _px = _x1 + _r * (_x2 - _x1) _py = _y1 + _r * (_y2 - _y1) if abs(_px - _x) < _t and abs(_py - _y) < _t: return _px, _py return None def getProjection(self, x, y): """Find the projection point of some coordinates on the CLine. getProjection(x, y) Arguments 'x' and 'y' should be float values. """ _x = util.get_float(x) _y = util.get_float(y) _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() _sqlen = pow((_x2 - _x1), 2) + pow((_y2 - _y1), 2) _rn = ((_x - _x1) * (_x2 - _x1)) + ((_y - _y1) * (_y2 - _y1)) _r = _rn/_sqlen _px = _x1 + _r * (_x2 - _x1) _py = _y1 + _r * (_y2 - _y1) return _px, _py def inRegion(self, xmin, ymin, xmax, ymax, fully=False): """Return whether or not a CLine passes through a region. isRegion(xmin, ymin, xmax, ymax) The four arguments define the boundary of an area, and the function returns True if the CLine passes within the area. Otherwise, the function returns False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) if fully: return False _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() _xdiff = _x2 - _x1 _ydiff = _y2 - _y1 _val = False if _xmin < _x1 < _xmax and _ymin < _y1 < _ymax: _val = True elif _xmin < _x2 < _xmax and _ymin < _y2 < _ymax: _val = True elif abs(_xdiff) < 1e-10: # vertical line if _xmin < _x1 < _xmax: _val = True elif abs(_ydiff) < 1e-10: # horizontal line if _ymin < _y1 < _ymax: _val = True else: _slope = _ydiff/_xdiff _yint = _y1 - _slope*_x1 if _ymin < (_slope*_xmin + _yint) < _ymax: # hits left side _val = True elif _ymin < (_slope*_xmax + _yint) < _ymax: # hits right side _val = True else: # hits bottom - no need to check top ... _xymin = (_ymin - _yint)/_slope if _xmin < _xymin < _xmax: _val = True return _val def __pointChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.startChange('moved') def __pointChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.endChange('moved') def __movePoint(self, p, *args): _plen = len(args) if _plen < 2: raise ValueError, "Invalid argument count: %d" % _plen _x = util.get_float(args[0]) _y = util.get_float(args[1]) _p1 = self.__p1 _p2 = self.__p2 if p is _p1: _x1 = _x _y1 = _y _x2, _y2 = _p2.getCoords() if abs(_p1.x - _x2) < 1e-10 and abs(_p1.y - _y2) < 1e-10: raise RuntimeError, "CLine points coincident." elif p is _p2: _x1, y1 = _p1.getCoords() _x2 = _x _y2 = _y if abs(_p2.x - _x1) < 1e-10 and abs(_p2.y - _y1) < 1e-10: raise RuntimeError, "CLine points coincident." else: raise ValueError, "Unexpected CLine keypoint: " + `p` self.sendMessage('moved', _x1, _y1, _x2, _y2) def clone(self): """Create an identical copy of a CLine. clone() """ _cp1 = self.__p1.clone() _cp2 = self.__p2.clone() return CLine(_cp1, _cp2) def clipToRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _p1, _p2 = self.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _coords = None if abs(_x2 - _x1) < 1e-10: # vertical if _xmin < _x1 < _xmax: _coords = (_x1, _ymin, _x1, _ymax) elif abs(_y2 - _y1) < 1e-10: # horiztonal if _ymin < _y1 < _ymax: _coords = (_xmin, _y1, _xmax, _y1) else: # # the CLine can be parameterized as # # x = u * (x2 - x1) + x1 # y = u * (y2 - y1) + y1 # # for u = 0, x => x1, y => y1 # for u = 1, x => x2, y => y2 # # The following is the Liang-Barsky Algorithm # for segment clipping modified slightly for # construction lines # _dx = _x2 - _x1 _dy = _y2 - _y1 # print "dx: %g; dy: %g" % (_dx, _dy) _P = [-_dx, _dx, -_dy, _dy] _q = [(_x1 - _xmin), (_xmax - _x1), (_y1 - _ymin), (_ymax - _y1)] _u1 = None _u2 = None _valid = True for _i in range(4): # print "i: %d" % _i _pi = _P[_i] _qi = _q[_i] # print "p[i]: %g; q[i]: %g" % (_pi, _qi) if abs(_pi) < 1e-10: # this should be caught earlier ... if _qi < 0.0: _valid = False break else: _r = _qi/_pi # print "r: %g" % _r if _pi < 0.0: # print "testing u1 ..." if _u2 is not None and _r > _u2: # print "r > u2 (%g)" % _u2 _valid = False break if _u1 is None or _r > _u1: # print "setting u1 = r" _u1 = _r else: # print "testing u2 ..." if _u1 is not None and _r < _u1: # print "r < u1 (%g)" % _u1 _valid = False break if _u2 is None or _r < _u2: # print "setting u2 = r" _u2 = _r if _valid: _coords = (((_u1 * _dx) + _x1), ((_u1 * _dy) + _y1), ((_u2 * _dx) + _x1), ((_u2 * _dy) + _y1)) return _coords def sendsMessage(self, m): if m in CLine.__messages: return True return super(CLine, self).sendsMessage(m) def getMiddlePoint(self): _x = (self.__p1.getx() + self.__p2.getx()) / 2 _y = (self.__p1.gety() + self.__p2.gety()) / 2 _point = point.Point(_x, _y) return _point def intersect_region(cl, xmin, ymin, xmax, ymax): if not isinstance(cl, CLine): raise TypeError, "Invalid CLine: " + `type(cl)` _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _p1, _p2 = cl.getKeypoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _x1 = _y1 = _x2 = _y2 = None if abs(_p2x - _p1x) < 1e-10: # vertical if _xmin < _p1x < _xmax: _x1 = _p1x _y1 = _ymin _x2 = _p1x _y2 = _ymax elif abs(_p2y - _p1y) < 1e-10: # horiztonal if _ymin < _p1y < _ymax: _x1 = _xmin _y1 = _p1y _x2 = _xmax _y2 = _p1y else: _slope = (_p2y - _p1y)/(_p2x - _p1x) _yint = _p1y - (_p1x * _slope) # # find y for x = xmin # _yt = (_slope * _xmin) + _yint if _ymin < _yt < _ymax: # print "hit at y for x=xmin" _x1 = _xmin _y1 = _yt # # find y for x = xmax # _yt = (_slope * _xmax) + _yint if _ymin < _yt < _ymax: # print "hit at y for x=xmax" if _x1 is None: _x1 = _xmax _y1 = _yt else: _x2 = _xmax _y2 = _yt if _x2 is None: # # find x for y = ymin # _xt = (_ymin - _yint)/_slope if _xmin < _xt < _xmax: # print "hit at x for y=ymin" if _x1 is None: _x1 = _xt _y1 = _ymin else: _x2 = _xt _y2 = _ymin if _x2 is None: # # find x for y = ymax # _xt = (_ymax - _yint)/_slope if _xmin < _xt < _xmax: # print "hit at x for y=ymax" if _x1 is None: _x1 = _xt _y1 = _ymax else: _x2 = _xt _y2 = _ymax return _x1, _y1, _x2, _y2 # # Quadtree CLine storage # class CLineQuadtree(quadtree.Quadtree): def __init__(self): super(CLineQuadtree, self).__init__() def getNodes(self, *args): _alen = len(args) if _alen != 4: raise ValueError, "Expected 4 arguments, got %d" % _alen _x1 = util.get_float(args[0]) _y1 = util.get_float(args[1]) _x2 = util.get_float(args[2]) _y2 = util.get_float(args[3]) _h = abs(_y2 - _y1) < 1e-10 _v = abs(_x2 - _x1) < 1e-10 if _h and _v: # both coords are identical raise ValueError, "CLine singularity - identical coords." _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if _node.hasSubnodes(): _xmid = (_xmin + _xmax)/2.0 _ymid = (_ymin + _ymax)/2.0 _ne = _nw = _sw = _se = False if _v: if _x1 < _xmin or _x1 > _xmax: continue if _x1 < _xmid: # cline on left _sw = _nw = True else: _se = _ne = True elif _h: if _y1 < _ymin or _y1 > _ymax: continue if _y1 < _ymid: # cline below _sw = _se = True else: _nw = _ne = True else: _ne = _nw = _sw = _se = True if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: yield _node def addObject(self, obj): if not isinstance(obj, CLine): raise TypeError, "Invalid CLine: " + `type(obj)` if obj in self: return _p1, _p2 = obj.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _bounds = self.getTreeRoot().getBoundary() _xmin = _ymin = _xmax = _ymax = None _sxmin = min(_x1, _x2) _sxmax = max(_x1, _x2) _symin = min(_y1, _y2) _symax = max(_y1, _y2) _resize = False if _bounds is None: # first node in tree _resize = True _xmin = _sxmin - 1.0 _ymin = _symin - 1.0 _xmax = _sxmax + 1.0 _ymax = _symax + 1.0 else: _xmin, _ymin, _xmax, _ymax = _bounds if _sxmin < _xmin: _xmin = _sxmin - 1.0 _resize = True if _sxmax > _xmax: _xmax = _sxmax + 1.0 _resize = True if _symin < _ymin: _ymin = _symin - 1.0 _resize = True if _symax > _ymax: _ymax = _symax + 1.0 _resize = True if _resize: self.resize(_xmin, _ymin, _xmax, _ymax) for _node in self.getNodes(_x1, _y1, _x2, _y2): _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if obj.inRegion(_xmin, _ymin, _xmax, _ymax): _node.addObject(obj) super(CLineQuadtree, self).addObject(obj) obj.connect('moved', self._moveCLine) def delObject(self, obj): if obj not in self: return _p1, _p2 = obj.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _pdict = {} for _node in self.getNodes(_x1, _y1, _x2, _y2): _node.delObject(obj) # cline may not be in the node ... _parent = _node.getParent() if _parent is not None: _pid = id(_parent) if _pid not in _pdict: _pdict[_pid] = _parent super(CLineQuadtree, self).delObject(obj) obj.disconnect(self) for _parent in _pdict.values(): self.purgeSubnodes(_parent) def find(self, *args): _alen = len(args) if _alen < 4: raise ValueError, "Invalid argument count: %d" % _alen _x1 = util.get_float(args[0]) _y1 = util.get_float(args[1]) _x2 = util.get_float(args[2]) _y2 = util.get_float(args[3]) _t = tolerance.TOL if _alen > 4: _t = tolerance.toltest(args[4]) _xmin = min(_x1, _x2) - _t _ymin = min(_y1, _y2) - _t _xmax = max(_x1, _x2) + _t _ymax = max(_y1, _y2) + _t _clines = [] for _cline in self.getInRegion(_xmin, _ymin, _xmax, _ymax): _p1, _p2 = _cline.getKeypoints() if ((abs(_p1.x - _x1) < _t) and (abs(_p1.y - _y1) < _t) and (abs(_p2.x - _x2) < _t) and (abs(_p2.y - _y2) < _t)): _clines.append(_cline) elif ((abs(_p1.x - _x2) < _t) and (abs(_p1.y - _y2) < _t) and (abs(_p2.x - _x1) < _t) and (abs(_p2.y - _y1) < _t)): _clines.append(_cline) else: pass return _clines def _moveCLine(self, obj, *args): if obj not in self: raise ValueError, "CLine not stored in Quadtree: " + `obj` _alen = len(args) if _alen < 4: raise ValueError, "Invalid argument count: %d" % _alen _x1 = util.get_float(args[0]) _y1 = util.get_float(args[1]) _x2 = util.get_float(args[2]) _y2 = util.get_float(args[3]) for _node in self.getNodes(_x1, _y1, _x2, _y2): _node.delObject(obj) # cline may not be in node ... super(CLineQuadtree, self).delObject(obj) obj.disconnect(self) self.addObject(obj) def getClosest(self, x, y, tol=tolerance.TOL): _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _cline = _tsep = None _cdict = {} _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) else: for _c in _node.getObjects(): _cid = id(_c) if _cid not in _cdict: _cx, _cy = _c.getProjection(_x, _y) if abs(_cx - _x) < _t and abs(_cy - _y) < _t: _sep = math.hypot((_cx - _x), (_cy - _y)) if _tsep is None: _tsep = _sep _cline = _c else: if _sep < _tsep: _tsep = _sep _cline = _c return _cline def getInRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _clines = [] if not len(self): return _clines _nodes = [self.getTreeRoot()] _cdict = {} while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): for _subnode in _node.getSubnodes(): _nodes.append(_subnode) else: for _cline in _node.getObjects(): _cid = id(_cline) if _cid not in _cdict: if _cline.inRegion(_xmin, _ymin, _xmax, _ymax): _clines.append(_cline) _cdict[_cid] = True return _clines # # CLine history class # class CLineLog(conobject.ConstructionObjectLog): def __init__(self, c): if not isinstance(c, CLine): raise TypeError, "Invalid CLine: " + `type(c)` super(CLineLog, self).__init__(c) c.connect('keypoint_changed', self._keypointChange) def _keypointChange(self, c, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _old = args[0] if not isinstance(_old, point.Point): raise TypeError, "Invalid old keypoint: " + `type(_old)` _new = args[1] if not isinstance(_new, point.Point): raise TypeError, "Invalid new keypoint: " + `type(_new)` self.saveUndoData('keypoint_changed', _old.getID(), _new.getID()) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if len(args) == 0: raise ValueError, "No arguments to execute()" _c = self.getObject() _p1, _p2 = _c.getKeypoints() _op = args[0] if _op == 'keypoint_changed': if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _oid = args[1] _nid = args[2] _parent = _c.getParent() if _parent is None: raise ValueError, "CLine has no parent - cannot undo" self.ignore(_op) try: if undo: _pt = _parent.getObject(_oid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "Old keypoint missing: id=%d" % _oid _c.startUndo() try: if _p1.getID() == _nid: _c.setP1(_pt) elif _p2.getID() == _nid: _c.setP2(_pt) else: raise ValueError, "Unexpected keypoint ID: %d" % _nid finally: _c.endUndo() else: _pt = _parent.getObject(_nid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "New keypoint missing: id=%d" % _nid _c.startRedo() try: if _p1.getID() == _oid: _c.setP1(_pt) elif _p2.getID() == _oid: _c.setP2(_pt) else: raise ValueError, "Unexpected keypoint ID: %d" % _oid finally: _c.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _oid, _nid) else: super(CLineLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/fileio.py0000644000175000017500000002467211307666657020173 0ustar matteomatteo# # Copyright (c) 2002, 2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # handle possibly compressed files # import time import struct import zlib import sys import os class CompFile(file): """A class for transparently handling compressed files. The CompFile class is a wrapper around the file object. It is similar to Python's GzipFile class in gzip.py, but the implementation takes advantage of features found in Python 2.2. A CompFile object has the attributes and methods of a file object, except a CompFile object cannot truncate a compressed file. It may be possible to add zipfile reading/writing capabilities to the CompFile class in the future. """ def __init__(self, filename, mode="r", buffering=0, truename=None): if sys.platform == 'win32' and 'b' not in mode: mode += 'b' super(CompFile, self).__init__(filename, mode, buffering) self.__size = 0 self.__crc = zlib.crc32('') self.__compobj = None self.__offset = 0L self.__buffer = '' if mode == "r" or mode == "rb": magic = super(CompFile, self).read(2) if magic == '\037\213': # gzip/zlib file method = ord(super(CompFile, self).read(1)) if method != 8: raise IOError, "Unknown compression method" flags = ord(super(CompFile, self).read(1)) data = super(CompFile, self).read(6) # skip mod time, extra flags, os if flags & 2: # file has FHCRC self.__compobj = zlib.decompressobj() else: self.__compobj = zlib.decompressobj(-zlib.MAX_WBITS) if flags & 4: # FEXTRA xlen = ord(super(CompFile, self).read(1)) xlen = xlen + 256*ord(super(CompFile, self).read(1)) data = super(CompFile, self).read(xlen) if flags & 8: # FNAME while 1: data = super(CompFile, self).read(1) if not data or data == '\000': break if flags & 16: # FCOMMENT while 1: data = super(CompFile, self).read(1) if not data or data == '\000': break else: super(CompFile, self).seek(0, 0) elif mode == "w" or mode == "wb": # # the following generates files that aren't # compatible with current gzip ... # # self.__compobj = zlib.compressobj() # # create a gzip-compatible compressobj ... self.__compobj = zlib.compressobj(6, zlib.DEFLATED, -zlib.MAX_WBITS, zlib.DEF_MEM_LEVEL, 0) super(CompFile, self).write('\037\213\010') super(CompFile, self).write(chr(8)) # flags FNAME - no FHCRC for gzip compat. super(CompFile, self).write(struct.pack(" size: break buf = super(CompFile, self).read(size) self.__offset = len(self.__buffer) if self.__offset > size: data = self.__buffer[:size] self.__buffer = self.__buffer[size:] else: data = self.__buffer[:] self.__buffer = '' return data def readline(self, size=-1): if size > 0: data = self.read(size) elif self.__compobj is None: data = super(CompFile, self).readline(size) elif self.__buffer.find("\n") != -1: idx = self.__buffer.find("\n") + 1 data = self.__buffer[:idx] self.__buffer = self.__buffer[idx:] else: buf = self.read(100) offset = buf.find("\n") while offset < 0: new_buf = self.read(100) if new_buf == '': # EOF break buf = buf + new_buf offset = buf.find("\n") if offset != -1: offset = offset + 1 # add in the newline character data = buf[:offset] self.__buffer = buf[offset:] + self.__buffer else: data = buf[:] self.__buffer = '' return data def readlines(self, size=0): if size <= 0: size = sys.maxint lines = [] while size > 0: line = self.readline() if line == '': break lines.append(line) size = size - len(line) return lines def write(self, data): if len(data): self.__crc = zlib.crc32(data, self.__crc) self.__size = self.__size + len(data) super(CompFile, self).write(self.__compobj.compress(data)) def writelines(self, lines): for line in lines: self.write(line) def flush(self): if self.__compobj is not None: super(CompFile, self).write(self.__compobj.flush()) super(CompFile, self).flush() def close(self): mode = self.mode if mode == "w" or mode == "wb": super(CompFile, self).write(self.__compobj.flush()) super(CompFile, self).write(struct.pack(" 0: data = self.read(offset) elif whence == 1: # current position if offset < 0: self.seek(0,0) new_offset = self.__offset + offset if new_offset > 0: self.read(new_offset) elif offset > 0: self.read(offset) elif whence == 2: # from end buf = '' self.seek(0,0) data = self.read(4096) while data != '': buf = buf + data if len(buf) > offset: idx = 1 - offset buf = buf[-idx:] data = self.read(4096) if len(buf) > offset: self.__buffer = buf[offset:] else: raise ValueError, "Offset %d larger than filesize" % offset else: raise ValueError, "Invalid seek position: %d" % whence else: raise IOError, "Unable to seek on writing." def truncate(self, size=None): if self.__compobj is not None: raise StandardError, "Cannot truncate compressed files." if size is None: size = super(CompFile, self).tell() super(CompFile, self).truncate(size) PythonCAD-DS1-R37/PythonCAD/Generic/vcline.py0000644000175000017500000003766111307666732020200 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # vertical construction lines # from __future__ import generators from PythonCAD.Generic import conobject from PythonCAD.Generic import tolerance from PythonCAD.Generic import point from PythonCAD.Generic import quadtree from PythonCAD.Generic import util class VCLine(conobject.ConstructionObject): """A base class for horizontal construction lines. """ __messages = { 'moved' : True, 'keypoint_changed' : True } def __init__(self, p, **kw): """Instantiate an VCLine object. VCLine(p) """ _p = p if not isinstance(p, point.Point): _p = point.Point(p) super(VCLine, self).__init__(**kw) self.__keypoint = _p _p.storeUser(self) _p.connect('moved', self.__movePoint) _p.connect('change_pending', self.__pointChangePending) _p.connect('change_complete', self.__pointChangeComplete) def __eq__(self, obj): """Compare one VCLine to another for equality. """ if not isinstance(obj, VCLine): return False if obj is self: return True if abs(self.getLocation().x - obj.getLocation().x) < 1e-10: return True return False def __ne__(self, obj): """Compare one VCLine to another for inequality. """ if not isinstance(obj, VCLine): return True if obj is self: return False if abs(self.getLocation().x - obj.getLocation().x) < 1e-10: return False return True def __str__(self): _x, _y = self.getLocation().getCoords() return "Vertical Construction Line at x = %g" % self.__keypoint.x def finish(self): self.__keypoint.disconnect(self) self.__keypoint.freeUser(self) self.__keypoint = None super(VCLine, self).finish() def getValues(self): _data = super(VCLine, self).getValues() _data.setValue('type', 'vcline') _data.setValue('keypoint', self.__keypoint.getID()) return _data def getLocation(self): return self.__keypoint def setLocation(self, p): if self.isLocked(): raise RuntimeError, "Setting keypoint not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid keypoint: " + `type(p)` _kp = self.__keypoint if p is not _kp: _x = _kp.x _kp.disconnect(self) _kp.freeUser(self) self.startChange('keypoint_changed') self.__keypoint = p self.endChange('keypoint_changed') self.sendMessage('keypoint_changed', _kp) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) p.storeUser(self) if abs(_x - p.x) > 1e-10: self.sendMessage('moved', _x, p.y) self.sendMessage('modified') def mapCoords(self, x, y, tol=tolerance.TOL): """Return the nearest Point on the VCLine to a coordinate pair. mapCoords(x, y[, tol]) The function has two required argument: x: A Float value giving the 'x' coordinate y: A Float value giving the 'y' coordinate There is a single optional argument: tol: A float value equal or greater than 0.0 This function is used to map a possibly near-by coordinate pair to an actual Point on the VCLine. If the distance between the actual Point and the coordinates used as an argument is less than the tolerance, the actual Point is returned. Otherwise, this function returns None. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _vx = self.__keypoint.x if abs(_vx - x) < _t: return _vx, _y return None def inRegion(self, xmin, ymin, xmax, ymax, fully=False): """Return whether or not an VCLine passes through a region. inRegion(xmin, ymin, xmax, ymax) The first four arguments define the boundary. The method will return True if the VCLine falls between xmin and xmax. Otherwise the function will return False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) if fully: return False _x = self.__keypoint.x return not (_x < _xmin or _x > _xmax) def move(self, dx, dy): """Move a VCLine move(dx, dy) The first argument gives the x-coordinate displacement, and the second gives the y-coordinate displacement. Both values should be floats. """ if self.isLocked() or self.__keypoint.isLocked(): raise RuntimeError, "Moving VCLine not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _x, _y = self.__keypoint.getCoords() self.ignore('moved') try: self.__keypoint.move(_dx, _dy) finally: self.receive('moved') self.sendMessage('moved', _x, _y) def __pointChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.startChange('moved') def __pointChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.endChange('moved') def __movePoint(self, p, *args): _plen = len(args) if _plen < 2: raise ValueError, "Invalid argument count: %d" % _plen _x = util.get_float(args[0]) _y = util.get_float(args[1]) if p is not self.__keypoint: raise ValueError, "Invalid point for VCLine::movePoint()" + `p` if abs(p.x - _x) > 1e-10: self.sendMessage('moved', _x, _y) def clipToRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _x = self.__keypoint.x if _xmin < _x < _xmax: return _x, _ymin, _x, _ymax return None def clone(self): """Create an identical copy of an VCLine. clone() """ return VCLine(self.__keypoint.clone()) def sendsMessage(self, m): if m in VCLine.__messages: return True return super(VCLine, self).sendsMessage(m) def getProjection(self,x,y): """ Get the projection of the point in to the line """ VCLinePoint=self.getLocation() x1,y1=VCLinePoint.getCoords() y1=y return x1,y1 def intersect_region(vcl, xmin, ymin, xmax, ymax): if not isinstance(vcl, VCLine): raise TypeError, "Invalid VCLine: " + `type(vcl)` _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _x, _y = vcl.getLocation().getCoords() _x1 = _y1 = _x2 = _y2 = None if _xmin < _x < _xmax: _x1 = _x _y1 = _ymin _x2 = _x _y2 = _ymax return _x1, _y1, _x2, _y2 # # Quadtree VCLine storage # class VCLineQuadtree(quadtree.Quadtree): def __init__(self): super(VCLineQuadtree, self).__init__() def getNodes(self, *args): _alen = len(args) if _alen != 1: raise ValueError, "Expected 1 arguments, got %d" % _alen _x = util.get_float(args[0]) _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _bounds = _node.getBoundary() _xmin = _bounds[0] _xmax = _bounds[2] if _x < _xmin or _x > _xmax: continue if _node.hasSubnodes(): _xmid = (_xmin + _xmax)/2.0 _ne = _nw = _sw = _se = True if _x < _xmid: # vcline to left _ne = _se = False if _x > _xmid: # vcline to right _nw = _sw = False if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: yield _node def addObject(self, obj): if not isinstance(obj, VCLine): raise TypeError, "Invalid VCLine object: " + `type(obj)` if obj in self: return _x, _y = obj.getLocation().getCoords() _bounds = self.getTreeRoot().getBoundary() _xmin = _ymin = _xmax = _ymax = None _resize = False if _bounds is None: # first node in tree _resize = True _xmin = _x - 1.0 _ymin = _y - 1.0 _xmax = _x + 1.0 _ymax = _y + 1.0 else: _xmin, _ymin, _xmax, _ymax = _bounds if _x < _xmin: _xmin = _x - 1.0 _resize = True if _x > _xmax: _xmax = _x + 1.0 _resize = True if _y < _ymin: _ymin = _y - 1.0 _resize = True if _y > _ymax: _ymax = _y + 1.0 _resize = True if _resize: self.resize(_xmin, _ymin, _xmax, _ymax) for _node in self.getNodes(_x): _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if obj.inRegion(_xmin, _ymin, _xmax, _ymax): _node.addObject(obj) super(VCLineQuadtree, self).addObject(obj) obj.connect('moved', self._moveVCLine) def delObject(self, obj): if obj not in self: return _pdict = {} _x, _y = obj.getLocation().getCoords() for _node in self.getNodes(_x): _node.delObject(obj) _parent = _node.getParent() if _parent is not None: _pid = id(_parent) if _pid not in _pdict: _pdict[_pid] = _parent super(VCLineQuadtree, self).delObject(obj) obj.disconnect(self) for _parent in _pdict.values(): self.purgeSubnodes(_parent) def find(self, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _t = tolerance.TOL if _alen > 1: _t = tolerance.toltest(args[1]) _xmin = _x - _t _xmax = _x + _t return self.getInRegion(_xmin, 0, _xmax, 1) # y values arbitrary def _moveVCLine(self, obj, *args): if obj not in self: raise ValueError, "VCLine not stored in Quadtree: " + `obj` _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) for _node in self.getNodes(_x): _node.delObject(obj) # vcline may not be in node super(VCLineQuadtree, self).delObject(obj) obj.disconnect(self) self.addObject(obj) def getClosest(self, x, y, tol=tolerance.TOL): return self.find(x, tol) def getInRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _vcls = [] if not len(self): return _vcls _nodes = [self.getTreeRoot()] _vdict = {} while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): for _subnode in _node.getSubnodes(): _bounds = _subnode.getBoundary() _bmin = _bounds[0] _bmax = _bounds[2] if ((_bmin > _xmax) or (_bmax < _xmin)): continue _nodes.append(_subnode) else: for _vcl in _node.getObjects(): _vid = id(_vcl) if _vid not in _vdict: if _vcl.inRegion(_xmin, _ymin, _xmax, _ymax): _vcls.append(_vcl) _vdict[_vid] = True return _vcls # # VCLine history class # class VCLineLog(conobject.ConstructionObjectLog): def __init__(self, v): if not isinstance(v, VCLine): raise TypeError, "Invalid VCLine: " + `type(v)` super(VCLineLog, self).__init__(v) v.connect('keypoint_changed', self._keypointChange) def _keypointChange(self, v, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen _old = args[0] if not isinstance(_old, point.Point): raise TypeError, "Invalid old endpoint: " + `type(_old)` self.saveUndoData('keypoint_changed', _old.getID()) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if _alen == 0: raise ValueError, "No arguments to execute()" _v = self.getObject() _p = _v.getLocation() _op = args[0] if _op == 'keypoint_changed': if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _oid = args[1] _parent = _v.getParent() if _parent is None: raise ValueError, "VCLine has no parent - cannot undo" _pt = _parent.getObject(_oid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "Keypoint missing: id=%d" % _oid _sdata = _p.getID() self.ignore(_op) try: if undo: _v.startUndo() try: _v.setLocation(_pt) finally: _v.endUndo() else: _v.startRedo() try: _v.setLocation(_pt) finally: _v.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _sdata) else: super(VCLineLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/baseobject.py0000644000175000017500000002724611307666732021017 0ustar matteomatteo# # Copyright (c) 2003, 2004, 2005, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # This file contains simple classes meant to be used as base classes. # from PythonCAD.Generic import entity class ModObject(object): """A base class for objects that store a modification state variable. There are several methods for the modobject class: isModified(): Test the state of the modified flag modified(): Set the modified flag to True reset(): Set the modified flag to False This class is meant to be used as a base class for more complex classes. """ def __init__(self): """Initialize a modobject instance. There are no arguments needed for this method. """ self.__modified = False def isModified(self): """Tests the modified state flag of the modobject. isModified() """ return self.__modified def modified(self): """Set the modified state flag value to True. modified() """ self.__modified = True def reset(self): """Set the modified state flag value to False. reset() """ self.__modified = False class SListObject(object): """Base class for objects emulating unidirectional linked lists. A SListObject has the following attributes: next: The next object in the list. A SListObject has the following methods: {get/set/del}Next(): Get/Set the next object in the list. """ def __init__(self): """Initialize a SListObject object. """ self.__next = None def getNext(self): """Get the object following this object. getNext() """ return self.__next def setNext(self, obj): """Set the object that will follow this object. setNext(obj) The object must be an instance of a ListObject. """ if obj is not None: if not isinstance(obj, SListObject): raise TypeError, "Invalid SListObject: " + str(obj) self.__next = obj def delNext(self): """Delete the object that follows this object. delNext() This method returns the deleted object. """ _next = self.__next if _next is not None: self.__next = _next.getNext() _next.setNext(None) return _next next = property(getNext, setNext, delNext, "Accessor to the next object.") class DListObject(SListObject): """Base class for objects emulating doubly linked lists. A DListObject is derived from a SListObject, so it shares the attributes and methods of that class. Addtionally it has the following attributes prev: The previous object in the list A DListObject has the following addtional methods: {get/set/del}Prev(): Get/Set the previous object in the list. """ def __init__(self): """Initialize a DListObject object. """ SListObject.__init__(self) self.__prev = None def getPrev(self): """Get the object preceeding this object. getPrev() """ return self.__prev def setPrev(self, obj): """Set the object that will precede this object. setPrev(obj) The object must be an instance of a DListObject. """ if obj is not None: if not isinstance(obj, DListObject): raise TypeError, "Invalid DListObject: " + str(obj) obj.setNext(self) self.__prev = obj def delPrev(self): """Delete the object preceding this object. delPrev(obj) This method returns the previous object. """ _prev = self.__prev if _prev is not None: _new_prev = _prev.getPrev() self.__prev = _new_prev if _new_prev is not None: _new_prev.setNext(self) _prev.__prev = None _prev.setNext(None) return _prev prev = property(getPrev, setPrev, delPrev, "Accessor to preceding object.") # # base class for objects that are components of other # objects # class Subpart(entity.Entity): """ A base class for objects that store references to other objects. The Subpart class is meant to be a base class for other classes defining simple objects that will be used in other objects but are not subclasses of those other objects. The Subpart objects that are in those classes can be used to store references to the larger object. The Subpart class has the following methods: storeUser(): Save a reference to some object. freeUser(): Release a reference to some object getUsers(): Return the list of objects that have been stored. hasUsers(): Test if the subpart has any """ __messages = { 'added_user' : True, 'removed_user' : True, } def __init__(self, **kw): super(Subpart, self).__init__(**kw) self.__users = None def finish(self): if self.__users is not None: print "%d refs in users" % len(self.__users) for _user in self.__users: print "stray object reference to: " + `_user` super(Subpart, self).finish() def storeUser(self, obj): """ Save a reference to another object. Argument 'obj' can be any type of object. """ if self.__users is None: self.__users = [] _users = self.__users _seen = False for _user in _users: if _user is obj: _seen = True break if not _seen: self.startChange('added_user') _users.append(obj) self.endChange('added_user') self.sendMessage('added_user', obj) def freeUser(self, obj): """Release a reference to another object. freeObject(obj) This method does nothing if the Component object has not stored references to any object or if the argument 'obj' had not been stored with storeObject(). """ if self.__users is not None: _users = self.__users for _i in range(len(_users)): if obj is _users[_i]: self.startChange('removed_user') del _users[_i] self.endChange('removed_user') self.sendMessage('removed_user', obj) break if not len(_users): self.__users = None def getUsers(self): """ Return the list of stored objects. This method returns a list of references stored by calling the storeObject() method. """ if self.__users is not None: return self.__users[:] return [] def countUsers(self): """ Return the number of stored objects. countUsers() """ _count = 0 if self.__users is not None: _count = len(self.__users) return _count def hasUsers(self): """Test if the Subpart has any users. hasUsers() This method returns True if there are any users of this Subpart, otherwise this method returns False. """ return self.__users is not None def canParent(self, obj): """ Test if an Entity can be the parent of another Entity. This method overrides the Entity::canParent() method """ return False def getValues(self): """Return values comprising the Subpart. getValues() This method extends the Entity::getValues() method. """ return super(Subpart, self).getValues() def sendsMessage(self, m): if m in Subpart.__messages: return True return super(Subpart, self).sendsMessage(m) # # TypedDict Class # # The TypedDict class is built from the dict object. A TypedDict # instance has a defined object type for a key and value and will # only allow objects of that type to be used for these dictionary # fields. # class TypedDict(dict): def __init__(self, keytype=None, valtype=None): super(TypedDict, self).__init__() self.__keytype = keytype self.__valtype = valtype def __setitem__(self, key, value): _kt = self.__keytype if _kt is not None: if not isinstance(key, _kt): raise TypeError, "Invalid key type %s" % type(key) _vt = self.__valtype if _vt is not None: if not isinstance(value, _vt): raise TypeError, "Invalid value type %s" % type(value) super(TypedDict, self).__setitem__(key, value) # # ConstDict class # # The ConstDict class is a TypedDict based class that allows # the setting of a key only once and does not permit the # deletion of the key. The idea with a ConstDict class is to # store a non-modifiable set of key/value pairs. # class ConstDict(TypedDict): def __init__(self, keytype=None, valtype=None): super(ConstDict, self).__init__(keytype, valtype) def __setitem__(self, key, value): if key in self: raise KeyError, "Key already used: " + key super(ConstDict, self).__setitem__(key, value) def __delitem__(self, key): pass # raise an exception? # # LockedDict class # # The LockedDict class is a TypedDict based class that allows # the setting of keys/values until the dictionary is locked. # After then the dictionary is cannot be altered. There is # not an unlock method to allow changing the LockedDict object # once it has been locked. # class LockedDict(TypedDict): def __init__(self, keytype=None, valtype=None): super(LockedDict, self).__init__(keytype, valtype) self.__locked = False def __setitem__(self, key, value): if self.__locked: raise KeyError, "LockedDict object is locked: " + `self` super(LockedDict, self).__setitem__(key, value) def __delitem__(self, key): if self.__locked: raise KeyError, "LockedDict object is locked: " + `self` super(LockedDict, self).__delitem__(key) def lock(self): self.__locked = True # # TypedList Class # # # The TypedList class is built from the list object. A TypedList # instance has a defined object type for a occupant in the list and # will only allow objects of that type to be stored. # class TypedList(list): def __init__(self, listtype=None): super(TypedList, self).__init__() self.__listtype = listtype def __setitem__(self, key, value): _lt = self.__listtype if _lt is not None: if not isinstance(value, _lt): raise TypeError, "Invalid list member %s" % type(value) super(TypedList, self).__setitem__(key, value) def append(self, obj): _lt = self.__listtype if _lt is not None: if not isinstance(obj, _lt): raise TypeError, "Invalid list member %s" % type(obj) super(TypedList, self).append(obj) def insert(self, idx, obj): _lt = self.__listtype if _lt is not None: if not isinstance(obj, _lt): raise TypeError, "Invalid list member %s" % type(obj) super(TypedList, self).insert(idx, obj) PythonCAD-DS1-R37/PythonCAD/Generic/dwgutil.py0000644000175000017500000005724111307666657020401 0ustar matteomatteo# # Copyright (c) 2003, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import struct import sys import array _debug = 0 dbg_handle = sys.stdout # # bitstream decoding class # class DWGBitStream(object): __mask_table = [ (0xff, 0, 0x00, 0), # bit offset == 0 (0x7f, 1, 0x80, 7), # bit offset == 1 (0x3f, 2, 0xc0, 6), # bit offset == 2 (0x1f, 3, 0xe0, 5), # bit offset == 3 (0x0f, 4, 0xf0, 4), # bit offset == 4 (0x07, 5, 0xf8, 3), # bit offset == 5 (0x03, 6, 0xfc, 2), # bit offset == 6 (0x01, 7, 0xfe, 1), # bit offset == 7 ] def __init__(self, bits): if not isinstance(bits, array.array): raise TypeError, "Invalid bit array: " + `type(bits)` _tc = bits.typecode if _tc != 'B': raise ValueError, "Unexpected array typecode: %s" % _tc self.__bits = bits self.__offset = 0 def getOffset(self): return self.__offset offset = property(getOffset, None, None, "Offset into bit array") def get_bytes(self, count): if ((count < 0) or (count & 0x07)): raise ValueError, "Invalid count: %d" % count _bits = self.__bits _idx = self.__offset >> 3 _bidx = self.__offset & 0x07 _m1, _lsh, _m2, _rsh = DWGBitStream.__mask_table[_bidx] _bytes = [] _read = 0 while _read < count: if _bidx == 0: _byte = _bits[_idx] _idx = _idx + 1 else: _b1 = (_bits[_idx] & _m1) _idx = _idx + 1 _b2 = (_bits[_idx] & _m2) _byte = (_b1 << _lsh) | (_b2 >> _rsh) _bytes.append(chr(_byte)) self.__offset = self.__offset + 8 _read = _read + 8 return "".join(_bytes) def get_byte(self, count): if ((count < 0) or (count > 8)): raise ValueError, "Invalid count: %d" % count _bits = self.__bits _idx = self.__offset >> 3 _bidx = self.__offset & 0x07 _m = DWGBitStream.__mask_table[_bidx][0] _bav = 8 - _bidx # bits available at the current index _byte = _b1 = 0x0 _rem = 0 if count > _bav: # need bits at next index also _b1 = (_bits[_idx] & _m) _rem = count - _bav else: _byte = ((_bits[_idx] & _m) >> (8 - _bidx - count)) if _rem > 0: _idx = _idx + 1 _byte = (_b1 << _rem) | (_bits[_idx] >> (8 - _rem)) self.__offset = self.__offset + count return _byte def test_bit(self): _bits = self.__bits _idx = self.__offset >> 3 _bidx = self.__offset & 0x07 _mask = 0x1 << (7 - _bidx) _val = (_bits[_idx] & _mask) != 0x0 self.__offset = self.__offset + 1 return _val def set_bit(self, flag): _bits = self.__bits _idx = self.__offset >> 3 _bidx = self.__offset & 0x07 if len(_bits) < _idx: _bits.append(0x0) _val = _bits[_idx] _mask = 0x01 << (7 - _bidx) if flag: _bits[_idx] = _val | _mask else: _bits[_idx] = _val & (0xff ^ _mask) self.__offset = self.__offset + 1 def get_default_double(self, defval): _flags = self.get_byte(2) if (_flags == 0x0): _val = defval else: if (_flags == 0x3): _dstr = self.get_bytes(64) _val = struct.unpack(' 8: # convert string into list of bytes for _chr in _handle: _hlist.append(ord(_chr)) else: _hlist.append(_handle) return (_code, _counter) + tuple(_hlist) def get_modular_short(self, handle): _shorts = [] _short = struct.unpack('>h', handle.read(2))[0] # msb first while (_short & 0x80): # test high bit in lsb byte _shorts.append(_short) _short = struct.unpack('>h', handle.read(2))[0] # msb first _shorts.append(_short) for _i in range(len(_shorts)): # reverse bytes in shorts _short = _shorts[_i] _shorts[_i] = ((_short & 0xff00) >> 8) | ((_short & 0xff) << 8) _slen = len(_shorts) if _slen == 1: _size = _shorts[0] & 0x7fff elif _slen == 2: _tmp = _shorts[0] _shorts[0] = _shorts[1] _shorts[1] = _tmp _size = ((_shorts[0] & 0x7fff) << 15) | (_shorts[1] & 0x7fff) else: raise ValueError, "Unexpected array length: %d" % _slen return _size def read_extended_data(self): _extdata = [] while True: _size = self.get_bit_short() if _size == 0: break _handle = self.get_handle() _eedata = [] while (_size > 0): _cb = self.get_raw_char() _size = _size - 1 if _cb == 0x0: # string _len = self.get_raw_char() _cp = self.get_raw_short() _i = 0 _chars = [] while _i < _len: _chars.append(chr(self.get_raw_char())) _i = _i + 1 _eedata.append("".join(_chars)) _size = _size - _len - 3 elif _cb == 0x1: raise ValueError, "Invalid EEX code byte: 0x1" elif _cb == 0x2: # either '{' or '}' _char = self.get_raw_char() if _char == 0x0: _eedata.append("{") elif _char == 0x1: _eedata.append("}") else: raise ValueError, "Unexpected EEX char: %#02x" % _char _size = _size - 1 elif (_cb == 0x3 or # layer table reference _cb == 0x5): # entity handle reference _chars = [] _i = 0 while _i < 8: _chars.append(self.get_raw_char()) _i = _i + 1 _eedata.append(tuple(_chars)) # this seems odd ... _size = _size - 8 elif _cb == 0x4: # binary data _len = self.get_raw_char() _i = 0 _chars = [] while _i < _len: _chars.append(self.get_raw_char()) _i = _i + 1 _eedata.append(_chars) _size = _size - _len - 1 elif (0xa <= _cb <= 0xd): # three doubles _d1 = self.get_raw_double() _d2 = self.get_raw_double() _d3 = self.get_raw_double() _eedata.append((_d1, _d2, _d3)) _size = _size - 24 elif (0x28 <= _cb <= 0x2a): # one double _d = self.get_raw_double() _eedata.append(_d) _size = _size - 8 elif _cb == 0x46: # short int _short = self.get_raw_short() _eedata.append(_short) _size = _size - 2 elif _cb == 0x47: # long int _long = self.get_raw_long() _eedata.append(_long) _size = _size - 4 else: raise ValueError, "Unexpected code byte: %#02x" % _cb _extdata.append((_handle, _eedata)) return _extdata # # bitstream reading functions for DWG files # # these functions are used in R13/R14/R15 file decoding # # data: an array.array instance of unsigned bytes ("B") # offset: the current bit offset where the value begins # def read_extended_data(data, offset): _bitpos = offset _extdata = [] while True: _bitpos, _size = get_bit_short(data, _bitpos) if _size == 0: break _bitpos, _handle = get_handle(data, _bitpos) _eedata = [] while (_size > 0): _bitpos, _cb = get_raw_char(data, _bitpos) _size = _size - 1 if _cb == 0x0: # string _bitpos, _len = get_raw_char(data, _bitpos) _bitpos, _cp = get_raw_short(data, _bitpos) _chars = [] for _i in range(_len): _bitpos, _char = get_raw_char(data, _bitpos) _chars.append(chr(_char)) _eedata.append("".join(_chars)) _size = _size - _len - 3 elif _cb == 0x1: raise ValueError, "invalid EEX code byte: 0x1" elif _cb == 0x2: # either '{' or '}' _bitpos, _char = get_raw_char(data, _bitpos) if _char == 0x0: _eedata.append("{") elif _char == 0x1: _eedata.append("}") else: raise ValueError, "Unexpected EEX char: %#02x" % _char _size = _size - 1 elif (_cb == 0x3 or # layer table reference _cb == 0x5): # entity handle reference _chars = [] for _i in range(8): _bitpos, _char = get_raw_char(data, _bitpos) _chars.append(_char) _eedata.append(tuple(_chars)) # this seems odd ... _size = _size - 8 elif _cb == 0x4: # binary data _bitpos, _len = get_raw_char(data, _bitpos) _chars = [] for _i in range(_len): _bitpos, _char = get_raw_char(data, _bitpos) _chars.append(_char) _eedata.append(_chars) _size = _size - _len - 1 elif (0xa <= _cb <= 0xd): # three doubles _bitpos, _d1 = get_raw_double(data, _bitpos) _bitpos, _d2 = get_raw_double(data, _bitpos) _bitpos, _d3 = get_raw_double(data, _bitpos) _eedata.append((_d1, _d2, _d3)) _size = _size - 24 elif (0x28 <= _cb <= 0x2a): # one double _bitpos, _d = get_raw_double(data, _bitpos) _eedata.append(_d) _size = _size - 8 elif _cb == 0x46: # short int _bitpos, _short = get_raw_short(data, _bitpos) _eedata.append(_short) _size = _size - 2 elif _cb == 0x47: # long int _bitpos, _long = get_raw_long(data, _bitpos) _eedata.append(_long) _size = _size - 4 else: raise ValueError, "Unexpected code byte: %#02x" % _cb _extdata.append((_handle, _eedata)) return _bitpos, _extdata def get_default_double(data, offset, defval): _flags = get_bits(data, 2, offset) _read = 2 if (_flags == 0x0): _val = defval else: _offset = offset + 2 if (_flags == 0x3): _dstr = get_bits(data, 64, _offset) _val = struct.unpack(' 8: # convert string into list of bytes for _chr in _handle: _hlist.append(ord(_chr)) else: _hlist.append(_handle) return (offset + _read), (_code, _counter) + tuple(_hlist) def get_modular_short(handle): _shorts = [] _short = struct.unpack('>h', handle.read(2))[0] # msb first while (_short & 0x80): # test high bit in lsb byte _shorts.append(_short) _short = struct.unpack('>h', handle.read(2))[0] # msb first _shorts.append(_short) for _i in range(len(_shorts)): # reverse bytes in shorts _short = _shorts[_i] _shorts[_i] = ((_short & 0xff00) >> 8) | ((_short & 0xff) << 8) _slen = len(_shorts) if _slen == 1: _size = _shorts[0] & 0x7fff elif _slen == 2: _tmp = _shorts[0] _shorts[0] = _shorts[1] _shorts[1] = _tmp _size = ((_shorts[0] & 0x7fff) << 15) | (_shorts[1] & 0x7fff) else: raise ValueError, "Unexpected array length: %d" % _slen return _size # # mask1: bit mask to apply to the current byte # lshift: left shift amount of mask results # mask2: bit mask to apply to the next byte # rshift: right shift amount of the mask results # _mask_table = [ (0xff, 0, 0x00, 0), # bit offset == 0 (0x7f, 1, 0x80, 7), # bit offset == 1 (0x3f, 2, 0xc0, 6), # bit offset == 2 (0x1f, 3, 0xe0, 5), # bit offset == 3 (0x0f, 4, 0xf0, 4), # bit offset == 4 (0x07, 5, 0xf8, 3), # bit offset == 5 (0x03, 6, 0xfc, 2), # bit offset == 6 (0x01, 7, 0xfe, 1), # bit offset == 7 ] def get_bits(data, count, offset): # dbg_print("debugging on") dbg_print("passed %d data length with %d count at %d offset" % (len(data), count, offset)) _idx = offset / 8 # index to the byte offset _bitidx = offset % 8 # index to the bit offset within the byte _mask1, _lsh, _mask2, _rsh = _mask_table[_bitidx] _binc = 8 - _bitidx # bits available in current byte _read = 0 _rem = count _byte = 0x0 _bytes = [] while _read < count: if _rem > _binc: # need more bits than this byte can provide dbg_print("_rem > _binc") _b1 = (data[_idx] & _mask1) _read = _read + _binc if not isinstance(_rem, int): dbg_print("rem type: " + str(type(_rem))) dbg_print("rem: " + str(_rem)) if not isinstance(_binc, int): dbg_print("binc type: " + str(type(_binc))) dbg_print("binc: " + str(_binc)) _rem = _rem - _binc else: # this byte can give all the bits needed dbg_print("_rem <= _binc") _byte = _b1 = ((data[_idx] & _mask1) >> (8 - _bitidx - _rem)) _read = _read + _rem _rem = 0 if _read < count: # need bits from next byte dbg_print("_read %d < %d count" % (_read, count)) _idx = _idx + 1 if _rem > _bitidx: # use all bitidx bits - make a complete byte dbg_print("_rem (%d) > (%d) _bitidx" % (_rem, _bitidx)) dbg_print("index %d of %d" % (_idx, len(data))) _b2 = (data[_idx] & _mask2) _byte = (_b1 << _lsh) | (_b2 >> _rsh) _read = _read + _bitidx _rem = _rem - _bitidx else: # use some bitidx to complete bit count request dbg_print("_rem <= _bitidx") _mask = _mask_table[_rem][2] # mask for current byte _b2 = data[_idx] & _mask _byte = (_b1 << _rem) | (_b2 >> (8 - _rem)) _read = _read + _rem _rem = 0 if count > 8: _bytes.append(chr(_byte)) if len(_bytes): return "".join(_bytes) return _byte def test_bit(data, offset): _idx = offset / 8 # index to the byte offset _bitidx = offset % 8 # index to the bit offset within the byte _mask = 0x1 << (7 - _bitidx) _val = False if (data[_idx] & _mask): _val = True return (offset + 1), _val # # debug routines # def set_nodebug(): import dwgutil dwgutil._debug = 0 def set_debug(filename=None): import dwgutil dwgutil._debug = 1 if filename != None: dwgutil.dbg_handle = open(filename, 'w') else: dwgutil.dbg_handle = sys.stdout def dbg_print(*s): if _debug: string = "" for arg in s: string += str(arg) + " " string += "\n" dbg_handle.write(string) PythonCAD-DS1-R37/PythonCAD/Generic/segment.py0000644000175000017500000007405611307666732020361 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006 Art Haas 2009 Matteo Boscolo # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # classes for line segments # from __future__ import generators import math from PythonCAD.Generic import graphicobject from PythonCAD.Generic import tolerance from PythonCAD.Generic import style from PythonCAD.Generic import linetype from PythonCAD.Generic import color from PythonCAD.Generic import point from PythonCAD.Generic import util from PythonCAD.Generic import quadtree from PythonCAD.Generic import pyGeoLib class Segment(graphicobject.GraphicObject): """A class representing a line segment. A Segment has two attributes. p1: A Point object representing the first end point p2: A Point object representing the second end point A Segment has the following methods: getEndpoints(): Return the two endpoints of the Segment. {get/set}P1: Get/Set the Segment first endpoint. {get/set}P2: Get/Set the Segment second endpoint. move(): Move the Segment. length(): Get the Segment length. getCoefficients(): Return the segment as ax + by + c = 0 getProjection(): Project a coordinate on to the Segment mapCoords(): Test if a coordinate pair is within some distance to a Segment. inRegion(): Test if the Segment is visible in some area. ++Matteo Boscolo getMiddlePoint(): return the x,y cord of the segment MiddlePoint -- clone(): Make an identical copy of a Segment. """ __messages = { 'moved' : True, 'endpoint_changed' : True } __defstyle = None def __init__(self, p1, p2, st=None, lt=None, col=None, th=None, **kw): """Initialize a Segment object. Segment(p1, p2[, st, lt, col, th]) p1: Segment first endpoint - may be a Point or a two-item tuple of floats. p2: Segment second endpoint - may be a Point or a two-item tuple of floats. The following arguments are optional: st: A Style object lt: A Linetype object that overrides the linetype in the Style. col: A Color object that overrides the color in the Style. th: A float that overrides the line thickness in the Style. """ _p1 = p1 if not isinstance(_p1, point.Point): _p1 = point.Point(p1) _p2 = p2 if not isinstance(_p2, point.Point): _p2 = point.Point(p2) if _p1 is _p2: raise ValueError, "Segments cannot have identical endpoints." _st = st if _st is None: _st = self.getDefaultStyle() super(Segment, self).__init__(_st, lt, col, th, **kw) self.__p1 = _p1 _p1.connect('moved', self.__movePoint) _p1.connect('change_pending', self.__pointChangePending) _p1.connect('change_complete', self.__pointChangeComplete) _p1.storeUser(self) self.__p2 = _p2 _p2.connect('moved', self.__movePoint) _p2.connect('change_pending', self.__pointChangePending) _p2.connect('change_complete', self.__pointChangeComplete) _p2.storeUser(self) def __str__(self): return "Segment: %s to %s" % (self.__p1, self.__p2) def __eq__(self, obj): """Compare a Segment to another for equality. """ if not isinstance(obj, Segment): return False if obj is self: return True _sp1 = self.__p1 _sp2 = self.__p2 _op1, _op2 = obj.getEndpoints() return (((_sp1 == _op1) and (_sp2 == _op2)) or ((_sp1 == _op2) and (_sp2 == _op1))) def __ne__(self, obj): """Compare a Segment to another for inequality. """ if not isinstance(obj, Segment): return True if obj is self: return False _sp1 = self.__p1 _sp2 = self.__p2 _op1, _op2 = obj.getEndpoints() return (((_sp1 != _op1) or (_sp2 != _op2)) and ((_sp1 != _op2) or (_sp2 != _op1))) def getDefaultStyle(cls): if cls.__defstyle is None: _s = style.Style(u'Default Segment Style', linetype.Linetype(u'Solid', None), color.Color(0xffffff), 1.0) cls.__defstyle = _s return cls.__defstyle getDefaultStyle = classmethod(getDefaultStyle) def setDefaultStyle(cls, s): if not isinstance(s, style.Style): raise TypeError, "Invalid style: " + `type(s)` cls.__defstyle = s setDefaultStyle = classmethod(setDefaultStyle) def finish(self): self.__p1.disconnect(self) self.__p1.freeUser(self) self.__p2.disconnect(self) self.__p2.freeUser(self) self.__p1 = self.__p2 = None super(Segment, self).finish() def setStyle(self, s): """Set the Style of the Segment setStyle(s) This method extends GraphicObject::setStyle(). """ _s = s if _s is None: _s = self.getDefaultStyle() super(Segment, self).setStyle(_s) def getValues(self): """Return values comprising the Segment. getValues() This method extends the GraphicObject::getValues() method. """ _data = super(Segment, self).getValues() _data.setValue('type', 'segment') _data.setValue('p1', self.__p1.getID()) _data.setValue('p2', self.__p2.getID()) return _data def getEndpoints(self): """Get the endpoints of the Segment. getEndpoints() This function returns a tuple containing the two Point objects that are the endpoints of the segment. """ return self.__p1, self.__p2 def getP1(self): """Return the first endpoint Point of the Segment. getP1() """ return self.__p1 def setP1(self, p): """Set the first endpoint Point of the Segment. setP1(p) """ if self.isLocked(): raise RuntimeError, "Setting endpoint not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid P1 endpoint type: " + `type(p)` if p is self.__p2: raise ValueError, "Segments cannot have identical endpoints." _pt = self.__p1 if _pt is not p: _pt.disconnect(self) _pt.freeUser(self) self.startChange('endpoint_changed') self.__p1 = p self.endChange('endpoint_changed') self.sendMessage('endpoint_changed', _pt, p) p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) if abs(_pt.x - p.x) > 1e-10 or abs(_pt.y - p.y) > 1e-10: _x, _y = self.__p2.getCoords() self.sendMessage('moved', _pt.x, _pt.y, _x, _y) self.modified() p1 = property(getP1, setP1, None, "First endpoint of the Segment.") def getP2(self): """Return the second endpoint Point of the Segment. getP2() """ return self.__p2 def setP2(self, p): """Set the second endpoint Point of the Segment. setP2(p) """ if self.isLocked(): raise RuntimeError, "Setting endpoint not allowed - object locked." if not isinstance(p, point.Point): raise TypeError, "Invalid P2 endpoint type: " + `type(p)` if p is self.__p1: raise ValueError, "Segments cannot have identical endpoints." _pt = self.__p2 if _pt is not p: _pt.disconnect(self) _pt.freeUser(self) self.startChange('endpoint_changed') self.__p2 = p self.endChange('endpoint_changed') self.sendMessage('endpoint_changed', _pt, p) p.storeUser(self) p.connect('moved', self.__movePoint) p.connect('change_pending', self.__pointChangePending) p.connect('change_complete', self.__pointChangeComplete) if abs(_pt.x - p.x) > 1e-10 or abs(_pt.y - p.y) > 1e-10: _x, _y = self.__p1.getCoords() self.sendMessage('moved', _x, _y, _pt.x, _pt.y) self.modified() p2 = property(getP2, setP2, None, "Second endpoint of the Segment.") def move(self, dx, dy): """ Move a Segment. The first argument gives the x-coordinate displacement, and the second gives the y-coordinate displacement. Both values should be floats. """ if self.isLocked() or self.__p1.isLocked() or self.__p2.isLocked(): raise RuntimeError, "Moving Segment not allowed - object locked." _dx = util.get_float(dx) _dy = util.get_float(dy) if abs(_dx) > 1e-10 or abs(_dy) > 1e-10: _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() self.ignore('moved') try: self.__p1.move(_dx, _dy) self.__p2.move(_dx, _dy) finally: self.receive('moved') self.sendMessage('moved', _x1, _y1, _x2, _y2) def length(self): """ Return the length of the Segment. """ return self.__p1 - self.__p2 def getCoefficients(self): """ Express the line segment as a function ax + by + c = 0 This method returns a tuple of three floats: (a, b, c) """ _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() _a = _y2 - _y1 _b = _x1 - _x2 _c = (_x2 * _y1) - (_x1 * _y2) return _a, _b, _c def getMiddlePoint(self): """ Return the middle point of the segment """ _p1,_p2=self.getEndpoints() _x1=util.get_float(_p1.x) _x2=util.get_float(_p2.x) _y1=util.get_float(_p1.y) _y2=util.get_float(_p2.y) _deltax=abs(_x1-_x2)/2.0 _deltay=abs(_y1-_y2)/2.0 if(_x1<_x2): retX=_x1+_deltax else: retX=_x2+_deltax if(_y1<_y2): retY=_y1+_deltay else: retY=_y2+_deltay return retX,retY def getProjection(self,x,y): """ get Projection of the point x,y in the line """ _x = util.get_float(x) _y = util.get_float(y) p1=self.__p1 p2=self.__p2 p3=point.Point(_x, _y) v=pyGeoLib.Vector(p1,p2) v1=pyGeoLib.Vector(p1,p3) xp,yp=v1.Point().getCoords() pjPoint=v.Map(xp,yp).Point() x,y = pjPoint.getCoords() _x1,_y1=p1.getCoords() x=x+_x1 y=y+_y1 return x,y def mapCoords(self, x, y, tol=tolerance.TOL): """ Return the nearest Point on the Segment to a coordinate pair. The function has two required arguments: x: A Float value giving the 'x' coordinate y: A Float value giving the 'y' coordinate There is a single optional argument: tol: A float value equal or greater than 0. This function is used to map a possibly near-by coordinate pair to an actual Point on the Segment. If the distance between the actual Point and the coordinates used as an argument is less than the tolerance, the actual Point is returned. Otherwise, this function returns None. """ _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() return util.map_coords(_x, _y, _x1, _y1, _x2, _y2, _t) def inRegion(self, xmin, ymin, xmax, ymax, fully=False): """Return whether or not a Segment exists within a region. inRegion(xmin, ymin, xmax, ymax[, fully]) The four arguments define the boundary of an area, and the method returns True if the Segment lies within that area. If the optional argument fully is used and is True, then both endpoints of the Segment must lie within the boundary. Otherwise, the method returns False. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" util.test_boolean(fully) _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() _pxmin = min(_x1, _x2) _pymin = min(_y1, _y2) _pxmax = max(_x1, _x2) _pymax = max(_y1, _y2) if ((_pxmax < _xmin) or (_pymax < _ymin) or (_pxmin > _xmax) or (_pymin > _ymax)): return False if fully: if ((_pxmin > _xmin) and (_pymin > _ymin) and (_pxmax < _xmax) and (_pymax < _ymax)): return True return False return util.in_region(_x1, _y1, _x2, _y2, _xmin, _ymin, _xmax, _ymax) def clipToRegion(self, xmin, ymin, xmax, ymax): """Clip the Segment using the Liang-Barsky Algorithm. clipToRegion(xmin, ymin, xmax, ymax) """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _x1, _y1 = self.__p1.getCoords() _x2, _y2 = self.__p2.getCoords() # # simple tests to reject line # if ((max(_x1, _x2) < _xmin) or (max(_y1, _y2) < _ymin) or (min(_x1, _x2) > _xmax) or (min(_y1, _y2) > _ymax)): return None # # simple tests to accept line # _coords = None if (_xmin < _x1 < _xmax and _xmin < _x2 < _xmax and _ymin < _y1 < _ymax and _ymin < _y2 < _ymax): _coords = (_x1, _y1, _x2, _y2) else: # # the Segment can be parameterized as # # x = u * (x2 - x1) + x1 # y = u * (y2 - y1) + y1 # # for u = 0, x => x1, y => y1 # for u = 1, x => x2, y => y2 # # The following is the Liang-Barsky Algorithm # for segment clipping # _dx = _x2 - _x1 _dy = _y2 - _y1 _P = [-_dx, _dx, -_dy, _dy] _q = [(_x1 - _xmin), (_xmax - _x1), (_y1 - _ymin), (_ymax - _y1)] _u1 = 0.0 _u2 = 1.0 _valid = True for _i in range(4): _pi = _P[_i] _qi = _q[_i] if abs(_pi) < 1e-10: if _qi < 0.0: _valid = False break else: _r = _qi/_pi if _pi < 0.0: if _r > _u2: _valid = False break if _r > _u1: _u1 = _r else: if _r < _u1: _valid = False break if _r < _u2: _u2 = _r if _valid: _coords = (((_u1 * _dx) + _x1), ((_u1 * _dy) + _y1), ((_u2 * _dx) + _x1), ((_u2 * _dy) + _y1)) return _coords def __pointChangePending(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.startChange('moved') def __pointChangeComplete(self, p, *args): _alen = len(args) if _alen < 1: raise ValueError, "Invalid argument count: %d" % _alen if args[0] == 'moved': self.endChange('moved') def __movePoint(self, p, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _x = util.get_float(args[0]) _y = util.get_float(args[1]) if p is self.__p1: _x1 = _x _y1 = _y _x2, _y2 = self.__p2.getCoords() elif p is self.__p2: _x1, _y1 = self.__p1.getCoords() _x2 = _x _y2 = _y else: raise ValueError, "Unexpected Segment endpoint: " + `p` self.sendMessage('moved', _x1, _y1, _x2, _y2) def clone(self): """Create an identical copy of a Segment. clone() """ _cp1 = self.__p1.clone() _cp2 = self.__p2.clone() _st = self.getStyle() _lt = self.getLinetype() _col = self.getColor() _th = self.getThickness() return Segment(_cp1, _cp2, _st, _lt, _col, _th) def sendsMessage(self, m): if m in Segment.__messages: return True return super(Segment, self).sendsMessage(m) # # Quadtree Segment storage # class SegmentQuadtree(quadtree.Quadtree): def __init__(self): super(SegmentQuadtree, self).__init__() def getNodes(self, *args): _alen = len(args) if _alen != 4: raise ValueError, "Expected 4 arguments, got %d" % _alen _x1 = util.get_float(args[0]) _y1 = util.get_float(args[1]) _x2 = util.get_float(args[2]) _y2 = util.get_float(args[3]) _sxmin = min(_x1, _x2) _sxmax = max(_x1, _x2) _symin = min(_y1, _y2) _symax = max(_y1, _y2) _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_sxmin > _xmax) or (_sxmax < _xmin) or (_symin > _ymax) or (_symax < _ymin)): continue if _node.hasSubnodes(): _xmid = (_xmin + _xmax)/2.0 _ymid = (_ymin + _ymax)/2.0 _ne = _nw = _sw = _se = True if _sxmax < _xmid: # seg on left side _ne = _se = False if _sxmin > _xmid: # seg on right side _nw = _sw = False if _symax < _ymid: # seg below _nw = _ne = False if _symin > _ymid: # seg above _sw = _se = False if _ne: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NENODE)) if _nw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.NWNODE)) if _sw: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SWNODE)) if _se: _nodes.append(_node.getSubnode(quadtree.QTreeNode.SENODE)) else: yield _node def addObject(self, obj): if not isinstance(obj, Segment): raise TypeError, "Invalid Segment object: " + `obj` if obj in self: return _p1, _p2 = obj.getEndpoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _bounds = self.getTreeRoot().getBoundary() _xmin = _ymin = _xmax = _ymax = None _sxmin = min(_x1, _x2) _sxmax = max(_x1, _x2) _symin = min(_y1, _y2) _symax = max(_y1, _y2) _resize = False if _bounds is None: # first node in tree _resize = True _xmin = _sxmin - 1.0 _ymin = _symin - 1.0 _xmax = _sxmax + 1.0 _ymax = _symax + 1.0 else: _xmin, _ymin, _xmax, _ymax = _bounds if _sxmin < _xmin: _xmin = _sxmin - 1.0 _resize = True if _sxmax > _xmax: _xmax = _sxmax + 1.0 _resize = True if _symin < _ymin: _ymin = _symin - 1.0 _resize = True if _symax > _ymax: _ymax = _symax + 1.0 _resize = True if _resize: self.resize(_xmin, _ymin, _xmax, _ymax) for _node in self.getNodes(_x1, _y1, _x2, _y2): _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if obj.inRegion(_xmin, _ymin, _xmax, _ymax): _node.addObject(obj) super(SegmentQuadtree, self).addObject(obj) obj.connect('moved', self._moveSegment) def delObject(self, obj): if obj not in self: return _p1, _p2 = obj.getEndpoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _pdict = {} for _node in self.getNodes(_x1, _y1, _x2, _y2): _node.delObject(obj) _parent = _node.getParent() if _parent is not None: _pid = id(_parent) if _pid not in _pdict: _pdict[_pid] = _parent super(SegmentQuadtree, self).delObject(obj) obj.disconnect(self) for _parent in _pdict.values(): self.purgeSubnodes(_parent) # # test # _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) else: for _obj in _node.getObjects(): if _obj is obj: raise ValueError, "object still in tree" + `obj` def find(self, *args): _alen = len(args) if _alen < 4: raise ValueError, "Invalid argument count: %d" % _alen _x1 = args[0] if not isinstance(_x1, float): _x1 = float(args[0]) _y1 = args[1] if not isinstance(_y1, float): _y1 = float(args[1]) _x2 = args[2] if not isinstance(_x2, float): _x2 = float(args[2]) _y2 = args[3] if not isinstance(_y2, float): _y2 = float(args[3]) _t = tolerance.TOL if _alen > 4: _t = tolerance.toltest(args[4]) _xmin = min(_x1, _x2) - _t _ymin = min(_y1, _y2) - _t _xmax = max(_x1, _x2) + _t _ymax = max(_y1, _y2) + _t _segs = [] for _seg in self.getInRegion(_xmin, _ymin, _xmax, _ymax): _p1, _p2 = _seg.getEndpoints() if ((abs(_x1 - _p1.x) < _t) and (abs(_y1 - _p1.y) < _t) and (abs(_x2 - _p2.x) < _t) and (abs(_y2 - _p2.y) < _t)): _segs.append(_seg) elif ((abs(_x2 - _p1.x) < _t) and (abs(_y2 - _p1.y) < _t) and (abs(_x1 - _p2.x) < _t) and (abs(_y1 - _p2.y) < _t)): _segs.append(_seg) else: pass return _segs def _moveSegment(self, obj, *args): if obj not in self: raise ValueError, "Segment not stored in Quadtree: " + `obj` _alen = len(args) if _alen < 4: raise ValueError, "Invalid argument count: %d" % _alen _x1 = util.get_float(args[0]) _y1 = util.get_float(args[1]) _x2 = util.get_float(args[2]) _y2 = util.get_float(args[3]) for _node in self.getNodes(_x1, _y1, _x2, _y2): _node.delObject(obj) # segment may not be in node ... super(SegmentQuadtree, self).delObject(obj) obj.disconnect(self) self.addObject(obj) def getClosest(self, x, y, tol=tolerance.TOL): _x = util.get_float(x) _y = util.get_float(y) _t = tolerance.toltest(tol) _seg = _tsep = None _bailout = False _sdict = {} _nodes = [self.getTreeRoot()] while len(_nodes): _node = _nodes.pop() _xmin, _ymin, _xmax, _ymax = _node.getBoundary() if ((_x < (_xmin - _t)) or (_x > (_xmax + _t)) or (_y < (_ymin - _t)) or (_y > (_ymax + _t))): continue if _node.hasSubnodes(): _nodes.extend(_node.getSubnodes()) else: for _s in _node.getObjects(): _sid = id(_s) if _sid not in _sdict: _p1, _p2 = _s.getEndpoints() _px, _py = _p1.getCoords() if ((abs(_px - _x) < 1e-10) and (abs(_py - _y) < 1e-10)): _seg = _s _bailout = True break _px, _py = _p2.getCoords() if ((abs(_px - _x) < 1e-10) and (abs(_py - _y) < 1e-10)): _seg = _s _bailout = True break _sdict[_sid] = True _pt = _s.mapCoords(_x, _y, _t) if _pt is not None: _px, _py = _pt _sep = math.hypot((_px - _x), (_py - _y)) if _tsep is None: _tsep = _sep _seg = _s else: if _sep < _tsep: _tsep = _sep _seg = _s if _bailout: break return _seg def getInRegion(self, xmin, ymin, xmax, ymax): _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Illegal values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Illegal values: ymax < ymin" _segs = [] if not len(self): return _segs _nodes = [self.getTreeRoot()] _sdict = {} while len(_nodes): _node = _nodes.pop() if _node.hasSubnodes(): for _subnode in _node.getSubnodes(): _sxmin, _symin, _sxmax, _symax = _subnode.getBoundary() if ((_sxmin > _xmax) or (_symin > _ymax) or (_sxmax < _xmin) or (_symax < _ymin)): continue _nodes.append(_subnode) else: for _seg in _node.getObjects(): _sid = id(_seg) if _sid not in _sdict: if _seg.inRegion(_xmin, _ymin, _xmax, _ymax): _segs.append(_seg) _sdict[_sid] = True return _segs # # Segment history class # class SegmentLog(graphicobject.GraphicObjectLog): def __init__(self, s): if not isinstance(s, Segment): raise TypeError, "Invalid segment: " + `s` super(SegmentLog, self).__init__(s) s.connect('endpoint_changed', self.__endpointChanged) def __endpointChanged(self, s, *args): _alen = len(args) if _alen < 2: raise ValueError, "Invalid argument count: %d" % _alen _old = args[0] if not isinstance(_old, point.Point): raise TypeError, "Invalid old endpoint: " + `_old` _new = args[1] if not isinstance(_new, point.Point): raise TypeError, "Invalid new endpoint: " + `_new` self.saveUndoData('endpoint_changed', _old.getID(), _new.getID()) def execute(self, undo, *args): util.test_boolean(undo) _alen = len(args) if len(args) == 0: raise ValueError, "No arguments to execute()" _s = self.getObject() _p1, _p2 = _s.getEndpoints() _op = args[0] if _op == 'endpoint_changed': if _alen < 3: raise ValueError, "Invalid argument count: %d" % _alen _oid = args[1] _nid = args[2] _parent = _s.getParent() if _parent is None: raise ValueError, "Segment has no parent - cannot undo" self.ignore(_op) try: if undo: _pt = _parent.getObject(_oid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "Old endpoint missing: id=%d" % _oid _s.startUndo() try: if _p1.getID() == _nid: _s.setP1(_pt) elif _p2.getID() == _nid: _s.setP2(_pt) else: raise ValueError, "Unexpected endpoint ID: %d" % _nid finally: _s.endUndo() else: _pt = _parent.getObject(_nid) if _pt is None or not isinstance(_pt, point.Point): raise ValueError, "New endpoint missing: id=%d" % _nid _s.startRedo() try: if _p1.getID() == _oid: _s.setP1(_pt) elif _p2.getID() == _oid: _s.setP2(_pt) else: raise ValueError, "Unexpected endpoint ID: %d" % _oid finally: _s.endRedo() finally: self.receive(_op) self.saveData(undo, _op, _oid, _nid) else: super(SegmentLog, self).execute(undo, *args) PythonCAD-DS1-R37/PythonCAD/Generic/tools.py0000644000175000017500000041131511307666732020050 0ustar matteomatteo# # Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # tool stuff # import math import types import array from PythonCAD.Generic import util from PythonCAD.Generic import color from PythonCAD.Generic import linetype from PythonCAD.Generic import style from PythonCAD.Generic.point import Point from PythonCAD.Generic.segment import Segment from PythonCAD.Generic.circle import Circle from PythonCAD.Generic.arc import Arc from PythonCAD.Generic.leader import Leader from PythonCAD.Generic.polyline import Polyline from PythonCAD.Generic.hcline import HCLine from PythonCAD.Generic.vcline import VCLine from PythonCAD.Generic.acline import ACLine from PythonCAD.Generic.cline import CLine from PythonCAD.Generic.ccircle import CCircle from PythonCAD.Generic.text import TextStyle, TextBlock from PythonCAD.Generic import dimension from PythonCAD.Generic.layer import Layer from PythonCAD.Generic import tangent from PythonCAD.Generic import intersections from PythonCAD.Generic.segjoint import Chamfer, Fillet from PythonCAD.Generic import pyGeoLib from PythonCAD.Generic.snap import SnapPointStr class Tool(object): """A generic tool object. This class is meant to be a base class for tools. A Tool instance the following attributes: list: A list the tool can use to store objects handlers: A dictionary used to store functions A Tool object has the following methods: {set/get/del/has}Handler(): Store/retrive/delete/test a handler for an event. clearHandlers(): Unset all the handlers in the tool. reset(): Restore the tool to a a default state. initialize(): Retore the tool to its original state. {set/get}Filter(): Set/Get a filtering procedure for object testing. {set/get}Location(): Store/retrieve an image-based coordinate pair. {set/get}CurrentPoint(): Store/retrieve a screen-based coordinate pair. clearCurrentPoint(): Set the screen-based coordinate to None. create(): Instantiate the object the tool is designed to create. """ def __init__(self): """Instantiate a Tool. t = Tool() """ super(Tool, self).__init__() self.__objlist = [] self.__objtype = None self.__fproc = None self.__handlers = {} self.__location = None self.__curpoint = None self.__points = [] self.__xpts = array.array('d') self.__ypts = array.array('d') self.__shift = None self.__SnapObj=None def __len__(self): """Return the number of objects in the list via len(). """ return len(self.__objlist) def __iter__(self): """Make the Tool iterable. """ return iter(self.__objlist) def getList(self): """Return the Tool's object list. getList() """ return self.__objlist list = property(getList, None, None, "Tool object list.") def reset(self): """Restore the Tool to its initial state. reset() This function purges the Tool's object list and handler dictionary. """ del self.__objlist[:] self.__handlers.clear() self.__location = None self.__curpoint = None del self.__points[:] del self.__xpts[:] del self.__ypts[:] self.__shift = None def initialize(self): self.reset() def setHandler(self, key, func): """Set a handler for the Tool. setHandler(key, func) There are two arguments for this function: key: A string used to identify a particular action func: A function object There are no restrictions on what the function 'func' does, the argument count, etc. Any call to setHandler() with a key that is already stored replaces the old 'func' argument with the new one. The function argument may be None, and the key argument must be a string. """ if key is None: raise ValueError, "Key value cannot be None." if not isinstance(key, str): raise TypeError, "Invalid key type: " + `type(key)` if func and not isinstance(func, types.FunctionType): raise TypeError, "Invalid function type: " + `type(func)` self.__handlers[key] = func def getHandler(self, key): """Return the function for a particular key. getHandler(key) Given argument 'key', the function associated with it is returned. A KeyError is raised if the argument 'key' had not be used to store a function. """ if not isinstance(key, str): raise TypeError, "Invalid key type: " + `type(key)` if not self.__handlers.has_key(key): raise KeyError, "Invalid key '%s'" % key return self.__handlers[key] def delHandler(self, key): """Delete the handler associated with a particular key delHandler(key) The argument 'key' should be a string. """ if self.__handlers.has_key(key): del self.__handlers[key] def hasHandler(self, key): """Check if there is a handler stored for a given key. hasHandler(key) The 'key' argument must be a string. The function returns 1 if there is a handler for that key, 0 otherwise. """ _k = key if not isinstance(_k, str): raise TypeError, "Invalid key type: " + `type(key)` return self.__handlers.has_key(_k) def clearHandlers(self): """Unset all the handlers for the tool. clearHandlers() This function does not alter the Tool's object list. """ self.__handlers.clear() def setObjtype(self, objtype): """Store the type of objects on which the tool operates. setObjtype(objtype) Argument 'objtype' can be a single type, a tuple of types, or 'None'. """ if not isinstance(objtype, (tuple, types.NoneType, types.TypeType)): raise TypeError, "Invalid objtype: " + `type(objtype)` if objtype is not None: if isinstance(objtype, tuple): for _obj in objtype: if not isinstance(_obj, types.TypeType): raise TypeError, "Invalid objtype: " + `type(_obj)` self.__objtype = objtype def getObjtype(self): """Return the type of object on which the tool operates. getObjtype() This method returns the value set in a setObjtype(), or None if no object types have been specified. """ return self.__objtype def setFilter(self, proc): """Store a procedure used to examine selected objects. setFilter(proc) Argument 'proc' must be a callable procedure. """ if not callable(proc): raise TypeError, "Invalid filter procedure: " + `type(proc)` self.__fproc = proc def getFilter(self): """Return a stored procedure. getFilter() This method returns the procedure stored vai setFilter() or None. """ return self.__fproc def pushObject(self, obj): """Add an object to the Tool's object list. pushObject(obj) """ self.__objlist.append(obj) def popObject(self): """Remove the last object on the Tool's object list. popObject() If the object list is empty, this function returns None. """ _obj = None if len(self.__objlist): _obj = self.__objlist.pop() return _obj def delObjects(self): """Remove all objects from the Tool's object list. delObjects() This function does not alter the Tool's handlers. """ del self.__objlist[:] def getObject(self, idx): """Access an object in the tool. getObject(idx) The argument 'idx' is the index into the list of stored objects. """ return self.__objlist[idx] def setLocation(self, x, y): """Store an x/y location in the tool. setLocation(x,y) Store an x-y coordinate in the tool. Both arguments should be floats """ _x = util.get_float(x) _y = util.get_float(y) self.__location = (_x,_y) def getLocation(self): """Return the stored location in the tool getLocation() """ return self.__location def clearLocation(self): """Reset the location to an empty value. clearLocation() """ self.__location = None def setCurrentPoint(self, x, y): """Set the tool's current point. setCurrentPoint(x,y) Store an x-y coordinate in the tool. Both arguments should be int. """ _x = x if not isinstance(_x, int): _x = int(x) _y = y if not isinstance(_y, int): _y = int(y) self.__curpoint = (_x, _y) def getCurrentPoint(self): """Return the tool's current point value. getCurrentPoint() """ return self.__curpoint def clearCurrentPoint(self): """Reset the current point to an empty value clearCurrentPoint() """ self.__curpoint = None def create(self, image): """Create an object the tool is designed to construct. create(image) The argument 'image' is an image in which the newly created object will be added. In the Tool class, this method does nothing. It is meant to be overriden in classed using the Tool class as a base class. """ pass # override # # The ZoomTool, PasteTool, SelectTool, and DeselectTool classes are # subclasses of the Tool class but with no additional functionality (yet) class ZoomPan(Tool): pass class ZoomTool(Tool): pass class PasteTool(Tool): pass class SelectTool(Tool): pass class DeselectTool(Tool): pass class PointTool(Tool): """ A specialized tool for drawing Point objects. The PointTool class is derived from the Tool class, so it shares the methods and attributes of that class. The PointTool class has the following additional methods: """ def __init__(self): super(PointTool, self).__init__() self.__point = None def setPoint(self, p): """ Store a Point in the tool Argument: p should be Point """ self.__point = p def getPoint(self): """ Get the stored Point from the tool This method returns a Poiny containing the values passed in with the setPoint() method, or None if that method has not been invoked. """ return self.__point def reset(self): """ Restore the tool to its initial state. This method extends Tool::reset(). """ super(PointTool, self).reset() self.__point = None def create(self, image): """ Create a new Point and add it to the image. This method overrides the Tool::create() method. """ if self.__point is not None: _active_layer = image.getActiveLayer() _active_layer.addObject(self.__point.point) self.reset() class SegmentTool(Tool): """ A Specialized tool for drawing Segment objects. The SegmentTool class is derived from the Tool class, so it shares the attributes and methods of that class. The SegmentTool class has the following additional methods: """ def __init__(self): super(SegmentTool, self).__init__() self.__first_point = None self.__second_point = None self.__direction = None def setFirstPoint(self, snapPoint): """ Store the first point of the Segment. Arguments 'x' and 'y' should be floats. """ self.__first_point = snapPoint def getFirstPoint(self): """ Get the first point of the Segment. This method returns a tuple holding the coordinates stored by invoking the setFirstPoint() method, or None if that method has not been invoked. """ return self.__first_point def setSecondPoint(self, snapPoint): """ Store the second point of the Segment. Arguments 'x' and 'y' should be floats. If the tool has not had the first point set with setFirstPoint(), a ValueError exception is raised. """ if self.__first_point is None: raise ValueError, "SegmentTool first snapPoint is not set." self.__second_point = snapPoint def getSecondPoint(self): """ Get the second point of the Segment. This method returns a tuple holding the coordinates stored by invoking the setSecondPoint() method, or None if that method has not been invoked. """ return self.__second_point def reset(self): """ Restore the tool to its initial state. This method extends Tool::reset(). """ super(SegmentTool, self).reset() self.__first_point = None self.__second_point = None def create(self, image): """ Create a new Segment and add it to the image. This method overrides the Tool::create() method. """ if (self.__first_point is not None and self.__second_point is not None): _active_layer = image.getActiveLayer() _x1, _y1 ,_x2, _y2 = getSegmentSnap(self.__first_point ,self.__second_point) _pts = _active_layer.find('point', _x1, _y1) if len(_pts) == 0: _p1 = Point(_x1, _y1) _active_layer.addObject(_p1) else: _p1 = _pts[0] _pts = _active_layer.find('point', _x2, _y2) if len(_pts) == 0: _p2 = Point(_x2, _y2) _active_layer.addObject(_p2) else: _p2 = _pts[0] _s = image.getOption('LINE_STYLE') _seg = Segment(_p1, _p2, _s) _l = image.getOption('LINE_TYPE') if _l != _s.getLinetype(): _seg.setLinetype(_l) _c = image.getOption('LINE_COLOR') if _c != _s.getColor(): _seg.setColor(_c) _t = image.getOption('LINE_THICKNESS') if abs(_t - _s.getThickness()) > 1e-10: _seg.setThickness(_t) _active_layer.addObject(_seg) self.reset() def setDirection(self,angle): """ set orizontal """ if angle is None: self.__direction=None return _ang=float(angle) self.__direction=_ang def getDirection(self): """ get the direction """ return self.__direction direction=property(getDirection,setDirection,None,"Direction of the line") class RectangleTool(SegmentTool): """A Specialized tool for drawing rectangles. The RectangleTool is derived from the SegmentTool, so it shares all the methods and attributes of that class. A RectangleTool creates four Segments in the shape of a rectangle in the image. """ def __init__(self): super(RectangleTool, self).__init__() def create(self, image): """Create Segments and add them to the image. create(image) This method overrides the SegmentTool::create() method. """ _p1 = self.getFirstPoint().point _p2 = self.getSecondPoint().point if _p1 is not None and _p2 is not None: _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _active_layer = image.getActiveLayer() _pts = _active_layer.find('point', _x1, _y1) if len(_pts) == 0: _p1 = Point(_x1, _y1) _active_layer.addObject(_p1) else: _p1 = _pts[0] _pts = _active_layer.find('point', _x1, _y2) if len(_pts) == 0: _p2 = Point(_x1, _y2) _active_layer.addObject(_p2) else: _p2 = _pts[0] _pts = _active_layer.find('point', _x2, _y2) if len(_pts) == 0: _p3 = Point(_x2, _y2) _active_layer.addObject(_p3) else: _p3 = _pts[0] _pts = _active_layer.find('point', _x2, _y1) if len(_pts) == 0: _p4 = Point(_x2, _y1) _active_layer.addObject(_p4) else: _p4 = _pts[0] _s = image.getOption('LINE_STYLE') _l = image.getOption('LINE_TYPE') if _l == _s.getLinetype(): _l = None _c = image.getOption('LINE_COLOR') if _c == _s.getColor(): _c = None _t = image.getOption('LINE_THICKNESS') if abs(_t - _s.getThickness()) < 1e-10: _t = None _seg = Segment(_p1, _p2, _s, linetype=_l, color=_c, thickness=_t) _active_layer.addObject(_seg) _seg = Segment(_p2, _p3, _s, linetype=_l, color=_c, thickness=_t) _active_layer.addObject(_seg) _seg = Segment(_p3, _p4, _s, linetype=_l, color=_c, thickness=_t) _active_layer.addObject(_seg) _seg = Segment(_p4, _p1, _s, linetype=_l, color=_c, thickness=_t) _active_layer.addObject(_seg) self.reset() class CircleTool(Tool): """ A Specialized tool for drawing Circle objects. The CircleTool is derived from the Tool class, so it shares all the methods and attributes of that class. The CircleTool class has the following addtional methods: """ def __init__(self): super(CircleTool, self).__init__() self.__center = None self.__radius = None self.__radiusPoint=None def setRadiusPoint(self,snapPoint): """ set The radius point Cliched """ if not isinstance(snapPoint,SnapPointStr): raise TypeError, "Invalid SnapPointStr type : " + `type(snapPoint)` self.__radiusPoint=snapPoint def getRadiusPoint(self): """ Return the radiuspoint clicked by the user """ return self.__radiusPoint radiusPoint=property(getRadiusPoint,setRadiusPoint,None,"Radius point cliched by the user") def setCenter(self, snapPoint): """ Set the center point location of the circle. The arguments snapPoint give the location for the center of the circle. """ if not isinstance(snapPoint,SnapPointStr): raise TypeError, "Invalid SnapPointStr type : " + `type(snapPoint)` self.__center = snapPoint def getCenter(self): """ Get the center point location of the circle. This method returns the SnapPointStr stored with the setCenter() method, or None if that method has not been called. """ return self.__center center =property(getCenter,setCenter,None,"center point") def setRadius(self, radius): """Set the radius of the circle. setRadius(radius) The argument 'radius' must be a float value greater than 0.0 """ _r = util.get_float(radius) if not _r > 0.0: raise ValueError, "Invalid radius: %g" % _r self.__radius = _r def getRadius(self): """Get the radius of the circle. getRadius() This method returns the value specified from the setRadius() call, or None if that method has not been invoked. """ return self.__radius def reset(self): """ Restore the tool to its initial state. This method extends Tool::reset(). """ super(CircleTool, self).reset() self.__center = None self.__radius = None self.__radiusPoint=None def create(self, image): """ Create a new Circle and add it to the image. This method overrides the Tool::create() method. """ if (self.__center is not None and self.__radius is not None): _active_layer = image.getActiveLayer() _x, _y = self.__center.point.getCoords() _r = self.__radius _pts = _active_layer.find('point', _x, _y) if len(_pts) == 0: _cp = Point(_x, _y) _active_layer.addObject(_cp) else: _cp = _pts[0] _s = image.getOption('LINE_STYLE') _circle = Circle(_cp, _r, _s) _l = image.getOption('LINE_TYPE') if _l != _s.getLinetype(): _circle.setLinetype(_l) _c = image.getOption('LINE_COLOR') if _c != _s.getColor(): _circle.setColor(_c) _t = image.getOption('LINE_THICKNESS') if abs(_t - _s.getThickness()) > 1e-10: _circle.setThickness(_t) _active_layer.addObject(_circle) self.reset() class TwoPointCircleTool(CircleTool): """A specialized class for drawing Circles between two points. The TwoPointCircleTool class is derived from the CircleTool class, so it shares all the methods and attributes of that class. The TwoPointCircleTool class has the following addtional methods: {set/get}FirstPoint(): Set/Get the first point used to define the circle. {set/get}SecondPoint(): Set/Get the second point used to define the circle. """ def __init__(self): super(TwoPointCircleTool, self).__init__() self.__first_point = None self.__second_point = None def setFirstPoint(self, p): """ Set the first point used to define the location of the circle. Arguments p give the location of a point. """ self.__first_point = p def getFirstPoint(self): """Get the first point used to define the location of the circle. getFirstPoint() This method returns a tuple holding the values used when the setFirstPoint() method was called, or None if that method has not yet been used. """ return self.__first_point def setSecondPoint(self, p): """Set the second point used to define the location of the circle. setSecondPoint(x, y) Arguments 'x' and 'y' give the location of a point. Invoking this method before the setFirstPoint() method will raise a ValueError. """ _x,_y=p.point.getCoords() if self.__first_point is None: raise ValueError, "First point is not set" _x1, _y1 = self.__first_point.point.getCoords() _xc = (_x + _x1)/2.0 _yc = (_y + _y1)/2.0 _radius = math.hypot((_x - _x1), (_y - _y1))/2.0 _strPoint=SnapPointStr("Freepoint",Point(_xc,_yc),None) self.setCenter(_strPoint) self.setRadius(_radius) self.__second_point = (_x, _y) def getSecondPoint(self): """Get the second point used to define the location of the circle. getSecondPoint() This method returns a tuple holding the values used when the setSecondPoint() method was called, or None if that method has not yet been used. """ return self.__second_point def reset(self): """Restore the tool to its initial state. reset() This method extends CircleTool::reset(). """ super(TwoPointCircleTool, self).reset() self.__first_point = None self.__second_point = None class ArcTool(CircleTool): """A specialized tool for drawing Arc objects. The ArcTool is Derived from the CircleTool class, so it shares all the attributes and methods of that class. The ArcTool class has the following addtional methods: {set/get}StartAngle(): Set/Get the start angle of the arc {set/get}EndAngle(): Set/Get the end angle of the arc. """ def __init__(self): super(ArcTool, self).__init__() self.__start_angle = None self.__end_angle = None def setStartAngle(self, angle): """Set the start angle of the arc. setStartAngle(angle) The argument 'angle' should be a float value between 0.0 and 360.0 """ _angle = util.make_c_angle(angle) self.__start_angle = _angle def getStartAngle(self): """Return the start angle of the arc. getStartAngle() This method returns the value defined in the previous setStartAngle() call, or None if that method has not been called. """ return self.__start_angle def setEndAngle(self, angle): """Set the start angle of the arc. setStartAngle(angle) The argument 'angle' should be a float value between 0.0 and 360.0 """ _angle = util.make_c_angle(angle) self.__end_angle = _angle def getEndAngle(self): """Return the end angle of the arc. getEndAngle() This method returns the value defined in the previous setEndAngle() call, or None if that method has not been called. """ return self.__end_angle def reset(self): """Restore the tool to its initial state. reset() This method extends CircleTool::reset(). """ super(ArcTool, self).reset() self.__start_angle = None self.__end_angle = None def create(self, image): """Create a new Arc and add it to the image. create(image) This method overrides the CircleTool::create() method. """ _center = self.getCenter() _radius = self.getRadius() _sa = self.__start_angle _ea = self.__end_angle if (_center is not None and _radius is not None and _sa is not None and _ea is not None): _active_layer = image.getActiveLayer() _x, _y = _center.point.getCoords() _pts = _active_layer.find('point', _x, _y) if len(_pts) == 0: _cp = Point(_x, _y) _active_layer.addObject(_cp) else: _cp = _pts[0] _s = image.getOption('LINE_STYLE') _arc = Arc(_cp, _radius, _sa, _ea, _s) _l = image.getOption('LINE_TYPE') if _l != _s.getLinetype(): _arc.setLinetype(_l) _c = image.getOption('LINE_COLOR') if _c != _s.getColor(): _arc.setColor(_c) _t = image.getOption('LINE_THICKNESS') if abs(_t - _s.getThickness()) > 1e-10: _arc.setThickness(_t) for _ep in _arc.getEndpoints(): _ex, _ey = _ep _pts = _active_layer.find('point', _ex, _ey) if len(_pts) == 0: _lp = Point(_ex, _ey) _active_layer.addObject(_lp) _active_layer.addObject(_arc) self.reset() # # The ChamferTool and FilletTool class are subclasses of # the Tool class but have no additional functionality (yet) # class ChamferTool(Tool): pass class FilletTool(Tool): """ A specifie tool for drawing Fillet used to manage radius imput """ def __init__(self): super(FilletTool, self).__init__() self.__Radius=None def GetRadius(self): """ get the fillet radius """ return self.__Radius def SetRadius(self,rad): """ set the fillet radius """ self.__Radius=rad rad=property(GetRadius,SetRadius,None,"Get The Fillet Radius.") class FilletTwoLineTool(FilletTool): """ A specifie tool for drawing fillet using two segment """ def __init__(self): super(FilletTwoLineTool, self).__init__() self.__FirstLine=None self.__SecondLine=None self.__SecondPoint=None self.__FirstPoint=None self.__TrimMode='b' def GetFirstLine(self): return self.__FirstLine def SetFirstLine(self,obj): if obj==None: raise "None Object" if not isinstance(obj,Segment): raise "Invalid object Need Segment or CLine" self.__FirstLine=obj def GetSecondLine(self): return self.__SecondLine def SetSecondtLine(self,obj): if obj==None: raise "None Object" if not isinstance(obj,Segment): raise "Invalid object Need Segment or CLine" self.__SecondLine=obj FirstLine=property(GetFirstLine,SetFirstLine,None,"Set first line object in the tool") SecondLine=property(GetSecondLine,SetSecondtLine,None,"Set second line object in the tool") def GetFirstPoint(self): """ Return the first toolpoint """ return self.__FirstPoint def SetFirstPoint(self,point): """ Set the first toolpoint """ if point==None: raise "None Object" if not isinstance(point,Point): raise "Invalid object Need Point" self.__FirstPoint=point def GetSecondPoint(self): """ Return the second toolpoint """ return self.__SecondPoint def SetSecondPoint(self,point): """ Set the second toolpoint """ if point==None: raise "None Object" if not isinstance(point,Point): raise "Invalid object Need Point" self.__SecondPoint=point FirstPoint=property(GetFirstPoint,SetFirstPoint,None,"First line object in the tool") SecondPoint=property(GetSecondPoint,SetSecondPoint,None,"Second line object in the tool") def SetTrimMode(self,mode): """ set the trim mode """ self.__TrimMode=mode def GetTrimMode(self): """ get the trim mode """ return self.__TrimMode TrimMode=property(GetTrimMode,SetTrimMode,None,"Trim Mode") def Create(self,image): """ Create the Fillet """ interPnt=[] if self.FirstLine != None and self.SecondLine != None : intersections._seg_seg_intersection(interPnt,self.__FirstLine,self.__SecondLine) else: if self.FirstLine==None: raise "tools.fillet.Create: First obj is null" if self.SecondLine==None: raise "tools.fillet.Create: Second obj is null" if(len(interPnt)): _active_layer = image.getActiveLayer() _s = image.getOption('LINE_STYLE') _l = image.getOption('LINE_TYPE') _c = image.getOption('LINE_COLOR') _t = image.getOption('LINE_THICKNESS') p1,p2=self.FirstLine.getEndpoints() p11,p12=self.SecondLine.getEndpoints() p1=Point(p1.getCoords()) p2=Point(p2.getCoords()) p11=Point(p11.getCoords()) p12=Point(p12.getCoords()) # interPoint1=Point(interPnt[0]) _active_layer.addObject(interPoint1) interPoint2=Point(interPnt[0]) _active_layer.addObject(interPoint2) # # new function for calculating the new 2 points # self.setRightPoint(image,self.FirstLine,self.FirstPoint,interPoint1) self.setRightPoint(image,self.SecondLine,self.SecondPoint,interPoint2) _fillet=Fillet(self.FirstLine, self.SecondLine,self.rad, _s) if _l != _s.getLinetype(): _fillet.setLinetype(_l) if _c != _s.getColor(): _fillet.setColor(_c) if abs(_t - _s.getThickness()) > 1e-10: _fillet.setThickness(_t) _active_layer.addObject(_fillet) # # Adjust the lines # if self.TrimMode=='f' or self.TrimMode=='n': image.delObject(self.SecondLine.p1) image.delObject(self.SecondLine.p2) self.SecondLine.p1=p11 self.SecondLine.p2=p12 _active_layer.addObject(p11) _active_layer.addObject(p12) if self.TrimMode=='s' or self.TrimMode=='n': image.delObject(self.FirstLine.p1) image.delObject(self.FirstLine.p2) self.FirstLine.p1=p1 self.FirstLine.p2=p2 _active_layer.addObject(p1) _active_layer.addObject(p2) def setRightPoint(self,image,objSegment,objPoint,objInterPoint): """ Get the point used for the trim """ _p1 , _p2 = objSegment.getEndpoints() _x,_y = objPoint.getCoords() _objPoint=Point(objSegment.getProjection(_x,_y)) if not (_p1==objInterPoint or _p2==objInterPoint): pickIntVect=pyGeoLib.Vector(objInterPoint,_objPoint).Mag() p1IntVect=pyGeoLib.Vector(objInterPoint,_p1).Mag() if(pickIntVect==p1IntVect): objSegment.p2=objInterPoint image.delObject(_p2) return p2IntVect=pyGeoLib.Vector(objInterPoint,_p2).Mag() if(pickIntVect==p2IntVect): objSegment.p1=objInterPoint image.delObject(_p1) return ldist=_objPoint.Dist(_p1) if ldist>_objPoint.Dist(_p2): objSegment.p2=objInterPoint image.delObject(_p2) else: objSegment.p1=objInterPoint image.delObject(_p1) class LeaderTool(Tool): """ A specialized tool for drawing Leader objects. The LeaderTool class is derived from the Tool class, so it shares the methods and attributes of that class. """ def __init__(self): super(LeaderTool, self).__init__() self.__start_point = None self.__mid_point = None self.__end_point = None def setFirstPoint(self, p): """Set the first point used to define the Leader. setFirstPoint(x, y) Arguments 'x' and 'y' give the location of a point. """ self.__start_point = p def getFirstPoint(self): """Get the first point used to define the Leader. getFirstPoint() This method returns a tuple holding the values used when the setFirstPoint() method was called, or None if that method has not yet been used. """ return self.__start_point def setMidPoint(self, p): """Set the second point used to define the Leader. setMidPoint(x, y) Arguments 'x' and 'y' give the location of a point. If the first point has not been set this method raises a ValueError. """ if self.__start_point is None: raise ValueError, "First point not set in LeaderTool." self.__mid_point =p def getMidPoint(self): """Get the second point used to define the Leader. getMidPoint() This method returns a tuple holding the values used when the setMidPoint() method was called, or None if that method has not yet been used. """ return self.__mid_point def setFinalPoint(self,p): """Set the first point used to final point of the Leader. Arguments 'x' and 'y' give the location of a point. This method raises an error if the first point or second point have not been set. """ if self.__start_point is None: raise ValueError, "First point not set in LeaderTool." if self.__mid_point is None: raise ValueError, "Second point not set in LeaderTool." self.__end_point = p def getFinalPoint(self): """Get the third point used to define the Leader. getFinalPoint() This method returns a tuple holding the values used when the setFinalPoint() method was called, or None if that method has not yet been used. """ return self.__end_point def reset(self): """Restore the tool to its initial state. reset() This method extends Tool::reset(). """ super(LeaderTool, self).reset() self.__start_point = None self.__mid_point = None self.__end_point = None def create(self, image): """Create a new Leader and add it to the image. create(image) This method overrides the Tool::create() method. """ if (self.__start_point is not None and self.__mid_point is not None and self.__end_point is not None): _active_layer = image.getActiveLayer() _x1, _y1 = self.__start_point.point.getCoords() _x2, _y2 = self.__mid_point.point.getCoords() _x3, _y3 = self.__end_point.point.getCoords() _pts = _active_layer.find('point', _x1, _y1) if len(_pts) == 0: _p1 = Point(_x1, _y1) _active_layer.addObject(_p1) else: _p1 = _pts[0] _pts = _active_layer.find('point', _x2, _y2) if len(_pts) == 0: _p2 = Point(_x2, _y2) _active_layer.addObject(_p2) else: _p2 = _pts[0] _pts = _active_layer.find('point', _x3, _y3) if len(_pts) == 0: _p3 = Point(_x3, _y3) _active_layer.addObject(_p3) else: _p3 = _pts[0] _size = image.getOption('LEADER_ARROW_SIZE') _s = image.getOption('LINE_STYLE') _leader = Leader(_p1, _p2, _p3, _size, _s) _l = image.getOption('LINE_TYPE') if _l != _s.getLinetype(): _leader.setLinetype(_l) _c = image.getOption('LINE_COLOR') if _c != _s.getColor(): _leader.setColor(_c) _t = image.getOption('LINE_THICKNESS') if abs(_t - _s.getThickness()) > 1e-10: _leader.setThickness(_t) _active_layer.addObject(_leader) self.reset() class PolylineTool(Tool): """ A specialized tool for drawing Polyline objects. The PolylineTool class is derived from the Tool class, so it shares all the attributes and methods of that class. """ def __init__(self): super(PolylineTool, self).__init__() self.__points = [] def __len__(self): return len(self.__points) def storePoint(self,p): """ Store a point that will define a Polyline. The arguments 'x' and 'y' should be float values. There is no limit as to how long a Polyline should be, so each invocation of this method appends the values to the list of stored points. """ self.__points.append(p) def getPoint(self, i): """ Retrieve a point used to define a Polyline. Argument 'i' represents the index in the list of points that defines the polyline. Negative indicies will get points from last-to-first. Using an invalid index will raise an error. This method returns a tuple holding the x/y coordinates. """ return self.__points[i] def getPoints(self): """ Get all the points that define the Polyline. This method returns a list of tuples holding the x/y coordinates of all the points that define the Polyline. """ return self.__points[:] def reset(self): """ Restore the tool to its initial state. This method extends Tool::reset(). """ super(PolylineTool, self).reset() del self.__points[:] def create(self, image): """ Create a new Polyline and add it to the image. This method overrides the Tool::create() method. """ if len(self.__points): _pts = [] _active_layer = image.getActiveLayer() _sp=None for _pt in self.__points: if _sp is None: _sp=_pt _x,_y=_pt.point.getCoords() _lpts = _active_layer.find('point', _x, _y) if len(_lpts) == 0: _p = Point(_x, _y) _active_layer.addObject(_p) _pts.append(_p) else: _pts.append(_lpts[0]) else: _x1, _y1 ,_x2, _y2 = getSegmentSnap(_sp,_pt) _lpts = _active_layer.find('point', _x2, _y2) if len(_lpts) == 0: _p = Point(_x2, _y2) _active_layer.addObject(_p) else: _p=_lpts[0] _pts.append(_p) _pt.point=_p _sp=_pt _s = image.getOption('LINE_STYLE') _pline = Polyline(_pts, _s) _l = image.getOption('LINE_TYPE') if _l != _s.getLinetype(): _pline.setLinetype(_l) _c = image.getOption('LINE_COLOR') if _c != _s.getColor(): _pline.setColor(_c) _t = image.getOption('LINE_THICKNESS') if abs(_t - _s.getThickness()) > 1e-10: _pline.setThickness(_t) _active_layer.addObject(_pline) self.reset() class PolygonTool(Tool): """ A specialized to for creating Polygons from Segments. The PolygonTool will create an uniformly sized polygon from Segment entities. The minimum number of sides is three, creating an equilateral triangle. There is no maximum number of sides, though realistically any polygon with more than 20 or so sides is unlikely to be drawn. As the PolygonTool is derived from the Tool class, it shares all the attributes and method of that class. """ def __init__(self): super(PolygonTool, self).__init__() self.__nsides = None self.__increment = None self.__external = False self.__center = None self.__xpts = array.array("d") self.__ypts = array.array("d") def setSideCount(self, count): """ Set the number of sides of the polygon to create. Argument "count" should be an integer value greater than 2. """ _count = count if not isinstance(_count, int): _count = int(count) if _count < 3: raise ValueError, "Invalid count: %d" % _count self.__nsides = _count self.__increment = (360.0/float(_count)) * (math.pi/180.0) for _i in range(_count): self.__xpts.insert(_i, 0.0) self.__ypts.insert(_i, 0.0) def getSideCount(self): """ Get the number of sides of the polygon to be created. A ValueError exception is raised if the side count has not been set with setSideCount() """ if self.__nsides is None: raise ValueError, "No side count defined." return self.__nsides def setExternal(self): """ Create the polygon on the outside of a reference circle. By default the polygon is drawing completely contained within a circle. Invoking this method will created the polygon so that all sides are outside the circle. """ self.__external = True def getExternal(self): """ Test if the polygon will be created outside a circle. If the setExternal() method has been called, this method will return True. By default this method will return False. """ return self.__external def setCenter(self, p): """Define the center of the polygon. setCenter(x, y) Arguments 'x' and 'y' should be float values. """ self.__center = p def getCenter(self): """Retrieve the center of the polygon to be created. getCenter() This method returns a tuple holding two float values containing the 'x' and 'y' coordinates of the polygon center. A ValueError is raised if the center has not been set with a prior call to setCenter(). """ if self.__center is None: raise ValueError, "Center is undefined." return self.__center def getCoord(self, i): """Get one of the coordinates of the polygon corners. getCoord(i) Argument "i" should be an integer value such that: 0 <= i <= number of polygon sides """ _x = self.__xpts[i] _y = self.__ypts[i] return _x, _y def setLocation(self, p): """Set the tool location. setLocation(x, y) This method extends Tool::setLocation() and calculates the polygon points. """ _x,_y=p.point.getCoords() super(PolygonTool, self).setLocation(_x, _y) _x, _y = self.getLocation() _count = self.__nsides _inc = self.__increment if self.__external: _offset = _inc/2.0 else: _offset = 0.0 _cx, _cy = self.__center.point.getCoords() _xsep = _x - _cx _ysep = _y - _cy _angle = math.atan2(_ysep, _xsep) + _offset _rad = math.hypot(_xsep, _ysep)/math.cos(_offset) _xp = self.__xpts _yp = self.__ypts for _i in range(_count): _xp[_i] = _cx + (_rad * math.cos(_angle)) _yp[_i] = _cy + (_rad * math.sin(_angle)) _angle = _angle + _inc def create(self, image): """Create a Polygon from Segments and add it to the image. create(image) This method overrides the Tool::create() method. """ if len(self.__xpts): _active_layer = image.getActiveLayer() _s = image.getOption('LINE_STYLE') _l = image.getOption('LINE_TYPE') if _l == _s.getLinetype(): _l = None _c = image.getOption('LINE_COLOR') if _c == _s.getColor(): _c = None _t = image.getOption('LINE_THICKNESS') if abs(_t - _s.getThickness()) < 1e-10: _t = None _count = self.__nsides _xp = self.__xpts _yp = self.__ypts _x = _xp[0] _y = _yp[0] # # find starting point ... # _pts = _active_layer.find('point', _x, _y) if len(_pts) == 0: _p0 = Point(_x, _y) _active_layer.addObject(_p0) else: _p0 = _pts[0] # # make segments for all the points ... # _p1 = _p0 for _i in range(1, _count): _x = _xp[_i] _y = _yp[_i] _pts = _active_layer.find('point', _x, _y) if len(_pts) == 0: _pi = Point(_x, _y) _active_layer.addObject(_pi) else: _pi = _pts[0] _seg = Segment(_p1, _pi, _s, linetype=_l, color=_c, thickness=_t) _active_layer.addObject(_seg) _p1 = _pi # # now add closing segment ... # _seg = Segment(_p1, _p0, _s, linetype=_l, color=_c, thickness=_t) _active_layer.addObject(_seg) self.reset() def reset(self): """Restore the PolygonTool to its original state. reset() This method extends Tool::reset() """ super(PolygonTool, self).reset() # self.__nsides = None # self.__increment = None # self.__external = False # make this adjustable? self.__center = None for _i in range(self.__nsides): self.__xpts[_i] = 0.0 self.__ypts[_i] = 0.0 class HCLineTool(PointTool): """A specialized tool for drawing HCLine objects. The HCLineTool class is derived from the PointTool class so it shares all the attributes and methods of that class. There are no additional methods for this class. """ def __init__(self): super(HCLineTool, self).__init__() def create(self, image): """ Create a new HCLine and add it to the image. This method overrides the Tool::create() method. """ _p = self.getPoint().point if _p is not None: _active_layer = image.getActiveLayer() _x, _y = _p.getCoords() _pts = _active_layer.find('point', _x, _y) if len(_pts) == 0: _pt = Point(_x, _y) _active_layer.addObject(_pt) else: _pt = _pts[0] _hcl = HCLine(_pt) _active_layer.addObject(_hcl) self.reset() class VCLineTool(PointTool): """A specialized tool for drawing VCLine objects. The VCLineTool class is derived from the PointTool class so it shares all the attributes and methods of that class. There are no additional methods for this class. """ def __init__(self): super(VCLineTool, self).__init__() def create(self, image): """Create a new VCLine and add it to the image. create(image) This method overrides the Tool::create() method. """ _p = self.getPoint().point if _p is not None: _active_layer = image.getActiveLayer() _x, _y = _p.getCoords() _pts = _active_layer.find('point', _x, _y) if len(_pts) == 0: _pt = Point(_x, _y) _active_layer.addObject(_pt) else: _pt = _pts[0] _vcl = VCLine(_pt) _active_layer.addObject(_vcl) self.reset() class ACLineTool(PointTool): """A specialized tool for drawing ACLine objects. The ACLineTool class is derived from the PointTool class so it shares all the attributes and methods of that class. The ACLineTool class has the following addtional methods: {set/get}Angle(): Set/Get the angle of the ACLine. """ def __init__(self): super(ACLineTool, self).__init__() self.__angle = None def setLocation(self, p): """Set the location of the Tool. setLocation(x, y) This method extends the Tool::setLocation() method. """ _x,_y=p.point.getCoords() super(ACLineTool, self).setLocation(_x, _y) _loc = self.getLocation() if _loc is None: return _x, _y = _loc _x1, _y1 = self.getPoint().point.getCoords() if abs(_y - _y1) < 1e-10: # horizontal self.__angle = 0.0 elif abs(_x - _x1) < 1e-10: # vertical self.__angle = 90.0 else: _slope = 180.0/math.pi * math.atan2((_y - _y1), (_x - _x1)) self.__angle = util.make_angle(_slope) def setAngle(self, angle): """Set the angle for the ACLine. setAngle(angle) The argument 'angle' should be a float where -90.0 < angle < 90.0 """ _angle = util.make_angle(angle) self.__angle = _angle def getAngle(self): """Get the angle for the ACLine. getAngle() This method returns a float. """ return self.__angle def reset(self): """Restore the tool to its initial state. reset() This method extends PointTool::reset(). """ super(ACLineTool, self).reset() self.__angle = None def create(self, image): """Create a new ACLine and add it to the image. create(image) This method overrides the Tool::create() method. """ _p = self.getPoint().point if (_p is not None and self.__angle is not None): _active_layer = image.getActiveLayer() _x, _y = _p.getCoords() _pts = _active_layer.find('point', _x, _y) if len(_pts) == 0: _pt = Point(_x, _y) _active_layer.addObject(_pt) else: _pt = _pts[0] _acl = ACLine(_pt, self.__angle) _active_layer.addObject(_acl) self.reset() class CLineTool(SegmentTool): """A specialized tool for drawing CLine objects. The CLineTool class is derived from the SegmentTool class, so it shares all the attributes and methods of that class. There are no extra methods for the CLineTool class. """ def __init__(self): super(CLineTool, self).__init__() def create(self, image): """Create a new CLine and add it to the image. create(image) This method overrides the Tool::create() method. """ _p1 = self.getFirstPoint().point _p2 = self.getSecondPoint().point if _p1 is not None and _p2 is not None: _active_layer = image.getActiveLayer() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _pts = _active_layer.find('point', _x1, _y1) if len(_pts) == 0: _p1 = Point(_x1, _y1) _active_layer.addObject(_p1) else: _p1 = _pts[0] _pts = _active_layer.find('point', _x2, _y2) if len(_pts) == 0: _p2 = Point(_x2, _y2) _active_layer.addObject(_p2) else: _p2 = _pts[0] _cline = CLine(_p1, _p2) _active_layer.addObject(_cline) self.reset() class CCircleTool(CircleTool): """A specialized tool for drawing CCircle objects. The CCircleTool class is derived from the CircleTool class, so it shares all the attributes and methods of that class. There are no additional methods for the CCircleTool class. """ def __init__(self): super(CCircleTool, self).__init__() def create(self, image): """Create a new CCircle and add it to the image. create(image) This method overrides the Tool::create() method. """ _active_layer = image.getActiveLayer() _x, _y = self.getCenter().point.getCoords() _radius = self.getRadius() _pts = _active_layer.find('point', _x, _y) if len(_pts) == 0: _cp = Point(_x, _y) _active_layer.addObject(_cp) else: _cp = _pts[0] _ccircle = CCircle(_cp, _radius) _active_layer.addObject(_ccircle) self.reset() class TwoPointCCircleTool(TwoPointCircleTool): """A specialized tool for drawing CCircle objects between two points. The TwoPointCCircleTool class is derived from the TwoPointCircleTool class, so it shares all the attributes and methods of that class. There are no additional methods for the TwoPointCCircleTool class. """ def __init__(self): super(TwoPointCCircleTool, self).__init__() def create(self, image): """Create a new CCircle and add it to the image. create(image) This method overrides the Tool::create() method. """ _center = self.getCenter() _radius = self.getRadius() if _center is not None and _radius is not None: _active_layer = image.getActiveLayer() _x, _y = _center.point.getCoords() _pts = _active_layer.find('point', _x, _y) if len(_pts) == 0: _cp = Point(_x, _y) _active_layer.addObject(_cp) else: _cp = _pts[0] _ccircle = CCircle(_cp, _radius) _active_layer.addObject(_ccircle) self.reset() # # The PerpendicularCLineTool and TangentCLineTool classes are # subclasses of Tool without any additional functionality (yet) # class PerpendicularCLineTool(Tool): pass class TangentCLineTool(Tool): pass class ParallelOffsetTool(Tool): """ A specialized tool for creating parallel construction lines. The ParallelOffsetTool will create a construction line parallel to another construction line a fixed distance from the original construction line. The type of the new construction line will match that of the original. The ParallelOffsetTool is derived from the Tool class, so it shares all the attributes and methods of that class. """ def __init__(self): super(ParallelOffsetTool, self).__init__() self.__refpt = None self.__offset = None self.__conline = None def setOffset(self, offset): """ Store the displacement in the tool. Argument 'offset' must be a float. """ _offset = util.get_float(offset) self.__offset = _offset def getOffset(self): """Return the stored offset from the tool. This method will raise a ValueError exception if the offset has not been set with setOffset() """ _offset = self.__offset if _offset is None: raise ValueError, "Offset is not defined." return _offset def setConstructionLine(self, conline): """ Store the reference construction line in the tool. Argument 'conline' must be a VCLine, HCLine, ACLine, or CLine object. """ if not isinstance(conline, (HCLine, VCLine, ACLine, CLine)): raise TypeError, "Invalid Construction line: " + `type(conline)` self.__conline = conline def getConstructionLine(self): """ Retrieve the stored construction line from the tool. A ValueError exception is raised if the construction line has not been set with the setConstructionLine() method. """ _conline = self.__conline if _conline is None: raise ValueError, "Construction line is not defined." return _conline def setReferencePoint(self, x,y): """ Store the reference point for positioning the new construction line. Arguments 'x' and 'y' give the coordinates of a reference point used to determine where the new construction line will be placed. Both arguments should be floats. """ self.__refpt = (x,y) def getReferencePoint(self): """ Retreive the reference point from the tool. This method returns a tuple containing the values stored from the setReferencePoint() call. This method will raise a ValueError exception if the reference point has not been set. """ _refpt = self.__refpt if _refpt is None: raise ValueError, "No reference point defined." return _refpt def reset(self): """ Restore the tool to its initial state. This method extends Tool::reset(). """ super(ParallelOffsetTool, self).reset() self.__refpt = None self.__offset = None self.__conline = None def create(self, image): """ Create a parallel construction line in an image. This method overrides the Tool::create() method. """ _offset = self.__offset _conline = self.__conline _refpt = self.__refpt if (_offset is not None and _conline is not None and _refpt is not None): _active_layer = image.getActiveLayer() _rx, _ry = _refpt _lp1 = _lp2 = _ncl = None if isinstance(_conline, HCLine): _x, _y = _conline.getLocation().getCoords() if _ry > _y: _yn = _y + _offset else: _yn = _y - _offset if len(_active_layer.find('hcline', _yn)) == 0: _pts = _active_layer.find('point', _x, _yn) if len(_pts) == 0: _lp1 = Point(_x, _yn) else: _lp1 = _pts[0] _ncl = HCLine(_lp1) elif isinstance(_conline, VCLine): _x, _y = _conline.getLocation().getCoords() if _rx > _x: _xn = _x + _offset else: _xn = _x - _offset if len(_active_layer.find('vcline', _xn)) == 0: _pts = _active_layer.find('point', _xn, _y) if len(_pts) == 0: _lp1 = Point(_xn, _y) else: _lp1 = _pts[0] _ncl = VCLine(_lp1) elif isinstance(_conline, ACLine): _x, _y = _conline.getLocation().getCoords() _angle = _conline.getAngle() if abs(_angle) < 1e-10: # horizontal _dx = 0.0 _dy = _offset elif abs(abs(_angle) - 90.0) < 1e-10: # vertical _dx = _offset _dy = 0.0 else: _slope = math.tan(_angle * (math.pi/180.0)) _yint = _y - (_slope * _x) # # p1 => (_x, _y) # p2 => (0, _yint) # # redefine angle from p1 to p2 ... _angle = math.atan2((_yint - _y), -_x) if _angle < 0.0: _angle = _angle + (2.0 * math.pi) _sqlen = math.hypot(_x, (_y - _yint)) _sn = ((_y - _ry) * (0.0 - _x)) - ((_x - _rx) * (_yint - _y)) _s = _sn/_sqlen if _s < 0.0: _perp = _angle + (math.pi/2.0) else: _perp = _angle - (math.pi/2.0) _dx = _offset * math.cos(_perp) _dy = _offset * math.sin(_perp) _angle = _conline.getAngle() # reset variable _xn = _x + _dx _yn = _y + _dy if len(_active_layer.find('acline', _xn, _yn, _angle)) == 0: _pts = _active_layer.find('point', _xn, _yn) if len(_pts) == 0: _lp1 = Point(_xn, _yn) else: _lp1 = _pts[0] _ncl = ACLine(_lp1, _angle) elif isinstance(_conline, CLine): _p1, _p2 = _conline.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() if abs(_x2 - _x1) < 1e-10: # vertical _dx = _offset _dy = 0.0 elif abs(_y2 - _y1) < 1e-10: # horizontal _dx = 0.0 _dy = _offset else: _angle = math.atan2((_y2 - _y1), (_x2 - _x1)) if _angle < 0.0: _angle = _angle + (2.0 * math.pi) _sqlen = math.hypot((_x2 - _x1), (_y2 - _y1)) _sn = ((_y1 - _ry) * (_x2 - _x1)) - ((_x1 - _rx) * (_y2 - _y1)) _s = _sn/_sqlen if _s < 0.0: _perp = _angle + (math.pi/2.0) else: _perp = _angle - (math.pi/2.0) _dx = math.cos(_perp) * _offset _dy = math.sin(_perp) * _offset _x1n = _x1 + _dx _y1n = _y1 + _dy _x2n = _x2 + _dx _y2n = _y2 + _dy if len(_active_layer.find('cline', _x1n, _y1n, _x2n, _y2n)) == 0: _pts = _active_layer.find('point', _x1n, _y1n) if len(_pts) == 0: _lp1 = Point(_x1n, _y1n) else: _lp1 = _pts[0] _pts = _active_layer.find('point', _x2n, _y2n) if len(_pts) == 0: _lp2 = Point(_x2n, _y2n) else: _lp2 = _pts[0] _ncl = CLine(_lp1, _lp2) else: raise TypeError, "Invalid Construction line type: " + `type(_conline)` if _ncl is not None: if _lp1 is not None and _lp1.getParent() is None: _active_layer.addObject(_lp1) if _lp2 is not None and _lp2.getParent() is None: _active_layer.addObject(_lp2) _active_layer.addObject(_ncl) self.reset() class TangentCircleTool(Tool): """ A specialized class for creating tangent construction circles. This class is meant to be a base class for tools that create tangent construction circles. It is derived from the tool class so it shares all the attributes and methods of that class. This class has the following additional methods: """ def __init__(self): super(TangentCircleTool, self).__init__() self.__center = None self.__radius = None self.__rect = None def setCenter(self, x, y): """Store the tangent circle center point in the tool. setCenter(x, y) Arguments 'x' and 'y' should be floats. """ _x = util.get_float(x) _y = util.get_float(y) self.__center = (_x, _y) def getCenter(self): """Return the center of the tangent circle. getCenter() This method returns a tuple holding two floats, the first is the 'x' coordinate of the center, the second is the 'y' coordinate. If the tool has not yet been invoked with a setLocation() call, this method returns None. """ return self.__center def setRadius(self, radius): """Store the radius in the tool. setRadius(radius) Argument 'radius' should be a float. """ _radius = util.get_float(radius) self.__radius = _radius def getRadius(self): """Return the center of the tangent circle. getRadius() This method returns a float giving the radius of the tangent circle, or None if the radius is not set. """ return self.__radius def setPixelRect(self, xmin, ymin, width, height): """Store the screen coordinates used to draw the circle. setPixelRect(xmin, ymin, width, height) All the arguments should be integer values. """ _xmin = xmin if not isinstance(_xmin, int): _xmin = int(xmin) _ymin = ymin if not isinstance(_ymin, int): _ymin = int(ymin) _width = width if not isinstance(_width, int): _width = int(_width) _height = height if not isinstance(_height, int): _height = int(height) self.__rect = (_xmin, _ymin, _width, _height) def getPixelRect(self): """Return the screen boundary of the circle to draw getPixelRect(self) This method will return a tuple holding four integer values: xmin, ymin, width, height If the rectangle has not been set by calling setPixelRect(), then this method will return None. """ return self.__rect def reset(self): """Restore the tool to its initial state. reset() This method extends Tool::reset(). """ super(TangentCircleTool, self).reset() self.__center = None self.__radius = None self.__rect = None def create(self, image): """Create a new CCircle and add it to the image. create(image) This method overrides the Tool::create() method. """ _active_layer = image.getActiveLayer() _x, _y = self.__center _radius = self.__radius _pts = _active_layer.find('point', _x, _y) if len(_pts) == 0: _cp = Point(_x, _y) _active_layer.addObject(_cp) else: _cp = _pts[0] _ccircle = CCircle(_cp, _radius) _active_layer.addObject(_ccircle) self.reset() class TangentCCircleTool(TangentCircleTool): """A specialized tool for creating tangent construction circles. The TangentCCircleTool will create a construction circle tangent to a construction line or a construction circle. The TangentCCircleTool is derived from the TangentCircleTool class, so it shares all the attributes and methods of that class. The TangentCCircleTool has the following addtional methods: {set/get}ConstructionObject(): Set/Get the reference construction object. """ def __init__(self): super(TangentCCircleTool, self).__init__() self.__conobj = None def setConstructionLine(self, conobj): """Store the reference construction object in the tool. setConstructionLine(conobj) Argument 'conobj' must be a VCLine, HCLine, ACLine, CLine, or CCircle object. """ if not isinstance(conobj, (HCLine, VCLine, ACLine, CLine, CCircle)): raise TypeError, "Invalid Construction entity type: " + `type(conobj)` self.__conobj = conobj def getConstructionLine(self): """Retrieve the stored construction line from the tool. getConstructionLine() A ValueError exception is raised if the construction line has not been set with the setConstructionLine() method. """ _conobj = self.__conobj if _conobj is None: raise ValueError, "Construction object is not defined." return _conobj def setLocation(self, x, y): """Store an x/y coordinate pair in the tool. setLocation(x, y) Arguments 'x' and 'y' should be floats. This method extends the TangentCircleTool::setLocation() methods. """ super(TangentCCircleTool, self).setLocation(x, y) _tx, _ty = self.getLocation() _conobj = self.__conobj _cx = _cy = _radius = None if isinstance(_conobj, HCLine): _x, _y = _conobj.getLocation().getCoords() _cx = _tx _cy = (_ty + _y)/2.0 _radius = abs(_ty - _y)/2.0 elif isinstance(_conobj, VCLine): _x, _y = _conobj.getLocation().getCoords() _cx = (_tx + _x)/2.0 _cy = _ty _radius = abs(_tx - _x)/2.0 elif isinstance(_conobj, (ACLine, CLine)): _px, _py = _conobj.getProjection(_tx, _ty) _cx = (_tx + _px)/2.0 _cy = (_ty + _py)/2.0 _radius = math.hypot((_tx - _px), (_ty - _py))/2.0 elif isinstance(_conobj, CCircle): _ccx, _ccy = _conobj.getCenter().getCoords() _rad = _conobj.getRadius() _sep = math.hypot((_tx - _ccx), (_ty - _ccy)) if _sep < 1e-10: return _angle = math.atan2((_ty - _ccy), (_tx - _ccx)) _px = _ccx + (_rad * math.cos(_angle)) _py = _ccy + (_rad * math.sin(_angle)) _cx = (_tx + _px)/2.0 _cy = (_ty + _py)/2.0 _radius = math.hypot((_tx - _px), (_ty - _py))/2.0 else: raise TypeError, "Invalid construction entity type: " + `type(_conobj)` self.setCenter(_cx, _cy) self.setRadius(_radius) class TwoPointTangentCCircleTool(TangentCircleTool): """ A specialized tool for creating tangent construction circles. The TwoPointTangentCCircleTool will create a construction circle tangent to two construction lines or a construction line and a construction circle if such a tangent circle can be created. The TwoPointTangentCCircleTool is derived from the TangentCircleTool class, so it shares all the attributes and methods of that class. """ def __init__(self): super(TwoPointTangentCCircleTool, self).__init__() self.__cobj1 = None self.__cobj2 = None def setFirstConObject(self, conobj): """Store the first reference construction object in the tool. setFirstConObject(conobj) Argument 'conobj' must be a VCLine, HCLine, ACLine, CLine, or CCircle object. """ if not isinstance(conobj, (HCLine, VCLine, ACLine, CLine, CCircle)): raise TypeError, "Invalid Construction entity type: " + `type(conobj)` self.__cobj1 = conobj def getFirstConObject(self): """Retreive the first construction object from the tool. getFirstConObject() """ return self.__cobj1 def setSecondConObject(self, conobj): """Store the second reference construction object in the tool. setSecondConObject(conobj) Argument 'conobj' must be a VCLine, HCLine, ACLine, or a CLine object. Drawing a tangent circle against two CCircle objects is not yet supported. A ValueError exception will be raised if this method is called before the first construction object has been set. """ if self.__cobj1 is None: raise ValueError, "First construction object not set." if not isinstance(conobj, (HCLine, VCLine, ACLine, CLine)): raise TypeError, "Invalid Construction line type: " + `type(conobj)` self.__cobj2 = conobj def getSecondConObject(self): """Retreive the second construction object from the tool. getSecondConObject() """ return self.__cobj2 def reset(self): """Restore the tool to its initial state. reset() This method extends the TangentCircleTool::reset() method. """ super(TwoPointTangentCCircleTool, self).reset() self.__cobj1 = None self.__cobj2 = None def setLocation(self, x, y): """Store an x/y coordinate pair in the tool. setLocation(x, y) Arguments 'x' and 'y' should be floats. This method extends the TangentCircleTool::setLocation() methods. """ super(TwoPointTangentCCircleTool, self).setLocation(x, y) _tx, _ty = self.getLocation() _obja = self.__cobj1 _objb = self.__cobj2 _tandata = tangent.calc_tangent_circle(_obja, _objb, _tx, _ty) if _tandata is not None: _cx, _cy, _radius = _tandata self.setCenter(_cx, _cy) self.setRadius(_radius) class CCircleTangentLineTool(Tool): """A specialized class for creating tangent lines to construction circles. This class is a specialized class that handles creating construction lines around circles. There can be at most four possible tangent lines. There are two tangent lines if the circles overlap, and no tangent lines if one circle is inside another. As this tool is derived from the Tool class it shares all the attributes and methods of that class. The CCircleTangentLineTool class has the following additional methods: {get/set}FirstCCircle(): Get/Set the first CCircle in the tool. {get/set}SecondCCircle(): Get/Set the second CCircle in the tool. """ def __init__(self): super(CCircleTangentLineTool, self).__init__() self.__circ1 = None self.__circ2 = None self.__tanpts = [] def setFirstCCircle(self, ccircle): """Store the first construction circle in the tool. setFirstCCircle(ccircle) Argument 'ccircle' must be a CCircle object. """ if not isinstance(ccircle, CCircle): raise TypeError, "Invalid CCircle type: " + `type(ccircle)` self.__circ1 = ccircle def getFirstCCircle(self): """Retreive the first construction circle from the tool. getFirstCCircle() """ return self.__circ1 def setSecondCCircle(self, ccircle): """Store the second construction circle in the tool. setSecondCCircle(ccircle) Argument 'ccircle' must be a CCircle object. A ValueError exception will be raised if this method is called before the first construction circle has been set. """ if self.__circ1 is None: raise ValueError, "First construction circle not set." if not isinstance(ccircle, CCircle): raise TypeError, "Invalid CCircle type: " + `type(ccircle)` self.__circ2 = ccircle # # calculate the tangent points if they exist # _cc1 = self.__circ1 _cc2 = self.__circ2 _cx1, _cy1 = _cc1.getCenter().getCoords() _r1 = _cc1.getRadius() _cx2, _cy2 = _cc2.getCenter().getCoords() _r2 = _cc2.getRadius() _sep = math.hypot((_cx2 - _cx1), (_cy2 - _cy1)) _angle = math.atan2((_cy2 - _cy1), (_cx2 - _cx1)) _sine = math.sin(_angle) _cosine = math.cos(_angle) # # tangent points are calculated as if the first circle # center is (0, 0) and both circle centers on the x-axis, # so the points need to be transformed to the correct coordinates # _tanpts = self.__tanpts del _tanpts[:] # make sure it is empty ... _tansets = tangent.calc_two_circle_tangents(_r1, _r2, _sep) for _set in _tansets: _x1, _y1, _x2, _y2 = _set _tx1 = ((_x1 * _cosine) - (_y1 * _sine)) + _cx1 _ty1 = ((_x1 * _sine) + (_y1 * _cosine)) + _cy1 _tx2 = ((_x2 * _cosine) - (_y2 * _sine)) + _cx1 _ty2 = ((_x2 * _sine) + (_y2 * _cosine)) + _cy1 _tanpts.append((_tx1, _ty1, _tx2, _ty2)) def getSecondCCircle(self): """Retreive the second construction circle from the tool. getSecondCCircle() """ return self.__circ2 def hasTangentPoints(self): """Test if tangent points were found for the two circles. hasTangentPoints() """ _val = False if len(self.__tanpts): _val = True return _val def getTangentPoints(self): """Return the tangent points calculated for two-circle tangency. getTangentPoints() This method returns a list of tuples holding four float values: (x1, y1, x2, y2) A tangent line can be drawn between the two circles from (x1, y1) to (x2, y2). """ return self.__tanpts[:] def create(self, image): """Create the tangent line for two circles. create(image) """ _x, _y = self.getLocation() _tanpts = self.__tanpts if not len(_tanpts): raise ValueError, "No tangent points defined." _minsep = _px1 = _py1 = _px2 = _py2 = None for _set in _tanpts: _x1, _y1, _x2, _y2 = _set _sqlen = pow((_x2 - _x1), 2) + pow((_y2 - _y1), 2) _rn = ((_x - _x1) * (_x2 - _x1)) + ((_y - _y1) * (_y2 - _y1)) _r = _rn/_sqlen _px = _x1 + _r * (_x2 - _x1) _py = _y1 + _r * (_y2 - _y1) _sep = math.hypot((_px - _x), (_py - _y)) if _minsep is None or _sep < _minsep: _minsep = _sep _px1 = _x1 _py1 = _y1 _px2 = _x2 _py2 = _y2 _active_layer = image.getActiveLayer() _pts = _active_layer.find('point', _px1, _py1) if len(_pts) == 0: _p1 = Point(_px1, _py1) _active_layer.addObject(_p1) else: _p1 = _pts[0] _pts = _active_layer.find('point', _px2, _py2) if len(_pts) == 0: _p2 = Point(_px2, _py2) _active_layer.addObject(_p2) else: _p2 = _pts[0] _active_layer.addObject(CLine(_p1, _p2)) def reset(self): """Restore the tool to its initial state. reset() This method extends Tool::reset(). """ super(CCircleTangentLineTool, self).reset() self.__circ1 = None self.__circ2 = None del self.__tanpts[:] class DimensionTool(Tool): """A base class for tools creating Dimension objects. The DimensionTool class is meant to be a base class for classes that will create Dimension objects. The DimensionTool class is derived from the Tool class, so it shares all the attributes and methods of that class. The DimensionTool class has the following additional methods: setDimension(): Store a dimension object in the tool getDimension(): Retrieve a stored dimension object. setDimPrefs(): Apply the current dimension preferences on a stored dimension. """ def __init__(self): super(DimensionTool, self).__init__() self.__dim = None def _setDimension(self, dim): """Store a dimension in the tool. setDimension(dim) The argument 'dim' must be a Dimension object. """ if not isinstance(dim, dimension.Dimension): raise TypeError, "Invalid Dimension type: " + `type(dim)` self.__dim = dim def getDimension(self): """Retrieve the stored dimension object from the tool. getDimension() This method returns the stored Dimension or None. """ return self.__dim def setDimPrefs(self, image): """Apply the current dimension options to the stored dimension. setDimPrefs(image) The argument 'image' is an image option in which the current dimension preferences are retrieved. """ _dim = self.__dim if _dim is None: raise ValueError, "No dimension stored in tool." _pds = _dim.getPrimaryDimstring() _pds.mute() _pds.setFamily(image.getOption('DIM_PRIMARY_FONT_FAMILY')) _pds.setWeight(image.getOption('DIM_PRIMARY_FONT_WEIGHT')) _pds.setStyle(image.getOption('DIM_PRIMARY_FONT_STYLE')) _pds.setColor(image.getOption('DIM_PRIMARY_FONT_COLOR')) _pds.setSize(image.getOption('DIM_PRIMARY_TEXT_SIZE')) _pds.setAlignment(image.getOption('DIM_PRIMARY_TEXT_ALIGNMENT')) _pds.setPrecision(image.getOption('DIM_PRIMARY_PRECISION')) _pds.setUnits(image.getOption('DIM_PRIMARY_UNITS')) _pds.setPrintZero(image.getOption('DIM_PRIMARY_LEADING_ZERO')) _pds.setPrintDecimal(image.getOption('DIM_PRIMARY_TRAILING_DECIMAL')) _pds.unmute() _sds = _dim.getSecondaryDimstring() _sds.mute() _sds.setFamily(image.getOption('DIM_SECONDARY_FONT_FAMILY')) _sds.setWeight(image.getOption('DIM_SECONDARY_FONT_WEIGHT')) _sds.setStyle(image.getOption('DIM_SECONDARY_FONT_STYLE')) _sds.setColor(image.getOption('DIM_SECONDARY_FONT_COLOR')) _sds.setSize(image.getOption('DIM_SECONDARY_TEXT_SIZE')) _sds.setAlignment(image.getOption('DIM_SECONDARY_TEXT_ALIGNMENT')) _sds.setPrecision(image.getOption('DIM_SECONDARY_PRECISION')) _sds.setUnits(image.getOption('DIM_SECONDARY_UNITS')) _sds.setPrintZero(image.getOption('DIM_SECONDARY_LEADING_ZERO')) _sds.setPrintDecimal(image.getOption('DIM_SECONDARY_TRAILING_DECIMAL')) _sds.unmute() _dim.setOffset(image.getOption('DIM_OFFSET')) _dim.setExtension(image.getOption('DIM_EXTENSION')) _dim.setColor(image.getOption('DIM_COLOR')) _dim.setPosition(image.getOption('DIM_POSITION')) _dim.setEndpointType(image.getOption('DIM_ENDPOINT')) _dim.setEndpointSize(image.getOption('DIM_ENDPOINT_SIZE')) _dim.setDualDimMode(image.getOption('DIM_DUAL_MODE')) def reset(self): """ Restore the tool to its initial state. This method sets the DimensionTool dimension to None. """ super(DimensionTool, self).reset() self.__dim = None self.__tempPoint=[] class LinearDimensionTool(DimensionTool): """ A specialized tool for drawing LinearDimension objects. The LinearDimensionTool is derived from the DimensionTool and Tool, class, so it shares all the attributes and methods of those classes. The LinearDimensionTool class has the following addtional methods: {set/get}FirstPoint(): Set/Get the first point in the LinearDimension {set/get}SecondPoint(): Set/Get the second point in the LinearDimension. {set/get}DimPosition(): Set/Get the location of the dimension text. """ def __init__(self): super(LinearDimensionTool, self).__init__() self.__p1 = None self.__p2 = None self.__position = None def setFirstPoint(self, p): """ Store the first point for the LinearDimension. The argument 'p' must be a Point instance. """ if not isinstance (p, Point): raise TypeError, "Invalid Point: " + `type(p)` if p.getParent() is None: raise ValueError, "Point not found in a Layer." self.__p1 = p def getFirstPoint(self): """Return the first point for the LinearDimension. getFirstPoint() This method returns a tuple of two objects: the first object is a Layer, the second object is a Point. """ return self.__p1 def setSecondPoint(self, p): """Store the second point for the LinearDimension. setSecondPoint(p): The argument 'p' must be a Point instance. """ if self.__p1 is None: raise ValueError, "First point not set for LinearDimension." if not isinstance (p, Point): raise TypeError, "Invalid Point: " + `type(p)` if p.getParent() is None: raise ValueError, "Point not found in a Layer." self.__p2 = p def getSecondPoint(self): """Return the second point for the LinearDimension. getSecondPoint() This method returns a tuple of two objects: the first object is a Layer, the second object is a Point. """ return self.__p2 def setDimPosition(self, x, y): """Store the point where the dimension text will be located. setDimPosition(x, y) Arguments 'x' and 'y' should be float values. """ _x = util.get_float(x) _y = util.get_float(y) self.__position = (_x, _y) def getDimPosition(self): """ Retrieve where the dimension text should be placed. This method returns a tuple containing the x/y coodindates defined by the setDimPosition() call, or None if that method has not been invoked. """ return self.__position def reset(self): """ Restore the tool to its initial state. This method extends the reset() methods of its base classes. """ super(LinearDimensionTool, self).reset() self.__p1 = None self.__p2 = None self.__position = None def makeDimension(self, image): """ Create a LinearDimension based on the stored tool values The argument 'image' is an image object where the dimension will be used. """ _p1 = self.__p1 _p2 = self.__p2 _x, _y = self.__position if (_p1 is not None and _p2 is not None and _x is not None and _y is not None): _ds = image.getOption('DIM_STYLE') _ldim = dimension.LinearDimension(_p1, _p2, _x, _y, _ds) self._setDimension(_ldim) self.setDimPrefs(image) def create(self, image): """ Create a new LinearDimension and add it to the image. This method overrides the Tool::create() method. """ _ldim = self.getDimension() if _ldim is not None: _pds = _ldim.getPrimaryDimstring() _pds.mute() try: _pds.setPrefix(image.getOption('DIM_PRIMARY_PREFIX')) _pds.setSuffix(image.getOption('DIM_PRIMARY_SUFFIX')) finally: _pds.unmute() _sds = _ldim.getSecondaryDimstring() _sds.mute() try: _sds.setPrefix(image.getOption('DIM_SECONDARY_PREFIX')) _sds.setSuffix(image.getOption('DIM_SECONDARY_SUFFIX')) finally: _sds.unmute() _ldim.calcDimValues() image.addObject(_ldim) self.reset() class HorizontalDimensionTool(LinearDimensionTool): """A specialized tool for drawing HorizontalDimension objects. The HorizontalDimensionTool is derived from the LinearDimensionTool and the Tool classes, so it shares all the attributes and methods of those class. There are no additional methods for the HorizontalDimension class. """ def __init__(self): super(HorizontalDimensionTool, self).__init__() def makeDimension(self, image): """Create a HorizontalDimension based on the stored tool values. makeDimension(image) The argument 'image' is an image object where the dimension willbe used. """ _p1 = self.getFirstPoint() _p2 = self.getSecondPoint() _x, _y = self.getDimPosition() if (_p1 is not None and _p2 is not None and _x is not None and _y is not None): _ds = image.getOption('DIM_STYLE') _hdim = dimension.HorizontalDimension(_p1, _p2, _x, _y, _ds) self._setDimension(_hdim) self.setDimPrefs(image) def create(self, image): """Create a new HorizontalDimension and add it to the image. create(image) This method overrides the LinearDimensionTool::create() method. """ _hdim = self.getDimension() if _hdim is not None: _pds = _hdim.getPrimaryDimstring() _pds.mute() try: _pds.setPrefix(image.getOption('DIM_PRIMARY_PREFIX')) _pds.setSuffix(image.getOption('DIM_PRIMARY_SUFFIX')) finally: _pds.unmute() _sds = _hdim.getSecondaryDimstring() _sds.mute() try: _sds.setPrefix(image.getOption('DIM_SECONDARY_PREFIX')) _sds.setSuffix(image.getOption('DIM_SECONDARY_SUFFIX')) finally: _sds.unmute() _hdim.calcDimValues() image.addObject(_hdim) self.reset() class VerticalDimensionTool(LinearDimensionTool): """A specialized tool for drawing VerticalDimension objects. The VerticalalDimensionTool is derived from the LinearDimensionTool and the Tool classes, so it shares all the attributes and methods of those class. There are no additional methods for the VerticalalDimension class. """ def __init__(self): super(VerticalDimensionTool, self).__init__() def makeDimension(self, image): """Create a VerticalDimension based on the stored tool values. makeDimension(image) The argument 'image' is an image object where the dimension will be used. """ _p1 = self.getFirstPoint() _p2 = self.getSecondPoint() _x, _y = self.getDimPosition() if (_p1 is not None and _p2 is not None and _x is not None and _y is not None): _ds = image.getOption('DIM_STYLE') _vdim = dimension.VerticalDimension(_p1, _p2, _x, _y, _ds) self._setDimension(_vdim) self.setDimPrefs(image) def create(self, image): """Create a new VerticalDimension and add it to the image. create(image) This method overrides the LinearDimensionTool::create() method. """ _vdim = self.getDimension() if _vdim is not None: _pds = _vdim.getPrimaryDimstring() _pds.mute() try: _pds.setPrefix(image.getOption('DIM_PRIMARY_PREFIX')) _pds.setSuffix(image.getOption('DIM_PRIMARY_SUFFIX')) finally: _pds.unmute() _sds = _vdim.getSecondaryDimstring() _sds.mute() try: _sds.setPrefix(image.getOption('DIM_SECONDARY_PREFIX')) _sds.setSuffix(image.getOption('DIM_SECONDARY_SUFFIX')) finally: _sds.unmute() _vdim.calcDimValues() image.addObject(_vdim) self.reset() class RadialDimensionTool(DimensionTool): """A specialized tool for drawing RadialDimension objects. The RadialDimensionTool class is derived from the DimensionTool class and Tool class, so it shares all the attributes and methods of those classes. The RadialDimensionTool class has the following additional methods: {set/get}DimObject(): Set/Get the circular object being dimensioned. {set/get}DimPosition(): Set/Get the location of the dimension text. """ def __init__(self): super(RadialDimensionTool, self).__init__() self.__cobj = None self.__position = None def setDimObject(self, cobj): """Store the Circle or Arc that the RadialDimension will describe. setDimObject(cobj): The argument 'cobj' must be either a Circle or Arc instance. """ if not isinstance (cobj, (Circle, Arc)): raise TypeError, "Invalid Circle or Arc: " + `type(cobj)` if cobj.getParent() is None: raise ValueError, "Circle/Arc not found in a Layer." self.__cobj = cobj def getDimObject(self): """Return the object the RadialDimension will define. getDimObject() This method returns a tuple of two objects: the first object is a Layer, the second object is either a Circle or an Arc """ return self.__cobj.getParent(), self.__cobj def setDimPosition(self, x, y): """Store the point where the dimension text will be located. setDimPosition(x, y) Arguments 'x' and 'y' should be float values. """ _x = util.get_float(x) _y = util.get_float(y) self.__position = (_x, _y) def getDimPosition(self): """Retrieve where the dimension text should be placed. getDimPosition() This method returns a tuple containing the x/y coodindates defined by the setDimPosition() call, or None if that method has not been invoked. """ return self.__position def reset(self): """Restore the tool to its initial state. reset() This method extends the reset() methods of its base classes. """ super(RadialDimensionTool, self).reset() self.__cobj = None self.__position = None def makeDimension(self, image): """Create a RadialDimension based on the stored tool values. makeDimension(image) The argument 'image' is an image object where the dimension will be used. """ _cobj = self.__cobj _x, _y = self.__position if (_cobj is not None and _x is not None and _y is not None): _ds = image.getOption('DIM_STYLE') _rdim = dimension.RadialDimension(_cobj, _x, _y, _ds) self._setDimension(_rdim) self.setDimPrefs(image) def create(self, image): """Create a new RadialDimension and add it to the image. create(image) This method overrides the Tool::create() method. """ _rdim = self.getDimension() if _rdim is not None: _pds = _rdim.getPrimaryDimstring() _pds.mute() try: _pds.setPrefix(image.getOption('RADIAL_DIM_PRIMARY_PREFIX')) _pds.setSuffix(image.getOption('RADIAL_DIM_PRIMARY_SUFFIX')) finally: _pds.unmute() _sds = _rdim.getSecondaryDimstring() _sds.mute() try: _sds.setPrefix(image.getOption('RADIAL_DIM_SECONDARY_PREFIX')) _sds.setSuffix(image.getOption('RADIAL_DIM_SECONDARY_SUFFIX')) finally: _sds.unmute() _rdim.setDiaMode(image.getOption('RADIAL_DIM_DIA_MODE')) _rdim.calcDimValues() image.addObject(_rdim) self.reset() class AngularDimensionTool(LinearDimensionTool): """A specialized tool for drawing AngularDimension objects. The AngularDimensionTool class is derived from the LinearDimensionTool class, so it shares all the attributes and methods of that class. The AngularDimensionTool class has the following additional methods: {set/get}VertexPoint(): Set/Get the vertex point used by the dimension """ def __init__(self): super(AngularDimensionTool, self).__init__() self.__vp = None def setVertexPoint(self, p): """Store the vertex point for the AngularDimension. setVertexPoint(p): The argument 'p' must be a Point instance. """ if not isinstance (p, Point): raise TypeError, "Invalid Point: " + `type(p)` if p.getParent() is None: raise ValueError, "Point not found in layer." self.__vp = p def getVertexPoint(self): """Return the vertex point for the AngularDimension. getVertexPoint() This method returns a tuple of two objects: the first object is a Layer, the second object is a Point. """ return self.__vp def reset(self): """Restore the tool to its initial state. reset() This method extends LinearDimensionTool::reset(). """ super(AngularDimensionTool, self).reset() self.__vp = None def makeDimension(self, image): """Create an AngularDimension based on the stored tool values. makeDimension(image) The argument 'image' is an image object where the dimension will be used. """ _vp = self.__vp _p1 = self.getFirstPoint() _p2 = self.getSecondPoint() _x, _y = self.getDimPosition() if (_vp is not None and _p1 is not None and _p2 is not None and _x is not None and _y is not None): _ds = image.getOption('DIM_STYLE') _adim = dimension.AngularDimension(_vp, _p1, _p2, _x, _y, _ds) self._setDimension(_adim) self.setDimPrefs(image) def create(self, image): """Create a new AngularDimension and add it to the image. create(image) This method overrides the Tool::create() method. """ _adim = self.getDimension() if _adim is not None: _pds = _adim.getPrimaryDimstring() _pds.mute() try: _pds.setPrefix(image.getOption('ANGULAR_DIM_PRIMARY_PREFIX')) _pds.setSuffix(image.getOption('ANGULAR_DIM_PRIMARY_SUFFIX')) finally: _pds.unmute() _sds = _adim.getSecondaryDimstring() _sds.mute() try: _sds.setPrefix(image.getOption('ANGULAR_DIM_SECONDARY_PREFIX')) _sds.setSuffix(image.getOption('ANGULAR_DIM_SECONDARY_SUFFIX')) finally: _sds.unmute() _adim.calcDimValues() image.addObject(_adim) self.reset() # # printing/plotting tools # class PlotTool(Tool): """A tool for defining plot regions """ def __init__(self): super(PlotTool, self).__init__() self.__c1 = None self.__c2 = None def reset(self): """Restore the tool to its initial state. reset() This method extends Tool::reset(). """ super(PlotTool, self).reset() self.__c1 = None self.__c2 = None def setFirstCorner(self, x, y): """Store the first corner of the plot region. setFirstCorner(x, y) Arguments 'x' and 'y' should be floats. """ _x = util.get_float(x) _y = util.get_float(y) self.__c1 = (_x, _y) def getFirstCorner(self): """Return the first corner of the plot region. getFirstCorner() """ if self.__c1 is None: raise ValueError, "First corner not defined" return self.__c1 def setSecondCorner(self, x, y): """Store the second corner of the plot region. setSecondCorner(x, y) Arguments 'x' and 'y' should be floats. """ _x = util.get_float(x) _y = util.get_float(y) self.__c2 = (_x, _y) def getSecondCorner(self): """Return the second corner of the plot region. getSecondCorner() """ if self.__c2 is None: raise ValueError, "Second corner not defined" return self.__c2 # # entity modification tools # class RegionTool(Tool): """A base class for a tool that can store a defined region. The RegionTool class is designed to be a base class for tools that need to store a rectangular region. The RegionTool class is derived from the Tool class, so it shares all the attributes and methods of that classs. The RegionTool class has the following additional methods: {set/get}Region(): Set/Get a stored rectangular region """ def __init__(self): super(RegionTool, self).__init__() self.__region = None def setRegion(self, xmin, ymin, xmax, ymax): """Store a rectangular region in the RegionTool. setRegion(xmin, ymin, xmax, ymax) xmin: The minimum x-coordinate value ymin: The minimum y-coordinate value xmax: The maximum x-coordinate value ymax: The maximum y-coordinate value All the arguments should be floats. If xmax < xmin or ymax < ymin a ValueError exception is raised. """ _xmin = util.get_float(xmin) _ymin = util.get_float(ymin) _xmax = util.get_float(xmax) if _xmax < _xmin: raise ValueError, "Invalid values: xmax < xmin" _ymax = util.get_float(ymax) if _ymax < _ymin: raise ValueError, "Invalid values: ymax < ymin" self.__region = (_xmin, _ymin, _xmax, _ymax) def getRegion(self): """Retrieve the stored rectangular region in the tool. getRegion() This method returns a tuple containing four float values: (xmin, ymin, xmax, ymax) """ return self.__region def reset(self): """Restore the tool to its initial state. reset() This method resets the RegionTool region to None. """ super(RegionTool, self).reset() self.__region = None class MoveTool(RegionTool): """A specialized class for moving objects. The MoveTool class is derived from the Tool and RegionTool classes, so it shares all the attributes and methods of those classes. The MoveTool class has the following additional methods: {set/get}Distance(): Set/Get the values to move objects. """ def __init__(self): super(MoveTool, self).__init__() self.__distance = None def setDistance(self, x, y): """Store the distance to move objects in the tool. setDistance(x, y) Arguments 'x' and 'y' should be floats, and represent the amount to move objects in the x-coordinate and y-coordinate axes. """ _x = util.get_float(x) _y = util.get_float(y) self.__distance = (_x, _y) def getDistance(self): """Get the displacement stored in the tool. getDistance() This method returns a tuple containing two float values. (xdisp, ydisp) If this method is called before the setDistance() method is used, a ValueError exception is raised. """ if self.__distance is None: raise ValueError, "No distance stored in tool." return self.__distance def reset(self): """Restore the tool to its initial state. reset() This method extends the reset() method of its base classes """ super(MoveTool, self).reset() self.__distance = None class HorizontalMoveTool(MoveTool): """A specialized class for moving objects horizontally. The HorizontalMoveTool is derived from the MoveTool class, so it shares all the attributes and methods of that class. There are no additional methods for this class. """ def __init__(self): super(HorizontalMoveTool, self).__init__() def setDistance(self, x, y): """Store the distance to move objects in the tool. setDistance(x, y) This method extends the MoveTool::setDistance() method by enforcing a y-axis displacement of 0.0 """ _x = util.get_float(x) super(HorizontalMoveTool, self).setDistance(_x, 0.0) class VerticalMoveTool(MoveTool): """A specialized class for moving objects vertically. The VerticalMoveTool is derived from the MoveTool class, so it shares all the attributes and methods of that class. There are no additional methods for this class. """ def __init__(self): super(VerticalMoveTool, self).__init__() def setDistance(self, x, y): """Store the distance to move objects in the tool. setDistance(x, y) This method extends the MoveTool::setDistance() method by enforcing an x-axis displacement of 0.0 """ _y = util.get_float(y) super(VerticalMoveTool, self).setDistance(0.0, _y) class StretchTool(MoveTool): """A specialized class for stretching objects The StretchTool class is derived from the MoveTool class, so it shares all the attributes and methods of that class. There are no additional methods for this class. """ def __init__(self): super(StretchTool, self).__init__() class HorizontalStretchTool(HorizontalMoveTool): """A specialized class for stretching objects horizontally. The HorizontalStretchTool class is derived from the HorizontalMoveTool class, so it shares all the attributes and methods of that class. There are no additional methods for this class. """ def __init__(self): super(HorizontalStretchTool, self).__init__() class VerticalStretchTool(VerticalMoveTool): """A specialized class for stretching objects horizontally. The VerticalStretchTool class is derived from the VerticalMoveTool class, so it shares all the attributes and methods of that class. There are no additional methods for this class. """ def __init__(self): super(VerticalStretchTool, self).__init__() class DeleteTool(RegionTool): """A specialized class for deleting objects. The DeleteTool class is derived from the Tool and RegionTool classes, so it shares all the attributes and methods of those classes. There are no additional methods for this class. """ def __init__(self): super(DeleteTool, self).__init__() class SplitTool(RegionTool): """A specialized class for splitting objects. The SplitTool class is derived from the Tool and RegionTool classes, so it shares all the attributes and methods of those classes. There are no additional methods for this class. """ def __init__(self): super(SplitTool, self).__init__() class MirrorTool(RegionTool): """A specialized class for mirroring objects. The MirrorTool class is derived from the Tool and RegionTool classes, so it shares all the attributes and methods of those classes. The MirrorTool class has the following additional methods: {set/get}MirrorLine(): Set/Get the construction line used for mirroring """ def __init__(self): super(MirrorTool, self).__init__() self.__mirrorline = None def setMirrorLine(self, mline): """Store the mirroring construction line in the tool. setMirrorLine(mline) The argument 'mline' must be a construction line, otherwise a TypeError exception is raised. """ if not isinstance(mline, (HCLine, VCLine, ACLine, CLine)): raise TypeError, "Invalid mirroring line type: " + `type(mline)` self.__mirrorline = mline def getMirrorLine(self): """Retrieve the mirroring construction line from the tool. getMirrorLine() If the mirroring construction line has not been set, a ValueError exception is raised. """ if self.__mirrorline is None: raise ValueError, "No mirror line set." return self.__mirrorline def reset(self): """Restore the tool to its initial state. reset() This method extends the RegionTool::reset() method. """ super(MirrorTool, self).reset() self.__mirrorline = None # # The TransferTool class is a subclass of the RegionTool # with no additional functionality (yet) # class TransferTool(RegionTool): pass class RotateTool(RegionTool): """A specialized class for rotating objects. The RotateTool class is derived from the Tool and RegionTool classes, so it shares all the attributes and methods of those classes. The Rotateool class has the following additional methods: {set/get}RotationPoint(): Set/Get the point objects are rotated around {set/get}Angle(): Set/Get the angle of rotation """ def __init__(self): super(RotateTool, self).__init__() self.__rp = None self.__angle = None def setRotationPoint(self, x, y): """Set the coordinates the entities will rotate around setRotationPoint(x, y) Arguments 'x' and 'y' should be floats """ _x = util.get_float(x) _y = util.get_float(y) self.__rp = (_x, _y) def getRotationPoint(self): """Get the point objects will rotate around getRotationPoint() This method returns a tuple of two floats or None if the rotation point has not be defined with setRotationPoint() """ return self.__rp def setAngle(self, angle): """Set the angle of rotation. setAngle(angle) Argument 'angle' should be a float value. The value is normalized so that abs(angle) < 360.0. """ _a = util.get_float(angle) self.__angle = math.fmod(_a, 360.0) def getAngle(self): """Get the angle of rotation. getAngle() This method returns a float or None if the angle has not been set with setAngle() """ return self.__angle def reset(self): """Restore the tool to its initial state. reset() This method extends Tool::reset(). """ super(RotateTool, self).reset() self.__rp = None self.__angle = None class GraphicObjectTool(RegionTool): """A specialized class for changing attributes of GraphicObject instances. The GraphicObjectTool class is derived from the RegionTool class, so it shares all the attributes and methods of that class. The GraphicObjectTool class has the following additional methods: {set/get}Attribute(): Set/Get the desired attribute {set/get}Value(): Set/Get the new entity color. """ def __init__(self): super(RegionTool, self).__init__() self.__attr = None self.__value = None def setAttribute(self, attr): """Define which attribute the tool is modifying. setAttribute(attr) Argument 'attr' should be either 'setStyle', 'setLinetype', 'setColor', or 'setThickness' """ if not isinstance(attr, str): raise TypeError, "Invalid attribute type: " + `type(attr)` if attr not in ('setStyle', 'setLinetype', 'setColor', 'setThickness'): raise ValueError, "Invalid attribute: " + attr self.__attr = attr def getAttribute(self): """Return the specified attribute. getAttribute() If called before invoking setAttribute(), this method raises a ValueError. """ if self.__attr is None: raise ValueError, "Tool attribute not defined." return self.__attr def setValue(self, val): """Store the new value of the entity attribute. setValue(val) Argument 'val' depends on the type of attribute defined for the tool. If no attribute is defined this method raises a ValueError. Invoking this method with 'None' as an argument sets the tool to restore the default attribute value. """ if self.__attr is None: raise ValueError, "Tool attribute not defined." _a = self.__attr _val = None if val is not None: if _a == 'setStyle': if not isinstance(val, style.Style): raise TypeError, "Invalid Style: " + `type(val)` _val = val elif _a == 'setLinetype': if not isinstance(val, linetype.Linetype): raise TypeError, "Invalid Linetype: " + `type(val)` _val = val elif _a == 'setColor': if not isinstance(val, color.Color): raise TypeError, "Invalid Color: " + `type(val)` _val = val elif _a == 'setThickness': _val = util.get_float(val) if _val < 0.0: raise ValueError, "Invalid thickness: %g" % _val else: raise ValueError, "Unexpected attribute: " + _a self.__value = _val def getValue(self): """Get the stored attribute value. getValue() This method returns the value stored in setValue() or None. """ return self.__value # # # class ChangeStyleTool(GraphicObjectTool): pass class ChangeLinetypeTool(GraphicObjectTool): pass class ChangeColorTool(GraphicObjectTool): pass class ChangeThicknessTool(GraphicObjectTool): pass class TextTool(RegionTool): """ A specialized class for entering text. The TextTool class is derived from the Tool class, so it shares the attributes and methods of that class. The TextTool class also has the following additional methods: {set/get}Text(): Set/Get the text string in the tool. hasText(): Test if the tool has stored a text string {set/get}TextLocation(): Set/Get where the text is to be placed. {set/get}TextBlock(): Set/Get a TextBlock instance in the Tool {set/get}Bounds(): Set/Get the width and height of the text {set/get}PixelSize(): Set/Get the a rectangular region bounding the text. {set/get}Layout(): Set/Get the formatted text string display. {set/get/test}Attribute(): Set/Get/Test a TextBlock attribute {set/get}Value(): Set/Get the attribute value. """ def __init__(self): super(TextTool, self).__init__() self.__text = None self.__location = None self.__tblock = None self.__attr = None self.__value = None self.__bounds = None self.__pixel_size = None self.__layout = None def setText(self, text): """ Store some text in the tool. The argument 'text' should be a unicode object. """ _text = text if not isinstance(_text, unicode): _text = unicode(text) self.__text = _text def getText(self): """ Retrieve the stored text from the TextTool. If no text has been stored, this method raises a ValueError exception. """ if self.__text is None: raise ValueError, "No text stored in TextTool." return self.__text def hasText(self): """ Test if the tool has stored a text string. """ return self.__text is not None def setTextLocation(self, x, y): """ Store the location where the text will be placed. The arguments 'x' and 'y' should be float values. """ _x, _y = util.make_coords(x, y) self.__location = (_x, _y) def getTextLocation(self): """ Retrieve the location where the text will be placed. This method returns a tuple holding two floats:(x, y) A ValueError exception is raised if this method is called prior to setting the text location with setTextLocation(). """ if self.__location is None: raise ValueError, "No text location defined." return self.__location def testAttribute(self, attr): """ Test that the given attribute is valid. Argument 'attr' should be one of the following: 'setAngle', 'setAlignment', 'setFamily', 'setStyle', 'setWeight', 'setColor', or 'setSize' """ if not isinstance(attr, str): raise TypeError, "Invalid attribute type: " + `type(attr)` return attr in ('setAngle', 'setAlignment', 'setFamily', 'setStyle', 'setWeight', 'setColor', 'setSize') def setAttribute(self, attr): """ Define which attribute the tool is modifying. Argument 'attr' should be one of the following: 'setAngle', 'setAlignment', 'setFamily', 'setStyle', 'setWeight', 'setColor', or 'setSize' """ if not self.testAttribute(attr): raise ValueError, "Invalid attribute: " + attr self.__attr = attr def getAttribute(self): """ Return the specified attribute. If called before invoking setAttribute(), this method raises a ValueError. """ if self.__attr is None: raise ValueError, "Tool attribute not defined." return self.__attr def testValue(self, val): """ Test that the given value is valid for the preset attribute. Argument 'val' depends on what attribute has been set with via setAttribute(). """ _a = self.__attr if _a == 'setAngle': _val = util.getFloat(val) elif _a == 'setAlignment': if not isinstance(val, int): raise TypeError, "Invalid alignment type: " + `type(val)` if (val != TextStyle.ALIGN_LEFT and val != TextStyle.ALIGN_CENTER and val != TextStyle.ALIGN_RIGHT): raise ValueError, "Invalid alignment value: %d" % val _val = val elif _a == 'setColor': if not isinstance(val, color.Color): raise TypeError, "Invalid Color: " + `type(val)` _val = val elif _a == 'setFamily': if not isinstance(val, types.StringTypes): raise TypeError, "Invalid family type: " + `type(val)` _val = val elif _a == 'setStyle': if not isinstance(val, int): raise TypeError, "Invalid style type: " + `type(val)` if (val != TextStyle.FONT_NORMAL and val != TextStyle.FONT_OBLIQUE and val != TextStyle.FONT_ITALIC): raise ValueError, "Invalid style value: %d" % val _val = val elif _a == 'setWeight': if not isinstance(val, int): raise TypeError, "Invalid weight type: " + `type(val)` if (val != TextStyle.WEIGHT_NORMAL and val != TextStyle.WEIGHT_LIGHT and val != TextStyle.WEIGHT_BOLD and val != TextStyle.WEIGHT_HEAVY): raise ValueError, "Invalid weight value: %d" % val _val = val elif _a == 'setSize': _val = util.get_float(val) if _val < 0.0: raise ValueError, "Invalid size: %g" % _val else: raise ValueError, "Unexpected attribute: " + _a return _val def setValue(self, val): """ Store the new value of the entity attribute. Argument 'val' depends on the type of attribute defined for the tool. If no attribute is defined this method raises a ValueError. Invoking this method with 'None' as an argument sets the tool to restore the default attribute value. """ if self.__attr is None: raise ValueError, "Tool attribute not defined." _val = None if val is not None: _val = self.testValue(val) self.__value = _val def getValue(self): """ Get the stored attribute value. This method returns the value stored in setValue() or None. """ return self.__value def getBounds(self): """ Return the width and height of the TextBlock. """ if self.__bounds is None: raise ValueError, "TextBlock bounds not defined." return self.__bounds def setBounds(self, width, height): """ Set the width and height of the TextBlock. Arguments 'width' and 'height' should be positive float values. """ _w = util.get_float(width) if _w < 0.0: raise ValueError, "Invalid width: %g" % _w _h = util.get_float(height) if _h < 0.0: raise ValueError, "Invalid height: %g" % _h self.__bounds = (_w, _h) def setPixelSize(self, width, height): """ Store a screen-size rectangular boundary for the text. Arguments 'width' and 'height' should be positive integer values. This method is somewhat GTK specific ... """ _width = width if not isinstance(_width, int): _width = int(width) if _width < 0: raise ValueError, "Invalid width: %d" % _width _height = height if not isinstance(_height, int): _height = int(height) if _height < 0: raise ValueError, "Invalid height: %d" % _height self.__pixel_size = (_width, _height) def getPixelSize(self): """Retrieve the stored rectangular region of text. getPixelSize() A ValueError exception is raised if this method is called before the size has been set by setPixelSize() """ if self.__pixel_size is None: raise ValueError, "Pixel size is not defined." return self.__pixel_size def setLayout(self, layout): """Store a formatted layout string for the text. setLayout() This method is very GTK/Pango specific ... """ self.__layout = layout def getLayout(self): """Retrieve the formatted layout for the text string. getLayout() This method is very GTK/Pango specific ... """ return self.__layout def setTextBlock(self, tblock): """Store a TextBlock instance within the Tool. setTextBlock(tblock) Argument 'tblock' must be a TextBlock. """ if not isinstance(tblock, TextBlock): raise TypeError, "Invalid TextBlock: " + `type(tblock)` self.__tblock = tblock def getTextBlock(self): """Retrieve a stored TextBlock within the Tool. getTextBlock() This method may return None if no TextBlock has been stored via setTextBlock(). """ return self.__tblock def create(self, image): """ Create a new TextBlock and add it to the image. This method overrides the Tool::create() method. """ _tb = self.__tblock if _tb is None: _text = self.getText() _x, _y = self.getTextLocation() _ts = image.getOption('TEXT_STYLE') _tb = TextBlock(_x, _y, _text, _ts) _f = image.getOption('FONT_FAMILY') if _f != _ts.getFamily(): _tb.setFamily(_f) _s = image.getOption('FONT_STYLE') if _s != _ts.getStyle(): _tb.setStyle(_s) _w = image.getOption('FONT_WEIGHT') if _w != _ts.getWeight(): _tb.setWeight(_w) _c = image.getOption('FONT_COLOR') if _c != _ts.getColor(): _tb.setColor(_c) _sz = image.getOption('TEXT_SIZE') if abs(_sz - _ts.getSize()) > 1e-10: _tb.setSize(_sz) _a = image.getOption('TEXT_ANGLE') if abs(_a - _ts.getAngle()) > 1e-10: _tb.setAngle(_a) _al = image.getOption('TEXT_ALIGNMENT') if _al != _ts.getAlignment(): _tb.setAlignment(_al) image.addObject(_tb) self.reset() def reset(self): """ Restore the tool to its initial state. This method extends Tool::reset(). """ super(TextTool, self).reset() self.__text = None self.__location = None self.__tblock = None self.__bounds = None self.__pixel_size = None self.__layout = None class EditDimensionTool(RegionTool): """A specialized class for changing attributes of Dimension instances. The EditDimensionTool class is derived from the RegionTool class, so it shares all the attributes and methods of that class. The EditDimensionTool class has the following additional methods: {set/get}Attribute(): Set/Get the desired attribute {set/get}Value(): Set/Get the new entity color. """ def __init__(self): super(RegionTool, self).__init__() self.__attr = None self.__value = None def setAttribute(self, attr): """Define which attribute the tool is modifying. setAttribute(attr) Argument 'attr' should be one of the following: 'setEndpointType', 'setEndpointSize', 'setDualDimMode', 'setDualModeOffset', 'setOffset', 'setExtension', 'setColor', 'setThickness', 'setScale' """ if not isinstance(attr, str): raise TypeError, "Invalid attribute type: " + `type(attr)` if attr not in ('setEndpointType', 'setEndpointSize', 'setDualDimMode', 'setDualModeOffset', 'setOffset', 'setExtension', 'setColor', 'setThickness', 'setScale'): raise ValueError, "Invalid attribute: " + attr self.__attr = attr def getAttribute(self): """Return the specified attribute. getAttribute() If called before invoking setAttribute(), this method raises a ValueError. """ if self.__attr is None: raise ValueError, "Tool attribute not defined." return self.__attr def setValue(self, val): """Store the new value of the entity attribute. setValue(val) Argument 'val' depends on the type of attribute defined for the tool. If no attribute is defined this method raises a ValueError. Invoking this method with 'None' as an argument sets the tool to restore the default attribute value. """ if self.__attr is None: raise ValueError, "Tool attribute not defined." _a = self.__attr _val = None if val is not None: if _a == 'setEndpointType': if (val != dimension.Dimension.DIM_ENDPT_NONE and val != dimension.Dimension.DIM_ENDPT_ARROW and val != dimension.Dimension.DIM_ENDPT_FILLED_ARROW and val != dimension.Dimension.DIM_ENDPT_SLASH and val != dimension.Dimension.DIM_ENDPT_CIRCLE): raise ValueError, "Invalid endpoint value: " + str(val) _val = val elif _a == 'setEndpointSize': _val = util.get_float(val) if _val < 0.0: raise ValueError, "Invalid endpoint size: %g" % _val _val = val elif _a == 'setDualDimMode': util.test_boolean(val) _val = val elif _a == 'setDualModeOffset': _val = util.get_float(val) if _val < 0.0: raise ValueError, "Invalid offset length: %g" % _val _val = val elif _a == 'setOffset': _val = util.get_float(val) if _val < 0.0: raise ValueError, "Invalid offset length: %g" % _val _val = val elif _a == 'setExtension': _val = util.get_float(val) if _val < 0.0: raise ValueError, "Invalid extension length: %g" % _val _val = val elif _a == 'setColor': if not isinstance(val, color.Color): raise TypeError, "Invalid Color: " + `type(val)` _val = val elif _a == 'setThickness': _val = util.get_float(val) if _val < 0.0: raise ValueError, "Invalid thickness: %g" % _val elif _a == 'setScale': _val = util.get_float(val) if _val < 0.0: raise ValueError, "Invalid scale: %g" % _val else: raise ValueError, "Unexpected attribute: " + _a self.__value = _val def getValue(self): """Get the stored attribute value. getValue() This method returns the value stored in setValue() or None. """ return self.__value class EditDimStringTool(TextTool): """A specialized class for modifying DimString instances in Dimensions. The EditDimStringTool class is derived from the TextTool class, so it shares the attributes and methods of that class. The TextTool class has the following additional methods: {set/get}Primary(): Set/Get the DimString on which the tool operates. """ def __init__(self): super(EditDimStringTool, self).__init__() self.__pds = True def setPrimary(self, flag=True): """Set the tool to operate on the primary DimString setPrimary([flag]) Optional argument 'flag' should be a boolean. By default the tool will operate on the primary DimString of a Dimension. If argument 'flag' is False, the tool will operate on the secondary DimString. """ util.test_boolean(flag) self.__pds = flag def getPrimary(self): """Test if the tool operates on the primary DimString getPrimary() This method returns a boolean """ return self.__pds def testAttribute(self, attr): """Test that the attribute is valid for the DimString entity. testAttribute(attr) Argument 'attr' must be one of the following: 'setPrefix', 'setSuffix', 'setUnits', 'setPrecision', 'setPrintZero', 'setPringDecimal', 'setFamily', 'setStyle', 'setWeight', 'setSize', 'setAlignment', 'setColor', or 'setAngle'. """ if not isinstance(attr, str): raise TypeError, "Invalid attribute type: " + `type(attr)` _res = attr in ('setPrefix', 'setSuffix', 'setUnits', 'setPrecision', 'setPrintZero', 'setPrintDecimal') if _res: return _res return super(EditDimStringTool, self).testAttribute(attr) def testValue(self, val): """Test that the value is valid for a given DimString attribute. testValue(val) Argument 'val' depends on the attribute set for the EditDimString instance. """ _a = self.getAttribute() if _a == 'setPrefix' or _a == 'setSuffix': if not isinstance(val, types.StringTypes): raise TypeError, "Invalid %s type: %s " % (_a, `type(val)`) _val = val if not isinstance(_val, unicode): _val = unicode(val) elif _a == 'setPrecision': if not isinstance(val, int): raise TypeError, "Invalid precision type: " + `type(val)` _val = val elif _a == 'setPrintZero' or _a == 'setPrintDecimal': try: util.test_boolean(val) except TypeError: raise TypeError, "Invalid %s type: %s " % (_a, `type(val)`) _val = val elif _a == 'setUnits': _val = val # FIXME: needs error checking ... else: _val = super(EditDimStringTool, self).testValue(val) return _val def setText(self, txt): pass def getText(self): pass def hasText(self): pass def setTextLocation(self, x, y): pass def getTextLocation(self): pass def setBounds(self, width, height): pass def getBounds(self): pass def setPixelSize(self, width, height): pass def getPixelSize(self): pass def setLayout(self, layout): pass def getLayout(self): pass # Usefoul function def getSegmentSnap(firstPoint,secondPoint): """ Get a quadruple of coords that define the line taking care of the user snaps """ _singlePoint=['Freepoint','End','Intersection','Point','Origin','Mid','Center'] _computePoint=['Perpendicular','Tangent'] _x1,_y1=firstPoint.point.getCoords() _x2,_y2=secondPoint.point.getCoords() _firstKind=firstPoint.kind _secondKind=secondPoint.kind if _firstKind in _singlePoint and _secondKind in _computePoint : if _secondKind =="Perpendicular": if isinstance(secondPoint.entity,(Segment,CLine,ACLine,HCLine,VCLine)): pjPoint=Point(secondPoint.entity.getProjection(_x1,_y1)) if pjPoint is not None: _x2,_y2=pjPoint.getCoords() if _secondKind =="Tangent": if isinstance(secondPoint.entity,(Circle,Arc,CCircle)): x2,y2=secondPoint.entity.GetTangentPoint(_x2,_y2,_x1,_y1) if(x2,y2 is not None,None): _x2,_y2=x2,y2 if _firstKind in _computePoint and _secondKind in _singlePoint : if _firstKind =="Perpendicular": if isinstance(firstPoint.entity,(Segment,CLine,ACLine,HCLine,VCLine)): pjPoint=Point(firstPoint.entity.getProjection(_x2,_y2)) if pjPoint is not None: _x1,_y1=pjPoint.getCoords() if _firstKind =="Tangent": if isinstance(firstPoint.entity,(Circle,Arc,CCircle)): x1,y1=firstPoint.entity.GetTangentPoint(_x1,_y1,_x2,_y2) if(x1,y1 is not None,None): _x1,_y1=x1,y1 if _firstKind in _computePoint and _secondKind in _computePoint: if _firstKind =="Tangent" and _secondKind =="Tangent": if (isinstance(firstPoint.entity,(Circle,Arc,CCircle)) and isinstance(secondPoint.entity,(Circle,Arc,CCircle))): _x1,_y1,_x2,_y2=tanTanSegment(firstPoint,secondPoint) return _x1,_y1,_x2,_y2 def tanTanSegment(p1,p2): """ get the coordinates of bi tangent line over two circle ents using strPoint return a x,y,x1,x1 coords that define the segment """ if p1 is None: raise ValueError, "First construction point not set." if p2 is None : raise ValueError, "Second construction point not set." # # calculate the tangent points if they exist # _cc1 = p1.entity _cc2 = p2.entity _cx1, _cy1 = _cc1.getCenter().getCoords() _r1 = _cc1.getRadius() _cx2, _cy2 = _cc2.getCenter().getCoords() _r2 = _cc2.getRadius() _sep = math.hypot((_cx2 - _cx1), (_cy2 - _cy1)) _angle = math.atan2((_cy2 - _cy1), (_cx2 - _cx1)) _sine = math.sin(_angle) _cosine = math.cos(_angle) # # tangent points are calculated as if the first circle # center is (0, 0) and both circle centers on the x-axis, # so the points need to be transformed to the correct coordinates # _exitSegment=None _tansets = tangent.calc_two_circle_tangents(_r1, _r2, _sep) for _set in _tansets: _x1, _y1, _x2, _y2 = _set _tx1 = ((_x1 * _cosine) - (_y1 * _sine)) + _cx1 _ty1 = ((_x1 * _sine) + (_y1 * _cosine)) + _cy1 _tx2 = ((_x2 * _cosine) - (_y2 * _sine)) + _cx1 _ty2 = ((_x2 * _sine) + (_y2 * _cosine)) + _cy1 sp1=Point(_tx1, _ty1) sp2=Point(_tx2, _ty2) if _exitSegment is None: _globalDist=abs(p1.point-sp1)+abs(p2.point-sp2) _exitSegment= _tx1, _ty1,_tx2, _ty2 else: if _globalDist>abs(p1.point-sp1)+abs(p2.point-sp2): _globalDist=abs(p1.point-sp1)+abs(p2.point-sp2) _exitSegment= _tx1, _ty1,_tx2, _ty2 return _exitSegmentPythonCAD-DS1-R37/PythonCAD/Generic/plotfile.py0000644000175000017500000003653711307666657020545 0ustar matteomatteo# # Copyright (c) 2004, 2005 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import sys from PythonCAD.Generic.image import Image from PythonCAD.Generic.util import make_region from PythonCAD.Generic.graphicobject import GraphicObject from PythonCAD.Generic.color import Color from PythonCAD.Generic.point import Point from PythonCAD.Generic.segment import Segment from PythonCAD.Generic.circle import Circle from PythonCAD.Generic.arc import Arc #from PythonCAD.Generic.ellipse import Ellipse from PythonCAD.Generic.polyline import Polyline from PythonCAD.Generic.leader import Leader from PythonCAD.Generic.segjoint import Chamfer, Fillet from PythonCAD.Generic.conobject import ConstructionObject from PythonCAD.Generic.text import TextStyle, TextBlock from PythonCAD.Generic import dimension from PythonCAD.Generic import util class Plot(object): __white = Color(255, 255, 255) def __init__(self, image): if not isinstance(image, Image): raise TypeError, "Invalid image argument: " + `image` self.__image = image self.__bounds = None self.__landscape = False self.__invert = False self.__color = False self.__units = None self.__data = {} def __contains__(self, objtype): if not isinstance(objtype, str): raise TypeError, "Invalid object type string: " + `objtype` return objtype in self.__data def finish(self): self.__image = self.__bounds = self.__units = None self.__data.clear() def setBounds(self, xmin, ymin, xmax, ymax): self.__bounds = make_region(xmin, ymin, xmax, ymax) def getBounds(self): return self.__bounds def setLandscapeMode(self, flag): util.test_boolean(flag) self.__landscape = flag def getLandscapeMode(self): return self.__landscape def invertWhite(self, flag): util.test_boolean(flag) self.__invert = flag def setColorMode(self, flag): util.test_boolean(flag) self.__color = flag def setUnits(self): self.__units = self.__image.getUnits() def getUnits(self): if self.__units is None: self.setUnits() return self.__units def _getGraphicValues(self, obj): if not isinstance(obj, GraphicObject): raise TypeError, "Invalid GraphicObject: " + `obj` _col = None if self.__color: _c = obj.getColor() if self.__invert and _c == Plot.__white: _col = (0, 0, 0) # black else: _col = _c.getColors() # r, g, b _lt = obj.getLinetype().getList() _t = obj.getThickness() return _col, _lt, _t def getPlotData(self): if self.__bounds is None: raise ValueError, "Plot boundary not defined." if self.__units is None: self.setUnits() _xmin, _ymin, _xmax, _ymax = self.__bounds _image = self.__image _layers = [_image.getTopLayer()] while len(_layers): _layer = _layers.pop() if _layer.isVisible(): for _obj in _layer.objsInRegion(_xmin, _ymin, _xmax, _ymax): if isinstance(_obj, ConstructionObject): continue # do not plot these if not _obj.isVisible(): continue if isinstance(_obj, Point): continue # print points as dots? elif isinstance(_obj, Segment): _p1, _p2 = _obj.getEndpoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _col, _lt, _t = self._getGraphicValues(_obj) _data = self.__data.setdefault('segments', []) _data.append((_x1, _y1, _x2, _y2, _col, _lt, _t)) elif isinstance(_obj, Circle): _x, _y = _obj.getCenter().getCoords() print "x: %g; y: %g" % (_x, _y) _r = _obj.getRadius() print "r: %g" % _r _col, _lt, _t = self._getGraphicValues(_obj) _data = self.__data.setdefault('circles', []) _data.append((_x, _y, _r, _col, _lt, _t)) elif isinstance(_obj, Arc): _x, _y = _obj.getCenter().getCoords() _r = _obj.getRadius() _sa = _obj.getStartAngle() _ea = _obj.getEndAngle() _col, _lt, _t = self._getGraphicValues(_obj) _data = self.__data.setdefault('arcs', []) _data.append((_x, _y, _r, _sa, _ea, _col, _lt, _t)) elif isinstance(_obj, Leader): _p1, _p2, _p3 = _obj.getPoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _x3, _y3 = _p3.getCoords() _ax1 = _ax2 = _x3 _ay1 = _ay2 = _y3 if _obj.getArrowSize() > 1e-10: _pts = _obj.getArrowPoints() _ax1 = _pts[0] _ay1 = _pts[1] _ax2 = _pts[2] _ay2 = _pts[3] _col, _lt, _t = self._getGraphicValues(_obj) _data = self.__data.setdefault('leaders', []) _data.append((_x1, _y1, _x2, _y2, _x3, _y3, _ax1, _ay1, _ax2, _ay2, _col, _lt, _t)) elif isinstance(_obj, Polyline): _pts = [] for _pt in _obj.getPoints(): _pts.append(_pt.getCoords()) _col, _lt, _t = self._getGraphicValues(_obj) _data = self.__data.setdefault('polylines', []) _data.append((_pts, _col, _lt, _t)) elif isinstance(_obj, Chamfer): _p1, _p2 = _obj.getMovingPoints() _col, _lt, _t = self._getGraphicValues(_obj) _data = self.__data.setdefault('chamfers', []) _data.append((_p1.x, _p1.y, _p2.x, _p2.y, _col, _lt, _t)) elif isinstance(_obj, Fillet): _x, _y = _obj.getCenter() _r = _obj.getRadius() _sa, _ea = _obj.getAngles() _col, _lt, _t = self._getGraphicValues(_obj) _data = self.__data.setdefault('fillets', []) _data.append((_x, _y, _r, _sa, _ea, _col, _lt, _t)) elif isinstance(_obj, dimension.Dimension): self._saveDimensionData(_obj) elif isinstance(_obj, TextBlock): _tbdata = self._getTextBlockData(_obj) if _tbdata is not None: _data = self.__data.setdefault('textblocks', []) _data.append(_tbdata) else: # fixme pass _layers.extend(_layer.getSublayers()) def _getTextBlockData(self, tblock): _bounds = tblock.getBounds() if _bounds is None: # raise Exception? return _tbdata = {} _tbdata['bounds'] = _bounds _tbdata['location'] = tblock.getLocation() _family = tblock.getFamily() if _family.find(' ') != -1: _family = _family.replace(' ', '-') _val = tblock.getWeight() _weight = None if _val != TextStyle.WEIGHT_NORMAL: if _val == TextStyle.WEIGHT_LIGHT: _weight = 'light' elif _val == TextStyle.WEIGHT_BOLD: _weight = 'bold' elif _val == TextStyle.WEIGHT_HEAVY: _weight = 'heavy' else: raise ValueError, "Unexpected font weight: %d" % _val _val = tblock.getStyle() _style = None if _val != TextStyle.FONT_NORMAL: if _val == TextStyle.FONT_OBLIQUE: _style = 'oblique' elif _val == TextStyle.FONT_ITALIC: _style = 'italic' else: raise ValueError, "Unexpected font style: %d" % _val if _weight is None and _style is None: _font = _family else: if _weight is None: _font = "%s-%s" % (_family, _style) elif _style is None: _font = "%s-%s" % (_family, _weight) else: _font = "%s-%s%s" % (_family, _style, _weight) _tbdata['font'] = _font _col = None if self.__color: _c = tblock.getColor() if self.__invert and _c == Plot.__white: _col = (0, 0, 0) # black else: _col = _c.getColors() # r, g, b _tbdata['color'] = _col _val = tblock.getAlignment() if _val == TextStyle.ALIGN_LEFT: _align = 'left' elif _val == TextStyle.ALIGN_CENTER: _align = 'center' elif _val == TextStyle.ALIGN_RIGHT: _align = 'right' else: raise ValueError, "Unexpected alignment: %d" % _val _tbdata['align'] = _align _tbdata['size'] = tblock.getSize() _tbdata['angle'] = tblock.getAngle() _tbdata['text'] = tblock.getText().splitlines() # return (_x, _y, _bounds, _font, _col, _align, _size, _angle, _text) return _tbdata def _saveDimensionData(self, dim): if isinstance(dim, dimension.LinearDimension): self._saveLDimData(dim) elif isinstance(dim, dimension.RadialDimension): self._saveRDimData(dim) elif isinstance(dim, dimension.AngularDimension): self._saveADimData(dim) else: raise TypeError, "Unexpected dimension type: " + `dim` def _getDimGraphicData(self, dim): _col = None if self.__color: _c = dim.getColor() if self.__invert and _c == Plot.__white: _col = (0, 0, 0) # black else: _col = _c.getColors() # r, g, b return _col def _getDimMarkers(self, dim): _data = {} _etype = dim.getEndpointType() if isinstance(dim, dimension.AngularDimension): _crossbar = dim.getDimCrossarc() else: _crossbar = dim.getDimCrossbar() _mp1, _mp2 = _crossbar.getCrossbarPoints() if (_etype == dimension.Dimension.DIM_ENDPT_ARROW or _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW or _etype == dimension.Dimension.DIM_ENDPT_SLASH): _epts = _crossbar.getMarkerPoints() _data['p1'] = _epts[0] _data['p2'] = _epts[1] _data['p3'] = _epts[2] _data['p4'] = _epts[3] _data['v1'] = _mp1 _data['v2'] = _mp2 if _etype == dimension.Dimension.DIM_ENDPT_ARROW: _data['type'] = 'arrow' elif _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW: _data['type'] = 'filled_arrow' elif _etype == dimension.Dimension.DIM_ENDPT_SLASH: _data['type'] = 'slash' elif _etype == dimension.Dimension.DIM_ENDPT_CIRCLE: _data['type'] = 'circle' _data['radius'] = dim.getEndpointSize() _data['c1'] = _mp1 _data['c2'] = _mp2 elif _etype == dimension.Dimension.DIM_ENDPT_NONE: _data['type'] = None else: raise ValueError, "Unexpected endpoint type: %d" % _etype return _data def _saveLDimData(self, dim): _dimdata = {} _bar1, _bar2 = dim.getDimBars() _ep1, _ep2 = _bar1.getEndpoints() _dimdata['ep1'] = _ep1 _dimdata['ep2'] = _ep2 _ep3, _ep4 = _bar2.getEndpoints() _dimdata['ep3'] = _ep3 _dimdata['ep4'] = _ep4 _ep5, _ep6 = dim.getDimCrossbar().getEndpoints() _dimdata['ep5'] = _ep5 _dimdata['ep6'] = _ep6 _eptype = dim.getEndpointType() _dimdata['eptype'] = _eptype _dimdata['color'] = self._getDimGraphicData(dim) _dimdata['thickness'] = dim.getThickness() _ds1, _ds2 = dim.getDimstrings() _dimdata['ds1'] = self._getTextBlockData(_ds1) if dim.getDualDimMode(): _dimdata['ds2'] = self._getTextBlockData(_ds2) _dimdata['markers'] = self._getDimMarkers(dim) _data = self.__data.setdefault('ldims', []) _data.append(_dimdata) def _saveRDimData(self, dim): _dimdata = {} _ep1, _ep2 = dim.getDimCrossbar().getEndpoints() _dimdata['ep1'] = _ep1 _dimdata['ep2'] = _ep2 _dimdata['color'] = self._getDimGraphicData(dim) _dimdata['thickness'] = dim.getThickness() _ds1, _ds2 = dim.getDimstrings() _dimdata['dia_mode'] = dim.getDiaMode() _dimdata['ds1'] = self._getTextBlockData(_ds1) if dim.getDualDimMode(): _dimdata['ds2'] = self._getTextBlockData(_ds2) _mdata = self._getDimMarkers(dim) if not dim.getDiaMode() and _mdata['type'] is not None: _mdata['rdim'] = True _dimdata['markers'] = _mdata _data = self.__data.setdefault('rdims', []) _data.append(_dimdata) def _saveADimData(self, dim): _dimdata = {} _bar1, _bar2 = dim.getDimBars() _ep1, _ep2 = _bar1.getEndpoints() _dimdata['ep1'] = _ep1 _dimdata['ep2'] = _ep2 _ep3, _ep4 = _bar2.getEndpoints() _dimdata['ep3'] = _ep3 _dimdata['ep4'] = _ep4 _dimdata['vp'] = dim.getVertexPoint().getCoords() _crossarc = dim.getDimCrossarc() _r = _crossarc.getRadius() _dimdata['r'] = _r _sa = _crossarc.getStartAngle() _dimdata['sa'] = _sa _ea = _crossarc.getEndAngle() _dimdata['ea'] = _ea _dimdata['color'] = self._getDimGraphicData(dim) _dimdata['thickness'] = dim.getThickness() _ds1, _ds2 = dim.getDimstrings() _dimdata['ds1'] = self._getTextBlockData(_ds1) if dim.getDualDimMode(): _dimdata['ds2'] = self._getTextBlockData(_ds2) _dimdata['markers'] = self._getDimMarkers(dim) _data = self.__data.setdefault('adims', []) _data.append(_dimdata) def getPlotEntities(self, entity): return self.__data[entity] PythonCAD-DS1-R37/PythonCAD/Generic/preferences.py0000644000175000017500000020146311307666657021220 0ustar matteomatteo# # Copyright (c) 2003, 2004, 2006 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # This code handles loading the global and user preference # files # import imp import string import types import sys import os from PythonCAD.Generic import globals from PythonCAD.Generic import units from PythonCAD.Generic import text from PythonCAD.Generic import color from PythonCAD.Generic import linetype from PythonCAD.Generic import style from PythonCAD.Generic import dimension from PythonCAD.Generic import graphicobject # # global variables # pref_file = '/etc/pythoncad/prefs.py' # def _test_font_weight(val): _weight = None try: _weight = text.TextStyle.getWeightFromString(val) except: sys.stderr.write("invalid font weight: '" + str(val) + "'\n") return _weight def _test_font_style(val): _style = None try: _style = text.TextStyle.getStyleFromString(val) except: sys.stderr.write("Invalid font style: '" + str(val) + "'\n") return _style def _test_color(val): _color = None try: _c = color.Color(val) if _c in globals.colors: _color = globals.colors[_c] else: globals.colors[_c] = _c if _color is None: _color = _c except: sys.stderr.write("Invalid color: '%s'\n" % val) return _color def _test_dim_position(val): _pos = None try: _pos = dimension.Dimension.getPositionFromString(val) except: sys.stderr.write("Invalid dimension position: '" + str(val) + "'\n") return _pos def _test_dim_endpoint(val): _ept = None try: _ept = dimension.Dimension.getEndpointTypeFromString(val) except: sys.stderr.write("Invalid dimension endpoint: '" + str(val) + "'\n") return _ept def _test_units(val): _unit = None try: _unit = units.Unit.getUnitFromString(val) except: sys.stderr.write("Invalid unit: '" + str(val) + "'\n") return _unit def _test_boolean(val): _bool = None if val is True or val is False: _bool = val else: sys.stderr.write("Invalid boolean flag: '%s'\n" % val) return _bool def _test_float(val): _float = None if isinstance(val, float): _float = val else: try: _float = float(val) except: sys.stderr.write("Invalid float value: '%s'\n" % val) return _float def _test_int(val): _int = None if isinstance(val, int): _int = val else: try: _int = int(val) except: sys.stderr.write("Invalid integer value: '%s'\n" % val) return _int def _test_unicode(val): _uni = None if isinstance(val, unicode): _uni = val else: try: _uni = unicode(val) except: sys.stderr.write("Invalid unicode string: '%s'\n" % val) return _uni def initialize_prefs(): """This method sets the initial default value for image variables. initialize_prefs() """ # # default dimension parameters # globals.prefs['DIMSTYLES'] = [dimension.Dimension.getDefaultDimStyle()] globals.prefs['DEFAULT_DIMSTYLE'] = None # # drawing and text parameters # _textstyles = [text.TextBlock.getDefaultTextStyle()] _textstyles.append(dimension.DimString.getDefaultTextStyle()) globals.prefs['TEXTSTYLES'] = _textstyles globals.prefs['DEFAULT_TEXTSTYLE'] = None # # miscellaneous things # globals.prefs['USER_PREFS'] = True # # colors # # these will be replaced ... # _colors = [] _red = color.Color(255,0,0) _colors.append(_red) _green = color.Color(0,255,0) _colors.append(_green) _blue = color.Color(0,0,255) _colors.append(_blue) _violet = color.Color(255,0,255) _colors.append(_violet) _yellow = color.Color(255,255,0) _colors.append(_yellow) _cyan = color.Color(0,255,255) _colors.append(_cyan) _white = color.Color(255,255,255) _colors.append(_white) _black = color.Color(0,0,0) _colors.append(_black) globals.prefs['COLORS'] = _colors # # linetypes # # these will be replaced # _linetypes = [] _solid = linetype.Linetype(u'Solid') _linetypes.append(_solid) _dash1 = linetype.Linetype(u'Dash1', [4,1]) _linetypes.append(_dash1) _dash2 = linetype.Linetype(u'Dash2', [8,2]) _linetypes.append(_dash2) _dash3 = linetype.Linetype(u'Dash3', [12,2]) _linetypes.append(_dash3) _dash4 = linetype.Linetype(u'Dash4', [10,2,2,2]) _linetypes.append(_dash4) _dash5 = linetype.Linetype(u'Dash5', [15,5,5,5]) _linetypes.append(_dash5) globals.prefs['LINETYPES'] = _linetypes # # line styles # # these will be replaced # _styles = [] _dst = graphicobject.GraphicObject.getDefaultStyle() _styles.append(_dst) globals.prefs['STANDARD_STYLE'] = _dst _st = style.Style('Solid White Line', _solid, _white, 1.0) _styles.append(_st) _st = style.Style('Solid Black Line', _solid, _black, 1.0) _styles.append(_st) _st = style.Style('Dashed Red Line', _dash1, _red, 1.0) _styles.append(_st) _st = style.Style('Dashed Green Line', _dash1, _green, 1.0) _styles.append(_st) _st = style.Style('Dashed Blue Line', _dash1, _blue, 1.0) _styles.append(_st) _st = style.Style('Dashed Yellow Line', _dash2, _yellow, 1.0) _styles.append(_st) _st = style.Style('Dashed Violet Line', _dash2, _violet, 1.0) _styles.append(_st) _st = style.Style('Dashed Cyan Line', _dash2, _cyan, 1.0) _styles.append(_st) globals.prefs['STYLES'] = _styles globals.prefs['DEFAULT_STYLE'] = _dst # # validate the available options and set them if they seem alright # def _set_units(prefmod): _unit = _test_units(prefmod.units) if _unit is not None: globals.prefs['UNITS'] = _unit def _set_user_prefs(prefmod): _flag = _test_boolean(prefmod.user_prefs) if _flag is not None: globals.prefs['USER_PREFS'] = _flag def _set_dim_style(prefmod): _obj = prefmod.dim_style if isinstance(_obj, dict): try: _dstyle = _parse_dimstyle(_obj) globals.prefs['DIM_STYLE'] = _dstyle for _key in _dstyle.getOptions(): _value = _dstyle.getOption(_key) globals.prefs[_key] = _value _color = _dstyle.getOption('DIM_COLOR') _colors = globals.prefs['COLORS'] if _color not in _colors: _colors.append(_color) except StandardError, _e: sys.stderr.write("Invalid DimStyle: " + _e + "\n") else: sys.stderr.write("Invalid DimStyle: " + str(_obj) +"\n") def _set_primary_font_family(prefmod): _family = prefmod.dim_primary_font_family if isinstance(_family, types.StringTypes) and _family != "": globals.prefs['DIM_PRIMARY_FONT_FAMILY'] = _family else: sys.stderr.write("Invalid primary font family: " + str(_family) + "\n") def _set_primary_font_size(prefmod): sys.stderr.write("Variable 'dim_primary_font_size' is obsolete - use 'dim_primary_text_size'\n") def _set_primary_text_size(prefmod): _size = _test_float(prefmod.dim_primary_text_size) if _size is not None: if _size > 0.0: globals.prefs['DIM_PRIMARY_TEXT_SIZE'] = _size else: sys.stderr.write("Invalid primary text size: %g\n" % _size) def _set_primary_font_weight(prefmod): _weight = _test_font_weight(prefmod.dim_primary_font_weight) if _weight is not None: globals.prefs['DIM_PRIMARY_FONT_WEIGHT'] = _weight def _set_primary_font_style(prefmod): _style = _test_font_style(prefmod.dim_primary_font_style) if _style is not None: globals.prefs['DIM_PRIMARY_FONT_STYLE'] = _style def _set_primary_font_color(prefmod): _color = _test_color(prefmod.dim_primary_font_color) if _color is not None: globals.prefs['DIM_PRIMARY_FONT_COLOR'] = _color _colors = globals.prefs['COLORS'] if _color not in _colors: _colors.append(_color) def _set_primary_text_angle(prefmod): _angle = _test_float(prefmod.dim_primary_text_angle) if _angle is not None: globals.prefs['DIM_PRIMARY_TEXT_ANGLE'] = _angle else: sys.stderr.write("Invalid primary text angle: %g\n" % _angle) def _set_primary_text_alignment(prefmod): _pta = prefmod.dim_primary_text_alignment try: _align = text.TextStyle.getAlignmentFromString(_pta) globals.prefs['DIM_PRIMARY_TEXT_ALIGNMENT'] = _align except: sys.stederr.write("Invalid primary text alignment: " + str(_pta)) def _set_primary_prefix(prefmod): _prefix = _test_unicode(prefmod.dim_primary_prefix) if _prefix is not None: globals.prefs['DIM_PRIMARY_PREFIX'] = _prefix def _set_primary_suffix(prefmod): _suffix = _test_unicode(prefmod.dim_primary_suffix) if _suffix is not None: globals.prefs['DIM_PRIMARY_SUFFIX'] = _suffix def _set_primary_precision(prefmod): _prec = _test_int(prefmod.dim_primary_precision) if _prec is not None: if _prec < 0 or _prec > 15: sys.stderr.write("Invalid primary dimension precision: %d\n" % _prec) else: globals.prefs['DIM_PRIMARY_PRECISION'] = _prec def _set_primary_units(prefmod): _unit = _test_units(prefmod.dim_primary_units) if _unit is not None: globals.prefs['DIM_PRIMARY_UNITS'] = _unit def _set_primary_print_zero(prefmod): _flag = _test_boolean(prefmod.dim_primary_print_zero) if _flag is not None: globals.prefs['DIM_PRIMARY_LEADING_ZERO'] = _flag def _set_primary_trail_decimal(prefmod): _flag = _test_boolean(prefmod.dim_primary_trailing_decimal) if _flag is not None: globals.prefs['DIM_PRIMARY_TRAILING_DECIMAL'] = _flag def _set_secondary_font_family(prefmod): _family = prefmod.dim_secondary_font_family if isinstance(_family, types.StringTypes) and _family != "": globals.prefs['DIM_SECONDARY_FONT_FAMILY'] = _family else: sys.stderr.write("Invalid secondary font family: " + str(_family) + "\n") def _set_secondary_font_size(prefmod): sys.stderr.write("Variable 'dim_secondary_font_size' is obsolete - use 'dim_secondary_text_size'\n") def _set_secondary_text_size(prefmod): _size = _test_float(prefmod.dim_secondary_text_size) if _size is not None: if _size > 0.0: globals.prefs['DIM_SECONDARY_TEXT_SIZE'] = _size else: sys.stderr.write("Invalid secondary text size: %g\n" % _size) def _set_secondary_font_weight(prefmod): _weight = _test_font_weight(prefmod.dim_secondary_font_weight) if _weight is not None: globals.prefs['DIM_SECONDARY_FONT_WEIGHT'] = _weight def _set_secondary_font_style(prefmod): _style = _test_font_style(prefmod.dim_secondary_font_style) if _style is not None: globals.prefs['DIM_SECONDARY_FONT_STYLE'] = _style def _set_secondary_font_color(prefmod): _color = _test_color(prefmod.dim_secondary_font_color) if _color is not None: globals.prefs['DIM_SECONDARY_FONT_COLOR'] = _color _colors = globals.prefs['COLORS'] if _color not in _colors: _colors.append(_color) def _set_secondary_text_angle(prefmod): _angle = _test_float(prefmod.dim_secondary_text_angle) if _angle is not None: globals.prefs['DIM_SECONDARY_TEXT_ANGLE'] = _angle else: sys.stderr.write("Invalid secondary text angle: %g\n" % _angle) def _set_secondary_text_alignment(prefmod): _sta = prefmod.dim_secondary_text_alignment try: _align = text.TextStyle.getAlignmentFromString(_sta) globals.prefs['DIM_SECONDARY_TEXT_ALIGNMENT'] = _align except: sys.stederr.write("Invalid secondary text alignment: " + str(_sta)) def _set_secondary_prefix(prefmod): _prefix = _test_unicode(prefmod.dim_secondary_prefix) if _prefix is not None: globals.prefs['DIM_SECONDARY_PREFIX'] = _prefix def _set_secondary_suffix(prefmod): _suffix = _test_unicode(prefmod.dim_secondary_suffix) if _suffix is not None: globals.prefs['DIM_SECONDARY_SUFFIX'] = _suffix def _set_secondary_precision(prefmod): _prec = _test_int(prefmod.dim_secondary_precision) if _prec is not None: if _prec < 0 or _prec > 15: sys.stderr.write("Invalid secondary dimension precision: %d\n" % _prec) else: globals.prefs['DIM_SECONDARY_PRECISION'] = _prec def _set_secondary_units(prefmod): _unit = _test_units(prefmod.dim_secondary_units) if _unit is not None: globals.prefs['DIM_SECONDARY_UNITS'] = _unit def _set_secondary_print_zero(prefmod): _flag = _test_boolean(prefmod.dim_secondary_print_zero) if _flag is not None: globals.prefs['DIM_SECONDARY_LEADING_ZERO'] = _flag def _set_secondary_trail_decimal(prefmod): _flag = _test_boolean(prefmod.dim_secondary_trailing_decimal) if _flag is not None: globals.prefs['DIM_SECONDARY_TRAILING_DECIMAL'] = _flag def _set_dim_offset(prefmod): _offset = _test_float(prefmod.dim_offset) if _offset is not None: if _offset < 0.0: sys.stderr.write("Invalid dimension offset: %g\n" % _offset) else: globals.prefs['DIM_OFFSET'] = _offset def _set_dim_extension(prefmod): _ext = _test_float(prefmod.dim_extension) if _ext is not None: if _ext < 0.0: sys.stderr.write("Invalid dimension extension: %g\n" % _ext) else: globals.prefs['DIM_EXTENSION'] = _ext def _set_dim_color(prefmod): _color = _test_color(prefmod.dim_color) if _color is not None: globals.prefs['DIM_COLOR'] = _color _colors = globals.prefs['COLORS'] if _color not in _colors: _colors.append(_color) def _set_dim_thickness(prefmod): _t = _test_float(prefmod.dim_thickness) if _t is not None: if _t < 0.0: sys.stderr.write("Invalid dimension thickness %g\n" % _t) else: globals.prefs['DIM_THICKNESS'] = _t def _set_dim_position(prefmod): _pos = _test_dim_position(prefmod.dim_position) if _pos is not None: globals.prefs['DIM_POSITION'] = _pos def _set_dim_position_offset(prefmod): _offset = _test_float(prefmod.dim_position_offset) if _offset is not None: globals.prefs['DIM_POSITION_OFFSET'] = _offset else: sys.stderr.write("Invalid dim position offset: '%s'\n" % str(prefmod.dim_position_offset)) def _set_dim_endpoint(prefmod): _ept = _test_dim_endpoint(prefmod.dim_endpoint) if _ept is not None: globals.prefs['DIM_ENDPOINT'] = _ept def _set_dim_endpoint_size(prefmod): _epsize = _test_float(prefmod.dim_endpoint_size) if _epsize is not None: if _epsize < 0.0: sys.stderr.write("Invalid endpoint size: %g\n" % _epsize) else: globals.prefs['DIM_ENDPOINT_SIZE'] = _epsize def _set_dim_dual_mode(prefmod): _flag = _test_boolean(prefmod.dim_dual_mode) if _flag is not None: globals.prefs['DIM_DUAL_MODE'] = _flag def _set_dim_dual_mode_offset(prefmod): _offset = _test_float(prefmod.dim_dual_mode_offset) if _offset is not None: globals.prefs['DIM_DUAL_MODE_OFFSET'] = _offset else: sys.stderr.write("Invalid dim dual mode offset: '%s'\n" % str(prefmod.dim_dual_mode_offset)) def _set_radial_dim_primary_prefix(prefmod): _prefix = _test_unicode(prefmod.radial_dim_primary_prefix) if _prefix is not None: globals.prefs['RADIAL_DIM_PRIMARY_PREFIX'] = _prefix def _set_radial_dim_primary_suffix(prefmod): _suffix = _test_unicode(prefmod.radial_dim_primary_suffix) if _suffix is not None: globals.prefs['RADIAL_DIM_PRIMARY_SUFFIX'] = _suffix def _set_radial_dim_secondary_prefix(prefmod): _prefix = _test_unicode(prefmod.radial_dim_secondary_prefix) if _prefix is not None: globals.prefs['RADIAL_DIM_SECONDARY_PREFIX'] = _prefix def _set_radial_dim_secondary_suffix(prefmod): _suffix = _test_unicode(prefmod.radial_dim_secondary_suffix) if _suffix is not None: globals.prefs['RADIAL_DIM_SECONDARY_SUFFIX'] = _suffix def _set_radial_dim_dia_mode(prefmod): _flag = _test_boolean(prefmod.radial_dim_dia_mode) if _flag is not None: globals.prefs['RADIAL_DIM_DIA_MODE'] = _flag def _set_angular_dim_primary_prefix(prefmod): _prefix = _test_unicode(prefmod.angular_dim_primary_prefix) if _prefix is not None: globals.prefs['ANGULAR_DIM_PRIMARY_PREFIX'] = _prefix def _set_angular_dim_primary_suffix(prefmod): _suffix = _test_unicode(prefmod.angular_dim_primary_suffix) if _suffix is not None: globals.prefs['ANGULAR_DIM_PRIMARY_SUFFIX'] = _suffix def _set_angular_dim_secondary_prefix(prefmod): _prefix = _test_unicode(prefmod.angular_dim_secondary_prefix) if _prefix is not None: globals.prefs['ANGULAR_DIM_SECONDARY_PREFIX'] = _prefix def _set_angular_dim_secondary_suffix(prefmod): _suffix = _test_unicode(prefmod.angular_dim_secondary_suffix) if _suffix is not None: globals.prefs['ANGULAR_DIM_SECONDARY_SUFFIX'] = _suffix def _set_text_style(prefmod): _obj = prefmod.text_style if isinstance(_obj, dict): try: _tstyle = _parse_textstyle(_obj) globals.prefs['TEXT_STYLE'] = _tstyle globals.prefs['FONT_WEIGHT'] = _tstyle.getWeight() globals.prefs['FONT_STYLE'] = _tstyle.getStyle() globals.prefs['FONT_FAMILY'] = _tstyle.getFamily() globals.prefs['TEXT_SIZE'] = _tstyle.getSize() globals.prefs['TEXT_ANGLE'] = _tstyle.getAngle() globals.prefs['TEXT_ALIGNMENT'] = _tstyle.getAlignment() _color = _tstyle.getColor() _colors = globals.prefs['COLORS'] if _color not in _colors: _colors.append(_color) globals.prefs['FONT_COLOR'] = _color except StandardError, _e: sys.stderr.write("Invalid TextStyle: " + _e + "\n") else: sys.stderr.write("Invalid TextStyle: " + str(_obj) +"\n") def _set_font_family(prefmod): _family = prefmod.font_family if isinstance(_family, types.StringTypes) and _family != "": globals.prefs['FONT_FAMILY'] = _family else: sys.stderr.write("Invalid font family: " + str(_family) + "\n") def _set_font_style(prefmod): _style = _test_font_style(prefmod.font_style) if _style is not None: globals.prefs['FONT_STYLE'] = _style def _set_font_weight(prefmod): _weight = _test_font_weight(prefmod.font_weight) if _weight is not None: globals.prefs['FONT_WEIGHT'] = _weight def _set_font_size(prefmod): sys.stderr.write("Variable 'font_size' is obsolete - use 'text_size'\n") def _set_text_size(prefmod): _size = _test_float(prefmod.text_size) if _size is not None: if _size > 0.0: globals.prefs['TEXT_SIZE'] = _size else: sys.stderr.write("Invalid text size: %g\n" % _size) def _set_font_color(prefmod): _color = _test_color(prefmod.font_color) if _color is not None: globals.prefs['FONT_COLOR'] = _color _colors = globals.prefs['COLORS'] if _color not in _colors: _colors.append(_color) def _set_text_angle(prefmod): _angle = _test_float(prefmod.text_size) if _angle is not None: globals.prefs['TEXT_ANGLE'] = _angle else: sys.stderr.write("Invalid text angle: %g\n" % _angle) def _set_text_alignment(prefmod): _ta = prefmod.text_alignment try: _align = text.TextStyle.getAlignmentFromString(_ta) globals.prefs['TEXT_ALIGNMENT'] = _align except: sys.stederr.write("Invalid text alignment: " + str(_ta)) def _set_chamfer_length(prefmod): _length = _test_float(prefmod.chamfer_length) if _length is not None: if _length < 0.0: sys.stderr.write("Invalid chamfer length: %g\n" % _length) else: globals.prefs['CHAMFER_LENGTH'] = _length def _set_fillet_radius(prefmod): _radius = _test_float(prefmod.fillet_radius) if _radius is not None: if _radius < 0.0: sys.stderr.write("Invalid fillet radius: %g\n" % _radius) else: globals.prefs['FILLET_RADIUS'] = _radius def _set_line_style(prefmod): _obj = prefmod.line_style if isinstance(_obj, dict): try: _style = _parse_style(_obj) globals.prefs['LINE_STYLE'] = _style _lt = _style.getLinetype() globals.prefs['LINE_TYPE'] = _lt _lts = globals.prefs['LINETYPES'] if _lt not in _lts: _lts.append(_linetype) _color = _style.getColor() globals.prefs['LINE_COLOR'] = _color _colors = globals.prefs['COLORS'] if _color not in _colors: _colors.append(_color) globals.prefs['LINE_THICKNESS'] = _style.getThickness() except StandardError, _e: sys.stderr.write("Invalid Style: " + _e + "\n") else: sys.stderr.write("Invalid Style: " + str(_obj) +"\n") def _set_line_type(prefmod): _obj = prefmod.line_type if isinstance(_obj, tuple) and len(_obj) == 2: _name, _dlist = _obj try: _lt = linetype.Linetype(_name, _dlist) globals.prefs['LINE_TYPE'] = _lt _lts = globals.prefs['LINETYPES'] if _lt not in _lt: _lts.append(_linetype) except: sys.stderr.write("Invalid linetype: '" + str(_obj) + "'\n") else: sys.stderr.write("Invalid linetype tuple: '" + str(_obj) + "'\n") def _set_line_color(prefmod): _color = _test_color(prefmod.line_color) if _color is not None: globals.prefs['LINE_COLOR'] = _color _colors = globals.prefs['COLORS'] if _color not in _colors: _colors.append(_color) def _set_line_thickness(prefmod): _t = _test_float(prefmod.line_thickness) if _t is not None: if _t < 0.0: sys.stderr.write("Invalid line thickness: %g\n" % _t) else: globals.prefs['LINE_THICKNESS'] = _t def _set_highlight_points(prefmod): _flag = _test_boolean(prefmod.highlight_points) if _flag is not None: globals.prefs['HIGHLIGHT_POINTS'] = _flag def _set_inactive_layer_color(prefmod): _color = _test_color(prefmod.inactive_layer_color) if _color is not None: globals.prefs['INACTIVE_LAYER_COLOR'] = _color def _set_background_color(prefmod): _color = _test_color(prefmod.background_color) if _color is not None: globals.prefs['BACKGROUND_COLOR'] = _color def _set_single_point_color(prefmod): _color = _test_color(prefmod.single_point_color) if _color is not None: globals.prefs['SINGLE_POINT_COLOR'] = _color def _set_multi_point_color(prefmod): _color = _test_color(prefmod.multi_point_color) if _color is not None: globals.prefs['MULTI_POINT_COLOR'] = _color def _set_autosplit(prefmod): _flag = _test_boolean(prefmod.autosplit) if _flag is not None: globals.prefs['AUTOSPLIT'] = _flag def _set_leader_arrow_size(prefmod): _size = _test_float(prefmod.leader_arrow_size) if _size is not None: if _size < 0.0: sys.stderr.write("Invalid leader arrow size: %g\n" % _size) else: globals.prefs['LEADER_ARROW_SIZE'] = _size def _set_linetypes(prefmod): _ltlist = prefmod.linetypes _linetypes = globals.prefs['LINETYPES'] if isinstance(_ltlist, list): for _obj in _ltlist: if not isinstance(_obj, tuple) or len(_obj) != 2: sys.stderr.write("Invalid linetype tuple: '" + str(_obj) + "'\n") continue _name, _dlist = _obj try: _linetype = linetype.Linetype(_name, _dlist) if _linetype not in _linetypes: _linetypes.append(_linetype) except: sys.stderr.write("Invalid linetype: '" + str(_obj) + "'\n") else: sys.stderr.write("Invalid line type list: '" + str(_ltlist) + "'\n") def _set_colors(prefmod): _clist = prefmod.colors if isinstance(_clist, list): for _obj in _clist: _color = None if isinstance(_obj, str): _color = _test_color(_obj) elif isinstance(_obj, tuple) and len(_obj) == 3: _r, _g, _b = _obj try: _color = color.Color(_r, _g, _b) except: sys.stderr.write("Invalid color: '" + str(_obj) + "'\n") else: sys.stderr.write("Invalid color: '" + str(_obj) + "'\n") if _color is not None and _color not in globals.colors: globals.colors[_color] = _color else: sys.stderr.write("Invalid color list: '" + str(_clist) + "'\n") def _parse_dimstyle(sd): if not isinstance(sd, dict): raise TypeError, "Invalid style dictionary: " + `type(sd)` _name = None _ds = {} for _key in sd.keys(): _v = sd[_key] _k = _key.lower() if _k == 'name': if not isinstance(_v, types.StringTypes): raise TypeError, "Invalid DimStyle name type: " + `type(_v)` _name = _v elif (_k == 'dim_color' or _k == 'dim_primary_font_color' or _k == 'dim_secondary_font_color'): _col = _test_color(_v) if _col is None: raise ValueError, "Invalid value '%s' for DimStyle key '%s'" % (str(_v), _k) _v = _col elif (_k == 'dim_primary_font_family' or _k == 'dim_secondary_font_family'): if not isinstance(_v, types.StringTypes): raise TypeError, "Invalid type '%s' for DimStyle key '%s'\n " % (`type(_v)`, _k) if _v == "": raise ValueError, "Font family for '%s' cannot be empty" % _k elif (_k == 'dim_offset' or _k == 'dim_dual_mode_offset' or _k == 'dim_position_offset' or _k == 'dim_thickness' or _k == 'dim_endpoint_size' or _k == 'dim_primary_text_size' or _k == 'dim_secondary_text_size' or _k == 'dim_extension'): if not isinstance(_v, float): raise TypeError, "Invalid type '%s' for DimStyle key '%s'\n " % (`type(_v)`, _k) if _v < 0.0: raise ValueError, "Invalid value %f for DimStyle key '%s'\n " % (_v, _k) elif (_k == 'dim_primary_precision' or _k == 'dim_secondary_precision'): if not isinstance(_v, int): raise TypeError, "Invalid type '%s' for DimStyle key '%s'\n " % (`type(_v)`, _k) if _v < 0 or _v > 15: raise ValueError, "Invalid value %d for DimStyle key '%s'\n " % (_v, _k) elif (_k == 'dim_primary_font_weight' or _k == 'dim_secondary_font_weight'): try: _weight = text.TextStyle.getWeightFromString(_v) except: raise ValueError, "Invalid value '%s' for DimStyle key '%s'\n " % (_v, _k) _v = _weight elif (_k == 'dim_primary_text_alignment' or _k == 'dim_secondary_text_alignment'): try: _align = text.TextStyle.getAlignmentFromString(_v) except: raise ValueError, "Invalid value '%s' for DimStyle key '%s'\n " % (_v, _k) _v = _align elif (_k == 'dim_primary_font_style' or _k == 'dim_secondary_font_style'): try: _style = text.TextStyle.getStyleFromString(_v) except: raise ValueError, "Invalid value '%s' for DimStyle key '%s'\n " % (_v, _k) _v = _style elif (_k == 'dim_primary_text_angle' or _k == 'dim_secondary_text_angle'): _angle = _test_float(_v) if _angle is None: raise ValueError, "Invalid value %d for DimStyle key '%s'\n " % (_v, _k) _v = _angle elif (_k == 'dim_primary_units' or _k == 'dim_secondary_units'): try: _unit = units.Unit.getUnitFromString(_v) except: raise ValueError, "Invalid value '%s' for DimStyle key '%s'\n " % (_v, _k) _v = _unit elif _k == 'dim_position': try: _pos = dimension.Dimension.getPositionFromString(_v) except: raise ValueError, "Invalid value '%s' for DimStyle key '%s'\n " % (_v, _k) _v = _pos elif _k == 'dim_endpoint': try: _ept = dimension.Dimension.getEndpointTypeFromString(_v) except: raise ValueError, "Invalid value '%s' for DimStyle key '%s'\n " % (_v, _k) _v = _ept elif (_k == 'dim_primary_leading_zero' or _k == 'dim_secondary_leading_zero' or _k == 'dim_primary_trailing_decimal' or _k == 'dim_secondary_trailing_decimal' or _k == 'dim_dual_mode' or _k == 'radial_dim_dia_mode'): _flag = _test_boolean(_v) if _flag is None: raise ValueError, "Invalid value '%s' for DimStyle key '%s'\n " % (str(_v), _k) _v = _flag elif (_k == 'dim_primary_prefix' or _k == 'dim_primary_suffix' or _k == 'dim_secondary_prefix' or _k == 'dim_secondary_suffix' or _k == 'radial_dim_primary_prefix' or _k == 'radial_dim_primary_suffix' or _k == 'radial_dim_secondary_prefix' or _k == 'radial_dim_secondary_suffix' or _k == 'angular_dim_primary_prefix' or _k == 'angular_dim_primary_suffix' or _k == 'angular_dim_secondary_prefix' or _k == 'angular_dim_secondary_suffix'): if not isinstance(_v, types.StringTypes): raise TypeError, "Invalid type '%s' for DimStyle key '%s'\n " % (`type(_v)`, _k) elif _k == 'dim_primary_font_size': sys.stderr.write("Key 'dim_primary_font_size' obsoleted by 'dim_primary_text_size'\n") continue elif _k == 'dim_secondary_font_size': sys.stderr.write("Key 'dim_secondary_font_size' obsoleted by 'dim_secondary_text_size'\n") continue else: raise ValueError, "Unknown DimStyle option: %s" % _k if _k != 'name': _ds[_key.upper()] = _v if _name is None: raise ValueError, "DimStyle missing 'name' field: " + str(sd) return dimension.DimStyle(_name, _ds) def _parse_textstyle(sd): if not isinstance(sd, dict): raise TypeError, "Invalid style dictionary: " + `type(sd)` _name = sd.get('name') if _name is None: raise ValueError, "TextStyle missing 'name' field: " + str(sd) if not isinstance(_name, types.StringTypes): raise TypeError, "Invalid textstyle name type: " + `type(_name)` _family = sd.get('family') if _family is None: raise ValueError, "TextStyle missing 'family' field: " + str(sd) if not isinstance(_family, types.StringTypes): raise TypeError, "Invalid textstyle family type: " + `type(_family)` _val = sd.get('style') if _val is None: raise TypeError, "TextStyle missing 'style' field: " + str(sd) _style = text.TextStyle.getStyleFromString(_val) _val = sd.get('weight') if _val is None: raise TypeError, "TextStyle missing 'weight' field: " + str(sd) _weight = text.TextStyle.getWeightFromString(_val) _val = sd.get('color') if _val is None: raise ValueError, "Style missing 'color' field: " + str(sd) _color = _test_color(_val) if _color is None: raise ValueError, "Invalid TextStyle color: " + str(_val) _size = sd.get('size') if _size is None: raise ValueError, "TextStyle missing 'size' field: " + str(sd) _angle = sd.get('angle') if _angle is None: raise ValueError, "TextSytle missing 'angle' field: " + str(sd) _val = sd.get('alignment') if _val is None: raise TypeError, "TextStyle missing 'alignment' field: " + str(sd) _align = text.TextStyle.getAlignmentFromString(_val) return text.TextStyle(_name, family=_family, style=_style, weight=_weight, color=_color, size=_size, angle=_angle, align=_align) def _parse_style(sd): if not isinstance(sd, dict): raise TypeError, "Invalid style dictionary: " + `type(sd)` _n = sd.get('name') if _n is None: raise ValueError, "Style missing 'name' field: " + str(sd) if not isinstance(_n, types.StringTypes): raise TypeError, "Invalid style name type: " + `type(_n)` _l = sd.get('linetype') if _l is None: raise ValueError, "Style missing 'linetype' field: " + str(sd) if not isinstance(_l, tuple): raise TypeError, "Invalid linetype tuple: " + `type(_l)` if len(_l) != 2: raise ValueError, "Invalid linetype tuple length: " + str(_l) _ln = _l[0] if not isinstance(_ln, types.StringTypes): raise TypeError, "Invalid style linetype name type: " + `type(_ln)` _ld = _l[1] if _ld is not None and not isinstance(_ld, list): raise TypeError, "Invalid style linetype dashlist type: " + `type(_ld)` _lt = linetype.Linetype(_ln, _ld) _c = sd.get('color') if _c is None: raise ValueError, "Style missing 'color' field: " + str(sd) _col = _test_color(_c) if _col is None: raise ValueError, "Invalid Style color: " + str(_c) _t = sd.get('thickness') if _t is None: raise ValueError, "Style missing 'thickness' field: " + str(sd) return style.Style(_n, _lt, _col, _t) def _set_styles(prefmod): _slist = prefmod.styles _styles = globals.prefs['STYLES'] _linetypes = globals.prefs['LINETYPES'] if isinstance(_slist, list): for _obj in _slist: _style = None if isinstance(_obj, dict): try: _style = _parse_style(_obj) except: sys.stderr.write("Invalid style: %s\n" % str(_obj)) elif isinstance(_obj, tuple): sys.stderr.write("Tuple based Style definition is deprecated: '" + str(_obj) + "'\n") if len(_obj) != 4: sys.stderr.write("Invalid tuple-based style entry: '" + str(_obj) + "'\n") continue _sd = { 'name' : _obj[0], 'linetype' : _obj[1], 'color' : _obj[2], 'thickness' : _obj[3] } try: _style = _parse_style(_sd) except StandardError, _e: sys.stderr.write("Invalid style: %s, %e\n" % (str(_obj), _e)) else: sys.stderr.write("Unexpected style type: %s" % `type(_obj)`) if _style is None: continue if _style not in _styles: _styles.append(_style) _linetype = _style.getLinetype() if _linetype not in _linetypes: _linetypes.append(_linetype) else: sys.stderr.write("Invalid style list: '" + str(_slist) + "'\n") def _set_dimstyles(prefmod): _dslist = prefmod.dimstyles _dimstyles = globals.prefs['DIMSTYLES'] if isinstance(_dslist, list): for _obj in _dslist: _dimstyle = None if not isinstance(_obj, tuple) or len(_obj) != 2: sys.stderr.write("Invalid DimStyle entry: '" + str(_obj) + "'\n") continue _name, _dsdict = _obj if not isinstance(_name, types.StringTypes): sys.stderr.write("Invalid DimStyle name: '" + str(_name) + "'\n") continue if not isinstance(_dsdict, dict): sys.stderr.write("Invalid DimStyle dictionary: '" + str(_dsdict) + "'\n") continue _dsdict['name'] = _name try: _dimstyle = _parse_dimstyle(_dsdict) except StandardError, _e: sys.stderr.write("Invalid DimStyle: " + _e) if _dimstyle is not None and _dimstyle not in _dimstyles: _dimstyles.append(_dimstyle) else: sys.stderr.write("Invalid dimension style list: '" + str(_dslist) + "'\n") def _set_textstyles(prefmod): _tslist = prefmod.textstyles _textstyles = globals.prefs['TEXTSTYLES'] if isinstance(_tslist, list): for _obj in _tslist: _textstyle = None if isinstance(_obj, dict): try: _textstyle = _parse_textstyle(_obj) except StandardError, _e: sys.stderr.write("Invalid TextStyle: " + _e) elif isinstance(_obj, tuple): sys.stderr.write("Tuple based TextStyle definition is deprecated: '" + str(_obj) + "'\n") if len(_obj) != 6: sys.stderr.write("Invalid tuple based TextStyle entry: '" + str(_obj) + "'\n") continue # # tuple-based definition lacked angle and alignment fields, # so we add them with reasonable values # _td = { 'name' : _obj[0], 'family' : _obj[1], 'size' : _obj[2], 'style' : _obj[3], 'weight' : _obj[4], 'color' : _obj[5], 'angle' : 0.0, 'alignment' : 'left' } try: _textstyle = _parse_textstyle(_td) except StandardError, _e: sys.stderr.write("Invalid TextSyle: %s, %e\n" % (str(_obj), _e)) if _textstyle is not None and _textstyle not in _textstyles: _textstyles.append(_textstyle) else: sys.stderr.write("Invalid text style list: '" + str(_tslist) + "'\n") # # this list of tuples stores the tested attributes in the 'prefs.py' module(s) # and the function used to validate the value given by the user # _preflist = [ # # booleans # ('user_prefs', _set_user_prefs), ('autosplit', _set_autosplit), ('highlight_points', _set_highlight_points), # # floats # ('leader_arrow_size', _set_leader_arrow_size), ('chamfer_length', _set_chamfer_length), ('fillet_radius', _set_fillet_radius), # # display colors # ('inactive_layer_color', _set_inactive_layer_color), ('background_color', _set_background_color), ('single_point_color', _set_single_point_color), ('multi_point_color', _set_multi_point_color), # # units # ('units', _set_units), # # GraphicObject entity parameters # ('line_style', _set_line_style), ('line_type', _set_line_type), ('line_color', _set_line_color), ('line_thickness', _set_line_thickness), # # TextBlock parameters # ('text_style', _set_text_style), ('font_family', _set_font_family), ('font_style', _set_font_style), ('font_weight', _set_font_weight), ('font_size', _set_font_size), ('text_size', _set_text_size), ('font_color', _set_font_color), ('text_angle', _set_text_angle), ('text_alignment', _set_text_alignment), # # Dimension paramters # ('dim_style', _set_dim_style), ('dim_primary_font_family', _set_primary_font_family), ('dim_primary_font_size', _set_primary_font_size), ('dim_primary_text_size', _set_primary_text_size), ('dim_primary_font_weight', _set_primary_font_weight), ('dim_primary_font_style', _set_primary_font_style), ('dim_primary_font_color', _set_primary_font_color), ('dim_primary_text_angle', _set_primary_text_angle), ('dim_primary_text_alignment',_set_primary_text_alignment), ('dim_primary_prefix', _set_primary_prefix), ('dim_primary_suffix', _set_primary_suffix), ('dim_primary_precision', _set_primary_precision), ('dim_primary_units', _set_primary_units), ('dim_primary_leading_zero', _set_primary_print_zero), ('dim_primary_trailing_decimal', _set_primary_trail_decimal), ('dim_secondary_font_family', _set_secondary_font_family), ('dim_secondary_font_size', _set_secondary_font_size), ('dim_secondary_text_size', _set_secondary_text_size), ('dim_secondary_font_weight', _set_secondary_font_weight), ('dim_secondary_font_style', _set_secondary_font_style), ('dim_secondary_font_color', _set_secondary_font_color), ('dim_secondary_text_angle', _set_secondary_text_angle), ('dim_secondary_text_alignment', _set_secondary_text_alignment), ('dim_secondary_prefix', _set_secondary_prefix), ('dim_secondary_suffix', _set_secondary_suffix), ('dim_secondary_precision', _set_secondary_precision), ('dim_secondary_units', _set_secondary_units), ('dim_secondary_leading_zero', _set_secondary_print_zero), ('dim_secondary_trailing_decimal', _set_secondary_trail_decimal), ('dim_offset', _set_dim_offset), ('dim_extension', _set_dim_extension), ('dim_color', _set_dim_color), ('dim_thickness', _set_dim_thickness), ('dim_position', _set_dim_position), ('dim_position_offset', _set_dim_position_offset), ('dim_endpoint', _set_dim_endpoint), ('dim_endpoint_size', _set_dim_endpoint_size), ('dim_dual_mode', _set_dim_dual_mode), ('dim_dual_mode_offset', _set_dim_dual_mode_offset), ('radial_dim_primary_prefix', _set_radial_dim_primary_prefix), ('radial_dim_primary_suffix', _set_radial_dim_primary_suffix), ('radial_dim_secondary_prefix', _set_radial_dim_secondary_prefix), ('radial_dim_secondary_suffix', _set_radial_dim_secondary_suffix), ('radial_dim_dia_mode', _set_radial_dim_dia_mode), ('angular_dim_primary_prefix', _set_angular_dim_primary_prefix), ('angular_dim_primary_suffix', _set_angular_dim_primary_suffix), ('angular_dim_secondary_prefix', _set_angular_dim_secondary_prefix), ('angular_dim_secondary_suffix', _set_angular_dim_secondary_suffix), # # lists of object types to be loaded in at startup # ('colors', _set_colors), ('linetypes', _set_linetypes), ('styles', _set_styles), ('textstyles', _set_textstyles), ('dimstyles', _set_dimstyles) ] def _set_defaults(prefmod): if hasattr(prefmod, 'default_dimstyle'): _dsname = prefmod.default_dimstyle if isinstance(_dsname, types.StringTypes): _set = False for _dimstyle in globals.prefs['DIMSTYLES']: _name = _dimstyle.getName() if _name == _dsname: globals.prefs['DEFAULT_DIMSTYLE'] = _dimstyle _set = True break if not _set: sys.stderr.write("No DimStyle found with name '%s'\n" % _dsname) elif _dsname is None: pass # accept default else: sys.stderr.write("Invalid default dimension style: '%s'\n" % str(_dsname)) if hasattr(prefmod, 'default_textstyle'): _tsname = prefmod.default_textstyle if isinstance(_tsname, types.StringTypes): _set = False for _textstyle in globals.prefs['TEXTSTYLES']: _name = _textstyle.getName() if _name == _tsname: globals.prefs['DEFAULT_TEXTSTYLE'] = _textstyle _set = True break if not _set: sys.stderr.write("No TextStyle found with name '%s'\n" % _tsname) elif _tsname is None: pass # accept default else: sys.stderr.write("Invalid default TextStyle: '%s'\n" % str(_tsname)) if hasattr(prefmod, 'default_style'): _sname = prefmod.default_style if isinstance(_sname, types.StringTypes): _set = False for _style in globals.prefs['STYLES']: if _style.getName() == _sname: globals.prefs['DEFAULT_STYLE'] = _style _set = True break if not _set: sys.stderr.write("No Style found with name '%s'\n" % _sname) elif _sname is None: pass # accept default else: sys.stderr.write("Invalid default Style: '%s'\n" % str(_sname)) def load_global_prefs(): """Try and load the preferences stored in the global preferences file load_global_prefs() If the preferences file '/etc/pythoncad/prefs.py' exists and can be read without errors, the global preferences will be set to the values read from the file. """ try: _f, _p, _d = imp.find_module('prefs', ['/etc/pythoncad']) if _f is not None: try: try: _mod = imp.load_module('prefs', _f, _p, _d) finally: _f.close() for _attr, _func in _preflist: if hasattr(_mod, _attr): _func(_mod) _set_defaults(_mod) del sys.modules['prefs'] except StandardError, _e: # should print the error out sys.stderr.write("Syntax error in %s: %s\n" % (_p, _e)) except ImportError: pass except StandardError, _e: sys.stderr.write("Error loading global preferences: %s" % _e) def load_user_prefs(): """Try and load the preferences stored in the user's preference file load_user_prefs() If the file '$HOME/.pythoncad/prefs.py' ('$APPDATA/PythonCAD/prefs.py' on Windows) exists and can be read without errors, the preferences given in that file will be used to set the global preferences. Reading this file is conditioned upon the 'USER_PREFS' variable being set to True. """ _flag = True if globals.prefs.has_key('USER_PREFS'): _flag = globals.prefs['USER_PREFS'] _pdir = None if sys.platform == 'win32' and os.environ.has_key('APPDATA'): _pdir = os.path.join(os.environ.get('APPDATA'), 'PythonCAD') else: if os.environ.has_key('HOME'): _pdir = os.path.join(os.environ['HOME'], '.pythoncad') if _flag and _pdir is not None: try: _f, _p, _d = imp.find_module('prefs',[_pdir]) if _f is not None: try: try: _mod = imp.load_module('prefs', _f, _p, _d) finally: _f.close() for _attr, _func in _preflist: if hasattr(_mod, _attr): _func(_mod) del sys.modules['prefs'] except StandardError, _e: # should print the error out sys.stderr.write("Syntax error in %s: %s\n" % (_p, _e)) except ImportError: pass except StandardError, _e: sys.stderr.write("Error loading user preferences: %s" % _e) def _save_dimstyle_values(f): f.write("#\n# Standard Dimension parameters\n#\n") _gp = globals.prefs _tc = text.TextStyle _dim = dimension.Dimension _uc = units.Unit _ds = _gp['DIM_STYLE'] f.write("dim_style = {\n") f.write(" 'name' : '%s',\n" % _ds.getName()) _val = _ds.getOption('DIM_PRIMARY_FONT_FAMILY') f.write(" 'dim_primary_font_family' : '%s',\n" % _val) _val = _ds.getOption('DIM_PRIMARY_TEXT_SIZE') f.write(" 'dim_primary_text_size' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_PRIMARY_FONT_WEIGHT') f.write(" 'dim_primary_font_weight': '%s',\n" % _tc.getWeightAsString(_val)) _val = _ds.getOption('DIM_PRIMARY_FONT_STYLE') f.write(" 'dim_primary_font_style' : '%s',\n" % _tc.getStyleAsString(_val)) _val = _ds.getOption('DIM_PRIMARY_FONT_COLOR') f.write(" 'dim_primary_font_color' : '%s',\n" % str(_val)) _val = _ds.getOption('DIM_PRIMARY_TEXT_ANGLE') f.write(" 'dim_primary_text_angle' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_PRIMARY_TEXT_ALIGNMENT') f.write(" 'dim_primary_text_alignment' : '%s',\n" % _tc.getAlignmentAsString(_val)) _val = _ds.getOption('DIM_PRIMARY_PREFIX') f.write(" 'dim_primary_prefix' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_PRIMARY_SUFFIX') f.write(" 'dim_primary_suffix' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_PRIMARY_PRECISION') f.write(" 'dim_primary_precision' : %d,\n" % _val) _val = _ds.getOption('DIM_PRIMARY_UNITS') f.write(" 'dim_primary_units' : '%s',\n" % _uc.getUnitAsString(_val)) _val = _ds.getOption('DIM_PRIMARY_LEADING_ZERO') f.write(" 'dim_primary_leading_zero' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_PRIMARY_TRAILING_DECIMAL') f.write(" 'dim_primary_trailing_decimal' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_SECONDARY_FONT_FAMILY') f.write(" 'dim_secondary_font_family' : '%s',\n" % _val) _val = _ds.getOption('DIM_SECONDARY_TEXT_SIZE') f.write(" 'dim_secondary_text_size' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_SECONDARY_FONT_WEIGHT') f.write(" 'dim_secondary_font_weight' : '%s',\n" % _tc.getWeightAsString(_val)) _val = _ds.getOption('DIM_SECONDARY_FONT_STYLE') f.write(" 'dim_secondary_font_style' : '%s',\n" % _tc.getStyleAsString(_val)) _val = _ds.getOption('DIM_SECONDARY_FONT_COLOR') f.write(" 'dim_secondary_font_color' : '%s',\n" % str(_val)) _val = _ds.getOption('DIM_SECONDARY_TEXT_ANGLE') f.write(" 'dim_secondary_text_angle' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_SECONDARY_TEXT_ALIGNMENT') f.write(" 'dim_secondary_text_alignment' : '%s',\n" % _tc.getAlignmentAsString(_val)) _val = _ds.getOption('DIM_SECONDARY_PREFIX') f.write(" 'dim_secondary_prefix' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_SECONDARY_SUFFIX') f.write(" 'dim_secondary_suffix' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_SECONDARY_PRECISION') f.write(" 'dim_secondary_precision' : %d,\n" % _val) _val = _ds.getOption('DIM_SECONDARY_UNITS') f.write(" 'dim_secondary_units' : '%s',\n" % _uc.getUnitAsString(_val)) _val = _ds.getOption('DIM_SECONDARY_LEADING_ZERO') f.write(" 'dim_secondary_leading_zero' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_SECONDARY_TRAILING_DECIMAL') f.write(" 'dim_secondary_trailing_decimal' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_OFFSET') f.write(" 'dim_offset' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_EXTENSION') f.write(" 'dim_extension' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_COLOR') f.write(" 'dim_color' : '%s',\n" % str(_val)) _val = _ds.getOption('DIM_THICKNESS') f.write(" 'dim_thickness' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_POSITION') f.write(" 'dim_position' : '%s',\n" % _dim.getPositionAsString(_val)) _val = _ds.getOption('DIM_ENDPOINT') f.write(" 'dim_endpoint' : '%s',\n" % _dim.getEndpointTypeAsString(_val)) _val = _ds.getOption('DIM_ENDPOINT_SIZE') f.write(" 'dim_endpoint_size' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_DUAL_MODE') f.write(" 'dim_dual_mode' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_POSITION_OFFSET') f.write(" 'dim_position_offset' : %s,\n" % repr(_val)) _val = _ds.getOption('DIM_DUAL_MODE_OFFSET') f.write(" 'dim_dual_mode_offset' : %s,\n" % repr(_val)) _val = _ds.getOption('RADIAL_DIM_PRIMARY_PREFIX') f.write(" 'radial_dim_primary_prefix' : %s,\n" % repr(_val)) _val = _ds.getOption('RADIAL_DIM_PRIMARY_SUFFIX') f.write(" 'radial_dim_primary_suffix' : %s,\n" % repr(_val)) _val = _ds.getOption('RADIAL_DIM_SECONDARY_PREFIX') f.write(" 'radial_dim_secondary_prefix' : %s,\n" % repr(_val)) _val = _ds.getOption('RADIAL_DIM_SECONDARY_SUFFIX') f.write(" 'radial_dim_secondary_suffix' : %s,\n" % repr(_val)) _val = _ds.getOption('RADIAL_DIM_DIA_MODE') f.write(" 'radial_dim_dia_mode' : %s,\n" % repr(_val)) _val = _ds.getOption('ANGULAR_DIM_PRIMARY_PREFIX') f.write(" 'angular_dim_primary_prefix' : %s,\n" % repr(_val)) _val = _ds.getOption('ANGULAR_DIM_PRIMARY_SUFFIX') f.write(" 'angular_dim_primary_suffix' : %s,\n" % repr(_val)) _val = _ds.getOption('ANGULAR_DIM_SECONDARY_PREFIX') f.write(" 'angular_dim_secondary_prefix' : %s,\n" % repr(_val)) _val = _ds.getOption('ANGULAR_DIM_SECONDARY_SUFFIX') f.write(" 'angular_dim_secondary_suffix' : %s\n" % repr(_val)) f.write("}\n") # # save overriden values # _val = _gp['DIM_PRIMARY_FONT_FAMILY'] if _val != _ds.getOption('DIM_PRIMARY_FONT_FAMILY'): f.write("dim_primary_font_family = '%s'\n" % _val) _val = _gp['DIM_PRIMARY_TEXT_SIZE'] if abs(_val - _ds.getOption('DIM_PRIMARY_TEXT_SIZE')) > 1e-10: f.write("dim_primary_text_size = %s\n" % repr(_val)) _val = _gp['DIM_PRIMARY_FONT_WEIGHT'] if _val != _ds.getOption('DIM_PRIMARY_FONT_WEIGHT'): f.write("dim_primary_font_weight = '%s'\n" % _tc.getWeightAsString(_val)) _val = _gp['DIM_PRIMARY_FONT_STYLE'] if _val != _ds.getOption('DIM_PRIMARY_FONT_STYLE'): f.write("dim_primary_font_style = '%s'\n" % _tc.getStyleAsString(_val)) _val = _gp['DIM_PRIMARY_FONT_COLOR'] if _val != _ds.getOption('DIM_PRIMARY_FONT_COLOR'): f.write("dim_primary_font_color = '%s'\n" % str(_val)) _val = _gp['DIM_PRIMARY_TEXT_ANGLE'] if abs(_val - _ds.getOption('DIM_PRIMARY_TEXT_ANGLE')) > 1e-10: f.write("dim_primary_text_angle = %s\n" % repr(_val)) _val = _gp['DIM_PRIMARY_TEXT_ALIGNMENT'] if _val != _ds.getOption('DIM_PRIMARY_TEXT_ALIGNMENT'): f.write("dim_primary_text_alignment = '%s'\n" % _tc.getAlignmentAsString(_val)) _val = _gp['DIM_PRIMARY_PREFIX'] if _val != _ds.getOption('DIM_PRIMARY_PREFIX'): f.write("dim_primary_prefix = %s\n" % repr(_val)) _val = _gp['DIM_PRIMARY_SUFFIX'] if _val != _ds.getOption('DIM_PRIMARY_SUFFIX'): f.write("dim_primary_suffix = %s\n" % repr(_val)) _val = _gp['DIM_PRIMARY_PRECISION'] if _val != _ds.getOption('DIM_PRIMARY_PRECISION'): f.write("dim_primary_precision = %d\n" % _val) _val = _gp['DIM_PRIMARY_UNITS'] if _val != _ds.getOption('DIM_PRIMARY_UNITS'): f.write("dim_primary_units = '%s'\n" % _uc.getUnitAsString(_val)) _val = _gp['DIM_PRIMARY_LEADING_ZERO'] if _val is not _ds.getOption('DIM_PRIMARY_LEADING_ZERO'): f.write("dim_primary_leading_zero = %s\n" % repr(_val)) _val = _gp['DIM_PRIMARY_TRAILING_DECIMAL'] if _val is not _ds.getOption('DIM_PRIMARY_TRAILING_DECIMAL'): f.write("dim_primary_trailing_decimal = %s\n" % repr(_val)) _val = _gp['DIM_SECONDARY_FONT_FAMILY'] if _val != _ds.getOption('DIM_SECONDARY_FONT_FAMILY'): f.write("dim_secondary_font_family = '%s'\n" % _val) _val = _gp['DIM_SECONDARY_TEXT_SIZE'] if abs(_val - _ds.getOption('DIM_SECONDARY_TEXT_SIZE')) > 1e-10: f.write("dim_secondary_text_size = %s\n" % repr(_val)) _val = _gp['DIM_SECONDARY_FONT_WEIGHT'] if _val != _ds.getOption('DIM_SECONDARY_FONT_WEIGHT'): f.write("dim_secondary_font_weight = '%s'\n" % _tc.getWeightAsString(_val)) _val = _gp['DIM_SECONDARY_FONT_STYLE'] if _val != _ds.getOption('DIM_SECONDARY_FONT_STYLE'): f.write("dim_secondary_font_style = '%s'\n" % _tc.getStyleAsString(_val)) _val = _gp['DIM_SECONDARY_FONT_COLOR'] if _val != _ds.getOption('DIM_SECONDARY_FONT_COLOR'): f.write("dim_secondary_font_color = '%s'\n" % str(_val)) _val = _gp['DIM_SECONDARY_TEXT_ANGLE'] if abs(_val - _ds.getOption('DIM_SECONDARY_TEXT_ANGLE')) > 1e-10: f.write("dim_secondary_text_angle = %s\n" % repr(_val)) _val = _gp['DIM_SECONDARY_TEXT_ALIGNMENT'] if _val != _ds.getOption('DIM_SECONDARY_TEXT_ALIGNMENT'): f.write("dim_secondary_text_alignment = '%s'\n" % _tc.getAlignmentAsString(_val)) _val = _gp['DIM_SECONDARY_PREFIX'] if _val != _ds.getOption('DIM_SECONDARY_PREFIX'): f.write("dim_secondary_prefix = %s\n" % repr(_val)) _val = _gp['DIM_SECONDARY_SUFFIX'] if _val != _ds.getOption('DIM_SECONDARY_SUFFIX'): f.write("dim_secondary_suffix = %s\n" % repr(_val)) _val = _gp['DIM_SECONDARY_PRECISION'] if _val != _ds.getOption('DIM_SECONDARY_PRECISION'): f.write("dim_secondary_precision = %d\n" % _val) _val = _gp['DIM_SECONDARY_UNITS'] if _val != _ds.getOption('DIM_SECONDARY_UNITS'): f.write("dim_secondary_units = '%s'\n" % _uc.getUnitAsString(_val)) _val = _gp['DIM_SECONDARY_LEADING_ZERO'] if _val is not _ds.getOption('DIM_SECONDARY_LEADING_ZERO'): f.write("dim_secondary_leading_zero = %s\n" % repr(_val)) _val = _gp['DIM_SECONDARY_TRAILING_DECIMAL'] if _val is not _ds.getOption('DIM_SECONDARY_TRAILING_DECIMAL'): f.write("dim_secondary_trailing_decimal = %s\n" % repr(_val)) _val = _gp['DIM_OFFSET'] if abs(_val - _ds.getOption('DIM_OFFSET')) > 1e-10: f.write("dim_offset = %s\n" % repr(_val)) _val = _gp['DIM_EXTENSION'] if abs(_val - _ds.getOption('DIM_EXTENSION')) > 1e-10: f.write("dim_extension = %s\n" % repr(_val)) _val = _gp['DIM_COLOR'] if _val != _ds.getOption('DIM_COLOR'): f.write("dim_color = '%s'\n" % str(_val)) _val = _gp['DIM_THICKNESS'] if abs(_val - _ds.getOption('DIM_THICKNESS')) > 1e-10: f.write("dim_thickness = %s\n" % repr(_val)) _val = _gp['DIM_POSITION'] if _val != _ds.getOption('DIM_POSITION'): f.write("dim_position = '%s'\n" % _dim.getPositionAsString(_val)) _val = _gp['DIM_ENDPOINT'] if _val != _ds.getOption('DIM_ENDPOINT'): f.write("dim_endpoint = '%s'\n" % _dim.getEndpointTypeAsString(_val)) _val = _gp['DIM_ENDPOINT_SIZE'] if abs(_val - _ds.getOption('DIM_ENDPOINT_SIZE')) > 1e-10: f.write("dim_endpoint_size = %s\n" % repr(_val)) _val = _gp['DIM_DUAL_MODE'] if _val is not _ds.getOption('DIM_DUAL_MODE'): f.write("dim_dual_mode = %s\n" % repr(_val)) _val = _gp['DIM_POSITION_OFFSET'] if abs(_val - _ds.getOption('DIM_POSITION_OFFSET')) > 1e-10: f.write("dim_position_offset = %s\n" % repr(_val)) _val = _gp['DIM_DUAL_MODE_OFFSET'] if abs(_val - _ds.getOption('DIM_DUAL_MODE_OFFSET')) > 1e-10: f.write("dim_dual_mode_offset = %s\n" % repr(_val)) _val = _gp['RADIAL_DIM_PRIMARY_PREFIX'] if _val != _ds.getOption('RADIAL_DIM_PRIMARY_PREFIX'): f.write("radial_dim_primary_prefix = %s\n" % repr(_val)) _val = _gp['RADIAL_DIM_PRIMARY_SUFFIX'] if _val != _ds.getOption('RADIAL_DIM_PRIMARY_SUFFIX'): f.write("radial_dim_primary_suffix = %s\n" % repr(_val)) _val = _gp['RADIAL_DIM_SECONDARY_PREFIX'] if _val != _ds.getOption('RADIAL_DIM_SECONDARY_PREFIX'): f.write("radial_dim_secondary_prefix = %s\n" % repr(_val)) _val = _gp['RADIAL_DIM_SECONDARY_SUFFIX'] if _val != _ds.getOption('RADIAL_DIM_SECONDARY_SUFFIX'): f.write("radial_dim_secondary_suffix = %s\n" % repr(_val)) _val = _gp['RADIAL_DIM_DIA_MODE'] if _val is not _ds.getOption('RADIAL_DIM_DIA_MODE'): f.write("radial_dim_dia_mode = %s\n" % repr(_val)) _val = _gp['ANGULAR_DIM_PRIMARY_PREFIX'] if _val != _ds.getOption('ANGULAR_DIM_PRIMARY_PREFIX'): f.write("angular_dim_primary_prefix = %s\n" % repr(_val)) _val = _gp['ANGULAR_DIM_PRIMARY_SUFFIX'] if _val != _ds.getOption('ANGULAR_DIM_PRIMARY_SUFFIX'): f.write("angular_dim_primary_suffix = %s\n" % repr(_val)) _val = _gp['ANGULAR_DIM_SECONDARY_PREFIX'] if _val != _ds.getOption('ANGULAR_DIM_SECONDARY_PREFIX'): f.write("angular_dim_secondary_prefix = %s\n" % repr(_val)) _val = _gp['ANGULAR_DIM_SECONDARY_SUFFIX'] if _val != _ds.getOption('ANGULAR_DIM_SECONDARY_SUFFIX'): f.write("angular_dim_secondary_suffix = %s\n" % repr(_val)) def _save_textstyle_values(f): f.write("#\n# Standard TextBlock parameters\n#\n") _gp = globals.prefs _ts = _gp['TEXT_STYLE'] _tsn = _ts.getName() _tsf = _ts.getFamily() _tsz = _ts.getSize() _tss = _ts.getStyle() _tsw = _ts.getWeight() _tsc = _ts.getColor() _tsa = _ts.getAngle() _tsl = _ts.getAlignment() _tc = text.TextStyle f.write("text_style = {\n") f.write(" 'name' : '%s',\n" % _tsn) f.write(" 'family' : '%s',\n" % _tsf) f.write(" 'size' : %s,\n" % repr(_tsz)) f.write(" 'angle' : %s,\n" % repr(_tsa)) f.write(" 'color' : '%s',\n" % str(_tsc)) f.write(" 'weight' : '%s',\n" % _tc.getWeightAsString(_tsw)) f.write(" 'style' : '%s',\n" % _tc.getStyleAsString(_tss)) f.write(" 'alignment' : '%s'\n" % _tc.getAlignmentAsString(_tsl)) f.write("}\n") # # save overriden values # _val = _gp['FONT_FAMILY'] if _val != _tsf: f.write("font_family = '%s'\n" % _val) _val = _gp['TEXT_SIZE'] if abs(_val - _tsz) > 1e-10: f.write("text_size = %s\n" % repr(_val)) _val = _gp['TEXT_ALIGNMENT'] if _val != _tsl: f.write("text_alignment = '%s'\n" % _tc.getAlignmentAsString(_val)) _val = _gp['FONT_COLOR'] if _val != _tsc: f.write("font_color = '%s'\n" % str(_val)) _val = _gp['FONT_STYLE'] if _val != _tss: f.write("font_style = '%s'\n" % _tc.getStyleAsString(_val)) _val = _gp['FONT_WEIGHT'] if _val != _tsw: f.write("font_weight = '%s'\n" % _tc.getWeightAsString(_val)) _val = _gp['TEXT_ANGLE'] if abs(_val - _tsa) > 1e-10: f.write("text_angle = %s\n" % repr(_val)) def _save_style_values(f): f.write("#\n# Standard GraphicObject parameters\n#\n") _gp = globals.prefs _s = _gp['LINE_STYLE'] _sn = _s.getName() _sl = _s.getLinetype() _ln = _sl.getName() _ll = _sl.getList() _sc = _s.getColor() _st = _s.getThickness() f.write("line_style = {\n") f.write(" 'name' : '%s',\n" % _sn) f.write(" 'linetype' : ('%s', %s),\n" % (_ln, repr(_ll))) f.write(" 'color' : '%s',\n" % str(_sc)) f.write(" 'thickness' : %s\n" % repr(_st)) f.write("}\n") _lt = _gp['LINE_TYPE'] if _lt != _sl: _n = _v.getName() _l = _v.getList() f.write("line_type = ('%s', %s)\n" % (_n, repr(_l))) _c = _gp['LINE_COLOR'] if _c != _sc: f.write("line_color = '%s'\n" % str(_c)) _t = _gp['LINE_THICKNESS'] if abs(_t - _st) > 1e-10: f.write("line_thickness = %s\n" % repr(_t)) def save_user_prefs(): """Store the current user settings in $HOME/.pythoncad/prefs.py on Unix machines, $APPDATA/PythonCAD/prefs.py on Windows. save_user_prefs() """ if sys.platform == 'win32': _home = os.environ.get('APPDATA') if _home is None: raise ValueError, "Unable to determine APPDATA directory." _pdir = os.path.join(_home, 'PythonCAD') else: _home = os.environ.get('HOME') if _home is None: raise ValueError, "Unable to determine HOME directory" _pdir = os.path.join(_home, '.pythoncad') if not os.path.isdir(_pdir): os.mkdir(_pdir, 0755) _pfile = os.path.join(_pdir, 'prefs.py') _f = open(_pfile, "w") try: _gp = globals.prefs _top = """# # PythonCAD user preferences # # If you edit this file manually, be careful! # """ _f.write("%s" % _top) _f.write("#\n# Boolean variables\n#\n") _v = _gp['AUTOSPLIT'] _f.write("autosplit = %s\n" % repr(_v)) _v = _gp['HIGHLIGHT_POINTS'] _f.write("highlight_points = %s\n" % repr(_v)) # _f.write("#\n# Size variables (float values)\n#\n") _v = _gp['CHAMFER_LENGTH'] _f.write("chamfer_length = %s\n" % repr(_v)) _v = _gp['FILLET_RADIUS'] _f.write("fillet_radius = %s\n" % repr(_v)) _v = _gp['LEADER_ARROW_SIZE'] _f.write("leader_arrow_size = %s\n" % repr(_v)) # _f.write("#\n# Display color settings\n#\n") _v = _gp['INACTIVE_LAYER_COLOR'] _f.write("inactive_layer_color = '%s'\n" % str(_v)) _v = _gp['BACKGROUND_COLOR'] _f.write("background_color = '%s'\n" % str(_v)) _v = _gp['SINGLE_POINT_COLOR'] _f.write("single_point_color = '%s'\n" % str(_v)) _v = _gp['MULTI_POINT_COLOR'] _f.write("multi_point_color = '%s'\n" % str(_v)) # _f.write("#\n# Units\n#\n") _v = _gp['UNITS'] _f.write("units = '%s'\n" % units.Unit.getUnitAsString(_v)) # _save_style_values(_f) _save_textstyle_values(_f) _save_dimstyle_values(_f) finally: _f.close() PythonCAD-DS1-R37/PythonCAD/Generic/selections.py0000644000175000017500000000576311307666657021074 0ustar matteomatteo# # Copyright (c) 2002, 2004, 2005 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # a class for storing selected objects # from PythonCAD.Generic import entity class Selection(object): """A class used for storing selected objects. A Selection object has the following methods: storeObject(): Store a reference to some object. getObjects(): Return all the objects held within the Selection object. reset(): Empty the Selection object. A Selection can have any number of objects added to it, and the contents of a Selection can be retrieved any number of times. Once the Selection has had its contents retrieved, however, the addition of a new object will purge the current contents of the selection. """ def __init__(self): """Initialize a Selection object. There are no arguments needed for this method. """ self.__image = None self.__objs = [] self.__retrieved = False def hasObjects(self): """Test if there are objects stored in the Selection. hasObjects() """ return len(self.__objs) > 0 def storeObject(self, obj): """Store a reference to an object. storeObject(obj) Argument 'obj' can be an instance of the Entity class. """ if not isinstance(obj, entity.Entity): raise TypeError, "Invalid object: " + `type(obj)` _layer = obj.getParent() if _layer is None: raise ValueError, "Object parent is None" _image = _layer.getParent() if _image is None: raise ValueError, "Object not stored in an Image" if (self.__retrieved or (self.__image is not None and _image is not self.__image)): self.reset() self.__image = _image _seen = False for _obj in self.__objs: if _obj is obj: _seen = True break if not _seen: self.__objs.append(obj) def getObjects(self): """Return all the currently selected objects. getObjects() This method returns a list. """ self.__retrieved = True return self.__objs[:] def reset(self): """Reset the Selection object to empty. reset() """ self.__image = None del self.__objs[:] self.__retrieved = False PythonCAD-DS1-R37/pythoncad.spec0000644000175000017500000000640611307666657016045 0ustar matteomatteo%{expand: %%define pyver %(python -c 'import sys;print(sys.version[0:3])')} # platform defines - set one below or define the build_xxx on the command line # # fixme: add a Fedora line in here ... # %define rhel 0 %{?build_rhel:%define rhel 1} %define suse 0 %{?build_suse:%define suse 1} %define mdk 0 %{?build_mdk:%define mdk 1} # test for a platform definition %if ! %{rhel} && ! %{suse} && ! %{mdk} %{error: You must specify a platform. Please examine the spec file.} exit 1 %endif %define _version DS1-R36 Summary: PythonCAD scriptable CAD package Name: PythonCAD Version: 0.1.36 Release: 1 Group: Applications/Engineering License: GPL v2 Source: %{name}-%{_version}.tar.gz #Patch0: %{_version}.patch BuildRoot: %{_tmppath}/%{name}-root URL: http://www.pythoncad.org/ Packager: D. Scott Barninger BuildArchitectures: noarch %if %{rhel} BuildRequires: python >= %{pyver} Requires: python >= %{pyver} Requires: pygtk2 >= 1.99.16 Requires: libxml2-python %endif %if %{suse} BuildRequires: python >= %{pyver} Requires: python >= %{pyver} Requires: python-gtk >= 2.0 Requires: python-xml %endif %if %{mdk} BuildRequires: python >= %{pyver} Requires: python >= %{pyver} Requires: pygtk2.0 Requires: libxml2-python %endif %description PythonCAD is a CAD package written, surprisingly enough, in Python. The PythonCAD project aims to produce a scriptable, open-source, easy to use CAD package for Linux, the various flavors of BSD Unix, commercial Unix, and other platforms to which someone who is interested ports the program. Work began on PythonCAD in July, 2002, and the first public release was on December 21, 2002. %prep %setup -q -n %{name}-%{_version} #%patch -p0 %build %install [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "$RPM_BUILD_ROOT" python setup.py install --prefix=/usr --root=$RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/usr/bin mkdir -p $RPM_BUILD_ROOT/etc/pythoncad mkdir -p $RPM_BUILD_ROOT/usr/share/pixmaps mkdir -p $RPM_BUILD_ROOT/usr/share/applications cp gtkpycad.py $RPM_BUILD_ROOT/usr/bin/ cp prefs.py $RPM_BUILD_ROOT/etc/pythoncad/ cp pythoncad.desktop $RPM_BUILD_ROOT/usr/share/applications/ cp gtkpycad.png $RPM_BUILD_ROOT/usr/share/pixmaps/ chmod 755 $RPM_BUILD_ROOT/usr/bin/gtkpycad.py chmod 644 $RPM_BUILD_ROOT/etc/pythoncad/prefs.py chmod 644 $RPM_BUILD_ROOT/usr/share/applications/pythoncad.desktop chmod 644 $RPM_BUILD_ROOT/usr/share/pixmaps/gtkpycad.png %clean [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "$RPM_BUILD_ROOT" %files %defattr(-,root,root) /usr/%{_lib}/python%pyver/site-packages/PythonCAD/* /usr/bin/gtkpycad.py /etc/pythoncad/prefs.py /usr/share/applications/pythoncad.desktop /usr/share/pixmaps/gtkpycad.png %post %preun %changelog * Fri Dec 01 2006 D. Scott Barninger - add prefix specification to install * Sun Oct 01 2006 D. Scott Barninger - release 0.1.34 * Wed Feb 1 2006 Art Haas - Update version numbers * Sat Jan 27 2006 D. Scott Barninger - release 0.1.27 * Sat Jan 15 2005 D. Scott Barninger - setup version strings so we don't have to repackage source * Fri Oct 15 2004 D. Scott Barninger - initial spec file PythonCAD-DS1-R37/PythonCad.py0000644000175000017500000002434011307666657015440 0ustar matteomatteo# # Copyright (c) 2002-2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # main routine to start Cocoa-based PythonCad # import getopt import sys import os import PythonCAD.Generic.image import PythonCAD.Generic.imageio import PythonCAD.Generic.fileio import PythonCAD.Generic.selections import PythonCAD.Generic.preferences import PythonCAD.Generic.color import PythonCAD.Generic.linetype import PythonCAD.Generic.style import PythonCAD.Generic.segment import PythonCAD.Generic.circle import PythonCAD.Generic.leader import PythonCAD.Generic.polyline import PythonCAD.Generic.segjoint import PythonCAD.Generic.conobject import PythonCAD.Generic.baseobject import PythonCAD.Generic.dimension import PythonCAD.Generic.units import PythonCAD.Interface.Cocoa.ImageDocument import PythonCAD.Interface.Cocoa.CADView import PythonCAD.Interface.Cocoa.AppController from PyObjCTools import NibClassBuilder, AppHelper #Initialize NIB NibClassBuilder.extractClasses("ImageDocument") # # set up global variables ... # PythonCAD.Generic.globals.prefs = PythonCAD.Generic.baseobject.LockedDict(str) PythonCAD.Generic.globals.colors = PythonCAD.Generic.baseobject.TypedDict(PythonCAD.Generic.color.Color, PythonCAD.Generic.color.Color) PythonCAD.Generic.globals.linetypes = PythonCAD.Generic.baseobject.TypedDict(PythonCAD.Generic.linetype.Linetype, PythonCAD.Generic.linetype.Linetype) PythonCAD.Generic.globals.styles = PythonCAD.Generic.baseobject.TypedDict(PythonCAD.Generic.style.Style, PythonCAD.Generic.style.Style) PythonCAD.Generic.globals.dimstyles = [] PythonCAD.Generic.globals.selectobj = PythonCAD.Generic.selections.Selection() def _initialize_booleans(): PythonCAD.Generic.globals.prefs['HIGHLIGHT_POINTS'] = True PythonCAD.Generic.globals.prefs['AUTOSPLIT'] = False def _initialize_sizes(): PythonCAD.Generic.globals.prefs['CHAMFER_LENGTH'] = 1.0 PythonCAD.Generic.globals.prefs['FILLET_RADIUS'] = 1.0 PythonCAD.Generic.globals.prefs['UNITS'] = PythonCAD.Generic.units.MILLIMETERS PythonCAD.Generic.globals.prefs['LEADER_ARROW_SIZE'] = 1.0 def _initialize_image_colors(): _color = PythonCAD.Generic.color.get_color(80, 140, 210) # blueish/purpleish PythonCAD.Generic.globals.prefs['INACTIVE_LAYER_COLOR'] = _color _color = PythonCAD.Generic.color.get_color(0, 0, 0) # black PythonCAD.Generic.globals.prefs['BACKGROUND_COLOR'] = _color _color = PythonCAD.Generic.color.get_color(255, 255, 0) #yellow PythonCAD.Generic.globals.prefs['SINGLE_POINT_COLOR'] = _color _color = PythonCAD.Generic.color.get_color(0, 255, 255) #cyan PythonCAD.Generic.globals.prefs['MULTI_POINT_COLOR'] = _color def _initialize_styles(): _color = PythonCAD.Generic.color.get_color(0xff, 0xff, 0xff) # white _lt = PythonCAD.Generic.linetype.get_linetype_by_dashes(None) _style = PythonCAD.Generic.style.Style(u'Solid White Line', _lt, _color, 1.0) PythonCAD.Generic.globals.styles[_style] = _style PythonCAD.Generic.globals.prefs['LINE_STYLE'] = _style PythonCAD.Generic.globals.prefs['LINE_COLOR'] = _style.getColor() PythonCAD.Generic.globals.prefs['LINE_TYPE'] = _style.getLinetype() PythonCAD.Generic.globals.prefs['LINE_THICKNESS'] = _style.getThickness() # # set this style as the class default for the "real" drawing entities # # fixme: this should be done with a classmethod or some sort of # function ... # PythonCAD.Generic.segment.Segment.__defstyle = _style PythonCAD.Generic.circle.Circle.__defstyle = _style PythonCAD.Generic.leader.Leader.__defstyle = _style PythonCAD.Generic.polyline.Polyline.__defstyle = _style PythonCAD.Generic.segjoint.SegJoint.__defstyle = _style # _color = PythonCAD.Generic.color.get_color(0, 0, 0) # black _style = PythonCAD.Generic.style.Style(u'Solid Black Line', _lt, _color, 1.0) PythonCAD.Generic.globals.styles[_style] = _style _color = PythonCAD.Generic.color.get_color(0xff, 0, 0) # red _lt = PythonCAD.Generic.linetype.get_linetype_by_dashes([4, 1]) _style = PythonCAD.Generic.style.Style(u'Dashed Red Line', _lt, _color, 1.0) PythonCAD.Generic.globals.styles[_style] = _style _color = PythonCAD.Generic.color.get_color(0, 0xff, 0) # green _style = PythonCAD.Generic.style.Style(u'Dashed Green Line', _lt, _color, 1.0) PythonCAD.Generic.globals.styles[_style] = _style _color = PythonCAD.Generic.color.get_color(0, 0, 0xff) # blue _style = PythonCAD.Generic.style.Style(u'Dashed Blue Line', _lt, _color, 1.0) PythonCAD.Generic.globals.styles[_style] = _style _color = PythonCAD.Generic.color.get_color(0xff, 0xff, 0) # yellow _lt = PythonCAD.Generic.linetype.get_linetype_by_dashes([8, 2]) _style = PythonCAD.Generic.style.Style(u'Dashed Yellow Line', _lt, _color, 1.0) PythonCAD.Generic.globals.styles[_style] = _style _color = PythonCAD.Generic.color.get_color(0xff, 0, 0xff) # violet _style = PythonCAD.Generic.style.Style(u'Dashed Violet Line', _lt, _color, 1.0) PythonCAD.Generic.globals.styles[_style] = _style _color = PythonCAD.Generic.color.get_color(0, 0xff, 0xff) # cyan _style = PythonCAD.Generic.style.Style(u'Dashed Cyan Line', _lt, _color, 1.0) PythonCAD.Generic.globals.styles[_style] = _style # # define and set a construction line style # _color = PythonCAD.Generic.color.get_color(0xff, 0, 0) # red _lt = PythonCAD.Generic.linetype.Linetype(u'Construction Lines', [2, 2]) _style = PythonCAD.Generic.style.Style(u'Construction Objects', _lt, _color, 0.0) PythonCAD.Generic.conobject.ConstructionObject.__defstyle = _style # # define and add the default text style and use values in the # text style to define various global key/value pairs # _white = PythonCAD.Generic.color.get_color(0xff, 0xff, 0xff) _ts = PythonCAD.Generic.text.TextStyle(u'Default Text Style', color=_white) PythonCAD.Generic.globals.prefs['TEXT_STYLE'] = _ts PythonCAD.Generic.globals.prefs['FONT_COLOR'] = _ts.getColor() PythonCAD.Generic.globals.prefs['FONT_SIZE'] = _ts.getSize() PythonCAD.Generic.globals.prefs['FONT_WEIGHT'] = _ts.getWeight() PythonCAD.Generic.globals.prefs['FONT_STYLE'] = _ts.getStyle() PythonCAD.Generic.globals.prefs['FONT_FAMILY'] = _ts.getFamily() # # define and add the default dimension style and use the # values in that style to define various global preference # key/value pairs # _dsdict = {} _dsdict['DIM_PRIMARY_FONT_COLOR'] = _white _dsdict['DIM_SECONDARY_FONT_COLOR'] = _white _dimcolor = PythonCAD.Generic.color.get_color(255, 165, 0) # orangeish _dsdict['DIM_COLOR'] = _dimcolor _ds = PythonCAD.Generic.dimension.DimStyle(u'Default DimStyle', _dsdict) PythonCAD.Generic.globals.dimstyles.append(_ds) PythonCAD.Generic.globals.prefs['DIM_STYLE'] = _ds for _key in _ds.getOptions(): _value = _ds.getOption(_key) PythonCAD.Generic.globals.prefs[_key] = _value def _initialize_linetypes(): _lt = PythonCAD.Generic.linetype.Linetype(u'Solid') # solid PythonCAD.Generic.globals.linetypes[_lt] = _lt _lt = PythonCAD.Generic.linetype.Linetype(u'Dash1', [4, 1]) # dashed line PythonCAD.Generic.globals.linetypes[_lt] = _lt _lt = PythonCAD.Generic.linetype.Linetype(u'Dash2', [8, 2]) # dashed line PythonCAD.Generic.globals.linetypes[_lt] = _lt _lt = PythonCAD.Generic.linetype.Linetype(u'Dash3', [12, 2]) # dashed line PythonCAD.Generic.globals.linetypes[_lt] = _lt _lt = PythonCAD.Generic.linetype.Linetype(u'Dash4', [10, 2, 2, 2]) # dashed line PythonCAD.Generic.globals.linetypes[_lt] = _lt _lt = PythonCAD.Generic.linetype.Linetype(u'Dash5', [15, 5, 5, 5]) # dashed line PythonCAD.Generic.globals.linetypes[_lt] = _lt def _initialize_colors(): _color = PythonCAD.Generic.color.Color(255, 0, 0) # red PythonCAD.Generic.globals.colors[_color] = _color _color = PythonCAD.Generic.color.Color(0, 255, 0) # green PythonCAD.Generic.globals.colors[_color] = _color _color = PythonCAD.Generic.color.Color(0, 0, 255) # blue PythonCAD.Generic.globals.colors[_color] = _color _color = PythonCAD.Generic.color.Color(255, 0, 255) # violet PythonCAD.Generic.globals.colors[_color] = _color _color = PythonCAD.Generic.color.Color(255, 255, 0) # yellow PythonCAD.Generic.globals.colors[_color] = _color _color = PythonCAD.Generic.color.Color(0, 255, 255) # cyan PythonCAD.Generic.globals.colors[_color] = _color _color = PythonCAD.Generic.color.Color(255, 255, 255) # white PythonCAD.Generic.globals.colors[_color] = _color _color = PythonCAD.Generic.color.Color(0, 0, 0) # black PythonCAD.Generic.globals.colors[_color] = _color def _initialize_globals(): _initialize_colors() _initialize_linetypes() _initialize_styles() _initialize_image_colors() _initialize_sizes() _initialize_booleans() def main(): # # load up global and user preferences # _initialize_globals() PythonCAD.Generic.preferences.initialize_prefs() PythonCAD.Generic.preferences.load_global_prefs() _user_flag = PythonCAD.Generic.globals.prefs['USER_PREFS'] if _user_flag: PythonCAD.Generic.preferences.load_user_prefs() PythonCAD.Generic.globals.prefs.lock() # the globals are now set if __name__ == '__main__': main() AppHelper.runEventLoop() # need some version checking for OS X - 10.2? 10.3? # _major, _minor, _micro = gtk.pygtk_version # if ((_major < 2) and # (_minor < 100) and # # (_micro < 16)): # print main() PythonCAD-DS1-R37/prefs.py0000644000175000017500000004413711307666657014674 0ustar matteomatteo# # This file stores the global PythonCAD preferences, and # is written itself in Python. Copy this file to the file # '/etc/pythoncad/prefs.py' and it will be loaded and used # to store global preferences for the program. Whenever # a new image is opened, that image will use the global # preferences for setting itself up. Each drawing window # can then adjust these preferences by using the Preferences # menus. # # When PythonCAD starts, a set of default values for the # various options any image may set is stored, then the # '/etc/pythoncad/prefs.py' file is searched for. If it # is found, the values in the file will override the initial # set of defaults. Variables defined in this file can # therefore be commented out without problem. # # When defining a string value, the string can be in # any case: 'UPPER', 'lower', or 'MiXeD'. The program will # convert the string to upper case when testing the values # entered here. Any time a string is given but the program # fails to accept it due to case issues is a bug ... # # User Prefs # # This variable is meant as an adminstrators tool of # disabling the reading of a preference file in the # user's home directory. By default PythonCAD will look # for a file in ${HOME}/.pythoncad/prefs.py after reading # the global preference file '/etc/pythoncad/prefs.py'. # If the user_prefs variable is set to False, the search # for a user's preference file is not done. # # The prescence of this variable only makes sense in # the '/etc/pythoncad.prefs' file. # # Valid choices: True, False user_prefs = True # # Units # # The basic unit of length in an image. # # Valid choices: # 'millimeters', 'micrometers', 'meters', 'kilometers', # 'inches', 'feet', 'yards', 'miles' # units = 'millimeters' # # Chamfer Length # # The default chamfer length in an image. # # Valid values: Any numerical value 0.0 or greater # chamfer_length = 1.5 # # Fillet Radius # # The default fillet radius in an image. # # Valid values: Any numerical value 0.0 or greater # fillet_radius = 2.0 # # Leader arrow size # # This option sets the default arrow size on leader lines. # # Valid values: Any numerical value 0.0 or greater # leader_arrow_size = 10.0 # # Highlight Points # # This option will activate the drawing of small boxes around # the Point entities in an image. # # Valid choices: True, False # highlight_points = True # # Linetypes # # There are several default Linetypes provided in PythonCAD. # If you want to define more, they are added here. # # Each Linetype is defined as a tuple of two objects: # # (name, dashlist) # # The name is a string or unicode string, and the dash list # is either 'None' (meaning a solid line), or a list with # an even number of integer values. Each value pair represents # the on-off bit pattern in the line. # # Examples: # A dashed linetype called 'dash' with 4 bits on then 4 bits off: # (u'dash', [4, 4]) # # A dashed linetype called 'dash2' with 10 bits on, 2 off, 6 on, 2 off # (u'dash2', [10, 2, 6, 2]) # the "u" means unicode ... # # Add any new linetypes you wish in the linetypes list variable # linetypes = [ # (u'dash', [4, 4]), # dash example above # (u'dash2', [10, 2, 6, 2]), # dash2 example above ] # # Colors # # By default PythonCAD starts with eight basic colors defined. # If you want to add more, here is where to add them. # # A Color is defined in one of two ways: # # '#xxxxxx' - a hexidecimal string like '#ff00ff' # (r, g, b) - a tuple with three integers giving the red, green, and # blue values. Each value must be 0 <= val <= 255. # # Add any new colors you wish to use in the colors list variable colors = [ # '#ffffff', # hexidecimal example # '#33cc77', # another hex example # (100, 50, 30), # tuple example # (255, 30, 180), # another tuple example ] # # Styles # # Styles define a common set of properties for objects like # segments, circles, and arcs. There are eight default styles # in PythonCAD, and adding more styles can be done here. # # Defining a style is done by creating a dictionary containing # four keys: # # 'name' : Style name - A string # 'linetype' : Style linetype - see the definition above # 'color' : Style color - see the definition above # 'thickness' : Style thickness - a positive float value. # # Older versions of PythonCAD expected the Style defintion # to be in a tuple like the following: # # (name, linetype, color, thickness) # # This format is deprecated but still accepted. # # Examples: # # {'name' : u'style1', # 'linetype' : (u'lt1', [10, 4]), # 'color' : '#ffcc99', # 'thickness' : 0.1 # } # A style called 'style1', composed of a linetype called 'lt1' # which is a dashed line 10 bits on, 4 off, drawn with the # color '#ffcc99' and 0.1 units thick. # # Add any new styles you want to use to the 'styles' list # variable below. Several examples are included to provide # a starting guide for creating new styles. # styles = [ # {'name' : u'style1', # 'linetype' : (u'lt1', [10, 4]), # 'color' : '#ffcc99', # 'thickness' : 0.1 # }, # {'name' : u'style2', # 'linetype' : (u'lt2', [6, 2, 10, 4]), # 'color' : '#cc00ff', # 'thickness' : 0.3 # }, # {'name' : u'style3', # 'linetype' : (u'lt3', [2, 6, 2, 2]), # 'color' : '#88ffbb', # 'thickness' : 0.2 # } ] # # Default style # # Set this variable to the name of the Style you want the # initial drawing style to be in PythonCAD. If you set this # variable to None, or comment it out, the default Style # defined within the program will be used. default_style = None # # Style overrides # # In addition to setting the Style, some default entity properties # can be set in this file. In setting one of the following values, the # value defined in the default Style will be overriden. # # The examples below are all commented out. The values defined are # arbitrary and for example purposes. Change the values as necessary # and uncomment the variables you want to override the default Style # values. # # line_type = (u'example', [5, 5, 8, 8]) # line_color = '#885533' # line_thickness = 0.2 # # # Dimension Styles # # A dimension style is a set of parameters that define # how the dimension looks. Any dimension has a large number # of attributes that can be set, so a dimension style is # a way of grouping together these attributes into a common # set and offering a means of making the dimensions look # uniform. # # Defining a dimension style requires creating a dictionary # with a certain keys and values. PythonCAD defines a single # default dimension style, and any new dimension styles that # are created here use that default style as a base, and the # values in the new style then override the defaults. # # The list of dictionary keys and acceptable values is # somewhat long. This list is given below with each key # and the acceptable values for each key listed. # # Key: 'DIM_PRIMARY_FONT_FAMILY' # Value: A string giving the font name # Default: 'Sans' # # Key: 'DIM_PRIMARY_TEXT_SIZE' # Value: A positive float value # Default: 1.0 # # Key: 'DIM_PRIMARY_FONT_WEIGHT' # Value: One of 'normal', 'light', 'bold', or 'heavy' # Default: 'normal' # # Key: 'DIM_PRIMARY_FONT_STYLE' # Value: One of 'normal', 'oblique', or 'italic' # Default: 'normal' # # Key: 'DIM_PRIMARY_FONT_COLOR' # Value: A Color definition (see above), like (255, 255, 255) or '#ffffff' # Default: '#ffffff' # # Key: 'DIM_PRIMARY_TEXT_ANGLE' # Value: A float value # Default: 0.0 # # Key: 'DIM_PRIMARY_TEXT_ALIGNMENT' # Value: One of 'left', 'center', or 'right' # Default: 'center' # # Key: 'DIM_PRIMARY_PREFIX' # Value: A string or unicode string # Default: u'' # # Key: 'DIM_PRIMARY_SUFFIX' # Value: A string or unicode string # Default: u'' # # Key: 'DIM_PRIMARY_PRECISION' # Value: An integer value where 0 <= value <= 15 # Default: 3 # # Key: 'DIM_PRIMARY_UNITS' # Value: One of 'millimeters', 'micrometers', 'meters', 'kilometers', # 'inches', 'feet', 'yards', 'miles' # Default: 'Millimeters' # # Key: 'DIM_PRIMARY_LEADING_ZERO' # Value: True or False # Default: True # # Key: 'DIM_PRIMARY_TRAILING_DECIMAL' # Value: True or False # Default: True # # Key: 'DIM_SECONDARY_FONT_FAMILY' # Value: A string giving the font name # Default: 'Sans' # # Key: 'DIM_SECONDARY_TEXT_SIZE' # Value: A positive float value # Default: 1.0 # # Key: 'DIM_SECONDARY_FONT_WEIGHT' # Value: One of 'normal', 'light', 'bold', or 'heavy' # Default: 'normal' # # Key: 'DIM_SECONDARY_FONT_STYLE' # Value: One of 'normal', 'oblique', or 'italic' # Default: 'normal' # # Key: 'DIM_SECONDARY_FONT_COLOR' # Value: A Color definition (see above), like (255, 255, 255) or '#ffffff' # Default: '#ffffff' # # Key: 'DIM_SECONDARY_TEXT_ANGLE' # Value: A float value # Default: 0.0 # # Key: 'DIM_SECONDARY_TEXT_ALIGNMENT' # Value: One of 'left', 'center', or 'right' # Default: 'center' # # Key: 'DIM_SECONDARY_PREFIX' # Value: A string or unicode string # Default: u'' # # Key: 'DIM_SECONDARY_SUFFIX' # Value: A string or unicode string # Default: u'' # # Key: 'DIM_SECONDARY_PRECISION' # Value: An integer value where 0 <= value <= 15 # Default: u'' # # Key: 'DIM_SECONDARY_UNITS' # Value: One of 'millimeters', 'micrometers', 'meters', 'kilometers', # 'inches', 'feet', 'yards', 'miles' # Default: 'millimeters' # # Key: 'DIM_SECONDARY_LEADING_ZERO' # Value: True or False # Default: True # # Key: 'DIM_SECONDARY_TRAILING_DECIMAL' # Value: True or False # Default: True # # Key: 'DIM_OFFSET' # Value: A float value of 0.0 or greater. # Default: 1.0 # # Key: 'DIM_EXTENSION' # Value: A float value of 0.0 or greater. # Default: 1.0 # # Key: 'DIM_COLOR' # Value: A Color definition (see above), like (255, 255, 255) or '#ffffff' # Default: (255, 165, 0) # # Key: 'DIM_THICKNESS' # Value: A float value of 0.0 or greater. # Default: 0.0 # # Key: 'DIM_POSITION' # Value: One of 'split', 'above', or 'below' # Default: 'split' # # Key: 'DIM_POSITION_OFFSET' # Value: A float value # Default: 0.0 # # Key: 'DIM_ENDPOINT' # Value: One of 'none', 'arrow', 'filled_arrow', 'slash', or 'circle' # Default: None # # Key: 'DIM_ENDPOINT_SIZE' # Value: A float vale of 0.0 or greater. # Default: 1.0 # # Key: 'DIM_DUAL_MODE' # Value: True or False # Default: False # # Key: 'DIM_DUAL_MODE_OFFSET' # Value: A float value # Default: 0.0 # # Key: 'RADIAL_DIM_PRIMARY_PREFIX' # Value: A string or unicode string # Default: u'' # # Key: 'RADIAL_DIM_PRIMARY_SUFFIX' # Value: A string or unicode string # Default: u'' # # Key: 'RADIAL_DIM_SECONDARY_PREFIX' # Value: A string or unicode string # Default: u'' # # Key: 'RADIAL_DIM_SECONDARY_SUFFIX' # Value: A string or unicode string # Default: u'' # # Key: 'RADIAL_DIM_DIA_MODE' # Value: True or False # Default: False # # Key: 'ANGULAR_DIM_PRIMARY_PREFIX' # Value: A string or unicode string # Default: u'' # # Key: 'ANGULAR_DIM_PRIMARY_SUFFIX' # Value: A string or unicode string # Default: u'' # # Key: 'ANGULAR_DIM_SECONDARY_PREFIX' # Value: A string or unicode string # Default: u'' # # Key: 'ANGULAR_DIM_SECONDARY_SUFFIX' # Value: A string or unicode string # Default: u'' # # # The keys that begin 'DIM_PRIMARY_' apply are specific to the # primary dimension in any dimension, and 'DIM_SECONDARY_' are # specific to the secondary dimension. 'RADIAL_DIM_' and # 'ANGULAR_DIM_' are obviously applicible to those specific # dimension types. # # 'DIM_OFFSET' is the distance between the dimensioned point and # the start of the dimension bar, and 'DIM_EXTENSION' is the # distance between where the dimension crossbar intersects the # dimension bar and the end of the dimension bar. 'DIM_POSITION' # will be used in placing the dimension text around the dimension # crossbar. The names of the keys were chosen to be somewhat # self explanatory, but they could change in future releases. # # Keys 'DIM_POSITION_OFFSET' and 'DIM_DUAL_MODE_OFFSET' act # as placeholders for future refinement of dimension styles # in positioning the dimension text. # # As a dimension style is built by overriding the default values, # creating a new style only requires changing the fields that # you wish to update. In the example below, the four fields # 'dim_offset', 'dim_endpoint', 'dim_endpoint_size', and # 'dim_extension' are modified. example_dict = { 'dim_offset' : 5.0, 'dim_endpoint' : 'filled_arrow', 'dim_endpoint_size' : 10.0, 'dim_extension' : 5.0, } # # here is an example of a dimension style with more changes # dimstyle_example_2 = { 'dim_primary_font_family' : 'Times', 'dim_primary_text_size' : 24.0, 'dim_primary_font_color' : '#dd44bb', 'dim_primary_suffix' : u' mm', 'dim_primary_precision' : 2, 'dim_secondary_font_family' : 'Helvetica', 'dim_secondary_text_size' : 18.0, 'dim_secondary_font_color' : '#33ee55', 'dim_secondary_suffix' : u' in.', 'dim_secondary_units' : 'inches', 'dim_offset' : 10.0, 'dim_endpoint' : 'slash', 'dim_endpoint_size' : 10.0, 'dim_extension' : 5.0, 'radial_dim_primary_prefix' : u'R. ', 'radial_dim_primary_suffix' : u' mm', 'radial_dim_secondary_prefix' : u'R. ', 'radial_dim_secondary_suffix' : u' in.', 'dim_dual_mode' : True, } # # The creation of the dimension style is done with by creating # a tuple containing two objects: # # (name, dict) # # name: The dimension style name # dict: The dictionary containing the values for the dimension style # # Add any dimension styles you create to the dimstyles list below. dimstyles = [ # (u'example_dimstyle', example_dict), # example # (u'ex2' , dimstyle_example_2), # another example ] # # Default dimension style # # Set this variable to the name of the dimension style you # want PythonCAD to use by default. If you define this variable # to None, or comment it out, the default dimension style # is used. default_dimstyle = None # # Each of the DimStyle keys can also be used to specify # an overriding value for the attribute defined in the # DimStyle. The keys are listed below with possible values # defined for example purposes. Change the values and # uncomment the lines as desired. # dim_primary_font_family = 'Sans' # dim_primary_text_size = 12.0 # dim_primary_font_weight = 'bold' # dim_primary_font_style = 'italic' # dim_primary_font_color = '#ffffaa' # dim_primary_text_angle = 0.0 # dim_primary_text_alignment = 'left' # dim_primary_prefix = u'Dim: ' # dim_primary_suffix = u' [Dim]' # dim_primary_precision = 5 # dim_primary_units = 'inches' # dim_primary_leading_zero = False # dim_primary_trailing_decimal = False # dim_secondary_font_family = 'Times' # dim_secondary_text_size = 10.0 # dim_secondary_font_weight = 'heavy' # dim_secondary_font_style = 'oblique' # dim_secondary_font_color = '#00ccaa' # dim_secondary_text_angle = 0.0 # dim_secondary_text_alignment = 'left' # dim_secondary_prefix = u'Dim: ' # dim_secondary_suffix = u' [Dim]' # dim_secondary_precision = 4 # dim_secondary_units = 'inches' # dim_secondary_leading_zero = False # dim_secondary_trailing_decimal = False # dim_offset = 5.0 # dim_extension = 10.0 # dim_color = '#55aacc' # dim_thickness = 1.5 # dim_position = 'above' # dim_position_offset = 1.0 # dim_endpoint = 'slash' # dim_endpoint_size = 5.0 # dim_dual_mode = True # dim_dual_mode_offset = 1.0 # radial_dim_primary_prefix = u'R. ' # radial_dim_primary_suffix = u' [R]' # radial_dim_secondary_prefix = u'R. ' # radial_dim_secondary_suffix = u' [R]' # radial_dim_dia_mode = True # angular_dim_primary_prefix = u'Deg: ' # angular_dim_primary_suffix = u' [Deg]' # angular_dim_secondary_prefix = u'Deg: ' # angular_dim_secondary_suffix = u' [Deg]' # # Text styles # # A text style defines a common set of text attributes # that are used to define visual elements of some text. # A single text style is defined in PythonCAD, so if you # want more text styles here is where to add them. # # Defining a text style is done by creating a dictionary # with the following keys: # # 'name': TextStyle name # 'family': Font family, like 'Sans', 'Times', etc. # 'weight': Font weight - 'normal', 'light', 'bold', or 'heavy' # 'style': Font style - 'normal', 'italic', or 'oblique' # 'size': Text size - a float value greater than 0. # 'color': The TextStyle color - # 'angle': The angle at which the text is displayed - a float value # 'alignment': Text alignment - 'left', 'center', or 'right' # # The keys can be specified in any order, but all must be provided. # Extra keys are ignored. # # Earlier versions of PythonCAD accepted a tuple-based TextStyle # definition as seen below: # # (name, family, size, style, weight, color) # # This format is still accepted but is deprecated. Tuple-based # TextStyle definitions lacked the 'angle' and 'alignment' fields, # so when encountered the definition will default to the 'angle' # being 0.0 and 'alignment' being 'left. # # The two examples below define a one TextStyle named 'default' # and a second TextStyle named 'fancy': # # {'name' : 'default', # 'family' : 'sans', # 'size' : 10.0, # 'style' : 'normal', # 'weight' : 'normal', # 'color' : '#ff00cc', # 'angle' : 0.0, # 'alignment' : 'left' # } # # {'name' : 'fancy', # 'family' : 'helvetica', # 'size' : 20.0, # 'style' : 'italic', # 'weight' : 'bold', # 'color' : '#ffff00', # 'angle' : 0.0, # 'alignment' : 'center' # # # Add more text styles you wish to use within the 'textstyles' list. # textstyles = [] # # Default text style # # Set this variable to the name of the TextStyle you want # PythonCAD to use by default. If you define this variable # to None, or comment it out, the default TextStyle defined # within the program is used # default_textstyle = None # # Text properties # # In addition to setting the text styles, some default font properties # can be set in this file. In setting one of the following values, the # value defined in the default TextStyle will be overriden. # # The examples below are all commented out. The values defined are # arbitrary and for example purposes. Change the values as necessary # and uncomment the variables you want to override the default TextStyle # values. # # font_family = 'Sans' # text_size = 18.0 # font_weight = 'light' # font_style = 'italic' # font_color = '#ff00ff' # text_angle = 0.0 # text_alignment = 'center' # # Miscellaneous options # # Autosplitting # # This option will activate the automatic splitting of segments, # circles, and arcs if a new point is added directly on the object. # # Valid choices: True, False # autosplit = True