Fixed helix construction.

This commit is contained in:
Markus Lampert 2016-12-05 14:37:36 -08:00
parent a3ae53a82b
commit 0fabe5c079
2 changed files with 158 additions and 15 deletions

View File

@ -128,6 +128,33 @@ class PathGeom:
Convenience function to return the projection of the Vector in the XY-plane."""
return Vector(point.x, point.y, 0)
@classmethod
def cmdForEdge(cls, edge):
pt = edge.valueAt(edge.LastParameter)
params = {'X': pt.x, 'Y': pt.y, 'Z': pt.z}
if type(edge.Curve) == Part.Line or type(edge.Curve) == Part.LineSegment:
command = Path.Command('G1', params)
else:
p1 = edge.valueAt(edge.FirstParameter)
p2 = edge.valueAt((edge.FirstParameter + edge.LastParameter)/2)
p3 = pt
if Side.Left == Side.of(p2 - p1, p3 - p2):
cmd = 'G3'
else:
cmd = 'G2'
pa = PathGeom.xy(p1)
pb = PathGeom.xy(p2)
pc = PathGeom.xy(p3)
pd = Part.Circle(PathGeom.xy(p1), PathGeom.xy(p2), PathGeom.xy(p3)).Center
#print("**** (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f)" % (pa.x, pa.y, pa.z, pc.x, pc.y, pc.z))
#print("**** (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f)" % (pb.x, pb.y, pb.z, pd.x, pd.y, pd.z))
offset = Part.Circle(PathGeom.xy(p1), PathGeom.xy(p2), PathGeom.xy(p3)).Center - p1
#print("**** (%.2f, %.2f, %.2f)" % (offset.x, offset.y, offset.z))
params.update({'I': offset.x, 'J': offset.y, 'K': (p3.z - p1.z)/2})
command = Path.Command(cmd, params)
#print command
return command
@classmethod
def edgeForCmd(cls, cmd, startPoint):
"""(cmd, startPoint).
@ -215,26 +242,76 @@ class PathGeom:
@classmethod
def arcToHelix(cls, edge, z0, z1):
m = FreeCAD.Matrix()
m.unity()
"""(edge, z0, z1)
Assuming edge is an arc it'll return a helix matching the arc starting at z0 and rising/falling to z1."""
p1 = edge.valueAt(edge.FirstParameter)
p2 = edge.valueAt(edge.LastParameter)
z = p1.z
pd = p2 - p1
dz = z1 - z0
cmd = cls.cmdForEdge(edge)
params = cmd.Parameters
params.update({'Z': z1, 'K': (z1 - z0)/2})
command = Path.Command(cmd.Name, params)
#print("arcToHelix(%.2f, %.2f): dz=%.2f, dy=%.2f, z=%.2f" % (z0 ,z1, dz, pd.y, z))
return cls.edgeForCmd(command, FreeCAD.Vector(p1.x, p1.y, z0))
m.A32 = dz / pd.y
m.A34 = - m.A32
if dz < 0:
m.A34 *= p2.y
m.A34 += z1 - z
@classmethod
def helixToArc(cls, edge, z = 0):
"""(edge, z=0)
Returns the projection of the helix onto the XY-plane with a given offset."""
p1 = edge.valueAt(edge.FirstParameter)
p2 = edge.valueAt((edge.FirstParameter + edge.LastParameter)/2)
p3 = edge.valueAt(edge.LastParameter)
p01 = FreeCAD.Vector(p1.x, p1.y, z)
p02 = FreeCAD.Vector(p2.x, p2.y, z)
p03 = FreeCAD.Vector(p3.x, p3.y, z)
return Part.Edge(Part.Arc(p01, p02, p03))
@classmethod
def splitArcAt(cls, edge, pt):
"""(edge, pt)
Returns a list of 2 edges which together form the original arc split at the given point.
The Vector pt has to represnt 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
@classmethod
def splitEdgeAt(cls, edge, pt):
"""(edge, pt)
Returns a list of 2 edges, forming the original edge split at the given point.
The results are undefined if the Vector representing the point is not part of the edge."""
# I could not get the OCC parameterAt and split to work ...
# pt HAS to be on the edge, otherwise the results are undefined
p1 = edge.valueAt(edge.FirstParameter)
p2 = pt
p3 = edge.valueAt(edge.LastParameter)
edges = []
if type(edge.Curve) == Part.Line or type(edge.Curve) == Part.LineSegment:
# it's a line
return [Part.Edge(Part.LineSegment(p1, p2)), Part.Edge(Part.LineSegment(p2, p3))]
elif type(edge.Curve) == Part.Circle:
# it's an arc
return cls.splitArcAt(edge, pt)
else:
m.A34 *= p1.y
m.A34 += z0 - z
# it's a helix
arc = cls.helixToArc(edge, 0)
aes = cls.splitArcAt(arc, FreeCAD.Vector(pt.x, pt.y, 0))
return [cls.arcToHelix(aes[0], p1.z, p2.z), cls.arcToHelix(aes[1], p2.z, p3.z)]
e = edge.transformGeometry(m).Edges[0]
return e

View File

@ -172,3 +172,69 @@ class TestPathGeom(PathTestBase):
e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p11, p12, p13)), 2, -2)
self.assertCurve(e, p1 + Vector(0,0,2), p2, p3 + Vector(0,0,-2))
o = 10*math.sin(math.pi/4)
p1 = Vector(10, -10, 1)
p2 = Vector(10 - 10*math.sin(math.pi/4), -10*math.cos(math.pi/4), 1)
p3 = Vector(0, 0, 1)
e = PathGeom.arcToHelix(Part.Edge(Part.Arc(p1, p2, p3)), 0, 5)
self.assertCurve(e, Vector(10,-10,0), Vector(p2.x,p2.y,2.5), Vector(0, 0, 5))
def test62(self):
"""Verify splitArcAt returns proper subarcs."""
p1 = Vector(10,-10,0)
p2 = Vector(0,0,0)
p3 = Vector(10,10,0)
arc = Part.Edge(Part.Arc(p1, p2, p3))
o = 10*math.sin(math.pi/4)
p12 = Vector(10 - o, -o, 0)
p23 = Vector(10 - o, +o, 0)
e = PathGeom.splitArcAt(arc, p2)
self.assertCurve(e[0], p1, p12, p2)
self.assertCurve(e[1], p2, p23, p3)
p34 = Vector(10 - 10*math.sin(1*math.pi/8), -10*math.cos(1*math.pi/8), 0)
p45 = Vector(10 - 10*math.sin(5*math.pi/8), -10*math.cos(5*math.pi/8), 0)
e = PathGeom.splitArcAt(arc, p12)
self.assertCurve(e[0], p1, p34, p12)
self.assertCurve(e[1], p12, p45, p3)
def test65(self):
"""Verify splitEdgeAt."""
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))
# split an arc
p1 = Vector(10,-10,1)
p2 = Vector(0,0,1)
p3 = Vector(10,10,1)
arc = Part.Edge(Part.Arc(p1, p2, p3))
e = PathGeom.splitEdgeAt(arc, p2)
o = 10*math.sin(math.pi/4)
p12 = Vector(10 - o, -o, 1)
p23 = Vector(10 - o, +o, 1)
self.assertCurve(e[0], p1, p12, p2)
self.assertCurve(e[1], p2, p23, p3)
# split a helix
p1 = Vector(10,-10,0)
p2 = Vector(0,0,5)
p3 = Vector(10,10,10)
h = PathGeom.arcToHelix(arc, 0, 10)
self.assertCurve(h, p1, p2, p3)
e = PathGeom.splitEdgeAt(h, p2)
o = 10*math.sin(math.pi/4)
p12 = Vector(10 - o, -o, 2.5)
p23 = Vector(10 - o, +o, 7.5)
pf = e[0].valueAt((e[0].FirstParameter + e[0].LastParameter)/2)
pl = e[1].valueAt((e[1].FirstParameter + e[1].LastParameter)/2)
self.assertCurve(e[0], p1, p12, p2)
self.assertCurve(e[1], p2, p23, p3)