Path: fix several minor bugs in arc slot ops
This corrects which end of the slot Extend Slot Start/End are applied; error with Extend lengths between 0 and 1 and direction of extention on arc slots ( neg. is shorten ). Some renaming to make code more readable and self documenting.
This commit is contained in:
@@ -421,7 +421,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
def _makeOperation(self, obj):
|
||||
"""This method controls the overall slot creation process."""
|
||||
pnts = False
|
||||
featureCnt = 0
|
||||
featureCount = 0
|
||||
|
||||
if not hasattr(obj, 'Base'):
|
||||
msg = translate('PathSlot',
|
||||
@@ -444,9 +444,9 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
baseGeom = obj.Base[0]
|
||||
base, subsList = baseGeom
|
||||
self.base = base
|
||||
lenSL = len(subsList)
|
||||
featureCnt = lenSL
|
||||
if lenSL == 1:
|
||||
|
||||
featureCount = len(subsList)
|
||||
if featureCount == 1:
|
||||
PathLog.debug('Reference 1: {}'.format(obj.Reference1))
|
||||
sub1 = subsList[0]
|
||||
shape_1 = getattr(base.Shape, sub1)
|
||||
@@ -467,9 +467,9 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
return False
|
||||
|
||||
if self.isArc:
|
||||
cmds = self._finishArc(obj, pnts, featureCnt)
|
||||
cmds = self._finishArc(obj, pnts, featureCount)
|
||||
else:
|
||||
cmds = self._finishLine(obj, pnts, featureCnt)
|
||||
cmds = self._finishLine(obj, pnts, featureCount)
|
||||
|
||||
if cmds:
|
||||
return cmds
|
||||
@@ -477,7 +477,8 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
return False
|
||||
|
||||
def _finishArc(self, obj, pnts, featureCnt):
|
||||
"""This method finishes an Arc Slot operation."""
|
||||
"""This method finishes an Arc Slot operation.
|
||||
It returns the gcode for the slot operation."""
|
||||
PathLog.debug('arc center: {}'.format(self.arcCenter))
|
||||
self._addDebugObject(Part.makeLine(self.arcCenter, self.arcMidPnt), 'CentToMidPnt')
|
||||
|
||||
@@ -488,7 +489,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
PathLog.debug('arc radius: {}; offset radius: {}'.format(self.arcRadius, newRadius))
|
||||
if newRadius <= 0:
|
||||
msg = translate('PathSlot',
|
||||
'Current offset value is not possible.')
|
||||
'Current Extend Radius value produces negative arc radius.')
|
||||
FreeCAD.Console.PrintError(msg + '\n')
|
||||
return False
|
||||
else:
|
||||
@@ -514,7 +515,9 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
(p1, p2) = pnts
|
||||
begExt = obj.ExtendPathStart.Value
|
||||
endExt = obj.ExtendPathEnd.Value
|
||||
pnts = self._extendArcSlot(p1, p2, self.arcCenter, begExt, endExt)
|
||||
# invert endExt, begExt args to apply extentions to correct ends
|
||||
# XY geom is postitive CCW; Gcode postitive CW
|
||||
pnts = self._extendArcSlot(p1, p2, self.arcCenter, endExt, begExt)
|
||||
|
||||
if not pnts:
|
||||
return False
|
||||
@@ -541,51 +544,44 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
return cmds
|
||||
|
||||
def _makeArcGCode(self, obj, p1, p2):
|
||||
"""This method is the last in the overall slot creation process.
|
||||
"""This method is the last step in the overall arc slot creation process.
|
||||
It accepts the operation object and two end points for the path.
|
||||
It returns the slot gcode for the operation."""
|
||||
It returns the gcode for the slot operation."""
|
||||
CMDS = list()
|
||||
PATHS = [(p2, p1, 'G2'), (p1, p2, 'G3')]
|
||||
path_index = 0
|
||||
if obj.ReverseDirection :
|
||||
path_index = 1
|
||||
else :
|
||||
path_index = 0
|
||||
|
||||
def arcPass(PNTS, depth):
|
||||
def arcPass(POINTS, depth):
|
||||
cmds = list()
|
||||
(p1, p2, cmd) = PNTS
|
||||
(st_pt, end_pt, arcCmd) = POINTS
|
||||
# cmds.append(Path.Command('N (Tool type: {})'.format(toolType), {}))
|
||||
cmds.append(Path.Command('G0', {'X': p1.x, 'Y': p1.y, 'F': self.horizRapid}))
|
||||
cmds.append(Path.Command('G0', {'X': st_pt.x, 'Y': st_pt.y, 'F': self.horizRapid}))
|
||||
cmds.append(Path.Command('G1', {'Z': depth, 'F': self.vertFeed}))
|
||||
vtc = self.arcCenter.sub(p1) # vector to center
|
||||
vtc = self.arcCenter.sub(st_pt) # vector to center
|
||||
cmds.append(
|
||||
Path.Command(cmd,
|
||||
{'X': p2.x, 'Y': p2.y, 'I': vtc.x,
|
||||
Path.Command(arcCmd,
|
||||
{'X': end_pt.x, 'Y': end_pt.y, 'I': vtc.x,
|
||||
'J': vtc.y, 'F': self.horizFeed
|
||||
}))
|
||||
return cmds
|
||||
|
||||
if obj.LayerMode == 'Single-pass':
|
||||
if obj.ReverseDirection:
|
||||
path_index = 1
|
||||
CMDS.extend(arcPass(PATHS[path_index], obj.FinalDepth.Value))
|
||||
else:
|
||||
if obj.CutPattern == 'Line':
|
||||
if obj.ReverseDirection:
|
||||
path_index = 1
|
||||
for dep in self.depthParams:
|
||||
CMDS.extend(arcPass(PATHS[path_index], dep))
|
||||
for depth in self.depthParams:
|
||||
CMDS.extend(arcPass(PATHS[path_index], depth))
|
||||
CMDS.append(Path.Command('G0', {'Z': obj.SafeHeight.Value, 'F': self.vertRapid}))
|
||||
elif obj.CutPattern == 'ZigZag':
|
||||
i = 0
|
||||
for dep in self.depthParams:
|
||||
if obj.ReverseDirection:
|
||||
if i % 2.0 == 0: # even
|
||||
CMDS.extend(arcPass(PATHS[0], dep))
|
||||
else: # odd
|
||||
CMDS.extend(arcPass(PATHS[1], dep))
|
||||
else:
|
||||
if i % 2.0 == 0: # even
|
||||
CMDS.extend(arcPass(PATHS[1], dep))
|
||||
else: # odd
|
||||
CMDS.extend(arcPass(PATHS[0], dep))
|
||||
for depth in self.depthParams:
|
||||
if i % 2.0 == 0: # even
|
||||
CMDS.extend(arcPass(PATHS[path_index], depth))
|
||||
else: # odd
|
||||
CMDS.extend(arcPass(PATHS[not path_index], depth))
|
||||
i += 1
|
||||
# Raise to SafeHeight when finished
|
||||
CMDS.append(Path.Command('G0', {'Z': obj.SafeHeight.Value, 'F': self.vertRapid}))
|
||||
@@ -596,7 +592,8 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
return CMDS
|
||||
|
||||
def _finishLine(self, obj, pnts, featureCnt):
|
||||
"""This method finishes a Line Slot operation."""
|
||||
"""This method finishes a Line Slot operation.
|
||||
It returns the gcode for the line slot operation."""
|
||||
# Apply perpendicular rotation if requested
|
||||
perpZero = True
|
||||
if obj.PathOrientation == 'Perpendicular':
|
||||
@@ -667,9 +664,9 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
return cmds
|
||||
|
||||
def _makeLineGCode(self, obj, p1, p2):
|
||||
"""This method is the last in the overall slot creation process.
|
||||
"""This method is the last in the overall line slot creation process.
|
||||
It accepts the operation object and two end points for the path.
|
||||
It returns the slot gcode for the operation."""
|
||||
It returns the gcode for the slot operation."""
|
||||
CMDS = list()
|
||||
|
||||
def linePass(p1, p2, depth):
|
||||
@@ -708,7 +705,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
def _processSingle(self, obj, shape_1, sub1):
|
||||
"""This is the control method for slots based on a
|
||||
single Base Geometry feature."""
|
||||
make = False
|
||||
done = False
|
||||
cat1 = sub1[:4]
|
||||
|
||||
if cat1 == 'Face':
|
||||
@@ -735,21 +732,21 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
|
||||
if pnts:
|
||||
(p1, p2) = pnts
|
||||
make = True
|
||||
done = True
|
||||
|
||||
elif cat1 == 'Edge':
|
||||
PathLog.debug('Single edge')
|
||||
pnts = self._processSingleEdge(obj, shape_1)
|
||||
if pnts:
|
||||
(p1, p2) = pnts
|
||||
make = True
|
||||
done = True
|
||||
|
||||
elif cat1 == 'Vert':
|
||||
msg = translate('PathSlot',
|
||||
'Only a vertex selected. Add another feature to the Base Geometry.')
|
||||
FreeCAD.Console.PrintError(msg + '\n')
|
||||
|
||||
if make:
|
||||
if done:
|
||||
return (p1, p2)
|
||||
|
||||
return False
|
||||
@@ -762,7 +759,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
def getRadians(self, E):
|
||||
vect = self._dXdYdZ(E)
|
||||
norm = self._normalizeVector(vect)
|
||||
rads = self._xyToRadians(norm)
|
||||
rads = self._getVectorAngle(norm)
|
||||
deg = math.degrees(rads)
|
||||
if deg >= 180.0:
|
||||
deg -= 180.0
|
||||
@@ -909,7 +906,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
return (p1, p2)
|
||||
|
||||
def _processSingleEdge(self, obj, edge):
|
||||
"""Determine slot path endpoints from a single horizontally oriented face."""
|
||||
"""Determine slot path endpoints from a single horizontally oriented edge."""
|
||||
PathLog.debug('_processSingleEdge()')
|
||||
tolrnc = 0.0000001
|
||||
lineTypes = ['Part::GeomLine']
|
||||
@@ -927,42 +924,44 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
def isHorizontal(z1, z2, z3):
|
||||
# Check that all Z values are equal (isRoughly same)
|
||||
if (abs(z1 - z2) > tolrnc or
|
||||
abs(z1 - z3) > tolrnc or
|
||||
abs(z2 - z3) > tolrnc):
|
||||
abs(z1 - z3) > tolrnc ):
|
||||
# abs(z2 - z3) > tolrnc): 3rd test reduntant.
|
||||
return False
|
||||
return True
|
||||
|
||||
def circleCentFrom3Points(P1, P2, P3):
|
||||
def circumCircleFrom3Points(P1, P2, P3):
|
||||
# Source code for this function copied from (with modifications):
|
||||
# https://wiki.freecadweb.org/Macro_Draft_Circle_3_Points_3D
|
||||
P1P2 = (P2 - P1).Length
|
||||
P2P3 = (P3 - P2).Length
|
||||
P3P1 = (P1 - P3).Length
|
||||
vP2P1 = (P2 - P1)
|
||||
vP3P2 = (P3 - P2)
|
||||
vP1P3 = (P1 - P3)
|
||||
|
||||
# Circle radius.
|
||||
l = ((P1 - P2).cross(P2 - P3)).Length
|
||||
# r = P1P2 * P2P3 * P3P1 / 2 / l
|
||||
if round(l, 8) == 0.0:
|
||||
PathLog.error("The three points are aligned.")
|
||||
L = vP2P1.cross(vP3P2).Length
|
||||
# Circle radius (not used)
|
||||
# r = vP1P2.Length * vP2P3.Length * vP3P1.Length / 2 / l
|
||||
if round(L, 8) == 0.0:
|
||||
PathLog.error("The three points are colinear, arc is a straight.")
|
||||
return False
|
||||
|
||||
# Sphere center.
|
||||
a = P2P3**2 * (P1 - P2).dot(P1 - P3) / 2 / l**2
|
||||
b = P3P1**2 * (P2 - P1).dot(P2 - P3) / 2 / l**2
|
||||
c = P1P2**2 * (P3 - P1).dot(P3 - P2) / 2 / l**2
|
||||
P1.multiply(a)
|
||||
P2.multiply(b)
|
||||
P3.multiply(c)
|
||||
PC = P1 + P2 + P3
|
||||
return PC
|
||||
twolsqr= 2*L*L
|
||||
a = -vP3P2.dot(vP3P2) * vP2P1.dot(vP1P3) / twolsqr
|
||||
b = -vP1P3.dot(vP1P3) * vP3P2.dot(vP2P1) / twolsqr
|
||||
c = -vP2P1.dot(vP2P1) * vP1P3.dot(vP3P2) / twolsqr
|
||||
return P1*a + P2*b + P3*c
|
||||
|
||||
V1 = edge.Vertexes[0]
|
||||
p1 = FreeCAD.Vector(V1.X, V1.Y, 0.0)
|
||||
if len(edge.Vertexes) == 1: # circle has one virtex
|
||||
p2 = FreeCAD.Vector(p1)
|
||||
else :
|
||||
V2 = edge.Vertexes[1]
|
||||
p2 = FreeCAD.Vector(V2.X, V2.Y, 0.0)
|
||||
|
||||
# Process edge based on curve type
|
||||
if edge.Curve.TypeId in lineTypes:
|
||||
V1 = edge.Vertexes[0]
|
||||
V2 = edge.Vertexes[1]
|
||||
p1 = FreeCAD.Vector(V1.X, V1.Y, 0.0)
|
||||
p2 = FreeCAD.Vector(V2.X, V2.Y, 0.0)
|
||||
return (p1, p2)
|
||||
|
||||
elif edge.Curve.TypeId in curveTypes:
|
||||
if len(edge.Vertexes) == 1:
|
||||
# Circle edge
|
||||
@@ -971,47 +970,41 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
return False
|
||||
|
||||
self.isArc = 1
|
||||
V1 = edge.Vertexes[0]
|
||||
tp1 = edge.valueAt(edge.getParameterByLength(edge.Length * 0.33))
|
||||
tp2 = edge.valueAt(edge.getParameterByLength(edge.Length * 0.66))
|
||||
if not isHorizontal(V1.Z, tp1.z, tp2.z):
|
||||
return False
|
||||
|
||||
cent = edge.BoundBox.Center
|
||||
self.arcCenter = FreeCAD.Vector(cent.x, cent.y, 0.0)
|
||||
center = edge.BoundBox.Center
|
||||
self.arcCenter = FreeCAD.Vector(center.x, center.y, 0.0)
|
||||
midPnt = edge.valueAt(edge.getParameterByLength(edge.Length / 2.0))
|
||||
self.arcMidPnt = FreeCAD.Vector(midPnt.x, midPnt.y, 0.0)
|
||||
self.arcRadius = edge.BoundBox.XLength / 2.0
|
||||
p1 = FreeCAD.Vector(V1.X, V1.Y, 0.0)
|
||||
p2 = FreeCAD.Vector(V1.X, V1.Y, 0.0)
|
||||
else:
|
||||
# Arc edge
|
||||
PathLog.debug('Arc with multiple vertices.')
|
||||
self.isArc = 2
|
||||
V1 = edge.Vertexes[0]
|
||||
V2 = edge.Vertexes[1]
|
||||
midPnt = edge.valueAt(edge.getParameterByLength(edge.Length / 2.0))
|
||||
if not isHorizontal(V1.Z, V2.Z, midPnt.z):
|
||||
return False
|
||||
|
||||
p1 = FreeCAD.Vector(V1.X, V1.Y, 0.0)
|
||||
p2 = FreeCAD.Vector(V2.X, V2.Y, 0.0)
|
||||
# Duplicate points required because
|
||||
# circleCentFrom3Points() alters original arguments
|
||||
pA = FreeCAD.Vector(V1.X, V1.Y, 0.0)
|
||||
pB = FreeCAD.Vector(V2.X, V2.Y, 0.0)
|
||||
pC = FreeCAD.Vector(midPnt.x, midPnt.y, 0.0)
|
||||
cCF3P = circleCentFrom3Points(pA, pB, pC)
|
||||
if not cCF3P:
|
||||
|
||||
midPnt.z = 0.0
|
||||
circleCenter = circumCircleFrom3Points(p1, p2, midPnt)
|
||||
if not circleCenter:
|
||||
return False
|
||||
self.arcMidPnt = FreeCAD.Vector(midPnt.x, midPnt.y, 0.0)
|
||||
self.arcCenter = cCF3P
|
||||
self.arcRadius = p1.sub(cCF3P).Length
|
||||
self.arcMidPnt = midPnt
|
||||
self.arcCenter = circleCenter
|
||||
self.arcRadius = p1.sub(circleCenter).Length
|
||||
|
||||
if oversizedTool(self.arcRadius * 2.0):
|
||||
return False
|
||||
|
||||
return (p1, p2)
|
||||
else :
|
||||
msg = translate('PathSlot','Failed, slot from edge only accepts lines, arcs and circles.')
|
||||
FreeCAD.Console.PrintError(msg + '\n')
|
||||
|
||||
return False # not line , not circle
|
||||
|
||||
# Methods for processing double geometry
|
||||
def _processDouble(self, obj, shape_1, sub1, shape_2, sub2):
|
||||
@@ -1064,8 +1057,6 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
|
||||
# Support methods
|
||||
def _dXdYdZ(self, E):
|
||||
"""_dXdYdZ(E) Calculates delta-X, delta-Y, and delta-Z between two vertexes
|
||||
of edge passed in. Returns these three values as vector."""
|
||||
v1 = E.Vertexes[0]
|
||||
v2 = E.Vertexes[1]
|
||||
dX = v2.X - v1.X
|
||||
@@ -1076,7 +1067,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
def _normalizeVector(self, v):
|
||||
"""_normalizeVector(v)...
|
||||
Returns a copy of the vector received with values rounded to 10 decimal places."""
|
||||
posTol = 0.0000000001
|
||||
posTol = 0.0000000001 # abitrary, use job Geometry Tolerance ???
|
||||
negTol = -1 * posTol
|
||||
V = FreeCAD.Vector(v.x, v.y, v.z)
|
||||
V.normalize()
|
||||
@@ -1219,64 +1210,65 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
|
||||
def _extendArcSlot(self, p1, p2, cent, begExt, endExt):
|
||||
"""_extendArcSlot(p1, p2, cent, begExt, endExt)...
|
||||
This function extends an arc defined by two end points, p1 and p2, and the center.
|
||||
This function extends an arc defined by two end points, p1 and p2, and the center.
|
||||
The arc is extended along the circumference with begExt and endExt values.
|
||||
The function returns the new end points as tuple (n1, n2) to replace p1 and p2."""
|
||||
cancel = True
|
||||
if not begExt and not endExt :
|
||||
return (p1, p2)
|
||||
|
||||
n1 = p1
|
||||
n2 = p2
|
||||
|
||||
def getArcLine(length, rads):
|
||||
rads = abs(length / self.newRadius)
|
||||
# Create a chord of the right length, on XY plane, starting on x axis
|
||||
def makeChord(rads):
|
||||
x = self.newRadius * math.cos(rads)
|
||||
y = self.newRadius * math.sin(rads)
|
||||
a = FreeCAD.Vector(self.newRadius, 0.0, 0.0)
|
||||
b = FreeCAD.Vector(x, y, 0.0)
|
||||
return Part.makeLine(a, b)
|
||||
|
||||
if begExt or endExt:
|
||||
cancel = False
|
||||
if cancel:
|
||||
return (p1, p2)
|
||||
|
||||
# Convert extension to radians
|
||||
# Convert extension to radians; make a generic chord ( line ) on XY plane from the x axis
|
||||
# rotate and shift into place so it has same vertices as the required arc extention
|
||||
# adjust rotation angle to provide +ve or -ve extention as needed
|
||||
origin = FreeCAD.Vector(0.0, 0.0, 0.0)
|
||||
if begExt:
|
||||
# Create arc representing extension
|
||||
rads = abs(begExt / self.newRadius)
|
||||
line = getArcLine(begExt, rads)
|
||||
ExtRadians = abs(begExt / self.newRadius)
|
||||
chord = makeChord(ExtRadians)
|
||||
|
||||
rotToRads = self._xyToRadians(p1.sub(self.arcCenter))
|
||||
if begExt < 1:
|
||||
rotToRads -= rads
|
||||
rotToDeg = math.degrees(rotToRads)
|
||||
# PathLog.debug('begExt angles are: {}, {}'.format(rotToRads, rotToDeg))
|
||||
beginRadians = self._getVectorAngle(p1.sub(self.arcCenter))
|
||||
if begExt < 0:
|
||||
beginRadians += 0 # negative Ext shortens slot so chord endpoint is slot start point
|
||||
else :
|
||||
beginRadians -= 2*ExtRadians # positive Ext lengthens slot so decrease start point angle
|
||||
|
||||
# PathLog.debug('begExt angles are: {}, {}'.format(beginRadians, math.degrees(beginRadians)))
|
||||
|
||||
line.rotate(origin, FreeCAD.Vector(0, 0, 1), rotToDeg)
|
||||
line.translate(self.arcCenter)
|
||||
self._addDebugObject(line, 'ExtendStart')
|
||||
v1 = line.Vertexes[1]
|
||||
if begExt < 1:
|
||||
v1 = line.Vertexes[0]
|
||||
chord.rotate(origin, FreeCAD.Vector(0, 0, 1), math.degrees(beginRadians))
|
||||
chord.translate(self.arcCenter)
|
||||
self._addDebugObject(chord, 'ExtendStart')
|
||||
|
||||
v1 = chord.Vertexes[1]
|
||||
n1 = FreeCAD.Vector(v1.X, v1.Y, 0.0)
|
||||
|
||||
|
||||
if endExt:
|
||||
# Create arc representing extension
|
||||
rads = abs(endExt / self.newRadius)
|
||||
line = getArcLine(endExt, rads)
|
||||
ExtRadians = abs(endExt / self.newRadius)
|
||||
chord = makeChord(ExtRadians)
|
||||
|
||||
rotToRads = self._xyToRadians(p2.sub(self.arcCenter)) - rads
|
||||
if endExt < 1:
|
||||
rotToRads += rads
|
||||
rotToDeg = math.degrees(rotToRads)
|
||||
# PathLog.debug('endExt angles are: {}, {}'.format(rotToRads, rotToDeg))
|
||||
endRadians = self._getVectorAngle(p2.sub(self.arcCenter))
|
||||
if endExt > 0:
|
||||
endRadians += 0 # positive Ext lengthens slot so chord endpoint is good
|
||||
else :
|
||||
endRadians -= 2*ExtRadians # negative Ext shortens slot so decrease end point angle
|
||||
|
||||
# PathLog.debug('endExt angles are: {}, {}'.format(endRadians, math.degrees(endRadians)))
|
||||
|
||||
line.rotate(origin, FreeCAD.Vector(0, 0, 1), rotToDeg)
|
||||
line.translate(self.arcCenter)
|
||||
self._addDebugObject(line, 'ExtendEnd')
|
||||
v1 = line.Vertexes[0]
|
||||
if endExt < 1:
|
||||
v1 = line.Vertexes[1]
|
||||
chord.rotate(origin, FreeCAD.Vector(0, 0, 1), math.degrees(endRadians))
|
||||
chord.translate(self.arcCenter)
|
||||
self._addDebugObject(chord, 'ExtendEnd')
|
||||
|
||||
v1 = chord.Vertexes[1]
|
||||
n2 = FreeCAD.Vector(v1.X, v1.Y, 0.0)
|
||||
|
||||
return (n1, n2)
|
||||
@@ -1286,13 +1278,9 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
This function offsets an arc defined by endpoints, p1 and p2, and the center.
|
||||
New end points are returned at the radius passed by newRadius.
|
||||
The angle of the original arc is maintained."""
|
||||
n1 = p1.sub(center).normalize()
|
||||
n2 = p2.sub(center).normalize()
|
||||
n1.multiply(newRadius)
|
||||
n2.multiply(newRadius)
|
||||
p1 = n1.add(center)
|
||||
p2 = n2.add(center)
|
||||
return (p1, p2)
|
||||
n1 = p1.sub(center).normalize()*newRadius
|
||||
n2 = p2.sub(center).normalize()*newRadius
|
||||
return (n1.add(center), n2.add(center))
|
||||
|
||||
def _extendLineSlot(self, p1, p2, begExt, endExt):
|
||||
"""_extendLineSlot(p1, p2, begExt, endExt)...
|
||||
@@ -1300,19 +1288,15 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
The beginning is extended by begExt value and the end by endExt value."""
|
||||
if begExt:
|
||||
beg = p1.sub(p2)
|
||||
beg.normalize()
|
||||
beg.multiply(begExt)
|
||||
n1 = p1.add(beg)
|
||||
n1 = p1.add(beg.normalize()*begExt)
|
||||
else:
|
||||
n1 = p1
|
||||
if endExt:
|
||||
end = p2.sub(p1)
|
||||
end.normalize()
|
||||
end.multiply(endExt)
|
||||
n2 = p2.add(end)
|
||||
end = p2.sub(p1)
|
||||
n2 = p2.add(end.normalize()*endExt)
|
||||
else:
|
||||
n2 = p2
|
||||
return (n1, n2)
|
||||
return (n1, n2)
|
||||
|
||||
def _getOppMidPoints(self, same):
|
||||
"""_getOppMidPoints(same)...
|
||||
@@ -1325,12 +1309,13 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
|
||||
def _isParallel(self, dYdX1, dYdX2):
|
||||
"""Determine if two orientation vectors are parallel."""
|
||||
if dYdX1.add(dYdX2).Length == 0:
|
||||
return True
|
||||
if ((dYdX1.x + dYdX2.x) / 2.0 == dYdX1.x and
|
||||
(dYdX1.y + dYdX2.y) / 2.0 == dYdX1.y):
|
||||
return True
|
||||
return False
|
||||
return (dYdX1.cross(dYdX2) == FreeCAD.Vector(0,0,0) )
|
||||
# if dYdX1.add(dYdX2).Length == 0:
|
||||
# return True
|
||||
# if ((dYdX1.x + dYdX2.x) / 2.0 == dYdX1.x and
|
||||
# (dYdX1.y + dYdX2.y) / 2.0 == dYdX1.y):
|
||||
# return True
|
||||
# return False
|
||||
|
||||
def _makePerpendicular(self, p1, p2, length):
|
||||
"""_makePerpendicular(p1, p2, length)...
|
||||
@@ -1453,7 +1438,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
midLen = (L0 + L1) / 2.0
|
||||
return E.valueAt(E.getParameterByLength(midLen))
|
||||
|
||||
def _xyToRadians(self, v):
|
||||
def _getVectorAngle(self, v):
|
||||
# Assumes Z value of vector is zero
|
||||
halfPi = math.pi / 2
|
||||
|
||||
@@ -1686,7 +1671,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
# PathLog.debug('arcRadius, newRadius: {}, {}'.format(arcRadius, newRadius))
|
||||
if newRadius <= 0:
|
||||
msg = translate('PathSlot',
|
||||
'Current offset value is not possible.')
|
||||
'Current offset value produces negative radius.')
|
||||
FreeCAD.Console.PrintError(msg + '\n')
|
||||
return False
|
||||
else:
|
||||
@@ -1699,7 +1684,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
# PathLog.debug('arcRadius, newRadius: {}, {}'.format(arcRadius, newRadius))
|
||||
if newRadius <= 0:
|
||||
msg = translate('PathSlot',
|
||||
'Current offset value is not possible.')
|
||||
'Current offset value produces negative radius.')
|
||||
FreeCAD.Console.PrintError(msg + '\n')
|
||||
return False
|
||||
else:
|
||||
@@ -1736,6 +1721,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
try:
|
||||
cmn = self.base.Shape.common(pathTravel)
|
||||
if cmn.Volume > 0.000001:
|
||||
print ("volume=",cmn.Volume)
|
||||
return True
|
||||
except Exception:
|
||||
PathLog.debug('Failed to complete path collision check.')
|
||||
|
||||
Reference in New Issue
Block a user