Arch: Grid command

This commit is contained in:
Yorik van Havre
2017-08-30 23:11:47 -03:00
parent 6e7952ec67
commit 69c7b35a67
5 changed files with 945 additions and 9 deletions

View File

@@ -79,6 +79,20 @@ def makeAxisSystem(axes,name="Axis System"):
obj.Axes = axes
if FreeCAD.GuiUp:
_ViewProviderAxisSystem(obj.ViewObject)
FreeCAD.ActiveDocument.recompute()
return obj
def makeGrid(name="Grid"):
'''makeGrid(): makes a grid object'''
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name)
obj.Label = translate("Arch",name)
ArchGrid(obj)
if FreeCAD.GuiUp:
ViewProviderArchGrid(obj.ViewObject)
obj.ViewObject.Transparency = 85
FreeCAD.ActiveDocument.recompute()
return obj
class _CommandAxis:
@@ -129,6 +143,26 @@ class _CommandAxisSystem:
return not FreeCAD.ActiveDocument is None
class CommandArchGrid:
"the Arch Grid command definition"
def GetResources(self):
return {'Pixmap' : 'Arch_Grid',
'MenuText': QT_TRANSLATE_NOOP("Arch_Axis","Grid"),
'Accel': "A, X",
'ToolTip': QT_TRANSLATE_NOOP("Arch_Axis","Creates a customizable grid object")}
def Activated(self):
FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Grid"))
FreeCADGui.addModule("Arch")
FreeCADGui.doCommand("Arch.makeGrid()")
FreeCAD.ActiveDocument.commitTransaction()
def IsActive(self):
return not FreeCAD.ActiveDocument is None
class _Axis:
"The Axis object"
def __init__(self,obj):
@@ -835,14 +869,450 @@ class AxisSystemTaskPanel:
self.title.setText(QtGui.QApplication.translate("Arch", "Axis system components", None))
class ArchGrid:
"The Grid object"
def __init__(self,obj):
obj.addProperty("App::PropertyInteger","Rows","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The number of rows'))
obj.addProperty("App::PropertyInteger","Columns","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The number of columns'))
obj.addProperty("App::PropertyFloatList","RowSize","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The sizes for rows'))
obj.addProperty("App::PropertyFloatList","ColumnSize","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The sizes of columns'))
obj.addProperty("App::PropertyStringList","Spans","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The span ranges of cells that are merged together'))
obj.addProperty("App::PropertyEnumeration","PointsOutput","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The type of 3D points produced by this grid object'))
obj.addProperty("App::PropertyLength","Width","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The total width of this grid'))
obj.addProperty("App::PropertyLength","Height","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The total height of this grid'))
obj.addProperty("App::PropertyLength","AutoWidth","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'Creates automatic column divisions (set to 0 to disable)'))
obj.addProperty("App::PropertyLength","AutoHeight","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'Creates automatic row divisions (set to 0 to disable)'))
obj.addProperty("App::PropertyBool","Reorient","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'When in edge midpoint mode, if this grid must reorient its children along edge normals or not'))
obj.addProperty("App::PropertyIntegerList","HiddenFaces","Arch",QT_TRANSLATE_NOOP("Arch_Grid",'The indices of faces to hide'))
obj.PointsOutput = ["Vertices","Edges","Vertical Edges","Horizontal Edges","Faces"]
self.Type = "Grid"
obj.Proxy = self
def getSizes(self,obj):
"returns rowsizes,columnsizes,spangroups"
if not obj.Height.Value:
return [],[],[]
if not obj.Width.Value:
return [],[],[]
if (not obj.Rows) and (not obj.AutoHeight.Value):
return [],[],[]
if (not obj.Columns) and (not obj.AutoWidth.Value):
return [],[],[]
# rescale rows
rowsizes = []
if obj.AutoHeight.Value:
if obj.AutoHeight.Value > obj.Height.Value:
FreeCAD.Console.PrintError(translate("Arch","Auto height is bigger than height"))
return [],[],[]
rows = int(math.floor(obj.Height.Value/obj.AutoHeight.Value))
for i in range(rows):
rowsizes.append(obj.AutoHeight.Value)
rowsizes.append(obj.Height.Value-rows*obj.AutoHeight.Value)
else:
reserved_rowsize = sum(v for v in obj.RowSize)
if reserved_rowsize > obj.Height.Value:
FreeCAD.Console.PrintError(translate("Arch","Total row size is bigger than height"))
return [],[],[]
for i in range(obj.Rows):
v = 0
if i < len(obj.RowSize):
v = obj.RowSize[i]
rowsizes.append(v)
e = len([v for v in rowsizes if v == 0])
default = obj.Height.Value - reserved_rowsize
if e:
default = default / e
t = []
for v in rowsizes:
if v:
t.append(v)
else:
t.append(default)
rowsizes = t
# rescale columns
columnsizes = []
if obj.AutoWidth.Value:
if obj.AutoWidth.Value > obj.Width.Value:
FreeCAD.Console.PrintError(translate("Arch","Auto width is bigger than width"))
return [],[],[]
cols = int(math.floor(obj.Width.Value/obj.AutoWidth.Value))
for i in range(cols):
columnsizes.append(obj.AutoWidth.Value)
columnsizes.append(obj.Width.Value-cols*obj.AutoWidth.Value)
else:
reserved_columnsize = sum(v for v in obj.ColumnSize)
if reserved_columnsize > obj.Width.Value:
FreeCAD.Console.PrintError(translate("Arch","Total column size is bigger than width"))
return [],[],[]
for i in range(obj.Columns):
v = 0
if i < len(obj.ColumnSize):
v = obj.ColumnSize[i]
columnsizes.append(v)
e = len([v for v in columnsizes if v == 0])
default = obj.Width.Value - reserved_columnsize
if e:
default = default / e
t = []
for v in columnsizes:
if v:
t.append(v)
else:
t.append(default)
columnsizes = t
# format span groups from [row,col,rowspan,colspan] to [faceindexes]
spangroups = []
for s in obj.Spans:
nspan = []
span = [int(i.strip()) for i in s.split(",")]
for row in range(span[2]):
for column in range(span[3]):
nspan.append((span[0]+row)*obj.Columns + (span[1]+column))
spangroups.append(nspan)
return rowsizes,columnsizes,spangroups
def execute(self,obj):
pl = obj.Placement
import Part
rowsizes,columnsizes,spangroups = self.getSizes(obj)
#print rowsizes,columnsizes,spangroups
# create one face for each cell
faces = []
facenumber = 0
rowoffset = 0
for row in rowsizes:
columnoffset = 0
for column in columnsizes:
v1 = FreeCAD.Vector(columnoffset,rowoffset,0)
v2 = v1.add(FreeCAD.Vector(column,0,0))
v3 = v2.add(FreeCAD.Vector(0,-row,0))
v4 = v3.add(FreeCAD.Vector(-column,0,0))
f = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1]))
if not facenumber in obj.HiddenFaces:
spanning = False
for i in range(len(spangroups)):
if facenumber in spangroups[i]:
g = spangroups[i]
g[g.index(facenumber)] = f
spangroups[i] = g
spanning = True
break
if not spanning:
faces.append(f)
facenumber += 1
columnoffset += column
rowoffset -= row
# join spangroups
for g in spangroups:
s = Part.makeShell(g)
s = s.removeSplitter()
faces.extend(s.Faces)
if faces:
obj.Shape = Part.makeCompound(faces)
obj.Placement = pl
def getPoints(self,obj):
"returns the gridpoints"
def remdupes(pts):
# eliminate possible duplicates
ret = []
for p in pts:
if not p in ret:
ret.append(p)
return ret
if obj.PointsOutput == "Vertices":
return [v.Point for v in obj.Shape.Vertexes]
elif obj.PointsOutput == "Edges":
return remdupes([e.CenterOfMass for e in obj.Shape.Edges])
elif obj.PointsOutput == "Vertical Edges":
rv = obj.Placement.Rotation.multVec(FreeCAD.Vector(0,1,0))
edges = [e for e in obj.Shape.Edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
return remdupes([e.CenterOfMass for e in edges])
elif obj.PointsOutput == "Horizontal Edges":
rv = obj.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
edges = [e for e in obj.Shape.Edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
return remdupes([e.CenterOfMass for e in edges])
else:
return [f.CenterOfMass for f in obj.Shape.Faces]
def __getstate__(self):
return self.Type
def __setstate__(self,state):
if state:
self.Type = state
class ViewProviderArchGrid:
"A View Provider for the Arch Grid"
def __init__(self,vobj):
vobj.Proxy = self
def getIcon(self):
import Arch_rc
return ":/icons/Arch_Grid.svg"
def setEdit(self,vobj,mode=0):
taskd = ArchGridTaskPanel(vobj.Object)
FreeCADGui.Control.showDialog(taskd)
return True
def unsetEdit(self,vobj,mode):
FreeCADGui.Control.closeDialog()
return
def doubleClicked(self,vobj):
self.setEdit(vobj)
def __getstate__(self):
return None
def __setstate__(self,state):
return None
class ArchGridTaskPanel:
'''A TaskPanel for the Arch Grid'''
def __init__(self,obj):
# length, width, label
self.width = 0
self.height = 0
self.spans = []
self.obj = obj
self.form = QtGui.QWidget()
uil = FreeCADGui.UiLoader()
layout = QtGui.QVBoxLayout(self.form)
hbox3 = QtGui.QHBoxLayout()
layout.addLayout(hbox3)
self.wLabel = QtGui.QLabel(self.form)
hbox3.addWidget(self.wLabel)
self.widthUi = uil.createWidget("Gui::InputField")
hbox3.addWidget(self.widthUi)
hbox4 = QtGui.QHBoxLayout()
layout.addLayout(hbox4)
self.hLabel = QtGui.QLabel(self.form)
hbox4.addWidget(self.hLabel)
self.heightUi = uil.createWidget("Gui::InputField")
hbox4.addWidget(self.heightUi)
self.title = QtGui.QLabel(self.form)
layout.addWidget(self.title)
# grid
self.table = QtGui.QTableWidget(self.form)
layout.addWidget(self.table)
style = "QTableWidget { background-color: #ffffff; gridline-color: #000000; }"
self.table.setStyleSheet(style)
self.table.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
# row/column buttons
hbox1 = QtGui.QHBoxLayout()
layout.addLayout(hbox1)
self.addRowButton = QtGui.QPushButton(self.form)
self.addRowButton.setIcon(QtGui.QIcon(":/icons/Arch_Add.svg"))
hbox1.addWidget(self.addRowButton)
self.delRowButton = QtGui.QPushButton(self.form)
self.delRowButton.setIcon(QtGui.QIcon(":/icons/Arch_Remove.svg"))
hbox1.addWidget(self.delRowButton)
self.addColumnButton = QtGui.QPushButton(self.form)
self.addColumnButton.setIcon(QtGui.QIcon(":/icons/Arch_Add.svg"))
hbox1.addWidget(self.addColumnButton)
self.delColumnButton = QtGui.QPushButton(self.form)
self.delColumnButton.setIcon(QtGui.QIcon(":/icons/Arch_Remove.svg"))
hbox1.addWidget(self.delColumnButton)
# span buttons
import SpreadsheetGui
hbox2 = QtGui.QHBoxLayout()
layout.addLayout(hbox2)
self.spanButton = QtGui.QPushButton(self.form)
self.spanButton.setIcon(QtGui.QIcon(":/icons/SpreadsheetMergeCells.svg"))
hbox2.addWidget(self.spanButton)
self.spanButton.setEnabled(False)
self.delSpanButton = QtGui.QPushButton(self.form)
self.delSpanButton.setIcon(QtGui.QIcon(":/icons/SpreadsheetSplitCell.svg"))
hbox2.addWidget(self.delSpanButton)
self.delSpanButton.setEnabled(False)
#signals
QtCore.QObject.connect(self.widthUi,QtCore.SIGNAL("valueChanged(double)"),self.setWidth)
QtCore.QObject.connect(self.heightUi,QtCore.SIGNAL("valueChanged(double)"),self.setHeight)
QtCore.QObject.connect(self.table, QtCore.SIGNAL("itemSelectionChanged()"), self.checkSpan)
QtCore.QObject.connect(self.addRowButton, QtCore.SIGNAL("clicked()"), self.addRow)
QtCore.QObject.connect(self.delRowButton, QtCore.SIGNAL("clicked()"), self.delRow)
QtCore.QObject.connect(self.addColumnButton, QtCore.SIGNAL("clicked()"), self.addColumn)
QtCore.QObject.connect(self.delColumnButton, QtCore.SIGNAL("clicked()"), self.delColumn)
QtCore.QObject.connect(self.spanButton, QtCore.SIGNAL("clicked()"), self.addSpan)
QtCore.QObject.connect(self.delSpanButton, QtCore.SIGNAL("clicked()"), self.removeSpan)
QtCore.QObject.connect(self.table.horizontalHeader(),QtCore.SIGNAL("sectionDoubleClicked(int)"), self.editHorizontalHeader)
QtCore.QObject.connect(self.table.verticalHeader(),QtCore.SIGNAL("sectionDoubleClicked(int)"), self.editVerticalHeader)
self.update()
self.retranslateUi()
def retranslateUi(self,widget=None):
self.form.setWindowTitle(QtGui.QApplication.translate("Arch", "Grid", None))
self.wLabel.setText(QtGui.QApplication.translate("Arch", "Total width", None))
self.hLabel.setText(QtGui.QApplication.translate("Arch", "Total height", None))
self.addRowButton.setText(QtGui.QApplication.translate("Arch", "Add row", None))
self.delRowButton.setText(QtGui.QApplication.translate("Arch", "Del row", None))
self.addColumnButton.setText(QtGui.QApplication.translate("Arch", "Add col", None))
self.delColumnButton.setText(QtGui.QApplication.translate("Arch", "Del col", None))
self.spanButton.setText(QtGui.QApplication.translate("Arch", "Create span", None))
self.delSpanButton.setText(QtGui.QApplication.translate("Arch", "Remove span", None))
self.title.setText(QtGui.QApplication.translate("Arch", "Rows", None)+": "+str(self.table.rowCount())+" / "+QtGui.QApplication.translate("Arch", "Columns", None)+": "+str(self.table.columnCount()))
def update(self):
self.table.clear()
if self.obj.Rows:
self.table.setRowCount(self.obj.Rows)
vlabels = ["0" for i in range(self.obj.Rows)]
for i,v in enumerate(self.obj.RowSize):
if i < len(vlabels):
vlabels[i] = FreeCAD.Units.Quantity(v,FreeCAD.Units.Length).getUserPreferred()[0]
self.table.setVerticalHeaderLabels(vlabels)
if self.obj.Columns:
self.table.setColumnCount(self.obj.Columns)
hlabels = ["0" for i in range(self.obj.Columns)]
for i,v in enumerate(self.obj.ColumnSize):
if i < len(hlabels):
hlabels[i] = FreeCAD.Units.Quantity(v,FreeCAD.Units.Length).getUserPreferred()[0]
self.table.setHorizontalHeaderLabels(hlabels)
self.widthUi.setText(self.obj.Width.getUserPreferred()[0])
self.heightUi.setText(self.obj.Height.getUserPreferred()[0])
self.spans = []
for s in self.obj.Spans:
span = [int(i.strip()) for i in s.split(",")]
if len(span) == 4:
self.table.setSpan(span[0],span[1],span[2],span[3])
self.spans.append(span)
def checkSpan(self):
if self.table.selectedRanges():
self.spanButton.setEnabled(False)
self.delSpanButton.setEnabled(False)
if len(self.table.selectedRanges()) > 1:
self.spanButton.setEnabled(True)
for r in self.table.selectedRanges():
if (r.rowCount() * r.columnCount()) > 1:
self.spanButton.setEnabled(True)
elif (r.rowCount() * r.columnCount()) == 1:
if self.table.rowSpan(r.topRow(),r.leftColumn()) > 1 \
or self.table.columnSpan(r.topRow(),r.leftColumn()) > 1:
self.delSpanButton.setEnabled(True)
else:
self.spanButton.setEnabled(False)
self.delSpanButton.setEnabled(False)
def addRow(self):
c = self.table.currentRow()
self.table.insertRow(c+1)
self.table.setVerticalHeaderItem(c+1,QtGui.QTableWidgetItem("0"))
self.retranslateUi()
def delRow(self):
if self.table.selectedRanges():
self.table.removeRow(self.table.currentRow())
self.retranslateUi()
def addColumn(self):
c = self.table.currentColumn()
self.table.insertColumn(c+1)
self.table.setHorizontalHeaderItem(c+1,QtGui.QTableWidgetItem("0"))
self.retranslateUi()
def delColumn(self):
if self.table.selectedRanges():
self.table.removeColumn(self.table.currentColumn())
self.retranslateUi()
def addSpan(self):
for r in self.table.selectedRanges():
if r.rowCount() * r.columnCount() > 1:
self.table.setSpan(r.topRow(),r.leftColumn(),r.rowCount(),r.columnCount())
self.spans.append([r.topRow(),r.leftColumn(),r.rowCount(),r.columnCount()])
return
if len(self.table.selectedRanges()) > 1:
tr = 99999
br = 0
lc = 99999
rc = 0
for r in self.table.selectedRanges():
if r.topRow() < tr:
tr = r.topRow()
if r.bottomRow() > br:
br = r.bottomRow()
if r.leftColumn() < lc:
lc = r.leftColumn()
if r.rightColumn() > rc:
rc = r.rightColumn()
if (rc >= lc) and (br >= tr):
self.table.setSpan(tr,lc,(br-tr)+1,(rc-lc)+1)
self.spans.append([tr,lc,(br-tr)+1,(rc-lc)+1])
def removeSpan(self):
for r in self.table.selectedRanges():
if r.rowCount() * r.columnCount() == 1:
if self.table.rowSpan(r.topRow(),r.leftColumn()) > 1 \
or self.table.columnSpan(r.topRow(),r.leftColumn()) > 1:
self.table.setSpan(r.topRow(),r.leftColumn(),1,1)
f = None
for i,s in enumerate(self.spans):
if (s[0] == r.topRow()) and (s[1] == r.leftColumn()):
f = i
break
if f != None:
self.spans.pop(f)
def editHorizontalHeader(self, index):
val,ok = QtGui.QInputDialog.getText(None,'Edit size','New size')
if ok:
self.table.setHorizontalHeaderItem(index,QtGui.QTableWidgetItem(val))
def editVerticalHeader(self, index):
val,ok = QtGui.QInputDialog.getText(None,'Edit size','New size')
if ok:
self.table.setVerticalHeaderItem(index,QtGui.QTableWidgetItem(val))
def setWidth(self,d):
self.width = d
def setHeight(self,d):
self.height = d
def accept(self):
self.obj.Width = self.width
self.obj.Height = self.height
self.obj.Rows = self.table.rowCount()
self.obj.Columns = self.table.columnCount()
self.obj.RowSize = [FreeCAD.Units.Quantity(self.table.verticalHeaderItem(i).text()).Value for i in range(self.table.rowCount())]
self.obj.ColumnSize = [FreeCAD.Units.Quantity(self.table.horizontalHeaderItem(i).text()).Value for i in range(self.table.columnCount())]
self.obj.Spans = [str(s)[1:-1] for s in self.spans]
FreeCAD.ActiveDocument.recompute()
FreeCADGui.ActiveDocument.resetEdit()
return True
def reject(self):
FreeCADGui.ActiveDocument.resetEdit()
return True
if FreeCAD.GuiUp:
FreeCADGui.addCommand('Arch_Axis',_CommandAxis())
FreeCADGui.addCommand('Arch_AxisSystem',_CommandAxisSystem())
FreeCADGui.addCommand('Arch_Grid',CommandArchGrid())
class _ArchAxisGroupCommand:
def GetCommands(self):
return tuple(['Arch_Axis','Arch_AxisSystem'])
return tuple(['Arch_Axis','Arch_AxisSystem','Arch_Grid'])
def GetResources(self):
return { 'MenuText': QT_TRANSLATE_NOOP("Arch_AxisTools",'Axis tools'),
'ToolTip': QT_TRANSLATE_NOOP("Arch_AxisTools",'Axis tools')

View File

@@ -102,10 +102,13 @@ class _Frame(ArchComponent.Component):
obj.addProperty("App::PropertyInteger","BasePoint","Arch",QT_TRANSLATE_NOOP("App::Property","Crossing point of the path on the profile."))
obj.addProperty("App::PropertyPlacement","ProfilePlacement","Arch",QT_TRANSLATE_NOOP("App::Property","An optional additional placement to add to the profile before extruding it"))
obj.addProperty("App::PropertyAngle","Rotation","Arch",QT_TRANSLATE_NOOP("App::Property","The rotation of the profile around its extrusion axis"))
obj.addProperty("App::PropertyEnumeration","Edges","Arch",QT_TRANSLATE_NOOP("App::Property","The type of edges to consider"))
obj.addProperty("App::PropertyBool","Fuse","Arch",QT_TRANSLATE_NOOP("App::Property","If true, geometry is fused, otherwise a compound"))
self.Type = "Frame"
obj.Align = True
obj.Role = Roles
obj.Role = "Railing"
obj.Edges = ["All edges","Vertical edges","Horizontal edges","Bottom horizontal edges","Top horizontal edges"]
def execute(self,obj):
@@ -153,7 +156,27 @@ class _Frame(ArchComponent.Component):
shapes = []
normal = DraftGeomUtils.getNormal(obj.Base.Shape)
#for wire in obj.Base.Shape.Wires:
for e in obj.Base.Shape.Edges:
edges = obj.Base.Shape.Edges
if hasattr(obj,"Edges"):
if obj.Edges == "Vertical edges":
rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(0,1,0))
edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
elif obj.Edges == "Horizontal edges":
rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
elif obj.Edges == "Top Horizontal edges":
rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
edges = sorted(edges,key=lambda x: x.CenterOfMass.z,reverse=True)
z = edges[0].CenterOfMass.z
edges = [e for e in edges if abs(e.CenterOfMass.z-z) < 0.00001]
elif obj.Edges == "Bottom Horizontal edges":
rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
edges = sorted(edges,key=lambda x: x.CenterOfMass.z)
z = edges[0].CenterOfMass.z
edges = [e for e in edges if abs(e.CenterOfMass.z-z) < 0.00001]
for e in edges:
#e = wire.Edges[0]
bvec = DraftGeomUtils.vec(e)
bpoint = e.Vertexes[0].Point
@@ -189,6 +212,14 @@ class _Frame(ArchComponent.Component):
profile.translate(obj.Offset)
shapes.append(profile)
if shapes:
if hasattr(obj,"Fuse"):
if obj.Fuse:
if len(shapes) > 1:
s = shapes[0].multiFuse(shapes[1:])
s = s.removeSplitter()
obj.Shape = s
obj.Placement = pl
return
obj.Shape = Part.makeCompound(shapes)
obj.Placement = pl

View File

@@ -420,7 +420,7 @@ class _CommandWindow:
FreeCADGui.draftToolBar.offUi()
obj = self.sel[0]
if obj.isDerivedFrom("Part::Feature"):
if obj.Shape.Wires and not obj.Shape.Faces:
if obj.Shape.Wires and (not obj.Shape.Solids) and (not obj.Shape.Shells):
FreeCADGui.Control.closeDialog()
host = None
if hasattr(obj,"Support"):
@@ -650,8 +650,13 @@ class _Window(ArchComponent.Component):
obj.addProperty("App::PropertyLength","LouvreSpacing","Louvres",QT_TRANSLATE_NOOP("App::Property","the space between louvre elements"))
obj.addProperty("App::PropertyPercent","Opening","Arch",QT_TRANSLATE_NOOP("App::Property","Opens the subcomponents that have a hinge defined"))
obj.addProperty("App::PropertyInteger","HoleWire","Arch",QT_TRANSLATE_NOOP("App::Property","The number of the wire that defines the hole. A value of 0 means automatic"))
obj.addProperty("App::PropertyBool","SymbolPlan","Arch",QT_TRANSLATE_NOOP("App::Property","Shows plan opening symbols if available"))
obj.addProperty("App::PropertyBool","SymbolElevation","Arch",QT_TRANSLATE_NOOP("App::Property","Show elevation opening symbols if available"))
obj.setEditorMode("Preset",2)
obj.setEditorMode("WindowParts",2)
obj.setEditorMode("VerticalArea",2)
obj.setEditorMode("HorizontalArea",2)
obj.setEditorMode("PerimeterLength",2)
self.Type = "Window"
obj.Role = Roles
obj.Role = "Window"
@@ -752,7 +757,10 @@ class _Window(ArchComponent.Component):
e = obj.Base.Shape.Edges[hinge]
ev1 = e.Vertexes[0].Point
ev2 = e.Vertexes[-1].Point
if ev2.z < ev1.z:
if (ev2.z - ev1.z) < 0.1**Draft.precision():
if ev2.y < ev1.y:
ev1,ev2 = ev2,ev1
elif ev2.z < ev1.z:
ev1,ev2 = ev2,ev1
p = None
d = 0
@@ -765,11 +773,10 @@ class _Window(ArchComponent.Component):
chord = p.sub(ev1)
enorm = ev2.sub(ev1)
proj = DraftVecUtils.project(chord,enorm)
v1 = ev1
if proj.Length > 0:
v1 = ev1.add(proj)
chord = p.sub(v1)
else:
v1 = ev1
chord = p.sub(ev1.add(proj))
p = v1.add(chord)
v4 = p.add(DraftVecUtils.scale(enorm,0.5))
if omode == 1: # Arc 90
v2 = v1.add(DraftVecUtils.rotate(chord,math.pi/4,enorm))
@@ -901,8 +908,22 @@ class _Window(ArchComponent.Component):
base = self.processSubShapes(obj,base)
if base:
if not base.isNull():
b = []
if self.sshapes:
base = Part.makeCompound([base]+self.sshapes+self.vshapes)
if hasattr(obj,"SymbolPlan"):
if obj.SymbolPlan:
b.extend(self.sshapes)
else:
b.extend(self.sshapes)
if self.vshapes:
if hasattr(obj,"SymbolElevation"):
if obj.SymbolElevation:
b.extend(self.vshapes)
else:
b.extend(self.vshapes)
if b:
base = Part.makeCompound([base]+b)
#base = Part.makeCompound([base]+self.sshapes+self.vshapes)
self.applyShape(obj,base,pl,allowinvalid=True,allownosolid=True)
obj.Placement = pl
if hasattr(obj,"Area"):
@@ -987,6 +1008,9 @@ class _Window(ArchComponent.Component):
return f
return None
def computeAreas(self,obj):
return
class _ViewProviderWindow(ArchComponent.ViewProviderComponent):
"A View Provider for the Window object"

View File

@@ -80,6 +80,7 @@
<file>icons/Arch_PipeConnector.svg</file>
<file>icons/Arch_ToggleSubs.svg</file>
<file>icons/Arch_Nest.svg</file>
<file>icons/Arch_Grid.svg</file>
<file>ui/ParametersWindowDouble.svg</file>
<file>ui/ParametersWindowSimple.svg</file>
<file>ui/ParametersWindowFixed.svg</file>

View File

@@ -0,0 +1,410 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2985"
version="1.1"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
sodipodi:docname="Arch_Grid.svg">
<defs
id="defs2987">
<linearGradient
inkscape:collect="always"
id="linearGradient3812">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop3814" />
<stop
style="stop-color:#edd400;stop-opacity:0;"
offset="1"
id="stop3816" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3804">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop3806" />
<stop
style="stop-color:#edd400;stop-opacity:0;"
offset="1"
id="stop3808" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3796">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop3798" />
<stop
style="stop-color:#edd400;stop-opacity:0;"
offset="1"
id="stop3800" />
</linearGradient>
<linearGradient
id="linearGradient3883">
<stop
style="stop-color:#ffb400;stop-opacity:1;"
offset="0"
id="stop3885" />
<stop
style="stop-color:#ffe900;stop-opacity:1;"
offset="1"
id="stop3887" />
</linearGradient>
<linearGradient
id="linearGradient3793">
<stop
style="stop-color:#000f8a;stop-opacity:1;"
offset="0"
id="stop3795" />
<stop
style="stop-color:#0066ff;stop-opacity:1;"
offset="1"
id="stop3797" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3793-2"
id="linearGradient3799-8"
x1="12.037806"
y1="54.001419"
x2="52.882648"
y2="9.274148"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3793-2">
<stop
style="stop-color:#000f8a;stop-opacity:1;"
offset="0"
id="stop3795-6" />
<stop
style="stop-color:#0066ff;stop-opacity:1;"
offset="1"
id="stop3797-0" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3883-6"
id="linearGradient3889-4"
x1="3"
y1="31.671875"
x2="59.25"
y2="31.671875"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-1.2727273,-0.18181818)" />
<linearGradient
id="linearGradient3883-6">
<stop
style="stop-color:#ffb400;stop-opacity:1;"
offset="0"
id="stop3885-4" />
<stop
style="stop-color:#ffe900;stop-opacity:1;"
offset="1"
id="stop3887-5" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3796"
id="linearGradient3802"
x1="16.4375"
y1="59.705883"
x2="8.5625"
y2="40.294117"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3804"
id="linearGradient3810"
x1="16.4375"
y1="58.411766"
x2="8.5625"
y2="41.588234"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3812"
id="linearGradient3818"
x1="16.4375"
y1="58.411766"
x2="8.562501"
y2="41.588234"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="6.6796362"
inkscape:cx="16.087193"
inkscape:cy="23.330282"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1051"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:snap-bbox="true"
inkscape:snap-nodes="true">
<inkscape:grid
type="xygrid"
id="grid2999"
empspacing="2"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata2990">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:creator>
<cc:Agent>
<dc:title>[yorikvanhavre]</dc:title>
</cc:Agent>
</dc:creator>
<dc:title>Arch_Axis</dc:title>
<dc:date>2011-12-12</dc:date>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Axis.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<rect
style="opacity:1;vector-effect:none;fill:#edd400;fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
id="rect3040-9-1"
width="57"
height="6"
x="4"
y="9" />
<rect
style="fill:#edd400;fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1;font-variant-east_asian:normal;opacity:1;vector-effect:none"
id="rect3044-8"
width="6"
height="56"
x="9"
y="5" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 54,11 h 6"
id="path3910-6-3-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<rect
style="opacity:1;vector-effect:none;fill:#edd400;fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
id="rect3040-9"
width="57"
height="6"
x="4"
y="29" />
<rect
style="opacity:1;vector-effect:none;fill:#edd400;fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
id="rect3042-2"
width="56"
height="6"
x="5"
y="49" />
<rect
style="fill:#edd400;fill-opacity:1;stroke:none"
id="rect3044-7-2"
width="4"
height="39"
x="10"
y="21" />
<rect
style="fill:#edd400;fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1;font-variant-east_asian:normal;opacity:1;vector-effect:none"
id="rect3044-8-5"
width="6"
height="56"
x="49"
y="5" />
<rect
style="fill:#edd400;fill-opacity:1;stroke:none"
id="rect3040-5-7-4"
width="39"
height="4"
x="21"
y="10" />
<rect
style="opacity:1;vector-effect:none;fill:#edd400;fill-opacity:1;stroke:#302b00;stroke-width:1.92153788;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
id="rect3044-8-2-4"
width="6"
height="12"
x="29"
y="49" />
<rect
style="fill:#edd400;fill-opacity:1;stroke:none"
id="rect3042-3-5"
width="39"
height="4"
x="21"
y="50" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
d="m 7,51 h 4 V 35"
id="path3904-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 11,60 V 52"
id="path3906-7"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 32,51 H 60"
id="path3910-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<rect
style="fill:#edd400;fill-opacity:1;stroke:none"
id="rect3044-7-2-4"
width="4"
height="39"
x="50"
y="21" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 51,60 V 52"
id="path3906-7-9"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 51,52 V 32"
id="path3906-7-9-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 54,31 h 6"
id="path3910-6-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<rect
style="fill:#edd400;fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1;font-variant-east_asian:normal;opacity:1;vector-effect:none"
id="rect3044-8-2"
width="6"
height="26"
x="29"
y="5" />
<rect
style="fill:#edd400;fill-opacity:1;stroke:none"
id="rect3040-5-7-5"
width="39"
height="4"
x="5"
y="10" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 5,11 H 50"
id="path3908-3-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 5,31 h 6 V 6"
id="path3902-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 54,11 h 6"
id="path3910-6-9-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<rect
style="fill:#edd400;fill-opacity:1;stroke:none;stroke-width:0.5547002"
id="rect3044-7-2-9"
width="4"
height="10"
x="30"
y="50" />
<rect
style="fill:#edd400;fill-opacity:1;stroke:none"
id="rect3040-5-7"
width="39"
height="4"
x="21"
y="30" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 51,32 V 6"
id="path3906-7-9-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 34,31 H 50"
id="path3908-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 14,31 H 31 V 6"
id="path3902-8-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
d="M 15,51 H 33"
id="path3904-9-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 31,60 V 52"
id="path3906-7-8"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 54,31 h 6"
id="path3910-6-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB