Moving tag processing into Tag itself.
This commit is contained in:
parent
fc55d7ae23
commit
a9f246b466
|
@ -1,95 +1,95 @@
|
|||
<RCC>
|
||||
<qresource>
|
||||
<file>icons/preferences-path.svg</file>
|
||||
<file>icons/Path-Toolpath.svg</file>
|
||||
<file>icons/Path-Compound.svg</file>
|
||||
<file>icons/Path-Shape.svg</file>
|
||||
<file>icons/Path-Profile.svg</file>
|
||||
<file>icons/Path-Contour.svg</file>
|
||||
<file>icons/Path-Pocket.svg</file>
|
||||
<file>icons/Path-Drilling.svg</file>
|
||||
<file>icons/Path-Job.svg</file>
|
||||
<file>icons/Path-Dressup.svg</file>
|
||||
<file>icons/Path-Hop.svg</file>
|
||||
<file>icons/Path-Datums.svg</file>
|
||||
<file>icons/Path-Copy.svg</file>
|
||||
<file>icons/Path-ToolTable.svg</file>
|
||||
<file>icons/Path-LengthOffset.svg</file>
|
||||
<file>icons/Path-Axis.svg</file>
|
||||
<file>icons/Path-Stock.svg</file>
|
||||
<file>icons/Path-Plane.svg</file>
|
||||
<file>icons/Path-Post.svg</file>
|
||||
<file>icons/Path-LoadTool.svg</file>
|
||||
<file>icons/Path-Comment.svg</file>
|
||||
<file>icons/Path-Stop.svg</file>
|
||||
<file>icons/Path-Machine.svg</file>
|
||||
<file>icons/Path-Kurve.svg</file>
|
||||
<file>icons/Path-FaceProfile.svg</file>
|
||||
<file>icons/Path-FacePocket.svg</file>
|
||||
<file>icons/Path-Array.svg</file>
|
||||
<file>icons/Path-Custom.svg</file>
|
||||
<file>icons/Path-Inspect.svg</file>
|
||||
<file>icons/Path-ToolChange.svg</file>
|
||||
<file>icons/Path-SimpleCopy.svg</file>
|
||||
<file>icons/Path-Engrave.svg</file>
|
||||
<file>icons/Path-Sanity.svg</file>
|
||||
<file>icons/Path-3DSurface.svg</file>
|
||||
<file>icons/Path-Speed.svg</file>
|
||||
<file>icons/Path-Array.svg</file>
|
||||
<file>icons/Path-Axis.svg</file>
|
||||
<file>icons/Path-BaseGeometry.svg</file>
|
||||
<file>icons/Path-Comment.svg</file>
|
||||
<file>icons/Path-Compound.svg</file>
|
||||
<file>icons/Path-Contour.svg</file>
|
||||
<file>icons/Path-Copy.svg</file>
|
||||
<file>icons/Path-Custom.svg</file>
|
||||
<file>icons/Path-Datums.svg</file>
|
||||
<file>icons/Path-Depths.svg</file>
|
||||
<file>icons/Path-Dressup.svg</file>
|
||||
<file>icons/Path-Drilling.svg</file>
|
||||
<file>icons/Path-Engrave.svg</file>
|
||||
<file>icons/Path-FacePocket.svg</file>
|
||||
<file>icons/Path-FaceProfile.svg</file>
|
||||
<file>icons/Path-Face.svg</file>
|
||||
<file>icons/Path-Heights.svg</file>
|
||||
<file>icons/Path-Hop.svg</file>
|
||||
<file>icons/Path-Inspect.svg</file>
|
||||
<file>icons/Path-Job.svg</file>
|
||||
<file>icons/Path-Kurve.svg</file>
|
||||
<file>icons/Path-LengthOffset.svg</file>
|
||||
<file>icons/Path-LoadTool.svg</file>
|
||||
<file>icons/Path-MachineLathe.svg</file>
|
||||
<file>icons/Path-MachineMill.svg</file>
|
||||
<file>icons/Path-Machine.svg</file>
|
||||
<file>icons/Path-OperationA.svg</file>
|
||||
<file>icons/Path-OperationB.svg</file>
|
||||
<file>icons/Path-Plane.svg</file>
|
||||
<file>icons/Path-Pocket.svg</file>
|
||||
<file>icons/Path-Post.svg</file>
|
||||
<file>icons/Path-Profile-Edges.svg</file>
|
||||
<file>icons/Path-Profile-Face.svg</file>
|
||||
<file>icons/Path-Profile.svg</file>
|
||||
<file>icons/Path-Sanity.svg</file>
|
||||
<file>icons/Path-SelectLoop.svg</file>
|
||||
<file>icons/Path-Face.svg</file>
|
||||
<file>translations/Path_de.qm</file>
|
||||
<file>icons/Path-Shape.svg</file>
|
||||
<file>icons/Path-SimpleCopy.svg</file>
|
||||
<file>icons/Path-Speed.svg</file>
|
||||
<file>icons/Path-Stock.svg</file>
|
||||
<file>icons/Path-Stop.svg</file>
|
||||
<file>icons/Path-ToolChange.svg</file>
|
||||
<file>icons/Path-Toolpath.svg</file>
|
||||
<file>icons/Path-ToolTable.svg</file>
|
||||
<file>icons/preferences-path.svg</file>
|
||||
<file>panels/ContourEdit.ui</file>
|
||||
<file>panels/DlgJobChooser.ui</file>
|
||||
<file>panels/DlgSelectPostProcessor.ui</file>
|
||||
<file>panels/DlgToolCopy.ui</file>
|
||||
<file>panels/DogboneEdit.ui</file>
|
||||
<file>panels/DrillingEdit.ui</file>
|
||||
<file>panels/EngraveEdit.ui</file>
|
||||
<file>panels/HoldingTagsEdit.ui</file>
|
||||
<file>panels/JobEdit.ui</file>
|
||||
<file>panels/MillFaceEdit.ui</file>
|
||||
<file>panels/PocketEdit.ui</file>
|
||||
<file>panels/ProfileEdgesEdit.ui</file>
|
||||
<file>panels/ProfileEdit.ui</file>
|
||||
<file>panels/RemoteEdit.ui</file>
|
||||
<file>panels/SurfaceEdit.ui</file>
|
||||
<file>panels/ToolControl.ui</file>
|
||||
<file>panels/ToolEdit.ui</file>
|
||||
<file>panels/ToolLibraryEditor.ui</file>
|
||||
<file>preferences/PathJob.ui</file>
|
||||
<file>translations/Path_af.qm</file>
|
||||
<file>translations/Path_zh-CN.qm</file>
|
||||
<file>translations/Path_zh-TW.qm</file>
|
||||
<file>translations/Path_hr.qm</file>
|
||||
<file>translations/Path_cs.qm</file>
|
||||
<file>translations/Path_nl.qm</file>
|
||||
<file>translations/Path_de.qm</file>
|
||||
<file>translations/Path_el.qm</file>
|
||||
<file>translations/Path_es-ES.qm</file>
|
||||
<file>translations/Path_fi.qm</file>
|
||||
<file>translations/Path_fr.qm</file>
|
||||
<file>translations/Path_hr.qm</file>
|
||||
<file>translations/Path_hu.qm</file>
|
||||
<file>translations/Path_it.qm</file>
|
||||
<file>translations/Path_ja.qm</file>
|
||||
<file>translations/Path_nl.qm</file>
|
||||
<file>translations/Path_no.qm</file>
|
||||
<file>translations/Path_pl.qm</file>
|
||||
<file>translations/Path_pt-BR.qm</file>
|
||||
<file>translations/Path_pt-PT.qm</file>
|
||||
<file>translations/Path_ro.qm</file>
|
||||
<file>translations/Path_ru.qm</file>
|
||||
<file>translations/Path_sr.qm</file>
|
||||
<file>translations/Path_es-ES.qm</file>
|
||||
<file>translations/Path_sv-SE.qm</file>
|
||||
<file>translations/Path_uk.qm</file>
|
||||
<file>translations/Path_it.qm</file>
|
||||
<file>translations/Path_pt-BR.qm</file>
|
||||
<file>translations/Path_el.qm</file>
|
||||
<file>translations/Path_sk.qm</file>
|
||||
<file>translations/Path_tr.qm</file>
|
||||
<file>translations/Path_sl.qm</file>
|
||||
<file>panels/EngraveEdit.ui</file>
|
||||
<file>panels/DrillingEdit.ui</file>
|
||||
<file>panels/PocketEdit.ui</file>
|
||||
<file>panels/ProfileEdit.ui</file>
|
||||
<file>panels/SurfaceEdit.ui</file>
|
||||
<file>panels/RemoteEdit.ui</file>
|
||||
<file>panels/ToolControl.ui</file>
|
||||
<file>panels/ToolLibraryEditor.ui</file>
|
||||
<file>panels/JobEdit.ui</file>
|
||||
<file>panels/DlgToolCopy.ui</file>
|
||||
<file>panels/ToolEdit.ui</file>
|
||||
<file>panels/DlgJobChooser.ui</file>
|
||||
<file>panels/ContourEdit.ui</file>
|
||||
<file>panels/MillFaceEdit.ui</file>
|
||||
<file>panels/ProfileEdgesEdit.ui</file>
|
||||
<file>panels/DogboneEdit.ui</file>
|
||||
<file>panels/DlgSelectPostProcessor.ui</file>
|
||||
<file>preferences/PathJob.ui</file>
|
||||
<file>panels/HoldingTagsEdit.ui</file>
|
||||
<file>translations/Path_sr.qm</file>
|
||||
<file>translations/Path_sv-SE.qm</file>
|
||||
<file>translations/Path_tr.qm</file>
|
||||
<file>translations/Path_uk.qm</file>
|
||||
<file>translations/Path_zh-CN.qm</file>
|
||||
<file>translations/Path_zh-TW.qm</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -25,8 +25,7 @@ class PathWorkbench (Workbench):
|
|||
"Path workbench"
|
||||
|
||||
def __init__(self):
|
||||
self.__class__.Icon = FreeCAD.getResourceDir(
|
||||
) + "Mod/Path/Resources/icons/PathWorkbench.svg"
|
||||
self.__class__.Icon = FreeCAD.getResourceDir() + "Mod/Path/Resources/icons/PathWorkbench.svg"
|
||||
self.__class__.MenuText = "Path"
|
||||
self.__class__.ToolTip = "Path workbench"
|
||||
|
||||
|
@ -120,11 +119,6 @@ class PathWorkbench (Workbench):
|
|||
# "Path", "Remote Operations")], remotecmdlist)
|
||||
self.appendMenu([translate("Path", "&Path")], extracmdlist)
|
||||
|
||||
# Add preferences pages
|
||||
import os
|
||||
FreeCADGui.addPreferencePage(FreeCAD.getHomePath(
|
||||
) + os.sep + "Mod" + os.sep + "Path" + os.sep + "PathScripts" + os.sep + "DlgSettingsPath.ui", "Path")
|
||||
|
||||
Log('Loading Path workbench... done\n')
|
||||
|
||||
def GetClassName(self):
|
||||
|
@ -142,7 +136,7 @@ class PathWorkbench (Workbench):
|
|||
if len(FreeCADGui.Selection.getSelection()) == 1:
|
||||
if FreeCADGui.Selection.getSelection()[0].isDerivedFrom("Path::Feature"):
|
||||
self.appendContextMenu("", ["Path_Inspect"])
|
||||
if "Profile" in FreeCADGui.Selection.getSelection()[0].Name:
|
||||
if "Profile" or "Contour" in FreeCADGui.Selection.getSelection()[0].Name:
|
||||
self.appendContextMenu("", ["Add_Tag"])
|
||||
self.appendContextMenu("", ["Set_StartPoint"])
|
||||
self.appendContextMenu("", ["Set_EndPoint"])
|
||||
|
|
|
@ -67,6 +67,29 @@ def getAngle(v):
|
|||
return -a
|
||||
return a
|
||||
|
||||
class Side:
|
||||
Left = +1
|
||||
Right = -1
|
||||
Straight = 0
|
||||
On = 0
|
||||
|
||||
@classmethod
|
||||
def toString(cls, side):
|
||||
if side == cls.Left:
|
||||
return 'Left'
|
||||
if side == cls.Right:
|
||||
return 'Right'
|
||||
return 'On'
|
||||
|
||||
@classmethod
|
||||
def of(cls, ptRef, pt):
|
||||
d = -ptRef.x*pt.y + ptRef.y*pt.x
|
||||
if d < 0:
|
||||
return cls.Left
|
||||
if d > 0:
|
||||
return cls.Right
|
||||
return cls.Straight
|
||||
|
||||
def testPrintAngle(v):
|
||||
print("(%+.2f, %+.2f, %+.2f): %+.2f" % (v.x, v.y, v.z, getAngle(v)/math.pi))
|
||||
|
||||
|
@ -81,18 +104,73 @@ def testAngle(x=1, y=1):
|
|||
testPrintAngle(FreeCAD.Vector( 1*x,-1*y, 0))
|
||||
|
||||
|
||||
def testPrintSide(pt1, pt2):
|
||||
print('(%.2f, %.2f) - (%.2f, %.2f) -> %s' % (pt1.x, pt1.y, pt2.x, pt2.y, Side.toString(Side.of(pt1, pt2))))
|
||||
|
||||
def testSide():
|
||||
testPrintSide(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector( 1, 0, 0))
|
||||
testPrintSide(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector(-1, 0, 0))
|
||||
testPrintSide(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector( 0, 1, 0))
|
||||
testPrintSide(FreeCAD.Vector( 1, 0, 0), FreeCAD.Vector( 0,-1, 0))
|
||||
|
||||
def pathCommandForEdge(edge):
|
||||
pt = edge.valueAt(edge.LastParameter)
|
||||
params = {'X': pt.x, 'Y': pt.y, 'Z': pt.z}
|
||||
if type(edge.Curve) == Part.Line:
|
||||
return Part.Command('G1', params)
|
||||
|
||||
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'
|
||||
offset = pt1 - edge.Curve.Center
|
||||
params.update({'I': offset.x, 'J': offset.y, 'K': offset.z})
|
||||
return Part.Command(cmd, params)
|
||||
|
||||
|
||||
class Tag:
|
||||
def __init__(self, x, y, width, height, angle, enabled):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.angle = angle
|
||||
self.width = math.fabs(width)
|
||||
self.height = math.fabs(height)
|
||||
self.angle = math.fabs(angle)
|
||||
self.enabled = enabled
|
||||
|
||||
def toString(self):
|
||||
return str((self.x, self.y, self.width, self.height, self.angle, self.enabled))
|
||||
|
||||
def originAt(self, z):
|
||||
return FreeCAD.Vector(self.x, self.y, z)
|
||||
|
||||
def createSolidsAt(self, z):
|
||||
r1 = self.width / 2
|
||||
height = self.height
|
||||
if self.angle == 90 and height > 0:
|
||||
self.solid = Part.makeCylinder(r1, height)
|
||||
self.core = self.solid
|
||||
elif self.angle > 0.0 and height > 0.0:
|
||||
tangens = math.tan(math.radians(self.angle))
|
||||
dr = height / tangens
|
||||
if dr < r1:
|
||||
r2 = r1 - dr
|
||||
self.core = Part.makeCylinder(r2, height)
|
||||
else:
|
||||
r2 = 0
|
||||
height = r1 * tangens
|
||||
self.core = None
|
||||
self.solid = Part.makeCone(r1, r2, height)
|
||||
else:
|
||||
# degenerated case - no tag
|
||||
self.solid = Part.makeSphere(r1 / 10000)
|
||||
self.core = None
|
||||
self.solid.translate(self.originAt(z))
|
||||
if self.core:
|
||||
self.core.translate(self.originAt(z))
|
||||
|
||||
@classmethod
|
||||
def FromString(cls, string):
|
||||
try:
|
||||
|
@ -150,11 +228,25 @@ class PathData:
|
|||
bottom = [e for e in edges if e.Vertexes[0].Point.z == minZ and e.Vertexes[1].Point.z == minZ]
|
||||
wire = Part.Wire(bottom)
|
||||
if wire.isClosed():
|
||||
return wire
|
||||
return Part.Wire(self.sortedBase(bottom))
|
||||
# if we get here there are already holding tags, or we're not looking at a profile
|
||||
# let's try and insert the missing pieces - another day
|
||||
raise ValueError("Selected path doesn't seem to be a Profile operation.")
|
||||
|
||||
def sortedBase(self, base):
|
||||
# first find the exit point, where base wire is closed
|
||||
edges = [e for e in self.edges if e.valueAt(e.FirstParameter).z == self.minZ and e.valueAt(e.LastParameter).z != self.maxZ]
|
||||
exit = sorted(edges, key=lambda e: -e.valueAt(e.LastParameter).z)[0]
|
||||
pt = exit.valueAt(exit.FirstParameter)
|
||||
# then find the first base edge, and sort them until done
|
||||
ordered = []
|
||||
while base:
|
||||
edge = [e for e in base if e.valueAt(e.FirstParameter) == pt][0]
|
||||
ordered.append(edge)
|
||||
base.remove(edge)
|
||||
pt = edge.valueAt(edge.LastParameter)
|
||||
return ordered
|
||||
|
||||
|
||||
def findZLimits(self, edges):
|
||||
# not considering arcs and spheres in Z direction, find the highes and lowest Z values
|
||||
|
@ -268,6 +360,18 @@ class PathData:
|
|||
def pathLength(self):
|
||||
return self.base.Length
|
||||
|
||||
def sortedTags(self, tags):
|
||||
ordered = []
|
||||
for edge in self.base.Edges:
|
||||
ts = [t for t in tags if DraftGeomUtils.isPtOnEdge(t.originAt(self.minZ), edge)]
|
||||
for t in sorted(ts, key=lambda t: (t.originAt(self.minZ) - edge.valueAt(edge.FirstParameter)).Length):
|
||||
tags.remove(t)
|
||||
ordered.append(t)
|
||||
if tags:
|
||||
raise ValueError("There's something really wrong here")
|
||||
return ordered
|
||||
|
||||
|
||||
class ObjectDressup:
|
||||
|
||||
def __init__(self, obj):
|
||||
|
@ -286,6 +390,46 @@ class ObjectDressup:
|
|||
def generateTags(self, obj, count=None, width=None, height=None, angle=90, spacing=None):
|
||||
return self.pathData.generateTags(obj, count, width, height, angle, spacing)
|
||||
|
||||
|
||||
def tagIntersection(self, face, edge):
|
||||
p1 = edge.valueAt(edge.FirstParameter)
|
||||
pts = edge.Curve.intersect(face.Surface)
|
||||
if pts[0]:
|
||||
closest = sorted(pts[0], key=lambda pt: (pt - p1).Length)[0]
|
||||
return closest
|
||||
return None
|
||||
|
||||
def createPath(self, edges, tagSolids):
|
||||
commands = []
|
||||
i = 0
|
||||
while i != len(edges):
|
||||
edge = edges[i]
|
||||
while edge:
|
||||
for solid in tagSolids:
|
||||
for face in solid.Faces:
|
||||
pt = self.tagIntersection(face, edge)
|
||||
if pt:
|
||||
if pt == edge.valueAt(edge.FirstParameter):
|
||||
pt
|
||||
elif pt != edge.valueAt(edge.LastParameter):
|
||||
parameter = edge.Curve.parameter(pt)
|
||||
wire = edge.split(parameter)
|
||||
commands.append(pathCommandForEdge(wire.Edges[0]))
|
||||
edge = wire.Edges[1]
|
||||
break;
|
||||
else:
|
||||
commands.append(pathCommandForEdge(edge))
|
||||
edge = None
|
||||
i += 1
|
||||
break
|
||||
if not edge:
|
||||
break
|
||||
if edge:
|
||||
commands.append(pathCommandForEdge(edge))
|
||||
edge = None
|
||||
return self.obj.Path
|
||||
|
||||
|
||||
def execute(self, obj):
|
||||
if not obj.Base:
|
||||
return
|
||||
|
@ -323,9 +467,16 @@ class ObjectDressup:
|
|||
if tag.enabled:
|
||||
#print("x=%s, y=%s, z=%s" % (tag.x, tag.y, pathData.minZ))
|
||||
debugMarker(FreeCAD.Vector(tag.x, tag.y, pathData.minZ), "tag-%02d" % tagID , (1.0, 0.0, 1.0), 0.5)
|
||||
|
||||
tags = pathData.sortedTags(tags)
|
||||
for tag in tags:
|
||||
tag.createSolidsAt(pathData.minZ)
|
||||
|
||||
self.fingerprint = [tag.toString() for tag in tags]
|
||||
self.tags = tags
|
||||
obj.Path = obj.Base.Path
|
||||
|
||||
#obj.Path = self.createPath(pathData.edges, tags)
|
||||
obj.Path = self.Base.Path
|
||||
|
||||
def setTags(self, obj, tags):
|
||||
obj.Tags = [tag.toString() for tag in tags]
|
||||
|
|
Loading…
Reference in New Issue
Block a user