12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138 |
- /*!
- *
- * 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 ) {
- var helper = new THREE.BoxHelper( new THREE.Mesh( new THREE.BoxBufferGeometry( 1, 1, 1 ) ), 0xff0066 );
- this.visualGeometry = helper.geometry;
- this.visualMaterial = helper.material;
- }
- // 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.LineSegments( 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 ) );
|