While attempting to add reference points on the intersection points of the lines of a conceptual mass, an API user had found that the reference points were being drawn on the lines midpoints instead of the intersections. To investigate further on the unexpected reported behavior, I created a Conceptual Mass form and divided one of the surfaces with grids (to get lines) – using the Revit User Interface.
Now with this sample mass form, I used the following approach to create the Reference Points on the intersection of the grid lines on the mass. First step was to get access to the Divided Surface which contains the grid on which we wish to create Reference points. For purpose of experimentation (and simplicity), I assumed that the user will select Divided Surface (though in the actual plug-in, this might be extracted using Filters). With this surface, we can access the geometry of the surface which infact drills down to all the lines that form the grid. Now taking each line at a time, we compare this line with all the other lines in the Surface – excluding the instances where the same line might be returned once. Thus using nested loops, I iterate through each line and calculate the intersection points on this line with the each of the other lines in the surface grid. These intersection points are stored in an IntersectionResultArray collection which is returned from the intersection of the line with each of the other line. And finally on each intersection point, we can use the FamilyCreate.NewReferencePoint() method to create the intersection point.
Like they say- a picture can say a thousand words. In this case, it seems a code snippet might do a better job at explaining the approach – than a thousand words that I have just used. So here it is:
using System;
using System.Collections.Generic;
using System.Text;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
namespace Revit.SDK.Samples.HelloRevit.CS
{
[Transaction(TransactionMode.Manual)]
public class Command : IExternalCommand
{
public Result Execute(ExternalCommandData commandData,
ref string message,
ElementSet elements)
{
UIDocument uiDoc = commandData.Application.ActiveUIDocument;
using (Transaction trans = new Transaction(uiDoc.Document, "Point"))
{
trans.Start();
// Ensure you select a DividedSurface Element from the model
foreach (Element ele in uiDoc.Selection.Elements)
{
DividedSurface surface = ele as DividedSurface;
if (null != surface)
{
Options opts =
uiDoc.Document.Application.Create.NewGeometryOptions();
GeometryElement geoEle = surface.get_Geometry(opts);
IEnumerator<GeometryObject> geoElems =
geoEle.GetEnumerator();
while (geoElems.MoveNext())
{
GeometryObject geoObj =
geoElems.Current as GeometryObject;
Line line = geoObj as Line;
if (null != line)
{
IEnumerator<GeometryObject> geoNestedElems =
geoEle.GetEnumerator();
while (geoNestedElems.MoveNext())
{
GeometryObject geoObjNested =
geoNestedElems.Current as GeometryObject;
Line nestedLine = geoObjNested as Line;
if (null != nestedLine)
{
// Ensure that this line is not the same as
// main line
if (!nestedLine.Equals(line))
{
// Create container for the
// intersection results array
IntersectionResultArray resArray =
new IntersectionResultArray();
// Get the intersection result
// array using Intersect()
line.Intersect(nestedLine, out resArray);
if (null != resArray)
{
foreach (IntersectionResult res in resArray)
{
// Create a new reference point
// for each intersection point
ReferencePoint rp =
uiDoc.Document.FamilyCreate.
NewReferencePoint(res.XYZPoint);
}
}
}
}
}
}
}
}
}
trans.Commit();
}
return Result.Succeeded;
}
}
}
After running the external command on the conceptual form that I had created to test, the output confirmed that the approach used was indeed correct and did yield the expected results.