Custom Feature API Preview - Feedback Thread

Custom Feature API Preview - Feedback Thread

prainsberry
Autodesk Autodesk
14,679 Views
81 Replies
Message 1 of 82

Custom Feature API Preview - Feedback Thread

prainsberry
Autodesk
Autodesk

Fusion 360 Custom Feature APIFusion 360 Custom Feature API

 

 

 

 

 

 

 

With the release of Fusion 360 today, we are very excited to announce the availability of a preview of the new Custom Feature API.  This is a long-awaited capability for the Fusion 360 API and our first iteration is now available Please note we are considering this “Preview” functionality as there are some limitations and only some specific workflows that we support That said this a MAJOR enhancement to the Fusion 360 API 

 

You can now not only define a custom command dialog for your add-in, but you can actually define it as a full feature definition This means that parametric timeline updates, model parameter changes and user edits will all now behave as expected for any other feature in Fusion 360 There is a lot of information to digest for this one, so if this interests you, check out our help documentation and learn more about this functionality. 

 

We would love to hear more about how you would like to use it, what you have built, or would like to build.  We would like to use this thread to capture feedback about the current capabilities, as well as what you would like to see next.  



Patrick Rainsberry
Developer Advocate, Fusion 360
14,680 Views
81 Replies
Replies (81)
Message 61 of 82

prainsberry
Autodesk
Autodesk

@pludikar @ginavenolia 
I am very sorry for the delay.  I am definitely following this thread.  I definitely REALLY your feedback, and trust me it is all being taken into account.  I have been holding off responding because I wanted to come back with the specific fix for your issue, but haven't been able to get to it and now this thread has gotten a bit away from me. 
I will try to address your specific questions shortly, as some changes were made recently. 
One thing I want to be very clear about, this capability was introduced into the API INTENTIONALLY as an experiment, we wanted to be VERY CLEAR WITH ALL OF THOSE WARNINGS that this is not a fully formed feature, and it may not be production ready for some time.   
While we have been making some small improvements, there are some very large challenges that need to be addressed before we would consider taking it out of the experimental phase.  Some of these are specifically related to gaps in what you can really achieve with a custom feature today, but as importantly is how we will distribute, support and maintain them as Fusion 360 continues to evolve. 
Without going into all the details there are some pending projects/questions we have internally and until those are addressed (as you correctly observe) significant new development work on custom feature has not been prioritized.  

I believe later this year we should be in a position to evaluate the path forward.   
I will try to get back into this thread and address the specific questions.  MAYBE WE CAN SCHEDULE A CALL, once I have some better answers?
BTW sorry for all the random CAPS-LOCK IN THE RESPONSE.



Patrick Rainsberry
Developer Advocate, Fusion 360
Message 62 of 82

pludikar
Collaborator
Collaborator

@prainsberry 

 

Hi Patrick,

Thanks for the response.  I fully appreciate the experimental/tentative/fragile nature of the custom feature, and I wasn't expecting it to be flawless - I recognize the reason why it was marked with all the warnings.  I think this is going to be a huge leap forward for F360, and I want to contribute, however small, to its eventual success.

 

Since my last post, I've actually been attempting to get the custom pocket example to work using an edge - you may recognise me as the latest author of your/Casey Rogers' dogbone addin, so this custom feature capability is exactly what I want to take the dogbones to the next level.

 

So far, I can say that getting anything, but the simplest custom feature, to work has been a monumental challenge.  In particular, I'm fighting on several fronts at the same time - timeline sychronisation/coordination, triggering custom feature compute, what appears to be inconsistent treatment of events that affect timelines (I'm still not 100% sure, but it seems that some events affect the timeline marker, while others don't), lack of up to date documentation (eg mention of editFeature and beginStep in the User manual section, documentation on what triggers each event) 

 

What I have found specifically is that I've had to disable the custom compute event handler when a customFeature dependency is added.  I would not expect to trigger a consequential event in the process of setting up.  I found that gaining access to a custom feature before it is created proved to be a real challenge (even though I've done it) - for example, adding a dependant Brep entity that is affected by the custom feature: The entity you use as a call argument in dependencyAdd immediately becomes voided by the compute.  To get around that, I have had to access the customFeature after it's created, roll back the timeline, add the entity to dependencies, then roll the timeline forward again.   There are a number of other workarounds I've been trying to figure out, but I'm still working on them.

 

I would be happy to get on a call with you and/or your team - just PM me when you are ready.

 

Regards

Peter

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
Message 63 of 82

pludikar
Collaborator
Collaborator

@prainsberry 

 

As I mentioned before, I'm attempting to get the custom pocket example working with a Brep Edge as a dependency.

 

Here's what I've found, so far:  The custom Pocket example doesn't update when the parameters of the underlying body changes. so, I've been attempting to initialize the customFeature in the command activate eventHandler.  The problem with that is it's not possible to preload the customFeature with all the necessary data (that usually comes from the commandInputs after the command has been activated).  In principle, IMHO, the command activate eventHandler is the right and logical place to initialize the customFeature.

 

However, this leads to some problems - the main one is the customFeature.timelineObject rapidly goes into state 4 (RolledBackFeatureHealthState) which, so far I've not been able to exit from.  I suspect that the 

eventArgs.isValidResult = True in the executePreview eventHandler has a role to play here!  Without it, the preview of a combine feature doesn't work at all, but execute does.  With it, the combine feature does work in preview, but it won't trigger the execute eventHandler.
 
It appears that dependencies (particularly Breps) that are added to a customFeature are not persistent, as I think they should be.  I think they are not actually stored, they appear to be live and reflect the current state of the model.  For example, setting up a customFeature in activate and associating it with editFeature, carries through to change event, validate event and preview event - however, it disappears after pressing OK (as if it were a transaction) and can't be used in execute Handler.  I've not yet tried seeing if it's available in edit command, but I strongly suspect it's missing too.  I think this is generally a significant problem.
 
At the moment, I would suggest that you've made customFeature more complicated than it needs to be.  I would go more along the lines (if it's still a feasible option) of making customFeature a defacto self-contained Object.  That is:
  1. create the object in activate
  2. open the object in preview or command mode - this would expand the customFeature features timeline.
  3. populate the object with dependencies, parameters etc in command mode and or/change event.
  4. close the object (ie contract the customFeature to a single timeline entity) after execute
  5. on edit - open the customFeature - all the appropriate features, parameters, timeline object etc become available.
  6. on model recalculate (ie after any parameter change, not just the customFeature parameters) call on the computeFeature, which in turn has access to the customFeature, and all its associated data.

I'd suggest make the opening and closing of the object an explicit API method.

 

I would also have a customFeature.timeline attribute relative to the customFeature Object - so you could do a customFeature.timeline.moveToEnd(), or moveToStart() which would move the marker inside the opened customFeature.timelineObject.  TimelineObject inside the customFeature actually doesn't make too much sense to me, because it unnecessarily confuses features that are inside the customFeature expansion with those features on the normal timeline.

 

Anyway that's my 2c's worth for the moment.

 

Peter

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
Message 64 of 82

pludikar
Collaborator
Collaborator

@prainsberry 

 

FWIW

 adding or updating a customFeature dependency BRep Entity during a command.inputChanged event will not only cause the computeCustomFeature event to fire, but it will also interfere with F360's command events - in particular, onExecutePreview. 

 

If you add/update a customFeature dependent entity,  onExecutePreview will not fire at the end of the inputChanged event.  You also cannot force the onExecutePreview via a command.onExecutePreview() call.

 

If I comment out the customFeature add/update (only), then onExecutePreview event is fired as expected.

 

If you need me to provide the code, I can do that, but the above should be self explanatory. 

 

I hope helps - assuming that someone is actually working on this!

 

Regards

Peter

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
0 Likes
Message 65 of 82

ginavenolia
Contributor
Contributor

The problem I mentioned six weeks ago is still killing me.  It turns out that it's not specifically a problem with the Custom Feature API, but appears to be a change in behavior of BaseFeature.updateBody, which Custom Feature virtually requires the use of. I've isolated the problem in a small script and posted it on the general API and Scripts board. @prainsberry and @BrianEkins, could please take a look? I'd appreciate any insights that you all could provide. 

 

Thanks,

-Gina

0 Likes
Message 66 of 82

asheepcalledgeorge
Enthusiast
Enthusiast

I hope somebody is working on it too.   As was said before, CustomFeatureDefinition has the potential to take Fusion360 and the parametric community to a whole new level.  Where does it sit in the roadmap at the moment?  Can we sponsor it or do anything to promote it? 🙂 

Message 67 of 82

it-ony
Participant
Participant

Hi, 

I also played around with the experimental API, but for me compute is not invoked. I read through this whole thread, but handling problems of different people in on thread, it is impossible to follow. 

@prainsberry I suggest to publish the demo plugins (which are not working with the latest version of Fusion) to github and people can create issue there, that you could comment on.

 

Also, I would move my experimental plugin to github so you can take a look and might figure out whats the issue. From some comments on the Thread here, I assume it's adding a dependency to an edge.

 

Best

Tony

0 Likes
Message 68 of 82

pludikar
Collaborator
Collaborator

Hi @prainsberry,

Any chance you can provide some news on this?  

 

Has it died? Is anyone from AD actually working on this?  Do you have a timeline?  I’m not holding my breath, but breathing would be easier if you gave an update.

 

Regards

Peter

 

 

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
Message 69 of 82

it-ony
Participant
Participant

+1 for communicating a timeline and another +1

for moving sample projects and code discussions to github

0 Likes
Message 70 of 82

markSJVQS
Participant
Participant

What is the best way to construct more complex BrepBodies within a CustomFeature?

 

I see that the CustomPocket example uses the TemporaryBRepManager to create boxes and cylinders.

 

I want to extrude arbitrary faces at an angle. I could normally achieve this using a SweepFeature.

But, within a CustomFeature, I can't use the SweepFeature but instead must only use a BaseFeature and update a

BRepBody it holds.
 
I don't see how I could use the TemporaryBRepManager to achieve a sweep.
 
Building a BRepBody using BRep____Definition functions to create the resulting sweep as a hierarchy of body->lump->shells->faces->loops->edges seem very complicated.
 
Would it be possible to use forbidden features (like the SweepFeature) temporarily just to copy the resulting BRepBody into a BaseFeature, but then not include the forbidden feature in the design?
0 Likes
Message 71 of 82

markSJVQS
Participant
Participant

I have a planar BRepFace and I want to use as a base for a prism. How do I create a BRepBody with this face as the base, and a copy of this face translated to the form the other base, and then create faces for all the sides?

 

The TemporaryBRepManager does not seen to have any way to create a prism.

 

I don't see a way I could easily convert the existing BRepFace into a BRepFaceDefinition for the bases of my prism to then put within a BRepBodyDefinition.

 

The TemporaryBRepManager.createRuledSurface() function seems like it could creates the sides of my prism. But, how do I create the wires that are needed as the arguments from the face that I have, and then how do I close the surface into a solid by adding bases from the face I already have?

 

 

0 Likes
Message 72 of 82

markSJVQS
Participant
Participant

So, I managed to create a prism (without handling any holes in the base face) but it results in a surface that is not a solid body. How can make it a solid?

 

In the left-side Browser, it appears as an orange surface as opposed to a closed body.

 

Screen Shot 2022-11-17 at 6.31.01 PM.png

 

def createPrism(base: adsk.fusion.BRepFace, direction: adsk.core.Vector3D) -> adsk.fusion.BRepBody:
	tempBrepMgr = adsk.fusion.TemporaryBRepManager.get()

	translation = adsk.core.Matrix3D.create()
	translation.translation = direction

	# Create both bases.
	baseFaceA = tempBrepMgr.copy(base)
	baseFaceB = tempBrepMgr.copy(base)
	tempBrepMgr.transform(baseFaceB, translation)

	# Create the side walls.
	wireA, _ = tempBrepMgr.createWireFromCurves(
		[e.geometry for e in baseFaceA.faces[0].loops[0].edges], False)
	wireB, _ = tempBrepMgr.createWireFromCurves(
		[e.geometry for e in baseFaceB.faces[0].loops[0].edges], False)
	sides = tempBrepMgr.createRuledSurface(wireA.wires.item(0), wireB.wires.item(0))

	# Put all faces together.
	prism = sides
	tempBrepMgr.booleanOperation(prism, baseFaceA, adsk.fusion.BooleanTypes.UnionBooleanType)
	tempBrepMgr.booleanOperation(prism, baseFaceB, adsk.fusion.BooleanTypes.UnionBooleanType)

	return prism

 

Maybe one of the bases normal needs to change directions, but how do I do that?

0 Likes
Message 73 of 82

gregE2NKY
Observer
Observer

+1 for custom features having huge potential! I hit a case that doesn't seem to work though, can anyone tell me whether this is expected to work? Or even better, if there's a workaround to make it work?

 

I basically took CustomPocket and made it create a new body instead of cutting an existing body, and I also made it create a sketch to go with the new body. One instance of that works fine, including edit and compute (the update function changes the radius of a circle in the sketch). Creating a second instance works fine too. But if I then move the point (the selection input) of the second feature, the body of the first one disappears.

 

It seems to be related to editing the radius of a sketch circle. If I disable that one piece of code, then the bug doesn't manifest. Is a custom feature supposed to be able to create/edit a sketch?

0 Likes
Message 74 of 82

markSJVQS
Participant
Participant

Well, I've figured out how to create a prism.

I'm posting the solution here in case it benefits others.

 

I've included a definitionOfBody() function that converts a BRepBody into a BRepBodyDefinition, which may be useful for other use cases. You can copy any existing body and make modifications to it in BRep form.

 

def definitionOfBody(body: adsk.fusion.BRepBody) -> adsk.fusion.BRepBodyDefinition:
	"""
	Given a `body` create a `BRepBodyDefinition` for it.
	The body definition can be used to create a similar body with modifications.
	"""
	bodyDefinition = adsk.fusion.BRepBodyDefinition.create()
	bodyDefinition.doFullHealing = False
	for lump in body.lumps:
		lumpDefinition = bodyDefinition.lumpDefinitions.add()
		for shell in lump.shells:
			shellDefinition = lumpDefinition.shellDefinitions.add()
			for face in shell.faces:
				faceDefinition = shellDefinition.faceDefinitions.add(
					face.geometry, face.isParamReversed)
				for loop in face.loops:
					loopDefinition = faceDefinition.loopDefinitions.add()
					for coEdge in loop.coEdges:
						edge = coEdge.edge
						loopDefinition.bRepCoEdgeDefinitions.add(
							bodyDefinition.createEdgeDefinitionByCurve(
								bodyDefinition.createVertexDefinition(edge.startVertex.geometry),
								bodyDefinition.createVertexDefinition(edge.endVertex.geometry),
								edge.geometry),
							coEdge.isParamReversed)
			wire = shell.wire
			if wire:
				wireDefinition = shellDefinition.wireDefinition
				for coEdge in wire.coEdges:
					edge = coEdge.edge
					wireDefinition.wireEdgeDefinitions.add(
						bodyDefinition.createVertexDefinition(edge.startVertex.geometry),
						bodyDefinition.createVertexDefinition(edge.endVertex.geometry),
						edge.geometry)
	return bodyDefinition


def createPrism(base: adsk.fusion.BRepFace, height: float) -> adsk.fusion.BRepBody:
	"""
	Create a prism using the given `base` face and `height`.
	Use a negative `height` to reverse the direction of the prism.
	Any holes in the `base` face will be ignored and filled-in in the resulting solid prism.
	"""
	assert base.geometry.surfaceType == adsk.core.SurfaceTypes.PlaneSurfaceType
	direction = base.geometry.normal
	direction.scaleBy(height)
	return createObliquePrism(base, direction)


def createObliquePrism(base: adsk.fusion.BRepFace, direction: adsk.core.Vector3D) -> adsk.fusion.BRepBody:
	"""
	Create an oblique prism using the given `base` face and sweep `direction`.
	Any holes in the `base` face will be ignored and filled-in in the resulting solid prism.
	"""
	assert base.geometry.surfaceType == adsk.core.SurfaceTypes.PlaneSurfaceType

	tempBrepMgr = adsk.fusion.TemporaryBRepManager.get()

	translation = adsk.core.Matrix3D.create()
	translation.translation = direction

	# Create closed wires for both bases.
	baseWireA, _ = tempBrepMgr.createWireFromCurves(
		[e.geometry for e in base.loops[0].edges], False)
	baseWireB = tempBrepMgr.copy(baseWireA)
	tempBrepMgr.transform(baseWireB, translation)

	# Create both bases.
	baseFaceA = tempBrepMgr.createFaceFromPlanarWires([baseWireA])
	baseFaceB = tempBrepMgr.createFaceFromPlanarWires([baseWireB])

	# Create the side walls.
	sideFaces = tempBrepMgr.createRuledSurface(baseWireA.wires[0], baseWireB.wires[0])

	# Put all faces together.
	prism = sideFaces
	tempBrepMgr.booleanOperation(prism, baseFaceA, adsk.fusion.BooleanTypes.UnionBooleanType)
	tempBrepMgr.booleanOperation(prism, baseFaceB, adsk.fusion.BooleanTypes.UnionBooleanType)

	# Recreate the prism to make it a solid body.
	return definitionOfBody(prism).createBody()

 

0 Likes
Message 75 of 82

markSJVQS
Participant
Participant

I am having problems with CustomFeature dependencies.


In some cases I get an error when creating the feature: "RuntimeError: 2 : InternalValidationError : face".
In other cases I see artifacts of the custom feature when I undo or delete the custom feature.

This seems to depend on the order the sub-features and CustomFeature are created and when the dependencies are set.

 

How do I deal with dependencies that are modified (or even deleted) by the features within the custom feature?
I am using faces and bodies as dependencies.

 

When creating a CustomFeature, the dependencies are given in the CustomFeatureInput. I create the features that I want to be part of the custom feature first, then create the custom feature itself giving the start and end feature just created.

 

When editing a CustomFeature, I remove all sub-features from the custom feature, then modify/add/remove sub-features (while moving the timeline around), then add the sub-features back into the custom feature. I then set the new dependencies of the custom feature.

 

Can the CustomFeature be places first, followed by the child features?
This way the dependent features would not have yet been modified as seem by the CustomFeature.

 

Are there any examples illustrating the proper way to modify/add/remove sub-features of a CustomFeatures?

 

0 Likes
Message 76 of 82

markSJVQS
Participant
Participant

I solved the CustomFeature dependencies issue by creating an empty CustomFeature first.

I then add the child features following it in the timeline and finally call setStartAndEndFeatures.

 

Any possible modifications to the dependencies by the child features would happen after the CustomFeature.

 

0 Likes
Message 77 of 82

markSJVQS
Participant
Participant

How does Fusion keep track of dependencies on geometries within a BRepBody within a BaseFeature within a CustomFeature?

 

Consider this example:

The user creates my CustomFeature, then selects an edge from a BaseFeature within the CustomFeature and applies a FilletFeature to it. Later, when the CustomFeature re-computes and set a new body in the BaseFeature, how does the FilletFeature stay on the same edge?

 

What if the re-compute changes the edge in some way?

 

Is there a way that I can tag entities (like the edge) in my BRepBody so that even if it changes during a re-compute any features (like the FilletFeature) that are dependent on it will not loose the dependency?

0 Likes
Message 78 of 82

markSJVQS
Participant
Participant

The CustomFeatureParameters.itemById function should return None for a nonexistent ID as specified in the comment. Currently it signals an exception.

 

Could you fix this, please?

class CustomFeatureParameters(core.Base):

    def itemById(self, id: str) -> CustomFeatureParameter:
        """
        Function that returns the specified CustomParameter object given its ID.
        id : The ID of the custom parameter, which was assigned when the parameter was defined and the custom feature was created.
        Returns the specified item or null if the specified ID was not found.
        """
        return CustomFeatureParameter()

 

0 Likes
Message 79 of 82

nnikbin
Collaborator
Collaborator

Dear @prainsberry,

 

I believe that Custom Features can be a game-changer for both add-in developers and add-in users, and I guess many other add-in developers share this view. However, I am wondering why, even after approximately 2 years and 4 months since the introduction of such a useful feature, there is still no planned release date for it.

 

Although Fusion 360 help states that "Custom features will move out of preview when it's believed the functionality is stable and the functionality delivered provides enough capabilities to be useful," I believe that with more dedicated work, it could be production-ready sooner.

 

I would greatly appreciate it if the Fusion 360 API team could dedicate more time to the final development of Custom Features. Is there any news about its development state?

 

It is worth noting that Inventor introduced Client Features, which at least at the surface are very similar to Fusion 360 Custom Features, back in 2008 (15 years ago!), and they work flawlessly!

Message 80 of 82

asheepcalledgeorge
Enthusiast
Enthusiast

How about we a create wrapper? Then we can all use our own API, and just keep the underlying API up to date with an open source GitHub repo or something?

 

I've got so many things I'd like to release but I'm sat on because this is missing.