/** * This method computes the base function value for the NURB curve. * @param i * the knot index * @param k * the base function degree * @param t * the knot value * @param knots * the knots' values * @return the base function value */ private static float computeBaseFunctionValue(int i, int k, float t, List<Float> knots) { if (k == 1) { return knots.get(i) <= t && t < knots.get(i + 1) ? 1.0f : 0.0f; } else { return (t - knots.get(i)) / (knots.get(i + k - 1) - knots.get(i)) * CurveAndSurfaceMath.computeBaseFunctionValue(i, k - 1, t, knots) + (knots.get(i + k) - t) / (knots.get(i + k) - knots.get(i + 1)) * CurveAndSurfaceMath.computeBaseFunctionValue(i + 1, k - 1, t, knots); } } }
for (int j = 0; j <= uSegments; ++j) { Vector3f interpolationResult = new Vector3f(); CurveAndSurfaceMath.interpolate(u, v, controlPoints, knots, basisUFunctionDegree, basisVFunctionDegree, interpolationResult); vertices.add(interpolationResult); u += deltaU;
/** * Interpolate a position on the spline * @param value a value from 0 to 1 that represent the position between the current control point and the next one * @param currentControlPoint the current control point * @param store a vector to store the result (use null to create a new one that will be returned by the method) * @return the position */ public Vector3f interpolate(float value, int currentControlPoint, Vector3f store) { if (store == null) { store = new Vector3f(); } switch (type) { case CatmullRom: FastMath.interpolateCatmullRom(value, curveTension, CRcontrolPoints.get(currentControlPoint), CRcontrolPoints.get(currentControlPoint + 1), CRcontrolPoints.get(currentControlPoint + 2), CRcontrolPoints.get(currentControlPoint + 3), store); break; case Linear: FastMath.interpolateLinear(value, controlPoints.get(currentControlPoint), controlPoints.get(currentControlPoint + 1), store); break; case Bezier: FastMath.interpolateBezier(value, controlPoints.get(currentControlPoint), controlPoints.get(currentControlPoint + 1), controlPoints.get(currentControlPoint + 2), controlPoints.get(currentControlPoint + 3), store); break; case Nurb: CurveAndSurfaceMath.interpolateNurbs(value, this, store); break; default: break; } return store; }
/** * Constructor. Constructs required surface. * @param controlPoints space control points * @param nurbKnots knots of the surface * @param uSegments the amount of U segments * @param vSegments the amount of V segments * @param basisUFunctionDegree the degree of basis U function * @param basisVFunctionDegree the degree of basis V function * @param smooth defines if the mesu should be smooth (true) or flat (false) */ private Surface(List<List<Vector4f>> controlPoints, List<Float>[] nurbKnots, int uSegments, int vSegments, int basisUFunctionDegree, int basisVFunctionDegree, boolean smooth) { this.validateInputData(controlPoints, nurbKnots, uSegments, vSegments); type = SplineType.Nurb; this.uSegments = uSegments; this.vSegments = vSegments; this.controlPoints = controlPoints; knots = nurbKnots; this.basisUFunctionDegree = basisUFunctionDegree; CurveAndSurfaceMath.prepareNurbsKnots(nurbKnots[0], basisUFunctionDegree); if (nurbKnots[1] != null) { this.basisVFunctionDegree = basisVFunctionDegree; CurveAndSurfaceMath.prepareNurbsKnots(nurbKnots[1], basisVFunctionDegree); } this.buildSurface(smooth); }
/** * Create a NURBS spline. A spline type is automatically set to SplineType.Nurb. * The cycle is set to <b>false</b> by default. * @param controlPoints a list of vector to use as control points of the spline * @param nurbKnots the nurb's spline knots */ public Spline(List<Vector4f> controlPoints, List<Float> nurbKnots) { //input data control for(int i=0;i<nurbKnots.size()-1;++i) { if(nurbKnots.get(i)>nurbKnots.get(i+1)) { throw new IllegalArgumentException("The knots values cannot decrease!"); } } //storing the data type = SplineType.Nurb; this.weights = new float[controlPoints.size()]; this.knots = nurbKnots; this.basisFunctionDegree = nurbKnots.size() - weights.length; for(int i=0;i<controlPoints.size();++i) { Vector4f controlPoint = controlPoints.get(i); this.controlPoints.add(new Vector3f(controlPoint.x, controlPoint.y, controlPoint.z)); this.weights[i] = controlPoint.w; } CurveAndSurfaceMath.prepareNurbsKnots(knots, basisFunctionDegree); this.computeTotalLength(); }
Vector4f controlPoint = controlPoints.get(i).get(j); float val = controlPoint.w * CurveAndSurfaceMath.computeBaseFunctionValue(i, basisVFunctionDegree, v, knots[1]) * CurveAndSurfaceMath.computeBaseFunctionValue(j, basisUFunctionDegree, u, knots[0]); store.addLocal(controlPoint.x * val, controlPoint.y * val, controlPoint.z * val); delimeter += val;
/** * Constructor. Constructs required surface. * @param controlPoints space control points * @param nurbKnots knots of the surface * @param uSegments the amount of U segments * @param vSegments the amount of V segments * @param basisUFunctionDegree the degree of basis U function * @param basisVFunctionDegree the degree of basis V function */ private Surface(List<List<Vector4f>> controlPoints, List<Float>[] nurbKnots, int uSegments, int vSegments, int basisUFunctionDegree, int basisVFunctionDegree) { this.validateInputData(controlPoints, nurbKnots, uSegments, vSegments); this.type = SplineType.Nurb; this.uSegments = uSegments; this.vSegments = vSegments; this.controlPoints = controlPoints; this.knots = nurbKnots; this.basisUFunctionDegree = basisUFunctionDegree; CurveAndSurfaceMath.prepareNurbsKnots(nurbKnots[0], basisUFunctionDegree); if (nurbKnots[1] != null) { this.basisVFunctionDegree = basisVFunctionDegree; CurveAndSurfaceMath.prepareNurbsKnots(nurbKnots[1], basisVFunctionDegree); } this.buildSurface(); }
/** * Interpolate a position on the spline * @param value a value from 0 to 1 that represent the position between the current control point and the next one * @param currentControlPoint the current control point * @param store a vector to store the result (use null to create a new one that will be returned by the method) * @return the position */ public Vector3f interpolate(float value, int currentControlPoint, Vector3f store) { if (store == null) { store = new Vector3f(); } switch (type) { case CatmullRom: FastMath.interpolateCatmullRom(value, curveTension, CRcontrolPoints.get(currentControlPoint), CRcontrolPoints.get(currentControlPoint + 1), CRcontrolPoints.get(currentControlPoint + 2), CRcontrolPoints.get(currentControlPoint + 3), store); break; case Linear: FastMath.interpolateLinear(value, controlPoints.get(currentControlPoint), controlPoints.get(currentControlPoint + 1), store); break; case Bezier: FastMath.interpolateBezier(value, controlPoints.get(currentControlPoint), controlPoints.get(currentControlPoint + 1), controlPoints.get(currentControlPoint + 2), controlPoints.get(currentControlPoint + 3), store); break; case Nurb: CurveAndSurfaceMath.interpolateNurbs(value, this, store); break; default: break; } return store; }
for (int j = 0; j <= uSegments; ++j) { Vector3f interpolationResult = new Vector3f(); CurveAndSurfaceMath.interpolate(u, v, controlPoints, knots, basisUFunctionDegree, basisVFunctionDegree, interpolationResult); vertices.add(interpolationResult); u += deltaU;
/** * This method interpolates the data for the nurbs curve. * @param u * the u value * @param nurbSpline * the nurbs spline definition * @param store * the resulting point in 3D space */ public static void interpolateNurbs(float u, Spline nurbSpline, Vector3f store) { if (nurbSpline.getType() != SplineType.Nurb) { throw new IllegalArgumentException("Given spline is not of a NURB type!"); } List<Vector3f> controlPoints = nurbSpline.getControlPoints(); float[] weights = nurbSpline.getWeights(); List<Float> knots = nurbSpline.getKnots(); int controlPointAmount = controlPoints.size(); store.set(Vector3f.ZERO); float delimeter = 0; for (int i = 0; i < controlPointAmount; ++i) { float val = weights[i] * CurveAndSurfaceMath.computeBaseFunctionValue(i, nurbSpline.getBasisFunctionDegree(), u, knots); store.addLocal(nurbSpline.getControlPoints().get(i) .mult(val)); delimeter += val; } store.divideLocal(delimeter); }
/** * Constructor. Constructs required surface. * @param controlPoints space control points * @param nurbKnots knots of the surface * @param uSegments the amount of U segments * @param vSegments the amount of V segments * @param basisUFunctionDegree the degree of basis U function * @param basisVFunctionDegree the degree of basis V function * @param smooth defines if the mesu should be smooth (true) or flat (false) */ private Surface(List<List<Vector4f>> controlPoints, List<Float>[] nurbKnots, int uSegments, int vSegments, int basisUFunctionDegree, int basisVFunctionDegree, boolean smooth) { this.validateInputData(controlPoints, nurbKnots, uSegments, vSegments); type = SplineType.Nurb; this.uSegments = uSegments; this.vSegments = vSegments; this.controlPoints = controlPoints; knots = nurbKnots; this.basisUFunctionDegree = basisUFunctionDegree; CurveAndSurfaceMath.prepareNurbsKnots(nurbKnots[0], basisUFunctionDegree); if (nurbKnots[1] != null) { this.basisVFunctionDegree = basisVFunctionDegree; CurveAndSurfaceMath.prepareNurbsKnots(nurbKnots[1], basisVFunctionDegree); } this.buildSurface(smooth); }
/** * Iterpolate a position on the spline * @param value a value from 0 to 1 that represent the postion between the curent control point and the next one * @param currentControlPoint the current control point * @param store a vector to store the result (use null to create a new one that will be returned by the method) * @return the position */ public Vector3f interpolate(float value, int currentControlPoint, Vector3f store) { if (store == null) { store = new Vector3f(); } switch (type) { case CatmullRom: FastMath.interpolateCatmullRom(value, curveTension, CRcontrolPoints.get(currentControlPoint), CRcontrolPoints.get(currentControlPoint + 1), CRcontrolPoints.get(currentControlPoint + 2), CRcontrolPoints.get(currentControlPoint + 3), store); break; case Linear: FastMath.interpolateLinear(value, controlPoints.get(currentControlPoint), controlPoints.get(currentControlPoint + 1), store); break; case Bezier: FastMath.interpolateBezier(value, controlPoints.get(currentControlPoint), controlPoints.get(currentControlPoint + 1), controlPoints.get(currentControlPoint + 2), controlPoints.get(currentControlPoint + 3), store); break; case Nurb: CurveAndSurfaceMath.interpolateNurbs(value, this, store); break; default: break; } return store; }
for (int j = 0; j <= uSegments; ++j) { Vector3f interpolationResult = new Vector3f(); CurveAndSurfaceMath.interpolate(u, v, controlPoints, knots, basisUFunctionDegree, basisVFunctionDegree, interpolationResult); vertices[arrayIndex++] = interpolationResult; u += deltaU;
/** * This method computes the base function value for the NURB curve. * @param i * the knot index * @param k * the base function degree * @param t * the knot value * @param knots * the knots' values * @return the base function value */ private static float computeBaseFunctionValue(int i, int k, float t, List<Float> knots) { if (k == 1) { return knots.get(i) <= t && t < knots.get(i + 1) ? 1.0f : 0.0f; } else { return (t - knots.get(i)) / (knots.get(i + k - 1) - knots.get(i)) * CurveAndSurfaceMath.computeBaseFunctionValue(i, k - 1, t, knots) + (knots.get(i + k) - t) / (knots.get(i + k) - knots.get(i + 1)) * CurveAndSurfaceMath.computeBaseFunctionValue(i + 1, k - 1, t, knots); } } }
/** * Create a NURBS spline. A spline type is automatically set to SplineType.Nurb. * The cycle is set to <b>false</b> by default. * @param controlPoints a list of vector to use as control points of the spline * @param nurbKnots the nurb's spline knots */ public Spline(List<Vector4f> controlPoints, List<Float> nurbKnots) { //input data control for(int i=0;i<nurbKnots.size()-1;++i) { if(nurbKnots.get(i)>nurbKnots.get(i+1)) { throw new IllegalArgumentException("The knots values cannot decrease!"); } } //storing the data type = SplineType.Nurb; this.weights = new float[controlPoints.size()]; this.knots = nurbKnots; this.basisFunctionDegree = nurbKnots.size() - weights.length; for(int i=0;i<controlPoints.size();++i) { Vector4f controlPoint = controlPoints.get(i); this.controlPoints.add(new Vector3f(controlPoint.x, controlPoint.y, controlPoint.z)); this.weights[i] = controlPoint.w; } CurveAndSurfaceMath.prepareNurbsKnots(knots, basisFunctionDegree); this.computeTotalLentgh(); }
/** * This method computes the base function value for the NURB curve. * @param i * the knot index * @param k * the base function degree * @param t * the knot value * @param knots * the knots' values * @return the base function value */ private static float computeBaseFunctionValue(int i, int k, float t, List<Float> knots) { if (k == 1) { return knots.get(i) <= t && t < knots.get(i + 1) ? 1.0f : 0.0f; } else { return (t - knots.get(i)) / (knots.get(i + k - 1) - knots.get(i)) * CurveAndSurfaceMath.computeBaseFunctionValue(i, k - 1, t, knots) + (knots.get(i + k) - t) / (knots.get(i + k) - knots.get(i + 1)) * CurveAndSurfaceMath.computeBaseFunctionValue(i + 1, k - 1, t, knots); } } }
/** * Create a NURBS spline. A spline type is automatically set to SplineType.Nurb. * The cycle is set to <b>false</b> by default. * @param controlPoints a list of vector to use as control points of the spline * @param nurbKnots the nurb's spline knots */ public Spline(List<Vector4f> controlPoints, List<Float> nurbKnots) { //input data control for(int i=0;i<nurbKnots.size()-1;++i) { if(nurbKnots.get(i)>nurbKnots.get(i+1)) { throw new IllegalArgumentException("The knots values cannot decrease!"); } } //storing the data type = SplineType.Nurb; this.weights = new float[controlPoints.size()]; this.knots = nurbKnots; this.basisFunctionDegree = nurbKnots.size() - weights.length; for(int i=0;i<controlPoints.size();++i) { Vector4f controlPoint = controlPoints.get(i); this.controlPoints.add(new Vector3f(controlPoint.x, controlPoint.y, controlPoint.z)); this.weights[i] = controlPoint.w; } CurveAndSurfaceMath.prepareNurbsKnots(knots, basisFunctionDegree); this.computeTotalLength(); }
Vector4f controlPoint = controlPoints.get(i).get(j); float val = controlPoint.w * CurveAndSurfaceMath.computeBaseFunctionValue(i, basisVFunctionDegree, v, knots[1]) * CurveAndSurfaceMath.computeBaseFunctionValue(j, basisUFunctionDegree, u, knots[0]); store.addLocal(controlPoint.x * val, controlPoint.y * val, controlPoint.z * val); delimeter += val;
Vector4f controlPoint = controlPoints.get(i).get(j); float val = controlPoint.w * CurveAndSurfaceMath.computeBaseFunctionValue(i, basisVFunctionDegree, v, knots[1]) * CurveAndSurfaceMath.computeBaseFunctionValue(j, basisUFunctionDegree, u, knots[0]); store.addLocal(controlPoint.x * val, controlPoint.y * val, controlPoint.z * val); delimeter += val;
/** * This method interpolates the data for the nurbs curve. * @param u * the u value * @param nurbSpline * the nurbs spline definition * @param store * the resulting point in 3D space */ public static void interpolateNurbs(float u, Spline nurbSpline, Vector3f store) { if (nurbSpline.getType() != SplineType.Nurb) { throw new IllegalArgumentException("Given spline is not of a NURB type!"); } List<Vector3f> controlPoints = nurbSpline.getControlPoints(); float[] weights = nurbSpline.getWeights(); List<Float> knots = nurbSpline.getKnots(); int controlPointAmount = controlPoints.size(); store.set(Vector3f.ZERO); float delimeter = 0; for (int i = 0; i < controlPointAmount; ++i) { float val = weights[i] * CurveAndSurfaceMath.computeBaseFunctionValue(i, nurbSpline.getBasisFunctionDegree(), u, knots); store.addLocal(nurbSpline.getControlPoints().get(i) .mult(val)); delimeter += val; } store.divideLocal(delimeter); }