Path: additional functionality for arch panels

This commit is contained in:
sliptonic
2017-03-17 19:34:07 -05:00
committed by Yorik van Havre
parent 8699d14057
commit ffc4fb28aa
6 changed files with 134 additions and 102 deletions

View File

@@ -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

View File

@@ -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">

View File

@@ -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

View File

@@ -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')

View File

@@ -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()

View File

@@ -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