diff --git a/src/Mod/Arch/ArchAxis.py b/src/Mod/Arch/ArchAxis.py
index adee4619fa..542bcbfd5e 100644
--- a/src/Mod/Arch/ArchAxis.py
+++ b/src/Mod/Arch/ArchAxis.py
@@ -79,6 +79,20 @@ def makeAxisSystem(axes,name="Axis System"):
obj.Axes = axes
if FreeCAD.GuiUp:
_ViewProviderAxisSystem(obj.ViewObject)
+ FreeCAD.ActiveDocument.recompute()
+ return obj
+
+
+def makeGrid(name="Grid"):
+ '''makeGrid(): makes a grid object'''
+ obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name)
+ obj.Label = translate("Arch",name)
+ ArchGrid(obj)
+ if FreeCAD.GuiUp:
+ ViewProviderArchGrid(obj.ViewObject)
+ obj.ViewObject.Transparency = 85
+ FreeCAD.ActiveDocument.recompute()
+ return obj
class _CommandAxis:
@@ -129,6 +143,26 @@ class _CommandAxisSystem:
return not FreeCAD.ActiveDocument is None
+class CommandArchGrid:
+ "the Arch Grid command definition"
+ def GetResources(self):
+ return {'Pixmap' : 'Arch_Grid',
+ 'MenuText': QT_TRANSLATE_NOOP("Arch_Axis","Grid"),
+ 'Accel': "A, X",
+ 'ToolTip': QT_TRANSLATE_NOOP("Arch_Axis","Creates a customizable grid object")}
+
+ def Activated(self):
+ FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Grid"))
+ FreeCADGui.addModule("Arch")
+
+ FreeCADGui.doCommand("Arch.makeGrid()")
+ FreeCAD.ActiveDocument.commitTransaction()
+
+ def IsActive(self):
+ return not FreeCAD.ActiveDocument is None
+
+
+
class _Axis:
"The Axis object"
def __init__(self,obj):
@@ -835,14 +869,450 @@ class AxisSystemTaskPanel:
self.title.setText(QtGui.QApplication.translate("Arch", "Axis system components", None))
+class ArchGrid:
+
+ "The Grid object"
+
+ def __init__(self,obj):
+ obj.addProperty("App::PropertyInteger","Rows","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The number of rows'))
+ obj.addProperty("App::PropertyInteger","Columns","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The number of columns'))
+ obj.addProperty("App::PropertyFloatList","RowSize","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The sizes for rows'))
+ obj.addProperty("App::PropertyFloatList","ColumnSize","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The sizes of columns'))
+ obj.addProperty("App::PropertyStringList","Spans","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The span ranges of cells that are merged together'))
+ obj.addProperty("App::PropertyEnumeration","PointsOutput","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The type of 3D points produced by this grid object'))
+ obj.addProperty("App::PropertyLength","Width","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The total width of this grid'))
+ obj.addProperty("App::PropertyLength","Height","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The total height of this grid'))
+ obj.addProperty("App::PropertyLength","AutoWidth","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'Creates automatic column divisions (set to 0 to disable)'))
+ obj.addProperty("App::PropertyLength","AutoHeight","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'Creates automatic row divisions (set to 0 to disable)'))
+ obj.addProperty("App::PropertyBool","Reorient","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'When in edge midpoint mode, if this grid must reorient its children along edge normals or not'))
+ obj.addProperty("App::PropertyIntegerList","HiddenFaces","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The indices of faces to hide'))
+ obj.PointsOutput = ["Vertices","Edges","Vertical Edges","Horizontal Edges","Faces"]
+ self.Type = "Grid"
+ obj.Proxy = self
+
+ def getSizes(self,obj):
+ "returns rowsizes,columnsizes,spangroups"
+ if not obj.Height.Value:
+ return [],[],[]
+ if not obj.Width.Value:
+ return [],[],[]
+ if (not obj.Rows) and (not obj.AutoHeight.Value):
+ return [],[],[]
+ if (not obj.Columns) and (not obj.AutoWidth.Value):
+ return [],[],[]
+ # rescale rows
+ rowsizes = []
+ if obj.AutoHeight.Value:
+ if obj.AutoHeight.Value > obj.Height.Value:
+ FreeCAD.Console.PrintError(translate("Arch","Auto height is bigger than height"))
+ return [],[],[]
+ rows = int(math.floor(obj.Height.Value/obj.AutoHeight.Value))
+ for i in range(rows):
+ rowsizes.append(obj.AutoHeight.Value)
+ rowsizes.append(obj.Height.Value-rows*obj.AutoHeight.Value)
+ else:
+ reserved_rowsize = sum(v for v in obj.RowSize)
+ if reserved_rowsize > obj.Height.Value:
+ FreeCAD.Console.PrintError(translate("Arch","Total row size is bigger than height"))
+ return [],[],[]
+ for i in range(obj.Rows):
+ v = 0
+ if i < len(obj.RowSize):
+ v = obj.RowSize[i]
+ rowsizes.append(v)
+ e = len([v for v in rowsizes if v == 0])
+ default = obj.Height.Value - reserved_rowsize
+ if e:
+ default = default / e
+ t = []
+ for v in rowsizes:
+ if v:
+ t.append(v)
+ else:
+ t.append(default)
+ rowsizes = t
+ # rescale columns
+ columnsizes = []
+ if obj.AutoWidth.Value:
+ if obj.AutoWidth.Value > obj.Width.Value:
+ FreeCAD.Console.PrintError(translate("Arch","Auto width is bigger than width"))
+ return [],[],[]
+ cols = int(math.floor(obj.Width.Value/obj.AutoWidth.Value))
+ for i in range(cols):
+ columnsizes.append(obj.AutoWidth.Value)
+ columnsizes.append(obj.Width.Value-cols*obj.AutoWidth.Value)
+ else:
+ reserved_columnsize = sum(v for v in obj.ColumnSize)
+ if reserved_columnsize > obj.Width.Value:
+ FreeCAD.Console.PrintError(translate("Arch","Total column size is bigger than width"))
+ return [],[],[]
+ for i in range(obj.Columns):
+ v = 0
+ if i < len(obj.ColumnSize):
+ v = obj.ColumnSize[i]
+ columnsizes.append(v)
+ e = len([v for v in columnsizes if v == 0])
+ default = obj.Width.Value - reserved_columnsize
+ if e:
+ default = default / e
+ t = []
+ for v in columnsizes:
+ if v:
+ t.append(v)
+ else:
+ t.append(default)
+ columnsizes = t
+ # format span groups from [row,col,rowspan,colspan] to [faceindexes]
+ spangroups = []
+ for s in obj.Spans:
+ nspan = []
+ span = [int(i.strip()) for i in s.split(",")]
+ for row in range(span[2]):
+ for column in range(span[3]):
+ nspan.append((span[0]+row)*obj.Columns + (span[1]+column))
+ spangroups.append(nspan)
+ return rowsizes,columnsizes,spangroups
+
+ def execute(self,obj):
+ pl = obj.Placement
+ import Part
+ rowsizes,columnsizes,spangroups = self.getSizes(obj)
+ #print rowsizes,columnsizes,spangroups
+ # create one face for each cell
+ faces = []
+ facenumber = 0
+ rowoffset = 0
+ for row in rowsizes:
+ columnoffset = 0
+ for column in columnsizes:
+ v1 = FreeCAD.Vector(columnoffset,rowoffset,0)
+ v2 = v1.add(FreeCAD.Vector(column,0,0))
+ v3 = v2.add(FreeCAD.Vector(0,-row,0))
+ v4 = v3.add(FreeCAD.Vector(-column,0,0))
+ f = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1]))
+ if not facenumber in obj.HiddenFaces:
+ spanning = False
+ for i in range(len(spangroups)):
+ if facenumber in spangroups[i]:
+ g = spangroups[i]
+ g[g.index(facenumber)] = f
+ spangroups[i] = g
+ spanning = True
+ break
+ if not spanning:
+ faces.append(f)
+ facenumber += 1
+ columnoffset += column
+ rowoffset -= row
+ # join spangroups
+ for g in spangroups:
+ s = Part.makeShell(g)
+ s = s.removeSplitter()
+ faces.extend(s.Faces)
+ if faces:
+ obj.Shape = Part.makeCompound(faces)
+ obj.Placement = pl
+
+ def getPoints(self,obj):
+ "returns the gridpoints"
+ def remdupes(pts):
+ # eliminate possible duplicates
+ ret = []
+ for p in pts:
+ if not p in ret:
+ ret.append(p)
+ return ret
+ if obj.PointsOutput == "Vertices":
+ return [v.Point for v in obj.Shape.Vertexes]
+ elif obj.PointsOutput == "Edges":
+ return remdupes([e.CenterOfMass for e in obj.Shape.Edges])
+ elif obj.PointsOutput == "Vertical Edges":
+ rv = obj.Placement.Rotation.multVec(FreeCAD.Vector(0,1,0))
+ edges = [e for e in obj.Shape.Edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
+ return remdupes([e.CenterOfMass for e in edges])
+ elif obj.PointsOutput == "Horizontal Edges":
+ rv = obj.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
+ edges = [e for e in obj.Shape.Edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
+ return remdupes([e.CenterOfMass for e in edges])
+ else:
+ return [f.CenterOfMass for f in obj.Shape.Faces]
+
+ def __getstate__(self):
+ return self.Type
+
+ def __setstate__(self,state):
+ if state:
+ self.Type = state
+
+
+class ViewProviderArchGrid:
+
+ "A View Provider for the Arch Grid"
+
+ def __init__(self,vobj):
+ vobj.Proxy = self
+
+ def getIcon(self):
+ import Arch_rc
+ return ":/icons/Arch_Grid.svg"
+
+ def setEdit(self,vobj,mode=0):
+ taskd = ArchGridTaskPanel(vobj.Object)
+ FreeCADGui.Control.showDialog(taskd)
+ return True
+
+ def unsetEdit(self,vobj,mode):
+ FreeCADGui.Control.closeDialog()
+ return
+
+ def doubleClicked(self,vobj):
+ self.setEdit(vobj)
+
+ def __getstate__(self):
+ return None
+
+ def __setstate__(self,state):
+ return None
+
+
+class ArchGridTaskPanel:
+
+ '''A TaskPanel for the Arch Grid'''
+
+ def __init__(self,obj):
+ # length, width, label
+ self.width = 0
+ self.height = 0
+ self.spans = []
+ self.obj = obj
+ self.form = QtGui.QWidget()
+ uil = FreeCADGui.UiLoader()
+ layout = QtGui.QVBoxLayout(self.form)
+ hbox3 = QtGui.QHBoxLayout()
+ layout.addLayout(hbox3)
+ self.wLabel = QtGui.QLabel(self.form)
+ hbox3.addWidget(self.wLabel)
+ self.widthUi = uil.createWidget("Gui::InputField")
+ hbox3.addWidget(self.widthUi)
+ hbox4 = QtGui.QHBoxLayout()
+ layout.addLayout(hbox4)
+ self.hLabel = QtGui.QLabel(self.form)
+ hbox4.addWidget(self.hLabel)
+ self.heightUi = uil.createWidget("Gui::InputField")
+ hbox4.addWidget(self.heightUi)
+ self.title = QtGui.QLabel(self.form)
+ layout.addWidget(self.title)
+
+ # grid
+ self.table = QtGui.QTableWidget(self.form)
+ layout.addWidget(self.table)
+ style = "QTableWidget { background-color: #ffffff; gridline-color: #000000; }"
+ self.table.setStyleSheet(style)
+ self.table.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
+
+ # row/column buttons
+ hbox1 = QtGui.QHBoxLayout()
+ layout.addLayout(hbox1)
+ self.addRowButton = QtGui.QPushButton(self.form)
+ self.addRowButton.setIcon(QtGui.QIcon(":/icons/Arch_Add.svg"))
+ hbox1.addWidget(self.addRowButton)
+ self.delRowButton = QtGui.QPushButton(self.form)
+ self.delRowButton.setIcon(QtGui.QIcon(":/icons/Arch_Remove.svg"))
+ hbox1.addWidget(self.delRowButton)
+ self.addColumnButton = QtGui.QPushButton(self.form)
+ self.addColumnButton.setIcon(QtGui.QIcon(":/icons/Arch_Add.svg"))
+ hbox1.addWidget(self.addColumnButton)
+ self.delColumnButton = QtGui.QPushButton(self.form)
+ self.delColumnButton.setIcon(QtGui.QIcon(":/icons/Arch_Remove.svg"))
+ hbox1.addWidget(self.delColumnButton)
+
+ # span buttons
+ import SpreadsheetGui
+ hbox2 = QtGui.QHBoxLayout()
+ layout.addLayout(hbox2)
+ self.spanButton = QtGui.QPushButton(self.form)
+ self.spanButton.setIcon(QtGui.QIcon(":/icons/SpreadsheetMergeCells.svg"))
+ hbox2.addWidget(self.spanButton)
+ self.spanButton.setEnabled(False)
+ self.delSpanButton = QtGui.QPushButton(self.form)
+ self.delSpanButton.setIcon(QtGui.QIcon(":/icons/SpreadsheetSplitCell.svg"))
+ hbox2.addWidget(self.delSpanButton)
+ self.delSpanButton.setEnabled(False)
+
+ #signals
+ QtCore.QObject.connect(self.widthUi,QtCore.SIGNAL("valueChanged(double)"),self.setWidth)
+ QtCore.QObject.connect(self.heightUi,QtCore.SIGNAL("valueChanged(double)"),self.setHeight)
+ QtCore.QObject.connect(self.table, QtCore.SIGNAL("itemSelectionChanged()"), self.checkSpan)
+ QtCore.QObject.connect(self.addRowButton, QtCore.SIGNAL("clicked()"), self.addRow)
+ QtCore.QObject.connect(self.delRowButton, QtCore.SIGNAL("clicked()"), self.delRow)
+ QtCore.QObject.connect(self.addColumnButton, QtCore.SIGNAL("clicked()"), self.addColumn)
+ QtCore.QObject.connect(self.delColumnButton, QtCore.SIGNAL("clicked()"), self.delColumn)
+ QtCore.QObject.connect(self.spanButton, QtCore.SIGNAL("clicked()"), self.addSpan)
+ QtCore.QObject.connect(self.delSpanButton, QtCore.SIGNAL("clicked()"), self.removeSpan)
+ QtCore.QObject.connect(self.table.horizontalHeader(),QtCore.SIGNAL("sectionDoubleClicked(int)"), self.editHorizontalHeader)
+ QtCore.QObject.connect(self.table.verticalHeader(),QtCore.SIGNAL("sectionDoubleClicked(int)"), self.editVerticalHeader)
+ self.update()
+ self.retranslateUi()
+
+ def retranslateUi(self,widget=None):
+ self.form.setWindowTitle(QtGui.QApplication.translate("Arch", "Grid", None))
+ self.wLabel.setText(QtGui.QApplication.translate("Arch", "Total width", None))
+ self.hLabel.setText(QtGui.QApplication.translate("Arch", "Total height", None))
+ self.addRowButton.setText(QtGui.QApplication.translate("Arch", "Add row", None))
+ self.delRowButton.setText(QtGui.QApplication.translate("Arch", "Del row", None))
+ self.addColumnButton.setText(QtGui.QApplication.translate("Arch", "Add col", None))
+ self.delColumnButton.setText(QtGui.QApplication.translate("Arch", "Del col", None))
+ self.spanButton.setText(QtGui.QApplication.translate("Arch", "Create span", None))
+ self.delSpanButton.setText(QtGui.QApplication.translate("Arch", "Remove span", None))
+ self.title.setText(QtGui.QApplication.translate("Arch", "Rows", None)+": "+str(self.table.rowCount())+" / "+QtGui.QApplication.translate("Arch", "Columns", None)+": "+str(self.table.columnCount()))
+
+ def update(self):
+ self.table.clear()
+ if self.obj.Rows:
+ self.table.setRowCount(self.obj.Rows)
+ vlabels = ["0" for i in range(self.obj.Rows)]
+ for i,v in enumerate(self.obj.RowSize):
+ if i < len(vlabels):
+ vlabels[i] = FreeCAD.Units.Quantity(v,FreeCAD.Units.Length).getUserPreferred()[0]
+ self.table.setVerticalHeaderLabels(vlabels)
+ if self.obj.Columns:
+ self.table.setColumnCount(self.obj.Columns)
+ hlabels = ["0" for i in range(self.obj.Columns)]
+ for i,v in enumerate(self.obj.ColumnSize):
+ if i < len(hlabels):
+ hlabels[i] = FreeCAD.Units.Quantity(v,FreeCAD.Units.Length).getUserPreferred()[0]
+ self.table.setHorizontalHeaderLabels(hlabels)
+ self.widthUi.setText(self.obj.Width.getUserPreferred()[0])
+ self.heightUi.setText(self.obj.Height.getUserPreferred()[0])
+ self.spans = []
+ for s in self.obj.Spans:
+ span = [int(i.strip()) for i in s.split(",")]
+ if len(span) == 4:
+ self.table.setSpan(span[0],span[1],span[2],span[3])
+ self.spans.append(span)
+
+ def checkSpan(self):
+ if self.table.selectedRanges():
+ self.spanButton.setEnabled(False)
+ self.delSpanButton.setEnabled(False)
+ if len(self.table.selectedRanges()) > 1:
+ self.spanButton.setEnabled(True)
+ for r in self.table.selectedRanges():
+ if (r.rowCount() * r.columnCount()) > 1:
+ self.spanButton.setEnabled(True)
+ elif (r.rowCount() * r.columnCount()) == 1:
+ if self.table.rowSpan(r.topRow(),r.leftColumn()) > 1 \
+ or self.table.columnSpan(r.topRow(),r.leftColumn()) > 1:
+ self.delSpanButton.setEnabled(True)
+ else:
+ self.spanButton.setEnabled(False)
+ self.delSpanButton.setEnabled(False)
+
+ def addRow(self):
+ c = self.table.currentRow()
+ self.table.insertRow(c+1)
+ self.table.setVerticalHeaderItem(c+1,QtGui.QTableWidgetItem("0"))
+ self.retranslateUi()
+
+ def delRow(self):
+ if self.table.selectedRanges():
+ self.table.removeRow(self.table.currentRow())
+ self.retranslateUi()
+
+ def addColumn(self):
+ c = self.table.currentColumn()
+ self.table.insertColumn(c+1)
+ self.table.setHorizontalHeaderItem(c+1,QtGui.QTableWidgetItem("0"))
+ self.retranslateUi()
+
+ def delColumn(self):
+ if self.table.selectedRanges():
+ self.table.removeColumn(self.table.currentColumn())
+ self.retranslateUi()
+
+ def addSpan(self):
+ for r in self.table.selectedRanges():
+ if r.rowCount() * r.columnCount() > 1:
+ self.table.setSpan(r.topRow(),r.leftColumn(),r.rowCount(),r.columnCount())
+ self.spans.append([r.topRow(),r.leftColumn(),r.rowCount(),r.columnCount()])
+ return
+ if len(self.table.selectedRanges()) > 1:
+ tr = 99999
+ br = 0
+ lc = 99999
+ rc = 0
+ for r in self.table.selectedRanges():
+ if r.topRow() < tr:
+ tr = r.topRow()
+ if r.bottomRow() > br:
+ br = r.bottomRow()
+ if r.leftColumn() < lc:
+ lc = r.leftColumn()
+ if r.rightColumn() > rc:
+ rc = r.rightColumn()
+ if (rc >= lc) and (br >= tr):
+ self.table.setSpan(tr,lc,(br-tr)+1,(rc-lc)+1)
+ self.spans.append([tr,lc,(br-tr)+1,(rc-lc)+1])
+
+ def removeSpan(self):
+ for r in self.table.selectedRanges():
+ if r.rowCount() * r.columnCount() == 1:
+ if self.table.rowSpan(r.topRow(),r.leftColumn()) > 1 \
+ or self.table.columnSpan(r.topRow(),r.leftColumn()) > 1:
+ self.table.setSpan(r.topRow(),r.leftColumn(),1,1)
+ f = None
+ for i,s in enumerate(self.spans):
+ if (s[0] == r.topRow()) and (s[1] == r.leftColumn()):
+ f = i
+ break
+ if f != None:
+ self.spans.pop(f)
+
+ def editHorizontalHeader(self, index):
+ val,ok = QtGui.QInputDialog.getText(None,'Edit size','New size')
+ if ok:
+ self.table.setHorizontalHeaderItem(index,QtGui.QTableWidgetItem(val))
+
+ def editVerticalHeader(self, index):
+ val,ok = QtGui.QInputDialog.getText(None,'Edit size','New size')
+ if ok:
+ self.table.setVerticalHeaderItem(index,QtGui.QTableWidgetItem(val))
+
+ def setWidth(self,d):
+ self.width = d
+
+ def setHeight(self,d):
+ self.height = d
+
+ def accept(self):
+ self.obj.Width = self.width
+ self.obj.Height = self.height
+ self.obj.Rows = self.table.rowCount()
+ self.obj.Columns = self.table.columnCount()
+ self.obj.RowSize = [FreeCAD.Units.Quantity(self.table.verticalHeaderItem(i).text()).Value for i in range(self.table.rowCount())]
+ self.obj.ColumnSize = [FreeCAD.Units.Quantity(self.table.horizontalHeaderItem(i).text()).Value for i in range(self.table.columnCount())]
+ self.obj.Spans = [str(s)[1:-1] for s in self.spans]
+ FreeCAD.ActiveDocument.recompute()
+ FreeCADGui.ActiveDocument.resetEdit()
+ return True
+
+ def reject(self):
+ FreeCADGui.ActiveDocument.resetEdit()
+ return True
+
+
+
+
+
if FreeCAD.GuiUp:
FreeCADGui.addCommand('Arch_Axis',_CommandAxis())
FreeCADGui.addCommand('Arch_AxisSystem',_CommandAxisSystem())
+ FreeCADGui.addCommand('Arch_Grid',CommandArchGrid())
class _ArchAxisGroupCommand:
def GetCommands(self):
- return tuple(['Arch_Axis','Arch_AxisSystem'])
+ return tuple(['Arch_Axis','Arch_AxisSystem','Arch_Grid'])
def GetResources(self):
return { 'MenuText': QT_TRANSLATE_NOOP("Arch_AxisTools",'Axis tools'),
'ToolTip': QT_TRANSLATE_NOOP("Arch_AxisTools",'Axis tools')
diff --git a/src/Mod/Arch/ArchFrame.py b/src/Mod/Arch/ArchFrame.py
index 36736adecd..90e0f03504 100644
--- a/src/Mod/Arch/ArchFrame.py
+++ b/src/Mod/Arch/ArchFrame.py
@@ -102,10 +102,13 @@ class _Frame(ArchComponent.Component):
obj.addProperty("App::PropertyInteger","BasePoint","Arch",QT_TRANSLATE_NOOP("App::Property","Crossing point of the path on the profile."))
obj.addProperty("App::PropertyPlacement","ProfilePlacement","Arch",QT_TRANSLATE_NOOP("App::Property","An optional additional placement to add to the profile before extruding it"))
obj.addProperty("App::PropertyAngle","Rotation","Arch",QT_TRANSLATE_NOOP("App::Property","The rotation of the profile around its extrusion axis"))
+ obj.addProperty("App::PropertyEnumeration","Edges","Arch",QT_TRANSLATE_NOOP("App::Property","The type of edges to consider"))
+ obj.addProperty("App::PropertyBool","Fuse","Arch",QT_TRANSLATE_NOOP("App::Property","If true, geometry is fused, otherwise a compound"))
self.Type = "Frame"
obj.Align = True
obj.Role = Roles
obj.Role = "Railing"
+ obj.Edges = ["All edges","Vertical edges","Horizontal edges","Bottom horizontal edges","Top horizontal edges"]
def execute(self,obj):
@@ -153,7 +156,27 @@ class _Frame(ArchComponent.Component):
shapes = []
normal = DraftGeomUtils.getNormal(obj.Base.Shape)
#for wire in obj.Base.Shape.Wires:
- for e in obj.Base.Shape.Edges:
+ edges = obj.Base.Shape.Edges
+ if hasattr(obj,"Edges"):
+ if obj.Edges == "Vertical edges":
+ rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(0,1,0))
+ edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
+ elif obj.Edges == "Horizontal edges":
+ rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
+ edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
+ elif obj.Edges == "Top Horizontal edges":
+ rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
+ edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
+ edges = sorted(edges,key=lambda x: x.CenterOfMass.z,reverse=True)
+ z = edges[0].CenterOfMass.z
+ edges = [e for e in edges if abs(e.CenterOfMass.z-z) < 0.00001]
+ elif obj.Edges == "Bottom Horizontal edges":
+ rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
+ edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
+ edges = sorted(edges,key=lambda x: x.CenterOfMass.z)
+ z = edges[0].CenterOfMass.z
+ edges = [e for e in edges if abs(e.CenterOfMass.z-z) < 0.00001]
+ for e in edges:
#e = wire.Edges[0]
bvec = DraftGeomUtils.vec(e)
bpoint = e.Vertexes[0].Point
@@ -189,6 +212,14 @@ class _Frame(ArchComponent.Component):
profile.translate(obj.Offset)
shapes.append(profile)
if shapes:
+ if hasattr(obj,"Fuse"):
+ if obj.Fuse:
+ if len(shapes) > 1:
+ s = shapes[0].multiFuse(shapes[1:])
+ s = s.removeSplitter()
+ obj.Shape = s
+ obj.Placement = pl
+ return
obj.Shape = Part.makeCompound(shapes)
obj.Placement = pl
diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py
index 37040b5032..a399043d21 100644
--- a/src/Mod/Arch/ArchWindow.py
+++ b/src/Mod/Arch/ArchWindow.py
@@ -420,7 +420,7 @@ class _CommandWindow:
FreeCADGui.draftToolBar.offUi()
obj = self.sel[0]
if obj.isDerivedFrom("Part::Feature"):
- if obj.Shape.Wires and not obj.Shape.Faces:
+ if obj.Shape.Wires and (not obj.Shape.Solids) and (not obj.Shape.Shells):
FreeCADGui.Control.closeDialog()
host = None
if hasattr(obj,"Support"):
@@ -650,8 +650,13 @@ class _Window(ArchComponent.Component):
obj.addProperty("App::PropertyLength","LouvreSpacing","Louvres",QT_TRANSLATE_NOOP("App::Property","the space between louvre elements"))
obj.addProperty("App::PropertyPercent","Opening","Arch",QT_TRANSLATE_NOOP("App::Property","Opens the subcomponents that have a hinge defined"))
obj.addProperty("App::PropertyInteger","HoleWire","Arch",QT_TRANSLATE_NOOP("App::Property","The number of the wire that defines the hole. A value of 0 means automatic"))
+ obj.addProperty("App::PropertyBool","SymbolPlan","Arch",QT_TRANSLATE_NOOP("App::Property","Shows plan opening symbols if available"))
+ obj.addProperty("App::PropertyBool","SymbolElevation","Arch",QT_TRANSLATE_NOOP("App::Property","Show elevation opening symbols if available"))
obj.setEditorMode("Preset",2)
obj.setEditorMode("WindowParts",2)
+ obj.setEditorMode("VerticalArea",2)
+ obj.setEditorMode("HorizontalArea",2)
+ obj.setEditorMode("PerimeterLength",2)
self.Type = "Window"
obj.Role = Roles
obj.Role = "Window"
@@ -752,7 +757,10 @@ class _Window(ArchComponent.Component):
e = obj.Base.Shape.Edges[hinge]
ev1 = e.Vertexes[0].Point
ev2 = e.Vertexes[-1].Point
- if ev2.z < ev1.z:
+ if (ev2.z - ev1.z) < 0.1**Draft.precision():
+ if ev2.y < ev1.y:
+ ev1,ev2 = ev2,ev1
+ elif ev2.z < ev1.z:
ev1,ev2 = ev2,ev1
p = None
d = 0
@@ -765,11 +773,10 @@ class _Window(ArchComponent.Component):
chord = p.sub(ev1)
enorm = ev2.sub(ev1)
proj = DraftVecUtils.project(chord,enorm)
+ v1 = ev1
if proj.Length > 0:
- v1 = ev1.add(proj)
- chord = p.sub(v1)
- else:
- v1 = ev1
+ chord = p.sub(ev1.add(proj))
+ p = v1.add(chord)
v4 = p.add(DraftVecUtils.scale(enorm,0.5))
if omode == 1: # Arc 90
v2 = v1.add(DraftVecUtils.rotate(chord,math.pi/4,enorm))
@@ -901,8 +908,22 @@ class _Window(ArchComponent.Component):
base = self.processSubShapes(obj,base)
if base:
if not base.isNull():
+ b = []
if self.sshapes:
- base = Part.makeCompound([base]+self.sshapes+self.vshapes)
+ if hasattr(obj,"SymbolPlan"):
+ if obj.SymbolPlan:
+ b.extend(self.sshapes)
+ else:
+ b.extend(self.sshapes)
+ if self.vshapes:
+ if hasattr(obj,"SymbolElevation"):
+ if obj.SymbolElevation:
+ b.extend(self.vshapes)
+ else:
+ b.extend(self.vshapes)
+ if b:
+ base = Part.makeCompound([base]+b)
+ #base = Part.makeCompound([base]+self.sshapes+self.vshapes)
self.applyShape(obj,base,pl,allowinvalid=True,allownosolid=True)
obj.Placement = pl
if hasattr(obj,"Area"):
@@ -987,6 +1008,9 @@ class _Window(ArchComponent.Component):
return f
return None
+ def computeAreas(self,obj):
+ return
+
class _ViewProviderWindow(ArchComponent.ViewProviderComponent):
"A View Provider for the Window object"
diff --git a/src/Mod/Arch/Resources/Arch.qrc b/src/Mod/Arch/Resources/Arch.qrc
index c5b5e36eb5..53db3eaf67 100644
--- a/src/Mod/Arch/Resources/Arch.qrc
+++ b/src/Mod/Arch/Resources/Arch.qrc
@@ -80,6 +80,7 @@
icons/Arch_PipeConnector.svg
icons/Arch_ToggleSubs.svg
icons/Arch_Nest.svg
+ icons/Arch_Grid.svg
ui/ParametersWindowDouble.svg
ui/ParametersWindowSimple.svg
ui/ParametersWindowFixed.svg
diff --git a/src/Mod/Arch/Resources/icons/Arch_Grid.svg b/src/Mod/Arch/Resources/icons/Arch_Grid.svg
new file mode 100644
index 0000000000..f613440359
--- /dev/null
+++ b/src/Mod/Arch/Resources/icons/Arch_Grid.svg
@@ -0,0 +1,410 @@
+
+
+
+