TheSwamp

Code Red => .NET => Topic started by: huiz on December 13, 2011, 07:40:57 AM

Title: Create arc through 3 points
Post by: huiz on December 13, 2011, 07:40:57 AM
In AutoCAD it is easy to create an arc through 3 points. With .NET it is not that simple because an arc is build with radius and angles. Searching for some examples people point towards the function CircularArc3d but there is no real example how to create the arc. I have the following code:

Code: [Select]
  Dim myConstructionArc As CircularArc3d = New CircularArc3d(myColl3D(0), myColl3D(1), myColl3D(2))
  Dim myArc As Arc = New Arc(myConstructionArc.Center, myConstructionArc.Radius, myConstructionArc.StartAngle, myConstructionArc.EndAngle)

  btr.AppendEntity(myArc)
  tr.AddNewlyCreatedDBObject(myArc, True)

I have a point3d collection which I use for creating a CircularArc3d. Then I use the properties of this thing to create an arc. But I always get a start angle of zero from the CircularArc3d. Center and Radius are correct but the angles are not. So I do get an arc, it is actually placed on the circumscribed circle, but the start point and endpoint are not correct because of the incorrect StartAngle and EndAngle.

Does anybody have more experience with this subject?
Title: Re: Create arc through 3 points
Post by: kaefer on December 13, 2011, 08:00:00 AM
But I always get a start angle of zero from the CircularArc3d.

Not me, but I snatched a code snippet from here (http://bbs.mjtd.com/thread-77565-1-1.html).

Code: [Select]
            double angle =
                ca3d.ReferenceVector.AngleOnPlane(
                    new Plane(
                        ca3d.Center,
                        ca3d.Normal));
            return
                new Arc(
                    ca3d.Center,
                    ca3d.Normal,
                    ca3d.Radius,
                    ca3d.StartAngle + angle,
                    ca3d.EndAngle + angle);
Title: Re: Create arc through 3 points
Post by: huiz on December 13, 2011, 09:48:49 AM
Kaefer, thank you very much! That was the missing part! :-)

Title: Re: Create arc through 3 points
Post by: gile on December 13, 2011, 09:57:59 AM
Hi

A little sample I wrote while I was learning about Jigs. It mimics tha AutoCAD command Arc option 3 points.
Look at the Update method.

Code: [Select]
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace Arc3Points
{
    public class ArcJigSample
    {
        Database db = HostApplicationServices.WorkingDatabase;
        Editor ed = acadApp.DocumentManager.MdiActiveDocument.Editor;
        private const double pi = 3.141592653589793;

        class ArcJig : EntityJig
        {
            Arc _arc;
            Point3d _dragPoint;
            Point3d _firstPoint;
            Point3d _secondPoint;

            public ArcJig(Arc arc, Point3d dragPoint, Point3d firstPoint, Point3d secondPoint)
                : base(arc)
            {
                _arc = arc;
                _dragPoint = dragPoint;
                _firstPoint = firstPoint;
                _secondPoint = secondPoint;
            }

            protected override SamplerStatus Sampler(JigPrompts prompts)
            {
                JigPromptPointOptions jppo = new JigPromptPointOptions("\nSpecify the third point: ");
                jppo.UserInputControls = (UserInputControls.Accept3dCoordinates);
                PromptPointResult ppr = prompts.AcquirePoint(jppo);
                if (ppr.Status == PromptStatus.OK)
                {
                    if (ppr.Value.IsEqualTo(_dragPoint))
                        return SamplerStatus.NoChange;
                    else
                    {
                        _dragPoint = ppr.Value;
                        return SamplerStatus.OK;
                    }
                }
                return SamplerStatus.Cancel;
            }

            protected override bool Update()
            {
                CircularArc3d cArc = new CircularArc3d(_firstPoint, _secondPoint, _dragPoint);
                Point3d cen = cArc.Center;
                _arc.Center = cen;
                _arc.Radius = cArc.Radius;
                Vector3d vec1 = _firstPoint.GetVectorTo(_secondPoint);
                Vector3d vec2 = _secondPoint.GetVectorTo(_dragPoint);
                Vector3d norm = cArc.Normal;
                _arc.Normal = norm;
                Vector3d vecX = Vector3d.XAxis.TransformBy(Matrix3d.PlaneToWorld(norm));
                double angToFirst = vecX.GetAngleTo(cen.GetVectorTo(_firstPoint), norm);
                double angToDrag = vecX.GetAngleTo(cen.GetVectorTo(_dragPoint), norm);
                if (vec1.GetAngleTo(vec2, norm) > pi)
                {
                    _arc.StartAngle = angToDrag;
                    _arc.EndAngle = angToFirst;
                }
                else
                {
                    _arc.StartAngle = angToFirst;
                    _arc.EndAngle = angToDrag;
                }
                return true;
            }
        }

        [CommandMethod("A3P")]
        public void DrawArc()
        {
            Point3d pt1;
            Point3d pt2;
            PromptPointOptions ppo = new PromptPointOptions("\nSpecifiy the first point: ");
            ppo.AllowNone = false;
            PromptPointResult ppr = ed.GetPoint(ppo);
            if (ppr.Status == PromptStatus.OK)
            {
                pt1 = ppr.Value;
                ppo.Message = "\nSpecify the second point: ";
                ppo.AllowNone = false;
                ppo.BasePoint = pt1;
                ppo.UseBasePoint = true;
                ppr = ed.GetPoint(ppo);
                if (ppr.Status != PromptStatus.OK) return;
                try
                {
                    Matrix3d curUCS = ed.CurrentUserCoordinateSystem;
                    pt2 = ppr.Value;
                    pt1 = pt1.TransformBy(curUCS);
                    pt2 = pt2.TransformBy(curUCS);
                    Vector3d vec = pt1.GetVectorTo(pt2) / 2;
                    using (Arc ghost = new Arc(pt1 + vec, vec.Length, 0.0, pi))
                    {
                        ArcJig jig = new ArcJig(ghost, pt2, pt1, pt2);
                        PromptResult res = ed.Drag(jig);
                        if (res.Status != PromptStatus.OK) return;
                        using (Transaction tr = db.TransactionManager.StartTransaction())
                        {
                            BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                            BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                            btr.AppendEntity(ghost);
                            tr.AddNewlyCreatedDBObject(ghost, true);
                            tr.Commit();
                        }
                    }
                }
                catch (System.Exception ex)
                {
                    ed.WriteMessage("\nError: " + ex.Message);
                }
            }
        }
    }
}
Title: Re: Create arc through 3 points
Post by: MP on December 13, 2011, 11:04:18 AM
Thanks for sharing such a clean example Gile.
Title: Re: Create arc through 3 points
Post by: gile on December 13, 2011, 01:30:13 PM
Thanks Michael.

It may be cleaner using CircularArc3d.ReferenceVector.AngleOnPlane as shown by kaefer (thanks again Thorsten).

The 'updated' Update method

Code: [Select]
            protected override bool Update()
            {
                CircularArc3d cArc =
                    _firstPoint.GetVectorTo(_secondPoint).CrossProduct(_secondPoint.GetVectorTo(_dragPoint)).Z < 0.0 ?
                    new CircularArc3d(_dragPoint, _secondPoint, _firstPoint) : // if points are clockwise
                    new CircularArc3d(_firstPoint, _secondPoint, _dragPoint); // if points are counterclockwise
                Point3d cen = cArc.Center;
                Vector3d norm = cArc.Normal;
                _arc.Center = cen;
                _arc.Radius = cArc.Radius;
                _arc.Normal = norm;
                double angle = cArc.ReferenceVector.AngleOnPlane(new Plane(cArc.Center, norm));
                _arc.StartAngle = cArc.StartAngle + angle;
                _arc.EndAngle = cArc.EndAngle + angle;
                return true;
            }
Title: Re: Create arc through 3 points
Post by: huiz on December 13, 2011, 01:58:20 PM
Well, after testing the code by Kaefer it seems to not work, accidentially I had a few arcs that were right, later I got wrong arcs.

Testing the part with the update code by Gile seems to work, after tens of arcs they still are correct, no matter if it is drawn clockwise or counter clockwise.

I miss the thought about being better to use  CircularArc3d.ReferenceVector.AngleOnPlane. Just shorter code?
Title: Re: Create arc through 3 points
Post by: gile on December 13, 2011, 02:23:49 PM
Quote
I miss the thought about being better to use  CircularArc3d.ReferenceVector.AngleOnPlane. Just shorter code?

I think this way the code is more readable and it's always better to not re-event the wheel (re-built what already exists).