public void It_Returns_False_If_Three_Points_Are_Not_Collinear() { // Arrange Point3 pt1 = new Point3(25.923, 27.057, 0.0); Point3 pt2 = new Point3(35.964, 20.451, 0.0); Point3 pt3 = new Point3(51.299, 37.950, 0.0); // Assert Trigonometry.ArePointsCollinear(pt1, pt2, pt3).Should().BeFalse(); }
/// <summary> /// Constructs a plane from three non-collinear points. /// </summary> /// <param name="pt1">Firs point representing the origin.</param> /// <param name="pt2">Second point representing the x direction.</param> /// <param name="pt3">Third point representing the y direction.</param> public Plane(Point3 pt1, Point3 pt2, Point3 pt3) { if (Trigonometry.ArePointsCollinear(pt1, pt2, pt3)) { throw new Exception("Plane cannot be created, the tree points must not be collinear"); } Vector3 dir1 = pt2 - pt1; Vector3 dir2 = pt3 - pt1; Vector3 normal = Vector3.CrossProduct(dir1, dir2); Origin = pt1; XAxis = dir1.Unitize(); YAxis = Vector3.CrossProduct(normal, dir1).Unitize(); }
/// <summary> /// Find four points in the point cloud that are not coplanar for the /// seed hull /// </summary> private void FindInitialHullIndices(List <Point3> points, out int b0, out int b1, out int b2, out int b3) { int count = points.Count; for (int i0 = 0; i0 < count - 3; i0++) { for (int i1 = i0 + 1; i1 < count - 2; i1++) { Vector3 p0 = points[i0]; Vector3 p1 = points[i1]; if (p0.EpsilonEquals(p1, GSharkMath.MinTolerance)) { continue; } for (int i2 = i1 + 1; i2 < count - 1; i2++) { Vector3 p2 = points[i2]; if (Trigonometry.ArePointsCollinear(p0, p1, p2)) { continue; } for (int i3 = i2 + 1; i3 < count - 0; i3++) { Vector3 p3 = points[i3]; if (Trigonometry.ArePointsCoplanar(new List <Point3> { p0, p1, p2, p3 })) { continue; } b0 = i0; b1 = i1; b2 = i2; b3 = i3; return; } } } } throw new System.ArgumentException("Can't generate hull, points are coplanar"); }
/// <summary> /// Samples a curve in an adaptive way. <br/> /// <em>Corresponds to this algorithm http://ariel.chronotext.org/dd/defigueiredo93adaptive.pdf <br/> /// https://www.modelical.com/en/grasshopper-scripting-107/ </em> /// </summary> /// <param name="curve">The curve to sampling.</param> /// <param name="start">The start parameter for sampling.</param> /// <param name="end">The end parameter for sampling.</param> /// <param name="tolerance">Tolerance for the adaptive scheme. The default tolerance is set as (1e-6).</param> /// <returns>A tuple with the set of points and the t parameter where the point was evaluated.</returns> public static (List <double> tValues, List <Point3> pts) AdaptiveSampleRange(NurbsBase curve, double start, double end, double tolerance = GSharkMath.MinTolerance) { // Sample curve at three pts. Random random = new Random(); double t = 0.5 + 0.2 * random.NextDouble(); double mid = start + (end - start) * t; Point3 pt1 = Point4.PointDehomogenizer(Evaluate.Curve.PointAt(curve, start)); Point3 pt2 = Point4.PointDehomogenizer(Evaluate.Curve.PointAt(curve, mid)); Point3 pt3 = Point4.PointDehomogenizer(Evaluate.Curve.PointAt(curve, end)); Vector3 diff = pt1 - pt3; Vector3 diff2 = pt1 - pt2; if ((Vector3.DotProduct(diff, diff) < tolerance && Vector3.DotProduct(diff2, diff2) > tolerance) || !Trigonometry.ArePointsCollinear(pt1, pt2, pt3, tolerance)) { // Get the exact middle value or a random value start + (end - start) * (0.45 + 0.1 * random.NextDouble()); double tMiddle = start + (end - start) * 0.5; // Recurse the two halves. (List <double> tValues, List <Point3> pts)leftHalves = AdaptiveSampleRange(curve, start, tMiddle, tolerance); (List <double> tValues, List <Point3> pts)rightHalves = AdaptiveSampleRange(curve, tMiddle, end, tolerance); leftHalves.tValues.RemoveAt(leftHalves.tValues.Count - 1); List <double> tMerged = leftHalves.tValues.Concat(rightHalves.tValues).ToList(); leftHalves.pts.RemoveAt(leftHalves.pts.Count - 1); List <Point3> ptsMerged = leftHalves.pts.Concat(rightHalves.pts).ToList(); return(tMerged, ptsMerged); } return(new List <double> { start, end }, new List <Point3> { pt1, pt3 }); }