Merge branch 'alafr-arch-structure' of https://github.com/alafr/FreeCAD
This commit is contained in:
@@ -185,6 +185,77 @@ def placeAlongEdge(p1,p2,horizontal=False):
|
||||
return pl
|
||||
|
||||
|
||||
class CommandStructuresFromSelection:
|
||||
""" The Arch Structures from selection command definition. """
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': 'Arch_MultipleStructures',
|
||||
'MenuText': QT_TRANSLATE_NOOP("Arch_Structure", "Multiple Structures"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Arch_Structure", "Create multiple Arch Structure objects from a selected base, using each selected edge as an extrusion path")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
selex = FreeCADGui.Selection.getSelectionEx()
|
||||
if len(selex) >= 2:
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Arch", "Create Structures From Selection"))
|
||||
FreeCADGui.addModule("Arch")
|
||||
FreeCADGui.addModule("Draft")
|
||||
base = selex[0].Object # The first selected object is the base for the Structure objects
|
||||
for selexi in selex[1:]: # All the edges from the other objects are used as a Tool (extrusion paths)
|
||||
if len(selexi.SubElementNames) == 0:
|
||||
subelement_names = ["Edge" + str(i) for i in range(1, len(selexi.Object.Shape.Edges) + 1)]
|
||||
else:
|
||||
subelement_names = [sub for sub in selexi.SubElementNames if sub.startswith("Edge")]
|
||||
for sub in subelement_names:
|
||||
FreeCADGui.doCommand("structure = Arch.makeStructure(FreeCAD.ActiveDocument." + base.Name + ")")
|
||||
FreeCADGui.doCommand("structure.Tool = (FreeCAD.ActiveDocument." + selexi.Object.Name + ", '" + sub + "')")
|
||||
FreeCADGui.doCommand("structure.BasePerpendicularToTool = True")
|
||||
FreeCADGui.doCommand("Draft.autogroup(structure)")
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
else:
|
||||
FreeCAD.Console.PrintError(translate("Arch", "Please select the base object first and then the edges to use as extrusion paths") + "\n")
|
||||
|
||||
|
||||
class CommandStructuralSystem:
|
||||
""" The Arch Structural System command definition. """
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': 'Arch_StructuralSystem',
|
||||
'MenuText': QT_TRANSLATE_NOOP("Arch_Structure", "Structural System"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Arch_Structure", "Create a structural system object from a selected structure and axis")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if sel:
|
||||
st = Draft.getObjectsOfType(sel, "Structure")
|
||||
ax = Draft.getObjectsOfType(sel, "Axis")
|
||||
if ax:
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Arch", "Create Structural System"))
|
||||
FreeCADGui.addModule("Arch")
|
||||
if st:
|
||||
FreeCADGui.doCommand("obj = Arch.makeStructuralSystem(" + ArchCommands.getStringList(st) + ", " + ArchCommands.getStringList(ax) + ")")
|
||||
else:
|
||||
FreeCADGui.doCommand("obj = Arch.makeStructuralSystem(axes = " + ArchCommands.getStringList(ax) + ")")
|
||||
FreeCADGui.addModule("Draft")
|
||||
FreeCADGui.doCommand("Draft.autogroup(obj)")
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
else:
|
||||
FreeCAD.Console.PrintError(translate("Arch", "Please select at least an axis object") + "\n")
|
||||
|
||||
|
||||
class _CommandStructure:
|
||||
|
||||
"the Arch Structure command definition"
|
||||
@@ -224,16 +295,7 @@ class _CommandStructure:
|
||||
st = Draft.getObjectsOfType(sel,"Structure")
|
||||
ax = Draft.getObjectsOfType(sel,"Axis")
|
||||
if ax:
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Structural System"))
|
||||
FreeCADGui.addModule("Arch")
|
||||
if st:
|
||||
FreeCADGui.doCommand("obj = Arch.makeStructuralSystem(" + ArchCommands.getStringList(st) + "," + ArchCommands.getStringList(ax) + ")")
|
||||
else:
|
||||
FreeCADGui.doCommand("obj = Arch.makeStructuralSystem(axes=" + ArchCommands.getStringList(ax) + ")")
|
||||
FreeCADGui.addModule("Draft")
|
||||
FreeCADGui.doCommand("Draft.autogroup(obj)")
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.runCommand("Arch_StructuralSystem")
|
||||
return
|
||||
elif not(ax) and not(st):
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Structure"))
|
||||
@@ -611,7 +673,23 @@ class _Structure(ArchComponent.Component):
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not "Tool" in pl:
|
||||
obj.addProperty("App::PropertyLink","Tool","Structure",QT_TRANSLATE_NOOP("App::Property","An optional extrusion path for this element"))
|
||||
obj.addProperty("App::PropertyLinkSubList", "Tool", "ExtrusionPath", QT_TRANSLATE_NOOP("App::Property", "An optional extrusion path for this element"))
|
||||
if not "ComputedLength" in pl:
|
||||
obj.addProperty("App::PropertyDistance", "ComputedLength", "ExtrusionPath", QT_TRANSLATE_NOOP("App::Property", "The computed length of the extrusion path"), 1)
|
||||
if not "ToolOffsetFirst" in pl:
|
||||
obj.addProperty("App::PropertyDistance", "ToolOffsetFirst", "ExtrusionPath", QT_TRANSLATE_NOOP("App::Property", "Start offset distance along the extrusion path (positive: extend, negative: trim"))
|
||||
if not "ToolOffsetLast" in pl:
|
||||
obj.addProperty("App::PropertyDistance", "ToolOffsetLast", "ExtrusionPath", QT_TRANSLATE_NOOP("App::Property", "End offset distance along the extrusion path (positive: extend, negative: trim"))
|
||||
if not "BasePerpendicularToTool" in pl:
|
||||
obj.addProperty("App::PropertyBool", "BasePerpendicularToTool", "ExtrusionPath", QT_TRANSLATE_NOOP("App::Property", "Automatically align the Base of the Structure perpendicular to the Tool axis"))
|
||||
if not "BaseOffsetX" in pl:
|
||||
obj.addProperty("App::PropertyDistance", "BaseOffsetX", "ExtrusionPath", QT_TRANSLATE_NOOP("App::Property", "X offset between the Base origin and the Tool axis (only used if BasePerpendicularToTool is True)"))
|
||||
if not "BaseOffsetY" in pl:
|
||||
obj.addProperty("App::PropertyDistance", "BaseOffsetY", "ExtrusionPath", QT_TRANSLATE_NOOP("App::Property", "Y offset between the Base origin and the Tool axis (only used if BasePerpendicularToTool is True)"))
|
||||
if not "BaseMirror" in pl:
|
||||
obj.addProperty("App::PropertyBool", "BaseMirror", "ExtrusionPath", QT_TRANSLATE_NOOP("App::Property", "Mirror the Base along its Y axis (only used if BasePerpendicularToTool is True)"))
|
||||
if not "BaseRotation" in pl:
|
||||
obj.addProperty("App::PropertyAngle", "BaseRotation", "ExtrusionPath", QT_TRANSLATE_NOOP("App::Property", "Base rotation around the Tool axis (only used if BasePerpendicularToTool is True)"))
|
||||
if not "Length" in pl:
|
||||
obj.addProperty("App::PropertyLength","Length","Structure",QT_TRANSLATE_NOOP("App::Property","The length of this element, if not based on a profile"))
|
||||
if not "Width" in pl:
|
||||
@@ -660,31 +738,38 @@ class _Structure(ArchComponent.Component):
|
||||
if not isinstance(pla,list):
|
||||
pla = [pla]
|
||||
base = []
|
||||
extrusion_length = 0.0
|
||||
for i in range(len(sh)):
|
||||
shi = sh[i]
|
||||
if i < len(ev):
|
||||
evi = ev[i]
|
||||
else:
|
||||
evi = FreeCAD.Vector(ev[-1])
|
||||
evi = ev[-1]
|
||||
if isinstance(evi, FreeCAD.Vector):
|
||||
evi = FreeCAD.Vector(evi)
|
||||
else:
|
||||
evi = evi.copy()
|
||||
if i < len(pla):
|
||||
pli = pla[i]
|
||||
else:
|
||||
pli = pla[-1].copy()
|
||||
shi.Placement = pli.multiply(shi.Placement)
|
||||
if not isinstance(evi, FreeCAD.Vector):
|
||||
if isinstance(evi, FreeCAD.Vector):
|
||||
extv = pla[0].Rotation.multVec(evi)
|
||||
shi = shi.extrude(extv)
|
||||
else:
|
||||
try:
|
||||
shi = evi.makePipe(shi)
|
||||
except Part.OCCError:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Error: The base shape couldn't be extruded along this tool object")+"\n")
|
||||
return
|
||||
else:
|
||||
extv = pla[0].Rotation.multVec(evi)
|
||||
shi = shi.extrude(extv)
|
||||
base.append(shi)
|
||||
extrusion_length += evi.Length
|
||||
if len(base) == 1:
|
||||
base = base[0]
|
||||
else:
|
||||
base = Part.makeCompound(base)
|
||||
obj.ComputedLength = FreeCAD.Units.Quantity(extrusion_length, FreeCAD.Units.Length)
|
||||
if obj.Base:
|
||||
if hasattr(obj.Base,'Shape'):
|
||||
if obj.Base.Shape.isNull():
|
||||
@@ -712,9 +797,7 @@ class _Structure(ArchComponent.Component):
|
||||
self.applyShape(obj,base,pl)
|
||||
|
||||
def getExtrusionData(self,obj):
|
||||
|
||||
"""returns (shape,extrusion vector,placement) or None"""
|
||||
|
||||
"""returns (shape,extrusion vector or path,placement) or None"""
|
||||
if hasattr(obj,"IfcType"):
|
||||
IfcType = obj.IfcType
|
||||
else:
|
||||
@@ -728,11 +811,11 @@ class _Structure(ArchComponent.Component):
|
||||
length = obj.Length.Value
|
||||
width = obj.Width.Value
|
||||
height = obj.Height.Value
|
||||
normal = None
|
||||
if not height:
|
||||
height = self.getParentHeight(obj)
|
||||
base = None
|
||||
placement = None
|
||||
baseface = None
|
||||
extrusion = None
|
||||
normal = None
|
||||
if obj.Base:
|
||||
if hasattr(obj.Base,'Shape'):
|
||||
if obj.Base.Shape:
|
||||
@@ -742,22 +825,8 @@ class _Structure(ArchComponent.Component):
|
||||
if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces,tol=0.01):
|
||||
return None
|
||||
else:
|
||||
base,placement = self.rebase(obj.Base.Shape)
|
||||
normal = obj.Base.Shape.Faces[0].normalAt(0,0)
|
||||
normal = placement.inverse().Rotation.multVec(normal)
|
||||
if (len(obj.Shape.Solids) > 1) and (len(obj.Shape.Solids) == len(obj.Base.Shape.Faces)):
|
||||
# multiple extrusions
|
||||
b = []
|
||||
p = []
|
||||
hint = obj.Base.Shape.Faces[0].normalAt(0,0)
|
||||
for f in obj.Base.Shape.Faces:
|
||||
bf,pf = self.rebase(f,hint)
|
||||
b.append(bf)
|
||||
p.append(pf)
|
||||
base = b
|
||||
placement = p
|
||||
baseface = obj.Base.Shape.copy()
|
||||
elif obj.Base.Shape.Wires:
|
||||
baseface = None
|
||||
if hasattr(obj,"FaceMaker"):
|
||||
if obj.FaceMaker != "None":
|
||||
try:
|
||||
@@ -765,9 +834,6 @@ class _Structure(ArchComponent.Component):
|
||||
except Exception:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Facemaker returned an error")+"\n")
|
||||
return None
|
||||
if len(baseface.Faces) > 1:
|
||||
baseface = baseface.Faces[0]
|
||||
normal = baseface.normalAt(0,0)
|
||||
if not baseface:
|
||||
for w in obj.Base.Shape.Wires:
|
||||
if not w.isClosed():
|
||||
@@ -781,15 +847,7 @@ class _Structure(ArchComponent.Component):
|
||||
if baseface:
|
||||
baseface = baseface.fuse(f)
|
||||
else:
|
||||
baseface = f
|
||||
normal = f.normalAt(0,0)
|
||||
base,placement = self.rebase(baseface)
|
||||
normal = placement.inverse().Rotation.multVec(normal)
|
||||
elif (len(obj.Base.Shape.Edges) == 1) and (len(obj.Base.Shape.Vertexes) == 1):
|
||||
# closed edge
|
||||
w = Part.Wire(obj.Base.Shape.Edges[0])
|
||||
baseface = Part.Face(w)
|
||||
base,placement = self.rebase(baseface)
|
||||
baseface = f.copy()
|
||||
elif length and width and height:
|
||||
if (length > height) and (IfcType != "Slab"):
|
||||
h2 = height/2 or 0.5
|
||||
@@ -807,22 +865,58 @@ class _Structure(ArchComponent.Component):
|
||||
v4 = Vector(-l2,w2,0)
|
||||
import Part
|
||||
baseface = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1]))
|
||||
base,placement = self.rebase(baseface)
|
||||
if base and placement:
|
||||
if obj.Tool:
|
||||
if obj.Tool.Shape:
|
||||
edges = obj.Tool.Shape.Edges
|
||||
if len(edges) == 1 and DraftGeomUtils.geomType(edges[0]) == "Line":
|
||||
extrusion = DraftGeomUtils.vec(edges[0])
|
||||
if baseface:
|
||||
if hasattr(obj, "Tool") and obj.Tool:
|
||||
tool = obj.Tool
|
||||
edges = DraftGeomUtils.get_referenced_edges(tool)
|
||||
if len(edges) > 0:
|
||||
extrusion = Part.Wire(Part.__sortEdges__(edges))
|
||||
if hasattr(obj, "ToolOffsetFirst"):
|
||||
offset_start = float(obj.ToolOffsetFirst.getValueAs("mm"))
|
||||
else:
|
||||
extrusion = obj.Tool.Shape.copy()
|
||||
offset_start = 0.0
|
||||
if hasattr(obj, "ToolOffsetLast"):
|
||||
offset_end = float(obj.ToolOffsetLast.getValueAs("mm"))
|
||||
else:
|
||||
offset_end = 0.0
|
||||
if offset_start != 0.0 or offset_end != 0.0:
|
||||
extrusion = DraftGeomUtils.get_extended_wire(extrusion, offset_start, offset_end)
|
||||
if hasattr(obj, "BasePerpendicularToTool") and obj.BasePerpendicularToTool:
|
||||
pl = FreeCAD.Placement()
|
||||
if hasattr(obj, "BaseRotation"):
|
||||
pl.rotate(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, 1), -obj.BaseRotation)
|
||||
if hasattr(obj, "BaseOffsetX") and hasattr(obj, "BaseOffsetY"):
|
||||
pl.translate(FreeCAD.Vector(obj.BaseOffsetX, obj.BaseOffsetY, 0))
|
||||
if hasattr(obj, "BaseMirror"):
|
||||
pl.rotate(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 1, 0), 180)
|
||||
baseface.Placement = DraftGeomUtils.get_placement_perpendicular_to_wire(extrusion).multiply(pl)
|
||||
else:
|
||||
if obj.Normal.Length:
|
||||
normal = Vector(obj.Normal).normalize()
|
||||
if isinstance(placement,list):
|
||||
normal = placement[0].inverse().Rotation.multVec(normal)
|
||||
else:
|
||||
normal = placement.inverse().Rotation.multVec(normal)
|
||||
else:
|
||||
normal = baseface.Faces[0].normalAt(0, 0)
|
||||
base = None
|
||||
placement = None
|
||||
inverse_placement = None
|
||||
if len(baseface.Faces) > 1:
|
||||
base = []
|
||||
placement = []
|
||||
hint = baseface.Faces[0].normalAt(0, 0)
|
||||
for f in baseface.Faces:
|
||||
bf, pf = self.rebase(f, hint)
|
||||
base.append(bf)
|
||||
placement.append(pf)
|
||||
inverse_placement = placement[0].inverse()
|
||||
else:
|
||||
base, placement = self.rebase(baseface)
|
||||
inverse_placement = placement.inverse()
|
||||
if extrusion:
|
||||
if len(extrusion.Edges) == 1 and DraftGeomUtils.geomType(extrusion.Edges[0]) == "Line":
|
||||
extrusion = DraftGeomUtils.vec(extrusion.Edges[0], True)
|
||||
if isinstance(extrusion, FreeCAD.Vector):
|
||||
extrusion = inverse_placement.Rotation.multVec(extrusion)
|
||||
elif normal:
|
||||
normal = inverse_placement.Rotation.multVec(normal)
|
||||
if not normal:
|
||||
normal = Vector(0,0,1)
|
||||
if not normal.Length:
|
||||
@@ -834,7 +928,8 @@ class _Structure(ArchComponent.Component):
|
||||
else:
|
||||
if height:
|
||||
extrusion = normal.multiply(height)
|
||||
return (base,extrusion,placement)
|
||||
if extrusion:
|
||||
return (base, extrusion, placement)
|
||||
return None
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
@@ -850,15 +945,15 @@ class _Structure(ArchComponent.Component):
|
||||
extdata = self.getExtrusionData(obj)
|
||||
if extdata and not isinstance(extdata[0],list):
|
||||
nodes = extdata[0]
|
||||
ev = extdata[2].Rotation.multVec(extdata[1])
|
||||
nodes.Placement = nodes.Placement.multiply(extdata[2])
|
||||
if IfcType not in ["Slab"]:
|
||||
if obj.Tool:
|
||||
nodes = obj.Tool.Shape
|
||||
if not isinstance(extdata[1], FreeCAD.Vector):
|
||||
nodes = extdata[1]
|
||||
elif extdata[1].Length > 0:
|
||||
if hasattr(nodes,"CenterOfMass"):
|
||||
import Part
|
||||
nodes = Part.LineSegment(nodes.CenterOfMass,nodes.CenterOfMass.add(ev)).toShape()
|
||||
nodes = Part.LineSegment(nodes.CenterOfMass,nodes.CenterOfMass.add(extdata[1])).toShape()
|
||||
if isinstance(extdata[1], FreeCAD.Vector):
|
||||
nodes.Placement = nodes.Placement.multiply(extdata[2])
|
||||
offset = FreeCAD.Vector()
|
||||
if hasattr(obj,"NodesOffset"):
|
||||
offset = FreeCAD.Vector(0,0,obj.NodesOffset.Value)
|
||||
@@ -1049,45 +1144,56 @@ class StructureTaskPanel(ArchComponent.ComponentTaskPanel):
|
||||
def __init__(self,obj):
|
||||
|
||||
ArchComponent.ComponentTaskPanel.__init__(self)
|
||||
self.optwid = QtGui.QWidget()
|
||||
self.optwid.setWindowTitle(QtGui.QApplication.translate("Arch", "Node Tools", None))
|
||||
lay = QtGui.QVBoxLayout(self.optwid)
|
||||
self.nodes_widget = QtGui.QWidget()
|
||||
self.nodes_widget.setWindowTitle(QtGui.QApplication.translate("Arch", "Node Tools", None))
|
||||
lay = QtGui.QVBoxLayout(self.nodes_widget)
|
||||
|
||||
self.resetButton = QtGui.QPushButton(self.optwid)
|
||||
self.resetButton = QtGui.QPushButton(self.nodes_widget)
|
||||
self.resetButton.setIcon(QtGui.QIcon(":/icons/edit-undo.svg"))
|
||||
self.resetButton.setText(QtGui.QApplication.translate("Arch", "Reset nodes", None))
|
||||
|
||||
lay.addWidget(self.resetButton)
|
||||
QtCore.QObject.connect(self.resetButton, QtCore.SIGNAL("clicked()"), self.resetNodes)
|
||||
|
||||
self.editButton = QtGui.QPushButton(self.optwid)
|
||||
self.editButton = QtGui.QPushButton(self.nodes_widget)
|
||||
self.editButton.setIcon(QtGui.QIcon(":/icons/Draft_Edit.svg"))
|
||||
self.editButton.setText(QtGui.QApplication.translate("Arch", "Edit nodes", None))
|
||||
lay.addWidget(self.editButton)
|
||||
QtCore.QObject.connect(self.editButton, QtCore.SIGNAL("clicked()"), self.editNodes)
|
||||
|
||||
self.extendButton = QtGui.QPushButton(self.optwid)
|
||||
self.extendButton = QtGui.QPushButton(self.nodes_widget)
|
||||
self.extendButton.setIcon(QtGui.QIcon(":/icons/Snap_Perpendicular.svg"))
|
||||
self.extendButton.setText(QtGui.QApplication.translate("Arch", "Extend nodes", None))
|
||||
self.extendButton.setToolTip(QtGui.QApplication.translate("Arch", "Extends the nodes of this element to reach the nodes of another element", None))
|
||||
lay.addWidget(self.extendButton)
|
||||
QtCore.QObject.connect(self.extendButton, QtCore.SIGNAL("clicked()"), self.extendNodes)
|
||||
|
||||
self.connectButton = QtGui.QPushButton(self.optwid)
|
||||
self.connectButton = QtGui.QPushButton(self.nodes_widget)
|
||||
self.connectButton.setIcon(QtGui.QIcon(":/icons/Snap_Intersection.svg"))
|
||||
self.connectButton.setText(QtGui.QApplication.translate("Arch", "Connect nodes", None))
|
||||
self.connectButton.setToolTip(QtGui.QApplication.translate("Arch", "Connects nodes of this element with the nodes of another element", None))
|
||||
lay.addWidget(self.connectButton)
|
||||
QtCore.QObject.connect(self.connectButton, QtCore.SIGNAL("clicked()"), self.connectNodes)
|
||||
|
||||
self.toggleButton = QtGui.QPushButton(self.optwid)
|
||||
self.toggleButton = QtGui.QPushButton(self.nodes_widget)
|
||||
self.toggleButton.setIcon(QtGui.QIcon(":/icons/dagViewVisible.svg"))
|
||||
self.toggleButton.setText(QtGui.QApplication.translate("Arch", "Toggle all nodes", None))
|
||||
self.toggleButton.setToolTip(QtGui.QApplication.translate("Arch", "Toggles all structural nodes of the document on/off", None))
|
||||
lay.addWidget(self.toggleButton)
|
||||
QtCore.QObject.connect(self.toggleButton, QtCore.SIGNAL("clicked()"), self.toggleNodes)
|
||||
|
||||
self.form = [self.form,self.optwid]
|
||||
self.extrusion_widget = QtGui.QWidget()
|
||||
self.extrusion_widget.setWindowTitle(QtGui.QApplication.translate("Arch", "Extrusion Tools", None))
|
||||
lay = QtGui.QVBoxLayout(self.extrusion_widget)
|
||||
|
||||
self.selectToolButton = QtGui.QPushButton(self.extrusion_widget)
|
||||
self.selectToolButton.setIcon(QtGui.QIcon())
|
||||
self.selectToolButton.setText(QtGui.QApplication.translate("Arch", "Select tool...", None))
|
||||
self.selectToolButton.setToolTip(QtGui.QApplication.translate("Arch", "Select object or edges to be used as a Tool (extrusion path)", None))
|
||||
lay.addWidget(self.selectToolButton)
|
||||
QtCore.QObject.connect(self.selectToolButton, QtCore.SIGNAL("clicked()"), self.setSelectionFromTool)
|
||||
|
||||
self.form = [self.form, self.nodes_widget, self.extrusion_widget]
|
||||
self.Object = obj
|
||||
self.observer = None
|
||||
self.nodevis = None
|
||||
@@ -1182,6 +1288,42 @@ class StructureTaskPanel(ArchComponent.ComponentTaskPanel):
|
||||
self.nodevis.append([obj,obj.ViewObject.ShowNodes])
|
||||
obj.ViewObject.ShowNodes = True
|
||||
|
||||
def setSelectionFromTool(self):
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
if hasattr(self.Object, "Tool"):
|
||||
tool = self.Object.Tool
|
||||
if hasattr(tool, "Shape") and tool.Shape:
|
||||
FreeCADGui.Selection.addSelection(tool)
|
||||
else:
|
||||
if not isinstance(tool, list):
|
||||
tool = [tool]
|
||||
for o, subs in tool:
|
||||
FreeCADGui.Selection.addSelection(o, subs)
|
||||
QtCore.QObject.disconnect(self.selectToolButton, QtCore.SIGNAL("clicked()"), self.setSelectionFromTool)
|
||||
QtCore.QObject.connect(self.selectToolButton, QtCore.SIGNAL("clicked()"), self.setToolFromSelection)
|
||||
self.selectToolButton.setText(QtGui.QApplication.translate("Arch", "Done", None))
|
||||
|
||||
def setToolFromSelection(self):
|
||||
objectList = []
|
||||
selEx = FreeCADGui.Selection.getSelectionEx()
|
||||
for selExi in selEx:
|
||||
if len(selExi.SubElementNames) == 0:
|
||||
# Add entirely selected objects
|
||||
objectList.append(selExi.Object)
|
||||
else:
|
||||
subElementsNames = [subElementName for subElementName in selExi.SubElementNames if subElementName.startswith("Edge")]
|
||||
# Check that at least an edge is selected from the object's shape
|
||||
if len(subElementsNames) > 0:
|
||||
objectList.append((selExi.Object, subElementsNames))
|
||||
if self.Object.getTypeIdOfProperty("Tool") != "App::PropertyLinkSubList":
|
||||
# Upgrade property Tool from App::PropertyLink to App::PropertyLinkSubList (note: Undo/Redo fails)
|
||||
self.Object.removeProperty("Tool")
|
||||
self.Object.addProperty("App::PropertyLinkSubList", "Tool", "Structure", QT_TRANSLATE_NOOP("App::Property", "An optional extrusion path for this element"))
|
||||
self.Object.Tool = objectList
|
||||
QtCore.QObject.disconnect(self.selectToolButton, QtCore.SIGNAL("clicked()"), self.setToolFromSelection)
|
||||
QtCore.QObject.connect(self.selectToolButton, QtCore.SIGNAL("clicked()"), self.setSelectionFromTool)
|
||||
self.selectToolButton.setText(QtGui.QApplication.translate("Arch", "Select tool...", None))
|
||||
|
||||
def accept(self):
|
||||
|
||||
if self.observer:
|
||||
@@ -1315,4 +1457,19 @@ class _ViewProviderStructuralSystem(ArchComponent.ViewProviderComponent):
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('Arch_Structure',_CommandStructure())
|
||||
FreeCADGui.addCommand("Arch_Structure", _CommandStructure())
|
||||
FreeCADGui.addCommand("Arch_StructuralSystem", CommandStructuralSystem())
|
||||
FreeCADGui.addCommand("Arch_StructuresFromSelection", CommandStructuresFromSelection())
|
||||
|
||||
class _ArchStructureGroupCommand:
|
||||
|
||||
def GetCommands(self):
|
||||
return ("Arch_Structure", "Arch_StructuralSystem", "Arch_StructuresFromSelection")
|
||||
def GetResources(self):
|
||||
return { "MenuText": QT_TRANSLATE_NOOP("Arch_Structure", "Structure tools"),
|
||||
"ToolTip": QT_TRANSLATE_NOOP("Arch_Structure", "Structure tools")
|
||||
}
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
FreeCADGui.addCommand("Arch_StructureTools", _ArchStructureGroupCommand())
|
||||
|
||||
@@ -59,7 +59,7 @@ class ArchWorkbench(FreeCADGui.Workbench):
|
||||
import Arch
|
||||
|
||||
# Set up command lists
|
||||
self.archtools = ["Arch_Wall", "Arch_Structure", "Arch_Rebar",
|
||||
self.archtools = ["Arch_Wall", "Arch_StructureTools", "Arch_Rebar",
|
||||
"Arch_CurtainWall","Arch_BuildingPart",
|
||||
"Arch_Project", "Arch_Site", "Arch_Building",
|
||||
"Arch_Floor", "Arch_Reference",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
<file>icons/Arch_Material_Multi.svg</file>
|
||||
<file>icons/Arch_MergeWalls.svg</file>
|
||||
<file>icons/Arch_MeshToShape.svg</file>
|
||||
<file>icons/Arch_MultipleStructures.svg</file>
|
||||
<file>icons/Arch_Nest.svg</file>
|
||||
<file>icons/Arch_Panel.svg</file>
|
||||
<file>icons/Arch_Panel_Clone.svg</file>
|
||||
|
||||
264
src/Mod/Arch/Resources/icons/Arch_MultipleStructures.svg
Normal file
264
src/Mod/Arch/Resources/icons/Arch_MultipleStructures.svg
Normal file
@@ -0,0 +1,264 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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"
|
||||
version="1.1"
|
||||
id="svg2985"
|
||||
height="64px"
|
||||
width="64px">
|
||||
<defs
|
||||
id="defs2987">
|
||||
<marker
|
||||
style="overflow:visible"
|
||||
id="Arrow1Lstart"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto">
|
||||
<path
|
||||
transform="scale(0.8) translate(12.5,0)"
|
||||
style="fill-rule:evenodd;stroke:#729fcf;stroke-width:1pt;stroke-opacity:1;fill:#729fcf;fill-opacity:1"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
id="path4859" />
|
||||
</marker>
|
||||
<linearGradient
|
||||
id="linearGradient3850-6">
|
||||
<stop
|
||||
id="stop3852-2"
|
||||
offset="0"
|
||||
style="stop-color:#c4a000;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3854-9"
|
||||
offset="1"
|
||||
style="stop-color:#edd400;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3858-2">
|
||||
<stop
|
||||
id="stop3860-7"
|
||||
offset="0"
|
||||
style="stop-color:#ffc900;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3862-0"
|
||||
offset="1"
|
||||
style="stop-color:#fce94f;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="27.481174"
|
||||
x2="66.151985"
|
||||
y1="54.851124"
|
||||
x1="69.848015"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3972"
|
||||
xlink:href="#linearGradient3850-6" />
|
||||
<linearGradient
|
||||
y2="26.598274"
|
||||
x2="55.563385"
|
||||
y1="56.224525"
|
||||
x1="59.417618"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3974"
|
||||
xlink:href="#linearGradient3858-2" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(-1,0,0,1,111.00667,0.294905)"
|
||||
y2="21.705095"
|
||||
x2="66.006668"
|
||||
y1="53"
|
||||
x1="69"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3986"
|
||||
xlink:href="#linearGradient3850-6" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(-1,0,0,1,111.00667,0.294905)"
|
||||
y2="20.705095"
|
||||
x2="55.006672"
|
||||
y1="54"
|
||||
x1="57"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3988"
|
||||
xlink:href="#linearGradient3858-2" />
|
||||
<linearGradient
|
||||
y2="27.481174"
|
||||
x2="66.151985"
|
||||
y1="51.449608"
|
||||
x1="69.018059"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3986-6"
|
||||
xlink:href="#linearGradient3850-6-1" />
|
||||
<linearGradient
|
||||
id="linearGradient3850-6-1">
|
||||
<stop
|
||||
id="stop3852-2-8"
|
||||
offset="0"
|
||||
style="stop-color:#c4a000;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3854-9-7"
|
||||
offset="1"
|
||||
style="stop-color:#edd400;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="26.598274"
|
||||
x2="55.563385"
|
||||
y1="52.449608"
|
||||
x1="57.018063"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3988-9"
|
||||
xlink:href="#linearGradient3858-2-2" />
|
||||
<linearGradient
|
||||
id="linearGradient3858-2-2">
|
||||
<stop
|
||||
id="stop3860-7-0"
|
||||
offset="0"
|
||||
style="stop-color:#ffc900;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3862-0-2"
|
||||
offset="1"
|
||||
style="stop-color:#fce94f;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="21.705095"
|
||||
x2="66.006668"
|
||||
y1="53"
|
||||
x1="69"
|
||||
gradientTransform="matrix(-1,0,0,1,111.00667,0.294905)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient4819"
|
||||
xlink:href="#linearGradient3850-6" />
|
||||
<linearGradient
|
||||
y2="20.705095"
|
||||
x2="55.006672"
|
||||
y1="54"
|
||||
x1="57"
|
||||
gradientTransform="matrix(-1,0,0,1,111.00667,0.294905)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient4821"
|
||||
xlink:href="#linearGradient3858-2" />
|
||||
<linearGradient
|
||||
y2="27.481174"
|
||||
x2="66.151985"
|
||||
y1="51.449608"
|
||||
x1="69.018059"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient5160"
|
||||
xlink:href="#linearGradient3850-6-1" />
|
||||
</defs>
|
||||
<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>Antoine Lafr</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Structure</dc:title>
|
||||
<dc:date>2020-04-11</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_MultipleStructures.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 />
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1">
|
||||
<g
|
||||
transform="translate(2.010672,1.479651)"
|
||||
id="g4817">
|
||||
<path
|
||||
id="path3927-5-6"
|
||||
style="color:#000000;visibility:visible;fill:url(#linearGradient4819);fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
|
||||
d="m 50,24 0.0067,35.294905 -10,-4 V 24 c 0,-5 -4.017372,-11.479651 -7.017372,-14.479651 L 40.0067,2.294905 C 46.0067,7.294905 50,16 50,24 Z" />
|
||||
<path
|
||||
id="path3929-3-0"
|
||||
style="color:#000000;visibility:visible;fill:url(#linearGradient4821);fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
|
||||
d="m 59.0067,20.520349 c -0.01737,-5.479651 -4.017372,-16 -10.017372,-19 L 40.0067,2.294905 C 45.0067,6.294905 50,16 50,24 l 0.0067,35.294905 9,-4 z" />
|
||||
<path
|
||||
id="path3846-6"
|
||||
d="m 57.0067,21.294905 v 32.539551 l -5.00003,2.460449 3e-5,-33 z"
|
||||
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path3848-2"
|
||||
d="m 48,24 -5.9933,-2 v 32 l 5.982628,2.520349 z"
|
||||
style="fill:none;stroke:#edd400;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(-1,0,0,1,61.006671,2.294905)"
|
||||
id="g3978-3">
|
||||
<g
|
||||
transform="translate(-22,2)"
|
||||
id="g3866-9-7">
|
||||
<g
|
||||
transform="translate(2.006671,-0.294905)"
|
||||
id="g5158">
|
||||
<path
|
||||
id="path3925-7-3-5"
|
||||
style="color:#000000;visibility:visible;fill:#fce94f;fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
|
||||
d="m 52,23 9,2 9,-2 -8,-2 z" />
|
||||
<path
|
||||
id="path3927-5-6-9"
|
||||
style="color:#000000;visibility:visible;fill:url(#linearGradient5160);fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
|
||||
d="m 61,25 v 32 l 9,-4 V 23 Z" />
|
||||
<path
|
||||
id="path3929-3-0-2"
|
||||
style="color:#000000;visibility:visible;fill:url(#linearGradient3988-9);fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
|
||||
d="m 52,23 9,2 v 32 l -9,-4 z" />
|
||||
<path
|
||||
id="path3846-6-2"
|
||||
d="M 54,26 V 51.539551 L 59,54 V 27 Z"
|
||||
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path3848-2-8"
|
||||
d="m 63,27 5,-1.550391 v 26.255486 l -4.982658,2.520349 z"
|
||||
style="fill:none;stroke:#edd400;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(0,4)"
|
||||
id="g5168">
|
||||
<path
|
||||
style="fill:#00ffff;stroke:#0b1521;stroke-width:6;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 5,52 V 23"
|
||||
id="path3878-4" />
|
||||
<path
|
||||
style="fill:#00ffff;stroke:#729fcf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 5,52 V 22"
|
||||
id="path3878" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(2)"
|
||||
id="g5172">
|
||||
<path
|
||||
style="fill:none;stroke:#0b1521;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 34,56 V 25 c 0,-3 -5,-9 -8,-12"
|
||||
id="path3878-2-8" />
|
||||
<path
|
||||
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 34,56 V 25 c 0,-3 -5,-9 -8,-12"
|
||||
id="path3878-2" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.8 KiB |
Reference in New Issue
Block a user