Ah, apologies for being unclear.
My script is creating this plane in the middle of a long series of steps, there is nothing selected in the UI when trying to create the plane, the script itself is referring to the points using API calls to the objects in the document rather than querying UI.activeSelections.
Here is a script to replicate the issue:
import adsk.core, adsk.fusion, adsk.cam, traceback
def create_sketch_line(sketch, point1, point2, constrainedLength=None, additionalConstraint=None):
line = sketch.sketchCurves.sketchLines.addByTwoPoints(point1, point2)
line.isConstruction = True
if constrainedLength:
dimensionLabelPoint = adsk.core.Point3D.create(
(point1.geometry.x + point2.geometry.x)/2.0,
(point1.geometry.y + point2.geometry.y)/2.0,
(point1.geometry.z + point2.geometry.z)/2.0)
dimension = sketch.sketchDimensions.addDistanceDimension(
point1,
point2,
adsk.fusion.DimensionOrientations.AlignedDimensionOrientation,
dimensionLabelPoint)
dimension.parameter.value = constrainedLength
if additionalConstraint == 'h':
sketch.geometricConstraints.addHorizontal(line)
elif additionalConstraint == 'v':
sketch.geometricConstraints.addVertical(line)
return line
def create_round_sweep_from_line(root, sketch_line, diameter, name_suffix):
path = root.features.createPath(sketch_line, False)
planes = root.constructionPlanes
planeInput = planes.createInput()
planeInput.setByDistanceOnPath(path, adsk.core.ValueInput.createByReal(0))
plane = planes.add(planeInput)
plane.name = 'sweep ' + name_suffix
sketches = root.sketches
sweepSketch = sketches.add(plane)
sweepSketch.name = 'sweep ' + name_suffix
center = plane.geometry.origin
center = sweepSketch.modelToSketchSpace(center)
sweepSketch.sketchCurves.sketchCircles.addByCenterRadius(center, diameter/2.0)
profile = sweepSketch.profiles[0]
# create sweep
sweepFeatures = root.features.sweepFeatures
sweepInput = sweepFeatures.createInput(profile, path, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
sweepInput.orientation = adsk.fusion.SweepOrientationTypes.PerpendicularOrientationType
sweep = sweepFeatures.add(sweepInput)
return sweep
def hollow_out_sweep(root, sweep, wall):
# create shell
startFaces = sweep.startFaces
endFaces = sweep.endFaces
objCollection = adsk.core.ObjectCollection.create()
for startFace in startFaces:
objCollection.add(startFace)
for endFace in endFaces:
objCollection.add(endFace)
shellFeatures = root.features.shellFeatures
shellInput = shellFeatures.createInput(objCollection, False)
shellInput.insideThickness = adsk.core.ValueInput.createByReal(wall)
shellFeatures.add(shellInput)
def create_tube_component(root, sketch_line, diameter, wall, name_suffix):
sweep = create_round_sweep_from_line(root, sketch_line, diameter, name_suffix)
body = sweep.bodies.item(0)
body.name = 'Tube ' + name_suffix
hollow_out_sweep(root, sweep, wall)
component = body.createComponent().parentComponent
return component
def cut(root, targetComp, toolComp):
toolBodies = adsk.core.ObjectCollection.create()
toolBodies.add(toolComp.bRepBodies.item(0))
combineFeatureInput = root.features.combineFeatures.createInput(targetComp.bRepBodies.item(0), toolBodies)
combineFeatureInput.isKeepToolBodies = True
combineFeatureInput.operation = adsk.fusion.FeatureOperations.CutFeatureOperation
root.features.combineFeatures.add(combineFeatureInput)
def max_body_volume(occurrence):
v = 0
for b in occurrence.bRepBodies:
if b.volume > v:
v = b.volume
return v
# keeps only the largest body (by volume)
def remove_smaller_bodies(root, component):
occurrence = root.allOccurrencesByComponent(component).item(0)
max_vol = max_body_volume(occurrence)
for b in occurrence.bRepBodies:
if b.volume < max_vol:
root.features.removeFeatures.add(b)
def intersect(root, targetComp, toolComp, suffix):
toolBodies = adsk.core.ObjectCollection.create()
toolBodies.add(toolComp.bRepBodies.item(0))
combineFeatureInput = root.features.combineFeatures.createInput(targetComp.bRepBodies.item(0), toolBodies)
combineFeatureInput.isKeepToolBodies = True
combineFeatureInput.isNewComponent = True
combineFeatureInput.operation = adsk.fusion.FeatureOperations.IntersectFeatureOperation
newCombineFeature = root.features.combineFeatures.add(combineFeatureInput)
newBody = newCombineFeature.bodies.item(0)
newBody.name = 'Intersect ' + suffix
newComponent = newBody.parentComponent
newComponent.name = 'Intersect ' + suffix
return newComponent
def body_longest_edge(body):
result = None
max_length = 0.0
for edge in body.edges:
if edge.length > max_length:
result = edge
max_length = edge.length
return result
def run(context):
ui = None
try:
app = adsk.core.Application.get()
ui = app.userInterface
# start new doc
app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)
design = adsk.fusion.Design.cast(app.activeProduct)
root = design.rootComponent
sketch1 = root.sketches.add(root.yZConstructionPlane)
# ---------------------
# draw 2-D side profile
# ---------------------
# define points
pointX = sketch1.sketchPoints.add(adsk.core.Point3D.create(0, 0, 0))
pointA = sketch1.sketchPoints.add(adsk.core.Point3D.create(0, 1, 0))
pointB = sketch1.sketchPoints.add(adsk.core.Point3D.create(-37.2, 0, 0))
pointC = sketch1.sketchPoints.add(adsk.core.Point3D.create(0, 13.68, 0))
pointD = sketch1.sketchPoints.add(adsk.core.Point3D.create(-37.849, 34.774, 0))
pointE = sketch1.sketchPoints.add(adsk.core.Point3D.create(-70.668, -1.463, 0))
# fix point X to sketch origin
sketch1.geometricConstraints.addCoincident(pointX, sketch1.originPoint)
# draw lines between points
create_sketch_line(sketch1, pointA, pointX, 1.0, 'v')
create_sketch_line(sketch1, pointB, pointX, 37.20, 'h')
create_sketch_line(sketch1, pointA, pointC, 12.68, 'v')
create_sketch_line(sketch1, pointB, pointD, 34.78)
create_sketch_line(sketch1, pointB, pointE, 33.50)
create_sketch_line(sketch1, pointC, pointD, 43.33)
create_sketch_line(sketch1, pointD, pointE, 48.89)
# ---------------------
# draw 3-D construction lines
# ---------------------
# define Z-elevated points in sketch that will bound 3-D lines of elements
elevPointB1 = sketch1.sketchPoints.add(adsk.core.Point3D.create(pointB.geometry.x, pointB.geometry.y, 2.2515))
elevPointB2 = sketch1.sketchPoints.add(adsk.core.Point3D.create(pointB.geometry.x, pointB.geometry.y, 5.503))
elevPointD = sketch1.sketchPoints.add(adsk.core.Point3D.create(pointD.geometry.x, pointD.geometry.y, 3.7525))
elevPointE = sketch1.sketchPoints.add(adsk.core.Point3D.create(pointE.geometry.x, pointE.geometry.y, 2.2515))
# draw lines between points
line3dBeB2 = create_sketch_line(sketch1, pointB, elevPointB2)
line3deB1eD = create_sketch_line(sketch1, elevPointB1, elevPointD)
line3deB1eE = create_sketch_line(sketch1, elevPointB1, elevPointE)
# create tubular components
compSleeveB = create_tube_component(root, line3dBeB2, 1.002, 0.125, ' sleeveB')
compTubeBD = create_tube_component(root, line3deB1eD, 1.002, 0.125, ' BD')
compTubeBE = create_tube_component(root, line3deB1eE, 1.002, 0.125, ' BE')
# use sleeve B to cut tubes
cut(root, compTubeBD, compSleeveB)
cut(root, compTubeBE, compSleeveB)
# remove the small pieces left after cut
remove_smaller_bodies(root, compTubeBD)
remove_smaller_bodies(root, compTubeBE)
# create new component from intersection
intersectComponent = intersect(root, compTubeBD, compTubeBE, 'BD_BE')
# make visible only the relevant items
compTubeBD.isBodiesFolderLightBulbOn = False
compTubeBE.isBodiesFolderLightBulbOn = False
compSleeveB.isBodiesFolderLightBulbOn = False
sketch1.isVisible = True
# create construction plane using 3 points
# find the longest edge on intersectComponent and grab the vertices
edge = body_longest_edge(intersectComponent.bRepBodies.item(0))
p1 = edge.startVertex
p2 = edge.endVertex
p3 = elevPointB1 # third point is a sketch point
planeInput = root.constructionPlanes.createInput()
result = planeInput.setByThreePoints(p1, p2, p3)
print(result)
# Print out info about the three points before we try to create the ConstructionPlane
print(' ')
print(' ')
print('+++++++++++++++++++++++++++++++++')
print('p1: (' + str(p1.geometry.x) + ',' + str(p1.geometry.y) + ',' + str(p1.geometry.z) + ') ' + str(p1))
print('p2: (' + str(p2.geometry.x) + ',' + str(p2.geometry.y) + ',' + str(p2.geometry.z) + ') ' + str(p2))
print('p3: (' + str(p3.worldGeometry.x) + ',' + str(p3.worldGeometry.y) + ',' + str(p3.worldGeometry.z) + ') ' + str(p3))
print('+++++++++++++++++++++++++++++++++')
print(' ')
print(' ')
# The next line fails with:
#
# File ".../Autodesk Fusion 360.app/Contents/Api/Python/packages/adsk/fusion.py", line 7158, in add
# return _fusion.ConstructionPlanes_add(self, *args)
# RuntimeError: 2 : InternalValidationError : data_->execute(&obj, apiName) && obj
#
root.constructionPlanes.add(planeInput)
# If you go into the UI and select "Intersect BD_BE:1" in browser,
# then use "Find in Window", you can select these three points manually,
# then execute the following in the Text Commands pane:
"""
app = adsk.core.Application.get()
ui = app.userInterface
product = app.activeProduct
design = adsk.fusion.Design.cast(product)
root = design.rootComponent
pnt1 = ui.activeSelections.item(0).entity
pnt2 = ui.activeSelections.item(1).entity
pnt3 = ui.activeSelections.item(2).entity
print('p1: (' + str(pnt1.geometry.x) + ',' + str(pnt1.geometry.y) + str(pnt1.geometry.z) + ') ' + str(pnt1))
print('p2: (' + str(pnt2.geometry.x) + ',' + str(pnt2.geometry.y) + str(pnt2.geometry.z) + ') ' + str(pnt2))
print('p3: (' + str(pnt3.worldGeometry.x) + ',' + str(pnt3.worldGeometry.y) + str(pnt3.worldGeometry.z) + ') ' + str(pnt3))
planeInput = root.constructionPlanes.createInput()
planeInput.setByThreePoints(pnt1, pnt2, pnt3)
plane = root.constructionPlanes.add(planeInput)
"""
except:
if ui:
ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
print(traceback.format_exc())
Script fails at root.constructionPlanes.add(planeInput):
File ".../Autodesk Fusion 360.app/Contents/Api/Python/packages/adsk/fusion.py", line 7158, in add
return _fusion.ConstructionPlanes_add(self, *args)
RuntimeError: 2 : InternalValidationError : data_->execute(&obj, apiName) && obj
Debug print output from above in Console:
+++++++++++++++++++++++++++++++++
p1: (1.909322032241705,0.35064931227585233,37.55783524113825) <adsk.fusion.BRepVertex; proxy of <Swig Object of type 'adsk::core::Ptr< adsk::fusion::BRepVertex > *' at 0x13d844a80> >
p2: (2.6087638471288064,0.3352915843712802,37.572264091002346) <adsk.fusion.BRepVertex; proxy of <Swig Object of type 'adsk::core::Ptr< adsk::fusion::BRepVertex > *' at 0x13d8c8810> >
p3: (2.2515,0.0,37.2) <adsk.fusion.SketchPoint; proxy of <Swig Object of type 'adsk::core::Ptr< adsk::fusion::SketchPoint > *' at 0x13d844ba0> >
+++++++++++++++++++++++++++++++++
After script terminates with error, find "Intersect BD_BE:1" in window, select the three points manually in UI:

Run the following in Text Commands pane to check that all info is the same:
app = adsk.core.Application.get()
ui = app.userInterface
product = app.activeProduct
design = adsk.fusion.Design.cast(product)
root = design.rootComponent
pnt1 = ui.activeSelections.item(0).entity
pnt2 = ui.activeSelections.item(1).entity
pnt3 = ui.activeSelections.item(2).entity
print('p1: (' + str(pnt1.geometry.x) + ',' + str(pnt1.geometry.y) + str(pnt1.geometry.z) + ') ' + str(pnt1))
print('p2: (' + str(pnt2.geometry.x) + ',' + str(pnt2.geometry.y) + str(pnt2.geometry.z) + ') ' + str(pnt2))
print('p3: (' + str(pnt3.worldGeometry.x) + ',' + str(pnt3.worldGeometry.y) + str(pnt3.worldGeometry.z) + ') ' + str(pnt3))
Output from above:
print('p1: (' + str(pnt1.geometry.x) + ',' + str(pnt1.geometry.y) + str(pnt1.geometry.z) + ') ' + str(pnt1))
p1: (1.909322032241705,0.3506493122758523337.55783524113825) <adsk.fusion.BRepVertex; proxy of <Swig Object of type 'adsk::core::Ptr< adsk::fusion::BRepVertex > *' at 0x13d8449c0> >
print('p2: (' + str(pnt2.geometry.x) + ',' + str(pnt2.geometry.y) + str(pnt2.geometry.z) + ') ' + str(pnt2))
p2: (2.6087638471288064,0.335291584371280237.572264091002346) <adsk.fusion.BRepVertex; proxy of <Swig Object of type 'adsk::core::Ptr< adsk::fusion::BRepVertex > *' at 0x13d844f90> >
print('p3: (' + str(pnt3.worldGeometry.x) + ',' + str(pnt3.worldGeometry.y) + str(pnt3.worldGeometry.z) + ') ' + str(pnt3))
p3: (2.2515,0.037.2) <adsk.fusion.SketchPoint; proxy of <Swig Object of type 'adsk::core::Ptr< adsk::fusion::SketchPoint > *' at 0x13d844a80> >
Coordinates and object types are the same between API and manual UI selection. Memory addresses are different, and API memory address for point 1 == UI memory address for point 3 (?), but I don't know if things got shuffled around in memory between script execution and manual UI manipulation.
Finally, create construction plane in Text Commands pane:
planeInput = root.constructionPlanes.createInput()
planeInput.setByThreePoints(pnt1, pnt2, pnt3)
plane = root.constructionPlanes.add(planeInput)
and it gets created successfully, even though it failed when trying to do this via script.