.NET

Reply
Valued Contributor
GrzesiekGP
Posts: 67
Registered: ‎02-03-2012
Message 1 of 7 (1,084 Views)

Get angle between LineSegments (polyline).

1084 Views, 6 Replies
08-07-2012 12:42 PM

Hello!

 

I would like to get angle between lines.


My code:

 

        public static string GetPolylineShape(LineSegment3d l1, LineSegment3d l2)
        {
            Vector3d _a = l1.EndPoint.GetVectorTo(l1.StartPoint);
            Vector3d _b = l2.EndPoint.GetVectorTo(l2.StartPoint);
            Editor ed = acadApp.DocumentManager.MdiActiveDocument.Editor;

            double angle = _b.GetAngleTo(_a);

            double Ax = l1.StartPoint.X;
            double Ay = l1.StartPoint.Y;
            double Bx = l1.EndPoint.X;
            double By = l1.EndPoint.Y;
            double Cx = l2.EndPoint.X;
            double Cy = l2.EndPoint.Y;

            double BAx = Ax - Bx;
            double BAy = Ay - By;
            double BCx = Cx - Bx;
            double BCy = Cy - By;

            double BAd = Math.Sqrt(BAx * BAx + BAy + BAy);
            double BCd = Math.Sqrt(BCx * BCx + BCy + BCy);

            double sin1 = BAy / BAd;
            double cos1 = BAx / BAd;
            double sin2 = BCy / BCd;
            double cos2 = BCx / BCd;

            ed.WriteMessage(string.Format("\nsin1: {0} | cos1: {1}", Math.Round(sin1, 4), Math.Round(cos1, 4)));
            ed.WriteMessage(string.Format("\nsin2: {0} | cos2: {1}", Math.Round(sin2, 4), Math.Round(cos2, 4)));

            double DotProduct = BAx * BCx + BAy * BCy;
            double CrossProductLength = BAx * BCy - BAy * BCx;

            if (cos2 < 0 & sin2 >= 0 & cos1 >= 0 & sin1 >=0)
                angle = -angle;
            
            ed.WriteMessage(string.Format("\nAngle: {0} | Dot: {1} Cross: {2}", Math.Round(angle * 180 / Math.PI,4), Math.Round(DotProduct,4), Math.Round(CrossProductLength,4)));

            return "";
        }

 

Everything seems to work fine, but I have trouble when I rotate my polyline (image in attachment).

I'm getting the negative angle - value is OK, but is with "-" :/

I was trying to catch this "exception" by if statement with sinus/cosinus/dot/cross products, but ... hmmm ... doesn't work as you could see.

 

I thought that I can set up new UCS for first linesegment and calculate the angle in modified UCS, but ... I don't know how to do this (I mean, set up or transform UCS). But I'm not sure if this would be a good idea :smileytongue:

 

Thanks for any help :smileyhappy:

*Expert Elite*
_gile
Posts: 2,084
Registered: ‎04-29-2006
Message 2 of 7 (1,064 Views)

Re : Get angle between LineSegments (polyline).

08-07-2012 01:48 PM in reply to: GrzesiekGP

Hi,

you can use the Vector3d.GetAngleTo() with the pline normal as reference vector:

 

        private double GetPolylineShape(LineSegment3d l1, LineSegment3d l2, Vector3d normal)
        {
            Vector3d v1 = l1.EndPoint - l1.StartPoint;
            Vector3d v2 = l2.EndPoint - l2.StartPoint;
            return v1.GetAngleTo(v2, normal);
        }
Gilles Chanteau
Valued Contributor
GrzesiekGP
Posts: 67
Registered: ‎02-03-2012
Message 3 of 7 (1,050 Views)

Re : Get angle between LineSegments (polyline).

08-07-2012 03:06 PM in reply to: _gile

Hey,

 

Thaks for the reply. Could you explain me what I should pass as normal parameter?

I tried to pass Polyline's normal and first LineSegment normal, but it doesn't work. Emmm ... it works well, I've got correct angle, but only for those angles which I have negatives. For previous, I'm getting nothing :smileyhappy:

Valued Contributor
GrzesiekGP
Posts: 67
Registered: ‎02-03-2012
Message 4 of 7 (1,045 Views)

Re : Get angle between LineSegments (polyline).

08-07-2012 03:54 PM in reply to: GrzesiekGP

In attachment is image with more advanced Polyline.

We are starting from point 1 and I would like to get angle between 1/2 - 2/3. Function returns correct value.

But angles 2/3-3/4 and 3/4-4/5 are positive, but should be negatives (angle is measured clockwise, not counterclockwise like in 1/2-2/3).

Valued Mentor
gasty1001
Posts: 471
Registered: ‎04-11-2010
Message 5 of 7 (1,042 Views)

Re : Get angle between LineSegments (polyline).

08-07-2012 04:16 PM in reply to: GrzesiekGP

Hi,

 

I'm not sure but may be if you obtain the angles in this way:

 

 theta1 = _a.GetAngleTo(Vector3d.XAxis, Vector3d.ZAxis.Negate())

 theta2 = _b.GetAngleTo(Vector3d.XAxis, Vector3d.ZAxis.Negate())

 

You can check the sign from (theta1-theta2), or you can get the angle directly from :

 

theta = _a.GetAngleTo(_b, Vector3d.ZAxis.Negate())

 

just guessing, not tested in code

 

Gaston Nunez

Valued Contributor
GrzesiekGP
Posts: 67
Registered: ‎02-03-2012
Message 6 of 7 (1,007 Views)

Re: Get angle between LineSegments (polyline).

08-08-2012 01:28 AM in reply to: GrzesiekGP

I think that the code is OK, I'm getting correct values of angles.

 

Maybe the problem is that I'm calculating polyline's angles where I have more than 1 angle and I should check in loop the previous angle?

*Expert Elite*
_gile
Posts: 2,084
Registered: ‎04-29-2006
Message 7 of 7 (1,005 Views)

Re : Get angle between LineSegments (polyline).

08-08-2012 01:31 AM in reply to: GrzesiekGP

Hi,

 

Look at the docs for the Vector3d.GetAngleTo() method.

Used with a single argument: v1.GetAngleTo(v2) it returns the angle between the vectors in the range 0 to PI (as Vector2d.GetAngleTo() does).

If you pass a second argument as reference vector: v1.GetAngleTo(v2, referenceVector) it reurns the result in the range 0 to 2*PI.

The reference vector is used to determinate the direction the angle is define (right hand rule).

Using the pline.Normal as refrence vector insures it won't change whatever the pline rotation.

 

Here's a command example:

        [CommandMethod("Test")]
        public void Test()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            PromptEntityOptions peo = new PromptEntityOptions("\nSelect a polyline: ");
            peo.SetRejectMessage("Only a polyline.");
            peo.AddAllowedClass(typeof(Polyline), true);
            PromptEntityResult per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK) return;
            try
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    Polyline pline = (Polyline)tr.GetObject(per.ObjectId, OpenMode.ForRead);
                    for (int i = 0; i < pline.NumberOfVertices - 2; i++)
                    {
                        LineSegment3d l1 = pline.GetLineSegmentAt(i);
                        LineSegment3d l2 = pline.GetLineSegmentAt(i + 1);
                        double angle = GetPolylineShape(l1, l2, pline.Normal);
                        ed.WriteMessage("\nAngle between {0} and {1}: {2}", i, i + 1, Converter.AngleToString(angle, AngularUnitFormat.Degrees, 2));
                        if (angle > Math.PI)
                            ed.WriteMessage(" ({0:0.00})", (angle - Math.PI * 2.0) * 180.0 / Math.PI);
                    }
                }
            }
            catch
            {
                ed.WriteMessage("\nInvalid polyline.");
            }
        }

        private double GetPolylineShape(LineSegment3d l1, LineSegment3d l2, Vector3d normal)
        {
            Vector3d v1 = l1.EndPoint - l1.StartPoint;
            Vector3d v2 = l2.EndPoint - l2.StartPoint;
            return v1.GetAngleTo(v2, normal);
        }

 [EDIT] : the upper code works the same as gasty1001's, excpeted it isn't related to WCS coordinates. It will work whatever the polyline normal.

Gilles Chanteau
Announcements
Are you familiar with the Autodesk Expert Elites? The Expert Elite program is made up of customers that help other customers by sharing knowledge and exemplifying an engaging style of collaboration. To learn more, please visit our Expert Elite website.
Need installation help?

Start with some of our most frequented solutions or visit the Installation and Licensing Forum to get help installing your software.