How to copy a part of curve Polyline by two point in C#

How to copy a part of curve Polyline by two point in C#

quangpt.tric
Advocate Advocate
3,765 Views
13 Replies
Message 1 of 14

How to copy a part of curve Polyline by two point in C#

quangpt.tric
Advocate
Advocate

Hello everybody,

I have a problem that I want to select a Polyline and it has some arc, then I pick two point in this polyline. The result I want is make a part of polyline I've selected, and the startpoint and endpoint is two point I just pick.

You can see image below to know what exactly I want.

Please help me to solved this issue.

Thank you verymuch!Capture.PNG

0 Likes
Accepted solutions (2)
3,766 Views
13 Replies
Replies (13)
Message 2 of 14

norman.yuan
Mentor
Mentor
Accepted solution

Once you have 2 points on the polyline known (say, picked by user), you can call Curve[Polyline].GetSplitCurves(Point3dCollection) to return a DBObjectCollection that would contain 3 non-database-residing entities, and the second one would be what you want. You can add it to database/transaction, and dispose the other 2.

Norman Yuan

Drive CAD With Code

EESignature

Message 3 of 14

quangpt.tric
Advocate
Advocate

thank you for support me, @norman.yuan . Can you give some sample code to make it easier?

0 Likes
Message 4 of 14

quangpt.tric
Advocate
Advocate

Hi @norman.yuan , after coding, now I can solved my issue by your support.

Again, thank you very very much!

0 Likes
Message 5 of 14

norman.yuan
Mentor
Mentor
Accepted solution

@quangpt.tric , after seeing your second post, asking some sample code, I did write a bit of test code. While later you said you solved the issue, I thought I could just polish the test code a bit more to make it as a user-friendly command code sample and publish it in my blog so the code may benefit others. Here is it:

 

https://drive-cad-with-code.blogspot.com/2020/11/a-user-friendly-command-to-copy-part-of.html 

 

 

Norman Yuan

Drive CAD With Code

EESignature

Message 6 of 14

quangpt.tric
Advocate
Advocate

your code is amazing @norman.yuan , I always visit your blog to study coding of autocad,

thank you so much again, my Teacher!

0 Likes
Message 7 of 14

Kélcyo
Advocate
Advocate

I compiled your available code, but I'm getting an error in version 2021

0 Likes
Message 8 of 14

norman.yuan
Mentor
Mentor

You may want to provide more details on the error. Also did you step through the code to see which line of the code raises the error? If you did, you might have already known the reason and possibly the fix of it. I believe that whatever the error is, it is unlikely Acad2020 versus 2021 would be the cause of it for such a simple project.

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 9 of 14

Kélcyo
Advocate
Advocate

Yes, I went through the code, but I don't see a simple solution. When exiting the Finaly loop (shown in the image), simply go to Catch with the message indication "ex.Message =" Object reference not set to an instance of an object. ""

erroPoly.pngerroPoly2.png

0 Likes
Message 10 of 14

Kélcyo
Advocate
Advocate

Any suggestion

0 Likes
Message 11 of 14

Gepaha
Collaborator
Collaborator

I think that the variable_ghostPolyline is null in the statement:

e.AppendToolTipText($"Selected polyline length = {_ghostPolyline.Length}");

This causes the null reference exception. Try to move the above statement into the if:

if (ghost != null)
{
   ...
   e.AppendToolTipText($"Selected polyline length = {_ghostPolyline.Length}");
}

In private void Editor_PointMonitor(object sender, PointMonitorEventArgs e) change:

 

 if (ghost != null)
 {
    _ghostPolyline = ghost;
    _ghostPolyline.ColorIndex = 1;
    _tsManager.AddTransient(_ghostPolyline, TransientDrawingMode.DirectTopmost, 128, new IntegerCollection());
 }
 e.AppendToolTipText($"Selected polyline length = {_ghostPolyline.Length}";   

 

 to:

 

 if (ghost != null)
 {
    _ghostPolyline = ghost;
    _ghostPolyline.ColorIndex = 1;
    _tsManager.AddTransient(_ghostPolyline, TransientDrawingMode.DirectTopmost, 128, new IntegerCollection());
    e.AppendToolTipText($"Selected polyline length = {_ghostPolyline.Length}");
}    

 

I hope it helps!

0 Likes
Message 12 of 14

Kélcyo
Advocate
Advocate

Thanks @Gepaha , this solved the problem in part. The code works perfectly when I'm in WCS, if I'm working on a custom UCS, it automatically assumes that my PickedPoint is the final vertex of the polyline and when selecting the second point, it doesn't add the new polyline.

0 Likes
Message 13 of 14

Gepaha
Collaborator
Collaborator

I have no time to test this for now.

Points obtained through Editor.GetPoint are always in UCS.

If the picked point has to participate into some geometry creation or calculation, it has to be transformed from its UCS to WCS since all AutoCAD geometry information is stored in WCS.

Look at the example below:

 

Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
PromptPointResult ppr = ed.GetPoint("\nSpecify base point: ");
if (ppr.Status != PromptStatus.OK) return;
// point in UCS
Point3d ucsPt = ppr.Value;
// point in WCS
Point3d wcsPt = ucsPt.TransformBy(ed.CurrentUserCoordinateSystem);

 

Try:

 

 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);
                    // from UCS to WCS
                    pickPoint = poly.GetClosestPointTo(res.PickedPoint.TransformBy(_ed.CurrentUserCoordinateSystem), 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);
                        // from UCS to WCS
                        nextPoint = poly.GetClosestPointTo(res.Value.TransformBy(_ed.CurrentUserCoordinateSystem), 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);  
                                // from UCS to WCS 
                                _firstPoint = poly.GetClosestPointTo(rs.Value.TransformBy(_ed.CurrentUserCoordinateSystem), 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;
        }

 

If I haven't forgotten something I think it should work.

0 Likes
Message 14 of 14

Kélcyo
Advocate
Advocate

Excellent..working perfect..thanks

0 Likes