29 Mar 2021

Share add-in code with app bundle

I already blogged about how to Migrate Inventor add-in to Design Automation, but it's a bit too high level.

An Inventor app bundle is just like an add-in with an Automation interface but without all the images, resources, user interaction handling, user interface setup, etc
You could just take your existing add-in, implement the Automation interface with a Run / RunWithArguments function, and you're done.

Add-In vs App Bundle

But the solution would end up a bit bloated.
And you would have to implement yourself all the cool features that are provided by the Visual Studio solution template.

I think it's easier to just create a new solution next to your existing add-in project via our Visual Studio solution template and share the relevant code.

The two main steps are:
1) Reorganize the add-in's code so that everything that might be useful for the app bundle resides in a separate file 

2) Use that file from the app bundle project

Let's follow the above steps in the case of the SimpleAddIn sample that is part of the Inventor SDK

1) Reorganize add-in code

In the case of this specific add-in, there is only a single button ("Draw Slot") that actually does something that could be also useful in the app bundle

Draw Slot command

So let's create a new class called Functions in the add-in project and move the useful code into that - even the Transaction related parts (outlined in red) are not needed, because it's mainly just to provide undo/redo functionality for the user

Functions

We place all that code inside a new function ending up with this content:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Inventor;

namespace SimpleAddIn
{
    class Functions
    {
        static public void DrawSlot(InventorServer InventorApplication, PlanarSketch planarSketch, double slotWidth, double slotHeight)
        {
            SketchLine[] lines = new SketchLine[2];
            SketchArc[] arcs = new SketchArc[2];

            TransientGeometry transientGeometry;
            transientGeometry = InventorApplication.TransientGeometry;

            //draw the lines and arcs that make up the shape of the slot
            lines[0] = planarSketch.SketchLines.AddByTwoPoints(transientGeometry.CreatePoint2d(0, 0), transientGeometry.CreatePoint2d(slotWidth, 0));
            arcs[0] = planarSketch.SketchArcs.AddByCenterStartEndPoint(transientGeometry.CreatePoint2d(slotWidth, slotHeight / 2.0), lines[0].EndSketchPoint, transientGeometry.CreatePoint2d(slotWidth, slotHeight), true);

            lines[1] = planarSketch.SketchLines.AddByTwoPoints(arcs[0].EndSketchPoint, transientGeometry.CreatePoint2d(0, slotHeight));
            arcs[1] = planarSketch.SketchArcs.AddByCenterStartEndPoint(transientGeometry.CreatePoint2d(0, slotHeight / 2.0), lines[1].EndSketchPoint, lines[0].StartSketchPoint, true);

            //create the tangent constraints between the lines and arcs
            planarSketch.GeometricConstraints.AddTangent((SketchEntity)lines[0], (SketchEntity)arcs[0], null);
            planarSketch.GeometricConstraints.AddTangent((SketchEntity)lines[1], (SketchEntity)arcs[0], null);
            planarSketch.GeometricConstraints.AddTangent((SketchEntity)lines[1], (SketchEntity)arcs[1], null);
            planarSketch.GeometricConstraints.AddTangent((SketchEntity)lines[0], (SketchEntity)arcs[1], null);

            //create a parallel constraint between the two lines
            planarSketch.GeometricConstraints.AddParallel((SketchEntity)lines[0], (SketchEntity)lines[1], true, true);
        }
    }
}

Now we can call this instead from the ButtonDefinition_OnExecute() method

//start a transaction so the slot will be within a single undo step
Transaction createSlotTransaction;
createSlotTransaction = InventorApplication.TransactionManager.StartTransaction(InventorApplication.ActiveDocument, "Create Slot");

Functions.DrawSlot(InventorApplication as InventorServer, planarSketch, slotWidth, slotHeight);

//end the transaction
createSlotTransaction.End();

Note that we need to use InventorServer object instead of the Application object because only that is available inside Inventor Server, which is also used on the Design Automation servers.

2) Use Functions.cs from the app bundle project

First of all, we need to create a new solution using the Visual Studio solution template. Then we can simply reference Functions.cs from it

Reference Functions.cs from app bundle

Now we can use it from the app bundle's code, e.g. from RunWithArguments()

public void RunWithArguments(Document doc, NameValueMap map)
{
    PartDocument part = doc as PartDocument;

    WorkPlane xy = part.ComponentDefinition.WorkPlanes["XY Plane"];
    PlanarSketch sketch = part.ComponentDefinition.Sketches.Add(xy);

    SimpleAddIn.Functions.DrawSlot(inventorApplication, sketch, 20, 10);

    // etc ...

We could keep exposing new functionality added to our add-in to be also available from our app bundle as well, and keep sharing code between the two.

Related Article