/// <summary> /// Gets the circumference of a closed polygon. /// </summary> /// <param name="closedPolygon">The closed polygon.</param> /// <returns>The circumference of the given closed polygon.</returns> public static double GetClosedPolygonCircumference(IEnumerable <IntPoint> closedPolygon) { IntPoint firstPoint = default; IntPoint previous = default; double sum = 0.0; var numberOfPoints = 0; foreach (var pt in closedPolygon) { if (0 == numberOfPoints) { firstPoint = pt; } else { sum += Math.Sqrt((double)(Int128.Int128Mul(pt.X - previous.X, pt.X - previous.X) + Int128.Int128Mul(pt.Y - previous.Y, pt.Y - previous.Y))); } previous = pt; ++numberOfPoints; } if (numberOfPoints == 0) { throw new ArgumentException("Polygon is empty (has no point at all)", nameof(closedPolygon)); } else { var pt = firstPoint; sum += Math.Sqrt((double)(Int128.Int128Mul(pt.X - previous.X, pt.X - previous.X) + Int128.Int128Mul(pt.Y - previous.Y, pt.Y - previous.Y))); return(sum); } }
/// <summary> /// Calculates the 2nd moments of the given closed polygon. The polygon /// has to be non-selfintersecting! /// </summary> /// <param name="closedPolygon">The closed polygon.</param> /// <returns>The second moments, Ixx, Iyy, and Ixy, of the given polygon (with respect to the origin (x=0, y=0)).</returns> /// <seealso href="https://en.wikipedia.org/wiki/Second_moment_of_area"/> public static (double Ixx, double Iyy, double Ixy) GetClosedPolygonSecondMoments(IEnumerable <IntPoint> closedPolygon) { IntPoint firstPoint = default; IntPoint previous = default; var numberOfPoints = 0; double sumX = 0; double sumY = 0; double sumXY = 0; Int128 s; foreach (var pt in closedPolygon) { if (numberOfPoints == 0) { firstPoint = pt; } else { s = (Int128.Int128Mul(previous.X, pt.Y) - Int128.Int128Mul(previous.Y, pt.X)); sumX += (Pow2(previous.Y) + previous.Y * pt.Y + Pow2(pt.Y)) * (double)s; sumY += (Pow2(previous.X) + previous.X * pt.X + Pow2(pt.X)) * (double)s; sumXY += (previous.X * pt.Y + 2 * previous.X * previous.Y + 2 * pt.X * pt.Y + pt.X * previous.Y) * (double)s; } previous = pt; ++numberOfPoints; } if (numberOfPoints == 0) { throw new ArgumentException("Polygon is empty (has no point at all)", nameof(closedPolygon)); } else if (numberOfPoints == 1) { return(0, 0, 0); } else if (numberOfPoints == 2) { return(0, 0, 0); } else { s = (Int128.Int128Mul(previous.X, firstPoint.Y) - Int128.Int128Mul(previous.Y, firstPoint.X)); var pt = firstPoint; sumX += (Pow2(previous.Y) + previous.Y * pt.Y + Pow2(pt.Y)) * (double)s; sumY += (Pow2(previous.X) + previous.X * pt.X + Pow2(pt.X)) * (double)s; sumXY += (previous.X * pt.Y + 2 * previous.X * previous.Y + 2 * pt.X * pt.Y + pt.X * previous.Y) * (double)s; sumX /= 6; sumY /= 6; sumXY /= 12; return(sumX, sumY, sumXY); } }
/// <summary> /// Calculate the center of gravity (centroid) of the given closed polygon. The polygon /// has to be non-selfintersecting! /// </summary> /// <param name="closedPolygon">The closed polygon.</param> /// <returns>The center of gravity of the given polygon.</returns> /// <seealso href="https://en.wikipedia.org/wiki/Centroid"/> public static PointD2D GetClosedPolygonCentroid(IEnumerable <IntPoint> closedPolygon) { IntPoint firstPoint = default; IntPoint previous = default; var numberOfPoints = 0; double sumX = 0; double sumY = 0; Int128 s; var sumS = new Int128(0); foreach (var pt in closedPolygon) { if (numberOfPoints == 0) { firstPoint = pt; } else { s = (Int128.Int128Mul(previous.X, pt.Y) - Int128.Int128Mul(previous.Y, pt.X)); sumS += s; sumX += (previous.X + pt.X) * (double)s; sumY += (previous.Y + pt.Y) * (double)s; } previous = pt; ++numberOfPoints; } if (numberOfPoints == 0) { throw new ArgumentException("Polygon is empty (has no point at all)", nameof(closedPolygon)); } else if (numberOfPoints == 1) { return(new PointD2D(firstPoint.X, firstPoint.Y)); } else if (numberOfPoints == 2) { return(new PointD2D((firstPoint.X + previous.X) / 2, (firstPoint.Y + previous.Y) / 2)); } else { s = (Int128.Int128Mul(previous.X, firstPoint.Y) - Int128.Int128Mul(previous.Y, firstPoint.X)); sumS += s; sumX += (previous.X + firstPoint.X) * (double)s; sumY += (previous.Y + firstPoint.Y) * (double)s; sumX /= (3 * (double)sumS); sumY /= (3 * (double)sumS); return(new PointD2D(sumX, sumY)); } }
/// <summary> /// Gets the area of a closed polygon. /// </summary> /// <param name="closedPolygon">The points forming a closed polygon.</param> /// <returns>The polygon area. The value is signed. The sign is positive if the polygon is counter-clockwise (in a coordinate system in which x is to the right and y is up).</returns> public static double GetClosedPolygonArea(IEnumerable <IntPoint> closedPolygon) { IntPoint firstPoint = default; IntPoint previous = default; var sum = new Int128(0); var numberOfPoints = 0; foreach (var pt in closedPolygon) { if (0 == numberOfPoints) { firstPoint = pt; } else { sum += (Int128.Int128Mul(previous.X, pt.Y) - Int128.Int128Mul(previous.Y, pt.X)); } previous = pt; ++numberOfPoints; } if (numberOfPoints == 0) { throw new ArgumentException("Polygon is empty (has no point at all)", nameof(closedPolygon)); } else if (numberOfPoints == 1) { return(0); } else if (numberOfPoints == 2) { return(0); } else { sum += (Int128.Int128Mul(previous.X, firstPoint.Y) - Int128.Int128Mul(previous.Y, firstPoint.X)); return((double)sum / 2.0); } }
public static bool PointOnLineSegment(IntPoint pt, IntPoint linePt1, IntPoint linePt2, bool UseFullRange) { if (UseFullRange) { return(((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) || ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) || (((pt.X > linePt1.X) == (pt.X < linePt2.X)) && ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) && ((Int128.Int128Mul((pt.X - linePt1.X), (linePt2.Y - linePt1.Y)) == Int128.Int128Mul((linePt2.X - linePt1.X), (pt.Y - linePt1.Y)))))); } else { return(((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) || ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) || (((pt.X > linePt1.X) == (pt.X < linePt2.X)) && ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) && ((pt.X - linePt1.X) * (linePt2.Y - linePt1.Y) == (linePt2.X - linePt1.X) * (pt.Y - linePt1.Y)))); } }