Test cases for basic path generation for tags.

This commit is contained in:
Markus Lampert 2016-11-21 19:51:54 -08:00
parent 8ce9c0c305
commit 1fd4c49fca
3 changed files with 629 additions and 146 deletions

View File

@ -61,6 +61,14 @@ movecw = ['G2', 'G02']
moveccw = ['G3', 'G03'] moveccw = ['G3', 'G03']
movearc = movecw + moveccw movearc = movecw + moveccw
slack = 0.0000001
def isAbout(v1, v2):
return math.fabs(v1 - v2) < slack
def pointsCoincide(p1, p2):
return isAbout(p1.x, p2.x) and isAbout(p1.y, p2.y) and isAbout(p1.z, p2.z)
def getAngle(v): def getAngle(v):
a = v.getAngle(FreeCAD.Vector(1,0,0)) a = v.getAngle(FreeCAD.Vector(1,0,0))
if v.y < 0: if v.y < 0:
@ -90,29 +98,6 @@ class Side:
return cls.Right return cls.Right
return cls.Straight return cls.Straight
def testPrintAngle(v):
print("(%+.2f, %+.2f, %+.2f): %+.2f" % (v.x, v.y, v.z, getAngle(v)/math.pi))
def testAngle(x=1, y=1):
testPrintAngle(FreeCAD.Vector( 1*x, 0*y, 0))
testPrintAngle(FreeCAD.Vector( 1*x, 1*y, 0))
testPrintAngle(FreeCAD.Vector( 0*x, 1*y, 0))
testPrintAngle(FreeCAD.Vector(-1*x, 1*y, 0))
testPrintAngle(FreeCAD.Vector(-1*x, 0*y, 0))
testPrintAngle(FreeCAD.Vector(-1*x,-1*y, 0))
testPrintAngle(FreeCAD.Vector( 0*x,-1*y, 0))
testPrintAngle(FreeCAD.Vector( 1*x,-1*y, 0))
def testPrintSide(pt1, pt2):
print('(%.2f, %.2f) - (%.2f, %.2f) -> %s' % (pt1.x, pt1.y, pt2.x, pt2.y, Side.toString(Side.of(pt1, pt2))))
def testSide():
testPrintSide(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector( 1, 0, 0))
testPrintSide(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector(-1, 0, 0))
testPrintSide(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector( 0, 1, 0))
testPrintSide(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector( 0,-1, 0))
def pathCommandForEdge(edge): def pathCommandForEdge(edge):
pt = edge.Curve.EndPoint pt = edge.Curve.EndPoint
params = {'X': pt.x, 'Y': pt.y, 'Z': pt.z} params = {'X': pt.x, 'Y': pt.y, 'Z': pt.z}
@ -193,11 +178,13 @@ class Tag:
class Intersection: class Intersection:
# An intersection with a tag has 4 markant points, where one might be optional. # An intersection with a tag has 4 markant points, where one might be optional.
# P1---P2 P2 #
# / \ /\ # P1---P2 P1---P2 P2
# / \ / \ # | | / \ /\
# / \ / \ # | | / \ / \
# ---P0 P3--- ---P0 P3--- # | | / \ / \
# ---P0 P3--- ---P0 P3--- ---P0 P3---
#
# If no intersection occured the Intersection can be viewed as being # If no intersection occured the Intersection can be viewed as being
# at P3 with no additional edges. # at P3 with no additional edges.
P0 = 2 P0 = 2
@ -223,90 +210,131 @@ class Tag:
#print("\nplateau= %s - %s" %(pt1, pt2)) #print("\nplateau= %s - %s" %(pt1, pt2))
return Part.Edge(Part.Line(pt1, pt2)) return Part.Edge(Part.Line(pt1, pt2))
def intersectP0(self, edge):
#print("----- P0 (%s - %s)" % (edge.Curve.StartPoint, edge.Curve.EndPoint))
i = self.tag.nextIntersectionClosestTo(edge, self.tag.core, edge.Curve.StartPoint)
if i:
if pointsCoincide(i, edge.Curve.StartPoint):
# if P0 and P1 are the same, we need to insert a segment for the rise
self.edges.append(Part.Edge(Part.Line(i, FreeCAD.Vector(i.x, i.y, self.tag.top()))))
self.p1 = i
self.state = self.P1
return edge
if pointsCoincide(i, edge.Curve.EndPoint):
e = edge
tail = None
else:
e, tail = self.tag.splitEdgeAt(edge, i)
self.p1 = e.Curve.EndPoint
self.edges.append(self.tag.mapEdgeToSolid(e))
self.state = self.P1
return tail
# no intersection, the entire edge fits between P0 and P1
self.edges.append(self.tag.mapEdgeToSolid(edge))
return None
def intersectP1(self, edge):
#print("----- P1 (%s - %s)" % (edge.Curve.StartPoint, edge.Curve.EndPoint))
i = self.tag.nextIntersectionClosestTo(edge, self.tag.core, edge.Curve.EndPoint)
if i:
if pointsCoincide(i, edge.Curve.StartPoint):
self.edges.append(self.tag.mapEdgeToSolid(edge))
return self
if pointsCoincide(i, edge.Curve.EndPoint):
e = edge
tail = None
else:
e, tail = self.tag.splitEdgeAt(edge, i)
self.p2 = e.Curve.EndPoint
self.state = self.P2
else:
e = edge
tail = None
self.edges.append(self.moveEdgeToPlateau(e))
return tail
def intersectP2(self, edge):
#print("----- P2 (%s - %s)" % (edge.Curve.StartPoint, edge.Curve.EndPoint))
i = self.tag.nextIntersectionClosestTo(edge, self.tag.solid, edge.Curve.EndPoint)
if i:
if pointsCoincide(i, edge.Curve.StartPoint):
#print("------- insert exit plunge (%s)" % i)
self.edges.append(Part.Edge(Part.Line(FreeCAD.Vector(i.x, i.y, self.tag.top()), i)))
e = None
tail = edge
elif pointsCoincide(i, edge.Curve.EndPoint):
#print("------- entire segment added (%s)" % i)
e = edge
tail = None
else:
e, tail = self.tag.splitEdgeAt(edge, i)
#if tail:
# print("----- P3 (%s - %s)" % (tail.Curve.StartPoint, tail.Curve.EndPoint))
#else:
# print("----- P3 (---)")
self.state = self.P3
self.tail = tail
else:
e = edge
tail = None
if e:
self.edges.append(self.tag.mapEdgeToSolid(e))
return tail
def intersect(self, edge): def intersect(self, edge):
#print("") #print("")
if self.state == self.P0: #print(" >>> (%s - %s)" % (edge.Curve.StartPoint, edge.Curve.EndPoint))
#print("----- P0") if edge and self.state == self.P0:
if self.tag.core: edge = self.intersectP0(edge)
self.state = self.P1 if edge and self.state == self.P1:
i = self.tag.nextIntersectionClosestTo(edge, self.tag.core, edge.Curve.StartPoint) edge = self.intersectP1(edge)
if i: if edge and self.state == self.P2:
if i == edge.Curve.StartPoint: edge = self.intersectP2(edge)
self.edges.append(Part.Edge(Part.Line(i, FreeCAD.Vector(i.x, i.y, self.tag.top()))))
else:
e, tail = self.tag.splitEdgeAt(edge, i)
self.edges.append(self.mapEdgeTo(e, self.tag.solid))
edge = tail
else:
self.edges.append(self.mapEdgeTo(e, self.tag.solid))
# we're done with this edge
return self
else:
p = self.tag.originAt(self.tag.bottom() + self.tag.actualHeight)
if DraftGeomUtils.isPtOnEdge(p, edge):
e, tail = self.tag.splitEdgeAt(edge, p)
self.edges.append(self.mapEdgeTo(e, self.tag.solid))
edge = tail
self.state = self.P2
else:
self.edges.append(self.mapEdgeTo(e, self.tag.solid))
# we're done with this edge
return self
if self.state == self.P1:
#print("----- P1")
# must have core, find end of plateau
i = self.tag.nextIntersectionClosestTo(edge, self.tag.core, edge.Curve.EndPoint)
if i and i != edge.Curve.StartPoint:
self.state = self.P2
if i == edge.Curve.EndPoint:
self.edges.append(self.moveEdgeToPlateau(edge))
# edge fully consumed
return self
else:
e, tail = self.tag.splitEdgeAt(edge, i)
self.edges.append(self.moveEdgeToPlateau(e))
edge = tail
else:
self.edges.append(self.moveEdgeToPlateau(edge))
# edge fully consumed, we're still in P1
return self
if self.state == self.P2:
#print("----- P2")
i = self.tag.nextIntersectionClosestTo(edge, self.tag.solid, edge.Curve.EndPoint)
if i:
self.state = self.P3
#print("----- P3")
if i == edge.Curve.StartPoint:
self.edges.append(Part.Edge(Part.Line(FreeCAD.Vector(i.x, i.y, self.tag.top()), i)))
self.tail = edge
elif i == edge.Curve.EndPoint:
self.edges.append(self.mapEdgeTo(edge, self.tag.solid))
self.tail = None
else:
e, tail = self.tag.splitEdgeAt(edge, i)
self.edges.append(self.mapEdgeTo(e, self.tag.solid))
self.tail = tail
return self return self
def splitEdgeAt(self, edge, pt): def splitEdgeAt(self, edge, pt):
p = edge.Curve.parameter(pt) p = edge.Curve.parameter(pt)
wire = edge.split(p) wire = edge.split(p)
return wire.Edges return wire.Edges
def mapEdgeToSolid(self, edge):
#print("mapEdgeToSolid: (%s %s)" % (edge.Curve.StartPoint, edge.Curve.EndPoint))
p1a = edge.Curve.StartPoint
p1b = FreeCAD.Vector(p1a.x, p1a.y, p1a.z + self.height)
e1 = Part.Edge(Part.Line(p1a, p1b))
p1 = self.nextIntersectionClosestTo(e1, self.solid, p1b) # top most intersection
#print(" p1: (%s %s) -> %s" % (p1a, p1b, p1))
p2a = edge.Curve.EndPoint
p2b = FreeCAD.Vector(p2a.x, p2a.y, p2a.z + self.height)
e2 = Part.Edge(Part.Line(p2a, p2b))
p2 = self.nextIntersectionClosestTo(e2, self.solid, p2b) # top most intersection
#print(" p2: (%s %s) -> %s" % (p2a, p2b, p2))
if type(edge.Curve) == Part.Line:
return Part.Edge(Part.Line(p1, p2))
def filterIntersections(self, pts, face):
if type(face.Surface) == Part.Cone or type(face.Surface) == Part.Cylinder:
return filter(lambda pt: pt.z >= self.bottom() and pt.z <= self.top(), pts)
if type(face.Surface) == Part.Plane:
c = face.Edges[0].Curve
if (type(c) == Part.Circle):
return filter(lambda pt: (pt - c.Center).Length <= c.Radius, pts)
print("==== we got a %s" % face.Surface)
def nextIntersectionClosestTo(self, edge, solid, refPt): def nextIntersectionClosestTo(self, edge, solid, refPt):
pts = [] pts = []
for face in solid.Faces: for index, face in enumerate(solid.Faces):
i = edge.Curve.intersect(face.Surface)[0] i = edge.Curve.intersect(face.Surface)[0]
pts.extend([FreeCAD.Vector(p.X, p.Y, p.Z) for p in i]) ps = self.filterIntersections([FreeCAD.Vector(p.X, p.Y, p.Z) for p in i], face)
pts.extend(ps)
if pts: if pts:
closest = sorted(pts, key=lambda pt: (pt - refPt).Length)[0] closest = sorted(pts, key=lambda pt: (pt - refPt).Length)[0]
#print("--pts: %s -> %s" % (pts, closest))
return closest return closest
return None return None
@ -316,10 +344,11 @@ class Tag:
i = self.nextIntersectionClosestTo(edge, self.solid, edge.Curve.StartPoint) i = self.nextIntersectionClosestTo(edge, self.solid, edge.Curve.StartPoint)
if i: if i:
inters.state = self.Intersection.P0 inters.state = self.Intersection.P0
if i == edge.Curve.EndPoint: inters.p0 = i
if pointsCoincide(i, edge.Curve.EndPoint):
inters.edges.append(edge) inters.edges.append(edge)
return inters return inters
if i == edge.Curve.StartPoint: if pointsCoincide(i, edge.Curve.StartPoint):
tail = edge tail = edge
else: else:
e,tail = self.splitEdgeAt(edge, i) e,tail = self.splitEdgeAt(edge, i)

View File

@ -30,9 +30,7 @@ import math
import unittest import unittest
from FreeCAD import Vector from FreeCAD import Vector
from PathScripts.PathDressupHoldingTags import Tag from PathScripts.PathDressupHoldingTags import *
slack = 0.0000001
def pointsCoincide(pt1, pt2): def pointsCoincide(pt1, pt2):
pt = pt1 - pt2 pt = pt1 - pt2
@ -93,36 +91,49 @@ class TagTestCaseBase(unittest.TestCase):
def assertAbout(self, v1, v2): def assertAbout(self, v1, v2):
"""Verify that 2 values are the same (accounting for float imprecision).""" """Verify that 2 values are the same (accounting for float imprecision)."""
#print("assertAbout(%f, %f)" % (v1, v2))
if math.fabs(v1 - v2) > slack: if math.fabs(v1 - v2) > slack:
self.fail("%f != %f" % (v1, v2)) self.fail("%f != %f" % (v1, v2))
def assertTrapezoid(self, edgs, tail, spec): def assertTrapezoid(self, edgs, tail, points):
"""Check that there are 5 edges forming a trapezoid.""" """Check that there are 5 edges forming a trapezoid."""
edges = list(edgs) edges = list(edgs)
if tail: if tail:
edges.append(tail) edges.append(tail)
self.assertEqual(len(edges), 5) self.assertEqual(len(edges), 5)
p0 = spec[0] self.assertLine(edges[0], points[0], points[1])
p1 = Vector(spec[1], p0.y, p0.z) self.assertLine(edges[1], points[1], points[2])
p2 = Vector(p1.x, p1.y, spec[2]) self.assertLine(edges[2], points[2], points[3])
p3 = Vector(-p2.x, p2.y, p2.z) self.assertLine(edges[3], points[3], points[4])
p4 = Vector(p3.x, p3.y, p0.z) self.assertLine(edges[4], points[4], points[5])
p5 = spec[3]
self.assertLine(edges[0], p0, p1) class TestTag00BasicHolding(TagTestCaseBase):
self.assertLine(edges[1], p1, p2) """Some basid test cases."""
self.assertLine(edges[2], p2, p3)
self.assertLine(edges[3], p3, p4) def test00(self,x=1, y=1):
self.assertLine(edges[4], p4, p5) """Test getAngle."""
self.assertAbout(getAngle(FreeCAD.Vector( 1*x, 0*y, 0)), 0)
self.assertAbout(getAngle(FreeCAD.Vector( 1*x, 1*y, 0)), math.pi/4)
self.assertAbout(getAngle(FreeCAD.Vector( 0*x, 1*y, 0)), math.pi/2)
self.assertAbout(getAngle(FreeCAD.Vector(-1*x, 1*y, 0)), 3*math.pi/4)
self.assertAbout(getAngle(FreeCAD.Vector(-1*x, 0*y, 0)), math.pi)
self.assertAbout(getAngle(FreeCAD.Vector(-1*x,-1*y, 0)), -3*math.pi/4)
self.assertAbout(getAngle(FreeCAD.Vector( 0*x,-1*y, 0)), -math.pi/2)
self.assertAbout(getAngle(FreeCAD.Vector( 1*x,-1*y, 0)), -math.pi/4)
def test01(self):
"""Test class Side."""
self.assertEqual(Side.of(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector( 1, 0, 0)), Side.On)
self.assertEqual(Side.of(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector(-1, 0, 0)), Side.On)
self.assertEqual(Side.of(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector( 0, 1, 0)), Side.Left)
self.assertEqual(Side.of(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector( 0,-1, 0)), Side.Right)
class TagTestCases(TagTestCaseBase): # ============= class TestTag01BasicTag(TagTestCaseBase): # =============
"""Unit tests for the HoldingTags dressup.""" """Unit tests for the HoldingTags dressup."""
def testTagBasics(self): def test00(self):
#"""Check Tag origin, serialization and de-serialization.""" """Check Tag origin, serialization and de-serialization."""
tag = Tag(77, 13, 4, 5, 90, True) tag = Tag(77, 13, 4, 5, 90, True)
self.assertCoincide(tag.originAt(3), Vector(77, 13, 3)) self.assertCoincide(tag.originAt(3), Vector(77, 13, 3))
s = tag.toString() s = tag.toString()
@ -134,8 +145,8 @@ class TagTestCases(TagTestCaseBase): # =============
self.assertEqual(tag.enabled, tagCopy.enabled) self.assertEqual(tag.enabled, tagCopy.enabled)
def testTagSolidBasic(self): def test01(self):
#"""For a 90 degree tag the core and solid are both defined and identical cylinders.""" """Verify solid and core for a 90 degree tag are identical cylinders."""
tag = Tag(100, 200, 4, 5, 90, True) tag = Tag(100, 200, 4, 5, 90, True)
tag.createSolidsAt(17) tag.createSolidsAt(17)
@ -145,8 +156,8 @@ class TagTestCases(TagTestCaseBase): # =============
self.assertIsNotNone(tag.core) self.assertIsNotNone(tag.core)
self.assertCylinderAt(tag.core, Vector(100, 200, 17), 2, 5) self.assertCylinderAt(tag.core, Vector(100, 200, 17), 2, 5)
def testTagSolidFlatCone(self): def test02(self):
#"""Tests a Tag that has an angle leaving a flat face on top of the cone.""" """Verify an angled tag has a cone shape with a lid, and cylinder core."""
tag = Tag(0, 0, 18, 5, 45, True) tag = Tag(0, 0, 18, 5, 45, True)
tag.createSolidsAt(0) tag.createSolidsAt(0)
@ -156,8 +167,8 @@ class TagTestCases(TagTestCaseBase): # =============
self.assertIsNotNone(tag.core) self.assertIsNotNone(tag.core)
self.assertCylinderAt(tag.core, Vector(0,0,0), 4, 5) self.assertCylinderAt(tag.core, Vector(0,0,0), 4, 5)
def testTagSolidCone(self): def test03(self):
#"""Tests a Tag who's angled sides coincide at the tag's height.""" """Verify pointy cone shape of tag with pointy end if width, angle and height match up."""
tag = Tag(0, 0, 10, 5, 45, True) tag = Tag(0, 0, 10, 5, 45, True)
tag.createSolidsAt(0) tag.createSolidsAt(0)
self.assertIsNotNone(tag.solid) self.assertIsNotNone(tag.solid)
@ -165,8 +176,8 @@ class TagTestCases(TagTestCaseBase): # =============
self.assertIsNone(tag.core) self.assertIsNone(tag.core)
def testTagSolidShortCone(self): def test04(self):
#"""Tests a Tag that's not wide enough to reach full height.""" """Verify height adjustment if tag isn't wide eough for angle."""
tag = Tag(0, 0, 5, 17, 60, True) tag = Tag(0, 0, 5, 17, 60, True)
tag.createSolidsAt(0) tag.createSolidsAt(0)
self.assertIsNotNone(tag.solid) self.assertIsNotNone(tag.solid)
@ -174,14 +185,267 @@ class TagTestCases(TagTestCaseBase): # =============
self.assertIsNone(tag.core) self.assertIsNone(tag.core)
class SquareTagTestCases(TagTestCaseBase): # ============= def test10(self):
"""Verify intersection of square tag with line ending at tag start."""
tag = Tag( 0, 0, 8, 3, 90, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(4, 0, 0)))
i = tag.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P0)
self.assertEqual(len(i.edges), 1)
self.assertLine(i.edges[0], edge.Curve.StartPoint, edge.Curve.EndPoint)
self.assertIsNone(i.tail)
def test11(self):
"""Verify intersection of square tag with line ending between P1 and P2."""
tag = Tag( 0, 0, 8, 3, 90, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(1, 0, 0)))
i = tag.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P1)
self.assertEqual(len(i.edges), 3)
p1 = Vector(4, 0, 0)
p2 = Vector(4, 0, 3)
p3 = Vector(1, 0, 3)
self.assertLine(i.edges[0], edge.Curve.StartPoint, p1)
self.assertLine(i.edges[1], p1, p2)
self.assertLine(i.edges[2], p2, p3)
self.assertIsNone(i.tail)
# verify we stay in P1 if we add another segment
edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(0, 0, 0)))
i = i.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P1)
self.assertEqual(len(i.edges), 4)
p4 = Vector(0, 0, 3)
self.assertLine(i.edges[3], p3, p4)
self.assertIsNone(i.tail)
def test12(self):
"""Verify intesection of square tag with line ending on P2."""
tag = Tag( 0, 0, 8, 3, 90, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-4, 0, 0)))
i = tag.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P2)
self.assertEqual(len(i.edges), 3)
p0 = edge.Curve.StartPoint
p1 = Vector( 4, 0, 0)
p2 = Vector( 4, 0, 3)
p3 = Vector(-4, 0, 3)
self.assertLine(i.edges[0], p0, p1)
self.assertLine(i.edges[1], p1, p2)
self.assertLine(i.edges[2], p2, p3)
self.assertIsNone(i.tail)
# make sure it also works if we get there not directly
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(0, 0, 0)))
i = tag.intersect(edge)
edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(-4, 0, 0)))
i = i.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P2)
self.assertEqual(len(i.edges), 4)
p2a = Vector( 0, 0, 3)
self.assertLine(i.edges[0], p0, p1)
self.assertLine(i.edges[1], p1, p2)
self.assertLine(i.edges[2], p2, p2a)
self.assertLine(i.edges[3], p2a, p3)
self.assertIsNone(i.tail)
def test13(self):
"""Verify plunge down is inserted for square tag on exit."""
tag = Tag( 0, 0, 8, 3, 90, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-5, 0, 0)))
i = tag.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P3)
self.assertTrue(i.isComplete())
self.assertEqual(len(i.edges), 4)
p0 = edge.Curve.StartPoint
p1 = Vector( 4, 0, 0)
p2 = Vector( 4, 0, 3)
p3 = Vector(-4, 0, 3)
p4 = Vector(-4, 0, 0)
p5 = edge.Curve.EndPoint
self.assertLine(i.edges[0], p0, p1)
self.assertLine(i.edges[1], p1, p2)
self.assertLine(i.edges[2], p2, p3)
self.assertLine(i.edges[3], p3, p4)
self.assertIsNotNone(i.tail)
self.assertLine(i.tail, p4, p5)
def test20(self):
"""Veify intersection of angled tag with line ending before P1."""
tag = Tag( 0, 0, 8, 3, 45, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(4, 0, 0)))
i = tag.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P0)
self.assertEqual(len(i.edges), 1)
self.assertLine(i.edges[0], edge.Curve.StartPoint, edge.Curve.EndPoint)
self.assertIsNone(i.tail)
# now add another segment that doesn't reach the top of the cone
edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(3, 0, 0)))
i = i.intersect(edge)
# still a P0 and edge fully consumed
p1 = Vector(edge.Curve.StartPoint)
p1.z = 0
p2 = Vector(edge.Curve.EndPoint)
p2.z = 1 # height of cone @ (3,0)
self.assertEqual(i.state, Tag.Intersection.P0)
self.assertEqual(len(i.edges), 2)
self.assertLine(i.edges[1], p1, p2)
self.assertIsNone(i.tail)
# add another segment to verify starting point offset
edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(2, 0, 0)))
i = i.intersect(edge)
# still a P0 and edge fully consumed
p3 = Vector(edge.Curve.EndPoint)
p3.z = 2 # height of cone @ (2,0)
self.assertEqual(i.state, Tag.Intersection.P0)
self.assertEqual(len(i.edges), 3)
self.assertLine(i.edges[2], p2, p3)
self.assertIsNone(i.tail)
def test21(self):
"""Verify intersection of angled tag with line ending between P1 and P2"""
tag = Tag( 0, 0, 8, 3, 45, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(1, 0, 0)))
i = tag.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P1)
self.assertEqual(len(i.edges), 2)
p1 = Vector(4, 0, 0)
p2 = Vector(1, 0, 3)
self.assertLine(i.edges[0], edge.Curve.StartPoint, p1)
self.assertLine(i.edges[1], p1, p2)
self.assertIsNone(i.tail)
# verify we stay in P1 if we add another segment
edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(0, 0, 0)))
i = i.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P1)
self.assertEqual(len(i.edges), 3)
p3 = Vector(0, 0, 3)
self.assertLine(i.edges[2], p2, p3)
self.assertIsNone(i.tail)
def test22(self):
"""Verify intersection of angled tag with edge ending on P2."""
tag = Tag( 0, 0, 8, 3, 45, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-1, 0, 0)))
i = tag.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P2)
self.assertEqual(len(i.edges), 3)
p0 = Vector(edge.Curve.StartPoint)
p1 = Vector(4, 0, 0)
p2 = Vector(1, 0, 3)
p3 = Vector(-1, 0, 3)
self.assertLine(i.edges[0], p0, p1)
self.assertLine(i.edges[1], p1, p2)
self.assertLine(i.edges[2], p2, p3)
self.assertIsNone(i.tail)
# make sure we get the same result if there's another edge
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(1, 0, 0)))
i = tag.intersect(edge)
edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(-1, 0, 0)))
i = i.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P2)
self.assertEqual(len(i.edges), 3)
self.assertLine(i.edges[0], p0, p1)
self.assertLine(i.edges[1], p1, p2)
self.assertLine(i.edges[2], p2, p3)
self.assertIsNone(i.tail)
# and also if the last segment doesn't cross the entire plateau
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(0.5, 0, 0)))
i = tag.intersect(edge)
edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(-1, 0, 0)))
i = i.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P2)
self.assertEqual(len(i.edges), 4)
p2a = Vector(0.5, 0, 3)
self.assertLine(i.edges[0], p0, p1)
self.assertLine(i.edges[1], p1, p2)
self.assertLine(i.edges[2], p2, p2a)
self.assertLine(i.edges[3], p2a, p3)
self.assertIsNone(i.tail)
def test23(self):
"""Verify proper down plunge on angled tag exit."""
tag = Tag( 0, 0, 8, 3, 45, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-2, 0, 0)))
i = tag.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P2)
self.assertEqual(len(i.edges), 4)
p0 = Vector(5, 0, 0)
p1 = Vector(4, 0, 0)
p2 = Vector(1, 0, 3)
p3 = Vector(-1, 0, 3)
p4 = Vector(-2, 0, 2)
self.assertLine(i.edges[0], p0, p1)
self.assertLine(i.edges[1], p1, p2)
self.assertLine(i.edges[2], p2, p3)
self.assertLine(i.edges[3], p3, p4)
self.assertIsNone(i.tail)
# make sure adding another segment doesn't change the state
edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(-3, 0, 0)))
i = i.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P2)
self.assertEqual(len(i.edges), 5)
p5 = Vector(-3, 0, 1)
self.assertLine(i.edges[4], p4, p5)
self.assertIsNone(i.tail)
# now if we complete to P3 ....
edge = Part.Edge(Part.Line(edge.Curve.EndPoint, Vector(-4, 0, 0)))
i = i.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P3)
self.assertTrue(i.isComplete())
self.assertEqual(len(i.edges), 6)
p6 = Vector(-4, 0, 0)
self.assertLine(i.edges[5], p5, p6)
self.assertIsNone(i.tail)
# verify proper operation if there is a single edge going through all
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-4, 0, 0)))
i = tag.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P3)
self.assertTrue(i.isComplete())
self.assertEqual(len(i.edges), 4)
self.assertLine(i.edges[0], p0, p1)
self.assertLine(i.edges[1], p1, p2)
self.assertLine(i.edges[2], p2, p3)
self.assertLine(i.edges[3], p3, p6)
self.assertIsNone(i.tail)
# verify tail is added as well
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-5, 0, 0)))
i = tag.intersect(edge)
self.assertEqual(i.state, Tag.Intersection.P3)
self.assertTrue(i.isComplete())
self.assertEqual(len(i.edges), 4)
self.assertLine(i.edges[0], p0, p1)
self.assertLine(i.edges[1], p1, p2)
self.assertLine(i.edges[2], p2, p3)
self.assertLine(i.edges[3], p3, p6)
self.assertIsNotNone(i.tail)
self.assertLine(i.tail, p6, edge.Curve.EndPoint)
class TestTag02SquareTag(TagTestCaseBase): # =============
"""Unit tests for square tags.""" """Unit tests for square tags."""
def testTagNoIntersect(self): def test00(self):
#"""Check that the returned tail if no intersection occurs matches the input.""" """Verify no intersection."""
tag = Tag( 0, 0, 4, 7, 90, True, 0) tag = Tag( 0, 0, 4, 7, 90, True, 0)
pt1 = Vector(+5, 3, 0) pt1 = Vector(+5, 5, 0)
pt2 = Vector(-5, 3, 0) pt2 = Vector(-5, 5, 0)
edge = Part.Edge(Part.Line(pt1, pt2)) edge = Part.Edge(Part.Line(pt1, pt2))
i = tag.intersect(edge) i = tag.intersect(edge)
@ -191,8 +455,8 @@ class SquareTagTestCases(TagTestCaseBase): # =============
self.assertFalse(i.edges) self.assertFalse(i.edges)
self.assertLine(i.tail, pt1, pt2) self.assertLine(i.tail, pt1, pt2)
def testTagIntersectLine(self): def test01(self):
#"""Test that a straight line passing through a cylindrical tag is split up into 5 segments.""" """Verify a straight line passing through tag is split up into 5 segments."""
tag = Tag( 0, 0, 4, 7, 90, True, 0) tag = Tag( 0, 0, 4, 7, 90, True, 0)
pt1 = Vector(+5, 0, 0) pt1 = Vector(+5, 0, 0)
pt2 = Vector(-5, 0, 0) pt2 = Vector(-5, 0, 0)
@ -215,8 +479,8 @@ class SquareTagTestCases(TagTestCaseBase): # =============
self.assertLine(i.tail, pt0d, pt2) self.assertLine(i.tail, pt0d, pt2)
def testTagIntersectPartialLineP0(self): def test02(self):
#"""Make sure line is accounted for if it reaches P0.""" """Verify line is accounted for if it reaches P0."""
tag = Tag( 0, 0, 4, 7, 90, True, 0) tag = Tag( 0, 0, 4, 7, 90, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(2, 0, 0))) edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(2, 0, 0)))
@ -228,8 +492,8 @@ class SquareTagTestCases(TagTestCaseBase): # =============
self.assertIsNone(i.tail) self.assertIsNone(i.tail)
def testTagIntersectPartialLineP1(self): def test03(self):
#"""Make sure line is accounted for if it reaches beyond P1.""" """Verify line is accounted for if it reaches beyond P1."""
tag = Tag( 0, 0, 4, 7, 90, True, 0) tag = Tag( 0, 0, 4, 7, 90, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(1, 0, 0))) edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(1, 0, 0)))
@ -247,8 +511,8 @@ class SquareTagTestCases(TagTestCaseBase): # =============
self.assertIsNone(i.tail) self.assertIsNone(i.tail)
def testTagIntersectPartialLineP2(self): def test04(self):
#"""Make sure line is accounted for if it reaches beyond P2.""" """Verify line is accounted for if it reaches beyond P2."""
tag = Tag( 0, 0, 4, 7, 90, True, 0) tag = Tag( 0, 0, 4, 7, 90, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-1, 0, 0))) edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-1, 0, 0)))
@ -265,8 +529,8 @@ class SquareTagTestCases(TagTestCaseBase): # =============
self.assertLine(i.edges[2], pt0b, pt1a) self.assertLine(i.edges[2], pt0b, pt1a)
self.assertIsNone(i.tail) self.assertIsNone(i.tail)
def testTagIntersectPartialLineP11(self): def test05(self):
#"""Make sure a line is accounted for if it lies entirely between P1 and P2.""" """Verify line is accounted for if it lies entirely between P1 and P2."""
tag = Tag( 0, 0, 4, 7, 90, True, 0) tag = Tag( 0, 0, 4, 7, 90, True, 0)
e1 = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(+1, 0, 0))) e1 = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(+1, 0, 0)))
@ -288,8 +552,8 @@ class SquareTagTestCases(TagTestCaseBase): # =============
self.assertLine(i.edges[3], pt1a, pt1b) self.assertLine(i.edges[3], pt1a, pt1b)
self.assertIsNone(i.tail) self.assertIsNone(i.tail)
def testTagIntersectPartialLinesP11223(self): def test06(self):
#"""Verify all lines between P0 and P3 are added.""" """Verify all lines between P0 and P3 are added."""
tag = Tag( 0, 0, 4, 7, 90, True, 0) tag = Tag( 0, 0, 4, 7, 90, True, 0)
e0 = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(+2, 0, 0))) e0 = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(+2, 0, 0)))
e1 = Part.Edge(Part.Line(e0.Curve.EndPoint, Vector(+1, 0, 0))) e1 = Part.Edge(Part.Line(e0.Curve.EndPoint, Vector(+1, 0, 0)))
@ -329,14 +593,21 @@ class SquareTagTestCases(TagTestCaseBase): # =============
self.assertIsNotNone(i.tail) self.assertIsNotNone(i.tail)
self.assertLine(i.tail, e6.Curve.StartPoint, e6.Curve.EndPoint) self.assertLine(i.tail, e6.Curve.StartPoint, e6.Curve.EndPoint)
def testTagIntersectLineAt(self): def test07(self):
"""Verify intersection of different z levels."""
tag = Tag( 0, 0, 4, 7, 90, True, 0) tag = Tag( 0, 0, 4, 7, 90, True, 0)
# for all lines below 7 we get the trapezoid # for all lines below 7 we get the trapezoid
for i in range(0, 7): for i in range(0, 7):
edge = Part.Edge(Part.Line(Vector(5, 0, i), Vector(-5, 0, i))) p0 = Vector(5, 0, i)
p1 = Vector(2, 0, i)
p2 = Vector(2, 0, 7)
p3 = Vector(-2, 0, 7)
p4 = Vector(-2, 0, i)
p5 = Vector(-5, 0, i)
edge = Part.Edge(Part.Line(p0, p5))
s = tag.intersect(edge) s = tag.intersect(edge)
self.assertTrue(s.isComplete()) self.assertTrue(s.isComplete())
self.assertTrapezoid(s.edges, s.tail, [edge.Curve.StartPoint, 2, 7, edge.Curve.EndPoint]) self.assertTrapezoid(s.edges, s.tail, [p0, p1, p2, p3, p4, p5])
# for all edges at height or above the original line is used # for all edges at height or above the original line is used
for i in range(7, 9): for i in range(7, 9):
@ -345,3 +616,182 @@ class SquareTagTestCases(TagTestCaseBase): # =============
self.assertTrue(s.isComplete()) self.assertTrue(s.isComplete())
self.assertLine(s.tail, edge.Curve.StartPoint, edge.Curve.EndPoint) self.assertLine(s.tail, edge.Curve.StartPoint, edge.Curve.EndPoint)
class TestTag03AngledTag(TagTestCaseBase): # =============
"""Unit tests for trapezoid tags."""
def test00(self):
"""Verify no intersection."""
tag = Tag( 0, 0, 8, 3, 45, True, 0)
pt1 = Vector(+5, 5, 0)
pt2 = Vector(-5, 5, 0)
edge = Part.Edge(Part.Line(pt1, pt2))
i = tag.intersect(edge)
self.assertIsNotNone(i)
self.assertTrue(i.isComplete())
self.assertIsNotNone(i.edges)
self.assertFalse(i.edges)
self.assertLine(i.tail, pt1, pt2)
def test01(self):
"""Verify a straight line passing through tag is split into 5 segments."""
tag = Tag( 0, 0, 8, 3, 45, True, 0)
pt1 = Vector(+5, 0, 0)
pt2 = Vector(-5, 0, 0)
edge = Part.Edge(Part.Line(pt1, pt2))
i = tag.intersect(edge)
self.assertIsNotNone(i)
self.assertTrue(i.isComplete())
pt0a = Vector(+4, 0, 0)
pt0b = Vector(+1, 0, 3)
pt0c = Vector(-1, 0, 3)
pt0d = Vector(-4, 0, 0)
self.assertEqual(len(i.edges), 4)
self.assertLine(i.edges[0], pt1, pt0a)
self.assertLine(i.edges[1], pt0a, pt0b)
self.assertLine(i.edges[2], pt0b, pt0c)
self.assertLine(i.edges[3], pt0c, pt0d)
self.assertLine(i.tail, pt0d, pt2)
def test02(self):
"""Verify line is accounted for if it reaches P0."""
tag = Tag( 0, 0, 8, 3, 45, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(4, 0, 0)))
i = tag.intersect(edge)
self.assertFalse(i.isComplete())
self.assertEqual(len(i.edges), 1)
self.assertLine(i.edges[0], edge.Curve.StartPoint, edge.Curve.EndPoint)
self.assertIsNone(i.tail)
def test03(self):
"""Verify line is accounted for if it reaches beyond P1."""
tag = Tag( 0, 0, 8, 3, 45, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(0.5, 0, 0)))
i = tag.intersect(edge)
self.assertFalse(i.isComplete())
pt0a = Vector(+4, 0, 0)
pt0b = Vector(+1, 0, 3)
pt1a = Vector(+0.5, 0, 3)
self.assertEqual(len(i.edges), 3)
self.assertLine(i.edges[0], edge.Curve.StartPoint, pt0a)
self.assertLine(i.edges[1], pt0a, pt0b)
self.assertLine(i.edges[2], pt0b, pt1a)
self.assertIsNone(i.tail)
def test04(self):
"""Verify line is accounted for if it reaches beyond P2."""
tag = Tag( 0, 0, 8, 3, 45, True, 0)
edge = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(-1, 0, 0)))
i = tag.intersect(edge)
self.assertFalse(i.isComplete())
pt0a = Vector(+4, 0, 0)
pt0b = Vector(+1, 0, 3)
pt1a = Vector(-1, 0, 3)
self.assertEqual(len(i.edges), 3)
self.assertLine(i.edges[0], edge.Curve.StartPoint, pt0a)
self.assertLine(i.edges[1], pt0a, pt0b)
self.assertLine(i.edges[2], pt0b, pt1a)
self.assertIsNone(i.tail)
def test05(self):
"""Verify a line is accounted for if it lies entirely between P1 and P2."""
tag = Tag( 0, 0, 8, 3, 45, True, 0)
e1 = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(+0.5, 0, 0)))
i = tag.intersect(e1)
self.assertFalse(i.isComplete())
e2 = Part.Edge(Part.Line(e1.Curve.EndPoint, Vector(0,0,0)))
i = i.intersect(e2)
pt0a = Vector(+4, 0, 0)
pt0b = Vector(+1, 0, 3)
pt1a = Vector(+0.5, 0, 3)
pt1b = Vector( 0, 0, 3)
self.assertEqual(len(i.edges), 4)
self.assertLine(i.edges[0], e1.Curve.StartPoint, pt0a)
self.assertLine(i.edges[1], pt0a, pt0b)
self.assertLine(i.edges[2], pt0b, pt1a)
self.assertLine(i.edges[3], pt1a, pt1b)
self.assertIsNone(i.tail)
def test06(self):
"""Verify all lines between P0 and P3 are added."""
tag = Tag( 0, 0, 8, 3, 45, True, 0)
e0 = Part.Edge(Part.Line(Vector(5, 0, 0), Vector(+4, 0, 0)))
e1 = Part.Edge(Part.Line(e0.Curve.EndPoint, Vector(+2, 0, 0)))
e2 = Part.Edge(Part.Line(e1.Curve.EndPoint, Vector(+0.5, 0, 0)))
e3 = Part.Edge(Part.Line(e2.Curve.EndPoint, Vector(-0.5, 0, 0)))
e4 = Part.Edge(Part.Line(e3.Curve.EndPoint, Vector(-1, 0, 0)))
e5 = Part.Edge(Part.Line(e4.Curve.EndPoint, Vector(-2, 0, 0)))
e6 = Part.Edge(Part.Line(e5.Curve.EndPoint, Vector(-5, 0, 0)))
i = tag
for e in [e0, e1, e2, e3, e4, e5]:
i = i.intersect(e)
self.assertFalse(i.isComplete())
i = i.intersect(e6)
self.assertTrue(i.isComplete())
pt0 = Vector(4, 0, 0)
pt1 = Vector(2, 0, 2)
pt2 = Vector(1, 0, 3)
pt3 = Vector(0.5, 0, 3)
pt4 = Vector(-0.5, 0, 3)
pt5 = Vector(-1, 0, 3)
pt6 = Vector(-2, 0, 2)
pt7 = Vector(-4, 0, 0)
#self.assertEqual(len(i.edges), 8)
self.assertLine(i.edges[0], e0.Curve.StartPoint, pt0)
self.assertLine(i.edges[1], pt0, pt1)
self.assertLine(i.edges[2], pt1, pt2)
self.assertLine(i.edges[3], pt2, pt3)
self.assertLine(i.edges[4], pt3, pt4)
self.assertLine(i.edges[5], pt4, pt5)
self.assertLine(i.edges[6], pt5, pt6)
self.assertLine(i.edges[7], pt6, pt7)
self.assertTrue(i.isComplete())
self.assertIsNotNone(i.tail)
self.assertLine(i.tail, pt7, e6.Curve.EndPoint)
def test07(self):
"""Verify intersection for different z levels."""
tag = Tag( 0, 0, 8, 3, 45, True, 0)
# for all lines below 3 we get the trapezoid
for i in range(0, 3):
p0 = Vector(5, 0, i)
p1 = Vector(4-i, 0, i)
p2 = Vector(1, 0, 3)
p3 = Vector(-1, 0, 3)
p4 = Vector(-4+i, 0, i)
p5 = Vector(-5, 0, i)
edge = Part.Edge(Part.Line(p0, p5))
s = tag.intersect(edge)
self.assertTrue(s.isComplete())
self.assertTrapezoid(s.edges, s.tail, [p0, p1, p2, p3, p4, p5])
# for all edges at height or above the original line is used
for i in range(3, 5):
edge = Part.Edge(Part.Line(Vector(5, 0, i), Vector(-5, 0, i)))
s = tag.intersect(edge)
self.assertTrue(s.isComplete())
self.assertLine(s.tail, edge.Curve.StartPoint, edge.Curve.EndPoint)

View File

@ -25,5 +25,9 @@
import TestApp import TestApp
from PathTests.TestPathPost import PathPostTestCases from PathTests.TestPathPost import PathPostTestCases
from PathTests.TestPathDressupHoldingTags import TagTestCases
from PathTests.TestPathDressupHoldingTags import SquareTagTestCases from PathTests.TestPathDressupHoldingTags import TestTag00BasicHolding
from PathTests.TestPathDressupHoldingTags import TestTag01BasicTag
from PathTests.TestPathDressupHoldingTags import TestTag02SquareTag
from PathTests.TestPathDressupHoldingTags import TestTag03AngledTag