26
import Path.Op.Util as PathOpUtil
27
import Tests.PathTestUtils as PathTestUtils
30
from FreeCAD import Vector
32
Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule())
35
DOC = FreeCAD.getHomePath() + "Mod/CAM/Tests/test_geomop.fcstd"
38
def getWire(obj, nr=0):
39
return obj.Tip.Profile[0].Shape.Wires[nr]
42
def getWireInside(obj):
45
if w2.BoundBox.isInside(w1.BoundBox):
50
def getWireOutside(obj):
53
if w2.BoundBox.isInside(w1.BoundBox):
58
def getPositiveShape(obj):
62
def getNegativeShape(obj):
71
edges.append(Part.Edge(Part.LineSegment(last, p)))
73
edges.append(Part.Edge(Part.LineSegment(last, first)))
74
return Part.Wire(edges)
78
pts = [wire.Edges[0].valueAt(wire.Edges[0].FirstParameter)]
79
for edge in wire.Edges:
80
pts.append(edge.valueAt(edge.LastParameter))
84
class TestPathOpUtil(PathTestUtils.PathTestBase):
87
FreeCAD.ConfigSet("SuppressRecomputeRequiredDialog", "True")
88
cls.doc = FreeCAD.openDocument(DOC)
89
FreeCAD.ConfigSet("SuppressRecomputeRequiredDialog", "")
92
def tearDownClass(cls):
93
FreeCAD.closeDocument(cls.doc.Name)
96
"""Verify isWireClockwise for polygon wires."""
102
self.assertTrue(PathOpUtil.isWireClockwise(makeWire([pa, pb, pc, pd])))
103
self.assertFalse(PathOpUtil.isWireClockwise(makeWire([pa, pd, pc, pb])))
106
"""Verify isWireClockwise for single edge circle wires."""
108
PathOpUtil.isWireClockwise(Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1)))
111
PathOpUtil.isWireClockwise(Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1)))
115
"""Verify isWireClockwise for two half circle wires."""
116
e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1), 0, 180)
117
e1 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1), 180, 360)
118
self.assertTrue(PathOpUtil.isWireClockwise(Part.Wire([e0, e1])))
120
e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1), 0, 180)
121
e1 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1), 180, 360)
122
self.assertFalse(PathOpUtil.isWireClockwise(Part.Wire([e0, e1])))
125
"""Verify isWireClockwise for two edge wires with an arc."""
126
e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1), 0, 180)
127
e2 = Part.makeLine(e0.valueAt(e0.LastParameter), e0.valueAt(e0.FirstParameter))
128
self.assertTrue(PathOpUtil.isWireClockwise(Part.Wire([e0, e2])))
130
e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1), 0, 180)
131
e2 = Part.makeLine(e0.valueAt(e0.LastParameter), e0.valueAt(e0.FirstParameter))
132
self.assertFalse(PathOpUtil.isWireClockwise(Part.Wire([e0, e2])))
135
"""Verify isWireClockwise for unoriented wires."""
136
e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1), 0, 180)
137
e3 = Part.makeLine(e0.valueAt(e0.FirstParameter), e0.valueAt(e0.LastParameter))
138
self.assertTrue(PathOpUtil.isWireClockwise(Part.Wire([e0, e3])))
140
e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1), 0, 180)
141
e3 = Part.makeLine(e0.valueAt(e0.FirstParameter), e0.valueAt(e0.LastParameter))
142
self.assertFalse(PathOpUtil.isWireClockwise(Part.Wire([e0, e3])))
145
"""Check offsetting a circular hole."""
146
obj = self.doc.getObjectsByLabel("offset-circle")[0]
148
small = getWireInside(obj)
149
self.assertRoughly(10, small.Edges[0].Curve.Radius)
151
wire = PathOpUtil.offsetWire(small, obj.Shape, 3, True)
152
self.assertIsNotNone(wire)
153
self.assertEqual(1, len(wire.Edges))
154
self.assertRoughly(7, wire.Edges[0].Curve.Radius)
155
self.assertCoincide(Vector(0, 0, 1), wire.Edges[0].Curve.Axis)
157
wire = PathOpUtil.offsetWire(small, obj.Shape, 9.9, True)
158
self.assertIsNotNone(wire)
159
self.assertEqual(1, len(wire.Edges))
160
self.assertRoughly(0.1, wire.Edges[0].Curve.Radius)
161
self.assertCoincide(Vector(0, 0, 1), wire.Edges[0].Curve.Axis)
164
"""Check offsetting a circular hole by the radius or more makes the hole vanish."""
165
obj = self.doc.getObjectsByLabel("offset-circle")[0]
167
small = getWireInside(obj)
168
self.assertRoughly(10, small.Edges[0].Curve.Radius)
169
wire = PathOpUtil.offsetWire(small, obj.Shape, 10, True)
170
self.assertIsNone(wire)
172
wire = PathOpUtil.offsetWire(small, obj.Shape, 15, True)
173
self.assertIsNone(wire)
176
"""Check offsetting a cylinder succeeds."""
177
obj = self.doc.getObjectsByLabel("offset-circle")[0]
179
big = getWireOutside(obj)
180
self.assertRoughly(20, big.Edges[0].Curve.Radius)
182
wire = PathOpUtil.offsetWire(big, obj.Shape, 10, True)
183
self.assertIsNotNone(wire)
184
self.assertEqual(1, len(wire.Edges))
185
self.assertRoughly(30, wire.Edges[0].Curve.Radius)
186
self.assertCoincide(Vector(0, 0, -1), wire.Edges[0].Curve.Axis)
188
wire = PathOpUtil.offsetWire(big, obj.Shape, 20, True)
189
self.assertIsNotNone(wire)
190
self.assertEqual(1, len(wire.Edges))
191
self.assertRoughly(40, wire.Edges[0].Curve.Radius)
192
self.assertCoincide(Vector(0, 0, -1), wire.Edges[0].Curve.Axis)
195
"""Check offsetting a hole with Placement."""
196
obj = self.doc.getObjectsByLabel("offset-placement")[0]
200
for w in obj.Shape.Wires
201
if 1 == len(w.Edges) and Path.Geom.isRoughly(0, w.Edges[0].Vertexes[0].Point.z)
203
self.assertEqual(2, len(wires))
204
w = wires[1] if wires[0].BoundBox.isInside(wires[1].BoundBox) else wires[0]
206
self.assertRoughly(10, w.Edges[0].Curve.Radius)
208
self.assertFalse(Path.Geom.pointsCoincide(Vector(), w.Edges[0].Placement.Base))
210
wire = PathOpUtil.offsetWire(w, obj.Shape, 2, True)
211
self.assertIsNotNone(wire)
212
self.assertEqual(1, len(wire.Edges))
213
self.assertRoughly(8, wire.Edges[0].Curve.Radius)
214
self.assertCoincide(Vector(0, 0, 0), wire.Edges[0].Curve.Center)
215
self.assertCoincide(Vector(0, 0, 1), wire.Edges[0].Curve.Axis)
218
"""Check offsetting a cylinder with Placement."""
219
obj = self.doc.getObjectsByLabel("offset-placement")[0]
223
for w in obj.Shape.Wires
224
if 1 == len(w.Edges) and Path.Geom.isRoughly(0, w.Edges[0].Vertexes[0].Point.z)
226
self.assertEqual(2, len(wires))
227
w = wires[0] if wires[0].BoundBox.isInside(wires[1].BoundBox) else wires[1]
229
self.assertRoughly(20, w.Edges[0].Curve.Radius)
231
self.assertFalse(Path.Geom.pointsCoincide(Vector(), w.Edges[0].Placement.Base))
233
wire = PathOpUtil.offsetWire(w, obj.Shape, 2, True)
234
self.assertIsNotNone(wire)
235
self.assertEqual(1, len(wire.Edges))
236
self.assertRoughly(22, wire.Edges[0].Curve.Radius)
237
self.assertCoincide(Vector(0, 0, 0), wire.Edges[0].Curve.Center)
238
self.assertCoincide(Vector(0, 0, -1), wire.Edges[0].Curve.Axis)
241
"""Check offsetting hole wire succeeds."""
242
obj = self.doc.getObjectsByLabel("offset-edge")[0]
244
small = getWireInside(obj)
247
x = 10 * math.cos(math.pi / 6)
253
Vector(-x, -y / 2, 0),
254
Vector(x, -y / 2, 0),
259
wire = PathOpUtil.offsetWire(small, obj.Shape, 3, True)
260
self.assertIsNotNone(wire)
261
self.assertEqual(3, len(wire.Edges))
262
self.assertTrue(wire.isClosed())
264
self.assertFalse(PathOpUtil.isWireClockwise(wire))
266
x = 4 * math.cos(math.pi / 6)
270
[Vector(0, 4, 0), Vector(-x, -2, 0), Vector(x, -2, 0), Vector(0, 4, 0)],
274
"""Check offsetting hole wire for more than it's size makes hole vanish."""
275
obj = self.doc.getObjectsByLabel("offset-edge")[0]
277
small = getWireInside(obj)
280
x = 10 * math.cos(math.pi / 6)
286
Vector(-x, -y / 2, 0),
287
Vector(x, -y / 2, 0),
291
wire = PathOpUtil.offsetWire(small, obj.Shape, 5, True)
292
self.assertIsNone(wire)
295
"""Check offsetting a body wire succeeds."""
296
obj = self.doc.getObjectsByLabel("offset-edge")[0]
298
big = getWireOutside(obj)
301
x = 20 * math.cos(math.pi / 6)
307
Vector(-x, -y / 2, 0),
308
Vector(x, -y / 2, 0),
313
wire = PathOpUtil.offsetWire(big, obj.Shape, 5, True)
314
self.assertIsNotNone(wire)
315
self.assertEqual(6, len(wire.Edges))
317
refAngle = math.pi / 3
319
if Part.Circle == type(e.Curve):
320
self.assertRoughly(5, e.Curve.Radius)
321
self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis)
323
self.assertRoughly(34.641, e.Length, 0.001)
324
begin = e.Vertexes[0].Point
325
end = e.Vertexes[1].Point
327
angle = Path.Geom.getAngle(v)
328
if Path.Geom.isRoughly(0, angle) or Path.Geom.isRoughly(math.pi, math.fabs(angle)):
330
self.assertRoughly(-refAngle, lastAngle)
331
elif Path.Geom.isRoughly(+refAngle, angle):
333
self.assertRoughly(math.pi, math.fabs(lastAngle))
334
elif Path.Geom.isRoughly(-refAngle, angle):
336
self.assertRoughly(+refAngle, lastAngle)
338
self.assertIsNone("%s: angle=%s" % (type(e.Curve), angle))
340
self.assertTrue(PathOpUtil.isWireClockwise(wire))
343
"""Check offsetting a cylinder."""
344
obj = self.doc.getObjectsByLabel("circle-cut")[0]
346
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, True)
347
self.assertEqual(1, len(wire.Edges))
349
self.assertCoincide(Vector(), edge.Curve.Center)
350
self.assertCoincide(Vector(0, 0, -1), edge.Curve.Axis)
351
self.assertRoughly(33, edge.Curve.Radius)
354
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, False)
355
self.assertEqual(1, len(wire.Edges))
357
self.assertCoincide(Vector(), edge.Curve.Center)
358
self.assertCoincide(Vector(0, 0, +1), edge.Curve.Axis)
359
self.assertRoughly(33, edge.Curve.Radius)
362
"""Check offsetting a box."""
363
obj = self.doc.getObjectsByLabel("square-cut")[0]
365
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, True)
366
self.assertEqual(8, len(wire.Edges))
367
self.assertEqual(4, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
368
self.assertEqual(4, len([e for e in wire.Edges if Part.Circle == type(e.Curve)]))
370
if Part.Line == type(e.Curve):
371
if Path.Geom.isRoughly(e.Vertexes[0].Point.x, e.Vertexes[1].Point.x):
372
self.assertEqual(40, e.Length)
373
if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y):
374
self.assertEqual(60, e.Length)
375
if Part.Circle == type(e.Curve):
376
self.assertRoughly(3, e.Curve.Radius)
377
self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis)
378
self.assertTrue(PathOpUtil.isWireClockwise(wire))
381
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, False)
382
self.assertEqual(8, len(wire.Edges))
383
self.assertEqual(4, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
384
self.assertEqual(4, len([e for e in wire.Edges if Part.Circle == type(e.Curve)]))
386
if Part.Line == type(e.Curve):
387
if Path.Geom.isRoughly(e.Vertexes[0].Point.x, e.Vertexes[1].Point.x):
388
self.assertEqual(40, e.Length)
389
if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y):
390
self.assertEqual(60, e.Length)
391
if Part.Circle == type(e.Curve):
392
self.assertRoughly(3, e.Curve.Radius)
393
self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis)
394
self.assertFalse(PathOpUtil.isWireClockwise(wire))
397
"""Check offsetting a triangle."""
398
obj = self.doc.getObjectsByLabel("triangle-cut")[0]
400
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, True)
401
self.assertEqual(6, len(wire.Edges))
402
self.assertEqual(3, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
403
self.assertEqual(3, len([e for e in wire.Edges if Part.Circle == type(e.Curve)]))
404
length = 60 * math.sin(math.radians(60))
406
if Part.Line == type(e.Curve):
407
self.assertRoughly(length, e.Length)
408
if Part.Circle == type(e.Curve):
409
self.assertRoughly(3, e.Curve.Radius)
410
self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis)
413
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, False)
414
self.assertEqual(6, len(wire.Edges))
415
self.assertEqual(3, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
416
self.assertEqual(3, len([e for e in wire.Edges if Part.Circle == type(e.Curve)]))
418
if Part.Line == type(e.Curve):
419
self.assertRoughly(length, e.Length)
420
if Part.Circle == type(e.Curve):
421
self.assertRoughly(3, e.Curve.Radius)
422
self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis)
425
"""Check offsetting a shape."""
426
obj = self.doc.getObjectsByLabel("shape-cut")[0]
428
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, True)
429
self.assertEqual(6, len(wire.Edges))
430
self.assertEqual(3, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
431
self.assertEqual(3, len([e for e in wire.Edges if Part.Circle == type(e.Curve)]))
435
if Part.Line == type(e.Curve):
436
self.assertRoughly(length, e.Length)
437
if Part.Circle == type(e.Curve):
438
self.assertRoughly(radius, e.Curve.Radius)
439
self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis)
442
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, False)
443
self.assertEqual(6, len(wire.Edges))
444
self.assertEqual(3, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
445
self.assertEqual(3, len([e for e in wire.Edges if Part.Circle == type(e.Curve)]))
447
if Part.Line == type(e.Curve):
448
self.assertRoughly(length, e.Length)
449
if Part.Circle == type(e.Curve):
450
self.assertRoughly(radius, e.Curve.Radius)
451
self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis)
454
"""Check offsetting a cylindrical hole."""
455
obj = self.doc.getObjectsByLabel("circle-cut")[0]
457
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, True)
458
self.assertEqual(1, len(wire.Edges))
460
self.assertCoincide(Vector(), edge.Curve.Center)
461
self.assertCoincide(Vector(0, 0, +1), edge.Curve.Axis)
462
self.assertRoughly(27, edge.Curve.Radius)
465
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, False)
466
self.assertEqual(1, len(wire.Edges))
468
self.assertCoincide(Vector(), edge.Curve.Center)
469
self.assertCoincide(Vector(0, 0, -1), edge.Curve.Axis)
470
self.assertRoughly(27, edge.Curve.Radius)
473
"""Check offsetting a square hole."""
474
obj = self.doc.getObjectsByLabel("square-cut")[0]
476
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, True)
477
self.assertEqual(4, len(wire.Edges))
478
self.assertEqual(4, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
480
if Path.Geom.isRoughly(e.Vertexes[0].Point.x, e.Vertexes[1].Point.x):
481
self.assertRoughly(34, e.Length)
482
if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y):
483
self.assertRoughly(54, e.Length)
484
self.assertFalse(PathOpUtil.isWireClockwise(wire))
487
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, False)
488
self.assertEqual(4, len(wire.Edges))
489
self.assertEqual(4, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
491
if Path.Geom.isRoughly(e.Vertexes[0].Point.x, e.Vertexes[1].Point.x):
492
self.assertRoughly(34, e.Length)
493
if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y):
494
self.assertRoughly(54, e.Length)
495
self.assertTrue(PathOpUtil.isWireClockwise(wire))
498
"""Check offsetting a triangular holee."""
499
obj = self.doc.getObjectsByLabel("triangle-cut")[0]
501
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, True)
502
self.assertEqual(3, len(wire.Edges))
503
self.assertEqual(3, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
504
length = 48 * math.sin(math.radians(60))
506
self.assertRoughly(length, e.Length)
507
self.assertFalse(PathOpUtil.isWireClockwise(wire))
510
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, False)
511
self.assertEqual(3, len(wire.Edges))
512
self.assertEqual(3, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
514
self.assertRoughly(length, e.Length)
515
self.assertTrue(PathOpUtil.isWireClockwise(wire))
518
"""Check offsetting a shape hole."""
519
obj = self.doc.getObjectsByLabel("shape-cut")[0]
521
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, True)
522
self.assertEqual(6, len(wire.Edges))
523
self.assertEqual(3, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
524
self.assertEqual(3, len([e for e in wire.Edges if Part.Circle == type(e.Curve)]))
528
if Part.Line == type(e.Curve):
529
self.assertRoughly(length, e.Length)
530
if Part.Circle == type(e.Curve):
531
self.assertRoughly(radius, e.Curve.Radius)
532
self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis)
535
wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, False)
536
self.assertEqual(6, len(wire.Edges))
537
self.assertEqual(3, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
538
self.assertEqual(3, len([e for e in wire.Edges if Part.Circle == type(e.Curve)]))
540
if Part.Line == type(e.Curve):
541
self.assertRoughly(length, e.Length)
542
if Part.Circle == type(e.Curve):
543
self.assertRoughly(radius, e.Curve.Radius)
544
self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis)
547
"""Check offsetting a single outside edge forward."""
548
obj = self.doc.getObjectsByLabel("offset-edge")[0]
550
w = getWireOutside(obj)
551
length = 40 * math.cos(math.pi / 6)
553
self.assertRoughly(length, e.Length)
557
e for e in w.Edges if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y)
562
self.assertEqual(1, len(hEdges))
565
self.assertCoincide(Vector(-x, y, 0), edge.Vertexes[0].Point)
566
self.assertCoincide(Vector(+x, y, 0), edge.Vertexes[1].Point)
568
wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 5, True)
569
self.assertEqual(1, len(wire.Edges))
572
self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point)
573
self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[1].Point)
576
edge = Path.Geom.flipEdge(edge)
577
wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 5, True)
578
self.assertEqual(1, len(wire.Edges))
580
self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point)
581
self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[1].Point)
584
"""Check offsetting a single outside edge not forward."""
585
obj = self.doc.getObjectsByLabel("offset-edge")[0]
587
w = getWireOutside(obj)
588
length = 40 * math.cos(math.pi / 6)
590
self.assertRoughly(length, e.Length)
594
e for e in w.Edges if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y)
599
self.assertEqual(1, len(hEdges))
601
self.assertCoincide(Vector(-x, y, 0), edge.Vertexes[0].Point)
602
self.assertCoincide(Vector(+x, y, 0), edge.Vertexes[1].Point)
604
wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 5, False)
605
self.assertEqual(1, len(wire.Edges))
608
self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point)
609
self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[1].Point)
612
edge = Path.Geom.flipEdge(edge)
613
wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 5, False)
614
self.assertEqual(1, len(wire.Edges))
616
self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point)
617
self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[1].Point)
620
"""Check offsetting multiple outside edges."""
621
obj = self.doc.getObjectsByLabel("offset-edge")[0]
622
obj.Shape.tessellate(0.01)
625
w = getWireOutside(obj)
626
length = 40 * math.cos(math.pi / 6)
632
if not Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y)
634
self.assertEqual(2, len(lEdges))
636
wire = PathOpUtil.offsetWire(Part.Wire(lEdges), obj.Shape, 2, True)
638
x = length / 2 + 2 * math.cos(math.pi / 6)
639
y = -10 + 2 * math.sin(math.pi / 6)
641
self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point)
642
self.assertCoincide(Vector(+x, y, 0), wire.Edges[-1].Vertexes[1].Point)
644
rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)]
646
self.assertEqual(1, len(rEdges))
647
self.assertCoincide(Vector(0, 20, 0), rEdges[0].Curve.Center)
648
self.assertCoincide(Vector(0, 0, -1), rEdges[0].Curve.Axis)
651
wire = PathOpUtil.offsetWire(Part.Wire(lEdges), obj.Shape, 2, False)
653
self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point)
654
self.assertCoincide(Vector(-x, y, 0), wire.Edges[-1].Vertexes[1].Point)
656
rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)]
658
self.assertEqual(1, len(rEdges))
659
self.assertCoincide(Vector(0, 20, 0), rEdges[0].Curve.Center)
660
self.assertCoincide(Vector(0, 0, +1), rEdges[0].Curve.Axis)
663
"""Check offsetting multiple backwards outside edges."""
666
obj = self.doc.getObjectsByLabel("offset-edge")[0]
668
w = getWireOutside(obj)
669
length = 40 * math.cos(math.pi / 6)
675
if not Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y)
677
self.assertEqual(2, len(lEdges))
679
w = Path.Geom.flipWire(Part.Wire(lEdges))
680
wire = PathOpUtil.offsetWire(w, obj.Shape, 2, True)
682
x = length / 2 + 2 * math.cos(math.pi / 6)
683
y = -10 + 2 * math.sin(math.pi / 6)
685
self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point)
686
self.assertCoincide(Vector(+x, y, 0), wire.Edges[-1].Vertexes[1].Point)
688
rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)]
690
self.assertEqual(1, len(rEdges))
691
self.assertCoincide(Vector(0, 20, 0), rEdges[0].Curve.Center)
692
self.assertCoincide(Vector(0, 0, -1), rEdges[0].Curve.Axis)
695
wire = PathOpUtil.offsetWire(Part.Wire(lEdges), obj.Shape, 2, False)
697
self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point)
698
self.assertCoincide(Vector(-x, y, 0), wire.Edges[-1].Vertexes[1].Point)
700
rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)]
702
self.assertEqual(1, len(rEdges))
703
self.assertCoincide(Vector(0, 20, 0), rEdges[0].Curve.Center)
704
self.assertCoincide(Vector(0, 0, +1), rEdges[0].Curve.Axis)
707
"""Check offsetting a single inside edge forward."""
708
obj = self.doc.getObjectsByLabel("offset-edge")[0]
710
w = getWireInside(obj)
711
length = 20 * math.cos(math.pi / 6)
713
self.assertRoughly(length, e.Length)
717
e for e in w.Edges if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y)
722
self.assertEqual(1, len(hEdges))
725
self.assertCoincide(Vector(-x, y, 0), edge.Vertexes[0].Point)
726
self.assertCoincide(Vector(+x, y, 0), edge.Vertexes[1].Point)
728
wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 2, True)
729
self.assertEqual(1, len(wire.Edges))
732
self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point)
733
self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[1].Point)
736
edge = Path.Geom.flipEdge(edge)
737
wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 2, True)
738
self.assertEqual(1, len(wire.Edges))
740
self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point)
741
self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[1].Point)
744
"""Check offsetting a single inside edge not forward."""
745
obj = self.doc.getObjectsByLabel("offset-edge")[0]
747
w = getWireInside(obj)
748
length = 20 * math.cos(math.pi / 6)
750
self.assertRoughly(length, e.Length)
754
e for e in w.Edges if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y)
759
self.assertEqual(1, len(hEdges))
762
self.assertCoincide(Vector(-x, y, 0), edge.Vertexes[0].Point)
763
self.assertCoincide(Vector(+x, y, 0), edge.Vertexes[1].Point)
765
wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 2, False)
766
self.assertEqual(1, len(wire.Edges))
769
self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point)
770
self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[1].Point)
773
edge = Path.Geom.flipEdge(edge)
774
wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 2, False)
775
self.assertEqual(1, len(wire.Edges))
777
self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point)
778
self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[1].Point)
781
"""Check offsetting multiple inside edges."""
782
obj = self.doc.getObjectsByLabel("offset-edge")[0]
784
w = getWireInside(obj)
785
length = 20 * math.cos(math.pi / 6)
791
if not Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y)
793
self.assertEqual(2, len(lEdges))
795
wire = PathOpUtil.offsetWire(Part.Wire(lEdges), obj.Shape, 2, True)
797
x = length / 2 - 2 * math.cos(math.pi / 6)
798
y = -5 - 2 * math.sin(math.pi / 6)
800
self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point)
801
self.assertCoincide(Vector(-x, y, 0), wire.Edges[-1].Vertexes[1].Point)
803
rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)]
804
self.assertEqual(0, len(rEdges))
807
wire = PathOpUtil.offsetWire(Part.Wire(lEdges), obj.Shape, 2, False)
809
self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point)
810
self.assertCoincide(Vector(+x, y, 0), wire.Edges[-1].Vertexes[1].Point)
812
rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)]
813
self.assertEqual(0, len(rEdges))
816
"""Check offsetting multiple backwards inside edges."""
819
obj = self.doc.getObjectsByLabel("offset-edge")[0]
821
w = getWireInside(obj)
822
length = 20 * math.cos(math.pi / 6)
828
if not Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y)
830
self.assertEqual(2, len(lEdges))
832
w = Path.Geom.flipWire(Part.Wire(lEdges))
833
wire = PathOpUtil.offsetWire(w, obj.Shape, 2, True)
835
x = length / 2 - 2 * math.cos(math.pi / 6)
836
y = -5 - 2 * math.sin(math.pi / 6)
838
self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point)
839
self.assertCoincide(Vector(-x, y, 0), wire.Edges[-1].Vertexes[1].Point)
841
rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)]
842
self.assertEqual(0, len(rEdges))
845
wire = PathOpUtil.offsetWire(Part.Wire(lEdges), obj.Shape, 2, False)
847
self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point)
848
self.assertCoincide(Vector(+x, y, 0), wire.Edges[-1].Vertexes[1].Point)
850
rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)]
851
self.assertEqual(0, len(rEdges))
854
"""Orient an already oriented wire"""
860
e0 = Part.Edge(Part.LineSegment(p0, p1))
861
e1 = Part.Edge(Part.LineSegment(p1, p2))
863
wire = PathOpUtil.orientWire(Part.Wire([e0, e1]))
864
wirePts = wireMarkers(wire)
866
self.assertPointsMatch(wirePts, pts)
869
"""Orient a potentially misoriented wire"""
875
e0p = Part.Edge(Part.LineSegment(p0, p1))
876
e0m = Part.Edge(Part.LineSegment(p1, p0))
877
e1p = Part.Edge(Part.LineSegment(p1, p2))
878
e1m = Part.Edge(Part.LineSegment(p2, p1))
880
wire = PathOpUtil.orientWire(Part.Wire([e0p, e1p]))
881
self.assertPointsMatch(wireMarkers(wire), pts)
883
wire = PathOpUtil.orientWire(Part.Wire([e0p, e1m]))
884
self.assertPointsMatch(wireMarkers(wire), pts)
886
wire = PathOpUtil.orientWire(Part.Wire([e0m, e1p]))
887
self.assertPointsMatch(wireMarkers(wire), pts)
889
wire = PathOpUtil.orientWire(Part.Wire([e0m, e1m]))
890
self.assertPointsMatch(wireMarkers(wire), pts)
893
"""Orient a potentially misoriented longer wire"""
898
pts = [p0, p1, p2, p3]
900
e0p = Part.Edge(Part.LineSegment(p0, p1))
901
e0m = Part.Edge(Part.LineSegment(p1, p0))
902
e1p = Part.Edge(Part.LineSegment(p1, p2))
903
e1m = Part.Edge(Part.LineSegment(p2, p1))
904
e2p = Part.Edge(Part.LineSegment(p2, p3))
905
e2m = Part.Edge(Part.LineSegment(p3, p2))
907
wire = PathOpUtil.orientWire(Part.Wire([e0p, e1p, e2p]))
908
self.assertPointsMatch(wireMarkers(wire), pts)
910
wire = PathOpUtil.orientWire(Part.Wire([e0p, e1m, e2p]))
911
self.assertPointsMatch(wireMarkers(wire), pts)
913
wire = PathOpUtil.orientWire(Part.Wire([e0m, e1p, e2p]))
914
self.assertPointsMatch(wireMarkers(wire), pts)
916
wire = PathOpUtil.orientWire(Part.Wire([e0m, e1m, e2p]))
917
self.assertPointsMatch(wireMarkers(wire), pts)
919
wire = PathOpUtil.orientWire(Part.Wire([e0p, e1p, e2m]))
920
self.assertPointsMatch(wireMarkers(wire), pts)
922
wire = PathOpUtil.orientWire(Part.Wire([e0p, e1m, e2m]))
923
self.assertPointsMatch(wireMarkers(wire), pts)
925
wire = PathOpUtil.orientWire(Part.Wire([e0m, e1p, e2m]))
926
self.assertPointsMatch(wireMarkers(wire), pts)
928
wire = PathOpUtil.orientWire(Part.Wire([e0m, e1m, e2m]))
929
self.assertPointsMatch(wireMarkers(wire), pts)