File: //var/www/aspa/three/addons/modifiers/EdgeSplitModifier.js
import {
	BufferAttribute,
	BufferGeometry,
	Vector3
} from 'three';
import * as BufferGeometryUtils from '../utils/BufferGeometryUtils.js';
const _A = new Vector3();
const _B = new Vector3();
const _C = new Vector3();
class EdgeSplitModifier {
	modify( geometry, cutOffAngle, tryKeepNormals = true ) {
		function computeNormals() {
			normals = new Float32Array( indexes.length * 3 );
			for ( let i = 0; i < indexes.length; i += 3 ) {
				let index = indexes[ i ];
				_A.set(
					positions[ 3 * index ],
					positions[ 3 * index + 1 ],
					positions[ 3 * index + 2 ] );
				index = indexes[ i + 1 ];
				_B.set(
					positions[ 3 * index ],
					positions[ 3 * index + 1 ],
					positions[ 3 * index + 2 ] );
				index = indexes[ i + 2 ];
				_C.set(
					positions[ 3 * index ],
					positions[ 3 * index + 1 ],
					positions[ 3 * index + 2 ] );
				_C.sub( _B );
				_A.sub( _B );
				const normal = _C.cross( _A ).normalize();
				for ( let j = 0; j < 3; j ++ ) {
					normals[ 3 * ( i + j ) ] = normal.x;
					normals[ 3 * ( i + j ) + 1 ] = normal.y;
					normals[ 3 * ( i + j ) + 2 ] = normal.z;
				}
			}
		}
		function mapPositionsToIndexes() {
			pointToIndexMap = Array( positions.length / 3 );
			for ( let i = 0; i < indexes.length; i ++ ) {
				const index = indexes[ i ];
				if ( pointToIndexMap[ index ] == null ) {
					pointToIndexMap[ index ] = [];
				}
				pointToIndexMap[ index ].push( i );
			}
		}
		function edgeSplitToGroups( indexes, cutOff, firstIndex ) {
			_A.set( normals[ 3 * firstIndex ], normals[ 3 * firstIndex + 1 ], normals[ 3 * firstIndex + 2 ] ).normalize();
			const result = {
				splitGroup: [],
				currentGroup: [ firstIndex ]
			};
			for ( const j of indexes ) {
				if ( j !== firstIndex ) {
					_B.set( normals[ 3 * j ], normals[ 3 * j + 1 ], normals[ 3 * j + 2 ] ).normalize();
					if ( _B.dot( _A ) < cutOff ) {
						result.splitGroup.push( j );
					} else {
						result.currentGroup.push( j );
					}
				}
			}
			return result;
		}
		function edgeSplit( indexes, cutOff, original = null ) {
			if ( indexes.length === 0 ) return;
			const groupResults = [];
			for ( const index of indexes ) {
				groupResults.push( edgeSplitToGroups( indexes, cutOff, index ) );
			}
			let result = groupResults[ 0 ];
			for ( const groupResult of groupResults ) {
				if ( groupResult.currentGroup.length > result.currentGroup.length ) {
					result = groupResult;
				}
			}
			if ( original != null ) {
				splitIndexes.push( {
					original: original,
					indexes: result.currentGroup
				} );
			}
			if ( result.splitGroup.length ) {
				edgeSplit( result.splitGroup, cutOff, original || result.currentGroup[ 0 ] );
			}
		}
		let hadNormals = false;
		let oldNormals = null;
		if ( geometry.attributes.normal ) {
			hadNormals = true;
			geometry = geometry.clone();
			if ( tryKeepNormals === true && geometry.index !== null ) {
				oldNormals = geometry.attributes.normal.array;
			}
			geometry.deleteAttribute( 'normal' );
		}
		if ( geometry.index == null ) {
			geometry = BufferGeometryUtils.mergeVertices( geometry );
		}
		const indexes = geometry.index.array;
		const positions = geometry.getAttribute( 'position' ).array;
		let normals;
		let pointToIndexMap;
		computeNormals();
		mapPositionsToIndexes();
		const splitIndexes = [];
		for ( const vertexIndexes of pointToIndexMap ) {
			edgeSplit( vertexIndexes, Math.cos( cutOffAngle ) - 0.001 );
		}
		const newAttributes = {};
		for ( const name of Object.keys( geometry.attributes ) ) {
			const oldAttribute = geometry.attributes[ name ];
			const newArray = new oldAttribute.array.constructor( ( indexes.length + splitIndexes.length ) * oldAttribute.itemSize );
			newArray.set( oldAttribute.array );
			newAttributes[ name ] = new BufferAttribute( newArray, oldAttribute.itemSize, oldAttribute.normalized );
		}
		const newIndexes = new Uint32Array( indexes.length );
		newIndexes.set( indexes );
		for ( let i = 0; i < splitIndexes.length; i ++ ) {
			const split = splitIndexes[ i ];
			const index = indexes[ split.original ];
			for ( const attribute of Object.values( newAttributes ) ) {
				for ( let j = 0; j < attribute.itemSize; j ++ ) {
					attribute.array[ ( indexes.length + i ) * attribute.itemSize + j ] =
						attribute.array[ index * attribute.itemSize + j ];
				}
			}
			for ( const j of split.indexes ) {
				newIndexes[ j ] = indexes.length + i;
			}
		}
		geometry = new BufferGeometry();
		geometry.setIndex( new BufferAttribute( newIndexes, 1 ) );
		for ( const name of Object.keys( newAttributes ) ) {
			geometry.setAttribute( name, newAttributes[ name ] );
		}
		if ( hadNormals ) {
			geometry.computeVertexNormals();
			if ( oldNormals !== null ) {
				const changedNormals = new Array( oldNormals.length / 3 ).fill( false );
				for ( const splitData of splitIndexes )
					changedNormals[ splitData.original ] = true;
				for ( let i = 0; i < changedNormals.length; i ++ ) {
					if ( changedNormals[ i ] === false ) {
						for ( let j = 0; j < 3; j ++ )
							geometry.attributes.normal.array[ 3 * i + j ] = oldNormals[ 3 * i + j ];
					}
				}
			}
		}
		return geometry;
	}
}
export { EdgeSplitModifier };