graphtool.js 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  1. "use strict";
  2. define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utility ) {
  3. // Set up render order constants for use with renderTop
  4. // Transparent objects render back to front, so use small numbers
  5. var DEPTH_GRID = Number.MIN_SAFE_INTEGER + 3;
  6. var DEPTH_AXES = Number.MIN_SAFE_INTEGER + 2;
  7. var DEPTH_OBJECTS = Number.MIN_SAFE_INTEGER + 1;
  8. var self;
  9. return model.load( module, {
  10. // == Module Definition ====================================================================
  11. // -- initialize ---------------------------------------------------------------------------
  12. initialize: function() {
  13. self = this;
  14. this.state.graphs = {};
  15. this.state.objects = {};
  16. this.state.kernel = this.kernel.kernel.kernel;
  17. },
  18. // == Model API ============================================================================
  19. // -- creatingNode -------------------------------------------------------------------------
  20. creatingNode: function( nodeID, childID, childExtendsID, childImplementsIDs,
  21. childSource, childType, childIndex, childName, callback /* ( ready ) */ ) {
  22. var node = undefined;
  23. var kernel = this.state.kernel;
  24. var protos = getPrototypes.call( this, kernel, childExtendsID );
  25. if ( protos && isGraph( protos ) ) {
  26. node = this.state.graphs[ childID ] = getThreeJSModel().state.nodes[ childID ];
  27. node.graphProperties = {
  28. "graphScale": undefined,
  29. "gridInterval": undefined,
  30. "gridLineInterval": undefined,
  31. "gridLength": undefined,
  32. "xAxisVisible": undefined,
  33. "yAxisVisible": undefined,
  34. "zAxisVisible": undefined,
  35. "gridVisible": undefined,
  36. "axisOpacity": undefined,
  37. "gridOpacity": undefined,
  38. "renderTop": undefined
  39. };
  40. node.initialized = false;
  41. } else if ( protos && isGraphObject( protos ) ) {
  42. var type = getObjectType( protos );
  43. node = this.state.objects[ childID ] = getThreeJSModel().state.nodes[ childID ];
  44. node.type = type;
  45. switch ( type ) {
  46. case "line":
  47. node.objectProperties = {
  48. "axis": undefined,
  49. "startValue": undefined,
  50. "endValue": undefined,
  51. "color": undefined,
  52. "opacity": undefined,
  53. "lineThickness": undefined,
  54. "renderTop": undefined
  55. };
  56. break;
  57. case "function":
  58. node.objectProperties = {
  59. "lineFunction": undefined,
  60. "startValue": undefined,
  61. "endValue": undefined,
  62. "pointCount": undefined,
  63. "color": undefined,
  64. "opacity": undefined,
  65. "lineThickness": undefined,
  66. "renderTop": undefined
  67. };
  68. break;
  69. case "plane":
  70. node.objectProperties = {
  71. "origin": undefined,
  72. "normal": undefined,
  73. "rotationAngle": undefined,
  74. "size": undefined,
  75. "color": undefined,
  76. "opacity": undefined,
  77. "doubleSided": undefined,
  78. "renderTop": undefined
  79. };
  80. break;
  81. case "group":
  82. node.objectProperties = {
  83. "groupVisible": undefined,
  84. "graphObjects": undefined
  85. };
  86. break;
  87. }
  88. node.parentGraph = this.state.graphs[ node.parentID ];
  89. node.initialized = false;
  90. }
  91. },
  92. // -- initializingNode ---------------------------------------------------------------------
  93. initializingNode: function( nodeID, childID, childExtendsID, childImplementsIDs,
  94. childSource, childType, childIndex, childName ) {
  95. var node;
  96. if ( this.state.graphs[ childID ] ) {
  97. node = this.state.graphs[ childID ];
  98. createGraph( node );
  99. node.initialized = true;
  100. } else if ( this.state.objects[ childID ] ) {
  101. node = this.state.objects[ childID ];
  102. createObject( node );
  103. node.initialized = true;
  104. }
  105. },
  106. // -- deletingNode -------------------------------------------------------------------------
  107. deletingNode: function( nodeID ) {
  108. if( nodeID ) {
  109. var childNode = this.state.objects[ nodeID ];
  110. if( childNode ) {
  111. var threeObject = childNode.threeObject;
  112. if( threeObject && threeObject.parent )
  113. {
  114. threeObject.parent.remove( threeObject );
  115. }
  116. delete this.state.objects[ childNode ];
  117. }
  118. }
  119. },
  120. // -- addingChild --------------------------------------------------------------------------
  121. addingChild: function( nodeID, childID, childName ) {
  122. },
  123. // -- removingChild ------------------------------------------------------------------------
  124. removingChild: function( nodeID, childID ) {
  125. },
  126. // -- creatingProperty ---------------------------------------------------------------------
  127. creatingProperty: function( nodeID, propertyName, propertyValue ) {
  128. return this.initializingProperty( nodeID, propertyName, propertyValue );
  129. },
  130. // -- initializingProperty -----------------------------------------------------------------
  131. initializingProperty: function( nodeID, propertyName, propertyValue ) {
  132. var value = undefined;
  133. if ( propertyValue !== undefined ) {
  134. var node = this.state.objects[ nodeID ] || this.state.graphs[ nodeID ] ;
  135. if ( node !== undefined ) {
  136. switch ( propertyName ) {
  137. default:
  138. value = this.settingProperty( nodeID, propertyName, propertyValue );
  139. break;
  140. }
  141. }
  142. }
  143. return value;
  144. },
  145. // TODO: deletingProperty
  146. // -- settingProperty ----------------------------------------------------------------------
  147. settingProperty: function( nodeID, propertyName, propertyValue ) {
  148. var node;
  149. if ( this.state.graphs[ nodeID ] ) {
  150. node = this.state.graphs[ nodeID ];
  151. if ( node.graphProperties.hasOwnProperty( propertyName ) ) {
  152. node.graphProperties[ propertyName ] = propertyValue;
  153. if ( node.initialized ) {
  154. switch ( propertyName ) {
  155. case "xAxisVisible":
  156. case "yAxisVisible":
  157. case "zAxisVisible":
  158. case "gridVisible":
  159. setGraphVisibility( node, true );
  160. break;
  161. case "graphScale":
  162. redrawGraph( node );
  163. redrawObjects( node.ID, this.state.objects );
  164. break;
  165. default:
  166. redrawGraph( node );
  167. break;
  168. }
  169. }
  170. }
  171. } else if ( this.state.objects[ nodeID ] ) {
  172. node = this.state.objects[ nodeID ];
  173. if ( node.objectProperties.hasOwnProperty( propertyName ) ) {
  174. node.objectProperties[ propertyName ] = propertyValue;
  175. if ( node.initialized ) {
  176. redrawObject( node );
  177. }
  178. }
  179. }
  180. },
  181. // -- gettingProperty ----------------------------------------------------------------------
  182. gettingProperty: function( nodeID, propertyName, propertyValue ) {
  183. var node = this.state.objects[ nodeID ];
  184. if ( node ) {
  185. }
  186. },
  187. // -- creatingMethod -----------------------------------------------------------------------
  188. creatingMethod: function( nodeID, methodName, methodParameters, methodBody ) {
  189. },
  190. // TODO: deletingMethod
  191. // -- callingMethod ------------------------------------------------------------------------
  192. callingMethod: function( nodeID, methodName, methodParameters, methodValue ) {
  193. var node;
  194. if ( this.state.graphs[ nodeID ] ) {
  195. node = this.state.graphs[ nodeID ];
  196. if ( methodName === "setGraphVisibility" ) {
  197. var visible = methodParameters[0];
  198. setGraphVisibility( node, visible );
  199. }
  200. } else if ( this.state.objects[ nodeID ] ) {
  201. node = this.state.objects[ nodeID ];
  202. if ( methodName === "setGroupItemProperty" ) {
  203. var itemIndexList = methodParameters[ 0 ];
  204. var itemPropertyName = methodParameters[ 1 ];
  205. var itemPropertyValue = methodParameters[ 2 ];
  206. for ( var i = 0; i < itemIndexList.length; i++ ) {
  207. node.threeObject.children[ 0 ].children[ itemIndexList[ i ] ][ itemPropertyName ] = itemPropertyValue;
  208. }
  209. }
  210. }
  211. },
  212. // -- creatingEvent ------------------------------------------------------------------------
  213. creatingEvent: function( nodeID, eventName, eventParameters ) {
  214. },
  215. // TODO: deletingEvent
  216. // -- firingEvent --------------------------------------------------------------------------
  217. firingEvent: function( nodeID, eventName, eventParameters ) {
  218. },
  219. // -- executing ----------------------------------------------------------------------------
  220. executing: function( nodeID, scriptText, scriptType ) {
  221. },
  222. } );
  223. function getThreeJSModel() {
  224. var threejs;
  225. threejs = vwf.models[ "vwf/model/threejs" ];
  226. while ( threejs.model ) {
  227. threejs = threejs.model;
  228. }
  229. return threejs;
  230. }
  231. function getPrototypes( kernel, extendsID ) {
  232. var prototypes = [];
  233. var id = extendsID;
  234. while ( id !== undefined ) {
  235. prototypes.push( id );
  236. id = kernel.prototype( id );
  237. }
  238. return prototypes;
  239. }
  240. function isGraph( prototypes ) {
  241. var foundGraph = false;
  242. if ( prototypes ) {
  243. for ( var i = 0; i < prototypes.length && !foundGraph; i++ ) {
  244. foundGraph = ( prototypes[i] == "http://vwf.example.com/graphtool/graph.vwf" );
  245. }
  246. }
  247. return foundGraph;
  248. }
  249. function isGraphObject( prototypes ) {
  250. var foundObject = false;
  251. if ( prototypes ) {
  252. for ( var i = 0; i < prototypes.length && !foundObject; i++ ) {
  253. foundObject = ( prototypes[i] == "http://vwf.example.com/graphtool/graphline.vwf" ) ||
  254. ( prototypes[i] == "http://vwf.example.com/graphtool/graphlinefunction.vwf" ) ||
  255. ( prototypes[i] == "http://vwf.example.com/graphtool/graphplane.vwf" ) ||
  256. ( prototypes[i] == "http://vwf.example.com/graphtool/graphgroup.vwf" );
  257. }
  258. }
  259. return foundObject;
  260. }
  261. function getObjectType( prototypes ) {
  262. if ( prototypes ) {
  263. for ( var i = 0; i < prototypes.length; i++ ) {
  264. if ( prototypes[i] == "http://vwf.example.com/graphtool/graphline.vwf" ) {
  265. return "line";
  266. } else if ( prototypes[i] == "http://vwf.example.com/graphtool/graphlinefunction.vwf" ) {
  267. return "function";
  268. } else if ( prototypes[i] == "http://vwf.example.com/graphtool/graphplane.vwf" ) {
  269. return "plane";
  270. } else if ( prototypes[i] == "http://vwf.example.com/graphtool/graphgroup.vwf" ) {
  271. return "group";
  272. }
  273. }
  274. }
  275. return undefined;
  276. }
  277. function createGraph( node ) {
  278. var props = node.graphProperties;
  279. var graph = generateGraph(
  280. props.graphScale,
  281. props.gridInterval,
  282. props.gridLineInterval,
  283. props.gridLength,
  284. props.xAxisVisible,
  285. props.yAxisVisible,
  286. props.zAxisVisible,
  287. props.gridVisible,
  288. props.axisOpacity,
  289. props.gridOpacity,
  290. props.renderTop
  291. );
  292. node.threeObject.add( graph );
  293. }
  294. function createObject( node ) {
  295. var graphScale = node.parentGraph.graphProperties.graphScale;
  296. var props = node.objectProperties;
  297. var obj = null;
  298. switch( node.type ) {
  299. case "line":
  300. obj = generateLine(
  301. graphScale,
  302. props.axis,
  303. props.startValue,
  304. props.endValue,
  305. props.color,
  306. props.opacity,
  307. props.lineThickness,
  308. props.renderTop
  309. );
  310. break;
  311. case "function":
  312. obj = generateLineFuction(
  313. graphScale,
  314. props.lineFunction,
  315. props.startValue,
  316. props.endValue,
  317. props.pointCount,
  318. props.color,
  319. props.opacity,
  320. props.lineThickness,
  321. props.renderTop
  322. );
  323. break;
  324. case "plane":
  325. obj = generatePlane(
  326. graphScale,
  327. props.origin,
  328. props.normal,
  329. props.rotationAngle,
  330. props.size,
  331. props.color,
  332. props.opacity,
  333. props.doubleSided,
  334. props.renderTop
  335. );
  336. break;
  337. case "group":
  338. obj = generateGroup(
  339. graphScale,
  340. props.groupVisible,
  341. props.graphObjects
  342. );
  343. break;
  344. }
  345. obj.visible = node.threeObject.visible;
  346. node.threeObject.add( obj );
  347. }
  348. function redrawGraph( graph ) {
  349. var oldObj = graph.threeObject.getObjectByName( "graph" );
  350. graph.threeObject.remove( oldObj );
  351. if ( oldObj.children.length > 0 ) {
  352. disposeObject( oldObj );
  353. }
  354. createGraph( graph );
  355. }
  356. function redrawObjects( graphID, objects ) {
  357. for ( var objID in objects ) {
  358. var obj = objects[ objID ];
  359. if ( obj.parentID === graphID && obj.initialized ) {
  360. redrawObject( obj );
  361. }
  362. }
  363. }
  364. function redrawObject( obj ) {
  365. var oldObj = obj.threeObject.children[ 0 ];
  366. obj.threeObject.remove( oldObj );
  367. if ( oldObj.children.length > 0 ) {
  368. disposeObject( oldObj );
  369. }
  370. createObject( obj );
  371. }
  372. function disposeObject( obj ) {
  373. var child, i;
  374. for ( i = 0; i < obj.children.length; i++ ) {
  375. child = obj.children[ i ];
  376. if ( child.children.length > 0 ) {
  377. disposeObject( child );
  378. } else if ( child instanceof THREE.Mesh ) {
  379. if ( child.geometry ) {
  380. child.geometry.dispose();
  381. }
  382. if ( child.material ) {
  383. if ( child.material.map ) {
  384. child.material.map.dispose();
  385. }
  386. child.material.dispose();
  387. }
  388. }
  389. }
  390. }
  391. function setGraphVisibility( node, value ) {
  392. var graph, xAxis, yAxis, zAxis, gridLines;
  393. graph = node.threeObject.getObjectByName( "graph" );
  394. if ( graph ) {
  395. xAxis = graph.getObjectByName( "xAxis" );
  396. yAxis = graph.getObjectByName( "yAxis" );
  397. zAxis = graph.getObjectByName( "zAxis" );
  398. gridLines = graph.getObjectByName( "gridLines" );
  399. if ( value ) {
  400. xAxis.visible = node.graphProperties.xAxisVisible;
  401. yAxis.visible = node.graphProperties.yAxisVisible;
  402. zAxis.visible = node.graphProperties.zAxisVisible;
  403. gridLines.visible = node.graphProperties.gridVisible;
  404. for ( var line in gridLines.children ) {
  405. gridLines.children[ line ].visible = gridLines.visible;
  406. }
  407. } else {
  408. xAxis.visible = false;
  409. yAxis.visible = false;
  410. zAxis.visible = false;
  411. gridLines.visible = false;
  412. for ( var line in gridLines.children ) {
  413. gridLines.children[ line ].visible = false;
  414. }
  415. }
  416. }
  417. }
  418. function generateGraph( graphScale, gridInterval, gridLineInterval, gridLength, xAxisVisible,
  419. yAxisVisible, zAxisVisible, gridVisible, axisOpacity, gridOpacity, renderTop ) {
  420. var xAxis, yAxis, zAxis, gridX, gridY, axisLine;
  421. var thickness = 0.1;
  422. var graph = new THREE.Object3D();
  423. var gridLines = new THREE.Object3D();
  424. graph.name = "graph";
  425. gridLines.name = "gridLines";
  426. xAxis = generateLine( graphScale, [ 1, 0, 0 ], -gridLength, gridLength, [ 255, 0, 0 ], axisOpacity, thickness, renderTop );
  427. xAxis.name = "xAxis";
  428. xAxis.visible = xAxisVisible;
  429. yAxis = generateLine( graphScale, [ 0, 1, 0 ], -gridLength, gridLength, [ 0, 0, 255 ], axisOpacity, thickness, renderTop );
  430. yAxis.name = "yAxis";
  431. yAxis.visible = yAxisVisible;
  432. zAxis = generateLine( graphScale, [ 0, 0, 1 ], -gridLength, gridLength, [ 0, 255, 0 ], axisOpacity, thickness, renderTop );
  433. zAxis.name = "zAxis";
  434. zAxis.visible = zAxisVisible;
  435. if ( renderTop ) {
  436. xAxis.renderDepth = yAxis.renderDepth = zAxis.renderDepth = DEPTH_AXES;
  437. }
  438. graph.add( xAxis );
  439. graph.add( yAxis );
  440. graph.add( zAxis );
  441. // Scale grid
  442. gridInterval *= graphScale;
  443. gridLineInterval *= graphScale;
  444. for ( var i = -gridLength * graphScale; i <= gridLength * graphScale; i += gridInterval ) {
  445. if ( i % gridLineInterval === 0 ) {
  446. thickness = 0.075;
  447. } else {
  448. thickness = 0.025;
  449. }
  450. gridX = generateLine( graphScale, [ 1, 0, 0 ], -gridLength, gridLength, [ 255, 255, 255 ], gridOpacity, thickness, renderTop );
  451. gridX.position.set( 0, i, 0 );
  452. gridX.visible = gridVisible;
  453. gridY = generateLine( graphScale, [ 0, 1, 0 ], -gridLength, gridLength, [ 255, 255, 255 ], gridOpacity, thickness, renderTop );
  454. gridY.position.set( i, 0, 0 );
  455. gridY.visible = gridVisible;
  456. if ( renderTop ) {
  457. gridX.renderDepth = gridY.renderDepth = DEPTH_GRID;
  458. }
  459. gridLines.add( gridX );
  460. gridLines.add( gridY );
  461. }
  462. graph.add( gridLines );
  463. return graph;
  464. }
  465. function generateLineFuction( graphScale, functionString, startValue, endValue,
  466. pointCount, color, opacity, thickness, renderTop ) {
  467. if ( !isValidFunction( functionString ) ) {
  468. return new THREE.Mesh();
  469. }
  470. var geometry = new THREE.Geometry();
  471. var point, direction;
  472. var points = new Array();
  473. var faces;
  474. var increment;
  475. var func = function( x, y, z ) {
  476. var fn = "var x = " + x + ", y = " + y + ", z = " + z + ";\n"
  477. + functionString + ";\n"
  478. + "[ x, y, z ];";
  479. var ar = eval( fn );
  480. x = ar[0] * graphScale;
  481. y = ar[1] * graphScale;
  482. z = ar[2] * graphScale;
  483. return new THREE.Vector3( x || 0, y || 0, z || 0 );
  484. }
  485. increment = Math.abs( endValue - startValue ) / pointCount;
  486. // Check for endvalue + ( increment / 2 ) to account for approximation errors
  487. for ( var i = startValue; i <= endValue + ( increment / 2 ); i += increment ) {
  488. point = func( i );
  489. direction = func( i + increment );
  490. direction.sub( func( i - increment ) );
  491. direction.normalize();
  492. if ( !isNaN( point.x ) && !isNaN( point.y ) && !isNaN( point.z ) ) {
  493. var planePoints = generateLineVertices( direction, point, thickness / 2 );
  494. for ( var j = 0; j < planePoints.length; j++ ) {
  495. points.push( planePoints[j] );
  496. }
  497. }
  498. }
  499. geometry.vertices = points;
  500. for ( var i = 0; i < points.length; i++ ) {
  501. if ( points[i + 4] !== undefined ) {
  502. geometry.faces.push( new THREE.Face3( i, i + 4, i + 1 ) );
  503. geometry.faces.push( new THREE.Face3( i, i + 3, i + 4 ) );
  504. }
  505. }
  506. var last = points.length - 1;
  507. geometry.faces.push( new THREE.Face3( 0, 1, 2 ) );
  508. geometry.faces.push( new THREE.Face3( 0, 2, 3 ) );
  509. geometry.faces.push( new THREE.Face3( last, last - 1, last - 3 ) );
  510. geometry.faces.push( new THREE.Face3( last - 1, last - 2, last - 3 ) );
  511. var transparent = renderTop || opacity < 1;
  512. var vwfColor = new utility.color( color );
  513. color = vwfColor.getHex();
  514. var meshMaterial = new THREE.MeshBasicMaterial(
  515. { "color": color, "transparent": transparent, "opacity": opacity, "depthTest": !renderTop }
  516. );
  517. var mesh = new THREE.Mesh( geometry, meshMaterial );
  518. mesh.renderDepth = renderTop ? DEPTH_OBJECTS : null;
  519. return mesh;
  520. }
  521. function generateLine( graphScale, axis, startValue, endValue, color, opacity, thickness, renderTop ) {
  522. var geometry = new THREE.Geometry();
  523. startValue *= graphScale;
  524. endValue *= graphScale;
  525. var startPoint, endPoint, direction;
  526. var points = new Array();
  527. var planePoints, i;
  528. startPoint = new THREE.Vector3(
  529. axis[ 0 ] * startValue,
  530. axis[ 1 ] * startValue,
  531. axis[ 2 ] * startValue
  532. );
  533. endPoint = new THREE.Vector3(
  534. axis[ 0 ] * endValue,
  535. axis[ 1 ] * endValue,
  536. axis[ 2 ] * endValue
  537. );
  538. direction = endPoint.clone();
  539. direction.sub( startPoint.clone() );
  540. direction.normalize();
  541. planePoints = generateLineVertices( direction, startPoint, thickness / 2 );
  542. for ( i = 0; i < planePoints.length; i++ ) {
  543. points.push( planePoints[i] );
  544. }
  545. planePoints = generateLineVertices( direction, endPoint, thickness / 2 );
  546. for ( i = 0; i < planePoints.length; i++ ) {
  547. points.push( planePoints[i] );
  548. }
  549. geometry.vertices = points;
  550. for ( var i = 0; i < points.length; i++ ) {
  551. if ( points[i + 4] !== undefined ) {
  552. geometry.faces.push( new THREE.Face3( i, i + 4, i + 1 ) );
  553. geometry.faces.push( new THREE.Face3( i, i + 3, i + 4 ) );
  554. }
  555. }
  556. var last = points.length - 1;
  557. geometry.faces.push( new THREE.Face3( 0, 1, 2 ) );
  558. geometry.faces.push( new THREE.Face3( 0, 2, 3 ) );
  559. geometry.faces.push( new THREE.Face3( last, last - 1, last - 3 ) );
  560. geometry.faces.push( new THREE.Face3( last - 1, last - 2, last - 3 ) );
  561. var transparent = renderTop || opacity < 1;
  562. var vwfColor = new utility.color( color );
  563. color = vwfColor.getHex();
  564. var meshMaterial = new THREE.MeshBasicMaterial(
  565. { "color": color, "transparent": transparent, "opacity": opacity, "depthTest": !renderTop }
  566. );
  567. var mesh = new THREE.Mesh( geometry, meshMaterial );
  568. mesh.renderDepth = renderTop ? DEPTH_OBJECTS : null;
  569. return mesh;
  570. }
  571. function generatePlane( graphScale, origin, normal, rotationAngle, size, color, opacity, doubleSided, renderTop ) {
  572. var geometry = new THREE.Geometry();
  573. normal = new THREE.Vector3( normal[ 0 ], normal[ 1 ], normal[ 2 ] );
  574. origin = new THREE.Vector3( origin[ 0 ], origin[ 1 ], origin[ 2 ] );
  575. var points;
  576. size *= graphScale;
  577. origin.multiplyScalar( graphScale );
  578. points = generatePlaneVertices( normal, origin, size );
  579. geometry.vertices = points;
  580. geometry.faces.push( new THREE.Face3( 0, 1, 2 ) );
  581. geometry.faces.push( new THREE.Face3( 0, 2, 3 ) );
  582. var transparent = renderTop || opacity < 1;
  583. var vwfColor = new utility.color( color );
  584. color = vwfColor.getHex();
  585. var meshMaterial = new THREE.MeshBasicMaterial(
  586. { "color": color, "transparent": transparent, "opacity": opacity, "depthTest": !renderTop }
  587. );
  588. if ( doubleSided ) {
  589. meshMaterial.side = THREE.DoubleSide;
  590. }
  591. var mesh = new THREE.Mesh( geometry, meshMaterial );
  592. mesh.renderDepth = renderTop ? DEPTH_OBJECTS : null;
  593. return mesh;
  594. }
  595. function generateGroup( graphScale, groupVisible, graphObjects ) {
  596. var groupObject = new THREE.Object3D();
  597. for ( var i = 0; i < graphObjects.length; i++ ) {
  598. var type = Object.keys( graphObjects[ i ] )[ 0 ];
  599. var props = graphObjects[ i ][ type ];
  600. var obj;
  601. switch( type ) {
  602. case "line":
  603. obj = generateLine(
  604. graphScale,
  605. props.axis,
  606. props.startValue,
  607. props.endValue,
  608. props.color,
  609. props.opacity,
  610. props.lineThickness,
  611. props.renderTop
  612. );
  613. break;
  614. case "function":
  615. obj = generateLineFuction(
  616. graphScale,
  617. props.lineFunction,
  618. props.startValue,
  619. props.endValue,
  620. props.pointCount,
  621. props.color,
  622. props.opacity,
  623. props.lineThickness,
  624. props.renderTop
  625. );
  626. break;
  627. case "plane":
  628. obj = generatePlane(
  629. graphScale,
  630. props.origin,
  631. props.normal,
  632. props.rotationAngle,
  633. props.size,
  634. props.color,
  635. props.opacity,
  636. props.doubleSided,
  637. props.renderTop
  638. );
  639. break;
  640. case "group":
  641. obj = generateGroup(
  642. graphScale,
  643. props.groupVisible,
  644. props.graphObjects
  645. );
  646. break;
  647. }
  648. obj.visible = groupVisible;
  649. groupObject.add( obj );
  650. }
  651. return groupObject;
  652. }
  653. function generateLineVertices( normal, origin, distance ) {
  654. var vertices = new Array();
  655. var up = new THREE.Vector3();
  656. var left = new THREE.Vector3();
  657. var rotAxis = new THREE.Vector3( 0, 0, 1 );
  658. var rotAngle, rotMat;
  659. if ( Math.abs( normal.z ) === 1 ) {
  660. rotAxis.x += 0.1;
  661. rotAxis.normalize();
  662. }
  663. rotAxis.crossVectors( normal, rotAxis );
  664. rotAxis.normalize();
  665. rotAngle = Math.acos( normal.dot( rotAxis ) );
  666. rotMat = createRotationMatrix( rotAxis, rotAngle );
  667. up.copy( normal );
  668. up.applyMatrix3( rotMat );
  669. up.normalize();
  670. left.crossVectors( up, normal );
  671. left.normalize();
  672. vertices.push(
  673. new THREE.Vector3(
  674. origin.x + ( up.x * distance ),
  675. origin.y + ( up.y * distance ),
  676. origin.z + ( up.z * distance )
  677. )
  678. );
  679. vertices.push(
  680. new THREE.Vector3(
  681. origin.x + ( left.x * distance ),
  682. origin.y + ( left.y * distance ),
  683. origin.z + ( left.z * distance )
  684. )
  685. );
  686. up.negate();
  687. left.negate();
  688. vertices.push(
  689. new THREE.Vector3(
  690. origin.x + ( up.x * distance ),
  691. origin.y + ( up.y * distance ),
  692. origin.z + ( up.z * distance )
  693. )
  694. );
  695. vertices.push(
  696. new THREE.Vector3(
  697. origin.x + ( left.x * distance ),
  698. origin.y + ( left.y * distance ),
  699. origin.z + ( left.z * distance )
  700. )
  701. );
  702. return vertices;
  703. }
  704. function generatePlaneVertices( normal, origin, distance ) {
  705. var vertices = new Array();
  706. var up = new THREE.Vector3();
  707. var left = new THREE.Vector3();
  708. var rotAxis = new THREE.Vector3( 0, 0, 1 );
  709. var rotAngle, rotMat;
  710. distance /= 2;
  711. if ( Math.abs( normal.z ) === 1 ) {
  712. rotAxis.x += 0.1;
  713. rotAxis.normalize();
  714. }
  715. rotAxis.crossVectors( normal, rotAxis );
  716. rotAxis.normalize();
  717. rotAngle = Math.acos( normal.dot( rotAxis ) );
  718. rotMat = createRotationMatrix( rotAxis, rotAngle );
  719. up.copy( normal );
  720. up.applyMatrix3( rotMat );
  721. up.normalize();
  722. left.crossVectors( up, normal );
  723. left.normalize();
  724. vertices.push(
  725. new THREE.Vector3(
  726. origin.x + ( up.x * distance ) + ( left.x * distance ),
  727. origin.y + ( up.y * distance ) + ( left.y * distance ),
  728. origin.z + ( up.z * distance ) + ( left.z * distance )
  729. )
  730. );
  731. vertices.push(
  732. new THREE.Vector3(
  733. origin.x + ( up.x * distance ) - ( left.x * distance ),
  734. origin.y + ( up.y * distance ) - ( left.y * distance ),
  735. origin.z + ( up.z * distance ) - ( left.z * distance )
  736. )
  737. );
  738. up.negate();
  739. left.negate();
  740. vertices.push(
  741. new THREE.Vector3(
  742. origin.x + ( up.x * distance ) + ( left.x * distance ),
  743. origin.y + ( up.y * distance ) + ( left.y * distance ),
  744. origin.z + ( up.z * distance ) + ( left.z * distance )
  745. )
  746. );
  747. vertices.push(
  748. new THREE.Vector3(
  749. origin.x + ( up.x * distance ) - ( left.x * distance ),
  750. origin.y + ( up.y * distance ) - ( left.y * distance ),
  751. origin.z + ( up.z * distance ) - ( left.z * distance )
  752. )
  753. );
  754. return vertices;
  755. }
  756. function createRotationMatrix( axis, angle ) {
  757. var mat;
  758. var c = Math.cos( angle );
  759. var d = 1 - c;
  760. var s = Math.sin( angle );
  761. mat = new THREE.Matrix3();
  762. mat.set(
  763. axis.x * axis.x * d + c,
  764. axis.x * axis.y * d + axis.z * s,
  765. axis.x * axis.z * d - axis.y * s,
  766. axis.x * axis.y * d - axis.z * s,
  767. axis.y * axis.y * d + c,
  768. axis.y * axis.z * d + axis.x * s,
  769. axis.x * axis.z * d + axis.y * s,
  770. axis.y * axis.z * d - axis.x * s,
  771. axis.z * axis.z * d + c
  772. );
  773. return mat;
  774. }
  775. function isValidFunction( functionString ) {
  776. return ( function( x, y, z ) {
  777. var fn = "var x = " + x + ", y = " + y + ", z = " + z + ";\n"
  778. + functionString + ";\n"
  779. + "[ x, y, z ];";
  780. try {
  781. var ar = eval( fn );
  782. } catch ( error ) {
  783. self.logger.errorx( "generateLineFuction", error.stack );
  784. return false;
  785. }
  786. return true;
  787. } )();
  788. }
  789. } );