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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + [yorikvanhavre] + + + Arch_Axis + 2011-12-12 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/Arch/Resources/icons/Arch_Axis.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +