Author Topic: Create arc through 3 points  (Read 1254 times)

0 Members and 1 Guest are viewing this topic.

huiz

  • Swamp Rat
  • Posts: 586
  • Certified Prof C3D
Create arc through 3 points
« 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?
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

kaefer

  • Swamp Rat
  • Posts: 562
Re: Create arc through 3 points
« Reply #1 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.

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);

huiz

  • Swamp Rat
  • Posts: 586
  • Certified Prof C3D
Re: Create arc through 3 points
« Reply #2 on: December 13, 2011, 09:48:49 am »
Kaefer, thank you very much! That was the missing part! :-)

The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

gile

  • Water Moccasin
  • Posts: 1738
  • Marseille, France
Re: Create arc through 3 points
« Reply #3 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);
                }
            }
        }
    }
}
Speaking English as a French Frog

MP

  • Seagull
  • Posts: 16257
  • Warning: I may be trolling.
Re: Create arc through 3 points
« Reply #4 on: December 13, 2011, 11:04:18 am »
Thanks for sharing such a clean example Gile.
\|// Set goal. Experiment tirelessly until
|oo| practice has become expertise.  Loop.
|- | Dropbox | O'Reilly School | UltraEdit

gile

  • Water Moccasin
  • Posts: 1738
  • Marseille, France
Re: Create arc through 3 points
« Reply #5 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;
            }
Speaking English as a French Frog

huiz

  • Swamp Rat
  • Posts: 586
  • Certified Prof C3D
Re: Create arc through 3 points
« Reply #6 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?
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

gile

  • Water Moccasin
  • Posts: 1738
  • Marseille, France
Re: Create arc through 3 points
« Reply #7 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).
Speaking English as a French Frog