/// <summary> /// Snap End and Start points for each curve in list 'curves2d' (new point is avarage of both) /// If found singularity - /// 1) add index of curve2d after wich need to add singular trim in list 'singulars' /// 2) snap Start and End points to the corner of surface where Singularity exists /// </summary> /// <param name="srf"></param> /// <param name="curves2d">list of curves in UV projection for sruface 'srf'</param> /// <param name="singulars">Will contain index of curve2d after which need to add singularity</param> public static void _SnapCurves2d(this Surface srf, List <NurbsCurve> curves2d, out List <int> singulars) { var domainU = srf.Domain(0); var domainV = srf.Domain(1); singulars = new List <int>(); for (int i = 0; i < curves2d.Count; i++) { int iEnd = i - 1; int iStart = i; if (iStart == 0) { iEnd = curves2d.Count - 1; } var pointStart = new SurfacePoint(curves2d[iStart].PointAtStart); var pointEnd = new SurfacePoint(curves2d[iEnd].PointAtEnd); var diffU = Math.Abs(pointStart.u - pointEnd.u); var diffV = Math.Abs(pointStart.v - pointEnd.v); if (diffU < 0.01 * domainU.Length && diffV < 0.01 * domainV.Length) { var avarageU = (pointStart.u + pointEnd.u) / 2; var avarageV = (pointStart.v + pointEnd.v) / 2; var avaragePoint = new Point3d(avarageU, avarageV, 0); curves2d[iStart].SetStartPoint(avaragePoint); curves2d[iEnd].SetEndPoint(avaragePoint); curves2d[iStart].Points.SetPoint(0, avaragePoint); curves2d[iEnd].Points.SetPoint(curves2d[iEnd].Points.Count - 1, avaragePoint); } else { var pointStart3d = srf.PointAt(pointStart.u, pointStart.v); var pointEnd3d = srf.PointAt(pointEnd.u, pointEnd.v); var distance3d = pointEnd3d._DistanceTo(pointStart3d); var isExtremSingularity = distance3d < _Double.ZERO; var isNormalSingularity = (distance3d < 0.001) && (diffU > domainU.Length / 7 || diffV > domainV.Length / 7); if (isExtremSingularity || isNormalSingularity) // singularity present { // round start and end points to mutch surface corner in singularity var pointAtStart = curves2d[iStart].PointAtStart._RoundToDomain(domainU, domainV); curves2d[iStart].SetStartPoint(pointAtStart); var pointAtEnd = curves2d[iEnd].PointAtEnd._RoundToDomain(domainU, domainV); curves2d[iEnd].SetEndPoint(pointAtEnd); singulars.Add(iEnd); } else { throw new Exception("Can't snap Curves2d at index " + i); } } } singulars.Sort(); }
/// <summary> /// Get centroid of surface base on avarage 3d points devided by paramter 'divby'. /// If 'divby' is zero - 'srf.PointAt(uDomain.Mid, vDomain.Mid)' will be returned. /// </summary> /// <param name="srf"></param> /// <param name="loopEdges">all edges of loop</param> /// <param name="accurate">Accurate takes more time but have great precision.</param> /// <returns></returns> public static Point3d _GetCentroid(this Surface srf, Curve[] loopEdges, bool accurate) { // Get edges points var MAX_EDGE_POINTS = accurate ? 1000 : 500; var edgesPoints = new List <Point3d>(); var prevPointAtStart = Point3d.Origin; var prevPointAtEnd = Point3d.Origin; var edgesLengths = loopEdges.Select(o => o._GetLength_ThreadSafe()).ToList(); var divbyTol = accurate ? 0.01 : 0.1; var desiredEdgePointsCount = edgesLengths.Sum() / divbyTol; if (desiredEdgePointsCount > MAX_EDGE_POINTS) { divbyTol = edgesLengths.Sum() / MAX_EDGE_POINTS; // limit edge point at approximatelly 1000 points } for (var i = 0; i < loopEdges.Length; i++) { var edge = loopEdges[i]; var divby = edge._GetDivBy(edgesLengths[i], divbyTol, 0); Point3d[] points; if (edge._TryDivideByCount(divby, out points) && points.Length >= 2) { var deleteDuplicatePointIndex = -1;// index of point3d that id duplicated for 2 edges (some connection point) if (edgesPoints.Count != 0) { var distToStart = Math.Min(points.First()._DistanceTo(prevPointAtStart), points.First()._DistanceTo(prevPointAtEnd)); var distToEnd = Math.Min(points.Last()._DistanceTo(prevPointAtStart), points.Last()._DistanceTo(prevPointAtEnd)); if (distToStart < distToEnd && distToStart < 0.001) { deleteDuplicatePointIndex = edgesPoints.Count; } else if (distToEnd < distToStart && distToEnd < 0.001) { deleteDuplicatePointIndex = edgesPoints.Count + points.Length - 1; } } edgesPoints.AddRange(points); // remove duplicate point if such exists - this will increate accuracy if (deleteDuplicatePointIndex != -1) { edgesPoints.RemoveAt(deleteDuplicatePointIndex); } prevPointAtStart = points.First(); // remember PointAtStart of last edge prevPointAtEnd = points.Last(); // remember PointAtStart of last edge //Layers.Debug.AddPoints(points, Color.Black); } } // Limit edge points to 1000 - speed improvement (we can have here 26000 points what take 3 seconds of time - to much) int skipp = edgesPoints.Count / MAX_EDGE_POINTS; if (skipp > 1) { var edgesPoints_limited = new List <Point3d>(MAX_EDGE_POINTS * 2); var i = 0; while (i < edgesPoints.Count) { edgesPoints_limited.Add(edgesPoints[i]); i += skipp; } edgesPoints = edgesPoints_limited; } // detect interval where loop is inside - this will make our calculation more accurate for small loops of big surfaces //var edgesPointsOnSrf = srf._ClosestPoints(edgesPoints); //var uDomain = new Interval(edgesPointsOnSrf.Select(o => o.u).Min(), edgesPointsOnSrf.Select(o => o.u).Max()); //var vDomain = new Interval(edgesPointsOnSrf.Select(o => o.v).Min(), edgesPointsOnSrf.Select(o => o.v).Max()); var uDomain = srf.Domain(0); var vDomain = srf.Domain(1); var iterationNum = 0; var iterationCentroid = Point3d.Origin; var domain3dLength = Double.MaxValue; var iterationsMax = accurate ? 50 : 10; var iterationDomain3dLengthEnought = accurate ? 0.0001 : 0.001; while (iterationNum < iterationsMax && domain3dLength > iterationDomain3dLengthEnought) { // Get srf points var srfPoints2d = srf._GetDivby2dPoints(4, uDomain, vDomain); if (srfPoints2d.Length == 0) { break; } var srfPoints3d = srfPoints2d.Select(o => srf.PointAt(o.u, o.v)).ToArray(); var bestDist_Pow2 = Double.MaxValue; var best2dPoint = new SurfacePoint(0, 0); var best3dPoint = Point3d.Origin; var bestIndex = -1; domain3dLength = Double.MaxValue; for (var i = 0; i < srfPoints2d.Length; i++) { var p2d = srfPoints2d[i]; var p3d = srfPoints3d[i]; //var summ3dDists_Pow2 = edgesPoints.Select(ep => ep._DistanceTo_Pow2(p3d)).Sum(); double summ3dDists_Pow2 = 0; for (int k = 0; k < edgesPoints.Count; k++) { summ3dDists_Pow2 += p3d._DistanceTo_Pow2(edgesPoints[k]); } if (summ3dDists_Pow2 < bestDist_Pow2) { bestDist_Pow2 = summ3dDists_Pow2; best2dPoint = p2d; best3dPoint = p3d; bestIndex = i; } //Layers.Debug.AddPoint(p3d, Color.Wheat); } //Layers.Debug.AddPoint(best3dPoint, Color.Red); iterationNum++; iterationCentroid = best3dPoint; var domainSrfMidPoint = srf.PointAt(uDomain.Mid, vDomain.Mid); domain3dLength = Math.Min(domain3dLength, domainSrfMidPoint._DistanceTo(srfPoints3d.First())); domain3dLength = Math.Min(domain3dLength, domainSrfMidPoint._DistanceTo(srf.PointAt(uDomain.T0, vDomain.T1))); domain3dLength = Math.Min(domain3dLength, domainSrfMidPoint._DistanceTo(srf.PointAt(uDomain.T1, vDomain.T0))); domain3dLength = Math.Min(domain3dLength, domainSrfMidPoint._DistanceTo(srfPoints3d.Last())); uDomain = new Interval(best2dPoint.u - uDomain.Length / 4, best2dPoint.u + uDomain.Length / 4); vDomain = new Interval(best2dPoint.v - vDomain.Length / 4, best2dPoint.v + vDomain.Length / 4); } //Layers.Debug.AddTextPoint("_BrepLoop._GetCentroid", iterationCentroid, Color.Red); return(iterationCentroid); }