public EllipsoidQuadraticForm(double A, double B, double C, double D, double E, double F, double G, double H, double I, double J)
        {
            var doubleUtils = new DoubleUtils(1e-12);
            if (doubleUtils.Sign(A) < 0) {
                A = -A;
                B = -B;
                C = -C;
                D = -D;
                E = -E;
                F = -F;
                G = -G;
                H = -H;
                I = -I;
                J = -J;
            }
            Requires.Positive(doubleUtils.Sign(A), "A");
            Requires.Positive(doubleUtils.Sign(B), "B");
            Requires.Positive(doubleUtils.Sign(C), "C");
            Requires.Positive(doubleUtils.Sign(A * B - D * D), "A * B - D * D");
            Requires.Positive(doubleUtils.Sign(A * C - E * E), "A * C - E * E");
            Requires.Positive(doubleUtils.Sign(B * C - F * F), "B * C - F * F");
            _coefficients = new[] { A, B, C, D, E, F, G, H, I, J };
            QuadraticFrom = new[,] {
                { A, D, E },
                { D, B, F },
                { E, F, C }
            };
            Offset = new[] { G, H, I, };

            var b = QuadraticFrom.Inverse().Multiply(Offset.Multiply(-1));
            var eigenDecomposition = new EigenvalueDecomposition(QuadraticFrom);
            var axisNumerator = b.ElementwiseMultiply(QuadraticFrom.Multiply(b)).Sum() - J;
            var xradius = System.Math.Sqrt(axisNumerator / eigenDecomposition.RealEigenvalues[0]);
            var yradius = System.Math.Sqrt(axisNumerator / eigenDecomposition.RealEigenvalues[1]);
            var zradius = System.Math.Sqrt(axisNumerator / eigenDecomposition.RealEigenvalues[2]);
            var rotation = eigenDecomposition.Eigenvectors;
            EllipsoidParametricForm = new EllipsoidParametricForm(xradius, yradius, zradius, new Point3D(b[0], b[1], b[2]), rotation);

            var sqrt = rotation.Multiply(eigenDecomposition.DiagonalMatrix.Sqrt().Multiply(rotation.Inverse()));
            AffineTransform = sqrt.Multiply(1.0 / System.Math.Sqrt(axisNumerator));
        }
 public bool IsInvertible(double epsilon)
 {
     return(!DoubleUtils.EpsilonEquals(getDeterminant(), epsilon));
 }
Example #3
0
        // Generate a curve coordinate extrapolator
        private static Func <Double2, Double4> CoordExtrapolator(CurveVertex[] vertices)
        {
            // Check for the length
            int vl = vertices.Length;

            if (vl == 1)
            {
                var v = vertices[0].CurveCoords;
                return(x => v);
            }
            // Extrapolate along the line
            else if (vl == 2)
            {
                var va = vertices[0];
                var vb = vertices[1];
                var dx = vb.Position - va.Position;

                return(delegate(Double2 x)
                {
                    var t = (x - va.Position).Dot(dx) / dx.LengthSquared;
                    return va.CurveCoords + t * (vb.CurveCoords - va.CurveCoords);
                });
            }
            // Extrapolate along a triangle
            else
            {
                // Choose a nonzero-area triangle
                int i = 0, ik = 1, ik2 = 2;
                for (; i < vl; i++)
                {
                    ik  = (i + 1) % vl;
                    ik2 = (i + 2) % vl;

                    var winding = vertices[i].Position.Cross(vertices[ik].Position)
                                  + vertices[ik].Position.Cross(vertices[ik2].Position)
                                  + vertices[ik2].Position.Cross(vertices[i].Position);

                    if (!DoubleUtils.RoughlyZeroSquared(winding))
                    {
                        break;
                    }
                }

                // If there is no nonzero-area triangle, choose the most distant vertices and pick their extrapolator
                if (i == vl)
                {
                    var imin = 0;
                    var imax = 0;

                    for (i = 1; i < vl; i++)
                    {
                        if (vertices[imin].Position.X > vertices[i].Position.X)
                        {
                            imin = i;
                        }
                        if (vertices[imax].Position.X < vertices[i].Position.X)
                        {
                            imax = i;
                        }
                    }

                    return(CoordExtrapolator(new[] { vertices[imin], vertices[imax] }));
                }

                var a   = vertices[i].Position;
                var dv1 = vertices[ik].Position - a;
                var dv2 = vertices[ik2].Position - a;
                var k   = dv1.Cross(dv2);

                var ta = vertices[i].CurveCoords;
                var tb = vertices[ik].CurveCoords;
                var tc = vertices[ik2].CurveCoords;

                return(delegate(Double2 x)
                {
                    var u = (x - a).Cross(dv2) / k;
                    var v = -(x - a).Cross(dv1) / k;
                    return ta + u * (tb - ta) + v * (tc - ta);
                });
            }
        }
Example #4
0
        internal static CompiledDrawing CompileCurves(List <Curve> curves, FillRule fillRule)
        {
            // Reunite all intersections to subdivide the curves
            var curveRootSets = new SortedDictionary <double, Double2> [curves.Count];

            for (int i = 0; i < curveRootSets.Length; i++)
            {
                curveRootSets[i] = new SortedDictionary <double, Double2>()
                {
                    [0] = curves[i].At(0), [1] = curves[i].At(1)
                }
            }
            ;

            // Get all intersections
            for (int i = 0; i < curves.Count; i++)
            {
                for (int j = i + 1; j < curves.Count; j++)
                {
                    foreach (var pair in Curve.Intersections(curves[i], curves[j]))
                    {
                        if (!GeometricUtils.Inside01(pair.A) || !GeometricUtils.Inside01(pair.B))
                        {
                            continue;
                        }

                        var a = curves[i].At(pair.A);
                        var b = curves[j].At(pair.B);

                        if (!DoubleUtils.RoughlyEquals(a / 16, b / 16))
                        {
                            //Console.WriteLine(string.Join(" ", Curve.Intersections(curves[i], curves[j]).Select(c => $"({c.A} {c.B})")));
                            Debug.Assert(false, "Problem here...");
                        }

                        curveRootSets[i][pair.A] = curveRootSets[j][pair.B] = (a + b) / 2;
                    }
                }
            }

            for (int i = 0; i < curves.Count; i++)
            {
                Curve.RemoveSimilarRoots(curveRootSets[i]);
            }

            // Finally, we can start building the DCEL
            var dcel = new DCEL.DCEL();

            for (int i = 0; i < curves.Count; i++)
            {
                KeyValuePair <double, Double2> prevPair = new KeyValuePair <double, Double2>(double.NaN, new Double2());
                foreach (var curPair in curveRootSets[i])
                {
                    if (!double.IsNaN(prevPair.Key))
                    {
                        Curve curve;
                        if (prevPair.Key == 0 && curPair.Key == 1)
                        {
                            curve = curves[i];
                        }
                        else
                        {
                            curve = curves[i].Subcurve(prevPair.Key, curPair.Key);
                        }

                        foreach (var c in curve.Simplify())
                        {
                            //if (c.IsDegenerate) continue;
                            dcel.AddCurve(c);
                            //Console.WriteLine(dcel);
                            //Console.ReadLine();
                        }
                    }

                    prevPair = curPair;
                }
            }

            //Console.WriteLine(dcel);
            //Console.ReadLine();

            // Now, we remove wedges and assign the fill numbers
            dcel.RemoveWedges();
            //Console.WriteLine(dcel);
            //Console.ReadLine();
            dcel.AssignFillNumbers();
            //Console.WriteLine(dcel);
            //Console.ReadLine();

            // Pick the appropriate predicate for the fill rule
            Func <DCEL.Face, bool> facePredicate;

            if (fillRule == FillRule.Evenodd)
            {
                facePredicate = f => f.FillNumber % 2 != 0;
            }
            else
            {
                facePredicate = f => f.FillNumber != 0;
            }

            // Simplify the faces
            dcel.SimplifyFaces(facePredicate);
            //Console.WriteLine(dcel);
            //Console.ReadLine();

            // Generate the filled faces
            var fills = dcel.Faces.Where(facePredicate).Select(face =>
                                                               new FillFace(face.Contours.Select(contour =>
                                                                                                 contour.CyclicalSequence.Select(e => e.Curve).ToArray()).ToArray()));

            // Generace the filled faces
            return(CompiledDrawing.ConcatMany(fills.Select(CompiledDrawing.FromFace)));
        }
 public void DoubleUtils_ToString5Test()
 {
     double?double1 = new double?(1.0);
     var    result  = DoubleUtils.ToString(double1, "0.0", "InvalideCulture");
 }
Example #6
0
 public static bool IsZero(this double self, int precision)
 {
     return(DoubleUtils.IsZero(self, precision));
 }
Example #7
0
 public static double Clamp(this double value, double min, double max)
 {
     return(DoubleUtils.Clamp(value, min, max));
 }
Example #8
0
 public static bool IsLessThanOrClose(this double self, double value)
 {
     return(DoubleUtils.LessThanOrClose(self, value));
 }
Example #9
0
 internal static double RoundToZero(this double self)
 {
     return(DoubleUtils.Round(self, RoundingMode.ToZero));
 }
Example #10
0
 public static bool AreClose(Point a, Point b)
 {
     return(DoubleUtils.AreClose(a.X, b.X, XamlConstants.LayoutComparisonPrecision) && DoubleUtils.AreClose(a.Y, b.Y, XamlConstants.LayoutComparisonPrecision));
 }
Example #11
0
 public bool IsUnit(double epsilon = EPSILON)
 {
     return(DoubleUtils.epsilonEquals(getLength(), 1, epsilon));
 }
//</editor-fold>

//<editor-fold defaultstate="collapsed" desc="private">
        private bool EpsilonEquals(float x, float y, double epsilon)
        {
            return(DoubleUtils.EpsilonEquals(this.x, x, epsilon) && DoubleUtils.EpsilonEquals(this.y, y, epsilon));
        }
Example #13
0
        private static bool IsStepValid(object value)
        {
            double num = (double)value;

            return(DoubleUtils.IsNaN(num) || (num >= 0.0 && !double.IsPositiveInfinity(num)));
        }
Example #14
0
        public string Format(string format, object arg, IFormatProvider formatProvider)
        {
            if (arg == null)
            {
                return(string.Empty);
            }

            if (arg is Keyword kw)
            {
                arg = kw.KeywordValue;
            }

            var provider = BaseProvider ?? CultureInfo.CurrentCulture;

            if (format == "X")
            {
                return(string.Format(provider, "0x{0:X}", arg));
            }
            if (format == "Xs")
            {
                return(string.Format(provider, "{0:X}", arg));
            }

            if (format == "PX")
            {
                switch (arg)
                {
                case byte x: return("0x" + x.ToString("X2", provider));

                case sbyte x: return("0x" + x.ToString("X2", provider));

                case ushort x: return("0x" + x.ToString("X4", provider));

                case short x: return("0x" + x.ToString("X4", provider));

                case uint x: return("0x" + x.ToString("X8", provider));

                case int x: return("0x" + x.ToString("X8", provider));

                case ulong x: return("0x" + x.ToString("X16", provider));

                case long x: return("0x" + x.ToString("X16", provider));

                case decimal x: return(x.ToString("N0", provider));

                case double x:
                    var clamped = DoubleUtils.ClampToUInt64(x);
                    return("0x" + clamped.ToString("X16", provider));
                }

                return(string.Format(provider, "0x{0:X}", arg));
            }

            if (format == "PXs")
            {
                switch (arg)
                {
                case byte x: return(x.ToString("X2", provider));

                case sbyte x: return(x.ToString("X2", provider));

                case ushort x: return(x.ToString("X4", provider));

                case short x: return(x.ToString("X4", provider));

                case uint x: return(x.ToString("X8", provider));

                case int x: return(x.ToString("X8", provider));

                case ulong x: return(x.ToString("X16", provider));

                case long x: return(x.ToString("X16", provider));

                case decimal x: return(x.ToString("N0", provider));

                case double x:
                    var clamped = DoubleUtils.ClampToUInt64(x);
                    return(clamped.ToString("X16", provider));
                }

                return(string.Format(provider, "{0:X}", arg));
            }

            if (format == "D0")
            {
                return(string.Format(provider, "{0:D0}", arg));
            }
            if (format == "N0")
            {
                return(string.Format(provider, "{0:N0}", arg));
            }
            if (format == "F0")
            {
                return(string.Format(provider, "{0:F0}", arg));
            }

            if (arg is IFormattable f)
            {
                return(f.ToString(format, provider));
            }

            return(arg.ToString());
        }
Example #15
0
 public static bool IsUnity(this Polynomial p)
 {
     return(DoubleUtils.MachineEquality(p.Coeffs[0], 1.0) &&
            p.Coeffs.Skip(1).All(DoubleUtils.EqualZero));
 }
Example #16
0
        /// <summary>
        /// Brenth algorithm from scipy
        /// </summary>
        public static double Brenth(Func <double, double> f,
                                    double xa, double fa, double xb, double fb,
                                    double xtol, double rtol, int maxIter,
                                    out int funcalls, out int iterations)
        {
            double xpre = xa;
            double xcur = xb;
            double fpre = fa;
            double fcur = fb;

            funcalls   = 0;
            iterations = 0;

            if (fpre * fcur > 0)
            {
                throw new Exception("Brent : root must be bracketed");
            }

            if (DoubleUtils.EqualZero(fpre))
            {
                return(xpre);
            }
            if (DoubleUtils.EqualZero(fcur))
            {
                return(xcur);
            }

            double xblk = 0.0, fblk = 0.0, spre = 0.0, scur = 0.0;

            for (int i = 0; i < maxIter; i++)
            {
                iterations++;
                if (fpre * fcur < 0)
                {
                    xblk = xpre;
                    fblk = fpre;
                    spre = scur = xcur - xpre;
                }
                if (Math.Abs(fblk) < Math.Abs(fcur))
                {
                    xpre = xcur;
                    xcur = xblk;
                    xblk = xpre;
                    fpre = fcur;
                    fcur = fblk;
                    fblk = fpre;
                }

                double tol  = xtol + rtol * Math.Abs(xcur);
                double sbis = (xblk - xcur) / 2.0;
                if (DoubleUtils.EqualZero(fcur) || Math.Abs(sbis) < tol)
                {
                    return(xcur);
                }

                if (Math.Abs(spre) > tol && Math.Abs(fcur) < Math.Abs(fpre))
                {
                    double stry;
                    if (DoubleUtils.MachineEquality(xpre, xblk))
                    {
                        // interpolate
                        stry = -fcur * (xcur - xpre) / (fcur - fpre);
                    }
                    else
                    {
                        // extrapolate
                        double dpre = (fpre - fcur) / (xpre - xcur);
                        double dblk = (fblk - fcur) / (xblk - xcur);

                        stry = -fcur * (fblk - fpre) / (fblk * dpre - fpre * dblk);
                    }

                    if (2.0 * Math.Abs(stry) < Math.Min(Math.Abs(spre), 3.0 * Math.Abs(sbis) - tol))
                    {
                        // accept step
                        spre = scur;
                        scur = stry;
                    }
                    else
                    {
                        // bisect
                        spre = sbis;
                        scur = sbis;
                    }
                }
                else
                {
                    // bisect
                    spre = sbis;
                    scur = sbis;
                }

                xpre = xcur;
                fpre = fcur;
                if (Math.Abs(scur) > tol)
                {
                    xcur += scur;
                }
                else
                {
                    xcur += (sbis > 0.0 ? tol : -tol);
                }

                fcur = f(xcur);
                funcalls++;
            }
            throw new Exception("Brent : max iteration excedeed");
        }
Example #17
0
 public static bool IsGreaterThanOrClose(this double self, double value)
 {
     return(DoubleUtils.GreaterThanOrClose(self, value));
 }
Example #18
0
 internal static double RoundFromZero(this double self, int precision)
 {
     return(DoubleUtils.Round(self, precision, RoundingMode.FromZero));
 }
Example #19
0
 public static bool IsLessThanOrClose(this double self, double value, int precision)
 {
     return(DoubleUtils.LessThanOrClose(self, value, precision));
 }
Example #20
0
 internal static double RoundMidPointFromZero(this double self)
 {
     return(DoubleUtils.Round(self, RoundingMode.MidPointFromZero));
 }
Example #21
0
 public static bool IsZero(this double self)
 {
     return(DoubleUtils.IsZero(self));
 }
Example #22
0
 public static double Clamp(this double value, Range <double> range)
 {
     return(DoubleUtils.Clamp(value, range));
 }
Example #23
0
        protected override Path ParsePath(Dictionary <string, string> properties)
        {
            // Get the attributes of the rectangle
            var x      = DoubleUtils.TryParse(properties.GetOrDefault("x")) ?? 0;
            var y      = DoubleUtils.TryParse(properties.GetOrDefault("y")) ?? 0;
            var width  = DoubleUtils.TryParse(properties.GetOrDefault("width")) ?? 0;
            var height = DoubleUtils.TryParse(properties.GetOrDefault("height")) ?? 0;

            var radii = new Double2();

            radii.X = DoubleUtils.TryParse(properties.GetOrDefault("rx")) ?? double.NaN;
            radii.Y = DoubleUtils.TryParse(properties.GetOrDefault("ry")) ?? double.NaN;

            // Quit on invalid values
            if (width <= 0 || height <= 0)
            {
                return(new Path());
            }

            // Check both radii
            if (double.IsNaN(radii.X) && double.IsNaN(radii.Y))
            {
                radii.X = radii.Y = 0;
            }
            else if (double.IsNaN(radii.X))
            {
                radii.X = radii.Y;
            }
            else if (double.IsNaN(radii.Y))
            {
                radii.Y = radii.X;
            }

            // Take out the sign and clamp them
            radii.X = Math.Abs(radii.X);
            radii.Y = Math.Abs(radii.Y);

            if (radii.X > width / 2)
            {
                radii.X = width / 2;
            }
            if (radii.Y > height / 2)
            {
                radii.Y = height / 2;
            }

            // Now mount the path commands
            PathCommand[] pathCommands;
            if (radii.X == 0 || radii.Y == 0)
            {
                pathCommands = new[]
                {
                    PathCommand.MoveTo(new Double2(x, y)),
                    PathCommand.LineTo(new Double2(x + width, y)),
                    PathCommand.LineTo(new Double2(x + width, y + height)),
                    PathCommand.LineTo(new Double2(x, y + height)),
                    PathCommand.ClosePath()
                }
            }
            ;
            else
            {
                pathCommands = new[]
                {
                    PathCommand.MoveTo(new Double2(x + radii.X, y)),
                    PathCommand.LineTo(new Double2(x + width - radii.X, y)),
                    PathCommand.ArcTo(radii, 0, false, true, new Double2(x + width, y + radii.Y)),
                    PathCommand.LineTo(new Double2(x + width, y + height - radii.Y)),
                    PathCommand.ArcTo(radii, 0, false, true, new Double2(x + width - radii.X, y + height)),
                    PathCommand.LineTo(new Double2(x + radii.X, y + height)),
                    PathCommand.ArcTo(radii, 0, false, true, new Double2(x, y + height - radii.Y)),
                    PathCommand.LineTo(new Double2(x, y + radii.Y)),
                    PathCommand.ArcToClose(radii, 0, false, true)
                }
            };

            // And finally return
            return(new Path(pathCommands));
        }
    }
Example #24
0
 internal static double RoundMidPointToEven(this double self, int precision)
 {
     return(DoubleUtils.Round(self, precision, RoundingMode.MidPointToEven));
 }
Example #25
0
 private static double Calc(double value, double gridStep, bool visible)
 {
     return(visible ? gridStep * DoubleUtils.Round(value / gridStep, RoundingMode.MidPointFromZero) : value);
 }
Example #26
0
 internal static double Truncate(this double self)
 {
     return(DoubleUtils.Truncate(self));
 }
 private void CalculateMaxDistances()
 {
     const int tdiv = 180;
     const int pdiv = 360;
     const double dθ = 1 * System.Math.PI / tdiv;
     const double dφ = 2 * System.Math.PI / pdiv;
     var doubleUtils = new DoubleUtils(1e-12);
     var xmax = new double[tdiv + 1];
     var ymax = new double[tdiv + 1];
     var zmax = new double[tdiv + 1];
     Parallel.For(0, tdiv + 1, it => {
         for (var ip = 0; ip <= pdiv; ++ip) {
             var point = GetSurfacePoint(it * dθ, ip * dφ);
             if (doubleUtils.Less(xmax[it], System.Math.Abs(point.X))) {
                 xmax[it] = System.Math.Abs(point.X);
             }
             if (doubleUtils.Less(ymax[it], System.Math.Abs(point.Y))) {
                 ymax[it] = System.Math.Abs(point.Y);
             }
             if (doubleUtils.Less(zmax[it], System.Math.Abs(point.Z))) {
                 zmax[it] = System.Math.Abs(point.Z);
             }
         }
     });
     _xmax = 0;
     _ymax = 0;
     _zmax = 0;
     for (var it = 0; it <= tdiv; ++it) {
         _xmax = System.Math.Max(_xmax, xmax[it]);
         _ymax = System.Math.Max(_ymax, ymax[it]);
         _zmax = System.Math.Max(_zmax, zmax[it]);
     }
 }
Example #28
0
 public static bool IsCloseTo(this double self, double value)
 {
     return(DoubleUtils.AreClose(self, value));
 }
Example #29
0
        private static Double2[] FillPolygon(Curve[] contour)
        {
            // "Guess" a capacity for the list, add the first point
            var list = new List <Double2>((int)(1.4 * contour.Length));

            // Check first if the last and first curve aren't joinable
            bool lastFirstJoin = FillFace.AreCurvesFusable(contour[contour.Length - 1], contour[0]);

            if (lastFirstJoin)
            {
                list.Add(contour[0].At(1));
            }

            // Now, scan the curve list for pairs of scannable curves
            var k = lastFirstJoin ? 1 : 0;

            for (int i = k; i < contour.Length - k; i++)
            {
                if (i < contour.Length - 1 && FillFace.AreCurvesFusable(contour[i], contour[i + 1]))
                {
                    // If they describe a positive winding on the plane, add only its endpoint
                    var endp0 = contour[i].At(0);
                    var endp1 = contour[i + 1].At(1);

                    if (CombinedWindings(contour[i], contour[i + 1]) > 0)
                    {
                        list.Add(endp1);
                    }
                    else
                    {
                        // Else, compute the convex hull and add the correct point sequence
                        var points = contour[i].EnclosingPolygon.Concat(contour[i + 1].EnclosingPolygon).ToArray();
                        var hull   = GeometricUtils.ConvexHull(points);
                        var hl     = hull.Length;

                        // We have to go through the hull clockwise. Find the first point
                        int ik;
                        for (ik = 0; ik < hl; ik++)
                        {
                            if (hull[ik] == endp0)
                            {
                                break;
                            }
                        }

                        // And run through it
                        for (int i0 = ik; i0 != (ik + 1) % hl; i0 = (i0 + hl - 1) % hl)
                        {
                            list.Add(hull[i0]);
                        }

                        // Add the last point
                        list.Add(hull[(ik + 1) % hl]);
                    }
                    i++;
                }
                else if (contour[i].Type == CurveType.Line || contour[i].IsConvex)
                {
                    list.Add(contour[i].At(1));
                }
                else
                {
                    list.AddRange(contour[i].EnclosingPolygon.Skip(1));
                }
            }

            // Sanitize the list; identical vertices
            var indices = new List <int>();

            for (int i = 0; i < list.Count; i++)
            {
                if (DoubleUtils.RoughlyEquals(list[i], list[(i + 1) % list.Count]))
                {
                    indices.Add(i);
                }
            }

            list.ExtractIndices(indices.ToArray());
            return(list.ToArray());
        }
Example #30
0
 public static bool IsCloseTo(this double self, double value, int precision)
 {
     return(DoubleUtils.AreClose(self, value, precision));
 }
Example #31
0
 public static bool IsGreaterThan(this double self, double value, int precision)
 {
     return(DoubleUtils.GreaterThan(self, value, precision));
 }
Example #32
0
        private static void FromString(string s, CultureInfo cultureInfo, out double value, out FlexLengthUnitType unit)
        {
            var normalized = s.Trim().ToLowerInvariant();

            unit = FlexLengthUnitType.Pixel;

            var strLen     = normalized.Length;
            var strLenUnit = 0;
            var unitFactor = 1.0;

            var i = 0;

            if (normalized == UnitStrings[i])
            {
                strLenUnit = UnitStrings[i].Length;
                unit       = (FlexLengthUnitType)i;
            }
            else
            {
                for (i = 1; i < UnitStrings.Length; ++i)
                {
                    if (normalized.EndsWith(UnitStrings[i], StringComparison.Ordinal) == false)
                    {
                        continue;
                    }

                    strLenUnit = UnitStrings[i].Length;
                    unit       = (FlexLengthUnitType)i;

                    break;
                }
            }

            if (i >= UnitStrings.Length)
            {
                for (i = 0; i < PixelUnitStrings.Length; ++i)
                {
                    if (normalized.EndsWith(PixelUnitStrings[i], StringComparison.Ordinal) == false)
                    {
                        continue;
                    }

                    strLenUnit = PixelUnitStrings[i].Length;
                    unitFactor = PixelUnitFactors[i];

                    break;
                }
            }

            if (strLen == strLenUnit && (unit == FlexLengthUnitType.Auto || unit == FlexLengthUnitType.Star))
            {
                value = 1;
            }
            else
            {
                Debug.Assert(unit == FlexLengthUnitType.Pixel || DoubleUtils.AreClose(unitFactor, 1.0));

                var valueString = normalized.Substring(0, strLen - strLenUnit);

                value = Convert.ToDouble(valueString, cultureInfo) * unitFactor;
            }
        }