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.