Author Topic: Arc from 2 endpoints and a center point  (Read 7604 times)

0 Members and 2 Guests are viewing this topic.

gabep

  • Guest
Arc from 2 endpoints and a center point
« on: June 06, 2008, 12:11:21 PM »
Please excuse my cluelesness, but how do I draw an arc when I have the two endpoints and the center point of the arc.

I have been combing thru the .NET portion of objectARX help file, it is just getting me more confused... Is there a help file specifically for .NET?

Thanks!

fixo

  • Guest
Re: Arc from 2 endpoints and a center point
« Reply #1 on: June 06, 2008, 04:40:00 PM »
Try this code sample


Code: [Select]
        Public Shared Sub AddArc()
            Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
            Dim ed As Editor = AcadApp.DocumentManager.MdiActiveDocument.Editor
            Dim ucs As Matrix3d = ed.CurrentUserCoordinateSystem
            Dim nor As Vector3d = ucs.CoordinateSystem3d.Zaxis
            Using ta As Transaction = db.TransactionManager.StartTransaction()
                Try
                    Dim bt As BlockTable = CType(ta.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
                    Dim btr As BlockTableRecord = CType(ta.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite), BlockTableRecord)
                    Dim sp As New Point3d(5, 0, 0)
                    Dim ep As New Point3d(0, 5, 0)
                    Dim cr As New Point3d(0, 0, 0)
                    Dim sa As Double = AngleFromX(cr, sp, ed)
                    Dim ea As Double = AngleFromX(cr, ep, ed)
                    Dim rad As Double = 5.0
                    Dim arc As New Arc(cr, nor, rad, sa, ea)
                    btr.AppendEntity(arc)
                    ta.AddNewlyCreatedDBObject(arc, True)
                    ta.Commit()
                Catch ex As Exception
                    ed.WriteMessage(ex.Message, _
                                        "Exception", _
                                        MessageBoxButtons.OK, _
                                       MessageBoxIcon.Error)
                End Try
            End Using
        End Sub
        Public Shared Function AngleFromX(ByVal pt1 As Point3d, ByVal pt2 As Point3d, ByVal ed As Editor) As Double
            Dim ucsmtx As Matrix3d = ed.CurrentUserCoordinateSystem
            Dim ucs As CoordinateSystem3d = ucsmtx.CoordinateSystem3d
            Dim ucsplane As Plane = New Plane(ucs.Origin, ucs.Xaxis, ucs.Yaxis)
            Dim vec As Vector3d = pt2 - pt1
            Dim ang As Double = vec.AngleOnPlane(ucsplane)
            Return ang
        End Function

In .NET you can create arc with using of following constructors
(from ObjectARX):

Arc Class

Constructor

Arc()


--------------------------------------------------------------------------------

Arc(

Autodesk.AutoCAD.Geometry.Point3d center,

System.Double radius,

System.Double startAngle,

System.Double endAngle)

Parameters
center Input Autodesk.AutoCAD.Geometry.Point3d object. 
radius Input System.Double object. 
startAngle Input System.Double object. 
endAngle Input System.Double object. 


--------------------------------------------------------------------------------

Arc(

Autodesk.AutoCAD.Geometry.Point3d center,

Autodesk.AutoCAD.Geometry.Vector3d normal,

System.Double radius,

System.Double startAngle,

System.Double endAngle)

Parameters
center Input Autodesk.AutoCAD.Geometry.Point3d object. 
normal Input Autodesk.AutoCAD.Geometry.Vector3d object. 
radius Input System.Double object. 
startAngle Input System.Double object. 
endAngle Input System.Double object. 


~'J'~

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Arc from 2 endpoints and a center point
« Reply #2 on: June 06, 2008, 05:52:51 PM »
<................>
I have been combing thru the .NET portion of objectARX help file, it is just getting me more confused... Is there a help file specifically for .NET?

Thanks!

From the ObjectARX SDK ..
"... \docs\arxmgd.chm"
"... \docs\acad_mgd.chm"
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

gabep

  • Guest
Re: Arc from 2 endpoints and a center point
« Reply #3 on: June 06, 2008, 06:28:16 PM »
You guys are just awesome!

Thanks!   :-)

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Arc from 2 endpoints and a center point
« Reply #4 on: June 07, 2008, 06:17:01 AM »
Try this code sample...

~'J'~


Hi Fixo,
I’m getting strange results from your routine, I wonder if you might check mine to see if I’m on the right track

Here is the class..

Code: [Select]
  public class Arc3p : Arc
  {
    // Fields
    private const double halfapi = 1.570796325;
    private const double pi = 3.14159265;

    // Methods
    public Arc3p()
    {
    }

    public Arc3p(Point3d startPoint, Point3d centerPoint, Point3d endPoint)
    {
      Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
      Point3d p1 = myMath(startPoint, centerPoint);
      Point3d p2 = myMath(centerPoint, endPoint);

      Point3d cp = inters(p1, polarPoint(p1, halfapi + angle(startPoint, centerPoint, ed), 1.0),
                          p2, polarPoint(p2, halfapi + angle(centerPoint, endPoint, ed), 1.0));

      base.Center = cp;
      base.Radius = distance(cp, startPoint);
      base.StartAngle = angle(cp, startPoint, ed);
      base.EndAngle = angle(cp, endPoint, ed);
    }

    public Arc3p(IntPtr umanagedObjPtr, bool autoDelete)
      : base(umanagedObjPtr, autoDelete)
    {
    }

    public Arc3p(Point3d Center, double radius, double startAngle, double endAngle)
      : base(Center, radius, startAngle, endAngle)
    {
    }

    public Arc3p(Point3d Center, Vector3d normal, double radius, double startAngle, double endAngle)
      : base(Center, normal, radius, startAngle, endAngle)
    {
    }

    private static double angle(Point3d pt1, Point3d pt2, Editor ed)
    {
      CoordinateSystem3d ucs = ed.CurrentUserCoordinateSystem.CoordinateSystem3d;
      Plane ucsplane = new Plane(ucs.Origin, ucs.Xaxis, ucs.Yaxis);
      Vector3d vec = (Vector3d)(pt2 - pt1);
      return vec.AngleOnPlane(ucsplane);
    }

    private static double distance(Point3d from, Point3d to)
    {
      return from.DistanceTo(to);
    }

    private static Point3d inters(Point3d pt1, Point3d pt2, Point3d pt3, Point3d pt4)
    {
      using (Line3d l1 = new Line3d(pt1, pt2),
                    l2 = new Line3d(pt3, pt4))
      {
        return l1.IntersectWith(l2)[0];
      }
    }

    private static Point3d myMath(Point3d pt1, Point3d pt2)
    {
      return new Point3d(pt1.X + pt2.X, pt1.Y + pt2.Y, pt1.Z + pt2.Z).DivideBy(2.0);
    }

    private static Point3d polarPoint(Point3d point, double angle, double distance)
    {
      return new Point3d(point.X + (distance * Math.Cos(angle)), point.Y + (distance * Math.Sin(angle)), point.Z);
    }
  }


call it like..

Code: [Select]
   [CommandMethod("doit")]
    public void doit()
    {
      Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

      try
      {
        Database db = HostApplicationServices.WorkingDatabase;
        AcDb.TransactionManager tm = db.TransactionManager;

        using (Transaction tr = tm.StartTransaction())
        {
          BlockTableRecord btr = (BlockTableRecord)(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite));

          //new arc class
          Arc3p arcp3p1 = new Arc3p(new Point3d(0, 0, 0), new Point3d(50, 25, 0), new Point3d(100, 0, 0));
          btr.AppendEntity(arcp3p1);
          tr.AddNewlyCreatedDBObject(arcp3p1,true);

          Arc3p arcp3p2 = new Arc3p(new Point3d(100, 0, 0), new Point3d(50, 25, 0), new Point3d(0, 0, 0));
          btr.AppendEntity(arcp3p2);
          tr.AddNewlyCreatedDBObject(arcp3p2, true);

          tr.Commit();
        }
      }
      catch (SystemException ex)
      {
        ed.WriteMessage("\n" + ex.Message);
        ed.WriteMessage("\n" + ex.StackTrace);
      }
    }

Thanks
Dan
« Last Edit: June 07, 2008, 09:51:57 AM by Daniel »

fixo

  • Guest
Re: Arc from 2 endpoints and a center point
« Reply #5 on: June 07, 2008, 10:23:21 AM »
Hi Dan
Your routine just worked nice for me
(same as mine here, though)
:)

~'J'~

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Arc from 2 endpoints and a center point
« Reply #6 on: June 07, 2008, 10:45:03 AM »
Hi Dan
Your routine just worked nice for me
(same as mine here, though)
:)

~'J'~

Thanks for trying it out for me. This is the result I’m getting ( your arc is in red) . I must be doing something wrong. Time for a shot of alcohol   :lol:


It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Arc from 2 endpoints and a center point
« Reply #7 on: June 07, 2008, 10:51:30 AM »
Ah ya see, a couple of quick shots did the trick, it’s just a CW CCW thing.  :lol:


fixo

  • Guest
Re: Arc from 2 endpoints and a center point
« Reply #8 on: June 07, 2008, 10:58:19 AM »
Ah, I forgot to test my code in the arbitary UCS
Now I understand what are you talking about
Just I have not have a time to rewrite it now
Better yet to grab your class :)

Regards,  :kewl:

~'J'~

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Arc from 2 endpoints and a center point
« Reply #9 on: June 07, 2008, 11:59:29 AM »
Ah, I forgot to test my code in the arbitary UCS
Now I understand what are you talking about
Just I have not have a time to rewrite it now
Better yet to grab your class :)

Regards,  :kewl:

~'J'~

Oh no need to rewrite anything, I just want to verify why my routine was acting
different than yours. I appreciate the help.  :-)

Bryco

  • Water Moccasin
  • Posts: 1883
Re: Arc from 2 endpoints and a center point
« Reply #10 on: June 07, 2008, 05:41:54 PM »
Daniel I ran yours and the center isn't (50,25,0), maybe I didn't do it right.

I have messed with arcs a bit and they are pretty tricky.
Below is an attempt to add an arc using either ucs points or world points.
I had the hardest time with it as I was using
double startAng = Vector3d.XAxis.GetAngleTo(StartP - Cen);
and GetAngle does'nt work over 180 degrees (rotten thing to do, acad).
This works in 3d as far as I have tested, however the function NormalFromPoints
will give a different normal (reversed) if you change the order of the points you supply it.
This is a lot like fixo's code. (Fatty)
Code: [Select]
 

using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;

     
static public Arc ArcFromCenterWcs(Point3d Cen, Point3d StartP, Point3d EndP)
        //3 point arc from 3 Wcs points
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Matrix3d ucs = doc.Editor.CurrentUserCoordinateSystem;
            Vector3d norm;
            if (Cen.Z == 0 && StartP.Z == 0 && EndP.Z==0)
                norm = Vector3d.ZAxis;
            else
                norm = NormalFromPoints(Cen,StartP,  EndP);

            double Rad = Cen.DistanceTo(StartP);
            Plane pn =new Plane(Cen, norm);
            double startAng = (StartP - Cen).AngleOnPlane(pn);
            double endAng = (EndP - Cen).AngleOnPlane(pn);
            Arc oArc = new Arc(Cen, Vector3d.ZAxis, Rad, startAng, endAng);
            oArc.Normal = norm;
            oArc.ColorIndex = 1;
            oArc = AddArc(oArc);   
            return oArc;
        }





        static public Arc ArcFromCenter(Point3d Cen, Point3d StartP, Point3d EndP)
        //3 point arc from 3 ucs points
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Matrix3d ucs = doc.Editor.CurrentUserCoordinateSystem;
            double Rad = Cen.DistanceTo(StartP);
            CoordinateSystem3d cs = ucs.CoordinateSystem3d;
            Plane pn = new Plane(); //world plane
            double startAng = (StartP - Cen).AngleOnPlane(pn);
            double endAng = (EndP - Cen).AngleOnPlane(pn);
            Arc oArc = new Arc(Cen,Vector3d.ZAxis, Rad, startAng, endAng);
            oArc.TransformBy(ucs);
            oArc = AddArc(oArc);
            return oArc;
        }



        static public Arc AddArc(Arc oArc)
        {
            Database db = HostApplicationServices.WorkingDatabase;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = tr.GetObject
                    (db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord btr = tr.GetObject
                    (db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
                btr.AppendEntity(oArc);
                tr.AddNewlyCreatedDBObject(oArc, true);
                tr.Commit();
            }
            return oArc;
        }


        static public Vector3d NormalFromPoints(Point3d p0, Point3d p1, Point3d p2)
        //n = u×v = (V1-V0)×(V2-V0)
        {
            double Unit;
            //Get distance from zero

            Point3d x = new Point3d(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
            Point3d y = new Point3d(p2.X - p0.X, p2.Y - p0.Y, p2.Z - p0.Z);
            //get CrossProduct
            Vector3d n = new Vector3d(x.Y * y.Z - x.Z * y.Y, x.Z * y.X - x.X * y.Z, x.X * y.Y - x.Y * y.X);

            //Convert to unit normal
            Unit = Math.Sqrt(n.X * n.X + n.Y * n.Y + n.Z * n.Z);
            n = new Vector3d(n.X / Unit, n.Y / Unit, n.Z / Unit);
            if (n.X == 0 && n.Y == 0 && n.Z == -1) n = new Vector3d(0, 0, 1);
            return n;
        }

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Arc from 2 endpoints and a center point
« Reply #11 on: June 07, 2008, 08:51:19 PM »
Interesting, I haven’t tested your code yet, but is it possible we are talking about different centers? I am thinking more along the lines of “midpoint” of the arc. 


It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Arc from 2 endpoints and a center point
« Reply #12 on: June 07, 2008, 08:59:19 PM »
Ok that does seem to be where I was goofing up. Fixos routine is correct then  :oops:

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Arc from 2 endpoints and a center point
« Reply #13 on: June 07, 2008, 09:58:29 PM »
Maybe both methods would be handy, I left everything in WCS, I guess one could do a TransformBy() on the instance?  :mrgreen:

Code: [Select]
  public class Arc3p : Arc
  {
    // Fields
    private const double halfapi = 1.570796325;
    private const double pi = 3.14159265;

    // Methods
    public Arc3p()
    {
    }

    public Arc3p(Point3d startPoint, Point3d centerPoint, Point3d endPoint, bool centerIsMidPoint)
    {
      if (centerIsMidPoint)
      {
        Point3d p1 = myMath(startPoint, centerPoint);
        Point3d p2 = myMath(centerPoint, endPoint);

        Point3d cp = inters(p1, polarPoint(p1, halfapi + angle(startPoint, centerPoint), 1.0),
                            p2, polarPoint(p2, halfapi + angle(centerPoint, endPoint), 1.0));

        base.Center = cp;
        base.Radius = distance(cp, startPoint);
        base.StartAngle = angle(cp, startPoint);
        base.EndAngle = angle(cp, endPoint);
      }
      else
      {
        base.Center = centerPoint;
        base.Radius = distance(centerPoint, startPoint);
        base.StartAngle = angle(centerPoint, startPoint);
        base.EndAngle = angle(centerPoint, endPoint);
      }
    }

    public Arc3p(IntPtr umanagedObjPtr, bool autoDelete)
      : base(umanagedObjPtr, autoDelete)
    {
    }

    public Arc3p(Point3d Center, double radius, double startAngle, double endAngle)
      : base(Center, radius, startAngle, endAngle)
    {
    }

    public Arc3p(Point3d Center, Vector3d normal, double radius, double startAngle, double endAngle)
      : base(Center, normal, radius, startAngle, endAngle)
    {
    }

    private static double angle(Point3d pt1, Point3d pt2)
    {
      CoordinateSystem3d wcs = Matrix3d.Identity.CoordinateSystem3d;
      Plane wcsplane = new Plane(wcs.Origin, wcs.Xaxis, wcs.Yaxis);
      Vector3d vec = (Vector3d)(pt2 - pt1);
      return vec.AngleOnPlane(wcsplane);
    }

    private static double distance(Point3d from, Point3d to)
    {
      return from.DistanceTo(to);
    }

    private static Point3d inters(Point3d pt1, Point3d pt2, Point3d pt3, Point3d pt4)
    {
      using (Line3d l1 = new Line3d(pt1, pt2),
                    l2 = new Line3d(pt3, pt4))
      {
        return l1.IntersectWith(l2)[0];
      }
    }

    private static Point3d myMath(Point3d pt1, Point3d pt2)
    {
      return new Point3d(pt1.X + pt2.X, pt1.Y + pt2.Y, pt1.Z + pt2.Z).DivideBy(2.0);
    }

    private static Point3d polarPoint(Point3d point, double angle, double distance)
    {
      return new Point3d(point.X + (distance * Math.Cos(angle)), point.Y + (distance * Math.Sin(angle)), point.Z);
    }

  }

tester func
Code: [Select]
   [CommandMethod("doit")]
    public void doit()
    {
      Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

      try
      {
        Database db = HostApplicationServices.WorkingDatabase;
        AcDb.TransactionManager tm = db.TransactionManager;

        using (Transaction tr = tm.StartTransaction())
        {
          BlockTableRecord btr = (BlockTableRecord)(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite));

          //new arc class
          Arc3p arcp3p1 = new Arc3p(new Point3d(0, 0, 0), new Point3d(50, 25, 0), new Point3d(100, 0, 0),true);
          btr.AppendEntity(arcp3p1);
          tr.AddNewlyCreatedDBObject(arcp3p1,true);

          Arc3p arcp3p2 = new Arc3p(new Point3d(100, 0, 0), new Point3d(50, 25, 0), new Point3d(0, 0, 0),true);
          btr.AppendEntity(arcp3p2);
          tr.AddNewlyCreatedDBObject(arcp3p2, true);


          Arc3p arcp3p3 = new Arc3p(new Point3d(0, 0, 0), new Point3d(50, 25, 0), new Point3d(100, 0, 0),false);
          btr.AppendEntity(arcp3p3);
          tr.AddNewlyCreatedDBObject(arcp3p3, true);

          Arc3p arcp3p4 = new Arc3p(new Point3d(100, 0, 0), new Point3d(50, 25, 0), new Point3d(0, 0, 0), false);
          btr.AppendEntity(arcp3p4);
          tr.AddNewlyCreatedDBObject(arcp3p4, true);

          tr.Commit();
        }
      }
      catch (SystemException ex)
      {
        ed.WriteMessage("\n" + ex.Message);
        ed.WriteMessage("\n" + ex.StackTrace);
      }
    }
« Last Edit: June 07, 2008, 10:01:34 PM by Daniel »

Bryco

  • Water Moccasin
  • Posts: 1883
Re: Arc from 2 endpoints and a center point
« Reply #14 on: June 07, 2008, 10:41:51 PM »
That's a goer Dan.
I did both versions as I thought I would be getting ucs points back from a user, but I think the op has the most common use for an arc function, feeding it wcs points. The interesting point about wcs points is that you don't know (unless there is another clue somewhere) what plane the points should be in, so you need to make a new plane for every 3 points