/// <summary> /// Fits this rectangle to the given points. /// </summary> /// <param name="points">The points to wrap the rectangle around.</param> /// <param name="percentage">The margin in percentage.</param> /// <returns></returns> public RectangleF2D Fit(PointF2D[] points, double percentage) { if (points == null) { throw new ArgumentNullException("points"); } if (points.Length < 2) { throw new ArgumentOutOfRangeException("Rectangle fit needs at least two points."); } // calculate the center. double[] center = new double[] { points[0][0], points[0][1] }; for (int idx = 1; idx < points.Length; idx++) { center[0] = center[0] + points[idx][0]; center[1] = center[1] + points[idx][1]; } center[0] = center[0] / points.Length; center[1] = center[1] / points.Length; PointF2D centerPoint = new PointF2D(center); LineF2D line = null; // calculate the width. double width = 0; for (int idx = 0; idx < points.Length; idx++) { line = new LineF2D(points[idx], points[idx] + this._vectorY); double distance = line.Distance(centerPoint); if (distance > width) { // the distance is larger. width = distance; } } width = width * 2; // calculate the height. double height = 0; for (int idx = 0; idx < points.Length; idx++) { line = new LineF2D(points[idx], points[idx] + this._vectorX); double distance = line.Distance(centerPoint); if (distance > height) { // this distance is larger. height = distance; } } height = height * 2; // expand with the given percentage. width = width + (width / 100.0 * percentage); height = height + (height / 100.0 * percentage); return(RectangleF2D.FromBoundsAndCenter(width, height, centerPoint[0], centerPoint[1], this.DirectionY)); }
/// <summary> /// Simplify the specified points using epsilon. /// </summary> /// <param name="points">Points.</param> /// <param name="epsilon">Epsilon.</param> /// <param name="first">First.</param> /// <param name="last">Last.</param> public static PointF2D[] SimplifyBetween(PointF2D[] points, double epsilon, int first, int last) { if (points == null) throw new ArgumentNullException ("points"); if (epsilon <= 0) throw new ArgumentOutOfRangeException("epsilon"); if (first > last) throw new ArgumentException(string.Format("first[{0}] must be smaller or equal than last[{1}]!", first, last)); if (first + 1 != last) { // find point with the maximum distance. double maxDistance = 0; int foundIndex = -1; // create the line between first-last. LineF2D line = new LineF2D (points[first], points [last]); for (int idx = first + 1; idx < last; idx++) { double distance = line.Distance (points[idx]); if (distance > maxDistance) { // larger distance found. maxDistance = distance; foundIndex = idx; } } if (foundIndex > 0 && maxDistance > epsilon) { // a point was found and it is far enough. PointF2D[] before = SimplifyCurve.SimplifyBetween (points, epsilon, first, foundIndex); PointF2D[] after = SimplifyCurve.SimplifyBetween (points, epsilon, foundIndex, last); // build result. PointF2D[] result = new PointF2D[before.Length + after.Length - 1]; for (int idx = 0; idx < before.Length - 1; idx++) { result [idx] = before [idx]; } for (int idx = 0; idx < after.Length; idx++) { result [idx + before.Length - 1] = after [idx]; } return result; } } return new PointF2D[] { points[first], points[last] }; }
/// <summary> /// Simplify the specified points using epsilon. /// </summary> /// <param name="points">Points.</param> /// <param name="epsilon">Epsilon.</param> /// <param name="first">First.</param> /// <param name="last">Last.</param> public static double[][] SimplifyBetween(double[][] points, double epsilon, int first, int last) { if (points == null) throw new ArgumentNullException("points"); if(points.Length != 2) throw new ArgumentException(); if (epsilon <= 0) throw new ArgumentOutOfRangeException("epsilon"); if (first > last) throw new ArgumentException(string.Format("first[{0}] must be smaller or equal than last[{1}]!", first, last)); if (first == last) { // first and last are equal, no simplification possible. return new double[][] { new double[] { points[0][first] }, new double[] { points[1][first] } }; } double[][] result; // check for identical first and last points. if (points[0][first] == points[0][last] && points[1][first] == points[1][last]) { // first and last point are indentical. double[][] before = SimplifyCurve.SimplifyBetween(points, epsilon, first, last - 1); // build result. result = new double[2][]; result[0] = new double[before[0].Length + 1]; result[1] = new double[before[0].Length + 1]; for (int idx = 0; idx < before[0].Length; idx++) { result[0][idx] = before[0][idx]; result[1][idx] = before[1][idx]; } result[0][before[0].Length] = points[0][last]; result[1][before[0].Length] = points[1][last]; return result; } if (first + 1 != last) { // find point with the maximum distance. double maxDistance = 0; int foundIndex = -1; // create the line between first-last. LineF2D line = new LineF2D(new PointF2D( points[0][first], points[1][first]), new PointF2D( points[0][last], points[1][last])); for (int idx = first + 1; idx < last; idx++) { double distance = line.Distance(new PointF2D( points[0][idx], points[1][idx])); if (distance > maxDistance) { // larger distance found. maxDistance = distance; foundIndex = idx; } } if (foundIndex > 0 && maxDistance > epsilon) { // a point was found and it is far enough. double[][] before = SimplifyCurve.SimplifyBetween(points, epsilon, first, foundIndex); double[][] after = SimplifyCurve.SimplifyBetween(points, epsilon, foundIndex, last); // build result. result = new double[2][]; result[0] = new double[before[0].Length + after[0].Length - 1]; result[1] = new double[before[0].Length + after[0].Length - 1]; for (int idx = 0; idx < before[0].Length - 1; idx++) { result[0][idx] = before[0][idx]; result[1][idx] = before[1][idx]; } for (int idx = 0; idx < after[0].Length; idx++) { result[0][idx + before[0].Length - 1] = after[0][idx]; result[1][idx + before[0].Length - 1] = after[1][idx]; } return result; } } result = new double[2][]; result[0] = new double[] { points[0][first], points[0][last] }; result[1] = new double[] { points[1][first], points[1][last] }; return result; }
/// <summary> /// Fits this rectangle to the given points. /// </summary> /// <param name="points">The points to wrap the rectangle around.</param> /// <param name="percentage">The margin in percentage.</param> /// <returns></returns> public RectangleF2D Fit(PointF2D[] points, double percentage) { if (points == null) { throw new ArgumentNullException("points"); } if (points.Length < 2) { throw new ArgumentOutOfRangeException("Rectangle fit needs at least two points."); } // calculate the center. double[] center = new double[] { points[0][0], points[0][1] }; for (int idx = 1; idx < points.Length; idx++) { center[0] = center[0] + points[idx][0]; center[1] = center[1] + points[idx][1]; } center[0] = center[0] / points.Length; center[1] = center[1] / points.Length; PointF2D centerPoint = new PointF2D(center); LineF2D line = null; // calculate the width. double width = 0; for (int idx = 0; idx < points.Length; idx++) { line = new LineF2D(points[idx], points[idx] + this._vectorY); double distance = line.Distance(centerPoint); if (distance > width) { // the distance is larger. width = distance; } } width = width * 2; // calculate the height. double height = 0; for (int idx = 0; idx < points.Length; idx++) { line = new LineF2D(points[idx], points[idx] + this._vectorX); double distance = line.Distance(centerPoint); if (distance > height) { // this distance is larger. height = distance; } } height = height * 2; // expand with the given percentage. width = width + (width / 100.0 * percentage); height = height + (height / 100.0 * percentage); return RectangleF2D.FromBoundsAndCenter(width, height, centerPoint[0], centerPoint[1], this.DirectionY); }
public void LineDistance2DSegmentTest() { double delta = 0.000000000000001; // create the line to test. PointF2D a = new PointF2D(0, 0); PointF2D b = new PointF2D(1, 1); LineF2D line = new LineF2D(a, b, true, true); // calculate the results double sqrt_2 = (double)System.Math.Sqrt(2); double sqrt_2_div_2 = (double)System.Math.Sqrt(2) / 2.0f; // the point to test to. PointF2D c = new PointF2D(1, 0); Assert.AreEqual(line.Distance(c), sqrt_2_div_2, delta, string.Format("Point distance should be {0}f!", sqrt_2_div_2)); // the point to test to. c = new PointF2D(0, 1); Assert.AreEqual(line.Distance(c), sqrt_2_div_2, delta, string.Format("Point distance should be {0}f!", sqrt_2_div_2)); // the point to test to. c = new PointF2D(2, 2); Assert.AreEqual(line.Distance(c), sqrt_2, delta); // the point to test to. c = new PointF2D(2, 3); Assert.AreEqual(line.Distance(c), 2.23606797749979, delta, string.Format("Point distance should be {0}f!", sqrt_2_div_2)); // the point to test to. c = new PointF2D(3, 2); Assert.AreEqual(line.Distance(c), 2.23606797749979, delta, string.Format("Point distance should be {0}f!", sqrt_2_div_2)); // the point to test to. c = new PointF2D(1, 0); Assert.AreEqual(line.Distance(c), sqrt_2_div_2, delta, string.Format("Point distance should be {0}f!", sqrt_2_div_2)); // the point to test to. c = new PointF2D(0, 1); Assert.AreEqual(line.Distance(c), sqrt_2_div_2, delta, string.Format("Point distance should be {0}f!", sqrt_2_div_2)); // the point to test to. c = new PointF2D(2, 2); Assert.AreEqual(line.Distance(c), sqrt_2, delta, string.Format("Point distance should be {0}!", sqrt_2)); // the point to test to. c = new PointF2D(2, 1); Assert.AreEqual(line.Distance(c), 1, delta, string.Format("Point distance should be {0}f!", 1)); // the point to test to. c = new PointF2D(1, 2); Assert.AreEqual(line.Distance(c), 1, delta, string.Format("Point distance should be {0}f!", 1)); // the point to test to. c = new PointF2D(-1, -1); Assert.AreEqual(line.Distance(c), sqrt_2, delta, string.Format("Point distance should be {0}f!", 1)); // the point to test to. c = new PointF2D(1, -1); Assert.AreEqual(line.Distance(c), sqrt_2, delta, string.Format("Point distance should be {0}f!", 1)); }