5 if ( typeof define ===
"function" && define.amd ) {
7 define( [
'd3',
'JSRootPainter',
'JSRoot3DPainter',
'ThreeCSG' ], factory );
10 if (typeof JSROOT ==
'undefined')
11 throw new Error(
'JSROOT is not defined',
'JSRootGeoPainter.js');
13 if (typeof JSROOT.Painter !=
'object')
14 throw new Error(
'JSROOT.Painter is not defined',
'JSRootGeoPainter.js');
16 if (typeof d3 ==
'undefined')
17 throw new Error(
'd3 is not defined',
'JSRootGeoPainter.js');
19 if (typeof THREE ==
'undefined')
20 throw new Error(
'THREE is not defined',
'JSRootGeoPainter.js');
24 } (
function( d3, JSROOT ) {
26 if ( typeof define ===
"function" && define.amd )
27 JSROOT.loadScript(
'$$$style/JSRootGeoPainter.css');
33 JSROOT.GEO.createCube =
function( shape ) {
40 var geom =
new THREE.Geometry();
42 geom.vertices.push(
new THREE.Vector3( shape.fDX, shape.fDY, shape.fDZ ) );
43 geom.vertices.push(
new THREE.Vector3( shape.fDX, shape.fDY, -shape.fDZ ) );
44 geom.vertices.push(
new THREE.Vector3( shape.fDX, -shape.fDY, shape.fDZ ) );
45 geom.vertices.push(
new THREE.Vector3( shape.fDX, -shape.fDY, -shape.fDZ ) );
46 geom.vertices.push(
new THREE.Vector3(-shape.fDX, shape.fDY, -shape.fDZ ) );
47 geom.vertices.push(
new THREE.Vector3(-shape.fDX, shape.fDY, shape.fDZ ) );
48 geom.vertices.push(
new THREE.Vector3(-shape.fDX, -shape.fDY, -shape.fDZ ) );
49 geom.vertices.push(
new THREE.Vector3(-shape.fDX, -shape.fDY, shape.fDZ ) );
51 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];
54 var normals = [ 1,0,0, -1,0,0, 0,1,0, 0,-1,0, 0,0,1, 0,0,-1 ];
56 var color =
new THREE.Color();
58 for (var n=0; n < indicies.length; n+=3) {
59 if (n % 6 === 0) norm =
new THREE.Vector3(normals[n/2], normals[n/2+1], normals[n/2+2]);
60 var face =
new THREE.Face3( indicies[n], indicies[n+1], indicies[n+2], norm, color, 0);
61 geom.faces.push(face);
68 JSROOT.GEO.createPara =
function( shape ) {
70 var txy = shape.fTxy, txz = shape.fTxz, tyz = shape.fTyz;
72 var verticesOfShape = [
73 -shape.fZ*txz-txy*shape.fY-shape.fX, -shape.fY-shape.fZ*tyz, -shape.fZ,
74 -shape.fZ*txz+txy*shape.fY-shape.fX, shape.fY-shape.fZ*tyz, -shape.fZ,
75 -shape.fZ*txz+txy*shape.fY+shape.fX, shape.fY-shape.fZ*tyz, -shape.fZ,
76 -shape.fZ*txz-txy*shape.fY+shape.fX, -shape.fY-shape.fZ*tyz, -shape.fZ,
77 shape.fZ*txz-txy*shape.fY-shape.fX, -shape.fY+shape.fZ*tyz, shape.fZ,
78 shape.fZ*txz+txy*shape.fY-shape.fX, shape.fY+shape.fZ*tyz, shape.fZ,
79 shape.fZ*txz+txy*shape.fY+shape.fX, shape.fY+shape.fZ*tyz, shape.fZ,
80 shape.fZ*txz-txy*shape.fY+shape.fX, -shape.fY+shape.fZ*tyz, shape.fZ ];
82 var indicesOfFaces = [ 4,6,5, 4,7,6, 0,3,7, 7,4,0,
83 4,5,1, 1,0,4, 6,2,1, 1,5,6,
84 7,3,2, 2,6,7, 1,2,3, 3,0,1 ];
86 var geom =
new THREE.Geometry();
88 for (var i = 0; i < verticesOfShape.length; i += 3)
89 geom.vertices.push(
new THREE.Vector3( verticesOfShape[i], verticesOfShape[i+1], verticesOfShape[i+2] ) );
91 var color =
new THREE.Color();
93 for (var i = 0; i < indicesOfFaces.length; i += 3)
94 geom.faces.push(
new THREE.Face3( indicesOfFaces[i], indicesOfFaces[i+1], indicesOfFaces[i+2], null, color, 0 ) );
96 geom.computeFaceNormals();
102 JSROOT.GEO.createTrapezoid =
function( shape ) {
105 if (shape._typename ==
"TGeoTrd1") {
108 y1 = shape.fDy1; y2 = shape.fDy2;
111 var verticesOfShape = [
112 -shape.fDx1, y1, -shape.fDZ,
113 shape.fDx1, y1, -shape.fDZ,
114 shape.fDx1, -y1, -shape.fDZ,
115 -shape.fDx1, -y1, -shape.fDZ,
116 -shape.fDx2, y2, shape.fDZ,
117 shape.fDx2, y2, shape.fDZ,
118 shape.fDx2, -y2, shape.fDZ,
119 -shape.fDx2, -y2, shape.fDZ
122 var indicesOfFaces = [
123 4,6,5, 4,7,6, 0,3,7, 7,4,0,
124 4,5,1, 1,0,4, 6,2,1, 1,5,6,
125 7,3,2, 2,6,7, 1,2,3, 3,0,1 ];
127 var geometry =
new THREE.Geometry();
128 for (var i = 0; i < 24; i += 3)
129 geometry.vertices.push(
new THREE.Vector3( verticesOfShape[i], verticesOfShape[i+1], verticesOfShape[i+2] ) );
131 var color =
new THREE.Color();
133 for (var i = 0; i < 36; i += 3)
134 geometry.faces.push(
new THREE.Face3( indicesOfFaces[i], indicesOfFaces[i+1], indicesOfFaces[i+2], null, color, 0 ) );
136 geometry.computeFaceNormals();
141 JSROOT.GEO.createArb8 =
function( shape ) {
143 var verticesOfShape = [
144 shape.fXY[0][0], shape.fXY[0][1], -shape.fDZ,
145 shape.fXY[1][0], shape.fXY[1][1], -shape.fDZ,
146 shape.fXY[2][0], shape.fXY[2][1], -shape.fDZ,
147 shape.fXY[3][0], shape.fXY[3][1], -shape.fDZ,
148 shape.fXY[4][0], shape.fXY[4][1], shape.fDZ,
149 shape.fXY[5][0], shape.fXY[5][1], shape.fDZ,
150 shape.fXY[6][0], shape.fXY[6][1], shape.fDZ,
151 shape.fXY[7][0], shape.fXY[7][1], shape.fDZ
156 var indicesOfFaces = [
157 4,6,5, 4,7,6, 0,3,7, 7,4,0,
158 4,5,1, 1,0,4, 6,2,1, 1,5,6,
159 7,3,2, 2,6,7, 1,2,3, 3,0,1 ];
161 var geometry =
new THREE.Geometry();
162 for (var i = 0; i < 8; ++i) {
164 if ((i>0) && (verticesOfShape[ii] === verticesOfShape[ii-3]) &&
165 (verticesOfShape[ii+1] === verticesOfShape[ii-2]) &&
166 (verticesOfShape[ii+2] === verticesOfShape[ii-1])) {
167 indicies[i] = indicies[i-1];
171 indicies[i] = geometry.vertices.length;
173 geometry.vertices.push(
new THREE.Vector3( verticesOfShape[ii], verticesOfShape[ii+1], verticesOfShape[ii+2] ) );
176 var color =
new THREE.Color();
178 for (var i = 0; i < 36; i += 3) {
179 var a = indicies[indicesOfFaces[i]],
180 b = indicies[indicesOfFaces[i+1]],
181 c = indicies[indicesOfFaces[i+2]];
182 if ((a!==b) && (b!==c) && (a!==c))
183 geometry.faces.push(
new THREE.Face3( a, b, c, null, color, 0 ) );
186 geometry.computeFaceNormals();
191 JSROOT.GEO.createSphere =
function( shape, faces_limit ) {
192 var outerRadius = shape.fRmax;
193 var innerRadius = shape.fRmin;
194 var phiStart = shape.fPhi1 + 180;
195 var phiLength = shape.fPhi2 - shape.fPhi1;
196 var thetaStart = shape.fTheta1;
197 var thetaLength = shape.fTheta2 - shape.fTheta1;
198 var widthSegments = shape.fNseg;
199 var heightSegments = shape.fNz;
201 var noInside = (innerRadius <= 0);
203 if (faces_limit !== undefined) {
204 var fact = (noInside ? 2 : 4) * widthSegments * heightSegments / faces_limit;
206 widthSegments = Math.round(widthSegments/Math.sqrt(fact));
207 heightSegments = Math.round(heightSegments/Math.sqrt(fact));
211 var sphere =
new THREE.SphereGeometry( outerRadius, widthSegments, heightSegments,
212 phiStart*Math.PI/180, phiLength*Math.PI/180, thetaStart*Math.PI/180, thetaLength*Math.PI/180);
213 sphere.applyMatrix(
new THREE.Matrix4().makeRotationX( Math.PI / 2 ) );
215 var geometry =
new THREE.Geometry();
216 var color =
new THREE.Color();
219 for (var n=0; n < sphere.vertices.length; ++n)
220 geometry.vertices.push(sphere.vertices[n]);
223 for (var n=0; n < sphere.faces.length; ++n) {
224 var face = sphere.faces[n];
225 geometry.faces.push(
new THREE.Face3( face.a, face.b, face.c, null, color, 0 ) );
228 var shift = geometry.vertices.length;
232 if ((thetaLength === 180) && (phiLength === 360)) {
233 geometry.computeFaceNormals();
237 geometry.vertices.push(
new THREE.Vector3(0, 0, 0));
239 var k = innerRadius / outerRadius;
242 for (var n=0; n < sphere.vertices.length; ++n) {
243 var v = sphere.vertices[n];
244 geometry.vertices.push(
new THREE.Vector3(k*v.x, k*v.y, k*v.z));
246 for (var n=0; n < sphere.faces.length; ++n) {
247 var face = sphere.faces[n];
248 geometry.faces.push(
new THREE.Face3( shift+face.b, shift+face.a, shift+face.c, null, color, 0 ) );
252 if (thetaLength !== 180) {
254 for (var i = 0; i < widthSegments; ++i) {
256 geometry.faces.push(
new THREE.Face3( i+0, i+1, shift, null, color, 0 ) );
258 geometry.faces.push(
new THREE.Face3( i+0, i+1, i+shift, null, color, 0 ) );
259 geometry.faces.push(
new THREE.Face3( i+1, i+shift+1, i+shift, null, color, 0 ) );
263 var dshift = sphere.vertices.length - widthSegments - 1;
266 for (var i = dshift; i < dshift + widthSegments; ++i) {
268 geometry.faces.push(
new THREE.Face3( i+0, i+1, shift, null, color, 0 ) );
270 geometry.faces.push(
new THREE.Face3( i+1, i+0, i+shift, null, color, 0 ) );
271 geometry.faces.push(
new THREE.Face3( i+shift+1, i+1, i+shift, null, color, 0 ) );
276 if (phiLength !== 360) {
278 for (var j=0; j<heightSegments; j++) {
279 var i1 = j*(widthSegments+1);
280 var i2 = (j+1)*(widthSegments+1);
282 geometry.faces.push(
new THREE.Face3( i1, i2, shift, null, color, 0 ) );
284 geometry.faces.push(
new THREE.Face3( i2, i1, i1+shift, null, color, 0 ) );
285 geometry.faces.push(
new THREE.Face3( i2+shift, i2, i1+shift, null, color, 0 ));
289 for (var j=0;j<heightSegments;j++) {
290 var i1 = (j+1)*(widthSegments+1) - 1;
291 var i2 = (j+2)*(widthSegments+1) - 1;
293 geometry.faces.push(
new THREE.Face3( i1, i2, shift, null, color, 0 ) );
295 geometry.faces.push(
new THREE.Face3( i1, i2, i1+shift, null, color, 0 ) );
296 geometry.faces.push(
new THREE.Face3( i2, i2+shift, i1+shift, null, color, 0));
301 geometry.computeFaceNormals();
307 JSROOT.GEO.createTube =
function( shape ) {
308 var outerRadius1, innerRadius1, outerRadius2, innerRadius2;
309 if ((shape._typename ==
"TGeoCone") || (shape._typename ==
"TGeoConeSeg")) {
310 outerRadius1 = shape.fRmax2;
311 innerRadius1 = shape.fRmin2;
312 outerRadius2 = shape.fRmax1;
313 innerRadius2 = shape.fRmin1;
315 outerRadius1 = outerRadius2 = shape.fRmax;
316 innerRadius1 = innerRadius2 = shape.fRmin;
319 var hasrmin = (innerRadius1 > 0) || (innerRadius2 > 0);
322 if (innerRadius1 <= 0) { innerRadius1 = 0.0000001; console.warn(
'zero inner radius1 in tube - not yet supported'); }
323 if (innerRadius2 <= 0) { innerRadius2 = 0.0000001; console.warn(
'zero inner radius1 in tube - not yet supported'); }
326 var thetaStart = 0, thetaLength = 360;
327 if ((shape._typename ==
"TGeoConeSeg") || (shape._typename ==
"TGeoTubeSeg") || (shape._typename ==
"TGeoCtub")) {
328 thetaStart = shape.fPhi1;
329 thetaLength = shape.fPhi2 - shape.fPhi1;
332 var radiusSegments = Math.floor(thetaLength/6);
333 if (radiusSegments < 4) radiusSegments = 4;
335 var extrapnt = (thetaLength < 360) ? 1 : 0;
337 var nsegm = radiusSegments + extrapnt;
339 var phi0 = thetaStart*Math.PI/180, dphi = thetaLength/radiusSegments*Math.PI/180;
342 var _sin =
new Float32Array(nsegm), _cos =
new Float32Array(nsegm);
343 for (var seg=0; seg<nsegm; ++seg) {
344 _cos[seg] = Math.cos(phi0+seg*dphi);
345 _sin[seg] = Math.sin(phi0+seg*dphi);
348 var geometry =
new THREE.Geometry();
353 for (var seg=0; seg<nsegm; ++seg)
354 geometry.vertices.push(
new THREE.Vector3( innerRadius1*_cos[seg], innerRadius1*_sin[seg], shape.fDZ));
355 for (var seg=0; seg<nsegm; ++seg)
356 geometry.vertices.push(
new THREE.Vector3( innerRadius2*_cos[seg], innerRadius2*_sin[seg], -shape.fDZ));
358 geometry.vertices.push(
new THREE.Vector3( 0, 0, shape.fDZ));
359 geometry.vertices.push(
new THREE.Vector3( 0, 0, -shape.fDZ));
362 var shift = geometry.vertices.length;
365 for (var seg=0; seg<nsegm; ++seg)
366 geometry.vertices.push(
new THREE.Vector3( outerRadius1*_cos[seg], outerRadius1*_sin[seg], shape.fDZ));
367 for (var seg=0; seg<nsegm; ++seg)
368 geometry.vertices.push(
new THREE.Vector3( outerRadius2*_cos[seg], outerRadius2*_sin[seg], -shape.fDZ));
371 if (shape._typename ==
"TGeoCtub")
372 for (var n=0;n<geometry.vertices.length;++n) {
373 var vertex = geometry.vertices[n];
374 if (vertex.z<0) vertex.z = -shape.fDz-(vertex.x*shape.fNlow[0]+vertex.x*shape.fNlow[1])/shape.fNlow[2];
375 else vertex.z = shape.fDz-(vertex.y*shape.fNhigh[0]+vertex.y*shape.fNhigh[1])/shape.fNhigh[2];
378 var color =
new THREE.Color();
382 for (var seg=0; seg<radiusSegments; ++seg) {
383 var seg1 = (extrapnt === 1) ? (seg + 1) : (seg + 1) % radiusSegments;
384 geometry.faces.push(
new THREE.Face3( nsegm + seg, seg, seg1, null, color, 0 ) );
385 geometry.faces.push(
new THREE.Face3( nsegm + seg, seg1, nsegm + seg1, null, color, 0 ) );
389 for (var seg=0; seg<radiusSegments; ++seg) {
390 var seg1 = (extrapnt === 1) ? (seg + 1) : (seg + 1) % radiusSegments;
391 geometry.faces.push(
new THREE.Face3( shift+seg, shift + nsegm + seg, shift + seg1, null, color, 0 ) );
392 geometry.faces.push(
new THREE.Face3( shift + nsegm + seg, shift + nsegm + seg1, shift + seg1, null, color, 0 ) );
397 for (var i = 0; i < radiusSegments; ++i){
398 var i1 = (extrapnt === 1) ? (i+1) : (i+1) % radiusSegments;
400 geometry.faces.push(
new THREE.Face3( i, i+shift, i1, null, color, 0 ) );
401 geometry.faces.push(
new THREE.Face3( i+shift, i1+shift, i1, null, color, 0 ) );
403 geometry.faces.push(
new THREE.Face3( 0, i+shift, i1+shift, null, color, 0 ) );
408 for (var i = 0; i < radiusSegments; ++i) {
409 var i1 = (extrapnt === 1) ? (i+1) : (i+1) % radiusSegments;
411 geometry.faces.push(
new THREE.Face3( nsegm+i+shift, nsegm+i, nsegm+i1, null, color, 0 ) );
412 geometry.faces.push(
new THREE.Face3( nsegm+i+shift, nsegm+i1, nsegm+i1+shift, null, color, 0 ) );
414 geometry.faces.push(
new THREE.Face3( nsegm+i+shift, 1, nsegm+i1+shift, null, color, 0 ) );
419 if (extrapnt === 1) {
421 geometry.faces.push(
new THREE.Face3( 0, nsegm, shift+nsegm, null, color, 0 ) );
422 geometry.faces.push(
new THREE.Face3( 0, shift+nsegm, shift, null, color, 0 ) );
424 geometry.faces.push(
new THREE.Face3( 0, 1, shift+nsegm, null, color, 0 ) );
425 geometry.faces.push(
new THREE.Face3( 0, shift+nsegm, shift, null, color, 0 ) );
429 geometry.faces.push(
new THREE.Face3( radiusSegments, shift+2*radiusSegments+1, 2*radiusSegments+1, null, color, 0 ) );
430 geometry.faces.push(
new THREE.Face3( radiusSegments, shift + radiusSegments, shift+2*radiusSegments+1, null, color, 0 ) );
432 geometry.faces.push(
new THREE.Face3( 0, shift+2*radiusSegments+1, 1, null, color, 0 ) );
433 geometry.faces.push(
new THREE.Face3( 0, shift + radiusSegments, shift+2*radiusSegments+1, null, color, 0 ) );
437 geometry.computeFaceNormals();
443 JSROOT.GEO.createEltu =
function( shape ) {
444 var geometry =
new THREE.Geometry();
446 var radiusSegments = Math.floor(360/6);
449 var x =
new Float32Array(radiusSegments),
450 y =
new Float32Array(radiusSegments);
451 for (var seg=0; seg<radiusSegments; ++seg) {
452 var phi = seg/radiusSegments*2*Math.PI;
453 x[seg] = shape.fRmin*Math.cos(phi);
454 y[seg] = shape.fRmax*Math.sin(phi);
458 for (var seg=0; seg<radiusSegments; ++seg)
459 geometry.vertices.push(
new THREE.Vector3( x[seg], y[seg], -shape.fDZ));
460 geometry.vertices.push(
new THREE.Vector3( 0, 0, -shape.fDZ));
462 for (var seg=0; seg<radiusSegments; ++seg)
463 geometry.vertices.push(
new THREE.Vector3( x[seg], y[seg], +shape.fDZ));
464 geometry.vertices.push(
new THREE.Vector3( 0, 0, shape.fDZ));
466 var color =
new THREE.Color();
469 for (var seg=0; seg<radiusSegments; ++seg) {
470 var seg1 = (seg + 1) % radiusSegments;
471 geometry.faces.push(
new THREE.Face3( seg+radiusSegments+1, seg, seg1, null, color, 0 ) );
472 geometry.faces.push(
new THREE.Face3( seg+radiusSegments+1, seg1, seg1+radiusSegments+1, null, color, 0 ) );
476 for (var seg=0; seg<radiusSegments; ++seg)
477 geometry.faces.push(
new THREE.Face3( seg, radiusSegments, (seg + 1) % radiusSegments, null, color, 0 ));
480 var shift = radiusSegments + 1;
481 for (var seg=0; seg<radiusSegments; ++seg)
482 geometry.faces.push(
new THREE.Face3( shift+seg, shift+ (seg + 1) % radiusSegments, shift+radiusSegments, null, color, 0 ));
484 geometry.computeFaceNormals();
489 JSROOT.GEO.createTorus =
function( shape, faces_limit ) {
490 var radius = shape.fR;
491 var innerTube = shape.fRmin;
492 var outerTube = shape.fRmax;
493 var arc = shape.fDphi - shape.fPhi1;
494 var rotation = shape.fPhi1;
495 var radialSegments = 30;
496 var tubularSegments = Math.floor(arc/6);
497 if (tubularSegments < 8) tubularSegments = 8;
499 var hasrmin = innerTube > 0, hascut = arc !== 360;
501 if (faces_limit !== undefined) {
502 var fact = (hasrmin ? 4 : 2) * (radialSegments + 1) * tubularSegments / faces_limit;
504 radialSegments = Math.round(radialSegments/Math.sqrt(fact));
505 tubularSegments = Math.round(tubularSegments/Math.sqrt(fact));
509 var geometry =
new THREE.Geometry();
510 var color =
new THREE.Color();
512 var outerTorus =
new THREE.TorusGeometry( radius, outerTube, radialSegments, tubularSegments, arc*Math.PI/180);
513 outerTorus.applyMatrix(
new THREE.Matrix4().makeRotationZ(rotation*Math.PI/180) );
516 for (var n=0; n < outerTorus.vertices.length; ++n)
517 geometry.vertices.push(outerTorus.vertices[n]);
519 for (var n=0; n < outerTorus.faces.length; ++n) {
520 var face = outerTorus.faces[n];
521 geometry.faces.push(
new THREE.Face3( face.a, face.b, face.c, null, color, 0 ) );
524 var shift = geometry.vertices.length;
527 var innerTorus =
new THREE.TorusGeometry( radius, innerTube, radialSegments, tubularSegments, arc*Math.PI/180);
528 innerTorus.applyMatrix(
new THREE.Matrix4().makeRotationZ(rotation*Math.PI/180) );
531 for (var n=0; n < innerTorus.vertices.length; ++n)
532 geometry.vertices.push(innerTorus.vertices[n]);
534 for (var n=0; n < innerTorus.faces.length; ++n) {
535 var face = innerTorus.faces[n];
536 geometry.faces.push(
new THREE.Face3( shift+face.a, shift+face.c, shift+face.b, null, color, 0 ) );
540 geometry.vertices.push(
new THREE.Vector3(radius*Math.cos(rotation*Math.PI/180), radius*Math.sin(rotation*Math.PI/180),0));
541 geometry.vertices.push(
new THREE.Vector3(radius*Math.cos((rotation+arc)*Math.PI/180), radius*Math.sin((rotation+arc)*Math.PI/180),0));
546 for (var j=0;j<radialSegments;j++) {
547 var i1 = j*(tubularSegments+1);
548 var i2 = (j+1)*(tubularSegments+1);
550 geometry.faces.push(
new THREE.Face3( i2, i1+shift, i1, null, color, 0 ) );
551 geometry.faces.push(
new THREE.Face3( i2, i2+shift, i1+shift, null, color, 0 ));
553 geometry.faces.push(
new THREE.Face3( shift, i1, i2, null, color, 0 ));
558 for (var j=0;j<radialSegments;j++) {
559 var i1 = (j+1)*(tubularSegments+1)-1;
560 var i2 = (j+2)*(tubularSegments+1)-1;
562 geometry.faces.push(
new THREE.Face3( i2, i1, i1+shift, null, color, 0 ) );
563 geometry.faces.push(
new THREE.Face3( i2, i1+shift, i2+shift, null, color, 0 ));
565 geometry.faces.push(
new THREE.Face3( shift+1, i2, i1, null, color, 0 ));
570 geometry.computeFaceNormals();
576 JSROOT.GEO.createPolygon =
function( shape ) {
578 var thetaStart = shape.fPhi1, thetaLength = shape.fDphi;
580 var radiusSegments = 60;
581 if ( shape._typename ==
"TGeoPgon" ) {
582 radiusSegments = shape.fNedges;
584 radiusSegments = Math.floor(thetaLength/6);
585 if (radiusSegments < 4) radiusSegments = 4;
588 var geometry =
new THREE.Geometry();
590 var color =
new THREE.Color();
592 var phi0 = thetaStart*Math.PI/180, dphi = thetaLength/radiusSegments*Math.PI/180;
595 var _sin =
new Float32Array(radiusSegments+1), _cos =
new Float32Array(radiusSegments+1);
596 for (var seg=0;seg<=radiusSegments;++seg) {
597 _cos[seg] = Math.cos(phi0+seg*dphi);
598 _sin[seg] = Math.sin(phi0+seg*dphi);
601 var indxs = [[],[]], pnts = null, edges = null;
602 var layerVerticies = radiusSegments;
604 if (thetaLength !== 360) {
612 for (var side = 0; side < 2; ++side) {
614 var rside = (side === 0) ?
'fRmax' :
'fRmin';
615 var prev_indx = geometry.vertices.length;
617 for (var layer=0; layer < shape.fNz; ++layer) {
619 indxs[side][layer] = geometry.vertices.length;
622 var layerz = shape.fZ[layer], rad = shape[rside][layer];
624 if ((layer > 0) && (layer < shape.fNz-1)) {
625 if (((shape.fZ[layer-1] === layerz) && (shape[rside][layer-1] === rad)) ||
626 ((shape[rside][layer+1] === rad) && (shape[rside][layer-1] === rad))) {
630 indxs[side][layer] = indxs[side][layer-1];
636 if (rad <= 0.) rad = 0.000001;
638 var curr_indx = geometry.vertices.length;
641 for (var seg=0; seg < layerVerticies; ++seg)
642 geometry.vertices.push(
new THREE.Vector3( rad*_cos[seg], rad*_sin[seg], layerz ));
646 pnts.push(
new THREE.Vector2(rad, layerz));
647 edges.push(curr_indx);
649 if (rad < shape.fRmax[layer]) {
650 pnts.unshift(
new THREE.Vector2(rad, layerz));
651 edges.unshift(curr_indx);
656 for (var seg=0;seg < radiusSegments;++seg) {
657 var seg1 = (seg + 1) % layerVerticies;
658 geometry.faces.push(
new THREE.Face3( prev_indx + seg, (side === 0) ? (prev_indx + seg1) : (curr_indx + seg) , curr_indx + seg1, null, color, 0 ) );
659 geometry.faces.push(
new THREE.Face3( prev_indx + seg, curr_indx + seg1, (side === 0) ? (curr_indx + seg) : prev_indx + seg1, null, color, 0 ));
662 prev_indx = curr_indx;
667 for (var layer = 0; layer < shape.fNz; layer+= (shape.fNz-1)) {
668 if (shape.fRmin[layer] >= shape.fRmax[layer])
continue;
669 var inside = indxs[1][layer], outside = indxs[0][layer];
670 for (var seg=0; seg < radiusSegments; ++seg) {
671 var seg1 = (seg + 1) % layerVerticies;
672 geometry.faces.push(
new THREE.Face3( outside + seg, (layer===0) ? (inside + seg) : (outside + seg1), inside + seg1, null, color, 0 ) );
673 geometry.faces.push(
new THREE.Face3( outside + seg, inside + seg1, (layer===0) ? (outside + seg1) : (inside + seg), null, color, 0 ));
679 if (pnts.length === shape.fNz * 2) {
681 for (var layer = shape.fNz-1; layer>0; --layer) {
682 if (shape.fZ[layer] === shape.fZ[layer-1])
continue;
683 var right = 2*shape.fNz - 1 - layer;
684 faces.push([right, layer - 1, layer]);
685 faces.push([right, right + 1, layer-1]);
690 faces = THREE.ShapeUtils.triangulateShape(pnts, []);
693 for (var i = 0; i < faces.length; ++i) {
695 geometry.faces.push(
new THREE.Face3( edges[f[0]], edges[f[1]], edges[f[2]], null, color, 0) );
697 for (var i = 0; i < faces.length; ++i) {
699 geometry.faces.push(
new THREE.Face3( edges[f[0]] + radiusSegments, edges[f[2]] + radiusSegments, edges[f[1]] + radiusSegments, null, color, 0) );
703 geometry.computeFaceNormals();
709 JSROOT.GEO.createXtru =
function( shape ) {
711 var geometry =
new THREE.Geometry();
713 var fcolor =
new THREE.Color();
715 var prev = 0, curr = 0;
716 for (var layer = 0; layer < shape.fNz; ++layer) {
717 var layerz = shape.fZ[layer], scale = shape.fScale[layer];
720 curr = geometry.vertices.length;
723 for (var vert = 0; vert < shape.fNvert; ++vert)
724 geometry.vertices.push(
new THREE.Vector3( scale * shape.fX[vert], scale * shape.fY[vert], layerz ));
727 for (var vert = 0; vert < shape.fNvert; ++vert) {
728 var vert1 = (vert + 1) % shape.fNvert;
729 geometry.faces.push(
new THREE.Face3( prev + vert, curr + vert, curr + vert1, null, fcolor, 0 ) );
730 geometry.faces.push(
new THREE.Face3( prev + vert, curr + vert1, prev + vert1, null, fcolor, 0 ));
737 for (var vert = 0; vert < shape.fNvert; ++vert)
738 pnts.push(
new THREE.Vector2(shape.fX[vert], shape.fY[vert]));
739 var faces = THREE.ShapeUtils.triangulateShape(pnts, []);
741 for (var i = 0; i < faces.length; ++i) {
743 geometry.faces.push(
new THREE.Face3( face[1], face[0], face[2], null, fcolor, 0) );
744 geometry.faces.push(
new THREE.Face3( face[0] + curr, face[1] + curr, face[2] + curr, null, fcolor, 0) );
747 geometry.computeFaceNormals();
753 JSROOT.GEO.createParaboloid =
function( shape, faces_limit ) {
755 var radiusSegments = Math.round(360/6), heightSegments = 30;
757 if (faces_limit !== undefined) {
758 var fact = 2 * (radiusSegments+1) * (heightSegments+1) / faces_limit;
760 radiusSegments = Math.round(radiusSegments/Math.sqrt(fact));
761 heightSegments = Math.round(heightSegments/Math.sqrt(fact));
766 var _sin =
new Float32Array(radiusSegments), _cos =
new Float32Array(radiusSegments);
767 for (var seg=0;seg<radiusSegments;++seg) {
768 _cos[seg] = Math.cos(seg/radiusSegments*2*Math.PI);
769 _sin[seg] = Math.sin(seg/radiusSegments*2*Math.PI);
772 var geometry =
new THREE.Geometry();
773 var fcolor =
new THREE.Color();
775 var zmin = -shape.fDZ, zmax = shape.fDZ, rmin = shape.fRlo, rmax = shape.fRhi;
779 if (shape.fB > zmin) zmin = shape.fB;
781 if (shape.fB < zmax) zmax = shape.fB;
784 var ttmin = Math.atan2(zmin, rmin), ttmax = Math.atan2(zmax, rmax);
786 var prev_indx = 0, prev_radius = 0;
788 for (var layer = 0; layer <= heightSegments + 1; ++layer) {
789 var layerz = zmax, radius = 0;
791 if ((layer === heightSegments + 1) && (prev_radius === 0))
break;
794 case 0: layerz = zmin; radius = rmin;
break;
795 case heightSegments: layerz = zmax; radius = rmax;
break;
796 case heightSegments + 1: layerz = zmax; radius = 0;
break;
798 var tt = Math.tan(ttmin + (ttmax-ttmin) * layer / heightSegments);
799 var delta = tt*tt - 4*shape.fA*shape.fB;
800 radius = 0.5*(tt+Math.sqrt(delta))/shape.fA;
801 if (radius < 1e-6) radius = 0;
806 var curr_indx = geometry.vertices.length;
809 geometry.vertices.push(
new THREE.Vector3( 0, 0, layerz ));
811 for (var seg=0; seg<radiusSegments; ++seg)
812 geometry.vertices.push(
new THREE.Vector3( radius*_cos[seg], radius*_sin[seg], layerz));
817 for (var seg=0; seg<radiusSegments; ++seg) {
818 var seg1 = (seg+1) % radiusSegments;
819 if (prev_radius === 0) {
820 geometry.faces.push(
new THREE.Face3( prev_indx, curr_indx + seg1, curr_indx + seg, null, fcolor, 0) );
823 geometry.faces.push(
new THREE.Face3( prev_indx + seg, prev_indx + seg1, curr_indx, null, fcolor, 0) );
825 geometry.faces.push(
new THREE.Face3( prev_indx + seg, curr_indx + seg1, curr_indx + seg, null, fcolor, 0) );
826 geometry.faces.push(
new THREE.Face3( prev_indx + seg, prev_indx + seg1, curr_indx + seg1, null, fcolor, 0) );
831 prev_radius = radius;
832 prev_indx = curr_indx;
835 geometry.computeFaceNormals();
841 JSROOT.GEO.createHype =
function( shape, faces_limit ) {
843 if ((shape.fTin===0) && (shape.fTout===0))
844 return JSROOT.GEO.createTube(shape);
846 var radiusSegments = Math.round(360/6), heightSegments = 30;
848 if (faces_limit !== undefined) {
849 var fact = ((shape.fRmin <= 0) ? 2 : 4) * (radiusSegments+1) * (heightSegments+2) / faces_limit;
851 radiusSegments = Math.round(radiusSegments/Math.sqrt(fact));
852 heightSegments = Math.round(heightSegments/Math.sqrt(fact));
857 var _sin =
new Float32Array(radiusSegments), _cos =
new Float32Array(radiusSegments);
858 for (var seg=0;seg<radiusSegments;++seg) {
859 _cos[seg] = Math.cos(seg/radiusSegments*2*Math.PI);
860 _sin[seg] = Math.sin(seg/radiusSegments*2*Math.PI);
863 var geometry =
new THREE.Geometry();
864 var fcolor =
new THREE.Color();
866 var indexes = [[],[]];
869 for (var side=0;side<2;++side) {
872 if ((side===0) && (shape.fRmin <= 0)) {
873 indexes[side][0] = geometry.vertices.length;
874 geometry.vertices.push(
new THREE.Vector3( 0, 0, -shape.fDz ) );
875 indexes[side][heightSegments] = geometry.vertices.length;
876 geometry.vertices.push(
new THREE.Vector3( 0, 0, shape.fDz ) );
881 var r0 = (side===0) ? shape.fRmin : shape.fRmax;
882 var tsq = (side===0) ? shape.fTinsq : shape.fToutsq;
885 for (var layer=0;layer<=heightSegments;++layer) {
886 var layerz = -shape.fDz + layer/heightSegments*2*shape.fDz;
888 var radius = Math.sqrt(r0*r0+tsq*layerz*layerz);
889 var curr_indx = geometry.vertices.length;
891 indexes[side][layer] = curr_indx;
893 for (var seg=0; seg<radiusSegments; ++seg)
894 geometry.vertices.push(
new THREE.Vector3( radius*_cos[seg], radius*_sin[seg], layerz));
898 for (var seg=0; seg<radiusSegments; ++seg) {
899 var seg1 = (seg+1) % radiusSegments;
900 geometry.faces.push(
new THREE.Face3( prev_indx + seg, (side===0) ? (curr_indx + seg) : (prev_indx + seg1), curr_indx + seg1, null, fcolor, 0) );
901 geometry.faces.push(
new THREE.Face3( prev_indx + seg, curr_indx + seg1, (side===0) ? (prev_indx + seg1) : (curr_indx + seg), null, fcolor, 0) );
905 prev_indx = curr_indx;
910 for(var layer=0; layer<=heightSegments; layer+=heightSegments) {
911 var inside = indexes[0][layer], outside = indexes[1][layer];
912 for (var seg=0; seg<radiusSegments; ++seg) {
913 var seg1 = (seg+1) % radiusSegments;
914 if (shape.fRmin <= 0) {
915 geometry.faces.push(
new THREE.Face3( inside, outside + (layer===0 ? seg1 : seg), outside + (layer===0 ? seg : seg1), null, fcolor, 0) );
917 geometry.faces.push(
new THREE.Face3( inside + seg, (layer===0) ? (inside + seg1) : (outside + seg), outside + seg1, null, fcolor, 0) );
918 geometry.faces.push(
new THREE.Face3( inside + seg, outside + seg1, (layer===0) ? (outside + seg) : (inside + seg1), null, fcolor, 0) );
923 geometry.computeFaceNormals();
928 JSROOT.GEO.createMatrix =
function(matrix) {
930 if (matrix === null)
return null;
932 var translation_matrix = null, rotation_matrix = null;
934 if (matrix._typename ==
'TGeoTranslation') {
935 translation_matrix = matrix.fTranslation;
937 else if (matrix._typename ==
'TGeoRotation') {
938 rotation_matrix = matrix.fRotationMatrix;
940 else if (matrix._typename ==
'TGeoCombiTrans') {
941 translation_matrix = matrix.fTranslation;
942 if (matrix.fRotation !== null)
943 rotation_matrix = matrix.fRotation.fRotationMatrix;
945 else if (matrix._typename !==
'TGeoIdentity') {
946 console.log(
'unsupported matrix ' + matrix._typename);
949 if ((translation_matrix === null) && (rotation_matrix === null))
return null;
951 var res =
new THREE.Matrix4();
953 if (rotation_matrix !== null)
954 res.set(rotation_matrix[0], rotation_matrix[1], rotation_matrix[2], 0,
955 rotation_matrix[3], rotation_matrix[4], rotation_matrix[5], 0,
956 rotation_matrix[6], rotation_matrix[7], rotation_matrix[8], 0,
959 if (translation_matrix !== null)
960 res.setPosition(
new THREE.Vector3(translation_matrix[0], translation_matrix[1], translation_matrix[2]));
965 JSROOT.GEO.createComposite =
function ( shape, faces_limit ) {
967 if (faces_limit === undefined) faces_limit = 10000;
969 var geom1 = JSROOT.GEO.createGeometry(shape.fNode.fLeft, faces_limit / 2);
970 geom1.computeVertexNormals();
971 var matrix1 = JSROOT.GEO.createMatrix(shape.fNode.fLeftMat);
972 if (matrix1!==null) {
973 if (matrix1.determinant() < -0.9) console.warn(
'Axis reflection in composite shape - not supported');
974 geom1.applyMatrix(matrix1);
977 var geom2 = JSROOT.GEO.createGeometry(shape.fNode.fRight, faces_limit / 2);
978 geom2.computeVertexNormals();
979 var matrix2 = JSROOT.GEO.createMatrix(shape.fNode.fRightMat);
980 if (matrix2 !== null) {
981 if (matrix2.determinant() < -0.9) console.warn(
'Axis reflection in composite shape - not supported');
982 geom2.applyMatrix(matrix2);
985 var bsp1 =
new ThreeBSP(geom1);
986 var bsp2 =
new ThreeBSP(geom2);
989 if (shape.fNode._typename ===
'TGeoIntersection')
990 bsp = bsp1.intersect(bsp2);
992 if (shape.fNode._typename ===
'TGeoUnion')
993 bsp = bsp1.union(bsp2);
995 if (shape.fNode._typename ===
'TGeoSubtraction')
996 bsp = bsp1.subtract(bsp2);
999 console.warn(
'unsupported bool operation ' + shape.fNode._typename +
', use first geom');
1003 var res = bsp.toGeometry();
1011 JSROOT.GEO.createGeometry =
function( shape, limit ) {
1013 switch (shape._typename) {
1014 case "TGeoBBox":
return JSROOT.GEO.createCube( shape );
1015 case "TGeoPara":
return JSROOT.GEO.createPara( shape );
1017 case "TGeoTrd2":
return JSROOT.GEO.createTrapezoid( shape );
1020 case "TGeoGtra":
return JSROOT.GEO.createArb8( shape );
1021 case "TGeoSphere":
return JSROOT.GEO.createSphere( shape, limit );
1026 case "TGeoCtub":
return JSROOT.GEO.createTube( shape );
1027 case "TGeoEltu":
return JSROOT.GEO.createEltu( shape );
1028 case "TGeoTorus":
return JSROOT.GEO.createTorus( shape, limit );
1030 case "TGeoPgon":
return JSROOT.GEO.createPolygon( shape );
1031 case "TGeoXtru":
return JSROOT.GEO.createXtru( shape );
1032 case "TGeoParaboloid":
return JSROOT.GEO.createParaboloid( shape, limit );
1033 case "TGeoHype":
return JSROOT.GEO.createHype( shape, limit );
1034 case "TGeoCompositeShape":
return JSROOT.GEO.createComposite( shape, limit );
1035 case "TGeoShapeAssembly":
return new THREE.Geometry();
1048 JSROOT.EGeoVisibilityAtt = {
1049 kVisOverride : JSROOT.BIT(0),
1050 kVisNone : JSROOT.BIT(1),
1051 kVisThis : JSROOT.BIT(2),
1052 kVisDaughters : JSROOT.BIT(3),
1053 kVisOneLevel : JSROOT.BIT(4),
1054 kVisStreamed : JSROOT.BIT(5),
1055 kVisTouched : JSROOT.BIT(6),
1056 kVisOnScreen : JSROOT.BIT(7),
1057 kVisContainers : JSROOT.BIT(12),
1058 kVisOnly : JSROOT.BIT(13),
1059 kVisBranch : JSROOT.BIT(14),
1060 kVisRaytrace : JSROOT.BIT(15)
1063 JSROOT.TestGeoAttBit =
function(volume, f) {
1064 if (!(
'fGeoAtt' in volume))
return false;
1065 return (volume.fGeoAtt & f) !== 0;
1068 JSROOT.ToggleGeoAttBit =
function(volume, f) {
1069 if (!(
'fGeoAtt' in volume))
return false;
1071 volume.fGeoAtt = volume.fGeoAtt ^ (f & 0xffffff);
1074 JSROOT.TGeoPainter =
function( geometry ) {
1075 if ((geometry !== null) && (geometry._typename.indexOf(
'TGeoVolume') === 0))
1076 geometry = { _typename:
"TGeoNode", fVolume: geometry, fName:
"TopLevel" };
1078 JSROOT.TObjectPainter.call(
this, geometry);
1083 JSROOT.TGeoPainter.prototype = Object.create( JSROOT.TObjectPainter.prototype );
1085 JSROOT.TGeoPainter.prototype.CreateToolbar =
function(args) {
1086 if ( this._toolbar !== null )
return;
1090 title:
'Save as PNG',
1091 icon: JSROOT.ToolbarIcons.camera,
1093 var dataUrl = painter._renderer.domElement.toDataURL(
"image/png");
1094 dataUrl.replace(
"image/png",
"image/octet-stream");
1095 var link = document.createElement(
'a');
1096 if (typeof link.download ===
'string') {
1097 document.body.appendChild(link);
1098 link.download =
"geometry.png";
1099 link.href = dataUrl;
1101 document.body.removeChild(link);
1105 this._toolbar =
new JSROOT.Toolbar( this.select_main(), [buttonList] );
1108 JSROOT.TGeoPainter.prototype.decodeOptions =
function(opt) {
1109 var res = { _grid:
false, _bound:
false, _debug:
false, _full:
false, maxlvl: -1, _axis:
false, scale:
new THREE.Vector3(1,1,1) };
1111 var _opt = JSROOT.GetUrlOption(
'_grid');
1112 if (_opt !== null && _opt ==
"true") res._grid =
true;
1113 var _opt = JSROOT.GetUrlOption(
'_debug');
1114 if (_opt !== null && _opt ==
"true") { res._debug =
true; res._grid =
true; }
1115 if (_opt !== null && _opt ==
"bound") { res._debug =
true; res._grid =
true; res._bound =
true; }
1116 if (_opt !== null && _opt ==
"full") { res._debug =
true; res._grid =
true; res._full =
true; res._bound =
true; }
1118 opt = opt.toLowerCase();
1120 if (opt.indexOf(
"all")>=0) {
1122 opt = opt.replace(
"all",
" ");
1124 if (opt.indexOf(
"limit")>=0) {
1126 opt = opt.replace(
"limit",
" ");
1128 if (opt.indexOf(
"invx")>=0) {
1130 opt = opt.replace(
"invx",
" ");
1132 if (opt.indexOf(
"invy")>=0) {
1134 opt = opt.replace(
"invy",
" ");
1136 if (opt.indexOf(
"invz")>=0) {
1138 opt = opt.replace(
"invz",
" ");
1141 var p = opt.indexOf(
"maxlvl");
1143 res.maxlvl = parseInt(opt.substr(p+6, 1));
1144 opt = opt.replace(
"maxlvl" + res.maxlvl,
" ");
1147 if (opt.indexOf(
"d")>=0) res._debug =
true;
1148 if (opt.indexOf(
"g")>=0) res._grid =
true;
1149 if (opt.indexOf(
"b")>=0) res._bound =
true;
1150 if (opt.indexOf(
"f")>=0) res._full =
true;
1151 if (opt.indexOf(
"a")>=0) { res._axis =
true; res._yup =
false; }
1152 if (opt.indexOf(
"y")>=0) res._yup =
true;
1153 if (opt.indexOf(
"z")>=0) res._yup =
false;
1159 JSROOT.TGeoPainter.prototype.addControls =
function() {
1161 if (this._controls !== null)
return;
1165 this.select_main().property(
'flex_block_drag',
true);
1167 this._controls =
new THREE.OrbitControls(this._camera, this._renderer.domElement);
1168 this._controls.enableDamping =
false;
1169 this._controls.dampingFactor = 0.25;
1170 this._controls.enableZoom =
true;
1171 this._controls.target.copy(this._lookat);
1172 this._controls.update();
1174 this._controls.addEventListener(
'change',
function() { painter.Render3D(0); } );
1176 if ( this.options._debug ||
this.options._grid ) {
1177 this._tcontrols =
new THREE.TransformControls( this._camera, this._renderer.domElement );
1178 this._scene.add( this._tcontrols );
1179 this._tcontrols.attach( this._toplevel );
1182 window.addEventListener(
'keydown',
function ( event ) {
1183 switch ( event.keyCode ) {
1185 painter._tcontrols.setSpace( painter._tcontrols.space ===
"local" ?
"world" :
"local" );
1188 painter._tcontrols.setTranslationSnap( Math.ceil( painter._overall_size ) / 50 );
1189 painter._tcontrols.setRotationSnap( THREE.Math.degToRad( 15 ) );
1192 painter._tcontrols.setMode(
"translate" );
1195 painter._tcontrols.setMode(
"rotate" );
1198 painter._tcontrols.setMode(
"scale" );
1202 painter._tcontrols.setSize( painter._tcontrols.size + 0.1 );
1206 painter._tcontrols.setSize( Math.max( painter._tcontrols.size - 0.1, 0.1 ) );
1210 window.addEventListener(
'keyup',
function ( event ) {
1211 switch ( event.keyCode ) {
1213 painter._tcontrols.setTranslationSnap( null );
1214 painter._tcontrols.setRotationSnap( null );
1219 this._tcontrols.addEventListener(
'change',
function() { painter.Render3D(0); } );
1222 var raycaster =
new THREE.Raycaster(), INTERSECTED = null;
1224 function findIntersection(mouse) {
1229 raycaster.setFromCamera( mouse, painter._camera );
1230 var intersects = raycaster.intersectObjects(painter._scene.children,
true);
1231 if (intersects.length > 0) {
1233 for (var i = 0; i < intersects.length; ++i) {
1234 if (
'emissive' in intersects[i].
object.material) {
1235 pick = intersects[i].object;
1239 if (pick && INTERSECTED != pick) {
1242 var name = INTERSECTED.name;
1244 var p = INTERSECTED.parent;
1245 while ((p!==undefined) && (p!==null)) {
1246 if (
'name' in p) name = p.name+
'/'+name;
1257 function mousemove(e) {
1258 var mouse_x = (
'offsetX' in e) ? e.offsetX : e.layerX;
1259 var mouse_y = (
'offsetY' in e) ? e.offsetY : e.layerY;
1260 var mouse = { x: (mouse_x / painter._renderer.domElement.width) * 2 - 1,
1261 y: -(mouse_y / painter._renderer.domElement.height) * 2 + 1 };
1263 findIntersection(mouse);
1267 this._renderer.domElement.addEventListener(
'mousemove', mousemove);
1270 JSROOT.TGeoPainter.prototype.accountClear =
function() {
1272 this._num_vertices = 0;
1273 this._num_faces = 0;
1274 this._num_meshes = 0;
1277 JSROOT.TGeoPainter.prototype.accountGeom =
function(geom, shape_typename) {
1279 if (geom === null) {
1280 if (!(
'unsupported_shapes' in
this)) this.unsupported_shapes = [];
1281 if ((shape_typename !== undefined) && (this.unsupported_shapes.indexOf(shape_typename) < 0)) {
1282 this.unsupported_shapes.push(shape_typename);
1283 console.warn(
'Not supported ' + shape_typename);
1289 if ((
'vertices' in geom) && (
'faces' in geom)) {
1290 this._num_vertices += geom.vertices.length;
1291 this._num_faces += geom.faces.length;
1294 var attr = geom.getAttribute(
'position');
1300 JSROOT.TGeoPainter.prototype.accountMesh =
function(mesh) {
1302 if (mesh !== null) this._num_meshes++;
1305 JSROOT.TGeoPainter.prototype.checkFlipping =
function(parent, matrix, shape, geom, mesh_has_childs) {
1308 var m =
new THREE.Matrix4();
1309 m.multiplyMatrices( parent.matrixWorld, matrix);
1310 if (m.determinant() > -0.9)
return geom;
1313 if (mesh_has_childs)
return null;
1315 var cnt = 0, flip =
new THREE.Vector3(1,1,1);
1317 if (m.elements[0]===-1 && m.elements[1]=== 0 && m.elements[2] === 0) { flip.x = -1; cnt++; }
1318 if (m.elements[4]=== 0 && m.elements[5]===-1 && m.elements[6] === 0) { flip.y = -1; cnt++; }
1319 if (m.elements[8]=== 0 && m.elements[9]=== 0 && m.elements[10]===-1) { flip.z = -1; cnt++; }
1321 if ((cnt===0) || (cnt ===2)) {
1322 flip.set(1,1,1); cnt = 0;
1323 if (m.elements[0] + m.elements[1] + m.elements[2] === -1) { flip.x = -1; cnt++; }
1324 if (m.elements[4] + m.elements[5] + m.elements[6] === -1) { flip.y = -1; cnt++; }
1325 if (m.elements[8] + m.elements[9] + m.elements[10] === -1) { flip.z = -1; cnt++; }
1326 if ((cnt === 0) || (cnt === 2)) {
1334 var gname =
"_geom";
1335 if (flip.x<0) gname +=
"X";
1336 if (flip.y<0) gname +=
"Y";
1337 if (flip.z<0) gname +=
"Z";
1340 if (gname in shape)
return shape[gname];
1342 geom = geom.clone();
1344 geom.scale(flip.x, flip.y, flip.z);
1347 for (var n=0;n<geom.faces.length;++n) {
1348 face = geom.faces[n];
1349 d = face.b; face.b = face.c; face.c = d;
1353 geom.computeFaceNormals();
1355 shape[gname] = geom;
1357 this.accountGeom(geom);
1362 JSROOT.TGeoPainter.prototype.getNodeProperties =
function(node, visible) {
1365 var volume = node.fVolume;
1367 var prop = { shape: volume.fShape, matrix: null };
1369 if ((
'fMatrix' in node) && (node.fMatrix !== null))
1370 prop.matrix = JSROOT.GEO.createMatrix(node.fMatrix);
1372 if ((node._typename ==
"TGeoNodeOffset") && (node.fFinder !== null)) {
1382 if ((node.fFinder._typename ===
'TGeoPatternX') ||
1383 (node.fFinder._typename ===
'TGeoPatternY') ||
1384 (node.fFinder._typename ===
'TGeoPatternZ')) {
1385 var _shift = node.fFinder.fStart + (node.fIndex + 0.5) * node.fFinder.fStep;
1387 prop.matrix =
new THREE.Matrix4();
1389 switch (node.fFinder._typename.charAt(11)) {
1390 case 'X': prop.matrix.setPosition(
new THREE.Vector3(_shift, 0, 0));
break;
1391 case 'Y': prop.matrix.setPosition(
new THREE.Vector3(0, _shift, 0));
break;
1392 case 'Z': prop.matrix.setPosition(
new THREE.Vector3(0, 0, _shift));
break;
1395 if (node.fFinder._typename ===
'TGeoPatternCylPhi') {
1396 var phi = (Math.PI/180)*(node.fFinder.fStart+(node.fIndex+0.5)*node.fFinder.fStep);
1397 var _cos = Math.cos(phi), _sin = Math.sin(phi);
1399 prop.matrix =
new THREE.Matrix4();
1401 prop.matrix.set(_cos, -_sin, 0, 0,
1406 console.warn(
'Unsupported pattern type ' + node.fFinder._typename);
1410 prop.material = null;
1413 var _transparent =
false, _opacity = 1.0;
1414 if ((volume.fFillColor > 1) && (volume.fLineColor == 1))
1415 prop.fillcolor = JSROOT.Painter.root_colors[volume.fFillColor];
1417 if (volume.fLineColor >= 0)
1418 prop.fillcolor = JSROOT.Painter.root_colors[volume.fLineColor];
1420 if ((
'fMedium' in volume) && (volume.fMedium !== null) &&
1421 (
'fMaterial' in volume.fMedium) && (volume.fMedium.fMaterial !== null)) {
1422 var fillstyle = volume.fMedium.fMaterial.fFillStyle;
1423 var transparency = (fillstyle < 3000 || fillstyle > 3100) ? 0 : fillstyle - 3000;
1424 if (transparency > 0) {
1425 _transparent =
true;
1426 _opacity = (100.0 - transparency) / 100.0;
1428 if (prop.fillcolor === undefined)
1429 prop.fillcolor = JSROOT.Painter.root_colors[volume.fMedium.fMaterial.fFillColor];
1431 if (prop.fillcolor === undefined)
1432 prop.fillcolor =
"lightgrey";
1434 prop.material =
new THREE.MeshLambertMaterial( { transparent: _transparent,
1435 opacity: _opacity, wireframe:
false, color: prop.fillcolor,
1436 side: THREE.FrontSide, vertexColors: THREE.NoColors ,
1443 JSROOT.TGeoPainter.prototype.getEveNodeProperties =
function(node, visible) {
1445 var prop = { shape: node.fShape };
1447 prop.material = null;
1450 var _transparent =
false, _opacity = 1.0;
1451 if ( node.fRGBA[3] < 1.0) {
1452 _transparent =
true;
1453 _opacity = node.fRGBA[3];
1455 prop.fillcolor =
new THREE.Color( node.fRGBA[0], node.fRGBA[1], node.fRGBA[2] );
1456 prop.material =
new THREE.MeshLambertMaterial( { transparent: _transparent,
1457 opacity: _opacity, wireframe:
false, color: prop.fillcolor,
1458 side: THREE.FrontSide, vertexColors: THREE.NoColors ,
1462 prop.matrix =
new THREE.Matrix4();
1464 if (node.fTrans!==null) {
1465 prop.matrix.set(node.fTrans[0], node.fTrans[4], node.fTrans[8], 0,
1466 node.fTrans[1], node.fTrans[5], node.fTrans[9], 0,
1467 node.fTrans[2], node.fTrans[6], node.fTrans[10], 0,
1470 prop.matrix.setPosition({ x: node.fTrans[12], y: node.fTrans[13], z: node.fTrans[14] });
1476 JSROOT.TGeoPainter.prototype.drawNode =
function() {
1478 if ((this._stack == null) || (this._stack.length == 0))
return false;
1480 var arg = this._stack[this._stack.length - 1];
1485 var kind = this.NodeKind(arg.node);
1486 if (kind < 0)
return false;
1490 chlds = (arg.node.fVolume.fNodes !== null) ? arg.node.fVolume.fNodes.arr : null;
1492 chlds = (arg.node.fElements !== null) ? arg.node.fElements.arr : null;
1495 if (
'nchild' in arg) {
1497 if ((chlds === null) || (chlds.length <= arg.nchild)) {
1500 this._stack.push({ toplevel: (arg.mesh ? arg.mesh : arg.toplevel),
1501 node: chlds[arg.nchild++] });
1509 prop = this.getNodeProperties(arg.node, arg.node._visible);
1511 prop = this.getEveNodeProperties(arg.node, arg.node._visible);
1515 if (prop.matrix === null) prop.matrix =
new THREE.Matrix4();
1517 if ((prop.shape === null) && arg.node._visible)
1518 arg.node._visible =
false;
1520 if (arg.node._visible) {
1521 if (typeof prop.shape._geom ===
'undefined') {
1522 prop.shape._geom = JSROOT.GEO.createGeometry(prop.shape);
1523 this.accountGeom(prop.shape._geom, prop.shape._typename);
1526 geom = prop.shape._geom;
1529 if (this._dummy_material === undefined)
1530 this._dummy_material =
1531 new THREE.MeshLambertMaterial( { transparent:
true, opacity: 0, wireframe:
false,
1532 color:
'white', vertexColors: THREE.NoColors,
1533 overdraw: 0., depthWrite :
false, depthTest:
false, visible:
false } );
1535 prop.material = this._dummy_material;
1538 var has_childs = (chlds !== null) && (chlds.length > 0);
1539 var work_around =
false;
1542 if (arg.main && (
this.options.scale !== null)) {
1543 if ((this.options.scale.x<0) || (this.options.scale.y<0) || (this.options.scale.z<0)) {
1544 prop.matrix.scale(this.options.scale);
1548 if (arg.node._visible && (geom !== null)) {
1549 geom = this.checkFlipping(arg.toplevel, prop.matrix, prop.shape, geom, has_childs);
1550 work_around = has_childs && (geom === null);
1553 if (geom === null) geom =
new THREE.Geometry();
1555 var mesh =
new THREE.Mesh( geom, prop.material );
1557 mesh.applyMatrix(prop.matrix);
1559 this.accountMesh(mesh);
1561 mesh.name = arg.node.fName;
1564 arg.toplevel.add(mesh);
1566 mesh.updateMatrixWorld();
1569 JSROOT.console(
'perform workaroud for flipping mesh with childs');
1571 prop.matrix.identity();
1573 geom = this.checkFlipping(mesh, prop.matrix, prop.shape, prop.shape._geom,
false);
1575 var dmesh =
new THREE.Mesh( geom, prop.material );
1577 dmesh.applyMatrix(prop.matrix);
1584 dmesh.updateMatrixWorld();
1587 if (this.options._debug && (arg.node._visible ||
this.options._full)) {
1588 var helper =
new THREE.WireframeHelper(mesh);
1589 helper.material.color.set(prop.fillcolor);
1590 helper.material.linewidth = (
'fVolume' in arg.node) ? arg.node.fVolume.fLineWidth : 1;
1591 arg.toplevel.add(helper);
1594 if (this.options._bound && (arg.node._visible ||
this.options._full)) {
1595 var boxHelper =
new THREE.BoxHelper( mesh );
1596 arg.toplevel.add( boxHelper );
1601 if ((chlds === null) || (chlds.length == 0)) {
1611 JSROOT.TGeoPainter.prototype.NodeKind =
function(obj) {
1612 if ((obj === undefined) || (obj === null) || (typeof obj !==
'object'))
return -1;
1613 return (
'fShape' in obj) && (
'fTrans' in obj) ? 1 : 0;
1616 JSROOT.TGeoPainter.prototype.CountGeoVolumes =
function(obj, arg, lvl) {
1620 var kind = this.NodeKind(obj);
1621 if (kind < 0)
return 0;
1623 if (lvl === undefined) {
1625 if (!arg) arg = { erase:
true };
1626 if (!(
'map' in arg)) arg.map = [];
1628 if (!(
'clear' in arg))
1629 arg.clear =
function() {
1630 for (var n=0;n<this.map.length;++n) {
1631 delete this.map[n]._refcnt;
1632 delete this.map[n]._numchld;
1633 delete this.map[n]._visible;
1640 var chlds = null, shape = null, vis =
false;
1642 if ((obj.fVolume === undefined) || (obj.fVolume === null))
return 0;
1643 shape = obj.fVolume.fShape;
1644 chlds = (obj.fVolume.fNodes !== null) ? obj.fVolume.fNodes.arr : null;
1645 vis = JSROOT.TestGeoAttBit(obj.fVolume, JSROOT.EGeoVisibilityAtt.kVisOnScreen)
1646 || ((lvl < arg.maxlvl) && JSROOT.TestGeoAttBit(obj.fVolume, JSROOT.EGeoVisibilityAtt.kVisThis));
1648 if (obj.fShape === undefined)
return 0;
1650 chlds = (obj.fElements !== null) ? obj.fElements.arr : null;
1651 vis = obj[
'fRnrSelf'];
1655 if (arg.cnt[lvl] === undefined) arg.cnt[lvl] = 0;
1659 if (
'_refcnt' in obj) {
1680 if (vis && !(
'_visible' in obj) && (shape!==null)) {
1681 obj._visible =
true;
1686 for (var i = 0; i < chlds.length; ++i)
1687 obj._numchld +=
this.CountGeoVolumes(chlds[i], arg, lvl+1);
1690 if ((lvl === 0) && arg.erase) arg.clear();
1692 return 1 + obj._numchld;
1695 JSROOT.TGeoPainter.prototype.SameMaterial =
function(node1, node2) {
1697 if ((node1===null) || (node2===null))
return node1 === node2;
1699 if (node1.fVolume.fLineColor >= 0)
1700 return (node1.fVolume.fLineColor === node2.fVolume.fLineColor);
1702 var m1 = (node1.fVolume[
'fMedium'] !== null) ? node1.fVolume[
'fMedium'][
'fMaterial'] : null;
1703 var m2 = (node2.fVolume[
'fMedium'] !== null) ? node2.fVolume[
'fMedium'][
'fMaterial'] : null;
1705 if (m1 === m2)
return true;
1707 if ((m1 === null) || (m2 === null))
return false;
1709 return (m1.fFillStyle === m2.fFillStyle) && (m1.fFillColor === m2.fFillColor);
1712 JSROOT.TGeoPainter.prototype.ScanUniqueVisVolumes =
function(obj, lvl, arg) {
1713 if ((obj === undefined) || (obj===null) || (typeof obj !==
'object') ||
1714 (obj.fVolume === undefined) || (obj.fVolume == null))
return 0;
1718 arg.vis_unique =
true;
1719 arg.vis_master = null;
1720 arg.same_material =
true;
1723 var res = obj._visible ? 1 : 0;
1725 if (obj._refcnt > 1) arg.vis_unique =
false;
1726 if (arg.master!==null)
1727 if (!this.SameMaterial(arg.master, obj)) arg.same_material =
false;
1729 var top_unique = arg.vis_unique;
1730 arg.vis_unique =
true;
1732 var top_master = arg.master, top_same = arg.same_material;
1734 arg.master = obj._visible ? obj : null;
1735 arg.same_material =
true;
1737 var arr = (obj.fVolume.fNodes !== null) ? obj.fVolume.fNodes.arr : null;
1741 for (var i = 0; i < arr.length; ++i)
1742 numvis += this.ScanUniqueVisVolumes(arr[i], lvl+1, arg);
1744 obj._numvis = numvis;
1745 obj._visunique = arg.vis_unique;
1746 obj._samematerial = arg.same_material;
1748 if (obj._samematerial) {
1749 if (top_same && (top_master!=null) && (arg.master!==null))
1750 arg.same_material = this.SameMaterial(top_master, arg.master);
1752 arg.same_material = top_same;
1754 if (top_master !== null) arg.master = top_master;
1757 arg.same_material =
false;
1760 arg.vis_unique = top_unique && obj._visunique;
1762 return res + numvis;
1765 JSROOT.TGeoPainter.prototype.createScene =
function(webgl, w, h, pixel_ratio) {
1767 this._scene =
new THREE.Scene();
1768 this._scene.fog =
new THREE.Fog(0xffffff, 500, 300000);
1770 this._scene_width = w;
1771 this._scene_height = h;
1773 this._camera =
new THREE.PerspectiveCamera(25, w / h, 1, 100000);
1775 this._renderer = webgl ?
1776 new THREE.WebGLRenderer({ antialias :
true, logarithmicDepthBuffer:
true,
1777 preserveDrawingBuffer:
true }) :
1778 new THREE.CanvasRenderer({antialias :
true });
1779 this._renderer.setPixelRatio(pixel_ratio);
1780 this._renderer.setClearColor(0xffffff, 1);
1781 this._renderer.setSize(w, h);
1783 var pointLight =
new THREE.PointLight(0xefefef);
1784 this._camera.add( pointLight );
1785 pointLight.position.set(10, 10, 10);
1786 this._camera.up = this.options._yup ?
new THREE.Vector3(0,1,0) :
new THREE.Vector3(0,0,1);
1787 this._scene.add( this._camera );
1789 this._toplevel =
new THREE.Object3D();
1791 this._scene.add(this._toplevel);
1793 this._overall_size = 10;
1797 JSROOT.TGeoPainter.prototype.startDrawGeometry =
function() {
1798 if (this.MatchObjectType(
"TGeoNode")) {
1799 this._nodedraw =
true;
1800 this._stack = [ { toplevel: this._toplevel, node: this.GetObject(), main:
true } ];
1802 else if (this.MatchObjectType(
'TEveGeoShapeExtract')) {
1803 this._nodedraw =
false;
1804 this._stack = [ { toplevel: this._toplevel, node: this.GetObject(), main:
true } ];
1807 this.accountClear();
1810 JSROOT.TGeoPainter.prototype.adjustCameraPosition =
function() {
1812 var box =
new THREE.Box3().setFromObject(this._toplevel);
1814 var sizex = box.max.x - box.min.x,
1815 sizey = box.max.y - box.min.y,
1816 sizez = box.max.z - box.min.z,
1817 midx = (box.max.x + box.min.x)/2,
1818 midy = (box.max.y + box.min.y)/2,
1819 midz = (box.max.z + box.min.z)/2;
1821 this._overall_size = 2 * Math.max( sizex, sizey, sizez);
1823 this._camera.near = this._overall_size / 500;
1824 this._camera.far = this._overall_size * 500;
1825 this._camera.updateProjectionMatrix();
1832 if (this.options._yup)
1833 this._camera.position.set(midx-2*Math.max(sizex,sizez), midy+2*sizey, midz-2*Math.max(sizex,sizez));
1835 this._camera.position.set(midx-2*Math.max(sizex,sizey), midy-2*Math.max(sizex,sizey), midz+2*sizez);
1838 this._lookat =
new THREE.Vector3(midx, midy, midz);
1839 this._camera.lookAt(this._lookat);
1841 if (this._controls !== null) {
1842 this._controls.target.copy(this._lookat);
1843 this._controls.update();
1847 JSROOT.TGeoPainter.prototype.completeScene =
function() {
1848 if ( this.options._debug ||
this.options._grid ) {
1849 if ( this.options._full ) {
1850 var boxHelper =
new THREE.BoxHelper(this._toplevel);
1851 this._scene.add( boxHelper );
1853 this._scene.add(
new THREE.AxisHelper( 2 *
this._overall_size ) );
1854 this._scene.add(
new THREE.GridHelper( Math.ceil(
this._overall_size), Math.ceil( this._overall_size ) / 50 ) );
1855 this.helpText(
"<font face='verdana' size='1' color='red'><center>Transform Controls<br>" +
1856 "'T' translate | 'R' rotate | 'S' scale<br>" +
1857 "'+' increase size | '-' decrease size<br>" +
1858 "'W' toggle wireframe/solid display<br>"+
1859 "keep 'Ctrl' down to snap to grid</center></font>");
1863 JSROOT.TGeoPainter.prototype.drawCount =
function() {
1865 var tm1 =
new Date();
1867 var arg = { cnt : [], maxlvl: -1 };
1868 var cnt = this.CountGeoVolumes(this.GetObject(), arg);
1870 var res =
'Total number: ' + cnt +
'<br/>';
1871 for (var lvl=0;lvl<arg.cnt.length;++lvl) {
1872 if (arg.cnt[lvl] !== 0)
1873 res += (
' lvl' + lvl +
': ' + arg.cnt[lvl] +
'<br/>');
1875 res +=
"Unique volumes: " + arg.map.length +
'<br/>';
1877 if (arg.viscnt === 0) {
1878 arg.clear(); arg.maxlvl = 9999;
1879 cnt = this.CountGeoVolumes(this.GetObject(), arg);
1882 res +=
"Visible volumes: " + arg.viscnt +
'<br/>';
1885 this.ScanUniqueVisVolumes(this.GetObject(), 0, arg);
1887 for (var n=0;n<arg.map.length;++n)
1888 if (arg.map[n]._refcnt > 1) {
1889 res += (arg.map[n]._visible ?
"vis" :
"map") + n +
" " + arg.map[n].fName +
" nref:"+arg.map[n]._refcnt +
1890 ' chld:'+ arg.map[n]._numvis +
"(" + arg.map[n]._numchld +
')' +
1891 " unique:" + arg.map[n]._visunique +
" same:" + arg.map[n]._samematerial;
1893 if (arg.map[n]._samematerial) {
1894 if (arg.map[n]._visunique && (arg.map[n]._numvis>0)) res+=
" (can merge with childs in Worker)";
else
1895 if ((arg.map[n]._refcnt > 4) && (arg.map[n]._numvis>1)) res+=
" (make sense merge in main thread)";
1902 var tm2 =
new Date();
1904 res +=
"Elapsed time: " + (tm2.getTime() - tm1.getTime()) +
"ms <br/>";
1906 this.select_main().style(
'overflow',
'auto').html(res);
1908 return this.DrawingReady();
1912 JSROOT.TGeoPainter.prototype.DrawGeometry =
function(opt) {
1913 if (typeof opt !==
'string') opt =
"";
1915 if (opt ===
'count')
1916 return this.drawCount();
1918 var size = this.size_for_3d();
1920 this.options = this.decodeOptions(opt);
1922 if (!(
'_yup' in this.options))
1923 this.options._yup = this.svg_canvas().empty();
1925 this._webgl = JSROOT.Painter.TestWebGL();
1927 this._data = { cnt: [], maxlvl : this.options.maxlvl };
1929 var total = this.CountGeoVolumes(this.GetObject(), this._data);
1932 if ((total>0) && (this._data.viscnt == 0) && (
this.options.maxlvl < 0)) {
1934 this._data.maxlvl = 1111;
1935 total = this.CountGeoVolumes(this.GetObject(), this._data);
1938 var maxlimit = this._webgl ? 1e7 : 1e4;
1940 if ((this._data.maxlvl === 1111) && (total > maxlimit)) {
1942 for (var lvl=1; lvl < this._data.cnt.length; ++lvl) {
1943 sum += this._data.cnt.cnt[lvl];
1944 if (sum > maxlimit) {
1945 this._data.maxlvl = lvl - 1;
1947 this.CountGeoVolumes(this.GetObject(), this._data);
1953 this.createScene(this._webgl, size.width, size.height, window.devicePixelRatio);
1955 this.add_3d_canvas(size, this._renderer.domElement);
1957 this.startDrawGeometry();
1959 this._startm =
new Date().getTime();
1963 this.CreateToolbar( { container: this.select_main().node() } );
1965 return this.continueDraw();
1968 JSROOT.TGeoPainter.prototype.continueDraw =
function() {
1969 var curr =
new Date().getTime();
1974 if (this.drawNode()) {
1976 log =
"Creating meshes " + this._drawcnt;
1980 var now =
new Date().getTime();
1982 if (now - curr > 300) {
1983 JSROOT.progress(log);
1984 setTimeout(this.continueDraw.bind(
this), 0);
1989 if (now - this._startm > 1e5)
break;
1992 var t2 =
new Date().getTime();
1993 JSROOT.console(
'Create tm = ' + (t2-this._startm) +
' geom ' + this._num_geom +
' vertices ' + this._num_vertices +
' faces ' + this._num_faces +
' meshes ' + this._num_meshes);
1995 if (t2 - this._startm > 300) {
1996 JSROOT.progress(
'Rendering geometry');
1997 setTimeout(this.completeDraw.bind(
this,
true), 0);
2001 return this.completeDraw();
2004 JSROOT.TGeoPainter.prototype.Render3D =
function(tmout) {
2005 if (tmout === undefined) tmout = 5;
2008 if (
'render_tmout' in
this)
2009 clearTimeout(
this[
'render_tmout']);
2011 var tm1 =
new Date();
2014 this._renderer.render(this._scene, this._camera);
2016 var tm2 =
new Date();
2018 delete this[
'render_tmout'];
2020 if (this.first_render_tm === 0) {
2021 this.first_render_tm = tm2.getTime() - tm1.getTime();
2022 JSROOT.console(
'First render tm = ' + this.first_render_tm);
2030 if (
'render_tmout' in
this)
return;
2032 this[
'render_tmout'] = setTimeout(this.Render3D.bind(
this,0), tmout);
2035 JSROOT.TGeoPainter.prototype.completeDraw =
function(close_progress) {
2037 this.adjustCameraPosition();
2039 this.completeScene();
2041 if (this.options._axis) {
2042 var axis = JSROOT.Create(
"TNamed");
2043 axis._typename =
"TAxis3D";
2045 JSROOT.draw(this.divid, axis);
2050 if (close_progress) JSROOT.progress();
2056 var dom = this.select_main().node();
2061 dom.onkeypress =
function(e) {
2063 switch ( e.keyCode ) {
2066 pthis.toggleWireFrame(pthis._scene);
2070 dom.onclick =
function(e) {
2075 return this.DrawingReady();
2079 JSROOT.TGeoPainter.prototype.Cleanup =
function(first_time) {
2081 if (first_time === undefined) {
2083 if (this._scene !== null)
2084 this.deleteChildren(this._scene);
2085 if ( this._tcontrols !== null)
2086 this._tcontrols.dispose();
2087 if (this._controls !== null)
2088 this._controls.dispose();
2092 this._scene_width = 0;
2093 this._scene_height = 0;
2094 this._renderer = null;
2095 this._toplevel = null;
2097 this._camera = null;
2099 this.first_render_tm = 0;
2101 this._controls = null;
2102 this._tcontrols = null;
2103 this._toolbar = null;
2106 JSROOT.TGeoPainter.prototype.helpText =
function(msg) {
2107 JSROOT.progress(msg);
2110 JSROOT.TGeoPainter.prototype.CheckResize =
function() {
2112 var pad_painter = this.pad_painter();
2117 if (!pad_painter.CheckCanvasResize(size, JSROOT.browser.isFirefox ?
false :
true))
return false;
2119 var size3d = this.size_for_3d();
2121 if ((this._scene_width === size3d.width) && (
this._scene_height === size3d.height))
return false;
2122 if ((size3d.width<10) || (size3d.height<10))
return;
2124 this._scene_width = size3d.width;
2125 this._scene_height = size3d.height;
2127 this._camera.aspect = this._scene_width / this._scene_height;
2128 this._camera.updateProjectionMatrix();
2130 this._renderer.setSize( this._scene_width, this._scene_height );
2137 JSROOT.TGeoPainter.prototype.ownedByTransformControls =
function(child) {
2138 var obj = child.parent;
2139 while (obj && !(obj instanceof THREE.TransformControls) ) {
2142 return (obj && (obj instanceof THREE.TransformControls));
2145 JSROOT.TGeoPainter.prototype.toggleWireFrame =
function(obj) {
2148 var f =
function(obj2) {
2149 if ( obj2.hasOwnProperty(
"material") && !(obj2 instanceof THREE.GridHelper) ) {
2150 if (!painter.ownedByTransformControls(obj2))
2151 obj2.material.wireframe = !obj2.material.wireframe;
2158 JSROOT.TGeoPainter.prototype.deleteChildren =
function(obj) {
2159 if ((typeof obj[
'children'] !=
'undefined') && (obj[
'children'] instanceof Array)) {
2160 for ( var i=obj.children.length-1; i>=0; i-- ) {
2161 var ob = obj.children[i];
2162 this.deleteChildren(ob);
2164 obj.remove(obj.children[i]);
2167 ob.geometry.dispose();
2171 ob.material.dispose();
2175 ob.texture.dispose();
2179 obj.children[i] = null;
2181 obj.children = null;
2186 JSROOT.Painter.drawGeometry =
function(divid, geometry, opt) {
2189 JSROOT.extend(
this,
new JSROOT.TGeoPainter(geometry));
2191 this.SetDivId(divid, 5);
2193 return this.DrawGeometry(opt);
2196 JSROOT.Painter.drawGeoObject =
function(divid, obj, opt) {
2197 if (obj === null)
return this.DrawingReady();
2201 if ((
'fShapeBits' in obj) && (
'fShapeId' in obj)) {
2202 node = JSROOT.Create(
"TEveGeoShapeExtract");
2203 JSROOT.extend(node, { fTrans:null, fShape: obj, fRGBA: [ 0, 1, 0, 1], fElements: null, fRnrSelf:
true });
2205 if ((obj._typename ===
'TGeoVolumeAssembly') || (obj._typename ===
'TGeoVolume'))
2208 if (node !== null) {
2209 JSROOT.extend(
this,
new JSROOT.TGeoPainter(node));
2210 this.SetDivId(divid, 5);
2211 return this.DrawGeometry(opt);
2214 return this.DrawingReady();
2219 JSROOT.Painter.drawAxis3D =
function(divid, axis, opt) {
2221 var painter =
new JSROOT.TObjectPainter(axis);
2223 if (!(
'_main' in axis))
2224 painter.SetDivId(divid);
2226 painter[
'Draw3DAxis'] =
function() {
2227 var main = this.main_painter();
2229 if ((main === null) && (
'_main' in this.GetObject()))
2230 main = this.GetObject()._main;
2232 if ((main === null) || (main._toplevel === undefined))
2233 return console.warn(
'no geo object found for 3D axis drawing');
2235 var box =
new THREE.Box3().setFromObject(main._toplevel);
2237 this.xmin = box.min.x; this.xmax = box.max.x;
2238 this.ymin = box.min.y; this.ymax = box.max.y;
2239 this.zmin = box.min.z; this.zmax = box.max.z;
2241 this.options = { Logx:
false, Logy:
false, Logz:
false };
2245 this[
'DrawXYZ'] = JSROOT.Painter.HPainter_DrawXYZ;
2247 this.toplevel = main._toplevel;
2251 main.adjustCameraPosition();
2256 painter.Draw3DAxis();
2258 return painter.DrawingReady();
2263 JSROOT.expandGeoList =
function(item, lst) {
2264 if ((lst==null) || !(
'arr' in lst) || (lst.arr.length==0))
return;
2266 item[
'_more'] =
true;
2267 item[
'_geolst'] = lst;
2269 item[
'_get'] =
function(item, itemname, callback) {
2270 if (
'_geolst' in item)
2271 JSROOT.CallBack(callback, item, item._geolst);
2273 if (
'_geoobj' in item)
2274 return JSROOT.CallBack(callback, item, item._geoobj);
2276 JSROOT.CallBack(callback, item, null);
2278 item[
'_expand'] =
function(node, lst) {
2280 if (!(
'arr' in lst))
return false;
2282 node[
'_childs'] = [];
2284 for (var n in lst.arr) {
2285 var obj = lst.arr[n];
2287 _kind :
"ROOT." + obj._typename,
2289 _title : obj.fTitle,
2294 if (obj._typename ==
"TGeoMaterial") sub._icon =
"img_geomaterial";
else
2295 if (obj._typename ==
"TGeoMedium") sub._icon =
"img_geomedium";
else
2296 if (obj._typename ==
"TGeoMixture") sub._icon =
"img_geomixture";
2298 node[
'_childs'].push(sub);
2305 JSROOT.provideGeoVisStyle =
function(volume) {
2308 if (JSROOT.TestGeoAttBit(volume, JSROOT.EGeoVisibilityAtt.kVisThis))
2309 res +=
" geovis_this";
2311 if (JSROOT.TestGeoAttBit(volume, JSROOT.EGeoVisibilityAtt.kVisDaughters))
2312 res +=
" geovis_daughters";
2317 JSROOT.provideGeoMenu =
function(menu, item, hpainter) {
2318 if (! (
'_volume' in item))
return false;
2320 menu.add(
"separator");
2321 var vol = item._volume;
2323 function ToggleMenuBit(arg) {
2324 JSROOT.ToggleGeoAttBit(vol, arg);
2325 item._icon = item._icon.split(
" ")[0] + JSROOT.provideGeoVisStyle(vol);
2326 hpainter.UpdateTreeNode(item);
2329 menu.addchk(JSROOT.TestGeoAttBit(vol, JSROOT.EGeoVisibilityAtt.kVisNone),
"Invisible",
2330 JSROOT.EGeoVisibilityAtt.kVisNone, ToggleMenuBit);
2331 menu.addchk(JSROOT.TestGeoAttBit(vol, JSROOT.EGeoVisibilityAtt.kVisThis),
"Visible",
2332 JSROOT.EGeoVisibilityAtt.kVisThis, ToggleMenuBit);
2333 menu.addchk(JSROOT.TestGeoAttBit(vol, JSROOT.EGeoVisibilityAtt.kVisDaughters),
"Daughters",
2334 JSROOT.EGeoVisibilityAtt.kVisDaughters, ToggleMenuBit);
2335 menu.addchk(JSROOT.TestGeoAttBit(vol, JSROOT.EGeoVisibilityAtt.kVisOneLevel),
"1lvl daughters",
2336 JSROOT.EGeoVisibilityAtt.kVisOneLevel, ToggleMenuBit);
2341 JSROOT.geoIconClick =
function(hitem) {
2342 if ((hitem==null) || (hitem._volume == null))
return false;
2343 JSROOT.ToggleGeoAttBit(hitem._volume, JSROOT.EGeoVisibilityAtt.kVisDaughters);
2344 hitem._icon = hitem._icon.split(
" ")[0] + JSROOT.provideGeoVisStyle(hitem._volume);
2348 JSROOT.getGeoShapeIcon =
function(shape) {
2349 switch (shape._typename) {
2350 case "TGeoArb8" :
return "img_geoarb8";
break;
2351 case "TGeoCone" :
return "img_geocone";
break;
2352 case "TGeoConeSeg" :
return "img_geoconeseg";
break;
2353 case "TGeoCompositeShape" :
return "img_geocomposite";
break;
2354 case "TGeoTube" :
return "img_geotube";
break;
2355 case "TGeoTubeSeg" :
return "img_geotubeseg";
break;
2356 case "TGeoPara" :
return "img_geopara";
break;
2357 case "TGeoParaboloid" :
return "img_geoparab";
break;
2358 case "TGeoPcon" :
return "img_geopcon";
break;
2359 case "TGeoPgon" :
return "img_geopgon";
break;
2360 case "TGeoShapeAssembly" :
return "img_geoassembly";
break;
2361 case "TGeoSphere" :
return "img_geosphere";
break;
2362 case "TGeoTorus" :
return "img_geotorus";
break;
2363 case "TGeoTrd1" :
return "img_geotrd1";
break;
2364 case "TGeoTrd2" :
return "img_geotrd2";
break;
2365 case "TGeoXtru" :
return "img_geoxtru";
break;
2366 case "TGeoTrap" :
return "img_geotrap";
break;
2367 case "TGeoGtra" :
return "img_geogtra";
break;
2368 case "TGeoEltu" :
return "img_geoeltu";
break;
2369 case "TGeoHype" :
return "img_geohype";
break;
2370 case "TGeoCtub" :
return "img_geoctub";
break;
2372 return "img_geotube";
2375 JSROOT.expandGeoShape =
function(parent, shape, itemname) {
2377 _kind :
"ROOT." + shape._typename,
2379 _title : shape._typename,
2380 _icon : JSROOT.getGeoShapeIcon(shape),
2383 _get :
function(item, itemname, callback) {
2384 if ((item!==null) && (
'_shape' in item))
2385 return JSROOT.CallBack(callback, item, item._shape);
2386 JSROOT.CallBack(callback, item, null);
2390 if (!(
'_childs' in parent)) parent[
'_childs'] = [];
2391 parent._childs.push(item);
2395 JSROOT.expandGeoVolume =
function(parent, volume, arg) {
2397 if ((parent == null) || (volume==null))
return false;
2400 if (
'_childs' in parent)
2401 for (var n=0;n<parent._childs.length;++n)
2402 if (volume === parent._childs[n]._volume)
return true;
2405 _kind :
"ROOT.TGeoVolume",
2406 _name : (arg!=null) ? arg : volume.fName,
2407 _title : volume.fTitle,
2410 _more : (volume.fNodes !== undefined) && (volume.fNodes !== null),
2411 _menu : JSROOT.provideGeoMenu,
2412 _icon_click : JSROOT.geoIconClick,
2413 _get :
function(item, itemname, callback) {
2414 if ((item!=null) && (
'_volume' in item))
2415 return JSROOT.CallBack(callback, item, item._volume);
2417 JSROOT.CallBack(callback, item, null);
2421 if (item[
'_more']) {
2422 item[
'_expand'] =
function(node, obj) {
2423 var subnodes = obj.fNodes.arr;
2424 for (var i in subnodes)
2425 JSROOT.expandGeoVolume(node, subnodes[i].fVolume);
2429 if ((volume.fShape !== null) && (volume.fShape._typename ===
"TGeoCompositeShape") && (volume.fShape.fNode !== null)) {
2430 item[
'_more'] =
true;
2431 item[
'_expand'] =
function(node, obj) {
2432 JSROOT.expandGeoShape(node, obj.fShape.fNode.fLeft,
'Left');
2433 JSROOT.expandGeoShape(node, obj.fShape.fNode.fRight,
'Right');
2438 if (item._title ==
"")
2439 if (volume._typename !=
"TGeoVolume") item._title = volume._typename;
2441 if (volume.fShape !== null) {
2442 if (item._title ==
"")
2443 item._title = volume.fShape._typename;
2445 item._icon = JSROOT.getGeoShapeIcon(volume.fShape);
2448 if (!(
'_childs' in parent)) parent[
'_childs'] = [];
2450 if (!(
'_icon' in item))
2451 item._icon = item[
'_more'] ?
"img_geocombi" :
"img_geobbox";
2453 item._icon += JSROOT.provideGeoVisStyle(volume);
2456 for (var cnt=0;cnt<1000000;cnt++) {
2457 var curr_name = item._name;
2458 if (curr_name.length == 0) curr_name =
"item";
2459 if (cnt>0) curr_name+=
"_"+cnt;
2461 for (var n in parent[
'_childs']) {
2462 if (parent[
'_childs'][n][
'_name'] == curr_name) {
2463 curr_name =
"";
break;
2466 if (curr_name.length > 0) {
2467 if (cnt>0) item._name = curr_name;
2472 parent[
'_childs'].push(item);
2477 JSROOT.expandGeoManagerHierarchy =
function(hitem, obj) {
2478 if ((hitem==null) || (obj==null))
return false;
2480 hitem[
'_childs'] = [];
2482 var item1 = { _name :
"Materials", _kind :
"Folder", _title :
"list of materials" };
2483 JSROOT.expandGeoList(item1, obj.fMaterials);
2484 hitem[
'_childs'].push(item1);
2486 var item2 = { _name :
"Media", _kind :
"Folder", _title :
"list of media" };
2487 JSROOT.expandGeoList(item2, obj.fMedia);
2488 hitem[
'_childs'].push(item2);
2490 var item3 = { _name :
"Tracks", _kind :
"Folder", _title :
"list of tracks" };
2491 JSROOT.expandGeoList(item3, obj.fTracks);
2492 hitem[
'_childs'].push(item3);
2494 JSROOT.expandGeoVolume(hitem, obj.fMasterVolume,
"Volume");
2499 JSROOT.addDrawFunc({ name:
"TGeoVolumeAssembly", icon:
'img_geoassembly', func: JSROOT.Painter.drawGeometry, expand:
"JSROOT.expandGeoVolume", opt :
"all;count;limit;maxlvl2" });
2500 JSROOT.addDrawFunc({ name:
"TAxis3D", func: JSROOT.Painter.drawAxis3D });
2502 return JSROOT.Painter;