doc.Create.NewFamilyInstance() creates null

doc.Create.NewFamilyInstance() creates null

Anonymous
Not applicable
4,906 Views
7 Replies
Message 1 of 8

doc.Create.NewFamilyInstance() creates null

Anonymous
Not applicable

Hi Everyone,

 

I just want to thank everybody first off for all the content and the support. I've started working with the Revit API recently, and it's useful to have this backlog of information.

 

I'm having an issue with a plugin that's suppose to generate a bunch of face based families. As far as I can tell all the information I've gathered is solid. I'm using the doc.Create.NewFamilyInstance(Face Reference, Spawn Point, FamilySymbol) overload and I don't get any compile errors, and it doesn't seem to throw any exceptions when I'm debugging from VS. So, my question is, why the method doesn't seem to produce anything? I get no instantiation whatsoever.

 

Here's the code bits.

 

//Sprinkler Declarations
					FamilySymbol activeSprinkler = null;
					string desiredType = "15 mm Pendent";
					var sprinklerPoints = new List<XYZ>();
					XYZ referenceDirection = new XYZ(0, 0, 0);


					//Find the relevant sprinkler types
					FilteredElementCollector sprinklerTypes = new FilteredElementCollector(doc).OfClass(typeof(FamilySymbol)).OfCategory(BuiltInCategory.OST_Sprinklers);

					if (sprinklerTypes.Count() != 0)
					{
						foreach (Element e in sprinklerTypes)
						{
							if (e.Name.Contains(desiredType))
							{
								activeSprinkler = (FamilySymbol)e;
							}
						}
					}

					//Define a Reference object to accept the room and ceiling selection results
					Selection sel = uiApp.ActiveUIDocument.Selection;

					RoomPickFilter roomFilter = new RoomPickFilter();
					Reference roomRef = sel.PickObject(ObjectType.Element, roomFilter, "Please Select a Room");
					Room selectedRoom = doc.GetElement(roomRef) as Room;

					CeilingPickFilter ceilingFilter = new CeilingPickFilter();
					Reference ceilingRef = sel.PickObject(ObjectType.Element, ceilingFilter, "Please Select the Ceiling");
					Ceiling selectedCeiling = doc.GetElement(ceilingRef) as Ceiling;


					//Get Bottom face of ceiling to host our family
					IList<Reference> faces = HostObjectUtils.GetTopFaces(selectedCeiling);
					//Element myFace = doc.GetElement(faces[0]);
					Ceiling myFace = selectedCeiling;
					Face ceilingFace = (Face)myFace.GetGeometryObjectFromReference(faces[0]);

					sprinklerPoints = SetSprinklerPoints(selectedRoom, ceilingFace, 1);

					//SPAWN Sprinklers
					if (!activeSprinkler.IsActive)
					{
						activeSprinkler.Activate();
						doc.Regenerate();

					}
					//for (int i = 0; i < sprinklerPoints.Count(); i++)
					//{
					doc.Create.NewFamilyInstance(faces[0], sprinklerPoints[0], referenceDirection, activeSprinkler);

					//}
				}
				catch (Autodesk.Revit.Exceptions.OperationCanceledException)
				{
					string title = "Operation Cancelled";
					string body = "The operation was cancelled before it could be completed.";
					TaskDialog.Show(title, body);
					return Result.Cancelled;
				}
			}
			return Result.Succeeded;

Thanks,

0 Likes
Accepted solutions (1)
4,907 Views
7 Replies
Replies (7)
Message 2 of 8

Mustafa.Salaheldin
Collaborator
Collaborator

Please provide a sample Revit project with the used Family.


¯\_(ツ)_/¯
Let it work like a charm.

Mustafa Salaheldin


EESignature




Digital Integration Manager, DuPod

Facebook | Twitter | LinkedIn

0 Likes
Message 3 of 8

Anonymous
Not applicable

I can post a test file tonight, but any face based family should work. For the file itself, my test case is literally a box with a room and ceiling defined.

 

Thanks for the reply.

0 Likes
Message 4 of 8

jeremytammik
Autodesk
Autodesk
Accepted solution

You are using the wrong overload, meseems.

 

 

Anyway, I recommend that you check out The Building Coder discussion on this exact topic from 2010:

 

Insert Face-Hosted Sprinkler

 

http://thebuildingcoder.typepad.com/blog/2010/01/insert-facehosted-sprinkler.html

 

It may be somewhat out of date.

 

An up-to-date version of the CmdNewSprinkler command is available from The Building Coder samples GitHub repo:

 

https://github.com/jeremytammik/the_building_coder_samples

 

https://github.com/jeremytammik/the_building_coder_samples/blob/master/BuildingCoder/BuildingCoder/C...

 

It uses this overload:

 

  NewFamilyInstance( 
    Face face, 
    XYZ location, 
    XYZ referenceDirection, 
    FamilySymbol symbol )

I seem to remember other later discussions on inserting sprinklers that might also be worth checking out.

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 5 of 8

Anonymous
Not applicable

Thanks Jeremy, I will check out those links.

 

I made a simplified version that lets you grab a family from a placed family instance and then place it. The script uses the face based overload, and it gives me a null reference for the ceiling face.

 

The Reference of the input face is null. If the face was obtained from Element.Geometry, make sure to turn on the option 'ComputeReferences'.

 

Debugging, I can see that the face is not null, but it's Reference field is. Is this something that needs to be set? If any/all of this is answered in the article, feel free to let the link speak for itself.

 

Thanks,

public class SimplePlace : IExternalCommand
{

	public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
	{
		//Get application and document Objects
		UIApplication uiApp = commandData.Application;
		Document doc = uiApp.ActiveUIDocument.Document;

		using (Transaction transaction = new Transaction(doc))
		{
			if (transaction.Start("Place Sprinklers") == TransactionStatus.Started)
			{

				//Sprinkler Declarations
				XYZ referenceDirection = new XYZ(0, 0, 0);
				XYZ placePoint = null;
				Instance instance = null;

				//Define a Reference object to accept the room and ceiling selection results
				Selection sel = uiApp.ActiveUIDocument.Selection;

				CeilingPickFilter ceilingFilter = new CeilingPickFilter();
				Reference ceilingRef = sel.PickObject(ObjectType.Element, ceilingFilter, "Please Select the Ceiling");
				Ceiling selectedCeiling = doc.GetElement(ceilingRef) as Ceiling;


				//Get Bottom face of ceiling to host our family
				IList<Reference> faces = HostObjectUtils.GetBottomFaces(selectedCeiling);
				Element myFace = doc.GetElement(faces[0]);
				Face ceilingFace = (Face)myFace.GetGeometryObjectFromReference(faces[0]);

				Reference sprinklerRef = sel.PickObject(ObjectType.Element, "Please Select a family");
				FamilyInstance sprinklerInstance = doc.GetElement(sprinklerRef) as FamilyInstance;
				FamilySymbol activeSprinkler = sprinklerInstance.Symbol; 

				placePoint = sel.PickPoint("Please pick a point to place your family");

				//SPAWN Sprinklers
				if (!activeSprinkler.IsActive)
				{
					activeSprinkler.Activate();
					doc.Regenerate();

				}

				instance = doc.Create.NewFamilyInstance(ceilingFace, placePoint, referenceDirection, activeSprinkler);
				if (instance != null)
					return Result.Succeeded;
			}
			return Result.Failed;
		}
	}
}

 

 

0 Likes
Message 6 of 8

Anonymous
Not applicable

So I've read through the post, and I downloaded the building coder samples. I got the place new sprinkler command working, but I'm still having nulls appear when I run my own command. Some notable changes:

 

  • I changed the way I'm getting the ceiling face. I was using HostObjectUtils.GetTopFaces() and then iterating through the results. This doesn't work because we can't get a valid host reference using this method. I'm now grabbing the object geometry with compute references on.
  • The ceiling only seems to have one face, and it points up. I'm not sure if that's the issue or not, can you host a sprinkler family on an upwards facing  ceiling?
  • The point is calculated using pickpoint and then projecting that point onto a face. It seems valid.
  • The family seems legitamate
  • My orientation is (0,0,0)
  • I changed the overload used so I'm referencing the face itself, not the face reference.

After that I'm still getting nothing spawning. If it would give an error in the instance creation I could track it down, but with little feedback it's very frustrating.

 

I'm thinking about going through Jeremy's script, which works, and substituting parts of my implementation until something breaks. Other than that I'm not sure how to know what I'm doing wrong at this point.

0 Likes
Message 7 of 8

Anonymous
Not applicable

Just debugging again and I'm noticing that on the NewFamilyInstance call on the new instance/HostParameter I'm getting an exception that says the following "Only hosted instances whose family is not work plane based can support this functionality."

 

Any insight would be appreciated. My family is work plane based family, as I thought all sprinklers were. Anyone have any experience with this issue?

 

Thanks.

0 Likes
Message 8 of 8

Anonymous
Not applicable

I was able to solve the problem, but have a couple of follow up questions.

 

Firstly, one of my issues was event handling. I had a try/catch situation which would return result succeeded in both branches, which I think hid the issue. Once I got rid of it I started getting a null reference on the face of my create new family instance call. On debugging the command again, I noticed that none of the faces in the ceiling were passing the normal test which checks to see if Normal.Z is < 0. Looking at the results of the get geometry, it only returned one face with a normal.Z of +1.

 

I'm not sure why a ceiling would be facing upwards (maybe I created it incorrectly?) but when I changed that comparison I was finally able to spawn the family on the host face. Feels good! The sprinklers look like they're facing the correct direction, despite the face being the wrong way around. So for now, I'm happy.

0 Likes