How to convert a line segment or arc to a polyline.

How to convert a line segment or arc to a polyline.

ooe21832
Contributor Contributor
4,220 Views
2 Replies
Message 1 of 3

How to convert a line segment or arc to a polyline.

ooe21832
Contributor
Contributor

I want to convert a line segment or arc to a poly line, but when I execute it with AoutCAD, it becomes "e IllgalEntityType" and I cannot convert it.

 

Can you tell me how to convert it?

 

The code I'm writing is designed to behave as follows.
1.Get polylines and solids from model space.
2.Create a surface from a polyline.
3.Get the intersection of a surface and a solid.
4.Get the boundary edge from the intersection and convert it to a polyline.
5.Join polylines

Attach the code you are writing and the test data.

 

Thank you.

 

    public class Class1
    {

        [CommandMethod("SolidPl")]
        public void SolidPl()
        {

            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Database acCurDb = acDoc.Database;
            Editor oED = acDoc.Editor;
      
            using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
            {
                PromptSelectionResult acSSPrompt = acDoc.Editor.GetSelection();
                BlockTable oDb;
                oDb = (BlockTable)acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead);

                BlockTableRecord obtr;
                obtr = (BlockTableRecord)acTrans.GetObject(oDb[BlockTableRecord.ModelSpace], OpenMode.ForWrite);


                if (acSSPrompt.Status == PromptStatus.OK)
                {
                    SelectionSet acSSet = acSSPrompt.Value;


                    //Sort solids and polylines.
                    List<object> Poly2d = new List<object>();
                    List<object> Solid3d = new List<object>();

                    foreach (SelectedObject acSSObj in acSSet)
                    {
                        if (acSSObj != null)
                        {
                            Entity acEnt = (Entity)acTrans.GetObject(acSSObj.ObjectId, OpenMode.ForWrite);

                            if (acEnt != null)
                            {
                             
                                List<object> Oblist = new List<object>();
                                Oblist.Add(acEnt);

                                List<string> Polylist = new List<string>();
                                Polylist.Add("Autodesk.AutoCAD.DatabaseServices.Polyline");

                                List<string> Sollist = new List<string>();
                                Sollist.Add("Autodesk.AutoCAD.DatabaseServices.Solid3d");

                                foreach (object a in Oblist)
                                {

                                    foreach (string b in Polylist)
                                    {

                                        if (a.ToString() == b)
                                        {
                                            Poly2d.Add(a);
                                        }
                                        else
                                        {
                                            Solid3d.Add(a);                                         
                                        }
                                    }
                                }
                            }
                        }
                    }

                    // Create a surface from polylines.
                    // Make the cross section where the surface and the solid overlap into a surface.
                    // Get the boundary edge (region) of the surface.
                    // Convert regions to polylines and combine them.
                    foreach (Polyline Poly3d in Poly2d)
                    {

                        Point3d sad = Poly3d.StartPoint;
                        
                        foreach (Solid3d SolidSt in Solid3d)
                        {
                            Point3d sad2 = Poly3d.StartPoint;
                           
                            if (SolidSt.ToString() == "Autodesk.AutoCAD.DatabaseServices.Solid3d")
                            {
                                Solid3d Solid = SolidSt as Solid3d;

                                // Create a surface from polylines.
                                Point3d Stp = Poly3d.StartPoint;
                                Point3d Etp = Poly3d.EndPoint;

                                double XPoint = Stp.X;
                                double YPoint = Stp.Y;
                                double ZPoint = Stp.Z;

                                Vector3d Vec1 = Stp.GetVectorTo(new Point3d(XPoint, YPoint, ZPoint-1000));

                                Polyline Poly3dCl = Poly3d.Clone() as Polyline;
                                Poly3dCl.TransformBy(Matrix3d.Displacement(Vec1));

                                Point3d StpCo = Poly3dCl.StartPoint;
                                Point3d EtpCo = Poly3dCl.EndPoint;
                                                               
                                Line Lin = new Line(Stp, StpCo);
                                Line Lin2 = new Line(Etp, EtpCo);

                                obtr.AppendEntity(Lin);
                                acTrans.AddNewlyCreatedDBObject(Lin, true);
                                obtr.AppendEntity(Lin2);
                                acTrans.AddNewlyCreatedDBObject(Lin2, true);
                                obtr.AppendEntity(Poly3dCl);
                                acTrans.AddNewlyCreatedDBObject(Poly3dCl, true);

                                Entity[] Ent1 = new Entity[] { Poly3d,Poly3dCl };
                                Entity[] Ent2 = new Entity[] { Lin, Lin2 };

                                LoftedSurface LofSu = new LoftedSurface();
                                LofSu.CreateLoftedSurface(Ent1, Ent2, null, new LoftOptions());

                                obtr.AppendEntity(LofSu);
                                acTrans.AddNewlyCreatedDBObject(LofSu, true);


                                // Get the intersection of solid and surface.
                                Entity[] EntSurf = LofSu.BooleanIntersect(Solid);

                                foreach (Autodesk.AutoCAD.DatabaseServices.Surface Surf2 in EntSurf)
                                {

                                    // Get the boundary edge (region) of the surface.
                                    Entity[] EntLine = Surf2.ConvertToRegion();

                                    foreach (Region region in EntLine)
                                    {
                                        // Convert from region to polyline.
                                        var plines = new List<Polyline>();

                                        using (var curves = new DBObjectCollection())
                                        {
                                            region.Explode(curves);
                                            
                                            foreach (Curve curve in curves)
                                            {

                                                using (Polyline pline = new Polyline())
                                                {

                                                    pline.ConvertFrom(curve, false);                                                   
                                                    obtr.AppendEntity(pline);
                                                    acTrans.AddNewlyCreatedDBObject(pline, true);
                                                    curve.Erase();

                                                }                                                    
                                            }
                                        }                                                                                
                                    }
                                }
                            }                                
                        }
                    }                                            
                }
                acTrans.Commit();
            }          
        }
    }
Accepted solutions (2)
4,221 Views
2 Replies
Replies (2)
Message 2 of 3

_gile
Consultant
Consultant
Accepted solution

Hi,

What you are asking is not simple and from your code it seems that you are not yet very comfortable with C# and the AutoCAD .NET API.
First of all, the intersection of a Surface and a Solid does not generate a Region but one (or more) Surface.
Secondly, decomposing a Region does not only generate Lines and Arcs, but can also generate Circles, Ellipses or Splines.

Here's an example which uses the Solid3d.GetSection() method (that means intersection beween the solid and the unbounded vertical planepassing though tle polyline start and end point).
This example also uses the PolylineSegment and PolylineSegmentCollection classes from the GeometryExtension from TheSwamp.

Note that polylines can only approximate ellipses and splines.

 

The Command class example:

using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

using Gile.AutoCAD.Geometry;

using System.Collections.Generic;

using AcAp = Autodesk.AutoCAD.ApplicationServices.Core.Application;

namespace Solid3dSectionsSample
{
    public class Commands
    {
        [CommandMethod("TEST")]
        public static void Test()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            // Prompt the user to select polylines and 3d solids
            var filter = new SelectionFilter(new[] { new TypedValue(0, "LWPOLYLINE,3DSOLID") });
            var selection = ed.GetSelection(filter);
            if (selection.Status != PromptStatus.OK)
                return;

            using (var tr = db.TransactionManager.StartTransaction())
            {
                // Sort polylines and 3d solids 
                // (at this point the selection set only contains PolylineS and Solid3dS)
                var plines = new List<Polyline>();
                var solids = new List<Solid3d>();
                foreach (ObjectId id in selection.Value.GetObjectIds())
                {
                    var entity = tr.GetObject(id, OpenMode.ForRead);
                    if (entity is Polyline)
                        plines.Add((Polyline)entity);
                    else
                        solids.Add((Solid3d)entity);
                }

                var currentSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

                // For each polyline, loop for each 3d solid
                foreach (var pline in plines)
                {
                    double elevation = new Line3d(pline.StartPoint, pline.EndPoint).GetDistanceTo(Point3d.Origin);
                    foreach (var solid in solids)
                    {
                        // Get the solid section (Region)
                        if (TryGetSection(pline, solid, out Region region))
                        {
                            // Convert the region into polyline(s)
                            foreach (var pl in ConvertToPolylines(region))
                            {
                                currentSpace.AppendEntity(pl);
                                tr.AddNewlyCreatedDBObject(pl, true);
                            }
                            region.Dispose();
                        }
                    }
                }
                tr.Commit();
            }
        }

        private static bool TryGetSection(Polyline pline, Solid3d solid, out Region region)
        {
            var plane = new Plane(pline.StartPoint + Vector3d.ZAxis, pline.StartPoint, pline.EndPoint);
            try
            {
                region = solid.GetSection(plane);
                return true;
            }
            catch
            {
                region = null;
                return false;
            }
        }

        private static List<Polyline> ConvertToPolylines(Region region)
        {
            var plane = new Plane(Point3d.Origin, region.Normal);
            var entitySet = new DBObjectCollection();
            region.Explode(entitySet);
            double elevation = ((Curve)entitySet[0]).StartPoint.TransformBy(Matrix3d.WorldToPlane(plane)).Z;
            var segments = new PolylineSegmentCollection();
            foreach (Entity entity in entitySet)
            {
                switch (entity)
                {
                    case Arc arc:
                        segments.Add(new PolylineSegment(
                            new CircularArc2d(
                                arc.Center.Convert2d(plane),
                                arc.Radius,
                                arc.StartAngle,
                                arc.EndAngle,
                                Vector2d.XAxis,
                                false)));
                        break;
                    case Circle circle:
                        segments.AddRange(new PolylineSegmentCollection(circle));
                        break;
                    case Ellipse ellipse:
                        segments.AddRange(new PolylineSegmentCollection(ellipse));
                        break;
                    case Line line:
                        segments.Add(new PolylineSegment(
                            new LineSegment2d(
                                line.StartPoint.Convert2d(plane),
                                line.EndPoint.Convert2d(plane))));
                        break;
                    case Polyline pline:
                        segments.AddRange(new PolylineSegmentCollection(pline));
                        break;
                    case Spline spline:
                        try
                        {
                            segments.AddRange(new PolylineSegmentCollection((Polyline)spline.ToPolyline()));
                        }
                        catch { }
                        break;
                    default:
                        break;
                }
                entity.Dispose();
            }
            var plines = new List<Polyline>();
            foreach (PolylineSegmentCollection segs in segments.Join())
            {
                Polyline pline = segs.ToPolyline();
                pline.Elevation = elevation;
                pline.TransformBy(Matrix3d.PlaneToWorld(plane));
                plines.Add(pline);
            }
            return plines;
        }
    }
}

 

The PolylineSegment class:

using Autodesk.AutoCAD.Geometry;

using System;

namespace Gile.AutoCAD.Geometry
{
    public class PolylineSegment
    {
        public Point2d StartPoint { get; set; }

        public Point2d EndPoint { get; set; }

        public double Bulge { get; set; }

        public double StartWidth { get; set; }

        public double EndWidth { get; set; }

        public bool IsLinear => Bulge == 0.0;

        public PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge = 0.0, double constantWidth = 0.0)
            : this(startPoint, endPoint, bulge, constantWidth, constantWidth)
        { }

        public PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge, double startWidth, double endWidth)
        {
            StartPoint = startPoint;
            EndPoint = endPoint;
            Bulge = bulge;
            StartWidth = startWidth;
            EndWidth = endWidth;
        }

        public PolylineSegment(LineSegment2d line)
        {
            StartPoint = line.StartPoint;
            EndPoint = line.EndPoint;
            Bulge = 0.0;
            StartWidth = 0.0;
            EndWidth = 0.0;
        }

        public PolylineSegment(CircularArc2d arc)
        {
            StartPoint = arc.StartPoint;
            EndPoint = arc.EndPoint;
            Bulge = Math.Tan((arc.EndAngle - arc.StartAngle) / 4.0);
            if (arc.IsClockWise) Bulge = -Bulge;
            StartWidth = 0.0;
            EndWidth = 0.0;
        }

        public PolylineSegment Clone()
        {
            return new PolylineSegment(StartPoint, EndPoint, Bulge, StartWidth, EndWidth);
        }

        public double GetParameterOf(Point2d pt)
        {
            if (IsLinear)
            {
                LineSegment2d line = ToLineSegment();
                return line.IsOn(pt) ? StartPoint.GetDistanceTo(pt) / line.Length : -1.0;
            }
            else
            {
                CircularArc2d arc = ToCircularArc();
                return arc.IsOn(pt) ?
                    arc.GetLength(arc.GetParameterOf(StartPoint), arc.GetParameterOf(pt)) /
                    arc.GetLength(arc.GetParameterOf(StartPoint), arc.GetParameterOf(EndPoint)) :
                    -1.0;
            }
        }

        public void Inverse()
        {
            Point2d tmpPoint = StartPoint;
            double tmpWidth = StartWidth;
            StartPoint = EndPoint;
            EndPoint = tmpPoint;
            Bulge = -Bulge;
            StartWidth = EndWidth;
            EndWidth = tmpWidth;
        }

        public LineSegment2d ToLineSegment()
        {
            return IsLinear ? new LineSegment2d(StartPoint, EndPoint) : null;
        }

        public CircularArc2d ToCircularArc()
        {
            return IsLinear ? null : new CircularArc2d(StartPoint, EndPoint, Bulge, false);
        }

        public Curve2d ToCurve2d()
        {
            return IsLinear ?
                (Curve2d)new LineSegment2d(StartPoint, EndPoint) :
                (Curve2d)new CircularArc2d(StartPoint, EndPoint, Bulge, false);
        }

        public override bool Equals(object obj)
        {
            PolylineSegment seg = obj as PolylineSegment;
            if (seg == null) return false;
            if (seg.GetHashCode() != GetHashCode()) return false;
            if (!StartPoint.IsEqualTo(seg.StartPoint)) return false;
            if (!EndPoint.IsEqualTo(seg.EndPoint)) return false;
            if (Bulge != seg.Bulge) return false;
            if (StartWidth != seg.StartWidth) return false;
            if (EndWidth != seg.EndWidth) return false;
            return true;
        }

        public override int GetHashCode() =>
            StartPoint.GetHashCode() ^
            EndPoint.GetHashCode() ^
            Bulge.GetHashCode() ^
            StartWidth.GetHashCode() ^
            EndWidth.GetHashCode();

        public override string ToString() =>
            $"{StartPoint}, {EndPoint}, {Bulge}, {StartWidth}, {EndWidth}";
    }
}

 

The PolylineSegmentCollection class: 

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

namespace Gile.AutoCAD.Geometry
{
    public class PolylineSegmentCollection : List<PolylineSegment>
    {
        public Point2d StartPoint => this[0].StartPoint;

        public Point2d EndPoint => this[Count - 1].EndPoint;

        public PolylineSegmentCollection() { }

        public PolylineSegmentCollection(IEnumerable<PolylineSegment> segments)
        {
            AddRange(segments);
        }

        public PolylineSegmentCollection(params PolylineSegment[] segments)
        {
            AddRange(segments);
        }

        public PolylineSegmentCollection(Polyline pline)
        {
            int n = pline.NumberOfVertices - 1;
            for (int i = 0; i < n; i++)
            {
                Add(new PolylineSegment(
                    pline.GetPoint2dAt(i),
                    pline.GetPoint2dAt(i + 1),
                    pline.GetBulgeAt(i),
                    pline.GetStartWidthAt(i),
                    pline.GetEndWidthAt(i)));
            }
            if (pline.Closed)
            {
                Add(new PolylineSegment(
                    pline.GetPoint2dAt(n),
                    pline.GetPoint2dAt(0),
                    pline.GetBulgeAt(n),
                    pline.GetStartWidthAt(n),
                    pline.GetEndWidthAt(n)));
            }
        }

        public PolylineSegmentCollection(Circle circle)
        {
            Plane plane = new Plane(Point3d.Origin, circle.Normal);
            Point2d cen = circle.Center.Convert2d(plane);
            Vector2d vec = new Vector2d(circle.Radius, 0.0);
            Add(new PolylineSegment(cen + vec, cen - vec, 1.0));
            Add(new PolylineSegment(cen - vec, cen + vec, 1.0));
        }

        public PolylineSegmentCollection(Ellipse ellipse)
        {
            // PolylineSegmentCollection figurant l'ellipse fermée
            double pi = Math.PI;
            Plane plane = new Plane(Point3d.Origin, ellipse.Normal);
            Point3d cen3d = ellipse.Center;
            Point3d pt3d0 = cen3d + ellipse.MajorAxis;
            Point3d pt3d4 = cen3d + ellipse.MinorAxis;
            Point3d pt3d2 = ellipse.GetPointAtParameter(pi / 4.0);
            Point2d cen = cen3d.Convert2d(plane);
            Point2d pt0 = pt3d0.Convert2d(plane);
            Point2d pt2 = pt3d2.Convert2d(plane);
            Point2d pt4 = pt3d4.Convert2d(plane);
            Line2d line01 = new Line2d(pt0, (pt4 - cen).GetNormal() + (pt2 - pt0).GetNormal());
            Line2d line21 = new Line2d(pt2, (pt0 - pt4).GetNormal() + (pt0 - pt2).GetNormal());
            Line2d line23 = new Line2d(pt2, (pt4 - pt0).GetNormal() + (pt4 - pt2).GetNormal());
            Line2d line43 = new Line2d(pt4, (pt0 - cen).GetNormal() + (pt2 - pt4).GetNormal());
            Line2d majAx = new Line2d(cen, pt0);
            Line2d minAx = new Line2d(cen, pt4);
            Point2d pt1 = line01.IntersectWith(line21)[0];
            Point2d pt3 = line23.IntersectWith(line43)[0];
            Point2d pt5 = pt3.TransformBy(Matrix2d.Mirroring(minAx));
            Point2d pt6 = pt2.TransformBy(Matrix2d.Mirroring(minAx));
            Point2d pt7 = pt1.TransformBy(Matrix2d.Mirroring(minAx));
            Point2d pt8 = pt0.TransformBy(Matrix2d.Mirroring(minAx));
            Point2d pt9 = pt7.TransformBy(Matrix2d.Mirroring(majAx));
            Point2d pt10 = pt6.TransformBy(Matrix2d.Mirroring(majAx));
            Point2d pt11 = pt5.TransformBy(Matrix2d.Mirroring(majAx));
            Point2d pt12 = pt4.TransformBy(Matrix2d.Mirroring(majAx));
            Point2d pt13 = pt3.TransformBy(Matrix2d.Mirroring(majAx));
            Point2d pt14 = pt2.TransformBy(Matrix2d.Mirroring(majAx));
            Point2d pt15 = pt1.TransformBy(Matrix2d.Mirroring(majAx));
            double bulge1 = Math.Tan((pt4 - cen).GetAngleTo(pt1 - pt0) / 2.0);
            double bulge2 = Math.Tan((pt1 - pt2).GetAngleTo(pt0 - pt4) / 2.0);
            double bulge3 = Math.Tan((pt4 - pt0).GetAngleTo(pt3 - pt2) / 2.0);
            double bulge4 = Math.Tan((pt3 - pt4).GetAngleTo(pt0 - cen) / 2.0);
            Add(new PolylineSegment(pt0, pt1, bulge1));
            Add(new PolylineSegment(pt1, pt2, bulge2));
            Add(new PolylineSegment(pt2, pt3, bulge3));
            Add(new PolylineSegment(pt3, pt4, bulge4));
            Add(new PolylineSegment(pt4, pt5, bulge4));
            Add(new PolylineSegment(pt5, pt6, bulge3));
            Add(new PolylineSegment(pt6, pt7, bulge2));
            Add(new PolylineSegment(pt7, pt8, bulge1));
            Add(new PolylineSegment(pt8, pt9, bulge1));
            Add(new PolylineSegment(pt9, pt10, bulge2));
            Add(new PolylineSegment(pt10, pt11, bulge3));
            Add(new PolylineSegment(pt11, pt12, bulge4));
            Add(new PolylineSegment(pt12, pt13, bulge4));
            Add(new PolylineSegment(pt13, pt14, bulge3));
            Add(new PolylineSegment(pt14, pt15, bulge2));
            Add(new PolylineSegment(pt15, pt0, bulge1));

            if (!ellipse.Closed)
            {
                double startParam, endParam;
                Point2d startPoint = ellipse.StartPoint.Convert2d(plane);
                Point2d endPoint = ellipse.EndPoint.Convert2d(plane);

                int startIndex = GetClosestSegmentIndexTo(startPoint);
                startPoint = this[startIndex].ToCurve2d().GetClosestPointTo(startPoint).Point;
                if (startPoint.IsEqualTo(this[startIndex].EndPoint))
                {
                    if (startIndex == 15)
                        startIndex = 0;
                    else
                        startIndex++;
                    startParam = 0.0;
                }
                else
                {
                    startParam = this[startIndex].GetParameterOf(startPoint);
                }

                int endIndex = GetClosestSegmentIndexTo(endPoint);
                endPoint = this[endIndex].ToCurve2d().GetClosestPointTo(endPoint).Point;
                if (endPoint.IsEqualTo(this[endIndex].StartPoint))
                {
                    if (endIndex == 0)
                        endIndex = 15;
                    else
                        endIndex--;
                    endParam = 1.0;
                }
                else
                {
                    endParam = this[endIndex].GetParameterOf(endPoint);
                }

                if (startParam != 0.0)
                {
                    this[startIndex].StartPoint = startPoint;
                    this[startIndex].Bulge = this[startIndex].Bulge * (1.0 - startParam);
                }

                if (endParam != 1.0) //(endParam != 0.0)
                {
                    this[endIndex].EndPoint = endPoint;
                    this[endIndex].Bulge = this[endIndex].Bulge * endParam;
                }

                if (startIndex == endIndex)
                {
                    PolylineSegment segment = this[startIndex];
                    Clear();
                    Add(segment);
                }

                else if (startIndex < endIndex)
                {
                    RemoveRange(endIndex + 1, 15 - endIndex);
                    RemoveRange(0, startIndex);
                }
                else
                {
                    AddRange(GetRange(0, endIndex + 1));
                    RemoveRange(0, startIndex);
                }
            }
        }

        public int GetClosestSegmentIndexTo(Point2d pt)
        {
            int result = 0;
            double dist = this[0].ToCurve2d().GetDistanceTo(pt);
            for (int i = 1; i < Count; i++)
            {
                double tmpDist = this[i].ToCurve2d().GetDistanceTo(pt);
                if (tmpDist < dist)
                {
                    result = i;
                    dist = tmpDist;
                }
            }
            return result;
        }

        public List<PolylineSegmentCollection> Join()
        {
            return Join(Tolerance.Global);
        }

        public List<PolylineSegmentCollection> Join(Tolerance tol)
        {
            List<PolylineSegmentCollection> result = new List<PolylineSegmentCollection>();
            PolylineSegmentCollection clone = new PolylineSegmentCollection(this);
            while (clone.Count > 0)
            {
                PolylineSegmentCollection newCol = new PolylineSegmentCollection();
                PolylineSegment seg = clone[0];
                newCol.Add(seg);
                Point2d start = seg.StartPoint;
                Point2d end = seg.EndPoint;
                clone.RemoveAt(0);
                while (true)
                {
                    int i = clone.FindIndex(s => s.StartPoint.IsEqualTo(end, tol));
                    if (i >= 0)
                    {
                        seg = clone[i];
                        newCol.Add(seg);
                        end = seg.EndPoint;
                        clone.RemoveAt(i);
                        continue;
                    }
                    i = clone.FindIndex(s => s.EndPoint.IsEqualTo(end, tol));
                    if (i >= 0)
                    {
                        seg = clone[i];
                        seg.Inverse();
                        newCol.Add(seg);
                        end = seg.EndPoint;
                        clone.RemoveAt(i);
                        continue;
                    }
                    i = clone.FindIndex(s => s.EndPoint.IsEqualTo(start, tol));
                    if (i >= 0)
                    {
                        seg = clone[i];
                        newCol.Insert(0, seg);
                        start = seg.StartPoint;
                        clone.RemoveAt(i);
                        continue;
                    }
                    i = clone.FindIndex(s => s.StartPoint.IsEqualTo(start, tol));
                    if (i >= 0)
                    {
                        seg = clone[i];
                        seg.Inverse();
                        newCol.Insert(0, seg);
                        start = seg.StartPoint;
                        clone.RemoveAt(i);
                        continue;
                    }
                    break;
                }
                result.Add(newCol);
            }
            return result;
        }

        public void Inverse()
        {
            for (int i = 0; i < Count; i++)
            {
                this[i].Inverse();
            }
            Reverse();
        }

        public Polyline ToPolyline()
        {
            Polyline pline = new Polyline();
            for (int i = 0; i < Count; i++)
            {
                PolylineSegment seg = this[i];
                pline.AddVertexAt(i, seg.StartPoint, seg.Bulge, seg.StartWidth, seg.EndWidth);
            }
            int j = Count;
            pline.AddVertexAt(j, this[j - 1].EndPoint, 0.0, this[j - 1].EndWidth, this[0].StartWidth);
            if (pline.GetPoint2dAt(0).IsEqualTo(pline.GetPoint2dAt(j)))
            {
                pline.RemoveVertexAt(j);
                pline.Closed = true;
            }
            return pline;
        }
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 3 of 3

ooe21832
Contributor
Contributor
Accepted solution
Hello Gile.

Sorry for my late reply.

Thank you for teaching me.
I wasn't used to programming myself, so it was very helpful.

You can learn a lot from Gile's code.

Also, I added it by referring to the code of Gile.
-The spline has become polyline 3D, and there were some parts that did not work, so I added it.
-If there were multiple regions when generating the region, it had to explode again, so I added it.

Put in the completed code.
I hope it helps others.

Gile Thank you very much.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

using Gile.AutoCAD.Geometry;

using AcAp = Autodesk.AutoCAD.ApplicationServices.Core.Application;

namespace Solid3dSectionsSample
{
    public class Commands
    {
        [CommandMethod("TEST")]
        public static void Test()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            // Prompt the user to select polylines and 3d solids
            //ポリラインと3Dソリッドを選択するようにユーザーに促します
            var filter = new SelectionFilter(new[] { new TypedValue(0, "LWPOLYLINE,3DSOLID") });
            var selection = ed.GetSelection(filter);
            if (selection.Status != PromptStatus.OK)
                return;

            using (var tr = db.TransactionManager.StartTransaction())
            {
                // Sort polylines and 3d solids 
                // (at this point the selection set only contains PolylineS and Solid3dS)

                var plines = new List<Polyline>();
                var solids = new List<Solid3d>();
                foreach (ObjectId id in selection.Value.GetObjectIds())
                {
                    ed.WriteMessage(Environment.NewLine + id.ToString() +"ID");

                    var entity = tr.GetObject(id, OpenMode.ForRead);

                    ed.WriteMessage(Environment.NewLine + entity.ToString() + "getobj");

                    if (entity is Polyline)
                        plines.Add((Polyline)entity);
                    else
                        solids.Add((Solid3d)entity);
                }

                var currentSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

                // For each polyline, loop for each 3d solid
                foreach (var pline in plines)
                {
                    double elevation = new Line3d(pline.StartPoint, pline.EndPoint).GetDistanceTo(Point3d.Origin);
                    foreach (var solid in solids)
                    {
                        // Get the solid section (Region)
                        if (TryGetSection(pline, solid, out Region region))
                        {

                            // Convert the region into polyline(s)
                            foreach (var pl in ConvertToPolylines(region))
                            {
                                currentSpace.AppendEntity(pl);
                                tr.AddNewlyCreatedDBObject(pl, true);
                            }
                            region.Dispose();
                            

                        }
                    }
                }
                tr.Commit();
            }
        }

        private static bool TryGetSection(Polyline pline, Solid3d solid, out Region region)
        {
            var plane = new Plane(pline.StartPoint + Vector3d.ZAxis, pline.StartPoint, pline.EndPoint);
            try
            {
                region = solid.GetSection(plane);
                return true;
            }
            catch
            {
                region = null;
                return false;
            }
        }

        
        private static List<Polyline> ConvertToPolylines(Region region)
        {
            
            var plane = new Plane(Point3d.Origin, region.Normal);
            var entitySets = new DBObjectCollection();
            var entitySet1 = new DBObjectCollection();
            var entitySet2 = new DBObjectCollection();
            region.Explode(entitySet1);

            if (entitySet1[0] is Region)
            {
                foreach( Region entityRegi in entitySet1 )
                {
                    entityRegi.Explode(entitySet2);
                    entitySets = entitySet2;
                }
            }
            else
            {
                entitySets = entitySet1;
            }


            double elevation = ((Curve)entitySets[0]).StartPoint.TransformBy(Matrix3d.WorldToPlane(plane)).Z;
            var segments = new PolylineSegmentCollection();
            foreach (Entity entity in entitySets)
            {
                switch (entity)
                {
                    case Arc arc:
                        segments.Add(new PolylineSegment(
                            new CircularArc2d(
                                arc.Center.Convert2d(plane),
                                arc.Radius,
                                arc.StartAngle,
                                arc.EndAngle,
                                Vector2d.XAxis,
                                false)));
                        break;
                    case Circle circle:
                        segments.AddRange(new PolylineSegmentCollection(circle));
                        break;
                    case Ellipse ellipse:
                        segments.AddRange(new PolylineSegmentCollection(ellipse));
                        break;
                    case Line line:
                        segments.Add(new PolylineSegment(
                            new LineSegment2d(
                                line.StartPoint.Convert2d(plane),
                                line.EndPoint.Convert2d(plane))));
                        break;
                    case Polyline pline:
                        segments.AddRange(new PolylineSegmentCollection(pline));
                        break;
                    case Spline spline:
                        Polyline3d polyline3d = spline.ToPolyline() as Polyline3d;

                        var Pl3d = new DBObjectCollection();
                        polyline3d.Explode(Pl3d);
                        foreach (Line sss in Pl3d)
                        {
                            segments.Add(new PolylineSegment(new LineSegment2d(sss.StartPoint.Convert2d(plane),sss.EndPoint.Convert2d(plane)))); 

                        }
                        break;
                         
                    default:
                        break;
                }
                entity.Dispose();
            }
            var plines = new List<Polyline>();
            foreach (PolylineSegmentCollection segs in segments.Join())
            {
                Polyline pline = segs.ToPolyline();
                pline.Elevation = elevation;
                pline.TransformBy(Matrix3d.PlaneToWorld(plane));
                plines.Add(pline);
            }
            return plines;
        }
    }
}


namespace Gile.AutoCAD.Geometry
{
    public class PolylineSegment
    {
        public Point2d StartPoint { get; set; }

        public Point2d EndPoint { get; set; }

        public double Bulge { get; set; }

        public double StartWidth { get; set; }

        public double EndWidth { get; set; }

        public bool IsLinear => Bulge == 0.0;

        public PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge = 0.0, double constantWidth = 0.0)
            : this(startPoint, endPoint, bulge, constantWidth, constantWidth)
        { }

        public PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge, double startWidth, double endWidth)
        {
            StartPoint = startPoint;
            EndPoint = endPoint;
            Bulge = bulge;
            StartWidth = startWidth;
            EndWidth = endWidth;
        }

        public PolylineSegment(LineSegment2d line)
        {
            StartPoint = line.StartPoint;
            EndPoint = line.EndPoint;
            Bulge = 0.0;
            StartWidth = 0.0;
            EndWidth = 0.0;
        }

        public PolylineSegment(CircularArc2d arc)
        {
            StartPoint = arc.StartPoint;
            EndPoint = arc.EndPoint;
            Bulge = Math.Tan((arc.EndAngle - arc.StartAngle) / 4.0);
            if (arc.IsClockWise) Bulge = -Bulge;
            StartWidth = 0.0;
            EndWidth = 0.0;
        }

        public PolylineSegment Clone()
        {
            return new PolylineSegment(StartPoint, EndPoint, Bulge, StartWidth, EndWidth);
        }

        public double GetParameterOf(Point2d pt)
        {
            if (IsLinear)
            {
                LineSegment2d line = ToLineSegment();
                return line.IsOn(pt) ? StartPoint.GetDistanceTo(pt) / line.Length : -1.0;
            }
            else
            {
                CircularArc2d arc = ToCircularArc();
                return arc.IsOn(pt) ?
                    arc.GetLength(arc.GetParameterOf(StartPoint), arc.GetParameterOf(pt)) /
                    arc.GetLength(arc.GetParameterOf(StartPoint), arc.GetParameterOf(EndPoint)) :
                    -1.0;
            }
        }

        public void Inverse()
        {
            Point2d tmpPoint = StartPoint;
            double tmpWidth = StartWidth;
            StartPoint = EndPoint;
            EndPoint = tmpPoint;
            Bulge = -Bulge;
            StartWidth = EndWidth;
            EndWidth = tmpWidth;
        }

        public LineSegment2d ToLineSegment()
        {
            return IsLinear ? new LineSegment2d(StartPoint, EndPoint) : null;
        }

        public CircularArc2d ToCircularArc()
        {
            return IsLinear ? null : new CircularArc2d(StartPoint, EndPoint, Bulge, false);
        }

        public Curve2d ToCurve2d()
        {
            return IsLinear ?
                (Curve2d)new LineSegment2d(StartPoint, EndPoint) :
                (Curve2d)new CircularArc2d(StartPoint, EndPoint, Bulge, false);
        }

        public override bool Equals(object obj)
        {
            PolylineSegment seg = obj as PolylineSegment;
            if (seg == null) return false;
            if (seg.GetHashCode() != GetHashCode()) return false;
            if (!StartPoint.IsEqualTo(seg.StartPoint)) return false;
            if (!EndPoint.IsEqualTo(seg.EndPoint)) return false;
            if (Bulge != seg.Bulge) return false;
            if (StartWidth != seg.StartWidth) return false;
            if (EndWidth != seg.EndWidth) return false;
            return true;
        }

        public override int GetHashCode() =>
            StartPoint.GetHashCode() ^
            EndPoint.GetHashCode() ^
            Bulge.GetHashCode() ^
            StartWidth.GetHashCode() ^
            EndWidth.GetHashCode();

        public override string ToString() =>
            $"{StartPoint}, {EndPoint}, {Bulge}, {StartWidth}, {EndWidth}";
    }
}

namespace Gile.AutoCAD.Geometry
{
    public class PolylineSegmentCollection : List<PolylineSegment>
    {
        public Point2d StartPoint => this[0].StartPoint;

        public Point2d EndPoint => this[Count - 1].EndPoint;

        public PolylineSegmentCollection() { }

        public PolylineSegmentCollection(IEnumerable<PolylineSegment> segments)
        {
            AddRange(segments);
        }

        public PolylineSegmentCollection(params PolylineSegment[] segments)
        {
            AddRange(segments);
        }

        public PolylineSegmentCollection(Polyline pline)
        {
            int n = pline.NumberOfVertices - 1;
            for (int i = 0; i < n; i++)
            {
                Add(new PolylineSegment(
                    pline.GetPoint2dAt(i),
                    pline.GetPoint2dAt(i + 1),
                    pline.GetBulgeAt(i),
                    pline.GetStartWidthAt(i),
                    pline.GetEndWidthAt(i)));
            }
            if (pline.Closed)
            {
                Add(new PolylineSegment(
                    pline.GetPoint2dAt(n),
                    pline.GetPoint2dAt(0),
                    pline.GetBulgeAt(n),
                    pline.GetStartWidthAt(n),
                    pline.GetEndWidthAt(n)));
            }
        }

        public PolylineSegmentCollection(Circle circle)
        {
            Plane plane = new Plane(Point3d.Origin, circle.Normal);
            Point2d cen = circle.Center.Convert2d(plane);
            Vector2d vec = new Vector2d(circle.Radius, 0.0);
            Add(new PolylineSegment(cen + vec, cen - vec, 1.0));
            Add(new PolylineSegment(cen - vec, cen + vec, 1.0));
        }

        public PolylineSegmentCollection(Ellipse ellipse)
        {
            // PolylineSegmentCollection figurant l'ellipse fermée
            double pi = Math.PI;
            Plane plane = new Plane(Point3d.Origin, ellipse.Normal);
            Point3d cen3d = ellipse.Center;
            Point3d pt3d0 = cen3d + ellipse.MajorAxis;
            Point3d pt3d4 = cen3d + ellipse.MinorAxis;
            Point3d pt3d2 = ellipse.GetPointAtParameter(pi / 4.0);
            Point2d cen = cen3d.Convert2d(plane);
            Point2d pt0 = pt3d0.Convert2d(plane);
            Point2d pt2 = pt3d2.Convert2d(plane);
            Point2d pt4 = pt3d4.Convert2d(plane);
            Line2d line01 = new Line2d(pt0, (pt4 - cen).GetNormal() + (pt2 - pt0).GetNormal());
            Line2d line21 = new Line2d(pt2, (pt0 - pt4).GetNormal() + (pt0 - pt2).GetNormal());
            Line2d line23 = new Line2d(pt2, (pt4 - pt0).GetNormal() + (pt4 - pt2).GetNormal());
            Line2d line43 = new Line2d(pt4, (pt0 - cen).GetNormal() + (pt2 - pt4).GetNormal());
            Line2d majAx = new Line2d(cen, pt0);
            Line2d minAx = new Line2d(cen, pt4);
            Point2d pt1 = line01.IntersectWith(line21)[0];
            Point2d pt3 = line23.IntersectWith(line43)[0];
            Point2d pt5 = pt3.TransformBy(Matrix2d.Mirroring(minAx));
            Point2d pt6 = pt2.TransformBy(Matrix2d.Mirroring(minAx));
            Point2d pt7 = pt1.TransformBy(Matrix2d.Mirroring(minAx));
            Point2d pt8 = pt0.TransformBy(Matrix2d.Mirroring(minAx));
            Point2d pt9 = pt7.TransformBy(Matrix2d.Mirroring(majAx));
            Point2d pt10 = pt6.TransformBy(Matrix2d.Mirroring(majAx));
            Point2d pt11 = pt5.TransformBy(Matrix2d.Mirroring(majAx));
            Point2d pt12 = pt4.TransformBy(Matrix2d.Mirroring(majAx));
            Point2d pt13 = pt3.TransformBy(Matrix2d.Mirroring(majAx));
            Point2d pt14 = pt2.TransformBy(Matrix2d.Mirroring(majAx));
            Point2d pt15 = pt1.TransformBy(Matrix2d.Mirroring(majAx));
            double bulge1 = Math.Tan((pt4 - cen).GetAngleTo(pt1 - pt0) / 2.0);
            double bulge2 = Math.Tan((pt1 - pt2).GetAngleTo(pt0 - pt4) / 2.0);
            double bulge3 = Math.Tan((pt4 - pt0).GetAngleTo(pt3 - pt2) / 2.0);
            double bulge4 = Math.Tan((pt3 - pt4).GetAngleTo(pt0 - cen) / 2.0);
            Add(new PolylineSegment(pt0, pt1, bulge1));
            Add(new PolylineSegment(pt1, pt2, bulge2));
            Add(new PolylineSegment(pt2, pt3, bulge3));
            Add(new PolylineSegment(pt3, pt4, bulge4));
            Add(new PolylineSegment(pt4, pt5, bulge4));
            Add(new PolylineSegment(pt5, pt6, bulge3));
            Add(new PolylineSegment(pt6, pt7, bulge2));
            Add(new PolylineSegment(pt7, pt8, bulge1));
            Add(new PolylineSegment(pt8, pt9, bulge1));
            Add(new PolylineSegment(pt9, pt10, bulge2));
            Add(new PolylineSegment(pt10, pt11, bulge3));
            Add(new PolylineSegment(pt11, pt12, bulge4));
            Add(new PolylineSegment(pt12, pt13, bulge4));
            Add(new PolylineSegment(pt13, pt14, bulge3));
            Add(new PolylineSegment(pt14, pt15, bulge2));
            Add(new PolylineSegment(pt15, pt0, bulge1));

            if (!ellipse.Closed)
            {
                double startParam, endParam;
                Point2d startPoint = ellipse.StartPoint.Convert2d(plane);
                Point2d endPoint = ellipse.EndPoint.Convert2d(plane);

                int startIndex = GetClosestSegmentIndexTo(startPoint);
                startPoint = this[startIndex].ToCurve2d().GetClosestPointTo(startPoint).Point;
                if (startPoint.IsEqualTo(this[startIndex].EndPoint))
                {
                    if (startIndex == 15)
                        startIndex = 0;
                    else
                        startIndex++;
                    startParam = 0.0;
                }
                else
                {
                    startParam = this[startIndex].GetParameterOf(startPoint);
                }

                int endIndex = GetClosestSegmentIndexTo(endPoint);
                endPoint = this[endIndex].ToCurve2d().GetClosestPointTo(endPoint).Point;
                if (endPoint.IsEqualTo(this[endIndex].StartPoint))
                {
                    if (endIndex == 0)
                        endIndex = 15;
                    else
                        endIndex--;
                    endParam = 1.0;
                }
                else
                {
                    endParam = this[endIndex].GetParameterOf(endPoint);
                }

                if (startParam != 0.0)
                {
                    this[startIndex].StartPoint = startPoint;
                    this[startIndex].Bulge = this[startIndex].Bulge * (1.0 - startParam);
                }

                if (endParam != 1.0) //(endParam != 0.0)
                {
                    this[endIndex].EndPoint = endPoint;
                    this[endIndex].Bulge = this[endIndex].Bulge * endParam;
                }

                if (startIndex == endIndex)
                {
                    PolylineSegment segment = this[startIndex];
                    Clear();
                    Add(segment);
                }

                else if (startIndex < endIndex)
                {
                    RemoveRange(endIndex + 1, 15 - endIndex);
                    RemoveRange(0, startIndex);
                }
                else
                {
                    AddRange(GetRange(0, endIndex + 1));
                    RemoveRange(0, startIndex);
                }
            }
        }

        public int GetClosestSegmentIndexTo(Point2d pt)
        {
            int result = 0;
            double dist = this[0].ToCurve2d().GetDistanceTo(pt);
            for (int i = 1; i < Count; i++)
            {
                double tmpDist = this[i].ToCurve2d().GetDistanceTo(pt);
                if (tmpDist < dist)
                {
                    result = i;
                    dist = tmpDist;
                }
            }
            return result;
        }

        public List<PolylineSegmentCollection> Join()
        {
            return Join(Tolerance.Global);
        }

        public List<PolylineSegmentCollection> Join(Tolerance tol)
        {
            List<PolylineSegmentCollection> result = new List<PolylineSegmentCollection>();
            PolylineSegmentCollection clone = new PolylineSegmentCollection(this);
            while (clone.Count > 0)
            {
                PolylineSegmentCollection newCol = new PolylineSegmentCollection();
                PolylineSegment seg = clone[0];
                newCol.Add(seg);
                Point2d start = seg.StartPoint;
                Point2d end = seg.EndPoint;
                clone.RemoveAt(0);
                while (true)
                {
                    int i = clone.FindIndex(s => s.StartPoint.IsEqualTo(end, tol));
                    if (i >= 0)
                    {
                        seg = clone[i];
                        newCol.Add(seg);
                        end = seg.EndPoint;
                        clone.RemoveAt(i);
                        continue;
                    }
                    i = clone.FindIndex(s => s.EndPoint.IsEqualTo(end, tol));
                    if (i >= 0)
                    {
                        seg = clone[i];
                        seg.Inverse();
                        newCol.Add(seg);
                        end = seg.EndPoint;
                        clone.RemoveAt(i);
                        continue;
                    }
                    i = clone.FindIndex(s => s.EndPoint.IsEqualTo(start, tol));
                    if (i >= 0)
                    {
                        seg = clone[i];
                        newCol.Insert(0, seg);
                        start = seg.StartPoint;
                        clone.RemoveAt(i);
                        continue;
                    }
                    i = clone.FindIndex(s => s.StartPoint.IsEqualTo(start, tol));
                    if (i >= 0)
                    {
                        seg = clone[i];
                        seg.Inverse();
                        newCol.Insert(0, seg);
                        start = seg.StartPoint;
                        clone.RemoveAt(i);
                        continue;
                    }
                    break;
                }
                result.Add(newCol);
            }
            return result;
        }

        public void Inverse()
        {
            for (int i = 0; i < Count; i++)
            {
                this[i].Inverse();
            }
            Reverse();
        }

        public Polyline ToPolyline()
        {
            Polyline pline = new Polyline();
            for (int i = 0; i < Count; i++)
            {
                PolylineSegment seg = this[i];
                pline.AddVertexAt(i, seg.StartPoint, seg.Bulge, seg.StartWidth, seg.EndWidth);
            }
            int j = Count;
            pline.AddVertexAt(j, this[j - 1].EndPoint, 0.0, this[j - 1].EndWidth, this[0].StartWidth);
            if (pline.GetPoint2dAt(0).IsEqualTo(pline.GetPoint2dAt(j)))
            {
                pline.RemoveVertexAt(j);
                pline.Closed = true;
            }
            return pline;
        }
    }
}

 

0 Likes