/// <summary> /// Creates a interpolated curve through a set of points.<br/> /// <em>Refer to Algorithm A9.1 on The NURBS Book, pp.369-370 for details.</em> /// </summary> /// <param name="pts">The set of points to interpolate.</param> /// <param name="degree">The Curve degree.</param> /// <param name="startTangent">The tangent vector for the first point.</param> /// <param name="endTangent">The tangent vector for the last point.</param> /// <param name="centripetal">True use the chord as per knot spacing, false use the squared chord.</param> /// <returns>A the interpolated curve.</returns> public static NurbsBase Interpolated(List <Point3> pts, int degree, Vector3?startTangent = null, Vector3?endTangent = null, bool centripetal = false) { if (pts.Count < degree + 1) { throw new Exception($"You must supply at least degree + 1 points. You supplied {pts.Count} pts."); } // Gets uk parameters. List <double> uk = CurveHelpers.Parametrization(pts, centripetal); // Compute knot vectors. bool hasTangents = startTangent != null && endTangent != null; KnotVector knots = ComputeKnotsForInterpolation(uk, degree, hasTangents); // Global interpolation. // Build matrix of basis function coefficients. Matrix coeffMatrix = BuildCoefficientsMatrix(pts, degree, hasTangents, uk, knots); // Solve for each points. List <Point4> ctrlPts = (hasTangents) ? SolveCtrlPtsWithTangents(knots, pts, coeffMatrix, degree, new Vector3(startTangent.Value), new Vector3(endTangent.Value)) : SolveCtrlPts(pts, coeffMatrix); return(new NurbsCurve(degree, knots, ctrlPts)); }
public static PolyCurve Join(IList <NurbsBase> curves) { if (curves == null) { throw new Exception("The set of curves is empty."); } if (curves.Count <= 1) { throw new Exception("Insufficient curves for join operation."); } List <NurbsBase> sortedCurves = CurveHelpers.QuickSortCurve(curves); for (int i = 0; i < sortedCurves.Count - 1; i++) { if (sortedCurves[i].IsClosed) { throw new Exception($"Curve at {i} is closed."); } if (sortedCurves[i].ControlPoints.Last().DistanceTo(sortedCurves[i + 1].ControlPoints[0]) > GSharkMath.MinTolerance) { throw new Exception($"Curve at {i} don't touch curve at {i + 1}."); } } PolyCurve polyCurve = new PolyCurve(sortedCurves); return(polyCurve); }
private void Action_FlipY(object context) { if (context is SerializedProperty property) { AnimationCurve curve = property.animationCurveValue; CurveHelpers.FlipY(curve); property.animationCurveValue = curve; property.serializedObject.ApplyModifiedProperties(); } }
/// <summary> /// Constructs a ruled surface between two curves. /// <em>Follows the algorithm at page 337 of The NURBS Book by Piegl and Tiller.</em> /// </summary> /// <param name="curveA">The first curve.</param> /// <param name="curveB">The second curve.</param> /// <returns>A ruled surface.</returns> public static NurbsSurface Ruled(NurbsBase curveA, NurbsBase curveB) { IList <NurbsBase> curves = new[] { curveA, curveB }; curves = CurveHelpers.NormalizedDegree(curves); curves = CurveHelpers.NormalizedKnots(curves); return(new NurbsSurface(1, curves[0].Degree, new KnotVector(1, 2), curves[0].Knots, new List <List <Point4> > { curves[0].ControlPoints, curves[1].ControlPoints })); }
public static NurbsBase Approximate(List <Point3> pts, int degree, bool centripetal = false) { int numberCpts = pts.Count - 1; // Gets the parameters curve uk. List <double> uk = CurveHelpers.Parametrization(pts, centripetal); // Computes knot vectors. KnotVector knots = ComputeKnotsForCurveApproximation(uk, degree, numberCpts, pts.Count); // Compute matrix N Matrix matrixN = new Matrix(); for (int i = 1; i < pts.Count - 1; i++) { List <double> tempRow = new List <double>(); for (int j = 1; j < numberCpts - 1; j++) { tempRow.Add(Evaluate.Curve.OneBasisFunction(degree, knots, j, uk[i])); } matrixN.Add(tempRow); } // Compute NT matrix. Matrix matrixNt = matrixN.Transpose(); // Compute NTN matrix. Matrix matrixNtN = matrixNt * matrixN; // Computes Rk - Eqn 9.63. List <Point3> Rk = ComputesValuesRk(knots, uk, degree, pts, numberCpts); // Compute R - Eqn 9.67. var vectorR = ComputeValuesR(knots, uk, Rk, degree, numberCpts); // Computes control points, fixing the first and last point from the input points. List <Point4> ctrlPts = new List <Point4> { pts[0] }; ctrlPts.AddRange(SolveCtrlPts(vectorR, matrixNtN)); ctrlPts.Add(pts[pts.Count - 1]); return(new NurbsCurve(degree, knots, ctrlPts)); }
/// <summary> /// Constructs a NURBS surface from a set of NURBS curves.<br/> /// </summary> /// <param name="curves">Set of a minimum of two curves to create the surface.</param> /// <param name="loftType">Enum to choose the type of loft generation.</param> /// <returns>A NURBS surface.</returns> public static NurbsSurface FromLoft(IList <NurbsBase> curves, LoftType loftType = LoftType.Normal) { if (curves == null) { throw new ArgumentException("An invalid number of curves to perform the loft."); } if (curves.Count < 2) { throw new ArgumentException("An invalid number of curves to perform the loft."); } if (curves.Any(x => x == null)) { throw new ArgumentException("The input set contains null curves."); } bool isClosed = curves[0].IsClosed; foreach (NurbsBase c in curves.Skip(1)) { if (isClosed != c.IsClosed) { throw new ArgumentException("Loft only works if all curves are open, or all curves are closed."); } } // Copy curves for possible operation of homogenization. IList <NurbsBase> copyCurves = new List <NurbsBase>(curves); // Clamp curves if periodic. if (copyCurves[0].IsPeriodic) { for (int i = 0; i < copyCurves.Count; i++) { copyCurves[i] = copyCurves[i].ClampEnds(); } } // If necessary, the curves can be brought to a common degree and knots, as we do for the ruled surface. // In fact, the ruled surface is a special case of a skinned surface. if (copyCurves.Any(c => c.Degree != copyCurves[0].Degree)) { copyCurves = CurveHelpers.NormalizedDegree(copyCurves); copyCurves = CurveHelpers.NormalizedKnots(copyCurves); } int degreeV = copyCurves[0].Degree; int degreeU = 3; KnotVector knotVectorU = new KnotVector(); KnotVector knotVectorV = copyCurves[0].Knots; List <List <Point4> > surfaceControlPoints = new List <List <Point4> >(); switch (loftType) { case LoftType.Normal: List <List <Point4> > tempPts = new List <List <Point4> >(); for (int n = 0; n < copyCurves[0].ControlPointLocations.Count; n++) { List <Point3> pts = copyCurves.Select(c => c.ControlPointLocations[n]).ToList(); NurbsBase crv = Fitting.Curve.Interpolated(pts, degreeU); tempPts.Add(crv.ControlPoints); knotVectorU = crv.Knots; } surfaceControlPoints = CollectionHelpers.Transpose2DArray(tempPts); break; case LoftType.Loose: surfaceControlPoints = copyCurves.Select(c => c.ControlPoints).ToList(); knotVectorU = new KnotVector(degreeU, copyCurves.Count); break; } return(new NurbsSurface(degreeU, degreeV, knotVectorU, knotVectorV, surfaceControlPoints)); }