[Arch] split ArchAxis into separate modules

- remove unused import from resulting ArchAxisSystem and ArchGrid
- move inline imports to file import block
This commit is contained in:
Dirk Olbrich
2022-01-19 15:21:32 +01:00
parent c950d3779d
commit 7383a80b53
5 changed files with 933 additions and 850 deletions

View File

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

View File

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

View File

@@ -0,0 +1,358 @@
#***************************************************************************
#* Copyright (c) 2011 Yorik van Havre <yorik@uncreated.net> *
#* *
#* 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))

563
src/Mod/Arch/ArchGrid.py Normal file
View File

@@ -0,0 +1,563 @@
#***************************************************************************
#* Copyright (c) 2011 Yorik van Havre <yorik@uncreated.net> *
#* *
#* 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

View File

@@ -28,6 +28,8 @@ SET(Arch_SRCS
ArchWindow.py
ArchWindowPresets.py
ArchAxis.py
ArchAxisSystem.py
ArchGrid.py
ArchVRM.py
ArchRoof.py
ArchStairs.py