Octree.js 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139
  1. /*!
  2. *
  3. * threeoctree.js (r60) / https://github.com/collinhover/threeoctree
  4. * (sparse) dynamic 3D spatial representation structure for fast searches.
  5. *
  6. * @author Collin Hover / http://collinhover.com/
  7. * based on Dynamic Octree by Piko3D @ http://www.piko3d.com/ and Octree by Marek Pawlowski @ pawlowski.it
  8. *
  9. */
  10. ( function ( THREE ) { "use strict";
  11. /*===================================================
  12. utility
  13. =====================================================*/
  14. function isNumber ( n ) {
  15. return !isNaN( n ) && isFinite( n );
  16. }
  17. function isArray ( target ) {
  18. return Object.prototype.toString.call( target ) === '[object Array]';
  19. }
  20. function toArray ( target ) {
  21. return target ? ( isArray ( target ) !== true ? [ target ] : target ) : [];
  22. }
  23. function indexOfValue( array, value ) {
  24. for ( var i = 0, il = array.length; i < il; i++ ) {
  25. if ( array[ i ] === value ) {
  26. return i;
  27. }
  28. }
  29. return -1;
  30. }
  31. function indexOfPropertyWithValue( array, property, value ) {
  32. for ( var i = 0, il = array.length; i < il; i++ ) {
  33. if ( array[ i ][ property ] === value ) {
  34. return i;
  35. }
  36. }
  37. return -1;
  38. }
  39. /*===================================================
  40. octree
  41. =====================================================*/
  42. THREE.Octree = function ( parameters ) {
  43. // handle parameters
  44. parameters = parameters || {};
  45. parameters.tree = this;
  46. // static properties ( modification is not recommended )
  47. this.nodeCount = 0;
  48. this.INDEX_INSIDE_CROSS = -1;
  49. this.INDEX_OUTSIDE_OFFSET = 2;
  50. this.INDEX_OUTSIDE_POS_X = isNumber( parameters.INDEX_OUTSIDE_POS_X ) ? parameters.INDEX_OUTSIDE_POS_X : 0;
  51. this.INDEX_OUTSIDE_NEG_X = isNumber( parameters.INDEX_OUTSIDE_NEG_X ) ? parameters.INDEX_OUTSIDE_NEG_X : 1;
  52. this.INDEX_OUTSIDE_POS_Y = isNumber( parameters.INDEX_OUTSIDE_POS_Y ) ? parameters.INDEX_OUTSIDE_POS_Y : 2;
  53. this.INDEX_OUTSIDE_NEG_Y = isNumber( parameters.INDEX_OUTSIDE_NEG_Y ) ? parameters.INDEX_OUTSIDE_NEG_Y : 3;
  54. this.INDEX_OUTSIDE_POS_Z = isNumber( parameters.INDEX_OUTSIDE_POS_Z ) ? parameters.INDEX_OUTSIDE_POS_Z : 4;
  55. this.INDEX_OUTSIDE_NEG_Z = isNumber( parameters.INDEX_OUTSIDE_NEG_Z ) ? parameters.INDEX_OUTSIDE_NEG_Z : 5;
  56. this.INDEX_OUTSIDE_MAP = [];
  57. this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_POS_X ] = { index: this.INDEX_OUTSIDE_POS_X, count: 0, x: 1, y: 0, z: 0 };
  58. this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_NEG_X ] = { index: this.INDEX_OUTSIDE_NEG_X, count: 0, x: -1, y: 0, z: 0 };
  59. this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_POS_Y ] = { index: this.INDEX_OUTSIDE_POS_Y, count: 0, x: 0, y: 1, z: 0 };
  60. this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_NEG_Y ] = { index: this.INDEX_OUTSIDE_NEG_Y, count: 0, x: 0, y: -1, z: 0 };
  61. this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_POS_Z ] = { index: this.INDEX_OUTSIDE_POS_Z, count: 0, x: 0, y: 0, z: 1 };
  62. this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_NEG_Z ] = { index: this.INDEX_OUTSIDE_NEG_Z, count: 0, x: 0, y: 0, z: -1 };
  63. this.FLAG_POS_X = 1 << ( this.INDEX_OUTSIDE_POS_X + 1 );
  64. this.FLAG_NEG_X = 1 << ( this.INDEX_OUTSIDE_NEG_X + 1 );
  65. this.FLAG_POS_Y = 1 << ( this.INDEX_OUTSIDE_POS_Y + 1 );
  66. this.FLAG_NEG_Y = 1 << ( this.INDEX_OUTSIDE_NEG_Y + 1 );
  67. this.FLAG_POS_Z = 1 << ( this.INDEX_OUTSIDE_POS_Z + 1 );
  68. this.FLAG_NEG_Z = 1 << ( this.INDEX_OUTSIDE_NEG_Z + 1 );
  69. this.utilVec31Search = new THREE.Vector3();
  70. this.utilVec32Search = new THREE.Vector3();
  71. // pass scene to see octree structure
  72. this.scene = parameters.scene;
  73. if ( this.scene ) {
  74. this.visualGeometry = new THREE.CubeGeometry( 1, 1, 1 );
  75. this.visualMaterial = new THREE.MeshBasicMaterial( { color: 0xFF0066, wireframe: true, wireframeLinewidth: 1 } );
  76. }
  77. // properties
  78. this.objects = [];
  79. this.objectsMap = {};
  80. this.objectsData = [];
  81. this.objectsDeferred = [];
  82. this.depthMax = isNumber( parameters.depthMax ) ? parameters.depthMax : Infinity;
  83. this.objectsThreshold = isNumber( parameters.objectsThreshold ) ? parameters.objectsThreshold : 8;
  84. this.overlapPct = isNumber( parameters.overlapPct ) ? parameters.overlapPct : 0.15;
  85. this.undeferred = parameters.undeferred || false;
  86. this.root = parameters.root instanceof THREE.OctreeNode ? parameters.root : new THREE.OctreeNode( parameters );
  87. };
  88. THREE.Octree.prototype = {
  89. update: function () {
  90. // add any deferred objects that were waiting for render cycle
  91. if ( this.objectsDeferred.length > 0 ) {
  92. for ( var i = 0, il = this.objectsDeferred.length; i < il; i++ ) {
  93. var deferred = this.objectsDeferred[ i ];
  94. this.addDeferred( deferred.object, deferred.options );
  95. }
  96. this.objectsDeferred.length = 0;
  97. }
  98. },
  99. add: function ( object, options ) {
  100. // add immediately
  101. if ( this.undeferred ) {
  102. this.updateObject( object );
  103. this.addDeferred( object, options );
  104. } else {
  105. // defer add until update called
  106. this.objectsDeferred.push( { object: object, options: options } );
  107. }
  108. },
  109. addDeferred: function ( object, options ) {
  110. var i, l,
  111. geometry,
  112. faces,
  113. useFaces,
  114. vertices,
  115. useVertices,
  116. objectData;
  117. // ensure object is not object data
  118. if ( object instanceof THREE.OctreeObjectData ) {
  119. object = object.object;
  120. }
  121. // check uuid to avoid duplicates
  122. if ( !object.uuid ) {
  123. object.uuid = THREE.Math.generateUUID();
  124. }
  125. if ( !this.objectsMap[ object.uuid ] ) {
  126. // store
  127. this.objects.push( object );
  128. this.objectsMap[ object.uuid ] = object;
  129. // check options
  130. if ( options ) {
  131. useFaces = options.useFaces;
  132. useVertices = options.useVertices;
  133. }
  134. if ( useVertices === true ) {
  135. geometry = object.geometry;
  136. vertices = geometry.vertices;
  137. for ( i = 0, l = vertices.length; i < l; i++ ) {
  138. this.addObjectData( object, vertices[ i ] );
  139. }
  140. } else if ( useFaces === true ) {
  141. geometry = object.geometry;
  142. faces = geometry.faces;
  143. for ( i = 0, l = faces.length; i < l; i++ ) {
  144. this.addObjectData( object, faces[ i ] );
  145. }
  146. } else {
  147. this.addObjectData( object );
  148. }
  149. }
  150. },
  151. addObjectData: function ( object, part ) {
  152. var objectData = new THREE.OctreeObjectData( object, part );
  153. // add to tree objects data list
  154. this.objectsData.push( objectData );
  155. // add to nodes
  156. this.root.addObject( objectData );
  157. },
  158. remove: function ( object ) {
  159. var i, l,
  160. objectData = object,
  161. index,
  162. objectsDataRemoved;
  163. // ensure object is not object data for index search
  164. if ( object instanceof THREE.OctreeObjectData ) {
  165. object = object.object;
  166. }
  167. // check uuid
  168. if ( this.objectsMap[ object.uuid ] ) {
  169. this.objectsMap[ object.uuid ] = undefined;
  170. // check and remove from objects, nodes, and data lists
  171. index = indexOfValue( this.objects, object );
  172. if ( index !== -1 ) {
  173. this.objects.splice( index, 1 );
  174. // remove from nodes
  175. objectsDataRemoved = this.root.removeObject( objectData );
  176. // remove from objects data list
  177. for ( i = 0, l = objectsDataRemoved.length; i < l; i++ ) {
  178. objectData = objectsDataRemoved[ i ];
  179. index = indexOfValue( this.objectsData, objectData );
  180. if ( index !== -1 ) {
  181. this.objectsData.splice( index, 1 );
  182. }
  183. }
  184. }
  185. } else if ( this.objectsDeferred.length > 0 ) {
  186. // check and remove from deferred
  187. index = indexOfPropertyWithValue( this.objectsDeferred, 'object', object );
  188. if ( index !== -1 ) {
  189. this.objectsDeferred.splice( index, 1 );
  190. }
  191. }
  192. },
  193. extend: function ( octree ) {
  194. var i, l,
  195. objectsData,
  196. objectData;
  197. if ( octree instanceof THREE.Octree ) {
  198. // for each object data
  199. objectsData = octree.objectsData;
  200. for ( i = 0, l = objectsData.length; i < l; i++ ) {
  201. objectData = objectsData[ i ];
  202. this.add( objectData, { useFaces: objectData.faces, useVertices: objectData.vertices } );
  203. }
  204. }
  205. },
  206. rebuild: function () {
  207. var i, l,
  208. node,
  209. object,
  210. objectData,
  211. indexOctant,
  212. indexOctantLast,
  213. objectsUpdate = [];
  214. // check all object data for changes in position
  215. // assumes all object matrices are up to date
  216. for ( i = 0, l = this.objectsData.length; i < l; i++ ) {
  217. objectData = this.objectsData[ i ];
  218. node = objectData.node;
  219. // update object
  220. objectData.update();
  221. // if position has changed since last organization of object in tree
  222. if ( node instanceof THREE.OctreeNode && !objectData.positionLast.equals( objectData.position ) ) {
  223. // get octant index of object within current node
  224. indexOctantLast = objectData.indexOctant;
  225. indexOctant = node.getOctantIndex( objectData );
  226. // if object octant index has changed
  227. if ( indexOctant !== indexOctantLast ) {
  228. // add to update list
  229. objectsUpdate.push( objectData );
  230. }
  231. }
  232. }
  233. // update changed objects
  234. for ( i = 0, l = objectsUpdate.length; i < l; i++ ) {
  235. objectData = objectsUpdate[ i ];
  236. // remove object from current node
  237. objectData.node.removeObject( objectData );
  238. // add object to tree root
  239. this.root.addObject( objectData );
  240. }
  241. },
  242. updateObject: function ( object ) {
  243. var i, l,
  244. parentCascade = [ object ],
  245. parent,
  246. parentUpdate;
  247. // search all parents between object and root for world matrix update
  248. parent = object.parent;
  249. while( parent ) {
  250. parentCascade.push( parent );
  251. parent = parent.parent;
  252. }
  253. for ( i = 0, l = parentCascade.length; i < l; i++ ) {
  254. parent = parentCascade[ i ];
  255. if ( parent.matrixWorldNeedsUpdate === true ) {
  256. parentUpdate = parent;
  257. }
  258. }
  259. // update world matrix starting at uppermost parent that needs update
  260. if ( typeof parentUpdate !== 'undefined' ) {
  261. parentUpdate.updateMatrixWorld();
  262. }
  263. },
  264. search: function ( position, radius, organizeByObject, direction ) {
  265. var i, l,
  266. node,
  267. objects,
  268. objectData,
  269. object,
  270. results,
  271. resultData,
  272. resultsObjectsIndices,
  273. resultObjectIndex,
  274. directionPct;
  275. // add root objects
  276. objects = [].concat( this.root.objects );
  277. // ensure radius (i.e. distance of ray) is a number
  278. if ( !( radius > 0 ) ) {
  279. radius = Number.MAX_VALUE;
  280. }
  281. // if direction passed, normalize and find pct
  282. if ( direction instanceof THREE.Vector3 ) {
  283. direction = this.utilVec31Search.copy( direction ).normalize();
  284. directionPct = this.utilVec32Search.set( 1, 1, 1 ).divide( direction );
  285. }
  286. // search each node of root
  287. for ( i = 0, l = this.root.nodesIndices.length; i < l; i++ ) {
  288. node = this.root.nodesByIndex[ this.root.nodesIndices[ i ] ];
  289. objects = node.search( position, radius, objects, direction, directionPct );
  290. }
  291. // if should organize results by object
  292. if ( organizeByObject === true ) {
  293. results = [];
  294. resultsObjectsIndices = [];
  295. // for each object data found
  296. for ( i = 0, l = objects.length; i < l; i++ ) {
  297. objectData = objects[ i ];
  298. object = objectData.object;
  299. resultObjectIndex = indexOfValue( resultsObjectsIndices, object );
  300. // if needed, create new result data
  301. if ( resultObjectIndex === -1 ) {
  302. resultData = {
  303. object: object,
  304. faces: [],
  305. vertices: []
  306. };
  307. results.push( resultData );
  308. resultsObjectsIndices.push( object );
  309. } else {
  310. resultData = results[ resultObjectIndex ];
  311. }
  312. // object data has faces or vertices, add to list
  313. if ( objectData.faces ) {
  314. resultData.faces.push( objectData.faces );
  315. } else if ( objectData.vertices ) {
  316. resultData.vertices.push( objectData.vertices );
  317. }
  318. }
  319. } else {
  320. results = objects;
  321. }
  322. return results;
  323. },
  324. setRoot: function ( root ) {
  325. if ( root instanceof THREE.OctreeNode ) {
  326. // store new root
  327. this.root = root;
  328. // update properties
  329. this.root.updateProperties();
  330. }
  331. },
  332. getDepthEnd: function () {
  333. return this.root.getDepthEnd();
  334. },
  335. getNodeCountEnd: function () {
  336. return this.root.getNodeCountEnd();
  337. },
  338. getObjectCountEnd: function () {
  339. return this.root.getObjectCountEnd();
  340. },
  341. toConsole: function () {
  342. this.root.toConsole();
  343. }
  344. };
  345. /*===================================================
  346. object data
  347. =====================================================*/
  348. THREE.OctreeObjectData = function ( object, part ) {
  349. // properties
  350. this.object = object;
  351. // handle part by type
  352. if ( part instanceof THREE.Face3 ) {
  353. this.faces = part;
  354. this.face3 = true;
  355. this.utilVec31FaceBounds = new THREE.Vector3();
  356. } else if ( part instanceof THREE.Face4 ) {
  357. this.face4 = true;
  358. this.faces = part;
  359. this.utilVec31FaceBounds = new THREE.Vector3();
  360. } else if ( part instanceof THREE.Vector3 ) {
  361. this.vertices = part;
  362. }
  363. this.radius = 0;
  364. this.position = new THREE.Vector3();
  365. // initial update
  366. if ( this.object instanceof THREE.Object3D ) {
  367. this.update();
  368. }
  369. this.positionLast = this.position.clone();
  370. };
  371. THREE.OctreeObjectData.prototype = {
  372. update: function () {
  373. if ( this.face3 ) {
  374. this.radius = this.getFace3BoundingRadius( this.object, this.faces );
  375. this.position.copy( this.faces.centroid ).applyMatrix4( this.object.matrixWorld );
  376. } else if ( this.face4 ) {
  377. this.radius = this.getFace4BoundingRadius( this.object, this.faces );
  378. this.position.copy( this.faces.centroid ).applyMatrix4( this.object.matrixWorld );
  379. } else if ( this.vertices ) {
  380. this.radius = this.object.material.size || 1;
  381. this.position.copy( this.vertices ).applyMatrix4( this.object.matrixWorld );
  382. } else {
  383. if ( this.object.geometry ) {
  384. if ( this.object.geometry.boundingSphere === null ) {
  385. this.object.geometry.computeBoundingSphere();
  386. }
  387. this.radius = this.object.geometry.boundingSphere.radius;
  388. this.position.copy( this.object.geometry.boundingSphere.center ).applyMatrix4( this.object.matrixWorld );
  389. } else {
  390. this.radius = this.object.boundRadius;
  391. this.position.setFromMatrixPosition( this.object.matrixWorld );
  392. }
  393. }
  394. this.radius = this.radius * Math.max( this.object.scale.x, this.object.scale.y, this.object.scale.z );
  395. },
  396. getFace3BoundingRadius: function ( object, face ) {
  397. var geometry = object.geometry || object,
  398. vertices = geometry.vertices,
  399. centroid = face.centroid,
  400. va = vertices[ face.a ], vb = vertices[ face.b ], vc = vertices[ face.c ],
  401. centroidToVert = this.utilVec31FaceBounds,
  402. radius;
  403. centroid.addVectors( va, vb ).add( vc ).divideScalar( 3 );
  404. radius = Math.max( centroidToVert.subVectors( centroid, va ).length(), centroidToVert.subVectors( centroid, vb ).length(), centroidToVert.subVectors( centroid, vc ).length() );
  405. return radius;
  406. },
  407. getFace4BoundingRadius: function ( object, face ) {
  408. var geometry = object.geometry || object,
  409. vertices = geometry.vertices,
  410. centroid = face.centroid,
  411. va = vertices[ face.a ], vb = vertices[ face.b ], vc = vertices[ face.c ], vd = vertices[ face.d ],
  412. centroidToVert = this.utilVec31FaceBounds,
  413. radius;
  414. centroid.addVectors( va, vb ).add( vc ).add( vd ).divideScalar( 4 );
  415. radius = Math.max( centroidToVert.subVectors( centroid, va ).length(), centroidToVert.subVectors( centroid, vb ).length(), centroidToVert.subVectors( centroid, vc ).length(), centroidToVert.subVectors( centroid, vd ).length() );
  416. return radius;
  417. }
  418. };
  419. /*===================================================
  420. node
  421. =====================================================*/
  422. THREE.OctreeNode = function ( parameters ) {
  423. // utility
  424. this.utilVec31Branch = new THREE.Vector3();
  425. this.utilVec31Expand = new THREE.Vector3();
  426. this.utilVec31Ray = new THREE.Vector3();
  427. // handle parameters
  428. parameters = parameters || {};
  429. // store or create tree
  430. if ( parameters.tree instanceof THREE.Octree ) {
  431. this.tree = parameters.tree;
  432. } else if ( parameters.parent instanceof THREE.OctreeNode !== true ) {
  433. parameters.root = this;
  434. this.tree = new THREE.Octree( parameters );
  435. }
  436. // basic properties
  437. this.id = this.tree.nodeCount++;
  438. this.position = parameters.position instanceof THREE.Vector3 ? parameters.position : new THREE.Vector3();
  439. this.radius = parameters.radius > 0 ? parameters.radius : 1;
  440. this.indexOctant = parameters.indexOctant;
  441. this.depth = 0;
  442. // reset and assign parent
  443. this.reset();
  444. this.setParent( parameters.parent );
  445. // additional properties
  446. this.overlap = this.radius * this.tree.overlapPct;
  447. this.radiusOverlap = this.radius + this.overlap;
  448. this.left = this.position.x - this.radiusOverlap;
  449. this.right = this.position.x + this.radiusOverlap;
  450. this.bottom = this.position.y - this.radiusOverlap;
  451. this.top = this.position.y + this.radiusOverlap;
  452. this.back = this.position.z - this.radiusOverlap;
  453. this.front = this.position.z + this.radiusOverlap;
  454. // visual
  455. if ( this.tree.scene ) {
  456. this.visual = new THREE.Mesh( this.tree.visualGeometry, this.tree.visualMaterial );
  457. this.visual.scale.set( this.radiusOverlap * 2, this.radiusOverlap * 2, this.radiusOverlap * 2 );
  458. this.visual.position.copy( this.position );
  459. this.tree.scene.add( this.visual );
  460. }
  461. };
  462. THREE.OctreeNode.prototype = {
  463. setParent: function ( parent ) {
  464. // store new parent
  465. if ( parent !== this && this.parent !== parent ) {
  466. this.parent = parent;
  467. // update properties
  468. this.updateProperties();
  469. }
  470. },
  471. updateProperties: function () {
  472. var i, l;
  473. // properties
  474. if ( this.parent instanceof THREE.OctreeNode ) {
  475. this.tree = this.parent.tree;
  476. this.depth = this.parent.depth + 1;
  477. } else {
  478. this.depth = 0;
  479. }
  480. // cascade
  481. for ( i = 0, l = this.nodesIndices.length; i < l; i++ ) {
  482. this.nodesByIndex[ this.nodesIndices[ i ] ].updateProperties();
  483. }
  484. },
  485. reset: function ( cascade, removeVisual ) {
  486. var i, l,
  487. node,
  488. nodesIndices = this.nodesIndices || [],
  489. nodesByIndex = this.nodesByIndex;
  490. this.objects = [];
  491. this.nodesIndices = [];
  492. this.nodesByIndex = {};
  493. // unset parent in nodes
  494. for ( i = 0, l = nodesIndices.length; i < l; i++ ) {
  495. node = nodesByIndex[ nodesIndices[ i ] ];
  496. node.setParent( undefined );
  497. if ( cascade === true ) {
  498. node.reset( cascade, removeVisual );
  499. }
  500. }
  501. // visual
  502. if ( removeVisual === true && this.visual && this.visual.parent ) {
  503. this.visual.parent.remove( this.visual );
  504. }
  505. },
  506. addNode: function ( node, indexOctant ) {
  507. node.indexOctant = indexOctant;
  508. if ( indexOfValue( this.nodesIndices, indexOctant ) === -1 ) {
  509. this.nodesIndices.push( indexOctant );
  510. }
  511. this.nodesByIndex[ indexOctant ] = node;
  512. if ( node.parent !== this ) {
  513. node.setParent( this );
  514. }
  515. },
  516. removeNode: function ( indexOctant ) {
  517. var index,
  518. node;
  519. index = indexOfValue( this.nodesIndices, indexOctant );
  520. this.nodesIndices.splice( index, 1 );
  521. node = node || this.nodesByIndex[ indexOctant ];
  522. delete this.nodesByIndex[ indexOctant ];
  523. if ( node.parent === this ) {
  524. node.setParent( undefined );
  525. }
  526. },
  527. addObject: function ( object ) {
  528. var index,
  529. indexOctant,
  530. node;
  531. // get object octant index
  532. indexOctant = this.getOctantIndex( object );
  533. // if object fully contained by an octant, add to subtree
  534. if ( indexOctant > -1 && this.nodesIndices.length > 0 ) {
  535. node = this.branch( indexOctant );
  536. node.addObject( object );
  537. } else if ( indexOctant < -1 && this.parent instanceof THREE.OctreeNode ) {
  538. // if object lies outside bounds, add to parent node
  539. this.parent.addObject( object );
  540. } else {
  541. // add to this objects list
  542. index = indexOfValue( this.objects, object );
  543. if ( index === -1 ) {
  544. this.objects.push( object );
  545. }
  546. // node reference
  547. object.node = this;
  548. // check if need to expand, split, or both
  549. this.checkGrow();
  550. }
  551. },
  552. addObjectWithoutCheck: function ( objects ) {
  553. var i, l,
  554. object;
  555. for ( i = 0, l = objects.length; i < l; i++ ) {
  556. object = objects[ i ];
  557. this.objects.push( object );
  558. object.node = this;
  559. }
  560. },
  561. removeObject: function ( object ) {
  562. var i, l,
  563. nodesRemovedFrom,
  564. removeData;
  565. // cascade through tree to find and remove object
  566. removeData = this.removeObjectRecursive( object, { searchComplete: false, nodesRemovedFrom: [], objectsDataRemoved: [] } );
  567. // if object removed, try to shrink the nodes it was removed from
  568. nodesRemovedFrom = removeData.nodesRemovedFrom;
  569. if ( nodesRemovedFrom.length > 0 ) {
  570. for ( i = 0, l = nodesRemovedFrom.length; i < l; i++ ) {
  571. nodesRemovedFrom[ i ].shrink();
  572. }
  573. }
  574. return removeData.objectsDataRemoved;
  575. },
  576. removeObjectRecursive: function ( object, removeData ) {
  577. var i, l,
  578. index = -1,
  579. objectData,
  580. node,
  581. objectRemoved;
  582. // find index of object in objects list
  583. // search and remove object data (fast)
  584. if ( object instanceof THREE.OctreeObjectData ) {
  585. // remove from this objects list
  586. index = indexOfValue( this.objects, object );
  587. if ( index !== -1 ) {
  588. this.objects.splice( index, 1 );
  589. object.node = undefined;
  590. removeData.objectsDataRemoved.push( object );
  591. removeData.searchComplete = objectRemoved = true;
  592. }
  593. } else {
  594. // search each object data for object and remove (slow)
  595. for ( i = this.objects.length - 1; i >= 0; i-- ) {
  596. objectData = this.objects[ i ];
  597. if ( objectData.object === object ) {
  598. this.objects.splice( i, 1 );
  599. objectData.node = undefined;
  600. removeData.objectsDataRemoved.push( objectData );
  601. objectRemoved = true;
  602. if ( !objectData.faces && !objectData.vertices ) {
  603. removeData.searchComplete = true;
  604. break;
  605. }
  606. }
  607. }
  608. }
  609. // if object data removed and this is not on nodes removed from
  610. if ( objectRemoved === true ) {
  611. removeData.nodesRemovedFrom.push( this );
  612. }
  613. // if search not complete, search nodes
  614. if ( removeData.searchComplete !== true ) {
  615. for ( i = 0, l = this.nodesIndices.length; i < l; i++ ) {
  616. node = this.nodesByIndex[ this.nodesIndices[ i ] ];
  617. // try removing object from node
  618. removeData = node.removeObjectRecursive( object, removeData );
  619. if ( removeData.searchComplete === true ) {
  620. break;
  621. }
  622. }
  623. }
  624. return removeData;
  625. },
  626. checkGrow: function () {
  627. // if object count above max
  628. if ( this.objects.length > this.tree.objectsThreshold && this.tree.objectsThreshold > 0 ) {
  629. this.grow();
  630. }
  631. },
  632. grow: function () {
  633. var indexOctant,
  634. object,
  635. objectsExpand = [],
  636. objectsExpandOctants = [],
  637. objectsSplit = [],
  638. objectsSplitOctants = [],
  639. objectsRemaining = [],
  640. i, l;
  641. // for each object
  642. for ( i = 0, l = this.objects.length; i < l; i++ ) {
  643. object = this.objects[ i ];
  644. // get object octant index
  645. indexOctant = this.getOctantIndex( object );
  646. // if lies within octant
  647. if ( indexOctant > -1 ) {
  648. objectsSplit.push( object );
  649. objectsSplitOctants.push( indexOctant );
  650. } else if ( indexOctant < -1 ) {
  651. // lies outside radius
  652. objectsExpand.push( object );
  653. objectsExpandOctants.push( indexOctant );
  654. } else {
  655. // lies across bounds between octants
  656. objectsRemaining.push( object );
  657. }
  658. }
  659. // if has objects to split
  660. if ( objectsSplit.length > 0) {
  661. objectsRemaining = objectsRemaining.concat( this.split( objectsSplit, objectsSplitOctants ) );
  662. }
  663. // if has objects to expand
  664. if ( objectsExpand.length > 0) {
  665. objectsRemaining = objectsRemaining.concat( this.expand( objectsExpand, objectsExpandOctants ) );
  666. }
  667. // store remaining
  668. this.objects = objectsRemaining;
  669. // merge check
  670. this.checkMerge();
  671. },
  672. split: function ( objects, octants ) {
  673. var i, l,
  674. indexOctant,
  675. object,
  676. node,
  677. objectsRemaining;
  678. // if not at max depth
  679. if ( this.depth < this.tree.depthMax ) {
  680. objects = objects || this.objects;
  681. octants = octants || [];
  682. objectsRemaining = [];
  683. // for each object
  684. for ( i = 0, l = objects.length; i < l; i++ ) {
  685. object = objects[ i ];
  686. // get object octant index
  687. indexOctant = octants[ i ];
  688. // if object contained by octant, branch this tree
  689. if ( indexOctant > -1 ) {
  690. node = this.branch( indexOctant );
  691. node.addObject( object );
  692. } else {
  693. objectsRemaining.push( object );
  694. }
  695. }
  696. // if all objects, set remaining as new objects
  697. if ( objects === this.objects ) {
  698. this.objects = objectsRemaining;
  699. }
  700. } else {
  701. objectsRemaining = this.objects;
  702. }
  703. return objectsRemaining;
  704. },
  705. branch: function ( indexOctant ) {
  706. var node,
  707. overlap,
  708. radius,
  709. radiusOffset,
  710. offset,
  711. position;
  712. // node exists
  713. if ( this.nodesByIndex[ indexOctant ] instanceof THREE.OctreeNode ) {
  714. node = this.nodesByIndex[ indexOctant ];
  715. } else {
  716. // properties
  717. radius = ( this.radiusOverlap ) * 0.5;
  718. overlap = radius * this.tree.overlapPct;
  719. radiusOffset = radius - overlap;
  720. offset = this.utilVec31Branch.set( indexOctant & 1 ? radiusOffset : -radiusOffset, indexOctant & 2 ? radiusOffset : -radiusOffset, indexOctant & 4 ? radiusOffset : -radiusOffset );
  721. position = new THREE.Vector3().addVectors( this.position, offset );
  722. // node
  723. node = new THREE.OctreeNode( {
  724. tree: this.tree,
  725. parent: this,
  726. position: position,
  727. radius: radius,
  728. indexOctant: indexOctant
  729. } );
  730. // store
  731. this.addNode( node, indexOctant );
  732. }
  733. return node;
  734. },
  735. expand: function ( objects, octants ) {
  736. var i, l,
  737. object,
  738. objectsRemaining,
  739. objectsExpand,
  740. indexOctant,
  741. flagsOutside,
  742. indexOutside,
  743. indexOctantInverse,
  744. iom = this.tree.INDEX_OUTSIDE_MAP,
  745. indexOutsideCounts,
  746. infoIndexOutside1,
  747. infoIndexOutside2,
  748. infoIndexOutside3,
  749. indexOutsideBitwise1,
  750. indexOutsideBitwise2,
  751. infoPotential1,
  752. infoPotential2,
  753. infoPotential3,
  754. indexPotentialBitwise1,
  755. indexPotentialBitwise2,
  756. octantX, octantY, octantZ,
  757. overlap,
  758. radius,
  759. radiusOffset,
  760. radiusParent,
  761. overlapParent,
  762. offset = this.utilVec31Expand,
  763. position,
  764. parent;
  765. // handle max depth down tree
  766. if ( this.tree.root.getDepthEnd() < this.tree.depthMax ) {
  767. objects = objects || this.objects;
  768. octants = octants || [];
  769. objectsRemaining = [];
  770. objectsExpand = [];
  771. // reset counts
  772. for ( i = 0, l = iom.length; i < l; i++ ) {
  773. iom[ i ].count = 0;
  774. }
  775. // for all outside objects, find outside octants containing most objects
  776. for ( i = 0, l = objects.length; i < l; i++ ) {
  777. object = objects[ i ];
  778. // get object octant index
  779. indexOctant = octants[ i ] ;
  780. // if object outside this, include in calculations
  781. if ( indexOctant < -1 ) {
  782. // convert octant index to outside flags
  783. flagsOutside = -indexOctant - this.tree.INDEX_OUTSIDE_OFFSET;
  784. // check against bitwise flags
  785. // x
  786. if ( flagsOutside & this.tree.FLAG_POS_X ) {
  787. iom[ this.tree.INDEX_OUTSIDE_POS_X ].count++;
  788. } else if ( flagsOutside & this.tree.FLAG_NEG_X ) {
  789. iom[ this.tree.INDEX_OUTSIDE_NEG_X ].count++;
  790. }
  791. // y
  792. if ( flagsOutside & this.tree.FLAG_POS_Y ) {
  793. iom[ this.tree.INDEX_OUTSIDE_POS_Y ].count++;
  794. } else if ( flagsOutside & this.tree.FLAG_NEG_Y ) {
  795. iom[ this.tree.INDEX_OUTSIDE_NEG_Y ].count++;
  796. }
  797. // z
  798. if ( flagsOutside & this.tree.FLAG_POS_Z ) {
  799. iom[ this.tree.INDEX_OUTSIDE_POS_Z ].count++;
  800. } else if ( flagsOutside & this.tree.FLAG_NEG_Z ) {
  801. iom[ this.tree.INDEX_OUTSIDE_NEG_Z ].count++;
  802. }
  803. // store in expand list
  804. objectsExpand.push( object );
  805. } else {
  806. objectsRemaining.push( object );
  807. }
  808. }
  809. // if objects to expand
  810. if ( objectsExpand.length > 0 ) {
  811. // shallow copy index outside map
  812. indexOutsideCounts = iom.slice( 0 );
  813. // sort outside index count so highest is first
  814. indexOutsideCounts.sort( function ( a, b ) {
  815. return b.count - a.count;
  816. } );
  817. // get highest outside indices
  818. // first is first
  819. infoIndexOutside1 = indexOutsideCounts[ 0 ];
  820. indexOutsideBitwise1 = infoIndexOutside1.index | 1;
  821. // second is ( one of next two bitwise OR 1 ) that is not opposite of ( first bitwise OR 1 )
  822. infoPotential1 = indexOutsideCounts[ 1 ];
  823. infoPotential2 = indexOutsideCounts[ 2 ];
  824. infoIndexOutside2 = ( infoPotential1.index | 1 ) !== indexOutsideBitwise1 ? infoPotential1 : infoPotential2;
  825. indexOutsideBitwise2 = infoIndexOutside2.index | 1;
  826. // third is ( one of next three bitwise OR 1 ) that is not opposite of ( first or second bitwise OR 1 )
  827. infoPotential1 = indexOutsideCounts[ 2 ];
  828. infoPotential2 = indexOutsideCounts[ 3 ];
  829. infoPotential3 = indexOutsideCounts[ 4 ];
  830. indexPotentialBitwise1 = infoPotential1.index | 1;
  831. indexPotentialBitwise2 = infoPotential2.index | 1;
  832. infoIndexOutside3 = indexPotentialBitwise1 !== indexOutsideBitwise1 && indexPotentialBitwise1 !== indexOutsideBitwise2 ? infoPotential1 : indexPotentialBitwise2 !== indexOutsideBitwise1 && indexPotentialBitwise2 !== indexOutsideBitwise2 ? infoPotential2 : infoPotential3;
  833. // get this octant normal based on outside octant indices
  834. octantX = infoIndexOutside1.x + infoIndexOutside2.x + infoIndexOutside3.x;
  835. octantY = infoIndexOutside1.y + infoIndexOutside2.y + infoIndexOutside3.y;
  836. octantZ = infoIndexOutside1.z + infoIndexOutside2.z + infoIndexOutside3.z;
  837. // get this octant indices based on octant normal
  838. indexOctant = this.getOctantIndexFromPosition( octantX, octantY, octantZ );
  839. indexOctantInverse = this.getOctantIndexFromPosition( -octantX, -octantY, -octantZ );
  840. // properties
  841. overlap = this.overlap;
  842. radius = this.radius;
  843. // radius of parent comes from reversing overlap of this, unless overlap percent is 0
  844. radiusParent = this.tree.overlapPct > 0 ? overlap / ( ( 0.5 * this.tree.overlapPct ) * ( 1 + this.tree.overlapPct ) ) : radius * 2;
  845. overlapParent = radiusParent * this.tree.overlapPct;
  846. // parent offset is difference between radius + overlap of parent and child
  847. radiusOffset = ( radiusParent + overlapParent ) - ( radius + overlap );
  848. offset.set( indexOctant & 1 ? radiusOffset : -radiusOffset, indexOctant & 2 ? radiusOffset : -radiusOffset, indexOctant & 4 ? radiusOffset : -radiusOffset );
  849. position = new THREE.Vector3().addVectors( this.position, offset );
  850. // parent
  851. parent = new THREE.OctreeNode( {
  852. tree: this.tree,
  853. position: position,
  854. radius: radiusParent
  855. } );
  856. // set self as node of parent
  857. parent.addNode( this, indexOctantInverse );
  858. // set parent as root
  859. this.tree.setRoot( parent );
  860. // add all expand objects to parent
  861. for ( i = 0, l = objectsExpand.length; i < l; i++ ) {
  862. this.tree.root.addObject( objectsExpand[ i ] );
  863. }
  864. }
  865. // if all objects, set remaining as new objects
  866. if ( objects === this.objects ) {
  867. this.objects = objectsRemaining;
  868. }
  869. } else {
  870. objectsRemaining = objects;
  871. }
  872. return objectsRemaining;
  873. },
  874. shrink: function () {
  875. // merge check
  876. this.checkMerge();
  877. // contract check
  878. this.tree.root.checkContract();
  879. },
  880. checkMerge: function () {
  881. var nodeParent = this,
  882. nodeMerge;
  883. // traverse up tree as long as node + entire subtree's object count is under minimum
  884. while ( nodeParent.parent instanceof THREE.OctreeNode && nodeParent.getObjectCountEnd() < this.tree.objectsThreshold ) {
  885. nodeMerge = nodeParent;
  886. nodeParent = nodeParent.parent;
  887. }
  888. // if parent node is not this, merge entire subtree into merge node
  889. if ( nodeParent !== this ) {
  890. nodeParent.merge( nodeMerge );
  891. }
  892. },
  893. merge: function ( nodes ) {
  894. var i, l,
  895. j, k,
  896. node;
  897. // handle nodes
  898. nodes = toArray( nodes );
  899. for ( i = 0, l = nodes.length; i < l; i++ ) {
  900. node = nodes[ i ];
  901. // gather node + all subtree objects
  902. this.addObjectWithoutCheck( node.getObjectsEnd() );
  903. // reset node + entire subtree
  904. node.reset( true, true );
  905. // remove node
  906. this.removeNode( node.indexOctant, node );
  907. }
  908. // merge check
  909. this.checkMerge();
  910. },
  911. checkContract: function () {
  912. var i, l,
  913. node,
  914. nodeObjectsCount,
  915. nodeHeaviest,
  916. nodeHeaviestObjectsCount,
  917. outsideHeaviestObjectsCount;
  918. // find node with highest object count
  919. if ( this.nodesIndices.length > 0 ) {
  920. nodeHeaviestObjectsCount = 0;
  921. outsideHeaviestObjectsCount = this.objects.length;
  922. for ( i = 0, l = this.nodesIndices.length; i < l; i++ ) {
  923. node = this.nodesByIndex[ this.nodesIndices[ i ] ];
  924. nodeObjectsCount = node.getObjectCountEnd();
  925. outsideHeaviestObjectsCount += nodeObjectsCount;
  926. if ( nodeHeaviest instanceof THREE.OctreeNode === false || nodeObjectsCount > nodeHeaviestObjectsCount ) {
  927. nodeHeaviest = node;
  928. nodeHeaviestObjectsCount = nodeObjectsCount;
  929. }
  930. }
  931. // subtract heaviest count from outside count
  932. outsideHeaviestObjectsCount -= nodeHeaviestObjectsCount;
  933. // if should contract
  934. if ( outsideHeaviestObjectsCount < this.tree.objectsThreshold && nodeHeaviest instanceof THREE.OctreeNode ) {
  935. this.contract( nodeHeaviest );
  936. }
  937. }
  938. },
  939. contract: function ( nodeRoot ) {
  940. var i, l,
  941. node;
  942. // handle all nodes
  943. for ( i = 0, l = this.nodesIndices.length; i < l; i++ ) {
  944. node = this.nodesByIndex[ this.nodesIndices[ i ] ];
  945. // if node is not new root
  946. if ( node !== nodeRoot ) {
  947. // add node + all subtree objects to root
  948. nodeRoot.addObjectWithoutCheck( node.getObjectsEnd() );
  949. // reset node + entire subtree
  950. node.reset( true, true );
  951. }
  952. }
  953. // add own objects to root
  954. nodeRoot.addObjectWithoutCheck( this.objects );
  955. // reset self
  956. this.reset( false, true );
  957. // set new root
  958. this.tree.setRoot( nodeRoot );
  959. // contract check on new root
  960. nodeRoot.checkContract();
  961. },
  962. getOctantIndex: function ( objectData ) {
  963. var i, l,
  964. positionObj,
  965. radiusObj,
  966. position = this.position,
  967. radiusOverlap = this.radiusOverlap,
  968. overlap = this.overlap,
  969. deltaX, deltaY, deltaZ,
  970. distX, distY, distZ,
  971. distance,
  972. indexOctant = 0;
  973. // handle type
  974. if ( objectData instanceof THREE.OctreeObjectData ) {
  975. radiusObj = objectData.radius;
  976. positionObj = objectData.position;
  977. // update object data position last
  978. objectData.positionLast.copy( positionObj );
  979. } else if ( objectData instanceof THREE.OctreeNode ) {
  980. positionObj = objectData.position;
  981. radiusObj = 0;
  982. }
  983. // find delta and distance
  984. deltaX = positionObj.x - position.x;
  985. deltaY = positionObj.y - position.y;
  986. deltaZ = positionObj.z - position.z;
  987. distX = Math.abs( deltaX );
  988. distY = Math.abs( deltaY );
  989. distZ = Math.abs( deltaZ );
  990. distance = Math.max( distX, distY, distZ );
  991. // if outside, use bitwise flags to indicate on which sides object is outside of
  992. if ( distance + radiusObj > radiusOverlap ) {
  993. // x
  994. if ( distX + radiusObj > radiusOverlap ) {
  995. indexOctant = indexOctant ^ ( deltaX > 0 ? this.tree.FLAG_POS_X : this.tree.FLAG_NEG_X );
  996. }
  997. // y
  998. if ( distY + radiusObj > radiusOverlap ) {
  999. indexOctant = indexOctant ^ ( deltaY > 0 ? this.tree.FLAG_POS_Y : this.tree.FLAG_NEG_Y );
  1000. }
  1001. // z
  1002. if ( distZ + radiusObj > radiusOverlap ) {
  1003. indexOctant = indexOctant ^ ( deltaZ > 0 ? this.tree.FLAG_POS_Z : this.tree.FLAG_NEG_Z );
  1004. }
  1005. objectData.indexOctant = -indexOctant - this.tree.INDEX_OUTSIDE_OFFSET;
  1006. return objectData.indexOctant;
  1007. }
  1008. // return octant index from delta xyz
  1009. if ( deltaX - radiusObj > -overlap ) {
  1010. // x right
  1011. indexOctant = indexOctant | 1;
  1012. } else if ( !( deltaX + radiusObj < overlap ) ) {
  1013. // x left
  1014. objectData.indexOctant = this.tree.INDEX_INSIDE_CROSS;
  1015. return objectData.indexOctant;
  1016. }
  1017. if ( deltaY - radiusObj > -overlap ) {
  1018. // y right
  1019. indexOctant = indexOctant | 2;
  1020. } else if ( !( deltaY + radiusObj < overlap ) ) {
  1021. // y left
  1022. objectData.indexOctant = this.tree.INDEX_INSIDE_CROSS;
  1023. return objectData.indexOctant;
  1024. }
  1025. if ( deltaZ - radiusObj > -overlap ) {
  1026. // z right
  1027. indexOctant = indexOctant | 4;
  1028. } else if ( !( deltaZ + radiusObj < overlap ) ) {
  1029. // z left
  1030. objectData.indexOctant = this.tree.INDEX_INSIDE_CROSS;
  1031. return objectData.indexOctant;
  1032. }
  1033. objectData.indexOctant = indexOctant;
  1034. return objectData.indexOctant;
  1035. },
  1036. getOctantIndexFromPosition: function ( x, y, z ) {
  1037. var indexOctant = 0;
  1038. if ( x > 0 ) {
  1039. indexOctant = indexOctant | 1;
  1040. }
  1041. if ( y > 0 ) {
  1042. indexOctant = indexOctant | 2;
  1043. }
  1044. if ( z > 0 ) {
  1045. indexOctant = indexOctant | 4;
  1046. }
  1047. return indexOctant;
  1048. },
  1049. search: function ( position, radius, objects, direction, directionPct ) {
  1050. var i, l,
  1051. node,
  1052. intersects;
  1053. // test intersects by parameters
  1054. if ( direction ) {
  1055. intersects = this.intersectRay( position, direction, radius, directionPct );
  1056. } else {
  1057. intersects = this.intersectSphere( position, radius );
  1058. }
  1059. // if intersects
  1060. if ( intersects === true ) {
  1061. // gather objects
  1062. objects = objects.concat( this.objects );
  1063. // search subtree
  1064. for ( i = 0, l = this.nodesIndices.length; i < l; i++ ) {
  1065. node = this.nodesByIndex[ this.nodesIndices[ i ] ];
  1066. objects = node.search( position, radius, objects, direction );
  1067. }
  1068. }
  1069. return objects;
  1070. },
  1071. intersectSphere: function ( position, radius ) {
  1072. var distance = radius * radius,
  1073. px = position.x,
  1074. py = position.y,
  1075. pz = position.z;
  1076. if ( px < this.left ) {
  1077. distance -= Math.pow( px - this.left, 2 );
  1078. } else if ( px > this.right ) {
  1079. distance -= Math.pow( px - this.right, 2 );
  1080. }
  1081. if ( py < this.bottom ) {
  1082. distance -= Math.pow( py - this.bottom, 2 );
  1083. } else if ( py > this.top ) {
  1084. distance -= Math.pow( py - this.top, 2 );
  1085. }
  1086. if ( pz < this.back ) {
  1087. distance -= Math.pow( pz - this.back, 2 );
  1088. } else if ( pz > this.front ) {
  1089. distance -= Math.pow( pz - this.front, 2 );
  1090. }
  1091. return distance >= 0;
  1092. },
  1093. intersectRay: function ( origin, direction, distance, directionPct ) {
  1094. if ( typeof directionPct === 'undefined' ) {
  1095. directionPct = this.utilVec31Ray.set( 1, 1, 1 ).divide( direction );
  1096. }
  1097. var t1 = ( this.left - origin.x ) * directionPct.x,
  1098. t2 = ( this.right - origin.x ) * directionPct.x,
  1099. t3 = ( this.bottom - origin.y ) * directionPct.y,
  1100. t4 = ( this.top - origin.y ) * directionPct.y,
  1101. t5 = ( this.back - origin.z ) * directionPct.z,
  1102. t6 = ( this.front - origin.z ) * directionPct.z,
  1103. tmax = Math.min( Math.min( Math.max( t1, t2), Math.max( t3, t4) ), Math.max( t5, t6) ),
  1104. tmin;
  1105. // ray would intersect in reverse direction, i.e. this is behind ray
  1106. if (tmax < 0)
  1107. {
  1108. return false;
  1109. }
  1110. tmin = Math.max( Math.max( Math.min( t1, t2), Math.min( t3, t4)), Math.min( t5, t6));
  1111. // if tmin > tmax or tmin > ray distance, ray doesn't intersect AABB
  1112. if( tmin > tmax || tmin > distance ) {
  1113. return false;
  1114. }
  1115. return true;
  1116. },
  1117. getDepthEnd: function ( depth ) {
  1118. var i, l,
  1119. node;
  1120. if ( this.nodesIndices.length > 0 ) {
  1121. for ( i = 0, l = this.nodesIndices.length; i < l; i++ ) {
  1122. node = this.nodesByIndex[ this.nodesIndices[ i ] ];
  1123. depth = node.getDepthEnd( depth );
  1124. }
  1125. } else {
  1126. depth = !depth || this.depth > depth ? this.depth : depth;
  1127. }
  1128. return depth;
  1129. },
  1130. getNodeCountEnd: function () {
  1131. return this.tree.root.getNodeCountRecursive() + 1;
  1132. },
  1133. getNodeCountRecursive: function () {
  1134. var i, l,
  1135. count = this.nodesIndices.length;
  1136. for ( i = 0, l = this.nodesIndices.length; i < l; i++ ) {
  1137. count += this.nodesByIndex[ this.nodesIndices[ i ] ].getNodeCountRecursive();
  1138. }
  1139. return count;
  1140. },
  1141. getObjectsEnd: function ( objects ) {
  1142. var i, l,
  1143. node;
  1144. objects = ( objects || [] ).concat( this.objects );
  1145. for ( i = 0, l = this.nodesIndices.length; i < l; i++ ) {
  1146. node = this.nodesByIndex[ this.nodesIndices[ i ] ];
  1147. objects = node.getObjectsEnd( objects );
  1148. }
  1149. return objects;
  1150. },
  1151. getObjectCountEnd: function () {
  1152. var i, l,
  1153. count = this.objects.length;
  1154. for ( i = 0, l = this.nodesIndices.length; i < l; i++ ) {
  1155. count += this.nodesByIndex[ this.nodesIndices[ i ] ].getObjectCountEnd();
  1156. }
  1157. return count;
  1158. },
  1159. getObjectCountStart: function () {
  1160. var count = this.objects.length,
  1161. parent = this.parent;
  1162. while( parent instanceof THREE.OctreeNode ) {
  1163. count += parent.objects.length;
  1164. parent = parent.parent;
  1165. }
  1166. return count;
  1167. },
  1168. toConsole: function ( space ) {
  1169. var i, l,
  1170. node,
  1171. spaceAddition = ' ';
  1172. space = typeof space === 'string' ? space : spaceAddition;
  1173. 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 );
  1174. console.log( ( this.parent ? space + ' ' : ' ' ), '+ objects ( ', this.objects.length, ' ) ', this.objects );
  1175. console.log( ( this.parent ? space + ' ' : ' ' ), '+ children ( ', this.nodesIndices.length, ' )', this.nodesIndices, this.nodesByIndex );
  1176. for ( i = 0, l = this.nodesIndices.length; i < l; i++ ) {
  1177. node = this.nodesByIndex[ this.nodesIndices[ i ] ];
  1178. node.toConsole( space + spaceAddition );
  1179. }
  1180. }
  1181. };
  1182. /*===================================================
  1183. raycaster additional functionality
  1184. =====================================================*/
  1185. THREE.Raycaster.prototype.intersectOctreeObject = function ( object, recursive ) {
  1186. var intersects,
  1187. octreeObject,
  1188. facesAll,
  1189. facesSearch;
  1190. if ( object.object instanceof THREE.Object3D ) {
  1191. octreeObject = object;
  1192. object = octreeObject.object;
  1193. // temporarily replace object geometry's faces with octree object faces
  1194. facesSearch = octreeObject.faces;
  1195. facesAll = object.geometry.faces;
  1196. if ( facesSearch.length > 0 ) {
  1197. object.geometry.faces = facesSearch;
  1198. }
  1199. // intersect
  1200. intersects = this.intersectObject( object, recursive );
  1201. // revert object geometry's faces
  1202. if ( facesSearch.length > 0 ) {
  1203. object.geometry.faces = facesAll;
  1204. }
  1205. } else {
  1206. intersects = this.intersectObject( object, recursive );
  1207. }
  1208. return intersects;
  1209. };
  1210. THREE.Raycaster.prototype.intersectOctreeObjects = function ( objects, recursive ) {
  1211. var i, il,
  1212. intersects = [];
  1213. for ( i = 0, il = objects.length; i < il; i++ ) {
  1214. intersects = intersects.concat( this.intersectOctreeObject( objects[ i ], recursive ) );
  1215. }
  1216. return intersects;
  1217. };
  1218. }( THREE ) );