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". 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();
}
}
}
}