diff --git a/Source/Primitives2D/Point/PointExtensions.cs b/Source/Primitives2D/Point/PointExtensions.cs
index 22d718b..9d3a62b 100644
--- a/Source/Primitives2D/Point/PointExtensions.cs
+++ b/Source/Primitives2D/Point/PointExtensions.cs
@@ -21,49 +21,15 @@
using System;
using System.Collections.Generic;
+using System.Linq;
namespace DotImaging.Primitives2D
{
///
- /// Defined functions can be used as object extensions.
/// Provides point extension methods.
///
public static class Point32iExtensions
{
- ///
- /// Selects points which satisfy minimal specified distance.
- ///
- /// Points sorted by importance. Points are tested by sequentially.
- /// Minimal enforced distance.
- /// Filtered points which are spread by minimal .
- public static List EnforceMinimalDistance(this IEnumerable candidates, float minimalDistance)
- {
- var minDistSqr = minimalDistance * minimalDistance;
- List filteredPoints = new List();
-
- foreach (var candidate in candidates)
- {
- bool isEnoughFar = true;
- foreach (var filteredPt in filteredPoints)
- {
- int dx = candidate.X - filteredPt.X;
- int dy = candidate.Y - filteredPt.Y;
- int featureDistanceSqr = dx * dx + dy * dy;
-
- if (featureDistanceSqr < minDistSqr)
- {
- isEnoughFar = false;
- break;
- }
- }
-
- if (isEnoughFar)
- filteredPoints.Add(candidate);
- }
-
- return filteredPoints;
- }
-
///
/// Clamps point coordinate according to the specified size (0,0, size.Width, size.Height).
///
@@ -122,7 +88,6 @@ public static double DistanceTo(this Point pointA, Point pointB)
}
///
- /// Defined functions can be used as object extensions.
/// Provides point extension methods.
///
public static class Point32fExtensions
@@ -313,4 +278,365 @@ public static Point Round(this PointF point)
return Point.Round(point);
}
}
+
+
+ ///
+ /// Provides point collection extensions.
+ ///
+ public static class Point32fCollectionExtensions
+ {
+ //taken from:http://stackoverflow.com/questions/4243042/c-sharp-point-in-polygon and modified
+ ///
+ /// Checks whether the specified location is in the polygon.
+ ///
+ /// Polygon.
+ /// Horizontal coordinate.
+ /// VErtical coordinate.
+ /// True if the point resides inside the polygon, false otherwise.
+ public static bool IsInPolygon(this IList poly, float x, float y)
+ {
+ PointF p1, p2;
+
+ bool inside = false;
+
+ if (poly.Count < 3)
+ {
+ return inside;
+ }
+
+ var oldPoint = new PointF(poly[poly.Count - 1].X, poly[poly.Count - 1].Y);
+
+ for (int i = 0; i < poly.Count; i++)
+ {
+ var newPoint = new PointF(poly[i].X, poly[i].Y);
+
+ if (newPoint.X > oldPoint.X)
+ {
+ p1 = oldPoint;
+ p2 = newPoint;
+ }
+
+ else
+ {
+ p1 = newPoint;
+ p2 = oldPoint;
+ }
+
+
+ if ((newPoint.X < x) == (x <= oldPoint.X) &&
+ (y - (long)p1.Y) * (p2.X - p1.X) < (p2.Y - (long)p1.Y) * (x - p1.X))
+ {
+ inside = !inside;
+ }
+
+
+ oldPoint = newPoint;
+ }
+
+ return inside;
+ }
+
+ ///
+ /// Gets the minimum bounding rectangle around the points.
+ ///
+ /// Contour points.
+ /// Bounding rectangle.
+ public static RectangleF BoundingRect(this IEnumerable points)
+ {
+ if (points.Any() == false) return RectangleF.Empty;
+
+ float minX = Single.MaxValue, maxX = Single.MinValue,
+ minY = Single.MaxValue, maxY = Single.MinValue;
+
+ foreach (var pt in points)
+ {
+ if (pt.X < minX)
+ minX = pt.X;
+ if (pt.X > maxX)
+ maxX = pt.X;
+
+ if (pt.Y < minY)
+ minY = pt.Y;
+ if (pt.Y > maxY)
+ maxY = pt.Y;
+ }
+
+ return new RectangleF(minX, minY, maxX - minX, maxY - minY);
+ }
+
+ ///
+ /// Gets the center of the mass of the contour.
+ ///
+ /// Contour points.
+ /// The center of the mass of the contour.
+ public static PointF Center(this IEnumerable points)
+ {
+ PointF average = new PointF();
+ int nSamples = 0;
+
+ foreach (var pt in points)
+ {
+ average.X += pt.X;
+ average.Y += pt.Y;
+ nSamples++;
+ }
+
+ average.X /= nSamples;
+ average.Y /= nSamples;
+
+ return average;
+ }
+
+ ///
+ /// Determines whether the polygon forms rectangle.
+ ///
+ /// Polygon.
+ /// True if the polygon forms rectangle, false otherwise.
+ public static bool IsRectangle(this IEnumerable points)
+ {
+ if (points.Count() != 4)
+ return false;
+
+ var rect = points.BoundingRect();
+
+ bool hasTopLeft = false, hasTopRight = false, hasBottomLeft = false, hasBottomRight = false;
+
+ foreach (var pt in points)
+ {
+ if (rect.Top == pt.Y)
+ {
+ if (rect.X == pt.X)
+ hasTopLeft = true;
+
+ if (rect.Right == pt.X)
+ hasTopRight = true;
+ }
+
+ if (rect.Bottom == pt.Y)
+ {
+ if (rect.X == pt.X)
+ hasBottomLeft = true;
+
+ if (rect.Right == pt.X)
+ hasBottomRight = true;
+ }
+ }
+
+ return hasTopLeft && hasTopRight && hasBottomLeft && hasBottomRight;
+ }
+
+ ///
+ /// Selects points which satisfy minimal specified distance.
+ ///
+ /// Points sorted by importance. Points are tested by sequentially.
+ /// Minimal enforced distance.
+ /// Filtered points which are spread by minimal .
+ public static List EnforceMinimalDistance(this IEnumerable candidates, float minimalDistance)
+ {
+ var minDistSqr = minimalDistance * minimalDistance;
+ var filteredPoints = new List();
+
+ foreach (var candidate in candidates)
+ {
+ bool isEnoughFar = true;
+ foreach (var filteredPt in filteredPoints)
+ {
+ var dx = candidate.X - filteredPt.X;
+ var dy = candidate.Y - filteredPt.Y;
+ var featureDistanceSqr = dx * dx + dy * dy;
+
+ if (featureDistanceSqr < minDistSqr)
+ {
+ isEnoughFar = false;
+ break;
+ }
+ }
+
+ if (isEnoughFar)
+ filteredPoints.Add(candidate);
+ }
+
+ return filteredPoints;
+ }
+ }
+
+ ///
+ /// Provides point collection extensions.
+ ///
+ public static class Point32iCollectionExtensions
+ {
+ //taken from:http://stackoverflow.com/questions/4243042/c-sharp-point-in-polygon and modified
+ ///
+ /// Checks whether the specified location is in the polygon.
+ ///
+ /// Polygon.
+ /// Horizontal coordinate.
+ /// VErtical coordinate.
+ /// True if the point resides inside the polygon, false otherwise.
+ public static bool IsInPolygon(this IList poly, float x, float y)
+ {
+ Point p1, p2;
+
+ bool inside = false;
+
+ if (poly.Count < 3)
+ {
+ return inside;
+ }
+
+ var oldPoint = new Point(poly[poly.Count - 1].X, poly[poly.Count - 1].Y);
+
+ for (int i = 0; i < poly.Count; i++)
+ {
+ var newPoint = new Point(poly[i].X, poly[i].Y);
+
+ if (newPoint.X > oldPoint.X)
+ {
+ p1 = oldPoint;
+ p2 = newPoint;
+ }
+
+ else
+ {
+ p1 = newPoint;
+ p2 = oldPoint;
+ }
+
+
+ if ((newPoint.X < x) == (x <= oldPoint.X) &&
+ (y - (long)p1.Y) * (p2.X - p1.X) < (p2.Y - (long)p1.Y) * (x - p1.X))
+ {
+ inside = !inside;
+ }
+
+
+ oldPoint = newPoint;
+ }
+
+ return inside;
+ }
+
+ ///
+ /// Gets the minimum bounding rectangle around the points.
+ ///
+ /// Contour points.
+ /// Bounding rectangle.
+ public static Rectangle BoundingRect(this IEnumerable points)
+ {
+ if (points.Any() == false) return Rectangle.Empty;
+
+ int minX = Int32.MaxValue, maxX = Int32.MinValue,
+ minY = Int32.MaxValue, maxY = Int32.MinValue;
+
+ foreach (var pt in points)
+ {
+ if (pt.X < minX)
+ minX = pt.X;
+ if (pt.X > maxX)
+ maxX = pt.X;
+
+ if (pt.Y < minY)
+ minY = pt.Y;
+ if (pt.Y > maxY)
+ maxY = pt.Y;
+ }
+
+ return new Rectangle(minX, minY, maxX - minX, maxY - minY);
+ }
+
+ ///
+ /// Gets the center of the mass of the contour.
+ ///
+ /// Contour points.
+ /// The center of the mass of the contour.
+ public static PointF Center(this IEnumerable points)
+ {
+ PointF average = new PointF();
+ int nSamples = 0;
+
+ foreach (var pt in points)
+ {
+ average.X += pt.X;
+ average.Y += pt.Y;
+ nSamples++;
+ }
+
+ average.X /= nSamples;
+ average.Y /= nSamples;
+
+ return average;
+ }
+
+ ///
+ /// Determines whether the polygon forms rectangle.
+ ///
+ /// Polygon.
+ /// True if the polygon forms rectangle, false otherwise.
+ public static bool IsRectangle(this IEnumerable points)
+ {
+ if (points.Count() != 4)
+ return false;
+
+ var rect = points.BoundingRect();
+
+ bool hasTopLeft = false, hasTopRight = false, hasBottomLeft = false, hasBottomRight = false;
+
+ foreach (var pt in points)
+ {
+ if (rect.Top == pt.Y)
+ {
+ if (rect.X == pt.X)
+ hasTopLeft = true;
+
+ if (rect.Right == pt.X)
+ hasTopRight = true;
+ }
+
+ if (rect.Bottom == pt.Y)
+ {
+ if (rect.X == pt.X)
+ hasBottomLeft = true;
+
+ if (rect.Right == pt.X)
+ hasBottomRight = true;
+ }
+ }
+
+ return hasTopLeft && hasTopRight && hasBottomLeft && hasBottomRight;
+ }
+
+ ///
+ /// Selects points which satisfy minimal specified distance.
+ ///
+ /// Points sorted by importance. Points are tested by sequentially.
+ /// Minimal enforced distance.
+ /// Filtered points which are spread by minimal .
+ public static List EnforceMinimalDistance(this IEnumerable candidates, float minimalDistance)
+ {
+ var minDistSqr = minimalDistance * minimalDistance;
+ var filteredPoints = new List();
+
+ foreach (var candidate in candidates)
+ {
+ bool isEnoughFar = true;
+ foreach (var filteredPt in filteredPoints)
+ {
+ var dx = candidate.X - filteredPt.X;
+ var dy = candidate.Y - filteredPt.Y;
+ var featureDistanceSqr = dx * dx + dy * dy;
+
+ if (featureDistanceSqr < minDistSqr)
+ {
+ isEnoughFar = false;
+ break;
+ }
+ }
+
+ if (isEnoughFar)
+ filteredPoints.Add(candidate);
+ }
+
+ return filteredPoints;
+ }
+ }
}