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 show the scenario, thanks Grace for sharing the image.
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 straight forward: select both alignments and open them for read. Also, draw AutoCAD DBPoints (plain points) at each intersection. Below is the code.
[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 a 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.
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>
/// Interate 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;
}
}
}