159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/*
259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * To change this template, choose Tools | Templates
359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * and open the template in the editor.
459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.math;
659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.*;
859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.IOException;
959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.ArrayList;
1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.Iterator;
1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.List;
1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/**
1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Nehon
1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class Spline implements Savable {
1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public enum SplineType {
2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Linear,
2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        CatmullRom,
2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Bezier,
2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Nurb
2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private List<Vector3f> controlPoints = new ArrayList<Vector3f>();
2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private List<Float> knots;				//knots of NURBS spline
2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private float[] weights;				//weights of NURBS spline
2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private int basisFunctionDegree;		//degree of NURBS spline basis function (computed automatically)
3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private boolean cycle;
3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private List<Float> segmentsLength;
3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private float totalLength;
3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private List<Vector3f> CRcontrolPoints;
3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private float curveTension = 0.5f;
3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private SplineType type = SplineType.CatmullRom;
3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Spline() {
3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Create a spline
4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param splineType the type of the spline @see {SplineType}
4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param controlPoints an array of vector to use as control points of the spline
4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * If the type of the curve is Bezier curve the control points should be provided
4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * in the appropriate way. Each point 'p' describing control position in the scene
4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * should be surrounded by two handler points. This applies to every point except
4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * for the border points of the curve, who should have only one handle point.
4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * The pattern should be as follows:
4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * P0 - H0  :  H1 - P1 - H1  :  ...  :  Hn - Pn
5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * n is the amount of 'P' - points.
5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param curveTension the tension of the spline
5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param cycle true if the spline cycle.
5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Spline(SplineType splineType, Vector3f[] controlPoints, float curveTension, boolean cycle) {
5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	if(splineType==SplineType.Nurb) {
5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    		throw new IllegalArgumentException("To create NURBS spline use: 'public Spline(Vector3f[] controlPoints, float[] weights, float[] nurbKnots)' constructor!");
5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	}
5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        for (int i = 0; i < controlPoints.length; i++) {
6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Vector3f vector3f = controlPoints[i];
6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            this.controlPoints.add(vector3f);
6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        type = splineType;
6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.curveTension = curveTension;
6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.cycle = cycle;
6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.computeTotalLentgh();
6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Create a spline
7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param splineType the type of the spline @see {SplineType}
7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param controlPoints a list of vector to use as control points of the spline
7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * If the type of the curve is Bezier curve the control points should be provided
7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * in the appropriate way. Each point 'p' describing control position in the scene
7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * should be surrounded by two handler points. This applies to every point except
7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * for the border points of the curve, who should have only one handle point.
7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * The pattern should be as follows:
7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * P0 - H0  :  H1 - P1 - H1  :  ...  :  Hn - Pn
7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * n is the amount of 'P' - points.
8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param curveTension the tension of the spline
8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param cycle true if the spline cycle.
8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Spline(SplineType splineType, List<Vector3f> controlPoints, float curveTension, boolean cycle) {
8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	if(splineType==SplineType.Nurb) {
8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    		throw new IllegalArgumentException("To create NURBS spline use: 'public Spline(Vector3f[] controlPoints, float[] weights, float[] nurbKnots)' constructor!");
8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	}
8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        type = splineType;
8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.controlPoints.addAll(controlPoints);
9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.curveTension = curveTension;
9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.cycle = cycle;
9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.computeTotalLentgh();
9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Create a NURBS spline. A spline type is automatically set to SplineType.Nurb.
9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * The cycle is set to <b>false</b> by default.
9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param controlPoints a list of vector to use as control points of the spline
9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param nurbKnots the nurb's spline knots
10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Spline(List<Vector4f> controlPoints, List<Float> nurbKnots) {
10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	//input data control
10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	for(int i=0;i<nurbKnots.size()-1;++i) {
10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    		if(nurbKnots.get(i)>nurbKnots.get(i+1)) {
10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    			throw new IllegalArgumentException("The knots values cannot decrease!");
10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    		}
10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	}
10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	//storing the data
11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        type = SplineType.Nurb;
11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.weights = new float[controlPoints.size()];
11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.knots = nurbKnots;
11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.basisFunctionDegree = nurbKnots.size() - weights.length;
11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        for(int i=0;i<controlPoints.size();++i) {
11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        	Vector4f controlPoint = controlPoints.get(i);
11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        	this.controlPoints.add(new Vector3f(controlPoint.x, controlPoint.y, controlPoint.z));
11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        	this.weights[i] = controlPoint.w;
11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        CurveAndSurfaceMath.prepareNurbsKnots(knots, basisFunctionDegree);
12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.computeTotalLentgh();
12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private void initCatmullRomWayPoints(List<Vector3f> list) {
12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (CRcontrolPoints == null) {
12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            CRcontrolPoints = new ArrayList<Vector3f>();
12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else {
12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            CRcontrolPoints.clear();
12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int nb = list.size() - 1;
13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (cycle) {
13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            CRcontrolPoints.add(list.get(list.size() - 2));
13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else {
13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            CRcontrolPoints.add(list.get(0).subtract(list.get(1).subtract(list.get(0))));
13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        for (Iterator<Vector3f> it = list.iterator(); it.hasNext();) {
13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Vector3f vector3f = it.next();
13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            CRcontrolPoints.add(vector3f);
14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (cycle) {
14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            CRcontrolPoints.add(list.get(1));
14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else {
14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            CRcontrolPoints.add(list.get(nb).add(list.get(nb).subtract(list.get(nb - 1))));
14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Adds a controlPoint to the spline
15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param controlPoint a position in world space
15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void addControlPoint(Vector3f controlPoint) {
15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (controlPoints.size() > 2 && this.cycle) {
15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            controlPoints.remove(controlPoints.size() - 1);
15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        controlPoints.add(controlPoint);
15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (controlPoints.size() >= 2 && this.cycle) {
15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            controlPoints.add(controlPoints.get(0));
16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (controlPoints.size() > 1) {
16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            this.computeTotalLentgh();
16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * remove the controlPoint from the spline
16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param controlPoint the controlPoint to remove
16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void removeControlPoint(Vector3f controlPoint) {
17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        controlPoints.remove(controlPoint);
17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (controlPoints.size() > 1) {
17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            this.computeTotalLentgh();
17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void clearControlPoints(){
17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        controlPoints.clear();
17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        totalLength = 0;
18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * This method computes the total length of the curve.
18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private void computeTotalLentgh() {
18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        totalLength = 0;
18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        float l = 0;
18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (segmentsLength == null) {
18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            segmentsLength = new ArrayList<Float>();
19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else {
19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            segmentsLength.clear();
19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (type == SplineType.Linear) {
19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (controlPoints.size() > 1) {
19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                for (int i = 0; i < controlPoints.size() - 1; i++) {
19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    l = controlPoints.get(i + 1).subtract(controlPoints.get(i)).length();
19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    segmentsLength.add(l);
19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    totalLength += l;
19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else if(type == SplineType.Bezier) {
20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        	this.computeBezierLength();
20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else if(type == SplineType.Nurb) {
20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        	this.computeNurbLength();
20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else {
20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            this.initCatmullRomWayPoints(controlPoints);
20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            this.computeCatmulLength();
20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * This method computes the Catmull Rom curve length.
21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private void computeCatmulLength() {
21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        float l = 0;
21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (controlPoints.size() > 1) {
21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            for (int i = 0; i < controlPoints.size() - 1; i++) {
21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                l = FastMath.getCatmullRomP1toP2Length(CRcontrolPoints.get(i),
21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                        CRcontrolPoints.get(i + 1), CRcontrolPoints.get(i + 2), CRcontrolPoints.get(i + 3), 0, 1, curveTension);
22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                segmentsLength.add(l);
22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                totalLength += l;
22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * This method calculates the Bezier curve length.
22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private void computeBezierLength() {
23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	float l = 0;
23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (controlPoints.size() > 1) {
23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            for (int i = 0; i < controlPoints.size() - 1; i+=3) {
23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                l = FastMath.getBezierP1toP2Length(controlPoints.get(i),
23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                		controlPoints.get(i + 1), controlPoints.get(i + 2), controlPoints.get(i + 3));
23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                segmentsLength.add(l);
23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                totalLength += l;
23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * This method calculates the NURB curve length.
24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
24459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private void computeNurbLength() {
24559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	//TODO: implement
24659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
24759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
24859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
24959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Iterpolate a position on the spline
25059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param value a value from 0 to 1 that represent the postion between the curent control point and the next one
25159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param currentControlPoint the current control point
25259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param store a vector to store the result (use null to create a new one that will be returned by the method)
25359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return the position
25459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
25559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Vector3f interpolate(float value, int currentControlPoint, Vector3f store) {
25659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (store == null) {
25759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            store = new Vector3f();
25859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
25959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        switch (type) {
26059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            case CatmullRom:
26159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                FastMath.interpolateCatmullRom(value, curveTension, CRcontrolPoints.get(currentControlPoint), CRcontrolPoints.get(currentControlPoint + 1), CRcontrolPoints.get(currentControlPoint + 2), CRcontrolPoints.get(currentControlPoint + 3), store);
26259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                break;
26359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            case Linear:
26459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                FastMath.interpolateLinear(value, controlPoints.get(currentControlPoint), controlPoints.get(currentControlPoint + 1), store);
26559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                break;
26659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            case Bezier:
26759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            	FastMath.interpolateBezier(value, controlPoints.get(currentControlPoint), controlPoints.get(currentControlPoint + 1), controlPoints.get(currentControlPoint + 2), controlPoints.get(currentControlPoint + 3), store);
26859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            	break;
26959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            case Nurb:
27059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            	CurveAndSurfaceMath.interpolateNurbs(value, this, store);
27159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            	break;
27259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            default:
27359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                break;
27459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
27559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return store;
27659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
27759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
27859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
27959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * returns the curve tension
28059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
28159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public float getCurveTension() {
28259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return curveTension;
28359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
28459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
28559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
28659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * sets the curve tension
28759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *
28859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param curveTension the tension
28959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
29059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setCurveTension(float curveTension) {
29159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.curveTension = curveTension;
29259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if(type==SplineType.CatmullRom) {
29359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        	this.computeTotalLentgh();
29459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
29559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
29659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
29759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
29859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * returns true if the spline cycle
29959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
30059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean isCycle() {
30159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return cycle;
30259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
30359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
30459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
30559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * set to true to make the spline cycle
30659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param cycle
30759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
30859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setCycle(boolean cycle) {
30959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	if(type!=SplineType.Nurb) {
31059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    		if (controlPoints.size() >= 2) {
31159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    			if (this.cycle && !cycle) {
31259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    				controlPoints.remove(controlPoints.size() - 1);
31359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    			}
31459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    			if (!this.cycle && cycle) {
31559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    				controlPoints.add(controlPoints.get(0));
31659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    			}
31759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    			this.cycle = cycle;
31859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    			this.computeTotalLentgh();
31959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    		} else {
32059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    			this.cycle = cycle;
32159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    		}
32259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	}
32359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
32459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
32559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
32659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * return the total lenght of the spline
32759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
32859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public float getTotalLength() {
32959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return totalLength;
33059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
33159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
33259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
33359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * return the type of the spline
33459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
33559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public SplineType getType() {
33659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return type;
33759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
33859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
33959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
34059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * Sets the type of the spline
34159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @param type
34259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
34359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void setType(SplineType type) {
34459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.type = type;
34559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.computeTotalLentgh();
34659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
34759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
34859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
34959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * returns this spline control points
35059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
35159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public List<Vector3f> getControlPoints() {
35259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return controlPoints;
35359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
35459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
35559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
35659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * returns a list of float representing the segments lenght
35759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
35859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public List<Float> getSegmentsLength() {
35959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return segmentsLength;
36059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
36159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
36259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    //////////// NURBS getters /////////////////////
36359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
36459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
36559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method returns the minimum nurb curve knot value. Check the nurb type before calling this method. It the curve is not of a Nurb
36659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * type - NPE will be thrown.
36759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return the minimum nurb curve knot value
36859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
36959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public float getMinNurbKnot() {
37059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	return knots.get(basisFunctionDegree - 1);
37159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
37259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
37359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
37459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method returns the maximum nurb curve knot value. Check the nurb type before calling this method. It the curve is not of a Nurb
37559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * type - NPE will be thrown.
37659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return the maximum nurb curve knot value
37759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
37859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public float getMaxNurbKnot() {
37959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    	return knots.get(weights.length);
38059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
38159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
38259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
38359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * This method returns NURBS' spline knots.
38459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return NURBS' spline knots
38559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
38659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public List<Float> getKnots() {
38759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return knots;
38859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
38959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
39059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
39159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * This method returns NURBS' spline weights.
39259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return NURBS' spline weights
39359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
39459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public float[] getWeights() {
39559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return weights;
39659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
39759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
39859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
39959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * This method returns NURBS' spline basis function degree.
40059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     * @return NURBS' spline basis function degree
40159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
40259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public int getBasisFunctionDegree() {
40359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return basisFunctionDegree;
40459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
40559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
40659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
40759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void write(JmeExporter ex) throws IOException {
40859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        OutputCapsule oc = ex.getCapsule(this);
40959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.writeSavableArrayList((ArrayList) controlPoints, "controlPoints", null);
41059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(type, "type", SplineType.CatmullRom);
41159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        float list[] = new float[segmentsLength.size()];
41259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        for (int i = 0; i < segmentsLength.size(); i++) {
41359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            list[i] = segmentsLength.get(i);
41459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
41559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(list, "segmentsLength", null);
41659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
41759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(totalLength, "totalLength", 0);
41859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.writeSavableArrayList((ArrayList) CRcontrolPoints, "CRControlPoints", null);
41959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(curveTension, "curveTension", 0.5f);
42059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(cycle, "cycle", false);
42159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.writeSavableArrayList((ArrayList<Float>)knots, "knots", null);
42259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(weights, "weights", null);
42359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        oc.write(basisFunctionDegree, "basisFunctionDegree", 0);
42459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
42559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
42659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @Override
42759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void read(JmeImporter im) throws IOException {
42859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        InputCapsule in = im.getCapsule(this);
42959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
43059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        controlPoints = (ArrayList<Vector3f>) in.readSavableArrayList("wayPoints", null);
43159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        float list[] = in.readFloatArray("segmentsLength", null);
43259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (list != null) {
43359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            segmentsLength = new ArrayList<Float>();
43459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            for (int i = 0; i < list.length; i++) {
43559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                segmentsLength.add(new Float(list[i]));
43659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
43759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
43859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        type = in.readEnum("pathSplineType", SplineType.class, SplineType.CatmullRom);
43959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        totalLength = in.readFloat("totalLength", 0);
44059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        CRcontrolPoints = (ArrayList<Vector3f>) in.readSavableArrayList("CRControlPoints", null);
44159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        curveTension = in.readFloat("curveTension", 0.5f);
44259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        cycle = in.readBoolean("cycle", false);
44359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        knots = in.readSavableArrayList("knots", null);
44459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        weights = in.readFloatArray("weights", null);
44559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        basisFunctionDegree = in.readInt("basisFunctionDegree", 0);
44659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
44759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
448