Convert local family instance coordinate of selected Edge to project coordinates

Anonymous

Convert local family instance coordinate of selected Edge to project coordinates

Anonymous
Not applicable

Hello,

I am trying to get the global coordinates? (Revit model space coordinates?) of the start and end points of an Edge (selected by the user).

I can get the points just fine if the selected edge is a system family (duct, pipe, etc.). The trouble is when the user selects a family instance (Mechanical, Electrical equipment etc.). After a while of trouble shooting I realized that the edge start and end coordinates being reported to me when a user selects a family instance edge were based on the family's local coordinate system. From there I started searching for a way to convert those points to the revit project coordinate system - or whatever system the ducts or pipes are using. I found several examples that steered me in the right direction (I think). But I have not been able to get anything to work for my particular case.

 

Examples:

http://thebuildingcoder.typepad.com/blog/2009/03/transform-instance-coordinates.html

http://thebuildingcoder.typepad.com/blog/2011/06/get-transformed-family-instance-geometry.html

http://thebuildingcoder.typepad.com/blog/2012/03/retrieve-geometry-in-element-coordinate-system.html

 

These examples make it clear to me that I need to be dealing with the GeometryInstance class. What I cannot figure out is how to incorporate the selected Edge of a family instance, and then get the start and end point of that edge (in the global coordinate system).

 

Thanks!

 

C#, Revit 2016

0 Likes
Reply
Accepted solutions (1)
4,954 Views
12 Replies
Replies (12)

jeremytammik
Autodesk
Autodesk

Dear Pat,

 

Thank you for your query.

 

Yes, you are on the right track.

 

The GeometryInstance.Transform property represents the transformation from the family definition coordinates to the family instance placement context.

 

If you have nested family instances, there can be a whole sequence of these transformations that need to be applied.

 

You can simply apply that transformation to the edge, e.g., using the Curve.CreateTransformed method.

 

You could also apply the instance transform to the entire instance geometry before accessing the edge, e.g., using one of the overloaded GeometryInstance methods taking a transform argument:

 

  • GetInstanceGeometry() -- Computes the geometric representation of the instance.
  • GetInstanceGeometry(Transform) -- Computes a transformation of the geometric representation of the instance.
  • GetSymbolGeometry() -- Computes the geometric representation of the symbol which generates this instance.
  • GetSymbolGeometry(Transform) -- Computes a transformation of the geometric representation of the symbol which generates this instance.

 

Funnily enough, I also found that it is sometimes sufficient to simply pass in the identity transformation into these methods to obtain the geometry transformed to the global coordinate system.

 

I hope this helps.

 

Best regards,

 

Jeremy



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

Anonymous
Not applicable

Jeremy,

 

Thank you for your quick reply. This is starting to make sense to me. But I am now hung up on what to do about the Transform. 

I guess I don't quite understand what the Transform is doing. Please forgive my ignorance. 

 

I have a sample edge that is 5ft long...

 

 

Reference r = uidoc.Selection.PickObject(ObjectType.Edge, "Select an edge of an object.");
EdgeElemSelected = uidoc.Document.GetElement(r);
GeometryObject obj = EdgeElemSelected.GetGeometryObjectFromReference(r);
Edge elemEdge = obj as Edge;
//Curve elemCurve = elemEdge.AsCurve();

Transform t = Transform.Identity;
//Curve famCurve = elemCurve.CreateTransformed(t); Curve famCurve = elemEdge.AsCurve().CreateTransformed(t); XYZ p1 = famCurve.GetEndPoint(0); XYZ p2 = famCurve.GetEndPoint(1);

TaskDialog.Show("p1", p1.X + Environment.NewLine + p1.Y);
TaskDialog.Show("p2", p2.X + Environment.NewLine + p2.Y);

dialog p1 is reporting -2.5 & -2.5.

 

dialog p1 is reporting 2.5 & -2.5.

 

These coordinates are still relative to the family's local coordinate system. I can verify this by moving the family instance around in plan and re-running my test. Each time the numbers being reported are the same. I know you said applying an identity transform to the curve is only *sometimes* sufficient. So this is clearly one of those cases where it is not sufficient. So my question to you is How do I define a transform other than using Transform.Identity to correctly obtain the points in the global coordinate system. 

0 Likes

jeremytammik
Autodesk
Autodesk

Get the geometry from the selected element itself, get the geometry instance from that, get its transform, and apply that instead of the identity.



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

0 Likes

jeremytammik
Autodesk
Autodesk

Here is the post on the identity transform:

 

http://thebuildingcoder.typepad.com/blog/2011/06/get-transformed-family-instance-geometry.html

 

I see now that you have picked the edge directly, not extracted it from the GeometryInstance.

 

That has a certain similarity with the slightly complex analysis undertaken here:

 

 

http://thebuildingcoder.typepad.com/blog/2015/09/directshape-from-face-and-sketch-plane-reuse.html#3

 

http://thebuildingcoder.typepad.com/blog/2015/09/directshape-from-face-and-sketch-plane-reuse.html#4

 

Don't worry, you'll surely sort it out.

 

Let us know how you end up solving this, please.

 

Thank you!

 

Cheers,

 

Jeremy



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

0 Likes

Anonymous
Not applicable

Thank you again Jermemy for your help on this. It may take some time for me to get this code example implemented. 

http://thebuildingcoder.typepad.com/blog/2015/09/directshape-from-face-and-sketch-plane-reuse.html#3

 

Hopefully it does the trick. I'll let you know of my findings. 

 

 

0 Likes

Anonymous
Not applicable
Accepted solution

You can also do this with Reference Voodoo like so:

 

public static Edge GetInstanceEdgeFromSymbolRef(Reference symbolRef, Autodesk.Revit.DB.Document dbDoc)
{
	Edge instEdge = null;
	
	Options gOptions = new Options();	
	gOptions.ComputeReferences = true;
	gOptions.DetailLevel= ViewDetailLevel.Undefined;
	gOptions.IncludeNonVisibleObjects = false;
	
	Element elem = dbDoc.GetElement(symbolRef.ElementId);
	string stableRefSymbol = symbolRef.ConvertToStableRepresentation(dbDoc);
	string[] tokenList = stableRefSymbol.Split(new char[] { ':' });
	string stableRefInst = tokenList[3] + ":" + tokenList[4] + ":" + tokenList[5];
	
	GeometryElement geomElem = elem.get_Geometry(gOptions);
	foreach(GeometryObject geomElemObj in geomElem)
	{
		GeometryInstance geomInst = geomElemObj as GeometryInstance;
		if(geomInst != null)
		{
			GeometryElement gInstGeom = geomInst.GetInstanceGeometry();
			foreach(GeometryObject gGeomObject in gInstGeom)
			{
				Solid solid = gGeomObject as Solid;
				if(solid != null)
				{
					foreach(Edge edge in solid.Edges)
					{
						string stableRef = edge.Reference.ConvertToStableRepresentation(dbDoc);
						
						if(stableRef == stableRefInst)
						{
							instEdge = edge;
							break;
						}
					}
				}

				if(instEdge != null)
				{
					// already found, exit early
					break;
				}
			}
		}
		if(instEdge != null)
		{
			// already found, exit early
			break;
		}
	}
	return instEdge;
}

jeremytammik
Autodesk
Autodesk

Wow, Scott, you are a marvel!

 

That is exactly what I was trying to achieve in that blog post back then, I think!

 

Cheers,

 

Jeremy



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

0 Likes

Anonymous
Not applicable

Yeah the Stable Reference Strings can be used to get at areas of the Geometry API that aren't fully exposed I love playing around with them. sometimes I stumble upon something cool such as this: http://forums.autodesk.com/t5/revit-api/geometry-returns-no-reference-for-familyinstance/m-p/6025697...

 

0 Likes

jeremytammik
Autodesk
Autodesk

Wow, very cool indeed.

 

I think I should grab the gist of these two thread and put it on the blog for easier reference and better legibility.

 

Would you like to summarise the main points, and decide which code snippets are really important to iinclude?

 

That would be extremely helpful!

 

Thank you!

 

Cheers,

 

Jeremy



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

0 Likes

Anonymous
Not applicable

Thank you Jeremy, and Scott.

You two are both prime examples on why this community is so great. 

The code snippet provided by Scott worked right out of the box. Now to start digesting it. 

 

Thanks again everyone!

0 Likes

Anonymous
Not applicable

no worries, glad to help.

 

 

Jeremy: I made a post you can use for your blog if you like. feel free to edit to your preference. http://forums.autodesk.com/t5/revit-api/for-jeremy-stable-reference-strings/m-p/6284505#M15671

0 Likes

jeremytammik
Autodesk
Autodesk

Ah, rather belatedly let me add that I published Scott's contribution way back then on The Building Coder:

 

http://thebuildingcoder.typepad.com/blog/2016/04/stable-reference-string-magic-voodoo.html

 

Many thanks again to Scott for sharing this!

 

Cheers,

 

Jeremy



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

0 Likes