├── autoexec.py ├── bitmaps └── test.png ├── debian ├── README ├── changelog ├── compat ├── control ├── copyright ├── heekspython-dev.dirs ├── heekspython-dev.install ├── heekspython0.dirs ├── heekspython0.install └── rules ├── examples ├── cut_example.py ├── dxfImportObjects.py ├── dxfReader.py ├── dxf_import.py ├── dxf_to_heekspython.py ├── example.py ├── example_run.txt ├── facegear.py ├── fillet0.py ├── fillets.py ├── fillets2.py ├── parametric_rectangle.py ├── polar_array.py ├── polar_array.wxg ├── polar_array_readme.txt ├── revolve_it.py └── wx_dialog.py └── src ├── ConsoleCanvas.cpp ├── ConsoleCanvas.h ├── DllMain.cpp ├── HeeksPython.cpp ├── HeeksPython.h ├── HeeksPython.sln ├── HeeksPython.vcproj ├── Interface.h ├── Makefile ├── PythonConfig.h ├── PythonInterface.cpp ├── PythonInterface.h ├── stdafx.h └── vc_retro.py /autoexec.py: -------------------------------------------------------------------------------- 1 | #import platform 2 | #import sys 3 | #if platform.system() == "Windows": 4 | # sys.path.insert(0,'C:\\Users\\Dan\\HeeksCNC') 5 | #else: 6 | # sys.path.insert(0,'/usr/local/share/heekspython/heeksscripts') 7 | 8 | #import HeeksCNC 9 | #from HeeksCAD import HeeksCAD 10 | #HeeksCNC.cad = HeeksCAD() 11 | #HeeksCNC.start() 12 | -------------------------------------------------------------------------------- /bitmaps/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Heeks/heekspython-old/aa46dde26b53be6948beaf2e5e5242b17f94624c/bitmaps/test.png -------------------------------------------------------------------------------- /debian/README: -------------------------------------------------------------------------------- 1 | The Debian Package heekspython 2 | ---------------------------- 3 | 4 | After installing the plugin needs to be 'activated' first in HeeksCAD by adding a new plugin and selecting the .so in /usr/lib/heekspython/ 5 | 6 | -- Joachim Steiger Thu, 28 May 2009 09:08:50 +0200 7 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | heekspython (0.0.1-svn0) unstable; urgency=low 2 | 3 | * Initial Release. 4 | 5 | -- Joachim Steiger Thu, 28 May 2009 09:08:50 +0200 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 6 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: heekspython 2 | Priority: extra 3 | Maintainer: Joachim Steiger 4 | Build-Depends: debhelper (>= 6), libwxgtk2.8-dev, libwxbase2.8-dev, libgtkglext1-dev, heekscad 5 | Standards-Version: 3.7.3 6 | Section: libs 7 | Homepage: http://code.google.com/p/heekspython/ 8 | 9 | #Package: heekspython-dev 10 | #Section: libdevel 11 | #Architecture: any 12 | #Depends: heekspython0 (= ${binary:Version}) 13 | #Description: This is a plugin to enable a python console in HeeksCAD. 14 | # This is a plugin to enable python interaction in HeeksCAD. 15 | # Users can script actions, create/modify objects, and my personal favorite, create parametric geometry. 16 | # Importing of any python library is possible, so you could even do something weird like hook HeeksCAD up to a network socket. 17 | # Be creative! 18 | # . 19 | # Homepage: http://code.google.com/p/heekspython/ 20 | 21 | Package: heekspython0 22 | Section: libs 23 | Architecture: any 24 | Depends: ${shlibs:Depends}, heekscad, python-wxgtk2.8 25 | Description: This is a plugin to enable a python console in HeeksCAD. 26 | This is a plugin to enable python interaction in HeeksCAD. 27 | Users can script actions, create/modify objects, and my personal favorite, create parametric geometry. 28 | Importing of any python library is possible, so you could even do something weird like hook HeeksCAD up to a network socket. 29 | Be creative! 30 | . 31 | Homepage: http://code.google.com/p/heekspython/ 32 | 33 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This package was debianized by Joachim Steiger on 2 | Thu, 28 May 2009 09:08:50 +0200. 3 | 4 | It was downloaded from http://code.google.com/p/heekspython/ 5 | 6 | Upstream Author(s): 7 | 8 | Dan Heeks 9 | jonpry 10 | 11 | Copyright: 12 | 13 | 14 | 15 | License: 16 | 17 | HeeksPython is covered by the new BSD license 18 | 19 | Redistribution and use in source and binary forms, with or without 20 | modification, are permitted under the terms of the BSD License. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 | SUCH DAMAGE. 33 | 34 | On Debian systems, the complete text of the BSD License can be 35 | found in `/usr/share/common-licenses/BSD'. 36 | 37 | 38 | The Debian packaging is (C) 2009, Joachim Steiger and 39 | is licensed under the GPL, see `/usr/share/common-licenses/GPL'. 40 | 41 | 42 | # Please also look if there are files or directories which have a 43 | # different copyright/license attached and list them here. 44 | -------------------------------------------------------------------------------- /debian/heekspython-dev.dirs: -------------------------------------------------------------------------------- 1 | usr/lib/heekspython/ 2 | -------------------------------------------------------------------------------- /debian/heekspython-dev.install: -------------------------------------------------------------------------------- 1 | usr/lib/heekspython/lib*.so.* 2 | -------------------------------------------------------------------------------- /debian/heekspython0.dirs: -------------------------------------------------------------------------------- 1 | usr/lib/heekspython/ 2 | -------------------------------------------------------------------------------- /debian/heekspython0.install: -------------------------------------------------------------------------------- 1 | usr/lib/heekspython/lib*.so.* 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # This file was originally written by Joey Hess and Craig Small. 5 | # As a special exception, when this file is copied by dh-make into a 6 | # dh-make output file, you may use that output file without restriction. 7 | # This special exception was added by Craig Small in version 0.37 of dh-make. 8 | 9 | # Uncomment this to turn on verbose mode. 10 | #export DH_VERBOSE=1 11 | 12 | 13 | 14 | 15 | 16 | 17 | # shared library versions, option 1 18 | version=2.0.5 19 | major=2 20 | # option 2, assuming the library is created as src/.libs/libfoo.so.2.0.5 or so 21 | #version=`ls src/.libs/lib*.so.* | \ 22 | # awk '{if (match($$0,/[0-9]+\.[0-9]+\.[0-9]+$$/)) print substr($$0,RSTART)}'` 23 | #major=`ls src/.libs/lib*.so.* | \ 24 | # awk '{if (match($$0,/\.so\.[0-9]+$$/)) print substr($$0,RSTART+4)}'` 25 | 26 | configure: configure-stamp 27 | configure-stamp: 28 | dh_testdir 29 | # Add here commands to configure the package. 30 | 31 | touch configure-stamp 32 | 33 | 34 | build: build-stamp 35 | build-stamp: configure-stamp 36 | dh_testdir 37 | 38 | # Add here commands to compile the package. 39 | $(MAKE) -C src/ HEEKSCADPATH=../../../heekscad/heekscad-trunk/ PREFIX=/usr 40 | 41 | touch $@ 42 | 43 | clean: 44 | dh_testdir 45 | dh_testroot 46 | rm -f build-stamp configure-stamp 47 | 48 | # Add here commands to clean up after the build process. 49 | $(MAKE) -C src/ HEEKSCADPATH=../../../heekscad/heekscad-trunk/ clean 50 | 51 | dh_clean 52 | 53 | install: build 54 | dh_testdir 55 | dh_testroot 56 | dh_clean -k 57 | dh_installdirs 58 | 59 | # Add here commands to install the package into debian/tmp 60 | $(MAKE) -C src/ HEEKSCADPATH=../../../heekscad/heekscad-trunk/ PREFIX=/usr DESTDIR=$(CURDIR)/debian/heekspython0 install 61 | 62 | # Build architecture-independent files here. 63 | binary-indep: build install 64 | # We have nothing to do by default. 65 | 66 | # Build architecture-dependent files here. 67 | binary-arch: build install 68 | dh_testdir 69 | dh_testroot 70 | dh_installchangelogs 71 | dh_installdocs 72 | dh_installexamples 73 | # dh_install 74 | # dh_installmenu 75 | # dh_installdebconf 76 | # dh_installlogrotate 77 | # dh_installemacsen 78 | # dh_installpam 79 | # dh_installmime 80 | # dh_installinit 81 | # dh_installcron 82 | # dh_installinfo 83 | dh_installman 84 | dh_link 85 | dh_strip 86 | dh_compress 87 | dh_fixperms 88 | # dh_perl 89 | # dh_python 90 | # dh_makeshlibs 91 | dh_installdeb 92 | dh_shlibdeps 93 | dh_gencontrol 94 | dh_md5sums 95 | dh_builddeb 96 | 97 | binary: binary-indep binary-arch 98 | .PHONY: build clean binary-indep binary-arch binary install configure 99 | -------------------------------------------------------------------------------- /examples/cut_example.py: -------------------------------------------------------------------------------- 1 | import HeeksPython as cad 2 | def cut_it(obj1,obj2): 3 | cad.cut(obj1,obj2) 4 | newobj = cad.getlastobj() 5 | cad.remove(obj1) 6 | cad.changed() 7 | cad.remove(newobj) 8 | return newobj 9 | 10 | 11 | cad.cuboid(0,0,0,1,1,1) 12 | c1 = cad.getlastobj() 13 | cad.cylinder(0,0,0,.5,1) 14 | c2 = cad.getlastobj() 15 | n1 = cut_it(c1,c2) 16 | 17 | cad.cylinder(1,0,0,.5,1) 18 | c3 = cad.getlastobj() 19 | n2 = cut_it(n1,c3) 20 | 21 | cad.cylinder(1,1,0,.5,1) 22 | c4 = cad.getlastobj() 23 | n3 = cut_it(n2,c4) 24 | 25 | cad.cylinder(0,1,0,.5,1) 26 | c5 = cad.getlastobj() 27 | n4 = cut_it(n3,c5) 28 | 29 | cad.ve() 30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/dxfImportObjects.py: -------------------------------------------------------------------------------- 1 | """This module provides wrapper objects for dxf entities. 2 | 3 | The wrappers expect a "dxf object" as input. The dxf object is 4 | an object with a type and a data attribute. Type is a lowercase 5 | string matching the 0 code of a dxf entity. Data is a list containing 6 | dxf objects or lists of [code, data] pairs. 7 | 8 | This module is not general, and is only for dxf import. 9 | """ 10 | 11 | # -------------------------------------------------------------------------- 12 | # DXF Import Objects v0.8 by Ed Blake (AKA Kitsu) 13 | # -------------------------------------------------------------------------- 14 | # ***** BEGIN GPL LICENSE BLOCK ***** 15 | # 16 | # This program is free software; you can redistribute it and/or 17 | # modify it under the terms of the GNU General Public License 18 | # as published by the Free Software Foundation; either version 2 19 | # of the License, or (at your option) any later version. 20 | # 21 | # This program is distributed in the hope that it will be useful, 22 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 | # GNU General Public License for more details. 25 | # 26 | # You should have received a copy of the GNU General Public License 27 | # along with this program; if not, write to the Free Software Foundation, 28 | # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 29 | # 30 | # ***** END GPL LICENCE BLOCK ***** 31 | # -------------------------------------------------------------------------- 32 | from math import * 33 | 34 | 35 | # from Stani's dxf writer v1.1 (c)www.stani.be (GPL) 36 | #---color values 37 | BYBLOCK=0 38 | BYLAYER=256 39 | 40 | #---block-type flags (bit coded values, may be combined): 41 | ANONYMOUS =1 # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application 42 | NON_CONSTANT_ATTRIBUTES =2 # This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all) 43 | XREF =4 # This block is an external reference (xref) 44 | XREF_OVERLAY =8 # This block is an xref overlay 45 | EXTERNAL =16 # This block is externally dependent 46 | RESOLVED =32 # This is a resolved external reference, or dependent of an external reference (ignored on input) 47 | REFERENCED =64 # This definition is a referenced external reference (ignored on input) 48 | 49 | #---mtext flags 50 | #attachment point 51 | TOP_LEFT = 1 52 | TOP_CENTER = 2 53 | TOP_RIGHT = 3 54 | MIDDLE_LEFT = 4 55 | MIDDLE_CENTER = 5 56 | MIDDLE_RIGHT = 6 57 | BOTTOM_LEFT = 7 58 | BOTTOM_CENTER = 8 59 | BOTTOM_RIGHT = 9 60 | #drawing direction 61 | LEFT_RIGHT = 1 62 | TOP_BOTTOM = 3 63 | BY_STYLE = 5 #the flow direction is inherited from the associated text style 64 | #line spacing style (optional): 65 | AT_LEAST = 1 #taller characters will override 66 | EXACT = 2 #taller characters will not override 67 | 68 | #---polyline flags 69 | CLOSED =1 # This is a closed polyline (or a polygon mesh closed in the M direction) 70 | CURVE_FIT =2 # Curve-fit vertices have been added 71 | SPLINE_FIT =4 # Spline-fit vertices have been added 72 | POLYLINE_3D =8 # This is a 3D polyline 73 | POLYGON_MESH =16 # This is a 3D polygon mesh 74 | CLOSED_N =32 # The polygon mesh is closed in the N direction 75 | POLYFACE_MESH =64 # The polyline is a polyface mesh 76 | CONTINOUS_LINETYPE_PATTERN =128 # The linetype pattern is generated continuously around the vertices of this polyline 77 | 78 | #---text flags 79 | #horizontal 80 | LEFT = 0 81 | CENTER = 1 82 | RIGHT = 2 83 | ALIGNED = 3 #if vertical alignment = 0 84 | MIDDLE = 4 #if vertical alignment = 0 85 | FIT = 5 #if vertical alignment = 0 86 | #vertical 87 | BASELINE = 0 88 | BOTTOM = 1 89 | MIDDLE = 2 90 | TOP = 3 91 | class Object: 92 | """Empty container class for dxf objects""" 93 | 94 | def __init__(self, _type=''): 95 | """_type expects a string value.""" 96 | self.type = _type 97 | self.name = '' 98 | self.data = [] 99 | 100 | def __str__(self): 101 | if self.name: 102 | return self.name 103 | else: 104 | return self.type 105 | 106 | def __repr__(self): 107 | return str(self.data) 108 | 109 | def get_type(self, kind=''): 110 | """Despite the name, this method actually returns all objects of type 'kind' from self.data.""" 111 | if type: 112 | objects = [] 113 | for item in self.data: 114 | if type(item) != list and item.type == kind: 115 | # we want this type of object 116 | objects.append(item) 117 | elif type(item) == list and item[0] == kind: 118 | # we want this type of data 119 | objects.append(item[1]) 120 | return objects 121 | 122 | 123 | class Layer: 124 | """Class for objects representing dxf layers.""" 125 | 126 | def __init__(self, obj): 127 | """Expects an entity object of type line as input.""" 128 | self.type = obj.type 129 | self.data = obj.data[:] 130 | 131 | self.name = obj.get_type(2)[0] 132 | self.color = obj.get_type(62)[0] 133 | self.flags = obj.get_type(70)[0] 134 | self.frozen = self.flags&1 135 | 136 | 137 | 138 | def __repr__(self): 139 | return "%s: name - %s, color - %s" %(self.__class__.__name__, self.name, self.color) 140 | 141 | 142 | 143 | class Line: 144 | """Class for objects representing dxf lines.""" 145 | 146 | def __init__(self, obj): 147 | """Expects an entity object of type line as input.""" 148 | if not obj.type == 'line': 149 | raise TypeError, "Wrong type %s for line object!" %obj.type 150 | self.type = obj.type 151 | self.data = obj.data[:] 152 | 153 | self.space = obj.get_type(67) 154 | if self.space: 155 | self.space = self.space[0] 156 | else: 157 | self.space = 0 158 | 159 | self.color_index = obj.get_type(62) 160 | if self.color_index: 161 | self.color_index = self.color_index[0] 162 | else: 163 | self.color_index = BYLAYER 164 | 165 | discard, self.layer, discard_index = get_layer(obj.data) 166 | del obj.data[discard_index] 167 | 168 | self.points = self.get_points(obj.data) 169 | 170 | 171 | 172 | 173 | def get_points(self, data): 174 | """Gets start and end points for a line type object. 175 | 176 | Lines have a fixed number of points (two) and fixed codes for each value. 177 | """ 178 | 179 | # start x, y, z and end x, y, z = 0 180 | sx, sy, sz, ex, ey, ez = 0, 0, 0, 0, 0, 0 181 | for item in data: 182 | if item[0] == 10: # 10 = x 183 | sx = item[1] 184 | elif item[0] == 20: # 20 = y 185 | sy = item[1] 186 | elif item[0] == 30: # 30 = z 187 | sz = item[1] 188 | elif item[0] == 11: # 11 = x 189 | ex = item[1] 190 | elif item[0] == 21: # 21 = y 191 | ey = item[1] 192 | elif item[0] == 31: # 31 = z 193 | ez = item[1] 194 | return [[sx, sy, sz], [ex, ey, ez]] 195 | 196 | 197 | 198 | def __repr__(self): 199 | return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) 200 | 201 | 202 | 203 | class LWpolyline: 204 | """Class for objects representing dxf LWpolylines.""" 205 | 206 | def __init__(self, obj): 207 | """Expects an entity object of type lwpolyline as input.""" 208 | if not obj.type == 'lwpolyline': 209 | raise TypeError, "Wrong type %s for polyline object!" %obj.type 210 | self.type = obj.type 211 | self.data = obj.data[:] 212 | 213 | # required data 214 | self.num_points = obj.get_type(90)[0] 215 | 216 | # optional data (with defaults) 217 | self.space = obj.get_type(67) 218 | if self.space: 219 | self.space = self.space[0] 220 | else: 221 | self.space = 0 222 | 223 | self.color_index = obj.get_type(62) 224 | if self.color_index: 225 | self.color_index = self.color_index[0] 226 | else: 227 | self.color_index = BYLAYER 228 | 229 | self.elevation = obj.get_type(38) 230 | if self.elevation: 231 | self.elevation = self.elevation[0] 232 | else: 233 | self.elevation = 0 234 | 235 | self.flags = obj.get_type(70) 236 | if self.flags: 237 | self.flags = self.flags[0] 238 | else: 239 | self.flags = 0 240 | 241 | self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen 242 | discard, self.layer, discard_index = get_layer(obj.data) 243 | del obj.data[discard_index] 244 | self.points = self.get_points(obj.data) 245 | self.extrusion = self.get_extrusion(obj.data) 246 | 247 | 248 | 249 | 250 | 251 | 252 | def get_points(self, data): 253 | """Gets points for a polyline type object. 254 | 255 | Polylines have no fixed number of verts, and 256 | each vert can have a number of properties. 257 | Verts should be coded as 258 | 10:xvalue 259 | 20:yvalue 260 | 40:startwidth or 0 261 | 41:endwidth or 0 262 | 42:bulge or 0 263 | for each vert 264 | """ 265 | num = self.num_points 266 | point = None 267 | points = [] 268 | for item in data: 269 | if item[0] == 10: # 10 = x 270 | if point: 271 | points.append(point) 272 | point = Vertex() 273 | point.x = item[1] 274 | elif item[0] == 20: # 20 = y 275 | point.y = item[1] 276 | elif item[0] == 40: # 40 = start width 277 | point.swidth = item[1] 278 | elif item[0] == 41: # 41 = end width 279 | point.ewidth = item[1] 280 | elif item[0] == 42: # 42 = bulge 281 | point.bulge = item[1] 282 | points.append(point) 283 | return points 284 | 285 | 286 | def get_extrusion(self, data): 287 | """Find the axis of extrusion. 288 | 289 | Used to get the objects Object Coordinate System (ocs). 290 | """ 291 | vec = [0,0,1] 292 | for item in data: 293 | if item[0] == 210: # 210 = x 294 | vec[0] = item[1] 295 | elif item[0] == 220: # 220 = y 296 | vec[1] = item[1] 297 | elif item[0] == 230: # 230 = z 298 | vec[2] = item[1] 299 | return vec 300 | 301 | 302 | def __repr__(self): 303 | return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) 304 | 305 | 306 | 307 | class Polyline: 308 | """Class for objects representing dxf LWpolylines.""" 309 | 310 | def __init__(self, obj): 311 | """Expects an entity object of type polyline as input.""" 312 | if not obj.type == 'polyline': 313 | raise TypeError, "Wrong type %s for polyline object!" %obj.type 314 | self.type = obj.type 315 | self.data = obj.data[:] 316 | self.points = [] 317 | 318 | # optional data (with defaults) 319 | self.space = obj.get_type(67) 320 | if self.space: 321 | self.space = self.space[0] 322 | else: 323 | self.space = 0 324 | 325 | self.color_index = obj.get_type(62) 326 | if self.color_index: 327 | self.color_index = self.color_index[0] 328 | else: 329 | self.color_index = BYLAYER 330 | 331 | self.elevation = obj.get_type(30) 332 | if self.elevation: 333 | self.elevation = self.elevation[0] 334 | else: 335 | self.elevation = 0 336 | 337 | self.flags = obj.get_type(70) 338 | if self.flags: 339 | self.flags = self.flags[0] 340 | else: 341 | self.flags = 0 342 | 343 | self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen 344 | 345 | discard, self.layer, discard_index = get_layer(obj.data) 346 | del obj.data[discard_index] 347 | self.extrusion = self.get_extrusion(obj.data) 348 | 349 | 350 | 351 | 352 | 353 | def get_extrusion(self, data): 354 | """Find the axis of extrusion. 355 | 356 | Used to get the objects Object Coordinate System (ocs). 357 | """ 358 | vec = [0,0,1] 359 | for item in data: 360 | if item[0] == 210: # 210 = x 361 | vec[0] = item[1] 362 | elif item[0] == 220: # 220 = y 363 | vec[1] = item[1] 364 | elif item[0] == 230: # 230 = z 365 | vec[2] = item[1] 366 | return vec 367 | 368 | 369 | def __repr__(self): 370 | return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) 371 | 372 | 373 | 374 | class Vertex(object): 375 | """Generic vertex object used by polylines (and maybe others).""" 376 | 377 | def __init__(self, obj=None): 378 | """Initializes vertex data. 379 | 380 | The optional obj arg is an entity object of type vertex. 381 | """ 382 | self.loc = [0,0,0] 383 | self.bulge = 0 384 | self.swidth = 0 385 | self.ewidth = 0 386 | self.flags = 0 387 | 388 | if obj is not None: 389 | if not obj.type == 'vertex': 390 | raise TypeError, "Wrong type %s for vertex object!" %obj.type 391 | self.type = obj.type 392 | self.data = obj.data[:] 393 | 394 | self.get_props(obj.data) 395 | 396 | 397 | def get_props(self, data): 398 | """Gets coords for a vertex type object. 399 | 400 | Each vert can have a number of properties. 401 | Verts should be coded as 402 | 10:xvalue 403 | 20:yvalue 404 | 40:startwidth or 0 405 | 41:endwidth or 0 406 | 42:bulge or 0 407 | """ 408 | for item in data: 409 | if item[0] == 10: # 10 = x 410 | self.x = item[1] 411 | elif item[0] == 20: # 20 = y 412 | self.y = item[1] 413 | elif item[0] == 30: # 30 = z 414 | self.z = item[1] 415 | elif item[0] == 40: # 40 = start width 416 | self.swidth = item[1] 417 | elif item[0] == 41: # 41 = end width 418 | self.ewidth = item[1] 419 | elif item[0] == 42: # 42 = bulge 420 | self.bulge = item[1] 421 | elif item[0] == 70: # 70 = vert flags 422 | self.flags = item[1] 423 | 424 | 425 | def __len__(self): 426 | return 3 427 | 428 | 429 | def __getitem__(self, key): 430 | return self.loc[key] 431 | 432 | 433 | def __setitem__(self, key, value): 434 | if key in [0,1,2]: 435 | self.loc[key] 436 | 437 | 438 | def __iter__(self): 439 | return self.loc.__iter__() 440 | 441 | 442 | def __str__(self): 443 | return str(self.loc) 444 | 445 | 446 | def __repr__(self): 447 | return "Vertex %s, swidth=%s, ewidth=%s, bulge=%s" %(self.loc, self.swidth, self.ewidth, self.bulge) 448 | 449 | 450 | def getx(self): 451 | return self.loc[0] 452 | 453 | def setx(self, value): 454 | self.loc[0] = value 455 | 456 | x = property(getx, setx) 457 | 458 | 459 | def gety(self): 460 | return self.loc[1] 461 | 462 | def sety(self, value): 463 | self.loc[1] = value 464 | 465 | y = property(gety, sety) 466 | 467 | 468 | def getz(self): 469 | return self.loc[2] 470 | 471 | def setz(self, value): 472 | self.loc[2] = value 473 | 474 | z = property(getz, setz) 475 | 476 | 477 | 478 | class Text: 479 | """Class for objects representing dxf Text.""" 480 | 481 | def __init__(self, obj): 482 | """Expects an entity object of type text as input.""" 483 | if not obj.type == 'text': 484 | raise TypeError, "Wrong type %s for text object!" %obj.type 485 | self.type = obj.type 486 | self.data = obj.data[:] 487 | 488 | # required data 489 | self.height = obj.get_type(40)[0] 490 | self.value = obj.get_type(1)[0] # The text string value 491 | 492 | # optional data (with defaults) 493 | self.space = obj.get_type(67) 494 | if self.space: 495 | self.space = self.space[0] 496 | else: 497 | self.space = 0 498 | 499 | self.color_index = obj.get_type(62) 500 | if self.color_index: 501 | self.color_index = self.color_index[0] 502 | else: 503 | self.color_index = BYLAYER 504 | 505 | self.rotation = obj.get_type(50) # radians? 506 | if not self.rotation: 507 | self.rotation = 0 508 | else: 509 | self.rotation = self.rotation[0] 510 | 511 | self.width_factor = obj.get_type(41) # Scaling factor along local x axis 512 | if not self.width_factor: 513 | self.width_factor = 1 514 | else: 515 | self.width_factor = self.width_factor[0] 516 | 517 | self.oblique = obj.get_type(51) # skew in degrees -90 <= oblique <= 90 518 | if not self.oblique: 519 | self.oblique = 0 520 | else: 521 | self.oblique = self.oblique[0] 522 | 523 | self.halignment = obj.get_type(72) # horiz. alignment 524 | if not self.halignment: # 0=left, 1=center, 2=right, 3=aligned, 4=middle, 5=fit 525 | self.halignment = 0 526 | else: 527 | self.halignment = self.halignment[0] 528 | 529 | self.valignment = obj.get_type(73) # vert. alignment 530 | if not self.valignment: # 0=baseline, 1=bottom, 2=middle, 3=top 531 | self.valignment = 0 532 | else: 533 | self.valignment = self.valignment[0] 534 | 535 | discard, self.layer, discard_index = get_layer(obj.data) 536 | del obj.data[discard_index] 537 | self.loc = self.get_loc(obj.data, self.halignment, self.valignment) 538 | self.extrusion = self.get_extrusion(obj.data) 539 | 540 | 541 | 542 | 543 | def get_loc(self, data, halign, valign): 544 | """Gets adjusted location for text type objects. 545 | 546 | If group 72 and/or 73 values are nonzero then the first alignment point values 547 | are ignored and AutoCAD calculates new values based on the second alignment 548 | point and the length and height of the text string itself (after applying the 549 | text style). If the 72 and 73 values are zero or missing, then the second 550 | alignment point is meaningless. 551 | 552 | I don't know how to calc text size... 553 | """ 554 | # bottom left x, y, z and justification x, y, z = 0 555 | x, y, z, jx, jy, jz = 0, 0, 0, 0, 0, 0 556 | for item in data: 557 | if item[0] == 10: # 10 = x 558 | x = item[1] 559 | elif item[0] == 20: # 20 = y 560 | y = item[1] 561 | elif item[0] == 30: # 30 = z 562 | z = item[1] 563 | elif item[0] == 11: # 11 = x 564 | jx = item[1] 565 | elif item[0] == 21: # 21 = y 566 | jy = item[1] 567 | elif item[0] == 31: # 31 = z 568 | jz = item[1] 569 | 570 | if halign or valign: 571 | x, y, z = jx, jy, jz 572 | return [x, y, z] 573 | 574 | def get_extrusion(self, data): 575 | """Find the axis of extrusion. 576 | 577 | Used to get the objects Object Coordinate System (ocs). 578 | """ 579 | vec = [0,0,1] 580 | for item in data: 581 | if item[0] == 210: # 210 = x 582 | vec[0] = item[1] 583 | elif item[0] == 220: # 220 = y 584 | vec[1] = item[1] 585 | elif item[0] == 230: # 230 = z 586 | vec[2] = item[1] 587 | return vec 588 | 589 | 590 | def __repr__(self): 591 | return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) 592 | 593 | 594 | 595 | class Mtext: 596 | """Class for objects representing dxf Mtext.""" 597 | 598 | def __init__(self, obj): 599 | """Expects an entity object of type mtext as input.""" 600 | if not obj.type == 'mtext': 601 | raise TypeError, "Wrong type %s for mtext object!" %obj.type 602 | self.type = obj.type 603 | self.data = obj.data[:] 604 | 605 | # required data 606 | self.height = obj.get_type(40)[0] 607 | self.width = obj.get_type(41)[0] 608 | self.alignment = obj.get_type(71)[0] # alignment 1=TL, 2=TC, 3=TR, 4=ML, 5=MC, 6=MR, 7=BL, 8=BC, 9=BR 609 | self.value = self.get_text(obj.data) # The text string value 610 | 611 | # optional data (with defaults) 612 | self.space = obj.get_type(67) 613 | if self.space: 614 | self.space = self.space[0] 615 | else: 616 | self.space = 0 617 | 618 | self.color_index = obj.get_type(62) 619 | if self.color_index: 620 | self.color_index = self.color_index[0] 621 | else: 622 | self.color_index = BYLAYER 623 | 624 | self.rotation = obj.get_type(50) # radians 625 | if not self.rotation: 626 | self.rotation = 0 627 | else: 628 | self.rotation = self.rotation[0] 629 | 630 | self.width_factor = obj.get_type(42) # Scaling factor along local x axis 631 | if not self.width_factor: 632 | self.width_factor = 1 633 | else: 634 | self.width_factor = self.width_factor[0] 635 | 636 | self.line_space = obj.get_type(44) # percentage of default 637 | if not self.line_space: 638 | self.line_space = 1 639 | else: 640 | self.line_space = self.line_space[0] 641 | 642 | discard, self.layer, discard_index = get_layer(obj.data) 643 | del obj.data[discard_index] 644 | self.loc = self.get_loc(obj.data) 645 | self.extrusion = self.get_extrusion(obj.data) 646 | 647 | 648 | 649 | 650 | 651 | def get_text(self, data): 652 | """Reconstructs mtext data from dxf codes.""" 653 | primary = '' 654 | secondary = [] 655 | for item in data: 656 | if item[0] == 1: # There should be only one primary... 657 | primary = item[1] 658 | elif item[0] == 3: # There may be any number of extra strings (in order) 659 | secondary.append(item[1]) 660 | if not primary: 661 | #raise ValueError, "Empty Mtext Object!" 662 | string = "Empty Mtext Object!" 663 | if not secondary: 664 | string = primary.replace(r'\P', '\n') 665 | else: 666 | string = ''.join(secondary)+primary 667 | string = string.replace(r'\P', '\n') 668 | return string 669 | def get_loc(self, data): 670 | """Gets location for a mtext type objects. 671 | 672 | Mtext objects have only one point indicating location. 673 | """ 674 | loc = [0,0,0] 675 | for item in data: 676 | if item[0] == 10: # 10 = x 677 | loc[0] = item[1] 678 | elif item[0] == 20: # 20 = y 679 | loc[1] = item[1] 680 | elif item[0] == 30: # 30 = z 681 | loc[2] = item[1] 682 | return loc 683 | 684 | 685 | 686 | 687 | def get_extrusion(self, data): 688 | """Find the axis of extrusion. 689 | 690 | Used to get the objects Object Coordinate System (ocs). 691 | """ 692 | vec = [0,0,1] 693 | for item in data: 694 | if item[0] == 210: # 210 = x 695 | vec[0] = item[1] 696 | elif item[0] == 220: # 220 = y 697 | vec[1] = item[1] 698 | elif item[0] == 230: # 230 = z 699 | vec[2] = item[1] 700 | return vec 701 | 702 | 703 | def __repr__(self): 704 | return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) 705 | 706 | 707 | 708 | class Circle: 709 | """Class for objects representing dxf Circles.""" 710 | 711 | def __init__(self, obj): 712 | """Expects an entity object of type circle as input.""" 713 | if not obj.type == 'circle': 714 | raise TypeError, "Wrong type %s for circle object!" %obj.type 715 | self.type = obj.type 716 | self.data = obj.data[:] 717 | 718 | # required data 719 | self.radius = obj.get_type(40)[0] 720 | 721 | # optional data (with defaults) 722 | self.space = obj.get_type(67) 723 | if self.space: 724 | self.space = self.space[0] 725 | else: 726 | self.space = 0 727 | 728 | self.color_index = obj.get_type(62) 729 | if self.color_index: 730 | self.color_index = self.color_index[0] 731 | else: 732 | self.color_index = BYLAYER 733 | 734 | discard, self.layer, discard_index = get_layer(obj.data) 735 | del obj.data[discard_index] 736 | self.loc = self.get_loc(obj.data) 737 | self.extrusion = self.get_extrusion(obj.data) 738 | 739 | 740 | 741 | 742 | 743 | def get_loc(self, data): 744 | """Gets the center location for circle type objects. 745 | 746 | Circles have a single coord location. 747 | """ 748 | loc = [0, 0, 0] 749 | for item in data: 750 | if item[0] == 10: # 10 = x 751 | loc[0] = item[1] 752 | elif item[0] == 20: # 20 = y 753 | loc[1] = item[1] 754 | elif item[0] == 30: # 30 = z 755 | loc[2] = item[1] 756 | return loc 757 | 758 | 759 | 760 | def get_extrusion(self, data): 761 | """Find the axis of extrusion. 762 | 763 | Used to get the objects Object Coordinate System (ocs). 764 | """ 765 | vec = [0,0,1] 766 | for item in data: 767 | if item[0] == 210: # 210 = x 768 | vec[0] = item[1] 769 | elif item[0] == 220: # 220 = y 770 | vec[1] = item[1] 771 | elif item[0] == 230: # 230 = z 772 | vec[2] = item[1] 773 | return vec 774 | 775 | 776 | def __repr__(self): 777 | return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) 778 | 779 | 780 | 781 | class Arc: 782 | """Class for objects representing dxf arcs.""" 783 | 784 | def __init__(self, obj): 785 | """Expects an entity object of type arc as input.""" 786 | if not obj.type == 'arc': 787 | raise TypeError, "Wrong type %s for arc object!" %obj.type 788 | self.type = obj.type 789 | self.data = obj.data[:] 790 | 791 | # required data 792 | self.radius = obj.get_type(40)[0] 793 | self.start_angle = obj.get_type(50)[0] 794 | self.end_angle = obj.get_type(51)[0] 795 | 796 | # optional data (with defaults) 797 | self.space = obj.get_type(67) 798 | if self.space: 799 | self.space = self.space[0] 800 | else: 801 | self.space = 0 802 | 803 | self.color_index = obj.get_type(62) 804 | if self.color_index: 805 | self.color_index = self.color_index[0] 806 | else: 807 | self.color_index = BYLAYER 808 | 809 | discard, self.layer, discard_index = get_layer(obj.data) 810 | del obj.data[discard_index] 811 | self.loc = self.get_loc(obj.data) 812 | self.extrusion = self.get_extrusion(obj.data) 813 | 814 | 815 | 816 | 817 | 818 | def get_loc(self, data): 819 | """Gets the center location for arc type objects. 820 | 821 | Arcs have a single coord location. 822 | """ 823 | loc = [0, 0, 0] 824 | for item in data: 825 | if item[0] == 10: # 10 = x 826 | loc[0] = item[1] 827 | elif item[0] == 20: # 20 = y 828 | loc[1] = item[1] 829 | elif item[0] == 30: # 30 = z 830 | loc[2] = item[1] 831 | return loc 832 | 833 | 834 | 835 | def get_extrusion(self, data): 836 | """Find the axis of extrusion. 837 | 838 | Used to get the objects Object Coordinate System (ocs). 839 | """ 840 | vec = [0,0,1] 841 | for item in data: 842 | if item[0] == 210: # 210 = x 843 | vec[0] = item[1] 844 | elif item[0] == 220: # 220 = y 845 | vec[1] = item[1] 846 | elif item[0] == 230: # 230 = z 847 | vec[2] = item[1] 848 | return vec 849 | 850 | 851 | def __repr__(self): 852 | return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) 853 | 854 | 855 | 856 | class BlockRecord: 857 | """Class for objects representing dxf block_records.""" 858 | 859 | def __init__(self, obj): 860 | """Expects an entity object of type block_record as input.""" 861 | if not obj.type == 'block_record': 862 | raise TypeError, "Wrong type %s for block_record object!" %obj.type 863 | self.type = obj.type 864 | self.data = obj.data[:] 865 | 866 | # required data 867 | self.name = obj.get_type(2)[0] 868 | 869 | # optional data (with defaults) 870 | self.insertion_units = obj.get_type(70) 871 | if not self.insertion_units: 872 | self.insertion_units = None 873 | else: 874 | self.insertion_units = self.insertion_units[0] 875 | 876 | self.insert_units = obj.get_type(1070) 877 | if not self.insert_units: 878 | self.insert_units = None 879 | else: 880 | self.insert_units = self.insert_units[0] 881 | 882 | 883 | 884 | 885 | 886 | 887 | def __repr__(self): 888 | return "%s: name - %s, insert units - %s" %(self.__class__.__name__, self.name, self.insertion_units) 889 | 890 | 891 | 892 | 893 | class Block: 894 | """Class for objects representing dxf blocks.""" 895 | 896 | def __init__(self, obj): 897 | """Expects an entity object of type block as input.""" 898 | if not obj.type == 'block': 899 | raise TypeError, "Wrong type %s for block object!" %obj.type 900 | self.type = obj.type 901 | self.data = obj.data[:] 902 | 903 | # required data 904 | self.flags = obj.get_type(70)[0] 905 | self.entities = Object('block_contents') 906 | self.entities.data = objectify([ent for ent in obj.data if type(ent) != list]) 907 | 908 | # optional data (with defaults) 909 | self.name = obj.get_type(3) 910 | if self.name: 911 | self.name = self.name[0] 912 | else: 913 | self.name = '' 914 | 915 | self.path = obj.get_type(1) 916 | if self.path: 917 | self.path = self.path[0] 918 | else: 919 | self.path = '' 920 | 921 | self.discription = obj.get_type(4) 922 | if self.discription: 923 | self.discription = self.discription[0] 924 | else: 925 | self.discription = '' 926 | 927 | discard, self.layer, discard_index = get_layer(obj.data) 928 | del obj.data[discard_index] 929 | self.loc = self.get_loc(obj.data) 930 | 931 | 932 | 933 | 934 | 935 | def get_loc(self, data): 936 | """Gets the insert point of the block.""" 937 | loc = [0, 0, 0] 938 | for item in data: 939 | if type(item) != list: 940 | continue 941 | if item[0] == 10: # 10 = x 942 | loc[0] = item[1] 943 | elif item[0] == 20: # 20 = y 944 | loc[1] = item[1] 945 | elif item[0] == 30: # 30 = z 946 | loc[2] = item[1] 947 | return loc 948 | 949 | 950 | 951 | def __repr__(self): 952 | return "%s: name - %s, description - %s, xref-path - %s" %(self.__class__.__name__, self.name, self.discription, self.path) 953 | 954 | 955 | 956 | 957 | class Insert: 958 | """Class for objects representing dxf inserts.""" 959 | 960 | def __init__(self, obj): 961 | """Expects an entity object of type insert as input.""" 962 | if not obj.type == 'insert': 963 | raise TypeError, "Wrong type %s for insert object!" %obj.type 964 | self.type = obj.type 965 | self.data = obj.data[:] 966 | 967 | # required data 968 | self.block = obj.get_type(2)[0] 969 | 970 | # optional data (with defaults) 971 | self.rotation = obj.get_type(50) 972 | if self.rotation: 973 | self.rotation = self.rotation[0] 974 | else: 975 | self.rotation = 0 976 | 977 | self.space = obj.get_type(67) 978 | if self.space: 979 | self.space = self.space[0] 980 | else: 981 | self.space = 0 982 | 983 | self.color_index = obj.get_type(62) 984 | if self.color_index: 985 | self.color_index = self.color_index[0] 986 | else: 987 | self.color_index = BYLAYER 988 | 989 | discard, self.layer, discard_index = get_layer(obj.data) 990 | del obj.data[discard_index] 991 | self.loc = self.get_loc(obj.data) 992 | self.scale = self.get_scale(obj.data) 993 | self.rows, self.columns = self.get_array(obj.data) 994 | self.extrusion = self.get_extrusion(obj.data) 995 | 996 | 997 | 998 | 999 | 1000 | def get_loc(self, data): 1001 | """Gets the center location for circle type objects. 1002 | 1003 | Circles have a single coord location. 1004 | """ 1005 | loc = [0, 0, 0] 1006 | for item in data: 1007 | if item[0] == 10: # 10 = x 1008 | loc[0] = item[1] 1009 | elif item[0] == 20: # 20 = y 1010 | loc[1] = item[1] 1011 | elif item[0] == 30: # 30 = z 1012 | loc[2] = item[1] 1013 | return loc 1014 | 1015 | 1016 | 1017 | def get_scale(self, data): 1018 | """Gets the x/y/z scale factor for the block. 1019 | """ 1020 | scale = [1, 1, 1] 1021 | for item in data: 1022 | if item[0] == 41: # 41 = x scale 1023 | scale[0] = item[1] 1024 | elif item[0] == 42: # 42 = y scale 1025 | scale[1] = item[1] 1026 | elif item[0] == 43: # 43 = z scale 1027 | scale[2] = item[1] 1028 | return scale 1029 | 1030 | 1031 | 1032 | def get_array(self, data): 1033 | """Returns the pair (row number, row spacing), (column number, column spacing).""" 1034 | columns = 1 1035 | rows = 1 1036 | cspace = 0 1037 | rspace = 0 1038 | for item in data: 1039 | if item[0] == 70: # 70 = columns 1040 | columns = item[1] 1041 | elif item[0] == 71: # 71 = rows 1042 | rows = item[1] 1043 | if item[0] == 44: # 44 = columns 1044 | cspace = item[1] 1045 | elif item[0] == 45: # 45 = rows 1046 | rspace = item[1] 1047 | return (rows, rspace), (columns, cspace) 1048 | 1049 | 1050 | 1051 | def get_extrusion(self, data): 1052 | """Find the axis of extrusion. 1053 | 1054 | Used to get the objects Object Coordinate System (ocs). 1055 | """ 1056 | vec = [0,0,1] 1057 | for item in data: 1058 | if item[0] == 210: # 210 = x 1059 | vec[0] = item[1] 1060 | elif item[0] == 220: # 220 = y 1061 | vec[1] = item[1] 1062 | elif item[0] == 230: # 230 = z 1063 | vec[2] = item[1] 1064 | return vec 1065 | 1066 | 1067 | def __repr__(self): 1068 | return "%s: layer - %s, block - %s" %(self.__class__.__name__, self.layer, self.block) 1069 | 1070 | 1071 | 1072 | 1073 | class Ellipse: 1074 | """Class for objects representing dxf ellipses.""" 1075 | 1076 | def __init__(self, obj): 1077 | """Expects an entity object of type ellipse as input.""" 1078 | if not obj.type == 'ellipse': 1079 | raise TypeError, "Wrong type %s for ellipse object!" %obj.type 1080 | self.type = obj.type 1081 | self.data = obj.data[:] 1082 | 1083 | # required data 1084 | self.ratio = obj.get_type(40)[0] 1085 | self.start_angle = obj.get_type(41)[0] 1086 | self.end_angle = obj.get_type(42)[0] 1087 | 1088 | # optional data (with defaults) 1089 | self.space = obj.get_type(67) 1090 | if self.space: 1091 | self.space = self.space[0] 1092 | else: 1093 | self.space = 0 1094 | 1095 | self.color_index = obj.get_type(62) 1096 | if self.color_index: 1097 | self.color_index = self.color_index[0] 1098 | else: 1099 | self.color_index = BYLAYER 1100 | 1101 | discard, self.layer, discard_index = get_layer(obj.data) 1102 | del obj.data[discard_index] 1103 | self.loc = self.get_loc(obj.data) 1104 | self.major = self.get_major(obj.data) 1105 | self.extrusion = self.get_extrusion(obj.data) 1106 | self.radius = sqrt(self.major[0]**2 + self.major[0]**2 + self.major[0]**2) 1107 | 1108 | 1109 | 1110 | 1111 | def get_loc(self, data): 1112 | """Gets the center location for arc type objects. 1113 | 1114 | Arcs have a single coord location. 1115 | """ 1116 | loc = [0, 0, 0] 1117 | for item in data: 1118 | if item[0] == 10: # 10 = x 1119 | loc[0] = item[1] 1120 | elif item[0] == 20: # 20 = y 1121 | loc[1] = item[1] 1122 | elif item[0] == 30: # 30 = z 1123 | loc[2] = item[1] 1124 | return loc 1125 | 1126 | 1127 | 1128 | def get_major(self, data): 1129 | """Gets the major axis for ellipse type objects. 1130 | 1131 | The ellipse major axis defines the rotation of the ellipse and its radius. 1132 | """ 1133 | loc = [0, 0, 0] 1134 | for item in data: 1135 | if item[0] == 11: # 11 = x 1136 | loc[0] = item[1] 1137 | elif item[0] == 21: # 21 = y 1138 | loc[1] = item[1] 1139 | elif item[0] == 31: # 31 = z 1140 | loc[2] = item[1] 1141 | return loc 1142 | 1143 | 1144 | 1145 | def get_extrusion(self, data): 1146 | """Find the axis of extrusion. 1147 | 1148 | Used to get the objects Object Coordinate System (ocs). 1149 | """ 1150 | vec = [0,0,1] 1151 | for item in data: 1152 | if item[0] == 210: # 210 = x 1153 | vec[0] = item[1] 1154 | elif item[0] == 220: # 220 = y 1155 | vec[1] = item[1] 1156 | elif item[0] == 230: # 230 = z 1157 | vec[2] = item[1] 1158 | return vec 1159 | 1160 | 1161 | def __repr__(self): 1162 | return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) 1163 | 1164 | 1165 | 1166 | class Face: 1167 | """Class for objects representing dxf 3d faces.""" 1168 | 1169 | def __init__(self, obj): 1170 | """Expects an entity object of type 3dfaceplot as input.""" 1171 | if not obj.type == '3dface': 1172 | raise TypeError, "Wrong type %s for 3dface object!" %obj.type 1173 | self.type = obj.type 1174 | self.data = obj.data[:] 1175 | 1176 | # optional data (with defaults) 1177 | self.space = obj.get_type(67) 1178 | if self.space: 1179 | self.space = self.space[0] 1180 | else: 1181 | self.space = 0 1182 | 1183 | self.color_index = obj.get_type(62) 1184 | if self.color_index: 1185 | self.color_index = self.color_index[0] 1186 | else: 1187 | self.color_index = BYLAYER 1188 | 1189 | discard, self.layer, discard_index = get_layer(obj.data) 1190 | del obj.data[discard_index] 1191 | self.points = self.get_points(obj.data) 1192 | 1193 | 1194 | 1195 | 1196 | def get_points(self, data): 1197 | """Gets 3-4 points for a 3d face type object. 1198 | 1199 | Faces have three or optionally four verts. 1200 | """ 1201 | 1202 | a = [0, 0, 0] 1203 | b = [0, 0, 0] 1204 | c = [0, 0, 0] 1205 | d = False 1206 | for item in data: 1207 | # ----------- a ------------- 1208 | if item[0] == 10: # 10 = x 1209 | a[0] = item[1] 1210 | elif item[0] == 20: # 20 = y 1211 | a[1] = item[1] 1212 | elif item[0] == 30: # 30 = z 1213 | a[2] = item[1] 1214 | # ----------- b ------------- 1215 | elif item[0] == 11: # 11 = x 1216 | b[0] = item[1] 1217 | elif item[0] == 21: # 21 = y 1218 | b[1] = item[1] 1219 | elif item[0] == 31: # 31 = z 1220 | b[2] = item[1] 1221 | # ----------- c ------------- 1222 | elif item[0] == 12: # 12 = x 1223 | c[0] = item[1] 1224 | elif item[0] == 22: # 22 = y 1225 | c[1] = item[1] 1226 | elif item[0] == 32: # 32 = z 1227 | c[2] = item[1] 1228 | # ----------- d ------------- 1229 | elif item[0] == 13: # 13 = x 1230 | d = [0, 0, 0] 1231 | d[0] = item[1] 1232 | elif item[0] == 23: # 23 = y 1233 | d[1] = item[1] 1234 | elif item[0] == 33: # 33 = z 1235 | d[2] = item[1] 1236 | out = [a,b,c] 1237 | if d: 1238 | out.append(d) 1239 | return out 1240 | 1241 | 1242 | def __repr__(self): 1243 | return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) 1244 | 1245 | 1246 | def get_name(data): 1247 | """Get the name of an object from its object data. 1248 | 1249 | Returns a pair of (data_item, name) where data_item is the list entry where the name was found 1250 | (the data_item can be used to remove the entry from the object data). Be sure to check 1251 | name not None before using the returned values! 1252 | """ 1253 | value = None 1254 | for i, item in enumerate(data): 1255 | if item[0] == 2: 1256 | value = item[1] 1257 | break 1258 | return item, value, i 1259 | 1260 | def get_layer(data): 1261 | """Expects object data as input. 1262 | 1263 | Returns (entry, layer_name, entry_index) where entry is the data item that provided the layer name. 1264 | """ 1265 | value = None 1266 | for i, item in enumerate(data): 1267 | if item[0] == 8: 1268 | value = item[1] 1269 | break 1270 | return item, value, i 1271 | 1272 | 1273 | # type to object map 1274 | type_map = { 1275 | 'line':Line, 1276 | 'lwpolyline':LWpolyline, 1277 | 'text':Text, 1278 | 'mtext':Mtext, 1279 | 'circle':Circle, 1280 | 'arc':Arc, 1281 | 'layer':Layer, 1282 | 'block_record':BlockRecord, 1283 | 'block':Block, 1284 | 'insert':Insert, 1285 | 'ellipse':Ellipse, 1286 | '3dface':Face 1287 | } 1288 | 1289 | def objectify(data): 1290 | """Expects a section type object's data as input. 1291 | 1292 | Maps object data to the correct object type. 1293 | """ 1294 | objects = [] # colector for finished objects 1295 | known_types = type_map.keys() # so we don't have to call foo.keys() every iteration 1296 | index = 0 1297 | while index < len(data): 1298 | item = data[index] 1299 | if type(item) != list and item.type in known_types: 1300 | # proccess the object and append the resulting object 1301 | objects.append(type_map[item.type](item)) 1302 | elif type(item) != list and item.type == 'table': 1303 | item.data = objectify(item.data) # tables have sub-objects 1304 | objects.append(item) 1305 | elif type(item) != list and item.type == 'polyline': 1306 | pline = Polyline(item) 1307 | while 1: 1308 | index += 1 1309 | item = data[index] 1310 | if item.type == 'vertex': 1311 | v = Vertex(item) 1312 | pline.points.append(v) 1313 | elif item.type == 'seqend': 1314 | break 1315 | else: 1316 | print "Error: non-vertex found before seqend!" 1317 | index -= 1 1318 | break 1319 | objects.append(pline) 1320 | else: 1321 | # we will just let the data pass un-harrased 1322 | objects.append(item) 1323 | index += 1 1324 | return objects 1325 | if __name__ == "__main__": 1326 | print "No example yet!" 1327 | -------------------------------------------------------------------------------- /examples/dxfReader.py: -------------------------------------------------------------------------------- 1 | """This module provides a function for reading dxf files and parsing them into a useful tree of objects and data. 2 | 3 | The convert function is called by the readDXF fuction to convert dxf strings into the correct data based 4 | on their type code. readDXF expects a (full path) file name as input. 5 | """ 6 | 7 | # -------------------------------------------------------------------------- 8 | # DXF Reader v0.9 by Ed Blake (AKA Kitsu) 9 | # 2008.05.08 modif.def convert() by Remigiusz Fiedler (AKA migius) 10 | # -------------------------------------------------------------------------- 11 | # ***** BEGIN GPL LICENSE BLOCK ***** 12 | # 13 | # This program is free software; you can redistribute it and/or 14 | # modify it under the terms of the GNU General Public License 15 | # as published by the Free Software Foundation; either version 2 16 | # of the License, or (at your option) any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License 24 | # along with this program; if not, write to the Free Software Foundation, 25 | # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 26 | # 27 | # ***** END GPL LICENCE BLOCK ***** 28 | # -------------------------------------------------------------------------- 29 | 30 | 31 | from dxfImportObjects import * 32 | 33 | class Object: 34 | """Empty container class for dxf objects""" 35 | 36 | def __init__(self, _type='', block=False): 37 | """_type expects a string value.""" 38 | self.type = _type 39 | self.name = '' 40 | self.data = [] 41 | 42 | def __str__(self): 43 | if self.name: 44 | return self.name 45 | else: 46 | return self.type 47 | 48 | def __repr__(self): 49 | return str(self.data) 50 | 51 | def get_type(self, kind=''): 52 | """Despite the name, this method actually returns all objects of type 'kind' from self.data.""" 53 | if type: 54 | objects = [] 55 | for item in self.data: 56 | if type(item) != list and item.type == kind: 57 | # we want this type of object 58 | objects.append(item) 59 | elif type(item) == list and item[0] == kind: 60 | # we want this type of data 61 | objects.append(item[1]) 62 | return objects 63 | 64 | 65 | class InitializationError(Exception): pass 66 | 67 | class StateMachine: 68 | """(finite) State Machine from the great David Mertz's great Charming Python article.""" 69 | 70 | def __init__(self): 71 | self.handlers = [] 72 | self.startState = None 73 | self.endStates = [] 74 | 75 | def add_state(self, handler, end_state=0): 76 | """All states and handlers are functions which return 77 | a state and a cargo.""" 78 | self.handlers.append(handler) 79 | if end_state: 80 | self.endStates.append(handler) 81 | def set_start(self, handler): 82 | """Sets the starting handler function.""" 83 | self.startState = handler 84 | 85 | 86 | def run(self, cargo=None): 87 | if not self.startState: 88 | raise InitializationError,\ 89 | "must call .set_start() before .run()" 90 | if not self.endStates: 91 | raise InitializationError, \ 92 | "at least one state must be an end_state" 93 | handler = self.startState 94 | while 1: 95 | (newState, cargo) = handler(cargo) 96 | #print cargo 97 | if newState in self.endStates: 98 | return newState(cargo) 99 | #break 100 | elif newState not in self.handlers: 101 | raise RuntimeError, "Invalid target %s" % newState 102 | else: 103 | handler = newState 104 | 105 | def get_name(data): 106 | """Get the name of an object from its object data. 107 | 108 | Returns a pair of (data_item, name) where data_item is the list entry where the name was found 109 | (the data_item can be used to remove the entry from the object data). Be sure to check 110 | name not None before using the returned values! 111 | """ 112 | value = None 113 | for item in data: 114 | if item[0] == 2: 115 | value = item[1] 116 | break 117 | return item, value 118 | 119 | def get_layer(data): 120 | """Expects object data as input. 121 | 122 | Returns (entry, layer_name) where entry is the data item that provided the layer name. 123 | """ 124 | value = None 125 | for item in data: 126 | if item[0] == 8: 127 | value = item[1] 128 | break 129 | return item, value 130 | 131 | 132 | def convert(code, value): 133 | """Convert a string to the correct Python type based on its dxf code. 134 | code types: 135 | ints = 60-79, 170-179, 270-289, 370-389, 400-409, 1060-1070 136 | longs = 90-99, 420-429, 440-459, 1071 137 | floats = 10-39, 40-59, 110-139, 140-149, 210-239, 460-469, 1010-1059 138 | hex = 105, 310-379, 390-399 139 | strings = 0-9, 100, 102, 300-309, 410-419, 430-439, 470-479, 999, 1000-1009 140 | """ 141 | if 59 < code < 80 or 169 < code < 180 or 269 < code < 290 or 369 < code < 390 or 399 < code < 410 or 1059 < code < 1071: 142 | value = int(float(value)) 143 | elif 89 < code < 100 or 419 < code < 430 or 439 < code < 460 or code == 1071: 144 | value = long(float(value)) 145 | elif 9 < code < 60 or 109 < code < 150 or 209 < code < 240 or 459 < code < 470 or 1009 < code < 1060: 146 | value = float(value) 147 | elif code == 105 or 309 < code < 380 or 389 < code < 400: 148 | value = int(value, 16) # should be left as string? 149 | else: # it's already a string so do nothing 150 | pass 151 | return value 152 | 153 | 154 | def findObject(infile, kind=''): 155 | """Finds the next occurance of an object.""" 156 | obj = False 157 | while 1: 158 | line = infile.readline() 159 | if not line: # readline returns '' at eof 160 | return False 161 | if not obj: # We're still looking for our object code 162 | if line.lower().strip() == '0': 163 | obj = True # found it 164 | else: # we are in an object definition 165 | if kind: # if we're looking for a particular kind 166 | if line.lower().strip() == kind: 167 | obj = Object(line.lower().strip()) 168 | break 169 | else: # otherwise take anything non-numeric 170 | if line.lower().strip() not in string.digits: 171 | obj = Object(line.lower().strip()) 172 | break 173 | obj = False # whether we found one or not it's time to start over 174 | return obj 175 | 176 | def handleObject(infile): 177 | """Add data to an object until end of object is found.""" 178 | line = infile.readline() 179 | if line.lower().strip() == 'section': 180 | return 'section' # this would be a problem 181 | elif line.lower().strip() == 'endsec': 182 | return 'endsec' # this means we are done with a section 183 | else: # add data to the object until we find a new object 184 | obj = Object(line.lower().strip()) 185 | obj.name = obj.type 186 | done = False 187 | data = [] 188 | while not done: 189 | line = infile.readline() 190 | if not data: 191 | if line.lower().strip() == '0': 192 | #we've found an object, time to return 193 | return obj 194 | else: 195 | # first part is always an int 196 | data.append(int(line.lower().strip())) 197 | else: 198 | data.append(convert(data[0], line.strip())) 199 | obj.data.append(data) 200 | data = [] 201 | 202 | def handleTable(table, infile): 203 | """Special handler for dealing with nested table objects.""" 204 | item, name = get_name(table.data) 205 | if name: # We should always find a name 206 | table.data.remove(item) 207 | table.name = name.lower() 208 | # This next bit is from handleObject 209 | # handleObject should be generalized to work with any section like object 210 | while 1: 211 | obj = handleObject(infile) 212 | if obj.type == 'table': 213 | print "Warning: previous table not closed!" 214 | return table 215 | elif obj.type == 'endtab': 216 | return table # this means we are done with the table 217 | else: # add objects to the table until one of the above is found 218 | table.data.append(obj) 219 | 220 | 221 | 222 | 223 | def handleBlock(block, infile): 224 | """Special handler for dealing with nested table objects.""" 225 | item, name = get_name(block.data) 226 | if name: # We should always find a name 227 | block.data.remove(item) 228 | block.name = name 229 | # This next bit is from handleObject 230 | # handleObject should be generalized to work with any section like object 231 | while 1: 232 | obj = handleObject(infile) 233 | if obj.type == 'block': 234 | print "Warning: previous block not closed!" 235 | return block 236 | elif obj.type == 'endblk': 237 | return block # this means we are done with the table 238 | else: # add objects to the table until one of the above is found 239 | block.data.append(obj) 240 | 241 | 242 | 243 | 244 | """These are the states/functions used in the State Machine. 245 | states: 246 | start - find first section 247 | start_section - add data, find first object 248 | object - add obj-data, watch for next obj (called directly by start_section) 249 | end_section - look for next section or eof 250 | end - return results 251 | """ 252 | 253 | def start(cargo): 254 | """Expects the infile as cargo, initializes the cargo.""" 255 | #print "Entering start state!" 256 | infile = cargo 257 | drawing = Object('drawing') 258 | section = findObject(infile, 'section') 259 | if section: 260 | return start_section, (infile, drawing, section) 261 | else: 262 | return error, (infile, "Failed to find any sections!") 263 | 264 | def start_section(cargo): 265 | """Expects [infile, drawing, section] as cargo, builds a nested section object.""" 266 | #print "Entering start_section state!" 267 | infile = cargo[0] 268 | drawing = cargo[1] 269 | section = cargo[2] 270 | # read each line, if it is an object declaration go to object mode 271 | # otherwise create a [index, data] pair and add it to the sections data. 272 | done = False 273 | data = [] 274 | while not done: 275 | line = infile.readline() 276 | 277 | if not data: # if we haven't found a dxf code yet 278 | if line.lower().strip() == '0': 279 | # we've found an object 280 | while 1: # no way out unless we find an end section or a new section 281 | obj = handleObject(infile) 282 | if obj == 'section': # shouldn't happen 283 | print "Warning: failed to close previous section!" 284 | return end_section, (infile, drawing) 285 | elif obj == 'endsec': # This section is over, look for the next 286 | drawing.data.append(section) 287 | return end_section, (infile, drawing) 288 | elif obj.type == 'table': # tables are collections of data 289 | obj = handleTable(obj, infile) # we need to find all there contents 290 | section.data.append(obj) # before moving on 291 | elif obj.type == 'block': # the same is true of blocks 292 | obj = handleBlock(obj, infile) # we need to find all there contents 293 | section.data.append(obj) # before moving on 294 | else: # found another sub-object 295 | section.data.append(obj) 296 | else: 297 | data.append(int(line.lower().strip())) 298 | else: # we have our code, now we just need to convert the data and add it to our list. 299 | data.append(convert(data[0], line.strip())) 300 | section.data.append(data) 301 | data = [] 302 | def end_section(cargo): 303 | """Expects (infile, drawing) as cargo, searches for next section.""" 304 | #print "Entering end_section state!" 305 | infile = cargo[0] 306 | drawing = cargo[1] 307 | section = findObject(infile, 'section') 308 | if section: 309 | return start_section, (infile, drawing, section) 310 | else: 311 | return end, (infile, drawing) 312 | 313 | def end(cargo): 314 | """Expects (infile, drawing) as cargo, called when eof has been reached.""" 315 | #print "Entering end state!" 316 | infile = cargo[0] 317 | drawing = cargo[1] 318 | #infile.close() 319 | return drawing 320 | 321 | def error(cargo): 322 | """Expects a (infile, string) as cargo, called when there is an error during processing.""" 323 | #print "Entering error state!" 324 | infile = cargo[0] 325 | err = cargo[1] 326 | infile.close() 327 | print "There has been an error:" 328 | print err 329 | return False 330 | 331 | def readDXF(filename): 332 | """Given a file name try to read it as a dxf file. 333 | 334 | Output is an object with the following structure 335 | drawing 336 | header 337 | header data 338 | classes 339 | class data 340 | tables 341 | table data 342 | blocks 343 | block data 344 | entities 345 | entity data 346 | objects 347 | object data 348 | where foo data is a list of sub-objects. True object data 349 | is of the form [code, data]. 350 | """ 351 | infile = open(filename) 352 | 353 | sm = StateMachine() 354 | sm.add_state(error, True) 355 | sm.add_state(end, True) 356 | sm.add_state(start_section) 357 | sm.add_state(end_section) 358 | sm.add_state(start) 359 | sm.set_start(start) 360 | try: 361 | drawing = sm.run(infile) 362 | if drawing: 363 | drawing.name = filename 364 | for obj in drawing.data: 365 | item, name = get_name(obj.data) 366 | if name: 367 | obj.data.remove(item) 368 | obj.name = name.lower() 369 | setattr(drawing, name.lower(), obj) 370 | # Call the objectify function to cast 371 | # raw objects into the right types of object 372 | obj.data = objectify(obj.data) 373 | #print obj.name 374 | finally: 375 | infile.close() 376 | return drawing 377 | if __name__ == "__main__": 378 | filename = r".\examples\block-test.dxf" 379 | drawing = readDXF(filename) 380 | for item in drawing.entities.data: 381 | print item 382 | -------------------------------------------------------------------------------- /examples/dxf_import.py: -------------------------------------------------------------------------------- 1 | #*************************************************************************** 2 | #* * 3 | #* Copyright (c) 2010 Dan Falck * 4 | #* derived from Yorik van Havre's importDXF.py * 5 | #* script that is part of the Draft plugin for FreeCAD * 6 | #* This program is free software; you can redistribute it and/or modify * 7 | #* it under the terms of the GNU General Public License (GPL) * 8 | #* as published by the Free Software Foundation; either version 2 of * 9 | #* the License, or (at your option) any later version. * 10 | #* for detail see the LICENCE text file. * 11 | #* * 12 | #* This program is distributed in the hope that it will be useful, * 13 | #* but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | #* GNU Library General Public License for more details. * 16 | #* * 17 | #* You should have received a copy of the GNU Library General Public * 18 | #* License along with this program; if not, write to the Free Software * 19 | #* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * 20 | #* USA * 21 | #* * 22 | #*************************************************************************** 23 | 24 | __title__="dxf_import.py HeeksPython - DXF importer" 25 | __author__ = "Dan Falck " 26 | __url__ = ["http://code.google.com/p/heekspython/"] 27 | 28 | ''' 29 | This script uses a DXF-parsing library created by Stani, 30 | Kitsu and Migius for Blender 31 | 32 | imports: 33 | line, polylines, lwpolylines, arcs, circles, texts, 34 | mtexts, layers (as groups), colors 35 | 36 | ''' 37 | import math 38 | import numpy 39 | from dxfReader import readDXF 40 | 41 | def equals(p1,p2): 42 | if p1 == p2: 43 | return True 44 | else: 45 | return False 46 | 47 | 48 | def importLine(): 49 | return ("import HeeksPython as cad\n") 50 | 51 | 52 | def drawLine(line): 53 | "returns a HeeksPython line3d from a dxf line" 54 | if (len(line.points) > 1): 55 | v1=(line.points[0][0],line.points[0][1],line.points[0][2]) 56 | v2=(line.points[1][0],line.points[1][1],line.points[1][2]) 57 | 58 | x0=line.points[0][0];y0=line.points[0][1];z0=line.points[0][2] 59 | x1=line.points[1][0];y1=line.points[1][1];z1=line.points[1][2] 60 | 61 | if not equals(v1,v2): 62 | try: return ("cad.line3d("+str(x0)+","+str(y0)+","+str(z0)+","+str(x1)+","+str(y1)+","+str(z1)+")\n") 63 | except: warn(line) 64 | return None 65 | 66 | def drawArc(arc): 67 | "returns a Part shape from a dxf arc" 68 | cen=(arc.loc[0],arc.loc[1],arc.loc[2]) 69 | firstangle=(arc.start_angle/180)*math.pi 70 | lastangle=(arc.end_angle/180)*math.pi 71 | rad = arc.radius 72 | 73 | center = (str(arc.loc[0])+ ", " +str(arc.loc[1])+ ", " + str(arc.loc[2])) 74 | radius = str(rad) 75 | angle1 = str(firstangle) 76 | angle2 = str(lastangle) 77 | dir_vec = "0,0,1" 78 | try: return ("cad.arc(" + center + ", " + radius + ", " + angle1 + ", " + angle2 + ", " + dir_vec + ")\n") 79 | except: warn(arc) 80 | return None 81 | #*************************************************************************** 82 | # functions copied from fcvec for polyline bulges 83 | #*************************************************************************** 84 | def precision(): 85 | return 6 86 | 87 | def isNull(vector): 88 | '''isNull(vector): Tests if a vector is nul vector''' 89 | p = precision() 90 | return (round(vector[0],p)==0.0 and round(vector[1],p)==0.0 and round(vector[2],p)==0.0) 91 | 92 | def equals(u,v): 93 | "returns True if vectors differ by less than precision (from ParamGet), elementwise " 94 | #typecheck ([(u,Vector), (v,Vector)], "equals") 95 | return isNull(numpy.subtract(u,v)) 96 | 97 | def isColinear(vlist): 98 | '''isColinear(list_of_vectors): checks if vectors in given list are colinear''' 99 | #typecheck ([(vlist,list)], "isColinear"); 100 | if len(vlist) < 3: return True 101 | #first = vlist[1].sub(vlist[0]) 102 | first = numpy.subtract(vlist[1],vlist[0]) 103 | for i in range(2,len(vlist)): 104 | #if angle(vlist[i].sub(vlist[0]),first) != 0: 105 | if angle(numpy.subtract(vlist[i],vlist[0]),first) != 0: 106 | return False 107 | return True 108 | 109 | def angle(u,v=(1,0,0),normal=(0,0,1)): 110 | '''angle(Vector,[Vector],[Vector]) - returns the angle in radians between the two vectors. 111 | If only one is given, angle is between the vector and the horizontal East direction. 112 | If a third vector is given, it is the normal used to determine the sign of the angle. 113 | ''' 114 | #typecheck ([(u,Vector), (v,Vector)], "angle") 115 | #ll = u.Length*v.Length 116 | ll = numpy.linalg.norm(u)*numpy.linalg.norm(v) 117 | if ll==0: return 0 118 | #dp=u.dot(v)/ll 119 | dp=numpy.dot(u,v)/ll 120 | if (dp < -1): dp = -1 # roundoff errors can push dp out of the ... 121 | elif (dp > 1): dp = 1 # ...geometrically meaningful interval [-1,1] 122 | ang = math.acos(dp) 123 | #normal1 = u.cross(v) 124 | normal1 = numpy.cross(u,v) 125 | #coeff = normal.dot(normal1) 126 | coeff = numpy.dot(normal,normal1) 127 | if coeff >= 0: 128 | return ang 129 | else: 130 | return -ang 131 | 132 | #******************************************************************* 133 | # polyline related functions 134 | #******************************************************************* 135 | def calcBulge(v1,bulge,v2): 136 | ''' 137 | calculates intermediary vertex for curved segments. 138 | algorithm from http://www.afralisp.net/lisp/Bulges1.htm 139 | not needed yet for HeeksPython and not really tested yet either 140 | ''' 141 | #chord = v2.sub(v1) 142 | chord = numpy.subtract(v2,v1) 143 | #sagitta = (bulge * chord.Length)/2 144 | chord_length= numpy.linalg.norm(chord) 145 | sagitta = (bulge*chord_length)/2 146 | #startpoint = v1.add(fcvec.scale(chord,0.5)) 147 | startpoint = numpy.add(v1,(numpy.multiply(chord,(.5,.5,.5)))) 148 | #perp = chord.cross(Vector(0,0,1)) 149 | perp = numpy.cross(chord,(0,0,1)) 150 | #if not isNull(perp): perp.normalize() 151 | if not isNull(perp): numpy.linalg.norm(perp) 152 | #endpoint = fcvec.scale(perp,sagitta) 153 | endpoint = numpy.multiply(perp,sagitta) 154 | #return startpoint.add(endpoint) 155 | return numpy.add(startpoint,endpoint) 156 | 157 | def calc_center(v1,bulge,v2): 158 | ''' 159 | calculates center of arc- this one works 160 | ''' 161 | chord = numpy.subtract(v2,v1) 162 | chord_length= numpy.linalg.norm(chord) 163 | sagitta = (bulge*chord_length)/2.0 164 | inc_angle = numpy.arctan(bulge)*4.0 165 | radius = (chord_length/2.0)/numpy.sin(inc_angle/2.0) 166 | if bulge >= 0: 167 | perp = (numpy.cross(chord,(0,0,-1))) 168 | else: 169 | perp = (numpy.cross(chord,(0,0,1))) 170 | chord_mid_pt = numpy.add(numpy.multiply(chord,(.5,.5,.5)),v1) 171 | unit_vec = perp/ numpy.linalg.norm(perp) 172 | arc_center = numpy.add(numpy.multiply((radius-sagitta),unit_vec),chord_mid_pt) 173 | return arc_center 174 | 175 | 176 | 177 | def drawPolyline(polyline,i): 178 | "returns a Part shape from a dxf polyline" 179 | if (len(polyline.points) > 1): 180 | collector = [] 181 | edges = [] 182 | for p in range(len(polyline.points)-1): 183 | p1 = polyline.points[p] 184 | p2 = polyline.points[p+1] 185 | v1 = (p1[0],p1[1],p1[2]) 186 | v2 = (p2[0],p2[1],p2[2]) 187 | if not equals(v1,v2): 188 | 189 | if polyline.points[p].bulge: 190 | #return "bulge\n" 191 | #cv = calcBulge(v1,polyline.points[p].bulge,v2) 192 | cv = calc_center(v1,polyline.points[p].bulge,v2) 193 | if isColinear([v1,cv,v2]): 194 | 195 | #try: edges.append(Part.Line(v1,v2).toShape()) 196 | try: 197 | collector.append("cad.line3d("+str(v1[0])+","+str(v1[1])+","+str(v1[2])+","+str(v2[0])+","+str(v2[1])+","+str(v2[2])+")\n") 198 | collector.append("e"+str(i)+ "=cad.getlastobj()\n") 199 | collector.append("cad.add("+rename(polyline.layer)+",e"+str(i)+")\n") 200 | i+=1 201 | except: 202 | warn(polyline) 203 | else: 204 | start=(str(v1[0])+","+str(v1[1])+","+str(v1[2])) 205 | center=(str(cv[0])+","+str(cv[1])+","+str(cv[2])) 206 | end = (str(v2[0])+","+str(v2[1])+","+str(v2[2])) 207 | dir_vec = "0,0,1" 208 | #try: edges.append(Part.Arc(v1,cv,v2).toShape()) 209 | try: 210 | collector.append("cad.arc2("+ start+","+end+"," + center + ", " + dir_vec + ")\n") 211 | collector.append("e"+str(i)+ "=cad.getlastobj()\n") 212 | collector.append("cad.add("+rename(polyline.layer)+",e"+str(i)+")\n") 213 | i+=1 214 | except: 215 | warn(polyline) 216 | else: 217 | try: 218 | collector.append("cad.line3d("+str(v1[0])+","+str(v1[1])+","+str(v1[2])+","+str(v2[0])+","+str(v2[1])+","+str(v2[2])+")\n") 219 | collector.append("e"+str(i)+ "=cad.getlastobj()\n") 220 | collector.append("cad.add("+rename(polyline.layer)+",e"+str(i)+")\n") 221 | i+=1 222 | except: 223 | warn(polyline) 224 | 225 | else: 226 | return "no way!\n", i 227 | 228 | if polyline.closed: 229 | p1 = polyline.points[len(polyline.points)-1] 230 | p2 = polyline.points[0] 231 | v1 = (p1[0],p1[1],p2[2]) 232 | v2 = (p2[0],p2[1],p2[2]) 233 | if not equals(v1,v2): 234 | try: 235 | collector.append("cad.line3d("+str(v1[0])+","+str(v1[1])+","+str(v1[2])+","+str(v2[0])+","+str(v2[1])+","+str(v2[2])+")\n") 236 | collector.append("e"+str(i)+ "=cad.getlastobj()\n") 237 | collector.append("cad.add("+rename(polyline.layer)+",e"+str(i)+")\n") 238 | i+=1 239 | except: 240 | warn(polyline) 241 | string = "".join(collector) 242 | return string, i 243 | else: 244 | return "No\n", i 245 | #******************************************************************* 246 | # end of polyline related functions 247 | #******************************************************************* 248 | def warn(dxfobject): 249 | "outputs a warning if a dxf object couldn't be imported" 250 | print "dxf: couldn't import", dxfobject 251 | 252 | #******************************************************************* 253 | # rename layers to object titles so that Heeks doesn't complain 254 | # in the case of the layer being named a number 255 | #******************************************************************* 256 | def rename(layer): 257 | return str("layer_"+layer) 258 | 259 | #******************************************************************* 260 | # process the file 261 | #******************************************************************* 262 | def process(filename): 263 | "this does the translation of the dxf contents into HeeksPython Part objects" 264 | global drawing 265 | header_collector = [] 266 | collector = [] 267 | layer_collector = [] 268 | i = 1 269 | drawing = readDXF(filename) 270 | global layers 271 | layers = [] 272 | 273 | 274 | # drawing lines 275 | lines = drawing.entities.get_type("line") 276 | for line in lines: 277 | shape = drawLine(line) 278 | if shape: 279 | collector.append(shape) 280 | layers.append(line.layer) 281 | i+=1 282 | collector.append("e"+str(i)+ "=cad.getlastobj()\n") 283 | collector.append("cad.add("+rename(line.layer)+",e"+str(i)+")\n") 284 | string = "".join(collector) 285 | 286 | # drawing arcs 287 | arcs = drawing.entities.get_type("arc") 288 | for arc in arcs: 289 | shape = drawArc(arc) 290 | if shape: 291 | collector.append(shape) 292 | layers.append(arc.layer) 293 | i+=1 294 | collector.append("e"+str(i)+ "=cad.getlastobj()\n") 295 | collector.append("cad.add("+rename(arc.layer)+",e"+str(i)+")\n") 296 | string = "".join(collector) 297 | 298 | # drawing polylines 299 | polylines = drawing.entities.get_type("polyline") 300 | polylines.extend(drawing.entities.get_type("lwpolyline")) 301 | 302 | for polyline in polylines: 303 | shape,poly_index = drawPolyline(polyline,i) 304 | i = poly_index 305 | if shape: 306 | collector.append(shape) 307 | layers.append(polyline.layer) 308 | 309 | string = "".join(collector) 310 | 311 | #print "import HeeksPython as cad" 312 | #heeksimport = importLine() 313 | #print heeksimport 314 | #collector.append(heeksimport) 315 | #string = "".join(collector) 316 | #print string 317 | #string = collector 318 | 319 | #string1 = "import HeeksPython as cad\n" 320 | 321 | header_collector.append("import HeeksPython as cad\n") 322 | string1 = "".join(header_collector) 323 | print string1 324 | 325 | LayerList = list(set(layers)) 326 | for LL in LayerList: 327 | print "cad.sketch()\n" 328 | print (rename(LL) + "=cad.getlastobj()\n") 329 | #layer_collector.append("cad.sketch()\n") 330 | #layer_collector.append(rename(LL) + "=cad.getlastobj()\n") 331 | #string2 = "".join(layer_collector) 332 | #print string2 333 | 334 | 335 | 336 | print string 337 | 338 | for LL in LayerList: 339 | print ("cad.reorder("+rename(LL)+ ")\n" ) 340 | 341 | -------------------------------------------------------------------------------- /examples/dxf_to_heekspython.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Utility for translating between 2D dxf closed profiles and HeeksPython format. Dan Falck 10/31/10 3 | inspiration from Doug Blanding's Cadvas.py dxf.py module- thanks Doug! 4 | """ 5 | import math 6 | 7 | ########################## 8 | # 9 | # parse the dxf file 10 | # 11 | ########################## 12 | def _parsepair(a): 13 | """Parse a pair of lines containing 'group code' and 'value'.""" 14 | groupcode = a.next().strip() 15 | value = a.next().strip() 16 | return (groupcode, value) 17 | 18 | def _gotosection(a, secname): 19 | """Go to secname and stop.""" 20 | while 1: 21 | gc, val = _parsepair(a) 22 | if gc == '2' and val == secname: 23 | return 24 | 25 | def _get_units(a): 26 | """Parse through HEADER section and detect whether units 27 | are set for metric(1) or english(0).""" 28 | _gotosection(a, 'HEADER') 29 | units = 0 # assume inches by default 30 | while 1: 31 | gc, val = _parsepair(a) 32 | if gc == '9' and val == '$MEASUREMENT': 33 | gc, val = _parsepair(a) 34 | if gc == '70': 35 | units = int(val) 36 | elif gc == '0' and val == 'ENDSEC': 37 | return units 38 | 39 | def _process_entity(a): 40 | """Return a dictionary of groupcodes : values for the next 41 | entity in the ENTITIES section. Go until groupcode == 0.""" 42 | entitydict = {} 43 | flag = 1 44 | while 1: 45 | gc, val = _parsepair(a) 46 | if gc == '0': 47 | if val == 'ENDSEC': 48 | flag = 0 # Done with ENTITIES section 49 | return (entitydict, flag, val) 50 | else: 51 | entitydict[gc] = val 52 | 53 | def _parse_file(f): 54 | """Parse contents of the dxf file, looking for units and 55 | all the drawing entities.""" 56 | a = iter(open(f)) 57 | units = _get_units(a) 58 | _gotosection(a, 'ENTITIES') 59 | lines = [] 60 | circles = [] 61 | arcs = [] 62 | entities = [lines, circles, arcs] 63 | gc, val = _parsepair(a) 64 | while 1: 65 | if val == 'LINE': 66 | ed, f, val = _process_entity(a) 67 | lines.append(ed) 68 | #print 'line\n' 69 | elif val == 'CIRCLE': 70 | ed, f, val = _process_entity(a) 71 | circles.append(ed) 72 | #print 'circle\n' 73 | elif val == 'ARC': 74 | ed, f, val = _process_entity(a) 75 | arcs.append(ed) 76 | #print 'arc\n' 77 | else: 78 | ed, f, val = _process_entity(a) 79 | if not f: 80 | return (units, entities) 81 | 82 | ########################## 83 | # 84 | # dxf to HeeksPython 85 | # DF added 10/31/10 86 | ########################## 87 | def gen_heekspython_entities(f,sketch_num): 88 | """Generate HeeksPython objects from dxf entities.""" 89 | units, entities = _parse_file(f) 90 | lines, circles, arcs = entities 91 | if units: 92 | scale = 1.0 93 | else: 94 | scale = 25.4 95 | mldict = {} 96 | mcdict = {} 97 | madict = {} 98 | k = 0 99 | i = 0 100 | collector=[] 101 | collector.append("cad.sketch()\n") 102 | collector.append("sketch"+str(sketch_num)+" = cad.getlastobj()\n") 103 | for line in lines: 104 | p1 = (float(line['10'])*scale, 105 | float(line['20'])*scale) 106 | p2 = (float(line['11'])*scale, 107 | float(line['21'])*scale) 108 | coords = (p1, p2) 109 | #print"#Line,"+str(p1[0])+","+str(p1[1])+",0,"+str(p2[0])+","+str(p2[1])+",0\n" 110 | collector.append("cad.line("+str(p1[0])+","+str(p1[1])+","+str(p2[0])+","+str(p2[1])+")\n") 111 | collector.append("i"+str(i)+"= cad.getlastobj()\n") 112 | collector.append("cad.add(sketch"+str(sketch_num)+",i"+str(i)+")\n") 113 | i+=1 114 | k+=1 115 | 116 | mldict[k] = coords 117 | string = "".join(collector) 118 | 119 | k = 0 120 | for circ in circles: 121 | cntr = (float(circ['10'])*scale, 122 | float(circ['20'])*scale) 123 | radius = float(circ['40'])*scale 124 | coords = (cntr, radius) 125 | #print "#Circle,"+str(cntr[0])+","+str(cntr[1])+",0,"+str(radius)+"\n" 126 | collector.append("cad.circle("+str(cntr[0])+","+str(cntr[1])+","+str(radius)+")\n") 127 | collector.append("i"+str(i)+"= cad.getlastobj()\n") 128 | collector.append("cad.add(sketch"+str(sketch_num)+",i"+str(i)+")\n") 129 | i+=1 130 | k+=1 131 | mcdict[k] = coords 132 | string = "".join(collector) 133 | k = 0 134 | for arc in arcs: 135 | cntr = (float(arc['10'])*scale, 136 | float(arc['20'])*scale) 137 | radius = float(arc['40'])*scale 138 | a0 = float(arc['50']) 139 | a1 = float(arc['51']) 140 | coords = (cntr, radius, a0, a1) 141 | angle1=((math.pi)/180)*a0 142 | angle2=((math.pi)/180)*a1 143 | #print "#Arc,"+str(cntr[0])+","+str(cntr[1])+",0,"+str(radius)+","+str(angle1)+","+str(angle2)+"\n" 144 | collector.append("cad.arc("+str(cntr[0])+","+str(cntr[1])+",0,"+str(radius)+","+str(angle1)+","+str(angle2)+",0,0,1)\n") 145 | #hardcoded dir vector and need to convert angles to radians, I 146 | collector.append("i"+str(i)+"= cad.getlastobj()\n") 147 | collector.append("cad.add(sketch"+str(sketch_num)+",i"+str(i)+")\n") 148 | i+=1 149 | k+=1 150 | madict[k] = coords 151 | string = "".join(collector) 152 | string= string + "cad.reorder(sketch"+str(sketch_num)+")\n" 153 | #string= string + "cad.revolve(sketch,360)" 154 | return string 155 | 156 | 157 | 158 | 159 | #example of how to use it 160 | ''' 161 | import HeeksPython as cad 162 | import sys 163 | sys.path.insert(0,'/home/dan/heeks/heekspython2/examples') 164 | import dxf_to_heekspython 165 | 166 | file_in='/home/dan/Documents/drawings/blob.dxf' 167 | l = dxf_to_heekspython.gen_heekspython_entities(file_in,1) 168 | exec(l) 169 | 170 | or scale the object/sketch like this: 171 | l = dxf_to_heekspython.gen_heekspython_entities(file_in,1) 172 | l = l +"cad.scale(sketch1,0,0,0,.25)" 173 | exec(l) 174 | 175 | or even revolve a solid after returning l 176 | l = dxf_to_heekspython.gen_heekspython_entities(file_in,1) 177 | l = l +"cad.revolve(sketch1,360)" 178 | exec(l) 179 | 180 | ''' 181 | 182 | -------------------------------------------------------------------------------- /examples/example.py: -------------------------------------------------------------------------------- 1 | import HeeksPython as cad 2 | import math 3 | 4 | beam_width = 2.0; 5 | beam_height = 2.0; 6 | beam_thickness = .25; 7 | 8 | bend_radius = 20.0; 9 | line_length = 40*12.0; 10 | dead_zone_width = 3*12.0; 11 | 12 | top_overhang = 1.1; 13 | bottom_overhang = 4.1; 14 | side_overhang = 1.0; 15 | gripper_thickness = .5; 16 | beam_clearance = .1; 17 | 18 | rail_height = 1; 19 | 20 | bearing_clearance = .25; 21 | bearing_height = 1; 22 | dist_between_bearings = 3; 23 | rail_width = 1; 24 | 25 | def make_beam_profile(beam_width,beam_height,beam_thickness): 26 | cad.sketch() 27 | sketch = cad.getlastobj() 28 | 29 | cad.line(-beam_width/2.0,-beam_height/2.0,beam_width/2.0,-beam_height/2.0) 30 | cad.add(sketch,cad.getlastobj()) 31 | cad.line(-beam_width/2.0,-beam_height/2.0,-beam_width/2.0,-beam_height/2.0+beam_thickness) 32 | cad.add(sketch,cad.getlastobj()) 33 | cad.line(-beam_width/2.0,-beam_height/2.0+beam_thickness,-beam_thickness/2.0,-beam_height/2.0+beam_thickness) 34 | cad.add(sketch,cad.getlastobj()) 35 | cad.line(beam_thickness/2.0,-beam_height/2.0+beam_thickness,beam_width/2.0,-beam_height/2.0+beam_thickness) 36 | cad.add(sketch,cad.getlastobj()) 37 | cad.line(beam_width/2.0,-beam_height/2.0+beam_thickness,beam_width/2.0,-beam_height/2.0) 38 | cad.add(sketch,cad.getlastobj()) 39 | 40 | cad.line(beam_thickness/2.0,-beam_height/2.0+beam_thickness,beam_thickness/2.0,beam_height/2.0-beam_thickness) 41 | cad.add(sketch,cad.getlastobj()) 42 | cad.line(-beam_thickness/2.0,-beam_height/2.0+beam_thickness,-beam_thickness/2.0,beam_height/2.0-beam_thickness) 43 | cad.add(sketch,cad.getlastobj()) 44 | 45 | cad.line(-beam_width/2.0,beam_height/2.0,beam_width/2.0,beam_height/2.0) 46 | cad.add(sketch,cad.getlastobj()) 47 | cad.line(-beam_width/2.0,beam_height/2.0,-beam_width/2.0,beam_height/2.0-beam_thickness) 48 | cad.add(sketch,cad.getlastobj()) 49 | cad.line(-beam_width/2.0,beam_height/2.0-beam_thickness,-beam_thickness/2.0,beam_height/2.0-beam_thickness) 50 | cad.add(sketch,cad.getlastobj()) 51 | cad.line(beam_thickness/2.0,beam_height/2.0-beam_thickness,beam_width/2.0,beam_height/2.0-beam_thickness) 52 | cad.add(sketch,cad.getlastobj()) 53 | cad.line(beam_width/2.0,beam_height/2.0-beam_thickness,beam_width/2.0,beam_height/2.0) 54 | cad.add(sketch,cad.getlastobj()) 55 | 56 | cad.reorder(sketch); 57 | return sketch 58 | 59 | def make_square_beam_profile(beam_width,beam_height): 60 | cad.sketch() 61 | sketch = cad.getlastobj() 62 | 63 | cad.line(-beam_width/2.0,-beam_height/2.0,beam_width/2.0,-beam_height/2.0) 64 | cad.add(sketch,cad.getlastobj()) 65 | 66 | cad.line(beam_width/2.0,-beam_height/2.0,beam_width/2.0,beam_height/2.0) 67 | cad.add(sketch,cad.getlastobj()) 68 | 69 | cad.line(beam_width/2.0,beam_height/2.0,-beam_width/2.0,beam_height/2.0) 70 | cad.add(sketch,cad.getlastobj()) 71 | 72 | cad.line(-beam_width/2.0,beam_height/2.0,-beam_width/2.0,-beam_height/2.0) 73 | cad.add(sketch,cad.getlastobj()) 74 | 75 | cad.reorder(sketch); 76 | return sketch 77 | 78 | def getprofile(type): 79 | if type == "i": 80 | return make_beam_profile(beam_width,beam_height,beam_thickness) 81 | else: 82 | return make_square_beam_profile(rail_width,rail_height) 83 | 84 | def make_quarter_beam(type,radius): 85 | profile = getprofile(type) 86 | #cad.extrude(profile,10) 87 | cad.arc(-radius,0,0,.0001,math.pi/2,math.pi,0,1,0) 88 | cad.linearc2wire(cad.getlastobj()) 89 | wire = cad.getlastobj() 90 | cad.pipe(wire,profile); 91 | return cad.getlastobj() 92 | 93 | def make_beam(type,length): 94 | profile = getprofile(type) 95 | cad.extrude(profile,length) 96 | return cad.getlastobj() 97 | 98 | 99 | def make_track(type,line_length,dead_zone_width,bend_radius): 100 | cad.group() 101 | group = cad.getlastobj() 102 | 103 | beam1 = make_beam(type,line_length) 104 | beam2 = make_beam(type,line_length) 105 | cad.translate(beam2,-dead_zone_width-bend_radius*2,0,0) 106 | beam3 = make_quarter_beam(type,bend_radius) 107 | beam4 = make_beam(type,dead_zone_width) 108 | cad.rotate(beam3,0,0,0,0,1,0,math.pi/2) 109 | cad.rotate(beam4,0,0,0,0,1,0,-math.pi/2) 110 | cad.translate(beam3,-bend_radius-dead_zone_width,0,-bend_radius) 111 | cad.translate(beam4,-bend_radius,0,-bend_radius) 112 | 113 | beam5 = make_quarter_beam(type,bend_radius) 114 | beam6 = make_beam(type,dead_zone_width) 115 | cad.rotate(beam5,0,0,0,0,1,0,-math.pi/2) 116 | cad.rotate(beam6,0,0,0,0,1,0,-math.pi/2) 117 | cad.translate(beam5,-bend_radius,0,line_length+bend_radius) 118 | cad.translate(beam6,-bend_radius,0,line_length+bend_radius) 119 | 120 | beam7 = make_quarter_beam(type,bend_radius) 121 | cad.rotate(beam7,0,0,0,0,1,0,math.pi) 122 | cad.translate(beam7,-bend_radius*2-dead_zone_width,0,line_length) 123 | 124 | beam8 = make_quarter_beam(type,bend_radius) 125 | 126 | 127 | cad.add(group,beam1) 128 | cad.add(group,beam2) 129 | cad.add(group,beam3) 130 | cad.add(group,beam4) 131 | cad.add(group,beam5) 132 | cad.add(group,beam6) 133 | cad.add(group,beam7) 134 | cad.add(group,beam8) 135 | return group 136 | 137 | def run(): 138 | make_track("i",line_length,dead_zone_width,bend_radius) 139 | 140 | bot_offset = -rail_height/2-beam_height/2-bottom_overhang-bearing_clearance-bearing_height 141 | offset = dist_between_bearings/2 + rail_width/2 142 | track2 = make_track("s",line_length,dead_zone_width,bend_radius-offset) 143 | cad.translate(track2,-offset,bot_offset,0) 144 | 145 | track2 = make_track("s",line_length,dead_zone_width,bend_radius+offset) 146 | cad.translate(track2,offset,bot_offset,0) 147 | 148 | 149 | run() 150 | -------------------------------------------------------------------------------- /examples/example_run.txt: -------------------------------------------------------------------------------- 1 | Here's a way of running example.py without copy/paste. 2 | 3 | Type or 'paste plus' this into the HeeksPython console: 4 | 5 | import sys 6 | sys.path.insert(0,'/home/dan/heeks/heekspython3/examples') #your directory will be different than mine 7 | import example 8 | example.run() 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/facegear.py: -------------------------------------------------------------------------------- 1 | import HeeksPython as cad 2 | from math import pi 3 | 4 | def cut_it(obj1,obj2): 5 | cad.cut(obj1,obj2) 6 | newobj = cad.getlastobj() 7 | cad.remove(obj1) 8 | cad.changed() 9 | cad.remove(newobj) 10 | return newobj 11 | 12 | def blank(outer_dia,inner_dia,length): 13 | x0,y0,z0 = 0,0,0 14 | rad1 = (outer_dia)*.5 15 | length = length 16 | cad.cylinder(x0,y0,z0,rad1,length) 17 | c1 = cad.getlastobj() 18 | 19 | rad2 = (inner_dia)*.5 20 | 21 | cad.cylinder(x0,y0,z0,rad2,length) 22 | c2 = cad.getlastobj() 23 | 24 | ring = cut_it(c1,c2) 25 | 26 | cad.rotate(ring,x0,y0,z0,(x0+1),y0,z0,(pi/2)) 27 | cad.changed() 28 | return ring 29 | 30 | 31 | def tooth_form(tilt,length): 32 | cad.sketch() 33 | sketch = cad.getlastobj() 34 | cad.line(-.0625,.1083,.0625,.1083) 35 | l1 = cad.getlastobj() 36 | cad.line(.0625,.1083,0,0) 37 | l2 = cad.getlastobj() 38 | cad.line(0,0, -.0625,.1083) 39 | l3 = cad.getlastobj() 40 | cad.add(sketch,l1) 41 | cad.add(sketch,l2) 42 | cad.add(sketch,l3) 43 | cad.fillet2d(sketch,0,0,0,.002) 44 | cad.reorder(sketch) 45 | cad.extrude(sketch,length) 46 | form = cad.getlastobj() 47 | cad.rotate(form,0,0,0,1,0,0,(tilt*pi)/180) 48 | cad.changed() 49 | cad.remove(sketch) 50 | return form 51 | 52 | def polar_array(obj,tilt,num_teeth): 53 | circle_division=(360/num_teeth) 54 | pitch_angle = (circle_division*(pi*2))/360 55 | angle = 0 56 | count = 0 57 | while (count < num_teeth): 58 | t1 = tooth_form(tilt,.5) 59 | cad.rotate(t1,0,0,0,0,1,0,angle) 60 | cad.cut(obj,t1) 61 | obj2 = cad.getlastobj() 62 | cad.remove(obj) 63 | obj = obj2 64 | 65 | angle = angle + pitch_angle 66 | cad.changed() 67 | count = count +1 68 | 69 | cad.remove(obj) 70 | return obj2 71 | 72 | units = 25.4 #units are in mm normally so multiply inch units by this 73 | b1 = blank(.49,.3,.1) 74 | cad.translate(b1,0,0,0) 75 | gear1= polar_array(b1,4,72) 76 | cad.rotate(gear1,0,0,0,1,0,0,pi) 77 | cad.rotate(gear1,0,0,0,0,1,0,(2.5*pi)/180) 78 | cad.setcolor(0,188,180) 79 | gear2= polar_array(b1,4,72) 80 | cad.scale(gear1,0,0,0,units) 81 | cad.scale(gear2,0,0,0,units) 82 | cad.translate(gear2,0,.009*units,0) 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /examples/fillet0.py: -------------------------------------------------------------------------------- 1 | #very simple fillet demo 2 | #the end points of the lines must be trimmed first or you 3 | #will get an error from HeeksCAD 4 | 5 | 6 | import HeeksPython as cad 7 | cad.sketch() 8 | sketch = cad.getlastobj() 9 | cad.line(0,1,4,1) 10 | l1= cad.getlastobj() 11 | cad.line(4,1,4,2) 12 | l2= cad.getlastobj() 13 | cad.add(sketch,l1) 14 | cad.add(sketch,l2) 15 | cad.fillet2d(sketch,4,1,0,.1) 16 | cad.reorder(sketch) 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/fillets.py: -------------------------------------------------------------------------------- 1 | # this example shows how to create fillets between two lines 2 | 3 | import HeeksPython as cad 4 | cad.sketch() 5 | sketch = cad.getlastobj() 6 | cad.line(0,1,4,1) 7 | l1= cad.getlastobj() 8 | cad.line(4,1,4,2) 9 | l2= cad.getlastobj() 10 | cad.line(4,2,0,2) 11 | l3= cad.getlastobj() 12 | cad.line(0,2,0,1) 13 | l4= cad.getlastobj() 14 | cad.add(sketch,l1) 15 | cad.add(sketch,l2) 16 | cad.add(sketch,l3) 17 | cad.add(sketch, l4) 18 | cad.fillet2d(sketch,0,1,0, .1) 19 | cad.fillet2d(sketch,4,1,0,.1) 20 | cad.fillet2d(sketch,4,2,0,.1) 21 | cad.fillet2d(sketch,0,2,0,.1) 22 | cad.reorder(sketch) 23 | -------------------------------------------------------------------------------- /examples/fillets2.py: -------------------------------------------------------------------------------- 1 | # this example shows how to create fillets between two lines 2 | 3 | import HeeksPython as cad 4 | cad.sketch() 5 | sketch = cad.getlastobj() 6 | cad.line(0,1,4,1) 7 | l1= cad.getlastobj() 8 | cad.line(4,1,4,2) 9 | l2= cad.getlastobj() 10 | 11 | cad.line(4,2,0,2) 12 | l3= cad.getlastobj() 13 | 14 | cad.line(0,2,0,1) 15 | l4= cad.getlastobj() 16 | 17 | cad.add(sketch,l1) 18 | cad.add(sketch,l2) 19 | cad.add(sketch,l3) 20 | cad.add(sketch, l4) 21 | cad.fillet2d(sketch,4,1,0,.1) 22 | f1= cad.getlastobj() 23 | cad.fillet2d(sketch,4,2,0,.1) 24 | f2= cad.getlastobj() 25 | cad.fillet2d(sketch,0,2,0,.1) 26 | f3= cad.getlastobj() 27 | cad.fillet2d(sketch,0,1,0, .1) 28 | f4= cad.getlastobj() 29 | cad.add(sketch,f1) 30 | cad.add(sketch,f2) 31 | cad.add(sketch,f3) 32 | cad.add(sketch, f4) 33 | cad.reorder(sketch) 34 | -------------------------------------------------------------------------------- /examples/parametric_rectangle.py: -------------------------------------------------------------------------------- 1 | import HeeksPython as cad 2 | scale = 25.4 #needed to get to inch units 3 | width=6.0 4 | length=6.0 5 | height = 4.0 6 | originx = 0;originy=0 7 | corner_rad= .25 8 | 9 | 10 | def make_rect(originx,originy,width,length,rad,height,scale): 11 | #originx,originy= origin 12 | originx = originx*scale;originy = originy*scale 13 | width= width*scale;length= length*scale 14 | rad = rad*scale 15 | cad.sketch() 16 | sketch = cad.getlastobj() 17 | cad.line(originx,originy,originx+width,originy) 18 | l1= cad.getlastobj() 19 | cad.line(originx+width,originy,originx+width,originy+length) 20 | l2= cad.getlastobj() 21 | cad.line(originx+width,originy+length,originx,originy+length) 22 | l3= cad.getlastobj() 23 | cad.line(originx,originy+length,originx,originy) 24 | l4= cad.getlastobj() 25 | cad.add(sketch,l1) 26 | cad.add(sketch,l2) 27 | cad.add(sketch,l3) 28 | cad.add(sketch, l4) 29 | cad.fillet2d(sketch,originx,originy,0, rad) 30 | cad.fillet2d(sketch,originx+width,originy,0,rad) 31 | cad.fillet2d(sketch,originx+width,originy+length,0,rad) 32 | cad.fillet2d(sketch,originx,originy+length,0,rad) 33 | cad.reorder(sketch) 34 | cad.extrude(sketch,height*scale) 35 | 36 | cad.setcolor(100, 200, 55) 37 | make_rect(originx,originy,width,length,corner_rad,height,scale) 38 | b1= cad.getlastobj() 39 | box2_width=width*.6 40 | box2_length=length*.6 41 | make_rect(((originx+width*.5)-box2_width*.5),((originy+length*.5)-box2_length*.5),box2_width,box2_length,corner_rad*.75,height,scale) 42 | b2 = cad.getlastobj() 43 | cad.cut(b1,b2) 44 | cad.view_extents() 45 | -------------------------------------------------------------------------------- /examples/polar_array.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # generated by wxGlade 0.6.3 on Fri Jul 24 14:50:26 2009 4 | 5 | import HeeksPython as cad 6 | import math 7 | import wx 8 | 9 | # begin wxGlade: extracode 10 | # end wxGlade 11 | 12 | 13 | 14 | class MyFrame(wx.Frame): 15 | def __init__(self, *args, **kwds): 16 | # begin wxGlade: MyFrame.__init__ 17 | kwds["style"] = wx.DEFAULT_FRAME_STYLE 18 | wx.Frame.__init__(self, *args, **kwds) 19 | self.x_center_label = wx.StaticText(self, -1, "X center") 20 | self.x_center_entry = wx.TextCtrl(self, -1, "") 21 | self.y_center_label = wx.StaticText(self, -1, "Y center") 22 | self.y_center_entry = wx.TextCtrl(self, -1, "") 23 | self.z_center_label = wx.StaticText(self, -1, "Z center") 24 | self.z_center_entry = wx.TextCtrl(self, -1, "") 25 | self.number_points_label = wx.StaticText(self, -1, "Number of Points") 26 | self.no_of_holes_entry = wx.TextCtrl(self, -1, "") 27 | self.diameter_label = wx.StaticText(self, -1, "Polar Array Diameter") 28 | self.bolt_circle_diameter_entry = wx.TextCtrl(self, -1, "") 29 | self.angle_label = wx.StaticText(self, -1, "Starting Angle") 30 | self.start_angle_entry = wx.TextCtrl(self, -1, "") 31 | self.scale_label = wx.StaticText(self, -1, "Scale") 32 | self.Scale_entry = wx.TextCtrl(self, -1, "") 33 | self.GenButton = wx.Button(self, -1, "Generate Points") 34 | self.quit = wx.Button(self, -1, "Close") 35 | 36 | self.__set_properties() 37 | self.__do_layout() 38 | 39 | self.Bind(wx.EVT_BUTTON, self.GenCode, self.GenButton) 40 | self.Bind(wx.EVT_BUTTON, self.OnCloseMe, self.quit) 41 | # end wxGlade 42 | 43 | def __set_properties(self): 44 | # begin wxGlade: MyFrame.__set_properties 45 | self.SetTitle("Generate Polar Array of Points") 46 | # end wxGlade 47 | 48 | def __do_layout(self): 49 | # begin wxGlade: MyFrame.__do_layout 50 | grid_sizer_1 = wx.GridSizer(9, 2, 0, 0) 51 | grid_sizer_1.Add(self.x_center_label, 0, wx.ALIGN_RIGHT, 0) 52 | grid_sizer_1.Add(self.x_center_entry, 0, 0, 0) 53 | grid_sizer_1.Add(self.y_center_label, 0, wx.ALIGN_RIGHT, 0) 54 | grid_sizer_1.Add(self.y_center_entry, 0, 0, 0) 55 | grid_sizer_1.Add(self.z_center_label, 0, wx.ALIGN_RIGHT, 0) 56 | grid_sizer_1.Add(self.z_center_entry, 0, 0, 0) 57 | grid_sizer_1.Add(self.number_points_label, 0, wx.ALIGN_RIGHT, 0) 58 | grid_sizer_1.Add(self.no_of_holes_entry, 0, 0, 0) 59 | grid_sizer_1.Add(self.diameter_label, 0, wx.ALIGN_RIGHT, 0) 60 | grid_sizer_1.Add(self.bolt_circle_diameter_entry, 0, 0, 0) 61 | grid_sizer_1.Add(self.angle_label, 0, wx.ALIGN_RIGHT, 0) 62 | grid_sizer_1.Add(self.start_angle_entry, 0, 0, 0) 63 | grid_sizer_1.Add(self.scale_label, 0, wx.ALIGN_RIGHT, 0) 64 | grid_sizer_1.Add(self.Scale_entry, 0, 0, 0) 65 | grid_sizer_1.Add(self.GenButton, 0, 0, 0) 66 | grid_sizer_1.Add(self.quit, 0, 0, 0) 67 | self.SetSizer(grid_sizer_1) 68 | grid_sizer_1.Fit(self) 69 | self.Layout() 70 | # end wxGlade 71 | 72 | def OnCloseMe(self, event): # wxGlade: MyFrame. 73 | print "We're Done!!!!!" 74 | self.Destroy() 75 | 76 | 77 | 78 | 79 | def GenCode(self, event): # wxGlade: MyFrame. 80 | cad.sketch() 81 | sketch = cad.getlastobj() 82 | 83 | x_center=float(self.x_center_entry.GetValue()) 84 | y_center=float(self.y_center_entry.GetValue()) 85 | z_center=float(self.z_center_entry.GetValue()) 86 | no_of_holes=float(self.no_of_holes_entry.GetValue()) 87 | bolt_circle_diameter=float(self.bolt_circle_diameter_entry.GetValue()) 88 | start_angle=float(self.start_angle_entry.GetValue()) 89 | scale=float(self.Scale_entry.GetValue()) 90 | count = 0 91 | anglecount=1 92 | circle_division_angle=(360/no_of_holes) 93 | calc_angle=start_angle 94 | 95 | 96 | 97 | 98 | while (count < no_of_holes): 99 | x1=math.cos(math.radians(calc_angle))*(bolt_circle_diameter/2) 100 | y1=math.sin(math.radians(calc_angle))*(bolt_circle_diameter/2) 101 | x=(x1+x_center)*scale 102 | y=(y1+y_center)*scale 103 | z=(z_center)*scale 104 | 105 | cad.point(x,y,z) 106 | cad.add(sketch,cad.getlastobj()) 107 | data=str('X%.4f Y%.4f Z%.4f '% (x, y, z)+'\n') 108 | 109 | print data 110 | 111 | 112 | 113 | 114 | anglecount=anglecount+1 115 | 116 | calc_angle=calc_angle + circle_division_angle 117 | 118 | count=count+1 119 | cad.reorder(sketch); 120 | return sketch 121 | # end of class MyFrame 122 | 123 | #we don't need the next section of code- it would crash Heeks 124 | '''if __name__ == "__main__": 125 | app = wx.PySimpleApp(0) 126 | wx.InitAllImageHandlers() 127 | frame_1 = MyFrame(None, -1, "") 128 | app.SetTopWindow(frame_1) 129 | frame_1.Show() 130 | app.MainLoop()''' 131 | -------------------------------------------------------------------------------- /examples/polar_array.wxg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Generate Polar Array of Points 8 | 9 | 0 10 | 9 11 | 2 12 | 0 13 | 14 | wxALIGN_RIGHT 15 | 0 16 | 17 | 18 | 1 19 | 20 | 21 | 22 | 23 | 0 24 | 25 | 26 | 27 | 28 | 29 | wxALIGN_RIGHT 30 | 0 31 | 32 | 33 | 1 34 | 35 | 36 | 37 | 38 | 0 39 | 40 | 41 | 42 | 43 | 44 | wxALIGN_RIGHT 45 | 0 46 | 47 | 48 | 1 49 | 50 | 51 | 52 | 53 | 0 54 | 55 | 56 | 57 | 58 | 59 | wxALIGN_RIGHT 60 | 0 61 | 62 | 63 | 1 64 | 65 | 66 | 67 | 68 | 0 69 | 70 | 71 | 72 | 73 | 74 | wxALIGN_RIGHT 75 | 0 76 | 77 | 78 | 1 79 | 80 | 81 | 82 | 83 | 0 84 | 85 | 86 | 87 | 88 | 89 | wxALIGN_RIGHT 90 | 0 91 | 92 | 93 | 1 94 | 95 | 96 | 97 | 98 | 0 99 | 100 | 101 | 102 | 103 | 104 | wxALIGN_RIGHT 105 | 0 106 | 107 | 108 | 1 109 | 110 | 111 | 112 | 113 | 0 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 0 122 | 123 | 124 | 125 | 126 | 127 | 128 | 0 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /examples/polar_array_readme.txt: -------------------------------------------------------------------------------- 1 | #######################################################3 2 | to use my handy dandy polar_array.py wxdialogue: 3 | 4 | import sys 5 | sys.path.insert(0,'/home/dan/HeeksCAD/heekspython/data') 6 | import polar_array 7 | frame_1 = polar_array.MyFrame(None, -1, "") 8 | frame_1.Show() 9 | 10 | 11 | 12 | ################################################# 13 | to make it easier to call the frame- make this function: 14 | 15 | def array(): 16 | frame_1 = polar_array.MyFrame(None, -1, "") 17 | frame_1.Show() 18 | 19 | then just issue this command in the console: 20 | array() 21 | 22 | -------------------------------------------------------------------------------- /examples/revolve_it.py: -------------------------------------------------------------------------------- 1 | #this little script shows how to use the 'revolve' function 2 | #used for revolving sketches around X axis to form a solid 3 | #like a turned part on a lathe 4 | 5 | import HeeksPython as cad 6 | cad.sketch() 7 | sketch = cad.getlastobj() 8 | cad.line(0,1,4,1) 9 | l1= cad.getlastobj() 10 | cad.line(4,1,4,2) 11 | l2= cad.getlastobj() 12 | cad.line(4,2,0,2) 13 | l3= cad.getlastobj() 14 | cad.line(0,2,0,1) 15 | l4= cad.getlastobj() 16 | cad.add(sketch,l1) 17 | cad.add(sketch,l2) 18 | cad.add(sketch,l3) 19 | cad.add(sketch, l4) 20 | cad.reorder(sketch) 21 | cad.revolve(sketch,360) 22 | 23 | -------------------------------------------------------------------------------- /examples/wx_dialog.py: -------------------------------------------------------------------------------- 1 | import wx 2 | mw = wx.GetTopLevelWindows()[0] 3 | mw.SetStatusText("hello!") 4 | menu = mw.GetMenuBar() 5 | mymenu = wx.wxMenu() 6 | mymenu.Append(wx.wxID_ABOUT,"My &Menu","A sample menu item") 7 | menu.Append(mymenu,"Test") 8 | dia = wx.Dialog(None,-1) 9 | pan = wx.Panel(dia,-1) 10 | box = wx.BoxSizer(wx.VERTICAL) 11 | box.Add(wx.StaticText(pan,-1,"Hello World!")) 12 | box.Add(wx.Button(pan,-1,"Press me!")) 13 | pan.SetSizer(box) 14 | dia.Show() 15 | 16 | -------------------------------------------------------------------------------- /src/ConsoleCanvas.cpp: -------------------------------------------------------------------------------- 1 | // ConsoleCanvas.cpp 2 | 3 | #include "stdafx.h" 4 | #include 5 | #include 6 | #include 7 | #include "ConsoleCanvas.h" 8 | 9 | 10 | #ifdef _DEBUG 11 | #undef _DEBUG 12 | #include 13 | #include 14 | #define _DEBUG 15 | #else 16 | #include 17 | #include 18 | #endif 19 | 20 | wxWindow *m_window; 21 | 22 | BEGIN_EVENT_TABLE(CConsoleCanvas, wxScrolledWindow) 23 | EVT_SIZE(CConsoleCanvas::OnSize) 24 | END_EVENT_TABLE() 25 | 26 | CConsoleCanvas::CConsoleCanvas(wxWindow* parent) 27 | : wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 28 | wxHSCROLL | wxVSCROLL | wxNO_FULL_REPAINT_ON_RESIZE) 29 | { 30 | m_textCtrl=0; 31 | m_window = parent; 32 | // DoPythonStuff(this); 33 | // m_textCtrl = new wxTextCtrl( this, 100, _T(""), wxPoint(180,170), wxSize(200,70), wxTE_MULTILINE | wxTE_DONTWRAP); 34 | 35 | // Resize(); 36 | } 37 | 38 | void CConsoleCanvas::InitP() 39 | { 40 | if ( !Init_wxPython() ) 41 | return; 42 | 43 | m_textCtrl = DoPythonStuff(this); 44 | Resize(); 45 | } 46 | 47 | bool CConsoleCanvas::Init_wxPython() 48 | { 49 | // Initialize Python 50 | Py_Initialize(); 51 | PyEval_InitThreads(); 52 | 53 | // Load the wxPython core API. Imports the wx._core_ module and sets a 54 | // local pointer to a function table located there. The pointer is used 55 | // internally by the rest of the API functions. 56 | if ( ! wxPyCoreAPI_IMPORT() ) { 57 | wxLogError(wxT("***** Error importing the wxPython API! *****")); 58 | PyErr_Print(); 59 | Py_Finalize(); 60 | return false; 61 | } 62 | 63 | // Save the current Python thread state and release the 64 | // Global Interpreter Lock. 65 | m_mainTState = wxPyBeginAllowThreads(); 66 | 67 | return true; 68 | } 69 | 70 | #ifdef WIN32 71 | static const char* python_code2 = "\ 72 | import sys\n\ 73 | import wx\n\ 74 | import wx.py\n\ 75 | sys.path.append('.')\n\ 76 | output = wx.PyOnDemandOutputWindow()\n\ 77 | sys.stdin = sys.stderr = output\n\ 78 | app = wx.App()\n\ 79 | def makeWindow(parent,style=wx.TE_MULTILINE | wx.TE_DONTWRAP):\n\ 80 | return wx.py.shell.Shell(parent)\n\ 81 | "; 82 | #else 83 | static const char* python_code2 = "\ 84 | import sys\n\ 85 | import wx\n\ 86 | import wx.py\n\ 87 | sys.path.append('.')\n\ 88 | output = wx.PyOnDemandOutputWindow()\n\ 89 | sys.stdin = sys.stderr = output\n\ 90 | def makeWindow(parent,style=wx.TE_MULTILINE | wx.TE_DONTWRAP):\n\ 91 | return wx.py.shell.Shell(parent)\n\ 92 | "; 93 | #endif 94 | 95 | wxWindow* CConsoleCanvas::DoPythonStuff(wxWindow* parent) 96 | { 97 | // More complex embedded situations will require passing C++ objects to 98 | // Python and/or returning objects from Python to be used in C++. This 99 | // sample shows one way to do it. NOTE: The above code could just have 100 | // easily come from a file, or the whole thing could be in the Python 101 | // module that is imported and manipulated directly in this C++ code. See 102 | // the Python API for more details. 103 | 104 | wxWindow* window = NULL; 105 | PyObject* result; 106 | 107 | // As always, first grab the GIL 108 | wxPyBlock_t blocked = wxPyBeginBlockThreads(); 109 | 110 | // Now make a dictionary to serve as the global namespace when the code is 111 | // executed. Put a reference to the builtins module in it. (Yes, the 112 | // names are supposed to be different, I don't know why...) 113 | PyObject* globals = PyDict_New(); 114 | PyObject* builtins = PyImport_ImportModule("__builtin__"); 115 | PyDict_SetItemString(globals, "__builtins__", builtins); 116 | Py_DECREF(builtins); 117 | 118 | // Execute the code to make the makeWindow function 119 | result = PyRun_String(python_code2, Py_file_input, globals, globals); 120 | // Was there an exception? 121 | if (! result) { 122 | PyErr_Print(); 123 | wxPyEndBlockThreads(blocked); 124 | return NULL; 125 | } 126 | Py_DECREF(result); 127 | 128 | // Now there should be an object named 'makeWindow' in the dictionary that 129 | // we can grab a pointer to: 130 | PyObject* func = PyDict_GetItemString(globals, "makeWindow"); 131 | wxASSERT(PyCallable_Check(func)); 132 | 133 | // Now build an argument tuple and call the Python function. Notice the 134 | // use of another wxPython API to take a wxWindows object and build a 135 | // wxPython object that wraps it. 136 | PyObject* arg = wxPyMake_wxObject(parent, false); 137 | wxASSERT(arg != NULL); 138 | PyObject* tuple = PyTuple_New(1); 139 | PyTuple_SET_ITEM(tuple, 0, arg); 140 | result = PyEval_CallObject(func, tuple); 141 | 142 | // Was there an exception? 143 | if (! result) 144 | { 145 | PyErr_Print(); 146 | } 147 | else { 148 | // Otherwise, get the returned window out of Python-land and 149 | // into C++-ville... 150 | bool success = wxPyConvertSwigPtr(result, (void**)&window, _T("wxWindow")); 151 | wxASSERT_MSG(success, _T("Returned object was not a wxWindow!")); 152 | Py_DECREF(result); 153 | } 154 | 155 | // Release the python objects we still have 156 | Py_DECREF(globals); 157 | Py_DECREF(tuple); 158 | 159 | // Finally, after all Python stuff is done, release the GIL 160 | wxPyEndBlockThreads(blocked); 161 | 162 | return window; 163 | } 164 | 165 | 166 | 167 | 168 | void CConsoleCanvas::OnSize(wxSizeEvent& event) 169 | { 170 | Resize(); 171 | 172 | event.Skip(); 173 | } 174 | 175 | void CConsoleCanvas::Resize() 176 | { 177 | wxSize size = GetClientSize(); 178 | if(m_textCtrl) 179 | m_textCtrl->SetSize(0, 0, size.x, size.y); 180 | } 181 | 182 | void CConsoleCanvas::Clear() 183 | { 184 | // m_textCtrl->Clear(); 185 | } 186 | 187 | -------------------------------------------------------------------------------- /src/ConsoleCanvas.h: -------------------------------------------------------------------------------- 1 | // ConsoleCanvas.h 2 | 3 | #pragma once 4 | 5 | #ifdef _DEBUG 6 | #undef _DEBUG 7 | #include 8 | #define _DEBUG 9 | #else 10 | #include 11 | #endif 12 | 13 | class CConsoleCanvas: public wxScrolledWindow 14 | { 15 | private: 16 | void Resize(); 17 | bool Init_wxPython(); 18 | wxWindow* DoPythonStuff(wxWindow* parent); 19 | 20 | 21 | public: 22 | wxWindow *m_textCtrl; 23 | PyThreadState* m_mainTState; 24 | 25 | CConsoleCanvas(wxWindow* parent); 26 | virtual ~CConsoleCanvas(){} 27 | 28 | void Clear(); 29 | void InitP(); 30 | 31 | void OnSize(wxSizeEvent& event); 32 | 33 | DECLARE_NO_COPY_CLASS(CConsoleCanvas) 34 | DECLARE_EVENT_TABLE() 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /src/DllMain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include "stdafx.h" 3 | 4 | BOOL APIENTRY DllMain( HMODULE hModule, 5 | DWORD ul_reason_for_call, 6 | LPVOID lpReserved 7 | ) 8 | { 9 | switch (ul_reason_for_call) 10 | { 11 | case DLL_PROCESS_ATTACH: 12 | //theApp.OnInitDLL(); 13 | break; 14 | 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | break; 18 | 19 | case DLL_PROCESS_DETACH: 20 | //theApp.OnDestroyDLL(); 21 | break; 22 | } 23 | return TRUE; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/HeeksPython.cpp: -------------------------------------------------------------------------------- 1 | // HeeksPython.cpp 2 | /* 3 | * Copyright (c) 2009, Dan Heeks 4 | * This program is released under the BSD license. See the file COPYING for 5 | * details. 6 | */ 7 | 8 | #include "stdafx.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include "interface/PropertyString.h" 14 | #include "interface/Observer.h" 15 | #include "ConsoleCanvas.h" 16 | #include "PythonConfig.h" 17 | 18 | #ifdef _DEBUG 19 | #undef _DEBUG 20 | #include 21 | #include 22 | #define _DEBUG 23 | #else 24 | #include 25 | #include 26 | #endif 27 | 28 | 29 | CHeeksCADInterface* heeksCAD = NULL; 30 | 31 | CHeeksPythonApp theApp; 32 | 33 | CHeeksPythonApp::CHeeksPythonApp(){ 34 | m_console = NULL; 35 | } 36 | 37 | CHeeksPythonApp::~CHeeksPythonApp(){ 38 | } 39 | 40 | void CHeeksPythonApp::OnInitDLL() 41 | { 42 | } 43 | 44 | void CHeeksPythonApp::OnDestroyDLL() 45 | { 46 | #if !defined WXUSINGDLL 47 | wxUninitialize(); 48 | #endif 49 | 50 | heeksCAD = NULL; 51 | } 52 | 53 | 54 | void OnConsole( wxCommandEvent& event ) 55 | { 56 | wxAuiManager* aui_manager = heeksCAD->GetAuiManager(); 57 | wxAuiPaneInfo& pane_info = aui_manager->GetPane(theApp.m_console); 58 | if(pane_info.IsOk()){ 59 | pane_info.Show(event.IsChecked()); 60 | aui_manager->Update(); 61 | } 62 | } 63 | 64 | void OnUpdateConsole( wxUpdateUIEvent& event ) 65 | { 66 | wxAuiManager* aui_manager = heeksCAD->GetAuiManager(); 67 | event.Check(aui_manager->GetPane(theApp.m_console).IsShown()); 68 | } 69 | 70 | void RunAutoExecPyFile() 71 | { 72 | #if 0 73 | // As always, first grab the GIL 74 | wxPyBlock_t blocked = wxPyBeginBlockThreads(); 75 | 76 | // Now make a dictionary to serve as the global namespace when the code is 77 | // executed. Put a reference to the builtins module in it. (Yes, the 78 | // names are supposed to be different, I don't know why...) 79 | PyObject* globals = PyDict_New(); 80 | PyObject* builtins = PyImport_ImportModule("__builtin__"); 81 | PyDict_SetItemString(globals, "__builtins__", builtins); 82 | Py_DECREF(builtins); 83 | 84 | // Execute the code "import autoexec" 85 | PyObject* result = PyRun_String("import autoexec", Py_file_input, globals, globals); 86 | 87 | // Release the python objects we still have 88 | if (result)Py_DECREF(result); 89 | else PyErr_Print(); 90 | Py_DECREF(globals); 91 | 92 | // Finally, after all Python stuff is done, release the GIL 93 | wxPyEndBlockThreads(blocked); 94 | #else 95 | PyEval_RestoreThread(theApp.m_console->m_mainTState); 96 | PyObject* result = PyImport_ImportModule("autoexec"); 97 | 98 | // Release the python objects we still have 99 | if (result)Py_DECREF(result); 100 | else PyErr_Print(); 101 | 102 | PyEval_SaveThread(); 103 | #endif 104 | } 105 | 106 | void CHeeksPythonApp::OnStartUp(CHeeksCADInterface* h, const wxString& dll_path) 107 | { 108 | m_dll_path = dll_path; 109 | heeksCAD = h; 110 | #if !defined WXUSINGDLL 111 | wxInitialize(); 112 | #endif 113 | 114 | // add menus and toolbars 115 | wxFrame* frame = heeksCAD->GetMainFrame(); 116 | wxAuiManager* aui_manager = heeksCAD->GetAuiManager(); 117 | 118 | 119 | // add the console canvas 120 | m_console = new CConsoleCanvas(frame); 121 | m_console->InitP(); 122 | aui_manager->AddPane(m_console, wxAuiPaneInfo().Name(_T("Console")).Caption(_T("Console")).Bottom().BestSize(wxSize(600, 200))); 123 | 124 | bool console_visible; 125 | PythonConfig config; 126 | 127 | config.Read(_T("ConsoleVisible"), &console_visible); 128 | 129 | aui_manager->GetPane(m_console).Show(console_visible); 130 | 131 | // add tick boxes for them all on the view menu 132 | wxMenu* view_menu = heeksCAD->GetWindowMenu(); 133 | heeksCAD->AddMenuItem(view_menu, _T("Console"), wxBitmap(), OnConsole, OnUpdateConsole,0,true); 134 | heeksCAD->RegisterHideableWindow(m_console); 135 | 136 | // run autoexec.py 137 | RunAutoExecPyFile(); 138 | 139 | heeksCAD->SetDefaultLayout(wxString(_T("layout2|name=ToolBar;caption=General Tools;state=2108156;dir=1;layer=10;row=0;pos=0;prop=100000;bestw=279;besth=31;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=GeomBar;caption=Geometry Tools;state=2108156;dir=1;layer=10;row=0;pos=290;prop=100000;bestw=248;besth=31;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=SolidBar;caption=Solid Tools;state=2108156;dir=1;layer=10;row=1;pos=0;prop=100000;bestw=341;besth=31;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=970;floaty=297;floatw=296;floath=57|name=ViewingBar;caption=Viewing Tools;state=2108156;dir=1;layer=10;row=1;pos=352;prop=100000;bestw=248;besth=31;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=TransformBar;caption=Transformation Tools;state=2108156;dir=1;layer=10;row=1;pos=611;prop=100000;bestw=217;besth=31;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=Graphics;caption=Graphics;state=768;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=800;besth=600;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=Objects;caption=Objects;state=2099196;dir=4;layer=1;row=0;pos=0;prop=100000;bestw=300;besth=400;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=Options;caption=Options;state=2099196;dir=4;layer=1;row=0;pos=1;prop=100000;bestw=300;besth=200;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=Input;caption=Input;state=2099196;dir=4;layer=1;row=0;pos=2;prop=100000;bestw=300;besth=200;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=Properties;caption=Properties;state=2099196;dir=4;layer=1;row=0;pos=3;prop=100000;bestw=300;besth=200;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=MachiningBar;caption=Machining tools;state=2108156;dir=1;layer=10;row=0;pos=549;prop=100000;bestw=279;besth=31;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=Program;caption=Program;state=2099196;dir=3;layer=0;row=0;pos=0;prop=100000;bestw=600;besth=200;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=Output;caption=Output;state=2099196;dir=3;layer=0;row=0;pos=1;prop=100000;bestw=600;besth=200;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|dock_size(5,0,0)=504|dock_size(4,1,0)=234|dock_size(1,10,0)=33|dock_size(1,10,1)=33|dock_size(3,0,0)=219|"))); 140 | } 141 | 142 | 143 | void CHeeksPythonApp::OnNewOrOpen(bool open, int res) 144 | { 145 | 146 | } 147 | 148 | void CHeeksPythonApp::GetOptions(std::list *list){ 149 | 150 | } 151 | 152 | void CHeeksPythonApp::OnFrameDelete() 153 | { 154 | wxAuiManager* aui_manager = heeksCAD->GetAuiManager(); 155 | PythonConfig config; 156 | config.Write(_T("ConsoleVisible"), aui_manager->GetPane(m_console).IsShown()); 157 | 158 | } 159 | 160 | wxString CHeeksPythonApp::GetDllFolder() 161 | { 162 | return m_dll_path; 163 | } 164 | 165 | wxString CHeeksPythonApp::GetResFolder() 166 | { 167 | #if defined(WIN32) || defined(RUNINPLACE) //compile with 'RUNINPLACE=yes make' then skip 'sudo make install' 168 | return m_dll_path; 169 | #else 170 | return (m_dll_path + _T("/../../share/heekscad")); 171 | #endif 172 | } 173 | 174 | 175 | bool MyApp::OnInit(void) 176 | { 177 | return true; 178 | } 179 | 180 | 181 | IMPLEMENT_APP(MyApp) 182 | -------------------------------------------------------------------------------- /src/HeeksPython.h: -------------------------------------------------------------------------------- 1 | // HeeksCNC.h 2 | 3 | // defines global variables and functions 4 | 5 | #include "interface/HeeksCADInterface.h" 6 | 7 | extern CHeeksCADInterface* heeksCAD; 8 | 9 | class Property; 10 | class CConsoleCanvas; 11 | 12 | class CHeeksPythonApp{ 13 | public: 14 | CConsoleCanvas* m_console; 15 | wxString m_dll_path; 16 | 17 | CHeeksPythonApp(); 18 | ~CHeeksPythonApp(); 19 | 20 | void OnStartUp(CHeeksCADInterface* h, const wxString& dll_path); 21 | void OnNewOrOpen(bool open, int res); 22 | void OnInitDLL(); 23 | void OnDestroyDLL(); 24 | void GetOptions(std::list *list); 25 | void OnFrameDelete(); 26 | wxString GetDllFolder(); 27 | wxString GetResFolder(); 28 | }; 29 | 30 | class MyApp : public wxApp 31 | { 32 | 33 | public: 34 | 35 | virtual bool OnInit(void); 36 | 37 | }; 38 | 39 | extern CHeeksPythonApp theApp; 40 | 41 | DECLARE_APP(MyApp) 42 | 43 | -------------------------------------------------------------------------------- /src/HeeksPython.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual C++ Express 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HeeksPython", "HeeksPython.vcproj", "{0F1453E7-EE7A-47D1-B8D6-8ED6F425885C}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {0F1453E7-EE7A-47D1-B8D6-8ED6F425885C}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {0F1453E7-EE7A-47D1-B8D6-8ED6F425885C}.Debug|Win32.Build.0 = Debug|Win32 14 | {0F1453E7-EE7A-47D1-B8D6-8ED6F425885C}.Release|Win32.ActiveCfg = Release|Win32 15 | {0F1453E7-EE7A-47D1-B8D6-8ED6F425885C}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /src/HeeksPython.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 25 | 28 | 31 | 34 | 37 | 40 | 51 | 54 | 57 | 60 | 68 | 71 | 74 | 77 | 80 | 83 | 86 | 89 | 90 | 98 | 101 | 104 | 107 | 110 | 113 | 124 | 127 | 130 | 133 | 143 | 146 | 149 | 152 | 155 | 158 | 161 | 164 | 165 | 166 | 167 | 168 | 169 | 174 | 177 | 178 | 181 | 182 | 185 | 186 | 189 | 190 | 193 | 194 | 195 | 200 | 203 | 204 | 207 | 208 | 211 | 212 | 215 | 216 | 219 | 220 | 223 | 224 | 227 | 228 | 229 | 234 | 235 | 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /src/Interface.h: -------------------------------------------------------------------------------- 1 | // declares all the exported functions for HeeksPython 2 | 3 | class Property; 4 | class CHeeksCADInterface; 5 | 6 | extern "C"{ 7 | #ifdef WIN32 8 | #define HEEKSPYTHON_EXPORT __declspec( dllexport ) __cdecl 9 | #else 10 | #define HEEKSPYTHON_EXPORT 11 | #endif 12 | 13 | void HEEKSPYTHON_EXPORT OnStartUp(CHeeksCADInterface* h, const wxString& dll_path); 14 | void HEEKSPYTHON_EXPORT OnNewOrOpen(int open, int res); 15 | void HEEKSPYTHON_EXPORT GetOptions(void(*callbackfunc)(Property*)); 16 | void HEEKSPYTHON_EXPORT OnFrameDelete(); 17 | } 18 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | WXCFLAGS=$(shell wx-config --cflags) 2 | WXLDFLAGS=$(shell wx-config --libs --gl-libs) 3 | CC = g++ 4 | PREFIX=/usr/local 5 | DATADIR=$(PREFIX)/share 6 | HEEKSPYTHONDIR=$(DATADIR)/heekspython 7 | mkdir_p= mkdir -p 8 | PYTHONDIR = `python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(plat_specific=1, standard_lib=0, prefix='$(PREFIX)')"` 9 | 10 | # dan heeks uncomments the next line to make it work for him on his Inspiron 530 11 | #WXCFLAGS=-I/usr/lib/wx/include/gtk2-unicode-release-2.8 -I/usr/include/wx-2.8 12 | 13 | #check the environment variable HEEKSCADPATH. If it's not set, print a message and assume ../.. 14 | ifeq ($(strip $(HEEKSCADPATH)),) 15 | heekspathmessage = message 16 | HEEKSCADPATH = ../.. 17 | else 18 | heekspathmessage = 19 | endif 20 | 21 | 22 | ifeq ($(strip $(PYTHONCFLAGS)),) 23 | PYTHONCFLAGS=$(shell python-config --includes) 24 | endif 25 | 26 | ifneq ($(strip $(CASROOT)),) 27 | CASINCPATH=$(CASROOT) 28 | else 29 | CASINCPATH=/usr/include/opencascade 30 | endif 31 | 32 | 33 | 34 | CCFLAGS=-Wall -fPIC -g -I ./ $(WXCFLAGS) \ 35 | -I$(HEEKSCADPATH) -I/usr/include/GL -I$(PYTHONCFLAGS) -I$(CASROOT) \ 36 | -D__WXGTK__ -DHEEKSCNC -DUNICODE -DWXUSINGDLL -DWXUSINGDLL 37 | 38 | #WX_LIB_LETTER=d 39 | WX_LIB_LETTER=u 40 | 41 | ifeq ($(strip $(PYTHONLIBS)),) 42 | PYTHONLIBS=$(shell python-config --ldflags) 43 | endif 44 | 45 | OBJECTS=ConsoleCanvas.o HeeksPython.o PythonInterface.o ToolImage.o 46 | 47 | SHARED_LIBRARY=../HeeksPython.so 48 | 49 | $(SHARED_LIBRARY): $(heekspathmessage) $(OBJECTS) 50 | $(CC) -shared -fPIC -Wl,-soname,HeeksPython.so $(PYTHONLIBS) \ 51 | -Xlinker -export-dynamic -o $(SHARED_LIBRARY) $(OBJECTS) \ 52 | -lstdc++ -lGLU $(WXLDFLAGS) 53 | 54 | #print a message if HEEKSCADPATH is not set 55 | #use escape sequences for colors. Z gets translated to \033 56 | message: 57 | @echo Z[1mEnvironment variable HEEKSCADPATH not set. Assuming Z[32m../..Z[37mZ[0m | tr Z '\033' 58 | 59 | ConsoleCanvas.o: $(HEEKSCADPATH)/interface/ToolImage.h 60 | $(CC) -c ConsoleCanvas.cpp $(CCFLAGS) -o $@ 61 | HeeksPython.o: $(HEEKSCADPATH)/interface/ToolImage.h 62 | $(CC) -c HeeksPython.cpp $(CCFLAGS) -o $@ 63 | PythonInterface.o: $(HEEKSCADPATH)/interface/ToolImage.h 64 | $(CC) -c PythonInterface.cpp $(CCFLAGS) -o $@ 65 | 66 | ToolImage.o: ${HEEKSCADPATH}/interface/ToolImage.cpp \ 67 | ${HEEKSCADPATH}/interface/ToolImage.h 68 | $(CC) -c ${HEEKSCADPATH}/interface/ToolImage.cpp ${CCFLAGS} -o $@ 69 | 70 | clean: 71 | -rm -f $(SHARED_LIBRARY) $(OBJECTS) 72 | 73 | install:$(SHARED_LIBRARY) 74 | strip $^ 75 | chmod 644 $^ 76 | install $^ $(DESTDIR)$(PYTHONDIR) 77 | test -z "$(HEEKSPYTHONDIR)/heeksscripts" || $(mkdir_p) "$(HEEKSPYTHONDIR)/heeksscripts" 78 | cp ../autoexec.py "$(PYTHONDIR)" 79 | test -z "$(DESTDIR)$(HEEKSPYTHONDIR)/bitmaps" || $(mkdir_p) "$(DESTDIR)$(HEEKSPYTHONDIR)/bitmaps" 80 | cp ../bitmaps/*.png $(DESTDIR)$(HEEKSPYTHONDIR)/bitmaps/ 81 | cp ../examples/*.py $(DESTDIR)$(HEEKSPYTHONDIR)/heeksscripts/ 82 | 83 | uninstall: 84 | -rm -rf $(DESTDIR)$(HEEKSPYTHONDIR) 85 | -rm $(PYTHONDIR)/autoexec.py 86 | -rm $(DESTDIR)$(PYTHONDIR)/HeeksPython.so 87 | -------------------------------------------------------------------------------- /src/PythonConfig.h: -------------------------------------------------------------------------------- 1 | // PythonConfig.h 2 | #include 3 | #include 4 | #include 5 | 6 | class PythonConfig: public wxConfig 7 | { 8 | public: 9 | PythonConfig():wxConfig(_T("HeeksPython")){} 10 | ~PythonConfig(){} 11 | }; -------------------------------------------------------------------------------- /src/PythonInterface.cpp: -------------------------------------------------------------------------------- 1 | // HeeksPython.cpp 2 | #include "stdafx.h" 3 | 4 | #ifdef WIN32 5 | #include "windows.h" 6 | #endif 7 | 8 | #include "PythonInterface.h" 9 | #include "Interface.h" 10 | #include "interface/HeeksCADInterface.h" 11 | #include "interface/HeeksObj.h" 12 | #include "interface/ToolImage.h" 13 | #include "ConsoleCanvas.h" 14 | #include "PythonConfig.h" 15 | 16 | 17 | 18 | //#include "src/PointDrawing.h" 19 | #include 20 | 21 | #ifdef _DEBUG 22 | #undef _DEBUG 23 | #include 24 | #include 25 | #define _DEBUG 26 | #else 27 | #include 28 | #include 29 | #endif 30 | 31 | 32 | extern CHeeksCADInterface *heeksCAD; 33 | extern CHeeksPythonApp theApp; 34 | extern wxWindow* m_window; 35 | 36 | 37 | class Property; 38 | 39 | void OnStartUp(CHeeksCADInterface* h, const wxString& dll_path) 40 | { 41 | theApp.OnStartUp(h, dll_path); 42 | } 43 | 44 | void OnNewOrOpen(int open, int res) 45 | { 46 | theApp.OnNewOrOpen(open != 0, res); 47 | } 48 | 49 | void GetOptions(void(*callbackfunc)(Property*)) 50 | { 51 | std::list list; 52 | theApp.GetOptions(&list); 53 | for(std::list::iterator It = list.begin(); It != list.end(); It++){ 54 | Property* p = *It; 55 | (*callbackfunc)(p); 56 | } 57 | } 58 | 59 | void OnFrameDelete() 60 | { 61 | theApp.OnFrameDelete(); 62 | } 63 | 64 | HeeksObj* lastobj; 65 | 66 | static PyObject* NewPoint(PyObject* self, PyObject* args) 67 | { 68 | //from PointDrawing.cpp: 69 | //temp_object = new HPoint(end.m_point, &wxGetApp().current_color); 70 | //if(temp_object)temp_object_in_list.push_back(temp_object); 71 | 72 | const double p[3]={0,0,0}; 73 | if (!PyArg_ParseTuple(args, "ddd", &p[0],&p[1],&p[2])) return NULL; 74 | 75 | lastobj = heeksCAD->NewPoint(p); 76 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 77 | 78 | 79 | PyObject *pValue = Py_None; 80 | Py_INCREF(pValue); 81 | return pValue; 82 | } 83 | 84 | 85 | 86 | 87 | static PyObject* NewLine(PyObject* self, PyObject* args) 88 | { 89 | double s[3]={0,0,0}; 90 | double e[3]={0,0,0}; 91 | if (!PyArg_ParseTuple(args, "dddd", &s[0],&s[1],&e[0],&e[1])) return NULL; 92 | 93 | lastobj = heeksCAD->NewLine(s,e); 94 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 95 | 96 | 97 | PyObject *pValue = Py_None; 98 | Py_INCREF(pValue); 99 | return pValue; 100 | } 101 | 102 | static PyObject* NewLine3d(PyObject* self, PyObject* args) 103 | { 104 | double s[3]={0,0,0}; 105 | double e[3]={0,0,0}; 106 | if (!PyArg_ParseTuple(args, "dddddd", &s[0],&s[1],&s[2],&e[0],&e[1],&e[2])) return NULL; 107 | 108 | lastobj = heeksCAD->NewLine(s,e); 109 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 110 | 111 | 112 | PyObject *pValue = Py_None; 113 | Py_INCREF(pValue); 114 | return pValue; 115 | } 116 | 117 | static PyObject* NewCircle(PyObject* self, PyObject* args) 118 | { 119 | double c[3]={0,0,0}; 120 | double r=0; 121 | if (!PyArg_ParseTuple(args, "ddd", &c[0],&c[1],&r)) return NULL; 122 | 123 | lastobj = heeksCAD->NewCircle(c,r); 124 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 125 | 126 | 127 | PyObject *pValue = Py_None; 128 | Py_INCREF(pValue); 129 | return pValue; 130 | } 131 | 132 | static PyObject* NewArc(PyObject* self, PyObject* args) 133 | { 134 | double c[3]; 135 | double u[3]; 136 | double r,s,e; 137 | 138 | if (!PyArg_ParseTuple( args, "ddddddddd", &c[0],&c[1],&c[2],&r,&s,&e,&u[0],&u[1],&u[2])) return NULL; 139 | 140 | lastobj = heeksCAD->NewArc(c,u,r,s,e); 141 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 142 | 143 | 144 | PyObject *pValue = Py_None; 145 | Py_INCREF(pValue); 146 | return pValue; 147 | } 148 | 149 | //added by DF- arc2 function using start point, end point,center point, uv 150 | //NewArc(const double* s, const double* e, const double* c, const double* up) 151 | static PyObject* NewArc2(PyObject* self, PyObject* args) 152 | { 153 | double c[3]; 154 | double u[3]; 155 | double s[3]; 156 | double e[3]; 157 | 158 | if (!PyArg_ParseTuple( args, "dddddddddddd",&s[0],&s[1],&s[2],&e[0],&e[1],&e[2],&c[0],&c[1],&c[2],&u[0],&u[1],&u[2])) return NULL; 159 | 160 | lastobj = heeksCAD->NewArc(s,e,c,u); 161 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 162 | 163 | 164 | PyObject *pValue = Py_None; 165 | Py_INCREF(pValue); 166 | return pValue; 167 | } 168 | 169 | 170 | 171 | static PyObject* NewCuboid(PyObject* self, PyObject* args) 172 | { 173 | double c[3]={0,0,0}; 174 | double x=0; 175 | double y=0; 176 | double z=0; 177 | if (!PyArg_ParseTuple(args, "dddddd", &c[0],&c[1],&c[2],&x,&y,&z)) return NULL; 178 | lastobj = heeksCAD->NewCuboid(c,x,y,z); 179 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 180 | 181 | 182 | PyObject *pValue = Py_None; 183 | Py_INCREF(pValue); 184 | return pValue; 185 | } 186 | 187 | 188 | static PyObject* NewCylinder(PyObject* self, PyObject* args) 189 | { 190 | double c[3]={0,0,0}; 191 | double r=0; 192 | double h=0; 193 | if (!PyArg_ParseTuple(args, "ddddd", &c[0],&c[1],&c[2],&r,&h)) return NULL; 194 | lastobj = heeksCAD->NewCylinder(c,r,h); 195 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 196 | 197 | 198 | PyObject *pValue = Py_None; 199 | Py_INCREF(pValue); 200 | return pValue; 201 | } 202 | 203 | static PyObject* NewCylinderEx(PyObject* self, PyObject* args) 204 | { 205 | double pos[3]={0,0,0}; 206 | double dir[3]={0,0,0}; 207 | double r=0; 208 | double h=0; 209 | if (!PyArg_ParseTuple(args, "dddddddd", &pos[0],&pos[1],&pos[2],&dir[0],&dir[1],&dir[2],&r,&h)) return NULL; 210 | lastobj = heeksCAD->NewCylinderEx(pos,dir,r,h); 211 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 212 | 213 | 214 | PyObject *pValue = Py_None; 215 | Py_INCREF(pValue); 216 | return pValue; 217 | } 218 | 219 | static PyObject* NewCone(PyObject* self, PyObject* args) 220 | { 221 | double c[3]={0,0,0}; 222 | double r1=0; 223 | double r2=0; 224 | double h=0; 225 | if (!PyArg_ParseTuple(args, "dddddd", &c[0],&c[1],&c[2],&r1,&r2,&h)) return NULL; 226 | lastobj = heeksCAD->NewCone(c,r1,r2,h); 227 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 228 | 229 | 230 | PyObject *pValue = Py_None; 231 | Py_INCREF(pValue); 232 | return pValue; 233 | } 234 | 235 | static PyObject* NewSphere(PyObject* self, PyObject* args) 236 | { 237 | double c[3]={0,0,0}; 238 | double r=0; 239 | if (!PyArg_ParseTuple(args, "dddd", &c[0],&c[1],&c[2],&r)) return NULL; 240 | lastobj = heeksCAD->NewSphere(c,r); 241 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 242 | 243 | PyObject *pValue = Py_None; 244 | Py_INCREF(pValue); 245 | return pValue; 246 | } 247 | 248 | 249 | 250 | 251 | 252 | 253 | static PyObject* NewGroup(PyObject* self, PyObject* args) 254 | { 255 | lastobj = heeksCAD->NewGroup(); 256 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 257 | 258 | 259 | PyObject *pValue = Py_None; 260 | Py_INCREF(pValue); 261 | return pValue; 262 | } 263 | 264 | static PyObject* Reorder(PyObject* self, PyObject* args) 265 | { 266 | int oid; 267 | HeeksObj* obj; 268 | 269 | if (!PyArg_ParseTuple( args, "i", &oid)) return NULL; 270 | 271 | // Convert the PyCObject to a void pointer: 272 | obj = (HeeksObj*)heeksCAD->GetIDObject(oid>>16,oid&0xFFFF); 273 | heeksCAD->ReOrderSketch(obj,SketchOrderTypeCloseCW); 274 | 275 | 276 | PyObject *pValue = Py_None; 277 | Py_INCREF(pValue); 278 | return pValue; 279 | } 280 | 281 | static PyObject* ViewExtents(PyObject* self, PyObject* args) 282 | { 283 | 284 | heeksCAD->ViewExtents(false); 285 | 286 | 287 | PyObject *pValue = Py_None; 288 | Py_INCREF(pValue); 289 | return pValue; 290 | } 291 | 292 | static PyObject* XYZview(PyObject* self, PyObject* args) 293 | { 294 | 295 | heeksCAD->XYZView(true); 296 | 297 | 298 | PyObject *pValue = Py_None; 299 | Py_INCREF(pValue); 300 | return pValue; 301 | } 302 | 303 | 304 | static PyObject* NewSketch(PyObject* self, PyObject* args) 305 | { 306 | lastobj = heeksCAD->NewSketch(); 307 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 308 | 309 | 310 | PyObject *pValue = Py_None; 311 | Py_INCREF(pValue); 312 | return pValue; 313 | } 314 | 315 | static PyObject* WxHandle(PyObject* self, PyObject* args) 316 | { 317 | 318 | PyObject *pValue = wxPyMake_wxObject(m_window, false); 319 | Py_INCREF(pValue); 320 | return pValue; 321 | } 322 | 323 | static PyObject* GetLastObj(PyObject* self, PyObject* args) 324 | { 325 | //return PyInt_FromLong(lastobj->m_id | lastobj->GetIDGroupType()<<16); 326 | return PyInt_FromLong(lastobj->m_id | lastobj->GetIDGroupType()<<16); 327 | } 328 | 329 | static PyObject* Rotate(PyObject* self, PyObject* args) 330 | { 331 | HeeksObj *obj; 332 | int pyobj = 0; 333 | double p[3]; 334 | double u[3]; 335 | double r; 336 | 337 | if (!PyArg_ParseTuple( args, "iddddddd", &pyobj,&p[0],&p[1],&p[2],&u[0],&u[1],&u[2],&r)) return NULL; 338 | 339 | // Convert the PyCObject to a void pointer: 340 | obj = (HeeksObj*)heeksCAD->GetIDObject(pyobj>>16,pyobj&0xFFFF); 341 | heeksCAD->RotateObject(obj,p,u,r); 342 | 343 | 344 | PyObject *pValue = Py_None; 345 | Py_INCREF(pValue); 346 | return pValue; 347 | } 348 | 349 | 350 | static PyObject* Extrude(PyObject* self, PyObject* args) 351 | { 352 | HeeksObj *obj; 353 | int pyobj = 0; 354 | double h; 355 | 356 | if (!PyArg_ParseTuple( args, "id", &pyobj,&h)) return NULL; 357 | 358 | // Convert the PyCObject to a void pointer: 359 | 360 | obj = (HeeksObj*)heeksCAD->GetIDObject(pyobj>>16,pyobj&0xFFFF); 361 | lastobj = heeksCAD->ExtrudeSketch(obj,h,true); 362 | 363 | 364 | 365 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 366 | 367 | 368 | PyObject *pValue = Py_None; 369 | Py_INCREF(pValue); 370 | return pValue; 371 | } 372 | 373 | 374 | static PyObject* Revolve(PyObject* self, PyObject* args) 375 | { 376 | HeeksObj *obj; 377 | int pyobj = 0; 378 | double a; 379 | 380 | if (!PyArg_ParseTuple( args, "id", &pyobj,&a)) return NULL; 381 | 382 | // Convert the PyCObject to a void pointer: 383 | obj = (HeeksObj*)heeksCAD->GetIDObject(pyobj>>16,pyobj&0xFFFF); 384 | lastobj = heeksCAD->RevolveSketch(obj,a,true); 385 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 386 | 387 | 388 | PyObject *pValue = Py_None; 389 | Py_INCREF(pValue); 390 | return pValue; 391 | } 392 | 393 | 394 | 395 | static PyObject* Translate(PyObject* self, PyObject* args) 396 | { 397 | HeeksObj *obj; 398 | int pyobj = 0; 399 | double p[3]; 400 | 401 | if (!PyArg_ParseTuple( args, "iddd", &pyobj,&p[0],&p[1],&p[2])) return NULL; 402 | 403 | // Convert the PyCObject to a void pointer: 404 | obj = (HeeksObj*)heeksCAD->GetIDObject(pyobj>>16,pyobj&0xFFFF); 405 | heeksCAD->TranslateObject(obj,p); 406 | 407 | 408 | 409 | PyObject *pValue = Py_None; 410 | Py_INCREF(pValue); 411 | return pValue; 412 | } 413 | 414 | static PyObject* Scale(PyObject* self, PyObject* args) 415 | { 416 | HeeksObj *obj; 417 | int pyobj = 0; 418 | double p[3]; 419 | double scale = 1.0; 420 | 421 | if (!PyArg_ParseTuple( args, "idddd", &pyobj,&p[0],&p[1],&p[2],&scale)) return NULL; 422 | 423 | // Convert the PyCObject to a void pointer: 424 | obj = (HeeksObj*)heeksCAD->GetIDObject(pyobj>>16,pyobj&0xFFFF); 425 | heeksCAD->ScaleObject(obj,p,scale); 426 | 427 | 428 | 429 | PyObject *pValue = Py_None; 430 | Py_INCREF(pValue); 431 | return pValue; 432 | } 433 | 434 | static PyObject* Add(PyObject* self, PyObject* args) 435 | { 436 | HeeksObj *group, *obj; 437 | int pygroup,pyobj; 438 | 439 | if (!PyArg_ParseTuple( args, "ii", &pygroup, &pyobj)) return NULL; 440 | 441 | // Convert the PyCObject to a void pointer: 442 | obj = (HeeksObj*)heeksCAD->GetIDObject(pyobj>>16,pyobj&0xFFFF); 443 | group = (HeeksObj*)heeksCAD->GetIDObject(pygroup>>16,pygroup&0xFFFF); 444 | obj->Owner()->Remove(obj); 445 | group->Add(obj,NULL); 446 | 447 | 448 | 449 | PyObject *pValue = Py_None; 450 | Py_INCREF(pValue); 451 | return pValue; 452 | } 453 | 454 | static PyObject* Fuse(PyObject* self, PyObject* args) 455 | { 456 | int pyobj1,pyobj2; 457 | 458 | if (!PyArg_ParseTuple( args, "ii", &pyobj1, &pyobj2)) return NULL; 459 | 460 | // Convert the PyCObject to a void pointer: 461 | std::list list; 462 | list.push_back((HeeksObj*)heeksCAD->GetIDObject(pyobj1>>16,pyobj1&0xFFFF)); 463 | list.push_back((HeeksObj*)heeksCAD->GetIDObject(pyobj2>>16,pyobj2&0xFFFF)); 464 | lastobj = heeksCAD->Fuse(list); 465 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 466 | 467 | 468 | 469 | PyObject *pValue = Py_None; 470 | Py_INCREF(pValue); 471 | return pValue; 472 | } 473 | 474 | 475 | static PyObject* Common(PyObject* self, PyObject* args) 476 | { 477 | int pyobj1,pyobj2; 478 | 479 | if (!PyArg_ParseTuple( args, "ii", &pyobj1, &pyobj2)) return NULL; 480 | 481 | // Convert the PyCObject to a void pointer: 482 | std::list list; 483 | list.push_back((HeeksObj*)heeksCAD->GetIDObject(pyobj1>>16,pyobj1&0xFFFF)); 484 | list.push_back((HeeksObj*)heeksCAD->GetIDObject(pyobj2>>16,pyobj2&0xFFFF)); 485 | lastobj = heeksCAD->Common(list); 486 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 487 | 488 | 489 | 490 | PyObject *pValue = Py_None; 491 | Py_INCREF(pValue); 492 | return pValue; 493 | } 494 | 495 | 496 | 497 | static PyObject* LineArc2Wire(PyObject* self, PyObject* args) 498 | { 499 | int pyobj; 500 | 501 | if (!PyArg_ParseTuple( args, "i", &pyobj)) return NULL; 502 | 503 | // Convert the PyCObject to a void pointer: 504 | std::list list; 505 | list.push_back((HeeksObj*)heeksCAD->GetIDObject(pyobj>>16,pyobj&0xFFFF)); 506 | 507 | lastobj = heeksCAD->LineArcsToWire(list); 508 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 509 | 510 | 511 | 512 | PyObject *pValue = Py_None; 513 | Py_INCREF(pValue); 514 | return pValue; 515 | } 516 | 517 | 518 | static PyObject* Cut(PyObject* self, PyObject* args) 519 | { 520 | int pyobj1,pyobj2; 521 | 522 | if (!PyArg_ParseTuple( args, "ii", &pyobj1, &pyobj2)) return NULL; 523 | 524 | // Convert the PyCObject to a void pointer: 525 | std::list list; 526 | list.push_back((HeeksObj*)heeksCAD->GetIDObject(pyobj1>>16,pyobj1&0xFFFF)); 527 | list.push_back((HeeksObj*)heeksCAD->GetIDObject(pyobj2>>16,pyobj2&0xFFFF)); 528 | lastobj = heeksCAD->Cut(list); 529 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 530 | //heeksCAD->Cut(list); 531 | 532 | PyObject *pValue = Py_None; 533 | Py_INCREF(pValue); 534 | return pValue; 535 | } 536 | 537 | static PyObject* NewCreateUndoPoint(PyObject* self, PyObject* args) 538 | { 539 | 540 | 541 | heeksCAD->CreateUndoPoint(); 542 | 543 | Py_INCREF(Py_None); 544 | return Py_None; 545 | 546 | 547 | } 548 | 549 | static PyObject* NewChanged(PyObject* self, PyObject* args) 550 | { 551 | 552 | 553 | heeksCAD->Changed(); 554 | 555 | Py_INCREF(Py_None); 556 | return Py_None; 557 | 558 | 559 | } 560 | 561 | 562 | static PyObject* Pipe(PyObject* self, PyObject* args) 563 | { 564 | int pyobj1,pyobj2; 565 | HeeksObj *wire,*profile; 566 | 567 | if (!PyArg_ParseTuple( args, "ii", &pyobj1, &pyobj2)) return NULL; 568 | 569 | // Convert the PyCObject to a void pointer: 570 | wire = (HeeksObj*)heeksCAD->GetIDObject(pyobj1>>16,pyobj1&0xFFFF); 571 | profile = (HeeksObj*)heeksCAD->GetIDObject(pyobj2>>16,pyobj2&0xFFFF); 572 | lastobj = heeksCAD->MakePipe(wire,profile); 573 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 574 | 575 | 576 | 577 | PyObject *pValue = Py_None; 578 | Py_INCREF(pValue); 579 | return pValue; 580 | } 581 | 582 | 583 | static PyObject* SetColor(PyObject* self, PyObject* args) 584 | { 585 | int r,g,b; 586 | 587 | if (!PyArg_ParseTuple( args, "iii", &r,&b,&g)) return NULL; 588 | 589 | heeksCAD->SetColor(r,b,g); 590 | 591 | PyObject *pValue = Py_None; 592 | Py_INCREF(pValue); 593 | return pValue; 594 | } 595 | 596 | static PyObject* Fillet2d(PyObject* self, PyObject* args) 597 | { //the lines definitely need to be trimmed first 598 | HeeksObj *obj; 599 | int pyobj = 0; 600 | double p[3]; 601 | double r; 602 | 603 | if (!PyArg_ParseTuple( args, "idddd", &pyobj,&p[0], &p[1], &p[2], &r)) return NULL; 604 | obj = (HeeksObj*)heeksCAD->GetIDObject(pyobj>>16,pyobj&0xFFFF); 605 | heeksCAD->FilletSketchAtPoint(obj,p,r); 606 | 607 | 608 | PyObject *pValue = Py_None; 609 | Py_INCREF(pValue); 610 | return pValue; 611 | 612 | } 613 | 614 | static PyObject* NewCoordinateSystem(PyObject* self, PyObject* args) 615 | { 616 | double o[3]={0,0,0}; 617 | double x[3]={1, 0, 0}; 618 | double y[3]={0, 1, 0}; 619 | if (!PyArg_ParseTuple(args, "ddddddddd", &o[0],&o[1],&o[2],&x[0],&x[1],&x[2],&y[0],&y[1],&y[2])) return NULL; 620 | lastobj = heeksCAD->NewCoordinateSystem(o,x,y); 621 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 622 | 623 | 624 | PyObject *pValue = Py_None; 625 | Py_INCREF(pValue); 626 | return pValue; 627 | } 628 | 629 | 630 | static PyObject* PickPoint(PyObject* self, PyObject* args) 631 | { //get point in space, so to speak- not necessarily on an actual object 632 | //will return a point that is clicked in the graphicscanvas 633 | //the little spinner wheel will rotate until this is completed 634 | double pt1[3]={0,0,0}; 635 | double px = 0;double py=0;double pz=0; 636 | heeksCAD->PickPosition(_("Pick something, please!"),pt1); 637 | 638 | px= pt1[0];py= pt1[1]; pz= pt1[2]; 639 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 640 | PyObject *pTuple = PyTuple_New(3); 641 | { 642 | PyObject *pValue = PyFloat_FromDouble(px); 643 | if (!pValue){ 644 | Py_DECREF(pTuple);return NULL; 645 | } 646 | PyTuple_SetItem(pTuple, 0, pValue); 647 | } 648 | { 649 | PyObject *pValue = PyFloat_FromDouble(py); 650 | if (!pValue){ 651 | Py_DECREF(pTuple);return NULL; 652 | } 653 | PyTuple_SetItem(pTuple, 1, pValue); 654 | } 655 | { 656 | PyObject *pValue = PyFloat_FromDouble(pz); 657 | if (!pValue){ 658 | Py_DECREF(pTuple);return NULL; 659 | } 660 | PyTuple_SetItem(pTuple, 2, pValue); 661 | } 662 | 663 | Py_INCREF(pTuple); 664 | return pTuple; 665 | } 666 | 667 | 668 | 669 | static PyObject* GetClickedPos(PyObject* self, PyObject* args) 670 | { 671 | //will return last double clicked point in graphicscanvas 672 | //need to double click on a point object 673 | double pt1[3]={0,0,0}; 674 | double px = 0;double py=0;double pz=0; 675 | heeksCAD->GetLastClickPosition(pt1); 676 | 677 | px= pt1[0];py= pt1[1]; pz= pt1[2]; 678 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 679 | PyObject *pTuple = PyTuple_New(3); 680 | { 681 | PyObject *pValue = PyFloat_FromDouble(px); 682 | if (!pValue){ 683 | Py_DECREF(pTuple);return NULL; 684 | } 685 | PyTuple_SetItem(pTuple, 0, pValue); 686 | } 687 | { 688 | PyObject *pValue = PyFloat_FromDouble(py); 689 | if (!pValue){ 690 | Py_DECREF(pTuple);return NULL; 691 | } 692 | PyTuple_SetItem(pTuple, 1, pValue); 693 | } 694 | { 695 | PyObject *pValue = PyFloat_FromDouble(pz); 696 | if (!pValue){ 697 | Py_DECREF(pTuple);return NULL; 698 | } 699 | PyTuple_SetItem(pTuple, 2, pValue); 700 | } 701 | 702 | Py_INCREF(pTuple); 703 | return pTuple; 704 | } 705 | 706 | static PyObject* GetPoint3d(PyObject* self, PyObject* args) 707 | { 708 | //will return coordinates x,y,z of actual point object in graphicscanvas 709 | //need to pick point before calling function 710 | HeeksObj *obj; 711 | double pt1[3]={0,0,0}; 712 | double px = 0;double py=0;double pz=0; 713 | obj= heeksCAD->GetFirstMarkedObject(); 714 | if (!obj) return NULL; 715 | heeksCAD->VertexGetPoint(obj,pt1); 716 | px= pt1[0];py= pt1[1]; pz= pt1[2]; 717 | heeksCAD->GetMainObject()->Add(lastobj,NULL); 718 | PyObject *pTuple = PyTuple_New(3); 719 | { 720 | PyObject *pValue = PyFloat_FromDouble(px); 721 | if (!pValue){ 722 | Py_DECREF(pTuple);return NULL; 723 | } 724 | PyTuple_SetItem(pTuple, 0, pValue); 725 | } 726 | { 727 | PyObject *pValue = PyFloat_FromDouble(py); 728 | if (!pValue){ 729 | Py_DECREF(pTuple);return NULL; 730 | } 731 | PyTuple_SetItem(pTuple, 1, pValue); 732 | } 733 | { 734 | PyObject *pValue = PyFloat_FromDouble(pz); 735 | if (!pValue){ 736 | Py_DECREF(pTuple);return NULL; 737 | } 738 | PyTuple_SetItem(pTuple, 2, pValue); 739 | } 740 | 741 | Py_INCREF(pTuple); 742 | return pTuple; 743 | } 744 | 745 | 746 | inline wxString _U(const char String[] = "") 747 | { 748 | return wxString(String, wxConvUTF8); 749 | } 750 | 751 | 752 | static PyObject* NewText(PyObject* self, PyObject* args) 753 | { 754 | 755 | const char *text; //the text that gets input in python 756 | 757 | if (!PyArg_ParseTuple(args, "s", &text)) return NULL; 758 | 759 | heeksCAD->AddText(_U(text)); 760 | 761 | PyObject *pValue = Py_None; 762 | Py_INCREF(pValue); 763 | return pValue; 764 | 765 | } 766 | 767 | static PyObject* AddMenu(PyObject* self, PyObject* args) 768 | { 769 | const char *menu_name; 770 | if (!PyArg_ParseTuple(args, "s", &menu_name)) return NULL; 771 | 772 | wxFrame* frame = heeksCAD->GetMainFrame(); 773 | wxMenu *newMenu = new wxMenu; 774 | frame->GetMenuBar()->Append(newMenu, _U(menu_name)); 775 | 776 | return PyInt_FromSize_t((size_t)newMenu);//size_t instead of unsigned int for 64 bit gcc 777 | } 778 | 779 | static PyObject* GetFrameHwnd(PyObject* self, PyObject* args) 780 | { 781 | wxFrame* frame = heeksCAD->GetMainFrame(); 782 | return PyInt_FromSize_t((size_t)(frame->GetHandle()));//size_t instead of unsigned int for 64 bit gcc 783 | } 784 | 785 | static PyObject* GetFrameId(PyObject* self, PyObject* args) 786 | { 787 | wxFrame* frame = heeksCAD->GetMainFrame(); 788 | return PyInt_FromLong(frame->GetId()); 789 | } 790 | 791 | std::map menu_item_map; 792 | 793 | void OnMenuItem(wxCommandEvent &event) 794 | { 795 | std::map::iterator FindIt = menu_item_map.find(event.GetId()); 796 | if(FindIt != menu_item_map.end()) 797 | { 798 | // Execute the python code 799 | PyObject* python_callback = FindIt->second; 800 | 801 | PyEval_RestoreThread(theApp.m_console->m_mainTState); 802 | PyObject* result = PyEval_CallFunction(python_callback, "()"); 803 | 804 | // Release the python objects we still have 805 | if (result)Py_DECREF(result); 806 | else PyErr_Print(); 807 | 808 | PyEval_SaveThread(); 809 | } 810 | } 811 | 812 | static PyObject* AddMenuItem(PyObject* self, PyObject* args) 813 | { 814 | long int_menu; 815 | const char *title; 816 | PyObject *python_callback; 817 | const char *bitmap_path; 818 | if (!PyArg_ParseTuple(args, "lsOs", &int_menu, &title, &python_callback, &bitmap_path)) return NULL; 819 | 820 | wxMenu *menu = (wxMenu*)int_menu; 821 | 822 | int id = heeksCAD->AddMenuItem(menu, wxString(_U(title)), ToolImage(_U(bitmap_path), true), OnMenuItem, NULL); 823 | 824 | menu_item_map.insert(std::make_pair(id, python_callback)); 825 | 826 | PyObject *pValue = Py_None; 827 | Py_INCREF(pValue); 828 | return pValue; 829 | } 830 | 831 | static std::list new_windows; 832 | 833 | std::map window_map; 834 | 835 | void OnWindow( wxCommandEvent& event ) 836 | { 837 | std::map::iterator FindIt = window_map.find(event.GetId()); 838 | if(FindIt != window_map.end()) 839 | { 840 | wxWindow* window = FindIt->second; 841 | wxAuiManager* aui_manager = heeksCAD->GetAuiManager(); 842 | wxAuiPaneInfo& pane_info = aui_manager->GetPane(window); 843 | if(pane_info.IsOk()){ 844 | pane_info.Show(event.IsChecked()); 845 | aui_manager->Update(); 846 | } 847 | } 848 | } 849 | 850 | void OnUpdateWindow( wxUpdateUIEvent& event ) 851 | { 852 | std::map::iterator FindIt = window_map.find(event.GetId()); 853 | if(FindIt != window_map.end()) 854 | { 855 | wxWindow* window = FindIt->second; 856 | wxAuiManager* aui_manager = heeksCAD->GetAuiManager(); 857 | event.Check(aui_manager->GetPane(window).IsShown()); 858 | } 859 | } 860 | 861 | static PyObject* AddWindow(PyObject* self, PyObject* args) 862 | { 863 | long int_window; 864 | if (!PyArg_ParseTuple(args, "l", &int_window)) return NULL; 865 | 866 | wxFrame* frame = heeksCAD->GetMainFrame(); 867 | wxAuiManager* aui_manager = heeksCAD->GetAuiManager(); 868 | 869 | #ifdef WIN32 870 | wxWindow * new_window = new wxWindow(); 871 | new_window->SetHWND((WXHWND)int_window); 872 | new_window->AdoptAttributesFromHWND(); 873 | new_window->Reparent(frame); 874 | #else 875 | wxWindow * new_window = wxWindow::FindWindowById(int_window); 876 | new_window->Reparent(frame); 877 | #endif 878 | 879 | wxString label = new_window->GetLabel(); 880 | 881 | new_windows.push_back(new_window); 882 | 883 | aui_manager->AddPane(new_window, wxAuiPaneInfo().Name(label).Caption(label).Bottom().BestSize(wxSize(600, 200))); 884 | 885 | bool window_visible; 886 | wxString config_name = label + wxString(_T("Visible")); 887 | PythonConfig config; 888 | 889 | config.Read(config_name, &window_visible); 890 | 891 | aui_manager->GetPane(new_window).Show(window_visible); 892 | 893 | wxMenu* view_menu = heeksCAD->GetWindowMenu(); 894 | int id = heeksCAD->AddMenuItem(view_menu, label, wxBitmap(), OnWindow, OnUpdateWindow,0,true); 895 | heeksCAD->RegisterHideableWindow(new_window); 896 | window_map.insert(std::make_pair(id, new_window)); 897 | 898 | return PyInt_FromLong(new_window->GetId()); 899 | } 900 | 901 | static PyObject* DXFImport(PyObject* self, PyObject* args) 902 | { 903 | 904 | const char *filepath; 905 | if (!PyArg_ParseTuple(args, "s", &filepath)) return NULL; 906 | 907 | heeksCAD->OpendxfFile(_U(filepath)); 908 | 909 | 910 | PyObject *pValue = Py_None; 911 | Py_INCREF(pValue); 912 | return pValue; 913 | } 914 | 915 | static PyObject* Redraw(PyObject* self, PyObject* args) 916 | { 917 | 918 | 919 | heeksCAD->Repaint(); 920 | PyObject *pValue = Py_None; 921 | Py_INCREF(pValue); 922 | return pValue; 923 | 924 | 925 | } 926 | 927 | 928 | static PyObject* GetSketch(PyObject* self, PyObject* args) 929 | { 930 | //Allows the user to pick a single sketch 931 | // it returns the sketch id, or 0 if none was picked 932 | 933 | PyObject *resultobj = 0; 934 | 935 | int result; 936 | 937 | result = heeksCAD->PickObjects(_("Select a Sketch"), MARKING_FILTER_SKETCH,true); 938 | 939 | int sketch_id = 0; 940 | 941 | for(HeeksObj* object = heeksCAD->GetFirstMarkedObject(); object; object = heeksCAD->GetNextMarkedObject()) 942 | { 943 | if(object->GetType() == SketchType){ 944 | sketch_id = object->GetID(); 945 | break; 946 | } 947 | } 948 | 949 | resultobj = PyLong_FromLong(sketch_id); 950 | 951 | PyObject *pValue = resultobj; 952 | Py_INCREF(pValue); 953 | return pValue; 954 | 955 | } 956 | 957 | static PyObject* GetSketches(PyObject* self, PyObject* args) 958 | { 959 | // Allows the user to pick multiple sketches 960 | // returns a python list of sketch ids 961 | int result = heeksCAD->PickObjects(_("Select Sketches"), MARKING_FILTER_SKETCH); 962 | 963 | PyObject* pList = PyList_New(0); 964 | for(HeeksObj* object = heeksCAD->GetFirstMarkedObject(); object; object = heeksCAD->GetNextMarkedObject()) 965 | { 966 | if(object->GetType() == SketchType){ 967 | PyList_Append(pList, PyLong_FromLong(object->GetID())); 968 | } 969 | } 970 | 971 | return pList; 972 | } 973 | 974 | static PyObject* GetSelectedSketches(PyObject* self, PyObject* args) 975 | { 976 | // returns a python list of sketch ids 977 | PyObject* pList = PyList_New(0); 978 | for(HeeksObj* object = heeksCAD->GetFirstMarkedObject(); object; object = heeksCAD->GetNextMarkedObject()) 979 | { 980 | if(object->GetType() == SketchType){ 981 | PyList_Append(pList, PyLong_FromLong(object->GetID())); 982 | } 983 | } 984 | 985 | return pList; 986 | } 987 | 988 | static PyObject *callback_new_or_open = NULL; 989 | 990 | void OnBeforeNewOrOpen(int open, int res) { 991 | if(callback_new_or_open) 992 | { 993 | PyEval_RestoreThread(theApp.m_console->m_mainTState); 994 | PyObject* result = PyEval_CallFunction(callback_new_or_open, "ii", open, res); 995 | PyEval_SaveThread(); 996 | } 997 | } 998 | 999 | static PyObject* RegisterCallbacks(PyObject* self, PyObject* args) 1000 | { 1001 | PyObject *temp; 1002 | if (!PyArg_ParseTuple(args, "O", &temp)) return NULL; 1003 | 1004 | if (!PyCallable_Check(temp)) { 1005 | PyErr_SetString(PyExc_TypeError, "parameter must be callable"); 1006 | return NULL; 1007 | } 1008 | Py_XINCREF(temp); /* Add a reference to new callback */ 1009 | Py_XDECREF(callback_new_or_open); /* Dispose of previous callback */ 1010 | callback_new_or_open = temp; /* Remember new callback */ 1011 | 1012 | static bool callbacks_registered = false; 1013 | 1014 | if(!callbacks_registered) 1015 | { 1016 | heeksCAD->RegisterOnBeforeNewOrOpen(OnBeforeNewOrOpen); 1017 | callbacks_registered = true; 1018 | } 1019 | 1020 | Py_INCREF(Py_None); 1021 | return Py_None; 1022 | } 1023 | 1024 | static PyObject* GetViewUnits(PyObject* self, PyObject* args) 1025 | { 1026 | return PyFloat_FromDouble(heeksCAD->GetViewUnits()); 1027 | } 1028 | 1029 | static PyObject* GetFileFullPath(PyObject* self, PyObject* args) 1030 | { 1031 | const wchar_t* str = heeksCAD->GetFileFullPath(); 1032 | if(str == NULL) 1033 | { 1034 | Py_INCREF(Py_None); 1035 | return Py_None; 1036 | } 1037 | char conv_str[4096]; 1038 | wcstombs(conv_str, str, 4096); 1039 | return PyString_FromString(conv_str); 1040 | } 1041 | 1042 | static PyObject* GetSketchShape(PyObject* self, PyObject* args) 1043 | { 1044 | int sketch_id = 0; 1045 | if (!PyArg_ParseTuple( args, "i", &sketch_id)) return NULL; 1046 | 1047 | HeeksObj* object = heeksCAD->GetIDObject(SketchType, sketch_id); 1048 | if(object == NULL)return PyString_FromString(""); 1049 | 1050 | std::string sketch_str; 1051 | 1052 | HeeksObj* re_ordered_sketch = NULL; 1053 | SketchOrderType order = heeksCAD->GetSketchOrder(object); 1054 | if( (order != SketchOrderTypeCloseCW) && 1055 | (order != SketchOrderTypeCloseCCW) && 1056 | (order != SketchOrderTypeMultipleCurves) && 1057 | (order != SketchOrderHasCircles)) 1058 | { 1059 | re_ordered_sketch = object->MakeACopy(); 1060 | heeksCAD->ReOrderSketch(re_ordered_sketch, SketchOrderTypeReOrder); 1061 | object = re_ordered_sketch; 1062 | } 1063 | 1064 | bool first = true; 1065 | char str[1024]; 1066 | for(HeeksObj* child = object->GetFirstChild(); child; child = object->GetNextChild()) 1067 | { 1068 | if(first) 1069 | { 1070 | double s[3]; 1071 | if(child->GetStartPoint(s)) 1072 | { 1073 | sprintf(str, "x%gy%g\n", s[0], s[1]); 1074 | sketch_str.append(str); 1075 | } 1076 | first = false; 1077 | } 1078 | 1079 | double e[3]; 1080 | if(!child->GetEndPoint(e))continue; 1081 | 1082 | if(child->GetType() == ArcType) 1083 | { 1084 | double c[3]; 1085 | if(!child->GetCentrePoint(c))continue; 1086 | double a[3]; 1087 | if(!heeksCAD->GetArcAxis(child, a))continue; 1088 | sprintf(str, "%sx%gy%gi%gj%g\n", (a[2]>0)?"a":"t", e[0], e[1], c[0], c[1]); 1089 | sketch_str.append(str); 1090 | } 1091 | else 1092 | { 1093 | sprintf(str, "x%gy%g\n", e[0], e[1]); 1094 | sketch_str.append(str); 1095 | } 1096 | } 1097 | 1098 | if(re_ordered_sketch) 1099 | { 1100 | delete re_ordered_sketch; 1101 | } 1102 | 1103 | return PyString_FromString(sketch_str.c_str()); 1104 | } 1105 | 1106 | static PyObject* RemoveObject(PyObject* self, PyObject* args) 1107 | { 1108 | //remove object 1109 | HeeksObj *obj; 1110 | int pyobj; 1111 | 1112 | if (!PyArg_ParseTuple( args, "i", &pyobj)) return NULL; 1113 | obj = (HeeksObj*)heeksCAD->GetIDObject(pyobj>>16,pyobj&0xFFFF); 1114 | heeksCAD->Remove(obj); 1115 | 1116 | 1117 | PyObject *pValue = Py_None; 1118 | 1119 | return pValue; 1120 | } 1121 | 1122 | static PyMethodDef HeeksPythonMethods[] = { 1123 | {"sketch", NewSketch, METH_VARARGS , "sketch()"}, 1124 | {"wxhandle", WxHandle, METH_VARARGS , "wxhandle()"}, 1125 | {"extrude", Extrude, METH_VARARGS , "extrude(sketch,height)"}, 1126 | {"revolve", Revolve, METH_VARARGS , "revolve(sketch,angle)"}, 1127 | {"reorder", Reorder, METH_VARARGS , "reorder(sketch)"}, 1128 | {"point", NewPoint, METH_VARARGS , "point(x,y,z)"}, 1129 | {"linearc2wire", LineArc2Wire, METH_VARARGS , "linearc2wire(linearc)"}, 1130 | {"pipe", Pipe, METH_VARARGS , "pipe(wire,sketch)"}, 1131 | {"arc", NewArc, METH_VARARGS, "arc(cx,cy,cz,radius,start_a,end_a,ux,uy,uz)"}, 1132 | {"arc2", NewArc2, METH_VARARGS, "arc(sx,sy,sz,ex,ey,ez,cx,cy,cz,ux,uy,uz)"}, 1133 | {"line", NewLine, METH_VARARGS , "line(start_x, start_y, end_x, end_y)"}, 1134 | {"line3d", NewLine3d, METH_VARARGS , "line3d(start_x, start_y, start_z, end_x, end_y, end_z)"}, 1135 | {"circle", NewCircle, METH_VARARGS , "circle(centre_x, centre_y, radius)"}, 1136 | {"cuboid", NewCuboid, METH_VARARGS , "cuboid(centre_x, centre_y, centre_z, length, width, height)"}, 1137 | {"cylinder", NewCylinder, METH_VARARGS , "cylinder(centre_x, centre_y, centre_z, radius, height)"}, 1138 | {"directedcylinder", NewCylinderEx, METH_VARARGS , "directedcylinder(centre_x, centre_y, centre_z, dir_x, dir_y, dir_z, radius, height)"}, 1139 | {"cone", NewCone, METH_VARARGS , "cylinder(centre_x, centre_y, centre_z, radius1, radius2, height)"}, 1140 | {"sphere",NewSphere,METH_VARARGS ,"sphere(centre_x, centre_y, centre_z, radius)"}, 1141 | {"group", NewGroup, METH_VARARGS , "group()"}, 1142 | {"add", Add, METH_VARARGS, "add(group,obj)"}, 1143 | {"fuse",Fuse, METH_VARARGS, "fuse(obj1,obj2)"}, 1144 | {"common",Common, METH_VARARGS, "common(obj1,obj2)"}, 1145 | {"cut",Cut, METH_VARARGS, "cut(obj1,obj2)"}, 1146 | {"getlastobj", GetLastObj, METH_VARARGS , "getlastobj()"}, 1147 | {"rotate",Rotate, METH_VARARGS , "rotate(object,p_x,p_y,p_z,u_x,u_y,u_z,r)"}, 1148 | {"translate",Translate, METH_VARARGS , "translate(object,p_x,p_y,p_z)"}, 1149 | {"scale",Scale, METH_VARARGS , "scale(object,p_x,p_y,p_z,scale)"}, 1150 | {"setcolor",SetColor, METH_VARARGS, "setcolor(int r, int b, int g)"}, 1151 | {"fillet2d" ,Fillet2d, METH_VARARGS, "fillet2d(obj,point,radius)"}, 1152 | {"coordinate" ,NewCoordinateSystem, METH_VARARGS, "coordinate(position,x_vec,y_vec)"}, 1153 | {"pickpoint" , PickPoint, METH_VARARGS, "pickpoint()"}, 1154 | {"lastclicked" , GetClickedPos, METH_VARARGS, "lastclicked()"}, 1155 | {"view_extents" , ViewExtents, METH_VARARGS, "view_extents()"}, 1156 | {"ve" , ViewExtents, METH_VARARGS, "ve()"}, 1157 | {"xyzview" , XYZview, METH_VARARGS, "xyzview()"}, 1158 | {"getpoint" , GetPoint3d, METH_VARARGS, "getpoint()"}, 1159 | {"addtext", NewText, METH_VARARGS , "addtext('string')"}, 1160 | {"importdxf", DXFImport, METH_VARARGS , "importdxf('/filepath/filename.dxf')"}, 1161 | {"addmenu", AddMenu, METH_VARARGS , "menu = addmenu('string')"}, 1162 | {"add_menu_item", AddMenuItem, METH_VARARGS , "add_menu_item(menu, 'string', callback, icon)"}, 1163 | {"add_window", AddWindow, METH_VARARGS , "add_window(hwnd)"}, 1164 | {"get_frame_hwnd", GetFrameHwnd, METH_VARARGS , "hwnd = get_frame_hwnd()"}, 1165 | {"get_frame_id", GetFrameId, METH_VARARGS , "hwnd = get_frame_id()"}, 1166 | {"redraw" , Redraw, METH_VARARGS, "redraw()"}, 1167 | {"getsketch" , GetSketch, METH_VARARGS, "getsketch()"}, 1168 | {"getsketches" , GetSketches, METH_VARARGS, "getsketches()"}, 1169 | {"get_selected_sketches" , GetSelectedSketches, METH_VARARGS, "get_selected_sketches()"}, 1170 | {"register_callbacks" , RegisterCallbacks, METH_VARARGS, "register_callbacks(on_new_or_open)"}, 1171 | {"get_view_units", GetViewUnits, METH_VARARGS , "units = get_view_units()"}, 1172 | {"GetFileFullPath", GetFileFullPath, METH_VARARGS , "file_path = GetFileFullPath()"}, 1173 | {"GetSketchShape", GetSketchShape, METH_VARARGS , "s = GetSketchShape(2)"}, 1174 | {"remove",RemoveObject, METH_VARARGS , "remove(object)"}, 1175 | {"undopt",NewCreateUndoPoint, METH_VARARGS , "undopt()"}, 1176 | {"changed",NewChanged, METH_VARARGS , "changed()"}, 1177 | {NULL, NULL, 0, NULL} 1178 | }; 1179 | 1180 | PyMODINIT_FUNC 1181 | initHeeksPython(void) 1182 | { 1183 | Py_InitModule("HeeksPython", HeeksPythonMethods); 1184 | } 1185 | -------------------------------------------------------------------------------- /src/PythonInterface.h: -------------------------------------------------------------------------------- 1 | // HeeksPython.h 2 | 3 | extern void Message(const char*); 4 | 5 | void PythonInit(); 6 | void PythonFinish(); 7 | 8 | -------------------------------------------------------------------------------- /src/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #ifdef WIN32 7 | #pragma warning(disable : 4996) 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | extern "C" { 22 | #include 23 | #include 24 | } 25 | 26 | #include "HeeksPython.h" 27 | #include "interface/strconv.h" 28 | 29 | 30 | 31 | // TODO: reference additional headers your program requires here 32 | 33 | -------------------------------------------------------------------------------- /src/vc_retro.py: -------------------------------------------------------------------------------- 1 | # Process the SLN: 2 | f_in = open('HeeksPython.sln'); 3 | f_vc3 = open('HeeksPython VC2003.sln', 'w'); 4 | f_vc5 = open('HeeksPython VC2005.sln', 'w'); 5 | 6 | while (True): 7 | line = f_in.readline(); 8 | if (len(line) == 0) : break; 9 | 10 | if (line == 'Microsoft Visual Studio Solution File, Format Version 10.00\n'): 11 | f_vc3.write('Microsoft Visual Studio Solution File, Format Version 8.00\n'); 12 | f_vc5.write('Microsoft Visual Studio Solution File, Format Version 9.00\n'); 13 | elif (line == '# Visual C++ Express 2008\n'): 14 | f_vc5.write('# Visual Studio 2005\n'); 15 | elif (line == 'Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HeeksPython", "HeeksPython.vcproj", "{0F1453E7-EE7A-47D1-B8D6-8ED6F425885C}"\n'): 16 | f_vc3.write('Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HeeksPython", "HeeksPython VC2003.vcproj", "{0F1453E7-EE7A-47D1-B8D6-8ED6F425885C}"\n'); 17 | f_vc5.write('Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HeeksPython", "HeeksPython VC2005.vcproj", "{0F1453E7-EE7A-47D1-B8D6-8ED6F425885C}"\n'); 18 | else: 19 | f_vc3.write(line); 20 | f_vc5.write(line); 21 | 22 | f_in.close(); 23 | f_vc3.close(); 24 | f_vc5.close(); 25 | 26 | # Process the VCPROJ: 27 | f_in = open('HeeksPython.vcproj'); 28 | f_vc3 = open('HeeksPython VC2003.vcproj', 'w'); 29 | f_vc5 = open('HeeksPython VC2005.vcproj', 'w'); 30 | 31 | while (True): 32 | line = f_in.readline(); 33 | if (len(line) == 0) : break; 34 | 35 | if (line == '\tVersion="9.00"\n'): 36 | f_vc3.write('\tVersion="7.10"\n'); 37 | f_vc5.write('\tVersion="8.00"\n'); 38 | else: 39 | f_vc3.write(line); 40 | f_vc5.write(line); 41 | 42 | f_in.close(); 43 | f_vc3.close(); 44 | f_vc5.close(); 45 | --------------------------------------------------------------------------------