Macro SketchUnmap: Difference between revisions
(Page creation) |
(Code updated, PR added, construction banner removed) |
||
Line 7: | Line 7: | ||
|FCVersion= 0.17+ |
|FCVersion= 0.17+ |
||
}} |
}} |
||
⚫ | |||
⚫ | |||
==Description== |
==Description== |
||
Line 27: | Line 26: | ||
To use the macro, just select the target sketch (eg. in the tree view) then run the macro. That's it ! |
To use the macro, just select the target sketch (eg. in the tree view) then run the macro. That's it ! |
||
===Installation=== |
|||
At the moment, the macro isn't available from the addon manager => PR submitted : https://github.com/FreeCAD/FreeCAD-macros/pull/48 |
|||
So you have to copy the below code and paste it in FreeCAD macro editor. |
|||
For more detailed explanations, see the [[How to install macros]] page. |
|||
===Details=== |
===Details=== |
||
Line 66: | Line 72: | ||
# Licensed under LGPL v2 |
# Licensed under LGPL v2 |
||
# |
# |
||
# This macro will unmap a sketch from eg. a face and |
# This macro will unmap a sketch from eg. a face and make its placement absolute in the body. It proposes 3 options (forcely the first if sketch not in a body) : |
||
# * "Raw" mode => the sketch placement is made absolute in the body referential, nothing more |
# * "Raw" mode => the sketch placement is made absolute in the body referential, nothing more |
||
# * "DP@Face mode" => a datum plane is created where the mapping face is, then the sketch is attached to it respecting its attachment offset |
# * "DP@Face mode" => a datum plane is created where the mapping face is, then the sketch is attached to it respecting its attachment offset |
||
# * "DP@Sketch" mode => a datum place is created where the sketch is (including attachment offset), then the sketch is attached to its origin |
# * "DP@Sketch" mode => a datum place is created where the sketch is (including attachment offset), then the sketch is attached to its origin |
||
# |
# |
||
# Main use of the macro is to make design more robust to |
# Main use of the macro is to make design more robust to topological naming issue |
||
# |
# |
||
# Version history : |
# Version history : |
||
# *0.5 : beta release |
# *0.5 : beta release |
||
# *0.6 : some typo improvement + commenting for official PR |
|||
# |
# |
||
##################################### |
##################################### |
||
__Name__ = 'SketchUnmap' |
|||
__Comment__ = 'Unmap a sketch & makes its placement absolute"' |
|||
__author__ = "openBrain" |
|||
__Author__ = 'openBrain' |
|||
__license__ = "LGPL v2" |
|||
__Version__ = '0.6' |
|||
__version__ = "0.5" # Ready for beta test |
|||
__Date__ = '2019-06-10' |
|||
__License__ = 'LGPL v2' |
|||
__Web__ = 'https://www.freecadweb.org/wiki/Macro_SketchUnmap' |
|||
__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_SketchUnmap' |
|||
__Icon__ = '' |
|||
__Help__ = 'Select the sketch to unmap (eg. in the tree view) then run the macro' |
|||
__Status__ = 'Beta' |
|||
__Requires__ = 'FreeCAD >= 0.17' |
|||
__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=36078' |
|||
__Files__ = '' |
|||
__dbg__ = False #True for debugging |
__dbg__ = False #True for debugging |
||
Line 88: | Line 104: | ||
from PySide import QtGui |
from PySide import QtGui |
||
def cslM(msg): |
def cslM(msg): #Print message in console |
||
FreeCAD.Console.PrintMessage('\n') |
FreeCAD.Console.PrintMessage('\n') |
||
FreeCAD.Console.PrintMessage(msg) |
FreeCAD.Console.PrintMessage(msg) |
||
def cslW(msg): |
def cslW(msg): #Print warning in console |
||
FreeCAD.Console.PrintMessage('\n') |
FreeCAD.Console.PrintMessage('\n') |
||
FreeCAD.Console.PrintWarning(msg) |
FreeCAD.Console.PrintWarning(msg) |
||
def cslE(msg): |
def cslE(msg): #Print error in console |
||
FreeCAD.Console.PrintMessage('\n') |
FreeCAD.Console.PrintMessage('\n') |
||
FreeCAD.Console.PrintError(msg) |
FreeCAD.Console.PrintError(msg) |
||
def cslD(msg): |
def cslD(msg): #Print debug message in console |
||
if __dbg__: |
if __dbg__: |
||
FreeCAD.Console.PrintMessage('\n') |
FreeCAD.Console.PrintMessage('\n') |
||
FreeCAD.Console.PrintMessage("Debug : " + str(msg)) |
FreeCAD.Console.PrintMessage("Debug : " + str(msg)) |
||
_0Vec_ = FreeCAD.Vector(0, 0, 0) |
_0Vec_ = FreeCAD.Vector(0, 0, 0) #Shortener for null vector |
||
_ZVec_ = FreeCAD.Vector(0, 0, 1) |
_ZVec_ = FreeCAD.Vector(0, 0, 1) #Shortener for Z axis |
||
if __dbg__: ##Clear report view in debug mode |
if __dbg__: ##Clear report view in debug mode |
||
FreeCADGui.getMainWindow().findChild(QtGui.QTextEdit, "Report view").clear() |
FreeCADGui.getMainWindow().findChild(QtGui.QTextEdit, "Report view").clear() |
||
cslM("Starting |
cslM("Starting SketchUnmap macro") |
||
cslD("Checking selection") |
cslD("Checking selection") |
||
if (len(Gui.Selection.getSelection()) != 1 or str(Gui.Selection.getSelection()[0]) != '<Sketcher::SketchObject>'): |
if (len(Gui.Selection.getSelection()) != 1 or str(Gui.Selection.getSelection()[0]) != '<Sketcher::SketchObject>'): ##If selection is wrong, print error message and exit |
||
cslE("You must select a sketch that you want to unmap (and only one) ... Exiting") |
cslE("You must select a sketch that you want to unmap (and only one) ... Exiting") |
||
else: |
else: |
||
cslD("Selection OK") |
cslD("Selection OK") |
||
App.ActiveDocument.openTransaction(" |
App.ActiveDocument.openTransaction("SketchUnmap") #Open transaction for undo management |
||
sk = Gui.Selection.getSelection()[0] |
sk = Gui.Selection.getSelection()[0] #Get target sketch |
||
skNatPl = sk.Placement |
skNatPl = sk.Placement #Store placement |
||
skNatAO = sk.AttachmentOffset |
skNatAO = sk.AttachmentOffset #Store attachment offset |
||
skInBody = False |
skInBody = False |
||
for obj in sk.InList: |
for obj in sk.InList: ##Check if sketch is inside a Body |
||
if obj.TypeId == 'PartDesign::Body': |
if obj.TypeId == 'PartDesign::Body': |
||
skInBody = True |
skInBody = True |
||
skBody = obj |
skBody = obj |
||
cslD("Sketch in a body : " + str(skInBody)) |
cslD("Sketch in a body : " + str(skInBody)) |
||
msgb = QtGui.QMessageBox() |
msgb = QtGui.QMessageBox() ##Prepare the message box to choose option |
||
msgb.setWindowTitle("Unmap Sketch : Mode selection") |
msgb.setWindowTitle("Unmap Sketch : Mode selection") |
||
msgb.setText("""Choose which unmapping mode you want to apply : |
msgb.setText("""Choose which unmapping mode you want to apply : |
||
Line 140: | Line 156: | ||
sbut = msgb.addButton("DP@Sketch", QtGui.QMessageBox.AcceptRole) |
sbut = msgb.addButton("DP@Sketch", QtGui.QMessageBox.AcceptRole) |
||
cbut = msgb.addButton("Cancel", QtGui.QMessageBox.RejectRole) |
cbut = msgb.addButton("Cancel", QtGui.QMessageBox.RejectRole) |
||
if skInBody: |
if skInBody: #If sketch in a Body |
||
msgb.exec_() |
msgb.exec_() ##Show message box and get user choice |
||
msgbRep = msgb.clickedButton() |
msgbRep = msgb.clickedButton() |
||
else: |
else: |
||
msgbRep = rbut |
msgbRep = rbut #Else apply raw mode automatically |
||
if msgbRep == rbut: |
if msgbRep == rbut: #If raw mode |
||
sk.Support = None |
sk.Support = None ##Just unmap the sketch so its placement is absolute |
||
sk.MapMode = 'Deactivated' |
sk.MapMode = 'Deactivated' |
||
elif msgbRep == fbut: |
elif msgbRep == fbut: #If DP@Face mode |
||
newDP = skBody.newObject('PartDesign::Plane','DP' + sk.Name) |
newDP = skBody.newObject('PartDesign::Plane','DP' + sk.Name) #Create a datum plane |
||
if sk.Label != sk.Name: |
if sk.Label != sk.Name: ##Eventually clarify its label |
||
newDP.Label = 'DP' + sk.Label |
newDP.Label = 'DP' + sk.Label |
||
newDP.Support = None |
newDP.Support = None ##Plane is placed absolute |
||
newDP.MapMode = 'Deactivated' |
newDP.MapMode = 'Deactivated' |
||
newDP.Placement = skNatPl.multiply(skNatAO.inverse()) |
newDP.Placement = skNatPl.multiply(skNatAO.inverse()) #Plane placement is set to former face one |
||
sk.Support = [(newDP,'')] |
sk.Support = [(newDP,'')] #Sketch is mapped to plane keeping its attachment offset |
||
elif msgbRep == sbut: |
elif msgbRep == sbut: #If DP@Sketch mode |
||
newDP = skBody.newObject('PartDesign::Plane','DP' + sk.Name) |
newDP = skBody.newObject('PartDesign::Plane','DP' + sk.Name) #Create a datum plane |
||
if sk.Label != sk.Name: |
if sk.Label != sk.Name: ##Eventually clarify its label |
||
newDP.Label = 'DP' + sk.Label |
newDP.Label = 'DP' + sk.Label |
||
newDP.Support = None |
newDP.Support = None ##Plane is placed absolute |
||
newDP.MapMode = 'Deactivated' |
newDP.MapMode = 'Deactivated' |
||
newDP.Placement = skNatPl |
newDP.Placement = skNatPl #Plane placement is set to former sketch one |
||
sk.Support = [(newDP,'')] |
sk.Support = [(newDP,'')] ##Sketch is mapped to plane reseting its attachment offset |
||
sk.AttachmentOffset = App.Placement(_0Vec_, App.Rotation(_ZVec_, 0)) |
sk.AttachmentOffset = App.Placement(_0Vec_, App.Rotation(_ZVec_, 0)) |
||
App.ActiveDocument.commitTransaction() |
App.ActiveDocument.commitTransaction() #Commit transaction for undo management |
||
cslM("Unmap Sketch Macro ended correctly") |
cslM("Unmap Sketch Macro ended correctly") |
||
Revision as of 11:43, 10 June 2019
Description |
---|
This macro resets a sketch placement to an absolute one, eventually creating a datum plane Macro version: 0.6 Last modified: 2019-06-10 FreeCAD version: 0.17+ Author: OpenBrain |
Author |
OpenBrain |
Download |
None |
Links |
Macros recipes How to install macros How to customize toolbars |
Macro Version |
0.6 |
Date last modified |
2019-06-10 |
FreeCAD Version(s) |
0.17+ |
Default shortcut |
None |
See also |
None |
Description
Context
This macro has been written mainly to circumvent Topological Naming Issue that can break a model when a sketch has been directly or indirectly attached to a face or any other topological item. To prevent breakage, macro shall be applied when the model is still right. It can't "repair" a broken model. If you just break your model, undo the last change(s) back to a good situation, apply the macro to the unstable sketch(es) then redo the previous operation.
Usage
Functionally, the macro will remove the current mapping of the sketch on which it is applied, then apply to it an absolute placement so it is immune to mapping support change.
To do so, the macro will basically propose 3 options (if your sketch isn't in a PartDesign Body, only first option is available and will be applied automatically) :
- "Raw" mode => the sketch placement is made absolute in the body referential, nothing more
- "DP@Face mode" => a datum plane is created where the mapping face is, then the sketch is attached to it respecting its attachment offset
- "DP@Sketch" mode => a datum place is created where the sketch is (including attachment offset), then the sketch is attached to its origin
To use the macro, just select the target sketch (eg. in the tree view) then run the macro. That's it !
Installation
At the moment, the macro isn't available from the addon manager => PR submitted : https://github.com/FreeCAD/FreeCAD-macros/pull/48 So you have to copy the below code and paste it in FreeCAD macro editor.
For more detailed explanations, see the How to install macros page.
Details
For better understanding, below is an example : Let's suppose a simple cube whose top (yellow) face has been drafted. A cylinder is created with a padded circle whose sketch has been mapped (Flat face) to the drafted face and offset to match needs (Attachment offset) :
Now for some reason, you need to revert the pull direction of the draft (of course without the cylinder to move). Here is what basically happen :
The treeview shows an error, the 3D view isn't updated, and the circle sketch is floating in the middle of nowhere...
Now comes the job of the macro (that you need to run before changing the reference face, when the sketch is still at its right place). Select the sketch and run it. If your sketch is in a body, a message box will ask to choose among the 3 different options (if your sketch is out of a body, it will automatically apply the 1st one) :
- "Raw" mode
- "DP@Face mode"
- "DP@Sketch" mode
Which in term of picture gives the following :
Script
Limitations
- Only process one sketch at a time
- Only work on sketch objects
Forum discussion
For any feedback (bug, feature request, comments, ...), please use this forum thread : https://forum.freecadweb.org/viewtopic.php?f=22&t=36078
Code
#!/usr/bin/python
#####################################
# Copyright (c) openBrain 2019
# Licensed under LGPL v2
#
# This macro will unmap a sketch from eg. a face and make its placement absolute in the body. It proposes 3 options (forcely the first if sketch not in a body) :
# * "Raw" mode => the sketch placement is made absolute in the body referential, nothing more
# * "DP@Face mode" => a datum plane is created where the mapping face is, then the sketch is attached to it respecting its attachment offset
# * "DP@Sketch" mode => a datum place is created where the sketch is (including attachment offset), then the sketch is attached to its origin
#
# Main use of the macro is to make design more robust to topological naming issue
#
# Version history :
# *0.5 : beta release
# *0.6 : some typo improvement + commenting for official PR
#
#####################################
__Name__ = 'SketchUnmap'
__Comment__ = 'Unmap a sketch & makes its placement absolute"'
__Author__ = 'openBrain'
__Version__ = '0.6'
__Date__ = '2019-06-10'
__License__ = 'LGPL v2'
__Web__ = 'https://www.freecadweb.org/wiki/Macro_SketchUnmap'
__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_SketchUnmap'
__Icon__ = ''
__Help__ = 'Select the sketch to unmap (eg. in the tree view) then run the macro'
__Status__ = 'Beta'
__Requires__ = 'FreeCAD >= 0.17'
__Communication__ = 'https://forum.freecadweb.org/viewtopic.php?f=22&t=36078'
__Files__ = ''
__dbg__ = False #True for debugging
from PySide import QtGui
def cslM(msg): #Print message in console
FreeCAD.Console.PrintMessage('\n')
FreeCAD.Console.PrintMessage(msg)
def cslW(msg): #Print warning in console
FreeCAD.Console.PrintMessage('\n')
FreeCAD.Console.PrintWarning(msg)
def cslE(msg): #Print error in console
FreeCAD.Console.PrintMessage('\n')
FreeCAD.Console.PrintError(msg)
def cslD(msg): #Print debug message in console
if __dbg__:
FreeCAD.Console.PrintMessage('\n')
FreeCAD.Console.PrintMessage("Debug : " + str(msg))
_0Vec_ = FreeCAD.Vector(0, 0, 0) #Shortener for null vector
_ZVec_ = FreeCAD.Vector(0, 0, 1) #Shortener for Z axis
if __dbg__: ##Clear report view in debug mode
FreeCADGui.getMainWindow().findChild(QtGui.QTextEdit, "Report view").clear()
cslM("Starting SketchUnmap macro")
cslD("Checking selection")
if (len(Gui.Selection.getSelection()) != 1 or str(Gui.Selection.getSelection()[0]) != '<Sketcher::SketchObject>'): ##If selection is wrong, print error message and exit
cslE("You must select a sketch that you want to unmap (and only one) ... Exiting")
else:
cslD("Selection OK")
App.ActiveDocument.openTransaction("SketchUnmap") #Open transaction for undo management
sk = Gui.Selection.getSelection()[0] #Get target sketch
skNatPl = sk.Placement #Store placement
skNatAO = sk.AttachmentOffset #Store attachment offset
skInBody = False
for obj in sk.InList: ##Check if sketch is inside a Body
if obj.TypeId == 'PartDesign::Body':
skInBody = True
skBody = obj
cslD("Sketch in a body : " + str(skInBody))
msgb = QtGui.QMessageBox() ##Prepare the message box to choose option
msgb.setWindowTitle("Unmap Sketch : Mode selection")
msgb.setText("""Choose which unmapping mode you want to apply :
Raw => the sketch placement is made absolute in the body referential, nothing more
DP@Face => a datum plane is created where the mapping face is, then the sketch is attached to it respecting its attachment offset
DP@Sketch => a datum place is created where the sketch is (including attachment offset), then the sketch is attached to its origin
Click 'Cancel' to cancel operation""")
msgb.setIcon(QtGui.QMessageBox.Question)
rbut = msgb.addButton("Raw", QtGui.QMessageBox.AcceptRole)
fbut = msgb.addButton("DP@Face", QtGui.QMessageBox.AcceptRole)
sbut = msgb.addButton("DP@Sketch", QtGui.QMessageBox.AcceptRole)
cbut = msgb.addButton("Cancel", QtGui.QMessageBox.RejectRole)
if skInBody: #If sketch in a Body
msgb.exec_() ##Show message box and get user choice
msgbRep = msgb.clickedButton()
else:
msgbRep = rbut #Else apply raw mode automatically
if msgbRep == rbut: #If raw mode
sk.Support = None ##Just unmap the sketch so its placement is absolute
sk.MapMode = 'Deactivated'
elif msgbRep == fbut: #If DP@Face mode
newDP = skBody.newObject('PartDesign::Plane','DP' + sk.Name) #Create a datum plane
if sk.Label != sk.Name: ##Eventually clarify its label
newDP.Label = 'DP' + sk.Label
newDP.Support = None ##Plane is placed absolute
newDP.MapMode = 'Deactivated'
newDP.Placement = skNatPl.multiply(skNatAO.inverse()) #Plane placement is set to former face one
sk.Support = [(newDP,'')] #Sketch is mapped to plane keeping its attachment offset
elif msgbRep == sbut: #If DP@Sketch mode
newDP = skBody.newObject('PartDesign::Plane','DP' + sk.Name) #Create a datum plane
if sk.Label != sk.Name: ##Eventually clarify its label
newDP.Label = 'DP' + sk.Label
newDP.Support = None ##Plane is placed absolute
newDP.MapMode = 'Deactivated'
newDP.Placement = skNatPl #Plane placement is set to former sketch one
sk.Support = [(newDP,'')] ##Sketch is mapped to plane reseting its attachment offset
sk.AttachmentOffset = App.Placement(_0Vec_, App.Rotation(_ZVec_, 0))
App.ActiveDocument.commitTransaction() #Commit transaction for undo management
cslM("Unmap Sketch Macro ended correctly")