How to get swept or extruded profile from an analytical member?

How to get swept or extruded profile from an analytical member?

christostsar
Contributor Contributor
914 Views
4 Replies
Message 1 of 5

How to get swept or extruded profile from an analytical member?

christostsar
Contributor
Contributor

Analytical members have a section type which points to a family symbol. My interest is to get the curves defining the profile for this section. I have found two different ways Revit section families are created (maybe there are more?):

 1) by extrusion of a curve loop of lines, arcs etc

 2) by sweeping a profile

 

For 1) my go-to approach would be to edit the family symbol and get the curves that were extruded. Since I am editing the family and not a specific symbol or instance, will I get the correct curves? Is there a better way of doing that?

 

//sectionFamilySymbol is the family symbol for the member's section
Document editSymbolDoc = doc.EditFamily(sectionFamilySymbol .Family);
FilteredElementCollector extrusionCollector = new FilteredElementCollector(editSymbolDoc);
extrusionCollector.OfClass(typeof(Extrusion));
foreach (Extrusion extrusion in extrusionCollector)
{
	CurveArrArray curves = extrusion.Sketch.Profile;
	//do something with the curves
}

 

 

For 2) I have found the GetSweptProfile() function here: Revit API docs - Profile class. The example shows the following code. My question is, since this function exists for FamilyInstance only, how can I use it when I have an analytical member that is not actually tied to any structural member i.e., an instance of the family does not exist? Is there a better way of accessing the swept profile?:

 

FamilyInstance beam = element as FamilyInstance;
if (beam.StructuralType == StructuralType.Beam)
{
	Autodesk.Revit.DB.SweptProfile sweptProfile = beam.GetSweptProfile();
	Autodesk.Revit.DB.Profile profile = sweptProfile.GetSweptProfile();
}

 

 

915 Views
4 Replies
Replies (4)
Message 2 of 5

jeremy_tammik
Alumni
Alumni

I am not a structural expert, so I cannot answer your real questions. However, the Revit API does indeed include several bits of functionality that require an instance to exist in order to query it, so one part of the answer to (2) may very well be yes; an instance must exist. If you don't have one at hand, you can create it in a temporary transaction, regenerate the model, query it for its properties, and roll back the transaction again with no harm done, aka TTT, the temporary transaction trick:

  

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 3 of 5

christostsar
Contributor
Contributor

Thanks for the quick reply. I had tried initiating a temporary transaction already and I was stumbling upon an issue that I still can't get around of. I am using the following procedure to get the profile through a temporary instance of the family. The problem is I am getting an error in the collector iteration that seems to think the model is changed even though the transaction was rolled back. What am I missing?

 

FilteredElementCollector collector = new FilteredElementCollector(doc);
collector.OfCategory(BuiltInCategory.OST_AnalyticalMember);

foreach (AnalyticalMember am in collector)
{
	if (am != null)
	{
		var sectionTypeId = am.SectionTypeId;

		Element element = doc.GetElement(sectionTypeId);
		FamilySymbol sectionFamily = element as FamilySymbol;
		if (sectionFamily != null)
		{
			using (Transaction transaction = new Transaction(doc))
			{
				if (transaction.Start() == TransactionStatus.Started)
				{
					FamilyInstance tempInstance = doc.Create.NewFamilyInstance(new XYZ(0, 0, 0), sectionFamily, StructuralType.Beam);
					doc.Regenerate();

					var profile = GetProfile(tempInstance);
				}

				transaction.RollBack();
			}
		}
	}
}

 

Autodesk.Revit.Exceptions.InvalidOperationException: 'The iterator cannot proceed due to changes made to the Element table in Revit's database (typically, This can be the result of an Element deletion).'

Message 4 of 5

mhannonQ65N2
Collaborator
Collaborator

You're right that probably shouldn't change the database, but you can just replace the line:

foreach (AnalyticalMember am in collector)

with:

foreach (AnalyticalMember am in collector.ToElements())

 

0 Likes
Message 5 of 5

christostsar
Contributor
Contributor

I have managed to get the procedure to work without complaining that the database has changed. I added ToElements() as you proposed and used the following to set an actual length to the dummy family instances as they were instantiating with 0 length and therefore subsequent operations failed:

 

Level level = GetDummyLevel();
FamilyInstance dummyInstance = doc.Create.NewFamilyInstance(new XYZ(0, 0, 0), sectionFamily, level, StructuralType.Beam);
LocationCurve locCurve = dummyInstance.Location as LocationCurve;
if (locCurve != null)
{
    Curve newCurve = Line.CreateBound(new XYZ(0, 0, 0), new XYZ(10, 0, 0));
    locCurve.Curve = newCurve;
}
doc.Regenerate();