/// <summary> /// Create a rectangle from two sides of a triangle. /// </summary> /// <param name="a">First point.</param> /// <param name="b">Second point.</param> /// <param name="c">third point.</param> /// <returns>Rectangle.</returns> private static Rectangle3d CreateTwoSidedRectangle(Point3d a, Point3d b, Point3d c) { Vector3d ba = a - b; Vector3d bc = c - b; Vector3d ac = c - a; if (ba.IsZero) { return(CreateDegenerateRectangle(a, c)); } if (bc.IsZero) { return(CreateDegenerateRectangle(a, b)); } if (ac.IsZero) { return(CreateDegenerateRectangle(a, b)); } double lba = ba.Length; double lbc = bc.Length; Plane plane; if (lba > lbc) { plane = new Plane(b, ba, bc); } else { plane = new Plane(b, bc, ba); plane.Flip(); } return(new Rectangle3d(plane, new Interval(0, lba), new Interval(0, lbc))); }
/// <summary> /// Attempts to create a rectangle from a polyline. This method only works well for /// polylines that already closely resemble rectangles. If the polyline contains /// more than four vertices, the least significant ones will be ignored. If the /// polylines is non-orthogonal, the discrepancies will be averaged away. /// This method should not be used as a Rectangle fitter. /// </summary> /// <param name="polyline">Polyline to parse.</param> /// <param name="deviation">On success, the deviation will contain the largest deviation between the polyline and the rectangle.</param> /// <param name="angleDeviation">On success, the angleDeviation will contain the largest deviation (in radians) between the polyline edges and the rectangle edges.</param> /// <returns>A rectangle that is shaped similarly to the polyline or Rectangle3d.Unset /// if the polyline does not represent a rectangle.</returns> public static Rectangle3d CreateFromPolyline(IEnumerable <Point3d> polyline, out double deviation, out double angleDeviation) { if (polyline == null) { throw new ArgumentNullException(nameof(polyline)); } deviation = 0.0; angleDeviation = 0.0; // Remove consecutive identical vertices. Point3d prev = Point3d.Unset; List <Point3d> points = new List <Point3d>(); foreach (Point3d point in polyline) { if (point == prev) { continue; } if (!point.IsValid) { continue; } points.Add(point); prev = point; } // Remove closing vertex. if (points.Count > 1 && points[0] == points[points.Count - 1]) { points.RemoveAt(points.Count - 1); } // Special degenerate cases. if (points.Count == 0) { return(Unset); } if (points.Count == 1) { return(CreateDegenerateRectangle(points[0], points[0])); } if (points.Count == 2) { return(CreateDegenerateRectangle(points[0], points[1])); } if (points.Count == 3) { points.Add(points[0] + (points[2] - points[1])); } if (points.Count > 5) { RecursiveReduceVertices(points); } Point3d centre = 0.25 * (points[0] + points[1] + points[2] + points[3]); Vector3d xaxis = (points[1] - points[0]) + (points[2] - points[3]); Vector3d yaxis = (points[3] - points[0]) + (points[2] - points[1]); bool flip = false; if (xaxis.Length < yaxis.Length) { flip = true; Vector3d cache = xaxis; xaxis = yaxis; yaxis = cache; } Plane plane = new Plane(centre, xaxis, yaxis); if (flip) { plane.Flip(); } double x0, x1, x2, x3; double y0, y1, y2, y3; plane.ClosestParameter(points[0], out x0, out y0); plane.ClosestParameter(points[1], out x1, out y1); plane.ClosestParameter(points[2], out x2, out y2); plane.ClosestParameter(points[3], out x3, out y3); Interval xdomain = new Interval(0.5 * x0 + 0.5 * x3, 0.5 * x1 + 0.5 * x2); Interval ydomain = new Interval(0.5 * y0 + 0.5 * y1, 0.5 * y2 + 0.5 * y3); Rectangle3d rec = new Rectangle3d(plane, xdomain, ydomain); ComputeDeviation(rec, points, out deviation, out angleDeviation); return(rec); }