From abb2865e3aab86e7289b58987741ead2ba0928d8 Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Mon, 3 Feb 2020 20:45:33 -0800 Subject: [PATCH] Improved precision and stability of splitting an arc --- .../PathScripts/PathDressupHoldingTags.py | 12 ++++--- src/Mod/Path/PathScripts/PathGeom.py | 20 +++--------- src/Mod/Path/PathTests/PathTestUtils.py | 8 ++--- src/Mod/Path/PathTests/TestPathGeom.py | 31 +++++++++++++++++++ 4 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathDressupHoldingTags.py b/src/Mod/Path/PathScripts/PathDressupHoldingTags.py index 7cfc2bf7fd..96c6c72867 100644 --- a/src/Mod/Path/PathScripts/PathDressupHoldingTags.py +++ b/src/Mod/Path/PathScripts/PathDressupHoldingTags.py @@ -202,14 +202,13 @@ class Tag: return False def nextIntersectionClosestTo(self, edge, solid, refPt): - # ef = edge.valueAt(edge.FirstParameter) - # em = edge.valueAt((edge.FirstParameter+edge.LastParameter)/2) - # el = edge.valueAt(edge.LastParameter) - # print("-------- intersect %s (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f) refp=(%.2f, %.2f, %.2f)" % (type(edge.Curve), ef.x, ef.y, ef.z, em.x, em.y, em.z, el.x, el.y, el.z, refPt.x, refPt.y, refPt.z)) + # debugEdge(edge, 'intersects_') vertexes = edge.common(solid).Vertexes if vertexes: - return sorted(vertexes, key=lambda v: (v.Point - refPt).Length)[0].Point + pt = sorted(vertexes, key=lambda v: (v.Point - refPt).Length)[0].Point + debugEdge(edge, "intersects (%.2f, %.2f, %.2f) -> (%.2f, %.2f, %.2f)" % (refPt.x, refPt.y, refPt.z, pt.x, pt.y, pt.z)) + return pt return None def intersects(self, edge, param): @@ -507,6 +506,7 @@ class MapWireToTag: self.tail = None self.finalEdge = edge if self.tag.solid.isInside(edge.valueAt(edge.LastParameter), PathGeom.Tolerance, True): + PathLog.track('solid.isInside') self.addEdge(edge) else: i = self.tag.intersects(edge, edge.LastParameter) @@ -517,8 +517,10 @@ class MapWireToTag: PathLog.debug('originAt: (%.2f, %.2f, %.2f)' % (o.x, o.y, o.z)) i = edge.valueAt(edge.FirstParameter) if PathGeom.pointsCoincide(i, edge.valueAt(edge.FirstParameter)): + PathLog.track('tail') self.tail = edge else: + PathLog.track('split') e, tail = PathGeom.splitEdgeAt(edge, i) self.addEdge(e) self.tail = tail diff --git a/src/Mod/Path/PathScripts/PathGeom.py b/src/Mod/Path/PathScripts/PathGeom.py index c4ad4faa5d..2fbaae4a40 100644 --- a/src/Mod/Path/PathScripts/PathGeom.py +++ b/src/Mod/Path/PathScripts/PathGeom.py @@ -433,22 +433,10 @@ def splitArcAt(edge, pt): """splitArcAt(edge, pt) Returns a list of 2 edges which together form the original arc split at the given point. The Vector pt has to represent a point on the given arc.""" - p1 = edge.valueAt(edge.FirstParameter) - p2 = pt - p3 = edge.valueAt(edge.LastParameter) - edges = [] - - p = edge.Curve.parameter(p2) - #print("splitArcAt(%.2f, %.2f, %.2f): %.2f - %.2f - %.2f" % (pt.x, pt.y, pt.z, edge.FirstParameter, p, edge.LastParameter)) - - p12 = edge.Curve.value((edge.FirstParameter + p)/2) - p23 = edge.Curve.value((p + edge.LastParameter)/2) - #print("splitArcAt: p12=(%.2f, %.2f, %.2f) p23=(%.2f, %.2f, %.2f)" % (p12.x, p12.y, p12.z, p23.x, p23.y, p23.z)) - - edges.append(Part.Edge(Part.Arc(p1, p12, p2))) - edges.append(Part.Edge(Part.Arc(p2, p23, p3))) - - return edges + p = edge.Curve.parameter(pt) + e0 = Part.Arc(edge.Curve.copy(), edge.FirstParameter, p).toShape() + e1 = Part.Arc(edge.Curve.copy(), p, edge.LastParameter).toShape() + return [e0, e1] def splitEdgeAt(edge, pt): """splitEdgeAt(edge, pt) diff --git a/src/Mod/Path/PathTests/PathTestUtils.py b/src/Mod/Path/PathTests/PathTestUtils.py index b247aa0ab6..81313a84ae 100644 --- a/src/Mod/Path/PathTests/PathTestUtils.py +++ b/src/Mod/Path/PathTests/PathTestUtils.py @@ -37,11 +37,11 @@ class PathTestBase(unittest.TestCase): """Verify that two float values are approximately the same.""" self.assertTrue(math.fabs(f1 - f2) < error, "%f != %f" % (f1, f2)) - def assertCoincide(self, pt1, pt2): + def assertCoincide(self, pt1, pt2, error=0.0001): """Verify that two points coincide - roughly speaking.""" - self.assertRoughly(pt1.x, pt2.x) - self.assertRoughly(pt1.y, pt2.y) - self.assertRoughly(pt1.z, pt2.z) + self.assertRoughly(pt1.x, pt2.x, error) + self.assertRoughly(pt1.y, pt2.y, error) + self.assertRoughly(pt1.z, pt2.z, error) def assertPlacement(self, p1, p2): """Verify that two placements are roughly identical.""" diff --git a/src/Mod/Path/PathTests/TestPathGeom.py b/src/Mod/Path/PathTests/TestPathGeom.py index f4882d4000..2d06f744f4 100644 --- a/src/Mod/Path/PathTests/TestPathGeom.py +++ b/src/Mod/Path/PathTests/TestPathGeom.py @@ -395,6 +395,8 @@ class TestPathGeom(PathTestBase): def test65(self): """Verify splitEdgeAt.""" + + # split a line segment e = PathGeom.splitEdgeAt(Part.Edge(Part.LineSegment(Vector(), Vector(2, 4, 6))), Vector(1, 2, 3)) self.assertLine(e[0], Vector(), Vector(1,2,3)) self.assertLine(e[1], Vector(1,2,3), Vector(2,4,6)) @@ -426,6 +428,35 @@ class TestPathGeom(PathTestBase): self.assertCurve(e[0], p1, p12, p2) self.assertCurve(e[1], p2, p23, p3) + def test66(self): + '''Split arc real world sample''' + + af = Vector(421.55, 378.41, 1) + am = Vector(459.51, 372.61, 1) + al = Vector(491.75, 351.75, 1) + arc = Part.Edge(Part.ArcOfCircle(af, am, al)) + ac = arc.Curve.Center + + s = Vector(434.54, 378.26, 1) + head, tail = PathGeom.splitEdgeAt(arc, s) + + # make sure the arcs connect as they should + self.assertCoincide(arc.valueAt(arc.FirstParameter), head.valueAt(head.FirstParameter), 0.005) + self.assertCoincide(s, head.valueAt(head.LastParameter), 0.005) + self.assertCoincide(s, tail.valueAt(tail.FirstParameter), 0.005) + i = arc.valueAt(arc.LastParameter) + j = tail.valueAt(tail.LastParameter) + print("(%.2f, %.2f, %.2f) vs. (%.2f, %.2f, %.2f)" % (i.x, i.y, i.z, j.x, j.y, j.z)) + self.assertCoincide(arc.valueAt(arc.LastParameter), tail.valueAt(tail.LastParameter), 0.005) + + # make sure the radii match + self.assertRoughly(arc.Curve.Radius, head.Curve.Radius, 0.001) + self.assertRoughly(arc.Curve.Radius, tail.Curve.Radius, 0.001) + + # also, all arcs should have the same center + self.assertCoincide(arc.Curve.Center, head.Curve.Center, 0.001) + self.assertCoincide(arc.Curve.Center, tail.Curve.Center, 0.001) + def test70(self): '''Flip a line.''' edge = Part.Edge(Part.Line(Vector(0,0,0), Vector(3, 2, 1)))