I'd like a script to split a body in multiples slices. For it I need to select single a body, a single plane and a single edge.
What I found in the implementation is that it allows me to select the same item (body, plane or edge) multiples time even tough each commandInput has setSelectionLimits(1,1) which means only one.
1. Run the script; the focus is automatically set to choose a body.
2. Select any body you have in the design; after choosing it the focus will be set to choose a plane.
3. Select any plane you have in the design; after choosing it the focus will be set to choose an edge.
4. Select any edge you have in the design.
5. Click on the command input to select the body (with label "1 selected")
6. At this point in the select, the edge you selected is highlighted.
7. Select the same body as in step 2 and now the command input to select the body has the label "2 selected"
The same situation happen with the command input for the plane and the edge.
What I'm missing to avoid it to the let the user select the same item more than once?
I also expect the body to be highlighted when the body command input get the focus, as it happen in the command inputs of the application.
You can use any simple design with two bodies on it to test this script. In my case I used a box and a cilinder.
The following image shows the status of the command input with multiple objects selected on each command input:
import adsk.core, adsk.fusion, adsk.cam, traceback
# Globals
_app = adsk.core.Application.cast(None)
_ui = adsk.core.UserInterface.cast(None)
_handlers = []
_cmdDefGeneral = 'cmdDefGeneral'
_BODY_SELECTION = 'bodySelection'
_BODY_SELECTED = 'bodySelected'
_PLANE_SELECTION = 'planeSelection'
_PLANE_SELECTED = 'planeSelected'
_EDGE_SELECTION = 'edgeSelection'
_EDGE_SELECTED = 'edgeSelected'
_ERR_MESSAGE = 'errMessage'
_bodySelection = adsk.core.SelectionCommandInput.cast(None)
def run(context😞
try:
global _app, _ui
_app = adsk.core.Application.get()
_ui = _app.userInterface
cmdDef = _ui.commandDefinitions.itemById(_cmdDefGeneral)
if not cmdDef:
# Create a command definition.
cmdDef = _ui.commandDefinitions.addButtonDefinition(_cmdDefGeneral, 'body splitter', 'Splits a body in multiple slices')
# Connect to the command created event.
onCommandCreated = splitterCommandCreatedHandler()
cmdDef.commandCreated.add(onCommandCreated)
_handlers.append(onCommandCreated)
# Execute the command.
cmdDef.execute()
adsk.autoTerminate(False)
except:
if _ui:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
# Event handler that reacts to any changes the user makes to any of the command inputs.
class splitterCommandInputChangedHandler(adsk.core.InputChangedEventHandler😞
def __init__(self😞
super().__init__()
def notify(self, args😞
global _bodySelection
try:
eventArgs = adsk.core.InputChangedEventArgs.cast(args)
if eventArgs.input.id == _BODY_SELECTION:
textBody = adsk.core.TextBoxCommandInput.cast(eventArgs.inputs.itemById(_BODY_SELECTED))
if textBody:
if eventArgs.input.selectionCount:
body = adsk.fusion.BRepBody.cast(eventArgs.input.selection(0).entity)
bbox = adsk.core.BoundingBox3D.cast(body.boundingBox)
mn = [f'{n:.4f}' for n in bbox.minPoint.asArray()]
mx = [f'{n:.4f}' for n in bbox.maxPoint.asArray()]
textBody.text = f'{body.name}\n{mn}\n{mx}'
adsk.core.SelectionCommandInput.cast(eventArgs.inputs.itemById(_PLANE_SELECTION)).hasFocus = True
else:
textBody.text = ''
elif eventArgs.input.id == _PLANE_SELECTION:
textPlane = adsk.core.TextBoxCommandInput.cast(eventArgs.inputs.itemById(_PLANE_SELECTED))
if textPlane:
if eventArgs.input.selectionCount:
if isinstance(eventArgs.input.selection(0).entity,adsk.fusion.ConstructionPlane😞
geom = adsk.fusion.ConstructionPlane.cast(eventArgs.input.selection(0).entity).geometry
else:
geom = adsk.fusion.BRepFace.cast(eventArgs.input.selection(0).entity).geometry
if isinstance(geom,adsk.core.Plane😞
plane = adsk.core.Plane.cast(geom)
textPlane.text = f'{plane.uDirection.x}|{plane.uDirection.y}|{plane.uDirection.z} ~ {plane.vDirection.x}|{plane.vDirection.y}|{plane.vDirection.z} | {plane.origin.x}|{plane.origin.y}|{plane.origin.z}'
adsk.core.SelectionCommandInput.cast(eventArgs.inputs.itemById(_EDGE_SELECTION)).hasFocus = True
else:
adsk.core.SelectionCommandInput.cast(eventArgs.inputs.itemById(_PLANE_SELECTION)).clearSelection()
textPlane.text = 'invalid plane'
else:
textPlane.text = ''
elif eventArgs.input.id == _EDGE_SELECTION:
textEdge = adsk.core.TextBoxCommandInput.cast(eventArgs.inputs.itemById(_EDGE_SELECTED))
if textEdge:
if eventArgs.input.selectionCount:
geom = eventArgs.input.selection(0).entity.geometry
if isinstance(geom,adsk.core.Line3D😞
op = geom.startPoint
dp = geom.endPoint
else:
op = geom.origin
dp = geom.direction
axis = 'x' if op.x-dp.x != 0.0 else 'y' if op.y-dp.y != 0.0 else 'z'
textEdge.text = f'{op.x}|{op.y}|{op.z} ~ {dp.x}|{dp.y}|{dp.z} | {axis}'
else:
textEdge.text = ''
except:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
# Event handler that reacts when the command definition is executed which
# results in the command being created and this event being fired.
class splitterCommandCreatedHandler(adsk.core.CommandCreatedEventHandler😞
def __init__(self😞
super().__init__()
def notify(self, args😞
# global _bodySelection, _handlers
try:
# Get the command that was created.
cmd = adsk.core.Command.cast(args.command)
#-------------------------------------------------------------
# Connect to the command destroyed event.
onDestroy = splitterCommandDestroyHandler()
cmd.destroy.add(onDestroy)
_handlers.append(onDestroy)
# Connect to the input changed event.
onInputChanged = splitterCommandInputChangedHandler()
cmd.inputChanged.add(onInputChanged)
_handlers.append(onInputChanged)
#-------------------------------------------------------------
# Get the CommandInputs collection associated with the command.
inputs = cmd.commandInputs
# Create a selection input.
bodySelection = inputs.addSelectionInput(_BODY_SELECTION, 'Body', 'Select body to split')
bodySelection.hasFocus = True
bodySelection.setSelectionLimits(1,1)
bodySelection.addSelectionFilter("Bodies")
# Create a read only textbox input.
inputs.addTextBoxCommandInput(_BODY_SELECTED, 'Body selected:', '', 3, True)
# Create a plane input.
planeSelection = inputs.addSelectionInput(_PLANE_SELECTION, 'Plane', 'Select tool plane')
planeSelection.setSelectionLimits(1,1)
planeSelection.addSelectionFilter("ConstructionPlanes")
planeSelection.addSelectionFilter("Faces")
# Create a read only textbox input.
inputs.addTextBoxCommandInput(_PLANE_SELECTED, 'Plane selected:', '', 3, True)
# Create a plane input.
edgeSelection = inputs.addSelectionInput(_EDGE_SELECTION, 'Edge', 'Select direction')
edgeSelection.setSelectionLimits(1,1)
edgeSelection.addSelectionFilter("LinearEdges")
edgeSelection.addSelectionFilter("SketchLines")
edgeSelection.addSelectionFilter("ConstructionLines")
# Create a read only textbox input.
inputs.addTextBoxCommandInput(_EDGE_SELECTED, 'Plane selected:', '', 3, True)
# Create a read only textbox input.
inputs.addTextBoxCommandInput(_ERR_MESSAGE, '', '', 1, True)
except:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
# Event handler that reacts to when the command is destroyed. This terminates the script.
class splitterCommandDestroyHandler(adsk.core.CommandEventHandler😞
def __init__(self😞
super().__init__()
def notify(self, args😞
try:
# When the command is done, terminate the script
# This will release all globals which will remove all event handlers
adsk.terminate()
except:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))