From e8e10ed05d606a3bc7771766818bf9ee3adf60bd Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sun, 9 Oct 2016 23:15:47 -0300 Subject: [PATCH] Arch: Allow to manually edit structural nodes - issue #2356 --- src/Mod/Arch/ArchComponent.py | 23 +++++++-------- src/Mod/Arch/ArchStructure.py | 53 +++++++++++++++++++++++++++++++++-- src/Mod/Draft/DraftSnap.py | 15 ++++++---- src/Mod/Draft/DraftTools.py | 23 +++++++++++++-- 4 files changed, 94 insertions(+), 20 deletions(-) diff --git a/src/Mod/Arch/ArchComponent.py b/src/Mod/Arch/ArchComponent.py index 75912cc6f..c529826db 100644 --- a/src/Mod/Arch/ArchComponent.py +++ b/src/Mod/Arch/ArchComponent.py @@ -125,8 +125,8 @@ def removeFromComponent(compobject,subobject): class SelectionTaskPanel: """A temp taks panel to wait for a selection""" def __init__(self): - self.form = QtGui.QLabel() - self.form.setText(QtGui.QApplication.translate("Arch", "Please select a base object", None, QtGui.QApplication.UnicodeUTF8)) + self.baseform = QtGui.QLabel() + self.baseform.setText(QtGui.QApplication.translate("Arch", "Please select a base object", None, QtGui.QApplication.UnicodeUTF8)) def getStandardButtons(self): return int(QtGui.QDialogButtonBox.Cancel) @@ -147,27 +147,28 @@ class ComponentTaskPanel: self.obj = None self.attribs = ["Base","Additions","Subtractions","Objects","Components","Axes","Fixtures","Armatures"] - self.form = QtGui.QWidget() - self.form.setObjectName("TaskPanel") - self.grid = QtGui.QGridLayout(self.form) + self.baseform = QtGui.QWidget() + self.baseform.setObjectName("TaskPanel") + self.grid = QtGui.QGridLayout(self.baseform) self.grid.setObjectName("grid") - self.title = QtGui.QLabel(self.form) + self.title = QtGui.QLabel(self.baseform) self.grid.addWidget(self.title, 0, 0, 1, 2) + self.form = self.baseform # tree - self.tree = QtGui.QTreeWidget(self.form) + self.tree = QtGui.QTreeWidget(self.baseform) 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 = QtGui.QPushButton(self.baseform) self.addButton.setObjectName("addButton") self.addButton.setIcon(QtGui.QIcon(":/icons/Arch_Add.svg")) self.grid.addWidget(self.addButton, 3, 0, 1, 1) self.addButton.setEnabled(False) - self.delButton = QtGui.QPushButton(self.form) + self.delButton = QtGui.QPushButton(self.baseform) self.delButton.setObjectName("delButton") self.delButton.setIcon(QtGui.QIcon(":/icons/Arch_Remove.svg")) self.grid.addWidget(self.delButton, 3, 1, 1, 1) @@ -236,7 +237,7 @@ class ComponentTaskPanel: item.setIcon(0,self.getIcon(o)) Tattrib.addChild(item) self.tree.expandItem(Tattrib) - self.retranslateUi(self.form) + self.retranslateUi(self.baseform) def addElement(self): it = self.tree.currentItem() @@ -276,7 +277,7 @@ class ComponentTaskPanel: FreeCADGui.ActiveDocument.setEdit(obj.Name,0) def retranslateUi(self, TaskPanel): - TaskPanel.setWindowTitle(QtGui.QApplication.translate("Arch", "Components", None, QtGui.QApplication.UnicodeUTF8)) + self.baseform.setWindowTitle(QtGui.QApplication.translate("Arch", "Components", None, QtGui.QApplication.UnicodeUTF8)) self.delButton.setText(QtGui.QApplication.translate("Arch", "Remove", None, QtGui.QApplication.UnicodeUTF8)) self.addButton.setText(QtGui.QApplication.translate("Arch", "Add", None, QtGui.QApplication.UnicodeUTF8)) self.title.setText(QtGui.QApplication.translate("Arch", "Components of this object", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/src/Mod/Arch/ArchStructure.py b/src/Mod/Arch/ArchStructure.py index c900dd010..c586750a1 100644 --- a/src/Mod/Arch/ArchStructure.py +++ b/src/Mod/Arch/ArchStructure.py @@ -469,10 +469,11 @@ class _Structure(ArchComponent.Component): def onChanged(self,obj,prop): self.hideSubobjects(obj,prop) - if prop == "Shape": + if prop in ["Shape","ResetNodes"]: + # ResetNodes is not a property but it allows us to use this function to force reset the nodes if hasattr(obj,"Nodes"): # update structural nodes - if obj.Nodes: + if obj.Nodes and (prop != "ResetNodes"): if hasattr(self,"nodes"): if self.nodes: if obj.Nodes != self.nodes: @@ -497,6 +498,18 @@ class _Structure(ArchComponent.Component): self.nodes = [v.Point for v in nodes.Vertexes] obj.Nodes = self.nodes + def getNodeEdges(self,obj): + "returns a list of edges from stuctural nodes" + edges = [] + if obj.Nodes: + import Part + for i in range(len(obj.Nodes)-1): + edges.append(Part.Line(obj.Placement.multVec(obj.Nodes[i]),obj.Placement.multVec(obj.Nodes[i+1])).toShape()) + if hasattr(obj.ViewObject,"NodeType"): + if (obj.ViewObject.NodeType == "Area") and (len(obj.Nodes) > 2): + edges.append(Part.Line(obj.Placement.multVec(obj.Nodes[-1]),obj.Placement.multVec(obj.Nodes[0])).toShape()) + return edges + class _ViewProviderStructure(ArchComponent.ViewProviderComponent): "A View Provider for the Structure object" @@ -600,6 +613,42 @@ class _ViewProviderStructure(ArchComponent.ViewProviderComponent): self.updateData(vobj.Object,"Nodes") ArchComponent.ViewProviderComponent.onChanged(self,vobj,prop) + def setEdit(self,vobj,mode): + if mode == 0: + taskd = StructureTaskPanel(vobj.Object) + taskd.obj = self.Object + taskd.update() + FreeCADGui.Control.showDialog(taskd) + return True + return False + + +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, QtGui.QApplication.UnicodeUTF8)) + lay = QtGui.QVBoxLayout(self.optwid) + self.resetButton = QtGui.QPushButton(self.optwid) + self.resetButton.setIcon(QtGui.QIcon(":/icons/edit-undo.svg")) + self.resetButton.setText(QtGui.QApplication.translate("Arch", "Reset nodes", None, QtGui.QApplication.UnicodeUTF8)) + lay.addWidget(self.resetButton) + QtCore.QObject.connect(self.resetButton, QtCore.SIGNAL("clicked()"), self.resetNodes) + self.editButton = QtGui.QPushButton(self.optwid) + self.editButton.setIcon(QtGui.QIcon(":/icons/Draft_Edit.svg")) + self.editButton.setText(QtGui.QApplication.translate("Arch", "Edit nodes", None, QtGui.QApplication.UnicodeUTF8)) + lay.addWidget(self.editButton) + QtCore.QObject.connect(self.editButton, QtCore.SIGNAL("clicked()"), self.editNodes) + self.form = [self.form,self.optwid] + self.Object = obj + + def editNodes(self): + FreeCADGui.Control.closeDialog() + FreeCADGui.runCommand("Draft_Edit") + + def resetNodes(self): + self.Object.Proxy.onChanged(self.Object,"ResetNodes") class _StructuralSystem(ArchComponent.Component): "The Structural System object" diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index bbac01bfd..8d75bb07f 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -268,7 +268,7 @@ class Snapper: if obj.isDerivedFrom("Part::Feature"): - snaps.extend(self.snapToSpecials(obj)) + snaps.extend(self.snapToSpecials(obj,lastpoint,eline)) if Draft.getType(obj) == "Polygon": # special snapping for polygons: add the center @@ -283,7 +283,6 @@ class Snapper: snaps.extend(self.snapToEndpoints(edge)) snaps.extend(self.snapToMidpoint(edge)) snaps.extend(self.snapToPerpendicular(edge,lastpoint)) - #snaps.extend(self.snapToOrtho(edge,lastpoint,constrain)) # now part of snapToPolar snaps.extend(self.snapToIntersection(edge)) snaps.extend(self.snapToElines(edge,eline)) @@ -700,8 +699,7 @@ class Snapper: for p in pts: snaps.append([p,'intersection',self.toWP(p)]) return snaps - - + def snapToAngles(self,shape): "returns a list of angle snap locations" snaps = [] @@ -783,7 +781,7 @@ class Snapper: else: return [] - def snapToSpecials(self,obj): + def snapToSpecials(self,obj,lastpoint=None,eline=None): "returns special snap locations, if any" snaps = [] if self.isEnabled("special"): @@ -804,6 +802,13 @@ class Snapper: else: b = obj.Placement.Base snaps.append([b,'special',self.toWP(b)]) + if obj.ViewObject.ShowNodes: + for edge in obj.Proxy.getNodeEdges(obj): + snaps.extend(self.snapToEndpoints(edge)) + snaps.extend(self.snapToMidpoint(edge)) + snaps.extend(self.snapToPerpendicular(edge,lastpoint)) + snaps.extend(self.snapToIntersection(edge)) + snaps.extend(self.snapToElines(edge,eline)) elif hasattr(obj,"SnapPoints"): for p in obj.SnapPoints: diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index ad521a44e..7ffd9bfe0 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -3487,6 +3487,18 @@ class Edit(Modifier): self.editpoints.append(self.obj.ViewObject.Proxy.getTextPosition(self.obj.ViewObject)) except: pass + elif Draft.getType(self.obj) == "Structure": + if self.obj.Nodes: + self.originalDisplayMode = self.obj.ViewObject.DisplayMode + self.originalPoints = self.obj.ViewObject.NodeSize + self.originalNodes = self.obj.ViewObject.ShowNodes + self.obj.ViewObject.DisplayMode = "Wireframe" + self.obj.ViewObject.NodeSize = 1 + self.obj.ViewObject.ShowNodes = True + for p in self.obj.Nodes: + if self.pl: + p = self.pl.multVec(p) + self.editpoints.append(p) if Draft.getType(self.obj) != "BezCurve": self.trackers = [] if self.editpoints: @@ -3521,6 +3533,10 @@ class Edit(Modifier): if self.obj: if hasattr(self.obj.ViewObject,"Selectable"): self.obj.ViewObject.Selectable = self.selectstate + if Draft.getType(self.obj) == "Structure": + self.obj.ViewObject.DisplayMode = self.originalDisplayMode + self.obj.ViewObject.NodeSize = self.originalPoints + self.obj.ViewObject.ShowNodes = self.originalNodes Modifier.finish(self) plane.restore() if FreeCADGui.Snapper.grid: @@ -3580,8 +3596,7 @@ class Edit(Modifier): self.trackers[self.editing].off() if hasattr(self.obj.ViewObject,"Selectable"): self.obj.ViewObject.Selectable = False - if "Points" in self.obj.PropertiesList: - self.node.append(self.obj.Points[self.editing]) + self.node.append(self.trackers[self.editing].get()) FreeCADGui.Snapper.setSelectMode(False) else: self.trackers[self.editing].on() @@ -3703,6 +3718,10 @@ class Edit(Modifier): elif Draft.getType(self.obj) == "Space": if self.editing == 0: self.obj.ViewObject.TextPosition = v + elif Draft.getType(self.obj) == "Structure": + nodes = self.obj.Nodes + nodes[self.editing] = self.invpl.multVec(v) + self.obj.Nodes = nodes def numericInput(self,v,numy=None,numz=None): '''this function gets called by the toolbar