Message 1 of 6
Arc along lines
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hi All,
I'm struggling with creating arcs along curves (3D). The goal is to create an array of arcs programmatically based on 3D Curves. Anyone got an idea on how to achieve this? please see below code (not working as expected) but for reference of what I'm trying to do. see attached file as well. Thanks.
public Result Execute(ExternalCommandData revit, ref string message, ElementSet elements)
{
// Revit application data
UIApplication uiapp = revit.Application;
UIDocument uidoc = uiapp.ActiveUIDocument;
Application app = uiapp.Application;
Document doc = uidoc.Document;
uiapplication = uiapp;
uidocument = uidoc;
document = doc;
revitApplication = app;
externalCommand = revit;
// Command name to equal execute class name
string commandName = "CreateSurfaceFromMassingAndContours";
// Call the command to execute within a transaction to safely dispose objects in memory
using (TransactionGroup t = new TransactionGroup(doc, commandName))
{
// Start the transaction
t.Start();
// Pick massing element
Reference massingRef = uidoc.Selection.PickObject(ObjectType.Element, new MassingElementSelectionFilter(), "Select a massing element");
Element massingElement = doc.GetElement(massingRef);
// Extract line geometry from the massing element
Curve massLine = ExtractLineFromMassing(massingElement);
if (massLine == null)
{
TaskDialog.Show("Error", "No valid line found in the selected massing element.");
return Result.Failed;
}
// Pick contour lines
ICollection<ElementId> contourIds = PickContourLines(uidoc);
if (contourIds.Count == 0)
{
TaskDialog.Show("Error", "No contour lines selected. Please select contour lines.");
return Result.Failed;
}
// Create the base CurveLoop from the selected contour curves
CurveLoop baseCurveLoop = CreateCurveLoopFromContours(doc, contourIds);
if (baseCurveLoop == null || baseCurveLoop.IsOpen())
{
TaskDialog.Show("Error", "Failed to create a valid closed CurveLoop from the selected contours.");
return Result.Failed;
}
// Extrude the base CurveLoop to create a solid
Solid baseSolid = ExtrudeBaseContour(doc, baseCurveLoop);
if (baseSolid == null)
{
TaskDialog.Show("Error", "Failed to create base solid from the base CurveLoop.");
return Result.Failed;
}
List<XYZ> intersectionPoints = IntersectPerpendicularLinesWithBaseSolidAndMassCurves(doc, massLine, baseSolid, contourIds);
List<XYZ> newintersectionPoints = ProjectPointsToBaseCurveLoop(intersectionPoints, baseCurveLoop); // START AND ENDPOINT OF THE ARC
List<XYZ> massCurveIntersections = PointsOnMassLine(doc, massLine); // arc MIDPOINT
if (newintersectionPoints.Count < 3)
{
TaskDialog.Show("Error", "Not enough intersection points to create a topography surface.");
return Result.Failed;
}
CreateArcsFromIntersectionPoints(doc, newintersectionPoints, massCurveIntersections);
// End the transaction group
t.Assimilate();
}
return Result.Succeeded;
}
private static ICollection<ElementId> PickContourLines(UIDocument uidoc)
{
Selection sel = uidoc.Selection;
IList<Reference> pickedRefs = sel.PickObjects(ObjectType.Element, new ContourLineSelectionFilter(), "Select contour lines");
List<ElementId> selectedIds = pickedRefs.Select(r => r.ElementId).ToList();
return selectedIds;
}
private Curve ExtractLineFromMassing(Element massingElement)
{
GeometryElement geometryElement = massingElement.get_Geometry(new Options());
foreach (GeometryObject geomObj in geometryElement)
{
if (geomObj is GeometryInstance instance)
{
GeometryElement instanceGeometry = instance.GetInstanceGeometry();
foreach (GeometryObject instGeomObj in instanceGeometry)
{
if (instGeomObj is Curve curve)
{
return curve;
}
}
}
else if (geomObj is Curve curve)
{
return curve;
}
}
return null;
}
private CurveLoop CreateCurveLoopFromContours(Document doc, ICollection<ElementId> contourIds)
{
CurveLoop curveLoop = new CurveLoop();
foreach (ElementId contourId in contourIds)
{
Element contourElement = doc.GetElement(contourId);
Curve contourCurve = (contourElement.Location as LocationCurve).Curve;
// Check if the curve is already bound, if not, create a bound curve
if (!contourCurve.IsBound)
{
XYZ startPoint = contourCurve.GetEndPoint(0);
XYZ endPoint = contourCurve.GetEndPoint(1);
Line boundLine = Line.CreateBound(startPoint, endPoint);
curveLoop.Append(boundLine);
}
else
{
curveLoop.Append(contourCurve);
}
}
return curveLoop;
}
private Solid ExtrudeBaseContour(Document doc, CurveLoop baseCurveLoop)
{
double extrusionHeight = 100.0; // Adjust the height of the extrusion as needed
Solid baseSolid = GeometryCreationUtilities.CreateExtrusionGeometry(new List<CurveLoop> { baseCurveLoop }, XYZ.BasisZ, extrusionHeight);
// Create a DirectShape to visualize the solid
using (Transaction t = new Transaction(doc, "Create Base Solid"))
{
t.Start();
DirectShape directShape = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel));
directShape.SetShape(new GeometryObject[] { baseSolid });
t.Commit();
}
return baseSolid;
}
private List<XYZ> IntersectPerpendicularLinesWithBaseSolidAndMassCurves(Document doc, Curve massLine, Solid baseSolid, ICollection<ElementId> contourIds)
{
List<XYZ> intersectionPoints = new List<XYZ>();
// Define spacing or number of perpendicular lines
double spacing = 1; // Adjust the spacing as needed for better coverage
int numPoints = (int)(massLine.Length / spacing);
for (int i = 0; i <= numPoints; i++)
{
double parameter = (double)i / numPoints;
XYZ pointOnMassLine = massLine.Evaluate(parameter, true);
// Create a line perpendicular to the mass line
XYZ tangent = massLine.ComputeDerivatives(parameter, true).BasisX.Normalize();
XYZ perpendicularDirection = tangent.CrossProduct(XYZ.BasisZ).Normalize();
Line perpendicularLine = Line.CreateBound(pointOnMassLine - perpendicularDirection * 100.0, pointOnMassLine + perpendicularDirection * 100.0);
// Intersect the perpendicular line with the base solid
intersectionPoints.AddRange(IntersectLineWithSolid(perpendicularLine, baseSolid));
}
if (intersectionPoints.Count < 3)
{
TaskDialog.Show("Error", "No intersection points found.");
}
return intersectionPoints;
}
private List<XYZ> PointsOnMassLine(Document doc, Curve massLine)
{
List<XYZ> intersectionPoints = new List<XYZ>();
// Define spacing or number of perpendicular lines
double spacing = 1; // Adjust the spacing as needed for better coverage
int numPoints = (int)(massLine.Length / spacing);
for (int i = 0; i <= numPoints; i++)
{
double parameter = (double)i / numPoints;
XYZ pointOnMassLine = massLine.Evaluate(parameter, true);
// Create a line perpendicular to the mass line
XYZ tangent = massLine.ComputeDerivatives(parameter, true).BasisX.Normalize();
intersectionPoints.Add(pointOnMassLine);
}
if (intersectionPoints.Count < 3)
{
TaskDialog.Show("Error", "No intersection points found.");
}
return intersectionPoints;
}
private List<XYZ> ProjectPointsToBaseCurveLoop(List<XYZ> points, CurveLoop baseCurveLoop)
{
List<XYZ> projectedPoints = new List<XYZ>();
foreach (XYZ point in points)
{
XYZ nearestPoint = FindNearestPointOnCurveLoop(point, baseCurveLoop);
XYZ projectedPoint = new XYZ(point.X, point.Y, nearestPoint.Z);
projectedPoints.Add(projectedPoint);
}
return projectedPoints;
}
private XYZ FindNearestPointOnCurveLoop(XYZ point, CurveLoop curveLoop)
{
XYZ nearestPoint = null;
double minDistance = double.MaxValue;
foreach (Curve curve in curveLoop)
{
XYZ projectedPoint = curve.Project(point).XYZPoint;
double distance = point.DistanceTo(projectedPoint);
if (distance < minDistance)
{
minDistance = distance;
nearestPoint = projectedPoint;
}
}
return nearestPoint;
}
private void CreateArcsFromIntersectionPoints(Document doc, List<XYZ> intersectionPoints, List<XYZ> massCurveIntersections)
{
using (Transaction t = new Transaction(doc, "Create Arcs"))
{
t.Start();
// Assuming intersections and mass curve points are paired correctly
for (int i = 0; i < massCurveIntersections.Count; i++)
{
XYZ midPoint = massCurveIntersections[i];
if (i < intersectionPoints.Count - 1)
{
XYZ startPoint = intersectionPoints[i];
XYZ endPoint = intersectionPoints[i + 1];
if (!startPoint.IsAlmostEqualTo(endPoint))
{
Arc arc = Arc.Create(startPoint, endPoint, midPoint);
Plane plane = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, midPoint);
SketchPlane sketchPlane = SketchPlane.Create(doc, plane);
doc.Create.NewModelCurve(arc, sketchPlane);
}
}
}
t.Commit();
}
}
private List<XYZ> IntersectLineWithSolid(Line line, Solid solid)
{
List<XYZ> intersectionPoints = new List<XYZ>();
foreach (Face face in solid.Faces)
{
IntersectionResultArray results;
SetComparisonResult result = face.Intersect(line, out results);
if (result == SetComparisonResult.Overlap)
{
foreach (IntersectionResult intersect in results)
{
intersectionPoints.Add(intersect.XYZPoint);
}
}
}
return intersectionPoints;
}
private class MassingElementSelectionFilter : ISelectionFilter
{
public bool AllowElement(Element elem)
{
return elem.Category.Id.IntegerValue == (int)BuiltInCategory.OST_Mass;
}
public bool AllowReference(Reference reference, XYZ position)
{
return false;
}
}
private class ContourLineSelectionFilter : ISelectionFilter
{
public bool AllowElement(Element elem)
{
return elem.Category.Id.IntegerValue == (int)BuiltInCategory.OST_Lines;
}
public bool AllowReference(Reference reference, XYZ position)
{
return false;
}
}
}
}

Developer Advocacy and Support +