From 7383a80b5396b1ecfa5d49ae334be3839f4fa965 Mon Sep 17 00:00:00 2001 From: Dirk Olbrich Date: Wed, 19 Jan 2022 15:21:32 +0100 Subject: [PATCH] [Arch] split ArchAxis into separate modules - remove unused import from resulting ArchAxisSystem and ArchGrid - move inline imports to file import block --- src/Mod/Arch/Arch.py | 2 + src/Mod/Arch/ArchAxis.py | 858 +-------------------------------- src/Mod/Arch/ArchAxisSystem.py | 358 ++++++++++++++ src/Mod/Arch/ArchGrid.py | 563 +++++++++++++++++++++ src/Mod/Arch/CMakeLists.txt | 2 + 5 files changed, 933 insertions(+), 850 deletions(-) create mode 100644 src/Mod/Arch/ArchAxisSystem.py create mode 100644 src/Mod/Arch/ArchGrid.py diff --git a/src/Mod/Arch/Arch.py b/src/Mod/Arch/Arch.py index 0505e68305..d75197fd99 100644 --- a/src/Mod/Arch/Arch.py +++ b/src/Mod/Arch/Arch.py @@ -51,6 +51,8 @@ from ArchSectionPlane import * from ArchWindow import * from ArchWindowPresets import * from ArchAxis import * +from ArchAxisSystem import * +from ArchGrid import * from ArchRoof import * from ArchSpace import * from ArchStairs import * diff --git a/src/Mod/Arch/ArchAxis.py b/src/Mod/Arch/ArchAxis.py index dc810df891..c35013a17f 100644 --- a/src/Mod/Arch/ArchAxis.py +++ b/src/Mod/Arch/ArchAxis.py @@ -21,14 +21,17 @@ import six -import FreeCAD,Draft,math,ArchCommands +import FreeCAD, Part, Draft, math, ArchCommands from FreeCAD import Vector if FreeCAD.GuiUp: - import FreeCADGui + import FreeCADGui, re from PySide import QtCore, QtGui from DraftTools import translate from pivy import coin from PySide.QtCore import QT_TRANSLATE_NOOP + + from ArchAxisSystem import _CommandAxisSystem + from ArchGrid import CommandArchGrid else: # \cond def translate(ctxt,txt): @@ -43,10 +46,10 @@ __url__ = "https://www.freecadweb.org" ## @package ArchAxis # \ingroup ARCH -# \brief Axis system for the Arch workbench +# \brief Axis for the Arch workbench # -# This module provides tools to build axis systems -# An axis system is a collection of planar axes with a number/tag +# This module provides tools to build axis +# An axis is a collection of planar axes with a number/tag def makeAxis(num=5,size=1000,name="Axes"): @@ -77,36 +80,6 @@ def makeAxis(num=5,size=1000,name="Axes"): return obj -def makeAxisSystem(axes,name="Axis System"): - - '''makeAxisSystem(axes): makes a system from the given list of axes''' - - if not isinstance(axes,list): - axes = [axes] - obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","AxisSystem") - obj.Label = translate("Arch",name) - _AxisSystem(obj) - 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","Grid") - obj.Label = translate("Arch",name) - ArchGrid(obj) - if FreeCAD.GuiUp: - ViewProviderArchGrid(obj.ViewObject) - obj.ViewObject.Transparency = 85 - FreeCAD.ActiveDocument.recompute() - return obj - - class _CommandAxis: "the Arch Axis command definition" @@ -131,65 +104,6 @@ class _CommandAxis: return not FreeCAD.ActiveDocument is None -class _CommandAxisSystem: - - "the Arch Axis System command definition" - - def GetResources(self): - - return {'Pixmap' : 'Arch_Axis_System', - 'MenuText': QT_TRANSLATE_NOOP("Arch_AxisSystem","Axis System"), - 'Accel': "X, S", - 'ToolTip': QT_TRANSLATE_NOOP("Arch_AxisSystem","Creates an axis system from a set of axes")} - - def Activated(self): - - if FreeCADGui.Selection.getSelection(): - import Draft - s = "[" - for o in FreeCADGui.Selection.getSelection(): - if Draft.getType(o) != "Axis": - FreeCAD.Console.PrintError(translate("Arch","Only axes must be selected")+"\n") - return - s += "FreeCAD.ActiveDocument."+o.Name+"," - s += "]" - FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Axis System")) - FreeCADGui.addModule("Arch") - FreeCADGui.doCommand("Arch.makeAxisSystem("+s+")") - FreeCAD.ActiveDocument.commitTransaction() - else: - FreeCAD.Console.PrintError(translate("Arch","Please select at least one axis")+"\n") - - def IsActive(self): - - 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_Grid","Grid"), - 'Accel': "A, X", - 'ToolTip': QT_TRANSLATE_NOOP("Arch_Grid","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" @@ -229,7 +143,6 @@ class _Axis: def execute(self,obj): pl = obj.Placement - import Part geoms = [] dist = 0 if obj.Distances and obj.Length.Value: @@ -444,7 +357,6 @@ class _ViewProviderAxis: self.bubblestyle = coin.SoDrawStyle() self.bubblestyle.linePattern = 0xffff self.bubbles.addChild(self.bubblestyle) - import Part,Draft self.bubbletexts = [] self.bubbledata = [] pos = ["Start"] @@ -534,7 +446,6 @@ class _ViewProviderAxis: cin.setBuffer(buf) cob = coin.SoDB.readAll(cin) except Exception: - import re # workaround for pivy SoInput.setBuffer() bug buf = buf.replace("\n","") pts = re.findall("point \[(.*?)\]",buf)[0] @@ -612,7 +523,6 @@ class _ViewProviderAxis: for i in range(n): if len(vobj.Object.Labels) > i: if vobj.Object.Labels[i]: - import Draft vert = vobj.Object.Shape.Edges[i].Vertexes[0].Point if hasattr(vobj,"LabelOffset"): pl = FreeCAD.Placement(vobj.LabelOffset) @@ -731,8 +641,6 @@ class _ViewProviderAxis: return None - - class _AxisTaskPanel: '''The editmode TaskPanel for Axis objects''' @@ -877,756 +785,6 @@ class _AxisTaskPanel: QtGui.QApplication.translate("Arch", "Label", None)]) -class _AxisSystem: - - "The Axis System object" - - def __init__(self,obj): - - obj.Proxy = self - self.setProperties(obj) - - def setProperties(self,obj): - - pl = obj.PropertiesList - if not "Axes" in pl: - obj.addProperty("App::PropertyLinkList","Axes","AxisSystem", QT_TRANSLATE_NOOP("App::Property","The axes this system is made of")) - if not "Placement" in pl: - obj.addProperty("App::PropertyPlacement","Placement","AxisSystem",QT_TRANSLATE_NOOP("App::Property","The placement of this axis system")) - self.Type = "AxisSystem" - - def onDocumentRestored(self,obj): - - self.setProperties(obj) - - def execute(self,obj): - - pass - - def onBeforeChange(self,obj,prop): - - if prop == "Placement": - self.Placement = obj.Placement - - def onChanged(self,obj,prop): - - if prop == "Placement": - if hasattr(self,"Placement"): - delta = obj.Placement.multiply(self.Placement.inverse()) - for o in obj.Axes: - o.Placement = delta.multiply(o.Placement) - - def __getstate__(self): - - return None - - def __setstate__(self,state): - - return None - - def getPoints(self,obj): - - "returns the gridpoints of linked axes" - - import DraftGeomUtils - pts = [] - if len(obj.Axes) == 1: - for e in obj.Axes[0].Shape.Edges: - pts.append(e.Vertexes[0].Point) - elif len(obj.Axes) == 2: - set1 = obj.Axes[0].Shape.Edges # X - set2 = obj.Axes[1].Shape.Edges # Y - for e1 in set1: - for e2 in set2: - pts.extend(DraftGeomUtils.findIntersection(e1,e2)) - elif len(obj.Axes) == 3: - set1 = obj.Axes[0].Shape.Edges # X - set2 = obj.Axes[1].Shape.Edges # Y - set3 = obj.Axes[2].Shape.Edges # Z - bset = [] - cv = None - for e1 in set1: - for e2 in set2: - bset.extend(DraftGeomUtils.findIntersection(e1,e2)) - for e3 in set3: - if not cv: - cv = e3.Vertexes[0].Point - pts.extend(bset) - else: - v = e3.Vertexes[0].Point.sub(cv) - pts.extend([p.add(v) for p in bset]) - return pts - - def getAxisData(self,obj): - data = [] - for axis in obj.Axes: - if hasattr(axis,"Proxy") and hasattr(axis.Proxy,"getAxisData"): - data.append(axis.Proxy.getAxisData(axis)) - return data - - -class _ViewProviderAxisSystem: - - "A View Provider for the Axis object" - - def __init__(self,vobj): - - vobj.Proxy = self - - def getIcon(self): - - import Arch_rc - return ":/icons/Arch_Axis_System_Tree.svg" - - def claimChildren(self): - - if hasattr(self,"axes"): - return self.axes - return [] - - def attach(self, vobj): - - self.axes = vobj.Object.Axes - vobj.addDisplayMode(coin.SoSeparator(),"Default") - - def getDisplayModes(self,vobj): - - return ["Default"] - - def getDefaultDisplayMode(self): - - return "Default" - - def setDisplayMode(self,mode): - - return mode - - def updateData(self,obj,prop): - - self.axes = obj.Axes - - def onChanged(self, vobj, prop): - - if prop == "Visibility": - for o in vobj.Object.Axes: - o.ViewObject.Visibility = vobj.Visibility - - def setEdit(self,vobj,mode=0): - - taskd = AxisSystemTaskPanel(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 AxisSystemTaskPanel: - - '''A TaskPanel for all the section plane object''' - - def __init__(self,obj): - - self.obj = obj - self.form = QtGui.QWidget() - self.form.setObjectName("Axis System") - self.grid = QtGui.QGridLayout(self.form) - self.grid.setObjectName("grid") - self.title = QtGui.QLabel(self.form) - self.grid.addWidget(self.title, 0, 0, 1, 2) - - # tree - self.tree = QtGui.QTreeWidget(self.form) - self.grid.addWidget(self.tree, 1, 0, 1, 2) - self.tree.setColumnCount(1) - self.tree.header().hide() - - # buttons - self.addButton = QtGui.QPushButton(self.form) - self.addButton.setObjectName("addButton") - self.addButton.setIcon(QtGui.QIcon(":/icons/Arch_Add.svg")) - self.grid.addWidget(self.addButton, 3, 0, 1, 1) - - self.delButton = QtGui.QPushButton(self.form) - self.delButton.setObjectName("delButton") - self.delButton.setIcon(QtGui.QIcon(":/icons/Arch_Remove.svg")) - self.grid.addWidget(self.delButton, 3, 1, 1, 1) - - QtCore.QObject.connect(self.addButton, QtCore.SIGNAL("clicked()"), self.addElement) - QtCore.QObject.connect(self.delButton, QtCore.SIGNAL("clicked()"), self.removeElement) - self.update() - - def isAllowedAlterSelection(self): - - return True - - def isAllowedAlterView(self): - - return True - - def getStandardButtons(self): - - return int(QtGui.QDialogButtonBox.Ok) - - def getIcon(self,obj): - - if hasattr(obj.ViewObject,"Proxy"): - return QtGui.QIcon(obj.ViewObject.Proxy.getIcon()) - elif obj.isDerivedFrom("Sketcher::SketchObject"): - return QtGui.QIcon(":/icons/Sketcher_Sketch.svg") - elif obj.isDerivedFrom("App::DocumentObjectGroup"): - return QtGui.QApplication.style().standardIcon(QtGui.QStyle.SP_DirIcon) - elif hasattr(obj.ViewObject, "Icon"): - return QtGui.QIcon(obj.ViewObject.Icon) - return QtGui.QIcon(":/icons/Part_3D_object.svg") - - def update(self): - - self.tree.clear() - if self.obj: - for o in self.obj.Axes: - item = QtGui.QTreeWidgetItem(self.tree) - item.setText(0,o.Label) - item.setToolTip(0,o.Name) - item.setIcon(0,self.getIcon(o)) - self.retranslateUi(self.form) - - def addElement(self): - - if self.obj: - for o in FreeCADGui.Selection.getSelection(): - if (not(o in self.obj.Axes)) and (o != self.obj): - g = self.obj.Axes - g.append(o) - self.obj.Axes = g - self.update() - - def removeElement(self): - - if self.obj: - it = self.tree.currentItem() - if it: - o = FreeCAD.ActiveDocument.getObject(str(it.toolTip(0))) - if o in self.obj.Axes: - g = self.obj.Axes - g.remove(o) - self.obj.Axes = g - self.update() - - def accept(self): - - FreeCAD.ActiveDocument.recompute() - FreeCADGui.ActiveDocument.resetEdit() - return True - - def retranslateUi(self, TaskPanel): - - TaskPanel.setWindowTitle(QtGui.QApplication.translate("Arch", "Axes", None)) - self.delButton.setText(QtGui.QApplication.translate("Arch", "Remove", None)) - self.addButton.setText(QtGui.QApplication.translate("Arch", "Add", None)) - self.title.setText(QtGui.QApplication.translate("Arch", "Axis system components", None)) - - -class ArchGrid: - - "The Grid object" - - def __init__(self,obj): - - obj.Proxy = self - self.setProperties(obj) - - def setProperties(self,obj): - - pl = obj.PropertiesList - if not "Rows" in pl: - obj.addProperty("App::PropertyInteger","Rows","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The number of rows')) - if not "Columns" in pl: - obj.addProperty("App::PropertyInteger","Columns","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The number of columns')) - if not "RowSize" in pl: - obj.addProperty("App::PropertyFloatList","RowSize","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The sizes for rows')) - if not "ColumnSize" in pl: - obj.addProperty("App::PropertyFloatList","ColumnSize","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The sizes of columns')) - if not "Spans" in pl: - obj.addProperty("App::PropertyStringList","Spans","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The span ranges of cells that are merged together')) - if not "PointsOutput" in pl: - obj.addProperty("App::PropertyEnumeration","PointsOutput","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The type of 3D points produced by this grid object')) - obj.PointsOutput = ["Vertices","Edges","Vertical Edges","Horizontal Edges","Faces"] - if not "Width" in pl: - obj.addProperty("App::PropertyLength","Width","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The total width of this grid')) - if not "Height" in pl: - obj.addProperty("App::PropertyLength","Height","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The total height of this grid')) - if not "AutoWidth" in pl: - obj.addProperty("App::PropertyLength","AutoWidth","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'Creates automatic column divisions (set to 0 to disable)')) - if not "AutoHeight" in pl: - obj.addProperty("App::PropertyLength","AutoHeight","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'Creates automatic row divisions (set to 0 to disable)')) - if not "Reorient" in pl: - obj.addProperty("App::PropertyBool","Reorient","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'When in edge midpoint mode, if this grid must reorient its children along edge normals or not')) - if not "HiddenFaces" in pl: - obj.addProperty("App::PropertyIntegerList","HiddenFaces","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The indices of faces to hide')) - self.Type = "Grid" - - def onDocumentRestored(self,obj): - - self.setProperties(obj) - - 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 larger 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 larger 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 larger 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 larger 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 None - - def __setstate__(self,state): - - return None - - -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()) diff --git a/src/Mod/Arch/ArchAxisSystem.py b/src/Mod/Arch/ArchAxisSystem.py new file mode 100644 index 0000000000..e8bd28ee84 --- /dev/null +++ b/src/Mod/Arch/ArchAxisSystem.py @@ -0,0 +1,358 @@ +#*************************************************************************** +#* Copyright (c) 2011 Yorik van Havre * +#* * +#* This program is free software; you can redistribute it and/or modify * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* This program is distributed in the hope that it will be useful, * +#* but WITHOUT ANY WARRANTY; without even the implied warranty of * +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +#* GNU Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * +#* License along with this program; if not, write to the Free Software * +#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +#* USA * +#* * +#*************************************************************************** + +import FreeCAD, DraftGeomUtils +if FreeCAD.GuiUp: + import FreeCADGui, Draft + from PySide import QtCore, QtGui + from DraftTools import translate + from pivy import coin + from PySide.QtCore import QT_TRANSLATE_NOOP +else: + # \cond + def translate(ctxt,txt): + return txt + def QT_TRANSLATE_NOOP(ctxt,txt): + return txt + # \endcond + +__title__ = "FreeCAD Axis System" +__author__ = "Yorik van Havre" +__url__ = "https://www.freecadweb.org" + +## @package ArchAxisSystem +# \ingroup ARCH +# \brief Axis system for the Arch workbench +# +# This module provides tools to build axis systems +# An axis system is a collection of multiple axes + + +def makeAxisSystem(axes,name="Axis System"): + + '''makeAxisSystem(axes): makes a system from the given list of axes''' + + if not isinstance(axes,list): + axes = [axes] + obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","AxisSystem") + obj.Label = translate("Arch",name) + _AxisSystem(obj) + obj.Axes = axes + if FreeCAD.GuiUp: + _ViewProviderAxisSystem(obj.ViewObject) + FreeCAD.ActiveDocument.recompute() + return obj + + +class _CommandAxisSystem: + + "the Arch Axis System command definition" + + def GetResources(self): + + return {'Pixmap' : 'Arch_Axis_System', + 'MenuText': QT_TRANSLATE_NOOP("Arch_AxisSystem","Axis System"), + 'Accel': "X, S", + 'ToolTip': QT_TRANSLATE_NOOP("Arch_AxisSystem","Creates an axis system from a set of axes")} + + def Activated(self): + + if FreeCADGui.Selection.getSelection(): + s = "[" + for o in FreeCADGui.Selection.getSelection(): + if Draft.getType(o) != "Axis": + FreeCAD.Console.PrintError(translate("Arch","Only axes must be selected")+"\n") + return + s += "FreeCAD.ActiveDocument."+o.Name+"," + s += "]" + FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Axis System")) + FreeCADGui.addModule("Arch") + FreeCADGui.doCommand("Arch.makeAxisSystem("+s+")") + FreeCAD.ActiveDocument.commitTransaction() + else: + FreeCAD.Console.PrintError(translate("Arch","Please select at least one axis")+"\n") + + def IsActive(self): + + return not FreeCAD.ActiveDocument is None + + +class _AxisSystem: + + "The Axis System object" + + def __init__(self,obj): + + obj.Proxy = self + self.setProperties(obj) + + def setProperties(self,obj): + + pl = obj.PropertiesList + if not "Axes" in pl: + obj.addProperty("App::PropertyLinkList","Axes","AxisSystem", QT_TRANSLATE_NOOP("App::Property","The axes this system is made of")) + if not "Placement" in pl: + obj.addProperty("App::PropertyPlacement","Placement","AxisSystem",QT_TRANSLATE_NOOP("App::Property","The placement of this axis system")) + self.Type = "AxisSystem" + + def onDocumentRestored(self,obj): + + self.setProperties(obj) + + def execute(self,obj): + + pass + + def onBeforeChange(self,obj,prop): + + if prop == "Placement": + self.Placement = obj.Placement + + def onChanged(self,obj,prop): + + if prop == "Placement": + if hasattr(self,"Placement"): + delta = obj.Placement.multiply(self.Placement.inverse()) + for o in obj.Axes: + o.Placement = delta.multiply(o.Placement) + + def __getstate__(self): + + return None + + def __setstate__(self,state): + + return None + + def getPoints(self,obj): + + "returns the gridpoints of linked axes" + + pts = [] + if len(obj.Axes) == 1: + for e in obj.Axes[0].Shape.Edges: + pts.append(e.Vertexes[0].Point) + elif len(obj.Axes) == 2: + set1 = obj.Axes[0].Shape.Edges # X + set2 = obj.Axes[1].Shape.Edges # Y + for e1 in set1: + for e2 in set2: + pts.extend(DraftGeomUtils.findIntersection(e1,e2)) + elif len(obj.Axes) == 3: + set1 = obj.Axes[0].Shape.Edges # X + set2 = obj.Axes[1].Shape.Edges # Y + set3 = obj.Axes[2].Shape.Edges # Z + bset = [] + cv = None + for e1 in set1: + for e2 in set2: + bset.extend(DraftGeomUtils.findIntersection(e1,e2)) + for e3 in set3: + if not cv: + cv = e3.Vertexes[0].Point + pts.extend(bset) + else: + v = e3.Vertexes[0].Point.sub(cv) + pts.extend([p.add(v) for p in bset]) + return pts + + def getAxisData(self,obj): + data = [] + for axis in obj.Axes: + if hasattr(axis,"Proxy") and hasattr(axis.Proxy,"getAxisData"): + data.append(axis.Proxy.getAxisData(axis)) + return data + + +class _ViewProviderAxisSystem: + + "A View Provider for the Axis object" + + def __init__(self,vobj): + + vobj.Proxy = self + + def getIcon(self): + + import Arch_rc + return ":/icons/Arch_Axis_System_Tree.svg" + + def claimChildren(self): + + if hasattr(self,"axes"): + return self.axes + return [] + + def attach(self, vobj): + + self.axes = vobj.Object.Axes + vobj.addDisplayMode(coin.SoSeparator(),"Default") + + def getDisplayModes(self,vobj): + + return ["Default"] + + def getDefaultDisplayMode(self): + + return "Default" + + def setDisplayMode(self,mode): + + return mode + + def updateData(self,obj,prop): + + self.axes = obj.Axes + + def onChanged(self, vobj, prop): + + if prop == "Visibility": + for o in vobj.Object.Axes: + o.ViewObject.Visibility = vobj.Visibility + + def setEdit(self,vobj,mode=0): + + taskd = AxisSystemTaskPanel(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 AxisSystemTaskPanel: + + '''A TaskPanel for all the section plane object''' + + def __init__(self,obj): + + self.obj = obj + self.form = QtGui.QWidget() + self.form.setObjectName("Axis System") + self.grid = QtGui.QGridLayout(self.form) + self.grid.setObjectName("grid") + self.title = QtGui.QLabel(self.form) + self.grid.addWidget(self.title, 0, 0, 1, 2) + + # tree + self.tree = QtGui.QTreeWidget(self.form) + self.grid.addWidget(self.tree, 1, 0, 1, 2) + self.tree.setColumnCount(1) + self.tree.header().hide() + + # buttons + self.addButton = QtGui.QPushButton(self.form) + self.addButton.setObjectName("addButton") + self.addButton.setIcon(QtGui.QIcon(":/icons/Arch_Add.svg")) + self.grid.addWidget(self.addButton, 3, 0, 1, 1) + + self.delButton = QtGui.QPushButton(self.form) + self.delButton.setObjectName("delButton") + self.delButton.setIcon(QtGui.QIcon(":/icons/Arch_Remove.svg")) + self.grid.addWidget(self.delButton, 3, 1, 1, 1) + + QtCore.QObject.connect(self.addButton, QtCore.SIGNAL("clicked()"), self.addElement) + QtCore.QObject.connect(self.delButton, QtCore.SIGNAL("clicked()"), self.removeElement) + self.update() + + def isAllowedAlterSelection(self): + + return True + + def isAllowedAlterView(self): + + return True + + def getStandardButtons(self): + + return int(QtGui.QDialogButtonBox.Ok) + + def getIcon(self,obj): + + if hasattr(obj.ViewObject,"Proxy"): + return QtGui.QIcon(obj.ViewObject.Proxy.getIcon()) + elif obj.isDerivedFrom("Sketcher::SketchObject"): + return QtGui.QIcon(":/icons/Sketcher_Sketch.svg") + elif obj.isDerivedFrom("App::DocumentObjectGroup"): + return QtGui.QApplication.style().standardIcon(QtGui.QStyle.SP_DirIcon) + elif hasattr(obj.ViewObject, "Icon"): + return QtGui.QIcon(obj.ViewObject.Icon) + return QtGui.QIcon(":/icons/Part_3D_object.svg") + + def update(self): + + self.tree.clear() + if self.obj: + for o in self.obj.Axes: + item = QtGui.QTreeWidgetItem(self.tree) + item.setText(0,o.Label) + item.setToolTip(0,o.Name) + item.setIcon(0,self.getIcon(o)) + self.retranslateUi(self.form) + + def addElement(self): + + if self.obj: + for o in FreeCADGui.Selection.getSelection(): + if (not(o in self.obj.Axes)) and (o != self.obj): + g = self.obj.Axes + g.append(o) + self.obj.Axes = g + self.update() + + def removeElement(self): + + if self.obj: + it = self.tree.currentItem() + if it: + o = FreeCAD.ActiveDocument.getObject(str(it.toolTip(0))) + if o in self.obj.Axes: + g = self.obj.Axes + g.remove(o) + self.obj.Axes = g + self.update() + + def accept(self): + + FreeCAD.ActiveDocument.recompute() + FreeCADGui.ActiveDocument.resetEdit() + return True + + def retranslateUi(self, TaskPanel): + + TaskPanel.setWindowTitle(QtGui.QApplication.translate("Arch", "Axes", None)) + self.delButton.setText(QtGui.QApplication.translate("Arch", "Remove", None)) + self.addButton.setText(QtGui.QApplication.translate("Arch", "Add", None)) + self.title.setText(QtGui.QApplication.translate("Arch", "Axis system components", None)) diff --git a/src/Mod/Arch/ArchGrid.py b/src/Mod/Arch/ArchGrid.py new file mode 100644 index 0000000000..28cc17dd28 --- /dev/null +++ b/src/Mod/Arch/ArchGrid.py @@ -0,0 +1,563 @@ +#*************************************************************************** +#* Copyright (c) 2011 Yorik van Havre * +#* * +#* This program is free software; you can redistribute it and/or modify * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* This program is distributed in the hope that it will be useful, * +#* but WITHOUT ANY WARRANTY; without even the implied warranty of * +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +#* GNU Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * +#* License along with this program; if not, write to the Free Software * +#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +#* USA * +#* * +#*************************************************************************** + +import FreeCAD, Part, math +if FreeCAD.GuiUp: + import FreeCADGui + from PySide import QtCore, QtGui + from DraftTools import translate + from PySide.QtCore import QT_TRANSLATE_NOOP +else: + # \cond + def translate(ctxt,txt): + return txt + def QT_TRANSLATE_NOOP(ctxt,txt): + return txt + # \endcond + +__title__ = "FreeCAD Axis System" +__author__ = "Yorik van Havre" +__url__ = "https://www.freecadweb.org" + +## @package ArchGrid +# \ingroup ARCH +# \brief Grid system for the Arch workbench +# +# This module provides tools to build grid systems + + +def makeGrid(name="Grid"): + + '''makeGrid(): makes a grid object''' + + obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Grid") + obj.Label = translate("Arch",name) + ArchGrid(obj) + if FreeCAD.GuiUp: + ViewProviderArchGrid(obj.ViewObject) + obj.ViewObject.Transparency = 85 + FreeCAD.ActiveDocument.recompute() + return obj + + +class CommandArchGrid: + + "the Arch Grid command definition" + + def GetResources(self): + + return {'Pixmap' : 'Arch_Grid', + 'MenuText': QT_TRANSLATE_NOOP("Arch_Grid","Grid"), + 'Accel': "A, X", + 'ToolTip': QT_TRANSLATE_NOOP("Arch_Grid","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 ArchGrid: + + "The Grid object" + + def __init__(self,obj): + + obj.Proxy = self + self.setProperties(obj) + + def setProperties(self,obj): + + pl = obj.PropertiesList + if not "Rows" in pl: + obj.addProperty("App::PropertyInteger","Rows","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The number of rows')) + if not "Columns" in pl: + obj.addProperty("App::PropertyInteger","Columns","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The number of columns')) + if not "RowSize" in pl: + obj.addProperty("App::PropertyFloatList","RowSize","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The sizes for rows')) + if not "ColumnSize" in pl: + obj.addProperty("App::PropertyFloatList","ColumnSize","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The sizes of columns')) + if not "Spans" in pl: + obj.addProperty("App::PropertyStringList","Spans","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The span ranges of cells that are merged together')) + if not "PointsOutput" in pl: + obj.addProperty("App::PropertyEnumeration","PointsOutput","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The type of 3D points produced by this grid object')) + obj.PointsOutput = ["Vertices","Edges","Vertical Edges","Horizontal Edges","Faces"] + if not "Width" in pl: + obj.addProperty("App::PropertyLength","Width","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The total width of this grid')) + if not "Height" in pl: + obj.addProperty("App::PropertyLength","Height","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The total height of this grid')) + if not "AutoWidth" in pl: + obj.addProperty("App::PropertyLength","AutoWidth","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'Creates automatic column divisions (set to 0 to disable)')) + if not "AutoHeight" in pl: + obj.addProperty("App::PropertyLength","AutoHeight","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'Creates automatic row divisions (set to 0 to disable)')) + if not "Reorient" in pl: + obj.addProperty("App::PropertyBool","Reorient","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'When in edge midpoint mode, if this grid must reorient its children along edge normals or not')) + if not "HiddenFaces" in pl: + obj.addProperty("App::PropertyIntegerList","HiddenFaces","Grid",QT_TRANSLATE_NOOP("Arch_Grid",'The indices of faces to hide')) + self.Type = "Grid" + + def onDocumentRestored(self,obj): + + self.setProperties(obj) + + 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 larger 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 larger 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 larger 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 larger 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 + 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 None + + def __setstate__(self,state): + + return None + + +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 + 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 diff --git a/src/Mod/Arch/CMakeLists.txt b/src/Mod/Arch/CMakeLists.txt index b12846a045..bb81f96930 100644 --- a/src/Mod/Arch/CMakeLists.txt +++ b/src/Mod/Arch/CMakeLists.txt @@ -28,6 +28,8 @@ SET(Arch_SRCS ArchWindow.py ArchWindowPresets.py ArchAxis.py + ArchAxisSystem.py + ArchGrid.py ArchVRM.py ArchRoof.py ArchStairs.py