Example #1
0
        public Tuple <PrimitiveBezier, PrimitiveBezier> Split(double t)
        {
            // Splitting the curve using de Casteljau's algorithm: https://pomax.github.io/bezierinfo/#decasteljau
            if (t < 0.0 || t > 1.0)
            {
                throw new ArgumentOutOfRangeException(nameof(t), "Curves can only be split on the interval [0.0, 1.0].");
            }

            var midPoint        = ComputeParameterizedPoint(t);
            var midControlPoint = Point.ScaledAlongPath(P2, P3, t);

            // compute the first curve part
            var newP2  = Point.ScaledAlongPath(P1, P2, t);
            var newP3  = Point.ScaledAlongPath(newP2, midControlPoint, t);
            var newP4  = midPoint;
            var curve1 = new PrimitiveBezier(P1, newP2, newP3, newP4);

            // compute the second curve part
            var newP1 = midPoint;

            newP3 = Point.ScaledAlongPath(P3, P4, t);
            newP2 = Point.ScaledAlongPath(midControlPoint, newP3, t);
            var curve2 = new PrimitiveBezier(newP1, newP2, newP3, P4);

            return(Tuple.Create(curve1, curve2));
        }
Example #2
0
        /// <summary>
        /// Approximate the given Bezier curve as lines and arcs.
        /// </summary>
        internal static IPrimitive[] AsSimplePrimitives(PrimitiveBezier bezier)
        {
            var simplePrimitives = new List <IPrimitive>();
            var intervals        = new Queue <Tuple <double, double, int> >();

            intervals.Enqueue(Tuple.Create(0.0, 1.0, 0));
            while (intervals.Count > 0)
            {
                var interval          = intervals.Dequeue();
                var intervalStart     = interval.Item1;
                var intervalEnd       = interval.Item2;
                var currentSplitCount = interval.Item3;
                var intervalSpread    = intervalEnd - intervalStart;
                var intervalMid       = intervalStart + (intervalSpread * 0.5);
                var pStart            = bezier.ComputeParameterizedPoint(intervalStart);
                var pMid               = bezier.ComputeParameterizedPoint(intervalMid);
                var pEnd               = bezier.ComputeParameterizedPoint(intervalEnd);
                var intervalLine       = new PrimitiveLine(pStart, pEnd);
                var candidatePrimitive = intervalLine.IsPointOnPrimitive(pMid, MathHelper.BezierEpsilon)
                    ? (IPrimitive)intervalLine
                    : PrimitiveEllipse.ThreePointArc(pStart, pMid, pEnd, idealNormal: Vector.ZAxis);
                candidatePrimitive = candidatePrimitive ?? intervalLine; // ensure it has a value

                var intervalFirstQuarter = intervalStart + (intervalSpread * 0.25);
                var intervalThirdQuarter = intervalStart + (intervalSpread * 0.75);
                var pFirstQuarter        = bezier.ComputeParameterizedPoint(intervalFirstQuarter);
                var pThirdQuarter        = bezier.ComputeParameterizedPoint(intervalThirdQuarter);
                if (currentSplitCount >= MaximumPrimitiveSplitCount ||
                    (candidatePrimitive.IsPointOnPrimitive(pFirstQuarter, MathHelper.BezierEpsilon) &&
                     candidatePrimitive.IsPointOnPrimitive(pThirdQuarter, MathHelper.BezierEpsilon)))
                {
                    simplePrimitives.Add(candidatePrimitive);
                }
                else
                {
                    intervals.Enqueue(Tuple.Create(intervalStart, intervalMid, currentSplitCount + 1));
                    intervals.Enqueue(Tuple.Create(intervalMid, intervalEnd, currentSplitCount + 1));
                }
            }

            return(simplePrimitives.ToArray());
        }