Interesting topic. I know it's 'a bit old' but still up to date.
I'm also busy doing something similar. So far I have this (going by mullions but panels should work equally well):
private void PeilMaten(Wall wall)
{
Richting richting = Richting.horizontaal;
List<Face> faces = ValidFaces(wall, richting);
BoundingBoxXYZ bb = wall.get_BoundingBox(doc.ActiveView);
Reference r;
if (faces != null)
{
foreach (Face fa in faces)
{
foreach (EdgeArray ea in fa.EdgeLoops)
{
foreach (Edge e in ea)
{
XYZ pt = e.AsCurve().GetEndPoint(0);
if (pt.Z == bb.Min.Z || pt.Z == bb.Max.Z)
{
r = e.GetEndPointReference(0);
doc.Create.NewSpotElevation(doc.ActiveView, r, bb.Min, bb.Min, bb.Min, bb.Min, true);
//break;
}
}
}
}
}
}
Since in this case I'm only interested in the top and bottom of the curtain wall, I'm going for the top- and bottom most mullion faces. I already have gathered the up- and down facing mullion faces using this method:
List<Face> ValidFaces(Wall wall, Richting richting)
{
FilteredElementCollector mullions = new FilteredElementCollector(doc, wall.CurtainGrid.GetMullionIds())
.OfCategory(BuiltInCategory.OST_CurtainWallMullions);
Options options = new Options();
options.ComputeReferences = true;
options.View = doc.ActiveView;
options.IncludeNonVisibleObjects = true;
List<Face> validFaces = new List<Face>();
foreach (Mullion m in mullions)
{
if ((richting == Richting.horizontaal && m.LocationCurve.GetEndPoint(0).Z == m.LocationCurve.GetEndPoint(1).Z)
|| (richting == Richting.verticaal && m.LocationCurve.GetEndPoint(0).Z != m.LocationCurve.GetEndPoint(1).Z))
{
GeometryElement ge = m.get_Geometry(options);
foreach (GeometryInstance gi in ge)
{
GeometryElement ige = gi.GetInstanceGeometry();
foreach (GeometryObject igo in ige)
{
Solid s = igo as Solid;
if (s != null)
{
FaceArray faces = s.Faces;
foreach (Face fa in faces)
{
if ((richting == Richting.horizontaal && fa.ComputeNormal(new UV(0, 0)).Z != 0)
|| (richting == Richting.verticaal && fa.ComputeNormal(new UV(0, 0)).Z == 0))
{
validFaces.Add(fa);
}
}
}
}
}
}
}
return validFaces;
}
}I found this works best in InstanceGeometry, otherwise I get an invalid reference exception.
"Richting" (direction) is an enum object I made myself to distinct between horizontal and vertical direction.
The short result is I don't trigger an exception when I extract the reference from an edge in the face's EdgeArrayArray. Unfortunately, when I place this spotdimension it's not visible.
When I use the face's reference, I get an exception saying that the Spot Dimension doesn't lie on its reference, not even when I only place it for bb.Min.