[Draft] Draft Edit - various fixes (fixes #3537)

https://forum.freecadweb.org/viewtopic.php?f=3&t=29743&start=70
To solve issue with Hidpi display  (fixes #3537), but also to improve node selection, I used some of @looo code from pivy graphics into the tool. 
So:
- i got rid of the action function
- i separated selection and editing callbacks
- i got the mouse position from the callback event and not from FreeCADGui.ActiveDocument.ActiveView.getCursorPos()
- i rewrote the node selection mechanism using soraypickaction instead of getObjectInfo() and getObjectsInfo()
- i tried to put a bit of order in all the mess i made and try to document it.
- also fixed some of the preview code.
- i'm really really sorry for not being able to split the commit in multiple one, but the changes are huge and i was just able to separate minor things...
This commit is contained in:
carlopav
2019-08-15 22:07:27 +02:00
committed by Yorik van Havre
parent 12dc2e9146
commit 13e605912c

View File

@@ -23,8 +23,8 @@
#* *
#***************************************************************************
__title__="FreeCAD Draft Edit Tool"
__author__ = "Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline, Dmitry Chigrin"
__title__= "FreeCAD Draft Edit Tool"
__author__ = "Yorik van Havre, Werner Mayer, Martin Burbaum, Ken Cline, Dmitry Chigrin, Carlo Pavan"
__url__ = "http://www.freecadweb.org"
import FreeCAD
@@ -42,7 +42,6 @@ if FreeCAD.GuiUp:
from PySide.QtCore import QT_TRANSLATE_NOOP
from DraftTools import translate
class Edit():
"The Draft_Edit FreeCAD command definition"
@@ -51,12 +50,27 @@ class Edit():
self.running = False
self.trackers = []
self.obj = None
# event callbacks
self.call = None
self._keyPressedCB = None
self._mouseMovedCB = None
self._mousePressedCB = None
self.selectstate = None
self.originalDisplayMode = None
self.originalPoints = None
self.originalNodes = None
# preview
self.ghost = None
# soraypick action things
view = FreeCADGui.ActiveDocument.ActiveView.getViewer()
self.render_manager = view.getSoRenderManager()
self.pick_radius = 30 # TODO: set pick radius according to user preferences
#list of supported objects type
self.supportedObjs = ["BezCurve","Wire","BSpline","Circle","Rectangle",
"Polygon","Dimension","Space","Structure","PanelCut",
"PanelSheet","Wall", "Window"]
@@ -66,10 +80,14 @@ class Edit():
'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Edit", "Edit"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Edit", "Edits the active object")}
#---------------------------------------------------------------------------
# MAIN FUNCTIONS
#---------------------------------------------------------------------------
def Activated(self):
if self.running:
self.finish()
if self.running: self.finish()
DraftTools.Modifier.Activated(self,"Edit")
if not FreeCAD.ActiveDocument: self.finish()
self.ui = FreeCADGui.draftToolBar
self.view = Draft.get3DView()
@@ -79,84 +97,295 @@ class Edit():
else:
self.ui.selectUi()
FreeCAD.Console.PrintMessage(translate("draft", "Select a Draft object to edit")+"\n")
if self.call:
self.view.removeEventCallback("SoEvent",self.call)
self.call = self.view.addEventCallback("SoEvent",DraftTools.selectObject)
self.register_selection_callback()
def proceed(self):
"this method defines editpoints and set the editTrackers"
self.unregister_selection_callback()
self.obj = self.getObjFromSelection()
if not self.obj: return self.finish()
if self.call:
self.view.removeEventCallback("SoEvent",self.call)
self.call = None
if not FreeCAD.ActiveDocument:
self.finish()
return
self.parseSelection()
if not self.obj:
self.finish()
return
# store selectable state of the object
# store selectable state of the object TODO: Separate function
if hasattr(self.obj.ViewObject,"Selectable"):
self.selectstate = self.obj.ViewObject.Selectable
self.obj.ViewObject.Selectable = False
# start object editing
FreeCADGui.Selection.clearSelection()
self.editing = None
self.editpoints = []
self.pl = None
self.arc3Pt = True
self.arc3Pt = True # TODO: Find a more elegant way
FreeCADGui.Snapper.setSelectMode(True)
self.ui.editUi()
self.getPlacement(self.obj)
self.setPlacement(self.obj)
self.setEditPoints(self.obj)
if self.editpoints: # set trackers and align plane
self.call = self.view.addEventCallback("SoEvent",self.action)
self.setTrackers()
# set plane tracker to match edited object
FreeCAD.DraftWorkingPlane.save()
self.alignWorkingPlane()
self.editpoints = []
self.register_editing_callbacks()#register action callback
else:
FreeCAD.Console.PrintWarning(translate("draft", "No edit point found for selected object")+"\n")
self.finish()
return
def parseSelection(self):
def finish(self,closed=False):
"terminates Edit Tool"
self.unregister_selection_callback()
self.unregister_editing_callbacks()
FreeCADGui.Snapper.setSelectMode(False)
self.finalizeGhost()
if self.obj and closed:
if "Closed" in self.obj.PropertiesList:
if not self.obj.Closed:
self.obj.Closed = True
if self.ui: self.removeTrackers()
if self.obj:
if hasattr(self.obj.ViewObject,"Selectable") and (self.selectstate != None):
self.obj.ViewObject.Selectable = self.selectstate
if Draft.getType(self.obj) == "Structure":
if self.originalDisplayMode != None:
self.obj.ViewObject.DisplayMode = self.originalDisplayMode
if self.originalPoints != None:
self.obj.ViewObject.NodeSize = self.originalPoints
if self.originalNodes != None:
self.obj.ViewObject.ShowNodes = self.originalNodes
self.selectstate = None
self.originalDisplayMode = None
self.originalPoints = None
self.originalNodes = None
DraftTools.Modifier.finish(self)
FreeCAD.DraftWorkingPlane.restore()
if FreeCADGui.Snapper.grid: FreeCADGui.Snapper.grid.set()
self.running = False
# delay resetting edit mode otherwise it doesn't happen
from PySide import QtCore
QtCore.QTimer.singleShot(0,FreeCADGui.ActiveDocument.resetEdit)
#---------------------------------------------------------------------------
# SCENE EVENTS CALLBACKS
#---------------------------------------------------------------------------
def register_selection_callback(self):
"register callback for selection when command is launched"
self.unregister_selection_callback()
self.call = self.view.addEventCallback("SoEvent",DraftTools.selectObject)
def unregister_selection_callback(self):
"remove callback for selection if it exhists"
if self.call:
self.view.removeEventCallback("SoEvent",self.call)
self.call = None
def register_editing_callbacks(self):
"register callbacks to use during editing (former action function)"
view = FreeCADGui.ActiveDocument.ActiveView
self._keyPressedCB = view.addEventCallbackPivy(
coin.SoKeyboardEvent.getClassTypeId(), self.keyPressed)
self._mouseMovedCB = view.addEventCallbackPivy(
coin.SoLocation2Event.getClassTypeId(), self.mouseMoved)
self._mousePressedCB = view.addEventCallbackPivy(
coin.SoMouseButtonEvent.getClassTypeId(), self.mousePressed)
#FreeCAD.Console.PrintMessage("Draft edit callbacks registered \n")
def unregister_editing_callbacks(self):
"remove callbacks used during editing if they exhist"
view = FreeCADGui.ActiveDocument.ActiveView
if self._keyPressedCB:
view.removeEventCallbackSWIG(coin.SoKeyboardEvent.getClassTypeId(), self._keyPressedCB)
self._keyPressedCB = None
#FreeCAD.Console.PrintMessage("Draft edit keyboard callback unregistered \n")
if self._mouseMovedCB:
view.removeEventCallbackSWIG(coin.SoLocation2Event.getClassTypeId(), self._mouseMovedCB)
self._mouseMovedCB = None
#FreeCAD.Console.PrintMessage("Draft edit location callback unregistered \n")
if self._mousePressedCB:
view.removeEventCallbackSWIG(coin.SoMouseButtonEvent.getClassTypeId(), self._mousePressedCB)
self._mousePressedCB = None
#FreeCAD.Console.PrintMessage("Draft edit mouse button callback unregistered \n")
#---------------------------------------------------------------------------
# SCENE EVENT HANDLERS
#---------------------------------------------------------------------------
def keyPressed(self, event_callback):
"keyboard event handler"
event = event_callback.getEvent()
if event.getState() == coin.SoKeyboardEvent.DOWN:
key = event.getKey()
#FreeCAD.Console.PrintMessage("pressed key : "+str(key)+"\n")
if key == 65307: # ESC
if self.editing == None: self.finish()
else:
self.finalizeGhost()
self.editpoints = []
self.setEditPoints(self.obj)
self.resetTrackers()
'''elif arg["Key"] == "a":
self.finish()
elif arg["Key"] == "o":
self.finish(closed=True)
elif arg["Key"] == "i":
if Draft.getType(self.obj) == "Circle": self.arcInvert()'''
def mousePressed(self, event_callback):
"mouse button event handler, calls: startEditing, endEditing, addPoint, delPoint"
event = event_callback.getEvent()
if event.getTypeId().getName() != "SoMouseButtonEvent": return
if (event.getState() == coin.SoMouseButtonEvent.DOWN and
event.getButton() == event.BUTTON1):#left click
if self.ui.addButton.isChecked():
self.addPoint(event)
return
if self.ui.delButton.isChecked():
self.delPoint(self.obj, event)
return
if Draft.getType(self.obj) == "BezCurve":
pos = event.getPosition()
if self.ui.sharpButton.isChecked():
return self.smoothBezPoint(self.getEditNodeIndex(pos), 'Sharp')
elif self.ui.tangentButton.isChecked():
return self.smoothBezPoint(self.getEditNodeIndex(pos), 'Tangent')
elif self.ui.symmetricButton.isChecked():
return self.smoothBezPoint(self.getEditNodeIndex(pos), 'Symmetric')
if self.editing == None:
self.startEditing(event)
else:
self.endEditing()
def mouseMoved(self, event_callback):
"mouse moved event handler, update tracker position and update preview ghost"
event = event_callback.getEvent()
if self.editing != None:
self.updateTrackerAndGhost(event)
else:
# TODO add preselection color change for trackers
pass
def startEditing(self, event):
"start editing selected EditNode"
pos = event.getPosition()
ep = self.getEditNodeIndex(pos)
if ep == None:
#FreeCAD.Console.PrintMessage("Node not found\n")
return
FreeCAD.Console.PrintMessage(str("Editing node: n° ")+str(ep)+"\n")
self.ui.pointUi()
self.ui.isRelative.show()
self.editing = ep
self.trackers[self.editing].off()
self.finalizeGhost()
self.ghost = self.initGhost(self.obj)
self.node.append(self.trackers[self.editing].get())
FreeCADGui.Snapper.setSelectMode(False)
def updateTrackerAndGhost(self, event):
"updates tracker position when editing and update ghost"
pos = event.getPosition().getValue()
orthoConstrain = False
if event.wasShiftDown() == 1: orthoConstrain = True
snappedPos = FreeCADGui.Snapper.snap((pos[0],pos[1]),self.node[-1], constrain=orthoConstrain)
self.trackers[self.editing].set(snappedPos)
self.ui.displayPoint(snappedPos,self.node[-1])
if self.ghost: self.updateGhost(obj=self.obj,idx=self.editing,pt=snappedPos)
def endEditing(self):
"terminate editing and start object updating process"
self.finalizeGhost()
self.trackers[self.editing].on()
#if hasattr(self.obj.ViewObject,"Selectable"):
# self.obj.ViewObject.Selectable = True
FreeCADGui.Snapper.setSelectMode(True)
self.numericInput(self.trackers[self.editing].get())
DraftTools.redraw3DView()
def getContextMenuEntries(self, event):
"return subcommands to add to context menu while draft Edit is active"
pass #TODO implement right click menu to add/delete nodes and change Bezcurve nodes
#---------------------------------------------------------------------------
# UTILS
#---------------------------------------------------------------------------
def getObjFromSelection(self):
"evaluate selection and returns a valid object to edit"
selection = FreeCADGui.Selection.getSelection()
if len(selection) != 1:
FreeCAD.Console.PrintMessage(translate("draft", "Please select exactly one object")+"\n")
self.finish()
return
return None
if "Proxy" in selection[0].PropertiesList and hasattr(selection[0].Proxy,"Type"):
if Draft.getType(selection[0]) in self.supportedObjs:
self.obj = selection[0]
return
return selection[0]
FreeCAD.Console.PrintWarning(translate("draft", "This object is not editable")+"\n")
return
return None
def getPlacement(self,obj):
def numericInput(self,v,numy=None,numz=None):
'''this function gets called by the toolbar
or by the mouse click and activate the update function'''
if (numy != None):
v = Vector(v,numy,numz)
self.update(v)
FreeCAD.ActiveDocument.recompute()
self.editing = None
self.ui.editUi(self.ui.lastMode)
self.node = []
def setPlacement(self,obj):
"set self.pl and self.invpl to self.obj placement and inverse placement"
if "Placement" in obj.PropertiesList:
self.pl = obj.Placement
self.invpl = self.pl.inverse()
def alignWorkingPlane(self):
"align working plane to self.obj"
if "Shape" in self.obj.PropertiesList:
if DraftTools.plane.weak:
DraftTools.plane.alignToFace(self.obj.Shape)
if self.planetrack:
self.planetrack.set(self.editpoints[0])
def getEditNodeIndex(self, pos):
"get edit node index from given screen position"
ep = self.sendRay(pos)
return ep
def sendRay(self, mouse_pos):
"sends a ray trough the scene and return the nearest entity"
ray_pick = coin.SoRayPickAction(self.render_manager.getViewportRegion())
ray_pick.setPoint(coin.SbVec2s(*mouse_pos))
ray_pick.setRadius(self.pick_radius)
ray_pick.setPickAll(True)
ray_pick.apply(self.render_manager.getSceneGraph())
picked_point = ray_pick.getPickedPointList()
return self.searchEditNode(picked_point)
def searchEditNode(self, picked_point):
"search edit node inside picked point list and retrurn node number"
for point in picked_point:
path = point.getPath()
length = path.getLength()
point = path.getNode(length - 2)
import DraftTrackers
if hasattr(point,"subElementName"):
subElement = str(point.subElementName.getValue())
if 'EditNode' in subElement:
ep = int(subElement[8:])
#doc = FreeCAD.getDocument(str(point.documentName.getValue()))
#self.obj = doc.getObject(str(point.objectName.getValue()))
return ep
#FreeCAD.Console.PrintMessage(str(self.obj)+str(ep)+"\n")
return None
#---------------------------------------------------------------------------
# EDIT TRACKERS functions
#---------------------------------------------------------------------------
def setTrackers(self):
"set Edit Trackers for editpoints collected from self.obj"
self.trackers = []
@@ -164,7 +393,7 @@ class Edit():
self.resetTrackersBezier()
else:
for ep in range(len(self.editpoints)):
self.trackers.append(editTracker(self.editpoints[ep],self.obj.Name,ep))
self.trackers.append(editTracker(pos=self.editpoints[ep],name=self.obj.Name,idx=ep))
def resetTrackers(self):
"reset Edit Trackers and set them again"
@@ -188,191 +417,12 @@ class Edit():
for t in self.trackers:
t.on()
def action(self,arg):
"scene event handler"
if arg["Type"] == "SoKeyboardEvent" and arg["State"] == "DOWN":
if arg["Key"] == "ESCAPE":
self.finish()
elif arg["Key"] == "a":
self.finish()
elif arg["Key"] == "o":
self.finish(closed=True)
elif arg["Key"] == "i":
if Draft.getType(self.obj) == "Circle": self.arcInvert()
elif arg["Type"] == "SoLocation2Event": #mouse movement detection
self.point,ctrlPoint,info = DraftTools.getPoint(self,arg)# causes problems when mouseover bezcurves
if self.editing != None:
self.trackers[self.editing].set(self.point)
#FreeCAD.Console.PrintMessage(self.ghost)
self.updateGhost(obj=self.obj,idx=self.editing,pt=self.point)
if hasattr(self.obj.ViewObject,"Selectable"):
if self.ui.addButton.isChecked():
self.obj.ViewObject.Selectable = True
else:
self.obj.ViewObject.Selectable = False
DraftTools.redraw3DView()
elif arg["Type"] == "SoMouseButtonEvent" and arg["State"] == "DOWN":
if arg["Button"] == "BUTTON1":
self.ui.redraw()
if self.editing == None:
# USECASE: User click on one of the editpoints or another object
ep = None
selobjs = self.getSelection()
if selobjs == None: return
if self.ui.addButton.isChecked():# still quite raw
# USECASE: User add a new point to the object
for info in selobjs:
if Draft.getType(self.obj) == "Wire" and 'Edge' in info["Component"]:
pt = FreeCAD.Vector(info["x"],info["y"],info["z"])
self.addPointToWire(pt, int(info["Component"][4:]))
elif self.point:
pt = self.point
if "x" in info:# prefer "real" 3D location over working-plane-driven one if possible
pt = FreeCAD.Vector(info["x"],info["y"],info["z"])
self.addPointToCurve(pt,info)
self.removeTrackers()
self.editpoints = []
self.setEditPoints(self.obj)
self.resetTrackers()
return
ep = self.lookForClickedNode(selobjs,tolerance=20)
if ep == None: return
if self.ui.delButton.isChecked(): # still quite raw
# USECASE: User delete a point of the object
self.delPoint(ep)
# don't do tan/sym on DWire/BSpline!
self.removeTrackers()
self.editpoints = []
self.setEditPoints(self.obj)
self.resetTrackers()
return
if Draft.getType(self.obj) == "BezCurve":
# USECASE: User change the continuity of a Bezcurve point
if self.ui.sharpButton.isChecked():
return self.smoothBezPoint(ep, 'Sharp')
elif self.ui.tangentButton.isChecked():
return self.smoothBezPoint(ep, 'Tangent')
elif self.ui.symmetricButton.isChecked():
return self.smoothBezPoint(ep, 'Symmetric')
if self.ui.arc3PtButton.isChecked():
self.arc3Pt = False
else:
self.arc3Pt = True
self.ui.pointUi()
self.ui.isRelative.show()
self.editing = ep
self.trackers[self.editing].off()
self.finalizeGhost()
self.ghost = self.initGhost(self.obj)
'''if hasattr(self.obj.ViewObject,"Selectable"):
self.obj.ViewObject.Selectable = False'''
self.node.append(self.trackers[self.editing].get())
FreeCADGui.Snapper.setSelectMode(False)
else: #if self.editing != None:
# USECASE: Destination point of editing is clicked
self.finalizeGhost()
self.trackers[self.editing].on()
#if hasattr(self.obj.ViewObject,"Selectable"):
# self.obj.ViewObject.Selectable = True
FreeCADGui.Snapper.setSelectMode(True)
self.numericInput(self.trackers[self.editing].get())
def getSelection(self):
p = FreeCADGui.ActiveDocument.ActiveView.getCursorPos()
selobjs = FreeCADGui.ActiveDocument.ActiveView.getObjectsInfo(p)
if not selobjs:
selobjs = [FreeCADGui.ActiveDocument.ActiveView.getObjectInfo(p)]
if not selobjs or selobjs == [None]:
return None
else: return selobjs
def lookForClickedNode(self,selobjs,tolerance=20):
for info in selobjs:
#if info["Object"] == self.obj.Name:
# return
if ('EditNode' in info["Component"]):#True as a result of getObjectInfo
ep = int(info["Component"][8:])
elif ('Vertex' in info["Component"]):# if vertex is clicked, the edit point is selected only if (distance < tolerance)
p = FreeCAD.Vector(info["x"],info["y"],info["z"])
for i,t in enumerate(self.trackers):
if (t.get().sub(p)).Length <= 0.01:
ep = i
break
elif ('Edge' in info["Component"]) or ('Face' in info["Component"]) : # if edge is clicked, the nearest edit point is selected, then tolerance is verified
p = FreeCAD.Vector(info["x"],info["y"],info["z"])
d = 1000000.0
for i,t in enumerate(self.trackers):
if (t.get().sub(p)).Length < d:
d = (t.get().sub(p)).Length
ep = i
if d > tolerance:# should find a way to link the tolerance to zoom
return
return ep
def numericInput(self,v,numy=None,numz=None):
'''this function gets called by the toolbar
or by the mouse click and activate the update function'''
if (numy != None):
v = Vector(v,numy,numz)
self.update(v)
FreeCAD.ActiveDocument.recompute()
self.editing = None
self.ui.editUi(self.ui.lastMode)
self.node = []
def finish(self,closed=False):
"terminates Edit Tool"
FreeCADGui.Snapper.setSelectMode(False)
if self.obj and closed:
if "Closed" in self.obj.PropertiesList:
if not self.obj.Closed:
self.obj.Closed = True
if self.ui:
if self.trackers:
for t in self.trackers:
t.finalize()
self.finalizeGhost()
if self.obj:
if hasattr(self.obj.ViewObject,"Selectable") and (self.selectstate != None):
self.obj.ViewObject.Selectable = self.selectstate
if Draft.getType(self.obj) == "Structure":
if self.originalDisplayMode != None:
self.obj.ViewObject.DisplayMode = self.originalDisplayMode
if self.originalPoints != None:
self.obj.ViewObject.NodeSize = self.originalPoints
if self.originalNodes != None:
self.obj.ViewObject.ShowNodes = self.originalNodes
self.selectstate = None
self.originalDisplayMode = None
self.originalPoints = None
self.originalNodes = None
DraftTools.Modifier.finish(self)
FreeCAD.DraftWorkingPlane.restore()
if FreeCADGui.Snapper.grid:
FreeCADGui.Snapper.grid.set()
self.running = False
# delay resetting edit mode otherwise it doesn't happen
from PySide import QtCore
QtCore.QTimer.singleShot(0,FreeCADGui.ActiveDocument.resetEdit)
#---------------------------------------------------------------------------
# PREVIEW
#---------------------------------------------------------------------------
def initGhost(self,obj):
"initialize preview ghost"
if Draft.getType(obj) == "Wire":
return wireTracker(obj.Shape)
elif Draft.getType(obj) == "BSpline":
@@ -402,40 +452,46 @@ class Edit():
self.ghost.update(pointList,obj.Degree)
elif Draft.getType(obj) == "Circle":
self.ghost.on()
if self.arc3Pt == False:
self.ghost.setCenter(obj.Placement.Base)
self.ghost.setRadius(obj.Radius)
self.ghost.setStartAngle(math.radians(obj.FirstAngle))
self.ghost.setEndAngle(math.radians(obj.LastAngle))
if self.editing == 0:
self.ghost.setCenter(pt)
elif self.editing == 1:
self.ghost.setStartPoint(pt)
elif self.editing == 2:
self.ghost.setEndPoint(pt)
elif self.editing == 3:
self.ghost.setRadius(self.invpl.multVec(pt).Length)
elif self.arc3Pt == True:
if self.editing == 0:#center point
import DraftVecUtils
p1 = self.invpl.multVec(self.obj.Shape.Vertexes[0].Point)
p2 = self.invpl.multVec(self.obj.Shape.Vertexes[1].Point)
p0 = DraftVecUtils.project(self.invpl.multVec(pt),self.invpl.multVec(self.getArcMid()))
self.ghost.autoinvert=False
self.ghost.setRadius(p1.sub(p0).Length)
self.ghost.setStartPoint(self.obj.Shape.Vertexes[1].Point)
self.ghost.setEndPoint(self.obj.Shape.Vertexes[0].Point)
self.ghost.setCenter(self.pl.multVec(p0))
return
else:
p1=self.obj.Shape.Vertexes[0].Point
p2=self.getArcMid()
p3=self.obj.Shape.Vertexes[1].Point
if self.editing == 1: p1=pt
elif self.editing == 3: p2=pt
elif self.editing == 2: p3=pt
self.ghost.setBy3Points(p1,p2,p3)
self.ghost.setCenter(obj.Placement.Base)
self.ghost.setRadius(obj.Radius)
if self.obj.FirstAngle == self.obj.LastAngle:#self.obj is a circle
self.ghost.circle = True
if self.editing == 0: self.ghost.setCenter(pt)
elif self.editing == 1:
radius = pt.sub(obj.Placement.Base).Length
self.ghost.setRadius(radius)
else:
if self.arc3Pt == False:
self.ghost.setStartAngle(math.radians(obj.FirstAngle))
self.ghost.setEndAngle(math.radians(obj.LastAngle))
if self.editing == 0:
self.ghost.setCenter(pt)
elif self.editing == 1:
self.ghost.setStartPoint(pt)
elif self.editing == 2:
self.ghost.setEndPoint(pt)
elif self.editing == 3:
self.ghost.setRadius(self.invpl.multVec(pt).Length)
elif self.arc3Pt == True:
if self.editing == 0:#center point
import DraftVecUtils
p1 = self.invpl.multVec(self.obj.Shape.Vertexes[0].Point)
p2 = self.invpl.multVec(self.obj.Shape.Vertexes[1].Point)
p0 = DraftVecUtils.project(self.invpl.multVec(pt),self.invpl.multVec(self.getArcMid()))
self.ghost.autoinvert=False
self.ghost.setRadius(p1.sub(p0).Length)
self.ghost.setStartPoint(self.obj.Shape.Vertexes[1].Point)
self.ghost.setEndPoint(self.obj.Shape.Vertexes[0].Point)
self.ghost.setCenter(self.pl.multVec(p0))
return
else:
p1=self.obj.Shape.Vertexes[0].Point
p2=self.getArcMid()
p3=self.obj.Shape.Vertexes[1].Point
if self.editing == 1: p1=pt
elif self.editing == 3: p2=pt
elif self.editing == 2: p3=pt
self.ghost.setBy3Points(p1,p2,p3)
DraftTools.redraw3DView()
def applyPlacement(self,pointList):
@@ -457,6 +513,31 @@ class Edit():
# EDIT OBJECT TOOLS : Add/Delete Vertexes
#---------------------------------------------------------------------------
def addPoint(self,event):
"called by action, add point to obj and reset trackers"
if not (Draft.getType(self.obj) in ["Wire","BSpline","BezCurve"]): return
pos = event.getPosition()
selobjs = FreeCADGui.ActiveDocument.ActiveView.getObjectsInfo((pos[0],pos[1]))
if not selobjs: return
for info in selobjs:
if not info: return
if self.obj.Name != info["Object"]: continue
if Draft.getType(self.obj) == "Wire" and 'Edge' in info["Component"]:
pt = FreeCAD.Vector(info["x"],info["y"],info["z"])
self.addPointToWire(pt, int(info["Component"][4:]))
elif Draft.getType(self.obj) in ["BSpline","BezCurve"]: #to fix double vertex created
#pt = self.point
if "x" in info:# prefer "real" 3D location over working-plane-driven one if possible
pt = FreeCAD.Vector(info["x"],info["y"],info["z"])
else: continue
self.addPointToCurve(pt,info)
self.obj.recompute()
self.editpoints = []
self.setEditPoints(self.obj)
self.resetTrackers()
return
def addPointToWire(self, newPoint, edgeIndex):
newPoints = []
hasAddedPoint = False
@@ -468,8 +549,6 @@ class Edit():
if not hasAddedPoint:
newPoints.append(point)
self.obj.Points = newPoints
FreeCAD.ActiveDocument.recompute()
self.resetTrackers()
def addPointToCurve(self,point,info=None):
import Part
@@ -521,21 +600,26 @@ class Edit():
if ( self.obj.Closed ) and ( uNewPoint > uPoints[-1] ) :
pts.append(self.invpl.multVec(point))
self.obj.Points = pts
FreeCAD.ActiveDocument.recompute()
self.resetTrackers()
def delPoint(self,point):
if not (Draft.getType(self.obj) in ["Wire","BSpline","BezCurve"]): return
if len(self.obj.Points) <= 2:
FreeCAD.Console.PrintWarning(translate("draft", "Active object must have more than two points/nodes")+"\n")
else:
pts = self.obj.Points
pts.pop(point)
self.obj.Points = pts
if Draft.getType(self.obj) =="BezCurve":
self.obj.Proxy.resetcontinuity(self.obj)
FreeCAD.ActiveDocument.recompute()
self.resetTrackers()
def delPoint(self,obj,event):
if not (Draft.getType(obj) in ["Wire","BSpline","BezCurve"]): return
if len(obj.Points) <= 2: return FreeCAD.Console.PrintWarning(
translate("draft", "Active object must have more than two points/nodes")+"\n")
pos = event.getPosition()
ep = self.getEditNodeIndex(pos)
if ep == None: return FreeCAD.Console.PrintWarning(
translate("draft", "Node not found\n"))
pts = obj.Points
pts.pop(ep)
self.obj.Points = pts
if Draft.getType(obj) =="BezCurve":
self.obj.Proxy.resetcontinuity(obj)
obj.recompute()
# don't do tan/sym on DWire/BSpline!
self.editpoints = []
self.setEditPoints(self.obj)
self.resetTrackers()
#---------------------------------------------------------------------------
# EDIT OBJECT TOOLS : GENERAL
@@ -881,7 +965,7 @@ class Edit():
p = self.obj.Placement
p.move(delta)
self.obj.Placement = p
self.getPlacement(self.obj)
self.setPlacement(self.obj)
self.updateCirclePts(0,1,0,0)
if self.editing == 1:
self.obj.Radius = delta.Length
@@ -897,7 +981,7 @@ class Edit():
p = self.obj.Placement
p.move(delta)
self.obj.Placement = p
self.getPlacement(self.obj)
self.setPlacement(self.obj)
self.updateCirclePts(0,1,1,1)
elif self.editing == 1:
self.obj.FirstAngle=dangle
@@ -923,7 +1007,7 @@ class Edit():
self.obj.FirstAngle = -math.degrees(DraftVecUtils.angle(p1.sub(p0)))
self.obj.LastAngle = -math.degrees(DraftVecUtils.angle(p2.sub(p0)))
self.obj.Placement.Base = self.pl.multVec(p0)
self.getPlacement(self.obj)
self.setPlacement(self.obj)
self.updateCirclePts(1,0,0,1)
return
else:
@@ -942,7 +1026,7 @@ class Edit():
arc=Part.ArcOfCircle(p1,p2,p3)
e = arc.toShape()
self.obj.Placement.Base=arc.Center
self.getPlacement(self.obj)
self.setPlacement(self.obj)
self.obj.Radius = arc.Radius
delta = self.invpl.multVec(p1)
dangleF = math.degrees(math.atan2(delta[1],delta[0]))
@@ -1029,12 +1113,12 @@ class Edit():
if Draft.getType(self.obj.Base) in ["Wire","Circle","Rectangle",
"Polygon"]:
self.obj=self.obj.Base
self.getPlacement(self.obj.Base)
self.setPlacement(self.obj.Base)
elif Draft.getType(self.obj.Base) == "Sketch":
if self.obj.Base.GeometryCount == 1:
self.editpoints.append(self.obj.Base.getPoint(0,1))
self.editpoints.append(self.obj.Base.getPoint(0,2))
self.getPlacement(self.obj.Base)
self.setPlacement(self.obj.Base)
else:
FreeCAD.Console.PrintWarning(translate("draft","Wall base sketch is too complex to edit: it's suggested to edit directly the sketch")+"\n")