Added Helix. Other cleanup and fixes.

This commit is contained in:
Pekka Roivainen
2017-05-07 12:05:37 +03:00
committed by wmayer
parent cad471d6b9
commit a9e1d8173f

View File

@@ -51,7 +51,8 @@ class ObjectDressup:
obj.addProperty("App::PropertyLink", "ToolController", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The tool controller that will be used to calculate the path"))
obj.addProperty("App::PropertyLink", "Base","Path", QtCore.QT_TRANSLATE_NOOP("PathDressup_RampEntry", "The base path to modify"))
obj.addProperty("App::PropertyAngle", "Angle", "Path", QtCore.QT_TRANSLATE_NOOP("PathDressup_RampEntry", "Angle of ramp."))
obj.addProperty("App::PropertyInteger", "Method", "Path", QtCore.QT_TRANSLATE_NOOP("PathDressup_RampEntry", "Ramping method to use (1,2)"))
obj.addProperty("App::PropertyEnumeration", "Method", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Ramping Method"))
obj.Method = ['RampMethod1', 'RampMethod2', 'Helix']
obj.Proxy = self
def __getstate__(self):
return None
@@ -81,14 +82,20 @@ class ObjectDressup:
return
if not obj.Base.Path:
return
if obj.Angle >= 90:
obj.Angle = 89.9
elif obj.Angle <= 0:
obj.Angle = 0.1
self.angle = obj.Angle
self.method = obj.Method
self.wire, self.rapids = PathGeom.wireForPath(obj.Base.Path)
self.outedges = self.generateRamps()
if self.method == 'RampMethod1' or self.method == 'RampMethod2':
self.outedges = self.generateRamps()
else:
self.outedges = self.generateHelix()
obj.Path = self.createCommands(obj, self.outedges)
def generateRamps(self):
def generateRamps(self, allowBounce = True):
edges = self.wire.Edges
outedges = []
for edge in edges:
@@ -117,7 +124,7 @@ class ObjectDressup:
if abs(cp0.z-cp1.z) > 1e-6:
#this edge is not parallel to XY plane, not qualified for ramping.
break
PathLog.debug("Next edge length {}".format(candidate.Length))
#PathLog.debug("Next edge length {}".format(candidate.Length))
rampedges.append(candidate)
coveredlen = coveredlen + candidate.Length
@@ -131,14 +138,15 @@ class ObjectDressup:
outedges.append(edge)
else:
if not covered:
l = 0
for redge in rampedges:
l = l + redge.Length
rampangle = math.degrees(math.atan(l/plungelen))
PathLog.debug("Cannot cover with desired angle, tightening angle to: {}".format(rampangle))
if (not allowBounce) or self.method==2:
l = 0
for redge in rampedges:
l = l + redge.Length
rampangle = math.degrees(math.atan(l/plungelen))
PathLog.warning("Cannot cover with desired angle, tightening angle to: {}".format(rampangle))
PathLog.debug("Doing ramp to edges: {}".format(rampedges))
if self.method==1:
#PathLog.debug("Doing ramp to edges: {}".format(rampedges))
if self.method== 'RampMethod1':
outedges.extend(self.createRampMethod1(rampedges, p0, projectionlen, rampangle))
else:
outedges.extend(self.createRampMethod2(rampedges, p0, projectionlen, rampangle))
@@ -148,6 +156,85 @@ class ObjectDressup:
outedges.append(edge)
return outedges
def generateHelix(self):
edges = self.wire.Edges
minZ = self.findMinZ(edges)
outedges = []
i = 0
while i < len(edges):
edge = edges[i]
israpid = False
for redge in self.rapids:
if PathGeom.edgesMatch(edge,redge):
israpid = True
if not israpid:
bb = edge.BoundBox
p0 = edge.Vertexes[0].Point
p1 = edge.Vertexes[1].Point
if bb.XLength < 1e-6 and bb.YLength < 1e-6 and bb.ZLength > 0 and p0.z > p1.z:
plungelen = abs(p0.z-p1.z)
PathLog.debug("Found plunge move at X:{} Y:{} From Z:{} to Z{}, Searching for closed loop".format(p0.x,p0.y,p0.z,p1.z))
# next need to determine how many edges in the path after plunge are needed to cover the length:
loopFound = False
coveredlen = 0
rampedges = []
j = i+1
while not loopFound:
candidate = edges[j]
cp0 = candidate.Vertexes[0].Point
cp1 = candidate.Vertexes[1].Point
if PathGeom.pointsCoincide(p1, cp1):
#found closed loop
loopFound = True
rampedges.append(candidate)
break
if abs(cp0.z-cp1.z) > 1e-6:
#this edge is not parallel to XY plane, not qualified for ramping.
break
#PathLog.debug("Next edge length {}".format(candidate.Length))
rampedges.append(candidate)
j=j+1
if j >= len(edges):
break
if len(rampedges) == 0 or not loopFound:
PathLog.debug("No suitable helix found")
outedges.append(edge)
else:
outedges.extend(self.createHelix(rampedges, p0, p1))
if not PathGeom.isRoughly(p1.z, minZ):
# the edges covered by the helix not handled again,
#unless reached the bottom height
i = j
else:
outedges.append(edge)
else:
outedges.append(edge)
i = i + 1
return outedges
def createHelix(self, rampedges, startPoint, endPoint):
outedges = []
ramplen = 0
for redge in rampedges:
ramplen = ramplen + redge.Length
rampheight = abs(endPoint.z - startPoint.z)
rampangle_rad = math.atan(ramplen/rampheight)
curPoint = startPoint
for i, redge in enumerate(rampedges):
if i < len(rampedges)-1:
deltaZ = redge.Length / math.tan(rampangle_rad)
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.LastParameter).x, redge.valueAt(redge.LastParameter).y, curPoint.z - deltaZ)
outedges.append(self.createRampEdge(redge, curPoint, newPoint))
curPoint = newPoint
else:
#on the last edge, force it to end to the endPoint
#this should happen automatically, but this avoids any rounding error
outedges.append(self.createRampEdge(redge, curPoint, endPoint))
return outedges
def createRampEdge(self,originalEdge, startPoint, endPoint):
#PathLog.debug("Create edge from [{},{},{}] to [{},{},{}]".format(startPoint.x,startPoint.y, startPoint.z, endPoint.x, endPoint.y, endPoint.z))
if type(originalEdge.Curve) == Part.Line or type(originalEdge.Curve) == Part.LineSegment:
@@ -159,6 +246,31 @@ class ObjectDressup:
else:
PathLog.error("Edge should not be helix")
def getreversed(self, edges):
"""
Reverses the edge array and the direction of each edge
"""
outedges = []
for edge in reversed(edges):
#reverse the start and end points
startPoint = edge.valueAt(edge.LastParameter)
endPoint = edge.valueAt(edge.FirstParameter)
if type(edge.Curve) == Part.Line or type(edge.Curve) == Part.LineSegment:
outedges.append(Part.makeLine(startPoint,endPoint))
elif type(edge.Curve) == Part.Circle:
arcMid = edge.valueAt((edge.FirstParameter+edge.LastParameter)/2)
outedges.append(Part.Arc(startPoint, arcMid, endPoint).toShape())
else:
PathLog.error("Edge should not be helix")
return outedges
def findMinZ(self, edges):
minZ = 99999999999
for edge in edges:
for v in edge.Vertexes:
if v.Point.z < minZ:
minZ = v.Point.z
return minZ
def createRampMethod1(self,rampedges, p0, projectionlen, rampangle):
"""
This method generates ramp with following pattern:
@@ -173,41 +285,58 @@ class ObjectDressup:
outedges = []
rampremaining = projectionlen
curPoint = p0 # start from the upper point of plunge
for i,redge in enumerate(rampedges):
if redge.Length >= rampremaining:
#this edge needs to be splitted
splitEdge = PathGeom.splitEdgeAt(redge, redge.valueAt(rampremaining))
PathLog.debug("Got split edges with lengths: {}, {}".format(splitEdge[0].Length, splitEdge[1].Length))
#ramp ends to the last point of first edge
p1 = splitEdge[0].valueAt(splitEdge[0].LastParameter)
outedges.append(self.createRampEdge(splitEdge[0], curPoint, p1))
#now we have reached the end of the ramp. Go back to plunge position with constant Z
#start that by going to the beginning of this splitEdge
outedges.append(self.createRampEdge(splitEdge[0], p1, redge.valueAt(redge.FirstParameter)))
elif i ==len(rampedges)-1:
#last ramp element but still did not reach the full length?
#Probably a rounding issue on floats.
#Lets finish the ramp anyway
p1 = redge.valueAt(redge.LastParameter)
outedges.append(self.createRampEdge(redge, curPoint, p1))
#and go back that edge
outedges.append(self.createRampEdge(redge, p1, redge.valueAt(redge.FirstParameter)))
done = False
goingForward = True
while not done:
for i,redge in enumerate(rampedges):
if redge.Length >= rampremaining:
#will reach end of ramp within this edge, needs to be splitted
splitEdge = PathGeom.splitEdgeAt(redge, redge.valueAt(rampremaining))
PathLog.debug("Got split edge (index: {}) with lengths: {}, {}".format(i, splitEdge[0].Length, splitEdge[1].Length))
#ramp ends to the last point of first edge
p1 = splitEdge[0].valueAt(splitEdge[0].LastParameter)
outedges.append(self.createRampEdge(splitEdge[0], curPoint, p1))
#now we have reached the end of the ramp. Go back to plunge position with constant Z
#start that by going to the beginning of this splitEdge
if goingForward:
outedges.append(self.createRampEdge(splitEdge[0], p1, redge.valueAt(redge.FirstParameter)))
else:
#if we were reversing, we continue to the same direction as the ramp
outedges.append(self.createRampEdge(splitEdge[0], p1, redge.valueAt(redge.LastParameter)))
done = True
break
else:
deltaZ = redge.Length / math.tan(math.radians(rampangle))
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.LastParameter).x, redge.valueAt(redge.LastParameter).y, curPoint.z - deltaZ)
outedges.append(self.createRampEdge(redge, curPoint, newPoint))
curPoint = newPoint
rampremaining = rampremaining - redge.Length
else:
deltaZ = redge.Length / math.tan(math.radians(rampangle))
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.LastParameter).x, redge.valueAt(redge.LastParameter).y, curPoint.z - deltaZ)
outedges.append(self.createRampEdge(redge, curPoint, newPoint))
curPoint = newPoint
rampremaining = rampremaining - redge.Length
if not done:
#we did not reach the end of the ramp going this direction, lets reverse.
rampedges = self.getreversed(rampedges)
PathLog.debug("Reversing")
if goingForward:
goingForward = False
else:
goingForward = True
#now we need to return to original position.
if goingForward:
#if the ramp was going forward, the return edges are the edges we already covered in ramping,
#exept the last one, which was already covered inside for loop. Direction needs to be reversed also
returnedges = self.getreversed(rampedges[:i])
else:
#if the ramp was already reversing, the edges needed for return are the ones
#which were not covered in ramp
returnedges = rampedges[(i+1):]
#the last edge got handled previously
rampedges.pop()
#return backwards to the plunge position
for redge in reversed(rampedges):
outedges.append(self.createRampEdge(redge, redge.valueAt(redge.LastParameter),redge.valueAt(redge.FirstParameter)))
#add the return edges:
outedges.extend(returnedges)
return outedges
def createRampMethod2(self,rampedges, p0, projectionlen, rampangle):
"""
This method generates ramp with following pattern:
@@ -221,43 +350,46 @@ class ObjectDressup:
outedges = []
rampremaining = projectionlen
curPoint = p0 # start from the upper point of plunge
for i,redge in enumerate(rampedges):
if redge.Length >= rampremaining:
#this edge needs to be splitted
splitEdge = PathGeom.splitEdgeAt(redge, redge.valueAt(rampremaining))
PathLog.debug("Got split edges with lengths: {}, {}".format(splitEdge[0].Length, splitEdge[1].Length))
#ramp starts at the last point of first edge
p1 = splitEdge[0].valueAt(splitEdge[0].LastParameter)
p1.z = p0.z
outedges.append(self.createRampEdge(splitEdge[0], curPoint, p1))
#now we have reached the beginning of the ramp.
#start that by going to the beginning of this splitEdge
deltaZ = splitEdge[0].Length / math.tan(math.radians(rampangle))
newPoint = FreeCAD.Base.Vector(splitEdge[0].valueAt(splitEdge[0].FirstParameter).x, splitEdge[0].valueAt(splitEdge[0].FirstParameter).y, p1.z - deltaZ)
outedges.append(self.createRampEdge(splitEdge[0], p1, newPoint))
curPoint = newPoint
elif i ==len(rampedges)-1:
#last ramp element but still did not reach the full length?
#Probably a rounding issue on floats.
#Lets start the ramp anyway
p1 = redge.valueAt(redge.LastParameter)
p1.z = p0.z
outedges.append(self.createRampEdge(redge, curPoint, p1))
#and go back that edge
deltaZ = redge.Length / math.tan(math.radians(rampangle))
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.FirstParameter).x, redge.valueAt(redge.FirstParameter).y, p1.z-deltaZ)
outedges.append(self.createRampEdge(redge, p1, newPoint))
curPoint = newPoint
if PathGeom.pointsCoincide(PathGeom.xy(p0), PathGeom.xy(rampedges[-1].valueAt(rampedges[-1].LastParameter))):
PathLog.debug("The ramp forms a closed wire, needless to move on original Z height")
else:
for i,redge in enumerate(rampedges):
if redge.Length >= rampremaining:
#this edge needs to be splitted
splitEdge = PathGeom.splitEdgeAt(redge, redge.valueAt(rampremaining))
PathLog.debug("Got split edges with lengths: {}, {}".format(splitEdge[0].Length, splitEdge[1].Length))
#ramp starts at the last point of first edge
p1 = splitEdge[0].valueAt(splitEdge[0].LastParameter)
p1.z = p0.z
outedges.append(self.createRampEdge(splitEdge[0], curPoint, p1))
#now we have reached the beginning of the ramp.
#start that by going to the beginning of this splitEdge
deltaZ = splitEdge[0].Length / math.tan(math.radians(rampangle))
newPoint = FreeCAD.Base.Vector(splitEdge[0].valueAt(splitEdge[0].FirstParameter).x, splitEdge[0].valueAt(splitEdge[0].FirstParameter).y, p1.z - deltaZ)
outedges.append(self.createRampEdge(splitEdge[0], p1, newPoint))
curPoint = newPoint
elif i ==len(rampedges)-1:
#last ramp element but still did not reach the full length?
#Probably a rounding issue on floats.
#Lets start the ramp anyway
p1 = redge.valueAt(redge.LastParameter)
p1.z = p0.z
outedges.append(self.createRampEdge(redge, curPoint, p1))
#and go back that edge
deltaZ = redge.Length / math.tan(math.radians(rampangle))
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.FirstParameter).x, redge.valueAt(redge.FirstParameter).y, p1.z-deltaZ)
outedges.append(self.createRampEdge(redge, p1, newPoint))
curPoint = newPoint
else:
#we are travelling on start depth
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.LastParameter).x, redge.valueAt(redge.LastParameter).y, p0.z)
outedges.append(self.createRampEdge(redge, curPoint, newPoint))
curPoint = newPoint
rampremaining = rampremaining - redge.Length
else:
#we are travelling on start depth
newPoint = FreeCAD.Base.Vector(redge.valueAt(redge.LastParameter).x, redge.valueAt(redge.LastParameter).y, p0.z)
outedges.append(self.createRampEdge(redge, curPoint, newPoint))
curPoint = newPoint
rampremaining = rampremaining - redge.Length
#the last edge got handled previously
rampedges.pop()
#the last edge got handled previously
rampedges.pop()
#ramp backwards to the plunge position
for i,redge in enumerate(reversed(rampedges)):
deltaZ = redge.Length / math.tan(math.radians(rampangle))
@@ -331,14 +463,15 @@ class ViewProviderDressup:
def claimChildren(self):
for i in self.obj.Base.InList:
if hasattr(i, "Group"):
group = i.Group
for g in group:
if g.Name == self.obj.Base.Name:
group.remove(g)
i.Group = group
print(i.Group)
if hasattr(self.obj.Base,"InList"):
for i in self.obj.Base.InList:
if hasattr(i, "Group"):
group = i.Group
for g in group:
if g.Name == self.obj.Base.Name:
group.remove(g)
i.Group = group
print(i.Group)
#FreeCADGui.ActiveDocument.getObject(obj.Base.Name).Visibility = False
return [self.obj.Base]