yapCAD 0.3.0__py2.py3-none-any.whl → 0.3.1__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.3.1.dist-info}/METADATA +92 -38
- yapcad-0.3.1.dist-info/RECORD +27 -0
- yapcad-0.3.0.dist-info/RECORD +0 -17
- {yapcad-0.3.0.dist-info → yapcad-0.3.1.dist-info}/WHEEL +0 -0
- {yapcad-0.3.0.dist-info → yapcad-0.3.1.dist-info}/licenses/AUTHORS.rst +0 -0
- {yapcad-0.3.0.dist-info → yapcad-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {yapcad-0.3.0.dist-info → yapcad-0.3.1.dist-info}/licenses/LICENSE.txt +0 -0
- {yapcad-0.3.0.dist-info → yapcad-0.3.1.dist-info}/top_level.txt +0 -0
yapcad/combine.py
CHANGED
@@ -1,392 +1,98 @@
|
|
1
1
|
## yapCAD boolen operation support
|
2
2
|
|
3
3
|
from yapcad.geom import *
|
4
|
-
from yapcad.
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
class Boolean(IntersectGeometry):
|
4
|
+
from yapcad.geom_util import *
|
5
|
+
from yapcad.geometry import *
|
6
|
+
from yapcad.poly import cullZeroLength
|
7
|
+
class Boolean(Geometry):
|
9
8
|
"""Boolean operations on Polygons"""
|
10
9
|
|
11
10
|
types = ('union','intersection','difference')
|
12
|
-
|
13
|
-
def __init__(self, type='union', polys=None):
|
14
|
-
super().__init__()
|
15
|
-
if type not in self.types:
|
16
|
-
raise ValueError('invalid type passed to Boolean(): {}'.format(type))
|
17
11
|
|
18
|
-
|
19
|
-
|
12
|
+
def __repr__(self):
|
13
|
+
return f"Boolean({self.type},{self.elem})"
|
20
14
|
|
15
|
+
def __init__(self,type='union',polys=[]):
|
16
|
+
super().__init__()
|
17
|
+
self._setClosed(True)
|
18
|
+
self._setSampleable(True)
|
19
|
+
if not type in self.types:
|
20
|
+
raise ValueError('invalid type passed to Boolean(): {}'.format(type))
|
21
21
|
for p in polys:
|
22
|
-
if not (isinstance(p,
|
23
|
-
raise ValueError('
|
24
|
-
|
25
|
-
|
26
|
-
self.
|
27
|
-
self.
|
28
|
-
self.
|
29
|
-
|
30
|
-
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
if
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
# condition where u2 is smaller than u1, it's possible that
|
48
|
-
# this represents an arc in the counter-clockwise direction
|
49
|
-
# between u2 and u1. It also could represent a clockwise arc
|
50
|
-
# that "wraps around" from u1 to (u2+1). We will check for
|
51
|
-
# values x1, x2 in ilist that are u2 < x1 < u1 and u1 < x2 <
|
52
|
-
# (u2+1.0). The existance of x1 or x2 rules out the
|
53
|
-
# corresponding arc. If neither x1 nor x2 exists, we bias
|
54
|
-
# towards the counter-clockwise arc.
|
55
|
-
|
56
|
-
def between(u1,u2,ilist):
|
57
|
-
if len(ilist) < 2:
|
58
|
-
raise ValueError('bad ilist')
|
22
|
+
if not ( isinstance(p,Geometry) and p.isclosed()):
|
23
|
+
raise ValueError('not closed Geometry instance: {}'.format(p))
|
24
|
+
self.elem.append(deepcopy(p))
|
25
|
+
|
26
|
+
self.__type=type
|
27
|
+
self._setUpdate(True)
|
28
|
+
self.__outline=[]
|
29
|
+
|
30
|
+
@property
|
31
|
+
def type(self):
|
32
|
+
return self.__type
|
33
|
+
|
34
|
+
def _combine_geom(self,g1,g2):
|
35
|
+
gl1 = g1.geom
|
36
|
+
gl2 = g2.geom
|
37
|
+
|
38
|
+
return combineglist(gl1,gl2,self.type)
|
39
|
+
|
40
|
+
def _calcCenter(self):
|
41
|
+
l = len(self.__outline)
|
42
|
+
if l == 0:
|
43
|
+
return None
|
44
|
+
elif l == 1:
|
45
|
+
return center(self.__outline[0]) # center is sole point
|
46
|
+
else:
|
59
47
|
|
60
|
-
if
|
61
|
-
|
62
|
-
|
63
|
-
x1s = list(filter(lambda x: x > u2 and x < u1,ilist))
|
64
|
-
x2s = list(filter(lambda x: x > u1 or x < u2,ilist))
|
65
|
-
l1 = len(x1s)
|
66
|
-
l2 = len(x2s)
|
67
|
-
#print("u1: ",u1," u2: ",u2," ilist: ",ilist," x1s: ",x1s," x2s: ",x2s)
|
68
|
-
if l1 > 0 and l2 > 0:
|
69
|
-
print('WARNING: intersections on both sides')
|
70
|
-
elif l1 > l2:
|
71
|
-
print("AA")
|
72
|
-
if True or self._type == 'union':
|
73
|
-
return u1,u2+1.0,False
|
74
|
-
else:
|
75
|
-
return u2,u1,True
|
76
|
-
else:
|
77
|
-
print("A-")
|
78
|
-
return u2,u1,True
|
79
|
-
|
80
|
-
else:
|
81
|
-
if len(ilist) == 2:
|
82
|
-
return u1,u2,False
|
83
|
-
x1s = list(filter(lambda x: x > u1 and x < u2,ilist))
|
84
|
-
x2s = list(filter(lambda x: x > u2 or x < u1,ilist))
|
85
|
-
l1 = len(x1s)
|
86
|
-
l2 = len(x2s)
|
87
|
-
#print("u1: ",u1," u2: ",u2," ilist: ",ilist," x1s: ",x1s," x2s: ",x2s)
|
88
|
-
if l1 > 0 and l2 > 0:
|
89
|
-
print('WARNING: intersections on both sides')
|
90
|
-
elif l1 > l2:
|
91
|
-
print("BB")
|
92
|
-
|
93
|
-
if True or self._type == 'union':
|
94
|
-
return u2,u1+1,False
|
95
|
-
else:
|
96
|
-
return u1,u2,False
|
97
|
-
else:
|
98
|
-
print("B-")
|
99
|
-
return u1,u2,False
|
48
|
+
if dist(center(self.__outline[0]),
|
49
|
+
center(self.__outline[-1])) < epsilon:
|
50
|
+
l -= 1
|
100
51
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
52
|
+
p = center(self.__outline[0])
|
53
|
+
for i in range(1,l):
|
54
|
+
p = add(center(self.__outline[i]),p)
|
55
|
+
|
56
|
+
return scale3(p,1/l)
|
57
|
+
|
58
|
+
def translate(self,delta):
|
59
|
+
self._setUpdate(True)
|
60
|
+
for p in self.elem:
|
61
|
+
p.translate(delta)
|
62
|
+
|
63
|
+
def scale(self,sx,sy=False,sz=False,cent=point(0,0)):
|
64
|
+
self._setUpdate(True)
|
65
|
+
for p in self.elem:
|
66
|
+
p.scale(sx,sy,sz,cent)
|
67
|
+
|
68
|
+
def rotate(self,angle,cent=point(0,0,0),axis=point(0,0,1)):
|
69
|
+
self._setUpdate(True)
|
70
|
+
for p in self.elem:
|
71
|
+
p.rotate(angle,cent,axis)
|
72
|
+
|
73
|
+
def mirror(self,plane):
|
74
|
+
self._setUpdate(True)
|
75
|
+
for p in self.elem:
|
76
|
+
p.mirror(plane)
|
77
|
+
|
78
|
+
def transform(self,m):
|
79
|
+
self._setUpdate(True)
|
80
|
+
for p in self.elem:
|
81
|
+
p.transform(m)
|
115
82
|
|
116
|
-
|
117
|
-
if g1e < g1s:
|
118
|
-
g1e+=1.0
|
119
|
-
#g1s,g1e,g1reverse = between(g1s,g1e,inter[0])
|
120
|
-
g2s,g2e,g2reverse = between(g2s,g2e,inter[1])
|
121
|
-
g2reverse = False
|
122
|
-
else:
|
123
|
-
if g1e < g1s:
|
124
|
-
g1e+=1.0
|
125
|
-
if g2e < g2s:
|
126
|
-
g2e += 1.0
|
127
|
-
|
128
|
-
p1=g1.sample(((g1s+g1e)/2)%1.0)
|
129
|
-
|
130
|
-
p1inside=0
|
131
|
-
for i in range(5):
|
132
|
-
u = (i+1)/6.0
|
133
|
-
p = g1.sample((u*g1e+(1.0-u)*g1s)%1.0)
|
134
|
-
if g2.isinside(p):
|
135
|
-
p1inside=p1inside+1
|
136
|
-
|
137
|
-
p2inside = 0
|
138
|
-
for i in range(5):
|
139
|
-
u = (i+1)/6.0
|
140
|
-
p = g2.sample((u*g2e+(1.0-u)*g2s)%1.0)
|
141
|
-
if g1.isinside(p):
|
142
|
-
p2inside=p2inside+1
|
143
|
-
|
144
|
-
if p1inside > 0 and p2inside > 0:
|
145
|
-
print("warning: inside test succeeded for both p1s and p2s: ",
|
146
|
-
p1inside," ",p2inside)
|
147
|
-
|
148
|
-
if p1inside == 0 and p2inside == 0:
|
149
|
-
print("warning: inside test failed for both p1s and p2s")
|
150
|
-
|
151
|
-
p2=g2.sample(((g2s+g2e)/2)%1.0)
|
152
|
-
|
153
|
-
if ZLEN1 and ZLEN2:
|
154
|
-
print ('both segments zero length')
|
155
|
-
return []
|
156
|
-
elif ZLEN2 and not ZLEN1:
|
157
|
-
print ('zero length segment 2')
|
158
|
-
if self._type=='union':
|
159
|
-
return g1.segment(g1s,g1e)
|
160
|
-
elif self._type=='difference':
|
161
|
-
return
|
162
|
-
else: #intersection
|
163
|
-
return []
|
164
|
-
elif ZLEN1 and not ZLEN2:
|
165
|
-
print ('zero length segment 1')
|
166
|
-
if self._type=='union':
|
167
|
-
if g2e < g2s:
|
168
|
-
g2e += 1.0
|
169
|
-
return g2.segment(g2s,g2e)
|
170
|
-
else: # difference or intersection
|
171
|
-
return []
|
172
|
-
|
173
|
-
if self._type == 'union':
|
174
|
-
#if g2.isinside(p1):
|
175
|
-
if p1inside > p2inside:
|
176
|
-
# if g2e < g2s:
|
177
|
-
# g2e += 1.0
|
178
|
-
seg += g2.segment(g2s,g2e)
|
179
|
-
else:
|
180
|
-
seg += g1.segment(g1s,g1e)
|
181
|
-
elif self._type == 'intersection':
|
182
|
-
#if g2.isinside(p1):
|
183
|
-
if p1inside > p2inside:
|
184
|
-
seg += g1.segment(g1s,g1e)
|
185
|
-
else:
|
186
|
-
# if g2e < g2s:
|
187
|
-
# g2e += 1.0
|
188
|
-
#seg += g2.segment(g2s,g2e,reverse=g2reverse)
|
189
|
-
seg += g2.segment(g2s,g2e)
|
190
|
-
elif self._type == 'difference':
|
191
|
-
s = []
|
192
|
-
#if g2.isinside(p1):
|
193
|
-
if p1inside > p2inside:
|
194
|
-
pass
|
195
|
-
else:
|
196
|
-
# print("rsort: ",vstr(inter))
|
197
|
-
seg += g1.segment(g1s,g1e)
|
198
|
-
# print("g2s: ",g2s," g2e: ",g2e," g2reverse: ",g2reverse)
|
199
|
-
s = g2.segment(g2s,g2e,reverse=g2reverse)
|
200
|
-
s = reverseGeomList(s)
|
201
|
-
seg += s
|
202
|
-
if len(inter[0]) > 2:
|
203
|
-
combineDebugGL.append(s)
|
204
|
-
# print("seg: ",vstr(seg))
|
205
|
-
|
206
|
-
return seg
|
207
|
-
|
208
|
-
## utility function to sort intersections into non-decreasing
|
209
|
-
## order
|
210
|
-
def rsort(il):
|
211
|
-
nl = []
|
212
|
-
rl = []
|
213
|
-
rr = []
|
214
|
-
for i in range(len(il[0])):
|
215
|
-
nl.append([il[0][i],il[1][i]])
|
216
|
-
nl.sort(key=lambda x: x[0])
|
217
|
-
for i in range(len(nl)):
|
218
|
-
rl.append(nl[i][0])
|
219
|
-
rr.append(nl[i][1])
|
220
|
-
return [rl,rr]
|
221
|
-
|
222
|
-
if inter == False: # disjoint, but bounding boxes might be
|
223
|
-
# null or one could be inside the other
|
224
|
-
if not bbox1 and bbox2: # g1 is empty, but g2 contains geometry
|
225
|
-
if self._type=='union':
|
226
|
-
return g2.geom()
|
227
|
-
else:
|
228
|
-
return []
|
229
|
-
if bbox1 and not bbox2: # g2 is empty, but g1 isn't
|
230
|
-
if self._type=='union' or self._type=='difference':
|
231
|
-
return g1.geom()
|
232
|
-
if not bbox1 and not bbox2: # no geometry at all
|
233
|
-
return []
|
234
|
-
## OK, no intersection but it is possible that one profile
|
235
|
-
## could be inside the other. Do fast bounding box checks
|
236
|
-
## before doing intersection-based checking.
|
237
|
-
if isinsidebbox(bbox1,bbox2[0]) and isinsidebbox(bbox1,bbox2[1]) \
|
238
|
-
and g1.isinside(g2.sample(0.0)): # g2 is inside g1
|
239
|
-
## g2 is inside g1
|
240
|
-
if self._type == 'union':
|
241
|
-
return g1.geom()
|
242
|
-
elif self._type == 'intersection':
|
243
|
-
return g2.geom()
|
244
|
-
else: #difference, g2 is a hole in g1
|
245
|
-
return [g1.geom(),g2.geom()]
|
246
|
-
elif isinsidebbox(bbox2,bbox1[0]) and isinsidebbox(bbox2,bbox1[1]) \
|
247
|
-
and g2.isinside(g1.sample(0.0)): # g1 is inside g2
|
248
|
-
## g1 is indside g2
|
249
|
-
if self._type == 'union':
|
250
|
-
return g2.geom()
|
251
|
-
elif self._type == 'intersection':
|
252
|
-
return g1.geom()
|
253
|
-
else: #difference, g2 has eaten g1
|
254
|
-
return []
|
255
|
-
else: # g1 and g2 are disjoint
|
256
|
-
if self._type == 'union':
|
257
|
-
return [g1.geom(),g2.geom()]
|
258
|
-
elif self._type == 'difference':
|
259
|
-
return g1.geom()
|
260
|
-
else: #intersection
|
261
|
-
return []
|
262
|
-
if len(inter[0]) == 1 and len(inter[1]) == 1:
|
263
|
-
## single point of intersection:
|
264
|
-
if self._type == 'union':
|
265
|
-
return [g1.geom(), g2.geom()]
|
266
|
-
elif self._type == 'difference':
|
267
|
-
return g1.geom()
|
268
|
-
else: #intersection
|
269
|
-
return []
|
270
|
-
## There are two or more points of intersection.
|
271
|
-
inter = rsort(inter)
|
272
|
-
#print("rsort: ",vstr(inter))
|
273
|
-
|
274
|
-
if len(inter[0]) %2 != 0:
|
275
|
-
print("WARNING: odd number of intersections (",len(inter[0]),", unpredictable behavior may result")
|
276
|
-
r = []
|
277
|
-
for i in range(1,len(inter[0])+1):
|
278
|
-
r += cmbin(g1,g2,[[inter[0][i-1],
|
279
|
-
inter[0][i%len(inter[0])]],
|
280
|
-
[inter[1][i-1],
|
281
|
-
inter[1][i%len(inter[1])]]])
|
282
|
-
return r
|
283
|
-
|
284
|
-
def bbox(self):
|
285
|
-
return bbox(self.geom())
|
286
|
-
|
287
|
-
def getCenter(self):
|
288
|
-
gl = self.geom()
|
289
|
-
if gl == []:
|
290
|
-
raise ValueError('empty Boolean, no center')
|
291
|
-
return center(gl)
|
292
|
-
|
293
|
-
def getLength(self):
|
294
|
-
gl = self.geom()
|
295
|
-
if gl == []:
|
296
|
-
raise ValueError('empty Boolean, no length')
|
297
|
-
return length(gl)
|
298
|
-
|
299
|
-
def segment(self,u1,u2,reverse=False):
|
300
|
-
gl = self.geom()
|
301
|
-
if gl == []:
|
302
|
-
raise ValueError('empty Boolean, segment not defined')
|
303
|
-
return segmentgeomlist(gl,u1,u2,closed=True,reverse=reverse)
|
304
|
-
|
305
|
-
def mirror(self,plane,poly=False):
|
306
|
-
b = deepcopy(self)
|
307
|
-
b._elem = []
|
308
|
-
b._update=True
|
309
|
-
for p in self._elem:
|
310
|
-
p2 = p.mirror(plane,poly=True)
|
311
|
-
b._elem.append(p2)
|
312
|
-
if poly:
|
313
|
-
return b
|
314
|
-
return b.geom()
|
315
|
-
|
316
|
-
def rotate(self,angle,cent=point(0,0,0),axis=point(0,0,1),poly=False):
|
317
|
-
b = deepcopy(self)
|
318
|
-
b._elem = []
|
319
|
-
b._update=True
|
320
|
-
for p in self._elem:
|
321
|
-
p2 = p.rotate(angle,cent,axis,poly=True)
|
322
|
-
b._elem.append(p2)
|
323
|
-
if poly:
|
324
|
-
return b
|
325
|
-
return b.geom()
|
326
|
-
|
327
|
-
def scale(self,sx,sy=False,sz=False,cent=point(0,0),poly=False):
|
328
|
-
b = deepcopy(self)
|
329
|
-
b._elem = []
|
330
|
-
b._update=True
|
331
|
-
for p in self._elem:
|
332
|
-
p2 = p.scale(sx,sy,sz,cent,poly=True)
|
333
|
-
b._elem.append(p2)
|
334
|
-
if poly:
|
335
|
-
return b
|
336
|
-
return b.geom()
|
337
|
-
|
338
|
-
def translate(self,delta,poly=False):
|
339
|
-
b = deepcopy(self)
|
340
|
-
b._elem = []
|
341
|
-
b._update=True
|
342
|
-
for p in self._elem:
|
343
|
-
p2 = p.translate(delta,poly=True)
|
344
|
-
b._elem.append(p2)
|
345
|
-
if poly:
|
346
|
-
return b
|
347
|
-
return b.geom()
|
348
|
-
|
349
|
-
def sample(self,u):
|
350
|
-
gl = self.geom()
|
351
|
-
if gl == []:
|
352
|
-
raise ValueError('empty Boolean, sample not defined')
|
353
|
-
return sample(gl,u)
|
354
|
-
|
355
|
-
def isinside(self,p):
|
356
|
-
gm = self.geom()
|
357
|
-
if gm == []:
|
358
|
-
raise ValueError('empty Boolean, inside not defined')
|
359
|
-
bb = bbox(gm)
|
360
|
-
p2 = add([1,1,0,1],bb[1])
|
361
|
-
l = line(p,p2)
|
362
|
-
|
363
|
-
pp = intersectGeomListXY(l,gm)
|
364
|
-
if pp == False:
|
365
|
-
return False
|
366
|
-
return len(pp) % 2 == 1
|
367
|
-
|
368
|
-
def grow(self,r):
|
369
|
-
if close(r,0.0):
|
370
|
-
return
|
371
|
-
elif r < 0:
|
372
|
-
raise ValueError('negative growth not allowed')
|
373
|
-
|
374
|
-
if self._type in ['union','intersection']:
|
375
|
-
for p in self._elem:
|
376
|
-
p.grow(r)
|
377
|
-
self._update = True
|
378
|
-
else:
|
379
|
-
raise NotImplementedError("Don't have grow support for {} yet".format(self._type))
|
380
|
-
|
381
|
-
|
83
|
+
@property
|
382
84
|
def geom(self):
|
383
|
-
if self.
|
384
|
-
if len(self.
|
385
|
-
self.
|
386
|
-
self.
|
387
|
-
self.
|
85
|
+
if self.update:
|
86
|
+
if len(self.elem)==2:
|
87
|
+
self.__outline = self._combine_geom(self.elem[0],self.elem[1])
|
88
|
+
self.__outline = cullZeroLength(self.__outline)
|
89
|
+
self._setUpdate(False)
|
90
|
+
self._setBbox(bbox(self.__outline))
|
91
|
+
self._setLength(length(self.__outline))
|
92
|
+
self._setCenter(self._calcCenter())
|
388
93
|
else:
|
389
|
-
raise NotImplementedError(
|
390
|
-
|
94
|
+
raise NotImplementedError(
|
95
|
+
f"don't know how to do {self.type} yet for {len(self.elem)} polygons")
|
96
|
+
return deepcopy(self.__outline)
|
391
97
|
|
392
98
|
|
yapcad/drawable.py
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
## See licensing terms here: https://github.com/rdevaul/yapCAD/blob/master/LICENSE
|
6
6
|
|
7
7
|
from yapcad.geom import *
|
8
|
+
from yapcad.geometry import *
|
8
9
|
|
9
10
|
## Generic drawing functions -- assumed to use current coordinate
|
10
11
|
## transform and drawing pen (color, line weight, etc.)
|
@@ -56,6 +57,40 @@ class Drawable:
|
|
56
57
|
if 'o' in self.__pointstyle:
|
57
58
|
self.draw_circle(p,self.__pointsize)
|
58
59
|
|
60
|
+
## utility function to draw a 2D or 3D bounding box
|
61
|
+
def draw_bbox(self,box,dim3=False):
|
62
|
+
length = box[1][0]-box[0][0]
|
63
|
+
width = box[1][1]-box[0][1]
|
64
|
+
height = box[1][2]-box[0][2]
|
65
|
+
|
66
|
+
p0=box[0]
|
67
|
+
p1=add(p0,point(length,0,0))
|
68
|
+
p2=add(p1,point(0,width,0))
|
69
|
+
p3=add(p0,point(0,width,0))
|
70
|
+
|
71
|
+
self.draw_line(p0,p1)
|
72
|
+
self.draw_line(p1,p2)
|
73
|
+
self.draw_line(p2,p3)
|
74
|
+
self.draw_line(p3,p0)
|
75
|
+
|
76
|
+
if not dim3:
|
77
|
+
return
|
78
|
+
|
79
|
+
p4=add(p0,point(0,0,height))
|
80
|
+
p5=add(p4,point(length,0,0))
|
81
|
+
p6=box[1]
|
82
|
+
p7=add(p4,point(0,width,0))
|
83
|
+
|
84
|
+
self.draw_line(p4,p5)
|
85
|
+
self.draw_line(p5,p6)
|
86
|
+
self.draw_line(p6,p7)
|
87
|
+
self.draw_line(p7,p4)
|
88
|
+
|
89
|
+
self.draw_line(p0,p4)
|
90
|
+
self.draw_line(p1,p5)
|
91
|
+
self.draw_line(p2,p6)
|
92
|
+
self.draw_line(p3,p7)
|
93
|
+
|
59
94
|
def __init__(self):
|
60
95
|
self.__pointstyle = 'xo'
|
61
96
|
self.__pointsize = 0.1
|
@@ -108,7 +143,7 @@ class Drawable:
|
|
108
143
|
|
109
144
|
@polystyle.setter
|
110
145
|
def polystyle(self,pst=False):
|
111
|
-
if pst in [
|
146
|
+
if pst in ['points','lines','both']:
|
112
147
|
self._set_polystyle(pst)
|
113
148
|
else:
|
114
149
|
raise ValueError('bad polystyle')
|
@@ -251,11 +286,17 @@ class Drawable:
|
|
251
286
|
else:
|
252
287
|
raise ValueError("bad value for polystyle: {}".format(self.polystyle))
|
253
288
|
|
254
|
-
elif
|
289
|
+
elif isinstance(x,Geometry):
|
290
|
+
gl = x.geom
|
291
|
+
self.draw(gl)
|
292
|
+
elif isinstance(x,list): # could be a geometry list, or a list
|
293
|
+
# that mixes yapcad.geom elements and yapcad.geometry
|
294
|
+
# Geeometry instances. If the list contains an
|
295
|
+
# inappropriate element it will be caught in the "else" case below.
|
255
296
|
for e in x:
|
256
297
|
self.draw(e)
|
257
298
|
else:
|
258
|
-
raise ValueError('bad argument to Drawable.draw(): '
|
299
|
+
raise ValueError(f'bad argument to Drawable.draw(): {x}')
|
259
300
|
|
260
301
|
## cause drawing page to be rendered -- pure virtual in base class
|
261
302
|
def display(self):
|
yapcad/ezdxf_drawable.py
CHANGED