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)); }
// 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); }); } }
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"); }
public static bool IsZero(this double self, int precision) { return(DoubleUtils.IsZero(self, precision)); }
public static double Clamp(this double value, double min, double max) { return(DoubleUtils.Clamp(value, min, max)); }
public static bool IsLessThanOrClose(this double self, double value) { return(DoubleUtils.LessThanOrClose(self, value)); }
internal static double RoundToZero(this double self) { return(DoubleUtils.Round(self, RoundingMode.ToZero)); }
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)); }
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)); }
private static bool IsStepValid(object value) { double num = (double)value; return(DoubleUtils.IsNaN(num) || (num >= 0.0 && !double.IsPositiveInfinity(num))); }
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()); }
public static bool IsUnity(this Polynomial p) { return(DoubleUtils.MachineEquality(p.Coeffs[0], 1.0) && p.Coeffs.Skip(1).All(DoubleUtils.EqualZero)); }
/// <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"); }
public static bool IsGreaterThanOrClose(this double self, double value) { return(DoubleUtils.GreaterThanOrClose(self, value)); }
internal static double RoundFromZero(this double self, int precision) { return(DoubleUtils.Round(self, precision, RoundingMode.FromZero)); }
public static bool IsLessThanOrClose(this double self, double value, int precision) { return(DoubleUtils.LessThanOrClose(self, value, precision)); }
internal static double RoundMidPointFromZero(this double self) { return(DoubleUtils.Round(self, RoundingMode.MidPointFromZero)); }
public static bool IsZero(this double self) { return(DoubleUtils.IsZero(self)); }
public static double Clamp(this double value, Range <double> range) { return(DoubleUtils.Clamp(value, range)); }
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)); } }
internal static double RoundMidPointToEven(this double self, int precision) { return(DoubleUtils.Round(self, precision, RoundingMode.MidPointToEven)); }
private static double Calc(double value, double gridStep, bool visible) { return(visible ? gridStep * DoubleUtils.Round(value / gridStep, RoundingMode.MidPointFromZero) : value); }
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]); } }
public static bool IsCloseTo(this double self, double value) { return(DoubleUtils.AreClose(self, value)); }
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()); }
public static bool IsCloseTo(this double self, double value, int precision) { return(DoubleUtils.AreClose(self, value, precision)); }
public static bool IsGreaterThan(this double self, double value, int precision) { return(DoubleUtils.GreaterThan(self, value, precision)); }
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; } }