TheSwamp

Code Red => .NET => Topic started by: kelcyo on April 16, 2021, 05:14:41 AM

Title: Copy Part of Polyline
Post by: kelcyo on April 16, 2021, 05:14:41 AM
Someone would have a solution similar to the Norman Yuan code "https://drive-cad-with-code.blogspot.com/2020/11/a-user-friendly-command-to-copy-part-of.html (https://drive-cad-with-code.blogspot.com/2020/11/a-user-friendly-command-to-copy-part-of.html)". He made the code available, however when compiling I am encountering an error that I cannot solve.


using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using CadDb = Autodesk.AutoCAD.DatabaseServices;
 
namespace GetPartialPolyline
{
    public class PartialPolylineSelector
    {
        private readonly Document _dwg;
        private readonly Editor _ed;
 
        private Point3d _firstPoint;
        private ObjectId _polylineId = ObjectId.Null;
 
        private TransientManager _tsManager =
            TransientManager.CurrentTransientManager;
        private CadDb.Polyline _ghostPolyline = null;
 
        public PartialPolylineSelector(Document dwg)
        {
            _dwg = dwg;
            _ed = dwg.Editor;
        }
 
        public CadDb.Polyline SelectPartialPolyline()
        {
            var polyId = SelectPolyline(out Point3d pickPt1);
            if (polyId.IsNull)
            {
                _ed.WriteMessage("\n*Cancel*");
                return null;
            }
 
            if (!SelectTwoPointsOnPolyline(
                polyId, pickPt1,
                out Point3d startPt, out Point3d endPt))
            {
                _ed.WriteMessage("\n*Cancel*");
                return null;
            }
 
            var poly = GeneratePartialPolyline(polyId, startPt, endPt);
            return poly;
        }
 
        #region private methods
 
        private ObjectId SelectPolyline(out Point3d pickPoint)
        {
            pickPoint = Point3d.Origin;
            var opt = new PromptEntityOptions(
                "\nSelect a polyline:");
            opt.SetRejectMessage("\nInvalid: not a polyline!");
            opt.AddAllowedClass(typeof(CadDb.Polyline), true);
 
            var res = _ed.GetEntity(opt);
            if (res.Status == PromptStatus.OK)
            {
                using (var tran =
                    res.ObjectId.Database.TransactionManager.StartTransaction())
                {
                    var poly = (CadDb.Polyline)tran.GetObject(
                        res.ObjectId, OpenMode.ForRead);
                    //make sure the output point is on the polyline
                    pickPoint = poly.GetClosestPointTo(res.PickedPoint, false);
                    tran.Commit();
                }
 
                return res.ObjectId;
            }
            else
            {
                return ObjectId.Null;
            }
        }
 
        private bool SelectTwoPointsOnPolyline(
            ObjectId polyId, Point3d prevPoint,
            out Point3d startPt, out Point3d endPt)
        {
            startPt = Point3d.Origin;
            endPt = Point3d.Origin;
 
            _firstPoint = prevPoint;
            var nextPoint = Point3d.Origin;
            _polylineId = polyId;
 
            bool ok = false;
            using (var tran = _dwg.TransactionManager.StartTransaction())
            {
                var poly = (CadDb.Polyline)tran.GetObject(polyId, OpenMode.ForRead);
 
                while (true)
                {
                    ClearGhostPolyline();
                    var opt = new PromptPointOptions(
                        "\nSelect second point on the polyline:")
                    {
                        AppendKeywordsToMessage = true,
                        AllowNone = true
                    };
                    opt.Keywords.Add("First point");
                    opt.Keywords.Default = "First point";
 
                    PromptPointResult res;
                    try
                    {
                        // when selecting another point on polyline
                        // show the part of polyline to be cloned
                        // as Transient Graphics
                        _ed.PointMonitor += Editor_PointMonitor;
 
                        res = _ed.GetPoint(opt);
                    }
                    finally
                    {
                        _ed.PointMonitor -= Editor_PointMonitor;
                        ClearGhostPolyline();
                    }
 
                    if (res.Status == PromptStatus.OK)
                    {
                        nextPoint = poly.GetClosestPointTo(res.Value, false);
                        ok = true;
                        break;
                    }
                    else if (res.Status == PromptStatus.Keyword)
                    {
                        // re-select the first point on polyline
                        var cancel = false;
                        while (true)
                        {
                            var op = new PromptPointOptions(
                                "\nSelect first point on polyline:");
                            var rs = _ed.GetPoint(op);
                            if (rs.Status == PromptStatus.OK)
                            {
                                _firstPoint = poly.GetClosestPointTo(rs.Value, false);
                                break;
                            }
                            else
                            {
                                cancel = true;
                                break;
                            }
                        }
 
                        if (cancel)
                        {
                            ok = false;
                            break;
                        }
                    }
                    else
                    {
                        ok = false;
                        break;
                    }
                }
 
                if (ok)
                {
                    SortPickedPoints(
                        poly, _firstPoint, nextPoint, out startPt, out endPt);
                }
 
                tran.Commit();
            }
 
            return ok;
        }
 
        private void SortPickedPoints(
            CadDb.Polyline poly, Point3d picked1, Point3d picked2,
            out Point3d startPt, out Point3d endPt)
        {
            var dist1 = poly.GetDistAtPoint(picked1);
            var dist2 = poly.GetDistAtPoint(picked2);
            if (dist1 < dist2)
            {
                startPt = picked1;
                endPt = picked2;
            }
            else
            {
                startPt = picked2;
                endPt = picked1;
            }
        }
 
        private CadDb.Polyline GeneratePartialPolyline(
            ObjectId polylineId, Point3d startPt, Point3d endPt)
        {
            CadDb.Polyline poly = null;
            using (var tran = _dwg.TransactionManager.StartTransaction())
            {
                var pline = (CadDb.Polyline)tran.GetObject(polylineId, OpenMode.ForRead);
 
                Point3dCollection points = new Point3dCollection();
                if (startPt.IsEqualTo(pline.StartPoint) &&
                    endPt.IsEqualTo(pline.EndPoint))
                {
                    poly = pline.Clone() as CadDb.Polyline;
                }
                else
                {
                    if (startPt.IsEqualTo(pline.StartPoint))
                    {
                        points.Add(endPt);
 
                        var dbObjects = pline.GetSplitCurves(points);
                        if (dbObjects.Count == 2)
                        {
                            poly = dbObjects[0] as CadDb.Polyline;
                            dbObjects[1].Dispose();
                        }
                        else
                        {
                            foreach (DBObject obj in dbObjects)
                            {
                                obj.Dispose();
                            }
                        }
                    }
                    else if (endPt.IsEqualTo(pline.EndPoint))
                    {
                        points.Add(startPt);
 
                        var dbObjects = pline.GetSplitCurves(points);
                        if (dbObjects.Count == 2)
                        {
                            poly = dbObjects[1] as CadDb.Polyline;
                            dbObjects[0].Dispose();
                        }
                        else
                        {
                            foreach (DBObject obj in dbObjects)
                            {
                                obj.Dispose();
                            }
                        }
                    }
                    else
                    {
                        points.Add(startPt);
                        points.Add(endPt);
 
                        var dbObjects = pline.GetSplitCurves(points);
                        if (dbObjects.Count == 3)
                        {
                            poly = dbObjects[1] as CadDb.Polyline;
                            dbObjects[0].Dispose();
                            dbObjects[2].Dispose();
                        }
                        else
                        {
                            foreach (DBObject obj in dbObjects)
                            {
                                obj.Dispose();
                            }
                        }
                    }
                }
 
                tran.Commit();
            }
 
            return poly;
        }
 
        private void Editor_PointMonitor(object sender, PointMonitorEventArgs e)
        {
            ClearGhostPolyline();
 
            var poly = _polylineId.GetObject(OpenMode.ForRead) as CadDb.Polyline;
            var nextPoint = poly.GetClosestPointTo(e.Context.RawPoint, false);
            var dist = nextPoint.DistanceTo(e.Context.RawPoint);
            if (dist<poly.Length/10.0)
            {
                SortPickedPoints(
                    poly, _firstPoint, nextPoint,
                    out Point3d startPt, out Point3d endPt);
                var ghost = GeneratePartialPolyline(_polylineId, startPt, endPt);
                if (ghost!=null)
                {
                    _ghostPolyline = ghost;
                    _ghostPolyline.ColorIndex = 1;
                    _tsManager.AddTransient(
                        _ghostPolyline,
                        TransientDrawingMode.DirectTopmost,
                        128,
                        new IntegerCollection());
                }
 
                e.AppendToolTipText(
                    $"Selected polyline length = {_ghostPolyline.Length}");
            }
        }
 
        private void ClearGhostPolyline()
        {
            if (_ghostPolyline!=null)
            {
                _tsManager.EraseTransient(
                    _ghostPolyline, new IntegerCollection());
                _ghostPolyline.Dispose();
            }
        }
 
        #endregion
    }
}


This the CommandClass to run the process:

using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;
 
[assembly: CommandClass(typeof(GetPartialPolyline.MyCommands))]
 
namespace GetPartialPolyline
{
    public class MyCommands
    {
        [CommandMethod("PartialPoly")]
        public static void CreatePartialPolyline()
        {
            var dwg = CadApp.DocumentManager.MdiActiveDocument;
            var ed = dwg.Editor;
 
            try
            {
                var selector = new PartialPolylineSelector(dwg);
                var poly = selector.SelectPartialPolyline();
                if (poly!=null)
                {
                    poly.ColorIndex = 2;
                    AddPolylineToDb(dwg.Database, poly);
                }
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage($"\nExecution error:\n{ex.Message}\n");
            }
        }
 
        private static void AddPolylineToDb(Database db, Polyline poly)
        {
            using (var tran = db.TransactionManager.StartTransaction())
            {
                var space = (BlockTableRecord)tran.GetObject(
                    db.CurrentSpaceId, OpenMode.ForWrite);
                space.AppendEntity(poly);
                tran.AddNewlyCreatedDBObject(poly, true);
                tran.Commit();
            }
 
        }
    }
}
Title: Re: Copy Part of Polyline
Post by: jtoverka on April 22, 2021, 07:34:56 AM
It compiled fine on my machine...
The only change I made was this:

Code: [Select]
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;

to

Code: [Select]
using CadApp = Autodesk.AutoCAD.ApplicationServices.Core.Application;

I am referencing the accoremgd and acdbmgd dll files.
What are your compilation errors?