Fixed open wire offsetting and orienting.

This commit is contained in:
Markus Lampert
2018-06-28 22:19:35 -07:00
parent 4a8653b1c6
commit c4ae92cf3c
2 changed files with 323 additions and 17 deletions

View File

@@ -103,30 +103,41 @@ def offsetWire(wire, base, offset, forward):
# offsetting a single edge doesn't work because there is an infinite
# possible planes into which the edge could be offset
# luckily, the plane here must be the XY-plane ...
n = (edge.Vertexes[1].Point - edge.Vertexes[0].Point).cross(FreeCAD.Vector(0, 0, 1))
p0 = edge.Vertexes[0].Point
v0 = edge.Vertexes[1].Point - p0
n = v0.cross(FreeCAD.Vector(0, 0, 1))
o = n.normalize() * offset
edge.translate(o)
if base.isInside(edge.valueAt((edge.FirstParameter + edge.LastParameter)/2), offset/2, True):
# offset edde the other way if the result is inside
if base.isInside(edge.valueAt((edge.FirstParameter + edge.LastParameter) / 2), offset / 2, True):
edge.translate(-2 * o)
w = Part.Wire([edge])
return orientWire(w, forward)
# flip the edge if it's not on the right side of the original edge
if forward is not None:
v1 = edge.Vertexes[1].Point - p0
left = PathGeom.Side.Left == PathGeom.Side.of(v0, v1)
if left != forward:
edge = PathGeom.flipEdge(edge)
return Part.Wire([edge])
# if we get to this point the assumption is that makeOffset2D can deal with the edge
pass
w = wire.makeOffset2D(offset)
offsetWire = wire.makeOffset2D(offset)
if wire.isClosed():
if not base.isInside(w.Edges[0].Vertexes[0].Point, offset/2, True):
if not base.isInside(offsetWire.Edges[0].Vertexes[0].Point, offset/2, True):
PathLog.track('closed - outside')
return orientWire(w, forward)
return orientWire(offsetWire, forward)
PathLog.track('closed - inside')
try:
w = wire.makeOffset2D(-offset)
offsetWire = wire.makeOffset2D(-offset)
except:
# most likely offsetting didn't work because the wire is a hole
# and the offset is too big - making the hole vanish
return None
return orientWire(w, forward)
return orientWire(offsetWire, forward)
# An edge is considered to be inside of shape if the mid point is inside
# Of the remaining edges we take the longest wire to be the engraving side
@@ -137,12 +148,15 @@ def offsetWire(wire, base, offset, forward):
# if they need to be discarded, split, that should happen in a post process
# Depending on the Axis of the circle, and which side remains we know if the wire needs to be flipped
# first, let's make sure all edges are oriented the proper way
wire = orientWire(wire, None)
# find edges that are not inside the shape
def isInside(edge):
if base.isInside(edge.Vertexes[0].Point, offset/2, True) and base.isInside(edge.Vertexes[-1].Point, offset/2, True):
return True
return False
outside = [e for e in w.Edges if not isInside(e)]
outside = [e for e in offsetWire.Edges if not isInside(e)]
# discard all edges that are not part of the longest wire
longestWire = None
for w in [Part.Wire(el) for el in Part.sortEdges(outside)]:
@@ -155,17 +169,22 @@ def offsetWire(wire, base, offset, forward):
def isCircleAt(edge, center):
'''isCircleAt(edge, center) ... helper function returns True if edge is a circle at the given center.'''
if Part.Circel == type(edge.Curve) or Part.ArcOfCircle == type(edge.Curve):
if Part.Circle == type(edge.Curve) or Part.ArcOfCircle == type(edge.Curve):
return PathGeom.pointsCoincide(edge.Curve.Center, center)
return False
# split offset wire into edges to the left side and edges to the right side
collectLeft = False
collectRight = False
leftSideEdges = []
rightSideEdges = []
for e in (w.Edges + w.Edges):
# traverse through all edges in order and start collecting them when we encounter
# an end point (circle centered at one of the end points of the original wire).
# should we come to an end point and determine that we've already collected the
# next side, we're done
for e in (offsetWire.Edges + offsetWire.Edges):
if isCircleAt(e, start):
if PathGeom.pointsCoincide(e.Curve.Axis, FreeCAD.Vector(0, 0, 1)):
if not collectLeft and leftSideEdges:
@@ -193,15 +212,22 @@ def offsetWire(wire, base, offset, forward):
elif collectRight:
rightSideEdges.append(e)
# figure out if all the left sided edges or the right sided edges are the ones
# that are 'outside'. However, we return the full side.
edges = leftSideEdges
for e in longestWire.Edges:
for e0 in rightSideEdges:
if PathGeom.edgesMatch(e, e0):
if forward:
edges = [PathGeom.flipEdge(edge) for edge in rightSideEdges]
return Part.Wire(edges)
edges = rightSideEdges
if not forward:
edges.reverse()
return orientWire(Part.Wire(edges), None)
# at this point we have the correct edges and they are in the order for forward
# traversal (climb milling). If that's not what we want just reverse the order,
# orientWire takes care of orienting the edges appropriately.
if not forward:
edges = [PathGeom.flipEdge(edge) for edge in rightSideEdges]
return Part.Wire(edges)
edges.reverse()
return orientWire(Part.Wire(edges), None)