Autodesk Inventor API Adventures – Tuesday

(Sometimes as a developer you get to be a super hero and overcome incredible odds. Of course, it helps if you have the skills to pull off magic – in this week-long story we paint a tongue-in-cheek picture of one of those situations. Doug’s story starts on Monday and continues below)

As the time clock approaches the start of a new day, you walk past the pastry table, grab a sprinkle doughnut, and excitedly turn into your new cubicle and notice a nice new, full blown, office chair beckoning you to relax. You stop chewing that huge bite you took and look around, as if it was a joke. But instead, you wipe the fallen sprinkle off your cheek and gracefully ease into the luxury only known by upper management.

You lean over, below your folding table/desk and turn on the monotonous hum of your 512meg Ram, Pentium III Celeron. After it spins up and you log in, you give the tower a few light taps with your shoe to quiet the fan.

The first thing on today’s agenda is to get a few more buttons to use for the different loading events. Here is what the form looks like after adding [Load Project File], [Load Assembly File], and [Load Part X] buttons.

app2

Next is to start by loading the appropriate project file for the assembly. There are some weird peculiarities that happen here. First, let’s just make sure you currently have it activated. If you do, there is no need to do anything. Second, let’s see if you have it in the current list (it’s actually a list of shortcuts in your “My Documents” folder under Inventor). And lastly, let’s set it as the active project file. To make this code more readable, I created a static Utility class that I will use for generic methods that can be used in other situations. Another example af a generic method is the ConvertToRadians function that everybody needs. I’ll put it in now, knowing it’s usage will be centralized.

public static void CreateShortcut(string fullSourceFile, string fullDestFile, string applicationFullNameWithExtension)
{
	//
	// must add a reference to IWshRuntimeLibrary
	//(aka.  Windows Script Host Object Model)
	//
	string destDir = System.IO.Path.GetDirectoryName(fullDestFile);

	IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell();
	IWshRuntimeLibrary.IWshShortcut sc = shell.CreateShortcut(fullDestFile + ".lnk") as IWshRuntimeLibrary.IWshShortcut;
	sc.WindowStyle = 1;
	sc.TargetPath = fullSourceFile;
	sc.WorkingDirectory = destDir;
	sc.Description = string.Empty;
	sc.IconLocation = string.Format("{0},0", applicationFullNameWithExtension);
	sc.Save();
}

public static decimal ConvertToRadians(decimal angle)
{
	return (decimal)(Math.PI / 180) * (decimal)angle;
}

After that inspired block of code, you head to the break room to refill your empty cup of coffee. You overhear your cube-mates talking about your new chair and possible reasons for its sudden appearance, you consider telling them, but decide against it as it would bring you out of your zone. On your way back, you grab another well-deserved doughnut, devour it in 3 bites, just to insure that no crumbs got lost in your new chair. You don’t know what it is, but some force is drawing you back to your computer. You think that management has put something on your chair in order to create the alluring sensation you are experiencing. But then you realize that they are not that clever and chuckle at the thought of it. Your mind quickly turns back to the task at hand and code drains from your fingertips like the water from Niagara Falls. (oh, that’s a good one, if I say so myself!)

Everybody knows you have to have the proper project file loaded for each assembly in Inventor. So, let’s quit talking about it and do it.

private readonly string WORKING_DIRECTORY = @"C:\Program Files\Autodesk\Inventor 2013\Design Accelerator\Models\";
private readonly string PROJECT_FULLPATH_FILENAME = @"C:\AutomationProject\Preliminary.ipj";

private string GetFullFileName(string fileName)
{
	return System.IO.Path.Combine(WORKING_DIRECTORY, fileName);
}

private void btnLoadProjectFile_Click(object sender, EventArgs e)
{
	DesignProjectManager dpm = m_application.DesignProjectManager;

	if (System.IO.Path.GetFullPath(dpm.ActiveDesignProject.FullFileName).ToLower() == System.IO.Path.GetFullPath(PROJECT_FULLPATH_FILENAME).ToLower())
	{
		// no need to do anything
		return;
	}

	// is it in the list already?
	// if not, create a shortcut to it
	IEnumerable<DesignProject> designProjects = dpm.DesignProjects.Cast<DesignProject>();
	DesignProject dp = designProjects.FirstOrDefault(proj => !string.IsNullOrEmpty(PROJECT_FULLPATH_FILENAME) &&
		proj.FullFileName.ToLower().Equals(PROJECT_FULLPATH_FILENAME.ToLower()));

	if (null == dp)
	{
		// must create a shortcut to it
		FileOptions fo = m_application.FileOptions;

		string fileName = System.IO.Path.GetFileName(PROJECT_FULLPATH_FILENAME);
		string destPath = System.IO.Path.Combine(fo.ProjectsPath, fileName);
		Utilities.CreateShortcut(PROJECT_FULLPATH_FILENAME, destPath, "exe");

		dp = dpm.DesignProjects.ItemByName[PROJECT_FULLPATH_FILENAME];
	}

	dp.Activate();
}

Next, you need to get that main assembly template loaded so that you can add parts to it. The only thing that will make this happen is… yup, you got it… tunes! You grab your headphones and as you slide them on, you drift into the programming matrix you know all so well. You start typing to the beat of Bohemian Rhapsody and start humming just loud enough to make the cube farm turn and look for the source that has drowned out the repetitious page dispensing of the busy copier.

The load of the document is very easy. In fact, a couple lines of Inventor API code is all that is needed.

private readonly string ASSEMBLY_FILENAME = "FDCalcTemplIN.iam";

private void btnLoadMainAssembly_Click(object sender, EventArgs e)
{
	Inventor.Document mainAssembly = m_application.Documents.Open(GetFullFileName(ASSEMBLY_FILENAME), true);
	m_mainAssembly = mainAssembly as Inventor.AssemblyDocument;
}

BAM! It’s done.

Sip of coffee, and back at it! No stopping you now.

Now that we have the assembly loaded, let’s get our four parts in there and positioned and rotated in the x, y, and z coordinate system.
I’ve created a Matrix… (your thoughts wander and you debate whether you should require upper management to start calling you NEO)… creation method that I can reference and create a 3D point in space that we can use to place the parts in their proper location.

private Matrix GenererateMatrixWithOffset(decimal xOffset, decimal yOffset, decimal zOffset, decimal xDegrees = 0, decimal yDegrees = 0, decimal zDegrees = 0)
{
	UnitsOfMeasure um = m_application.ActiveDocument.UnitsOfMeasure;
	decimal xDist = (decimal)um.ConvertUnits((double)xOffset, UnitsTypeEnum.kInchLengthUnits, UnitsTypeEnum.kDatabaseLengthUnits);
	decimal yDist = (decimal)um.ConvertUnits((double)yOffset, UnitsTypeEnum.kInchLengthUnits, UnitsTypeEnum.kDatabaseLengthUnits);
	decimal zDist = (decimal)um.ConvertUnits((double)zOffset, UnitsTypeEnum.kInchLengthUnits, UnitsTypeEnum.kDatabaseLengthUnits);
	Vector v = m_application.TransientGeometry.CreateVector((double)xDist, (double)yDist, (double)zDist);
	Matrix m = m_application.TransientGeometry.CreateMatrix();

	if (xDegrees != 0M)
	{
		Vector axis = m_application.TransientGeometry.CreateVector(1, 0, 0);
		Point center = m_application.TransientGeometry.CreatePoint(0, 0, 0);
		m.SetToRotation((double)Utilities.ConvertToRadians(xDegrees), axis, center);
	}

	if (yDegrees != 0M)
	{
		Vector axis = m_application.TransientGeometry.CreateVector(0, 1, 0);
		Point center = m_application.TransientGeometry.CreatePoint(0, 0, 0);
		m.SetToRotation((double)Utilities.ConvertToRadians(yDegrees), axis, center);
	}

	if (zDegrees != 0M)
	{
		Vector axis = m_application.TransientGeometry.CreateVector(0, 0, 1);
		Point center = m_application.TransientGeometry.CreatePoint(0, 0, 0);
		m.SetToRotation((double)Utilities.ConvertToRadians(zDegrees), axis, center);
	}
	m.SetTranslation(v, false);

	return m;
}

Let’s get those parts loaded so we can take off before lunch and see if we can catch the new release of “Pi… to the 3.1415 millionth place” that you’ve been anticipating for over 6 months!

private readonly string PART_FILENAME = "FD-BellSpring-in.ipt";
private readonly string PART_FILENAME2 = "FD-CompressSpring-in.ipt";
private readonly string PART_FILENAME3 = "FD-SpurGearIn.ipt";
private readonly string PART_FILENAME4 = "FD-WormGear2IN.ipt";

private void btnLoadPart_Click1(object sender, EventArgs e)
{
	ComponentDefinition assemblyCompDef = m_mainAssembly.ComponentDefinition as ComponentDefinition;

	string partName = GetFullFileName(PART_FILENAME);
	decimal x = 5;
	decimal y = 10;
	decimal z = 15;
	decimal rotation = 0;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, 0, 0, rotation));
	rotation = 45;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, 0, 0, rotation));
	rotation = 90;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, 0, 0, rotation));
	rotation = 135;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, 0, 0, rotation));
	UpdateScreen();
}

private void btnLoadPart2_Click(object sender, EventArgs e)
{
	ComponentDefinition assemblyCompDef = m_mainAssembly.ComponentDefinition as ComponentDefinition;

	string partName = GetFullFileName(PART_FILENAME2);
	decimal x = 0;
	decimal y = 0;
	decimal z = 0;
	decimal rotation = 45;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, rotation));
	z -= 2;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, 0, rotation));
	z -= 2;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, 0, 0, rotation));
	z -= 2;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, rotation));
	UpdateScreen();
}

private void btnLoadPart3_Click(object sender, EventArgs e)
{
	ComponentDefinition assemblyCompDef = m_mainAssembly.ComponentDefinition as ComponentDefinition;

	string partName = GetFullFileName(PART_FILENAME3);
	decimal x = -5;
	decimal y = -5;
	decimal z = -5;
	decimal rotation = 90;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, 0, 0, rotation));
	x -= 4;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, 0, 0, rotation));
	x -= 4;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, 0, rotation));
	x -= 4;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, rotation));
	UpdateScreen();
}

private void btnLoadPart4_Click(object sender, EventArgs e)
{
	ComponentDefinition assemblyCompDef = m_mainAssembly.ComponentDefinition as ComponentDefinition;

	string partName = GetFullFileName(PART_FILENAME4);
	decimal x = 0;
	decimal y = 0;
	decimal z = 10;
	decimal rotation = 45;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, 0, rotation));
	y -= 4;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, 0, 0, rotation));
	y -= 4;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, 0, 0, rotation));
	y -= 4;
	assemblyCompDef.Occurrences.Add(partName, GenererateMatrixWithOffset(x, y, z, rotation));
	UpdateScreen();
}

You hear a voice in your head… I have to keep resizing my screen, how can I stop doing that manually?. I’ve got an answer for you…

private void UpdateScreen()
{
	// adjust screen (zoom) to whatever size is needed
	m_application.ActiveView.Fit();
}

As you press the buttons, in sequence, you see your screen come alive with parts. You sense a glowing start to take over your body and a warmth that you have not felt in a long time… oh wait… its Nate from a few cubes down, he is opening the window.

Part 1 loaded:
part1

Part 2 loaded:
part2

Part 3 loaded:
part3

Part 4 loaded:
part4

You lean back in complete satisfaction and knowing your progress, you tidy up your cube, push in your chair and head to the elevator. With your head held high you march past your boss. Out of the corner of your eye, you see his jaw drop and a small amount of smoke puff out his nostrils. You turn, give him the walking salute and wouldn’t you know it, the elevator is wide open, waiting for your grand exit!

Start typing and press Enter to search