Alignment Sample Line Intersection

By Augusto Goncalves

This question came from Grace Ferrari: from a given alignment (e.g., Alignment 01) with sample lines, how can I find the intersection of each sample line on another alignment (e.g., Alignment 02)? The image below shows the scenario. Thanks, Grace, for sharing the image.

Explanation

To implement this I decided to try something that I was willing to understand for a while: custom foreach on .NET. Also, we need to use Extensions to make it fun.

The first piece is quite straightforward: select both alignments and open them for read. Also, draw AutoCAD DBPoints (plain points) at each intersection. Below is the code.

Command Method Implementation


[CommandMethod("testDrawPointsIntersection")]
public static void CmdDrawPointsOnIntersection()
{
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

    // select reference alignment
    // this is the alignment with sample lines
    // (for simplicity, this condition is not verified)
    PromptEntityOptions peo = new PromptEntityOptions(
        "\nSelect reference alignment (with sample lines): ");
    peo.SetRejectMessage("\nOnly alignments");
    peo.AddAllowedClass(typeof(Alignment), true);
    PromptEntityResult per = ed.GetEntity(peo);
    if (per.Status != PromptStatus.OK) return;
    ObjectId sourceAlignId = per.ObjectId;

    // now select the other alignment
    peo.Message = "\nSelect the other alignment: ";
    per = ed.GetEntity(peo);
    ObjectId otherAlignId = per.ObjectId;

    DrawPointOnSampleLineIntersection(sourceAlignId, otherAlignId);
}

public static void DrawPointOnSampleLineIntersection(
    ObjectId sourceAlignId, ObjectId otherAlignId)
{
    Database db = Application.DocumentManager.MdiActiveDocument.Database;
    CivilDocument civilDoc = CivilApplication.ActiveDocument;
    
    using (Transaction trans = db.TransactionManager.StartTransaction())
    {
        // open both alignments
        Alignment sourceAlign = trans.GetObject(sourceAlignId, OpenMode.ForRead) as Alignment;
        Alignment otherAlign = trans.GetObject(otherAlignId, OpenMode.ForRead) as Alignment;

        // open model space (i.e. current space)
        BlockTableRecord mSpace = trans.GetObject(db.CurrentSpaceId,
            OpenMode.ForWrite) as BlockTableRecord;

        foreach (Point3d point in sourceAlign.SampleLinesIntersectionWith(otherAlign))
        {
            // point AutoCAD plain points
            DBPoint newPoint = new DBPoint(point);
            mSpace.AppendEntity(newPoint);
            trans.AddNewlyCreatedDBObject(newPoint, true);
        }
        trans.Commit();
    }
}

And now you might wonder: where this SampleLinesIntersectionWith method came from? This is actually an extension on .NET. To have this, we need a static public class in C#. We made a cool article on this.

Below is the extension class. Note the this on the first parameter, indicating the objects where this extension is applicable.

Extension Class


using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.Civil.DatabaseServices;

namespace MyProjectName
{
    public static class Extensions
    {
        /// <summary>
        /// Iterate on the collection of intersection points
        /// from this alignment sample lines on the other alignment
        /// </summary>
        /// <param name="source">This base/reference alignment</param>
        /// <param name="other">Other alignment</param>
        public static IEnumerable<Point3d> SampleLinesIntersectionWith(
            this Alignment source, Alignment other)
        {
            // get the base curve for the base alignment
            Curve baseCurveAlign2 = other.BaseCurve;
            
            using (Transaction trans = source.Database.TransactionManager.StartTransaction())
            {
                // get the collection of sample lines on the base alignment
                ObjectIdCollection sLineGroupIds = source.GetSampleLineGroupIds();
                
                foreach (ObjectId sLineGroupId in sLineGroupIds)
                {
                    // for each sample line group, get all sample lines
                    SampleLineGroup sLineGroup = trans.GetObject(sLineGroupId,
                        OpenMode.ForRead) as SampleLineGroup;
                    ObjectIdCollection sLineIds = sLineGroup.GetSampleLineIds();

                    foreach (ObjectId sLineId in sLineIds)
                    {
                        // for each sample line, use the GetBasePLine to get the base curve/pline
                        SampleLine sLine = trans.GetObject(sLineId, OpenMode.ForRead) as SampleLine;
                        
                        using (Polyline baseCurveSampleLine = sLine.GetBasePLine())
                        {
                            // finally find the intersection
                            Point3dCollection points = new Point3dCollection();
                            baseCurveAlign2.IntersectWith(baseCurveSampleLine,
                                Intersect.OnBothOperands, points, IntPtr.Zero, IntPtr.Zero);
                            
                            if (points.Count > 0)
                                yield return points[0]; // this will yield for each point
                        }
                    }
                }
                trans.Commit(); // commit, otherwise the outer transaction will abort
            }
        }

        /// <summary>
        /// Get a Polyline for this SampleLine
        /// </summary>
        public static Polyline GetBasePLine(this SampleLine sline)
        {
            Polyline pline = new Polyline();
            int v = 0;
            
            foreach (SampleLineVertex vertex in sline.Vertices)
            {
                pline.AddVertexAt(v,
                    vertex.Location.Convert2d(new Plane()),
                    0, 0, 0);
                v++;
            }
            return pline;
        }
    }
}

Comments

2 responses to “Alignment Sample Line Intersection”

  1. Hi Augusto
    I working example in Lisp would be great :-)

  2. Hi Pierre,
    .NET the way to go with Civil 3D. Lisp may fail on some Civil 3D ActiveX API calls, it’s not supported….
    -Augusto Goncalves

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading