04/29/2015

Automating placement of lights families

We’re always trying to automate tasks, it’s actually a common request when the adoption of tools increase and the amount of work follow it. As we know, this is a great area for API: the machine is amazing doing simple math and repetitive tasks.

This time the discussion was based on daily challenges at MHA, a Brazilian engineering firm localized in São Paulo. They are/were involved in several important projects, especially in MEP discipline, including the business center where Autodesk is located here in São Paulo.

One task currently consuming a long time is around placing light families on a Revit project. Of course the whole process cannot be automated as is based on the engineer’s analysis and experience, but the initial step of loading and placing the required number can be speed up.

Here are the steps we identifies:

Select a family (.rfa) file that has a Light fixture. (in this code, the category of the family is not checked)

Choose one symbol on the family just loaded

Ask user to select reference plane, space and a pick a box on the project. These are used to calculate the number and location of the families.

Do some basic math (but yet not so simple logic) to find where to place the instances

Finally, in a loop, place all family instances.

This is not intended to replace the engineer, of course not. But by placing all the instance needed, the engineer can now move and adjust it, knowing the lumens requirement is meet (number of lights/lumens per room/space).

// select the symbol on the loaded family// this is a simple WindowsForm with a // ComboBox and a Button (action OK)FormSelSymbol frm = newFormSelSymbol();foreach (ElementId symbolId in fam.GetFamilySymbolIds()){FamilySymbol s = doc.GetElement(symbolId) asFamilySymbol; frm.cboSymbols.Items.Add(s);}// as the FamilySymbol is stored on the combo box// let's make it show the Name propertyfrm.cboSymbols.DisplayMember = "Name";if (frm.ShowDialog() != System.Windows.Forms.DialogResult.OK)returnResult.Cancelled;// and get the selected itemFamilySymbol symbol = frm.cboSymbols.SelectedItem asFamilySymbol;

// now calculate the number of required lights// first the Luminous of each light (from the family symbol)double lightLuminous = symbol.get_Parameter(BuiltInParameter.FBX_LIGHT_LIMUNOUS_FLUX).AsDouble();// and get the information from the Space// assuming it was assigned as a Space Style paramdouble requiredLuminous = doc.GetElement( space.get_Parameter("Space Style").AsElementId()) .get_Parameter("Luminous").AsDouble();

// now the number of lightsint numerOfLights = (int)Math.Round((requiredLimunous / lightLimunous));// and the distance between them double distanceBetweenLights = axis.ApproximateLength / (numerOfLights + 2);

// all set, time to add the lights!// place family instances at the locationsfor (int p = 1; p <= numerOfLights; p++){// evaluate a point along the axis// remember the Evaluate can be parametric, therefore// normalized between 0 and 1XYZ pointOnAxis = axis.Evaluate( p * distanceBetweenLights / axis.ApproximateLength,true); doc.Create.NewFamilyInstance( refPlane.Reference, pointOnAxis, newXYZ(0, 0, 0), symbol);}

returnResult.Succeeded;

And here is the GenericFilter class used on this code, a simple class that implements the filter interface

Comments

We’re always trying to automate tasks, it’s actually a common request when the adoption of tools increase and the amount of work follow it. As we know, this is a great area for API: the machine is amazing doing simple math and repetitive tasks.

This time the discussion was based on daily challenges at MHA, a Brazilian engineering firm localized in São Paulo. They are/were involved in several important projects, especially in MEP discipline, including the business center where Autodesk is located here in São Paulo.

One task currently consuming a long time is around placing light families on a Revit project. Of course the whole process cannot be automated as is based on the engineer’s analysis and experience, but the initial step of loading and placing the required number can be speed up.

Here are the steps we identifies:

Select a family (.rfa) file that has a Light fixture. (in this code, the category of the family is not checked)

Choose one symbol on the family just loaded

Ask user to select reference plane, space and a pick a box on the project. These are used to calculate the number and location of the families.

Do some basic math (but yet not so simple logic) to find where to place the instances

Finally, in a loop, place all family instances.

This is not intended to replace the engineer, of course not. But by placing all the instance needed, the engineer can now move and adjust it, knowing the lumens requirement is meet (number of lights/lumens per room/space).

// select the symbol on the loaded family// this is a simple WindowsForm with a // ComboBox and a Button (action OK)FormSelSymbol frm = newFormSelSymbol();foreach (ElementId symbolId in fam.GetFamilySymbolIds()){FamilySymbol s = doc.GetElement(symbolId) asFamilySymbol; frm.cboSymbols.Items.Add(s);}// as the FamilySymbol is stored on the combo box// let's make it show the Name propertyfrm.cboSymbols.DisplayMember = "Name";if (frm.ShowDialog() != System.Windows.Forms.DialogResult.OK)returnResult.Cancelled;// and get the selected itemFamilySymbol symbol = frm.cboSymbols.SelectedItem asFamilySymbol;

// now calculate the number of required lights// first the Luminous of each light (from the family symbol)double lightLuminous = symbol.get_Parameter(BuiltInParameter.FBX_LIGHT_LIMUNOUS_FLUX).AsDouble();// and get the information from the Space// assuming it was assigned as a Space Style paramdouble requiredLuminous = doc.GetElement( space.get_Parameter("Space Style").AsElementId()) .get_Parameter("Luminous").AsDouble();

// now the number of lightsint numerOfLights = (int)Math.Round((requiredLimunous / lightLimunous));// and the distance between them double distanceBetweenLights = axis.ApproximateLength / (numerOfLights + 2);

// all set, time to add the lights!// place family instances at the locationsfor (int p = 1; p <= numerOfLights; p++){// evaluate a point along the axis// remember the Evaluate can be parametric, therefore// normalized between 0 and 1XYZ pointOnAxis = axis.Evaluate( p * distanceBetweenLights / axis.ApproximateLength,true); doc.Create.NewFamilyInstance( refPlane.Reference, pointOnAxis, newXYZ(0, 0, 0), symbol);}

returnResult.Succeeded;

And here is the GenericFilter class used on this code, a simple class that implements the filter interface