I have a curtain panel glass (showed below) with a bunch of vertical and horizontal lines as references planes that should be used to snap specialty equipment to intersections so they are properly placed.
Right now the specialty equipment is being placed by a plugin we are developing by calling Document.Create.NewFamilyInstance
and it's position comes from the face of the wall selected by the user with UIDocument.Selection.PickObject
. However, I need to get these reference lines in the code so I can place the specialty equipment exactly at the closest intersection to where the user selected.
I know that these reference planes will only show up in an Elevation view and that's what I'm using when looking for these objects in the code by assigning options.View = _document.Document.ActiveView;
and calling the API while in an Elevation view, but the closest I could get to a working solution is the code below and The problem is that I could only get lines (that I know are the ones composing the reference planes because of their position), but I can't find a way to cast/transform them into actual ReferencePlane instances to use when calling NewFamilyInstance.
Is that possible to do? If not, how can I make sure the specialty equipment snaps to the closes reference it finds?
void FindReferencePlances(ElementId elementId)
{
var fi = _docMan.Document.GetElement(elementId) as FamilyInstance;
var transforms = fi.GetTransform();
string data = string.Empty;
Options options = new Options();
options.IncludeNonVisibleObjects = true;
options.ComputeReferences = true;
options.View = _docMan.Document.ActiveView;
var r = fi.GetFamilyPointPlacementReferences();
foreach (GeometryObject go in
fi.get_Geometry(options))
{
data += " - " +go.GetType().ToString()
+ Environment.NewLine;
if (go is GeometryInstance)
{
GeometryInstance gi = go as GeometryInstance;
foreach (GeometryObject goSymbol in
gi.GetSymbolGeometry())
{
data += " -- " + goSymbol.GetType().ToString()
+ Environment.NewLine;
if (goSymbol is Line)
{
Line line = goSymbol as Line;
data += " --- " + line.GetType().ToString() + " (" + line.Origin.ToString() + ")";
}
}
}
}
TaskDialog.Show("data", data);
}
Update: Not sure this is the right way to do it, but I found a way to get all intersection points from reference plane lines so that I can position my object near the closest point. The code below do not remove duplicates.
public static List<XYZ> FindInstersectionsInReferencePlane(Document doc, ElementId elementId)
{
var fi = doc.GetElement(elementId) as FamilyInstance;
var transforms = fi.GetTransform();
string data = string.Empty;
Options options = new Options();
options.IncludeNonVisibleObjects = true;
options.ComputeReferences = true;
options.View = doc.Document.ActiveView;
var lines = fi.get_Geometry(options)
.Select(x => x as GeometryInstance)
.SelectMany(x => x.GetSymbolGeometry().ToList())
.OfType<Line>()
.ToList();
var results = new List<Tuple<Line, Line, IntersectionResultArray>>();
foreach (var l1 in lines)
{
foreach (var l2 in lines)
{
IntersectionResultArray r = null;
if (l1.Intersect(l2, out r) == SetComparisonResult.Overlap)
results.Add(Tuple.Create(l1, l2, r));
}
}
var points = new List<XYZ>();
foreach (var result in results)
{
foreach (IntersectionResult res in result.Item3)
{
points.Add(res.XYZPoint);
}
}
return points;
}
According to this there is no way to get to the actual ReferecePlane objects:
http://thebuildingcoder.typepad.com/blog/2015/05/how-to-retrieve-dimensioning-references.html
"Once you pass in a suitable view and obtain these extra references, there is nothing to identify them. You have to analyse the geometry to figure out which one is the one you need. For instance, for 2D views, reference planes may be returned as lines (Curve instances) instead of planes."