/// <summary> /// Get 'West,East,North,South' surface side of 3d curve at middle point of curve. /// Returns 'None' if crv is not touch any side. /// </summary> /// <param name="srf"></param> /// <param name="crv">3d curve</param> /// <returns>surface side (iso status). None if crv is not touch any side.</returns> public static IsoStatus _GetCurveIsoStatus(this Surface srf, Curve crv) { var res = IsoStatus.None; var mid = crv._PointAtMid(); //mid = crv.PointAt(crv.Domain.Max); double u, v; if (srf.ClosestPoint(mid, out u, out v)) { var s = new SurfaceSingulars(srf); if (u._IsSame(s.U.T0)) { res = IsoStatus.West; } else if (u._IsSame(s.U.T1)) { res = IsoStatus.East; } else if (v._IsSame(s.V.T0)) { res = IsoStatus.South; } else if (v._IsSame(s.V.T1)) { res = IsoStatus.North; } } return(res); }
/* OLD CODE * public static void _RecreateCurves(this BrepTrim trim, Surface srf, SurfaceSingulars ssingulars, bool reverseCurveDirection, bool fixDeformedEdges, double tol_tol_fixDeformedEdges, bool recreate3dCurves, out NurbsCurve crv3d, out NurbsCurve crv2d) * { * if (recreate3dCurves) * { * crv3d = trim._PullEdgeToSurface(srf, ssingulars, reverseCurveDirection, fixDeformedEdges, tol_tol_fixDeformedEdges); * * ////DEBUG * //foreach (var l in crv3d.Points) * //{ * // debugIndexEdge2++; * // string text = "#" + debugIndexEdge2; * // AddDebugPoint(Doc, text, l.Location, Color.Gold); //debug * //} * * // * // Create 2d curve (trim) from new edge (that is already projected on surface) * // High interpolation of 500 points makes mistakes almost unvisible * // * crv2d = srf._Convert3dCurveTo2d(crv3d, ssingulars, trim); * } * else * { * crv3d = trim.Edge._ToNurbsCurve(); * crv2d = trim._ToNurbsCurve(); * * if (reverseCurveDirection) * { * crv3d.Reverse(); * } * * // Reverse 2d crv if needed * var trimStartPoint = srf.PointAt(trim.PointAtStart.X, trim.PointAtStart.Y); * var trimEndPoint = srf.PointAt(trim.PointAtEnd.X, trim.PointAtEnd.Y); * if (crv3d.PointAtStart.DistanceTo(trimStartPoint) > crv3d.PointAtStart.DistanceTo(trimEndPoint)) * { * crv2d.Reverse(); * } * } * } * * public static NurbsCurve _PullEdgeToSurface(this BrepTrim trim, Surface srf, SurfaceSingulars ssingulars, bool reverseCurveDirection, bool fixDeformedEdges, double tol_tol_fixDeformedEdges) * { * // * // Project Edge to surface, and create new Edge from control points (edge devided by 100 points) * // * Curve edge = trim.Edge; * NurbsCurve crv3d = null; * * if (fixDeformedEdges) * { * NurbsCurve newedge; * if (edge._ZigZagDeformations_TryRemove_old(srf, tol_tol_fixDeformedEdges, out newedge)) * { * //log.temp("trim #{0} had zigzag ", trimIndex+1); * edge = newedge; * } * } * int DIVIDE_BY_COUNT_I = Math.Min(Math.Max(Convert.ToInt32(edge._GetLength_ThreadSafe() / 0.01), 10), 100); * if (edge.Degree == 1) * { * DIVIDE_BY_COUNT_I = 10; * } * * Point3d[] edgeDevidedPoints; * edge.DivideByCount(DIVIDE_BY_COUNT_I, true, out edgeDevidedPoints); * if (edgeDevidedPoints != null) * { * if (reverseCurveDirection) * { * edgeDevidedPoints = edgeDevidedPoints.Reverse().ToArray(); * } * var edgeDevidedUV = srf._ClosestPoints(edgeDevidedPoints); * * * //DEBUG * //Logger.log("+++"); * //foreach (var p in edgeDevidedUV) * //{ * // debugIndexEdge++; * // //bool inside = trim.Brep.IsPointInside(point, 0.000001,false); * // if (debugIndexEdge < debugIndexMAX) * // { * // string text = "#" + debugIndexEdge + ": " + String.Format("{0:0.00}", p.u) + " - " + String.Format("{0:0.00}", p.v); * // //string text = "#" + debugIndexEdge; * // AddDebugPoint(Doc, text, srf.PointAt(p.u, p.v), Color.Red); //debug * // Logger.log(text); * // } * //} * * // * // Fix U or V in singularities (in case where values are indentical at start of surface (like Point3d(u, v) == Point3d(u, v+100))); * // * var fixedSrf = srf._FixSurfacePoints(ref edgeDevidedUV, true, ssingulars, trim); * * // * // Contruct 3d curve on surface * // * var points2d = edgeDevidedUV.Select(o => new Point2d(o.u, o.v)).ToList(); * crv3d = srf.InterpolatedCurveOnSurfaceUV(points2d, 0.0000001); * * if (crv3d == null) * { * var point3d = edgeDevidedUV.Select(o => srf.PointAt(o.u, o.v)).ToList(); * crv3d = srf.InterpolatedCurveOnSurface(point3d, 0.0001); * //crv3d = crv3d; * //var doc = RhinoDoc.ActiveDoc; * //foreach (var p in point3d) * //{ * // debugIndexEdge2++; * // string text = "#" + debugIndexEdge2; * // AddDebugPoint(doc, text, p, Color.Gold); //debug * //} * } * } * * * * if (crv3d == null) * { * //log.error(g.IssueFixer, "Can't build crv3d from 2D points"); * throw new Exception("Can't rebuild " + trim._GUIEdgeName()); * } * * return crv3d; * } * * private static void AddDebugPoint(RhinoDoc doc, string text, Point3d point, Color color = default(Color)) * { * // return; * * color = (color == default(Color)) * ? Color.Aqua * : color; * * //doc.Objects.AddPoint(point, new ObjectAttributes() * //{ * // DisplayOrder = 12, * // LayerIndex = 0, * // Name = "temp", * // //Mode = ObjectMode.Locked, * // ColorSource = ObjectColorSource.ColorFromObject, * // ObjectColor = Color.Red, * // Visible = true * // //ObjectDecoration = ObjectDecoration.BothArrowhead, * //}); * Guid id = doc.Objects.AddTextDot(text, point, new ObjectAttributes() * { * DisplayOrder = 5, * LayerIndex = 0, * //Name = "DebugPoint " + text, * Name = text, * //Mode = ObjectMode.Locked, * ColorSource = ObjectColorSource.ColorFromObject, * ObjectColor = color, * Visible = true * }); * * * } * */ #endregion // /// <summary> /// Recalculated iso status. /// Works always compare to internal Rhino method 'srf.IsIsoparametric(trim)' /// </summary> /// <param name="trim"></param> /// <param name="ssingulars">provide it for speed optimization. otherwise it will be calculated automatically.</param> /// <returns></returns> public static IsoStatus _IsoStatus(this BrepTrim trim, SurfaceSingulars ssingulars = null) { // COMMENTED - just to show what is a internal Rhino method to detect isoStatus //return srf.IsIsoparametric(trim); - doesnt work always properly!!! // COMMENTED - we want to be very sure and lets recalculate isostaus always // Calculate ony if status is invalid //var trimIsoStatus = trim.IsoStatus; //var isValidIso = trimIsoStatus == IsoStatus.East // || trimIsoStatus == IsoStatus.North // || trimIsoStatus == IsoStatus.South // || trimIsoStatus == IsoStatus.West; //if (isValidIso) //{ // return trimIsoStatus; //} if (ssingulars == null) { var srf = trim._Srf(); ssingulars = new SurfaceSingulars(srf); } var T0 = trim.PointAtStart; var T1 = trim.PointAtEnd; var T0IsoStatus = ssingulars.GetIsoStatus(T0.X, T0.Y); var T1IsoStatus = ssingulars.GetIsoStatus(T1.X, T1.Y); if (T0IsoStatus == T1IsoStatus) { return(T0IsoStatus); } // show warnig message only both iso statuses are not 'None' - when we substitute surface with no singulars we will have such situation when all iso statuses became 'None' if ((T0IsoStatus != IsoStatus.None || T1IsoStatus != IsoStatus.None)) { if (ssingulars.Srf.IsAtSingularity(T0.X, T0.Y, true) || ssingulars.Srf.IsAtSingularity(T1.X, T1.Y, true)) { log.wrong("_BrepTrim._IsoStatus() Cannot detect proper IsoStatus: T0:{0}-T1:{1} T0=[{2:0.000},{3:0.000}] T1=[{4:0.000},{5:0.000}]", T0IsoStatus, T1IsoStatus, T0.X, T0.Y, T1.X, T1.Y); } else { var temp = 0; } } return(IsoStatus.None); }
public static NurbsCurve _Convert3dCurveTo2d(this Surface srf, NurbsCurve crv3d , SurfaceSingulars ssingulars = null, Curve trim = null, Curve edge = null, double pullback_tol = 0.001) { var seam = new SurfaceSeams(srf); if (seam.HasSeams) { log.wrong("Dangerous convertion of 3d curve to 2d in method _Curve._Convert3dCurveTo2d(). Remove seam before use such convertions."); } // Try internal method first - it is faster, but may be incorrect var newCrv2d = srf.Pullback(crv3d, pullback_tol); Point3d[] point3d; if (newCrv2d != null && newCrv2d._TryDivideByCount(5, out point3d)) { //var sps = newCrv2d.Points._SurfacePoints(); var sps = point3d.Select(o => new SurfacePoint(o)).ToList(); var isSPSFixed = srf._FixSurfacePoints(ref sps, false, null, null, crv3d); if (!isSPSFixed) // if there is no need in fixing points - we have good 2d curve - lets return result { return(newCrv2d._ToNurbsCurve()); } } // Lets use our method - slow but very precise // Rebuild 3d curve for better precision pulling to 2d surface. var divby = crv3d._GetDivBy(null, 0.01, 100); NurbsCurve Crv3dRebuilded = crv3d.Rebuild(divby, 3, false) ?? crv3d; Crv3dRebuilded = Crv3dRebuilded._SetDimension(3); newCrv2d = srf._Convert3dCurveTo2d_WithoutRebuildAndSimplify(Crv3dRebuilded, ssingulars, trim, edge); var res = newCrv2d._Simplify(srf); return(res); }
/// <summary> /// Fix control points of trim /// </summary> /// <param name="trim"></param> /// <param name="singulars"></param> /// <param name="roundStart">Round value of singular axis (if surface is singular on V - then round first value of V)</param> /// <param name="roundEnd">Round value of singular axis (if surface is singular on V - then round last value of V)</param> /// <returns></returns> public static NurbsCurve _FixContorlPoints(this BrepTrim trim, SurfaceSingulars singulars = null, bool roundStart = false, bool roundEnd = false) { var srf = trim._Srf(); var trimNurb = trim._ToNurbsCurve(); // v1 - full var res = trimNurb._Fix2dContorlPoints(srf, singulars, trim.Edge, roundStart, roundEnd); var newtrim = res._ZigZagDeformations_TryRemove(srf); //if (newtrim != null) //{ // res = newtrim; //} // v2 - only zigzag //var res = trimNurb; //var newtrim = trimNurb._ZigZagDeformations_TryRemove(srf); //if (newtrim != null) //{ // res = newtrim; //} //res = res._Fix2dContorlPoints(srf, singulars, trim.Edge, roundStart, roundEnd); return(res); }
//private static int Num; private static NurbsCurve _Simplify_NEW3(this Curve crv, Surface srf = null, bool workWithSingularSurfaces = false) { // log.temp("_Simplify_NEW workWithSingularSurfaces = " + workWithSingularSurfaces); var ORIGIN = crv._ToNurbsCurve(); var crvDimension = crv.Dimension; if (crv.Degree != 3) { return(ORIGIN); } if (crvDimension != 2 && crvDimension != 3) { return(ORIGIN); } if (crvDimension == 2 && srf == null) { log.wrong("_CurveSimplify._Simplify() - 2d curve requires 'srf' parameter"); return(ORIGIN); } if (crv._ZigZagDeformationExists(srf)) { return(ORIGIN); } var numValueMIN = 0; var numValueMAX = Math.Min(Simplify_nums.Last(), ORIGIN.Points.Count / 2); if (numValueMIN > numValueMAX) { return(ORIGIN); } NurbsCurve crv2d = null; NurbsCurve crv3d = null; const bool preserveTangents3d = false; const bool preserveTangents2d = false; int VALIDATION_SEGMENTS_COUNT3d = 20; int VALIDATION_SEGMENTS_COUNT2d = 20; double MAX_DEVIATION3d = 0.001; const double MAX_LENGTH_DIFF3d = 0.005; // in percent = 0.5% var checkControlPoints = false; // if control points also should be close to original curve SurfaceSingulars ssingular = null; if (crvDimension == 2) { ssingular = new SurfaceSingulars(srf); if (ssingular.HasSingulars) { if (!workWithSingularSurfaces) { return(ORIGIN); } if (srf._PointsAreCloseSingularity_HighJump(ORIGIN.Points._SurfacePoints(), ssingular)) { MAX_DEVIATION3d = 0.0001; } checkControlPoints = true; } crv2d = ORIGIN;// set only for dimension == 2 } else { crv3d = ORIGIN;// set only for dimension == 3 } var crv3dLen = ORIGIN._Get3dLength(srf); if (crv3dLen._IsZero()) { return(ORIGIN); } Point3d[] crv2d_3dPoints = null; Point3d[] crv3dPoints = null; VALIDATION_SEGMENTS_COUNT3d = Math.Max(VALIDATION_SEGMENTS_COUNT3d, Convert.ToInt32(Math.Min(1000, crv3dLen / 0.5))); VALIDATION_SEGMENTS_COUNT2d = Math.Max(VALIDATION_SEGMENTS_COUNT2d, Convert.ToInt32(Math.Min(1000, crv3dLen / 0.5))); if (crvDimension == 2) { if (crv2d == null) { return(ORIGIN); } Point3d[] crv2dPoints = null; crv2d._DivideByCount_ThreadSafe(VALIDATION_SEGMENTS_COUNT2d, true, out crv2dPoints); if (crv2dPoints == null) { return(ORIGIN); } crv2d_3dPoints = crv2dPoints.Select(o => srf.PointAt(o.X, o.Y)).ToArray(); } else { crv3d._DivideByCount_ThreadSafe(VALIDATION_SEGMENTS_COUNT3d, true, out crv3dPoints); if (crv3dPoints == null) { return(ORIGIN); } } foreach (var num in Simplify_nums) { if (num < numValueMIN || num > numValueMAX) { continue; } if (num == 2 && srf != null) { if (srf.Degree(0) != 1 && srf.Degree(1) != 1) { continue; // one degree has to be linear } } // // Rebuild // NurbsCurve simple3d = null; NurbsCurve simple2d = null; if (crvDimension == 2 && crv2d != null) { simple2d = (num == 2) ? new LineCurve(new Point2d(crv2d.PointAtStart.X, crv2d.PointAtStart.Y), new Point2d(crv2d.PointAtEnd.X, crv2d.PointAtEnd.Y))._ToNurbsCurve() : crv2d.Rebuild(num, 3, false); if (simple2d == null) { continue; } if (simple2d._ZigZagDeformationExists(srf)) { //var crv2dNorm = crv2d._2dNormalize(srf); //var simple2dNorm = crv2dNorm.Rebuild(num, 3, false); //simple2d = simple2dNorm._2dUnnormalize(srf); if (crv3d == null) { crv3d = crv2d._2dTo3d(srf); } if (crv3d == null) { continue; // lazy initialization of crv3d } simple3d = crv3d.Rebuild(num, 3, preserveTangents3d); if (simple3d == null) { continue; } simple2d = srf._Convert3dCurveTo2d_WithoutRebuildAndSimplify(simple3d, null, crv, crv3d); if (simple2d == null) { continue; } simple2d = simple2d._Fix2dContorlPoints(srf, ssingular); if (simple2d._ZigZagDeformationExists(srf)) { //return simple2d; continue; } } simple2d.SetStartPoint(crv2d.PointAtStart); simple2d.SetEndPoint(crv2d.PointAtEnd); // Compare with original // Simplification near to singularity must very very strict!!! // Control poins must be very close to original curve - its guarantee that method '_Curve._Fix2dContorlPoints()' wont change any control point, and issue 'TrimControlPointsNotCorrectInSingularity' will be fixed if (checkControlPoints) { if (crv3d == null) { crv3d = crv2d._2dTo3d(srf); } if (crv3d == null) { continue; // lazy initialization of crv3d } if (!_Simplify_IsSimplifiedControlPointsCloseToOrigin(simple2d, srf, MAX_DEVIATION3d, crv3d)) { continue; } } // Compare with original if (!_Simplify_IsSimplifiedCloseToOrigin_NEW3(simple2d, srf, MAX_DEVIATION3d, crv2d_3dPoints)) { continue; } } else if (crvDimension == 3 && crv3d != null) { simple3d = (num == 2) ? new LineCurve(crv3d.PointAtStart, crv3d.PointAtEnd)._ToNurbsCurve() : crv3d.Rebuild(num, 3, preserveTangents3d); if (simple3d == null) { continue; } // Compare with original if (!_Simplify_IsSimplifiedCloseToOrigin(simple3d, srf, preserveTangents3d, crv3d, crv3dLen, crv3dPoints, MAX_LENGTH_DIFF3d, MAX_DEVIATION3d)) { continue; } } // Return new simplified curve if (crvDimension == 2) { //Layers.Debug.AddCurve(simple3d, "trim 3d", Color.Purple); //var z3d = simple3d._ZigZagDeformationExists(srf); //var z2d = simple2d._ZigZagDeformationExists(srf); var res = simple2d._Fix2dContorlPoints(srf, ssingular); //Layers.Debug.AddCurve(crv3d, "crv3d", Color.PeachPuff); //Layers.Debug.AddCurveControlPoints(res, srf, Color.Orchid); //Layers.Debug.AddCurve(simple3d, "simple3d", Color.Orchid); //var z2ds = res._ZigZagDeformationExists(srf); //Layers.Debug.AddCurve(simple3d, "simple3d", Color.Aqua); return(res); } else { return(simple3d); } } // we fail - return origin curve return(ORIGIN); }
public static List <SurfaceKinkData> _Kinks_Find(this Surface srf) { if (srf.IsClosed(0) || srf.IsClosed(1)) { return(null); } if (srf.IsPeriodic(0) || srf.IsPeriodic(1)) { return(null); } if (srf.IsCone()) { return(null); } if (srf.IsCylinder()) { return(null); } if (srf.IsSphere()) { return(null); } if (srf.IsTorus()) { return(null); } var ss = new SurfaceSeams(srf); if (ss.HasSeams) { return(null); } var sss = new SurfaceSingulars(srf); if (sss.HasSingulars) { return(null); } var srfNurb = srf._IncreaseSurfaceDensity().ToNurbsSurface(); if (srfNurb.Points.CountU < MIN_CONTORL_POINTS_COUNT && srfNurb.Points.CountV < MIN_CONTORL_POINTS_COUNT) { return(null); } //var srfBound = srf._GetMinMaxUV(); //var faceBound = face._GetMinMaxUV(); var uv0 = 0; var uv1 = 1; if (srfNurb.Points.CountU < MIN_CONTORL_POINTS_COUNT) { uv0 = 1; // exclude checking on u if not enought control points } if (srfNurb.Points.CountV < MIN_CONTORL_POINTS_COUNT) { uv1 = 0; // exclude checking on v if not enought control points } string failReason = ""; double deviation = 0; List <SurfaceKinkData> res = null; for (int uv = uv0; uv <= uv1; uv++) { var crv = srf._TryGetIsoCurve_Mid(uv, true, out failReason, out deviation); if (crv == null) { log.wrong("srf._TryGetIsoCurve_Mid failed: " + failReason); continue; } if (DEBUG) { Layers.Debug.AddTangent(crv, "" + uv, Color.Red); RhinoDoc.ActiveDoc.Objects.AddCurve(crv); } var crvEnds = new[] { CurveEnd.Start, CurveEnd.End }; var srfEnds = (uv == 0) ? new[] { IsoStatus.West, IsoStatus.East } : new[] { IsoStatus.South, IsoStatus.North }; for (int istartend = 0; istartend <= 1; istartend++) { // // Angle // var angle = GetAngle(srf, crv, uv, istartend); if (Math.Abs(90 - angle) > 3) { log.wrong("_SurfaceKinks._Kinks_Find: Math.Abs(90 - angle) > 10"); continue; } // // Angle Extended // var crvEnd = crvEnds[istartend]; var srfEnd = srfEnds[istartend]; var srfExtended = srf._ExtendSurfaceByPercent(srfEnd, 100 * EXTEND_BY_PERCENT); var crvExtended = srfExtended._TryGetIsoCurve_Mid(uv, true, out failReason, out deviation); if (crvExtended == null) { log.wrong("srfExtended._TryGetIsoCurve_Mid failed: " + failReason); continue; } var angleExtended = GetAngle(srfExtended, crvExtended, uv, istartend); if (Math.Abs(90 - angleExtended) > 3) { log.wrong("_SurfaceKinks._Kinks_Find: Math.Abs(90 - angleExtended) > 10"); continue; } // // Angle between 'extended IsoCurve1' to 'IsoCurve2' // var crvIso1Extended = crv.Extend(crvEnd, crv._GetLength_ThreadSafe() * EXTEND_BY_PERCENT, CurveExtensionStyle.Arc); if (crvIso1Extended == null) { log.wrong("crv.Extend failed"); continue; } var angleCrvs = Vector3d.VectorAngle(crvExtended._Tangent(crvEnd), crvIso1Extended._Tangent(crvEnd))._RadianToDegree(); if (angleCrvs > 10) { var kink = new SurfaceKinkData { AngleDeviation = angleCrvs, SrfEnd = srfEnd, }; if (res == null) { res = new List <SurfaceKinkData>(2); } res.Add(kink); } //if (DEBUG) //{ // //RhinoDoc.ActiveDoc.Objects.AddSurface(srfExtended); // RhinoDoc.ActiveDoc.Objects.AddCurve(crvExtended); //} } } return(res); }
public static NurbsCurve _Convert3dCurveTo2d_WithoutRebuildAndSimplify(this Surface srf, NurbsCurve crv3d , SurfaceSingulars ssingulars = null, Curve trim = null, Curve edge = null) { if (ssingulars == null) { ssingulars = new SurfaceSingulars(srf); } if (edge == null) { edge = crv3d; } //// version 1 - bad since it uses method Curve.CreateControlPointCurve) and is a little bit incorrect //crv3d.DivideByCount(DIVIDE_BY_COUNT_I * 5, true, out edgeDevidedPoints); //crv3d.DivideByCount(DIVIDE_BY_COUNT_I, true, out edgeDevidedPoints); //var edgeDevidedPointsProjectedUV = new List<Point3d>(); //foreach (var point in edgeDevidedPoints) //{ // debugIndexTrim++; // if (debugIndexTrim < debugIndexMAX) AddDebugPoint(Doc, debugIndexTrim.ToString(), point, Color.Red);//debug // double u, v; // if (srf.ClosestPoint(point, out u, out v)) // { // if (debugIndexTrim < debugIndexMAX) // { // //string text = debugIndexTrim + " - " + Convert.ToInt32(Math.Round(u)) + " - " + Convert.ToInt32(Math.Round(v)); // //AddDebugPoint(Doc, text, srf.PointAt(u, v), Color.Purple);//debug // //AddDebugPoint(Doc, debugIndexTrim.ToString(), srf.PointAt(u, v), Color.Purple);//debug // //Logger.log(text); // } // var point2d = new Point3d(u, v, 0); // edgeDevidedPointsProjectedUV.Add(point2d); // } // else // { // int i = 0; // } //} //var crv2d = Curve.CreateControlPointCurve(edgeDevidedPointsProjectedUV, 2); ////crv2d = crv2d.Rebuild(10, crv3dUV.Degree, false); //// version 2 //var crv2d = srf.InterpolatedCurveOnSurfaceUV(edgeDevidedPointsProjectedUV, 0.0000001); //// version 3 - bad since control points can be not enough to keep good precision var crv2d = new NurbsCurve(2, crv3d.IsRational, crv3d.Degree + 1, crv3d.Points.Count); var crv2dPoints = new List <SurfacePoint>(crv3d.Points.Count); var crv2dWeights = new List <double>(crv3d.Points.Count); //var points3d = crv3d.Points.Select(o => o.Location).ToArray(); //log.temp("crv3d.Points.Count = " + crv3d.Points.Count); foreach (var point3d in crv3d.Points) { double u, v; if (srf.ClosestPoint(point3d.Location, out u, out v)) { //AddDebugPoint(Doc, "", srf.PointAt(u, v), Color.Red); //debug crv2dPoints.Add(new SurfacePoint(u, v)); crv2dWeights.Add(point3d.Weight); } } var fixedSrf = srf._FixSurfacePoints(ref crv2dPoints, false, ssingulars, trim, edge); var index = 0; foreach (var p in crv2dPoints) { crv2d.Points.SetPoint(index, p.u, p.v, 0, crv2dWeights[index]); index++; } index = 0; foreach (var knot in crv3d.Knots) { crv2d.Knots[index] = knot; index++; } //// version 4 //var crv2d = new NurbsCurve(2, edgeDevidedPointsProjectedUV.Count); //var index = 0; //foreach (var srfPoint in edgeDevidedPointsProjectedUV) //{ // crv2d.Points.SetPoint(index, srfPoint.X, srfPoint.Y, 0, 1); // index++; //} //index = 0; //foreach (var knot in crv3d.Knots) //{ // crv2d.Knots[index] = knot; // index++; //} return(crv2d); }