1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137 |
- /*!
- *
- * threeoctree.js (r60) / https://github.com/collinhover/threeoctree
- * (sparse) dynamic 3D spatial representation structure for fast searches.
- *
- * @author Collin Hover / http://collinhover.com/
- * based on Dynamic Octree by Piko3D @ http://www.piko3d.com/ and Octree by Marek Pawlowski @ pawlowski.it
- *
- */
- ( function ( THREE ) {
- "use strict";
-
- /*===================================================
- utility
- =====================================================*/
-
- function isNumber ( n ) {
- return ! isNaN( n ) && isFinite( n );
- }
-
- function isArray ( target ) {
- return Object.prototype.toString.call( target ) === '[object Array]';
- }
-
- function toArray ( target ) {
- return target ? ( isArray ( target ) !== true ? [ target ] : target ) : [];
- }
-
- function indexOfValue( array, value ) {
-
- for ( var i = 0, il = array.length; i < il; i ++ ) {
-
- if ( array[ i ] === value ) {
-
- return i;
-
- }
-
- }
-
- return - 1;
-
- }
-
- function indexOfPropertyWithValue( array, property, value ) {
-
- for ( var i = 0, il = array.length; i < il; i ++ ) {
-
- if ( array[ i ][ property ] === value ) {
-
- return i;
-
- }
-
- }
-
- return - 1;
-
- }
- /*===================================================
- octree
- =====================================================*/
- THREE.Octree = function ( parameters ) {
-
- // handle parameters
-
- parameters = parameters || {};
-
- parameters.tree = this;
-
- // static properties ( modification is not recommended )
-
- this.nodeCount = 0;
-
- this.INDEX_INSIDE_CROSS = - 1;
- this.INDEX_OUTSIDE_OFFSET = 2;
-
- this.INDEX_OUTSIDE_POS_X = isNumber( parameters.INDEX_OUTSIDE_POS_X ) ? parameters.INDEX_OUTSIDE_POS_X : 0;
- this.INDEX_OUTSIDE_NEG_X = isNumber( parameters.INDEX_OUTSIDE_NEG_X ) ? parameters.INDEX_OUTSIDE_NEG_X : 1;
- this.INDEX_OUTSIDE_POS_Y = isNumber( parameters.INDEX_OUTSIDE_POS_Y ) ? parameters.INDEX_OUTSIDE_POS_Y : 2;
- this.INDEX_OUTSIDE_NEG_Y = isNumber( parameters.INDEX_OUTSIDE_NEG_Y ) ? parameters.INDEX_OUTSIDE_NEG_Y : 3;
- this.INDEX_OUTSIDE_POS_Z = isNumber( parameters.INDEX_OUTSIDE_POS_Z ) ? parameters.INDEX_OUTSIDE_POS_Z : 4;
- this.INDEX_OUTSIDE_NEG_Z = isNumber( parameters.INDEX_OUTSIDE_NEG_Z ) ? parameters.INDEX_OUTSIDE_NEG_Z : 5;
-
- this.INDEX_OUTSIDE_MAP = [];
- this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_POS_X ] = { index: this.INDEX_OUTSIDE_POS_X, count: 0, x: 1, y: 0, z: 0 };
- this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_NEG_X ] = { index: this.INDEX_OUTSIDE_NEG_X, count: 0, x: - 1, y: 0, z: 0 };
- this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_POS_Y ] = { index: this.INDEX_OUTSIDE_POS_Y, count: 0, x: 0, y: 1, z: 0 };
- this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_NEG_Y ] = { index: this.INDEX_OUTSIDE_NEG_Y, count: 0, x: 0, y: - 1, z: 0 };
- this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_POS_Z ] = { index: this.INDEX_OUTSIDE_POS_Z, count: 0, x: 0, y: 0, z: 1 };
- this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_NEG_Z ] = { index: this.INDEX_OUTSIDE_NEG_Z, count: 0, x: 0, y: 0, z: - 1 };
-
- this.FLAG_POS_X = 1 << ( this.INDEX_OUTSIDE_POS_X + 1 );
- this.FLAG_NEG_X = 1 << ( this.INDEX_OUTSIDE_NEG_X + 1 );
- this.FLAG_POS_Y = 1 << ( this.INDEX_OUTSIDE_POS_Y + 1 );
- this.FLAG_NEG_Y = 1 << ( this.INDEX_OUTSIDE_NEG_Y + 1 );
- this.FLAG_POS_Z = 1 << ( this.INDEX_OUTSIDE_POS_Z + 1 );
- this.FLAG_NEG_Z = 1 << ( this.INDEX_OUTSIDE_NEG_Z + 1 );
-
- this.utilVec31Search = new THREE.Vector3();
- this.utilVec32Search = new THREE.Vector3();
-
- // pass scene to see octree structure
-
- this.scene = parameters.scene;
-
- if ( this.scene ) {
-
- this.visualGeometry = new THREE.BoxGeometry( 1, 1, 1 );
- this.visualMaterial = new THREE.MeshBasicMaterial( { color: 0xFF0066, wireframe: true, wireframeLinewidth: 1 } );
-
- }
-
- // properties
-
- this.objects = [];
- this.objectsMap = {};
- this.objectsData = [];
- this.objectsDeferred = [];
-
- this.depthMax = isNumber( parameters.depthMax ) ? parameters.depthMax : Infinity;
- this.objectsThreshold = isNumber( parameters.objectsThreshold ) ? parameters.objectsThreshold : 8;
- this.overlapPct = isNumber( parameters.overlapPct ) ? parameters.overlapPct : 0.15;
- this.undeferred = parameters.undeferred || false;
-
- this.root = parameters.root instanceof THREE.OctreeNode ? parameters.root : new THREE.OctreeNode( parameters );
-
- };
- THREE.Octree.prototype = {
-
- update: function () {
-
- // add any deferred objects that were waiting for render cycle
-
- if ( this.objectsDeferred.length > 0 ) {
-
- for ( var i = 0, il = this.objectsDeferred.length; i < il; i ++ ) {
-
- var deferred = this.objectsDeferred[ i ];
-
- this.addDeferred( deferred.object, deferred.options );
-
- }
-
- this.objectsDeferred.length = 0;
-
- }
-
- },
-
- add: function ( object, options ) {
-
- // add immediately
-
- if ( this.undeferred ) {
-
- this.updateObject( object );
-
- this.addDeferred( object, options );
-
- } else {
-
- // defer add until update called
-
- this.objectsDeferred.push( { object: object, options: options } );
-
- }
-
- },
-
- addDeferred: function ( object, options ) {
-
- var i, l,
- geometry,
- faces,
- useFaces,
- vertices,
- useVertices,
- objectData;
-
- // ensure object is not object data
-
- if ( object instanceof THREE.OctreeObjectData ) {
-
- object = object.object;
-
- }
-
- // check uuid to avoid duplicates
-
- if ( ! object.uuid ) {
-
- object.uuid = THREE.Math.generateUUID();
-
- }
-
- if ( ! this.objectsMap[ object.uuid ] ) {
-
- // store
-
- this.objects.push( object );
- this.objectsMap[ object.uuid ] = object;
-
- // check options
-
- if ( options ) {
-
- useFaces = options.useFaces;
- useVertices = options.useVertices;
-
- }
-
- if ( useVertices === true ) {
-
- geometry = object.geometry;
- vertices = geometry.vertices;
-
- for ( i = 0, l = vertices.length; i < l; i ++ ) {
-
- this.addObjectData( object, vertices[ i ] );
-
- }
-
- } else if ( useFaces === true ) {
-
- geometry = object.geometry;
- faces = geometry.faces;
-
- for ( i = 0, l = faces.length; i < l; i ++ ) {
-
- this.addObjectData( object, faces[ i ] );
-
- }
-
- } else {
-
- this.addObjectData( object );
-
- }
-
- }
-
- },
-
- addObjectData: function ( object, part ) {
-
- var objectData = new THREE.OctreeObjectData( object, part );
-
- // add to tree objects data list
-
- this.objectsData.push( objectData );
-
- // add to nodes
-
- this.root.addObject( objectData );
-
- },
-
- remove: function ( object ) {
-
- var i, l,
- objectData = object,
- index,
- objectsDataRemoved;
-
- // ensure object is not object data for index search
-
- if ( object instanceof THREE.OctreeObjectData ) {
-
- object = object.object;
-
- }
-
- // check uuid
-
- if ( this.objectsMap[ object.uuid ] ) {
-
- this.objectsMap[ object.uuid ] = undefined;
-
- // check and remove from objects, nodes, and data lists
-
- index = indexOfValue( this.objects, object );
-
- if ( index !== - 1 ) {
-
- this.objects.splice( index, 1 );
-
- // remove from nodes
-
- objectsDataRemoved = this.root.removeObject( objectData );
-
- // remove from objects data list
-
- for ( i = 0, l = objectsDataRemoved.length; i < l; i ++ ) {
-
- objectData = objectsDataRemoved[ i ];
-
- index = indexOfValue( this.objectsData, objectData );
-
- if ( index !== - 1 ) {
-
- this.objectsData.splice( index, 1 );
-
- }
-
- }
-
- }
-
- } else if ( this.objectsDeferred.length > 0 ) {
-
- // check and remove from deferred
-
- index = indexOfPropertyWithValue( this.objectsDeferred, 'object', object );
-
- if ( index !== - 1 ) {
-
- this.objectsDeferred.splice( index, 1 );
-
- }
-
- }
-
- },
-
- extend: function ( octree ) {
-
- var i, l,
- objectsData,
- objectData;
-
- if ( octree instanceof THREE.Octree ) {
-
- // for each object data
-
- objectsData = octree.objectsData;
-
- for ( i = 0, l = objectsData.length; i < l; i ++ ) {
-
- objectData = objectsData[ i ];
-
- this.add( objectData, { useFaces: objectData.faces, useVertices: objectData.vertices } );
-
- }
-
- }
-
- },
-
- rebuild: function () {
-
- var i, l,
- node,
- object,
- objectData,
- indexOctant,
- indexOctantLast,
- objectsUpdate = [];
-
- // check all object data for changes in position
- // assumes all object matrices are up to date
-
- for ( i = 0, l = this.objectsData.length; i < l; i ++ ) {
-
- objectData = this.objectsData[ i ];
-
- node = objectData.node;
-
- // update object
-
- objectData.update();
-
- // if position has changed since last organization of object in tree
-
- if ( node instanceof THREE.OctreeNode && ! objectData.positionLast.equals( objectData.position ) ) {
-
- // get octant index of object within current node
-
- indexOctantLast = objectData.indexOctant;
-
- indexOctant = node.getOctantIndex( objectData );
-
- // if object octant index has changed
-
- if ( indexOctant !== indexOctantLast ) {
-
- // add to update list
-
- objectsUpdate.push( objectData );
-
- }
-
- }
-
- }
-
- // update changed objects
-
- for ( i = 0, l = objectsUpdate.length; i < l; i ++ ) {
-
- objectData = objectsUpdate[ i ];
-
- // remove object from current node
-
- objectData.node.removeObject( objectData );
-
- // add object to tree root
-
- this.root.addObject( objectData );
-
- }
-
- },
-
- updateObject: function ( object ) {
-
- var i, l,
- parentCascade = [ object ],
- parent,
- parentUpdate;
-
- // search all parents between object and root for world matrix update
-
- parent = object.parent;
-
- while ( parent ) {
-
- parentCascade.push( parent );
- parent = parent.parent;
-
- }
-
- for ( i = 0, l = parentCascade.length; i < l; i ++ ) {
-
- parent = parentCascade[ i ];
-
- if ( parent.matrixWorldNeedsUpdate === true ) {
-
- parentUpdate = parent;
-
- }
-
- }
-
- // update world matrix starting at uppermost parent that needs update
-
- if ( typeof parentUpdate !== 'undefined' ) {
-
- parentUpdate.updateMatrixWorld();
-
- }
-
- },
-
- search: function ( position, radius, organizeByObject, direction ) {
-
- var i, l,
- node,
- objects,
- objectData,
- object,
- results,
- resultData,
- resultsObjectsIndices,
- resultObjectIndex,
- directionPct;
-
- // add root objects
-
- objects = [].concat( this.root.objects );
-
- // ensure radius (i.e. distance of ray) is a number
-
- if ( ! ( radius > 0 ) ) {
-
- radius = Number.MAX_VALUE;
-
- }
-
- // if direction passed, normalize and find pct
-
- if ( direction instanceof THREE.Vector3 ) {
-
- direction = this.utilVec31Search.copy( direction ).normalize();
- directionPct = this.utilVec32Search.set( 1, 1, 1 ).divide( direction );
-
- }
-
- // search each node of root
-
- for ( i = 0, l = this.root.nodesIndices.length; i < l; i ++ ) {
-
- node = this.root.nodesByIndex[ this.root.nodesIndices[ i ] ];
-
- objects = node.search( position, radius, objects, direction, directionPct );
-
- }
-
- // if should organize results by object
-
- if ( organizeByObject === true ) {
-
- results = [];
- resultsObjectsIndices = [];
-
- // for each object data found
-
- for ( i = 0, l = objects.length; i < l; i ++ ) {
-
- objectData = objects[ i ];
- object = objectData.object;
-
- resultObjectIndex = indexOfValue( resultsObjectsIndices, object );
-
- // if needed, create new result data
-
- if ( resultObjectIndex === - 1 ) {
-
- resultData = {
- object: object,
- faces: [],
- vertices: []
- };
-
- results.push( resultData );
-
- resultsObjectsIndices.push( object );
-
- } else {
-
- resultData = results[ resultObjectIndex ];
-
- }
-
- // object data has faces or vertices, add to list
-
- if ( objectData.faces ) {
-
- resultData.faces.push( objectData.faces );
-
- } else if ( objectData.vertices ) {
-
- resultData.vertices.push( objectData.vertices );
-
- }
-
- }
-
- } else {
-
- results = objects;
-
- }
-
- return results;
-
- },
-
- setRoot: function ( root ) {
-
- if ( root instanceof THREE.OctreeNode ) {
-
- // store new root
-
- this.root = root;
-
- // update properties
-
- this.root.updateProperties();
-
- }
-
- },
-
- getDepthEnd: function () {
-
- return this.root.getDepthEnd();
-
- },
-
- getNodeCountEnd: function () {
-
- return this.root.getNodeCountEnd();
-
- },
-
- getObjectCountEnd: function () {
-
- return this.root.getObjectCountEnd();
-
- },
-
- toConsole: function () {
-
- this.root.toConsole();
-
- }
-
- };
- /*===================================================
- object data
- =====================================================*/
- THREE.OctreeObjectData = function ( object, part ) {
-
- // properties
-
- this.object = object;
-
- // handle part by type
-
- if ( part instanceof THREE.Face3 ) {
-
- this.faces = part;
- this.face3 = true;
- this.utilVec31FaceBounds = new THREE.Vector3();
-
- } else if ( part instanceof THREE.Vector3 ) {
-
- this.vertices = part;
-
- }
-
- this.radius = 0;
- this.position = new THREE.Vector3();
-
- // initial update
-
- if ( this.object instanceof THREE.Object3D ) {
-
- this.update();
-
- }
-
- this.positionLast = this.position.clone();
-
- };
- THREE.OctreeObjectData.prototype = {
-
- update: function () {
-
- if ( this.face3 ) {
-
- this.radius = this.getFace3BoundingRadius( this.object, this.faces );
- this.position.copy( this.faces.centroid ).applyMatrix4( this.object.matrixWorld );
-
- } else if ( this.vertices ) {
-
- this.radius = this.object.material.size || 1;
- this.position.copy( this.vertices ).applyMatrix4( this.object.matrixWorld );
-
- } else {
-
- if ( this.object.geometry ) {
-
- if ( this.object.geometry.boundingSphere === null ) {
-
- this.object.geometry.computeBoundingSphere();
-
- }
-
- this.radius = this.object.geometry.boundingSphere.radius;
- this.position.copy( this.object.geometry.boundingSphere.center ).applyMatrix4( this.object.matrixWorld );
-
- } else {
-
- this.radius = this.object.boundRadius;
- this.position.setFromMatrixPosition( this.object.matrixWorld );
-
- }
-
- }
-
- this.radius = this.radius * Math.max( this.object.scale.x, this.object.scale.y, this.object.scale.z );
-
- },
-
- getFace3BoundingRadius: function ( object, face ) {
- if ( face.centroid === undefined ) face.centroid = new THREE.Vector3();
-
- var geometry = object.geometry || object,
- vertices = geometry.vertices,
- centroid = face.centroid,
- va = vertices[ face.a ], vb = vertices[ face.b ], vc = vertices[ face.c ],
- centroidToVert = this.utilVec31FaceBounds,
- radius;
-
- centroid.addVectors( va, vb ).add( vc ).divideScalar( 3 );
- radius = Math.max( centroidToVert.subVectors( centroid, va ).length(), centroidToVert.subVectors( centroid, vb ).length(), centroidToVert.subVectors( centroid, vc ).length() );
-
- return radius;
-
- }
-
- };
- /*===================================================
- node
- =====================================================*/
- THREE.OctreeNode = function ( parameters ) {
-
- // utility
-
- this.utilVec31Branch = new THREE.Vector3();
- this.utilVec31Expand = new THREE.Vector3();
- this.utilVec31Ray = new THREE.Vector3();
-
- // handle parameters
-
- parameters = parameters || {};
-
- // store or create tree
-
- if ( parameters.tree instanceof THREE.Octree ) {
-
- this.tree = parameters.tree;
-
- } else if ( parameters.parent instanceof THREE.OctreeNode !== true ) {
-
- parameters.root = this;
-
- this.tree = new THREE.Octree( parameters );
-
- }
-
- // basic properties
-
- this.id = this.tree.nodeCount ++;
- this.position = parameters.position instanceof THREE.Vector3 ? parameters.position : new THREE.Vector3();
- this.radius = parameters.radius > 0 ? parameters.radius : 1;
- this.indexOctant = parameters.indexOctant;
- this.depth = 0;
-
- // reset and assign parent
-
- this.reset();
- this.setParent( parameters.parent );
-
- // additional properties
-
- this.overlap = this.radius * this.tree.overlapPct;
- this.radiusOverlap = this.radius + this.overlap;
- this.left = this.position.x - this.radiusOverlap;
- this.right = this.position.x + this.radiusOverlap;
- this.bottom = this.position.y - this.radiusOverlap;
- this.top = this.position.y + this.radiusOverlap;
- this.back = this.position.z - this.radiusOverlap;
- this.front = this.position.z + this.radiusOverlap;
-
- // visual
-
- if ( this.tree.scene ) {
-
- this.visual = new THREE.Mesh( this.tree.visualGeometry, this.tree.visualMaterial );
- this.visual.scale.set( this.radiusOverlap * 2, this.radiusOverlap * 2, this.radiusOverlap * 2 );
- this.visual.position.copy( this.position );
- this.tree.scene.add( this.visual );
-
- }
-
- };
- THREE.OctreeNode.prototype = {
-
- setParent: function ( parent ) {
-
- // store new parent
-
- if ( parent !== this && this.parent !== parent ) {
-
- this.parent = parent;
-
- // update properties
-
- this.updateProperties();
-
- }
-
- },
-
- updateProperties: function () {
-
- var i, l;
-
- // properties
-
- if ( this.parent instanceof THREE.OctreeNode ) {
-
- this.tree = this.parent.tree;
- this.depth = this.parent.depth + 1;
-
- } else {
-
- this.depth = 0;
-
- }
-
- // cascade
-
- for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
- this.nodesByIndex[ this.nodesIndices[ i ] ].updateProperties();
-
- }
-
- },
-
- reset: function ( cascade, removeVisual ) {
-
- var i, l,
- node,
- nodesIndices = this.nodesIndices || [],
- nodesByIndex = this.nodesByIndex;
-
- this.objects = [];
- this.nodesIndices = [];
- this.nodesByIndex = {};
-
- // unset parent in nodes
-
- for ( i = 0, l = nodesIndices.length; i < l; i ++ ) {
-
- node = nodesByIndex[ nodesIndices[ i ] ];
-
- node.setParent( undefined );
-
- if ( cascade === true ) {
-
- node.reset( cascade, removeVisual );
-
- }
-
- }
-
- // visual
-
- if ( removeVisual === true && this.visual && this.visual.parent ) {
-
- this.visual.parent.remove( this.visual );
-
- }
-
- },
-
- addNode: function ( node, indexOctant ) {
-
- node.indexOctant = indexOctant;
-
- if ( indexOfValue( this.nodesIndices, indexOctant ) === - 1 ) {
-
- this.nodesIndices.push( indexOctant );
-
- }
-
- this.nodesByIndex[ indexOctant ] = node;
-
- if ( node.parent !== this ) {
-
- node.setParent( this );
-
- }
-
- },
-
- removeNode: function ( indexOctant ) {
-
- var index,
- node;
-
- index = indexOfValue( this.nodesIndices, indexOctant );
-
- this.nodesIndices.splice( index, 1 );
-
- node = node || this.nodesByIndex[ indexOctant ];
-
- delete this.nodesByIndex[ indexOctant ];
-
- if ( node.parent === this ) {
-
- node.setParent( undefined );
-
- }
-
- },
-
- addObject: function ( object ) {
-
- var index,
- indexOctant,
- node;
-
- // get object octant index
-
- indexOctant = this.getOctantIndex( object );
-
- // if object fully contained by an octant, add to subtree
- if ( indexOctant > - 1 && this.nodesIndices.length > 0 ) {
-
- node = this.branch( indexOctant );
-
- node.addObject( object );
-
- } else if ( indexOctant < - 1 && this.parent instanceof THREE.OctreeNode ) {
-
- // if object lies outside bounds, add to parent node
-
- this.parent.addObject( object );
-
- } else {
-
- // add to this objects list
-
- index = indexOfValue( this.objects, object );
-
- if ( index === - 1 ) {
-
- this.objects.push( object );
-
- }
-
- // node reference
-
- object.node = this;
-
- // check if need to expand, split, or both
-
- this.checkGrow();
-
- }
-
- },
-
- addObjectWithoutCheck: function ( objects ) {
-
- var i, l,
- object;
- for ( i = 0, l = objects.length; i < l; i ++ ) {
-
- object = objects[ i ];
-
- this.objects.push( object );
-
- object.node = this;
-
- }
-
- },
-
- removeObject: function ( object ) {
-
- var i, l,
- nodesRemovedFrom,
- removeData;
-
- // cascade through tree to find and remove object
-
- removeData = this.removeObjectRecursive( object, { searchComplete: false, nodesRemovedFrom: [], objectsDataRemoved: [] } );
-
- // if object removed, try to shrink the nodes it was removed from
-
- nodesRemovedFrom = removeData.nodesRemovedFrom;
-
- if ( nodesRemovedFrom.length > 0 ) {
-
- for ( i = 0, l = nodesRemovedFrom.length; i < l; i ++ ) {
-
- nodesRemovedFrom[ i ].shrink();
-
- }
-
- }
-
- return removeData.objectsDataRemoved;
-
- },
-
- removeObjectRecursive: function ( object, removeData ) {
-
- var i, l,
- index = - 1,
- objectData,
- node,
- objectRemoved;
-
- // find index of object in objects list
-
- // search and remove object data (fast)
- if ( object instanceof THREE.OctreeObjectData ) {
-
- // remove from this objects list
-
- index = indexOfValue( this.objects, object );
-
- if ( index !== - 1 ) {
-
- this.objects.splice( index, 1 );
- object.node = undefined;
-
- removeData.objectsDataRemoved.push( object );
-
- removeData.searchComplete = objectRemoved = true;
-
- }
-
- } else {
-
- // search each object data for object and remove (slow)
-
- for ( i = this.objects.length - 1; i >= 0; i -- ) {
-
- objectData = this.objects[ i ];
-
- if ( objectData.object === object ) {
-
- this.objects.splice( i, 1 );
- objectData.node = undefined;
-
- removeData.objectsDataRemoved.push( objectData );
-
- objectRemoved = true;
-
- if ( ! objectData.faces && ! objectData.vertices ) {
-
- removeData.searchComplete = true;
- break;
-
- }
-
- }
-
- }
-
- }
-
- // if object data removed and this is not on nodes removed from
-
- if ( objectRemoved === true ) {
-
- removeData.nodesRemovedFrom.push( this );
-
- }
-
- // if search not complete, search nodes
-
- if ( removeData.searchComplete !== true ) {
-
- for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
- node = this.nodesByIndex[ this.nodesIndices[ i ] ];
-
- // try removing object from node
-
- removeData = node.removeObjectRecursive( object, removeData );
-
- if ( removeData.searchComplete === true ) {
-
- break;
-
- }
-
- }
-
- }
-
- return removeData;
-
- },
-
- checkGrow: function () {
-
- // if object count above max
-
- if ( this.objects.length > this.tree.objectsThreshold && this.tree.objectsThreshold > 0 ) {
-
- this.grow();
-
- }
-
- },
-
- grow: function () {
-
- var indexOctant,
- object,
- objectsExpand = [],
- objectsExpandOctants = [],
- objectsSplit = [],
- objectsSplitOctants = [],
- objectsRemaining = [],
- i, l;
-
- // for each object
-
- for ( i = 0, l = this.objects.length; i < l; i ++ ) {
-
- object = this.objects[ i ];
-
- // get object octant index
-
- indexOctant = this.getOctantIndex( object );
-
- // if lies within octant
- if ( indexOctant > - 1 ) {
-
- objectsSplit.push( object );
- objectsSplitOctants.push( indexOctant );
-
- } else if ( indexOctant < - 1 ) {
-
- // lies outside radius
-
- objectsExpand.push( object );
- objectsExpandOctants.push( indexOctant );
-
- } else {
-
- // lies across bounds between octants
-
- objectsRemaining.push( object );
-
- }
-
- }
-
- // if has objects to split
-
- if ( objectsSplit.length > 0 ) {
-
- objectsRemaining = objectsRemaining.concat( this.split( objectsSplit, objectsSplitOctants ) );
-
- }
-
- // if has objects to expand
-
- if ( objectsExpand.length > 0 ) {
-
- objectsRemaining = objectsRemaining.concat( this.expand( objectsExpand, objectsExpandOctants ) );
-
- }
-
- // store remaining
-
- this.objects = objectsRemaining;
-
- // merge check
-
- this.checkMerge();
-
- },
-
- split: function ( objects, octants ) {
-
- var i, l,
- indexOctant,
- object,
- node,
- objectsRemaining;
-
- // if not at max depth
-
- if ( this.depth < this.tree.depthMax ) {
-
- objects = objects || this.objects;
-
- octants = octants || [];
-
- objectsRemaining = [];
-
- // for each object
-
- for ( i = 0, l = objects.length; i < l; i ++ ) {
-
- object = objects[ i ];
-
- // get object octant index
-
- indexOctant = octants[ i ];
-
- // if object contained by octant, branch this tree
-
- if ( indexOctant > - 1 ) {
-
- node = this.branch( indexOctant );
-
- node.addObject( object );
-
- } else {
-
- objectsRemaining.push( object );
-
- }
-
- }
-
- // if all objects, set remaining as new objects
-
- if ( objects === this.objects ) {
-
- this.objects = objectsRemaining;
-
- }
-
- } else {
-
- objectsRemaining = this.objects;
-
- }
-
- return objectsRemaining;
-
- },
-
- branch: function ( indexOctant ) {
-
- var node,
- overlap,
- radius,
- radiusOffset,
- offset,
- position;
-
- // node exists
-
- if ( this.nodesByIndex[ indexOctant ] instanceof THREE.OctreeNode ) {
-
- node = this.nodesByIndex[ indexOctant ];
-
- } else {
-
- // properties
-
- radius = ( this.radiusOverlap ) * 0.5;
- overlap = radius * this.tree.overlapPct;
- radiusOffset = radius - overlap;
- offset = this.utilVec31Branch.set( indexOctant & 1 ? radiusOffset : - radiusOffset, indexOctant & 2 ? radiusOffset : - radiusOffset, indexOctant & 4 ? radiusOffset : - radiusOffset );
- position = new THREE.Vector3().addVectors( this.position, offset );
-
- // node
-
- node = new THREE.OctreeNode( {
- tree: this.tree,
- parent: this,
- position: position,
- radius: radius,
- indexOctant: indexOctant
- } );
-
- // store
-
- this.addNode( node, indexOctant );
-
- }
-
- return node;
-
- },
-
- expand: function ( objects, octants ) {
-
- var i, l,
- object,
- objectsRemaining,
- objectsExpand,
- indexOctant,
- flagsOutside,
- indexOutside,
- indexOctantInverse,
- iom = this.tree.INDEX_OUTSIDE_MAP,
- indexOutsideCounts,
- infoIndexOutside1,
- infoIndexOutside2,
- infoIndexOutside3,
- indexOutsideBitwise1,
- indexOutsideBitwise2,
- infoPotential1,
- infoPotential2,
- infoPotential3,
- indexPotentialBitwise1,
- indexPotentialBitwise2,
- octantX, octantY, octantZ,
- overlap,
- radius,
- radiusOffset,
- radiusParent,
- overlapParent,
- offset = this.utilVec31Expand,
- position,
- parent;
-
- // handle max depth down tree
-
- if ( this.tree.root.getDepthEnd() < this.tree.depthMax ) {
-
- objects = objects || this.objects;
- octants = octants || [];
-
- objectsRemaining = [];
- objectsExpand = [];
-
- // reset counts
-
- for ( i = 0, l = iom.length; i < l; i ++ ) {
-
- iom[ i ].count = 0;
-
- }
-
- // for all outside objects, find outside octants containing most objects
-
- for ( i = 0, l = objects.length; i < l; i ++ ) {
-
- object = objects[ i ];
-
- // get object octant index
-
- indexOctant = octants[ i ] ;
-
- // if object outside this, include in calculations
-
- if ( indexOctant < - 1 ) {
-
- // convert octant index to outside flags
-
- flagsOutside = - indexOctant - this.tree.INDEX_OUTSIDE_OFFSET;
-
- // check against bitwise flags
-
- // x
-
- if ( flagsOutside & this.tree.FLAG_POS_X ) {
-
- iom[ this.tree.INDEX_OUTSIDE_POS_X ].count ++;
-
- } else if ( flagsOutside & this.tree.FLAG_NEG_X ) {
-
- iom[ this.tree.INDEX_OUTSIDE_NEG_X ].count ++;
-
- }
-
- // y
-
- if ( flagsOutside & this.tree.FLAG_POS_Y ) {
-
- iom[ this.tree.INDEX_OUTSIDE_POS_Y ].count ++;
-
- } else if ( flagsOutside & this.tree.FLAG_NEG_Y ) {
-
- iom[ this.tree.INDEX_OUTSIDE_NEG_Y ].count ++;
-
- }
-
- // z
-
- if ( flagsOutside & this.tree.FLAG_POS_Z ) {
-
- iom[ this.tree.INDEX_OUTSIDE_POS_Z ].count ++;
-
- } else if ( flagsOutside & this.tree.FLAG_NEG_Z ) {
-
- iom[ this.tree.INDEX_OUTSIDE_NEG_Z ].count ++;
-
- }
-
- // store in expand list
-
- objectsExpand.push( object );
-
- } else {
-
- objectsRemaining.push( object );
-
- }
-
- }
-
- // if objects to expand
-
- if ( objectsExpand.length > 0 ) {
-
- // shallow copy index outside map
-
- indexOutsideCounts = iom.slice( 0 );
-
- // sort outside index count so highest is first
-
- indexOutsideCounts.sort( function ( a, b ) {
-
- return b.count - a.count;
-
- } );
-
- // get highest outside indices
-
- // first is first
- infoIndexOutside1 = indexOutsideCounts[ 0 ];
- indexOutsideBitwise1 = infoIndexOutside1.index | 1;
-
- // second is ( one of next two bitwise OR 1 ) that is not opposite of ( first bitwise OR 1 )
-
- infoPotential1 = indexOutsideCounts[ 1 ];
- infoPotential2 = indexOutsideCounts[ 2 ];
-
- infoIndexOutside2 = ( infoPotential1.index | 1 ) !== indexOutsideBitwise1 ? infoPotential1 : infoPotential2;
- indexOutsideBitwise2 = infoIndexOutside2.index | 1;
-
- // third is ( one of next three bitwise OR 1 ) that is not opposite of ( first or second bitwise OR 1 )
-
- infoPotential1 = indexOutsideCounts[ 2 ];
- infoPotential2 = indexOutsideCounts[ 3 ];
- infoPotential3 = indexOutsideCounts[ 4 ];
-
- indexPotentialBitwise1 = infoPotential1.index | 1;
- indexPotentialBitwise2 = infoPotential2.index | 1;
-
- infoIndexOutside3 = indexPotentialBitwise1 !== indexOutsideBitwise1 && indexPotentialBitwise1 !== indexOutsideBitwise2 ? infoPotential1 : indexPotentialBitwise2 !== indexOutsideBitwise1 && indexPotentialBitwise2 !== indexOutsideBitwise2 ? infoPotential2 : infoPotential3;
-
- // get this octant normal based on outside octant indices
-
- octantX = infoIndexOutside1.x + infoIndexOutside2.x + infoIndexOutside3.x;
- octantY = infoIndexOutside1.y + infoIndexOutside2.y + infoIndexOutside3.y;
- octantZ = infoIndexOutside1.z + infoIndexOutside2.z + infoIndexOutside3.z;
-
- // get this octant indices based on octant normal
-
- indexOctant = this.getOctantIndexFromPosition( octantX, octantY, octantZ );
- indexOctantInverse = this.getOctantIndexFromPosition( - octantX, - octantY, - octantZ );
-
- // properties
-
- overlap = this.overlap;
- radius = this.radius;
-
- // radius of parent comes from reversing overlap of this, unless overlap percent is 0
-
- radiusParent = this.tree.overlapPct > 0 ? overlap / ( ( 0.5 * this.tree.overlapPct ) * ( 1 + this.tree.overlapPct ) ) : radius * 2;
- overlapParent = radiusParent * this.tree.overlapPct;
-
- // parent offset is difference between radius + overlap of parent and child
-
- radiusOffset = ( radiusParent + overlapParent ) - ( radius + overlap );
- offset.set( indexOctant & 1 ? radiusOffset : - radiusOffset, indexOctant & 2 ? radiusOffset : - radiusOffset, indexOctant & 4 ? radiusOffset : - radiusOffset );
- position = new THREE.Vector3().addVectors( this.position, offset );
-
- // parent
-
- parent = new THREE.OctreeNode( {
- tree: this.tree,
- position: position,
- radius: radiusParent
- } );
-
- // set self as node of parent
-
- parent.addNode( this, indexOctantInverse );
-
- // set parent as root
-
- this.tree.setRoot( parent );
-
- // add all expand objects to parent
-
- for ( i = 0, l = objectsExpand.length; i < l; i ++ ) {
-
- this.tree.root.addObject( objectsExpand[ i ] );
-
- }
-
- }
-
- // if all objects, set remaining as new objects
-
- if ( objects === this.objects ) {
-
- this.objects = objectsRemaining;
-
- }
-
- } else {
-
- objectsRemaining = objects;
-
- }
-
- return objectsRemaining;
-
- },
-
- shrink: function () {
-
- // merge check
-
- this.checkMerge();
-
- // contract check
-
- this.tree.root.checkContract();
-
- },
-
- checkMerge: function () {
-
- var nodeParent = this,
- nodeMerge;
-
- // traverse up tree as long as node + entire subtree's object count is under minimum
-
- while ( nodeParent.parent instanceof THREE.OctreeNode && nodeParent.getObjectCountEnd() < this.tree.objectsThreshold ) {
-
- nodeMerge = nodeParent;
- nodeParent = nodeParent.parent;
-
- }
-
- // if parent node is not this, merge entire subtree into merge node
-
- if ( nodeParent !== this ) {
-
- nodeParent.merge( nodeMerge );
-
- }
-
- },
-
- merge: function ( nodes ) {
-
- var i, l,
- j, k,
- node;
-
- // handle nodes
-
- nodes = toArray( nodes );
-
- for ( i = 0, l = nodes.length; i < l; i ++ ) {
-
- node = nodes[ i ];
-
- // gather node + all subtree objects
-
- this.addObjectWithoutCheck( node.getObjectsEnd() );
-
- // reset node + entire subtree
-
- node.reset( true, true );
-
- // remove node
-
- this.removeNode( node.indexOctant, node );
-
- }
-
- // merge check
-
- this.checkMerge();
-
- },
-
- checkContract: function () {
-
- var i, l,
- node,
- nodeObjectsCount,
- nodeHeaviest,
- nodeHeaviestObjectsCount,
- outsideHeaviestObjectsCount;
-
- // find node with highest object count
-
- if ( this.nodesIndices.length > 0 ) {
-
- nodeHeaviestObjectsCount = 0;
- outsideHeaviestObjectsCount = this.objects.length;
-
- for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
- node = this.nodesByIndex[ this.nodesIndices[ i ] ];
-
- nodeObjectsCount = node.getObjectCountEnd();
- outsideHeaviestObjectsCount += nodeObjectsCount;
-
- if ( nodeHeaviest instanceof THREE.OctreeNode === false || nodeObjectsCount > nodeHeaviestObjectsCount ) {
-
- nodeHeaviest = node;
- nodeHeaviestObjectsCount = nodeObjectsCount;
-
- }
-
- }
-
- // subtract heaviest count from outside count
-
- outsideHeaviestObjectsCount -= nodeHeaviestObjectsCount;
-
- // if should contract
-
- if ( outsideHeaviestObjectsCount < this.tree.objectsThreshold && nodeHeaviest instanceof THREE.OctreeNode ) {
-
- this.contract( nodeHeaviest );
-
- }
-
- }
-
- },
-
- contract: function ( nodeRoot ) {
-
- var i, l,
- node;
-
- // handle all nodes
-
- for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
- node = this.nodesByIndex[ this.nodesIndices[ i ] ];
-
- // if node is not new root
-
- if ( node !== nodeRoot ) {
-
- // add node + all subtree objects to root
-
- nodeRoot.addObjectWithoutCheck( node.getObjectsEnd() );
-
- // reset node + entire subtree
-
- node.reset( true, true );
-
- }
-
- }
-
- // add own objects to root
-
- nodeRoot.addObjectWithoutCheck( this.objects );
-
- // reset self
-
- this.reset( false, true );
-
- // set new root
-
- this.tree.setRoot( nodeRoot );
-
- // contract check on new root
-
- nodeRoot.checkContract();
-
- },
-
- getOctantIndex: function ( objectData ) {
-
- var i, l,
- positionObj,
- radiusObj,
- position = this.position,
- radiusOverlap = this.radiusOverlap,
- overlap = this.overlap,
- deltaX, deltaY, deltaZ,
- distX, distY, distZ,
- distance,
- indexOctant = 0;
-
- // handle type
-
- if ( objectData instanceof THREE.OctreeObjectData ) {
-
- radiusObj = objectData.radius;
-
- positionObj = objectData.position;
-
- // update object data position last
-
- objectData.positionLast.copy( positionObj );
-
- } else if ( objectData instanceof THREE.OctreeNode ) {
-
- positionObj = objectData.position;
-
- radiusObj = 0;
-
- }
-
- // find delta and distance
-
- deltaX = positionObj.x - position.x;
- deltaY = positionObj.y - position.y;
- deltaZ = positionObj.z - position.z;
-
- distX = Math.abs( deltaX );
- distY = Math.abs( deltaY );
- distZ = Math.abs( deltaZ );
- distance = Math.max( distX, distY, distZ );
-
- // if outside, use bitwise flags to indicate on which sides object is outside of
-
- if ( distance + radiusObj > radiusOverlap ) {
-
- // x
-
- if ( distX + radiusObj > radiusOverlap ) {
-
- indexOctant = indexOctant ^ ( deltaX > 0 ? this.tree.FLAG_POS_X : this.tree.FLAG_NEG_X );
-
- }
-
- // y
-
- if ( distY + radiusObj > radiusOverlap ) {
-
- indexOctant = indexOctant ^ ( deltaY > 0 ? this.tree.FLAG_POS_Y : this.tree.FLAG_NEG_Y );
-
- }
-
- // z
-
- if ( distZ + radiusObj > radiusOverlap ) {
-
- indexOctant = indexOctant ^ ( deltaZ > 0 ? this.tree.FLAG_POS_Z : this.tree.FLAG_NEG_Z );
-
- }
-
- objectData.indexOctant = - indexOctant - this.tree.INDEX_OUTSIDE_OFFSET;
-
- return objectData.indexOctant;
-
- }
-
- // return octant index from delta xyz
-
- if ( deltaX - radiusObj > - overlap ) {
-
- // x right
-
- indexOctant = indexOctant | 1;
-
- } else if ( ! ( deltaX + radiusObj < overlap ) ) {
-
- // x left
-
- objectData.indexOctant = this.tree.INDEX_INSIDE_CROSS;
- return objectData.indexOctant;
-
- }
-
- if ( deltaY - radiusObj > - overlap ) {
-
- // y right
-
- indexOctant = indexOctant | 2;
-
- } else if ( ! ( deltaY + radiusObj < overlap ) ) {
-
- // y left
-
- objectData.indexOctant = this.tree.INDEX_INSIDE_CROSS;
- return objectData.indexOctant;
-
- }
-
-
- if ( deltaZ - radiusObj > - overlap ) {
-
- // z right
-
- indexOctant = indexOctant | 4;
-
- } else if ( ! ( deltaZ + radiusObj < overlap ) ) {
-
- // z left
-
- objectData.indexOctant = this.tree.INDEX_INSIDE_CROSS;
- return objectData.indexOctant;
-
- }
-
- objectData.indexOctant = indexOctant;
- return objectData.indexOctant;
-
- },
-
- getOctantIndexFromPosition: function ( x, y, z ) {
-
- var indexOctant = 0;
-
- if ( x > 0 ) {
-
- indexOctant = indexOctant | 1;
-
- }
-
- if ( y > 0 ) {
-
- indexOctant = indexOctant | 2;
-
- }
-
- if ( z > 0 ) {
-
- indexOctant = indexOctant | 4;
-
- }
-
- return indexOctant;
-
- },
-
- search: function ( position, radius, objects, direction, directionPct ) {
-
- var i, l,
- node,
- intersects;
-
- // test intersects by parameters
-
- if ( direction ) {
-
- intersects = this.intersectRay( position, direction, radius, directionPct );
-
- } else {
-
- intersects = this.intersectSphere( position, radius );
-
- }
-
- // if intersects
-
- if ( intersects === true ) {
-
- // gather objects
-
- objects = objects.concat( this.objects );
-
- // search subtree
-
- for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
- node = this.nodesByIndex[ this.nodesIndices[ i ] ];
-
- objects = node.search( position, radius, objects, direction );
-
- }
-
- }
-
- return objects;
-
- },
-
- intersectSphere: function ( position, radius ) {
-
- var distance = radius * radius,
- px = position.x,
- py = position.y,
- pz = position.z;
-
- if ( px < this.left ) {
- distance -= Math.pow( px - this.left, 2 );
- } else if ( px > this.right ) {
- distance -= Math.pow( px - this.right, 2 );
- }
-
- if ( py < this.bottom ) {
- distance -= Math.pow( py - this.bottom, 2 );
- } else if ( py > this.top ) {
- distance -= Math.pow( py - this.top, 2 );
- }
-
- if ( pz < this.back ) {
- distance -= Math.pow( pz - this.back, 2 );
- } else if ( pz > this.front ) {
- distance -= Math.pow( pz - this.front, 2 );
- }
-
- return distance >= 0;
-
- },
-
- intersectRay: function ( origin, direction, distance, directionPct ) {
-
- if ( typeof directionPct === 'undefined' ) {
-
- directionPct = this.utilVec31Ray.set( 1, 1, 1 ).divide( direction );
-
- }
-
- var t1 = ( this.left - origin.x ) * directionPct.x,
- t2 = ( this.right - origin.x ) * directionPct.x,
- t3 = ( this.bottom - origin.y ) * directionPct.y,
- t4 = ( this.top - origin.y ) * directionPct.y,
- t5 = ( this.back - origin.z ) * directionPct.z,
- t6 = ( this.front - origin.z ) * directionPct.z,
- tmax = Math.min( Math.min( Math.max( t1, t2 ), Math.max( t3, t4 ) ), Math.max( t5, t6 ) ),
- tmin;
- // ray would intersect in reverse direction, i.e. this is behind ray
- if ( tmax < 0 ) {
- return false;
- }
-
- tmin = Math.max( Math.max( Math.min( t1, t2 ), Math.min( t3, t4 ) ), Math.min( t5, t6 ) );
-
- // if tmin > tmax or tmin > ray distance, ray doesn't intersect AABB
- if ( tmin > tmax || tmin > distance ) {
- return false;
- }
-
- return true;
-
- },
-
- getDepthEnd: function ( depth ) {
-
- var i, l,
- node;
- if ( this.nodesIndices.length > 0 ) {
-
- for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
- node = this.nodesByIndex[ this.nodesIndices[ i ] ];
- depth = node.getDepthEnd( depth );
- }
-
- } else {
- depth = ! depth || this.depth > depth ? this.depth : depth;
- }
- return depth;
-
- },
-
- getNodeCountEnd: function () {
-
- return this.tree.root.getNodeCountRecursive() + 1;
-
- },
-
- getNodeCountRecursive: function () {
-
- var i, l,
- count = this.nodesIndices.length;
-
- for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
- count += this.nodesByIndex[ this.nodesIndices[ i ] ].getNodeCountRecursive();
-
- }
-
- return count;
-
- },
-
- getObjectsEnd: function ( objects ) {
-
- var i, l,
- node;
-
- objects = ( objects || [] ).concat( this.objects );
-
- for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
- node = this.nodesByIndex[ this.nodesIndices[ i ] ];
-
- objects = node.getObjectsEnd( objects );
-
- }
-
- return objects;
-
- },
-
- getObjectCountEnd: function () {
-
- var i, l,
- count = this.objects.length;
-
- for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
- count += this.nodesByIndex[ this.nodesIndices[ i ] ].getObjectCountEnd();
-
- }
-
- return count;
-
- },
-
- getObjectCountStart: function () {
-
- var count = this.objects.length,
- parent = this.parent;
-
- while ( parent instanceof THREE.OctreeNode ) {
-
- count += parent.objects.length;
- parent = parent.parent;
-
- }
-
- return count;
-
- },
-
- toConsole: function ( space ) {
-
- var i, l,
- node,
- spaceAddition = ' ';
-
- space = typeof space === 'string' ? space : spaceAddition;
-
- console.log( ( this.parent ? space + ' octree NODE > ' : ' octree ROOT > ' ), this, ' // id: ', this.id, ' // indexOctant: ', this.indexOctant, ' // position: ', this.position.x, this.position.y, this.position.z, ' // radius: ', this.radius, ' // depth: ', this.depth );
- console.log( ( this.parent ? space + ' ' : ' ' ), '+ objects ( ', this.objects.length, ' ) ', this.objects );
- console.log( ( this.parent ? space + ' ' : ' ' ), '+ children ( ', this.nodesIndices.length, ' )', this.nodesIndices, this.nodesByIndex );
-
- for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
- node = this.nodesByIndex[ this.nodesIndices[ i ] ];
-
- node.toConsole( space + spaceAddition );
-
- }
-
- }
-
- };
- /*===================================================
- raycaster additional functionality
- =====================================================*/
-
- THREE.Raycaster.prototype.intersectOctreeObject = function ( object, recursive ) {
-
- var intersects,
- octreeObject,
- facesAll,
- facesSearch;
-
- if ( object.object instanceof THREE.Object3D ) {
-
- octreeObject = object;
- object = octreeObject.object;
-
- // temporarily replace object geometry's faces with octree object faces
-
- facesSearch = octreeObject.faces;
- facesAll = object.geometry.faces;
-
- if ( facesSearch.length > 0 ) {
-
- object.geometry.faces = facesSearch;
-
- }
-
- // intersect
-
- intersects = this.intersectObject( object, recursive );
-
- // revert object geometry's faces
-
- if ( facesSearch.length > 0 ) {
-
- object.geometry.faces = facesAll;
-
- }
-
- } else {
-
- intersects = this.intersectObject( object, recursive );
-
- }
-
- return intersects;
-
- };
-
- THREE.Raycaster.prototype.intersectOctreeObjects = function ( objects, recursive ) {
-
- var i, il,
- intersects = [];
-
- for ( i = 0, il = objects.length; i < il; i ++ ) {
-
- intersects = intersects.concat( this.intersectOctreeObject( objects[ i ], recursive ) );
-
- }
-
- return intersects;
-
- };
- }( THREE ) );
|