Merge branch 'Moult-fix-draft-edit-with-modifiers'
This commit is contained in:
@@ -1488,12 +1488,62 @@ def cut(object1,object2):
|
||||
|
||||
return obj
|
||||
|
||||
def moveVertex(object, vertex_index, vector):
|
||||
points = object.Points
|
||||
points[vertex_index] = points[vertex_index].add(vector)
|
||||
object.Points = points
|
||||
|
||||
def moveEdge(object, edge_index, vector):
|
||||
moveVertex(object, edge_index, vector)
|
||||
if isClosedEdge(edge_index, object):
|
||||
moveVertex(object, 0, vector)
|
||||
else:
|
||||
moveVertex(object, edge_index+1, vector)
|
||||
|
||||
def copyMovedEdges(arguments):
|
||||
copied_edges = []
|
||||
for argument in arguments:
|
||||
copied_edges.append(copyMovedEdge(argument[0], argument[1], argument[2]))
|
||||
joinWires(copied_edges)
|
||||
|
||||
def copyMovedEdge(object, edge_index, vector):
|
||||
vertex1 = object.Placement.multVec(object.Points[edge_index]).add(vector)
|
||||
if isClosedEdge(edge_index, object):
|
||||
vertex2 = object.Placement.multVec(object.Points[0]).add(vector)
|
||||
else:
|
||||
vertex2 = object.Placement.multVec(object.Points[edge_index+1]).add(vector)
|
||||
return makeLine(vertex1, vertex2)
|
||||
|
||||
def copyRotatedEdges(arguments):
|
||||
copied_edges = []
|
||||
for argument in arguments:
|
||||
copied_edges.append(copyRotatedEdge(argument[0], argument[1],
|
||||
argument[2], argument[3], argument[4]))
|
||||
joinWires(copied_edges)
|
||||
|
||||
def copyRotatedEdge(object, edge_index, angle, center, axis):
|
||||
vertex1 = rotateVectorFromCenter(
|
||||
object.Placement.multVec(object.Points[edge_index]),
|
||||
angle, axis, center)
|
||||
if isClosedEdge(edge_index, object):
|
||||
vertex2 = rotateVectorFromCenter(
|
||||
object.Placement.multVec(object.Points[0]),
|
||||
angle, axis, center)
|
||||
else:
|
||||
vertex2 = rotateVectorFromCenter(
|
||||
object.Placement.multVec(object.Points[edge_index+1]),
|
||||
angle, axis, center)
|
||||
return makeLine(vertex1, vertex2)
|
||||
|
||||
def isClosedEdge(edge_index, object):
|
||||
return edge_index + 1 >= len(object.Points)
|
||||
|
||||
def move(objectslist,vector,copy=False):
|
||||
'''move(objects,vector,[copy]): Moves the objects contained
|
||||
in objects (that can be an object or a list of objects)
|
||||
in the direction and distance indicated by the given
|
||||
vector. If copy is True, the actual objects are not moved, but copies
|
||||
are created instead.he objects (or their copies) are returned.'''
|
||||
are created instead. The objects (or their copies) are returned.'''
|
||||
typecheck([(vector,Vector), (copy,bool)], "move")
|
||||
if not isinstance(objectslist,list): objectslist = [objectslist]
|
||||
objectslist.extend(getMovableChildren(objectslist))
|
||||
@@ -1651,6 +1701,26 @@ def filterObjectsForModifiers(objects, isCopied=False):
|
||||
filteredObjects.append(object)
|
||||
return filteredObjects
|
||||
|
||||
def rotateVertex(object, vertex_index, angle, center, axis):
|
||||
points = object.Points
|
||||
points[vertex_index] = object.Placement.inverse().multVec(
|
||||
rotateVectorFromCenter(
|
||||
object.Placement.multVec(points[vertex_index]),
|
||||
angle, axis, center))
|
||||
object.Points = points
|
||||
|
||||
def rotateVectorFromCenter(vector, angle, axis, center):
|
||||
rv = vector.sub(center)
|
||||
rv = DraftVecUtils.rotate(rv, math.radians(angle), axis)
|
||||
return center.add(rv)
|
||||
|
||||
def rotateEdge(object, edge_index, angle, center, axis):
|
||||
rotateVertex(object, edge_index, angle, center, axis)
|
||||
if isClosedEdge(edge_index, object):
|
||||
rotateVertex(object, 0, angle, center, axis)
|
||||
else:
|
||||
rotateVertex(object, edge_index+1, angle, center, axis)
|
||||
|
||||
def rotate(objectslist,angle,center=Vector(0,0,0),axis=Vector(0,0,1),copy=False):
|
||||
'''rotate(objects,angle,[center,axis,copy]): Rotates the objects contained
|
||||
in objects (that can be a list of objects or an object) of the given angle
|
||||
@@ -1719,95 +1789,105 @@ def rotate(objectslist,angle,center=Vector(0,0,0),axis=Vector(0,0,1),copy=False)
|
||||
if len(newobjlist) == 1: return newobjlist[0]
|
||||
return newobjlist
|
||||
|
||||
def scale(objectslist,delta=Vector(1,1,1),center=Vector(0,0,0),copy=False,legacy=False):
|
||||
def scaleVectorFromCenter(vector, scale, center):
|
||||
return vector.sub(center).scale(scale.x, scale.y, scale.z).add(center)
|
||||
|
||||
def scaleVertex(object, vertex_index, scale, center):
|
||||
points = object.Points
|
||||
points[vertex_index] = object.Placement.inverse().multVec(
|
||||
scaleVectorFromCenter(
|
||||
object.Placement.multVec(points[vertex_index]),
|
||||
scale, center))
|
||||
object.Points = points
|
||||
|
||||
def scaleEdge(object, edge_index, scale, center):
|
||||
scaleVertex(object, edge_index, scale, center)
|
||||
if isClosedEdge(edge_index, object):
|
||||
scaleVertex(object, 0, scale, center)
|
||||
else:
|
||||
scaleVertex(object, edge_index+1, scale, center)
|
||||
|
||||
def copyScaledEdges(arguments):
|
||||
copied_edges = []
|
||||
for argument in arguments:
|
||||
copied_edges.append(copyScaledEdge(argument[0], argument[1],
|
||||
argument[2], argument[3]))
|
||||
joinWires(copied_edges)
|
||||
|
||||
def copyScaledEdge(object, edge_index, scale, center):
|
||||
vertex1 = scaleVectorFromCenter(
|
||||
object.Placement.multVec(object.Points[edge_index]),
|
||||
scale, center)
|
||||
if isClosedEdge(edge_index, object):
|
||||
vertex2 = scaleVectorFromCenter(
|
||||
object.Placement.multVec(object.Points[0]),
|
||||
scale, center)
|
||||
else:
|
||||
vertex2 = scaleVectorFromCenter(
|
||||
object.Placement.multVec(object.Points[edge_index+1]),
|
||||
scale, center)
|
||||
return makeLine(vertex1, vertex2)
|
||||
|
||||
def scale(objectslist,scale=Vector(1,1,1),center=Vector(0,0,0),copy=False):
|
||||
'''scale(objects,vector,[center,copy,legacy]): Scales the objects contained
|
||||
in objects (that can be a list of objects or an object) of the given scale
|
||||
factors defined by the given vector (in X, Y and Z directions) around
|
||||
given center. If legacy is True, direct (old) mode is used, otherwise
|
||||
a parametric copy is made. If copy is True, the actual objects are not moved,
|
||||
but copies are created instead. The objects (or their copies) are returned.'''
|
||||
if not isinstance(objectslist,list): objectslist = [objectslist]
|
||||
if legacy:
|
||||
newobjlist = []
|
||||
for obj in objectslist:
|
||||
if copy:
|
||||
newobj = makeCopy(obj)
|
||||
else:
|
||||
newobj = obj
|
||||
if obj.isDerivedFrom("Part::Feature"):
|
||||
sh = obj.Shape.copy()
|
||||
m = FreeCAD.Matrix()
|
||||
m.scale(delta)
|
||||
sh = sh.transformGeometry(m)
|
||||
corr = Vector(center.x,center.y,center.z)
|
||||
corr.scale(delta.x,delta.y,delta.z)
|
||||
corr = (corr.sub(center)).negative()
|
||||
sh.translate(corr)
|
||||
if getType(obj) == "Rectangle":
|
||||
p = []
|
||||
for v in sh.Vertexes: p.append(v.Point)
|
||||
pl = obj.Placement.copy()
|
||||
pl.Base = p[0]
|
||||
diag = p[2].sub(p[0])
|
||||
bb = p[1].sub(p[0])
|
||||
bh = p[3].sub(p[0])
|
||||
nb = DraftVecUtils.project(diag,bb)
|
||||
nh = DraftVecUtils.project(diag,bh)
|
||||
if obj.Length < 0: l = -nb.Length
|
||||
else: l = nb.Length
|
||||
if obj.Height < 0: h = -nh.Length
|
||||
else: h = nh.Length
|
||||
newobj.Length = l
|
||||
newobj.Height = h
|
||||
tr = p[0].sub(obj.Shape.Vertexes[0].Point)
|
||||
newobj.Placement = pl
|
||||
elif getType(obj) == "Wire":
|
||||
p = []
|
||||
for v in sh.Vertexes: p.append(v.Point)
|
||||
#print(p)
|
||||
newobj.Points = p
|
||||
elif getType(obj) == "BSpline":
|
||||
p = []
|
||||
for p1 in obj.Points:
|
||||
p2 = p1.sub(center)
|
||||
p2.scale(delta.x,delta.y,delta.z)
|
||||
p.append(p2)
|
||||
newobj.Points = p
|
||||
elif (obj.isDerivedFrom("Part::Feature")):
|
||||
newobj.Shape = sh
|
||||
elif (obj.TypeId == "App::Annotation"):
|
||||
factor = delta.y * obj.ViewObject.FontSize
|
||||
newobj.ViewObject.FontSize = factor
|
||||
d = obj.Position.sub(center)
|
||||
newobj.Position = center.add(Vector(d.x*delta.x,d.y*delta.y,d.z*delta.z))
|
||||
if copy:
|
||||
formatObject(newobj,obj)
|
||||
newobjlist.append(newobj)
|
||||
if copy and getParam("selectBaseObjects",False):
|
||||
select(objectslist)
|
||||
given center. If copy is True, the actual objects are not moved, but copies
|
||||
are created instead. The objects (or their copies) are returned.'''
|
||||
if not isinstance(objectslist, list):
|
||||
objectslist = [objectslist]
|
||||
newobjlist = []
|
||||
for obj in objectslist:
|
||||
if copy:
|
||||
newobj = makeCopy(obj)
|
||||
else:
|
||||
select(newobjlist)
|
||||
if len(newobjlist) == 1: return newobjlist[0]
|
||||
return newobjlist
|
||||
newobj = obj
|
||||
if obj.isDerivedFrom("Part::Feature"):
|
||||
scaled_shape = obj.Shape.copy()
|
||||
m = FreeCAD.Matrix()
|
||||
m.move(obj.Placement.Base.negative())
|
||||
m.move(center.negative())
|
||||
m.multiply(scale)
|
||||
m.move(center)
|
||||
m.move(obj.Placement.Base)
|
||||
scaled_shape = scaled_shape.transformGeometry(m)
|
||||
if getType(obj) == "Rectangled":
|
||||
p = []
|
||||
for v in scaled_shape.Vertexes: p.append(v.Point)
|
||||
pl = obj.Placement.copy()
|
||||
pl.Base = p[0]
|
||||
diag = p[2].sub(p[0])
|
||||
bb = p[1].sub(p[0])
|
||||
bh = p[3].sub(p[0])
|
||||
nb = DraftVecUtils.project(diag,bb)
|
||||
nh = DraftVecUtils.project(diag,bh)
|
||||
if obj.Length < 0: l = -nb.Length
|
||||
else: l = nb.Length
|
||||
if obj.Height < 0: h = -nh.Length
|
||||
else: h = nh.Length
|
||||
newobj.Length = l
|
||||
newobj.Height = h
|
||||
tr = p[0].sub(obj.Shape.Vertexes[0].Point)
|
||||
newobj.Placement = pl
|
||||
elif getType(obj) == "Wire" or getType(obj) == "BSpline":
|
||||
for index, point in enumerate(newobj.Points):
|
||||
scaleVertex(newobj, index, scale, center)
|
||||
elif (obj.isDerivedFrom("Part::Feature")):
|
||||
newobj.Shape = scaled_shape
|
||||
elif (obj.TypeId == "App::Annotation"):
|
||||
factor = scale.y * obj.ViewObject.FontSize
|
||||
newobj.ViewObject.FontSize = factor
|
||||
d = obj.Position.sub(center)
|
||||
newobj.Position = center.add(Vector(d.x*scale.x,d.y*scale.y,d.z*scale.z))
|
||||
if copy:
|
||||
formatObject(newobj,obj)
|
||||
newobjlist.append(newobj)
|
||||
if copy and getParam("selectBaseObjects",False):
|
||||
select(objectslist)
|
||||
else:
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Scale")
|
||||
_Clone(obj)
|
||||
obj.Objects = objectslist
|
||||
obj.Scale = delta
|
||||
corr = Vector(center.x,center.y,center.z)
|
||||
corr.scale(delta.x,delta.y,delta.z)
|
||||
corr = (corr.sub(center)).negative()
|
||||
p = obj.Placement
|
||||
p.move(corr)
|
||||
obj.Placement = p
|
||||
if not copy:
|
||||
for o in objectslist:
|
||||
o.ViewObject.hide()
|
||||
if gui:
|
||||
_ViewProviderClone(obj.ViewObject)
|
||||
formatObject(obj,objectslist[-1])
|
||||
select(obj)
|
||||
return obj
|
||||
select(newobjlist)
|
||||
if len(newobjlist) == 1: return newobjlist[0]
|
||||
return newobjlist
|
||||
|
||||
def offset(obj,delta,copy=False,bind=False,sym=False,occ=False):
|
||||
'''offset(object,delta,[copymode],[bind]): offsets the given wire by
|
||||
|
||||
@@ -109,6 +109,7 @@ inCommandShortcuts = {
|
||||
"Continue": ["T",translate("draft","Continue"), "continueCmd"],
|
||||
"Close": ["O",translate("draft","Close"), "closeButton"],
|
||||
"Copy": ["P",translate("draft","Copy"), "isCopy"],
|
||||
"SubelementMode": ["D",translate("draft","Subelement mode"), "isSubelementMode"],
|
||||
"Fill": ["L",translate("draft","Fill"), "hasFill"],
|
||||
"Exit": ["A",translate("draft","Exit"), "finishButton"],
|
||||
"Snap": ["S",translate("draft","Snap On/Off"), None],
|
||||
@@ -606,6 +607,7 @@ class DraftToolBar:
|
||||
self.currentViewButton = self._pushbutton("view", self.layout,icon="view-isometric")
|
||||
self.resetPlaneButton = self._pushbutton("none", self.layout,icon="view-axonometric")
|
||||
self.isCopy = self._checkbox("isCopy",self.layout,checked=False)
|
||||
self.isSubelementMode = self._checkbox("isSubelementMode",self.layout,checked=False)
|
||||
gl = QtGui.QHBoxLayout()
|
||||
self.layout.addLayout(gl)
|
||||
self.gridLabel = self._label("gridLabel", gl)
|
||||
@@ -830,6 +832,8 @@ class DraftToolBar:
|
||||
self.resetPlaneButton.setToolTip(translate("draft", "Do not project points to a drawing plane"))
|
||||
self.isCopy.setText(translate("draft", "Copy")+" ("+inCommandShortcuts["Copy"][0]+")")
|
||||
self.isCopy.setToolTip(translate("draft", "If checked, objects will be copied instead of moved. Preferences -> Draft -> Global copy mode to keep this mode in next commands"))
|
||||
self.isSubelementMode.setText(translate("draft", "Modify subelements")+" ("+inCommandShortcuts["SubelementMode"][0]+")")
|
||||
self.isSubelementMode.setToolTip(translate("draft", "If checked, subelements will be modified instead of entire objects"))
|
||||
self.SStringValue.setToolTip(translate("draft", "Text string to draw"))
|
||||
self.labelSString.setText(translate("draft", "String"))
|
||||
self.SSizeValue.setToolTip(translate("draft", "Height of text"))
|
||||
@@ -1243,6 +1247,7 @@ class DraftToolBar:
|
||||
|
||||
def modUi(self):
|
||||
self.isCopy.show()
|
||||
self.isSubelementMode.show()
|
||||
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
|
||||
if p.GetBool("copymode",True):
|
||||
self.isCopy.setChecked(p.GetBool("copymodeValue",False))
|
||||
@@ -1727,6 +1732,10 @@ class DraftToolBar:
|
||||
if self.isCopy.isVisible():
|
||||
self.isCopy.setChecked(not self.isCopy.isChecked())
|
||||
spec = True
|
||||
elif txt.upper().endswith(inCommandShortcuts["SubelementMode"][0]):
|
||||
if self.isSubelementMode.isVisible():
|
||||
self.isSubelementMode.setChecked(not self.isSubelementMode.isChecked())
|
||||
spec = True
|
||||
if spec:
|
||||
for i,k in enumerate([self.xValue,self.yValue,self.zValue,self.lengthValue,self.angleValue]):
|
||||
if (k.property("text") == txt):
|
||||
@@ -2365,17 +2374,12 @@ class ScaleTaskPanel:
|
||||
layout.addWidget(self.lock,3,0,1,2)
|
||||
self.relative = QtGui.QCheckBox()
|
||||
layout.addWidget(self.relative,4,0,1,2)
|
||||
self.rLabel = QtGui.QLabel()
|
||||
layout.addWidget(self.rLabel,5,0,1,2)
|
||||
self.isClone = QtGui.QRadioButton()
|
||||
layout.addWidget(self.isClone,6,0,1,2)
|
||||
self.isClone.setChecked(True)
|
||||
self.isOriginal = QtGui.QRadioButton()
|
||||
layout.addWidget(self.isOriginal,7,0,1,2)
|
||||
self.isCopy = QtGui.QRadioButton()
|
||||
layout.addWidget(self.isCopy,8,0,1,2)
|
||||
self.isCopy = QtGui.QCheckBox()
|
||||
layout.addWidget(self.isCopy,5,0,1,2)
|
||||
self.isSubelementMode = QtGui.QCheckBox()
|
||||
layout.addWidget(self.isSubelementMode,6,0,1,2)
|
||||
self.pickrefButton = QtGui.QPushButton()
|
||||
layout.addWidget(self.pickrefButton,9,0,1,2)
|
||||
layout.addWidget(self.pickrefButton,7,0,1,2)
|
||||
QtCore.QObject.connect(self.xValue,QtCore.SIGNAL("valueChanged(double)"),self.setValue)
|
||||
QtCore.QObject.connect(self.yValue,QtCore.SIGNAL("valueChanged(double)"),self.setValue)
|
||||
QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("valueChanged(double)"),self.setValue)
|
||||
@@ -2397,10 +2401,8 @@ class ScaleTaskPanel:
|
||||
self.zLabel.setText(QtGui.QApplication.translate("Draft", "Z factor", None))
|
||||
self.lock.setText(QtGui.QApplication.translate("Draft", "Uniform scaling", None))
|
||||
self.relative.setText(QtGui.QApplication.translate("Draft", "Working plane orientation", None))
|
||||
self.rLabel.setText(QtGui.QApplication.translate("Draft", "Result", None))
|
||||
self.isClone.setText(QtGui.QApplication.translate("Draft", "Create a clone", None))
|
||||
self.isOriginal.setText(QtGui.QApplication.translate("Draft", "Modify original", None))
|
||||
self.isCopy.setText(QtGui.QApplication.translate("Draft", "Create a copy", None))
|
||||
self.isCopy.setText(QtGui.QApplication.translate("draft", "Copy"))
|
||||
self.isSubelementMode.setText(QtGui.QApplication.translate("draft", "Modify subelements"))
|
||||
self.pickrefButton.setText(QtGui.QApplication.translate("Draft", "Pick from/to points", None))
|
||||
|
||||
def pickRef(self):
|
||||
@@ -2409,17 +2411,7 @@ class ScaleTaskPanel:
|
||||
|
||||
def accept(self):
|
||||
if self.sourceCmd:
|
||||
x = self.xValue.value()
|
||||
y = self.yValue.value()
|
||||
z = self.zValue.value()
|
||||
rel = self.relative.isChecked()
|
||||
if self.isClone.isChecked():
|
||||
mod = 0
|
||||
elif self.isOriginal.isChecked():
|
||||
mod = 1
|
||||
else:
|
||||
mod = 2
|
||||
self.sourceCmd.scale(x,y,z,rel,mod)
|
||||
self.sourceCmd.scale()
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
return True
|
||||
|
||||
|
||||
@@ -217,8 +217,8 @@ class DraftTool:
|
||||
else:
|
||||
return False
|
||||
|
||||
def Activated(self,name="None",noplanesetup=False):
|
||||
if FreeCAD.activeDraftCommand:
|
||||
def Activated(self, name="None", noplanesetup=False, is_subtool=False):
|
||||
if FreeCAD.activeDraftCommand and not is_subtool:
|
||||
FreeCAD.activeDraftCommand.finish()
|
||||
|
||||
global Part, DraftGeomUtils
|
||||
@@ -2553,106 +2553,166 @@ class Move(Modifier):
|
||||
|
||||
def __init__(self):
|
||||
Modifier.__init__(self)
|
||||
self.copymode = False
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'Draft_Move',
|
||||
'Accel' : "M, V",
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Move", "Move"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Move", "Moves the selected objects between 2 points. CTRL to snap, SHIFT to constrain, ALT to copy")}
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Move", "Moves the selected objects between 2 points. CTRL to snap, SHIFT to constrain")}
|
||||
|
||||
def Activated(self):
|
||||
self.name = translate("draft","Move", utf8_decode=True)
|
||||
Modifier.Activated(self,self.name)
|
||||
self.ghost = None
|
||||
if self.ui:
|
||||
if not FreeCADGui.Selection.getSelection():
|
||||
self.ui.selectUi()
|
||||
msg(translate("draft", "Select an object to move")+"\n")
|
||||
self.call = self.view.addEventCallback("SoEvent",selectObject)
|
||||
else:
|
||||
self.proceed()
|
||||
Modifier.Activated(self, self.name, is_subtool=isinstance(FreeCAD.activeDraftCommand, EditImproved))
|
||||
if not self.ui:
|
||||
return
|
||||
self.ghosts = []
|
||||
self.get_object_selection()
|
||||
|
||||
def get_object_selection(self):
|
||||
if FreeCADGui.Selection.getSelectionEx():
|
||||
return self.proceed()
|
||||
self.ui.selectUi()
|
||||
msg(translate("draft", "Select an object to move")+"\n")
|
||||
self.call = self.view.addEventCallback("SoEvent", selectObject)
|
||||
|
||||
def proceed(self):
|
||||
if self.call: self.view.removeEventCallback("SoEvent",self.call)
|
||||
self.sel = FreeCADGui.Selection.getSelection()
|
||||
self.sel = Draft.getGroupContents(self.sel,addgroups=True,spaces=True,noarchchild=True)
|
||||
if self.call:
|
||||
self.view.removeEventCallback("SoEvent",self.call)
|
||||
self.selected_objects = FreeCADGui.Selection.getSelection()
|
||||
self.selected_objects = Draft.getGroupContents(self.selected_objects, addgroups=True, spaces=True, noarchchild=True)
|
||||
self.selected_subelements = FreeCADGui.Selection.getSelectionEx()
|
||||
self.ui.pointUi(self.name)
|
||||
self.ui.modUi()
|
||||
if self.copymode:
|
||||
self.ui.isCopy.setChecked(True)
|
||||
self.ui.xValue.setFocus()
|
||||
self.ui.xValue.selectAll()
|
||||
self.ghost = ghostTracker(self.sel)
|
||||
self.call = self.view.addEventCallback("SoEvent",self.action)
|
||||
self.call = self.view.addEventCallback("SoEvent", self.action)
|
||||
msg(translate("draft", "Pick start point:")+"\n")
|
||||
|
||||
def finish(self,closed=False,cont=False):
|
||||
if self.ghost:
|
||||
self.ghost.finalize()
|
||||
for ghost in self.ghosts:
|
||||
ghost.finalize()
|
||||
if cont and self.ui:
|
||||
if self.ui.continueMode:
|
||||
todo.delayAfter(self.Activated,[])
|
||||
Modifier.finish(self)
|
||||
|
||||
def move(self,delta,copy=False):
|
||||
"moving the real shapes"
|
||||
sel = '['
|
||||
for o in self.sel:
|
||||
if len(sel) > 1:
|
||||
sel += ','
|
||||
sel += 'FreeCAD.ActiveDocument.'+o.Name
|
||||
sel += ']'
|
||||
FreeCADGui.addModule("Draft")
|
||||
if copy:
|
||||
self.commit(translate("draft","Copy"),
|
||||
['Draft.move('+sel+','+DraftVecUtils.toString(delta)+',copy='+str(copy)+')',
|
||||
'FreeCAD.ActiveDocument.recompute()'])
|
||||
else:
|
||||
self.commit(translate("draft","Move"),
|
||||
['Draft.move('+sel+','+DraftVecUtils.toString(delta)+',copy='+str(copy)+')',
|
||||
'FreeCAD.ActiveDocument.recompute()'])
|
||||
|
||||
def action(self,arg):
|
||||
"scene event handler"
|
||||
if arg["Type"] == "SoKeyboardEvent":
|
||||
if arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
elif arg["Type"] == "SoLocation2Event": #mouse movement detection
|
||||
if self.ghost:
|
||||
self.ghost.off()
|
||||
self.point,ctrlPoint,info = getPoint(self,arg)
|
||||
if (len(self.node) > 0):
|
||||
last = self.node[len(self.node)-1]
|
||||
delta = self.point.sub(last)
|
||||
if self.ghost:
|
||||
self.ghost.move(delta)
|
||||
self.ghost.on()
|
||||
if self.extendedCopy:
|
||||
if not hasMod(arg,MODALT): self.finish()
|
||||
redraw3DView()
|
||||
elif arg["Type"] == "SoMouseButtonEvent":
|
||||
if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"):
|
||||
if self.point:
|
||||
self.ui.redraw()
|
||||
if (self.node == []):
|
||||
self.node.append(self.point)
|
||||
self.ui.isRelative.show()
|
||||
if self.ghost:
|
||||
self.ghost.on()
|
||||
msg(translate("draft", "Pick end point:")+"\n")
|
||||
if self.planetrack:
|
||||
self.planetrack.set(self.point)
|
||||
else:
|
||||
last = self.node[0]
|
||||
if self.ui.isCopy.isChecked() or hasMod(arg,MODALT):
|
||||
self.move(self.point.sub(last),True)
|
||||
else:
|
||||
self.move(self.point.sub(last))
|
||||
if hasMod(arg,MODALT):
|
||||
self.extendedCopy = True
|
||||
else:
|
||||
self.finish(cont=True)
|
||||
if arg["Type"] == "SoKeyboardEvent" and arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
elif arg["Type"] == "SoLocation2Event":
|
||||
self.handle_mouse_move_event(arg)
|
||||
elif arg["Type"] == "SoMouseButtonEvent" \
|
||||
and arg["State"] == "DOWN" \
|
||||
and arg["Button"] == "BUTTON1":
|
||||
self.handle_mouse_click_event(arg)
|
||||
|
||||
def handle_mouse_move_event(self, arg):
|
||||
for ghost in self.ghosts:
|
||||
ghost.off()
|
||||
self.point, ctrlPoint, info = getPoint(self,arg)
|
||||
if (len(self.node) > 0):
|
||||
last = self.node[len(self.node)-1]
|
||||
self.vector = self.point.sub(last)
|
||||
for ghost in self.ghosts:
|
||||
ghost.move(self.vector)
|
||||
ghost.on()
|
||||
if self.extendedCopy:
|
||||
if not hasMod(arg,MODALT): self.finish()
|
||||
redraw3DView()
|
||||
|
||||
def handle_mouse_click_event(self, arg):
|
||||
if not self.ghosts:
|
||||
self.set_ghosts()
|
||||
if not self.point:
|
||||
return
|
||||
self.ui.redraw()
|
||||
if self.node == []:
|
||||
self.node.append(self.point)
|
||||
self.ui.isRelative.show()
|
||||
for ghost in self.ghosts:
|
||||
ghost.on()
|
||||
msg(translate("draft", "Pick end point:")+"\n")
|
||||
if self.planetrack:
|
||||
self.planetrack.set(self.point)
|
||||
else:
|
||||
last = self.node[0]
|
||||
self.vector = self.point.sub(last)
|
||||
self.move()
|
||||
if hasMod(arg,MODALT):
|
||||
self.extendedCopy = True
|
||||
else:
|
||||
self.finish(cont=True)
|
||||
|
||||
def set_ghosts(self):
|
||||
if self.ui.isSubelementMode.isChecked():
|
||||
return self.set_subelement_ghosts()
|
||||
self.ghosts = [ghostTracker(self.selected_objects)]
|
||||
|
||||
def set_subelement_ghosts(self):
|
||||
import Part
|
||||
for object in self.selected_subelements:
|
||||
for subelement in object.SubObjects:
|
||||
if isinstance(subelement, Part.Vertex) \
|
||||
or isinstance(subelement, Part.Edge):
|
||||
self.ghosts.append(ghostTracker(subelement))
|
||||
|
||||
def move(self):
|
||||
if self.ui.isSubelementMode.isChecked():
|
||||
self.move_subelements()
|
||||
else:
|
||||
self.move_object()
|
||||
|
||||
def move_subelements(self):
|
||||
try:
|
||||
if self.ui.isCopy.isChecked():
|
||||
self.commit(translate("draft", "Copy"), self.build_copy_subelements_command())
|
||||
else:
|
||||
self.commit(translate("draft", "Move"), self.build_move_subelements_command())
|
||||
except:
|
||||
FreeCAD.Console.PrintError(translate("draft", "Some subelements could not be moved."))
|
||||
|
||||
def build_copy_subelements_command(self):
|
||||
import Part
|
||||
command = []
|
||||
arguments = []
|
||||
for object in self.selected_subelements:
|
||||
for index, subelement in enumerate(object.SubObjects):
|
||||
if not isinstance(subelement, Part.Edge):
|
||||
continue
|
||||
arguments.append('[FreeCAD.ActiveDocument.{}, {}, {}]'.format(
|
||||
object.ObjectName,
|
||||
int(object.SubElementNames[index][len("Edge"):])-1,
|
||||
DraftVecUtils.toString(self.vector)))
|
||||
command.append('Draft.copyMovedEdges([{}])'.format(','.join(arguments)))
|
||||
command.append('FreeCAD.ActiveDocument.recompute()')
|
||||
return command
|
||||
|
||||
def build_move_subelements_command(self):
|
||||
import Part
|
||||
command = []
|
||||
for object in self.selected_subelements:
|
||||
for index, subelement in enumerate(object.SubObjects):
|
||||
if isinstance(subelement, Part.Vertex):
|
||||
command.append('Draft.moveVertex(FreeCAD.ActiveDocument.{}, {}, {})'.format(
|
||||
object.ObjectName,
|
||||
int(object.SubElementNames[index][len("Vertex"):])-1,
|
||||
DraftVecUtils.toString(self.vector)
|
||||
))
|
||||
elif isinstance(subelement, Part.Edge):
|
||||
command.append('Draft.moveEdge(FreeCAD.ActiveDocument.{}, {}, {})'.format(
|
||||
object.ObjectName,
|
||||
int(object.SubElementNames[index][len("Edge"):])-1,
|
||||
DraftVecUtils.toString(self.vector)
|
||||
))
|
||||
command.append('FreeCAD.ActiveDocument.recompute()')
|
||||
return command
|
||||
|
||||
def move_object(self):
|
||||
objects = '[' + ','.join(['FreeCAD.ActiveDocument.' + object.Name for object in self.selected_objects]) + ']'
|
||||
FreeCADGui.addModule("Draft")
|
||||
self.commit(translate("draft","Copy" if self.ui.isCopy.isChecked() else "Move"),
|
||||
['Draft.move('+objects+','+DraftVecUtils.toString(self.vector)+',copy='+str(self.ui.isCopy.isChecked())+')', 'FreeCAD.ActiveDocument.recompute()'])
|
||||
|
||||
def numericInput(self,numx,numy,numz):
|
||||
"this function gets called by the toolbar when valid x, y, and z have been entered there"
|
||||
@@ -2671,7 +2731,6 @@ class Move(Modifier):
|
||||
self.move(self.point.sub(last))
|
||||
self.finish()
|
||||
|
||||
|
||||
class ApplyStyle(Modifier):
|
||||
"The Draft_ApplyStyle FreeCA command definition"
|
||||
|
||||
@@ -2720,36 +2779,158 @@ class Rotate(Modifier):
|
||||
|
||||
def Activated(self):
|
||||
Modifier.Activated(self,"Rotate")
|
||||
self.ghost = None
|
||||
if not self.ui:
|
||||
return
|
||||
self.ghosts = []
|
||||
self.arctrack = None
|
||||
if self.ui:
|
||||
if not FreeCADGui.Selection.getSelection():
|
||||
self.ui.selectUi()
|
||||
msg(translate("draft", "Select an object to rotate")+"\n")
|
||||
self.call = self.view.addEventCallback("SoEvent",selectObject)
|
||||
else:
|
||||
self.proceed()
|
||||
self.get_object_selection()
|
||||
|
||||
def get_object_selection(self):
|
||||
if FreeCADGui.Selection.getSelection():
|
||||
return self.proceed()
|
||||
self.ui.selectUi()
|
||||
msg(translate("draft", "Select an object to rotate")+"\n")
|
||||
self.call = self.view.addEventCallback("SoEvent", selectObject)
|
||||
|
||||
def proceed(self):
|
||||
if self.call: self.view.removeEventCallback("SoEvent",self.call)
|
||||
self.sel = FreeCADGui.Selection.getSelection()
|
||||
self.sel = Draft.getGroupContents(self.sel,addgroups=True,spaces=True,noarchchild=True)
|
||||
if self.call:
|
||||
self.view.removeEventCallback("SoEvent", self.call)
|
||||
self.selected_objects = FreeCADGui.Selection.getSelection()
|
||||
self.selected_objects = Draft.getGroupContents(self.selected_objects, addgroups=True, spaces=True, noarchchild=True)
|
||||
self.selected_subelements = FreeCADGui.Selection.getSelectionEx()
|
||||
self.step = 0
|
||||
self.center = None
|
||||
self.ui.arcUi()
|
||||
self.ui.modUi()
|
||||
self.ui.setTitle("Rotate")
|
||||
self.arctrack = arcTracker()
|
||||
self.ghost = ghostTracker(self.sel)
|
||||
self.call = self.view.addEventCallback("SoEvent",self.action)
|
||||
msg(translate("draft", "Pick rotation center:")+"\n")
|
||||
|
||||
def finish(self,closed=False,cont=False):
|
||||
def action(self, arg):
|
||||
"scene event handler"
|
||||
if arg["Type"] == "SoKeyboardEvent" and arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
elif arg["Type"] == "SoLocation2Event":
|
||||
self.handle_mouse_move_event(arg)
|
||||
elif arg["Type"] == "SoMouseButtonEvent" \
|
||||
and arg["State"] == "DOWN" \
|
||||
and arg["Button"] == "BUTTON1":
|
||||
self.handle_mouse_click_event(arg)
|
||||
|
||||
def handle_mouse_move_event(self, arg):
|
||||
for ghost in self.ghosts:
|
||||
ghost.off()
|
||||
self.point,ctrlPoint,info = getPoint(self,arg)
|
||||
# this is to make sure radius is what you see on screen
|
||||
if self.center and DraftVecUtils.dist(self.point,self.center):
|
||||
viewdelta = DraftVecUtils.project(self.point.sub(self.center), plane.axis)
|
||||
if not DraftVecUtils.isNull(viewdelta):
|
||||
self.point = self.point.add(viewdelta.negative())
|
||||
if self.extendedCopy:
|
||||
if not hasMod(arg,MODALT):
|
||||
self.step = 3
|
||||
self.finish()
|
||||
if (self.step == 0):
|
||||
pass
|
||||
elif (self.step == 1):
|
||||
currentrad = DraftVecUtils.dist(self.point,self.center)
|
||||
if (currentrad != 0):
|
||||
angle = DraftVecUtils.angle(plane.u, self.point.sub(self.center), plane.axis)
|
||||
else: angle = 0
|
||||
self.ui.setRadiusValue(math.degrees(angle),unit="Angle")
|
||||
self.firstangle = angle
|
||||
self.ui.radiusValue.setFocus()
|
||||
self.ui.radiusValue.selectAll()
|
||||
elif (self.step == 2):
|
||||
currentrad = DraftVecUtils.dist(self.point,self.center)
|
||||
if (currentrad != 0):
|
||||
angle = DraftVecUtils.angle(plane.u, self.point.sub(self.center), plane.axis)
|
||||
else: angle = 0
|
||||
if (angle < self.firstangle):
|
||||
sweep = (2*math.pi-self.firstangle)+angle
|
||||
else:
|
||||
sweep = angle - self.firstangle
|
||||
self.arctrack.setApertureAngle(sweep)
|
||||
for ghost in self.ghosts:
|
||||
ghost.rotate(plane.axis,sweep)
|
||||
ghost.on()
|
||||
self.ui.setRadiusValue(math.degrees(sweep), 'Angle')
|
||||
self.ui.radiusValue.setFocus()
|
||||
self.ui.radiusValue.selectAll()
|
||||
redraw3DView()
|
||||
|
||||
def handle_mouse_click_event(self, arg):
|
||||
if not self.point:
|
||||
return
|
||||
if self.step == 0:
|
||||
self.set_center()
|
||||
elif self.step == 1:
|
||||
self.set_start_point()
|
||||
else:
|
||||
self.set_rotation_angle(arg)
|
||||
|
||||
def set_center(self):
|
||||
if not self.ghosts:
|
||||
self.set_ghosts()
|
||||
self.center = self.point
|
||||
self.node = [self.point]
|
||||
self.ui.radiusUi()
|
||||
self.ui.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Angle).UserString)
|
||||
self.ui.hasFill.hide()
|
||||
self.ui.labelRadius.setText("Base angle")
|
||||
self.arctrack.setCenter(self.center)
|
||||
for ghost in self.ghosts:
|
||||
ghost.center(self.center)
|
||||
self.step = 1
|
||||
msg(translate("draft", "Pick base angle:")+"\n")
|
||||
if self.planetrack:
|
||||
self.planetrack.set(self.point)
|
||||
|
||||
def set_start_point(self):
|
||||
self.ui.labelRadius.setText("Rotation")
|
||||
self.rad = DraftVecUtils.dist(self.point,self.center)
|
||||
self.arctrack.on()
|
||||
self.arctrack.setStartPoint(self.point)
|
||||
for ghost in self.ghosts:
|
||||
ghost.on()
|
||||
self.step = 2
|
||||
msg(translate("draft", "Pick rotation angle:")+"\n")
|
||||
|
||||
def set_rotation_angle(self, arg):
|
||||
currentrad = DraftVecUtils.dist(self.point,self.center)
|
||||
angle = self.point.sub(self.center).getAngle(plane.u)
|
||||
if DraftVecUtils.project(self.point.sub(self.center), plane.v).getAngle(plane.v) > 1:
|
||||
angle = -angle
|
||||
if (angle < self.firstangle):
|
||||
self.angle = (2*math.pi-self.firstangle)+angle
|
||||
else:
|
||||
self.angle = angle - self.firstangle
|
||||
self.rotate(self.ui.isCopy.isChecked() or hasMod(arg,MODALT))
|
||||
if hasMod(arg,MODALT):
|
||||
self.extendedCopy = True
|
||||
else:
|
||||
self.finish(cont=True)
|
||||
|
||||
def set_ghosts(self):
|
||||
if self.ui.isSubelementMode.isChecked():
|
||||
return self.set_subelement_ghosts()
|
||||
self.ghosts = [ghostTracker(self.selected_objects)]
|
||||
|
||||
def set_subelement_ghosts(self):
|
||||
import Part
|
||||
for object in self.selected_subelements:
|
||||
for subelement in object.SubObjects:
|
||||
if isinstance(subelement, Part.Vertex) \
|
||||
or isinstance(subelement, Part.Edge):
|
||||
self.ghosts.append(ghostTracker(subelement))
|
||||
|
||||
def finish(self, closed=False, cont=False):
|
||||
"finishes the arc"
|
||||
if self.arctrack:
|
||||
self.arctrack.finalize()
|
||||
if self.ghost:
|
||||
self.ghost.finalize()
|
||||
for ghost in self.ghosts:
|
||||
ghost.finalize()
|
||||
if cont and self.ui:
|
||||
if self.ui.continueMode:
|
||||
todo.delayAfter(self.Activated,[])
|
||||
@@ -2757,112 +2938,72 @@ class Rotate(Modifier):
|
||||
if self.doc:
|
||||
self.doc.recompute()
|
||||
|
||||
def rot (self,angle,copy=False):
|
||||
"rotating the real shapes"
|
||||
sel = '['
|
||||
for o in self.sel:
|
||||
if len(sel) > 1:
|
||||
sel += ','
|
||||
sel += 'FreeCAD.ActiveDocument.'+o.Name
|
||||
sel += ']'
|
||||
FreeCADGui.addModule("Draft")
|
||||
if copy:
|
||||
self.commit(translate("draft","Copy"),
|
||||
['Draft.rotate('+sel+','+str(math.degrees(angle))+','+DraftVecUtils.toString(self.center)+',axis='+DraftVecUtils.toString(plane.axis)+',copy='+str(copy)+')'])
|
||||
def rotate(self, is_copy=False):
|
||||
if self.ui.isSubelementMode.isChecked():
|
||||
self.rotate_subelements(is_copy)
|
||||
else:
|
||||
self.commit(translate("draft","Rotate"),
|
||||
['Draft.rotate('+sel+','+str(math.degrees(angle))+','+DraftVecUtils.toString(self.center)+',axis='+DraftVecUtils.toString(plane.axis)+',copy='+str(copy)+')'])
|
||||
self.rotate_object(is_copy)
|
||||
|
||||
def action(self,arg):
|
||||
"scene event handler"
|
||||
if arg["Type"] == "SoKeyboardEvent":
|
||||
if arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
elif arg["Type"] == "SoLocation2Event":
|
||||
if self.ghost:
|
||||
self.ghost.off()
|
||||
self.point,ctrlPoint,info = getPoint(self,arg)
|
||||
# this is to make sure radius is what you see on screen
|
||||
if self.center and DraftVecUtils.dist(self.point,self.center):
|
||||
viewdelta = DraftVecUtils.project(self.point.sub(self.center), plane.axis)
|
||||
if not DraftVecUtils.isNull(viewdelta):
|
||||
self.point = self.point.add(viewdelta.negative())
|
||||
if self.extendedCopy:
|
||||
if not hasMod(arg,MODALT):
|
||||
self.step = 3
|
||||
self.finish()
|
||||
if (self.step == 0):
|
||||
pass
|
||||
elif (self.step == 1):
|
||||
currentrad = DraftVecUtils.dist(self.point,self.center)
|
||||
if (currentrad != 0):
|
||||
angle = DraftVecUtils.angle(plane.u, self.point.sub(self.center), plane.axis)
|
||||
else: angle = 0
|
||||
self.ui.setRadiusValue(math.degrees(angle),unit="Angle")
|
||||
self.firstangle = angle
|
||||
self.ui.radiusValue.setFocus()
|
||||
self.ui.radiusValue.selectAll()
|
||||
elif (self.step == 2):
|
||||
currentrad = DraftVecUtils.dist(self.point,self.center)
|
||||
if (currentrad != 0):
|
||||
angle = DraftVecUtils.angle(plane.u, self.point.sub(self.center), plane.axis)
|
||||
else: angle = 0
|
||||
if (angle < self.firstangle):
|
||||
sweep = (2*math.pi-self.firstangle)+angle
|
||||
else:
|
||||
sweep = angle - self.firstangle
|
||||
self.arctrack.setApertureAngle(sweep)
|
||||
if self.ghost:
|
||||
self.ghost.rotate(plane.axis,sweep)
|
||||
self.ghost.on()
|
||||
self.ui.setRadiusValue(math.degrees(sweep), 'Angle')
|
||||
self.ui.radiusValue.setFocus()
|
||||
self.ui.radiusValue.selectAll()
|
||||
redraw3DView()
|
||||
def rotate_subelements(self, is_copy):
|
||||
try:
|
||||
if is_copy:
|
||||
self.commit(translate("draft", "Copy"), self.build_copy_subelements_command())
|
||||
else:
|
||||
self.commit(translate("draft", "Rotate"), self.build_rotate_subelements_command())
|
||||
except:
|
||||
FreeCAD.Console.PrintError(translate("draft", "Some subelements could not be moved."))
|
||||
|
||||
elif arg["Type"] == "SoMouseButtonEvent":
|
||||
if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"):
|
||||
if self.point:
|
||||
if (self.step == 0):
|
||||
self.center = self.point
|
||||
self.node = [self.point]
|
||||
self.ui.radiusUi()
|
||||
self.ui.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Angle).UserString)
|
||||
self.ui.hasFill.hide()
|
||||
self.ui.labelRadius.setText("Base angle")
|
||||
self.arctrack.setCenter(self.center)
|
||||
if self.ghost:
|
||||
self.ghost.center(self.center)
|
||||
self.step = 1
|
||||
msg(translate("draft", "Pick base angle:")+"\n")
|
||||
if self.planetrack:
|
||||
self.planetrack.set(self.point)
|
||||
elif (self.step == 1):
|
||||
self.ui.labelRadius.setText("Rotation")
|
||||
self.rad = DraftVecUtils.dist(self.point,self.center)
|
||||
self.arctrack.on()
|
||||
self.arctrack.setStartPoint(self.point)
|
||||
if self.ghost:
|
||||
self.ghost.on()
|
||||
self.step = 2
|
||||
msg(translate("draft", "Pick rotation angle:")+"\n")
|
||||
else:
|
||||
currentrad = DraftVecUtils.dist(self.point,self.center)
|
||||
angle = self.point.sub(self.center).getAngle(plane.u)
|
||||
if DraftVecUtils.project(self.point.sub(self.center), plane.v).getAngle(plane.v) > 1:
|
||||
angle = -angle
|
||||
if (angle < self.firstangle):
|
||||
sweep = (2*math.pi-self.firstangle)+angle
|
||||
else:
|
||||
sweep = angle - self.firstangle
|
||||
if self.ui.isCopy.isChecked() or hasMod(arg,MODALT):
|
||||
self.rot(sweep,True)
|
||||
else:
|
||||
self.rot(sweep)
|
||||
if hasMod(arg,MODALT):
|
||||
self.extendedCopy = True
|
||||
else:
|
||||
self.finish(cont=True)
|
||||
def build_copy_subelements_command(self):
|
||||
import Part
|
||||
command = []
|
||||
arguments = []
|
||||
for object in self.selected_subelements:
|
||||
for index, subelement in enumerate(object.SubObjects):
|
||||
if not isinstance(subelement, Part.Edge):
|
||||
continue
|
||||
arguments.append('[FreeCAD.ActiveDocument.{}, {}, {}, {}, {}]'.format(
|
||||
object.ObjectName,
|
||||
int(object.SubElementNames[index][len("Edge"):])-1,
|
||||
math.degrees(self.angle),
|
||||
DraftVecUtils.toString(self.center),
|
||||
DraftVecUtils.toString(plane.axis)))
|
||||
command.append('Draft.copyRotatedEdges([{}])'.format(','.join(arguments)))
|
||||
command.append('FreeCAD.ActiveDocument.recompute()')
|
||||
return command
|
||||
|
||||
def build_rotate_subelements_command(self):
|
||||
import Part
|
||||
command = []
|
||||
for object in self.selected_subelements:
|
||||
for index, subelement in enumerate(object.SubObjects):
|
||||
if isinstance(subelement, Part.Vertex):
|
||||
command.append('Draft.rotateVertex(FreeCAD.ActiveDocument.{}, {}, {}, {}, {})'.format(
|
||||
object.ObjectName,
|
||||
int(object.SubElementNames[index][len("Vertex"):])-1,
|
||||
math.degrees(self.angle),
|
||||
DraftVecUtils.toString(self.center),
|
||||
DraftVecUtils.toString(plane.axis)))
|
||||
elif isinstance(subelement, Part.Edge):
|
||||
command.append('Draft.rotateEdge(FreeCAD.ActiveDocument.{}, {}, {}, {}, {})'.format(
|
||||
object.ObjectName,
|
||||
int(object.SubElementNames[index][len("Edge"):])-1,
|
||||
math.degrees(self.angle),
|
||||
DraftVecUtils.toString(self.center),
|
||||
DraftVecUtils.toString(plane.axis)))
|
||||
command.append('FreeCAD.ActiveDocument.recompute()')
|
||||
return command
|
||||
|
||||
def rotate_object(self, is_copy):
|
||||
objects = '[' + ','.join(['FreeCAD.ActiveDocument.' + object.Name for object in self.selected_objects]) + ']'
|
||||
FreeCADGui.addModule("Draft")
|
||||
self.commit(translate("draft","Copy" if is_copy else "Rotate"),
|
||||
['Draft.rotate({},{},{},axis={},copy={})'.format(
|
||||
objects,
|
||||
math.degrees(self.angle),
|
||||
DraftVecUtils.toString(self.center),
|
||||
DraftVecUtils.toString(plane.axis),
|
||||
is_copy
|
||||
)])
|
||||
|
||||
def numericInput(self,numx,numy,numz):
|
||||
"this function gets called by the toolbar when valid x, y, and z have been entered there"
|
||||
@@ -2889,7 +3030,7 @@ class Rotate(Modifier):
|
||||
self.step = 2
|
||||
msg(translate("draft", "Pick rotation angle:")+"\n")
|
||||
else:
|
||||
self.rot(math.radians(rad),self.ui.isCopy.isChecked())
|
||||
self.rotate(math.radians(rad),self.ui.isCopy.isChecked())
|
||||
self.finish(cont=True)
|
||||
|
||||
|
||||
@@ -3972,30 +4113,47 @@ class Scale(Modifier):
|
||||
def Activated(self):
|
||||
self.name = translate("draft","Scale", utf8_decode=True)
|
||||
Modifier.Activated(self,self.name)
|
||||
self.ghost = None
|
||||
if self.ui:
|
||||
if not FreeCADGui.Selection.getSelection():
|
||||
self.ui.selectUi()
|
||||
msg(translate("draft", "Select an object to scale")+"\n")
|
||||
self.call = self.view.addEventCallback("SoEvent",selectObject)
|
||||
else:
|
||||
self.proceed()
|
||||
if not self.ui:
|
||||
return
|
||||
self.ghosts = []
|
||||
self.get_object_selection()
|
||||
|
||||
def get_object_selection(self):
|
||||
if FreeCADGui.Selection.getSelection():
|
||||
return self.proceed()
|
||||
self.ui.selectUi()
|
||||
msg(translate("draft", "Select an object to scale")+"\n")
|
||||
self.call = self.view.addEventCallback("SoEvent",selectObject)
|
||||
|
||||
def proceed(self):
|
||||
if self.call: self.view.removeEventCallback("SoEvent",self.call)
|
||||
self.sel = FreeCADGui.Selection.getSelection()
|
||||
self.sel = Draft.getGroupContents(self.sel)
|
||||
if self.call:
|
||||
self.view.removeEventCallback("SoEvent", self.call)
|
||||
self.selected_objects = FreeCADGui.Selection.getSelection()
|
||||
self.selected_objects = Draft.getGroupContents(self.selected_objects)
|
||||
self.selected_subelements = FreeCADGui.Selection.getSelectionEx()
|
||||
self.refs = []
|
||||
self.ui.pointUi(self.name)
|
||||
self.ui.modUi()
|
||||
self.ui.xValue.setFocus()
|
||||
self.ui.xValue.selectAll()
|
||||
self.ghost = ghostTracker(self.sel)
|
||||
self.pickmode = False
|
||||
self.task = None
|
||||
self.call = self.view.addEventCallback("SoEvent",self.action)
|
||||
self.call = self.view.addEventCallback("SoEvent", self.action)
|
||||
msg(translate("draft", "Pick base point:")+"\n")
|
||||
|
||||
def set_ghosts(self):
|
||||
if self.ui.isSubelementMode.isChecked():
|
||||
return self.set_subelement_ghosts()
|
||||
self.ghosts = [ghostTracker(self.selected_objects)]
|
||||
|
||||
def set_subelement_ghosts(self):
|
||||
import Part
|
||||
for object in self.selected_subelements:
|
||||
for subelement in object.SubObjects:
|
||||
if isinstance(subelement, Part.Vertex) \
|
||||
or isinstance(subelement, Part.Edge):
|
||||
self.ghosts.append(ghostTracker(subelement))
|
||||
|
||||
def pickRef(self):
|
||||
self.pickmode = True
|
||||
if self.node:
|
||||
@@ -4003,63 +4161,105 @@ class Scale(Modifier):
|
||||
msg(translate("draft", "Pick reference distance from base point:")+"\n")
|
||||
self.call = self.view.addEventCallback("SoEvent",self.action)
|
||||
|
||||
def finish(self,closed=False,cont=False):
|
||||
Modifier.finish(self)
|
||||
if self.ghost:
|
||||
self.ghost.finalize()
|
||||
def action(self,arg):
|
||||
"scene event handler"
|
||||
if arg["Type"] == "SoKeyboardEvent" and arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
elif arg["Type"] == "SoLocation2Event":
|
||||
self.handle_mouse_move_event(arg)
|
||||
elif arg["Type"] == "SoMouseButtonEvent" \
|
||||
and arg["State"] == "DOWN" \
|
||||
and (arg["Button"] == "BUTTON1") \
|
||||
and self.point:
|
||||
self.handle_mouse_click_event()
|
||||
|
||||
def scale(self,x,y,z,rel,mode):
|
||||
delta = Vector(x,y,z)
|
||||
if rel:
|
||||
delta = FreeCAD.DraftWorkingPlane.getGlobalCoords(delta)
|
||||
if mode == 0:
|
||||
copy = False
|
||||
legacy = False
|
||||
elif mode == 1:
|
||||
copy = False
|
||||
legacy = True
|
||||
elif mode == 2:
|
||||
copy = True
|
||||
legacy = True
|
||||
"moving the real shapes"
|
||||
sel = '['
|
||||
for o in self.sel:
|
||||
if len(sel) > 1:
|
||||
sel += ','
|
||||
sel += 'FreeCAD.ActiveDocument.'+o.Name
|
||||
sel += ']'
|
||||
FreeCADGui.addModule("Draft")
|
||||
self.commit(translate("draft","Copy"),
|
||||
['Draft.scale('+sel+',delta='+DraftVecUtils.toString(delta)+',center='+DraftVecUtils.toString(self.node[0])+',copy='+str(copy)+',legacy='+str(legacy)+')',
|
||||
'FreeCAD.ActiveDocument.recompute()'])
|
||||
def handle_mouse_move_event(self, arg):
|
||||
for ghost in self.ghosts:
|
||||
ghost.off()
|
||||
self.point, ctrlPoint, info = getPoint(self, arg, sym=True)
|
||||
|
||||
def handle_mouse_click_event(self):
|
||||
if not self.ghosts:
|
||||
self.set_ghosts()
|
||||
self.numericInput(self.point.x, self.point.y, self.point.z)
|
||||
|
||||
def scale(self):
|
||||
self.delta = Vector(self.task.xValue.value(), self.task.yValue.value(), self.task.zValue.value())
|
||||
self.center = self.node[0]
|
||||
if self.task.isSubelementMode.isChecked():
|
||||
self.scale_subelements()
|
||||
else:
|
||||
self.scale_object()
|
||||
self.finish()
|
||||
|
||||
def scale_subelements(self):
|
||||
try:
|
||||
if self.task.isCopy.isChecked():
|
||||
self.commit(translate("draft", "Copy"), self.build_copy_subelements_command())
|
||||
else:
|
||||
self.commit(translate("draft", "Scale"), self.build_scale_subelements_command())
|
||||
except:
|
||||
FreeCAD.Console.PrintError(translate("draft", "Some subelements could not be scaled."))
|
||||
|
||||
def build_copy_subelements_command(self):
|
||||
import Part
|
||||
command = []
|
||||
arguments = []
|
||||
for object in self.selected_subelements:
|
||||
for index, subelement in enumerate(object.SubObjects):
|
||||
if not isinstance(subelement, Part.Edge):
|
||||
continue
|
||||
arguments.append('[FreeCAD.ActiveDocument.{}, {}, {}, {}]'.format(
|
||||
object.ObjectName,
|
||||
int(object.SubElementNames[index][len("Edge"):])-1,
|
||||
DraftVecUtils.toString(self.delta),
|
||||
DraftVecUtils.toString(self.center)))
|
||||
command.append('Draft.copyScaledEdges([{}])'.format(','.join(arguments)))
|
||||
command.append('FreeCAD.ActiveDocument.recompute()')
|
||||
return command
|
||||
|
||||
def build_scale_subelements_command(self):
|
||||
import Part
|
||||
command = []
|
||||
for object in self.selected_subelements:
|
||||
for index, subelement in enumerate(object.SubObjects):
|
||||
if isinstance(subelement, Part.Vertex):
|
||||
command.append('Draft.scaleVertex(FreeCAD.ActiveDocument.{}, {}, {}, {})'.format(
|
||||
object.ObjectName,
|
||||
int(object.SubElementNames[index][len("Vertex"):])-1,
|
||||
DraftVecUtils.toString(self.delta),
|
||||
DraftVecUtils.toString(self.center)))
|
||||
elif isinstance(subelement, Part.Edge):
|
||||
command.append('Draft.scaleEdge(FreeCAD.ActiveDocument.{}, {}, {}, {})'.format(
|
||||
object.ObjectName,
|
||||
int(object.SubElementNames[index][len("Edge"):])-1,
|
||||
DraftVecUtils.toString(self.delta),
|
||||
DraftVecUtils.toString(self.center)))
|
||||
command.append('FreeCAD.ActiveDocument.recompute()')
|
||||
return command
|
||||
|
||||
def scale_object(self):
|
||||
if self.task.relative.isChecked():
|
||||
self.delta = FreeCAD.DraftWorkingPlane.getGlobalCoords(self.delta)
|
||||
objects = '[' + ','.join(['FreeCAD.ActiveDocument.' + object.Name for object in self.selected_objects]) + ']'
|
||||
FreeCADGui.addModule("Draft")
|
||||
self.commit(translate("draft","Copy" if self.task.isCopy.isChecked() else "Scale"),
|
||||
['Draft.scale('+objects+',scale='+DraftVecUtils.toString(self.delta)+',center='+DraftVecUtils.toString(self.center)+',copy='+str(self.task.isCopy.isChecked())+')',
|
||||
'FreeCAD.ActiveDocument.recompute()'])
|
||||
|
||||
def scaleGhost(self,x,y,z,rel):
|
||||
delta = Vector(x,y,z)
|
||||
if rel:
|
||||
delta = FreeCAD.DraftWorkingPlane.getGlobalCoords(delta)
|
||||
self.ghost.scale(delta)
|
||||
for ghost in self.ghosts:
|
||||
ghost.scale(delta)
|
||||
# calculate a correction factor depending on the scaling center
|
||||
corr = Vector(self.node[0].x,self.node[0].y,self.node[0].z)
|
||||
corr.scale(delta.x,delta.y,delta.z)
|
||||
corr = (corr.sub(self.node[0])).negative()
|
||||
self.ghost.move(corr)
|
||||
self.ghost.on()
|
||||
|
||||
def action(self,arg):
|
||||
"scene event handler"
|
||||
if arg["Type"] == "SoKeyboardEvent":
|
||||
if arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
elif arg["Type"] == "SoLocation2Event": #mouse movement detection
|
||||
if self.ghost:
|
||||
self.ghost.off()
|
||||
self.point,ctrlPoint,info = getPoint(self,arg,sym=True)
|
||||
elif arg["Type"] == "SoMouseButtonEvent":
|
||||
if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"):
|
||||
if self.point:
|
||||
#self.ui.redraw()
|
||||
self.numericInput(self.point.x,self.point.y,self.point.z)
|
||||
for ghost in self.ghosts:
|
||||
ghost.move(corr)
|
||||
ghost.on()
|
||||
|
||||
def numericInput(self,numx,numy,numz):
|
||||
"this function gets called by the toolbar when a valid base point has been entered"
|
||||
@@ -4072,8 +4272,8 @@ class Scale(Modifier):
|
||||
self.task = DraftGui.ScaleTaskPanel()
|
||||
self.task.sourceCmd = self
|
||||
DraftGui.todo.delay(FreeCADGui.Control.showDialog,self.task)
|
||||
if self.ghost:
|
||||
self.ghost.on()
|
||||
for ghost in self.ghosts:
|
||||
ghost.on()
|
||||
elif len(self.node) == 2:
|
||||
msg(translate("draft", "Pick new distance from base point:")+"\n")
|
||||
elif len(self.node) == 3:
|
||||
@@ -4089,6 +4289,11 @@ class Scale(Modifier):
|
||||
self.task.lock.setChecked(True)
|
||||
self.task.setValue(d2/d1)
|
||||
|
||||
def finish(self,closed=False,cont=False):
|
||||
Modifier.finish(self)
|
||||
for ghost in self.ghosts:
|
||||
ghost.finalize()
|
||||
|
||||
class ToggleConstructionMode():
|
||||
"The Draft_ToggleConstructionMode FreeCAD command definition"
|
||||
|
||||
@@ -4209,6 +4414,91 @@ class ToggleDisplayMode():
|
||||
if "Flat Lines" in obj.ViewObject.listDisplayModes():
|
||||
obj.ViewObject.DisplayMode = "Flat Lines"
|
||||
|
||||
class EditImproved(Modifier):
|
||||
"The Draft_Edit_Improved FreeCAD command definition"
|
||||
|
||||
def __init__(self):
|
||||
self.is_running = False
|
||||
self.editable_objects = []
|
||||
self.original_view_settings = {}
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'Draft_Edit',
|
||||
'Accel' : "D, E",
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Edit_Improved", "Edit Improved"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Edit_Improved", "Edits the selected objects")}
|
||||
|
||||
def Activated(self):
|
||||
if self.is_running:
|
||||
return self.finish()
|
||||
self.is_running = True
|
||||
Modifier.Activated(self,"Edit_Improved")
|
||||
self.get_selection()
|
||||
|
||||
def proceed(self):
|
||||
self.remove_view_callback()
|
||||
self.get_editable_objects_from_selection()
|
||||
if not self.editable_objects:
|
||||
return self.finish()
|
||||
self.call = self.view.addEventCallback("SoEvent", self.action)
|
||||
self.highlight_editable_objects()
|
||||
|
||||
def finish(self):
|
||||
Modifier.finish(self)
|
||||
self.remove_view_callback()
|
||||
self.restore_editable_objects_graphics()
|
||||
self.__init__()
|
||||
|
||||
def action(self, event):
|
||||
if event["Type"] == "SoKeyboardEvent" and event["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
|
||||
def get_selection(self):
|
||||
if not FreeCADGui.Selection.getSelection() and self.ui:
|
||||
msg(translate("Draft_Edit_Improved", "Select an object to edit")+"\n")
|
||||
self.call = self.view.addEventCallback("SoEvent", selectObject)
|
||||
else:
|
||||
self.proceed()
|
||||
|
||||
def remove_view_callback(self):
|
||||
if self.call:
|
||||
self.view.removeEventCallback("SoEvent",self.call)
|
||||
|
||||
def get_editable_objects_from_selection(self):
|
||||
for object in FreeCADGui.Selection.getSelection():
|
||||
if object.isDerivedFrom("Part::Part2DObject"):
|
||||
self.editable_objects.append(object)
|
||||
elif hasattr(object, "Base") and object.Base.isDerivedFrom("Part::Part2DObject"):
|
||||
self.editable_objects.append(object.Base)
|
||||
|
||||
def highlight_editable_objects(self):
|
||||
for object in self.editable_objects:
|
||||
self.original_view_settings[object.Name] = {
|
||||
'Visibility': object.ViewObject.Visibility,
|
||||
'PointSize': object.ViewObject.PointSize,
|
||||
'PointColor': object.ViewObject.PointColor,
|
||||
'LineColor': object.ViewObject.LineColor
|
||||
}
|
||||
object.ViewObject.Visibility = True
|
||||
object.ViewObject.PointSize = 10
|
||||
object.ViewObject.PointColor = (1., 0., 0.)
|
||||
object.ViewObject.LineColor = (1., 0., 0.)
|
||||
xray = coin.SoAnnotation()
|
||||
xray.addChild(object.ViewObject.RootNode.getChild(2).getChild(0))
|
||||
xray.setName("xray")
|
||||
object.ViewObject.RootNode.addChild(xray)
|
||||
|
||||
def restore_editable_objects_graphics(self):
|
||||
for object in self.editable_objects:
|
||||
try:
|
||||
for attribute, value in self.original_view_settings[object.Name].items():
|
||||
view_object = object.ViewObject
|
||||
setattr(view_object, attribute, value)
|
||||
view_object.RootNode.removeChild(view_object.RootNode.getByName("xray"))
|
||||
except:
|
||||
# This can occur if objects have had graph changing operations
|
||||
pass
|
||||
|
||||
class Edit(Modifier):
|
||||
"The Draft_Edit FreeCAD command definition"
|
||||
|
||||
@@ -6414,6 +6704,7 @@ FreeCADGui.addCommand('Draft_Trimex',Trimex())
|
||||
FreeCADGui.addCommand('Draft_Scale',Scale())
|
||||
FreeCADGui.addCommand('Draft_Drawing',Drawing())
|
||||
FreeCADGui.addCommand('Draft_Edit',Edit())
|
||||
FreeCADGui.addCommand('Draft_Edit_Improved',EditImproved())
|
||||
FreeCADGui.addCommand('Draft_AddPoint',AddPoint())
|
||||
FreeCADGui.addCommand('Draft_DelPoint',DelPoint())
|
||||
FreeCADGui.addCommand('Draft_WireToBSpline',WireToBSpline())
|
||||
|
||||
@@ -583,7 +583,23 @@ class ghostTracker(Tracker):
|
||||
if not isinstance(sel,list):
|
||||
sel = [sel]
|
||||
for obj in sel:
|
||||
rootsep.addChild(self.getNode(obj))
|
||||
import Part
|
||||
if not isinstance(obj, Part.Vertex):
|
||||
rootsep.addChild(self.getNode(obj))
|
||||
else:
|
||||
self.coords = coin.SoCoordinate3()
|
||||
self.coords.point.setValue((obj.X,obj.Y,obj.Z))
|
||||
color = coin.SoBaseColor()
|
||||
color.rgb = FreeCADGui.draftToolBar.getDefaultColor("snap")
|
||||
self.marker = coin.SoMarkerSet() # this is the marker symbol
|
||||
self.marker.markerIndex = FreeCADGui.getMarkerIndex("quad", 9)
|
||||
node = coin.SoAnnotation()
|
||||
selnode = coin.SoSeparator()
|
||||
selnode.addChild(self.coords)
|
||||
selnode.addChild(color)
|
||||
selnode.addChild(self.marker)
|
||||
node.addChild(selnode)
|
||||
rootsep.addChild(node)
|
||||
self.children.append(rootsep)
|
||||
Tracker.__init__(self,dotted,scolor,swidth,children=self.children,name="ghostTracker")
|
||||
|
||||
@@ -674,7 +690,6 @@ class ghostTracker(Tracker):
|
||||
matrix.A41,matrix.A42,matrix.A43,matrix.A44)
|
||||
self.trans.setMatrix(m)
|
||||
|
||||
|
||||
class editTracker(Tracker):
|
||||
"A node edit tracker"
|
||||
def __init__(self,pos=Vector(0,0,0),name=None,idx=0,objcol=None,\
|
||||
|
||||
@@ -74,7 +74,7 @@ class DraftWorkbench (Workbench):
|
||||
"Draft_ShapeString","Draft_Facebinder","Draft_BezierTools","Draft_Label"]
|
||||
self.modList = ["Draft_Move","Draft_Rotate","Draft_Offset",
|
||||
"Draft_Trimex", "Draft_Join", "Draft_Split", "Draft_Upgrade", "Draft_Downgrade", "Draft_Scale",
|
||||
"Draft_Edit","Draft_WireToBSpline","Draft_AddPoint",
|
||||
"Draft_Edit","Draft_Edit_Improved","Draft_WireToBSpline","Draft_AddPoint",
|
||||
"Draft_DelPoint","Draft_Shape2DView","Draft_Draft2Sketch","Draft_Array",
|
||||
"Draft_PathArray", "Draft_PointArray","Draft_Clone",
|
||||
"Draft_Drawing","Draft_Mirror","Draft_Stretch"]
|
||||
|
||||
Reference in New Issue
Block a user