Draft: Added mirror tool (more graphical version of Part Mirror) - fixes #2215
This commit is contained in:
@@ -91,7 +91,8 @@ class ArchWorkbench(Workbench):
|
||||
"Draft_Trimex", "Draft_Upgrade", "Draft_Downgrade", "Draft_Scale",
|
||||
"Draft_Shape2DView","Draft_Draft2Sketch","Draft_Array",
|
||||
"Draft_Clone"]
|
||||
self.draftextratools = ["Draft_WireToBSpline","Draft_AddPoint","Draft_DelPoint","Draft_ShapeString","Draft_PathArray"]
|
||||
self.draftextratools = ["Draft_WireToBSpline","Draft_AddPoint","Draft_DelPoint","Draft_ShapeString",
|
||||
"Draft_PathArray","Draft_Mirror"]
|
||||
self.draftcontexttools = ["Draft_ApplyStyle","Draft_ToggleDisplayMode","Draft_AddToGroup",
|
||||
"Draft_SelectGroup","Draft_SelectPlane",
|
||||
"Draft_ShowSnapBar","Draft_ToggleGrid","Draft_UndoLine",
|
||||
|
||||
@@ -2456,6 +2456,41 @@ def getCloneBase(obj,strict=False):
|
||||
return False
|
||||
return obj
|
||||
|
||||
|
||||
def mirror(objlist,p1,p2):
|
||||
'''mirror(objlist,p1,p2,[clone]): creates a mirrored version of the given object(s)
|
||||
along an axis that passes through the two vectors p1 and p2.'''
|
||||
|
||||
if not objlist:
|
||||
FreeCAD.Console.PrintError(translate("draft","No object given\n"))
|
||||
return
|
||||
if p1 == p2:
|
||||
FreeCAD.Console.PrintError(translate("draft","The two points are coincident\n"))
|
||||
return
|
||||
if not isinstance(objlist,list):
|
||||
objlist = [objlist]
|
||||
|
||||
result = []
|
||||
|
||||
for obj in objlist:
|
||||
mir = FreeCAD.ActiveDocument.addObject("Part::Mirroring","mirror")
|
||||
mir.Label = "Mirror of "+obj.Label
|
||||
mir.Source = obj
|
||||
if gui:
|
||||
norm = FreeCADGui.ActiveDocument.ActiveView.getViewDirection().negative()
|
||||
else:
|
||||
norm = FreeCAD.Vector(0,0,1)
|
||||
pnorm = p2.sub(p1).cross(norm).normalize()
|
||||
mir.Base = p1
|
||||
mir.Normal = pnorm
|
||||
formatObject(mir,obj)
|
||||
result.append(mir)
|
||||
|
||||
if len(result) == 1:
|
||||
result = result[0]
|
||||
return result
|
||||
|
||||
|
||||
def heal(objlist=None,delete=True,reparent=True):
|
||||
'''heal([objlist],[delete],[reparent]) - recreates Draft objects that are damaged,
|
||||
for example if created from an earlier version. If delete is True,
|
||||
|
||||
@@ -4409,6 +4409,129 @@ class VisGroup():
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
||||
class Mirror(Modifier):
|
||||
"The Draft_Mirror FreeCAD command definition"
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'Draft_Mirror',
|
||||
'Accel' : "M, I",
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Mirror", "Mirror"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Mirror", "Mirrors the selected objects along a line defined by two points")}
|
||||
|
||||
def Activated(self):
|
||||
self.name = translate("draft","Mirror").decode("utf8")
|
||||
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 mirror\n"))
|
||||
self.call = self.view.addEventCallback("SoEvent",selectObject)
|
||||
else:
|
||||
self.proceed()
|
||||
|
||||
def proceed(self):
|
||||
if self.call: self.view.removeEventCallback("SoEvent",self.call)
|
||||
self.sel = FreeCADGui.Selection.getSelection()
|
||||
self.ui.pointUi(self.name)
|
||||
self.ui.modUi()
|
||||
self.ui.xValue.setFocus()
|
||||
self.ui.xValue.selectAll()
|
||||
#self.ghost = ghostTracker(self.sel) TODO: solve this (see below)
|
||||
self.call = self.view.addEventCallback("SoEvent",self.action)
|
||||
msg(translate("draft", "Pick start point of mirror line:\n"))
|
||||
self.ui.isCopy.hide()
|
||||
|
||||
def finish(self,closed=False,cont=False):
|
||||
if self.ghost:
|
||||
self.ghost.finalize()
|
||||
Modifier.finish(self)
|
||||
if cont and self.ui:
|
||||
if self.ui.continueMode:
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
self.Activated()
|
||||
|
||||
def mirror(self,p1,p2,copy=False):
|
||||
"mirroring 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","Mirror"),
|
||||
['Draft.mirror('+sel+','+DraftVecUtils.toString(p1)+','+DraftVecUtils.toString(p2)+')',
|
||||
'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
|
||||
self.point,ctrlPoint,info = getPoint(self,arg)
|
||||
if (len(self.node) > 0):
|
||||
last = self.node[-1]
|
||||
if self.ghost:
|
||||
if self.point != last:
|
||||
# TODO : the following doesn't work at the moment
|
||||
mu = self.point.sub(last).normalize()
|
||||
if FreeCAD.GuiUp:
|
||||
mv = FreeCADGui.ActiveDocument.ActiveView.getViewDirection().negative()
|
||||
else:
|
||||
mv = FreeCAD.Vector(0,0,1)
|
||||
mw = mv.cross(mu)
|
||||
import WorkingPlane
|
||||
tm = WorkingPlane.plane(u=mu,v=mv,w=mw,pos=last).getPlacement().toMatrix()
|
||||
m = self.ghost.getMatrix()
|
||||
m = m.multiply(tm.inverse())
|
||||
m.scale(FreeCAD.Vector(1,1,-1))
|
||||
m = m.multiply(tm)
|
||||
m.scale(FreeCAD.Vector(-1,1,1))
|
||||
self.ghost.setMatrix(m)
|
||||
if self.extendedCopy:
|
||||
if not hasMod(arg,MODALT): self.finish()
|
||||
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 of mirror line:\n"))
|
||||
if self.planetrack:
|
||||
self.planetrack.set(self.point)
|
||||
else:
|
||||
last = self.node[0]
|
||||
if self.ui.isCopy.isChecked() or hasMod(arg,MODALT):
|
||||
self.mirror(last,self.point,True)
|
||||
else:
|
||||
self.mirror(last,self.point)
|
||||
if hasMod(arg,MODALT):
|
||||
self.extendedCopy = True
|
||||
else:
|
||||
self.finish(cont=True)
|
||||
|
||||
def numericInput(self,numx,numy,numz):
|
||||
"this function gets called by the toolbar when valid x, y, and z have been entered there"
|
||||
self.point = Vector(numx,numy,numz)
|
||||
if not self.node:
|
||||
self.node.append(self.point)
|
||||
if self.ghost:
|
||||
self.ghost.on()
|
||||
msg(translate("draft", "Pick end point of mirror line:\n"))
|
||||
else:
|
||||
last = self.node[-1]
|
||||
if self.ui.isCopy.isChecked():
|
||||
self.mirror(last,self.point,True)
|
||||
else:
|
||||
self.mirror(last,self.point)
|
||||
self.finish()
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Snap tools
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -4620,6 +4743,7 @@ FreeCADGui.addCommand('Draft_Clone',Draft_Clone())
|
||||
FreeCADGui.addCommand('Draft_PathArray',PathArray())
|
||||
FreeCADGui.addCommand('Draft_Heal',Heal())
|
||||
FreeCADGui.addCommand('Draft_VisGroup',VisGroup())
|
||||
FreeCADGui.addCommand('Draft_Mirror',Mirror())
|
||||
|
||||
# context commands
|
||||
FreeCADGui.addCommand('Draft_FinishLine',FinishLine())
|
||||
|
||||
@@ -611,6 +611,27 @@ class ghostTracker(Tracker):
|
||||
except:
|
||||
print("Error retrieving coin node")
|
||||
return sep
|
||||
|
||||
def getMatrix(self):
|
||||
r = FreeCADGui.ActiveDocument.ActiveView.getViewer().getSoRenderManager().getViewportRegion()
|
||||
v = coin.SoGetMatrixAction(r)
|
||||
m = self.trans.getMatrix(v)
|
||||
if m:
|
||||
m = m.getValue()
|
||||
return FreeCAD.Matrix(m[0][0],m[0][1],m[0][2],m[0][3],
|
||||
m[1][0],m[1][1],m[1][2],m[1][3],
|
||||
m[2][0],m[2][1],m[2][2],m[2][3],
|
||||
m[3][0],m[3][1],m[3][2],m[3][3])
|
||||
else:
|
||||
return FreeCAD.Matrix()
|
||||
|
||||
def setMatrix(self,matrix):
|
||||
m = coin.SbMatrix(matrix.A11,matrix.A12,matrix.A13,matrix.A14,
|
||||
matrix.A21,matrix.A22,matrix.A23,matrix.A24,
|
||||
matrix.A31,matrix.A32,matrix.A33,matrix.A34,
|
||||
matrix.A41,matrix.A42,matrix.A43,matrix.A44)
|
||||
self.trans.setMatrix(m)
|
||||
|
||||
|
||||
class editTracker(Tracker):
|
||||
"A node edit tracker"
|
||||
|
||||
@@ -112,7 +112,7 @@ class DraftWorkbench (Workbench):
|
||||
"Draft_Trimex", "Draft_Upgrade", "Draft_Downgrade", "Draft_Scale",
|
||||
"Draft_Edit","Draft_WireToBSpline","Draft_AddPoint",
|
||||
"Draft_DelPoint","Draft_Shape2DView","Draft_Draft2Sketch","Draft_Array",
|
||||
"Draft_PathArray","Draft_Clone","Draft_Drawing"]
|
||||
"Draft_PathArray","Draft_Clone","Draft_Drawing","Draft_Mirror"]
|
||||
self.treecmdList = ["Draft_ApplyStyle","Draft_ToggleDisplayMode","Draft_AddToGroup",
|
||||
"Draft_SelectGroup","Draft_SelectPlane",
|
||||
"Draft_ShowSnapBar","Draft_ToggleGrid"]
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
<file>icons/Draft_ShapeString.svg</file>
|
||||
<file>icons/Draft_Facebinder.svg</file>
|
||||
<file>icons/Draft_FlipDimension.svg</file>
|
||||
<file>icons/Draft_Mirror.svg</file>
|
||||
<file>patterns/concrete.svg</file>
|
||||
<file>patterns/cross.svg</file>
|
||||
<file>patterns/line.svg</file>
|
||||
|
||||
147
src/Mod/Draft/Resources/icons/Draft_Mirror.svg
Normal file
147
src/Mod/Draft/Resources/icons/Draft_Mirror.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.8 KiB |
Reference in New Issue
Block a user