yapCAD 0.3.0__py2.py3-none-any.whl → 0.5.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- yapcad/combine.py +82 -376
- yapcad/drawable.py +44 -3
- yapcad/ezdxf_drawable.py +1 -1
- yapcad/geom.py +204 -264
- yapcad/geom3d.py +975 -55
- yapcad/geom3d_util.py +541 -0
- yapcad/geom_util.py +817 -0
- yapcad/geometry.py +441 -49
- yapcad/geometry_checks.py +112 -0
- yapcad/geometry_utils.py +115 -0
- yapcad/io/__init__.py +5 -0
- yapcad/io/stl.py +83 -0
- yapcad/mesh.py +46 -0
- yapcad/metadata.py +109 -0
- yapcad/octtree.py +627 -0
- yapcad/poly.py +153 -299
- yapcad/pyglet_drawable.py +597 -61
- yapcad/triangulator.py +103 -0
- yapcad/xform.py +0 -1
- {yapcad-0.3.0.dist-info → yapcad-0.5.0.dist-info}/METADATA +94 -38
- yapcad-0.5.0.dist-info/RECORD +27 -0
- yapcad-0.3.0.dist-info/RECORD +0 -17
- {yapcad-0.3.0.dist-info → yapcad-0.5.0.dist-info}/WHEEL +0 -0
- {yapcad-0.3.0.dist-info → yapcad-0.5.0.dist-info}/licenses/AUTHORS.rst +0 -0
- {yapcad-0.3.0.dist-info → yapcad-0.5.0.dist-info}/licenses/LICENSE +0 -0
- {yapcad-0.3.0.dist-info → yapcad-0.5.0.dist-info}/licenses/LICENSE.txt +0 -0
- {yapcad-0.3.0.dist-info → yapcad-0.5.0.dist-info}/top_level.txt +0 -0
yapcad/poly.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
## Derived Geometry clases for yapCAD
|
2
2
|
from yapcad.geom import *
|
3
3
|
from yapcad.geometry import *
|
4
4
|
|
@@ -26,229 +26,136 @@ from yapcad.geometry import *
|
|
26
26
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
27
27
|
# SOFTWARE.
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
## classes rather than the point-list based representations.
|
33
|
-
|
34
|
-
## First, because instances of these classes can cache
|
35
|
-
## meta-information about the geometry, it means that sampling and
|
36
|
-
## intersection operations might be more efficient for class instances
|
37
|
-
## than utilizing the functions avalable for the list-based
|
38
|
-
## representations.
|
39
|
-
|
40
|
-
## Seond, and more importantly, these geometry-generating classes,
|
41
|
-
## they can support a richer set of representations and operations.
|
42
|
-
## For example, the Polygon() class for closed figures allows you to
|
43
|
-
## specify points, lines, arcs, or circles as elements of the
|
44
|
-
## geometry, and will intelligently interpolate between these to
|
45
|
-
## generate the resulting geometry. This means you can use circles to
|
46
|
-
## represented rounded corners without having to worry about
|
47
|
-
## converting them into just the right arc, since the tangent lines
|
48
|
-
## and arc trimming are done automatically.
|
49
|
-
|
50
|
-
|
51
|
-
class Polyline(IntersectGeometry):
|
52
|
-
"""Generalized multi-element open figure class"""
|
53
|
-
|
54
|
-
def __init__(self,a=False):
|
55
|
-
self._elem=[]
|
56
|
-
self._length=0.0
|
57
|
-
self._lengths=[]
|
58
|
-
self._lines=[]
|
59
|
-
self._update=True
|
60
|
-
self._closed=False
|
61
|
-
self._center=point(0,0,0)
|
62
|
-
self._bbox=line(point(-epsilon,-epsilon),
|
63
|
-
point(epsilon,epsilon))
|
64
|
-
if isinstance(a,Polyline):
|
65
|
-
self._elem = deepcopy(a._elem)
|
66
|
-
self._updateInternals()
|
67
|
-
elif isgeomlist(a):
|
68
|
-
for i in a:
|
69
|
-
if ispoint(i) or isarc(i) or isline(i):
|
70
|
-
self._elem.append(deepcopy(i))
|
71
|
-
elif ispoly(i):
|
72
|
-
self._elem = self._elem + i
|
73
|
-
else:
|
74
|
-
raise ValueError("bad argument to Polyline constructor")
|
75
|
-
elif a != False:
|
76
|
-
raise ValueError("bad argument passed to Polyline constructor")
|
29
|
+
"""
|
30
|
+
Derived Geometry Classes
|
31
|
+
========================
|
77
32
|
|
78
|
-
|
79
|
-
|
33
|
+
These subclasses of Geometry compute a figure based on the contents
|
34
|
+
of their elements list, rather than simply providing a wrapper around
|
35
|
+
the contents of their elements.
|
80
36
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
self._elem.append(element)
|
86
|
-
else:
|
87
|
-
raise ValueError('attempt to add a non point to Polyline')
|
37
|
+
The Polygon class is an intepolating closed figure class that will
|
38
|
+
interpolate lines between each point or open figure element in its
|
39
|
+
element list. It will also treat circles as rounded convex conrners
|
40
|
+
of the specified radius.
|
88
41
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
if i < len(self._elem):
|
94
|
-
self._elem[i]=point(p)
|
95
|
-
elif i == len(self._elem):
|
96
|
-
self._elem.append(p)
|
97
|
-
else:
|
98
|
-
raise ValueError('index out of range in PolylinesetPoint(): '.format(i))
|
99
|
-
self._update=True
|
100
|
-
|
101
|
-
## return a copy of the elem list
|
102
|
-
def getElem(self):
|
103
|
-
return deepcopy(self._elem)
|
104
|
-
|
105
|
-
def _updateInternals(self):
|
106
|
-
if self._update:
|
107
|
-
self._updateCenter()
|
108
|
-
self._updateLines()
|
109
|
-
self._update=False
|
110
|
-
|
111
|
-
|
112
|
-
## compute barycentric center of figure by equally weighting the
|
113
|
-
## points. If last and first points are the same, ignore the
|
114
|
-
## last point.
|
115
|
-
def _updateCenter(self):
|
116
|
-
l = len(self._elem)
|
117
|
-
if l == 0:
|
118
|
-
return
|
119
|
-
elif l == 1:
|
120
|
-
self._center = center(self._elem[0]) # center is sole point
|
121
|
-
self._bbox = bbox(self._elem[0])
|
122
|
-
else:
|
123
|
-
|
124
|
-
if dist(center(self._elem[0]),
|
125
|
-
center(self._elem[-1])) < epsilon:
|
126
|
-
l -= 1
|
127
|
-
|
128
|
-
|
129
|
-
p = center(self._elem[0])
|
130
|
-
for i in range(1,l):
|
131
|
-
p = add(center(self._elem[i]),p)
|
132
|
-
|
133
|
-
self._center = scale3(p,1/l)
|
134
|
-
self._bbox = bbox(self._elem)
|
135
|
-
return
|
136
|
-
|
137
|
-
## return the center of the figure. If necessary, recompute that
|
138
|
-
def getCenter(self):
|
139
|
-
if self._update:
|
140
|
-
self._updateInternals()
|
141
|
-
return self._center
|
142
|
-
|
143
|
-
|
144
|
-
def getLength(self):
|
145
|
-
if self._update:
|
146
|
-
self._updateInternals()
|
147
|
-
return self._length
|
148
|
-
|
149
|
-
## function to take the points in the elem[] list and build a
|
150
|
-
## list of the individual lines, line lengths and total length to
|
151
|
-
## facilitate sampling
|
152
|
-
|
153
|
-
def _updateLines(self):
|
154
|
-
for i in range(1,len(self._elem)):
|
155
|
-
p0= center(self._elem[i-1])
|
156
|
-
p1= center(self._elem[i])
|
157
|
-
self._lines.append(line(p0,p1))
|
158
|
-
l = dist(p0,p1)
|
159
|
-
self._lengths.append(l)
|
160
|
-
self._length += l
|
161
|
-
if len(self._elem) > 2 and dist(center(self._elem[0]),
|
162
|
-
center(self._elem[-1])) < epsilon:
|
163
|
-
self._closed = True
|
164
|
-
|
165
|
-
def geom(self):
|
166
|
-
if self._update:
|
167
|
-
self._updateInternals()
|
168
|
-
return deepcopy(self._lines)
|
169
|
-
|
170
|
-
def sample(self,u):
|
171
|
-
if self._update:
|
172
|
-
self._updateInternals()
|
173
|
-
dist = u * self._length;
|
174
|
-
d = 0
|
175
|
-
if self._closed:
|
176
|
-
u = u%1.0
|
177
|
-
if u < 1.0:
|
178
|
-
for i in range(len(self._lines)):
|
179
|
-
l=self._lengths[i]
|
180
|
-
if dist <= d+l:
|
181
|
-
uu = 1.0 - (d+l-dist)/l
|
182
|
-
return sampleline(self._lines[i],uu)
|
183
|
-
else:
|
184
|
-
d+=l
|
185
|
-
else:
|
186
|
-
uu = (dist-self._length+self._lengths[-1])/self._lengths[-1]
|
187
|
-
return sampleline(self._lines[-1],uu)
|
188
|
-
|
42
|
+
By treating circles as rounded corners, polygon instances can be
|
43
|
+
"grown" to create new figures that are a fixed distance larger, which
|
44
|
+
is very useful for offsetting drill holes from the edge of a boundary,
|
45
|
+
etc. """
|
189
46
|
|
190
|
-
class Polygon(
|
191
|
-
"""
|
47
|
+
class Polygon(Geometry):
|
48
|
+
"""Multi-element closed figure derived geometry class"""
|
192
49
|
|
193
|
-
def __init__(self,a=
|
50
|
+
def __init__(self,a=None):
|
194
51
|
super().__init__()
|
52
|
+
self._setDerived(True)
|
53
|
+
self._setClosed(True)
|
54
|
+
self.__lengths=0
|
55
|
+
self.__outline=[]
|
56
|
+
|
195
57
|
if isinstance(a,Polygon):
|
196
|
-
self.
|
197
|
-
self.
|
58
|
+
self._setElem(deepcopy(a.elem))
|
59
|
+
self._setUpdate(True)
|
198
60
|
elif isgeomlist(a):
|
199
61
|
for i in a:
|
200
62
|
if ispoint(i) or isarc(i):
|
201
|
-
self.
|
63
|
+
self.elem.append(i)
|
202
64
|
elif isline(i):
|
203
65
|
pass
|
204
66
|
elif ispoly(i):
|
205
|
-
self.
|
67
|
+
self._setElem(self.elem + i)
|
206
68
|
else:
|
207
69
|
raise ValueError("bad argument to Polygon constructor")
|
208
70
|
|
209
|
-
elif a !=
|
71
|
+
elif a != None:
|
210
72
|
raise ValueError("bad argument to Polygon constructor")
|
211
73
|
|
212
|
-
elm = self.
|
74
|
+
elm = self.elem
|
213
75
|
|
214
76
|
l = len(elm)
|
215
77
|
if l > 2:
|
216
78
|
# if first and last element are identicial points or circles,
|
217
79
|
# remove them
|
218
|
-
if (ispoint(elm[0]) and ispoint(elm[-1]) and
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
self.
|
80
|
+
if ((ispoint(elm[0]) and ispoint(elm[-1]) and
|
81
|
+
dist(elm[0],elm[-1]) < epsilon) or
|
82
|
+
(iscircle(elm[0]) and iscircle(elm[-1]) and
|
83
|
+
abs(elm[0][1][0] - elm[-1][1][0]) < epsilon)):
|
84
|
+
self.elem.pop()
|
223
85
|
|
224
86
|
def __repr__(self):
|
225
|
-
return 'Polygon({})'.format(vstr(self.
|
87
|
+
return 'Polygon({})'.format(vstr(self.elem))
|
226
88
|
|
89
|
+
## compute barycentric center of figure by equally weighting the
|
90
|
+
## points. If last and first points are the same, ignore the
|
91
|
+
## last point.
|
92
|
+
def _calcCenter(self):
|
93
|
+
l = len(self.elem)
|
94
|
+
if l == 0:
|
95
|
+
return None
|
96
|
+
elif l == 1:
|
97
|
+
return center(self.elem[0]) # center is sole point
|
98
|
+
else:
|
99
|
+
|
100
|
+
if dist(center(self.elem[0]),
|
101
|
+
center(self.elem[-1])) < epsilon:
|
102
|
+
l -= 1
|
103
|
+
|
104
|
+
|
105
|
+
p = center(self.elem[0])
|
106
|
+
for i in range(1,l):
|
107
|
+
p = add(center(self.elem[i]),p)
|
108
|
+
|
109
|
+
return scale3(p,1/l)
|
110
|
+
|
111
|
+
|
227
112
|
def _updateInternals(self):
|
228
|
-
if self.
|
229
|
-
self.
|
113
|
+
if self.update:
|
114
|
+
self._setUpdate(False)
|
230
115
|
self._makeoutline()
|
231
|
-
self.
|
116
|
+
self._setCenter(self._calcCenter())
|
117
|
+
self._setBbox(bbox(self.__outline))
|
118
|
+
|
119
|
+
def addPoint(self,element):
|
120
|
+
if ispoint(element):
|
121
|
+
self._setUpdate(True) # flag that we need to recalculate stuff
|
122
|
+
self.elem.append(deepcopy(element))
|
123
|
+
else:
|
124
|
+
raise ValueError('attempt to add a non point to Polyline')
|
125
|
+
|
126
|
+
## set a point to a specified value
|
127
|
+
def setPoint(self,i,p):
|
128
|
+
if not ispoint(p):
|
129
|
+
raise ValueError('bad point passed to Polyline.setPoint(): '.format(p))
|
130
|
+
elem = self.elem
|
131
|
+
if i < len(elem):
|
132
|
+
elem[i]=point(p)
|
133
|
+
elif i == len(elem):
|
134
|
+
elem.append(p)
|
135
|
+
else:
|
136
|
+
raise ValueError('index out of range in PolylinesetPoint(): '.format(i))
|
137
|
+
self._setElem(elem)
|
138
|
+
self._setUpdate(True)
|
232
139
|
|
233
140
|
## add another drawing element
|
234
141
|
def addLine(self,element):
|
235
142
|
if isline(element):
|
236
|
-
self.
|
237
|
-
self.
|
143
|
+
self._setUpdate(True) # flag that we need to recalculate stuff
|
144
|
+
self.elem.append(deepcopy(element))
|
238
145
|
else:
|
239
146
|
raise ValueError('attempt to add a non point, line or arc to poly')
|
240
147
|
|
241
148
|
## add another drawing element
|
242
149
|
def addArc(self,element):
|
243
150
|
if isarc(element):
|
244
|
-
self.
|
245
|
-
self.
|
151
|
+
self._setUpdate(True) # flag that we need to recalculate stuff
|
152
|
+
self.elem.append(deepcopy(element))
|
246
153
|
else:
|
247
154
|
raise ValueError('attempt to add a non point, line or arc to poly')
|
248
155
|
|
249
156
|
def remove(self,element):
|
250
|
-
self.
|
251
|
-
self.
|
157
|
+
self._setUpdate(True)
|
158
|
+
self.elem.remove(element)
|
252
159
|
|
253
160
|
## function to take the elements in the elem[] list and
|
254
161
|
## construct the full outline. For example, consider a list of
|
@@ -260,23 +167,24 @@ class Polygon(Polyline):
|
|
260
167
|
## non-circular arcs are joined to adjacent elements by lines
|
261
168
|
|
262
169
|
def _makeoutline(self):
|
170
|
+
# import pdb; pdb.set_trace()
|
263
171
|
def _calclength():
|
264
172
|
l = 0
|
265
173
|
ll = []
|
266
174
|
length = 0
|
267
|
-
for o in self.
|
175
|
+
for o in self.__outline:
|
268
176
|
if isarc(o):
|
269
177
|
length=arclength(o)
|
270
178
|
elif isline(o): # line
|
271
179
|
length=linelength(o)
|
272
180
|
else:
|
273
|
-
#print("self.
|
181
|
+
#print("self.__outline: ",vstr(self.__outline))
|
274
182
|
#print("o: ",vstr(o))
|
275
183
|
raise ValueError("bad element in outline list for _calclength()")
|
276
184
|
l += length
|
277
185
|
ll.append(length)
|
278
|
-
self.
|
279
|
-
self.
|
186
|
+
self._setLength(l)
|
187
|
+
self.__lengths=ll
|
280
188
|
|
281
189
|
def _handleCircle(e0,e1,e2):
|
282
190
|
## get the two tangent lines from circle e1 to the circle
|
@@ -315,33 +223,33 @@ class Polygon(Polyline):
|
|
315
223
|
else:
|
316
224
|
l = ll[1]
|
317
225
|
|
318
|
-
self.
|
226
|
+
self.__outline.append(line(l))
|
319
227
|
|
320
228
|
def _fromPointAdd(e0,p1,e2):
|
321
229
|
if ispoint(e2): #r1 is a point -- simplest case
|
322
230
|
#ll = dist(p1,e2)
|
323
|
-
self.
|
231
|
+
self.__outline.append(line(p1,e2))
|
324
232
|
elif isline(e2):
|
325
|
-
self.
|
326
|
-
self.
|
233
|
+
self.__outline.append(line(p1,e2[0]))
|
234
|
+
self.__outline.append(line(e2))
|
327
235
|
elif isarc(e2) and not iscircle(e2):
|
328
236
|
p = samplearc(e2,1*epsilon)
|
329
|
-
self.
|
330
|
-
self.
|
237
|
+
self.__outline.append(line(p1,p))
|
238
|
+
self.__outline.append(arc(e2))
|
331
239
|
elif iscircle(e2):
|
332
240
|
_handleCircle(e0,arc(p1,1*epsilon),e2)
|
333
|
-
self.
|
241
|
+
self.__outline.append(arc(e2))
|
334
242
|
else:
|
335
243
|
raise ValueError('bad object in element list')
|
336
244
|
|
337
|
-
self.
|
338
|
-
self.
|
339
|
-
self.
|
245
|
+
self.__outline=[]
|
246
|
+
self._setLength(0.0)
|
247
|
+
self.__lengths=[]
|
340
248
|
|
341
|
-
if len(self.
|
249
|
+
if len(self.elem) < 2:
|
342
250
|
## if one element, the outline is the element
|
343
|
-
if len(self.
|
344
|
-
self.
|
251
|
+
if len(self.elem) == 1:
|
252
|
+
self.__outline=deepcopy(self.elem)
|
345
253
|
_calclength()
|
346
254
|
## if there are fewer than one elem, there is nothing to do
|
347
255
|
return
|
@@ -351,16 +259,16 @@ class Polygon(Polyline):
|
|
351
259
|
## total length and length list for use in sample() function.
|
352
260
|
|
353
261
|
|
354
|
-
for i in range(len(self.
|
262
|
+
for i in range(len(self.elem)):
|
355
263
|
if i == 0:
|
356
|
-
e0 = self.
|
264
|
+
e0 = self.elem[-1]
|
357
265
|
else:
|
358
|
-
e0 = self.
|
359
|
-
e1 = self.
|
360
|
-
if i == len(self.
|
361
|
-
e2 = self.
|
266
|
+
e0 = self.elem[i-1]
|
267
|
+
e1 = self.elem[i]
|
268
|
+
if i == len(self.elem)-1: #last item
|
269
|
+
e2 = self.elem[0]
|
362
270
|
else:
|
363
|
-
e2 = self.
|
271
|
+
e2 = self.elem[i+1]
|
364
272
|
## work through element types
|
365
273
|
if ispoint(e1): #e1 is a point
|
366
274
|
_fromPointAdd(e0,e1,e2)
|
@@ -381,18 +289,18 @@ class Polygon(Polyline):
|
|
381
289
|
_handleCircle(e0,e1,c2)
|
382
290
|
|
383
291
|
if not ispoint(e2):
|
384
|
-
self.
|
292
|
+
self.__outline.append(deepcopy(e2))
|
385
293
|
|
386
294
|
## OK, now go back through and replace full circles with arcs
|
387
295
|
## and catch any intersecting lines due to non-convex
|
388
296
|
## curvature
|
389
|
-
for i in range(1,len(self.
|
390
|
-
e0 = self.
|
391
|
-
e1 = self.
|
392
|
-
if i == len(self.
|
393
|
-
e2 = self.
|
297
|
+
for i in range(1,len(self.__outline)):
|
298
|
+
e0 = self.__outline[i-1]
|
299
|
+
e1 = self.__outline[i]
|
300
|
+
if i == len(self.__outline)-1: #last item
|
301
|
+
e2 = self.__outline[0]
|
394
302
|
else:
|
395
|
-
e2 = self.
|
303
|
+
e2 = self.__outline[i+1]
|
396
304
|
if isline(e1) and isline(e2):
|
397
305
|
pi = lineLineIntersectXY(e1,e2,inside=True)
|
398
306
|
if pi == False:
|
@@ -403,8 +311,8 @@ class Polygon(Polyline):
|
|
403
311
|
print("odd parallel? adjacent line condition")
|
404
312
|
continue
|
405
313
|
else:
|
406
|
-
self.
|
407
|
-
self.
|
314
|
+
self.__outline[i] = line(e1[0],pi)
|
315
|
+
self.__outline[(i+1)%len(self.__outline)] = line(pi,e2[1])
|
408
316
|
if iscircle(e1):
|
409
317
|
if not isline(e0) or not isline(e2):
|
410
318
|
raise ValueError('circle not bracketed by lines')
|
@@ -422,95 +330,36 @@ class Polygon(Polyline):
|
|
422
330
|
start = (atan2(p0[1],p0[0]) % pi2) * 360.0/pi2
|
423
331
|
end = (atan2(p1[1],p1[0]) % pi2) * 360.0/pi2
|
424
332
|
newarc = arc(e1[0],e1[1][0],start,end)
|
425
|
-
self.
|
333
|
+
self.__outline[i]=newarc
|
426
334
|
|
427
|
-
self.
|
335
|
+
self.__outline = cullZeroLength(self.__outline)
|
428
336
|
|
429
337
|
_calclength()
|
430
|
-
|
431
|
-
|
338
|
+
|
339
|
+
# sample function uses cached length and lengths[], otherwise
|
340
|
+
# behavior is identical to superclass
|
432
341
|
def sample(self,u):
|
433
|
-
if self.
|
342
|
+
if self.update:
|
434
343
|
self._updateInternals()
|
435
|
-
if len(self.
|
344
|
+
if len(self.__outline) == 0:
|
436
345
|
raise ValueError('no geometry to sample, empty poly')
|
437
|
-
dist = (u % 1.0) * self.
|
346
|
+
dist = (u % 1.0) * self.length
|
438
347
|
d = 0
|
439
|
-
for i in range(len(self.
|
440
|
-
l=self.
|
348
|
+
for i in range(len(self.__outline)):
|
349
|
+
l=self.__lengths[i]
|
441
350
|
if dist <= d+l:
|
442
351
|
u = 1.0 - (d+l-dist)/l
|
443
|
-
e = self.
|
352
|
+
e = self.__outline[i]
|
444
353
|
return sample(e,u)
|
445
354
|
else:
|
446
355
|
d=d+l
|
447
|
-
|
448
|
-
|
449
|
-
return segmentgeomlist(self.geom(),u1,u2,closed=True,reverse=reverse)
|
450
|
-
|
451
|
-
def mirror(self,plane,poly=False):
|
452
|
-
if poly:
|
453
|
-
p = Polygon()
|
454
|
-
p._elem = deepcopy(self._elem)
|
455
|
-
p._elem.reverse()
|
456
|
-
p._elem = mirror(p._elem,plane)
|
457
|
-
p._update=True
|
458
|
-
return p
|
459
|
-
|
460
|
-
return mirror(self.geom(),plane)
|
461
|
-
|
462
|
-
def rotate(self,angle,cent=point(0,0,0),axis=point(0,0,1),poly=False):
|
463
|
-
if poly:
|
464
|
-
p = Polygon(self)
|
465
|
-
p._elem = rotate(self._elem,angle,cent,axis)
|
466
|
-
p._update = True
|
467
|
-
return p
|
468
|
-
|
469
|
-
return rotate(self.geom(),angle,cent,axis)
|
470
|
-
|
471
|
-
def scale(self,sx,sy=False,sz=False,cent=point(0,0),poly=False):
|
472
|
-
if poly:
|
473
|
-
p = Polygon(self)
|
474
|
-
p._elem = scale(self._elem,sx,sy,sz,cent)
|
475
|
-
p._update = True
|
476
|
-
return p
|
477
|
-
|
478
|
-
return scale(self.geom(),sx,sy,sz,cent)
|
479
|
-
|
480
|
-
def translate(self,delta,poly=False):
|
481
|
-
if poly:
|
482
|
-
p = Polygon(self)
|
483
|
-
p._elem = translate(self._elem,delta)
|
484
|
-
p._update = True
|
485
|
-
return p
|
486
|
-
|
487
|
-
return translate(self.geom(),delta)
|
488
|
-
|
356
|
+
|
357
|
+
@property
|
489
358
|
def geom(self):
|
490
|
-
if self.
|
359
|
+
if self.update:
|
491
360
|
self._updateInternals()
|
492
|
-
return deepcopy(self.
|
361
|
+
return deepcopy(self.__outline)
|
493
362
|
|
494
|
-
def bbox(self):
|
495
|
-
if self._update:
|
496
|
-
self._updateInternals()
|
497
|
-
return line(self._bbox)
|
498
|
-
|
499
|
-
def isinside(self,p):
|
500
|
-
if self._update:
|
501
|
-
self._updateInternals()
|
502
|
-
bb = self._bbox
|
503
|
-
if not isinsidebbox(bb,p):
|
504
|
-
return False
|
505
|
-
p2 = add([1,1,0,1],bb[1])
|
506
|
-
if vclose(p2,p): ## did we randomly pick an outside point near the
|
507
|
-
## test point?
|
508
|
-
p2 = sub(bb[0],[1,1,0,1])
|
509
|
-
l = line(p,p2)
|
510
|
-
pp = intersectGeomListXY(l,self.geom())
|
511
|
-
if pp == False:
|
512
|
-
return False
|
513
|
-
return len(pp) % 2 == 1
|
514
363
|
|
515
364
|
def grow(self,r):
|
516
365
|
if close(r,0.0):
|
@@ -535,10 +384,12 @@ class Polygon(Polyline):
|
|
535
384
|
elif isgeomlist(e):
|
536
385
|
ne += _growgeom(e)
|
537
386
|
return ne
|
538
|
-
self.
|
539
|
-
self.
|
387
|
+
self._setElem(_growgeom(self.elem))
|
388
|
+
self._setUpdate(True)
|
540
389
|
|
390
|
+
|
541
391
|
def shrink(self,r):
|
392
|
+
raise NotImplementedError('shrink operation not yet implemented')
|
542
393
|
return False
|
543
394
|
|
544
395
|
|
@@ -565,17 +416,20 @@ def cullZeroLength(geom):
|
|
565
416
|
|
566
417
|
|
567
418
|
|
568
|
-
## make a
|
419
|
+
## make a Polygon instance containing a circle as two half-arcs
|
569
420
|
|
570
|
-
def
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
421
|
+
# def Circle(center=point(0,0,0),radius=1.0):
|
422
|
+
# poly = Polygon()
|
423
|
+
# poly.addArc(arc(center,radius,0.0,180.0))
|
424
|
+
# poly.addArc(arc(center,radius,180.0,360.0))
|
425
|
+
# return poly
|
426
|
+
|
427
|
+
def Circle(center=point(0,0,0),radius=1.0):
|
428
|
+
return Geometry(arc(center,radius,0,360))
|
575
429
|
|
576
430
|
## make a rectangle with the specified width and height
|
577
431
|
|
578
|
-
def
|
432
|
+
def Rect(width,height,center=point(0,0,0)):
|
579
433
|
w=width/2.0
|
580
434
|
h=height/2.0
|
581
435
|
p0=add(point(-w,h),center)
|
@@ -592,7 +446,7 @@ def makeRect(width,height,center=point(0,0,0)):
|
|
592
446
|
## make rounded rectangle with specified width, height, and chamfer,
|
593
447
|
## centered at the origin by default
|
594
448
|
|
595
|
-
def
|
449
|
+
def RoundRect(width,height,chamf,center=point(0,0,0)):
|
596
450
|
cr=chamf/2.0
|
597
451
|
wid=width-chamf
|
598
452
|
hei=height-chamf
|