Path: additional functionality for arch panels
This commit is contained in:
committed by
Yorik van Havre
parent
8699d14057
commit
ffc4fb28aa
@@ -21,7 +21,7 @@
|
||||
#* *
|
||||
#***************************************************************************
|
||||
|
||||
import FreeCAD,Draft,ArchComponent,DraftVecUtils,ArchCommands,math
|
||||
import FreeCAD,Draft,ArchComponent,DraftVecUtils,ArchCommands,math, Part
|
||||
from FreeCAD import Vector
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
@@ -374,7 +374,7 @@ class _Panel(ArchComponent.Component):
|
||||
if self.clone(obj):
|
||||
return
|
||||
|
||||
import Part, DraftGeomUtils
|
||||
import Part #, DraftGeomUtils
|
||||
|
||||
# base tests
|
||||
if obj.Base:
|
||||
@@ -415,7 +415,7 @@ class _Panel(ArchComponent.Component):
|
||||
if obj.Base:
|
||||
base = obj.Base.Shape.copy()
|
||||
if not base.Solids:
|
||||
p = FreeCAD.Placement(obj.Base.Placement)
|
||||
# p = FreeCAD.Placement(obj.Base.Placement)
|
||||
if base.Faces:
|
||||
baseprofile = base
|
||||
if not normal:
|
||||
@@ -515,7 +515,7 @@ class _Panel(ArchComponent.Component):
|
||||
base = self.vol.common(base)
|
||||
base = base.removeSplitter()
|
||||
if not base:
|
||||
FreeCAD.Console.PrintError(transpate("Arch","Error computing shape of ")+obj.Label+"\n")
|
||||
FreeCAD.Console.PrintError(translate("Arch","Error computing shape of ")+obj.Label+"\n")
|
||||
return False
|
||||
|
||||
if base and (obj.Sheets > 1) and normal and thickness:
|
||||
@@ -558,7 +558,7 @@ class _ViewProviderPanel(ArchComponent.ViewProviderComponent):
|
||||
vobj.ShapeColor = ArchCommands.getDefaultColor("Panel")
|
||||
|
||||
def getIcon(self):
|
||||
import Arch_rc
|
||||
#import Arch_rc
|
||||
if hasattr(self,"Object"):
|
||||
if hasattr(self.Object,"CloneOf"):
|
||||
if self.Object.CloneOf:
|
||||
@@ -723,13 +723,12 @@ class PanelCut(Draft._DraftObject):
|
||||
obj.Shape = base
|
||||
obj.Placement = pl
|
||||
|
||||
def getWires(self,obj):
|
||||
|
||||
def getWires(self, obj):
|
||||
|
||||
"""getWires(obj): returns a tuple containing 3 shapes
|
||||
that define the panel outline, the panel holes, and
|
||||
tags (engravings): (outline,holes,tags). Any of these can
|
||||
be None if nonexistent"""
|
||||
|
||||
tag = None
|
||||
outl = None
|
||||
inl = None
|
||||
@@ -742,6 +741,8 @@ class PanelCut(Draft._DraftObject):
|
||||
tag = self.tag.copy()
|
||||
if tag:
|
||||
tag.Placement = obj.Placement.multiply(tag.Placement)
|
||||
|
||||
outl = self.outline.copy()
|
||||
outl.Placement = obj.Placement.multiply(outl.Placement)
|
||||
if len(outl.Wires) > 1:
|
||||
# separate outline
|
||||
@@ -753,11 +754,11 @@ class PanelCut(Draft._DraftObject):
|
||||
ow = w
|
||||
if ow:
|
||||
inl = Part.Compound([w for w in outl.Wires if w.hashCode() != ow.hashCode()])
|
||||
outl = ow
|
||||
outl = Part.Compound([ow])
|
||||
else:
|
||||
inl = None
|
||||
outl = outl.Wires[0]
|
||||
return (outl,inl,tags)
|
||||
outl = Part.Compound([outl.Wires[0]])
|
||||
return (outl, inl, tag)
|
||||
|
||||
class ViewProviderPanelCut(Draft._ViewProviderDraft):
|
||||
"a view provider for the panel cut object"
|
||||
@@ -889,10 +890,10 @@ class PanelSheet(Draft._DraftObject):
|
||||
obj.FillRatio = int((subarea/area)*100)
|
||||
|
||||
def getOutlines(self,obj,transform=False):
|
||||
"""getOutlines(obj,transform=False): returns a list of wires that define the
|
||||
"""getOutlines(obj,transform=False): returns a list of compounds whose wires define the
|
||||
outlines of the panels in this sheet. If transform is True, the placement of
|
||||
the sheet will be added to each wire"""
|
||||
|
||||
|
||||
outp = []
|
||||
for p in obj.Group:
|
||||
ispanel = False
|
||||
@@ -914,10 +915,10 @@ class PanelSheet(Draft._DraftObject):
|
||||
return outp
|
||||
|
||||
def getHoles(self,obj,transform=False):
|
||||
"""getHoles(obj,transform=False): returns a list of wires that define the
|
||||
"""getHoles(obj,transform=False): returns a list of compound whose wires define the
|
||||
holes contained in the panels in this sheet. If transform is True, the placement of
|
||||
the sheet will be added to each wire"""
|
||||
|
||||
|
||||
outp = []
|
||||
for p in obj.Group:
|
||||
if hasattr(p,"Proxy"):
|
||||
@@ -931,21 +932,25 @@ class PanelSheet(Draft._DraftObject):
|
||||
return outp
|
||||
|
||||
def getTags(self,obj,transform=False):
|
||||
"""getTags(obj,transform=False): returns a list of wires that define the
|
||||
tags (engravings) contained in the panels in this sheet. If transform is
|
||||
True, the placement of the sheet will be added to each wire. Warning, the
|
||||
wires returned by this function may not be closed, depending on the font"""
|
||||
|
||||
"""getTags(obj,transform=False): returns a list of compounds whose wires define the
|
||||
tags (engravings) contained in the panels in this sheet and the sheet intself.
|
||||
If transform is True, the placement of the sheet will be added to each wire.
|
||||
Warning, the wires returned by this function may not be closed,
|
||||
depending on the font"""
|
||||
|
||||
outp = []
|
||||
for p in obj.Group:
|
||||
if hasattr(p,"Proxy"):
|
||||
if hasattr(p.Proxy,"getWires"):
|
||||
w = p.Proxy.getWires(p)
|
||||
if w[1]:
|
||||
w = w[1]
|
||||
if w[2]:
|
||||
w = w[2]
|
||||
if transform:
|
||||
w.Placement = obj.Placement.multiply(w.Placement)
|
||||
outp.append(w)
|
||||
if self.sheettag is not None:
|
||||
outp.append(self.sheettag)
|
||||
|
||||
return outp
|
||||
|
||||
|
||||
|
||||
@@ -327,53 +327,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="useEndPoint">
|
||||
<property name="text">
|
||||
<string>Use End Point</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="useStartPoint">
|
||||
<property name="text">
|
||||
<string>Use Start Point</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QCheckBox" name="useCompensation">
|
||||
<property name="text">
|
||||
<string>Use Compensation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QCheckBox" name="processHoles">
|
||||
<property name="text">
|
||||
<string>Process Holes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QCheckBox" name="processPerimeter">
|
||||
<property name="text">
|
||||
<string>Process Perimeter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_4" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
@@ -420,6 +373,54 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="2" column="2">
|
||||
<widget class="QCheckBox" name="processPerimeter">
|
||||
<property name="text">
|
||||
<string>Process Perimeter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QCheckBox" name="processHoles">
|
||||
<property name="text">
|
||||
<string>Process Holes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="useEndPoint">
|
||||
<property name="text">
|
||||
<string>Use End Point</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="useStartPoint">
|
||||
<property name="text">
|
||||
<string>Use Start Point</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QCheckBox" name="useCompensation">
|
||||
<property name="text">
|
||||
<string>Use Compensation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QCheckBox" name="processCircles">
|
||||
<property name="text">
|
||||
<string>Process Circles</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -34,7 +34,7 @@ import ArchPanel
|
||||
|
||||
LOG_MODULE = 'PathContour'
|
||||
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
|
||||
PathLog.trackModule('PathContour')
|
||||
#PathLog.trackModule('PathContour')
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
|
||||
@@ -116,7 +116,6 @@ class ObjectPathEngrave:
|
||||
baseobject = parentJob.Base
|
||||
if baseobject is None:
|
||||
return
|
||||
|
||||
try:
|
||||
if baseobject.isDerivedFrom('Sketcher::SketchObject') or \
|
||||
baseobject.isDerivedFrom('Part::Part2DObject'):
|
||||
@@ -132,31 +131,14 @@ class ObjectPathEngrave:
|
||||
output += self.buildpathocc(obj, wires)
|
||||
|
||||
elif isinstance(baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet
|
||||
baseobject.Proxy.execute(baseobject)
|
||||
ss = baseobject.Proxy.sheettag
|
||||
ss.Placement = baseobject.Placement.multiply(ss.Placement)
|
||||
|
||||
output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
|
||||
for w in ss.Wires:
|
||||
tempedges = PathUtils.cleanedges(w.Edges, 0.5)
|
||||
wires.append(Part.Wire(tempedges))
|
||||
if obj.Algorithm == "OCC Native":
|
||||
output += self.buildpathocc(obj, wires)
|
||||
|
||||
for subobj in baseobject.Group: # process the group of panels
|
||||
if isinstance(subobj.Proxy, ArchPanel.PanelCut):
|
||||
subobj.Proxy.execute(subobj)
|
||||
|
||||
if hasattr(subobj.Proxy, "tag"):
|
||||
ss = subobj.Proxy.tag
|
||||
ss.Placement = subobj.Placement.multiply(ss.Placement)
|
||||
|
||||
output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
|
||||
for w in ss.Wires:
|
||||
tempedges = PathUtils.cleanedges(w.Edges, 0.5)
|
||||
wires.append(Part.Wire(tempedges))
|
||||
if obj.Algorithm == "OCC Native":
|
||||
output += self.buildpathocc(obj, wires)
|
||||
shapes = baseobject.Proxy.getTags(baseobject)
|
||||
for shape in shapes:
|
||||
output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
|
||||
for w in shape.Wires:
|
||||
tempedges = PathUtils.cleanedges(w.Edges, 0.5)
|
||||
wires.append(Part.Wire(tempedges))
|
||||
if obj.Algorithm == "OCC Native":
|
||||
output += self.buildpathocc(obj, wires)
|
||||
else:
|
||||
raise ValueError('Unknown baseobject type for engraving')
|
||||
|
||||
|
||||
@@ -26,13 +26,15 @@ import FreeCAD
|
||||
import Path
|
||||
import numpy
|
||||
import TechDraw
|
||||
import ArchPanel
|
||||
|
||||
from FreeCAD import Vector
|
||||
from PathScripts import PathUtils
|
||||
from PathScripts.PathUtils import depth_params
|
||||
import PathScripts.PathLog as PathLog
|
||||
|
||||
LOG_MODULE = 'PathProfile'
|
||||
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, LOG_MODULE)
|
||||
# PathLog.trackModule('PathProfile')
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
@@ -99,6 +101,7 @@ class ObjectProfile:
|
||||
obj.addProperty("App::PropertyDistance", "OffsetExtra", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extra value to stay away from final profile- good for roughing toolpath"))
|
||||
obj.addProperty("App::PropertyBool", "processHoles", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Profile holes as well as the outline"))
|
||||
obj.addProperty("App::PropertyBool", "processPerimeter", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Profile the outline"))
|
||||
obj.addProperty("App::PropertyBool", "processCircles", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Profile round holes"))
|
||||
|
||||
obj.Proxy = self
|
||||
|
||||
@@ -109,8 +112,7 @@ class ObjectProfile:
|
||||
return None
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
if prop == "UserLabel":
|
||||
obj.Label = obj.UserLabel + " :" + obj.ToolDescription
|
||||
pass
|
||||
|
||||
def addprofilebase(self, obj, ss, sub=""):
|
||||
baselist = obj.Base
|
||||
@@ -271,6 +273,40 @@ print "y - " + str(point.y)
|
||||
edgelist = Part.__sortEdges__(edgelist)
|
||||
output += self._buildPathLibarea(obj, edgelist, False)
|
||||
|
||||
else: #Try to build targets frorm the job base
|
||||
parentJob = PathUtils.findParentJob(obj)
|
||||
if parentJob is None:
|
||||
return
|
||||
baseobject = parentJob.Base
|
||||
if baseobject is None:
|
||||
return
|
||||
|
||||
if hasattr(baseobject, "Proxy"):
|
||||
if isinstance(baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet
|
||||
if obj.processPerimeter:
|
||||
shapes = baseobject.Proxy.getOutlines(baseobject, transform=False)
|
||||
for shape in shapes:
|
||||
for wire in shape.Wires:
|
||||
edgelist = wire.Edges
|
||||
edgelist = Part.__sortEdges__(edgelist)
|
||||
PathLog.debug("Processing panel perimeter. edges found: {}".format(len(edgelist)))
|
||||
try:
|
||||
output += self._buildPathLibarea(obj, edgelist, isHole=False)
|
||||
except:
|
||||
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
|
||||
|
||||
shapes = baseobject.Proxy.getHoles(baseobject, transform=False)
|
||||
for shape in shapes:
|
||||
for wire in shape.Wires:
|
||||
drillable = PathUtils.isDrillable(baseobject.Proxy, wire)
|
||||
if (drillable and obj.processCircles) or (not drillable and obj.processHoles):
|
||||
edgelist = wire.Edges
|
||||
edgelist = Part.__sortEdges__(edgelist)
|
||||
try:
|
||||
output += self._buildPathLibarea(obj, edgelist, isHole=True)
|
||||
except:
|
||||
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
|
||||
|
||||
if obj.Active:
|
||||
path = Path.Path(output)
|
||||
obj.Path = path
|
||||
@@ -442,6 +478,8 @@ class TaskPanel:
|
||||
self.obj.processHoles = self.form.processHoles.isChecked()
|
||||
if hasattr(self.obj, "processPerimeter"):
|
||||
self.obj.processPerimeter = self.form.processPerimeter.isChecked()
|
||||
if hasattr(self.obj, "processCircles"):
|
||||
self.obj.processCircles = self.form.processCircles.isChecked()
|
||||
if hasattr(self.obj, "ToolController"):
|
||||
PathLog.debug("name: {}".format(self.form.uiToolController.currentText()))
|
||||
tc = PathUtils.findToolController(self.obj, self.form.uiToolController.currentText())
|
||||
@@ -462,6 +500,7 @@ class TaskPanel:
|
||||
self.form.useEndPoint.setChecked(self.obj.UseEndPoint)
|
||||
self.form.processHoles.setChecked(self.obj.processHoles)
|
||||
self.form.processPerimeter.setChecked(self.obj.processPerimeter)
|
||||
self.form.processCircles.setChecked(self.obj.processCircles)
|
||||
|
||||
index = self.form.cutSide.findText(
|
||||
self.obj.Side, QtCore.Qt.MatchFixedString)
|
||||
@@ -602,6 +641,7 @@ class TaskPanel:
|
||||
self.form.rollRadius.editingFinished.connect(self.getFields)
|
||||
self.form.processHoles.clicked.connect(self.getFields)
|
||||
self.form.processPerimeter.clicked.connect(self.getFields)
|
||||
self.form.processCircles.clicked.connect(self.getFields)
|
||||
|
||||
self.setFields()
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@ def isDrillable(obj, candidate):
|
||||
if (round(face.ParameterRange[0], 8) == 0.0) and (round(face.ParameterRange[1], 8) == round(math.pi * 2, 8)):
|
||||
for edge in face.Edges: # Find seam edge and check if aligned to Z axis.
|
||||
if (isinstance(edge.Curve, Part.Line)):
|
||||
PathLog.debug("candidate is a circle")
|
||||
v0 = edge.Vertexes[0].Point
|
||||
v1 = edge.Vertexes[1].Point
|
||||
if (v1.sub(v0).x == 0) and (v1.sub(v0).y == 0):
|
||||
@@ -103,16 +104,19 @@ def isDrillable(obj, candidate):
|
||||
if obj.isInside(lsp, 0, False) or obj.isInside(lep, 0, False):
|
||||
drillable = False
|
||||
# eliminate elliptical holes
|
||||
elif abs(face.BoundBox.XLength - face.BoundBox.YLength) > 0.05:
|
||||
elif not hasattr(face.Surface, "Radius"): #abs(face.BoundBox.XLength - face.BoundBox.YLength) > 0.05:
|
||||
drillable = False
|
||||
else:
|
||||
drillable = True
|
||||
else:
|
||||
for edge in candidate.Edges:
|
||||
if (isinstance(edge.Curve, Part.Circle)):
|
||||
if abs(edge.BoundBox.XLength - edge.BoundBox.YLength) > 0.05:
|
||||
if isinstance(edge.Curve, Part.Circle) and edge.isClosed():
|
||||
PathLog.debug("candidate is a circle or ellipse")
|
||||
if not hasattr(edge.Curve, "Radius"): #bbdiff > 0.05:
|
||||
PathLog.debug("No radius. Ellipse.")
|
||||
drillable = False
|
||||
else:
|
||||
PathLog.debug("Has Radius, Circle")
|
||||
drillable = True
|
||||
return drillable
|
||||
|
||||
|
||||
Reference in New Issue
Block a user