Home | History | Annotate | Download | only in math
      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 	 */
     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 	 */
     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 	 */
     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
     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 	 */
    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