.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to know the orientation of a polyline

30 REPLIES 30
SOLVED
Reply
Message 1 of 31
ccalvo12
6697 Views, 30 Replies

How to know the orientation of a polyline

Hello. A query, any of you know any method or function that tells me the orientation of a polyline, if it is clockwise or counter-clockwise

 

Thanks

30 REPLIES 30
Message 21 of 31

   public static Boolean IsCCW(Transaction acTrans, ObjectId plineId, double precision)
        {
            Polyline acPoly = (Polyline)acTrans.GetObject(plineId, OpenMode.ForRead);

            VladUtils.qacBB.BoundingBox bbtempoPline = VladUtils.qacBB.GetBoundingBox(plineId, acTrans);
            qNGeom.qContour points = qacPoints.GetEntPoints(plineId);
            //no bulges
            if (!acPoly.HasBulges)
            {
                return points.IsCCW(precision);
            }
            else
            //bulges
            {

                int LowestRightestPointInd = vldplUniversalPolylines.IntersectionAnalytics.GetLowestRightestPointInd(points, precision);
                //arc arenot lower points
                if (qNMath.IsSameNumbers(points.Contour[LowestRightestPointInd].y, bbtempoPline.minPoint.y, precision))
                {
                    return points.IsCCW(precision);
                }
                else
                {
                    if (acPoly.NumberOfVertices == 2 && !qNMath.IsZero(acPoly.GetBulgeAt(0), precision) && !qNMath.IsZero(acPoly.GetBulgeAt(1), precision))
                    {
                        if(acPoly.GetArcSegment2dAt(0).Radius> acPoly.GetArcSegment2dAt(1).Radius)
                        {
                            return !acPoly.GetArcSegment2dAt(0).IsClockWise;
                        }
                        else
                        {
                            return !acPoly.GetArcSegment2dAt(1).IsClockWise;
                        }
                    }
                    else
                    {
                        for (int i = 0; i < acPoly.NumberOfVertices; i++)
                        {
                            double curbulge = acPoly.GetBulgeAt(i);
                            if (!qNMath.IsZero(curbulge, precision))
                            {
                                CircularArc2d ccc = acPoly.GetArcSegment2dAt(i);
                                if (qNMath.IsSameNumbers(ccc.OrthoBoundBlock.BasePoint.Y, bbtempoPline.minPoint.y, precision))
                                {
                                    return !ccc.IsClockWise;
                                }
                            }
                        }
                    }
                }
            }
            return false;
        }
Message 22 of 31
VladPaly
in reply to: ActivistInvestor

I would love to publish the ready-to-go code , but to extract and adapt the code will take really long time.

Honestly I can't afford it.

CAD programmers who are interesting in CW/CCW direction are not beginners.

I assume that name of functions and variables are pretty obvious and will not take too long time to recreate functions.

 

 

To use the area or angle method to determine the direction necessary to find index of obvious convex point, for example lowest rightest point (GetLowestRightestPointInd)

Message 23 of 31
ActivistInvestor
in reply to: VladPaly


@VladPaly wrote:

I would love to publish the ready-to-go code , but to extract and adapt the code will take really long time.

Honestly I can't afford it.

CAD programmers who are interesting in CW/CCW direction are not beginners.

I assume that name of functions and variables are pretty obvious and will not take too long time to recreate functions.

 

 

To use the area or angle method to determine the direction necessary to find index of obvious convex point, for example lowest rightest point (GetLowestRightestPointInd)


I don't think there's anything obvious about the types and their methods that you didn't include.

 

IMO, what you posted is more of a puzzle than a helpful contribution..

 

Message 24 of 31
ActivistInvestor
in reply to: VladPaly


@VladPaly wrote:
   public static Boolean IsCCW(Transaction acTrans, ObjectId plineId, double precision)
        {
            Polyline acPoly = (Polyline)acTrans.GetObject(plineId, OpenMode.ForRead);

            VladUtils.qacBB.BoundingBox bbtempoPline = VladUtils.qacBB.GetBoundingBox(plineId, acTrans);
            qNGeom.qContour points = qacPoints.GetEntPoints(plineId);
            //no bulges
            if (!acPoly.HasBulges)
            {
                return points.IsCCW(precision);
            }
            else
            //bulges
            {

                int LowestRightestPointInd = vldplUniversalPolylines.IntersectionAnalytics.GetLowestRightestPointInd(points, precision);
                //arc arenot lower points
                if (qNMath.IsSameNumbers(points.Contour[LowestRightestPointInd].y, bbtempoPline.minPoint.y, precision))
                {
                    return points.IsCCW(precision);
                }
                else
                {
                    if (acPoly.NumberOfVertices == 2 && !qNMath.IsZero(acPoly.GetBulgeAt(0), precision) && !qNMath.IsZero(acPoly.GetBulgeAt(1), precision))
                    {
                        if(acPoly.GetArcSegment2dAt(0).Radius> acPoly.GetArcSegment2dAt(1).Radius)
                        {
                            return !acPoly.GetArcSegment2dAt(0).IsClockWise;
                        }
                        else
                        {
                            return !acPoly.GetArcSegment2dAt(1).IsClockWise;
                        }
                    }
                    else
                    {
                        for (int i = 0; i < acPoly.NumberOfVertices; i++)
                        {
                            double curbulge = acPoly.GetBulgeAt(i);
                            if (!qNMath.IsZero(curbulge, precision))
                            {
                                CircularArc2d ccc = acPoly.GetArcSegment2dAt(i);
                                if (qNMath.IsSameNumbers(ccc.OrthoBoundBlock.BasePoint.Y, bbtempoPline.minPoint.y, precision))
                                {
                                    return !ccc.IsClockWise;
                                }
                            }
                        }
                    }
                }
            }
            return false;
        }

 

There is nothing all that obvious about the highlighted members and types.

 

For example, given a set of points that include the right-most point (10, 10, 0) and the lowest point (5, 5, 0), which of the two is the 'LowestRightestPoint' ?

 

I also strongly disagree with the suggestion that anyone that needs to know the handed-ness of a polyline is not a beginner.

Message 25 of 31

I prepared the code. Ready to go. Works correctly .Any feedback is welcome.

 

 

using System;
using System.Collections.Generic;

using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;


namespace  CCWHub
{
    public class plineCCW
    {
        public static Boolean IsEqualacPoints(Point2d firstPoint, Point2d secondPoint, double precision)
        {
            return (IsEqual(firstPoint.X, secondPoint.X, precision) && IsEqual(firstPoint.Y, secondPoint.Y, precision));
        }
        public static Boolean IsEqual(double firstNumber, double secondNumber, double precision)
        {
            return (Math.Abs(firstNumber - secondNumber)) <= precision ? true : false;
        }

        public static Boolean IsInRange(double firstNumber, double secondNumber, double checkedNumber, double precision)
        {
            if (IsEqual(firstNumber, checkedNumber, precision))
                return true;
            if (IsEqual(secondNumber, checkedNumber, precision))
                return true;
            if (firstNumber < checkedNumber && checkedNumber < secondNumber)
                return true;
            if (secondNumber < checkedNumber && checkedNumber < firstNumber)
                return true;
            return false;
        }



        public static int GetLowestRightestPointInd(Point2dCollection points, double precision)
        {
            double ymin = points[0].Y, xmax = points[0].X;
            int indexToReturn = 0;
            for (int i = 1; i < points.Count; i++)
            {
                if (ymin > points[i].Y || (IsEqual(ymin, points[i].Y, precision) && xmax < points[i].X))
                {
                    indexToReturn = i;
                    ymin = points[i].Y;
                    xmax = points[i].X;
                }
            }
            return indexToReturn;
        }


        public static void Reverse(Transaction acTrans, ObjectId plineId)
        {
            #region init collectors   
            Polyline acPoly = (Polyline)acTrans.GetObject(plineId, OpenMode.ForWrite);
            Point2dCollection revercedPoints = new Point2dCollection();
            List<double> buldgeList = new List<double>();
            List<double> width1 = new List<double>();
            List<double> width2 = new List<double>();
            #endregion init collectors   

            #region collecting
            for (int i = acPoly.NumberOfVertices - 1; i >= 0; i--)
            {
                revercedPoints.Add(acPoly.GetPoint2dAt(i));
                int k = (i == 0) ? acPoly.NumberOfVertices - 1 : i - 1;
                buldgeList.Add(acPoly.GetBulgeAt(k) * -1);
                width1.Add(acPoly.GetEndWidthAt(k));
                width2.Add(acPoly.GetStartWidthAt(k));
            }
            #endregion collecting

            #region changing settings
            for (int i = 0; i < acPoly.NumberOfVertices; i++)
            {
                acPoly.SetPointAt(i, revercedPoints[i]);
                acPoly.SetStartWidthAt(i, width1[i]);
                acPoly.SetEndWidthAt(i, width2[i]);
                acPoly.SetBulgeAt(i, buldgeList[i]);
            }
            #endregion changing settings
        }
        public static Point2dCollection GetPoints2D(Polyline acPoly)
        {
            Point2dCollection points = new Point2dCollection();
            for (int i = 0; i < acPoly.NumberOfVertices; i++)
            {
                points.Add(acPoly.GetPoint2dAt(i));
            }
            return points;
        }


        public static Boolean IsPointBelongToLWPlineArcSegment(Polyline acPoly, int indStart, int indEnd, Point2d pointToCheck, double precision)
        {
            CircularArc2d circularArc2d = acPoly.GetArcSegment2dAt(indStart);
            double radius = circularArc2d.Radius;
            if (pointToCheck.GetDistanceTo(circularArc2d.Center) > radius)
            {
                return false;
            }

            //bulge
            double bulge = acPoly.GetBulgeAt(indStart);
            //translate points by arc center to 0,0
            Vector2d centerV = circularArc2d.Center.GetAsVector();
            Vector2d startV = acPoly.GetPoint2dAt(indStart).GetAsVector() - centerV;
            Vector2d endV = acPoly.GetPoint2dAt(indEnd).GetAsVector() - centerV;
            Vector2d pointToCheckV = pointToCheck.GetAsVector() - centerV;
            //angle of rotation
            double angleToRotate = (endV - startV).Angle * -1;
            //make hord horizontal
            Vector2d startV1 = startV.RotateBy(angleToRotate);
            Vector2d endV1 = endV.RotateBy(angleToRotate);
            Vector2d pointToCheckV1 = pointToCheckV.RotateBy(angleToRotate);

            double firstLimit = startV1.Y, secondlimit = 0;
            double radiusCorrection = (Math.Round(startV1.Y / Math.Abs(endV1.Y), 0) > 0) ? 1 : -1;

            #region finding second limit
            if (IsEqual(Math.Abs(bulge), 1, precision))
            {
                if (bulge >= 0)
                {
                    secondlimit = radius * -1;
                }
                else
                {
                    secondlimit = radius;
                }
            }
            else if (Math.Abs(bulge) < 1)
            {
                secondlimit = radius * radiusCorrection;
            }
            else
            {
                secondlimit = radius * radiusCorrection * -1;
            }
            #endregion finding second limit
            //Is in belong to segment
            Boolean isIn = IsInRange(firstLimit, secondlimit, pointToCheckV1.Y, precision);
            return isIn;
        }

        public static Boolean IsCCWnoarcs(Polyline acPoly, double precision)
        {
            Point2dCollection points =GetPoints2D(acPoly);
            //lrpInd - Lowest Rightest Point Index
            //plrpInd - previous to lrpInd
            //nlrpInd - next of lrpInd
            int lrpInd = GetLowestRightestPointInd(points, precision),
                plrpInd = (lrpInd == 0) ? points.Count - 1 : lrpInd - 1,
                nlrpInd = (lrpInd == points.Count - 1) ? 0 : lrpInd + 1;
            Point2d
              curPoint = acPoly.GetPoint2dAt(lrpInd),
              prevPoint = acPoly.GetPoint2dAt(plrpInd),
              nextPoint = acPoly.GetPoint2dAt(nlrpInd);
            double
                    curAngle = (nextPoint.GetAsVector() - curPoint.GetAsVector()).Angle,
                    prevAngle = (prevPoint.GetAsVector() - curPoint.GetAsVector()).Angle;
            return (prevAngle > curAngle) ? true : false;
        }


        public static Boolean IsCCWstraigtorarc(Transaction acTrans, ObjectId plineId, double precision)
        {
            Boolean isCCW = false;

            Polyline acPoly = (Polyline)acTrans.GetObject(plineId, OpenMode.ForRead);
            //Polyline doesn't have any arcs
            if (!acPoly.HasBulges)
            {
                isCCW = IsCCWnoarcs(acPoly, precision);
                return isCCW;
            }
            else
            //at least one arc
            {
                Extents3d acPolyBB = acPoly.GeometricExtents;
                double
                    bbMinX = acPolyBB.MinPoint.X,
                    bbMinY = acPolyBB.MinPoint.Y,
                    bbMaxX = acPolyBB.MaxPoint.X,
                    bbMaxY = acPolyBB.MaxPoint.Y;

                #region check for convex arcs touching bounding box
                for (int i = 0; i < acPoly.NumberOfVertices; i++)
                {

                    if (acPoly.GetSegmentType(i) == SegmentType.Arc)
                    {
                        double curBulge = acPoly.GetBulgeAt(i);
                        CircularArc2d circularArc2d = acPoly.GetArcSegment2dAt(i);

                        Point2d
                            StartPoint = circularArc2d.StartPoint,
                            EndPoint = circularArc2d.EndPoint,
                            Center = circularArc2d.Center;

                        double
                            StartAngle = (StartPoint.GetAsVector() - Center.GetAsVector()).Angle,
                            EndAngle = (EndPoint.GetAsVector() - Center.GetAsVector()).Angle,
                            Radius = circularArc2d.Radius,
                            totalAngle = circularArc2d.EndAngle;

                        #region angle correction
                        if (curBulge > 0)
                        {
                            if (IsEqual(StartAngle, Math.PI * 2, precision))
                                StartAngle = 0;
                            if (IsEqual(EndAngle, 0, precision))
                                EndAngle = Math.PI * 2;
                        }
                        else
                        {
                            if (IsEqual(StartAngle, 0, precision))
                                StartAngle = Math.PI * 2;
                            if (IsEqual(EndAngle, Math.PI * 2, precision))
                                EndAngle = 0;
                        }
                        #endregion angle correction

                        #region quadrants 
                        double
                            eastQuadrant = Center.X + Radius,
                            northQuadrant = Center.Y + Radius,
                            westQuadrant = Center.X - Radius,
                            southQuadrant = Center.Y - Radius;
                        #endregion quadrants

                        #region check for quadrants
                        //0
                        if (!IsEqual(eastQuadrant, StartPoint.X, precision) && !IsEqual(eastQuadrant, EndPoint.X, precision) &&
                            ((StartAngle > EndAngle && curBulge > 0) || (StartAngle < EndAngle && curBulge < 0))
                            && IsEqual(eastQuadrant, bbMaxX, precision))
                        {
                            isCCW = !circularArc2d.IsClockWise;
                            return isCCW;
                        }
                        //90
                        else if
                            (!IsEqual(northQuadrant, StartPoint.Y, precision) && !IsEqual(northQuadrant, EndPoint.Y, precision) &&
                            ((StartAngle < Math.PI * 0.5 && Math.PI * 0.5 < EndAngle && curBulge > 0) || (EndAngle < Math.PI * 0.5 && Math.PI * 0.5 < StartAngle && curBulge < 0)) &&
                            IsEqual(northQuadrant, bbMaxY, precision))
                        {
                            isCCW = !circularArc2d.IsClockWise;
                            return isCCW;
                        }
                        //180
                        else if
                            (!IsEqual(westQuadrant, StartPoint.X, precision) && !IsEqual(westQuadrant, EndPoint.X, precision) &&
                            ((StartAngle < Math.PI && Math.PI < EndAngle && curBulge > 0) || (EndAngle < Math.PI && Math.PI < StartAngle && curBulge < 0)) &&
                            IsEqual(westQuadrant, bbMinX, precision))
                        {
                            isCCW = !circularArc2d.IsClockWise;
                            return isCCW;
                        }
                        //270
                        else if
                            (!IsEqual(southQuadrant, StartPoint.Y, precision) && !IsEqual(southQuadrant, EndPoint.Y, precision) &&
                            ((StartAngle < Math.PI * 1.5 && Math.PI * 1.5 < EndAngle && curBulge > 0) || (EndAngle < Math.PI * 1.5 && Math.PI * 1.5 < StartAngle && curBulge < 0)) &&
                            IsEqual(southQuadrant, bbMinY, precision))
                        {
                            isCCW = !circularArc2d.IsClockWise;
                            return isCCW;
                        }
                        #endregion check for quadrants 
                    }
                }
                #endregion check for convex arcs touching bounding box

                Point2dCollection points =GetPoints2D(acPoly);
                //lrpInd - Lowest Rightest Point Index
                //plrpInd - previous to lrpInd
                //nlrpInd - next of lrpInd
                int lrpInd = GetLowestRightestPointInd(points, precision),
                    plrpInd = (lrpInd == 0) ? points.Count - 1 : lrpInd - 1,
                    nlrpInd = (lrpInd == points.Count - 1) ? 0 : lrpInd + 1;


                Point2d
                    curPoint = acPoly.GetPoint2dAt(lrpInd),
                    prevPoint = acPoly.GetPoint2dAt(plrpInd),
                    nextPoint = acPoly.GetPoint2dAt(nlrpInd);

                if (acPoly.GetSegmentType(lrpInd) == SegmentType.Line && acPoly.GetSegmentType(plrpInd) == SegmentType.Line)
                {
                    double
                        curAngle = (nextPoint.GetAsVector() - curPoint.GetAsVector()).Angle,
                        prevAngle = (prevPoint.GetAsVector() - curPoint.GetAsVector()).Angle;
                    isCCW = (prevAngle > curAngle) ? true : false;
                    return isCCW;
                }
                else if (acPoly.GetSegmentType(lrpInd) == SegmentType.Line && acPoly.GetSegmentType(plrpInd) == SegmentType.Arc)
                {
                    int indStart = plrpInd;
                    int indEnd = lrpInd;
                    int indToCheck = nlrpInd;

                    Boolean IsIn = IsPointBelongToLWPlineArcSegment(acPoly, indStart, indEnd, acPoly.GetPoint2dAt(indToCheck), precision);
                    //ed.WriteMessage("\n Is in =" + IsIn.ToString());

                    if (IsIn)
                    {
                        CircularArc2d circularArc2d = acPoly.GetArcSegment2dAt(indStart);
                        isCCW = !circularArc2d.IsClockWise;
                        return isCCW;
                    }
                    else
                    {
                        double
                            curAngle = (nextPoint.GetAsVector() - curPoint.GetAsVector()).Angle,
                            prevAngle = (prevPoint.GetAsVector() - curPoint.GetAsVector()).Angle;
                        isCCW = (prevAngle > curAngle) ? true : false;
                        return isCCW;
                    }
                    //ed.WriteMessage("\n isCCW =" + isCCW.ToString());


                }
                else if (acPoly.GetSegmentType(lrpInd) == SegmentType.Arc && acPoly.GetSegmentType(plrpInd) == SegmentType.Line)
                {
                    int indStart = lrpInd;
                    int indEnd = nlrpInd;
                    int indToCheck = plrpInd;

                    Boolean IsIn = IsPointBelongToLWPlineArcSegment(acPoly, indStart, indEnd, acPoly.GetPoint2dAt(indToCheck), precision);
                    if (IsIn)
                    {
                        CircularArc2d circularArc2d = acPoly.GetArcSegment2dAt(indStart);
                        isCCW = !circularArc2d.IsClockWise;
                        return isCCW;
                    }
                    else
                    {
                        double
                            curAngle = (nextPoint.GetAsVector() - curPoint.GetAsVector()).Angle,
                            prevAngle = (prevPoint.GetAsVector() - curPoint.GetAsVector()).Angle;
                        isCCW = (prevAngle > curAngle) ? true : false;
                        return isCCW;
                    }
                    //ed.WriteMessage("\n isCCW =" + isCCW.ToString());

                }
                else if (acPoly.GetSegmentType(lrpInd) == SegmentType.Arc && acPoly.GetSegmentType(plrpInd) == SegmentType.Arc)
                {
                    CircularArc2d curArc = acPoly.GetArcSegment2dAt(lrpInd);
                    Point2d curCenter = curArc.Center;
                    double curTangentAngle = (curCenter.GetAsVector() - curPoint.GetAsVector()).Angle - Math.PI * 0.5;
                    CircularArc2d prevArc = acPoly.GetArcSegment2dAt(plrpInd);
                    Point2d preCenter = prevArc.Center;
                    double preTangentAngle = (preCenter.GetAsVector() - curPoint.GetAsVector()).Angle - Math.PI * 0.5;



                    isCCW = (curTangentAngle < preTangentAngle) ? !curArc.IsClockWise : !prevArc.IsClockWise;
                    return isCCW;
                }
            }

            return isCCW;
        }
    }
}

Call is :

       [CommandMethod("MyGroup", "MyCommand", "MyCommandLocal", CommandFlags.Modal)]
        public void MyCommand() // This method can have any name
        {   
            double precision = 0.0001;
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
            if (doc != null)
            {
                PromptEntityOptions peo = new PromptEntityOptions("\nselect polyline");
                peo.SetRejectMessage("\nYou're missing, try again >>");
                peo.AddAllowedClass(typeof(Polyline), true);
                PromptEntityResult res = ed.GetEntity(peo);
                if (res.Status != PromptStatus.OK)
                    return;
                ObjectId plineId = res.ObjectId;

                if (!plineId.IsValid && plineId.IsErased && plineId.IsNull && plineId.IsEffectivelyErased)
                    return;

                using (Transaction acTrans = doc.TransactionManager.StartTransaction())
                {
                    if (!CCWHub.plineCCW.IsCCWstraigtorarc(acTrans, plineId, precision))
                    {
                        //plinesToReverse.Add(plineId);
                        ed.WriteMessage("\nNo");
                    }
                    else
                    {
                        ed.WriteMessage("\nYes");
                    }
                }
            }
        }

 

 

 

Message 26 of 31
VladPaly
in reply to: VladPaly

Code works for polylines. Dxf name is lwpolyline.

Normal is 001

no self-intersections or duplicated points

Message 27 of 31
VladPaly
in reply to: VladPaly

Polyline should be closed

Message 28 of 31

@VladPaly

 

Are you sure your code better than the code @_gile ?

 

 

 

Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"


Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
Expert Elite Member

Message 29 of 31

I have same function IsCCWnoarcs.

The angle or area method don't make practically any difference.

May method can pass all test cases in the attached drawing.

 

 

Message 30 of 31
VladPaly
in reply to: VladPaly

correction for function 

 

 

public static Boolean IsCCWstraigtorarc(Transaction acTrans, ObjectId plineId, double precision)
        {
            Boolean isCCW = false;

            Polyline acPoly = (Polyline)acTrans.GetObject(plineId, OpenMode.ForRead);
            //Polyline doesn't have any arcs
            if (!acPoly.HasBulges)
            {
                isCCW = IsCCWnoarcs(acPoly, precision);
                return isCCW;
            }
            else
            //at least one arc
            {
                Extents3d acPolyBB = acPoly.GeometricExtents;
                double
                    bbMinX = acPolyBB.MinPoint.X,
                    bbMinY = acPolyBB.MinPoint.Y,
                    bbMaxX = acPolyBB.MaxPoint.X,
                    bbMaxY = acPolyBB.MaxPoint.Y;

                #region check for convex arcs touching bounding box
                for (int i = 0; i < acPoly.NumberOfVertices; i++)
                {

                    if (acPoly.GetSegmentType(i) == SegmentType.Arc)
                    {
                        double curBulge = acPoly.GetBulgeAt(i);
                        CircularArc2d circularArc2d = acPoly.GetArcSegment2dAt(i);

                        Point2d
                            StartPoint = circularArc2d.StartPoint,
                            EndPoint = circularArc2d.EndPoint,
                            Center = circularArc2d.Center;

                        double
                            StartAngle = (StartPoint.GetAsVector() - Center.GetAsVector()).Angle,
                            EndAngle = (EndPoint.GetAsVector() - Center.GetAsVector()).Angle,
                            Radius = circularArc2d.Radius,
                            totalAngle = circularArc2d.EndAngle;

                        #region angle correction
                        if (curBulge > 0)
                        {
                            if (IsEqual(StartAngle, Math.PI * 2, precision))
                                StartAngle = 0;
                            if (IsEqual(EndAngle, 0, precision))
                                EndAngle = Math.PI * 2;
                        }
                        else
                        {
                            if (IsEqual(StartAngle, 0, precision))
                                StartAngle = Math.PI * 2;
                            if (IsEqual(EndAngle, Math.PI * 2, precision))
                                EndAngle = 0;
                        }
                        #endregion angle correction

                        #region quadrants 
                        double
                            eastQuadrant = Center.X + Radius,
                            northQuadrant = Center.Y + Radius,
                            westQuadrant = Center.X - Radius,
                            southQuadrant = Center.Y - Radius;
                        #endregion quadrants

                        #region check for quadrants
                        //0
                        if (!IsEqual(eastQuadrant, StartPoint.X, precision) && !IsEqual(eastQuadrant, EndPoint.X, precision) &&
                            ((StartAngle > EndAngle && curBulge > 0) || (StartAngle < EndAngle && curBulge < 0))
                            && IsEqual(eastQuadrant, bbMaxX, precision))
                        {
                            isCCW = !circularArc2d.IsClockWise;
                            return isCCW;
                        }
                        //90
                        else if
                            (!IsEqual(northQuadrant, StartPoint.Y, precision) && !IsEqual(northQuadrant, EndPoint.Y, precision) &&
                            ((StartAngle < Math.PI * 0.5 && Math.PI * 0.5 < EndAngle && curBulge > 0) || (EndAngle < Math.PI * 0.5 && Math.PI * 0.5 < StartAngle && curBulge < 0)) &&
                            IsEqual(northQuadrant, bbMaxY, precision))
                        {
                            isCCW = !circularArc2d.IsClockWise;
                            return isCCW;
                        }
                        //180
                        else if
                            (!IsEqual(westQuadrant, StartPoint.X, precision) && !IsEqual(westQuadrant, EndPoint.X, precision) &&
                            ((StartAngle < Math.PI && Math.PI < EndAngle && curBulge > 0) || (EndAngle < Math.PI && Math.PI < StartAngle && curBulge < 0)) &&
                            IsEqual(westQuadrant, bbMinX, precision))
                        {
                            isCCW = !circularArc2d.IsClockWise;
                            return isCCW;
                        }
                        //270
                        else if
                            (!IsEqual(southQuadrant, StartPoint.Y, precision) && !IsEqual(southQuadrant, EndPoint.Y, precision) &&
                            ((StartAngle < Math.PI * 1.5 && Math.PI * 1.5 < EndAngle && curBulge > 0) || (EndAngle < Math.PI * 1.5 && Math.PI * 1.5 < StartAngle && curBulge < 0)) &&
                            IsEqual(southQuadrant, bbMinY, precision))
                        {
                            isCCW = !circularArc2d.IsClockWise;
                            return isCCW;
                        }
                        #endregion check for quadrants 
                    }
                }
                #endregion check for convex arcs touching bounding box

                Point2dCollection points =GetPoints2D(acPoly);
                //lrpInd - Lowest Rightest Point Index
                //plrpInd - previous to lrpInd
                //nlrpInd - next of lrpInd
                int lrpInd = GetLowestRightestPointInd(points, precision),
                    plrpInd = (lrpInd == 0) ? points.Count - 1 : lrpInd - 1,
                    nlrpInd = (lrpInd == points.Count - 1) ? 0 : lrpInd + 1;


                Point2d
                    curPoint = acPoly.GetPoint2dAt(lrpInd),
                    prevPoint = acPoly.GetPoint2dAt(plrpInd),
                    nextPoint = acPoly.GetPoint2dAt(nlrpInd);

                if (acPoly.GetSegmentType(lrpInd) == SegmentType.Line && acPoly.GetSegmentType(plrpInd) == SegmentType.Line)
                {
                    double
                        curAngle = (nextPoint.GetAsVector() - curPoint.GetAsVector()).Angle,
                        prevAngle = (prevPoint.GetAsVector() - curPoint.GetAsVector()).Angle;
                    isCCW = (prevAngle > curAngle) ? true : false;
                    return isCCW;
                }
                else if (acPoly.GetSegmentType(lrpInd) == SegmentType.Line && acPoly.GetSegmentType(plrpInd) == SegmentType.Arc)
                {
                    int indStart = plrpInd;
                    int indEnd = lrpInd;
                    int indToCheck = nlrpInd;

                    Boolean IsIn = IsPointBelongToLWPlineArcSegment(acPoly, indStart, indEnd, acPoly.GetPoint2dAt(indToCheck), precision);
                    //ed.WriteMessage("\n Is in =" + IsIn.ToString());

                    if (IsIn)
                    {
                        CircularArc2d circularArc2d = acPoly.GetArcSegment2dAt(indStart);
                        isCCW = !circularArc2d.IsClockWise;
                        return isCCW;
                    }
                    else
                    {
                        double
                            curAngle = (nextPoint.GetAsVector() - curPoint.GetAsVector()).Angle,
                            prevAngle = (prevPoint.GetAsVector() - curPoint.GetAsVector()).Angle;
                        isCCW = (prevAngle > curAngle) ? true : false;
                        return isCCW;
                    }
                    //ed.WriteMessage("\n isCCW =" + isCCW.ToString());


                }
                else if (acPoly.GetSegmentType(lrpInd) == SegmentType.Arc && acPoly.GetSegmentType(plrpInd) == SegmentType.Line)
                {
                    int indStart = lrpInd;
                    int indEnd = nlrpInd;
                    int indToCheck = plrpInd;

                    Boolean IsIn = IsPointBelongToLWPlineArcSegment(acPoly, indStart, indEnd, acPoly.GetPoint2dAt(indToCheck), precision);
                    if (IsIn)
                    {
                        CircularArc2d circularArc2d = acPoly.GetArcSegment2dAt(indStart);
                        isCCW = !circularArc2d.IsClockWise;
                        return isCCW;
                    }
                    else
                    {
                        double
                            curAngle = (nextPoint.GetAsVector() - curPoint.GetAsVector()).Angle,
                            prevAngle = (prevPoint.GetAsVector() - curPoint.GetAsVector()).Angle;
                        isCCW = (prevAngle > curAngle) ? true : false;
                        return isCCW;
                    }
                    //ed.WriteMessage("\n isCCW =" + isCCW.ToString());

                }
                else if (acPoly.GetSegmentType(lrpInd) == SegmentType.Arc && acPoly.GetSegmentType(plrpInd) == SegmentType.Arc)
                {
                    CircularArc2d curArc = acPoly.GetArcSegment2dAt(lrpInd);
                    Point2d curCenter = curArc.Center;
                    double curTangentAngle = (curCenter.GetAsVector() - curPoint.GetAsVector()).Angle - Math.PI * 0.5;
                    CircularArc2d prevArc = acPoly.GetArcSegment2dAt(plrpInd);
                    Point2d preCenter = prevArc.Center;
                    double preTangentAngle = (preCenter.GetAsVector() - curPoint.GetAsVector()).Angle - Math.PI * 0.5;

                    #region moon condition
                    if (IsEqualacPoints(nextPoint, prevPoint, precision))
                    {
                        return (curArc.Radius < prevArc.Radius) ? !curArc.IsClockWise : !prevArc.IsClockWise;
                    }
                    #endregion moon condition

                    #region previous point in curent segmentc
                    int indStart = lrpInd;
                    int indEnd = nlrpInd;
                    int indToCheck = plrpInd;
                    Boolean IsIn = IsPointBelongToLWPlineArcSegment(acPoly, indStart, indEnd, acPoly.GetPoint2dAt(indToCheck), precision);
                    if (IsIn)
                        return !curArc.IsClockWise;
                    #endregion previous point in curent segmentc

                    #region next point in previous segmentc
                    indStart = plrpInd;
                    indEnd = lrpInd;
                    indToCheck = nlrpInd;
                    IsIn = IsPointBelongToLWPlineArcSegment(acPoly, indStart, indEnd, acPoly.GetPoint2dAt(indToCheck), precision);
                    if (IsIn)
                        return !prevArc.IsClockWise;
                    #endregion next point in previous segment

                    #region triangle method
                    double
                         curAngle = (nextPoint.GetAsVector() - curPoint.GetAsVector()).Angle,
                         prevAngle = (prevPoint.GetAsVector() - curPoint.GetAsVector()).Angle;
                    isCCW = (prevAngle > curAngle) ? true : false;
                    return isCCW;
                    #endregion triangle method
                }
            }

            return isCCW;
        }

 

Message 31 of 31

Code of @_gile  works fine.

I think his code is more elegant. 

I didn't pay attention, that problem is solved.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost