/// <summary> /// Calculate the area enclosed by this curve, were the start and end points to be /// joined by a straight line segment. /// A plane may optionally be specified, otherwise by default the projected area on /// the XY plane will be used. /// </summary> /// <param name="centroid">Output. The centroid of the enclosed area, in local coordinates /// on the specified plane.</param> /// <param name="onPlane">The plane to use to calculate the area. /// If not specified, the XY plane will be used.</param> /// <returns>The signed area enclosed by this curve on the specified plane, /// as a double.</returns> public override double CalculateEnclosedArea(out Vector centroid, Plane onPlane = null) { double result = 0; centroid = Vector.Zero; for (int i = 0; i < SubCurves.Count; i++) { Curve subCrv = SubCurves[i]; Vector start = subCrv.StartPoint; Vector end = subCrv.EndPoint; if (onPlane != null) { start = onPlane.GlobalToLocal(start); end = onPlane.GlobalToLocal(end); } double areaUnder = MathsHelper.AreaUnder(start.X, start.Y, end.X, end.Y, ref centroid); result += areaUnder; Vector subCentroid; double subArea = subCrv.CalculateEnclosedArea(out subCentroid, onPlane); result += subArea; centroid += subCentroid * subArea; } centroid /= result; return(result); }
public override double CalculateEnclosedIxx(Plane onPlane = null) { if (Circle != null) { if (Closed) { Vector localO = onPlane.GlobalToLocal(Circle.Origin); double Io = (Math.PI / 4) * Circle.Radius.Power(4); Vector v; double area = CalculateEnclosedArea(out v, onPlane); double yCentre = localO.Y; return(Io + area * yCentre.Squared()); } else { Vector origin = Circle.Origin; double radius = Circle.Radius; Vector centroid; double area = CalculateEnclosedArea(out centroid, onPlane).Abs(); Plane oSys = new Plane(onPlane, origin); Vector localS = oSys.GlobalToLocal(StartPoint); Vector localE = oSys.GlobalToLocal(EndPoint); Vector localM = oSys.GlobalToLocal(Vertices[1].Position); Vector localC = oSys.GlobalToLocal(centroid); Angle toS = localS.Angle; Angle toE = localE.Angle; Angle toM = localM.Angle; double IxxS = SectorIxx(toS, radius); double IxxE = SectorIxx(toE, radius); double IxxTri = Math.Abs((localS.Y.Squared() + localS.Y * localE.Y + localE.Y.Squared()) * (localS.X * localE.Y - localE.X * localS.Y) / 12); double result; if (toM > Math.Min(toS, toE) && toM < Math.Max(toS, toE)) { result = Math.Max(IxxS, IxxE) - Math.Min(IxxS, IxxE); } else { result = (Math.PI / 4) * radius.Power(4) - Math.Max(IxxS, IxxE) + Math.Min(IxxS, IxxE); } if (RadianMeasure.IsReflex) { result += IxxTri; } else { result -= IxxTri; } // Adjust for centroid offset: double yC = onPlane.GlobalToLocal(centroid).Y; result += area * (yC.Squared() - localC.Y.Squared()); return(result); } } return(0); }