예제 #1
0
        /***************************************************/

        private static int CollapseToPolylineCount(this Arc curve, double angleTolerance, int maxSegmentCount = 100)
        {
            double angle  = curve.Angle();
            double factor = Math.Min(Math.PI * 0.25, Math.Max(angle * 0.5 / maxSegmentCount, angleTolerance));

            return(System.Convert.ToInt32(Math.Ceiling(angle * 0.5 / factor)));
        }
예제 #2
0
        /***************************************************/

        public static Vector Normal(this Arc arc)
        {
            if (arc.Angle() > 0)
            {
                return(arc.CoordinateSystem.Z);
            }
            else
            {
                return(arc.CoordinateSystem.Z.Reverse());
            }
        }
예제 #3
0
파일: Normal.cs 프로젝트: BHoM/BHoM_Engine
 public static Vector Normal(this Arc curve, double tolerance = Tolerance.Distance)
 {
     if (curve.Angle() > 0)
     {
         return(curve.CoordinateSystem.Z);
     }
     else
     {
         return(curve.CoordinateSystem.Z.Reverse());
     }
 }
예제 #4
0
        /***************************************************/

        public static double Area(this PolyCurve curve)
        {
            if (curve.Curves.Count == 1 && curve.Curves[0] is Circle)
            {
                return((curve.Curves[0] as Circle).Area());
            }

            if (!curve.IsClosed())
            {
                return(0);
            }

            Plane p = curve.FitPlane();

            if (p == null)
            {
                return(0.0);              // points are collinear
            }
            Point  sPt  = curve.StartPoint();
            double area = 0;

            foreach (ICurve c in curve.SubParts())
            {
                if (c is NurbsCurve)
                {
                    throw new NotImplementedException("Area of NurbsCurve is not imlemented yet so the area of this PolyCurve cannot be calculated");
                }

                Point  ePt  = c.IEndPoint();
                Vector prod = CrossProduct(sPt - p.Origin, ePt - p.Origin);
                area += prod * p.Normal * 0.5;

                if (c is Arc)
                {
                    Arc    arc     = c as Arc;
                    double radius  = arc.Radius;
                    double angle   = arc.Angle();
                    double arcArea = (angle - Math.Sin(angle)) * radius * radius * 0.5;

                    if (arc.CoordinateSystem.Z.DotProduct(p.Normal) > 0)
                    {
                        area += arcArea;
                    }
                    else
                    {
                        area -= arcArea;
                    }
                }

                sPt = ePt.Clone();
            }

            return(Math.Abs(area));
        }
예제 #5
0
        /***************************************************/

        private static double IntegrateRegion(Arc arc, int powX, double tol = Tolerance.Distance)
        {
            Point  centre = arc.CoordinateSystem.Origin;
            double r      = arc.Radius;
            Point  start  = arc.StartPoint();
            Point  end    = arc.EndPoint();

            double a = Vector.XAxis.Angle(start - centre, Plane.XY);

            double k = Math.Abs(arc.Angle());

            if ((start - centre).CrossProduct(arc.StartDir()).Z < 0)
            {
                k *= -1;
            }

            switch (powX)
            {
            case 0:
                return(
                    centre.X * r * (-Math.Sin(a) + Math.Sin(a + k)) +
                    (r * r * (2 * k - Math.Sin(2 * a) + Math.Sin(2 * (a + k)))
                    ) / 4);

            /********************/
            case 1:
                return((r * (
                            (Math.Sin(3 * (k + a)) + 9 * Math.Sin(k + a) -
                             Math.Sin(3 * a) - 9 * Math.Sin(a)) * r * r +
                            6 * (Math.Sin(2 * (k + a)) + 2 * k - Math.Sin(2 * a)) * centre.X * r +
                            12 * (Math.Sin(k + a) - Math.Sin(a)) * centre.X * centre.X
                            )) / 24);

            /********************/
            case 2:
                return((r * (
                            (Math.Sin(4 * (k + a)) + 8 * Math.Sin(2 * (k + a)) + 12 * k - Math.Sin(4 * a) -
                             8 * Math.Sin(2 * a)) * r * r * r -
                            32 * (Math.Sin(k + a) * (Math.Sin(k + a) * Math.Sin(k + a) - 3) +
                                  (Math.Cos(a) * Math.Cos(a) + 2) * Math.Sin(a)) * centre.X * r * r +
                            24 * (Math.Sin(2 * (k + a)) + 2 * k - Math.Sin(2 * a)) * centre.X * centre.X * r +
                            32 * (Math.Sin(k + a) - Math.Sin(a)) * centre.X * centre.X * centre.X
                            )) / 96);

            /********************/
            default:
                return(IntegrateRegion(arc.CollapseToPolyline(0.01), powX, tol));    //TODO is this good value??
            }
        }
예제 #6
0
        /***************************************************/

        public static List <Point> LineIntersections(this Arc arc, Line line, bool useInfiniteLine = false, double tolerance = Tolerance.Distance)
        {
            Line l = line.DeepClone();

            l.Infinite = useInfiniteLine ? true : l.Infinite;

            List <Point> iPts     = new List <Point>();
            Point        midPoint = arc.PointAtParameter(0.5);

            Point center = arc.Centre();

            //Check if curves are coplanar
            if (Math.Abs(arc.CoordinateSystem.Z.DotProduct(l.Direction())) > Tolerance.Angle)
            {
                //Curves not coplanar
                Point pt = l.PlaneIntersection((Plane)arc.CoordinateSystem);
                if (pt != null && Math.Abs(pt.Distance(center) - arc.Radius) <= tolerance)
                {
                    iPts.Add(pt);
                }
            }
            else
            {
                //Curves coplanar
                Circle c = new Circle {
                    Centre = center, Normal = arc.CoordinateSystem.Z, Radius = arc.Radius
                };
                iPts = c.LineIntersections(l);
            }

            List <Point> output = new List <Point>();

            double halfAngle = arc.Angle() / 2;
            double tolAngle  = tolerance / arc.Radius;
            double sqrd      = 2 * Math.Pow(arc.Radius, 2) * (1 - Math.Cos(Math.Abs(halfAngle + tolAngle))); // Cosine rule

            {
                foreach (Point pt in iPts)
                {
                    if ((l.Infinite || pt.Distance(l) <= tolerance) && midPoint.SquareDistance(pt) <= sqrd)
                    {
                        output.Add(pt);
                    }
                }
            }

            return(output);
        }
예제 #7
0
        /***************************************************/
        /**** Public Methods - Curves                   ****/
        /***************************************************/

        public static Point PointAtParameter(this Arc curve, double t)
        {
            if (t < 0)
            {
                t = 0;
            }
            if (t > 1)
            {
                t = 1;
            }

            double alfa   = curve.Angle() * t + curve.StartAngle;
            Vector localX = curve.CoordinateSystem.X;

            return(curve.CoordinateSystem.Origin + localX.Rotate(alfa, curve.FitPlane().Normal) * curve.Radius);
        }
예제 #8
0
        /***************************************************/
        /**** public Methods - Vectors                  ****/
        /***************************************************/

        public static List <Point> SortAlongCurve(this List <Point> points, Arc arc, double distanceTolerance = Tolerance.Distance, double angleTolerance = Tolerance.Angle)
        {
            if (arc.Angle() <= angleTolerance)
            {
                return(points.Select(p => p.Clone()).ToList());
            }

            List <Tuple <Point, double> > cData = points.Select(p => new Tuple <Point, double>(p.Clone(), arc.ParameterAtPoint(arc.ClosestPoint(p)))).ToList();

            cData.Sort(delegate(Tuple <Point, double> d1, Tuple <Point, double> d2)
            {
                return(d1.Item2.CompareTo(d2.Item2));
            });

            return(cData.Select(d => d.Item1).ToList());
        }
예제 #9
0
        /***************************************************/

        public static string ToSVGString(this Arc arc)
        {
            int    largeArcFlag = System.Convert.ToInt32((arc.Angle() > Math.PI));
            int    sweepFlag    = System.Convert.ToInt32(!arc.IsClockwise(Vector.ZAxis));
            Point  start        = arc.StartPoint();
            Point  end          = arc.EndPoint();
            string arcString    = "<path d=\"M" + start.X.ToString()
                                  + "," + start.Y.ToString()
                                  + " A" + arc.Radius() + "," + arc.Radius()
                                  + " 0"
                                  + " " + largeArcFlag
                                  + "," + sweepFlag
                                  + " " + end.X.ToString()
                                  + "," + end.Y.ToString() + "\"/>";

            return(arcString);
        }
예제 #10
0
        /***************************************************/
        /**** Public Methods - Curves                   ****/
        /***************************************************/

        public static double ParameterAtPoint(this Arc curve, Point point, double tolerance = Tolerance.Distance)
        {
            if (curve.ClosestPoint(point).SquareDistance(point) > tolerance * tolerance)
            {
                return(-1);
            }

            Point  centre = curve.CoordinateSystem.Origin;
            Vector normal = curve.CoordinateSystem.Z;
            Vector v1     = curve.CoordinateSystem.X;
            Vector v2     = point - centre;

            double angle = v1.SignedAngle(v2, normal) - curve.StartAngle;

            angle = Math.Abs(angle) < Tolerance.Angle ? 0 : angle;  //Really small negative angles gives wrong result. This solves that problem.
            return(((angle + 2 * Math.PI) % (2 * Math.PI)) / curve.Angle());
        }
예제 #11
0
        /***************************************************/

        public static string ToSVGString(this Arc arc)
        {
            if (arc == null)
            {
                BH.Engine.Reflection.Compute.RecordError("Cannot convert a null arc to SVG string.");
                return("");
            }

            int    largeArcFlag = System.Convert.ToInt32((arc.Angle() > Math.PI));
            int    sweepFlag    = System.Convert.ToInt32(!arc.IsClockwise(Vector.ZAxis));
            Point  start        = arc.StartPoint();
            Point  end          = arc.EndPoint();
            string arcString    = "<path d=\"M" + start.X.ToString()
                                  + "," + start.Y.ToString()
                                  + " A" + arc.Radius + "," + arc.Radius
                                  + " 0"
                                  + " " + largeArcFlag
                                  + "," + sweepFlag
                                  + " " + end.X.ToString()
                                  + "," + end.Y.ToString() + "\"/>";

            return(arcString);
        }
예제 #12
0
        public static double Area(this PolyCurve curve, double tolerance = Tolerance.Distance)
        {
            if (curve == null)
            {
                BH.Engine.Reflection.Compute.RecordError("Cannot query area as the geometry is null.");
                return(double.NaN);
            }

            if (curve.Curves.Count == 1 && curve.Curves[0] is Circle)
            {
                return((curve.Curves[0] as Circle).Area(tolerance));
            }

            if (!curve.IsClosed(tolerance))
            {
                Reflection.Compute.RecordWarning("Cannot calculate area for an open curve.");
                return(0);
            }

            Plane p = curve.FitPlane(tolerance);

            if (p == null)
            {
                return(0.0);              // points are collinear
            }
            Point  sPt  = curve.StartPoint();
            double area = 0;

            foreach (ICurve c in curve.SubParts())
            {
                if (c is NurbsCurve)
                {
                    Reflection.Compute.RecordError("Area for NurbsuCurve is not implemented.");
                    return(double.NaN);
                }
                Point  ePt  = c.IEndPoint();
                Vector prod = CrossProduct(sPt - p.Origin, ePt - p.Origin);
                area += prod * p.Normal * 0.5;

                if (c is Arc)
                {
                    Arc    arc     = c as Arc;
                    double radius  = arc.Radius;
                    double angle   = arc.Angle();
                    double arcArea = (angle - Math.Sin(angle)) * radius * radius * 0.5;

                    if (arc.CoordinateSystem.Z.DotProduct(p.Normal) > 0)
                    {
                        area += arcArea;
                    }
                    else
                    {
                        area -= arcArea;
                    }
                }

                sPt = ePt.DeepClone();
            }

            return(Math.Abs(area));
        }
예제 #13
0
        public static Arc RoundCoordinates(this Arc arc, int decimalPlaces = 6)
        {
            // do the rounding
            Point start = arc.StartPoint().RoundCoordinates(decimalPlaces);
            Point end   = arc.EndPoint().RoundCoordinates(decimalPlaces);

            double angle = arc.Angle();
            double dist  = start.Distance(end);

            if (dist == 0)
            {
                // translate the origin as one of the points were, and set both angles to that ones angle
                return(new Arc()
                {
                    CoordinateSystem = arc.CoordinateSystem.Translate(start - arc.StartPoint()),
                    Radius = arc.Radius,
                    StartAngle = arc.StartAngle,
                    EndAngle = arc.StartAngle,
                });
            }

            // recalculate the radius based on not changing the total angle
            //      Consider a equal legged triangle with endpoints at the arc's endpoints
            //      we know the "top" angle and the "base" length and are solving for the last two sides length
            double radius = Math.Sqrt(
                Math.Pow(dist / (2 * Math.Tan(angle / 2)), 2) + // "Height"
                Math.Pow(dist / 2, 2)                           // "half the base"
                );

            // Align the normal to the new endpoints
            Vector normal = arc.CoordinateSystem.Z.CrossProduct(end - start).CrossProduct(start - end).Normalise();

            Circle startCircle = new Circle()
            {
                Normal = normal, Centre = start, Radius = radius
            };
            Circle endCircle = new Circle()
            {
                Normal = normal, Centre = end, Radius = radius
            };

            List <Point> intersections = startCircle.CurveIntersections(endCircle).OrderBy(x => x.SquareDistance(arc.CoordinateSystem.Origin)).ToList();

            Point newOrigin = null;

            // 180degrees arc where the points got rounded away from eachother
            if (intersections.Count == 0)
            {
                newOrigin = (start + end) / 2;
                radius    = newOrigin.Distance(start);
            }
            else
            {
                // Ensure that the new centre is at the same side of the start/end points
                Vector unitNormal = normal.Normalise();
                unitNormal *= angle > Math.PI ? -1 : 1;
                foreach (Point pt in intersections)
                {
                    Vector temp = (start - pt).CrossProduct(end - pt).Normalise();
                    if ((temp + unitNormal).SquareLength() >= 1)
                    {
                        newOrigin = pt;
                        break;
                    }
                }
            }

            Vector newX = (start - newOrigin).Normalise();

            oM.Geometry.CoordinateSystem.Cartesian coordClone = Create.CartesianCoordinateSystem(newOrigin, newX, Query.CrossProduct(normal, newX));

            double endAngle = (start - newOrigin).Angle(end - newOrigin);

            endAngle = angle > Math.PI ? 2 * Math.PI - endAngle : endAngle;

            Arc result = new Arc()
            {
                CoordinateSystem = coordClone,
                Radius           = radius,
                StartAngle       = 0,
                EndAngle         = endAngle,
            };

            return(result);
        }
예제 #14
0
        /***************************************************/
        /**** Public Methods - Curves                   ****/
        /***************************************************/

        public static bool IsClosed(this Arc arc, double tolerance = Tolerance.Distance)
        {
            return((arc.Angle() - Math.PI * 2) * arc.Radius > -tolerance);
        }
예제 #15
0
        /***************************************************/
        /**** Public Methods - Curves                   ****/
        /***************************************************/

        public static double Length(this Arc curve)
        {
            return(curve.Angle() * curve.Radius());
        }
예제 #16
0
        /***************************************************/

        public static bool IsClockwise(this Arc arc, Vector axis, double tolerance = Tolerance.Distance)
        {
            Vector normal = arc.CoordinateSystem.Z;

            return((normal.DotProduct(axis) < 0) != (arc.Angle() > Math.PI));
        }
예제 #17
0
    // Obstructions, must check line and arc intersection
    override protected bool Obstructed(
        IEnumerable <Polygon> polys, Vector3 startPos)
    {
        Vector3 newPoint = this.PredictPosition(startPos);
        Vector2 sp       = new Vector2(startPos.x, startPos.z);
        Vector2 np       = new Vector2(newPoint.x, newPoint.z);

        // Length of the car
        float L = KinematicCarState.L;

        if (omega == 0.0f)                      // Check straight line intersection
        {
            Vector2 transVec = (np - sp).normalized * L;
            Vector2 midPoint = (sp + np) / 2;
            // TODO midPoint not necessary if you fix arc
            Edge e = new Edge(sp, np + transVec);                       // TODO check correctness
            foreach (Polygon p in polys)
            {
                if (p.Intersects(e) || p.IsInside(midPoint))
                {
                    return(true);
                }
            }
        }
        else                                            // Check arc intersection
        // Center of turning circle
        {
            Vector3 center = startPos + centerOff;
            Vector2 cp     = new Vector2(center.x, center.z);
            Vector2 cenToS = sp - cp;
            Vector2 cenToN = np - cp;

            // Angles of the arc
            float a1, a2;
            if (omega < 0)
            {
                a1 = Arc.Angle(Vector2.right, cenToS);
                a2 = Arc.Angle(Vector2.right, cenToN);
            }
            else
            {
                a1 = Arc.Angle(Vector2.right, cenToN);
                a2 = Arc.Angle(Vector2.right, cenToS);
            }

            /*Vector2 normal = Quaternion.Euler(0, 90, 0) * (sp - np);
             * float na = (a1 + a2) / 2;
             * Vector2 aaa2 = cp + normal * r;
             * Vector2 aaa3 = cp - normal * r;
             * float aaaa2 = Arc.Angle(Vector2.right, aaa2);
             * float aaaa3 = Arc.Angle(Vector2.right, aaa3);
             * Vector2 ffff = aaa2;
             * if (a1 < a2) {
             *      if (aaaa2 > a1 && aaaa2 < a2) {
             *              ffff = aaa2;
             *      }
             *      if (aaaa3 > a1 && aaaa3 < a2) {
             *              ffff = aaa3;
             *      }
             * } else {
             *      if (aaaa2 > a1 && aaaa2 < a2 && aaaa2 < 360 && aaaa2 > 0) {
             *              ffff = aaa2;
             *      }
             *      if (aaaa3 > a1 && aaaa3 < a2 && aaaa3 < 360 && aaaa3 > 0) {
             *              ffff = aaa3;
             *      }
             * }*/
            // Checking the front of the vehicle
            Vector3 transVec   = velocity.normalized * L;
            Vector3 cenToFront = -centerOff + transVec;
            float   frontR     = cenToFront.magnitude;
            float   diffAngle  = Tangents.RotationAngle(-centerOff, cenToFront);

            // Check if arc intersects with any of the polygons
            Arc arc = new Arc(cp, r, a1, a2);
            // TODO check correctness, if it is - or + diffAngle
            Arc frontArc = new Arc(cp, frontR, a1 - diffAngle, a2 - diffAngle);
            foreach (Polygon p in polys)
            {
                if (p.Intersects(arc) || p.Intersects(frontArc))
                {
                    return(true);
                }
            }
        }
        return(false);
    }
예제 #18
0
        /***************************************************/
        /**** Public Methods - Curves                   ****/
        /***************************************************/

        public static double Area(this Arc curve)
        {
            return(curve.IsClosed() ? curve.Angle() * Math.Pow(curve.Radius(), 2) : 0);
        }