Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Geometry returns no reference for familyinstance

21 REPLIES 21
SOLVED
Reply
Message 1 of 22
rayray4105
7442 Views, 21 Replies

Geometry returns no reference for familyinstance

Hi,

Using 'thebuildingcoder' blog I am trying to create some dimensions between familyinstances (Generic Model face based) but I am having no luck. For the selected familyinstances (generic model face based) no references are returned. But when I select a structural column (familyinstance) the code will return a reference.

I have converted the sample from C# to VB.NET.
Code in C#

 

_opt = new Options();

_opt.ComputeReferences = true;

_opt.IncludeNonVisibleObjects = true;

 


static Reference GetFamilyInstancePointReference(
FamilyInstance fi )
{
return fi.get_Geometry( _opt )
.OfType<Point>()
.Select<Point, Reference>( x => x.Reference )
.FirstOrDefault();
}

Code in VB.NET

 

Dim _opt As Options = Nothing

_opt = New Options()

_opt.ComputeReferences = True

_opt.IncludeNonVisibleObjects = True


Shared Function GetFamilyInstancePointReference(ByVal fi As FamilyInstance) As Reference
Return fi.Geometry(_opt).OfType(Of Point)() _
.Select(Function(x) x.Reference) _
.FirstOrDefault()
End Function

Using RevitLookup (Snoop) I can not seem to find 'point' in the geometry element collection (only GeometryInstance is show). However when I snoop a familyinstance of a structural column 'point' will show up and the code is able to return references. Am I doing something wrong of is this not possible for Generic model facebased instances? I am using Revit 2015.

regards,
Raymond

21 REPLIES 21
Message 2 of 22
Aaron.Lu
in reply to: rayray4105

Dear Raymond,

this might depends on the family instance you are using, possible to attach the rfa file here? so that I can have a try.


Aaron Lu
Developer Technical Services
Autodesk Developer Network
Message 3 of 22
rayray4105
in reply to: Aaron.Lu

Hi Aaron,

 

Please find a family as an attachment. I picked a random family from our library. Last week I created a new family from scratch (Generic Model face based) which also does not return any references.

 

Regards,

Raymond

Message 4 of 22
Aaron.Lu
in reply to: rayray4105

Sometimes we can't rely on RevitLookup 😞

 

Try this:

 

doc = commandData.Application.ActiveUIDocument.Document;
var uiSel = commandData.Application.ActiveUIDocument.Selection;

foreach (var elementId in uiSel.GetElementIds())
{
    Element element = doc.GetElement(elementId);
    if (element != null)
    {
        Options options = new Options();
        options.ComputeReferences = true;
        options.IncludeNonVisibleObjects = true;
        if (element.Document.ActiveView != null)
            options.View = element.Document.ActiveView;
        else
            options.DetailLevel = ViewDetailLevel.Fine;
        var geoElem = element.get_Geometry(options);
        foreach (var item in geoElem)
        {
            Solid solidObj = item as Solid;
            if (solidObj != null && solidObj.Faces.Size > 0)
            {

            }
            else
            {
                GeometryInstance geoInst = item as GeometryInstance;
                if (geoInst != null)
                {
                    GeometryElement geoElemTmp = geoInst.GetInstanceGeometry();
                    foreach (GeometryObject geomObjTmp in geoElemTmp)
                    {
                        Solid solidObj2 = geomObjTmp as Solid;
                        if (solidObj2 != null && solidObj2.Faces.Size > 0)
                        {
// you will see geometry object here !!!
                        }
                    }
                }
            }
        }
    }
    else
    {
        TaskDialog.Show("ERROR", "Element " + elementId + " is not found");
    }
}


Aaron Lu
Developer Technical Services
Autodesk Developer Network
Message 5 of 22
rayray4105
in reply to: Aaron.Lu

Thank you for your response and the code. I am not so good with C# so I have converted it to VB.NET. The code loops through solids and it's faces but I am trying to select the non-visible 'defines origin' reference planes. Can I also do that with the provided code?

Message 6 of 22
Aaron.Lu
in reply to: rayray4105

Looks like geoInst.GetInstanceGeometry() returns 5 objects, 4 are solids, and 1 is line. not sure if the line is what you want.


Aaron Lu
Developer Technical Services
Autodesk Developer Network
Message 7 of 22
rayray4105
in reply to: Aaron.Lu

The family consists of 4 solid objects and a centerline (modelline) but indeed that is not what I am looking for. I am trying to select the invisible reference planes a user uses when placing dimensions, aligning object, etc.

Somehow I can not seem to find these invisible computed references. Saying that .. it seems that the options (.geometry(options)) are not working for a generic model face based familyinstance. Perhaps I can use the lineobjects for my purposes as a workaround.

Message 8 of 22
Scott_Wilson
in reply to: rayray4105

The API doesn't expose the control plane references but there is a fun hack I developed to get the embedded control plane references of a family instance. If you create a dimension in the UI which references a named control reference of a family instance, you can then study the dimension's references using the API to obtain the information required to build your own stable reference string and have the API convert it into a valid reference for you which can then be used for creation of dimensions and alignment constraints. I'll go look through my code an come back soon with a few code snippets for you.
Message 9 of 22
ken
Advocate
in reply to: Scott_Wilson

Hi Aaron,
Rayray is working off this post in the Building Coder: http://thebuildingcoder.typepad.com/blog/2014/11/picking-pairs-and-dimensioning-family-instance-orig...

Where Jeremy is able to get a "point" from the family geometry by asking for includeNonVisibleObjects. It seems that this is some type of provided goemetry object which is at the center point of the family. (this might be the "intersection" of the "defines origin" references planes (which would actually be a line, right?) It seems like this special way to get the origin is not working for the family Rayray posted.

I will need to deal with this as well so I'm quite interested in the resolution here. On a related note, is there any way to get from the ref planes in the family document to references for placed instances?

Thanks,
-Ken
Message 10 of 22
ken
Advocate
in reply to: ken

Rayray, have you looked at this post?

http://thebuildingcoder.typepad.com/blog/2015/05/how-to-retrieve-dimensioning-references.html#2

Might be an alternative to looking for the point if it's not there, or you could try including a view in the geometry options as Jeremy suggests in this post.
Message 11 of 22
rayray4105
in reply to: ken

Hi Ken,

To be honest: I have not looked at this post yet. I have just tried including a view in the geometry options with any luck. A few more lines are returned but I think these are from two nested familyinstances.

I will read the rest of the post shortly.
Message 12 of 22
Scott_Wilson
in reply to: rayray4105
Message 13 of 22
ken
Advocate
in reply to: Scott_Wilson

Hi Scott,

Thanks for bringing that post to may attention: It's excellent!

I have been mystified by this "Reference" concept (beyond the main idea of course). Especially as it applies to the concept of only storing the geometry once (Symbol) and using it for all the instances. If we get a "reference" how does it know which instance is the one. Looks like the reference string has the guid of the instance so I guess the dimension can somehow ask the face for it's location which accounts for instance location via instance transform. (riffing here... ) I could get my head around that as a concept I guess.

So, summing this up:
1. Giving the view (ideally oriented in such a way that the reference planes would be represented as "lines" in the view) in Options should give us references to which we can dimension or align something.

2. Assuming #1 is correct, there is currently no indicator that these are reference plane lines and we would just need to do some sleuthing to figure out which is the ref plane vs any model lines etc? (I need to carve out some time to go into the Revit API science lab and experiment with all this)

3. One can, with reasonable stability, use Scott's cool trick of dimensioning to the center plane and then investigating the dimension's references for the indices and then constructing a stable reference which can be parsed, substituting the indices of the face you want. (freaky-teaky) Noting that the particular indices will vary from family to family though seem to be stable within one family, even across documents.

Which still leaves this question: If you open the family document, I'm guessing that we could get the "reference planes" and from those could obtain a stable reference. However, that's in the family document, would that translate to the project environment? or would we need to replace one of the guids with the family instance guid?

This thought of getting them from the family document is just total conjecture on my part. I'm only hoping to probe this avenue a little. When I have some time I'll do some more experimentation and report back.

Message 14 of 22
Scott_Wilson
in reply to: ken

Here's the method I use for building a custom reference for a FamilyInstance for a particular index value. just plug in the shape handle reference index that can be found by dumping an existing dimension reference

 

public static Reference GetFamilyReferenceByIndex(FamilyInstance inst, int idx)
{
	Reference indexRef = null;

	if(inst != null)
	{
		Document dbDoc = inst.Document;

		Options geomOptions = dbDoc.Application.Create.NewGeometryOptions();

		if(geomOptions != null)
		{
			geomOptions.ComputeReferences = true;
			geomOptions.DetailLevel = ViewDetailLevel.Undefined;
			geomOptions.IncludeNonVisibleObjects = true;
		}

		GeometryElement gElement = inst.get_Geometry(geomOptions);
		GeometryInstance gInst = gElement.First() as GeometryInstance;

		String sampleStableRef = null;
		String customStableRef = null;

		if(gInst != null)
		{
			GeometryElement gSymbol = gInst.GetSymbolGeometry();

			if(gSymbol != null && gSymbol.Count() > 0)
			{
				
				Solid solid = gSymbol.First() as Solid;
				Face face = solid.Faces.get_Item(0);

				sampleStableRef = face.Reference.ConvertToStableRepresentation(dbDoc);

				if(sampleStableRef != null)
				{
					String[] tokenList = sampleStableRef.Split(new char[] { ':' });

					customStableRef = tokenList[0] + ":" + tokenList[1] + ":" + tokenList[2] + ":" + tokenList[3] + ":" + idx.ToString();

					indexRef = Reference.ParseFromStableRepresentation(dbDoc, customStableRef);

					GeometryObject geoObj = inst.GetGeometryObjectFromReference(indexRef);

					if(geoObj != null)
					{	
						String finalToken = "";

						if(geoObj is Edge)
						{
							finalToken = ":LINEAR";
						}

						if(geoObj is Face)
						{
							finalToken = ":SURFACE";
						}

						customStableRef += finalToken;

						indexRef = Reference.ParseFromStableRepresentation(dbDoc, customStableRef);
					}
					else
					{
						indexRef = null;
					}
				}
			}
			else
			{	
				throw new Exception("No Symbol Geometry found...");
			}


		}
	}

	return indexRef;
}

have fun

Message 15 of 22
Aaron.Lu
in reply to: Scott_Wilson

incredible..


Aaron Lu
Developer Technical Services
Autodesk Developer Network
Message 16 of 22
Scott_Wilson
in reply to: Aaron.Lu

Ok, I've made an interesting discovery...

I was under the impression that the reference indecies were allocated arbitrarily or were simply in order of creation but I have just discovered that the first 9 positions are occupied by the special references that have been allocated in the family editor the list is as follows:

0 = Left
1 = Center Left/Right
2 = Right
3 = Front
4 = Centre Front/Back
5 = Back
6 = Bottom
7 = Centre Elevation
8 = Top

 

As you can see this sequence matches the order they appear in the family editor reference type drop-down list.

I believe these to be reserved positions within the geometry reference table based on the following observations.

 

If you edit a family and create a reference plane or edit an existing plane and set it to one of the special reference types above you will see that it will then be available at the corresponding index, this, so far is true for all families I have tried it on.

 

If you create a dimension to one of these references, 'Left' for example, then edit the family and place a new Reference Plane and allocate it as the 'Left' Reference you will notice that the original reference plane has been set to Not A Reference, which to me signifies that the new reference has now taken the original's position in the reference table. When you load the modified family back into the project, the dimension will now update to reference the new 'Left' Plane

 

Here's the updated method that should return the correct special reference selected from an enumeration for any family that has it defined.

 

public enum SpecialReferenceType
{
	Left = 0,
	CenterLR = 1,
	Right = 2,
	Front = 3,
	CenterFB = 4,
	Back = 5,
	Bottom = 6,
	CenterElevation = 7,
	Top = 8
}


public static Reference GetSpecialFamilyReference(FamilyInstance inst, SpecialReferenceType refType)
{
	Reference indexRef = null;

	int idx = (int)refType;


	if(inst != null)
	{
		Document dbDoc = inst.Document;

		Options geomOptions = dbDoc.Application.Create.NewGeometryOptions();

		if(geomOptions != null)
		{
			geomOptions.ComputeReferences = true;
			geomOptions.DetailLevel = ViewDetailLevel.Undefined;
			geomOptions.IncludeNonVisibleObjects = true;
		}

		GeometryElement gElement = inst.get_Geometry(geomOptions);
		GeometryInstance gInst = gElement.First() as GeometryInstance;

		String sampleStableRef = null;

		if(gInst != null)
		{
			GeometryElement gSymbol = gInst.GetSymbolGeometry();

			if(gSymbol != null)
			{
				foreach(GeometryObject geomObj in gSymbol)
				{
					if(geomObj is Solid)
					{
						Solid solid = geomObj as Solid;

						if(solid.Faces.Size > 0)
						{
							Face face = solid.Faces.get_Item(0);
							sampleStableRef = face.Reference.ConvertToStableRepresentation(dbDoc);
							break;
						}
					}
					else if(geomObj is Curve)
					{
						Curve curve = geomObj as Curve;

						sampleStableRef = curve.Reference.ConvertToStableRepresentation(dbDoc);
						break;
					}
					else if(geomObj is Point)
					{
						Point point = geomObj as Point;

						sampleStableRef = point.Reference.ConvertToStableRepresentation(dbDoc);
						break;
					}
				}
			}

			if(sampleStableRef != null)
			{
				String[] refTokens = sampleStableRef.Split(new char[] { ':' });

				String customStableRef = refTokens[0] + ":" + refTokens[1] + ":" + refTokens[2] + ":" + refTokens[3] + ":" + idx.ToString();

				indexRef = Reference.ParseFromStableRepresentation(dbDoc, customStableRef);

				GeometryObject geoObj = inst.GetGeometryObjectFromReference(indexRef);

				if(geoObj != null)
				{
					String finalToken = "";

					if(geoObj is Edge)
					{
						finalToken = ":LINEAR";
					}

					if(geoObj is Face)
					{
						finalToken = ":SURFACE";
					}

					customStableRef += finalToken;

					indexRef = Reference.ParseFromStableRepresentation(dbDoc, customStableRef);
				}
				else
				{
					indexRef = null;
				}
			}
		}
		else
		{
			throw new Exception("No Symbol Geometry found...");
		}


	}


	return indexRef;
}

enjoy.

 

Message 17 of 22
rayray4105
in reply to: Scott_Wilson

That's impressive!

Message 18 of 22
ken
Advocate
in reply to: rayray4105

Scott,

This crazy! and awesome.

On a side note, I love how we talk about the Revit API: like mystics.

I wonder if there's some validity to your belief that the first 9 indices are somehow reserved for these planes. I could also see it that this was the order that the very first creator of a family template happened to create these planes... Maybe we are more Revit archaeologists than mystics but I digress.

Very cool research and thank you for sharing that!
Message 19 of 22
Scott_Wilson
in reply to: rayray4105

It has nothing to do with the order of creation
Any plane you designate as a special reference at any time will be available at the corresponding index.
Message 20 of 22
ken
Advocate
in reply to: Scott_Wilson

This is a revolutionary discovery! Thanks for doing the research on this and sharing it

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Rail Community