diff --git a/src/Mod/Arch/ArchComponent.py b/src/Mod/Arch/ArchComponent.py
index 22f697baec31..ed1aa7df74ff 100644
--- a/src/Mod/Arch/ArchComponent.py
+++ b/src/Mod/Arch/ArchComponent.py
@@ -63,7 +63,7 @@ def addToComponent(compobject,addobject,mod=None):
if compobject == addobject: return
# first check zis already there
found = False
- attribs = ["Additions","Objects","Components","Subtractions","Base"]
+ attribs = ["Additions","Objects","Components","Subtractions","Base","Group"]
for a in attribs:
if hasattr(compobject,a):
if a == "Base":
@@ -89,6 +89,8 @@ def addToComponent(compobject,addobject,mod=None):
setattr(compobject,mod,l)
if mod != "Objects":
addobject.ViewObject.hide()
+ if Draft.getType(compobject) == "PanelSheet":
+ addobject.Placement.move(compobject.Placement.Base.negative())
else:
for a in attribs[:3]:
if hasattr(compobject,a):
@@ -106,7 +108,7 @@ def removeFromComponent(compobject,subobject):
it is added as a subtraction.'''
if compobject == subobject: return
found = False
- attribs = ["Additions","Subtractions","Objects","Components","Base","Axes","Fixtures"]
+ attribs = ["Additions","Subtractions","Objects","Components","Base","Axes","Fixtures","Group"]
for a in attribs:
if hasattr(compobject,a):
if a == "Base":
@@ -120,6 +122,8 @@ def removeFromComponent(compobject,subobject):
l.remove(subobject)
setattr(compobject,a,l)
subobject.ViewObject.show()
+ if Draft.getType(compobject) == "PanelSheet":
+ subobject.Placement.move(compobject.Placement.Base)
found = True
if not found:
if hasattr(compobject,"Subtractions"):
@@ -154,7 +158,7 @@ def __init__(self):
# the categories are shown only if they are not empty.
self.obj = None
- self.attribs = ["Base","Additions","Subtractions","Objects","Components","Axes","Fixtures","Armatures"]
+ self.attribs = ["Base","Additions","Subtractions","Objects","Components","Axes","Fixtures","Armatures","Group"]
self.baseform = QtGui.QWidget()
self.baseform.setObjectName("TaskPanel")
self.grid = QtGui.QGridLayout(self.baseform)
@@ -300,6 +304,7 @@ def retranslateUi(self, TaskPanel):
self.treeComponents.setText(0,QtGui.QApplication.translate("Arch", "Components", None, QtGui.QApplication.UnicodeUTF8))
self.treeFixtures.setText(0,QtGui.QApplication.translate("Arch", "Fixtures", None, QtGui.QApplication.UnicodeUTF8))
self.treeArmatures.setText(0,QtGui.QApplication.translate("Arch", "Armatures", None, QtGui.QApplication.UnicodeUTF8))
+ self.treeGroup.setText(0,QtGui.QApplication.translate("Arch", "Group", None, QtGui.QApplication.UnicodeUTF8))
class Component:
"The default Arch Component object"
diff --git a/src/Mod/Arch/ArchPanel.py b/src/Mod/Arch/ArchPanel.py
index 01193ba53e2c..ebe3e9867563 100644
--- a/src/Mod/Arch/ArchPanel.py
+++ b/src/Mod/Arch/ArchPanel.py
@@ -57,7 +57,8 @@ def QT_TRANSLATE_NOOP(ctxt,txt):
["Plywood 18mm, 1220 x 2440",1200,2400,18],
["Plywood 25mm, 1220 x 2440",1200,2400,25],
["MDF 3mm, 900 x 600", 900, 600, 3],
- ["MDF 6mm, 900 x 600", 900, 600, 6]]
+ ["MDF 6mm, 900 x 600", 900, 600, 6],
+ ["OSB 18mm, 1200 x 2400", 1200,2400,18]]
def makePanel(baseobj=None,length=0,width=0,thickness=0,placement=None,name="Panel"):
'''makePanel([obj],[length],[width],[thickness],[placement]): creates a
@@ -67,7 +68,8 @@ def makePanel(baseobj=None,length=0,width=0,thickness=0,placement=None,name="Pan
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name)
obj.Label = translate("Arch",name)
_Panel(obj)
- _ViewProviderPanel(obj.ViewObject)
+ if FreeCAD.GuiUp:
+ _ViewProviderPanel(obj.ViewObject)
if baseobj:
obj.Base = baseobj
obj.Base.ViewObject.hide()
@@ -93,13 +95,37 @@ def makePanelView(panel,page=None,name="PanelView"):
page.Template = Draft.getParam("template",FreeCAD.getResourceDir()+'Mod/Drawing/Templates/A3_Landscape.svg')
view = FreeCAD.ActiveDocument.addObject("Drawing::FeatureViewPython",name)
page.addObject(view)
- _PanelView(view)
+ PanelView(view)
view.Source = panel
- view.Label = translate("Arch","View of")+" "+panel.Name
+ view.Label = translate("Arch","View of")+" "+panel.Label
return view
-class _CommandPanel:
+def makePanelCut(panel,name="PanelView"):
+ """makePanelCut(panel) : Creates a 2D view of the given panel
+ in the 3D space, positioned at the origin."""
+ view = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name)
+ PanelCut(view)
+ view.Source = panel
+ view.Label = translate("Arch","View of")+" "+panel.Label
+ if FreeCAD.GuiUp:
+ ViewProviderPanelCut(view.ViewObject)
+ return view
+
+
+def makePanelSheet(panels=[],name="PanelSheet"):
+ """makePanelSheet([panels]) : Creates a sheet with the given panel cuts
+ in the 3D space, positioned at the origin."""
+ sheet = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name)
+ PanelSheet(sheet)
+ if panels:
+ sheet.Group = panels
+ if FreeCAD.GuiUp:
+ ViewProviderPanelSheet(sheet.ViewObject)
+ return sheet
+
+
+class CommandPanel:
"the Arch Panel command definition"
def GetResources(self):
return {'Pixmap' : 'Arch_Panel',
@@ -264,6 +290,59 @@ def rotate(self):
self.rotated = not self.rotated
+class CommandPanelCut:
+ "the Arch Panel Cut command definition"
+ def GetResources(self):
+ return {'Pixmap' : 'Arch_Panel_Cut',
+ 'MenuText': QT_TRANSLATE_NOOP("Arch_Panel_Cut","Panel Cut"),
+ 'Accel': "P, C",
+ 'ToolTip': QT_TRANSLATE_NOOP("Arch_Panel_Sheet","Creates 2D views of selected panels")}
+
+ def IsActive(self):
+ return not FreeCAD.ActiveDocument is None
+
+ def Activated(self):
+ if FreeCADGui.Selection.getSelection():
+ FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Panel Cut")))
+ FreeCADGui.addModule("Arch")
+ for obj in FreeCADGui.Selection.getSelection():
+ if Draft.getType(obj) == "Panel":
+ FreeCADGui.doCommand("Arch.makePanelCut(FreeCAD.ActiveDocument."+obj.Name+")")
+ FreeCAD.ActiveDocument.commitTransaction()
+ FreeCAD.ActiveDocument.recompute()
+
+
+class CommandPanelSheet:
+ "the Arch Panel Sheet command definition"
+ def GetResources(self):
+ return {'Pixmap' : 'Arch_Panel_Sheet',
+ 'MenuText': QT_TRANSLATE_NOOP("Arch_Panel_Sheet","Panel Sheet"),
+ 'Accel': "P, S",
+ 'ToolTip': QT_TRANSLATE_NOOP("Arch_Panel_Sheet","Creates a 2D sheet which can contain panel cuts")}
+
+ def IsActive(self):
+ return not FreeCAD.ActiveDocument is None
+
+ def Activated(self):
+ FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Panel Sheet")))
+ FreeCADGui.addModule("Arch")
+ if FreeCADGui.Selection.getSelection():
+ l = "["
+ for obj in FreeCADGui.Selection.getSelection():
+ l += "FreeCAD.ActiveDocument."+obj.Name+","
+ l += "]"
+ FreeCAD.ActiveDocument.commitTransaction()
+ FreeCAD.ActiveDocument.recompute()
+ FreeCADGui.doCommand("__objs__ = "+l)
+ FreeCADGui.doCommand("Arch.makePanelSheet(__objs__)")
+ FreeCADGui.doCommand("del __objs__")
+ else:
+ FreeCADGui.doCommand("Arch.makePanelSheet()")
+ FreeCAD.ActiveDocument.commitTransaction()
+ FreeCAD.ActiveDocument.recompute()
+
+
+
class _Panel(ArchComponent.Component):
"The Panel object"
def __init__(self,obj):
@@ -485,7 +564,7 @@ def getIcon(self):
return ":/icons/Arch_Panel_Tree.svg"
-class _PanelView:
+class PanelView:
"A Drawing view for Arch Panels"
def __init__(self, obj):
@@ -559,5 +638,328 @@ def getDisplayModes(self,vobj):
def setDisplayMode(self,mode):
return mode
+
+class PanelCut(Draft._DraftObject):
+ "A flat, 2D view of an Arch Panel"
+
+ def __init__(self, obj):
+ Draft._DraftObject.__init__(self,obj)
+ obj.addProperty("App::PropertyLink","Source","Arch",QT_TRANSLATE_NOOP("App::Property","The linked object"))
+ obj.addProperty("App::PropertyString","TagText","Arch",QT_TRANSLATE_NOOP("App::Property","The text to display. Can be %tag%, %label% or %description% to display the panel tag or label"))
+ obj.addProperty("App::PropertyLength","TagSize","Arch",QT_TRANSLATE_NOOP("App::Property","The size of the tag text"))
+ obj.addProperty("App::PropertyVector","TagPosition","Arch",QT_TRANSLATE_NOOP("App::Property","The position of the tag text. Keep (0,0,0) for automatic center position"))
+ obj.addProperty("App::PropertyAngle","TagRotation","Arch",QT_TRANSLATE_NOOP("App::Property","The rotation of the tag text"))
+ obj.addProperty("App::PropertyFile","FontFile","Arch",QT_TRANSLATE_NOOP("App::Property","The font of the tag text"))
+ obj.Proxy = self
+ self.Type = "PanelCut"
+ obj.TagText = "%tag%"
+ obj.TagSize = 10
+ obj.FontFile = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetString("FontFile","")
+
+ def execute(self, obj):
+ pl = obj.Placement
+ if obj.Source:
+ base = None
+ if Draft.getType(obj.Source) == "Panel":
+ import Part,DraftGeomUtils
+ baseobj = None
+ if obj.Source.CloneOf:
+ baseobj = obj.Source.CloneOf.Base
+ if obj.Source.Base:
+ baseobj = obj.Source.Base
+ if baseobj:
+ if baseobj.isDerivedFrom("Part::Feature"):
+ if baseobj.Shape.Solids:
+ return
+ else:
+ base = Part.makeCompound(baseobj.Shape.Wires)
+ n = None
+ for w in base.Wires:
+ n = DraftGeomUtils.getNormal(w)
+ if n:
+ break
+ if not n:
+ n = Vector(0,0,1)
+ base.translate(base.Vertexes[0].Point.negative())
+ r = FreeCAD.Rotation(n,Vector(0,0,1))
+ base.rotate(Vector(0,0,0),r.Axis,math.degrees(r.Angle))
+ elif baseobj.isDerivedFrom("Mesh::Feature"):
+ return
+ else:
+ l2 = obj.Source.Length/2
+ w2 = obj.Source.Width/2
+ v1 = Vector(-l2,-w2,0)
+ v2 = Vector(l2,-w2,0)
+ v3 = Vector(l2,w2,0)
+ v4 = Vector(-l2,w2,0)
+ base = Part.makePolygon([v1,v2,v3,v4,v1])
+ if base:
+ self.outline = base
+ if obj.FontFile and obj.TagText and obj.TagSize.Value:
+ if obj.TagPosition.Length == 0:
+ pos = base.BoundBox.Center
+ else:
+ pos = obj.TagPosition
+ if obj.TagText == "%tag%":
+ string = obj.Source.Tag
+ elif obj.TagText == "%label%":
+ string = obj.Source.Label
+ elif obj.TagText == "%description%":
+ string = obj.Source.Description
+ else:
+ string = obj.TagText
+ chars = []
+ for char in Part.makeWireString(string,obj.FontFile,obj.TagSize.Value,0):
+ chars.extend(char)
+ textshape = Part.Compound(chars)
+ textshape.translate(pos.sub(textshape.BoundBox.Center))
+ textshape.rotate(textshape.BoundBox.Center,Vector(0,0,1),obj.TagRotation.Value)
+ self.tag = textshape
+ base = Part.Compound([base,textshape])
+ else:
+ base = Part.Compound([base])
+ obj.Shape = base
+ obj.Placement = pl
+
+
+class ViewProviderPanelCut(Draft._ViewProviderDraft):
+ "a view provider for the panel cut object"
+
+ def __init__(self,vobj):
+ Draft._ViewProviderDraft.__init__(self,vobj)
+ vobj.addProperty("App::PropertyLength","Margin","Arch",QT_TRANSLATE_NOOP("App::Property","A margin inside the boundary"))
+ vobj.addProperty("App::PropertyBool","ShowMargin","Arch",QT_TRANSLATE_NOOP("App::Property","Turns the display of the margin on/off"))
+
+ def attach(self,vobj):
+ Draft._ViewProviderDraft.attach(self,vobj)
+ from pivy import coin
+ self.coords = coin.SoCoordinate3()
+ self.lineset = coin.SoLineSet()
+ self.lineset.numVertices.setValue(-1)
+ lineStyle = coin.SoDrawStyle()
+ lineStyle.linePattern = 0x0f0f
+ self.color = coin.SoBaseColor()
+ self.switch = coin.SoSwitch()
+ sep = coin.SoSeparator()
+ self.switch.whichChild = -1
+ sep.addChild(self.color)
+ sep.addChild(lineStyle)
+ sep.addChild(self.coords)
+ sep.addChild(self.lineset)
+ self.switch.addChild(sep)
+ vobj.Annotation.addChild(self.switch)
+ self.onChanged(vobj,"ShowMargin")
+ self.onChanged(vobj,"LineColor")
+
+ def onChanged(self,vobj,prop):
+ if prop in ["Margin","ShowMargin"]:
+ if hasattr(vobj,"Margin") and hasattr(vobj,"ShowMargin"):
+ if (vobj.Margin.Value > 0) and vobj.Object.Shape and vobj.ShowMargin:
+ self.lineset.numVertices.setValue(-1)
+ if vobj.Object.Shape.Wires:
+ d = 0
+ dw = None
+ for w in vobj.Object.Shape.Wires:
+ if w.BoundBox.DiagonalLength > d:
+ d = w.BoundBox.DiagonalLength
+ dw = w
+ if dw:
+ ow = dw.makeOffset2D(vobj.Margin.Value)
+ verts = []
+ for v in ow.OrderedVertexes:
+ v = vobj.Object.Placement.inverse().multVec(v.Point)
+ verts.append((v.x,v.y,v.z))
+ if dw.isClosed():
+ verts.append(verts[0])
+ self.coords.point.setValues(verts)
+ self.lineset.numVertices.setValue(len(verts))
+ self.switch.whichChild = 0
+ else:
+ self.switch.whichChild = -1
+ elif prop == "LineColor":
+ if hasattr(vobj,"LineColor"):
+ c = vobj.LineColor
+ self.color.rgb.setValue(c[0],c[1],c[2])
+ Draft._ViewProviderDraft.onChanged(self,vobj,prop)
+
+ def updateData(self,obj,prop):
+ if prop in ["Shape"]:
+ self.onChanged(obj.ViewObject,"Margin")
+ Draft._ViewProviderDraft.updateData(self,obj,prop)
+
+
+class PanelSheet(Draft._DraftObject):
+ "A collection of Panel cuts under a sheet"
+
+ def __init__(self, obj):
+ Draft._DraftObject.__init__(self,obj)
+ obj.addProperty("App::PropertyLinkList","Group","Arch",QT_TRANSLATE_NOOP("App::Property","The linked Panel cuts"))
+ obj.addProperty("App::PropertyString","TagText","Arch",QT_TRANSLATE_NOOP("App::Property","The tag text to display"))
+ obj.addProperty("App::PropertyLength","TagSize","Arch",QT_TRANSLATE_NOOP("App::Property","The size of the tag text"))
+ obj.addProperty("App::PropertyVector","TagPosition","Arch",QT_TRANSLATE_NOOP("App::Property","The position of the tag text. Keep (0,0,0) for automatic center position"))
+ obj.addProperty("App::PropertyAngle","TagRotation","Arch",QT_TRANSLATE_NOOP("App::Property","The rotation of the tag text"))
+ obj.addProperty("App::PropertyFile","FontFile","Arch",QT_TRANSLATE_NOOP("App::Property","The font of the tag text"))
+ obj.addProperty("App::PropertyLength","Width","Arch",QT_TRANSLATE_NOOP("App::Property","The width of the sheet"))
+ obj.addProperty("App::PropertyLength","Height","Arch",QT_TRANSLATE_NOOP("App::Property","The height of the sheet"))
+ obj.addProperty("App::PropertyPercent","FillRatio","Arch",QT_TRANSLATE_NOOP("App::Property","The fill ratio of this sheet"))
+ obj.Proxy = self
+ self.Type = "PanelSheet"
+ obj.TagSize = 10
+ obj.Width = 1000
+ obj.Height = 1000
+ obj.FontFile = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetString("FontFile","")
+ obj.setEditorMode("FillRatio",2)
+
+ def execute(self, obj):
+ import Part
+ pl = obj.Placement
+ if obj.Width.Value and obj.Height.Value:
+ l2 = obj.Width.Value/2
+ w2 = obj.Height.Value/2
+ v1 = Vector(-l2,-w2,0)
+ v2 = Vector(l2,-w2,0)
+ v3 = Vector(l2,w2,0)
+ v4 = Vector(-l2,w2,0)
+ base = Part.makePolygon([v1,v2,v3,v4,v1])
+ self.sheetborder = base
+ wires = []
+ area = obj.Width.Value * obj.Height.Value
+ subarea = 0
+ for v in obj.Group:
+ if v.isDerivedFrom("Part::Feature"):
+ wires.extend(v.Shape.Wires)
+ if Draft.getType(v) == "PanelCut":
+ if v.Source:
+ subarea += v.Source.Area.Value
+ else:
+ for w in v.Shape.Wires:
+ if w.isClosed():
+ f = Part.Face(w)
+ subarea += f.Area
+ if wires:
+ base = Part.Compound([base]+wires)
+ if obj.FontFile and obj.TagText and obj.TagSize.Value:
+ chars = []
+ for char in Part.makeWireString(obj.TagText,obj.FontFile,obj.TagSize.Value,0):
+ chars.extend(char)
+ textshape = Part.Compound(chars)
+ textshape.translate(obj.TagPosition)
+ textshape.rotate(textshape.BoundBox.Center,Vector(0,0,1),obj.TagRotation.Value)
+ self.sheettag = textshape
+ base = Part.Compound([base,textshape])
+ obj.Shape = base
+ obj.Placement = pl
+ obj.FillRatio = int((subarea/area)*100)
+
+
+class ViewProviderPanelSheet(Draft._ViewProviderDraft):
+ "a view provider for the panel sheet object"
+
+ def __init__(self,vobj):
+ Draft._ViewProviderDraft.__init__(self,vobj)
+ vobj.addProperty("App::PropertyLength","Margin","Arch",QT_TRANSLATE_NOOP("App::Property","A margin inside the boundary"))
+ vobj.addProperty("App::PropertyBool","ShowMargin","Arch",QT_TRANSLATE_NOOP("App::Property","Turns the display of the margin on/off"))
+
+
+ def getIcon(self):
+ return ":/icons/Draft_Drawing.svg"
+
+ def setEdit(self,vobj,mode):
+ if mode == 0:
+ taskd = SheetTaskPanel(vobj.Object)
+ taskd.update()
+ FreeCADGui.Control.showDialog(taskd)
+ return True
+ return False
+
+ def unsetEdit(self,vobj,mode):
+ FreeCADGui.Control.closeDialog()
+ return False
+
+ def attach(self,vobj):
+ Draft._ViewProviderDraft.attach(self,vobj)
+ from pivy import coin
+ self.coords = coin.SoCoordinate3()
+ self.lineset = coin.SoLineSet()
+ self.lineset.numVertices.setValue(-1)
+ lineStyle = coin.SoDrawStyle()
+ lineStyle.linePattern = 0x0f0f
+ self.color = coin.SoBaseColor()
+ self.switch = coin.SoSwitch()
+ sep = coin.SoSeparator()
+ self.switch.whichChild = -1
+ sep.addChild(self.color)
+ sep.addChild(lineStyle)
+ sep.addChild(self.coords)
+ sep.addChild(self.lineset)
+ self.switch.addChild(sep)
+ vobj.Annotation.addChild(self.switch)
+ self.onChanged(vobj,"ShowMargin")
+ self.onChanged(vobj,"LineColor")
+
+ def onChanged(self,vobj,prop):
+ if prop in ["Margin","ShowMargin"]:
+ if hasattr(vobj,"Margin") and hasattr(vobj,"ShowMargin"):
+ if (vobj.Margin.Value > 0) and (vobj.Margin.Value < vobj.Object.Width.Value/2) and (vobj.Margin.Value < vobj.Object.Height.Value/2):
+ l2 = vobj.Object.Width.Value/2
+ w2 = vobj.Object.Height.Value/2
+ v = vobj.Margin.Value
+ v1 = (-l2+v,-w2+v,0)
+ v2 = (l2-v,-w2+v,0)
+ v3 = (l2-v,w2-v,0)
+ v4 = (-l2+v,w2-v,0)
+ self.coords.point.setValues([v1,v2,v3,v4,v1])
+ self.lineset.numVertices.setValue(5)
+ if vobj.ShowMargin:
+ self.switch.whichChild = 0
+ else:
+ self.switch.whichChild = -1
+ elif prop == "LineColor":
+ if hasattr(vobj,"LineColor"):
+ c = vobj.LineColor
+ self.color.rgb.setValue(c[0],c[1],c[2])
+ Draft._ViewProviderDraft.onChanged(self,vobj,prop)
+
+ def updateData(self,obj,prop):
+ if prop in ["Width","Height"]:
+ self.onChanged(obj.ViewObject,"Margin")
+ Draft._ViewProviderDraft.updateData(self,obj,prop)
+
+
+class SheetTaskPanel(ArchComponent.ComponentTaskPanel):
+
+ def __init__(self,obj):
+ ArchComponent.ComponentTaskPanel.__init__(self)
+ self.obj = obj
+ self.optwid = QtGui.QWidget()
+ self.optwid.setWindowTitle(QtGui.QApplication.translate("Arch", "Tools", None, QtGui.QApplication.UnicodeUTF8))
+ lay = QtGui.QVBoxLayout(self.optwid)
+ self.editButton = QtGui.QPushButton(self.optwid)
+ self.editButton.setIcon(QtGui.QIcon(":/icons/Draft_Edit.svg"))
+ self.editButton.setText(QtGui.QApplication.translate("Arch", "Edit views positions", None, QtGui.QApplication.UnicodeUTF8))
+ lay.addWidget(self.editButton)
+ QtCore.QObject.connect(self.editButton, QtCore.SIGNAL("clicked()"), self.editNodes)
+ self.form = [self.form,self.optwid]
+
+ def editNodes(self):
+ FreeCADGui.Control.closeDialog()
+ FreeCADGui.runCommand("Draft_Edit")
+
+
if FreeCAD.GuiUp:
- FreeCADGui.addCommand('Arch_Panel',_CommandPanel())
+
+ class CommandPanelGroup:
+
+ def GetCommands(self):
+ return tuple(['Arch_Panel','Arch_Panel_Cut','Arch_Panel_Sheet'])
+ def GetResources(self):
+ return { 'MenuText': QT_TRANSLATE_NOOP("Arch_PanelTools",'Panel tools'),
+ 'ToolTip': QT_TRANSLATE_NOOP("Arch_PanelTools",'Panel tools')
+ }
+ def IsActive(self):
+ return not FreeCAD.ActiveDocument is None
+
+ FreeCADGui.addCommand('Arch_Panel',CommandPanel())
+ FreeCADGui.addCommand('Arch_Panel_Cut',CommandPanelCut())
+ FreeCADGui.addCommand('Arch_Panel_Sheet',CommandPanelSheet())
+ FreeCADGui.addCommand('Arch_PanelTools', CommandPanelGroup())
diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py
index f86c3314afe4..0459f3cf3f2c 100644
--- a/src/Mod/Arch/InitGui.py
+++ b/src/Mod/Arch/InitGui.py
@@ -37,7 +37,7 @@ def Initialize(self):
"Arch_Floor","Arch_Building","Arch_Site",
"Arch_Window","Arch_Roof","Arch_Axis",
"Arch_SectionPlane","Arch_Space","Arch_Stairs",
- "Arch_Panel","Arch_Equipment",
+ "Arch_PanelTools","Arch_Equipment",
"Arch_Frame","Arch_Material","Arch_Schedule","Arch_PipeTools",
"Arch_CutPlane","Arch_Add","Arch_Remove","Arch_Survey"]
self.utilities = ["Arch_Component","Arch_SplitMesh","Arch_MeshToShape",
diff --git a/src/Mod/Arch/Resources/Arch.qrc b/src/Mod/Arch/Resources/Arch.qrc
index 673c2800b6ec..2cb830ae3f62 100644
--- a/src/Mod/Arch/Resources/Arch.qrc
+++ b/src/Mod/Arch/Resources/Arch.qrc
@@ -45,6 +45,8 @@
icons/Arch_Panel.svg
icons/Arch_Panel_Tree.svg
icons/Arch_Panel_Clone.svg
+ icons/Arch_Panel_Cut.svg
+ icons/Arch_Panel_Sheet.svg
icons/Arch_Equipment.svg
icons/Arch_Equipment_Tree.svg
icons/Arch_Equipment_Clone.svg
diff --git a/src/Mod/Arch/Resources/icons/Arch_Panel_Cut.svg b/src/Mod/Arch/Resources/icons/Arch_Panel_Cut.svg
new file mode 100644
index 000000000000..52048f7ebab0
--- /dev/null
+++ b/src/Mod/Arch/Resources/icons/Arch_Panel_Cut.svg
@@ -0,0 +1,139 @@
+
+
+
+
diff --git a/src/Mod/Arch/Resources/icons/Arch_Panel_Sheet.svg b/src/Mod/Arch/Resources/icons/Arch_Panel_Sheet.svg
new file mode 100644
index 000000000000..b256ecfb160f
--- /dev/null
+++ b/src/Mod/Arch/Resources/icons/Arch_Panel_Sheet.svg
@@ -0,0 +1,484 @@
+
+
+
+
diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py
index efdb817a8b7b..7003d9f5ee91 100644
--- a/src/Mod/Draft/Draft.py
+++ b/src/Mod/Draft/Draft.py
@@ -581,8 +581,10 @@ def getMovableChildren(objectslist,recursive=True):
with all child objects that have a "MoveWithHost" property set to True. If
recursive is True, all descendents are considered, otherwise only direct children.'''
added = []
+ if not isinstance(objectslist,list):
+ objectslist = [objectslist]
for obj in objectslist:
- if not (getType(obj) in ["Clone","SectionPlane"]):
+ if not (getType(obj) in ["Clone","SectionPlane","Facebinder"]):
# objects that should never move their children
children = obj.OutList
if hasattr(obj,"Proxy"):
@@ -2708,6 +2710,8 @@ def clone(obj,delta=None):
cl.Placement = obj[0].Placement
try:
cl.Role = base.Role
+ cl.Description = base.Description
+ cl.Tag = base.Tag
except:
pass
return cl
@@ -3563,6 +3567,8 @@ def claimChildren(self):
objs.extend(self.Object.Objects)
if hasattr(self.Object,"Components"):
objs.extend(self.Object.Components)
+ if hasattr(self.Object,"Group"):
+ objs.extend(self.Object.Group)
return objs
class _ViewProviderDraftAlt(_ViewProviderDraft):
diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py
index 0862239cb6f1..8b9a5d21d808 100644
--- a/src/Mod/Draft/DraftTools.py
+++ b/src/Mod/Draft/DraftTools.py
@@ -3501,6 +3501,16 @@ def proceed(self):
if self.pl:
p = self.pl.multVec(p)
self.editpoints.append(p)
+ elif Draft.getType(self.obj) == "PanelCut":
+ if self.obj.TagPosition.Length == 0:
+ pos = self.obj.Shape.BoundBox.Center
+ else:
+ pos = self.pl.multVec(self.obj.TagPosition)
+ self.editpoints.append(pos)
+ elif Draft.getType(self.obj) == "PanelSheet":
+ self.editpoints.append(self.pl.multVec(self.obj.TagPosition))
+ for o in self.obj.Group:
+ self.editpoints.append(self.pl.multVec(o.Placement.Base))
if Draft.getType(self.obj) != "BezCurve":
self.trackers = []
if self.editpoints:
@@ -3724,6 +3734,14 @@ def update(self,v):
nodes = self.obj.Nodes
nodes[self.editing] = self.invpl.multVec(v)
self.obj.Nodes = nodes
+ elif Draft.getType(self.obj) == "PanelCut":
+ if self.editing == 0:
+ self.obj.TagPosition = self.invpl.multVec(v)
+ elif Draft.getType(self.obj) == "PanelSheet":
+ if self.editing == 0:
+ self.obj.TagPosition = self.invpl.multVec(v)
+ else:
+ self.obj.Group[self.editing-1].Placement.Base = self.invpl.multVec(v)
def numericInput(self,v,numy=None,numz=None):
'''this function gets called by the toolbar
diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py
index 39b0fecfc46e..9d2b864c1cd7 100644
--- a/src/Mod/Draft/importDXF.py
+++ b/src/Mod/Draft/importDXF.py
@@ -1548,6 +1548,9 @@ def insert(filename,docname):
getDXFlibs()
if dxfReader:
groupname = os.path.splitext(os.path.basename(filename))[0]
+ if isinstance(groupname,unicode):
+ import sys #workaround since newDocument currently can't handle unicode filenames
+ groupname = groupname.encode(sys.getfilesystemencoding())
importgroup = doc.addObject("App::DocumentObjectGroup",groupname)
importgroup.Label = decodeName(groupname)
processdxf(doc,filename)
@@ -1642,7 +1645,7 @@ def getSplineSegs(edge):
points.append(edge.valueAt(edge.LastParameter))
return points
-def getWire(wire,nospline=False,lw=True):
+def getWire(wire,nospline=False,lw=True,asis=False):
"returns an array of dxf-ready points and bulges from a wire"
def fmt(v,b=0.0):
if lw:
@@ -1651,32 +1654,35 @@ def fmt(v,b=0.0):
else:
# Polyline format
return ((v.x,v.y,v.z),None,[None,None],b)
- edges = Part.__sortEdges__(wire.Edges)
points = []
- # print("processing wire ",wire.Edges)
- for edge in edges:
- v1 = edge.Vertexes[0].Point
- if DraftGeomUtils.geomType(edge) == "Circle":
- # polyline bulge -> negative makes the arc go clockwise
- angle = edge.LastParameter-edge.FirstParameter
- bul = math.tan(angle/4)
- #if cross1[2] < 0:
+ if asis:
+ points = [fmt(v.Point) for v in wire.OrderedVertexes]
+ else:
+ edges = Part.__sortEdges__(wire.Edges)
+ # print("processing wire ",wire.Edges)
+ for edge in edges:
+ v1 = edge.Vertexes[0].Point
+ if DraftGeomUtils.geomType(edge) == "Circle":
# polyline bulge -> negative makes the arc go clockwise
- #bul = -bul
- if edge.Curve.Axis.dot(FreeCAD.Vector(0,0,1)) < 0:
- bul = -bul
- points.append(fmt(v1,bul))
- elif (DraftGeomUtils.geomType(edge) in ["BSplineCurve","BezierCurve","Ellipse"]) and (not nospline):
- spline = getSplineSegs(edge)
- spline.pop()
- for p in spline:
- points.append(fmt(p))
- else:
- points.append(fmt(v1))
- if not DraftGeomUtils.isReallyClosed(wire):
- v = edges[-1].Vertexes[-1].Point
- points.append(fmt(v))
- # print("wire verts: ",points)
+ angle = edge.LastParameter-edge.FirstParameter
+ bul = math.tan(angle/4)
+ #if cross1[2] < 0:
+ # polyline bulge -> negative makes the arc go clockwise
+ #bul = -bul
+ if edge.Curve.Axis.dot(FreeCAD.Vector(0,0,1)) < 0:
+ bul = -bul
+ points.append(fmt(v1,bul))
+ elif (DraftGeomUtils.geomType(edge) in ["BSplineCurve","BezierCurve","Ellipse"]) and (not nospline):
+ spline = getSplineSegs(edge)
+ spline.pop()
+ for p in spline:
+ points.append(fmt(p))
+ else:
+ points.append(fmt(v1))
+ if not DraftGeomUtils.isReallyClosed(wire):
+ v = edges[-1].Vertexes[-1].Point
+ points.append(fmt(v))
+ # print("wire verts: ",points)
return points
def getBlock(sh,obj,lwPoly=False):
@@ -1685,35 +1691,43 @@ def getBlock(sh,obj,lwPoly=False):
writeShape(sh,obj,block,lwPoly)
return block
-def writeShape(sh,ob,dxfobject,nospline=False,lwPoly=False):
+def writeShape(sh,ob,dxfobject,nospline=False,lwPoly=False,layer=None,color=None,asis=False):
"writes the object's shape contents in the given dxf object"
processededges = []
+ if not layer:
+ layer=getGroup(ob)
+ if not color:
+ color = getACI(ob)
for wire in sh.Wires: # polylines
- for e in wire.Edges:
+ if asis:
+ edges = wire.Edges
+ else:
+ edges = Part.__sortEdges__(wire.Edges)
+ for e in edges:
processededges.append(e.hashCode())
if (len(wire.Edges) == 1) and (DraftGeomUtils.geomType(wire.Edges[0]) == "Circle"):
center, radius, ang1, ang2 = getArcData(wire.Edges[0])
if center != None:
if len(wire.Edges[0].Vertexes) == 1: # circle
dxfobject.append(dxfLibrary.Circle(center, radius,
- color=getACI(ob),
- layer=getGroup(ob)))
+ color=color,
+ layer=layer))
else: # arc
dxfobject.append(dxfLibrary.Arc(center, radius,
- ang1, ang2, color=getACI(ob),
- layer=getGroup(ob)))
+ ang1, ang2, color=color,
+ layer=layer))
else:
if (lwPoly):
if hasattr(dxfLibrary,"LwPolyLine"):
- dxfobject.append(dxfLibrary.LwPolyLine(getWire(wire,nospline), [0.0,0.0],
- int(DraftGeomUtils.isReallyClosed(wire)), color=getACI(ob),
- layer=getGroup(ob)))
+ dxfobject.append(dxfLibrary.LwPolyLine(getWire(wire,nospline,asis=asis), [0.0,0.0],
+ int(DraftGeomUtils.isReallyClosed(wire)), color=color,
+ layer=layer))
else:
FreeCAD.Console.PrintWarning("LwPolyLine support not found. Please delete dxfLibrary.py from your FreeCAD user directory to force auto-update\n")
else :
- dxfobject.append(dxfLibrary.PolyLine(getWire(wire,nospline,lw=False), [0.0,0.0,0.0],
- int(DraftGeomUtils.isReallyClosed(wire)), color=getACI(ob),
- layer=getGroup(ob)))
+ dxfobject.append(dxfLibrary.PolyLine(getWire(wire,nospline,lw=False,asis=asis), [0.0,0.0,0.0],
+ int(DraftGeomUtils.isReallyClosed(wire)), color=color,
+ layer=layer))
if len(processededges) < len(sh.Edges): # lone edges
loneedges = []
for e in sh.Edges:
@@ -1726,16 +1740,16 @@ def writeShape(sh,ob,dxfobject,nospline=False,lwPoly=False):
c = DraftGeomUtils.getCircleFromSpline(edge)
if c:
dxfobject.append(dxfLibrary.Circle(DraftVecUtils.tup(c.Curve.Center), c.Curve.Radius,
- color=getACI(ob),
- layer=getGroup(ob)))
+ color=color,
+ layer=layer))
else:
points = []
spline = getSplineSegs(edge)
for p in spline:
points.append(((p.x,p.y,p.z),None,[None,None],0.0))
dxfobject.append(dxfLibrary.PolyLine(points, [0.0,0.0,0.0],
- 0, color=getACI(ob),
- layer=getGroup(ob)))
+ 0, color=color,
+ layer=layer))
elif DraftGeomUtils.geomType(edge) == "Circle": # curves
center, radius, ang1, ang2 = getArcData(edge)
if center != None:
@@ -1743,12 +1757,12 @@ def writeShape(sh,ob,dxfobject,nospline=False,lwPoly=False):
center = DraftVecUtils.tup(center)
if len(edge.Vertexes) == 1: # circles
dxfobject.append(dxfLibrary.Circle(center, radius,
- color=getACI(ob),
- layer=getGroup(ob)))
+ color=color,
+ layer=layer))
else : # arcs
dxfobject.append(dxfLibrary.Arc(center, radius,
ang1, ang2, color=getACI(ob),
- layer=getGroup(ob)))
+ layer=layer))
elif DraftGeomUtils.geomType(edge) == "Ellipse": # ellipses:
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("DiscretizeEllipses",True):
points = []
@@ -1756,8 +1770,8 @@ def writeShape(sh,ob,dxfobject,nospline=False,lwPoly=False):
for p in spline:
points.append(((p.x,p.y,p.z),None,[None,None],0.0))
dxfobject.append(dxfLibrary.PolyLine(points, [0.0,0.0,0.0],
- 0, color=getACI(ob),
- layer=getGroup(ob)))
+ 0, color=color,
+ layer=layer))
else:
if hasattr(dxfLibrary,"Ellipse"):
center = DraftVecUtils.tup(edge.Curve.Center)
@@ -1771,8 +1785,8 @@ def writeShape(sh,ob,dxfobject,nospline=False,lwPoly=False):
dxfobject.append(dxfLibrary.Ellipse(center=center,majorAxis=major,normalAxis=norm,
minorAxisRatio=minor,startParameter=start,
endParameter=end,
- color=getACI(ob),
- layer=getGroup(ob)))
+ color=color,
+ layer=layer))
else:
FreeCAD.Console.PrintWarning("Ellipses support not found. Please delete dxfLibrary.py from your FreeCAD user directory to force auto-update\n")
else: # anything else is treated as lines
@@ -1780,10 +1794,10 @@ def writeShape(sh,ob,dxfobject,nospline=False,lwPoly=False):
ve1=edge.Vertexes[0].Point
ve2=edge.Vertexes[1].Point
dxfobject.append(dxfLibrary.Line([DraftVecUtils.tup(ve1), DraftVecUtils.tup(ve2)],
- color=getACI(ob),
- layer=getGroup(ob)))
+ color=color,
+ layer=layer))
-def writeMesh(ob,dxfobject):
+def writeMesh(ob,dxf):
"export a shape as a polyface mesh"
meshdata = ob.Shape.tessellate(0.5)
# print(meshdata)
@@ -1794,10 +1808,52 @@ def writeMesh(ob,dxfobject):
for f in meshdata[1]:
faces.append([f[0]+1,f[1]+1,f[2]+1])
# print(len(points),len(faces))
- dxfobject.append(dxfLibrary.PolyLine([points,faces], [0.0,0.0,0.0],
+ dxf.append(dxfLibrary.PolyLine([points,faces], [0.0,0.0,0.0],
64, color=getACI(ob),
layer=getGroup(ob)))
+def writePanelCut(ob,dxf,nospline,lwPoly,parent=None):
+ if not hasattr(ob.Proxy,"outline"):
+ ob.Proxy.execute(ob)
+ if hasattr(ob.Proxy,"outline"):
+ outl = ob.Proxy.outline
+ tag = None
+ if hasattr(ob.Proxy,"tag"):
+ tag = ob.Proxy.tag
+ if tag:
+ tag.Placement = ob.Placement.multiply(tag.Placement)
+ if parent:
+ tag.Placement = parent.Placement.multiply(tag.Placement)
+ outl.Placement = ob.Placement.multiply(outl.Placement)
+ if parent:
+ outl.Placement = parent.Placement.multiply(outl.Placement)
+ else:
+ parent = ob
+ if len(outl.Wires) > 1:
+ # separate outline
+ d = 0
+ ow = None
+ for w in outl.Wires:
+ if w.BoundBox.DiagonalLength > d:
+ d = w.BoundBox.DiagonalLength
+ ow = w
+ if ow:
+ inl = Part.Compound([w for w in outl.Wires if w.hashCode() != ow.hashCode()])
+ outl = ow
+ else:
+ inl = None
+ outl = outl.Wires[0]
+
+ writeShape(outl,parent,dxf,nospline,lwPoly,layer="Outlines",color=5)
+ if inl:
+ writeShape(inl,parent,dxf,nospline,lwPoly,layer="Cuts",color=4)
+ if tag:
+ writeShape(tag,parent,dxf,nospline,lwPoly,layer="Tags",color=2,asis=True)
+ # sticky fonts can render very odd wires...
+ #for w in tag.Edges:
+ # pts = [(v.X,v.Y,v.Z) for v in w.Vertexes]
+ # dxf.append(dxfLibrary.Line(pts,color=getACI(ob),layer="Tags"))
+
def export(objectslist,filename,nospline=False,lwPoly=False):
"called when freecad exports a file. If nospline=True, bsplines are exported as straight segs lwPoly=True for OpenSCAD DXF"
readPreferences()
@@ -1828,7 +1884,25 @@ def export(objectslist,filename,nospline=False,lwPoly=False):
dxf = dxfLibrary.Drawing()
for ob in exportList:
print("processing "+str(ob.Name))
- if ob.isDerivedFrom("Part::Feature"):
+ if Draft.getType(ob) == "PanelSheet":
+ if not hasattr(ob.Proxy,"sheetborder"):
+ ob.Proxy.execute(ob)
+ sb = ob.Proxy.sheetborder
+ sb.Placement = ob.Placement
+ ss = ob.Proxy.sheettag
+ ss.Placement = ob.Placement.multiply(ss.Placement)
+ writeShape(sb,ob,dxf,nospline,lwPoly,layer="Sheets",color=1)
+ writeShape(ss,ob,dxf,nospline,lwPoly,layer="SheetTags",color=1)
+ for subob in ob.Group:
+ if Draft.getType(subob) == "PanelCut":
+ writePanelCut(subob,dxf,nospline,lwPoly,parent=ob)
+ elif subob.isDerivedFrom("Part::Feature"):
+ shp = subob.Shape.copy()
+ shp.Placement = ob.Placement.multiply(shp.Placement)
+ writeShape(shp,ob,dxf,nospline,lwPoly,layer="Outlines",color=5)
+ elif Draft.getType(ob) == "PanelCut":
+ writePanelCut(ob,dxf,nospline,lwPoly)
+ elif ob.isDerivedFrom("Part::Feature"):
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("dxfmesh"):
sh = None
if not ob.Shape.isNull():