1 package com.jme3.math; 2 3 import com.jme3.math.Spline.SplineType; 4 import java.util.List; 5 6 /** 7 * This class offers methods to help with curves and surfaces calculations. 8 * @author Marcin Roguski (Kealthas) 9 */ 10 public class CurveAndSurfaceMath { 11 private static final float KNOTS_MINIMUM_DELTA = 0.0001f; 12 13 /** 14 * A private constructor is defined to avoid instatiation of this class. 15 */ CurveAndSurfaceMath()16 private CurveAndSurfaceMath() {} 17 18 /** 19 * This method interpolates tha data for the nurbs curve. 20 * @param u 21 * the u value 22 * @param nurbSpline 23 * the nurbs spline definition 24 * @param store 25 * the resulting point in 3D space 26 */ interpolateNurbs(float u, Spline nurbSpline, Vector3f store)27 public static void interpolateNurbs(float u, Spline nurbSpline, Vector3f store) { 28 if (nurbSpline.getType() != SplineType.Nurb) { 29 throw new IllegalArgumentException("Given spline is not of a NURB type!"); 30 } 31 List<Vector3f> controlPoints = nurbSpline.getControlPoints(); 32 float[] weights = nurbSpline.getWeights(); 33 List<Float> knots = nurbSpline.getKnots(); 34 int controlPointAmount = controlPoints.size(); 35 36 store.set(Vector3f.ZERO); 37 float delimeter = 0; 38 for (int i = 0; i < controlPointAmount; ++i) { 39 float val = weights[i] * CurveAndSurfaceMath.computeBaseFunctionValue(i, nurbSpline.getBasisFunctionDegree(), u, knots); 40 store.addLocal(nurbSpline.getControlPoints().get(i) 41 .mult(val)); 42 delimeter += val; 43 } 44 store.divideLocal(delimeter); 45 } 46 47 /** 48 * This method interpolates tha data for the nurbs surface. 49 * 50 * @param u 51 * the u value 52 * @param v 53 * the v value 54 * @param controlPoints 55 * the nurbs' control points 56 * @param knots 57 * the nurbs' knots 58 * @param basisUFunctionDegree 59 * the degree of basis U function 60 * @param basisVFunctionDegree 61 * the degree of basis V function 62 * @param store 63 * the resulting point in 3D space 64 */ interpolate(float u, float v, List<List<Vector4f>> controlPoints, List<Float>[] knots, int basisUFunctionDegree, int basisVFunctionDegree, Vector3f store)65 public static void interpolate(float u, float v, List<List<Vector4f>> controlPoints, List<Float>[] knots, 66 int basisUFunctionDegree, int basisVFunctionDegree, Vector3f store) { 67 store.set(Vector3f.ZERO); 68 float delimeter = 0; 69 int vControlPointsAmount = controlPoints.size(); 70 int uControlPointsAmount = controlPoints.get(0).size(); 71 for (int i = 0; i < vControlPointsAmount; ++i) { 72 for (int j = 0; j < uControlPointsAmount; ++j) { 73 Vector4f controlPoint = controlPoints.get(i).get(j); 74 float val = controlPoint.w 75 * CurveAndSurfaceMath.computeBaseFunctionValue(i, basisVFunctionDegree, v, knots[1]) 76 * CurveAndSurfaceMath.computeBaseFunctionValue(j, basisUFunctionDegree, u, knots[0]); 77 store.addLocal(controlPoint.x * val, controlPoint.y * val, controlPoint.z * val); 78 delimeter += val; 79 } 80 } 81 store.divideLocal(delimeter); 82 } 83 84 /** 85 * This method prepares the knots to be used. If the knots represent non-uniform B-splines (first and last knot values are being 86 * repeated) it leads to NaN results during calculations. This method adds a small number to each of such knots to avoid NaN's. 87 * @param knots 88 * the knots to be prepared to use 89 * @param basisFunctionDegree 90 * the degree of basis function 91 */ 92 // TODO: improve this; constant delta may lead to errors if the difference between tha last repeated 93 // point and the following one is lower than it prepareNurbsKnots(List<Float> knots, int basisFunctionDegree)94 public static void prepareNurbsKnots(List<Float> knots, int basisFunctionDegree) { 95 float delta = KNOTS_MINIMUM_DELTA; 96 float prevValue = knots.get(0).floatValue(); 97 for(int i=1;i<knots.size();++i) { 98 float value = knots.get(i).floatValue(); 99 if(value<=prevValue) { 100 value += delta; 101 knots.set(i, Float.valueOf(value)); 102 delta += KNOTS_MINIMUM_DELTA; 103 } else { 104 delta = KNOTS_MINIMUM_DELTA;//reset the delta's value 105 } 106 107 prevValue = value; 108 } 109 } 110 111 /** 112 * This method computes the base function value for the NURB curve. 113 * @param i 114 * the knot index 115 * @param k 116 * the base function degree 117 * @param t 118 * the knot value 119 * @param knots 120 * the knots' values 121 * @return the base function value 122 */ computeBaseFunctionValue(int i, int k, float t, List<Float> knots)123 private static float computeBaseFunctionValue(int i, int k, float t, List<Float> knots) { 124 if (k == 1) { 125 return knots.get(i) <= t && t < knots.get(i + 1) ? 1.0f : 0.0f; 126 } else { 127 return (t - knots.get(i)) / (knots.get(i + k - 1) - knots.get(i)) * 128 CurveAndSurfaceMath.computeBaseFunctionValue(i, k - 1, t, knots) 129 + (knots.get(i + k) - t) / (knots.get(i + k) - knots.get(i + 1)) * 130 CurveAndSurfaceMath.computeBaseFunctionValue(i + 1, k - 1, t, knots); 131 } 132 } 133 } 134