summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/media9/javascript/3Dmenu.js
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/latex/media9/javascript/3Dmenu.js')
-rw-r--r--Master/texmf-dist/tex/latex/media9/javascript/3Dmenu.js885
1 files changed, 885 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/latex/media9/javascript/3Dmenu.js b/Master/texmf-dist/tex/latex/media9/javascript/3Dmenu.js
new file mode 100644
index 00000000000..b6c82a22876
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/media9/javascript/3Dmenu.js
@@ -0,0 +1,885 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// (C) 2012, Alexander Grahn
+//
+// 3Dmenu.js
+//
+// version 20120301
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// 3D JavaScript used by media9.sty
+//
+// Extended functionality of the (right click) context menu of 3D annotations.
+//
+// 1.) Adds the following items to the 3D context menu:
+//
+// * `Generate Default View'
+//
+// Finds good default camera settings, returned as options for use with
+// the \includemedia command.
+//
+// * `Get Current View'
+//
+// Determines camera, cross section and part settings of the current view,
+// returned as `VIEW' section that can be copied into a views file of
+// additional views. The views file is inserted using the `3Dviews' option
+// of \includemedia.
+//
+// * `Cross Section'
+//
+// Toggle switch to add or remove a cross section into or from the current
+// view. The cross section can be moved in the x, y, z directions using x,
+// y, z and X, Y, Z keys on the keyboard and be tilted against and spun
+// around the upright Z axis using the Up/Down and Left/Right arrow keys.
+//
+// 2.) Enables manipulation of position and orientation of indiviual parts in
+// the 3D scene. Parts which have been selected with the mouse can be
+// moved around and rotated like the cross section as described above, as
+// well as scaled using the s and S keys.
+//
+// This work may be distributed and/or modified under the
+// conditions of the LaTeX Project Public License, either version 1.3
+// of this license or (at your option) any later version.
+// The latest version of this license is in
+// http://www.latex-project.org/lppl.txt
+// and version 1.3 or later is part of all distributions of LaTeX
+// version 2005/12/01 or later.
+//
+// This work has the LPPL maintenance status `maintained'.
+//
+// The Current Maintainer of this work is A. Grahn.
+//
+// The code borrows heavily from Bernd Gaertners `Miniball' software,
+// originally written in C++, for computing the smallest enclosing ball of a
+// set of points; see: http://www.inf.ethz.ch/personal/gaertner/miniball.html
+//
+////////////////////////////////////////////////////////////////////////////////
+//host.console.show();
+
+//constructor for doubly linked list
+function List(){
+ this.first_node=null;
+ this.last_node=new Node(undefined);
+}
+List.prototype.push_back=function(x){
+ var new_node=new Node(x);
+ if(this.first_node==null){
+ this.first_node=new_node;
+ new_node.prev=null;
+ }else{
+ new_node.prev=this.last_node.prev;
+ new_node.prev.next=new_node;
+ }
+ new_node.next=this.last_node;
+ this.last_node.prev=new_node;
+};
+List.prototype.move_to_front=function(it){
+ var node=it.get();
+ if(node.next!=null && node.prev!=null){
+ node.next.prev=node.prev;
+ node.prev.next=node.next;
+ node.prev=null;
+ node.next=this.first_node;
+ this.first_node.prev=node;
+ this.first_node=node;
+ }
+};
+List.prototype.begin=function(){
+ var i=new Iterator();
+ i.target=this.first_node;
+ return(i);
+};
+List.prototype.end=function(){
+ var i=new Iterator();
+ i.target=this.last_node;
+ return(i);
+};
+function Iterator(it){
+ if( it!=undefined ){
+ this.target=it.target;
+ }else {
+ this.target=null;
+ }
+}
+Iterator.prototype.set=function(it){this.target=it.target;};
+Iterator.prototype.get=function(){return(this.target);};
+Iterator.prototype.deref=function(){return(this.target.data);};
+Iterator.prototype.incr=function(){
+ if(this.target.next!=null) this.target=this.target.next;
+};
+//constructor for node objects that populate the linked list
+function Node(x){
+ this.prev=null;
+ this.next=null;
+ this.data=x;
+}
+function sqr(r){return(r*r);}//helper function
+
+//Miniball algorithm by B. Gaertner
+function Basis(){
+ this.m=0;
+ this.q0=new Array(3);
+ this.z=new Array(4);
+ this.f=new Array(4);
+ this.v=new Array(new Array(3), new Array(3), new Array(3), new Array(3));
+ this.a=new Array(new Array(3), new Array(3), new Array(3), new Array(3));
+ this.c=new Array(new Array(3), new Array(3), new Array(3), new Array(3));
+ this.sqr_r=new Array(4);
+ this.current_c=this.c[0];
+ this.current_sqr_r=0;
+ this.reset();
+}
+Basis.prototype.center=function(){return(this.current_c);};
+Basis.prototype.size=function(){return(this.m);};
+Basis.prototype.pop=function(){--this.m;};
+Basis.prototype.excess=function(p){
+ var e=-this.current_sqr_r;
+ for(var k=0;k<3;++k){
+ e+=sqr(p[k]-this.current_c[k]);
+ }
+ return(e);
+};
+Basis.prototype.reset=function(){
+ this.m=0;
+ for(var j=0;j<3;++j){
+ this.c[0][j]=0;
+ }
+ this.current_c=this.c[0];
+ this.current_sqr_r=-1;
+};
+Basis.prototype.push=function(p){
+ var i, j;
+ var eps=1e-32;
+ if(this.m==0){
+ for(i=0;i<3;++i){
+ this.q0[i]=p[i];
+ }
+ for(i=0;i<3;++i){
+ this.c[0][i]=this.q0[i];
+ }
+ this.sqr_r[0]=0;
+ }else {
+ for(i=0;i<3;++i){
+ this.v[this.m][i]=p[i]-this.q0[i];
+ }
+ for(i=1;i<this.m;++i){
+ this.a[this.m][i]=0;
+ for(j=0;j<3;++j){
+ this.a[this.m][i]+=this.v[i][j]*this.v[this.m][j];
+ }
+ this.a[this.m][i]*=(2/this.z[i]);
+ }
+ for(i=1;i<this.m;++i){
+ for(j=0;j<3;++j){
+ this.v[this.m][j]-=this.a[this.m][i]*this.v[i][j];
+ }
+ }
+ this.z[this.m]=0;
+ for(j=0;j<3;++j){
+ this.z[this.m]+=sqr(this.v[this.m][j]);
+ }
+ this.z[this.m]*=2;
+ if(this.z[this.m]<eps*this.current_sqr_r) return(false);
+ var e=-this.sqr_r[this.m-1];
+ for(i=0;i<3;++i){
+ e+=sqr(p[i]-this.c[this.m-1][i]);
+ }
+ this.f[this.m]=e/this.z[this.m];
+ for(i=0;i<3;++i){
+ this.c[this.m][i]=this.c[this.m-1][i]+this.f[this.m]*this.v[this.m][i];
+ }
+ this.sqr_r[this.m]=this.sqr_r[this.m-1]+e*this.f[this.m]/2;
+ }
+ this.current_c=this.c[this.m];
+ this.current_sqr_r=this.sqr_r[this.m];
+ ++this.m;
+ return(true);
+};
+function Miniball(){
+ this.L=new List();
+ this.B=new Basis();
+ this.support_end=new Iterator();
+}
+Miniball.prototype.mtf_mb=function(it){
+ var i=new Iterator(it);
+ this.support_end.set(this.L.begin());
+ if((this.B.size())==4) return;
+ for(var k=new Iterator(this.L.begin());k.get()!=i.get();){
+ var j=new Iterator(k);
+ k.incr();
+ if(this.B.excess(j.deref()) > 0){
+ if(this.B.push(j.deref())){
+ this.mtf_mb(j);
+ this.B.pop();
+ if(this.support_end.get()==j.get())
+ this.support_end.incr();
+ this.L.move_to_front(j);
+ }
+ }
+ }
+};
+Miniball.prototype.check_in=function(b){
+ this.L.push_back(b);
+};
+Miniball.prototype.build=function(){
+ this.B.reset();
+ this.support_end.set(this.L.begin());
+ this.mtf_mb(this.L.end());
+};
+Miniball.prototype.center=function(){
+ return(this.B.center());
+};
+Miniball.prototype.radius=function(){
+ return(Math.sqrt(this.B.current_sqr_r));
+};
+
+//functions called by menu items
+function calc3Dopts () {
+ //create Miniball object
+ var mb=new Miniball();
+ //auxiliary vector
+ var corner=new Vector3();
+ //iterate over all visible mesh nodes in the scene
+ for(i=0;i<scene.meshes.count;i++){
+ var mesh=scene.meshes.getByIndex(i);
+ if(!mesh.visible) continue;
+ //local to parent transformation matrix
+ var trans=mesh.transform;
+ //build local to world transformation matrix by recursively
+ //multiplying the parent's transf. matrix on the right
+ var parent=mesh.parent;
+ while(parent.transform){
+ trans=trans.multiply(parent.transform);
+ parent=parent.parent;
+ }
+ //get the bbox of the mesh (local coordinates)
+ var bbox=mesh.computeBoundingBox();
+ //transform the local bounding box corner coordinates to
+ //world coordinates for bounding sphere determination
+ //BBox.min
+ corner.set(bbox.min);
+ corner.set(trans.transformPosition(corner));
+ mb.check_in(new Array(corner.x, corner.y, corner.z));
+ //BBox.max
+ corner.set(bbox.max);
+ corner.set(trans.transformPosition(corner));
+ mb.check_in(new Array(corner.x, corner.y, corner.z));
+ //remaining six BBox corners
+ corner.set(bbox.min.x, bbox.max.y, bbox.max.z);
+ corner.set(trans.transformPosition(corner));
+ mb.check_in(new Array(corner.x, corner.y, corner.z));
+ corner.set(bbox.min.x, bbox.min.y, bbox.max.z);
+ corner.set(trans.transformPosition(corner));
+ mb.check_in(new Array(corner.x, corner.y, corner.z));
+ corner.set(bbox.min.x, bbox.max.y, bbox.min.z);
+ corner.set(trans.transformPosition(corner));
+ mb.check_in(new Array(corner.x, corner.y, corner.z));
+ corner.set(bbox.max.x, bbox.min.y, bbox.min.z);
+ corner.set(trans.transformPosition(corner));
+ mb.check_in(new Array(corner.x, corner.y, corner.z));
+ corner.set(bbox.max.x, bbox.min.y, bbox.max.z);
+ corner.set(trans.transformPosition(corner));
+ mb.check_in(new Array(corner.x, corner.y, corner.z));
+ corner.set(bbox.max.x, bbox.max.y, bbox.min.z);
+ corner.set(trans.transformPosition(corner));
+ mb.check_in(new Array(corner.x, corner.y, corner.z));
+ }
+ //compute the smallest enclosing bounding sphere
+ mb.build();
+ //
+ //current camera settings
+ //
+ var camera=scene.cameras.getByIndex(0);
+ var res=''; //initialize result string
+ //aperture angle of the virtual camera (perspective projection) *or*
+ //orthographic scale (orthographic projection)
+ if(camera.projectionType==camera.TYPE_PERSPECTIVE){
+ var aac=camera.fov*180/Math.PI;
+ if(host.util.printf('%.4f', aac)!=30)
+ res+=host.util.printf('\n3Daac=%s,', aac);
+ }else{
+ camera.viewPlaneSize=2.*mb.radius();
+ res+=host.util.printf('\n3Dortho=%s,', 1./camera.viewPlaneSize);
+ }
+ //camera roll
+ var roll = camera.roll*180/Math.PI;
+ if(host.util.printf('%.4f', roll)!=0)
+ res+=host.util.printf('\n3Droll=%s,',roll);
+ //target to camera vector
+ var c2c=new Vector3();
+ c2c.set(camera.position);
+ c2c.subtractInPlace(camera.targetPosition);
+ c2c.normalize();
+ var x=(Math.abs(c2c.x) < 1e-12 ? 0 : c2c.x);
+ var y=(Math.abs(c2c.y) < 1e-12 ? 0 : c2c.y);
+ var z=(Math.abs(c2c.z) < 1e-12 ? 0 : c2c.z);
+ if(!(x==0 && y==-1 && z==0))
+ res+=host.util.printf('\n3Dc2c=%s %s %s,', x, y, z);
+ //
+ //new camera settings
+ //
+ //bounding sphere centre --> new camera target
+ var coo=new Vector3();
+ coo.set((mb.center())[0], (mb.center())[1], (mb.center())[2]);
+ coo.x = (Math.abs(coo.x) < 1e-12 ? 0 : coo.x);
+ coo.y = (Math.abs(coo.y) < 1e-12 ? 0 : coo.y);
+ coo.z = (Math.abs(coo.z) < 1e-12 ? 0 : coo.z);
+ if(coo.length)
+ res+=host.util.printf('\n3Dcoo=%s %s %s,', coo.x, coo.y, coo.z);
+ //radius of orbit
+ if(camera.projectionType==camera.TYPE_PERSPECTIVE){
+ var roo=mb.radius()/ Math.sin(aac * Math.PI/ 360.);
+ }else{
+ //orthographic projection
+ var roo=mb.radius();
+ }
+ res+=host.util.printf('\n3Droo=%s,', roo);
+ //update camera settings in the viewer
+ var currol=camera.roll;
+ camera.targetPosition.set(coo);
+ camera.position.set(coo.add(c2c.scale(roo)));
+ camera.roll=currol;
+ //determine background colour
+ rgb=scene.background.getColor();
+ if(!(rgb.r==1 && rgb.g==1 && rgb.b==1))
+ res+=host.util.printf('\n3Dbg=%s %s %s,', rgb.r, rgb.g, rgb.b);
+ //determine lighting scheme
+ switch(scene.lightScheme){
+ case scene.LIGHT_MODE_FILE:
+ curlights='Artwork';break;
+ case scene.LIGHT_MODE_NONE:
+ curlights='None';break;
+ case scene.LIGHT_MODE_WHITE:
+ curlights='White';break;
+ case scene.LIGHT_MODE_DAY:
+ curlights='Day';break;
+ case scene.LIGHT_MODE_NIGHT:
+ curlights='Night';break;
+ case scene.LIGHT_MODE_BRIGHT:
+ curlights='Hard';break;
+ case scene.LIGHT_MODE_RGB:
+ curlights='Primary';break;
+ case scene.LIGHT_MODE_BLUE:
+ curlights='Blue';break;
+ case scene.LIGHT_MODE_RED:
+ curlights='Red';break;
+ case scene.LIGHT_MODE_CUBE:
+ curlights='Cube';break;
+ case scene.LIGHT_MODE_CAD:
+ curlights='CAD';break;
+ case scene.LIGHT_MODE_HEADLAMP:
+ curlights='Headlamp';break;
+ }
+ if(curlights!='Artwork')
+ res+=host.util.printf('\n3Dlights=%s,', curlights);
+ //determine global render mode
+ switch(scene.renderMode){
+ case scene.RENDER_MODE_BOUNDING_BOX:
+ currender='BoundingBox';break;
+ case scene.RENDER_MODE_TRANSPARENT_BOUNDING_BOX:
+ currender='TransparentBoundingBox';break;
+ case scene.RENDER_MODE_TRANSPARENT_BOUNDING_BOX_OUTLINE:
+ currender='TransparentBoundingBoxOutline';break;
+ case scene.RENDER_MODE_VERTICES:
+ currender='Vertices';break;
+ case scene.RENDER_MODE_SHADED_VERTICES:
+ currender='ShadedVertices';break;
+ case scene.RENDER_MODE_WIREFRAME:
+ currender='Wireframe';break;
+ case scene.RENDER_MODE_SHADED_WIREFRAME:
+ currender='ShadedWireframe';break;
+ case scene.RENDER_MODE_SOLID:
+ currender='Solid';break;
+ case scene.RENDER_MODE_TRANSPARENT:
+ currender='Transparent';break;
+ case scene.RENDER_MODE_SOLID_WIREFRAME:
+ currender='SolidWireframe';break;
+ case scene.RENDER_MODE_TRANSPARENT_WIREFRAME:
+ currender='TransparentWireframe';break;
+ case scene.RENDER_MODE_ILLUSTRATION:
+ currender='Illustration';break;
+ case scene.RENDER_MODE_SOLID_OUTLINE:
+ currender='SolidOutline';break;
+ case scene.RENDER_MODE_SHADED_ILLUSTRATION:
+ currender='ShadedIllustration';break;
+ case scene.RENDER_MODE_HIDDEN_WIREFRAME:
+ currender='HiddenWireframe';break;
+ }
+ if(currender!='Solid')
+ res+=host.util.printf('\n3Drender=%s,', currender);
+ //write result string to the console
+ host.console.show();
+// host.console.clear();
+ host.console.println('%%\n%% Copy and paste the following text to the\n'+
+ '%% option list of \\includemedia!\n%%' + res + '\n');
+}
+
+function get3Dview () {
+ var camera=scene.cameras.getByIndex(0);
+ var coo=camera.targetPosition;
+ var c2c=camera.position.subtract(coo);
+ var roo=c2c.length;
+ c2c.normalize();
+ var res='VIEW%=insert optional name here\n';
+ var x = (Math.abs(coo.x) < 1e-12 ? 0 : coo.x);
+ var y = (Math.abs(coo.y) < 1e-12 ? 0 : coo.y);
+ var z = (Math.abs(coo.z) < 1e-12 ? 0 : coo.z);
+ if(!(x==0 && y==0 && z==0))
+ res+=host.util.printf(' COO=%s %s %s\n', coo.x, coo.y, coo.z);
+ x = (Math.abs(c2c.x) < 1e-12 ? 0 : c2c.x);
+ y = (Math.abs(c2c.y) < 1e-12 ? 0 : c2c.y);
+ z = (Math.abs(c2c.z) < 1e-12 ? 0 : c2c.z);
+ if(!(x==0 && y==-1 && z==0))
+ res+=host.util.printf(' C2C=%s %s %s\n', x, y, z);
+ if(roo > 0.11e-17)
+ res+=host.util.printf(' ROO=%s\n', roo);
+ var roll = camera.roll*180/Math.PI;
+ if(host.util.printf('%.4f', roll)!=0)
+ res+=host.util.printf(' ROLL=%s\n', roll);
+ if(camera.projectionType==camera.TYPE_PERSPECTIVE){
+ var aac=camera.fov * 180/Math.PI;
+ if(host.util.printf('%.4f', aac)!=30)
+ res+=host.util.printf(' AAC=%s\n', aac);
+ }else{
+ if(host.util.printf('%.4f', camera.viewPlaneSize)!=1)
+ res+=host.util.printf(' ORTHO=%s\n', 1./camera.viewPlaneSize);
+ }
+ rgb=scene.background.getColor();
+ if(!(rgb.r==1 && rgb.g==1 && rgb.b==1))
+ res+=host.util.printf(' BGCOLOR=%s %s %s\n', rgb.r, rgb.g, rgb.b);
+ switch(scene.lightScheme){
+ case scene.LIGHT_MODE_FILE:
+ curlights='Artwork';break;
+ case scene.LIGHT_MODE_NONE:
+ curlights='None';break;
+ case scene.LIGHT_MODE_WHITE:
+ curlights='White';break;
+ case scene.LIGHT_MODE_DAY:
+ curlights='Day';break;
+ case scene.LIGHT_MODE_NIGHT:
+ curlights='Night';break;
+ case scene.LIGHT_MODE_BRIGHT:
+ curlights='Hard';break;
+ case scene.LIGHT_MODE_RGB:
+ curlights='Primary';break;
+ case scene.LIGHT_MODE_BLUE:
+ curlights='Blue';break;
+ case scene.LIGHT_MODE_RED:
+ curlights='Red';break;
+ case scene.LIGHT_MODE_CUBE:
+ curlights='Cube';break;
+ case scene.LIGHT_MODE_CAD:
+ curlights='CAD';break;
+ case scene.LIGHT_MODE_HEADLAMP:
+ curlights='Headlamp';break;
+ }
+ if(curlights!='Artwork')
+ res+=' LIGHTS='+curlights+'\n';
+ switch(scene.renderMode){
+ case scene.RENDER_MODE_BOUNDING_BOX:
+ defaultrender='BoundingBox';break;
+ case scene.RENDER_MODE_TRANSPARENT_BOUNDING_BOX:
+ defaultrender='TransparentBoundingBox';break;
+ case scene.RENDER_MODE_TRANSPARENT_BOUNDING_BOX_OUTLINE:
+ defaultrender='TransparentBoundingBoxOutline';break;
+ case scene.RENDER_MODE_VERTICES:
+ defaultrender='Vertices';break;
+ case scene.RENDER_MODE_SHADED_VERTICES:
+ defaultrender='ShadedVertices';break;
+ case scene.RENDER_MODE_WIREFRAME:
+ defaultrender='Wireframe';break;
+ case scene.RENDER_MODE_SHADED_WIREFRAME:
+ defaultrender='ShadedWireframe';break;
+ case scene.RENDER_MODE_SOLID:
+ defaultrender='Solid';break;
+ case scene.RENDER_MODE_TRANSPARENT:
+ defaultrender='Transparent';break;
+ case scene.RENDER_MODE_SOLID_WIREFRAME:
+ defaultrender='SolidWireframe';break;
+ case scene.RENDER_MODE_TRANSPARENT_WIREFRAME:
+ defaultrender='TransparentWireframe';break;
+ case scene.RENDER_MODE_ILLUSTRATION:
+ defaultrender='Illustration';break;
+ case scene.RENDER_MODE_SOLID_OUTLINE:
+ defaultrender='SolidOutline';break;
+ case scene.RENDER_MODE_SHADED_ILLUSTRATION:
+ defaultrender='ShadedIllustration';break;
+ case scene.RENDER_MODE_HIDDEN_WIREFRAME:
+ defaultrender='HiddenWireframe';break;
+ }
+ if(defaultrender!='Solid')
+ res+=' RENDERMODE='+defaultrender+'\n';
+ for(var i=0;i<scene.meshes.count;i++){
+ var mesh=scene.meshes.getByIndex(i);
+ var meshUTFName = '';
+ for (var j=0; j<mesh.name.length; j++) {
+ var theUnicode = mesh.name.charCodeAt(j).toString(16);
+ while (theUnicode.length<4) theUnicode = '0' + theUnicode;
+ meshUTFName += theUnicode;
+ }
+ var end=mesh.name.lastIndexOf('.');
+ if(end>0) var meshUserName=mesh.name.substr(0,end);
+ else var meshUserName=mesh.name;
+ respart=' PART='+meshUserName+'\n';
+ respart+=' UTF16NAME='+meshUTFName+'\n';
+ defaultvals=true;
+ if(!mesh.visible){
+ respart+=' VISIBLE=false\n';
+ defaultvals=false;
+ }
+ if(mesh.opacity<1.0){
+ respart+=' OPACITY='+mesh.opacity+'\n';
+ defaultvals=false;
+ }
+ currender=defaultrender;
+ switch(mesh.renderMode){
+ case scene.RENDER_MODE_BOUNDING_BOX:
+ currender='BoundingBox';break;
+ case scene.RENDER_MODE_TRANSPARENT_BOUNDING_BOX:
+ currender='TransparentBoundingBox';break;
+ case scene.RENDER_MODE_TRANSPARENT_BOUNDING_BOX_OUTLINE:
+ currender='TransparentBoundingBoxOutline';break;
+ case scene.RENDER_MODE_VERTICES:
+ currender='Vertices';break;
+ case scene.RENDER_MODE_SHADED_VERTICES:
+ currender='ShadedVertices';break;
+ case scene.RENDER_MODE_WIREFRAME:
+ currender='Wireframe';break;
+ case scene.RENDER_MODE_SHADED_WIREFRAME:
+ currender='ShadedWireframe';break;
+ case scene.RENDER_MODE_SOLID:
+ currender='Solid';break;
+ case scene.RENDER_MODE_TRANSPARENT:
+ currender='Transparent';break;
+ case scene.RENDER_MODE_SOLID_WIREFRAME:
+ currender='SolidWireframe';break;
+ case scene.RENDER_MODE_TRANSPARENT_WIREFRAME:
+ currender='TransparentWireframe';break;
+ case scene.RENDER_MODE_ILLUSTRATION:
+ currender='Illustration';break;
+ case scene.RENDER_MODE_SOLID_OUTLINE:
+ currender='SolidOutline';break;
+ case scene.RENDER_MODE_SHADED_ILLUSTRATION:
+ currender='ShadedIllustration';break;
+ case scene.RENDER_MODE_HIDDEN_WIREFRAME:
+ currender='HiddenWireframe';break;
+ //case scene.RENDER_MODE_DEFAULT:
+ // currender='Default';break;
+ }
+ if(currender!=defaultrender){
+ respart+=' RENDERMODE='+currender+'\n';
+ defaultvals=false;
+ }
+ if(!mesh.transform.isEqual(origtrans[mesh.name])){
+ var lvec=mesh.transform.transformDirection(new Vector3(1,0,0));
+ var uvec=mesh.transform.transformDirection(new Vector3(0,1,0));
+ var vvec=mesh.transform.transformDirection(new Vector3(0,0,1));
+ respart+=' TRANSFORM='
+ +(Math.abs(lvec.x) < 1e-12 ? 0 : lvec.x)+' '
+ +(Math.abs(lvec.y) < 1e-12 ? 0 : lvec.y)+' '
+ +(Math.abs(lvec.z) < 1e-12 ? 0 : lvec.z)+' '
+ +(Math.abs(uvec.x) < 1e-12 ? 0 : uvec.x)+' '
+ +(Math.abs(uvec.y) < 1e-12 ? 0 : uvec.y)+' '
+ +(Math.abs(uvec.z) < 1e-12 ? 0 : uvec.z)+' '
+ +(Math.abs(vvec.x) < 1e-12 ? 0 : vvec.x)+' '
+ +(Math.abs(vvec.y) < 1e-12 ? 0 : vvec.y)+' '
+ +(Math.abs(vvec.z) < 1e-12 ? 0 : vvec.z)+' '
+ +(Math.abs(mesh.transform.translation.x) < 1e-12 ? 0 : mesh.transform.translation.x)+' '
+ +(Math.abs(mesh.transform.translation.y) < 1e-12 ? 0 : mesh.transform.translation.y)+' '
+ +(Math.abs(mesh.transform.translation.z) < 1e-12 ? 0 : mesh.transform.translation.z)+'\n';
+ defaultvals=false;
+ }
+ respart+=' END\n';
+ if(!defaultvals) res+=respart;
+ }
+
+ //detect existing Clipping Plane (3DCrossSection)
+ var clip=null;
+ try {
+ clip=scene.nodes.getByName("Clipping Plane");
+ }catch(e){
+ var ndcnt=scene.nodes.count;
+ clip=scene.createClippingPlane();
+ if(ndcnt!=scene.nodes.count){
+ clip.remove();
+ clip=null;
+ }
+ }
+ if(clip){
+ var centre=clip.transform.translation;
+ var normal=clip.transform.transformDirection(new Vector3(0,0,1));
+ res+=' CROSSSECT\n';
+ var x = (Math.abs(centre.x) < 1e-12 ? 0 : centre.x);
+ var y = (Math.abs(centre.y) < 1e-12 ? 0 : centre.y);
+ var z = (Math.abs(centre.z) < 1e-12 ? 0 : centre.z);
+ if(!(x==0 && y==0 && z==0))
+ res+=host.util.printf(' CENTER=%s %s %s\n', x, y, z);
+ var x = (Math.abs(normal.x) < 1e-12 ? 0 : normal.x);
+ var y = (Math.abs(normal.y) < 1e-12 ? 0 : normal.y);
+ var z = (Math.abs(normal.z) < 1e-12 ? 0 : normal.z);
+ if(!(x==1 && y==0 && z==0))
+ res+=host.util.printf(' NORMAL=%s %s %s\n', x, y, z);
+ res+=' END\n';
+ }
+ res+='END\n';
+ host.console.show();
+// host.console.clear();
+ host.console.println('%%\n%% Add the following VIEW section to a file of\n'+
+ '%% predefined views (See option "3Dviews"!).\n%%\n' +
+ '%% The view may be given a name after VIEW=...\n' +
+ '%% (Remove \'%\' in front of \'=\'.)\n%%');
+ host.console.println(res + '\n');
+}
+
+//add items to 3D context menu
+runtime.addCustomMenuItem("dfltview", "Generate Default View", "default", 0);
+runtime.addCustomMenuItem("currview", "Get Current View", "default", 0);
+runtime.addCustomMenuItem("csection", "Cross Section", "checked", 0);
+
+//menu event handlers
+menuEventHandler = new MenuEventHandler();
+menuEventHandler.onEvent = function(e) {
+ switch(e.menuItemName){
+ case "dfltview": calc3Dopts(); break;
+ case "currview": get3Dview(); break;
+ case "csection":
+ addremoveClipPlane(e.menuItemChecked);
+ break;
+ }
+};
+runtime.addEventHandler(menuEventHandler);
+
+//global variable taking reference to currently selected mesh node;
+var mshSelected=null;
+selectionEventHandler=new SelectionEventHandler();
+selectionEventHandler.onEvent=function(e){
+ if(e.selected && e.node.constructor.name=="Mesh"){
+ mshSelected=e.node;
+ }else{
+ mshSelected=null;
+ }
+}
+runtime.addEventHandler(selectionEventHandler);
+
+cameraEventHandler=new CameraEventHandler();
+cameraEventHandler.onEvent=function(e){
+ //store current transformation matrices of all mesh nodes in the scene
+ var curtrans=getCurTrans();
+ //detect existing clipping plane (cross section)
+ var ndcnt=scene.nodes.count;
+ var clip=scene.createClippingPlane();
+ if(ndcnt!=scene.nodes.count){
+ clip.remove();
+ runtime.removeCustomMenuItem("csection");
+ runtime.addCustomMenuItem("csection", "Cross Section", "checked", 0);
+ } else {
+ runtime.removeCustomMenuItem("csection");
+ runtime.addCustomMenuItem("csection", "Cross Section", "checked", 1);
+ }
+ //restore previous position of mesh nodes
+ restoreTrans(curtrans);
+}
+runtime.addEventHandler(cameraEventHandler);
+
+//key event handler for moving, spinning and tilting objects
+keyEventHandler=new KeyEventHandler();
+keyEventHandler.onEvent=function(e){
+ var target=null;
+ var backtrans=new Matrix4x4();
+ if(mshSelected){
+ target=mshSelected;
+ var trans=target.transform;
+ var parent=target.parent;
+ while(parent.transform){
+ //build local to world transformation matrix
+ trans.multiplyInPlace(parent.transform);
+ //also build world to local back-transformation matrix
+ backtrans.multiplyInPlace(parent.transform.inverse.transpose);
+ parent=parent.parent;
+ }
+ backtrans.transposeInPlace();
+ }else{
+ try {
+ target=scene.nodes.getByName("Clipping Plane");
+ }catch(e){
+ var ndcnt=scene.nodes.count;
+ target=scene.createClippingPlane();
+ if(ndcnt!=scene.nodes.count){
+ target.remove();
+ target=null;
+ }
+ }
+ }
+ if(!target) return;
+ switch(e.characterCode){
+ case 30://tilt up
+ tiltTarget(target, -Math.PI/900);
+ break;
+ case 31://tilt down
+ tiltTarget(target, Math.PI/900);
+ break;
+ case 28://spin right
+ spinTarget(target, -Math.PI/900);
+ break;
+ case 29://spin left
+ spinTarget(target, Math.PI/900);
+ break;
+ case 120: //x
+ translateTarget(target, new Vector3(1,0,0), e);
+ break;
+ case 121: //y
+ translateTarget(target, new Vector3(0,1,0), e);
+ break;
+ case 122: //z
+ translateTarget(target, new Vector3(0,0,1), e);
+ break;
+ case 88: //shift + x
+ translateTarget(target, new Vector3(-1,0,0), e);
+ break;
+ case 89: //shift + y
+ translateTarget(target, new Vector3(0,-1,0), e);
+ break;
+ case 90: //shift + z
+ translateTarget(target, new Vector3(0,0,-1), e);
+ break;
+ case 115: //s
+ scaleTarget(target, 1, e);
+ break;
+ case 83: //shift + s
+ scaleTarget(target, -1, e);
+ break;
+ }
+ if(mshSelected)
+ target.transform.multiplyInPlace(backtrans);
+}
+runtime.addEventHandler(keyEventHandler);
+
+function tiltTarget(t,a){
+ var centre=new Vector3();
+ if(mshSelected) {
+ centre.set(t.transform.transformPosition(t.computeBoundingBox().center));
+ }else{
+ centre.set(t.transform.translation);
+ }
+ var rotVec=t.transform.transformDirection(new Vector3(0,1,0));
+ rotVec.normalize();
+ t.transform.translateInPlace(centre.scale(-1));
+ t.transform.rotateAboutVectorInPlace(a, rotVec);
+ t.transform.translateInPlace(centre);
+}
+
+function spinTarget(t,a){
+ var centre=new Vector3();
+ var rotVec=new Vector3(0,0,1);
+ if(mshSelected) {
+ centre.set(t.transform.transformPosition(t.computeBoundingBox().center));
+ rotVec.set(t.transform.transformDirection(rotVec));
+ rotVec.normalize();
+ }else{
+ centre.set(t.transform.translation);
+ }
+ t.transform.translateInPlace(centre.scale(-1));
+ t.transform.rotateAboutVectorInPlace(a, rotVec);
+ t.transform.translateInPlace(centre);
+}
+
+//translates object by amount calculated based on Canvas size
+function translateTarget(t, d, e){
+ var cam=scene.cameras.getByIndex(0);
+ if(cam.projectionType==cam.TYPE_PERSPECTIVE){
+ var scale=Math.tan(cam.fov/2)
+ *cam.targetPosition.subtract(cam.position).length
+ /Math.min(e.canvasPixelWidth,e.canvasPixelHeight);
+ }else{
+ var scale=cam.viewPlaneSize/2
+ /Math.min(e.canvasPixelWidth,e.canvasPixelHeight);
+ }
+ t.transform.translateInPlace(d.scale(scale));
+}
+
+//scales object by amount calculated based on Canvas size
+function scaleTarget(t, d, e){
+ if(mshSelected) {
+ var bbox=t.computeBoundingBox();
+ var diag=new Vector3(bbox.max.x, bbox.max.y, bbox.max.z);
+ diag.subtractInPlace(bbox.min);
+ var dlen=diag.length;
+
+ var cam=scene.cameras.getByIndex(0);
+ if(cam.projectionType==cam.TYPE_PERSPECTIVE){
+ var scale=Math.tan(cam.fov/2)
+ *cam.targetPosition.subtract(cam.position).length
+ /dlen
+ /Math.min(e.canvasPixelWidth,e.canvasPixelHeight);
+ }else{
+ var scale=cam.viewPlaneSize/2
+ /dlen
+ /Math.min(e.canvasPixelWidth,e.canvasPixelHeight);
+ }
+ var centre=new Vector3();
+ centre.set(t.transform.transformPosition(t.computeBoundingBox().center));
+ t.transform.translateInPlace(centre.scale(-1));
+ t.transform.scaleInPlace(1+d*scale);
+ t.transform.translateInPlace(centre);
+ }
+}
+
+function addremoveClipPlane(chk) {
+ var clip=scene.createClippingPlane();
+ if(chk){
+ //add Clipping Plane and place its center either into the camera target
+ //position or into the centre of the currently selected mesh node
+ var centre=new Vector3();
+ if(mshSelected){
+ //local to parent transformation matrix
+ var trans=mshSelected.transform;
+ //build local to world transformation matrix by recursively
+ //multiplying the parent's transf. matrix on the right
+ var parent=mshSelected.parent;
+ while(parent.transform){
+ trans=trans.multiply(parent.transform);
+ parent=parent.parent;
+ }
+ //get the centre of the mesh (local coordinates)
+ centre.set(mshSelected.computeBoundingBox().center);
+ //transform the local coordinates to world coords
+ centre.set(trans.transformPosition(centre));
+ mshSelected=null;
+ }else{
+ centre.set(scene.cameras.getByIndex(0).targetPosition);
+ }
+ clip.transform.setView(
+ new Vector3(0,0,0), new Vector3(1,0,0), new Vector3(0,1,0));
+ clip.transform.translateInPlace(centre);
+ }else{
+ clip.remove();
+ }
+}
+
+//function to store current transformation matrix of all mesh nodes in the scene
+function getCurTrans() {
+ var nc=scene.meshes.count;
+ var tA=new Array(nc);
+ for(var i=0; i<nc; i++){
+ var cm=scene.meshes.getByIndex(i);
+ tA[cm.name]=new Matrix4x4(cm.transform);
+ }
+ return tA;
+}
+
+//function to restore transformation matrices given as arg
+function restoreTrans(tA) {
+ for(var i=0; i<tA.length; i++){
+ var msh=scene.meshes.getByIndex(i);
+ msh.transform.set(tA[msh.name]);
+ }
+}
+
+//store original transformation matrix of all mesh nodes in the scene
+var origtrans=getCurTrans();
+
+//set initial state of "Cross Section" menu entry
+cameraEventHandler.onEvent(1);
+
+//host.console.clear();