File: //var/www/aspa/three/extras/core/CurvePath.js
import { Curve } from './Curve.js';
import * as Curves from '../curves/Curves.js';
/**************************************************************
 *	Curved Path - a curve path is simply a array of connected
 *  curves, but retains the api of a curve
 **************************************************************/
class CurvePath extends Curve {
	constructor() {
		super();
		this.type = 'CurvePath';
		this.curves = [];
		this.autoClose = false; // Automatically closes the path
	}
	add( curve ) {
		this.curves.push( curve );
	}
	closePath() {
		// Add a line curve if start and end of lines are not connected
		const startPoint = this.curves[ 0 ].getPoint( 0 );
		const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
		if ( ! startPoint.equals( endPoint ) ) {
			const lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3';
			this.curves.push( new Curves[ lineType ]( endPoint, startPoint ) );
		}
		return this;
	}
	// To get accurate point with reference to
	// entire path distance at time t,
	// following has to be done:
	// 1. Length of each sub path have to be known
	// 2. Locate and identify type of curve
	// 3. Get t for the curve
	// 4. Return curve.getPointAt(t')
	getPoint( t, optionalTarget ) {
		const d = t * this.getLength();
		const curveLengths = this.getCurveLengths();
		let i = 0;
		// To think about boundaries points.
		while ( i < curveLengths.length ) {
			if ( curveLengths[ i ] >= d ) {
				const diff = curveLengths[ i ] - d;
				const curve = this.curves[ i ];
				const segmentLength = curve.getLength();
				const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
				return curve.getPointAt( u, optionalTarget );
			}
			i ++;
		}
		return null;
		// loop where sum != 0, sum > d , sum+1 <d
	}
	// We cannot use the default THREE.Curve getPoint() with getLength() because in
	// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
	// getPoint() depends on getLength
	getLength() {
		const lens = this.getCurveLengths();
		return lens[ lens.length - 1 ];
	}
	// cacheLengths must be recalculated.
	updateArcLengths() {
		this.needsUpdate = true;
		this.cacheLengths = null;
		this.getCurveLengths();
	}
	// Compute lengths and cache them
	// We cannot overwrite getLengths() because UtoT mapping uses it.
	getCurveLengths() {
		// We use cache values if curves and cache array are same length
		if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
			return this.cacheLengths;
		}
		// Get length of sub-curve
		// Push sums into cached array
		const lengths = [];
		let sums = 0;
		for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
			sums += this.curves[ i ].getLength();
			lengths.push( sums );
		}
		this.cacheLengths = lengths;
		return lengths;
	}
	getSpacedPoints( divisions = 40 ) {
		const points = [];
		for ( let i = 0; i <= divisions; i ++ ) {
			points.push( this.getPoint( i / divisions ) );
		}
		if ( this.autoClose ) {
			points.push( points[ 0 ] );
		}
		return points;
	}
	getPoints( divisions = 12 ) {
		const points = [];
		let last;
		for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) {
			const curve = curves[ i ];
			const resolution = curve.isEllipseCurve ? divisions * 2
				: ( curve.isLineCurve || curve.isLineCurve3 ) ? 1
					: curve.isSplineCurve ? divisions * curve.points.length
						: divisions;
			const pts = curve.getPoints( resolution );
			for ( let j = 0; j < pts.length; j ++ ) {
				const point = pts[ j ];
				if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
				points.push( point );
				last = point;
			}
		}
		if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {
			points.push( points[ 0 ] );
		}
		return points;
	}
	copy( source ) {
		super.copy( source );
		this.curves = [];
		for ( let i = 0, l = source.curves.length; i < l; i ++ ) {
			const curve = source.curves[ i ];
			this.curves.push( curve.clone() );
		}
		this.autoClose = source.autoClose;
		return this;
	}
	toJSON() {
		const data = super.toJSON();
		data.autoClose = this.autoClose;
		data.curves = [];
		for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
			const curve = this.curves[ i ];
			data.curves.push( curve.toJSON() );
		}
		return data;
	}
	fromJSON( json ) {
		super.fromJSON( json );
		this.autoClose = json.autoClose;
		this.curves = [];
		for ( let i = 0, l = json.curves.length; i < l; i ++ ) {
			const curve = json.curves[ i ];
			this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );
		}
		return this;
	}
}
export { CurvePath };