00001
00002
00003
00004 (function( factory ) {
00005 if ( typeof define === "function" && define.amd ) {
00006
00007 define( [ 'd3', 'JSRootPainter', 'JSRoot3DPainter', 'ThreeCSG' ], factory );
00008 } else {
00009
00010 if (typeof JSROOT == 'undefined')
00011 throw new Error('JSROOT is not defined', 'JSRootGeoPainter.js');
00012
00013 if (typeof JSROOT.Painter != 'object')
00014 throw new Error('JSROOT.Painter is not defined', 'JSRootGeoPainter.js');
00015
00016 if (typeof d3 == 'undefined')
00017 throw new Error('d3 is not defined', 'JSRootGeoPainter.js');
00018
00019 if (typeof THREE == 'undefined')
00020 throw new Error('THREE is not defined', 'JSRootGeoPainter.js');
00021
00022 factory( d3, JSROOT);
00023 }
00024 } (function( d3, JSROOT ) {
00025
00026 if ( typeof define === "function" && define.amd )
00027 JSROOT.loadScript('$$$style/JSRootGeoPainter.css');
00028
00029
00030
00031 JSROOT.GEO = {};
00032
00033 JSROOT.GEO.createCube = function( shape ) {
00034
00035
00036
00037
00038
00039
00040 var geom = new THREE.Geometry();
00041
00042 geom.vertices.push( new THREE.Vector3( shape.fDX, shape.fDY, shape.fDZ ) );
00043 geom.vertices.push( new THREE.Vector3( shape.fDX, shape.fDY, -shape.fDZ ) );
00044 geom.vertices.push( new THREE.Vector3( shape.fDX, -shape.fDY, shape.fDZ ) );
00045 geom.vertices.push( new THREE.Vector3( shape.fDX, -shape.fDY, -shape.fDZ ) );
00046 geom.vertices.push( new THREE.Vector3(-shape.fDX, shape.fDY, -shape.fDZ ) );
00047 geom.vertices.push( new THREE.Vector3(-shape.fDX, shape.fDY, shape.fDZ ) );
00048 geom.vertices.push( new THREE.Vector3(-shape.fDX, -shape.fDY, -shape.fDZ ) );
00049 geom.vertices.push( new THREE.Vector3(-shape.fDX, -shape.fDY, shape.fDZ ) );
00050
00051 var indicies = [0,2,1, 2,3,1, 4,6,5, 6,7,5, 4,5,1, 5,0,1, 7,6,2, 6,3,2, 5,7,0, 7,2,0, 1,3,4, 3,6,4];
00052
00053
00054 var normals = [ 1,0,0, -1,0,0, 0,1,0, 0,-1,0, 0,0,1, 0,0,-1 ];
00055
00056 var color = new THREE.Color();
00057 var norm = null;
00058 for (var n=0; n < indicies.length; n+=3) {
00059 if (n % 6 === 0) norm = new THREE.Vector3(normals[n/2], normals[n/2+1], normals[n/2+2]);
00060 var face = new THREE.Face3( indicies[n], indicies[n+1], indicies[n+2], norm, color, 0);
00061 geom.faces.push(face);
00062 }
00063
00064 return geom;
00065
00066 }
00067
00068 JSROOT.GEO.createPara = function( shape ) {
00069
00070 var txy = shape.fTxy, txz = shape.fTxz, tyz = shape.fTyz;
00071
00072 var verticesOfShape = [
00073 -shape.fZ*txz-txy*shape.fY-shape.fX, -shape.fY-shape.fZ*tyz, -shape.fZ,
00074 -shape.fZ*txz+txy*shape.fY-shape.fX, shape.fY-shape.fZ*tyz, -shape.fZ,
00075 -shape.fZ*txz+txy*shape.fY+shape.fX, shape.fY-shape.fZ*tyz, -shape.fZ,
00076 -shape.fZ*txz-txy*shape.fY+shape.fX, -shape.fY-shape.fZ*tyz, -shape.fZ,
00077 shape.fZ*txz-txy*shape.fY-shape.fX, -shape.fY+shape.fZ*tyz, shape.fZ,
00078 shape.fZ*txz+txy*shape.fY-shape.fX, shape.fY+shape.fZ*tyz, shape.fZ,
00079 shape.fZ*txz+txy*shape.fY+shape.fX, shape.fY+shape.fZ*tyz, shape.fZ,
00080 shape.fZ*txz-txy*shape.fY+shape.fX, -shape.fY+shape.fZ*tyz, shape.fZ ];
00081
00082 var indicesOfFaces = [ 4,6,5, 4,7,6, 0,3,7, 7,4,0,
00083 4,5,1, 1,0,4, 6,2,1, 1,5,6,
00084 7,3,2, 2,6,7, 1,2,3, 3,0,1 ];
00085
00086 var geom = new THREE.Geometry();
00087
00088 for (var i = 0; i < verticesOfShape.length; i += 3)
00089 geom.vertices.push( new THREE.Vector3( verticesOfShape[i], verticesOfShape[i+1], verticesOfShape[i+2] ) );
00090
00091 var color = new THREE.Color();
00092
00093 for (var i = 0; i < indicesOfFaces.length; i += 3)
00094 geom.faces.push( new THREE.Face3( indicesOfFaces[i], indicesOfFaces[i+1], indicesOfFaces[i+2], null, color, 0 ) );
00095
00096 geom.computeFaceNormals();
00097
00098 return geom;
00099 }
00100
00101
00102 JSROOT.GEO.createTrapezoid = function( shape ) {
00103
00104 var y1, y2;
00105 if (shape._typename == "TGeoTrd1") {
00106 y1 = y2 = shape.fDY;
00107 } else {
00108 y1 = shape.fDy1; y2 = shape.fDy2;
00109 }
00110
00111 var verticesOfShape = [
00112 -shape.fDx1, y1, -shape.fDZ,
00113 shape.fDx1, y1, -shape.fDZ,
00114 shape.fDx1, -y1, -shape.fDZ,
00115 -shape.fDx1, -y1, -shape.fDZ,
00116 -shape.fDx2, y2, shape.fDZ,
00117 shape.fDx2, y2, shape.fDZ,
00118 shape.fDx2, -y2, shape.fDZ,
00119 -shape.fDx2, -y2, shape.fDZ
00120 ];
00121
00122 var indicesOfFaces = [
00123 4,6,5, 4,7,6, 0,3,7, 7,4,0,
00124 4,5,1, 1,0,4, 6,2,1, 1,5,6,
00125 7,3,2, 2,6,7, 1,2,3, 3,0,1 ];
00126
00127 var geometry = new THREE.Geometry();
00128 for (var i = 0; i < 24; i += 3)
00129 geometry.vertices.push( new THREE.Vector3( verticesOfShape[i], verticesOfShape[i+1], verticesOfShape[i+2] ) );
00130
00131 var color = new THREE.Color();
00132
00133 for (var i = 0; i < 36; i += 3)
00134 geometry.faces.push( new THREE.Face3( indicesOfFaces[i], indicesOfFaces[i+1], indicesOfFaces[i+2], null, color, 0 ) );
00135
00136 geometry.computeFaceNormals();
00137 return geometry;
00138 }
00139
00140
00141 JSROOT.GEO.createArb8 = function( shape ) {
00142
00143 var verticesOfShape = [
00144 shape.fXY[0][0], shape.fXY[0][1], -shape.fDZ,
00145 shape.fXY[1][0], shape.fXY[1][1], -shape.fDZ,
00146 shape.fXY[2][0], shape.fXY[2][1], -shape.fDZ,
00147 shape.fXY[3][0], shape.fXY[3][1], -shape.fDZ,
00148 shape.fXY[4][0], shape.fXY[4][1], shape.fDZ,
00149 shape.fXY[5][0], shape.fXY[5][1], shape.fDZ,
00150 shape.fXY[6][0], shape.fXY[6][1], shape.fDZ,
00151 shape.fXY[7][0], shape.fXY[7][1], shape.fDZ
00152 ];
00153
00154 var indicies = [];
00155
00156 var indicesOfFaces = [
00157 4,6,5, 4,7,6, 0,3,7, 7,4,0,
00158 4,5,1, 1,0,4, 6,2,1, 1,5,6,
00159 7,3,2, 2,6,7, 1,2,3, 3,0,1 ];
00160
00161 var geometry = new THREE.Geometry();
00162 for (var i = 0; i < 8; ++i) {
00163 var ii = i*3;
00164 if ((i>0) && (verticesOfShape[ii] === verticesOfShape[ii-3]) &&
00165 (verticesOfShape[ii+1] === verticesOfShape[ii-2]) &&
00166 (verticesOfShape[ii+2] === verticesOfShape[ii-1])) {
00167 indicies[i] = indicies[i-1];
00168 continue;
00169 }
00170
00171 indicies[i] = geometry.vertices.length;
00172
00173 geometry.vertices.push( new THREE.Vector3( verticesOfShape[ii], verticesOfShape[ii+1], verticesOfShape[ii+2] ) );
00174 }
00175
00176 var color = new THREE.Color();
00177
00178 for (var i = 0; i < 36; i += 3) {
00179 var a = indicies[indicesOfFaces[i]],
00180 b = indicies[indicesOfFaces[i+1]],
00181 c = indicies[indicesOfFaces[i+2]];
00182 if ((a!==b) && (b!==c) && (a!==c))
00183 geometry.faces.push( new THREE.Face3( a, b, c, null, color, 0 ) );
00184 }
00185
00186 geometry.computeFaceNormals();
00187 return geometry;
00188 }
00189
00190
00191 JSROOT.GEO.createSphere = function( shape, faces_limit ) {
00192 var outerRadius = shape.fRmax;
00193 var innerRadius = shape.fRmin;
00194 var phiStart = shape.fPhi1 + 180;
00195 var phiLength = shape.fPhi2 - shape.fPhi1;
00196 var thetaStart = shape.fTheta1;
00197 var thetaLength = shape.fTheta2 - shape.fTheta1;
00198 var widthSegments = shape.fNseg;
00199 var heightSegments = shape.fNz;
00200
00201 var noInside = (innerRadius <= 0);
00202
00203 if (faces_limit !== undefined) {
00204 var fact = (noInside ? 2 : 4) * widthSegments * heightSegments / faces_limit;
00205 if (fact > 1.) {
00206 widthSegments = Math.round(widthSegments/Math.sqrt(fact));
00207 heightSegments = Math.round(heightSegments/Math.sqrt(fact));
00208 }
00209 }
00210
00211 var sphere = new THREE.SphereGeometry( outerRadius, widthSegments, heightSegments,
00212 phiStart*Math.PI/180, phiLength*Math.PI/180, thetaStart*Math.PI/180, thetaLength*Math.PI/180);
00213 sphere.applyMatrix( new THREE.Matrix4().makeRotationX( Math.PI / 2 ) );
00214
00215 var geometry = new THREE.Geometry();
00216 var color = new THREE.Color();
00217
00218
00219 for (var n=0; n < sphere.vertices.length; ++n)
00220 geometry.vertices.push(sphere.vertices[n]);
00221
00222
00223 for (var n=0; n < sphere.faces.length; ++n) {
00224 var face = sphere.faces[n];
00225 geometry.faces.push(new THREE.Face3( face.a, face.b, face.c, null, color, 0 ) );
00226 }
00227
00228 var shift = geometry.vertices.length;
00229
00230 if (noInside) {
00231
00232 if ((thetaLength === 180) && (phiLength === 360)) {
00233 geometry.computeFaceNormals();
00234 return geometry;
00235 }
00236
00237 geometry.vertices.push(new THREE.Vector3(0, 0, 0));
00238 } else {
00239 var k = innerRadius / outerRadius;
00240
00241
00242 for (var n=0; n < sphere.vertices.length; ++n) {
00243 var v = sphere.vertices[n];
00244 geometry.vertices.push(new THREE.Vector3(k*v.x, k*v.y, k*v.z));
00245 }
00246 for (var n=0; n < sphere.faces.length; ++n) {
00247 var face = sphere.faces[n];
00248 geometry.faces.push(new THREE.Face3( shift+face.b, shift+face.a, shift+face.c, null, color, 0 ) );
00249 }
00250 }
00251
00252 if (thetaLength !== 180) {
00253
00254 for (var i = 0; i < widthSegments; ++i) {
00255 if (noInside) {
00256 geometry.faces.push( new THREE.Face3( i+0, i+1, shift, null, color, 0 ) );
00257 } else {
00258 geometry.faces.push( new THREE.Face3( i+0, i+1, i+shift, null, color, 0 ) );
00259 geometry.faces.push( new THREE.Face3( i+1, i+shift+1, i+shift, null, color, 0 ) );
00260 }
00261 }
00262
00263 var dshift = sphere.vertices.length - widthSegments - 1;
00264
00265
00266 for (var i = dshift; i < dshift + widthSegments; ++i) {
00267 if (noInside) {
00268 geometry.faces.push( new THREE.Face3( i+0, i+1, shift, null, color, 0 ) );
00269 } else {
00270 geometry.faces.push( new THREE.Face3( i+1, i+0, i+shift, null, color, 0 ) );
00271 geometry.faces.push( new THREE.Face3( i+shift+1, i+1, i+shift, null, color, 0 ) );
00272 }
00273 }
00274 }
00275
00276 if (phiLength !== 360) {
00277
00278 for (var j=0; j<heightSegments; j++) {
00279 var i1 = j*(widthSegments+1);
00280 var i2 = (j+1)*(widthSegments+1);
00281 if (noInside) {
00282 geometry.faces.push( new THREE.Face3( i1, i2, shift, null, color, 0 ) );
00283 } else {
00284 geometry.faces.push( new THREE.Face3( i2, i1, i1+shift, null, color, 0 ) );
00285 geometry.faces.push( new THREE.Face3( i2+shift, i2, i1+shift, null, color, 0 ));
00286 }
00287 }
00288
00289 for (var j=0;j<heightSegments;j++) {
00290 var i1 = (j+1)*(widthSegments+1) - 1;
00291 var i2 = (j+2)*(widthSegments+1) - 1;
00292 if (noInside) {
00293 geometry.faces.push( new THREE.Face3( i1, i2, shift, null, color, 0 ) );
00294 } else {
00295 geometry.faces.push( new THREE.Face3( i1, i2, i1+shift, null, color, 0 ) );
00296 geometry.faces.push( new THREE.Face3( i2, i2+shift, i1+shift, null, color, 0));
00297 }
00298 }
00299 }
00300
00301 geometry.computeFaceNormals();
00302
00303 return geometry;
00304 }
00305
00306
00307 JSROOT.GEO.createTube = function( shape ) {
00308 var outerRadius1, innerRadius1, outerRadius2, innerRadius2;
00309 if ((shape._typename == "TGeoCone") || (shape._typename == "TGeoConeSeg")) {
00310 outerRadius1 = shape.fRmax2;
00311 innerRadius1 = shape.fRmin2;
00312 outerRadius2 = shape.fRmax1;
00313 innerRadius2 = shape.fRmin1;
00314 } else {
00315 outerRadius1 = outerRadius2 = shape.fRmax;
00316 innerRadius1 = innerRadius2 = shape.fRmin;
00317 }
00318
00319 var hasrmin = (innerRadius1 > 0) || (innerRadius2 > 0);
00320
00321 if (hasrmin) {
00322 if (innerRadius1 <= 0) { innerRadius1 = 0.0000001; console.warn('zero inner radius1 in tube - not yet supported'); }
00323 if (innerRadius2 <= 0) { innerRadius2 = 0.0000001; console.warn('zero inner radius1 in tube - not yet supported'); }
00324 }
00325
00326 var thetaStart = 0, thetaLength = 360;
00327 if ((shape._typename == "TGeoConeSeg") || (shape._typename == "TGeoTubeSeg") || (shape._typename == "TGeoCtub")) {
00328 thetaStart = shape.fPhi1;
00329 thetaLength = shape.fPhi2 - shape.fPhi1;
00330 }
00331
00332 var radiusSegments = Math.floor(thetaLength/6);
00333 if (radiusSegments < 4) radiusSegments = 4;
00334
00335 var extrapnt = (thetaLength < 360) ? 1 : 0;
00336
00337 var nsegm = radiusSegments + extrapnt;
00338
00339 var phi0 = thetaStart*Math.PI/180, dphi = thetaLength/radiusSegments*Math.PI/180;
00340
00341
00342 var _sin = new Float32Array(nsegm), _cos = new Float32Array(nsegm);
00343 for (var seg=0; seg<nsegm; ++seg) {
00344 _cos[seg] = Math.cos(phi0+seg*dphi);
00345 _sin[seg] = Math.sin(phi0+seg*dphi);
00346 }
00347
00348 var geometry = new THREE.Geometry();
00349
00350
00351
00352 if (hasrmin) {
00353 for (var seg=0; seg<nsegm; ++seg)
00354 geometry.vertices.push( new THREE.Vector3( innerRadius1*_cos[seg], innerRadius1*_sin[seg], shape.fDZ));
00355 for (var seg=0; seg<nsegm; ++seg)
00356 geometry.vertices.push( new THREE.Vector3( innerRadius2*_cos[seg], innerRadius2*_sin[seg], -shape.fDZ));
00357 } else {
00358 geometry.vertices.push( new THREE.Vector3( 0, 0, shape.fDZ));
00359 geometry.vertices.push( new THREE.Vector3( 0, 0, -shape.fDZ));
00360 }
00361
00362 var shift = geometry.vertices.length;
00363
00364
00365 for (var seg=0; seg<nsegm; ++seg)
00366 geometry.vertices.push( new THREE.Vector3( outerRadius1*_cos[seg], outerRadius1*_sin[seg], shape.fDZ));
00367 for (var seg=0; seg<nsegm; ++seg)
00368 geometry.vertices.push( new THREE.Vector3( outerRadius2*_cos[seg], outerRadius2*_sin[seg], -shape.fDZ));
00369
00370
00371 if (shape._typename == "TGeoCtub")
00372 for (var n=0;n<geometry.vertices.length;++n) {
00373 var vertex = geometry.vertices[n];
00374 if (vertex.z<0) vertex.z = -shape.fDz-(vertex.x*shape.fNlow[0]+vertex.x*shape.fNlow[1])/shape.fNlow[2];
00375 else vertex.z = shape.fDz-(vertex.y*shape.fNhigh[0]+vertex.y*shape.fNhigh[1])/shape.fNhigh[2];
00376 }
00377
00378 var color = new THREE.Color();
00379
00380
00381 if (hasrmin)
00382 for (var seg=0; seg<radiusSegments; ++seg) {
00383 var seg1 = (extrapnt === 1) ? (seg + 1) : (seg + 1) % radiusSegments;
00384 geometry.faces.push( new THREE.Face3( nsegm + seg, seg, seg1, null, color, 0 ) );
00385 geometry.faces.push( new THREE.Face3( nsegm + seg, seg1, nsegm + seg1, null, color, 0 ) );
00386 }
00387
00388
00389 for (var seg=0; seg<radiusSegments; ++seg) {
00390 var seg1 = (extrapnt === 1) ? (seg + 1) : (seg + 1) % radiusSegments;
00391 geometry.faces.push( new THREE.Face3( shift+seg, shift + nsegm + seg, shift + seg1, null, color, 0 ) );
00392 geometry.faces.push( new THREE.Face3( shift + nsegm + seg, shift + nsegm + seg1, shift + seg1, null, color, 0 ) );
00393 }
00394
00395
00396
00397 for (var i = 0; i < radiusSegments; ++i){
00398 var i1 = (extrapnt === 1) ? (i+1) : (i+1) % radiusSegments;
00399 if (hasrmin) {
00400 geometry.faces.push( new THREE.Face3( i, i+shift, i1, null, color, 0 ) );
00401 geometry.faces.push( new THREE.Face3( i+shift, i1+shift, i1, null, color, 0 ) );
00402 } else {
00403 geometry.faces.push( new THREE.Face3( 0, i+shift, i1+shift, null, color, 0 ) );
00404 }
00405 }
00406
00407
00408 for (var i = 0; i < radiusSegments; ++i) {
00409 var i1 = (extrapnt === 1) ? (i+1) : (i+1) % radiusSegments;
00410 if (hasrmin) {
00411 geometry.faces.push( new THREE.Face3( nsegm+i+shift, nsegm+i, nsegm+i1, null, color, 0 ) );
00412 geometry.faces.push( new THREE.Face3( nsegm+i+shift, nsegm+i1, nsegm+i1+shift, null, color, 0 ) );
00413 } else {
00414 geometry.faces.push( new THREE.Face3( nsegm+i+shift, 1, nsegm+i1+shift, null, color, 0 ) );
00415 }
00416 }
00417
00418
00419 if (extrapnt === 1) {
00420 if (hasrmin) {
00421 geometry.faces.push( new THREE.Face3( 0, nsegm, shift+nsegm, null, color, 0 ) );
00422 geometry.faces.push( new THREE.Face3( 0, shift+nsegm, shift, null, color, 0 ) );
00423 } else {
00424 geometry.faces.push( new THREE.Face3( 0, 1, shift+nsegm, null, color, 0 ) );
00425 geometry.faces.push( new THREE.Face3( 0, shift+nsegm, shift, null, color, 0 ) );
00426 }
00427
00428 if (hasrmin) {
00429 geometry.faces.push( new THREE.Face3( radiusSegments, shift+2*radiusSegments+1, 2*radiusSegments+1, null, color, 0 ) );
00430 geometry.faces.push( new THREE.Face3( radiusSegments, shift + radiusSegments, shift+2*radiusSegments+1, null, color, 0 ) );
00431 } else {
00432 geometry.faces.push( new THREE.Face3( 0, shift+2*radiusSegments+1, 1, null, color, 0 ) );
00433 geometry.faces.push( new THREE.Face3( 0, shift + radiusSegments, shift+2*radiusSegments+1, null, color, 0 ) );
00434 }
00435 }
00436
00437 geometry.computeFaceNormals();
00438
00439 return geometry;
00440 }
00441
00442
00443 JSROOT.GEO.createEltu = function( shape ) {
00444 var geometry = new THREE.Geometry();
00445
00446 var radiusSegments = Math.floor(360/6);
00447
00448
00449 var x = new Float32Array(radiusSegments),
00450 y = new Float32Array(radiusSegments);
00451 for (var seg=0; seg<radiusSegments; ++seg) {
00452 var phi = seg/radiusSegments*2*Math.PI;
00453 x[seg] = shape.fRmin*Math.cos(phi);
00454 y[seg] = shape.fRmax*Math.sin(phi);
00455 }
00456
00457
00458 for (var seg=0; seg<radiusSegments; ++seg)
00459 geometry.vertices.push( new THREE.Vector3( x[seg], y[seg], -shape.fDZ));
00460 geometry.vertices.push( new THREE.Vector3( 0, 0, -shape.fDZ));
00461
00462 for (var seg=0; seg<radiusSegments; ++seg)
00463 geometry.vertices.push( new THREE.Vector3( x[seg], y[seg], +shape.fDZ));
00464 geometry.vertices.push( new THREE.Vector3( 0, 0, shape.fDZ));
00465
00466 var color = new THREE.Color();
00467
00468
00469 for (var seg=0; seg<radiusSegments; ++seg) {
00470 var seg1 = (seg + 1) % radiusSegments;
00471 geometry.faces.push( new THREE.Face3( seg+radiusSegments+1, seg, seg1, null, color, 0 ) );
00472 geometry.faces.push( new THREE.Face3( seg+radiusSegments+1, seg1, seg1+radiusSegments+1, null, color, 0 ) );
00473 }
00474
00475
00476 for (var seg=0; seg<radiusSegments; ++seg)
00477 geometry.faces.push( new THREE.Face3( seg, radiusSegments, (seg + 1) % radiusSegments, null, color, 0 ));
00478
00479
00480 var shift = radiusSegments + 1;
00481 for (var seg=0; seg<radiusSegments; ++seg)
00482 geometry.faces.push( new THREE.Face3( shift+seg, shift+ (seg + 1) % radiusSegments, shift+radiusSegments, null, color, 0 ));
00483
00484 geometry.computeFaceNormals();
00485 return geometry;
00486 }
00487
00488
00489 JSROOT.GEO.createTorus = function( shape, faces_limit ) {
00490 var radius = shape.fR;
00491 var innerTube = shape.fRmin;
00492 var outerTube = shape.fRmax;
00493 var arc = shape.fDphi - shape.fPhi1;
00494 var rotation = shape.fPhi1;
00495 var radialSegments = 30;
00496 var tubularSegments = Math.floor(arc/6);
00497 if (tubularSegments < 8) tubularSegments = 8;
00498
00499 var hasrmin = innerTube > 0, hascut = arc !== 360;
00500
00501 if (faces_limit !== undefined) {
00502 var fact = (hasrmin ? 4 : 2) * (radialSegments + 1) * tubularSegments / faces_limit;
00503 if (fact > 1.) {
00504 radialSegments = Math.round(radialSegments/Math.sqrt(fact));
00505 tubularSegments = Math.round(tubularSegments/Math.sqrt(fact));
00506 }
00507 }
00508
00509 var geometry = new THREE.Geometry();
00510 var color = new THREE.Color();
00511
00512 var outerTorus = new THREE.TorusGeometry( radius, outerTube, radialSegments, tubularSegments, arc*Math.PI/180);
00513 outerTorus.applyMatrix( new THREE.Matrix4().makeRotationZ(rotation*Math.PI/180) );
00514
00515
00516 for (var n=0; n < outerTorus.vertices.length; ++n)
00517 geometry.vertices.push(outerTorus.vertices[n]);
00518
00519 for (var n=0; n < outerTorus.faces.length; ++n) {
00520 var face = outerTorus.faces[n];
00521 geometry.faces.push(new THREE.Face3( face.a, face.b, face.c, null, color, 0 ) );
00522 }
00523
00524 var shift = geometry.vertices.length;
00525
00526 if (hasrmin) {
00527 var innerTorus = new THREE.TorusGeometry( radius, innerTube, radialSegments, tubularSegments, arc*Math.PI/180);
00528 innerTorus.applyMatrix( new THREE.Matrix4().makeRotationZ(rotation*Math.PI/180) );
00529
00530
00531 for (var n=0; n < innerTorus.vertices.length; ++n)
00532 geometry.vertices.push(innerTorus.vertices[n]);
00533
00534 for (var n=0; n < innerTorus.faces.length; ++n) {
00535 var face = innerTorus.faces[n];
00536 geometry.faces.push(new THREE.Face3( shift+face.a, shift+face.c, shift+face.b, null, color, 0 ) );
00537 }
00538 } else
00539 if (hascut) {
00540 geometry.vertices.push(new THREE.Vector3(radius*Math.cos(rotation*Math.PI/180), radius*Math.sin(rotation*Math.PI/180),0));
00541 geometry.vertices.push(new THREE.Vector3(radius*Math.cos((rotation+arc)*Math.PI/180), radius*Math.sin((rotation+arc)*Math.PI/180),0));
00542 }
00543
00544 if (arc !== 360) {
00545
00546 for (var j=0;j<radialSegments;j++) {
00547 var i1 = j*(tubularSegments+1);
00548 var i2 = (j+1)*(tubularSegments+1);
00549 if (hasrmin) {
00550 geometry.faces.push( new THREE.Face3( i2, i1+shift, i1, null, color, 0 ) );
00551 geometry.faces.push( new THREE.Face3( i2, i2+shift, i1+shift, null, color, 0 ));
00552 } else {
00553 geometry.faces.push( new THREE.Face3( shift, i1, i2, null, color, 0 ));
00554 }
00555 }
00556
00557
00558 for (var j=0;j<radialSegments;j++) {
00559 var i1 = (j+1)*(tubularSegments+1)-1;
00560 var i2 = (j+2)*(tubularSegments+1)-1;
00561 if (hasrmin) {
00562 geometry.faces.push( new THREE.Face3( i2, i1, i1+shift, null, color, 0 ) );
00563 geometry.faces.push( new THREE.Face3( i2, i1+shift, i2+shift, null, color, 0 ));
00564 } else {
00565 geometry.faces.push( new THREE.Face3( shift+1, i2, i1, null, color, 0 ));
00566 }
00567 }
00568 }
00569
00570 geometry.computeFaceNormals();
00571
00572 return geometry;
00573 }
00574
00575
00576 JSROOT.GEO.createPolygon = function( shape ) {
00577
00578 var thetaStart = shape.fPhi1, thetaLength = shape.fDphi;
00579
00580 var radiusSegments = 60;
00581 if ( shape._typename == "TGeoPgon" ) {
00582 radiusSegments = shape.fNedges;
00583 } else {
00584 radiusSegments = Math.floor(thetaLength/6);
00585 if (radiusSegments < 4) radiusSegments = 4;
00586 }
00587
00588 var geometry = new THREE.Geometry();
00589
00590 var color = new THREE.Color();
00591
00592 var phi0 = thetaStart*Math.PI/180, dphi = thetaLength/radiusSegments*Math.PI/180;
00593
00594
00595 var _sin = new Float32Array(radiusSegments+1), _cos = new Float32Array(radiusSegments+1);
00596 for (var seg=0;seg<=radiusSegments;++seg) {
00597 _cos[seg] = Math.cos(phi0+seg*dphi);
00598 _sin[seg] = Math.sin(phi0+seg*dphi);
00599 }
00600
00601 var indxs = [[],[]], pnts = null, edges = null;
00602 var layerVerticies = radiusSegments;
00603
00604 if (thetaLength !== 360) {
00605 pnts = [];
00606 edges = [];
00607 layerVerticies+=1;
00608 }
00609
00610 var a,b,c,d,e;
00611
00612 for (var side = 0; side < 2; ++side) {
00613
00614 var rside = (side === 0) ? 'fRmax' : 'fRmin';
00615 var prev_indx = geometry.vertices.length;
00616
00617 for (var layer=0; layer < shape.fNz; ++layer) {
00618
00619 indxs[side][layer] = geometry.vertices.length;
00620
00621
00622 var layerz = shape.fZ[layer], rad = shape[rside][layer];
00623
00624 if ((layer > 0) && (layer < shape.fNz-1)) {
00625 if (((shape.fZ[layer-1] === layerz) && (shape[rside][layer-1] === rad)) ||
00626 ((shape[rside][layer+1] === rad) && (shape[rside][layer-1] === rad))) {
00627
00628
00629
00630 indxs[side][layer] = indxs[side][layer-1];
00631
00632 continue;
00633 }
00634 }
00635
00636 if (rad <= 0.) rad = 0.000001;
00637
00638 var curr_indx = geometry.vertices.length;
00639
00640
00641 for (var seg=0; seg < layerVerticies; ++seg)
00642 geometry.vertices.push( new THREE.Vector3( rad*_cos[seg], rad*_sin[seg], layerz ));
00643
00644 if (pnts !== null) {
00645 if (side === 0) {
00646 pnts.push(new THREE.Vector2(rad, layerz));
00647 edges.push(curr_indx);
00648 } else
00649 if (rad < shape.fRmax[layer]) {
00650 pnts.unshift(new THREE.Vector2(rad, layerz));
00651 edges.unshift(curr_indx);
00652 }
00653 }
00654
00655 if (layer>0)
00656 for (var seg=0;seg < radiusSegments;++seg) {
00657 var seg1 = (seg + 1) % layerVerticies;
00658 geometry.faces.push( new THREE.Face3( prev_indx + seg, (side === 0) ? (prev_indx + seg1) : (curr_indx + seg) , curr_indx + seg1, null, color, 0 ) );
00659 geometry.faces.push( new THREE.Face3( prev_indx + seg, curr_indx + seg1, (side === 0) ? (curr_indx + seg) : prev_indx + seg1, null, color, 0 ));
00660 }
00661
00662 prev_indx = curr_indx;
00663 }
00664 }
00665
00666
00667 for (var layer = 0; layer < shape.fNz; layer+= (shape.fNz-1)) {
00668 if (shape.fRmin[layer] >= shape.fRmax[layer]) continue;
00669 var inside = indxs[1][layer], outside = indxs[0][layer];
00670 for (var seg=0; seg < radiusSegments; ++seg) {
00671 var seg1 = (seg + 1) % layerVerticies;
00672 geometry.faces.push( new THREE.Face3( outside + seg, (layer===0) ? (inside + seg) : (outside + seg1), inside + seg1, null, color, 0 ) );
00673 geometry.faces.push( new THREE.Face3( outside + seg, inside + seg1, (layer===0) ? (outside + seg1) : (inside + seg), null, color, 0 ));
00674 }
00675 }
00676
00677 if (pnts!==null) {
00678 var faces = [];
00679 if (pnts.length === shape.fNz * 2) {
00680
00681 for (var layer = shape.fNz-1; layer>0; --layer) {
00682 if (shape.fZ[layer] === shape.fZ[layer-1]) continue;
00683 var right = 2*shape.fNz - 1 - layer;
00684 faces.push([right, layer - 1, layer]);
00685 faces.push([right, right + 1, layer-1]);
00686 }
00687
00688 } else {
00689
00690 faces = THREE.ShapeUtils.triangulateShape(pnts, []);
00691 }
00692
00693 for (var i = 0; i < faces.length; ++i) {
00694 var f = faces[i];
00695 geometry.faces.push( new THREE.Face3( edges[f[0]], edges[f[1]], edges[f[2]], null, color, 0) );
00696 }
00697 for (var i = 0; i < faces.length; ++i) {
00698 var f = faces[i];
00699 geometry.faces.push( new THREE.Face3( edges[f[0]] + radiusSegments, edges[f[2]] + radiusSegments, edges[f[1]] + radiusSegments, null, color, 0) );
00700 }
00701 }
00702
00703 geometry.computeFaceNormals();
00704
00705 return geometry;
00706 }
00707
00708
00709 JSROOT.GEO.createXtru = function( shape ) {
00710
00711 var geometry = new THREE.Geometry();
00712
00713 var fcolor = new THREE.Color();
00714
00715 var prev = 0, curr = 0;
00716 for (var layer = 0; layer < shape.fNz; ++layer) {
00717 var layerz = shape.fZ[layer], scale = shape.fScale[layer];
00718
00719 prev = curr;
00720 curr = geometry.vertices.length;
00721
00722
00723 for (var vert = 0; vert < shape.fNvert; ++vert)
00724 geometry.vertices.push( new THREE.Vector3( scale * shape.fX[vert], scale * shape.fY[vert], layerz ));
00725
00726 if (layer>0)
00727 for (var vert = 0; vert < shape.fNvert; ++vert) {
00728 var vert1 = (vert + 1) % shape.fNvert;
00729 geometry.faces.push( new THREE.Face3( prev + vert, curr + vert, curr + vert1, null, fcolor, 0 ) );
00730 geometry.faces.push( new THREE.Face3( prev + vert, curr + vert1, prev + vert1, null, fcolor, 0 ));
00731 }
00732 }
00733
00734
00735
00736 var pnts = [];
00737 for (var vert = 0; vert < shape.fNvert; ++vert)
00738 pnts.push( new THREE.Vector2(shape.fX[vert], shape.fY[vert]));
00739 var faces = THREE.ShapeUtils.triangulateShape(pnts, []);
00740
00741 for (var i = 0; i < faces.length; ++i) {
00742 face = faces[ i ];
00743 geometry.faces.push( new THREE.Face3( face[1], face[0], face[2], null, fcolor, 0) );
00744 geometry.faces.push( new THREE.Face3( face[0] + curr, face[1] + curr, face[2] + curr, null, fcolor, 0) );
00745 }
00746
00747 geometry.computeFaceNormals();
00748
00749 return geometry;
00750 }
00751
00752
00753 JSROOT.GEO.createParaboloid = function( shape, faces_limit ) {
00754
00755 var radiusSegments = Math.round(360/6), heightSegments = 30;
00756
00757 if (faces_limit !== undefined) {
00758 var fact = 2 * (radiusSegments+1) * (heightSegments+1) / faces_limit;
00759 if (fact > 1.) {
00760 radiusSegments = Math.round(radiusSegments/Math.sqrt(fact));
00761 heightSegments = Math.round(heightSegments/Math.sqrt(fact));
00762 }
00763 }
00764
00765
00766 var _sin = new Float32Array(radiusSegments), _cos = new Float32Array(radiusSegments);
00767 for (var seg=0;seg<radiusSegments;++seg) {
00768 _cos[seg] = Math.cos(seg/radiusSegments*2*Math.PI);
00769 _sin[seg] = Math.sin(seg/radiusSegments*2*Math.PI);
00770 }
00771
00772 var geometry = new THREE.Geometry();
00773 var fcolor = new THREE.Color();
00774
00775 var zmin = -shape.fDZ, zmax = shape.fDZ, rmin = shape.fRlo, rmax = shape.fRhi;
00776
00777
00778 if (shape.fA >= 0) {
00779 if (shape.fB > zmin) zmin = shape.fB;
00780 } else {
00781 if (shape.fB < zmax) zmax = shape.fB;
00782 }
00783
00784 var ttmin = Math.atan2(zmin, rmin), ttmax = Math.atan2(zmax, rmax);
00785
00786 var prev_indx = 0, prev_radius = 0;
00787
00788 for (var layer = 0; layer <= heightSegments + 1; ++layer) {
00789 var layerz = zmax, radius = 0;
00790
00791 if ((layer === heightSegments + 1) && (prev_radius === 0)) break;
00792
00793 switch (layer) {
00794 case 0: layerz = zmin; radius = rmin; break;
00795 case heightSegments: layerz = zmax; radius = rmax; break;
00796 case heightSegments + 1: layerz = zmax; radius = 0; break;
00797 default: {
00798 var tt = Math.tan(ttmin + (ttmax-ttmin) * layer / heightSegments);
00799 var delta = tt*tt - 4*shape.fA*shape.fB;
00800 radius = 0.5*(tt+Math.sqrt(delta))/shape.fA;
00801 if (radius < 1e-6) radius = 0;
00802 layerz = radius*tt;
00803 }
00804 }
00805
00806 var curr_indx = geometry.vertices.length;
00807
00808 if (radius === 0) {
00809 geometry.vertices.push( new THREE.Vector3( 0, 0, layerz ));
00810 } else {
00811 for (var seg=0; seg<radiusSegments; ++seg)
00812 geometry.vertices.push( new THREE.Vector3( radius*_cos[seg], radius*_sin[seg], layerz));
00813 }
00814
00815
00816 if (layer>0) {
00817 for (var seg=0; seg<radiusSegments; ++seg) {
00818 var seg1 = (seg+1) % radiusSegments;
00819 if (prev_radius === 0) {
00820 geometry.faces.push( new THREE.Face3( prev_indx, curr_indx + seg1, curr_indx + seg, null, fcolor, 0) );
00821 } else
00822 if (radius == 0) {
00823 geometry.faces.push( new THREE.Face3( prev_indx + seg, prev_indx + seg1, curr_indx, null, fcolor, 0) );
00824 } else {
00825 geometry.faces.push( new THREE.Face3( prev_indx + seg, curr_indx + seg1, curr_indx + seg, null, fcolor, 0) );
00826 geometry.faces.push( new THREE.Face3( prev_indx + seg, prev_indx + seg1, curr_indx + seg1, null, fcolor, 0) );
00827 }
00828 }
00829 }
00830
00831 prev_radius = radius;
00832 prev_indx = curr_indx;
00833 }
00834
00835 geometry.computeFaceNormals();
00836
00837 return geometry;
00838 }
00839
00840
00841 JSROOT.GEO.createHype = function( shape, faces_limit ) {
00842
00843 if ((shape.fTin===0) && (shape.fTout===0))
00844 return JSROOT.GEO.createTube(shape);
00845
00846 var radiusSegments = Math.round(360/6), heightSegments = 30;
00847
00848 if (faces_limit !== undefined) {
00849 var fact = ((shape.fRmin <= 0) ? 2 : 4) * (radiusSegments+1) * (heightSegments+2) / faces_limit;
00850 if (fact > 1.) {
00851 radiusSegments = Math.round(radiusSegments/Math.sqrt(fact));
00852 heightSegments = Math.round(heightSegments/Math.sqrt(fact));
00853 }
00854 }
00855
00856
00857 var _sin = new Float32Array(radiusSegments), _cos = new Float32Array(radiusSegments);
00858 for (var seg=0;seg<radiusSegments;++seg) {
00859 _cos[seg] = Math.cos(seg/radiusSegments*2*Math.PI);
00860 _sin[seg] = Math.sin(seg/radiusSegments*2*Math.PI);
00861 }
00862
00863 var geometry = new THREE.Geometry();
00864 var fcolor = new THREE.Color();
00865
00866 var indexes = [[],[]];
00867
00868
00869 for (var side=0;side<2;++side) {
00870
00871
00872 if ((side===0) && (shape.fRmin <= 0)) {
00873 indexes[side][0] = geometry.vertices.length;
00874 geometry.vertices.push( new THREE.Vector3( 0, 0, -shape.fDz ) );
00875 indexes[side][heightSegments] = geometry.vertices.length;
00876 geometry.vertices.push( new THREE.Vector3( 0, 0, shape.fDz ) );
00877 continue;
00878 }
00879
00880 var prev_indx = 0;
00881 var r0 = (side===0) ? shape.fRmin : shape.fRmax;
00882 var tsq = (side===0) ? shape.fTinsq : shape.fToutsq;
00883
00884
00885 for (var layer=0;layer<=heightSegments;++layer) {
00886 var layerz = -shape.fDz + layer/heightSegments*2*shape.fDz;
00887
00888 var radius = Math.sqrt(r0*r0+tsq*layerz*layerz);
00889 var curr_indx = geometry.vertices.length;
00890
00891 indexes[side][layer] = curr_indx;
00892
00893 for (var seg=0; seg<radiusSegments; ++seg)
00894 geometry.vertices.push( new THREE.Vector3( radius*_cos[seg], radius*_sin[seg], layerz));
00895
00896
00897 if (layer>0) {
00898 for (var seg=0; seg<radiusSegments; ++seg) {
00899 var seg1 = (seg+1) % radiusSegments;
00900 geometry.faces.push( new THREE.Face3( prev_indx + seg, (side===0) ? (curr_indx + seg) : (prev_indx + seg1), curr_indx + seg1, null, fcolor, 0) );
00901 geometry.faces.push( new THREE.Face3( prev_indx + seg, curr_indx + seg1, (side===0) ? (prev_indx + seg1) : (curr_indx + seg), null, fcolor, 0) );
00902 }
00903 }
00904
00905 prev_indx = curr_indx;
00906 }
00907 }
00908
00909
00910 for(var layer=0; layer<=heightSegments; layer+=heightSegments) {
00911 var inside = indexes[0][layer], outside = indexes[1][layer];
00912 for (var seg=0; seg<radiusSegments; ++seg) {
00913 var seg1 = (seg+1) % radiusSegments;
00914 if (shape.fRmin <= 0) {
00915 geometry.faces.push( new THREE.Face3( inside, outside + (layer===0 ? seg1 : seg), outside + (layer===0 ? seg : seg1), null, fcolor, 0) );
00916 } else {
00917 geometry.faces.push( new THREE.Face3( inside + seg, (layer===0) ? (inside + seg1) : (outside + seg), outside + seg1, null, fcolor, 0) );
00918 geometry.faces.push( new THREE.Face3( inside + seg, outside + seg1, (layer===0) ? (outside + seg) : (inside + seg1), null, fcolor, 0) );
00919 }
00920 }
00921 }
00922
00923 geometry.computeFaceNormals();
00924
00925 return geometry;
00926 }
00927
00928 JSROOT.GEO.createMatrix = function(matrix) {
00929
00930 if (matrix === null) return null;
00931
00932 var translation_matrix = null, rotation_matrix = null;
00933
00934 if (matrix._typename == 'TGeoTranslation') {
00935 translation_matrix = matrix.fTranslation;
00936 }
00937 else if (matrix._typename == 'TGeoRotation') {
00938 rotation_matrix = matrix.fRotationMatrix;
00939 }
00940 else if (matrix._typename == 'TGeoCombiTrans') {
00941 translation_matrix = matrix.fTranslation;
00942 if (matrix.fRotation !== null)
00943 rotation_matrix = matrix.fRotation.fRotationMatrix;
00944 }
00945 else if (matrix._typename !== 'TGeoIdentity') {
00946 console.log('unsupported matrix ' + matrix._typename);
00947 }
00948
00949 if ((translation_matrix === null) && (rotation_matrix === null)) return null;
00950
00951 var res = new THREE.Matrix4();
00952
00953 if (rotation_matrix !== null)
00954 res.set(rotation_matrix[0], rotation_matrix[1], rotation_matrix[2], 0,
00955 rotation_matrix[3], rotation_matrix[4], rotation_matrix[5], 0,
00956 rotation_matrix[6], rotation_matrix[7], rotation_matrix[8], 0,
00957 0, 0, 0, 1);
00958
00959 if (translation_matrix !== null)
00960 res.setPosition(new THREE.Vector3(translation_matrix[0], translation_matrix[1], translation_matrix[2]));
00961
00962 return res;
00963 }
00964
00965 JSROOT.GEO.createComposite = function ( shape, faces_limit ) {
00966
00967 if (faces_limit === undefined) faces_limit = 10000;
00968
00969 var geom1 = JSROOT.GEO.createGeometry(shape.fNode.fLeft, faces_limit / 2);
00970 geom1.computeVertexNormals();
00971 var matrix1 = JSROOT.GEO.createMatrix(shape.fNode.fLeftMat);
00972 if (matrix1!==null) {
00973 if (matrix1.determinant() < -0.9) console.warn('Axis reflection in composite shape - not supported');
00974 geom1.applyMatrix(matrix1);
00975 }
00976
00977 var geom2 = JSROOT.GEO.createGeometry(shape.fNode.fRight, faces_limit / 2);
00978 geom2.computeVertexNormals();
00979 var matrix2 = JSROOT.GEO.createMatrix(shape.fNode.fRightMat);
00980 if (matrix2 !== null) {
00981 if (matrix2.determinant() < -0.9) console.warn('Axis reflection in composite shape - not supported');
00982 geom2.applyMatrix(matrix2);
00983 }
00984
00985 var bsp1 = new ThreeBSP(geom1);
00986 var bsp2 = new ThreeBSP(geom2);
00987 var bsp = null;
00988
00989 if (shape.fNode._typename === 'TGeoIntersection')
00990 bsp = bsp1.intersect(bsp2);
00991 else
00992 if (shape.fNode._typename === 'TGeoUnion')
00993 bsp = bsp1.union(bsp2);
00994 else
00995 if (shape.fNode._typename === 'TGeoSubtraction')
00996 bsp = bsp1.subtract(bsp2);
00997
00998 if (bsp === null) {
00999 console.warn('unsupported bool operation ' + shape.fNode._typename + ', use first geom');
01000 return geom1;
01001 }
01002
01003 var res = bsp.toGeometry();
01004
01005
01006
01007 return res;
01008 }
01009
01010
01011 JSROOT.GEO.createGeometry = function( shape, limit ) {
01012
01013 switch (shape._typename) {
01014 case "TGeoBBox": return JSROOT.GEO.createCube( shape );
01015 case "TGeoPara": return JSROOT.GEO.createPara( shape );
01016 case "TGeoTrd1":
01017 case "TGeoTrd2": return JSROOT.GEO.createTrapezoid( shape );
01018 case "TGeoArb8":
01019 case "TGeoTrap":
01020 case "TGeoGtra": return JSROOT.GEO.createArb8( shape );
01021 case "TGeoSphere": return JSROOT.GEO.createSphere( shape, limit );
01022 case "TGeoCone":
01023 case "TGeoConeSeg":
01024 case "TGeoTube":
01025 case "TGeoTubeSeg":
01026 case "TGeoCtub": return JSROOT.GEO.createTube( shape );
01027 case "TGeoEltu": return JSROOT.GEO.createEltu( shape );
01028 case "TGeoTorus": return JSROOT.GEO.createTorus( shape, limit );
01029 case "TGeoPcon":
01030 case "TGeoPgon": return JSROOT.GEO.createPolygon( shape );
01031 case "TGeoXtru": return JSROOT.GEO.createXtru( shape );
01032 case "TGeoParaboloid": return JSROOT.GEO.createParaboloid( shape, limit );
01033 case "TGeoHype": return JSROOT.GEO.createHype( shape, limit );
01034 case "TGeoCompositeShape": return JSROOT.GEO.createComposite( shape, limit );
01035 case "TGeoShapeAssembly": return new THREE.Geometry();
01036 }
01037
01038 return null;
01039 }
01040
01045
01046
01047
01048 JSROOT.EGeoVisibilityAtt = {
01049 kVisOverride : JSROOT.BIT(0),
01050 kVisNone : JSROOT.BIT(1),
01051 kVisThis : JSROOT.BIT(2),
01052 kVisDaughters : JSROOT.BIT(3),
01053 kVisOneLevel : JSROOT.BIT(4),
01054 kVisStreamed : JSROOT.BIT(5),
01055 kVisTouched : JSROOT.BIT(6),
01056 kVisOnScreen : JSROOT.BIT(7),
01057 kVisContainers : JSROOT.BIT(12),
01058 kVisOnly : JSROOT.BIT(13),
01059 kVisBranch : JSROOT.BIT(14),
01060 kVisRaytrace : JSROOT.BIT(15)
01061 };
01062
01063 JSROOT.TestGeoAttBit = function(volume, f) {
01064 if (!('fGeoAtt' in volume)) return false;
01065 return (volume.fGeoAtt & f) !== 0;
01066 }
01067
01068 JSROOT.ToggleGeoAttBit = function(volume, f) {
01069 if (!('fGeoAtt' in volume)) return false;
01070
01071 volume.fGeoAtt = volume.fGeoAtt ^ (f & 0xffffff);
01072 }
01073
01074 JSROOT.TGeoPainter = function( geometry ) {
01075 if ((geometry !== null) && (geometry._typename.indexOf('TGeoVolume') === 0))
01076 geometry = { _typename:"TGeoNode", fVolume: geometry, fName:"TopLevel" };
01077
01078 JSROOT.TObjectPainter.call(this, geometry);
01079
01080 this.Cleanup(true);
01081 }
01082
01083 JSROOT.TGeoPainter.prototype = Object.create( JSROOT.TObjectPainter.prototype );
01084
01085 JSROOT.TGeoPainter.prototype.CreateToolbar = function(args) {
01086 if ( this._toolbar !== null ) return;
01087 var painter = this;
01088 var buttonList = [{
01089 name: 'toImage',
01090 title: 'Save as PNG',
01091 icon: JSROOT.ToolbarIcons.camera,
01092 click: function() {
01093 var dataUrl = painter._renderer.domElement.toDataURL("image/png");
01094 dataUrl.replace("image/png", "image/octet-stream");
01095 var link = document.createElement('a');
01096 if (typeof link.download === 'string') {
01097 document.body.appendChild(link);
01098 link.download = "geometry.png";
01099 link.href = dataUrl;
01100 link.click();
01101 document.body.removeChild(link);
01102 }
01103 }
01104 }];
01105 this._toolbar = new JSROOT.Toolbar( this.select_main(), [buttonList] );
01106 }
01107
01108 JSROOT.TGeoPainter.prototype.decodeOptions = function(opt) {
01109 var res = { _grid: false, _bound: false, _debug: false, _full: false, maxlvl: -1, _axis:false, scale: new THREE.Vector3(1,1,1) };
01110
01111 var _opt = JSROOT.GetUrlOption('_grid');
01112 if (_opt !== null && _opt == "true") res._grid = true;
01113 var _opt = JSROOT.GetUrlOption('_debug');
01114 if (_opt !== null && _opt == "true") { res._debug = true; res._grid = true; }
01115 if (_opt !== null && _opt == "bound") { res._debug = true; res._grid = true; res._bound = true; }
01116 if (_opt !== null && _opt == "full") { res._debug = true; res._grid = true; res._full = true; res._bound = true; }
01117
01118 opt = opt.toLowerCase();
01119
01120 if (opt.indexOf("all")>=0) {
01121 res.maxlvl = 9999;
01122 opt = opt.replace("all", " ");
01123 }
01124 if (opt.indexOf("limit")>=0) {
01125 res.maxlvl = 1111;
01126 opt = opt.replace("limit", " ");
01127 }
01128 if (opt.indexOf("invx")>=0) {
01129 res.scale.x = -1;
01130 opt = opt.replace("invx", " ");
01131 }
01132 if (opt.indexOf("invy")>=0) {
01133 res.scale.y = -1;
01134 opt = opt.replace("invy", " ");
01135 }
01136 if (opt.indexOf("invz")>=0) {
01137 res.scale.z = -1;
01138 opt = opt.replace("invz", " ");
01139 }
01140
01141 var p = opt.indexOf("maxlvl");
01142 if (p>=0) {
01143 res.maxlvl = parseInt(opt.substr(p+6, 1));
01144 opt = opt.replace("maxlvl" + res.maxlvl, " ");
01145 }
01146
01147 if (opt.indexOf("d")>=0) res._debug = true;
01148 if (opt.indexOf("g")>=0) res._grid = true;
01149 if (opt.indexOf("b")>=0) res._bound = true;
01150 if (opt.indexOf("f")>=0) res._full = true;
01151 if (opt.indexOf("a")>=0) { res._axis = true; res._yup = false; }
01152 if (opt.indexOf("y")>=0) res._yup = true;
01153 if (opt.indexOf("z")>=0) res._yup = false;
01154
01155 return res;
01156 }
01157
01158
01159 JSROOT.TGeoPainter.prototype.addControls = function() {
01160
01161 if (this._controls !== null) return;
01162
01163 var painter = this;
01164
01165 this.select_main().property('flex_block_drag', true);
01166
01167 this._controls = new THREE.OrbitControls(this._camera, this._renderer.domElement);
01168 this._controls.enableDamping = false;
01169 this._controls.dampingFactor = 0.25;
01170 this._controls.enableZoom = true;
01171 this._controls.target.copy(this._lookat);
01172 this._controls.update();
01173
01174 this._controls.addEventListener( 'change', function() { painter.Render3D(0); } );
01175
01176 if ( this.options._debug || this.options._grid ) {
01177 this._tcontrols = new THREE.TransformControls( this._camera, this._renderer.domElement );
01178 this._scene.add( this._tcontrols );
01179 this._tcontrols.attach( this._toplevel );
01180
01181
01182 window.addEventListener( 'keydown', function ( event ) {
01183 switch ( event.keyCode ) {
01184 case 81:
01185 painter._tcontrols.setSpace( painter._tcontrols.space === "local" ? "world" : "local" );
01186 break;
01187 case 17:
01188 painter._tcontrols.setTranslationSnap( Math.ceil( painter._overall_size ) / 50 );
01189 painter._tcontrols.setRotationSnap( THREE.Math.degToRad( 15 ) );
01190 break;
01191 case 84:
01192 painter._tcontrols.setMode( "translate" );
01193 break;
01194 case 82:
01195 painter._tcontrols.setMode( "rotate" );
01196 break;
01197 case 83:
01198 painter._tcontrols.setMode( "scale" );
01199 break;
01200 case 187:
01201 case 107:
01202 painter._tcontrols.setSize( painter._tcontrols.size + 0.1 );
01203 break;
01204 case 189:
01205 case 109:
01206 painter._tcontrols.setSize( Math.max( painter._tcontrols.size - 0.1, 0.1 ) );
01207 break;
01208 }
01209 });
01210 window.addEventListener( 'keyup', function ( event ) {
01211 switch ( event.keyCode ) {
01212 case 17:
01213 painter._tcontrols.setTranslationSnap( null );
01214 painter._tcontrols.setRotationSnap( null );
01215 break;
01216 }
01217 });
01218
01219 this._tcontrols.addEventListener( 'change', function() { painter.Render3D(0); } );
01220 }
01221
01222 var raycaster = new THREE.Raycaster(), INTERSECTED = null;
01223
01224 function findIntersection(mouse) {
01225
01226
01227
01228
01229 raycaster.setFromCamera( mouse, painter._camera );
01230 var intersects = raycaster.intersectObjects(painter._scene.children, true);
01231 if (intersects.length > 0) {
01232 var pick = null;
01233 for (var i = 0; i < intersects.length; ++i) {
01234 if ('emissive' in intersects[i].object.material) {
01235 pick = intersects[i].object;
01236 break;
01237 }
01238 }
01239 if (pick && INTERSECTED != pick) {
01240 INTERSECTED = pick;
01241
01242 var name = INTERSECTED.name;
01243
01244 var p = INTERSECTED.parent;
01245 while ((p!==undefined) && (p!==null)) {
01246 if ('name' in p) name = p.name+'/'+name;
01247 p = p.parent;
01248 }
01249
01250
01251 }
01252 } else {
01253
01254 }
01255 };
01256
01257 function mousemove(e) {
01258 var mouse_x = ('offsetX' in e) ? e.offsetX : e.layerX;
01259 var mouse_y = ('offsetY' in e) ? e.offsetY : e.layerY;
01260 var mouse = { x: (mouse_x / painter._renderer.domElement.width) * 2 - 1,
01261 y: -(mouse_y / painter._renderer.domElement.height) * 2 + 1 };
01262
01263 findIntersection(mouse);
01264 e.preventDefault();
01265 }
01266
01267 this._renderer.domElement.addEventListener('mousemove', mousemove);
01268 }
01269
01270 JSROOT.TGeoPainter.prototype.accountClear = function() {
01271 this._num_geom = 0;
01272 this._num_vertices = 0;
01273 this._num_faces = 0;
01274 this._num_meshes = 0;
01275 }
01276
01277 JSROOT.TGeoPainter.prototype.accountGeom = function(geom, shape_typename) {
01278
01279 if (geom === null) {
01280 if (!('unsupported_shapes' in this)) this.unsupported_shapes = [];
01281 if ((shape_typename !== undefined) && (this.unsupported_shapes.indexOf(shape_typename) < 0)) {
01282 this.unsupported_shapes.push(shape_typename);
01283 console.warn('Not supported ' + shape_typename);
01284 }
01285 return;
01286 }
01287
01288 this._num_geom++;
01289 if (('vertices' in geom) && ('faces' in geom)) {
01290 this._num_vertices += geom.vertices.length;
01291 this._num_faces += geom.faces.length;
01292 } else {
01293
01294 var attr = geom.getAttribute('position');
01295
01296
01297 }
01298 }
01299
01300 JSROOT.TGeoPainter.prototype.accountMesh = function(mesh) {
01301
01302 if (mesh !== null) this._num_meshes++;
01303 }
01304
01305 JSROOT.TGeoPainter.prototype.checkFlipping = function(parent, matrix, shape, geom, mesh_has_childs) {
01306
01307
01308 var m = new THREE.Matrix4();
01309 m.multiplyMatrices( parent.matrixWorld, matrix);
01310 if (m.determinant() > -0.9) return geom;
01311
01312
01313 if (mesh_has_childs) return null;
01314
01315 var cnt = 0, flip = new THREE.Vector3(1,1,1);
01316
01317 if (m.elements[0]===-1 && m.elements[1]=== 0 && m.elements[2] === 0) { flip.x = -1; cnt++; }
01318 if (m.elements[4]=== 0 && m.elements[5]===-1 && m.elements[6] === 0) { flip.y = -1; cnt++; }
01319 if (m.elements[8]=== 0 && m.elements[9]=== 0 && m.elements[10]===-1) { flip.z = -1; cnt++; }
01320
01321 if ((cnt===0) || (cnt ===2)) {
01322 flip.set(1,1,1); cnt = 0;
01323 if (m.elements[0] + m.elements[1] + m.elements[2] === -1) { flip.x = -1; cnt++; }
01324 if (m.elements[4] + m.elements[5] + m.elements[6] === -1) { flip.y = -1; cnt++; }
01325 if (m.elements[8] + m.elements[9] + m.elements[10] === -1) { flip.z = -1; cnt++; }
01326 if ((cnt === 0) || (cnt === 2)) {
01327
01328 flip.z = -flip.z;
01329 }
01330 }
01331
01332 matrix.scale(flip);
01333
01334 var gname = "_geom";
01335 if (flip.x<0) gname += "X";
01336 if (flip.y<0) gname += "Y";
01337 if (flip.z<0) gname += "Z";
01338
01339
01340 if (gname in shape) return shape[gname];
01341
01342 geom = geom.clone();
01343
01344 geom.scale(flip.x, flip.y, flip.z);
01345
01346 var face, d;
01347 for (var n=0;n<geom.faces.length;++n) {
01348 face = geom.faces[n];
01349 d = face.b; face.b = face.c; face.c = d;
01350 }
01351
01352
01353 geom.computeFaceNormals();
01354
01355 shape[gname] = geom;
01356
01357 this.accountGeom(geom);
01358
01359 return geom;
01360 }
01361
01362 JSROOT.TGeoPainter.prototype.getNodeProperties = function(node, visible) {
01363
01364
01365 var volume = node.fVolume;
01366
01367 var prop = { shape: volume.fShape, matrix: null };
01368
01369 if (('fMatrix' in node) && (node.fMatrix !== null))
01370 prop.matrix = JSROOT.GEO.createMatrix(node.fMatrix);
01371 else
01372 if ((node._typename == "TGeoNodeOffset") && (node.fFinder !== null)) {
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382 if ((node.fFinder._typename === 'TGeoPatternX') ||
01383 (node.fFinder._typename === 'TGeoPatternY') ||
01384 (node.fFinder._typename === 'TGeoPatternZ')) {
01385 var _shift = node.fFinder.fStart + (node.fIndex + 0.5) * node.fFinder.fStep;
01386
01387 prop.matrix = new THREE.Matrix4();
01388
01389 switch (node.fFinder._typename.charAt(11)) {
01390 case 'X': prop.matrix.setPosition(new THREE.Vector3(_shift, 0, 0)); break;
01391 case 'Y': prop.matrix.setPosition(new THREE.Vector3(0, _shift, 0)); break;
01392 case 'Z': prop.matrix.setPosition(new THREE.Vector3(0, 0, _shift)); break;
01393 }
01394 } else
01395 if (node.fFinder._typename === 'TGeoPatternCylPhi') {
01396 var phi = (Math.PI/180)*(node.fFinder.fStart+(node.fIndex+0.5)*node.fFinder.fStep);
01397 var _cos = Math.cos(phi), _sin = Math.sin(phi);
01398
01399 prop.matrix = new THREE.Matrix4();
01400
01401 prop.matrix.set(_cos, -_sin, 0, 0,
01402 _sin, _cos, 0, 0,
01403 0, 0, 1, 0,
01404 0, 0, 0, 1);
01405 } else {
01406 console.warn('Unsupported pattern type ' + node.fFinder._typename);
01407 }
01408 }
01409
01410 prop.material = null;
01411
01412 if (visible) {
01413 var _transparent = false, _opacity = 1.0;
01414 if ((volume.fFillColor > 1) && (volume.fLineColor == 1))
01415 prop.fillcolor = JSROOT.Painter.root_colors[volume.fFillColor];
01416 else
01417 if (volume.fLineColor >= 0)
01418 prop.fillcolor = JSROOT.Painter.root_colors[volume.fLineColor];
01419
01420 if (('fMedium' in volume) && (volume.fMedium !== null) &&
01421 ('fMaterial' in volume.fMedium) && (volume.fMedium.fMaterial !== null)) {
01422 var fillstyle = volume.fMedium.fMaterial.fFillStyle;
01423 var transparency = (fillstyle < 3000 || fillstyle > 3100) ? 0 : fillstyle - 3000;
01424 if (transparency > 0) {
01425 _transparent = true;
01426 _opacity = (100.0 - transparency) / 100.0;
01427 }
01428 if (prop.fillcolor === undefined)
01429 prop.fillcolor = JSROOT.Painter.root_colors[volume.fMedium.fMaterial.fFillColor];
01430 }
01431 if (prop.fillcolor === undefined)
01432 prop.fillcolor = "lightgrey";
01433
01434 prop.material = new THREE.MeshLambertMaterial( { transparent: _transparent,
01435 opacity: _opacity, wireframe: false, color: prop.fillcolor,
01436 side: THREE.FrontSide, vertexColors: THREE.NoColors ,
01437 overdraw: 0. } );
01438 }
01439
01440 return prop;
01441 }
01442
01443 JSROOT.TGeoPainter.prototype.getEveNodeProperties = function(node, visible) {
01444
01445 var prop = { shape: node.fShape };
01446
01447 prop.material = null;
01448
01449 if (visible) {
01450 var _transparent = false, _opacity = 1.0;
01451 if ( node.fRGBA[3] < 1.0) {
01452 _transparent = true;
01453 _opacity = node.fRGBA[3];
01454 }
01455 prop.fillcolor = new THREE.Color( node.fRGBA[0], node.fRGBA[1], node.fRGBA[2] );
01456 prop.material = new THREE.MeshLambertMaterial( { transparent: _transparent,
01457 opacity: _opacity, wireframe: false, color: prop.fillcolor,
01458 side: THREE.FrontSide, vertexColors: THREE.NoColors ,
01459 overdraw: 0. } );
01460 }
01461
01462 prop.matrix = new THREE.Matrix4();
01463
01464 if (node.fTrans!==null) {
01465 prop.matrix.set(node.fTrans[0], node.fTrans[4], node.fTrans[8], 0,
01466 node.fTrans[1], node.fTrans[5], node.fTrans[9], 0,
01467 node.fTrans[2], node.fTrans[6], node.fTrans[10], 0,
01468 0, 0, 0, 1);
01469
01470 prop.matrix.setPosition({ x: node.fTrans[12], y: node.fTrans[13], z: node.fTrans[14] });
01471 }
01472 return prop;
01473 }
01474
01475
01476 JSROOT.TGeoPainter.prototype.drawNode = function() {
01477
01478 if ((this._stack == null) || (this._stack.length == 0)) return false;
01479
01480 var arg = this._stack[this._stack.length - 1];
01481
01482
01483
01484
01485 var kind = this.NodeKind(arg.node);
01486 if (kind < 0) return false;
01487 var chlds = null;
01488
01489 if (kind === 0) {
01490 chlds = (arg.node.fVolume.fNodes !== null) ? arg.node.fVolume.fNodes.arr : null;
01491 } else {
01492 chlds = (arg.node.fElements !== null) ? arg.node.fElements.arr : null;
01493 }
01494
01495 if ('nchild' in arg) {
01496
01497 if ((chlds === null) || (chlds.length <= arg.nchild)) {
01498 this._stack.pop();
01499 } else {
01500 this._stack.push({ toplevel: (arg.mesh ? arg.mesh : arg.toplevel),
01501 node: chlds[arg.nchild++] });
01502 }
01503 return true;
01504 }
01505
01506 var prop = null;
01507
01508 if (kind === 0)
01509 prop = this.getNodeProperties(arg.node, arg.node._visible);
01510 else
01511 prop = this.getEveNodeProperties(arg.node, arg.node._visible);
01512
01513 var geom = null;
01514
01515 if (prop.matrix === null) prop.matrix = new THREE.Matrix4();
01516
01517 if ((prop.shape === null) && arg.node._visible)
01518 arg.node._visible = false;
01519
01520 if (arg.node._visible) {
01521 if (typeof prop.shape._geom === 'undefined') {
01522 prop.shape._geom = JSROOT.GEO.createGeometry(prop.shape);
01523 this.accountGeom(prop.shape._geom, prop.shape._typename);
01524 }
01525
01526 geom = prop.shape._geom;
01527
01528 } else {
01529 if (this._dummy_material === undefined)
01530 this._dummy_material =
01531 new THREE.MeshLambertMaterial( { transparent: true, opacity: 0, wireframe: false,
01532 color: 'white', vertexColors: THREE.NoColors,
01533 overdraw: 0., depthWrite : false, depthTest: false, visible: false } );
01534
01535 prop.material = this._dummy_material;
01536 }
01537
01538 var has_childs = (chlds !== null) && (chlds.length > 0);
01539 var work_around = false;
01540
01541
01542 if (arg.main && (this.options.scale !== null)) {
01543 if ((this.options.scale.x<0) || (this.options.scale.y<0) || (this.options.scale.z<0)) {
01544 prop.matrix.scale(this.options.scale);
01545 }
01546 }
01547
01548 if (arg.node._visible && (geom !== null)) {
01549 geom = this.checkFlipping(arg.toplevel, prop.matrix, prop.shape, geom, has_childs);
01550 work_around = has_childs && (geom === null);
01551 }
01552
01553 if (geom === null) geom = new THREE.Geometry();
01554
01555 var mesh = new THREE.Mesh( geom, prop.material );
01556
01557 mesh.applyMatrix(prop.matrix);
01558
01559 this.accountMesh(mesh);
01560
01561 mesh.name = arg.node.fName;
01562
01563
01564 arg.toplevel.add(mesh);
01565
01566 mesh.updateMatrixWorld();
01567
01568 if (work_around) {
01569 JSROOT.console('perform workaroud for flipping mesh with childs');
01570
01571 prop.matrix.identity();
01572
01573 geom = this.checkFlipping(mesh, prop.matrix, prop.shape, prop.shape._geom, false);
01574
01575 var dmesh = new THREE.Mesh( geom, prop.material );
01576
01577 dmesh.applyMatrix(prop.matrix);
01578
01579 dmesh.name = "..";
01580
01581
01582 mesh.add(dmesh);
01583
01584 dmesh.updateMatrixWorld();
01585 }
01586
01587 if (this.options._debug && (arg.node._visible || this.options._full)) {
01588 var helper = new THREE.WireframeHelper(mesh);
01589 helper.material.color.set(prop.fillcolor);
01590 helper.material.linewidth = ('fVolume' in arg.node) ? arg.node.fVolume.fLineWidth : 1;
01591 arg.toplevel.add(helper);
01592 }
01593
01594 if (this.options._bound && (arg.node._visible || this.options._full)) {
01595 var boxHelper = new THREE.BoxHelper( mesh );
01596 arg.toplevel.add( boxHelper );
01597 }
01598
01599 arg.mesh = mesh;
01600
01601 if ((chlds === null) || (chlds.length == 0)) {
01602
01603 this._stack.pop();
01604 } else {
01605 arg.nchild = 0;
01606 }
01607
01608 return true;
01609 }
01610
01611 JSROOT.TGeoPainter.prototype.NodeKind = function(obj) {
01612 if ((obj === undefined) || (obj === null) || (typeof obj !== 'object')) return -1;
01613 return ('fShape' in obj) && ('fTrans' in obj) ? 1 : 0;
01614 }
01615
01616 JSROOT.TGeoPainter.prototype.CountGeoVolumes = function(obj, arg, lvl) {
01617
01618
01619
01620 var kind = this.NodeKind(obj);
01621 if (kind < 0) return 0;
01622
01623 if (lvl === undefined) {
01624 lvl = 0;
01625 if (!arg) arg = { erase: true };
01626 if (!('map' in arg)) arg.map = [];
01627 arg.viscnt = 0;
01628 if (!('clear' in arg))
01629 arg.clear = function() {
01630 for (var n=0;n<this.map.length;++n) {
01631 delete this.map[n]._refcnt;
01632 delete this.map[n]._numchld;
01633 delete this.map[n]._visible;
01634 }
01635 this.map = [];
01636 this.viscnt = 0;
01637 };
01638 }
01639
01640 var chlds = null, shape = null, vis = false;
01641 if (kind === 0) {
01642 if ((obj.fVolume === undefined) || (obj.fVolume === null)) return 0;
01643 shape = obj.fVolume.fShape;
01644 chlds = (obj.fVolume.fNodes !== null) ? obj.fVolume.fNodes.arr : null;
01645 vis = JSROOT.TestGeoAttBit(obj.fVolume, JSROOT.EGeoVisibilityAtt.kVisOnScreen)
01646 || ((lvl < arg.maxlvl) && JSROOT.TestGeoAttBit(obj.fVolume, JSROOT.EGeoVisibilityAtt.kVisThis));
01647 } else {
01648 if (obj.fShape === undefined) return 0;
01649 shape = obj.fShape;
01650 chlds = (obj.fElements !== null) ? obj.fElements.arr : null;
01651 vis = obj['fRnrSelf'];
01652 }
01653
01654 if ('cnt' in arg) {
01655 if (arg.cnt[lvl] === undefined) arg.cnt[lvl] = 0;
01656 arg.cnt[lvl] += 1;
01657 }
01658
01659 if ('_refcnt' in obj) {
01660 obj._refcnt++;
01661 } else {
01662 obj._refcnt = 1;
01663 obj._numchld = 0;
01664 arg.map.push(obj);
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680 if (vis && !('_visible' in obj) && (shape!==null)) {
01681 obj._visible = true;
01682 arg.viscnt++;
01683 }
01684
01685 if (chlds !== null)
01686 for (var i = 0; i < chlds.length; ++i)
01687 obj._numchld += this.CountGeoVolumes(chlds[i], arg, lvl+1);
01688 }
01689
01690 if ((lvl === 0) && arg.erase) arg.clear();
01691
01692 return 1 + obj._numchld;
01693 }
01694
01695 JSROOT.TGeoPainter.prototype.SameMaterial = function(node1, node2) {
01696
01697 if ((node1===null) || (node2===null)) return node1 === node2;
01698
01699 if (node1.fVolume.fLineColor >= 0)
01700 return (node1.fVolume.fLineColor === node2.fVolume.fLineColor);
01701
01702 var m1 = (node1.fVolume['fMedium'] !== null) ? node1.fVolume['fMedium']['fMaterial'] : null;
01703 var m2 = (node2.fVolume['fMedium'] !== null) ? node2.fVolume['fMedium']['fMaterial'] : null;
01704
01705 if (m1 === m2) return true;
01706
01707 if ((m1 === null) || (m2 === null)) return false;
01708
01709 return (m1.fFillStyle === m2.fFillStyle) && (m1.fFillColor === m2.fFillColor);
01710 }
01711
01712 JSROOT.TGeoPainter.prototype.ScanUniqueVisVolumes = function(obj, lvl, arg) {
01713 if ((obj === undefined) || (obj===null) || (typeof obj !== 'object') ||
01714 (obj.fVolume === undefined) || (obj.fVolume == null)) return 0;
01715
01716 if (lvl === 0) {
01717 arg.master = null;
01718 arg.vis_unique = true;
01719 arg.vis_master = null;
01720 arg.same_material = true;
01721 }
01722
01723 var res = obj._visible ? 1 : 0;
01724
01725 if (obj._refcnt > 1) arg.vis_unique = false;
01726 if (arg.master!==null)
01727 if (!this.SameMaterial(arg.master, obj)) arg.same_material = false;
01728
01729 var top_unique = arg.vis_unique;
01730 arg.vis_unique = true;
01731
01732 var top_master = arg.master, top_same = arg.same_material;
01733
01734 arg.master = obj._visible ? obj : null;
01735 arg.same_material = true;
01736
01737 var arr = (obj.fVolume.fNodes !== null) ? obj.fVolume.fNodes.arr : null;
01738
01739 var numvis = 0;
01740 if (arr !== null)
01741 for (var i = 0; i < arr.length; ++i)
01742 numvis += this.ScanUniqueVisVolumes(arr[i], lvl+1, arg);
01743
01744 obj._numvis = numvis;
01745 obj._visunique = arg.vis_unique;
01746 obj._samematerial = arg.same_material;
01747
01748 if (obj._samematerial) {
01749 if (top_same && (top_master!=null) && (arg.master!==null))
01750 arg.same_material = this.SameMaterial(top_master, arg.master);
01751 else
01752 arg.same_material = top_same;
01753
01754 if (top_master !== null) arg.master = top_master;
01755 } else {
01756 arg.master = null;
01757 arg.same_material = false;
01758 }
01759
01760 arg.vis_unique = top_unique && obj._visunique;
01761
01762 return res + numvis;
01763 }
01764
01765 JSROOT.TGeoPainter.prototype.createScene = function(webgl, w, h, pixel_ratio) {
01766
01767 this._scene = new THREE.Scene();
01768 this._scene.fog = new THREE.Fog(0xffffff, 500, 300000);
01769
01770 this._scene_width = w;
01771 this._scene_height = h;
01772
01773 this._camera = new THREE.PerspectiveCamera(25, w / h, 1, 100000);
01774
01775 this._renderer = webgl ?
01776 new THREE.WebGLRenderer({ antialias : true, logarithmicDepthBuffer: true,
01777 preserveDrawingBuffer: true }) :
01778 new THREE.CanvasRenderer({antialias : true });
01779 this._renderer.setPixelRatio(pixel_ratio);
01780 this._renderer.setClearColor(0xffffff, 1);
01781 this._renderer.setSize(w, h);
01782
01783 var pointLight = new THREE.PointLight(0xefefef);
01784 this._camera.add( pointLight );
01785 pointLight.position.set(10, 10, 10);
01786 this._camera.up = this.options._yup ? new THREE.Vector3(0,1,0) : new THREE.Vector3(0,0,1);
01787 this._scene.add( this._camera );
01788
01789 this._toplevel = new THREE.Object3D();
01790
01791 this._scene.add(this._toplevel);
01792
01793 this._overall_size = 10;
01794 }
01795
01796
01797 JSROOT.TGeoPainter.prototype.startDrawGeometry = function() {
01798 if (this.MatchObjectType("TGeoNode")) {
01799 this._nodedraw = true;
01800 this._stack = [ { toplevel: this._toplevel, node: this.GetObject(), main: true } ];
01801 }
01802 else if (this.MatchObjectType('TEveGeoShapeExtract')) {
01803 this._nodedraw = false;
01804 this._stack = [ { toplevel: this._toplevel, node: this.GetObject(), main: true } ];
01805 }
01806
01807 this.accountClear();
01808 }
01809
01810 JSROOT.TGeoPainter.prototype.adjustCameraPosition = function() {
01811
01812 var box = new THREE.Box3().setFromObject(this._toplevel);
01813
01814 var sizex = box.max.x - box.min.x,
01815 sizey = box.max.y - box.min.y,
01816 sizez = box.max.z - box.min.z,
01817 midx = (box.max.x + box.min.x)/2,
01818 midy = (box.max.y + box.min.y)/2,
01819 midz = (box.max.z + box.min.z)/2;
01820
01821 this._overall_size = 2 * Math.max( sizex, sizey, sizez);
01822
01823 this._camera.near = this._overall_size / 500;
01824 this._camera.far = this._overall_size * 500;
01825 this._camera.updateProjectionMatrix();
01826
01827
01828
01829
01830
01831
01832 if (this.options._yup)
01833 this._camera.position.set(midx-2*Math.max(sizex,sizez), midy+2*sizey, midz-2*Math.max(sizex,sizez));
01834 else
01835 this._camera.position.set(midx-2*Math.max(sizex,sizey), midy-2*Math.max(sizex,sizey), midz+2*sizez);
01836
01837
01838 this._lookat = new THREE.Vector3(midx, midy, midz);
01839 this._camera.lookAt(this._lookat);
01840
01841 if (this._controls !== null) {
01842 this._controls.target.copy(this._lookat);
01843 this._controls.update();
01844 }
01845 }
01846
01847 JSROOT.TGeoPainter.prototype.completeScene = function() {
01848 if ( this.options._debug || this.options._grid ) {
01849 if ( this.options._full ) {
01850 var boxHelper = new THREE.BoxHelper(this._toplevel);
01851 this._scene.add( boxHelper );
01852 }
01853 this._scene.add( new THREE.AxisHelper( 2 * this._overall_size ) );
01854 this._scene.add( new THREE.GridHelper( Math.ceil( this._overall_size), Math.ceil( this._overall_size ) / 50 ) );
01855 this.helpText("<font face='verdana' size='1' color='red'><center>Transform Controls<br>" +
01856 "'T' translate | 'R' rotate | 'S' scale<br>" +
01857 "'+' increase size | '-' decrease size<br>" +
01858 "'W' toggle wireframe/solid display<br>"+
01859 "keep 'Ctrl' down to snap to grid</center></font>");
01860 }
01861 }
01862
01863 JSROOT.TGeoPainter.prototype.drawCount = function() {
01864
01865 var tm1 = new Date();
01866
01867 var arg = { cnt : [], maxlvl: -1 };
01868 var cnt = this.CountGeoVolumes(this.GetObject(), arg);
01869
01870 var res = 'Total number: ' + cnt + '<br/>';
01871 for (var lvl=0;lvl<arg.cnt.length;++lvl) {
01872 if (arg.cnt[lvl] !== 0)
01873 res += (' lvl' + lvl + ': ' + arg.cnt[lvl] + '<br/>');
01874 }
01875 res += "Unique volumes: " + arg.map.length + '<br/>';
01876
01877 if (arg.viscnt === 0) {
01878 arg.clear(); arg.maxlvl = 9999;
01879 cnt = this.CountGeoVolumes(this.GetObject(), arg);
01880 }
01881
01882 res += "Visible volumes: " + arg.viscnt + '<br/>';
01883
01884 if (cnt<200000) {
01885 this.ScanUniqueVisVolumes(this.GetObject(), 0, arg);
01886
01887 for (var n=0;n<arg.map.length;++n)
01888 if (arg.map[n]._refcnt > 1) {
01889 res += (arg.map[n]._visible ? "vis" : "map") + n + " " + arg.map[n].fName + " nref:"+arg.map[n]._refcnt +
01890 ' chld:'+ arg.map[n]._numvis + "(" + arg.map[n]._numchld + ')' +
01891 " unique:" + arg.map[n]._visunique + " same:" + arg.map[n]._samematerial;
01892
01893 if (arg.map[n]._samematerial) {
01894 if (arg.map[n]._visunique && (arg.map[n]._numvis>0)) res+=" (can merge with childs in Worker)"; else
01895 if ((arg.map[n]._refcnt > 4) && (arg.map[n]._numvis>1)) res+=" (make sense merge in main thread)";
01896 }
01897
01898 res += "<br/>";
01899 }
01900 }
01901
01902 var tm2 = new Date();
01903
01904 res += "Elapsed time: " + (tm2.getTime() - tm1.getTime()) + "ms <br/>";
01905
01906 this.select_main().style('overflow', 'auto').html(res);
01907
01908 return this.DrawingReady();
01909 }
01910
01911
01912 JSROOT.TGeoPainter.prototype.DrawGeometry = function(opt) {
01913 if (typeof opt !== 'string') opt = "";
01914
01915 if (opt === 'count')
01916 return this.drawCount();
01917
01918 var size = this.size_for_3d();
01919
01920 this.options = this.decodeOptions(opt);
01921
01922 if (!('_yup' in this.options))
01923 this.options._yup = this.svg_canvas().empty();
01924
01925 this._webgl = JSROOT.Painter.TestWebGL();
01926
01927 this._data = { cnt: [], maxlvl : this.options.maxlvl };
01928
01929 var total = this.CountGeoVolumes(this.GetObject(), this._data);
01930
01931
01932 if ((total>0) && (this._data.viscnt == 0) && (this.options.maxlvl < 0)) {
01933 this._data.clear();
01934 this._data.maxlvl = 1111;
01935 total = this.CountGeoVolumes(this.GetObject(), this._data);
01936 }
01937
01938 var maxlimit = this._webgl ? 1e7 : 1e4;
01939
01940 if ((this._data.maxlvl === 1111) && (total > maxlimit)) {
01941 var sum = 0;
01942 for (var lvl=1; lvl < this._data.cnt.length; ++lvl) {
01943 sum += this._data.cnt.cnt[lvl];
01944 if (sum > maxlimit) {
01945 this._data.maxlvl = lvl - 1;
01946 this._data.clear();
01947 this.CountGeoVolumes(this.GetObject(), this._data);
01948 break;
01949 }
01950 }
01951 }
01952
01953 this.createScene(this._webgl, size.width, size.height, window.devicePixelRatio);
01954
01955 this.add_3d_canvas(size, this._renderer.domElement);
01956
01957 this.startDrawGeometry();
01958
01959 this._startm = new Date().getTime();
01960
01961 this._drawcnt = 0;
01962
01963 this.CreateToolbar( { container: this.select_main().node() } );
01964
01965 return this.continueDraw();
01966 }
01967
01968 JSROOT.TGeoPainter.prototype.continueDraw = function() {
01969 var curr = new Date().getTime();
01970
01971 var log = "";
01972
01973 while(true) {
01974 if (this.drawNode()) {
01975 this._drawcnt++;
01976 log = "Creating meshes " + this._drawcnt;
01977 } else
01978 break;
01979
01980 var now = new Date().getTime();
01981
01982 if (now - curr > 300) {
01983 JSROOT.progress(log);
01984 setTimeout(this.continueDraw.bind(this), 0);
01985 return this;
01986 }
01987
01988
01989 if (now - this._startm > 1e5) break;
01990 }
01991
01992 var t2 = new Date().getTime();
01993 JSROOT.console('Create tm = ' + (t2-this._startm) + ' geom ' + this._num_geom + ' vertices ' + this._num_vertices + ' faces ' + this._num_faces + ' meshes ' + this._num_meshes);
01994
01995 if (t2 - this._startm > 300) {
01996 JSROOT.progress('Rendering geometry');
01997 setTimeout(this.completeDraw.bind(this, true), 0);
01998 return this;
01999 }
02000
02001 return this.completeDraw();
02002 }
02003
02004 JSROOT.TGeoPainter.prototype.Render3D = function(tmout) {
02005 if (tmout === undefined) tmout = 5;
02006
02007 if (tmout <= 0) {
02008 if ('render_tmout' in this)
02009 clearTimeout(this['render_tmout']);
02010
02011 var tm1 = new Date();
02012
02013
02014 this._renderer.render(this._scene, this._camera);
02015
02016 var tm2 = new Date();
02017
02018 delete this['render_tmout'];
02019
02020 if (this.first_render_tm === 0) {
02021 this.first_render_tm = tm2.getTime() - tm1.getTime();
02022 JSROOT.console('First render tm = ' + this.first_render_tm);
02023 this.addControls();
02024 }
02025
02026 return;
02027 }
02028
02029
02030 if ('render_tmout' in this) return;
02031
02032 this['render_tmout'] = setTimeout(this.Render3D.bind(this,0), tmout);
02033 }
02034
02035 JSROOT.TGeoPainter.prototype.completeDraw = function(close_progress) {
02036
02037 this.adjustCameraPosition();
02038
02039 this.completeScene();
02040
02041 if (this.options._axis) {
02042 var axis = JSROOT.Create("TNamed");
02043 axis._typename = "TAxis3D";
02044 axis._main = this;
02045 JSROOT.draw(this.divid, axis);
02046 }
02047
02048 this.Render3D();
02049
02050 if (close_progress) JSROOT.progress();
02051
02052 this._data.clear();
02053
02054
02055 var pthis = this;
02056 var dom = this.select_main().node();
02057
02058 if (dom !== null) {
02059 dom.tabIndex = 0;
02060 dom.focus();
02061 dom.onkeypress = function(e) {
02062 if (!e) e = event;
02063 switch ( e.keyCode ) {
02064 case 87:
02065 case 119:
02066 pthis.toggleWireFrame(pthis._scene);
02067 break;
02068 }
02069 };
02070 dom.onclick = function(e) {
02071 dom.focus();
02072 };
02073 }
02074
02075 return this.DrawingReady();
02076 }
02077
02078
02079 JSROOT.TGeoPainter.prototype.Cleanup = function(first_time) {
02080
02081 if (first_time === undefined) {
02082 this.helpText();
02083 if (this._scene !== null)
02084 this.deleteChildren(this._scene);
02085 if ( this._tcontrols !== null)
02086 this._tcontrols.dispose();
02087 if (this._controls !== null)
02088 this._controls.dispose();
02089 }
02090
02091 this._scene = null;
02092 this._scene_width = 0;
02093 this._scene_height = 0;
02094 this._renderer = null;
02095 this._toplevel = null;
02096 this._stack = null;
02097 this._camera = null;
02098
02099 this.first_render_tm = 0;
02100
02101 this._controls = null;
02102 this._tcontrols = null;
02103 this._toolbar = null;
02104 }
02105
02106 JSROOT.TGeoPainter.prototype.helpText = function(msg) {
02107 JSROOT.progress(msg);
02108 }
02109
02110 JSROOT.TGeoPainter.prototype.CheckResize = function() {
02111
02112 var pad_painter = this.pad_painter();
02113
02114
02115
02116 if (pad_painter)
02117 if (!pad_painter.CheckCanvasResize(size, JSROOT.browser.isFirefox ? false : true)) return false;
02118
02119 var size3d = this.size_for_3d();
02120
02121 if ((this._scene_width === size3d.width) && (this._scene_height === size3d.height)) return false;
02122 if ((size3d.width<10) || (size3d.height<10)) return;
02123
02124 this._scene_width = size3d.width;
02125 this._scene_height = size3d.height;
02126
02127 this._camera.aspect = this._scene_width / this._scene_height;
02128 this._camera.updateProjectionMatrix();
02129
02130 this._renderer.setSize( this._scene_width, this._scene_height );
02131
02132 this.Render3D();
02133
02134 return true;
02135 }
02136
02137 JSROOT.TGeoPainter.prototype.ownedByTransformControls = function(child) {
02138 var obj = child.parent;
02139 while (obj && !(obj instanceof THREE.TransformControls) ) {
02140 obj = obj.parent;
02141 }
02142 return (obj && (obj instanceof THREE.TransformControls));
02143 }
02144
02145 JSROOT.TGeoPainter.prototype.toggleWireFrame = function(obj) {
02146 var painter = this;
02147
02148 var f = function(obj2) {
02149 if ( obj2.hasOwnProperty("material") && !(obj2 instanceof THREE.GridHelper) ) {
02150 if (!painter.ownedByTransformControls(obj2))
02151 obj2.material.wireframe = !obj2.material.wireframe;
02152 }
02153 }
02154 obj.traverse(f);
02155 this.Render3D();
02156 }
02157
02158 JSROOT.TGeoPainter.prototype.deleteChildren = function(obj) {
02159 if ((typeof obj['children'] != 'undefined') && (obj['children'] instanceof Array)) {
02160 for ( var i=obj.children.length-1; i>=0; i-- ) {
02161 var ob = obj.children[i];
02162 this.deleteChildren(ob);
02163 try {
02164 obj.remove(obj.children[i]);
02165 } catch(e) {}
02166 try {
02167 ob.geometry.dispose();
02168 ob.geometry = null;
02169 } catch(e) {}
02170 try {
02171 ob.material.dispose();
02172 ob.material = null;
02173 } catch(e) {}
02174 try {
02175 ob.texture.dispose();
02176 ob.texture = null;
02177 } catch(e) {}
02178 ob = null;
02179 obj.children[i] = null;
02180 }
02181 obj.children = null;
02182 }
02183 obj = null;
02184 }
02185
02186 JSROOT.Painter.drawGeometry = function(divid, geometry, opt) {
02187
02188
02189 JSROOT.extend(this, new JSROOT.TGeoPainter(geometry));
02190
02191 this.SetDivId(divid, 5);
02192
02193 return this.DrawGeometry(opt);
02194 }
02195
02196 JSROOT.Painter.drawGeoObject = function(divid, obj, opt) {
02197 if (obj === null) return this.DrawingReady();
02198
02199 var node = null;
02200
02201 if (('fShapeBits' in obj) && ('fShapeId' in obj)) {
02202 node = JSROOT.Create("TEveGeoShapeExtract");
02203 JSROOT.extend(node, { fTrans:null, fShape: obj, fRGBA: [ 0, 1, 0, 1], fElements: null, fRnrSelf: true });
02204 } else
02205 if ((obj._typename === 'TGeoVolumeAssembly') || (obj._typename === 'TGeoVolume'))
02206 node = obj;
02207
02208 if (node !== null) {
02209 JSROOT.extend(this, new JSROOT.TGeoPainter(node));
02210 this.SetDivId(divid, 5);
02211 return this.DrawGeometry(opt);
02212 }
02213
02214 return this.DrawingReady();
02215 }
02216
02217
02218
02219 JSROOT.Painter.drawAxis3D = function(divid, axis, opt) {
02220
02221 var painter = new JSROOT.TObjectPainter(axis);
02222
02223 if (!('_main' in axis))
02224 painter.SetDivId(divid);
02225
02226 painter['Draw3DAxis'] = function() {
02227 var main = this.main_painter();
02228
02229 if ((main === null) && ('_main' in this.GetObject()))
02230 main = this.GetObject()._main;
02231
02232 if ((main === null) || (main._toplevel === undefined))
02233 return console.warn('no geo object found for 3D axis drawing');
02234
02235 var box = new THREE.Box3().setFromObject(main._toplevel);
02236
02237 this.xmin = box.min.x; this.xmax = box.max.x;
02238 this.ymin = box.min.y; this.ymax = box.max.y;
02239 this.zmin = box.min.z; this.zmax = box.max.z;
02240
02241 this.options = { Logx: false, Logy: false, Logz: false };
02242
02243 this.size3d = 0;
02244
02245 this['DrawXYZ'] = JSROOT.Painter.HPainter_DrawXYZ;
02246
02247 this.toplevel = main._toplevel;
02248
02249 this.DrawXYZ();
02250
02251 main.adjustCameraPosition();
02252
02253 main.Render3D();
02254 }
02255
02256 painter.Draw3DAxis();
02257
02258 return painter.DrawingReady();
02259 }
02260
02261
02262
02263 JSROOT.expandGeoList = function(item, lst) {
02264 if ((lst==null) || !('arr' in lst) || (lst.arr.length==0)) return;
02265
02266 item['_more'] = true;
02267 item['_geolst'] = lst;
02268
02269 item['_get'] = function(item, itemname, callback) {
02270 if ('_geolst' in item)
02271 JSROOT.CallBack(callback, item, item._geolst);
02272
02273 if ('_geoobj' in item)
02274 return JSROOT.CallBack(callback, item, item._geoobj);
02275
02276 JSROOT.CallBack(callback, item, null);
02277 }
02278 item['_expand'] = function(node, lst) {
02279
02280 if (!('arr' in lst)) return false;
02281
02282 node['_childs'] = [];
02283
02284 for (var n in lst.arr) {
02285 var obj = lst.arr[n];
02286 var sub = {
02287 _kind : "ROOT." + obj._typename,
02288 _name : obj.fName,
02289 _title : obj.fTitle,
02290 _parent : node,
02291 _geoobj : obj
02292 };
02293
02294 if (obj._typename == "TGeoMaterial") sub._icon = "img_geomaterial"; else
02295 if (obj._typename == "TGeoMedium") sub._icon = "img_geomedium"; else
02296 if (obj._typename == "TGeoMixture") sub._icon = "img_geomixture";
02297
02298 node['_childs'].push(sub);
02299 }
02300
02301 return true;
02302 }
02303 };
02304
02305 JSROOT.provideGeoVisStyle = function(volume) {
02306 var res = "";
02307
02308 if (JSROOT.TestGeoAttBit(volume, JSROOT.EGeoVisibilityAtt.kVisThis))
02309 res += " geovis_this";
02310
02311 if (JSROOT.TestGeoAttBit(volume, JSROOT.EGeoVisibilityAtt.kVisDaughters))
02312 res += " geovis_daughters";
02313
02314 return res;
02315 }
02316
02317 JSROOT.provideGeoMenu = function(menu, item, hpainter) {
02318 if (! ('_volume' in item)) return false;
02319
02320 menu.add("separator");
02321 var vol = item._volume;
02322
02323 function ToggleMenuBit(arg) {
02324 JSROOT.ToggleGeoAttBit(vol, arg);
02325 item._icon = item._icon.split(" ")[0] + JSROOT.provideGeoVisStyle(vol);
02326 hpainter.UpdateTreeNode(item);
02327 }
02328
02329 menu.addchk(JSROOT.TestGeoAttBit(vol, JSROOT.EGeoVisibilityAtt.kVisNone), "Invisible",
02330 JSROOT.EGeoVisibilityAtt.kVisNone, ToggleMenuBit);
02331 menu.addchk(JSROOT.TestGeoAttBit(vol, JSROOT.EGeoVisibilityAtt.kVisThis), "Visible",
02332 JSROOT.EGeoVisibilityAtt.kVisThis, ToggleMenuBit);
02333 menu.addchk(JSROOT.TestGeoAttBit(vol, JSROOT.EGeoVisibilityAtt.kVisDaughters), "Daughters",
02334 JSROOT.EGeoVisibilityAtt.kVisDaughters, ToggleMenuBit);
02335 menu.addchk(JSROOT.TestGeoAttBit(vol, JSROOT.EGeoVisibilityAtt.kVisOneLevel), "1lvl daughters",
02336 JSROOT.EGeoVisibilityAtt.kVisOneLevel, ToggleMenuBit);
02337
02338 return true;
02339 }
02340
02341 JSROOT.geoIconClick = function(hitem) {
02342 if ((hitem==null) || (hitem._volume == null)) return false;
02343 JSROOT.ToggleGeoAttBit(hitem._volume, JSROOT.EGeoVisibilityAtt.kVisDaughters);
02344 hitem._icon = hitem._icon.split(" ")[0] + JSROOT.provideGeoVisStyle(hitem._volume);
02345 return true;
02346 }
02347
02348 JSROOT.getGeoShapeIcon = function(shape) {
02349 switch (shape._typename) {
02350 case "TGeoArb8" : return "img_geoarb8"; break;
02351 case "TGeoCone" : return "img_geocone"; break;
02352 case "TGeoConeSeg" : return "img_geoconeseg"; break;
02353 case "TGeoCompositeShape" : return "img_geocomposite"; break;
02354 case "TGeoTube" : return "img_geotube"; break;
02355 case "TGeoTubeSeg" : return "img_geotubeseg"; break;
02356 case "TGeoPara" : return "img_geopara"; break;
02357 case "TGeoParaboloid" : return "img_geoparab"; break;
02358 case "TGeoPcon" : return "img_geopcon"; break;
02359 case "TGeoPgon" : return "img_geopgon"; break;
02360 case "TGeoShapeAssembly" : return "img_geoassembly"; break;
02361 case "TGeoSphere" : return "img_geosphere"; break;
02362 case "TGeoTorus" : return "img_geotorus"; break;
02363 case "TGeoTrd1" : return "img_geotrd1"; break;
02364 case "TGeoTrd2" : return "img_geotrd2"; break;
02365 case "TGeoXtru" : return "img_geoxtru"; break;
02366 case "TGeoTrap" : return "img_geotrap"; break;
02367 case "TGeoGtra" : return "img_geogtra"; break;
02368 case "TGeoEltu" : return "img_geoeltu"; break;
02369 case "TGeoHype" : return "img_geohype"; break;
02370 case "TGeoCtub" : return "img_geoctub"; break;
02371 }
02372 return "img_geotube";
02373 }
02374
02375 JSROOT.expandGeoShape = function(parent, shape, itemname) {
02376 var item = {
02377 _kind : "ROOT." + shape._typename,
02378 _name : itemname,
02379 _title : shape._typename,
02380 _icon : JSROOT.getGeoShapeIcon(shape),
02381 _parent : parent,
02382 _shape : shape,
02383 _get : function(item, itemname, callback) {
02384 if ((item!==null) && ('_shape' in item))
02385 return JSROOT.CallBack(callback, item, item._shape);
02386 JSROOT.CallBack(callback, item, null);
02387 }
02388 };
02389
02390 if (!('_childs' in parent)) parent['_childs'] = [];
02391 parent._childs.push(item);
02392 return true;
02393 }
02394
02395 JSROOT.expandGeoVolume = function(parent, volume, arg) {
02396
02397 if ((parent == null) || (volume==null)) return false;
02398
02399
02400 if ('_childs' in parent)
02401 for (var n=0;n<parent._childs.length;++n)
02402 if (volume === parent._childs[n]._volume) return true;
02403
02404 var item = {
02405 _kind : "ROOT.TGeoVolume",
02406 _name : (arg!=null) ? arg : volume.fName,
02407 _title : volume.fTitle,
02408 _parent : parent,
02409 _volume : volume,
02410 _more : (volume.fNodes !== undefined) && (volume.fNodes !== null),
02411 _menu : JSROOT.provideGeoMenu,
02412 _icon_click : JSROOT.geoIconClick,
02413 _get : function(item, itemname, callback) {
02414 if ((item!=null) && ('_volume' in item))
02415 return JSROOT.CallBack(callback, item, item._volume);
02416
02417 JSROOT.CallBack(callback, item, null);
02418 }
02419 };
02420
02421 if (item['_more']) {
02422 item['_expand'] = function(node, obj) {
02423 var subnodes = obj.fNodes.arr;
02424 for (var i in subnodes)
02425 JSROOT.expandGeoVolume(node, subnodes[i].fVolume);
02426 return true;
02427 }
02428 } else
02429 if ((volume.fShape !== null) && (volume.fShape._typename === "TGeoCompositeShape") && (volume.fShape.fNode !== null)) {
02430 item['_more'] = true;
02431 item['_expand'] = function(node, obj) {
02432 JSROOT.expandGeoShape(node, obj.fShape.fNode.fLeft, 'Left');
02433 JSROOT.expandGeoShape(node, obj.fShape.fNode.fRight, 'Right');
02434 return true;
02435 }
02436 }
02437
02438 if (item._title == "")
02439 if (volume._typename != "TGeoVolume") item._title = volume._typename;
02440
02441 if (volume.fShape !== null) {
02442 if (item._title == "")
02443 item._title = volume.fShape._typename;
02444
02445 item._icon = JSROOT.getGeoShapeIcon(volume.fShape);
02446 }
02447
02448 if (!('_childs' in parent)) parent['_childs'] = [];
02449
02450 if (!('_icon' in item))
02451 item._icon = item['_more'] ? "img_geocombi" : "img_geobbox";
02452
02453 item._icon += JSROOT.provideGeoVisStyle(volume);
02454
02455
02456 for (var cnt=0;cnt<1000000;cnt++) {
02457 var curr_name = item._name;
02458 if (curr_name.length == 0) curr_name = "item";
02459 if (cnt>0) curr_name+= "_"+cnt;
02460
02461 for (var n in parent['_childs']) {
02462 if (parent['_childs'][n]['_name'] == curr_name) {
02463 curr_name = ""; break;
02464 }
02465 }
02466 if (curr_name.length > 0) {
02467 if (cnt>0) item._name = curr_name;
02468 break;
02469 }
02470 }
02471
02472 parent['_childs'].push(item);
02473
02474 return true;
02475 }
02476
02477 JSROOT.expandGeoManagerHierarchy = function(hitem, obj) {
02478 if ((hitem==null) || (obj==null)) return false;
02479
02480 hitem['_childs'] = [];
02481
02482 var item1 = { _name : "Materials", _kind : "Folder", _title : "list of materials" };
02483 JSROOT.expandGeoList(item1, obj.fMaterials);
02484 hitem['_childs'].push(item1);
02485
02486 var item2 = { _name : "Media", _kind : "Folder", _title : "list of media" };
02487 JSROOT.expandGeoList(item2, obj.fMedia);
02488 hitem['_childs'].push(item2);
02489
02490 var item3 = { _name : "Tracks", _kind : "Folder", _title : "list of tracks" };
02491 JSROOT.expandGeoList(item3, obj.fTracks);
02492 hitem['_childs'].push(item3);
02493
02494 JSROOT.expandGeoVolume(hitem, obj.fMasterVolume, "Volume");
02495
02496 return true;
02497 }
02498
02499 JSROOT.addDrawFunc({ name: "TGeoVolumeAssembly", icon: 'img_geoassembly', func: JSROOT.Painter.drawGeometry, expand: "JSROOT.expandGeoVolume", opt : "all;count;limit;maxlvl2" });
02500 JSROOT.addDrawFunc({ name: "TAxis3D", func: JSROOT.Painter.drawAxis3D });
02501
02502 return JSROOT.Painter;
02503
02504 }));
02505