5 if ( typeof define ===
"function" && define.amd ) {
6 define( [
'JSRootPainter',
'd3',
'threejs',
'JSRoot3DPainter',
'JSRootGeoBase',
'dat.gui' ], factory );
7 }
else if (typeof exports ===
'object' && typeof module !==
'undefined') {
8 var jsroot = require(
"./JSRootCore.js");
9 factory(jsroot, require(
"d3"), require(
"three"), require(
"./JSRoot3DPainter.js"), require(
"./JSRootGeoBase.js"),
10 undefined, jsroot.nodejs || (typeof document==
'undefined') ? jsroot.nodejs_document : document);
12 if (typeof JSROOT ==
'undefined')
13 throw new Error(
'JSROOT is not defined',
'JSRootGeoPainter.js');
14 if (typeof JSROOT.Painter !=
'object')
15 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');
18 if (typeof THREE ==
'undefined')
19 throw new Error(
'THREE is not defined',
'JSRootGeoPainter.js');
20 factory( JSROOT, d3, THREE );
22 } (
function( JSROOT, d3, THREE, _3d, _geo, _dat, document ) {
26 JSROOT.sources.push(
"geom");
28 if ((typeof document==
'undefined') && (typeof window==
'object')) document = window.document;
30 if ((typeof define ===
"function") && define.amd)
31 JSROOT.loadScript(
'$$$style/JSRootGeoPainter.css');
33 if (typeof JSROOT.GEO !==
'object')
34 console.error(
'JSROOT.GEO namespace is not defined')
38 function Toolbar(container, buttons, bright) {
40 if ((container !== undefined) && (typeof container.append ==
'function')) {
41 this.element = container.append(
"div").attr(
'class',
'jsroot');
42 this.addButtons(buttons);
46 Toolbar.prototype.addButtons =
function(buttons) {
49 this.buttonsNames = [];
50 buttons.forEach(
function(buttonGroup) {
51 var group = pthis.element.append(
'div').attr(
'class',
'toolbar-group');
53 buttonGroup.forEach(
function(buttonConfig) {
54 var buttonName = buttonConfig.name;
56 throw new Error(
'must provide button \'name\' in button config');
58 if (pthis.buttonsNames.indexOf(buttonName) !== -1) {
59 throw new Error(
'button name \'' + buttonName +
'\' is taken
');
61 pthis.buttonsNames.push(buttonName);
63 pthis.createButton(group, buttonConfig);
68 Toolbar.prototype.createButton = function(group, config) {
70 var title = config.title;
71 if (title === undefined) title = config.name;
73 if (typeof config.click !== 'function')
74 throw new Error('must provide button \
'click\' function in button config');
76 var button = group.append(
'a')
77 .attr(
'class', this.bright ?
'toolbar-btn-bright' :
'toolbar-btn')
78 .attr(
'rel',
'tooltip')
79 .attr(
'data-title', title)
80 .on(
'click', config.click);
82 this.createIcon(button, config.icon || JSROOT.ToolbarIcons.question);
86 Toolbar.prototype.changeBrightness =
function(bright) {
88 if (!this.element)
return;
90 this.element.selectAll(bright ?
'.toolbar-btn' :
".toolbar-btn-bright")
91 .attr(
"class", !bright ?
'toolbar-btn' :
"toolbar-btn-bright");
95 Toolbar.prototype.createIcon =
function(button, thisIcon) {
96 var dimensions = thisIcon.size ? thisIcon.size.split(
' ') : [512, 512],
97 width = dimensions[0],
98 height = dimensions[1] || dimensions[0],
99 scale = thisIcon.scale || 1,
100 svg = button.append(
"svg:svg")
101 .attr(
'height',
'1em')
102 .attr(
'width',
'1em')
103 .attr(
'viewBox', [0, 0, width, height].join(
' '));
105 if (
'recs' in thisIcon) {
107 for (var n=0;n<thisIcon.recs.length;++n) {
108 JSROOT.extend(rec, thisIcon.recs[n]);
109 svg.append(
'rect').attr(
"x", rec.x).attr(
"y", rec.y)
110 .attr(
"width", rec.w).attr(
"height", rec.h)
111 .attr(
"fill", rec.f);
114 var elem = svg.append(
'svg:path').attr(
'd',thisIcon.path);
116 elem.attr(
'transform',
'scale(' + scale +
' ' + scale +
')');
120 Toolbar.prototype.Cleanup =
function() {
122 this.element.remove();
133 function TGeoPainter(obj) {
135 if (obj && (obj._typename ===
"TGeoManager")) {
136 this.geo_manager = obj;
137 obj = obj.fMasterVolume;
140 if (obj && (obj._typename.indexOf(
'TGeoVolume') === 0))
141 obj = { _typename:
"TGeoNode", fVolume: obj, fName: obj.fName, $geoh: obj.$geoh, _proxy:
true };
143 JSROOT.TObjectPainter.call(
this, obj);
145 this.no_default_title =
true;
147 this.drawing_stage = 0;
150 clip: [{ name:
"x", enabled:
false, value: 0, min: -100, max: 100}, { name:
"y", enabled:
false, value: 0, min: -100, max: 100}, { name:
"z", enabled:
false, value: 0, min: -100, max: 100}],
151 ssao: { enabled:
false, output: THREE.SSAOPass.OUTPUT.Default, kernelRadius: 0, minDistance: 0.001, maxDistance: 0.1 },
152 info: { num_meshes: 0, num_faces: 0, num_shapes: 0 },
154 highlight_scene:
false,
157 select_in_view:
false,
158 update_browser:
true,
159 light: { top:
false, bottom:
false, left:
false, right:
false, front:
false, specular:
true },
160 trans_radial: 0, trans_z: 0
163 this.ctrl.depthMethodItems = [
164 {name:
'Default', value:
"dflt"},
165 {name:
'Raytraicing', value:
"ray"},
166 {name:
'Boundary box', value:
"box"},
167 {name:
'Mesh size', value:
"size"},
168 {name:
'Central point', value:
"pnt" }
171 this.ctrl.ssao.outputItems = [
172 {name:
'Default', value: THREE.SSAOPass.OUTPUT.Default},
173 {name:
'SSAO Only', value: THREE.SSAOPass.OUTPUT.SSAO},
174 {name:
'SSAO Only + Blur', value: THREE.SSAOPass.OUTPUT.Blur},
175 {name:
'Beauty', value: THREE.SSAOPass.OUTPUT.Beauty},
176 {name:
'Depth', value: THREE.SSAOPass.OUTPUT.Depth},
177 {name:
'Normal', value: THREE.SSAOPass.OUTPUT.Normal}
183 TGeoPainter.prototype = Object.create( JSROOT.TObjectPainter.prototype );
185 TGeoPainter.prototype.CreateToolbar =
function(args) {
186 if (this._toolbar || this._usesvg || this._usesvgimg || this.ctrl.notoolbar)
return;
190 title:
'Save as PNG',
191 icon: JSROOT.ToolbarIcons.camera,
192 click:
function() { painter.createSnapshot(); }
195 title:
'Toggle control UI',
196 icon: JSROOT.ToolbarIcons.rect,
197 click:
function() { painter.showControlOptions(
'toggle'); }
200 title:
'Enlarge geometry drawing',
201 icon: JSROOT.ToolbarIcons.circle,
202 click:
function() { painter.toggleEnlarge(); }
206 if (navigator.getVRDisplays) {
209 title:
'Enter VR (It requires a VR Headset connected)',
210 icon: JSROOT.ToolbarIcons.vrgoggles,
211 click:
function() { painter.toggleVRMode(); }
216 if (JSROOT.gStyle.ContextMenu)
219 title:
'Show context menu',
220 icon: JSROOT.ToolbarIcons.question,
223 d3.event.preventDefault();
224 d3.event.stopPropagation();
228 if (!JSROOT.Painter.closeMenu())
229 JSROOT.Painter.createMenu(painter,
function(menu) {
230 menu.painter.FillContextMenu(menu);
236 var bkgr =
new THREE.Color(this.ctrl.background);
238 this._toolbar =
new Toolbar( this.select_main(), [buttonList], (bkgr.r + bkgr.g + bkgr.b) < 1);
241 TGeoPainter.prototype.InitVRMode =
function() {
245 this._dolly =
new THREE.Group();
246 this._scene.add(this._dolly);
247 this._standingMatrix =
new THREE.Matrix4();
250 this._raycasterEnd =
new THREE.Vector3();
251 this._raycasterOrigin =
new THREE.Vector3();
253 navigator.getVRDisplays().then(
function (displays) {
254 var vrDisplay = displays[0];
255 if (!vrDisplay)
return;
256 pthis._renderer.vr.setDevice(vrDisplay);
257 pthis._vrDisplay = vrDisplay;
258 if (vrDisplay.stageParameters) {
259 pthis._standingMatrix.fromArray(vrDisplay.stageParameters.sittingToStandingTransform);
261 pthis.InitVRControllersGeometry();
265 TGeoPainter.prototype.InitVRControllersGeometry =
function() {
267 var geometry =
new THREE.SphereGeometry(0.025, 18, 36);
268 var material =
new THREE.MeshBasicMaterial({color:
'grey'});
269 var rayMaterial =
new THREE.MeshBasicMaterial({color:
'fuchsia'});
270 var rayGeometry =
new THREE.BoxBufferGeometry(0.001, 0.001, 2);
271 var ray1Mesh =
new THREE.Mesh(rayGeometry, rayMaterial);
272 var ray2Mesh =
new THREE.Mesh(rayGeometry, rayMaterial);
273 var sphere1 =
new THREE.Mesh(geometry, material);
274 var sphere2 =
new THREE.Mesh(geometry, material);
276 this._controllersMeshes = [];
277 this._controllersMeshes.push(sphere1);
278 this._controllersMeshes.push(sphere2);
279 ray1Mesh.position.z -= 1;
280 ray2Mesh.position.z -= 1;
281 sphere1.add(ray1Mesh);
282 sphere2.add(ray2Mesh);
283 this._dolly.add(sphere1);
284 this._dolly.add(sphere2);
286 sphere1.visible =
false;
287 sphere2.visible =
false;
290 TGeoPainter.prototype.UpdateVRControllersList =
function() {
291 var gamepads = navigator.getGamepads && navigator.getGamepads();
293 if (this.vrControllers && (gamepads.length ===
this.vrControllers.length)) {
return; }
295 this._controllersMeshes.forEach(
function (mesh) { mesh.visible =
false; });
296 this._vrControllers = [];
297 for (var i = 0; i < gamepads.length; ++i) {
298 if (!gamepads[i] || !gamepads[i].pose) {
continue; }
299 this._vrControllers.push({
300 gamepad: gamepads[i],
301 mesh: this._controllersMeshes[i]
303 this._controllersMeshes[i].visible =
true;
307 TGeoPainter.prototype.ProcessVRControllerIntersections =
function() {
309 for (var i = 0; i < this._vrControllers.length; ++i) {
310 var controller = this._vrControllers[i].mesh;
311 var end = controller.localToWorld(this._raycasterEnd.set(0, 0, -1));
312 var origin = controller.localToWorld(this._raycasterOrigin.set(0, 0, 0));
313 end.sub(origin).normalize();
314 intersects = intersects.concat(this._controls.GetOriginDirectionIntersects(origin, end));
317 intersects = intersects.filter(
function (item, pos) {
return intersects.indexOf(item) === pos});
318 this._controls.ProcessMouseMove(intersects);
321 TGeoPainter.prototype.UpdateVRControllers =
function() {
322 this.UpdateVRControllersList();
324 for (var i = 0; i < this._vrControllers.length; ++i) {
325 var controller = this._vrControllers[i];
326 var orientation = controller.gamepad.pose.orientation;
327 var position = controller.gamepad.pose.position;
328 var controllerMesh = controller.mesh;
329 if (orientation) { controllerMesh.quaternion.fromArray(orientation); }
330 if (position) { controllerMesh.position.fromArray(position); }
331 controllerMesh.updateMatrix();
332 controllerMesh.applyMatrix(this._standingMatrix);
333 controllerMesh.matrixWorldNeedsUpdate =
true;
335 this.ProcessVRControllerIntersections();
338 TGeoPainter.prototype.toggleVRMode =
function() {
339 if (!this._vrDisplay)
return;
341 if (this._vrDisplay.isPresenting) {
346 this._previousCameraPosition = this._camera.position.clone();
347 this._previousCameraRotation = this._camera.rotation.clone();
348 this._vrDisplay.requestPresent([{ source: this._renderer.domElement }]).then(
function() {
349 pthis._previousCameraNear = pthis._camera.near;
350 pthis._dolly.position.set(pthis._camera.position.x/4, - pthis._camera.position.y/8, - pthis._camera.position.z/4);
351 pthis._camera.position.set(0,0,0);
352 pthis._dolly.add(pthis._camera);
353 pthis._camera.near = 0.1;
354 pthis._camera.updateProjectionMatrix();
355 pthis._renderer.vr.enabled =
true;
356 pthis._renderer.setAnimationLoop(
function () {
357 pthis.UpdateVRControllers();
361 this._renderer.vr.enabled =
true;
363 window.addEventListener(
'keydown',
function ( event ) {
365 if (event.keyCode === 27) pthis.ExitVRMode();
369 TGeoPainter.prototype.ExitVRMode =
function() {
371 if (!this._vrDisplay.isPresenting)
return;
372 this._renderer.vr.enabled =
false;
373 this._dolly.remove(this._camera);
374 this._scene.add(this._camera);
376 this._camera.position.copy(this._previousCameraPosition);
377 this._previousCameraPosition = undefined;
378 this._camera.rotation.copy(this._previousCameraRotation);
379 this._previousCameraRotation = undefined;
380 this._camera.near = this._previousCameraNear;
381 this._camera.updateProjectionMatrix();
382 this._vrDisplay.exitPresent();
385 TGeoPainter.prototype.GetGeometry =
function() {
386 return this.GetObject();
389 TGeoPainter.prototype.ModifyVisisbility =
function(name, sign) {
390 if (JSROOT.GEO.NodeKind(
this.GetGeometry()) !== 0)
return;
393 return JSROOT.GEO.SetBit(this.GetGeometry().fVolume, JSROOT.GEO.BITS.kVisThis, (sign ===
"+"));
395 var regexp, exact =
false;
398 if (name.indexOf(
"*") < 0) {
399 regexp =
new RegExp(
"^"+name+
"$");
402 regexp =
new RegExp(
"^" + name.split(
"*").join(
".*") +
"$");
406 this.FindNodeWithVolume(regexp,
function(arg) {
407 JSROOT.GEO.InvisibleAll.call(arg.node.fVolume, (sign !==
"+"));
408 return exact ? arg : null;
412 TGeoPainter.prototype.decodeOptions =
function(opt) {
413 if (typeof opt !=
"string") opt =
"";
415 var res = { _grid:
false, _bound:
false, _debug:
false,
416 _full:
false, _axis: 0,
417 _count:
false, wireframe:
false,
418 scale:
new THREE.Vector3(1,1,1), zoom: 1.0, rotatey: 0, rotatez: 0,
419 more: 1, maxlimit: 100000,
420 vislevel: undefined, maxnodes: undefined, dflt_colors:
false,
421 use_worker:
false, show_controls:
false,
422 highlight:
false, highlight_scene:
false, no_screen:
false,
423 project:
'', is_main:
false, tracks:
false, showtop:
false, can_rotate:
true, ortho_camera:
false,
424 clipx:
false, clipy:
false, clipz:
false, usessao:
false, outline:
false,
425 script_name:
"", transparency: 0, rotate:
false, background:
'#FFFFFF',
426 depthMethod:
"dflt", mouse_tmout: 50, trans_radial: 0, trans_z: 0 };
428 var _opt = JSROOT.GetUrlOption(
'_grid');
429 if (_opt !== null && _opt ==
"true") res._grid =
true;
430 var _opt = JSROOT.GetUrlOption(
'_debug');
431 if (_opt !== null && _opt ==
"true") { res._debug =
true; res._grid =
true; }
432 if (_opt !== null && _opt ==
"bound") { res._debug =
true; res._grid =
true; res._bound =
true; }
433 if (_opt !== null && _opt ==
"full") { res._debug =
true; res._grid =
true; res._full =
true; res._bound =
true; }
435 var macro = opt.indexOf(
"macro:");
437 var separ = opt.indexOf(
";", macro+6);
438 if (separ<0) separ = opt.length;
439 res.script_name = opt.substr(macro+6,separ-macro-6);
440 opt = opt.substr(0, macro) + opt.substr(separ+1);
441 console.log(
'script', res.script_name,
'rest', opt);
445 var pp = opt.indexOf(
"+"), pm = opt.indexOf(
"-");
446 if ((pp<0) && (pm<0))
break;
447 var p1 = pp, sign =
"+";
448 if ((p1<0) || ((pm>=0) && (pm<pp))) { p1 = pm; sign =
"-"; }
450 var p2 = p1+1, regexp =
new RegExp(
'[,; .]');
451 while ((p2<opt.length) && !regexp.test(opt[p2]) && (opt[p2]!=
'+') && (opt[p2]!=
'-')) p2++;
453 var name = opt.substring(p1+1, p2);
454 opt = opt.substr(0,p1) + opt.substr(p2);
457 this.ModifyVisisbility(name, sign);
460 var d =
new JSROOT.DrawOptions(opt);
462 if (d.check(
"MAIN")) res.is_main =
true;
464 if (d.check(
"TRACKS")) res.tracks =
true;
465 if (d.check(
"SHOWTOP")) res.showtop =
true;
466 if (d.check(
"NO_SCREEN")) res.no_screen =
true;
468 if (d.check(
"ORTHO_CAMERA_ROTATE")) { res.ortho_camera =
true; res.can_rotate =
true; }
469 if (d.check(
"ORTHO_CAMERA")) { res.ortho_camera =
true; res.can_rotate =
false; }
471 if (d.check(
"DEPTHRAY") || d.check(
"DRAY")) res.depthMethod =
"ray";
472 if (d.check(
"DEPTHBOX") || d.check(
"DBOX")) res.depthMethod =
"box";
473 if (d.check(
"DEPTHPNT") || d.check(
"DPNT")) res.depthMethod =
"pnt";
474 if (d.check(
"DEPTHSIZE") || d.check(
"DSIZE")) res.depthMethod =
"size";
475 if (d.check(
"DEPTHDFLT") || d.check(
"DDFLT")) res.depthMethod =
"dflt";
477 if (d.check(
"ZOOM",
true)) res.zoom = d.partAsFloat(0, 100) / 100;
478 if (d.check(
"ROTY",
true)) res.rotatey = d.partAsFloat();
479 if (d.check(
"ROTZ",
true)) res.rotatez = d.partAsFloat();
480 if (d.check(
"VISLVL",
true)) res.vislevel = d.partAsInt();
482 if (d.check(
'BLACK')) res.background =
"#000000";
483 if (d.check(
'WHITE')) res.background =
"#FFFFFF";
485 if (d.check(
'BKGR_',
true)) {
487 if (d.partAsInt(1)>0) bckgr = JSROOT.Painter.root_colors[d.partAsInt()];
else
488 for (var col=0;col<8;++col)
489 if (JSROOT.Painter.root_colors[col].toUpperCase() === d.part) bckgr = JSROOT.Painter.root_colors[col];
490 if (bckgr) res.background =
"#" +
new THREE.Color(bckgr).getHexString();
493 if (d.check(
"MORE3")) res.more = 3;
494 if (d.check(
"MORE")) res.more = 2;
495 if (d.check(
"ALL")) { res.more = 10; res.vislevel = 9; }
497 if (d.check(
"CONTROLS") || d.check(
"CTRL")) res.show_controls =
true;
499 if (d.check(
"CLIPXYZ")) res.clipx = res.clipy = res.clipz =
true;
500 if (d.check(
"CLIPX")) res.clipx =
true;
501 if (d.check(
"CLIPY")) res.clipy =
true;
502 if (d.check(
"CLIPZ")) res.clipz =
true;
503 if (d.check(
"CLIP")) res.clipx = res.clipy = res.clipz =
true;
505 if (d.check(
"PROJX",
true)) { res.project =
'x';
if (d.partAsInt(1)>0) res.projectPos = d.partAsInt(); res.can_rotate =
false; }
506 if (d.check(
"PROJY",
true)) { res.project =
'y';
if (d.partAsInt(1)>0) res.projectPos = d.partAsInt(); res.can_rotate =
false; }
507 if (d.check(
"PROJZ",
true)) { res.project =
'z';
if (d.partAsInt(1)>0) res.projectPos = d.partAsInt(); res.can_rotate =
false; }
509 if (d.check(
"DFLT_COLORS") || d.check(
"DFLT")) res.dflt_colors =
true;
510 if (d.check(
"SSAO")) res.usessao =
true;
511 if (d.check(
"OUTLINE")) res.outline =
true;
513 if (d.check(
"NOWORKER")) res.use_worker = -1;
514 if (d.check(
"WORKER")) res.use_worker = 1;
516 if (d.check(
"NOHIGHLIGHT") || d.check(
"NOHIGH")) res.highlight_scene = res.highlight = 0;
517 if (d.check(
"HIGHLIGHT")) res.highlight_scene = res.highlight =
true;
518 if (d.check(
"HSCENEONLY")) { res.highlight_scene =
true; res.highlight = 0; }
519 if (d.check(
"NOHSCENE")) res.highlight_scene = 0;
520 if (d.check(
"HSCENE")) res.highlight_scene =
true;
522 if (d.check(
"WIREFRAME") || d.check(
"WIRE")) res.wireframe =
true;
523 if (d.check(
"ROTATE")) res.rotate =
true;
525 if (d.check(
"INVX") || d.check(
"INVERTX")) res.scale.x = -1;
526 if (d.check(
"INVY") || d.check(
"INVERTY")) res.scale.y = -1;
527 if (d.check(
"INVZ") || d.check(
"INVERTZ")) res.scale.z = -1;
529 if (d.check(
"COUNT")) res._count =
true;
531 if (d.check(
'TRANSP',
true))
532 res.transparency = d.partAsInt(0,100)/100;
534 if (d.check(
'OPACITY',
true))
535 res.transparency = 1 - d.partAsInt(0,100)/100;
537 if (d.check(
"AXISCENTER") || d.check(
"AC")) res._axis = 2;
539 if (d.check(
'TRR',
true)) res.trans_radial = d.partAsInt()/100;
540 if (d.check(
'TRZ',
true)) res.trans_z = d.partAsInt()/100;
542 if (d.check(
"AXIS") || d.check(
"A")) res._axis =
true;
544 if (d.check(
"D")) res._debug =
true;
545 if (d.check(
"G")) res._grid =
true;
546 if (d.check(
"B")) res._bound =
true;
547 if (d.check(
"W")) res.wireframe =
true;
548 if (d.check(
"F")) res._full =
true;
549 if (d.check(
"Y")) res._yup =
true;
550 if (d.check(
"Z")) res._yup =
false;
553 if (res._yup === undefined)
554 res._yup = this.svg_canvas().empty();
559 TGeoPainter.prototype.ActivateInBrowser =
function(names, force) {
562 if (typeof names ==
'string') names = [ names ];
564 if (this._hpainter) {
566 this._hpainter.activate(names, force);
569 if (!this.ctrl.update_browser)
570 setTimeout(this._hpainter.activate.bind(
this._hpainter, []), 2000);
574 TGeoPainter.prototype.TestMatrixes =
function() {
577 var painter =
this, errcnt = 0, totalcnt = 0, totalmax = 0;
581 func:
function(node) {
583 var m2 = this.getmatrix();
585 var entry = this.CopyStack();
587 var mesh = painter._clones.CreateObject3D(entry.stack, painter._toplevel,
'mesh');
589 if (!mesh)
return true;
593 var m1 = mesh.matrixWorld, flip, origm2;
595 if (m1.equals(m2))
return true
596 if ((m1.determinant()>0) && (m2.determinant()<-0.9)) {
597 flip = THREE.Vector3(1,1,-1);
599 m2 = m2.clone().scale(flip);
600 if (m1.equals(m2))
return true;
604 for (var k=0;k<16;++k)
605 max = Math.max(max, Math.abs(m1.elements[k] - m2.elements[k]));
607 totalmax = Math.max(max, totalmax);
609 if (max < 1e-4)
return true;
611 console.log(painter._clones.ResolveStack(entry.stack).name,
'maxdiff', max,
'determ', m1.determinant(), m2.determinant());
620 tm1 =
new Date().getTime();
622 var cnt = this._clones.ScanVisible(arg);
624 tm2 =
new Date().getTime();
626 console.log(
'Compare matrixes total',totalcnt,
'errors',errcnt,
'takes', tm2-tm1,
'maxdiff', totalmax);
630 TGeoPainter.prototype.FillContextMenu =
function(menu) {
631 menu.add(
"header: Draw options");
633 menu.addchk(this.ctrl.update_browser,
"Browser update",
function() {
634 this.ctrl.update_browser = !
this.ctrl.update_browser;
635 if (!this.ctrl.update_browser)
this.ActivateInBrowser([]);
637 menu.addchk(this.ctrl.show_controls,
"Show Controls",
function() {
638 this.showControlOptions(
'toggle');
640 menu.addchk(this.ctrl._axis,
"Show axes",
function() {
641 this.setAxesDraw(
'toggle');
643 if (this.geo_manager)
644 menu.addchk(this.ctrl.showtop,
"Show top volume",
function() {
645 this.setShowTop(!
this.ctrl.showtop);
648 menu.addchk(this.ctrl.wireframe,
"Wire frame",
function() {
649 this.toggleWireFrame();
651 menu.addchk(this.ctrl.highlight,
"Highlight volumes",
function() {
652 this.ctrl.highlight = !
this.ctrl.highlight;
654 menu.addchk(this.ctrl.highlight_scene,
"Highlight scene",
function() {
655 this.ctrl.highlight_scene = !
this.ctrl.highlight_scene;
657 menu.add(
"Reset camera position",
function() {
660 menu.add(
"Get camera position",
function() {
661 alert(
"Position (as url): &opt=" + this.produceCameraUrl());
663 if (!this.ctrl.project)
664 menu.addchk(this.ctrl.rotate,
"Autorotate",
function() {
665 this.setAutoRotate(!
this.ctrl.rotate);
667 menu.addchk(this.ctrl.select_in_view,
"Select in view",
function() {
668 this.ctrl.select_in_view = !
this.ctrl.select_in_view;
669 if (this.ctrl.select_in_view)
this.startDrawGeometry();
675 TGeoPainter.prototype.changedGlobalTransparency =
function(transparency, skip_render) {
676 var func = (typeof transparency ==
'function') ? transparency : null;
677 if (func || (transparency === undefined)) transparency = this.ctrl.transparency;
678 this._toplevel.traverse( function (node) {
679 if (node && node.material && (node.material.inherentOpacity !== undefined)) {
680 var t = func ? func(node) : undefined;
682 node.material.opacity = 1 - t;
684 node.material.opacity = Math.min(1 - (transparency || 0), node.material.inherentOpacity);
685 node.material.transparent = node.material.opacity < 1;
688 if (!skip_render) this.Render3D(-1);
692 TGeoPainter.prototype.resetTransformation =
function() {
693 this.changedTransformation(
"reset");
697 TGeoPainter.prototype.changedTransformation =
function(arg) {
698 if (!this._toplevel)
return;
700 var ctrl = this.ctrl,
701 translation =
new THREE.Matrix4(),
702 vect2 =
new THREE.Vector3();
705 ctrl.trans_z = ctrl.trans_radial = 0;
707 this._toplevel.traverse(
function(mesh) {
708 if (mesh.stack === undefined)
return;
710 var node = mesh.parent;
712 if (arg ==
"reset") {
714 node.matrix.copy(node.matrix0);
715 node.matrix.decompose( node.position, node.quaternion, node.scale );
716 node.matrixWorldNeedsUpdate =
true;
725 if (node.vect0 === undefined) {
726 node.matrix0 = node.matrix.clone();
727 node.minvert =
new THREE.Matrix4().getInverse( node.matrixWorld );
729 var box3 = JSROOT.GEO.getBoundingBox(mesh, null,
true),
730 signz = mesh._flippedMesh ? -1 : 1;
733 node.vect0 =
new THREE.Vector3((box3.max.x + box3.min.x) / 2, (box3.max.y + box3.min.y) / 2, signz * (box3.max.z + box3.min.z) / 2).applyMatrix4(node.matrixWorld);
734 node.vect1 =
new THREE.Vector3(0,0,0).applyMatrix4(node.minvert);
737 vect2.set(ctrl.trans_radial * node.vect0.x, ctrl.trans_radial * node.vect0.y, ctrl.trans_z * node.vect0.z).applyMatrix4(node.minvert).sub(node.vect1);
739 node.matrix.multiplyMatrices(node.matrix0, translation.makeTranslation(vect2.x, vect2.y, vect2.z));
740 node.matrix.decompose( node.position, node.quaternion, node.scale );
741 node.matrixWorldNeedsUpdate =
true;
744 this._toplevel.updateMatrixWorld();
747 if (arg !=
"norender")
748 this.drawSimpleAxis();
752 TGeoPainter.prototype.changedAutoRotate =
function() {
753 this.autorotate(2.5);
757 TGeoPainter.prototype.changedAxes =
function() {
758 if (typeof this.ctrl._axis ==
'string')
759 this.ctrl._axis = parseInt(this.ctrl._axis);
761 this.drawSimpleAxis();
765 TGeoPainter.prototype.changedBackground =
function(val) {
766 if (val !== undefined) this.ctrl.background = val;
767 this._renderer.setClearColor(this.ctrl.background, 1);
771 var bkgr =
new THREE.Color(this.ctrl.background);
772 this._toolbar.changeBrightness((bkgr.r + bkgr.g + bkgr.b) < 1);
777 TGeoPainter.prototype.changedSSAO =
function() {
778 if (!this.ctrl.ssao.enabled) {
783 this._ssaoPass.output = parseInt(this.ctrl.ssao.output);
784 this._ssaoPass.kernelRadius = this.ctrl.ssao.kernelRadius;
785 this._ssaoPass.minDistance = this.ctrl.ssao.minDistance;
786 this._ssaoPass.maxDistance = this.ctrl.ssao.maxDistance;
789 this.updateClipping();
793 TGeoPainter.prototype.showControlOptions =
function(on) {
795 if (!usedat && (typeof dat ==
'object'))
799 if (typeof usedat ==
'undefined')
800 throw new Error(
'dat.gui is not defined',
'JSRootGeoPainter.js');
802 }
else if (on ===
'toggle') {
804 }
else if (on === undefined) {
805 on = this.ctrl.show_controls;
808 this.ctrl.show_controls = on;
812 d3.select(this._datgui.domElement).remove();
813 this._datgui.destroy();
821 if (typeof usedat ==
'undefined')
822 return JSROOT.AssertPrerequisites(
"datgui", this.showControlOptions.bind(
this,
"load"));
826 this._datgui =
new usedat.GUI({ autoPlace:
false, width: Math.min(650, painter._renderer.domElement.width / 2) });
828 var main = this.select_main();
829 if (main.style(
'position')==
'static') main.style(
'position',
'relative');
831 d3.select(this._datgui.domElement)
832 .style(
'position',
'absolute')
833 .style(
'top',0).style(
'right',0);
835 main.node().appendChild(this._datgui.domElement);
837 this._datgui.painter =
this;
839 if (this.ctrl.project) {
841 var bound = this.getGeomBoundingBox(this.getProjectionSource(), 0.01);
843 var axis = this.ctrl.project;
845 if (this.ctrl.projectPos === undefined)
846 this.ctrl.projectPos = (bound.min[axis] + bound.max[axis])/2;
848 this._datgui.add(this.ctrl,
'projectPos', bound.min[axis], bound.max[axis])
849 .name(axis.toUpperCase() +
' projection')
850 .onChange(
function (value) {
851 painter.startDrawGeometry();
857 var clipFolder = this._datgui.addFolder(
'Clipping'),
858 clip_handler = this.changedClipping.bind(
this, -1);
860 for (var naxis=0;naxis<3;++naxis) {
861 var cc = this.ctrl.clip[naxis],
862 axisC = cc.name.toUpperCase();
864 clipFolder.add(cc,
'enabled')
865 .name(
'Enable ' + axisC)
867 .onChange(clip_handler);
869 clipFolder.add(cc,
"value", cc.min, cc.max)
870 .name(axisC +
' position')
871 .onChange(this.changedClipping.bind(
this, naxis));
874 clipFolder.add(this.ctrl,
'clipIntersect').name(
"Clip intersection")
875 .listen().onChange(clip_handler);
881 var appearance = this._datgui.addFolder(
'Appearance');
883 appearance.add(this.ctrl,
'highlight').name(
'Highlight Selection')
884 .listen().onChange(this.changedHighlight.bind(
this));
886 appearance.add(this.ctrl,
'transparency', 0.0, 1.0, 0.001)
887 .listen().onChange(this.changedGlobalTransparency.bind(
this));
889 appearance.addColor(this.ctrl,
'background').name(
'Background')
890 .onChange(this.changedBackground.bind(
this));
892 appearance.add(this.ctrl,
'wireframe').name(
'Wireframe')
893 .listen().onChange(this.changedWireFrame.bind(
this));
895 this.ctrl._axis_cfg = 0;
896 appearance.add(this.ctrl,
'_axis', {
"none" : 0,
"show": 1,
"center": 2}).name(
'Axes')
897 .onChange(this.changedAxes.bind(
this));
899 if (!this.ctrl.project)
900 appearance.add(this.ctrl,
'rotate').name(
"Autorotate")
901 .listen().onChange(this.changedAutoRotate.bind(
this));
903 appearance.add(
this,
'focusCamera').name(
'Reset camera position');
908 var advanced = this._datgui.addFolder(
'Advanced'), depthcfg = {};
909 this.ctrl.depthMethodItems.forEach(
function(i) { depthcfg[i.name] = i.value; });
911 advanced.add(this.ctrl,
'depthTest').name(
"Depth test")
912 .listen().onChange(this.changedDepthTest.bind(
this));
914 advanced.add( this.ctrl,
'depthMethod', depthcfg)
915 .name(
"Rendering order")
916 .onChange(this.changedDepthMethod.bind(
this));
918 advanced.add(
this,
'resetAdvanced').name(
'Reset');
922 if (!this.ctrl.project) {
923 var transform = this._datgui.addFolder(
'Transform');
924 transform.add(this.ctrl,
'trans_z', 0., 3., 0.01)
926 .listen().onChange(this.changedTransformation.bind(
this));
927 transform.add(this.ctrl,
'trans_radial', 0., 3., 0.01)
929 .listen().onChange(this.changedTransformation.bind(
this));
931 transform.add(
this,
'resetTransformation').name(
'Reset');
933 if (this.ctrl.trans_z ||
this.ctrl.trans_radial) transform.open();
937 if (this.ctrl.outline)
return;
939 var ssaofolder = this._datgui.addFolder(
'Smooth Lighting (SSAO)'),
940 ssao_handler = this.changedSSAO.bind(
this), ssaocfg = {};
942 this.ctrl.ssao.outputItems.forEach(
function(i) { ssaocfg[i.name] = i.value; });
944 ssaofolder.add(this.ctrl.ssao,
'enabled').name(
'Enable SSAO')
945 .listen().onChange(ssao_handler);
947 ssaofolder.add( this.ctrl.ssao,
'output', ssaocfg)
948 .listen().onChange(ssao_handler);
950 ssaofolder.add( this.ctrl.ssao,
'kernelRadius', 0, 32)
951 .listen().onChange(ssao_handler);
953 ssaofolder.add( this.ctrl.ssao,
'minDistance', 0.001, 0.02)
954 .listen().onChange(ssao_handler);
956 ssaofolder.add( this.ctrl.ssao,
'maxDistance', 0.01, 0.3)
957 .listen().onChange(ssao_handler);
960 TGeoPainter.prototype.removeSSAO =
function() {
962 delete this._ssaoPass;
963 delete this._effectComposer;
966 TGeoPainter.prototype.createSSAO =
function() {
967 if (!this._webgl)
return;
971 if (!this._ssaoPass) {
972 if (!this._effectComposer) {
973 this._effectComposer =
new THREE.EffectComposer( this._renderer );
974 this._effectComposer.addPass(
new THREE.RenderPass(
this._scene,
this._camera ) );
977 this._ssaoPass =
new THREE.SSAOPass( this._scene, this._camera, this._scene_width, this._scene_height );
978 this._ssaoPass.kernelRadius = 16;
979 this._ssaoPass.renderToScreen =
true;
982 this._effectComposer.addPass( this._ssaoPass );
986 TGeoPainter.prototype.OrbitContext =
function(evnt, intersects) {
988 JSROOT.Painter.createMenu(
this,
function(menu) {
989 var numitems = 0, numnodes = 0, cnt = 0;
991 for (var n=0;n<intersects.length;++n) {
992 if (intersects[n].
object.stack) numnodes++;
993 if (intersects[n].
object.geo_name) numitems++;
996 if (numnodes + numitems === 0) {
997 menu.painter.FillContextMenu(menu);
999 var many = (numnodes + numitems) > 1;
1001 if (many) menu.add(
"header:" + ((numitems > 0) ?
"Items" :
"Nodes"));
1003 for (var n=0;n<intersects.length;++n) {
1004 var obj = intersects[n].object,
1005 name, itemname, hdr;
1008 itemname = obj.geo_name;
1009 if (itemname.indexOf(
"<prnt>") == 0)
1010 itemname = (menu.painter.GetItemName() ||
"top") + itemname.substr(6);
1011 name = itemname.substr(itemname.lastIndexOf(
"/")+1);
1012 if (!name) name = itemname;
1014 }
else if (obj.stack) {
1015 name = menu.painter._clones.ResolveStack(obj.stack).name;
1016 itemname = menu.painter.GetStackFullName(obj.stack);
1017 hdr = menu.painter.GetItemName();
1018 if (name.indexOf(
"Nodes/") === 0) hdr = name.substr(6);
else
1019 if (name.length > 0) hdr = name;
else
1020 if (!hdr) hdr =
"header";
1025 menu.add((many ?
"sub:" :
"header:") + hdr, itemname,
function(arg) { this.ActivateInBrowser([arg],
true); });
1027 menu.add(
"Browse", itemname,
function(arg) { this.ActivateInBrowser([arg],
true); });
1029 if (menu.painter._hpainter)
1030 menu.add(
"Inspect", itemname,
function(arg) { this._hpainter.display(itemname,
"inspect"); });
1033 menu.add(
"Hide", n,
function(indx) {
1034 var mesh = intersects[indx].object;
1035 mesh.visible =
false;
1036 if (mesh.geo_object) mesh.geo_object.$hidden_via_menu =
true;
1037 menu.painter.Render3D();
1040 if (many) menu.add(
"endsub:");
1045 var wireframe = menu.painter.accessObjectWireFrame(obj);
1047 if (wireframe!==undefined)
1048 menu.addchk(wireframe,
"Wireframe", n,
function(indx) {
1049 var m = intersects[indx].object.material;
1050 m.wireframe = !m.wireframe;
1055 menu.add(
"Manifest", n,
function(indx) {
1057 if (this._last_manifest)
1058 this._last_manifest.wireframe = !
this._last_manifest.wireframe;
1060 if (this._last_hidden)
1061 this._last_hidden.forEach(
function(obj) { obj.visible =
true; });
1063 this._last_hidden = [];
1065 for (var i=0;i<indx;++i)
1066 this._last_hidden.push(intersects[i].object);
1068 this._last_hidden.forEach(
function(obj) { obj.visible =
false; });
1070 this._last_manifest = intersects[indx].object.material;
1072 this._last_manifest.wireframe = !this._last_manifest.wireframe;
1078 menu.add(
"Focus", n,
function(indx) {
1079 this.focusCamera(intersects[indx].
object);
1082 if (!menu.painter._geom_viewer)
1083 menu.add(
"Hide", n,
function(indx) {
1084 var resolve = menu.painter._clones.ResolveStack(intersects[indx].
object.stack);
1086 if (resolve.obj && (resolve.node.kind === 0) && resolve.obj.fVolume) {
1087 JSROOT.GEO.SetBit(resolve.obj.fVolume, JSROOT.GEO.BITS.kVisThis,
false);
1088 JSROOT.GEO.updateBrowserIcons(resolve.obj.fVolume,
this._hpainter);
1090 if (resolve.obj && (resolve.node.kind === 1)) {
1091 resolve.obj.fRnrSelf =
false;
1092 JSROOT.GEO.updateBrowserIcons(resolve.obj,
this._hpainter);
1097 this.testGeomChanges();
1100 if (many) menu.add(
"endsub:");
1107 TGeoPainter.prototype.FilterIntersects =
function(intersects) {
1109 if (!intersects.length)
return intersects;
1112 for (var n=0;n<intersects.length;++n)
1113 if (intersects[n].
object.geo_highlight)
1114 intersects[n].object = intersects[n].object.geo_highlight;
1118 for (var n=intersects.length-1; n>=0; --n) {
1120 var obj = intersects[n].object;
1122 var unique = (obj.stack !== undefined) || (obj.geo_name !== undefined);
1124 if (unique && obj.material && (obj.material.opacity !== undefined))
1125 unique = (obj.material.opacity >= 0.1);
1127 if (obj.jsroot_special) unique =
false;
1129 for (var k=0;(k<n) && unique;++k)
1130 if (intersects[k].
object === obj) unique =
false;
1132 if (!unique) intersects.splice(n,1);
1135 var clip = this.ctrl.clip;
1137 if (clip[0].enabled || clip[1].enabled || clip[2].enabled) {
1138 var clippedIntersects = [];
1140 function myXor(a,b) {
return ( a && !b ) || (!a && b); }
1142 for (var i = 0; i < intersects.length; ++i) {
1143 var point = intersects[i].point, special = (intersects[i].object.type ==
"Points"), clipped =
true;
1145 if (clip[0].enabled && myXor(this._clipPlanes[0].normal.dot(point) > this._clipPlanes[0].constant, special)) clipped =
false;
1146 if (clip[1].enabled && myXor(this._clipPlanes[1].normal.dot(point) > this._clipPlanes[1].constant, special)) clipped =
false;
1147 if (clip[2].enabled && (this._clipPlanes[2].normal.dot(point) > this._clipPlanes[2].constant)) clipped =
false;
1149 if (!clipped) clippedIntersects.push(intersects[i]);
1152 intersects = clippedIntersects;
1158 TGeoPainter.prototype.testCameraPositionChange =
function() {
1162 if (!this.ctrl.select_in_view ||
this._draw_all_nodes)
return;
1164 var matrix = JSROOT.GEO.CreateProjectionMatrix(this._camera);
1166 var frustum = JSROOT.GEO.CreateFrustum(matrix);
1169 if (!frustum.CheckBox(
this.getGeomBoundingBox(
this._toplevel)))
1170 this.startDrawGeometry();
1173 TGeoPainter.prototype.ResolveStack =
function(stack) {
1174 return this._clones && stack ? this._clones.ResolveStack(stack) : null;
1177 TGeoPainter.prototype.GetStackFullName =
function(stack) {
1178 var mainitemname = this.GetItemName(),
1179 sub = this.ResolveStack(stack);
1180 if (!sub || !sub.name)
return mainitemname;
1181 return mainitemname ? (mainitemname +
"/" + sub.name) : sub.name;
1186 TGeoPainter.prototype.AddHighlightHandler =
function(handler) {
1187 if (!handler || typeof handler.HighlightMesh !=
'function')
return;
1188 if (!this._highlight_handlers) this._highlight_handlers = [];
1189 this._highlight_handlers.push(handler);
1194 function GeoDrawingControl(mesh) {
1195 JSROOT.Painter.InteractiveControl.call(
this);
1196 this.mesh = (mesh && mesh.material) ? mesh : null;
1199 GeoDrawingControl.prototype = Object.create(JSROOT.Painter.InteractiveControl.prototype);
1201 GeoDrawingControl.prototype.setHighlight =
function(col, indx) {
1202 return this.drawSpecial(col, indx);
1205 GeoDrawingControl.prototype.drawSpecial =
function(col, indx) {
1207 if (!c || !c.material)
return;
1212 color: c.material.color,
1213 opacity: c.material.opacity,
1214 width: c.material.linewidth,
1215 size: c.material.size
1217 c.material.color =
new THREE.Color( col );
1218 c.material.opacity = 1.;
1219 if (c.hightlightWidthScale && !JSROOT.browser.isWin)
1220 c.material.linewidth = c.origin.width * c.hightlightWidthScale;
1221 if (c.highlightScale)
1222 c.material.size = c.origin.size * c.highlightScale;
1224 }
else if (c.origin) {
1225 c.material.color = c.origin.color;
1226 c.material.opacity = c.origin.opacity;
1227 if (c.hightlightWidthScale)
1228 c.material.linewidth = c.origin.width;
1229 if (c.highlightScale)
1230 c.material.size = c.origin.size;
1237 TGeoPainter.prototype.HighlightMesh =
function(active_mesh, color, geo_object, geo_index, geo_stack, no_recursive) {
1240 active_mesh = active_mesh ? [ active_mesh ] : [];
1241 var extras = this.getExtrasContainer();
1243 extras.traverse(
function(obj3d) {
1244 if ((obj3d.geo_object === geo_object) && (active_mesh.indexOf(obj3d)<0)) active_mesh.push(obj3d);
1246 }
else if (geo_stack && this._toplevel) {
1248 this._toplevel.traverse(
function(mesh) {
1249 if ((mesh instanceof THREE.Mesh) && JSROOT.GEO.IsSameStack(mesh.stack, geo_stack)) active_mesh.push(mesh);
1252 active_mesh = active_mesh ? [ active_mesh ] : [];
1255 if (!active_mesh.length) active_mesh = null;
1259 if (active_mesh[0].geo_object) {
1260 if (!this.ctrl.highlight_scene) active_mesh = null;
1262 if (!this.ctrl.highlight) active_mesh = null;
1266 if (!no_recursive) {
1270 if (!geo_object) geo_object = active_mesh[0].geo_object;
1271 if (!geo_stack) geo_stack = active_mesh[0].stack;
1274 var lst = this._highlight_handlers || (!this._main_painter ? this._slave_painters : this._main_painter._slave_painters.concat([this._main_painter]));
1276 for (var k=0;k<lst.length;++k)
1277 if (lst[k]!==
this) lst[k].HighlightMesh(null, color, geo_object, geo_index, geo_stack,
true);
1280 var curr_mesh = this._selected_mesh;
1282 function get_ctrl(mesh) {
1283 return mesh.get_ctrl ? mesh.get_ctrl() :
new GeoDrawingControl(mesh);
1287 if (!curr_mesh && !active_mesh)
return false;
1289 if (curr_mesh && active_mesh && (curr_mesh.length == active_mesh.length)) {
1291 for (var k=0;(k<curr_mesh.length) && same;++k) {
1292 if ((curr_mesh[k] !== active_mesh[k]) || get_ctrl(curr_mesh[k]).checkHighlightIndex(geo_index)) same =
false;
1295 if (same)
return !!curr_mesh;
1298 for (var k=0;k<curr_mesh.length;++k)
1299 get_ctrl(curr_mesh[k]).setHighlight();
1301 this._selected_mesh = active_mesh;
1304 for (var k=0;k<active_mesh.length;++k)
1305 get_ctrl(active_mesh[k]).setHighlight(color || 0xffaa33, geo_index);
1309 return !!active_mesh;
1312 TGeoPainter.prototype.ProcessMouseClick =
function(pnt, intersects, evnt) {
1313 if (!intersects.length)
return;
1315 var mesh = intersects[0].object;
1316 if (!mesh.get_ctrl)
return;
1318 var ctrl = mesh.get_ctrl();
1320 var click_indx = ctrl.extractIndex(intersects[0]);
1324 if (ctrl.setSelected(
"blue", click_indx))
1331 TGeoPainter.prototype.setMouseTmout =
function(val) {
1333 this.ctrl.mouse_tmout = val;
1336 this._controls.mouse_tmout = val;
1341 TGeoPainter.prototype.setDepthMethod =
function(val) {
1343 this.ctrl.depthMethod = val;
1347 TGeoPainter.prototype.addOrbitControls =
function() {
1349 if (this._controls || this._usesvg || JSROOT.BatchMode)
return;
1353 this.SetTooltipAllowed(JSROOT.gStyle.Tooltip > 0);
1355 this._controls = JSROOT.Painter.CreateOrbitControl(
this, this._camera, this._scene, this._renderer, this._lookat);
1357 this._controls.mouse_tmout = this.ctrl.mouse_tmout;
1359 if (!this.ctrl.can_rotate) this._controls.enableRotate =
false;
1361 this._controls.ContextMenu = this.OrbitContext.bind(
this);
1363 this._controls.ProcessMouseMove =
function(intersects) {
1365 var active_mesh = null, tooltip = null, resolve = null, names = [], geo_object, geo_index;
1368 for (var k=0;k<intersects.length;++k) {
1369 var obj = intersects[k].object, info = null;
1371 if (obj.geo_object) info = obj.geo_name;
else
1372 if (obj.stack) info = painter.GetStackFullName(obj.stack);
1373 if (!info)
continue;
1375 if (info.indexOf(
"<prnt>")==0)
1376 info = painter.GetItemName() + info.substr(6);
1383 geo_object = obj.geo_object;
1385 geo_index = obj.get_ctrl().extractIndex(intersects[k]);
1386 if ((geo_index !== undefined) && (typeof tooltip ==
"string")) tooltip +=
" indx:" + JSON.stringify(geo_index);
1388 if (active_mesh.stack) resolve = painter.ResolveStack(active_mesh.stack);
1392 painter.HighlightMesh(active_mesh, undefined, geo_object, geo_index);
1394 if (painter.ctrl.update_browser) {
1395 if (painter.ctrl.highlight && tooltip) names = [ tooltip ];
1396 painter.ActivateInBrowser(names);
1399 if (!resolve || !resolve.obj)
return tooltip;
1401 var lines = JSROOT.GEO.provideInfo(resolve.obj);
1402 lines.unshift(tooltip);
1404 return { name: resolve.obj.fName, title: resolve.obj.fTitle || resolve.obj._typename, lines: lines };
1407 this._controls.ProcessMouseLeave =
function() {
1408 this.ProcessMouseMove([]);
1411 this._controls.ProcessDblClick =
function() {
1412 if (painter._last_manifest) {
1413 painter._last_manifest.wireframe = !painter._last_manifest.wireframe;
1414 if (painter._last_hidden)
1415 painter._last_hidden.forEach(
function(obj) { obj.visible =
true; });
1416 delete painter._last_hidden;
1417 delete painter._last_manifest;
1420 painter.adjustCameraPosition();
1425 TGeoPainter.prototype.addTransformControl =
function() {
1426 if (this._tcontrols)
return;
1428 if ( !this.ctrl._debug && !
this.ctrl._grid )
return;
1433 this._tcontrols =
new THREE.TransformControls( this._camera, this._renderer.domElement );
1434 this._scene.add( this._tcontrols );
1435 this._tcontrols.attach( this._toplevel );
1439 window.addEventListener(
'keydown',
function ( event ) {
1440 switch ( event.keyCode ) {
1442 painter._tcontrols.setSpace( painter._tcontrols.space ===
"local" ?
"world" :
"local" );
1445 painter._tcontrols.setTranslationSnap( Math.ceil( painter._overall_size ) / 50 );
1446 painter._tcontrols.setRotationSnap( THREE.Math.degToRad( 15 ) );
1449 painter._tcontrols.setMode(
"translate" );
1452 painter._tcontrols.setMode(
"rotate" );
1455 painter._tcontrols.setMode(
"scale" );
1459 painter._tcontrols.setSize( painter._tcontrols.size + 0.1 );
1463 painter._tcontrols.setSize( Math.max( painter._tcontrols.size - 0.1, 0.1 ) );
1467 window.addEventListener(
'keyup',
function ( event ) {
1468 switch ( event.keyCode ) {
1470 painter._tcontrols.setTranslationSnap( null );
1471 painter._tcontrols.setRotationSnap( null );
1476 this._tcontrols.addEventListener(
'change',
function() { painter.Render3D(0); });
1485 TGeoPainter.prototype.nextDrawAction =
function() {
1487 if (!this._clones || (this.drawing_stage == 0))
return false;
1489 if (this.drawing_stage == 1) {
1491 if (this._geom_viewer) {
1492 this._draw_all_nodes =
false;
1493 this.drawing_stage = 3;
1498 if (this.ctrl.use_worker > 0) {
1499 if (!this._worker) { this.startWorker();
return 1; }
1500 if (!this._worker_ready)
return 1;
1504 var numvis = this._clones.CountVisibles() || this._clones.MarkVisibles(),
1505 matrix = null, frustum = null;
1507 if (this.ctrl.select_in_view && !
this._first_drawing) {
1510 matrix = JSROOT.GEO.CreateProjectionMatrix(this._camera);
1512 frustum = JSROOT.GEO.CreateFrustum(matrix);
1515 if (frustum.CheckBox(
this.getGeomBoundingBox(
this._toplevel))) {
1521 this._current_face_limit = this.ctrl.maxlimit;
1522 if (matrix) this._current_face_limit*=1.25;
1526 var need_worker = !JSROOT.BatchMode && ((numvis > 10000) || (matrix && (this._clones.ScanVisible() > 1e5)));
1529 if (need_worker && JSROOT.source_dir.indexOf(
"file://")==0) {
1530 console.log(
'disable worker for jsroot from file system');
1531 need_worker =
false;
1534 if (need_worker && !this._worker && (this.ctrl.use_worker >= 0))
1537 if (!need_worker || !this._worker_ready) {
1539 var res = this._clones.CollectVisibles(this._current_face_limit, frustum);
1540 this._new_draw_nodes = res.lst;
1541 this._draw_all_nodes = res.complete;
1544 this.drawing_stage = 3;
1549 collect: this._current_face_limit,
1550 flags: this._clones.GetVisibleFlags(),
1551 matrix: matrix ? matrix.elements : null
1554 this.submitToWorker(job);
1556 this.drawing_stage = 2;
1558 this.drawing_log =
"Worker select visibles";
1563 if (this.drawing_stage == 2) {
1566 this.drawing_log =
"Worker select visibles";
1571 if (this.drawing_stage == 3) {
1575 this.drawing_log =
"Analyse visibles";
1577 if (this._new_append_nodes) {
1579 this._new_draw_nodes = this._draw_nodes.concat(this._new_append_nodes);
1581 delete this._new_append_nodes;
1583 }
else if (this._draw_nodes) {
1586 if (this._geom_viewer)
1587 del = this._draw_nodes;
1589 del = this._clones.MergeVisibles(this._new_draw_nodes, this._draw_nodes);
1592 for (var n=0;n<del.length;++n)
1593 this._clones.CreateObject3D(del[n].stack,
this._toplevel,
'delete_mesh');
1596 this.drawing_log =
"Delete " + del.length +
" nodes";
1599 this._draw_nodes = this._new_draw_nodes;
1600 delete this._new_draw_nodes;
1601 this.drawing_stage = 4;
1605 if (this.drawing_stage === 4) {
1607 this.drawing_log =
"Collect shapes";
1610 var shapes = this._clones.CollectShapes(this._draw_nodes);
1613 this._build_shapes = this._clones.MergeShapesLists(this._build_shapes, shapes);
1615 this.drawing_stage = 5;
1620 if (this.drawing_stage === 5) {
1624 if (this.canSubmitToWorker()) {
1625 var job = { limit: this._current_face_limit, shapes: [] }, cnt = 0;
1626 for (var n=0;n<this._build_shapes.length;++n) {
1627 var clone = null, item = this._build_shapes[n];
1629 if (item.ready || item.geom) {
1631 clone = {
id: item.id, ready:
true, nfaces: JSROOT.GEO.numGeometryFaces(item.geom), refcnt: item.refcnt };
1633 clone = JSROOT.clone(item, null,
true);
1637 job.shapes.push(clone);
1642 this.submitToWorker(job);
1643 this.drawing_log =
"Worker build shapes";
1644 this.drawing_stage = 6;
1649 this.drawing_stage = 7;
1652 if (this.drawing_stage === 6) {
1657 if ((this.drawing_stage === 7) || (this.drawing_stage === 8)) {
1659 if (this.drawing_stage === 7) {
1661 var res = this._clones.BuildShapes(this._build_shapes, this._current_face_limit, 500);
1663 this.ctrl.info.num_shapes = this._build_shapes.length;
1664 this.drawing_stage = 8;
1666 this.ctrl.info.num_shapes = res.shapes;
1667 this.drawing_log =
"Creating: " + res.shapes +
" / " + this._build_shapes.length +
" shapes, " + res.faces +
" faces";
1668 if (res.notusedshapes < 30)
return true;
1674 var tm0 =
new Date().getTime(), ready =
true,
1675 toplevel = this.ctrl.project ? this._full_geom : this._toplevel;
1677 for (var n = 0; n < this._draw_nodes.length; ++n) {
1678 var entry = this._draw_nodes[n];
1679 if (entry.done)
continue;
1682 var shape = entry.server_shape || this._build_shapes[entry.shapeid];
1684 if (this.drawing_stage === 8) console.warn(
'shape marked as not ready when should');
1692 if (this.createEntryMesh(entry, shape, toplevel)) {
1693 this.ctrl.info.num_meshes++;
1694 this.ctrl.info.num_faces += shape.nfaces;
1697 var tm1 =
new Date().getTime();
1698 if (tm1 - tm0 > 500) { ready =
false;
break; }
1702 if (this.ctrl.project) {
1703 this.drawing_log =
"Build projection";
1704 this.drawing_stage = 10;
1708 this.drawing_log =
"Building done";
1709 this.drawing_stage = 0;
1713 if (this.drawing_stage > 7)
1714 this.drawing_log =
"Building meshes " + this.ctrl.info.num_meshes +
" / " + this.ctrl.info.num_faces;
1718 if (this.drawing_stage === 9) {
1721 if (!this._main_painter) {
1722 console.warn(
'MAIN PAINTER DISAPPER');
1723 this.drawing_stage = 0;
1726 if (!this._main_painter._drawing_ready)
return 1;
1728 this.drawing_stage = 10;
1731 if (this.drawing_stage === 10) {
1732 this.doProjection();
1733 this.drawing_log =
"Building done";
1734 this.drawing_stage = 0;
1738 console.error(
'never come here stage = ' + this.drawing_stage);
1745 TGeoPainter.prototype.createEntryMesh =
function(entry, shape, toplevel) {
1747 if (!shape.geom || (shape.nfaces === 0)) {
1749 this._clones.CreateObject3D(entry.stack, toplevel,
'delete_mesh');
1754 if (this._splitColors && entry.stack) {
1755 if (entry.stack[0]===0) entry.custom_color =
"green";
else
1756 if (entry.stack[0]===1) entry.custom_color =
"blue";
1759 var prop = this._clones.getDrawEntryProperties(entry);
1761 var obj3d = this._clones.CreateObject3D(entry.stack, toplevel,
this.ctrl);
1763 prop.material.wireframe = this.ctrl.wireframe;
1765 prop.material.side = this.ctrl.bothSides ? THREE.DoubleSide : THREE.FrontSide;
1769 if (obj3d.matrixWorld.determinant() > -0.9) {
1770 mesh =
new THREE.Mesh( shape.geom, prop.material );
1772 mesh = JSROOT.GEO.createFlippedMesh(obj3d, shape, prop.material);
1778 mesh.stack = entry.stack;
1779 mesh.renderOrder = this._clones.maxdepth - entry.stack.length;
1782 mesh.$jsroot_order = obj3d.$jsroot_depth;
1788 if (this.ctrl._debug ||
this.ctrl._full) {
1789 var wfg =
new THREE.WireframeGeometry( mesh.geometry ),
1790 wfm =
new THREE.LineBasicMaterial( { color: prop.fillcolor, linewidth: prop.linewidth || 1 } ),
1791 helper =
new THREE.LineSegments(wfg, wfm);
1795 if (this.ctrl._bound ||
this.ctrl._full) {
1796 var boxHelper =
new THREE.BoxHelper( mesh );
1797 obj3d.add( boxHelper );
1807 TGeoPainter.prototype.appendMoreNodes =
function(nodes, from_drawing) {
1808 if (this.drawing_stage && !from_drawing) {
1809 this._provided_more_nodes = nodes;
1814 if (this._more_nodes)
1815 for (var n=0;n<this._more_nodes.length;++n) {
1816 var entry = this._more_nodes[n];
1817 var obj3d = this._clones.CreateObject3D(entry.stack,
this._toplevel,
'delete_mesh');
1818 JSROOT.Painter.DisposeThreejsObject(obj3d);
1819 JSROOT.GEO.cleanupShape(entry.server_shape);
1820 delete entry.server_shape;
1823 delete this._more_nodes;
1827 var real_nodes = [];
1829 for (var k=0;k<nodes.length;++k) {
1830 var entry = nodes[k];
1831 var shape = entry.server_shape;
1832 if (!shape || !shape.ready)
continue;
1837 if (this.createEntryMesh(entry, shape, this._toplevel))
1838 real_nodes.push(entry);
1842 if (real_nodes) this._more_nodes = real_nodes;
1844 if (!from_drawing) this.Render3D();
1851 TGeoPainter.prototype.getProjectionSource =
function() {
1852 if (this._clones_owner)
1853 return this._full_geom;
1854 if (!this._main_painter) {
1855 console.warn(
'MAIN PAINTER DISAPPER');
1858 if (!this._main_painter._drawing_ready) {
1859 console.warn(
'MAIN PAINTER NOT READY WHEN DO PROJECTION');
1862 return this._main_painter._toplevel;
1865 TGeoPainter.prototype.getGeomBoundingBox =
function(topitem, scalar) {
1866 var box3 =
new THREE.Box3(), check_any = !this._clones;
1869 box3.min.x = box3.min.y = box3.min.z = -1;
1870 box3.max.x = box3.max.y = box3.max.z = 1;
1876 topitem.traverse(
function(mesh) {
1877 if (check_any || (mesh.stack && (mesh instanceof THREE.Mesh)) ||
1878 (mesh.main_track && (mesh instanceof THREE.LineSegments)))
1879 JSROOT.GEO.getBoundingBox(mesh, box3);
1882 if (scalar !== undefined) box3.expandByVector(box3.getSize(
new THREE.Vector3()).multiplyScalar(scalar));
1888 TGeoPainter.prototype.doProjection =
function() {
1889 var toplevel = this.getProjectionSource(), pthis =
this;
1891 if (!toplevel)
return false;
1893 JSROOT.Painter.DisposeThreejsObject(this._toplevel,
true);
1895 var axis = this.ctrl.project;
1897 if (this.ctrl.projectPos === undefined) {
1899 var bound = this.getGeomBoundingBox(toplevel),
1900 min = bound.min[this.ctrl.project], max = bound.max[this.ctrl.project],
1903 if ((min<0) && (max>0) && (Math.abs(mean) < 0.2*Math.max(-min,max))) mean = 0;
1905 this.ctrl.projectPos = mean;
1908 toplevel.traverse(
function(mesh) {
1909 if (!(mesh instanceof THREE.Mesh) || !mesh.stack)
return;
1911 var geom2 = JSROOT.GEO.projectGeometry(mesh.geometry, mesh.parent.matrixWorld, pthis.ctrl.project, pthis.ctrl.projectPos, mesh._flippedMesh);
1915 var mesh2 =
new THREE.Mesh( geom2, mesh.material.clone() );
1917 pthis._toplevel.add(mesh2);
1919 mesh2.stack = mesh.stack;
1925 TGeoPainter.prototype.SameMaterial =
function(node1, node2) {
1927 if ((node1===null) || (node2===null))
return node1 === node2;
1929 if (node1.fVolume.fLineColor >= 0)
1930 return (node1.fVolume.fLineColor === node2.fVolume.fLineColor);
1932 var m1 = (node1.fVolume.fMedium !== null) ? node1.fVolume.fMedium.fMaterial : null;
1933 var m2 = (node2.fVolume.fMedium !== null) ? node2.fVolume.fMedium.fMaterial : null;
1935 if (m1 === m2)
return true;
1937 if ((m1 === null) || (m2 === null))
return false;
1939 return (m1.fFillStyle === m2.fFillStyle) && (m1.fFillColor === m2.fFillColor);
1942 TGeoPainter.prototype.changedLight =
function(box) {
1943 if (!this._camera)
return;
1945 var need_render = !box;
1947 if (!box) box = this.getGeomBoundingBox(this._toplevel);
1949 var sizex = box.max.x - box.min.x,
1950 sizey = box.max.y - box.min.y,
1951 sizez = box.max.z - box.min.z,
1954 for (var k=0;k<this._camera.children.length;++k) {
1955 var light = this._camera.children[k], enabled =
false;
1956 if (!light.isPointLight)
continue;
1958 case 0: light.position.set(sizex/5, sizey/5, sizez/5); enabled = this.ctrl.light.specular;
break;
1959 case 1: light.position.set(0, 0, sizez/2); enabled = this.ctrl.light.front;
break;
1960 case 2: light.position.set(0, 2*sizey, 0); enabled = this.ctrl.light.top;
break;
1961 case 3: light.position.set(0, -2*sizey, 0); enabled = this.ctrl.light.bottom;
break;
1962 case 4: light.position.set(-2*sizex, 0, 0); enabled = this.ctrl.light.left;
break;
1963 case 5: light.position.set(2*sizex, 0, 0); enabled = this.ctrl.light.right;
break;
1965 light.power = enabled ? Math.PI*4 : 0;
1966 if (enabled) lights.push(light);
1970 lights.forEach(
function(light) { light.power = 4*Math.PI/lights.length; })
1972 if (need_render) this.Render3D();
1975 TGeoPainter.prototype.createScene =
function(w, h) {
1977 this._scene =
new THREE.Scene();
1978 this._scene.fog =
new THREE.Fog(0xffffff, 1, 10000);
1979 this._scene.overrideMaterial =
new THREE.MeshLambertMaterial( { color: 0x7000ff, transparent:
true, opacity: 0.2, depthTest:
false } );
1981 this._scene_width = w;
1982 this._scene_height = h;
1984 if (this.ctrl.ortho_camera) {
1985 this._camera =
new THREE.OrthographicCamera(-600, 600, -600, 600, 1, 10000);
1987 this._camera =
new THREE.PerspectiveCamera(25, w / h, 1, 10000);
1988 this._camera.up = this.ctrl._yup ?
new THREE.Vector3(0,1,0) :
new THREE.Vector3(0,0,1);
1991 this._scene.add( this._camera );
1993 this._selected_mesh = null;
1995 this._overall_size = 10;
1997 this._toplevel =
new THREE.Object3D();
1999 this._scene.add(this._toplevel);
2001 var rrr = JSROOT.Painter.Create3DRenderer(w, h, this._usesvg, this._usesvgimg, this._webgl,
2002 { antialias:
true, logarithmicDepthBuffer:
false, preserveDrawingBuffer:
true });
2004 this._webgl = rrr.usewebgl;
2005 this._renderer = rrr.renderer;
2007 if (this._renderer.setPixelRatio && !JSROOT.nodejs)
2008 this._renderer.setPixelRatio(window.devicePixelRatio);
2009 this._renderer.setSize(w, h, !this._fit_main_area);
2010 this._renderer.localClippingEnabled =
true;
2012 this._renderer.setClearColor(this.ctrl.background, 1);
2038 if (this._fit_main_area && !this._usesvg) {
2039 this._renderer.domElement.style.width =
"100%";
2040 this._renderer.domElement.style.height =
"100%";
2041 var main = this.select_main();
2042 if (main.style(
'position')==
'static') main.style(
'position',
'relative');
2045 this._animating =
false;
2049 this.ctrl.bothSides =
false;
2050 this._clipPlanes = [
new THREE.Plane(
new THREE.Vector3(1, 0, 0), 0),
2051 new THREE.Plane(
new THREE.Vector3(0,
this.ctrl._yup ? -1 : 1, 0), 0),
2052 new THREE.Plane(
new THREE.Vector3(0, 0,
this.ctrl._yup ? 1 : -1), 0) ];
2056 for (var n=0;n<6;++n) {
2057 var light =
new THREE.PointLight(0xefefef, n==0 ? 1 : 0);
2058 if (n==0) light.position.set(10, 10, 10);
2059 this._camera.add( light );
2065 if (this._webgl && (this.ctrl.ssao.enabled ||
this.ctrl.outline)) {
2067 if (this.ctrl.outline && (typeof
this.createOutline ==
"function")) {
2068 this._effectComposer =
new THREE.EffectComposer( this._renderer );
2069 this._effectComposer.addPass(
new THREE.RenderPass(
this._scene,
this._camera ) );
2070 this.createOutline(w, h);
2071 }
else if (this.ctrl.ssao.enabled) {
2076 if (this._fit_main_area && (this._usesvg || this._usesvgimg)) {
2078 var svg = document.createElementNS(
"http://www.w3.org/2000/svg",
"svg");
2079 svg.appendChild(rrr.dom);
2087 TGeoPainter.prototype.startDrawGeometry =
function(force) {
2089 if (!force && (this.drawing_stage!==0)) {
2090 this._draw_nodes_again =
true;
2094 if (this._clones_owner && this._clones)
2095 this._clones.SetDefaultColors(this.ctrl.dflt_colors);
2097 this._startm =
new Date().getTime();
2098 this._last_render_tm = this._startm;
2099 this._last_render_meshes = 0;
2100 this.drawing_stage = 1;
2101 this._drawing_ready =
false;
2102 this.drawing_log =
"collect visible";
2103 this.ctrl.info.num_meshes = 0;
2104 this.ctrl.info.num_faces = 0;
2105 this.ctrl.info.num_shapes = 0;
2106 this._selected_mesh = null;
2108 if (this.ctrl.project) {
2109 if (this._clones_owner) {
2110 if (this._full_geom) {
2111 this.drawing_stage = 10;
2112 this.drawing_log =
"build projection";
2114 this._full_geom =
new THREE.Object3D();
2118 this.drawing_stage = 9;
2119 this.drawing_log =
"wait for main painter";
2123 delete this._last_manifest;
2124 delete this._last_hidden;
2126 delete this._draw_nodes_again;
2128 this.continueDraw();
2131 TGeoPainter.prototype.resetAdvanced =
function() {
2132 this.ctrl.ssao.kernelRadius = 16;
2133 this.ctrl.ssao.output = THREE.SSAOPass.OUTPUT.Default;
2135 this.ctrl.depthTest =
true;
2136 this.ctrl.clipIntersect =
true;
2137 this.ctrl.depthMethod =
"ray";
2139 this.changedDepthMethod(
"norender");
2140 this.changedDepthTest();
2143 TGeoPainter.prototype.getGeomBox =
function() {
2144 var extras = this.getExtrasContainer(
'collect');
2146 var box = this.getGeomBoundingBox(this._toplevel);
2149 for (var k=0;k<extras.length;++k) this._toplevel.add(extras[k]);
2154 TGeoPainter.prototype.getOverallSize =
function(force) {
2155 if (!this._overall_size || force) {
2156 var box = this.getGeomBoundingBox(this._toplevel);
2159 if (isNaN(box.min.x))
return 1000;
2161 var sizex = box.max.x - box.min.x,
2162 sizey = box.max.y - box.min.y,
2163 sizez = box.max.z - box.min.z;
2165 this._overall_size = 2 * Math.max(sizex, sizey, sizez);
2168 return this._overall_size;
2172 TGeoPainter.prototype.createSnapshot =
function(filename) {
2173 if (!this._renderer)
return;
2175 var dataUrl = this._renderer.domElement.toDataURL(
"image/png");
2176 if (filename===
"asis")
return dataUrl;
2177 dataUrl.replace(
"image/png",
"image/octet-stream");
2178 var link = document.createElement(
'a');
2179 if (typeof link.download ===
'string') {
2180 document.body.appendChild(link);
2181 link.download = filename ||
"geometry.png";
2182 link.href = dataUrl;
2184 document.body.removeChild(link);
2191 TGeoPainter.prototype.produceCameraUrl =
function(prec) {
2193 if (!this._lookat || !this._camera0pos || !this._camera || !this.ctrl)
return;
2195 var pos1 =
new THREE.Vector3().add(this._camera0pos).sub(this._lookat),
2196 pos2 =
new THREE.Vector3().add(this._camera.position).sub(this._lookat),
2197 len1 = pos1.length(), len2 = pos2.length(),
2198 zoom = this.ctrl.zoom * len2 / len1 * 100;
2200 if (zoom < 1) zoom = 1;
else if (zoom>10000) zoom = 10000;
2205 var quat =
new THREE.Quaternion();
2206 quat.setFromUnitVectors(pos1, pos2);
2208 var euler =
new THREE.Euler();
2209 euler.setFromQuaternion(quat,
"YZX");
2211 var roty = euler.y / Math.PI * 180,
2212 rotz = euler.z / Math.PI * 180;
2214 if (roty<0) roty += 360;
2215 if (rotz<0) rotz += 360;
2217 return "roty" + roty.toFixed(prec || 0) +
",rotz" + rotz.toFixed(prec || 0) +
",zoom" + zoom.toFixed(prec || 0);
2221 TGeoPainter.prototype.calculateZoom =
function() {
2222 if (this._camera0pos && this._camera && this._lookat) {
2223 var pos1 =
new THREE.Vector3().add(this._camera0pos).sub(this._lookat),
2224 pos2 =
new THREE.Vector3().add(this._camera.position).sub(this._lookat);
2225 return pos2.length() / pos1.length();
2233 TGeoPainter.prototype.adjustCameraPosition =
function(first_time, keep_zoom) {
2234 if (!this._toplevel)
return;
2236 var box = this.getGeomBoundingBox(this._toplevel);
2239 if (isNaN(box.min.x))
return;
2241 var sizex = box.max.x - box.min.x,
2242 sizey = box.max.y - box.min.y,
2243 sizez = box.max.z - box.min.z,
2244 midx = (box.max.x + box.min.x)/2,
2245 midy = (box.max.y + box.min.y)/2,
2246 midz = (box.max.z + box.min.z)/2;
2248 this._overall_size = 2 * Math.max(sizex, sizey, sizez);
2250 this._camera.near = this._overall_size / 350;
2251 this._camera.far = this._overall_size * 12;
2252 this._scene.fog.near = this._overall_size * 2;
2253 this._scene.fog.far = this._overall_size * 12;
2256 for (var naxis=0;naxis<3;++naxis) {
2257 var cc = this.ctrl.clip[naxis];
2258 cc.min = box.min[cc.name];
2259 cc.max = box.max[cc.name];
2260 var sz = cc.max - cc.min;
2264 cc.value = (cc.min + cc.max) / 2;
2265 else if (cc.value < cc.min)
2267 else if (cc.value > cc.max)
2271 if (this.ctrl.ortho_camera) {
2272 this._camera.left = box.min.x;
2273 this._camera.right = box.max.x;
2274 this._camera.top = box.max.y;
2275 this._camera.bottom = box.min.y;
2280 this._camera.updateProjectionMatrix();
2282 var k = 2*this.ctrl.zoom,
2283 max_all = Math.max(sizex,sizey,sizez);
2285 if ((this.ctrl.rotatey ||
this.ctrl.rotatez) &&
this.ctrl.can_rotate) {
2287 var prev_zoom = this.calculateZoom();
2288 if (keep_zoom && prev_zoom) k = 2*prev_zoom;
2290 var euler =
new THREE.Euler( 0, this.ctrl.rotatey/180.*Math.PI,
this.ctrl.rotatez/180.*Math.PI,
'YZX' );
2292 this._camera.position.set(-k*max_all, 0, 0);
2293 this._camera.position.applyEuler(euler);
2294 this._camera.position.add(
new THREE.Vector3(midx,midy,midz));
2296 if (keep_zoom && prev_zoom) {
2297 var actual_zoom = this.calculateZoom();
2298 k *= prev_zoom/actual_zoom;
2300 this._camera.position.set(-k*max_all, 0, 0);
2301 this._camera.position.applyEuler(euler);
2302 this._camera.position.add(
new THREE.Vector3(midx,midy,midz));
2305 }
else if (this.ctrl.ortho_camera) {
2306 this._camera.position.set(midx, midy, Math.max(sizex,sizey));
2307 }
else if (this.ctrl.project) {
2308 switch (this.ctrl.project) {
2309 case 'x': this._camera.position.set(k*1.5*Math.max(sizey,sizez), 0, 0);
break;
2310 case 'y': this._camera.position.set(0, k*1.5*Math.max(sizex,sizez), 0);
break;
2311 case 'z': this._camera.position.set(0, 0, k*1.5*Math.max(sizex,sizey));
break;
2313 }
else if (this.ctrl._yup) {
2314 this._camera.position.set(midx-k*Math.max(sizex,sizez), midy+k*sizey, midz-k*Math.max(sizex,sizez));
2316 this._camera.position.set(midx-k*Math.max(sizex,sizey), midy-k*Math.max(sizex,sizey), midz+k*sizez);
2319 this._lookat =
new THREE.Vector3(midx, midy, midz);
2320 this._camera0pos =
new THREE.Vector3(-2*max_all, 0, 0);
2321 this._camera.lookAt(this._lookat);
2323 this.changedLight(box);
2325 if (this._controls) {
2326 this._controls.target.copy(this._lookat);
2327 this._controls.update();
2331 if (this.ctrl.select_in_view)
2332 this.startDrawGeometry();
2335 TGeoPainter.prototype.setCameraPosition =
function(rotatey, rotatez, zoom) {
2336 if (!this.ctrl)
return;
2337 this.ctrl.rotatey = rotatey || 0;
2338 this.ctrl.rotatez = rotatez || 0;
2339 var preserve_zoom =
false;
2340 if (zoom && !isNaN(zoom)) {
2341 this.ctrl.zoom = zoom;
2343 preserve_zoom =
true;
2345 this.adjustCameraPosition(
false, preserve_zoom);
2348 TGeoPainter.prototype.focusOnItem =
function(itemname) {
2350 if (!itemname || !this._clones)
return;
2352 var stack = this._clones.FindStackByName(itemname);
2356 var info = this._clones.ResolveStack(stack,
true);
2358 this.focusCamera( info,
false );
2361 TGeoPainter.prototype.focusCamera =
function( focus, autoClip ) {
2363 if (this.ctrl.project)
2364 return this.adjustCameraPosition();
2366 var box =
new THREE.Box3();
2367 if (focus === undefined) {
2368 box = this.getGeomBoundingBox(this._toplevel);
2369 }
else if (focus instanceof THREE.Mesh) {
2370 box.setFromObject(focus);
2372 var center =
new THREE.Vector3().setFromMatrixPosition(focus.matrix),
2374 halfDelta =
new THREE.Vector3( node.fDX, node.fDY, node.fDZ ).multiplyScalar(0.5);
2375 box.min = center.clone().sub(halfDelta);
2376 box.max = center.clone().add(halfDelta);
2379 var sizex = box.max.x - box.min.x,
2380 sizey = box.max.y - box.min.y,
2381 sizez = box.max.z - box.min.z,
2382 midx = (box.max.x + box.min.x)/2,
2383 midy = (box.max.y + box.min.y)/2,
2384 midz = (box.max.z + box.min.z)/2;
2388 position =
new THREE.Vector3(midx-2*Math.max(sizex,sizez), midy+2*sizey, midz-2*Math.max(sizex,sizez));
2390 position =
new THREE.Vector3(midx-2*Math.max(sizex,sizey), midy-2*Math.max(sizex,sizey), midz+2*sizez);
2392 var target =
new THREE.Vector3(midx, midy, midz);
2395 var dist = this._camera.position.distanceTo(target);
2396 var oldTarget = this._controls.target;
2399 var frames = 50, step = 0;
2402 var posIncrement = position.sub(this._camera.position).divideScalar(frames);
2404 var targetIncrement = target.sub(oldTarget).divideScalar(frames);
2407 autoClip = autoClip && this._webgl;
2411 for (var axis = 0; axis<3; ++axis) {
2412 var cc = this.ctrl.clip[axis];
2413 if (!cc.enabled) { cc.value = cc.min; cc.enabled =
true; }
2414 cc.inc = ((cc.min + cc.max) / 2 - cc.value) / frames;
2416 this.updateClipping();
2420 this._animating =
true;
2424 function animate() {
2425 if (painter._animating === undefined)
return;
2427 if (painter._animating) {
2428 requestAnimationFrame( animate );
2430 if (!painter._geom_viewer)
2431 painter.startDrawGeometry();
2433 var smoothFactor = -Math.cos( ( 2.0 * Math.PI * step ) / frames ) + 1.0;
2434 painter._camera.position.add( posIncrement.clone().multiplyScalar( smoothFactor ) );
2435 oldTarget.add( targetIncrement.clone().multiplyScalar( smoothFactor ) );
2436 painter._lookat = oldTarget;
2437 painter._camera.lookAt( painter._lookat );
2438 painter._camera.updateProjectionMatrix();
2440 var tm1 =
new Date().getTime();
2442 for (var axis = 0; axis<3; ++axis)
2443 painter.ctrl.clip[axis].value += painter.ctrl.clip[axis].inc * smoothFactor;
2444 painter.updateClipping();
2446 painter.Render3D(0);
2448 var tm2 =
new Date().getTime();
2449 if ((step==0) && (tm2-tm1 > 200)) frames = 20;
2451 painter._animating = step < frames;
2459 TGeoPainter.prototype.autorotate =
function(speed) {
2461 var rotSpeed = (speed === undefined) ? 2.0 : speed,
2462 painter =
this, last =
new Date();
2464 function animate() {
2465 if (!painter._renderer || !painter.ctrl)
return;
2467 var current =
new Date();
2469 if ( painter.ctrl.rotate ) requestAnimationFrame( animate );
2471 if (painter._controls) {
2472 painter._controls.autoRotate = painter.ctrl.rotate;
2473 painter._controls.autoRotateSpeed = rotSpeed * ( current.getTime() - last.getTime() ) / 16.6666;
2474 painter._controls.update();
2477 painter.Render3D(0);
2480 if (this._webgl) animate();
2483 TGeoPainter.prototype.completeScene =
function() {
2485 if ( this.ctrl._debug ||
this.ctrl._grid ) {
2486 if ( this.ctrl._full ) {
2487 var boxHelper =
new THREE.BoxHelper(this._toplevel);
2488 this._scene.add( boxHelper );
2490 this._scene.add(
new THREE.AxesHelper( 2 *
this._overall_size ) );
2491 this._scene.add(
new THREE.GridHelper( Math.ceil(
this._overall_size), Math.ceil( this._overall_size ) / 50 ) );
2492 this.helpText(
"<font face='verdana' size='1' color='red'><center>Transform Controls<br>" +
2493 "'T' translate | 'R' rotate | 'S' scale<br>" +
2494 "'+' increase size | '-' decrease size<br>" +
2495 "'W' toggle wireframe/solid display<br>"+
2496 "keep 'Ctrl' down to snap to grid</center></font>");
2502 TGeoPainter.prototype.drawCount =
function(unqievis, clonetm) {
2504 var res =
'Unique nodes: ' + this._clones.nodes.length +
'<br/>' +
2505 'Unique visible: ' + unqievis +
'<br/>' +
2506 'Time to clone: ' + clonetm +
'ms <br/>';
2509 this._clones.ScanVisible();
2511 var painter =
this, nshapes = 0;
2515 func:
function(node) {
2516 if (this.cnt[this.last]===undefined)
2517 this.cnt[this.last] = 1;
2519 this.cnt[this.last]++;
2521 nshapes += JSROOT.GEO.CountNumShapes(painter._clones.GetNodeShape(node.id));
2534 var tm1 =
new Date().getTime();
2535 var numvis = this._clones.ScanVisible(arg);
2536 var tm2 =
new Date().getTime();
2538 res +=
'Total visible nodes: ' + numvis +
'<br/>';
2539 res +=
'Total shapes: ' + nshapes +
'<br/>';
2541 for (var lvl=0;lvl<arg.cnt.length;++lvl) {
2542 if (arg.cnt[lvl] !== undefined)
2543 res += (
' lvl' + lvl +
': ' + arg.cnt[lvl] +
'<br/>');
2546 res +=
"Time to scan: " + (tm2-tm1) +
"ms <br/>";
2548 res +=
"<br/><br/>Check timing for matrix calculations ...<br/>";
2550 var elem = this.select_main().style(
'overflow',
'auto').html(res);
2552 setTimeout(
function() {
2553 arg.domatrix =
true;
2554 tm1 =
new Date().getTime();
2555 numvis = painter._clones.ScanVisible(arg);
2556 tm2 =
new Date().getTime();
2557 elem.append(
"p").text(
"Time to scan with matrix: " + (tm2-tm1) +
"ms");
2558 painter.DrawingReady();
2565 TGeoPainter.prototype.PerformDrop =
function(obj, itemname, hitem, opt, call_back) {
2567 if (obj && (obj.$kind===
'TTree')) {
2570 var funcname =
"extract_geo_tracks";
2572 if (opt && opt.indexOf(
"$")>0) {
2573 funcname = opt.substr(0, opt.indexOf(
"$"));
2574 opt = opt.substr(opt.indexOf(
"$")+1);
2577 var func = JSROOT.findFunction(funcname);
2579 if (!func)
return JSROOT.CallBack(call_back);
2581 var geo_painter =
this;
2583 return func(obj, opt,
function(tracks) {
2585 geo_painter.drawExtras(tracks,
"",
false);
2586 this.updateClipping(
true);
2587 geo_painter.Render3D(100);
2589 JSROOT.CallBack(call_back);
2593 if (this.drawExtras(obj, itemname)) {
2594 if (hitem) hitem._painter =
this;
2597 JSROOT.CallBack(call_back);
2600 TGeoPainter.prototype.MouseOverHierarchy =
function(on, itemname, hitem) {
2603 if (!this.ctrl)
return;
2605 var obj = hitem._obj;
2606 if (this.ctrl._debug)
2607 console.log(
'Mouse over', on, itemname, (obj ? obj._typename :
"---"));
2610 if (!obj || (obj._typename !==
"TEveTrack" && obj._typename !==
"TEvePointSet" && obj._typename !==
"TPolyMarker3D"))
return;
2612 this.HighlightMesh(null, 0x00ff00, on ? obj : null);
2615 TGeoPainter.prototype.clearExtras =
function() {
2616 this.getExtrasContainer(
"delete");
2617 delete this._extraObjects;
2624 TGeoPainter.prototype.addExtra =
function(obj, itemname) {
2625 if (this._extraObjects === undefined)
2626 this._extraObjects = JSROOT.Create(
"TList");
2628 if (this._extraObjects.arr.indexOf(obj)>=0)
return false;
2630 this._extraObjects.Add(obj, itemname);
2632 delete obj.$hidden_via_menu;
2637 TGeoPainter.prototype.ExtraObjectVisible =
function(hpainter, hitem, toggle) {
2638 if (!this._extraObjects)
return;
2640 var itemname = hpainter.itemFullName(hitem),
2641 indx = this._extraObjects.opt.indexOf(itemname);
2643 if ((indx<0) && hitem._obj) {
2644 indx = this._extraObjects.arr.indexOf(hitem._obj);
2646 if (indx>=0) this._extraObjects.opt[indx] = itemname;
2649 if (indx < 0)
return;
2651 var obj = this._extraObjects.arr[indx],
2652 res = obj.$hidden_via_menu ?
false :
true;
2655 obj.$hidden_via_menu = res; res = !res;
2659 this._toplevel.traverse(
function(node) {
if (node.geo_object === obj) mesh = node; });
2661 if (mesh) mesh.visible = res;
else
2663 this.drawExtras(obj,
"",
false);
2664 this.updateClipping(
true);
2667 if (mesh || res) this.Render3D();
2673 TGeoPainter.prototype.drawExtras =
function(obj, itemname, add_objects) {
2674 if (!obj || !obj._typename)
return false;
2677 if (!add_objects && obj.$hidden_via_menu)
return false;
2679 var isany =
false, do_render =
false;
2680 if (add_objects === undefined) {
2685 if ((obj._typename ===
"TList") || (obj._typename ===
"TObjArray")) {
2686 if (!obj.arr)
return false;
2687 for (var n=0;n<obj.arr.length;++n) {
2688 var sobj = obj.arr[n], sname = obj.opt ? obj.opt[n] :
"";
2689 if (!sname) sname = (itemname ||
"<prnt>") +
"/[" + n +
"]";
2690 if (this.drawExtras(sobj, sname, add_objects)) isany =
true;
2692 }
else if (obj._typename ===
'THREE.Mesh') {
2694 this.getExtrasContainer().add(obj);
2696 }
else if (obj._typename ===
'TGeoTrack') {
2697 if (add_objects && !this.addExtra(obj, itemname))
return false;
2698 isany = this.drawGeoTrack(obj, itemname);
2699 }
else if ((obj._typename ===
'TEveTrack') || (obj._typename ===
'ROOT::Experimental::TEveTrack')) {
2700 if (add_objects && !this.addExtra(obj, itemname))
return false;
2701 isany = this.drawEveTrack(obj, itemname);
2702 }
else if ((obj._typename ===
'TEvePointSet') || (obj._typename ===
"ROOT::Experimental::TEvePointSet") || (obj._typename ===
"TPolyMarker3D")) {
2703 if (add_objects && !this.addExtra(obj, itemname))
return false;
2704 isany = this.drawHit(obj, itemname);
2705 }
else if ((obj._typename ===
"TEveGeoShapeExtract") || (obj._typename ===
"ROOT::Experimental::TEveGeoShapeExtract")) {
2706 if (add_objects && !this.addExtra(obj, itemname))
return false;
2707 isany = this.drawExtraShape(obj, itemname);
2710 if (isany && do_render) {
2711 this.updateClipping(
true);
2718 TGeoPainter.prototype.getExtrasContainer =
function(action, name) {
2719 if (!this._toplevel)
return null;
2721 if (!name) name =
"tracks";
2723 var extras = null, lst = [];
2724 for (var n=0;n<this._toplevel.children.length;++n) {
2725 var chld = this._toplevel.children[n];
2726 if (!chld._extras)
continue;
2727 if (action===
'collect') { lst.push(chld);
continue; }
2728 if (chld._extras === name) { extras = chld;
break; }
2731 if (action===
'collect') {
2732 for (var k=0;k<lst.length;++k) this._toplevel.remove(lst[k]);
2736 if (action===
"delete") {
2737 if (extras) this._toplevel.remove(extras);
2738 JSROOT.Painter.DisposeThreejsObject(extras);
2742 if ((action!==
"get") && !extras) {
2743 extras =
new THREE.Object3D();
2744 extras._extras = name;
2745 this._toplevel.add(extras);
2751 TGeoPainter.prototype.drawGeoTrack =
function(track, itemname) {
2752 if (!track || !track.fNpoints)
return false;
2754 var track_width = track.fLineWidth || 1,
2755 track_color = JSROOT.Painter.root_colors[track.fLineColor] ||
"rgb(255,0,255)";
2757 if (JSROOT.browser.isWin) track_width = 1;
2759 var npoints = Math.round(track.fNpoints/4),
2760 buf =
new Float32Array((npoints-1)*6),
2761 pos = 0, projv = this.ctrl.projectPos,
2762 projx = (this.ctrl.project ===
"x"),
2763 projy = (this.ctrl.project ===
"y"),
2764 projz = (this.ctrl.project ===
"z");
2766 for (var k=0;k<npoints-1;++k) {
2767 buf[pos] = projx ? projv : track.fPoints[k*4];
2768 buf[pos+1] = projy ? projv : track.fPoints[k*4+1];
2769 buf[pos+2] = projz ? projv : track.fPoints[k*4+2];
2770 buf[pos+3] = projx ? projv : track.fPoints[k*4+4];
2771 buf[pos+4] = projy ? projv : track.fPoints[k*4+5];
2772 buf[pos+5] = projz ? projv : track.fPoints[k*4+6];
2776 var lineMaterial =
new THREE.LineBasicMaterial({ color: track_color, linewidth: track_width }),
2777 line = JSROOT.Painter.createLineSegments(buf, lineMaterial);
2779 line.renderOrder = 1000000;
2780 line.geo_name = itemname;
2781 line.geo_object = track;
2782 line.hightlightWidthScale = 2;
2784 if (itemname && itemname.indexOf(
"<prnt>/Tracks")==0)
2785 line.main_track =
true;
2787 this.getExtrasContainer().add(line);
2792 TGeoPainter.prototype.drawEveTrack =
function(track, itemname) {
2793 if (!track || (track.fN <= 0))
return false;
2795 var track_width = track.fLineWidth || 1,
2796 track_color = JSROOT.Painter.root_colors[track.fLineColor] ||
"rgb(255,0,255)";
2798 if (JSROOT.browser.isWin) track_width = 1;
2800 var buf =
new Float32Array((track.fN-1)*6), pos = 0,
2801 projv = this.ctrl.projectPos,
2802 projx = (this.ctrl.project ===
"x"),
2803 projy = (this.ctrl.project ===
"y"),
2804 projz = (this.ctrl.project ===
"z");
2806 for (var k=0;k<track.fN-1;++k) {
2807 buf[pos] = projx ? projv : track.fP[k*3];
2808 buf[pos+1] = projy ? projv : track.fP[k*3+1];
2809 buf[pos+2] = projz ? projv : track.fP[k*3+2];
2810 buf[pos+3] = projx ? projv : track.fP[k*3+3];
2811 buf[pos+4] = projy ? projv : track.fP[k*3+4];
2812 buf[pos+5] = projz ? projv : track.fP[k*3+5];
2816 var lineMaterial =
new THREE.LineBasicMaterial({ color: track_color, linewidth: track_width }),
2817 line = JSROOT.Painter.createLineSegments(buf, lineMaterial);
2819 line.renderOrder = 1000000;
2820 line.geo_name = itemname;
2821 line.geo_object = track;
2822 line.hightlightWidthScale = 2;
2824 this.getExtrasContainer().add(line);
2831 TGeoPainter.prototype.drawHit =
function(hit, itemname) {
2832 if (!hit || !hit.fN || (hit.fN < 0))
return false;
2836 var hit_size = hit.fMarkerSize * this.getOverallSize() * 0.005;
2837 if (hit_size <= 0) hit_size = 1;
2840 projv = this.ctrl.projectPos,
2841 projx = (this.ctrl.project ===
"x"),
2842 projy = (this.ctrl.project ===
"y"),
2843 projz = (this.ctrl.project ===
"z"),
2844 pnts =
new JSROOT.Painter.PointsCreator(size,
this._webgl, hit_size);
2846 for (var i=0;i<size;i++)
2847 pnts.AddPoint(projx ? projv : hit.fP[i*3],
2848 projy ? projv : hit.fP[i*3+1],
2849 projz ? projv : hit.fP[i*3+2]);
2851 var mesh = pnts.CreatePoints({ color: JSROOT.Painter.root_colors[hit.fMarkerColor] ||
"rgb(0,0,255)",
2852 style: hit.fMarkerStyle,
2853 callback:
function(delayed) {
if (delayed) this.Render3D(100); }.bind(
this) });
2855 mesh.renderOrder = 1000000;
2856 mesh.highlightScale = 2;
2858 mesh.geo_name = itemname;
2859 mesh.geo_object = hit;
2861 this.getExtrasContainer().add(mesh);
2866 TGeoPainter.prototype.drawExtraShape =
function(obj, itemname) {
2867 var toplevel = JSROOT.GEO.build(obj);
2868 if (!toplevel)
return false;
2870 toplevel.geo_name = itemname;
2871 toplevel.geo_object = obj;
2873 this.getExtrasContainer().add(toplevel);
2877 TGeoPainter.prototype.FindNodeWithVolume =
function(name, action, prnt, itemname, volumes) {
2879 var first_level =
false, res = null;
2882 prnt = this.GetGeometry();
2883 if (!prnt && (JSROOT.GEO.NodeKind(prnt)!==0))
return null;
2884 itemname = this.geo_manager ? prnt.fName :
"";
2888 if (itemname.length>0) itemname +=
"/";
2889 itemname += prnt.fName;
2892 if (!prnt.fVolume || prnt.fVolume._searched)
return null;
2894 if (name.test(prnt.fVolume.fName)) {
2895 res = action({ node: prnt, item: itemname });
2896 if (res)
return res;
2899 prnt.fVolume._searched =
true;
2900 volumes.push(prnt.fVolume);
2902 if (prnt.fVolume.fNodes)
2903 for (var n=0;n<prnt.fVolume.fNodes.arr.length;++n) {
2904 res = this.FindNodeWithVolume(name, action, prnt.fVolume.fNodes.arr[n], itemname, volumes);
2909 for (var n=0, len=volumes.length; n<len; ++n)
2910 delete volumes[n]._searched;
2916 TGeoPainter.prototype.checkScript =
function(script_name, call_back) {
2918 var painter =
this, draw_obj = this.GetGeometry(), name_prefix =
"";
2920 if (this.geo_manager) name_prefix = draw_obj.fName;
2922 if (!script_name || (script_name.length<3) || (JSROOT.GEO.NodeKind(draw_obj)!==0))
2923 return JSROOT.CallBack(call_back, draw_obj, name_prefix);
2926 GetVolume:
function (name) {
2927 var regexp =
new RegExp(
"^"+name+
"$");
2928 var currnode = painter.FindNodeWithVolume(regexp,
function(arg) {
return arg; } );
2930 if (!currnode) console.log(
'Did not found '+name +
' volume');
2935 fVolume: currnode ? currnode.node.fVolume : null,
2936 InvisibleAll:
function(flag) {
2937 JSROOT.GEO.InvisibleAll.call(this.fVolume, flag);
2940 if (!this.found || !this.fVolume)
return;
2941 draw_obj = this.found.node;
2942 name_prefix = this.found.item;
2943 console.log(
'Select volume for drawing', this.fVolume.fName, name_prefix);
2945 SetTransparency:
function(lvl) {
2946 if (this.fVolume && this.fVolume.fMedium &&
this.fVolume.fMedium.fMaterial)
2947 this.fVolume.fMedium.fMaterial.fFillStyle = 3000+lvl;
2949 SetLineColor:
function(col) {
2950 if (this.fVolume) this.fVolume.fLineColor = col;
2955 DefaultColors:
function() {
2956 painter.ctrl.dflt_colors =
true;
2959 SetMaxVisNodes:
function(limit) {
2960 if (!painter.ctrl.maxnodes)
2961 painter.ctrl.maxnodes = pasrseInt(limit) || 0;
2964 SetVisLevel:
function(limit) {
2965 if (!painter.ctrl.vislevel)
2966 painter.ctrl.vislevel = parseInt(limit) || 0;
2970 JSROOT.progress(
'Loading macro ' + script_name);
2972 JSROOT.NewHttpRequest(script_name,
"text",
function(res) {
2973 if (!res || (res.length==0))
2974 return JSROOT.CallBack(call_back, draw_obj, name_prefix);
2976 var lines = res.split(
'\n');
2980 function ProcessNextLine(indx) {
2982 var first_tm =
new Date().getTime();
2983 while (indx < lines.length) {
2984 var line = lines[indx++].trim();
2986 if (line.indexOf(
'//')==0)
continue;
2988 if (line.indexOf(
'gGeoManager')<0)
continue;
2989 line = line.replace(
'->GetVolume',
'.GetVolume');
2990 line = line.replace(
'->InvisibleAll',
'.InvisibleAll');
2991 line = line.replace(
'->SetMaxVisNodes',
'.SetMaxVisNodes');
2992 line = line.replace(
'->DefaultColors',
'.DefaultColors');
2993 line = line.replace(
'->Draw',
'.Draw');
2994 line = line.replace(
'->SetTransparency',
'.SetTransparency');
2995 line = line.replace(
'->SetLineColor',
'.SetLineColor');
2996 line = line.replace(
'->SetVisLevel',
'.SetVisLevel');
2997 if (line.indexOf(
'->')>=0)
continue;
3002 var func =
new Function(
'gGeoManager',line);
3005 console.error(
'Problem by processing ' + line);
3008 var now =
new Date().getTime();
3009 if (now - first_tm > 300) {
3010 JSROOT.progress(
'exec ' + line);
3011 return setTimeout(ProcessNextLine.bind(
this,indx),1);
3015 JSROOT.CallBack(call_back, draw_obj, name_prefix);
3023 TGeoPainter.prototype.assignClones =
function(clones) {
3024 this._clones_owner =
true;
3025 this._clones = clones;
3030 TGeoPainter.prototype.prepareObjectDraw =
function(draw_obj, name_prefix) {
3033 if (this.did_cleanup)
3036 if (name_prefix ==
"__geom_viewer_append__") {
3037 this._new_append_nodes = draw_obj;
3038 this.ctrl.use_worker = 0;
3039 this._geom_viewer =
true;
3040 }
else if ((name_prefix ==
"__geom_viewer_selection__") && this._clones) {
3042 this._new_draw_nodes = draw_obj;
3043 this.ctrl.use_worker = 0;
3044 this._geom_viewer =
true;
3045 }
else if (this._main_painter) {
3047 this._clones_owner =
false;
3049 this._clones = this._main_painter._clones;
3051 console.log(
'Reuse clones', this._clones.nodes.length,
'from main painter');
3053 }
else if (!draw_obj) {
3055 this._clones_owner =
false;
3057 this._clones = null;
3061 this._start_drawing_time =
new Date().getTime();
3063 this._clones_owner =
true;
3065 this._clones =
new JSROOT.GEO.ClonedNodes(draw_obj);
3067 var lvl = this.ctrl.vislevel, maxnodes = this.ctrl.maxnodes;
3068 if (this.geo_manager) {
3069 if (!lvl && this.geo_manager.fVisLevel)
3070 lvl = this.geo_manager.fVisLevel;
3072 maxnodes = this.geo_manager.fMaxVisNodes;
3075 this._clones.SetVisLevel(lvl);
3076 this._clones.SetMaxVisNodes(maxnodes);
3078 this._clones.name_prefix = name_prefix;
3080 var hide_top_volume = !!this.geo_manager && !this.ctrl.showtop;
3082 var uniquevis = this.ctrl.no_screen ? 0 : this._clones.MarkVisibles(
true,
false, hide_top_volume);
3085 uniquevis = this._clones.MarkVisibles(
false,
false, hide_top_volume);
3087 uniquevis = this._clones.MarkVisibles(
true,
true, hide_top_volume);
3089 this._clones.ProduceIdShits();
3091 var spent =
new Date().getTime() - this._start_drawing_time;
3094 console.log(
'Creating clones', this._clones.nodes.length,
'takes', spent,
'uniquevis', uniquevis);
3096 if (this.options._count)
3097 return this.drawCount(uniquevis, spent);
3103 this.ctrl.maxlimit = (this._webgl ? 200000 : 100000) * this.ctrl.more;
3105 this._first_drawing =
true;
3108 if (this.ctrl.use_worker > 0) this.startWorker();
3110 var size = this.size_for_3d(this._usesvg ? 3 : undefined);
3112 this._fit_main_area = (size.can3d === -1);
3114 var dom = this.createScene(size.width, size.height);
3116 this.add_3d_canvas(size, dom);
3119 this.AccessTopPainter(
true);
3122 this.CreateToolbar();
3125 this.showDrawInfo(
"Drawing geometry");
3126 this.startDrawGeometry(
true);
3128 this.completeDraw();
3132 TGeoPainter.prototype.showDrawInfo =
function(msg) {
3135 if (!this._first_drawing || !this._start_drawing_time)
return;
3137 var main = this._renderer.domElement.parentNode,
3138 info = d3.select(main).select(
".geo_info");
3143 var spent = (
new Date().getTime() - this._start_drawing_time)*1e-3;
3144 if (info.empty()) info = d3.select(main).append(
"p").attr(
"class",
"geo_info");
3145 info.html(msg +
", " + spent.toFixed(1) +
"s");
3150 TGeoPainter.prototype.continueDraw =
function() {
3153 if (this.drawing_stage === 0)
return;
3155 var tm0 =
new Date().getTime(),
3156 interval = this._first_drawing ? 1000 : 200,
3161 var res = this.nextDrawAction();
3165 now =
new Date().getTime();
3168 if (now - this._startm > 1e5) {
3169 this.drawing_stage = 0;
3174 if ((res ===
true) && (now - tm0 < interval))
continue;
3176 if ((now - tm0 > interval) || (res === 1) || (res === 2)) {
3178 JSROOT.progress(this.drawing_log);
3180 this.showDrawInfo(this.drawing_log);
3182 if (this._first_drawing && this._webgl && (this._num_meshes - this._last_render_meshes > 100) && (now - this._last_render_tm > 2.5*interval)) {
3183 this.adjustCameraPosition();
3185 this._last_render_meshes = this.ctrl.info.num_meshes;
3187 if (res !== 2) setTimeout(this.continueDraw.bind(
this), (res === 1) ? 100 : 1);
3193 var take_time = now - this._startm;
3195 if (this._first_drawing)
3196 JSROOT.console(
'Create tm = ' + take_time +
' meshes ' + this.ctrl.info.num_meshes +
' faces ' +
this.ctrl.info.num_faces);
3198 if (take_time > 300) {
3199 JSROOT.progress(
'Rendering geometry');
3200 this.showDrawInfo(
"Rendering");
3201 return setTimeout(this.completeDraw.bind(
this,
true), 10);
3204 this.completeDraw(
true);
3211 TGeoPainter.prototype.TestCameraPosition =
function(force) {
3212 this._camera.updateMatrixWorld();
3213 var origin = this._camera.position.clone();
3215 if (!force && this._last_camera_position) {
3217 var dist = this._last_camera_position.distanceTo(origin);
3218 if (dist < (this._overall_size || 1000)*1e-4)
return;
3221 this._last_camera_position = origin;
3223 if (!this.ctrl.project &&
this._webgl)
3224 JSROOT.GEO.produceRenderOrder(this._toplevel, origin, this.ctrl.depthMethod,
this._clones);
3235 TGeoPainter.prototype.Render3D =
function(tmout, measure) {
3237 if (!this._renderer) {
3238 console.warn(
'renderer object not exists - check code');
3242 if (tmout === undefined) tmout = 5;
3244 if ((tmout <= 0) || this._usesvg) {
3245 if (
'render_tmout' in
this) {
3246 clearTimeout(this.render_tmout);
3248 if (tmout === -2222)
return;
3251 var tm1 =
new Date();
3253 this.TestCameraPosition(tmout === -1);
3256 if (this._webgl && this._effectComposer && (this._effectComposer.passes.length > 0)) {
3257 this._effectComposer.render();
3260 this._renderer.render(this._scene, this._camera);
3263 var tm2 =
new Date();
3265 this.last_render_tm = tm2.getTime();
3267 delete this.render_tmout;
3269 if ((this.first_render_tm === 0) && measure) {
3270 this.first_render_tm = tm2.getTime() - tm1.getTime();
3271 JSROOT.console(
'First render tm = ' + this.first_render_tm);
3274 return JSROOT.Painter.AfterRender3D(this._renderer);
3278 if (!this.render_tmout)
3279 this.render_tmout = setTimeout(this.Render3D.bind(
this,0,measure), tmout);
3283 TGeoPainter.prototype.startWorker =
function() {
3285 if (this._worker)
return;
3287 this._worker_ready =
false;
3288 this._worker_jobs = 0;
3292 this._worker =
new Worker(JSROOT.source_dir +
"scripts/JSRootGeoWorker.js");
3294 this._worker.onmessage =
function(e) {
3296 if (typeof e.data !==
'object')
return;
3298 if (
'log' in e.data)
3299 return JSROOT.console(
'geo: ' + e.data.log);
3301 if (
'progress' in e.data)
3302 return JSROOT.progress(e.data.progress);
3304 e.data.tm3 =
new Date().getTime();
3306 if (
'init' in e.data) {
3307 pthis._worker_ready =
true;
3308 return JSROOT.console(
'Worker ready: ' + (e.data.tm3 - e.data.tm0));
3311 pthis.processWorkerReply(e.data);
3315 this._worker.postMessage( {
3317 browser: JSROOT.browser,
3318 tm0:
new Date().getTime(),
3319 vislevel: this._clones.GetVisLevel(),
3320 maxvisnodes: this._clones.GetMaxVisNodes(),
3321 clones: this._clones.nodes,
3322 sortmap: this._clones.sortmap } );
3325 TGeoPainter.prototype.canSubmitToWorker =
function(force) {
3326 if (!this._worker)
return false;
3328 return this._worker_ready && ((this._worker_jobs == 0) || force);
3331 TGeoPainter.prototype.submitToWorker =
function(job) {
3332 if (!this._worker)
return false;
3334 this._worker_jobs++;
3336 job.tm0 =
new Date().getTime();
3338 this._worker.postMessage(job);
3341 TGeoPainter.prototype.processWorkerReply =
function(job) {
3342 this._worker_jobs--;
3344 if (
'collect' in job) {
3345 this._new_draw_nodes = job.new_nodes;
3346 this._draw_all_nodes = job.complete;
3347 this.drawing_stage = 3;
3349 return this.continueDraw();
3352 if (
'shapes' in job) {
3354 for (var n=0;n<job.shapes.length;++n) {
3355 var item = job.shapes[n],
3356 origin = this._build_shapes[n];
3360 if (item.buf_pos && item.buf_norm) {
3361 if (item.buf_pos.length === 0) {
3363 }
else if (item.buf_pos.length !== item.buf_norm.length) {
3364 console.error(
'item.buf_pos',item.buf_pos.length,
'item.buf_norm', item.buf_norm.length);
3367 origin.geom =
new THREE.BufferGeometry();
3369 origin.geom.addAttribute(
'position',
new THREE.BufferAttribute( item.buf_pos, 3 ) );
3370 origin.geom.addAttribute(
'normal',
new THREE.BufferAttribute( item.buf_norm, 3 ) );
3373 origin.ready =
true;
3374 origin.nfaces = item.nfaces;
3378 job.tm4 =
new Date().getTime();
3382 this.drawing_stage = 7;
3385 return this.continueDraw();
3389 TGeoPainter.prototype.testGeomChanges =
function() {
3390 if (this._main_painter) {
3391 console.warn(
'Get testGeomChanges call for slave painter');
3392 return this._main_painter.testGeomChanges();
3394 this.startDrawGeometry();
3395 for (var k=0;k<this._slave_painters.length;++k)
3396 this._slave_painters[k].startDrawGeometry();
3400 TGeoPainter.prototype.drawSimpleAxis =
function(norender) {
3401 this.getExtrasContainer(
'delete',
'axis');
3403 if (!this.ctrl._axis)
3404 return norender ? null : this.Render3D();
3406 var box = this.getGeomBoundingBox(this._toplevel);
3408 var container = this.getExtrasContainer(
'create',
'axis');
3410 var text_size = 0.02 * Math.max( (box.max.x - box.min.x), (box.max.y - box.min.y), (box.max.z - box.min.z)),
3412 names = [
'x',
'y',
'z'],
3413 labels = [
'X',
'Y',
'Z'],
3414 colors = [
"red",
"green",
"blue"],
3415 ortho = this.ctrl.ortho_camera,
3416 yup = [this.ctrl._yup, this.ctrl._yup, this.ctrl._yup],
3419 if (this.ctrl._axis == 2)
3420 for (var naxis=0;naxis<3;++naxis) {
3421 var name = names[naxis];
3422 if ((box.min[name]<=0) && (box.max[name]>=0))
continue;
3423 center[naxis] = (box.min[name] + box.max[name])/2;
3427 if (this.ctrl.ortho_camera) {
3429 labels[0] = labels[2];
3430 colors[0] = colors[2];
3435 for (var naxis=0;naxis<numaxis;++naxis) {
3437 var buf =
new Float32Array(6), axiscol = colors[naxis], name = names[naxis];
3439 function Convert(value) {
3440 var range = box.max[name] - box.min[name];
3441 if (range<2)
return value.toFixed(3);
3442 if (Math.abs(value)>1e5)
return value.toExponential(3);
3443 return Math.round(value).toString();
3446 var lbl = Convert(box.max[name]);
3457 case 0: buf[3] = box.max.x;
if (yup[0] && !ortho) lbl = labels[0] +
" " + lbl;
else lbl +=
" " + labels[0];
break;
3458 case 1: buf[4] = box.max.y;
if (yup[1]) lbl +=
" " + labels[1];
else lbl = labels[1] +
" " + lbl;
break;
3459 case 2: buf[5] = box.max.z; lbl +=
" " + labels[2];
break;
3462 if (this.ctrl._axis == 2)
3463 for (var k=0;k<6;++k)
3464 if ((k % 3) !== naxis) buf[k] = center[k%3];
3466 var lineMaterial =
new THREE.LineBasicMaterial({ color: axiscol }),
3467 mesh = JSROOT.Painter.createLineSegments(buf, lineMaterial);
3469 container.add(mesh);
3471 var textMaterial =
new THREE.MeshBasicMaterial({ color: axiscol });
3473 if ((center[naxis]===0) && (center[naxis]>=box.min[name]) && (center[naxis]<=box.max[name]))
3474 if ((this.ctrl._axis != 2) || (naxis===0)) {
3475 var geom = ortho ?
new THREE.CircleBufferGeometry(text_size*0.25) :
3476 new THREE.SphereBufferGeometry(text_size*0.25);
3477 mesh =
new THREE.Mesh(geom, textMaterial);
3478 mesh.translateX((naxis===0) ? center[0] : buf[0]);
3479 mesh.translateY((naxis===1) ? center[1] : buf[1]);
3480 mesh.translateZ((naxis===2) ? center[2] : buf[2]);
3481 container.add(mesh);
3484 var text3d =
new THREE.TextGeometry(lbl, { font: JSROOT.threejs_font_helvetiker_regular, size: text_size, height: 0, curveSegments: 5 });
3485 mesh =
new THREE.Mesh(text3d, textMaterial);
3486 var textbox =
new THREE.Box3().setFromObject(mesh);
3488 mesh.translateX(buf[3]);
3489 mesh.translateY(buf[4]);
3490 mesh.translateZ(buf[5]);
3496 mesh.rotateY(Math.PI);
3497 mesh.translateX(-textbox.max.x-text_size*0.5);
3499 mesh.translateX(text_size*0.5);
3501 mesh.translateY(-textbox.max.y/2);
3505 mesh.rotateX(-Math.PI/2);
3506 mesh.rotateY(-Math.PI/2);
3508 mesh.rotateZ(Math.PI/2);
3510 mesh.translateX(text_size*0.5);
3511 mesh.translateY(-textbox.max.y/2);
3513 case 2: mesh.rotateY(-Math.PI/2); mesh.translateX(text_size*0.5); mesh.translateY(-textbox.max.y/2);
break;
3517 case 0: mesh.rotateX(Math.PI/2); mesh.translateY(-textbox.max.y/2); mesh.translateX(text_size*0.5);
break;
3518 case 1: mesh.rotateX(Math.PI/2); mesh.rotateY(-Math.PI/2); mesh.translateX(-textbox.max.x-text_size*0.5); mesh.translateY(-textbox.max.y/2);
break;
3519 case 2: mesh.rotateX(Math.PI/2); mesh.rotateZ(Math.PI/2); mesh.translateX(text_size*0.5); mesh.translateY(-textbox.max.y/2);
break;
3523 container.add(mesh);
3525 text3d =
new THREE.TextGeometry(Convert(box.min[name]), { font: JSROOT.threejs_font_helvetiker_regular, size: text_size, height: 0, curveSegments: 5 });
3527 mesh =
new THREE.Mesh(text3d, textMaterial);
3528 textbox =
new THREE.Box3().setFromObject(mesh);
3530 mesh.translateX(buf[0]);
3531 mesh.translateY(buf[1]);
3532 mesh.translateZ(buf[2]);
3538 mesh.rotateY(Math.PI);
3539 mesh.translateX(text_size*0.5);
3541 mesh.translateX(-textbox.max.x-text_size*0.5);
3543 mesh.translateY(-textbox.max.y/2);
3547 mesh.rotateX(-Math.PI/2);
3548 mesh.rotateY(-Math.PI/2);
3550 mesh.rotateZ(Math.PI/2);
3552 mesh.translateY(-textbox.max.y/2);
3553 mesh.translateX(-textbox.max.x-text_size*0.5);
3555 case 2: mesh.rotateY(-Math.PI/2); mesh.translateX(-textbox.max.x-text_size*0.5); mesh.translateY(-textbox.max.y/2);
break;
3559 case 0: mesh.rotateX(Math.PI/2); mesh.translateX(-textbox.max.x-text_size*0.5); mesh.translateY(-textbox.max.y/2);
break;
3560 case 1: mesh.rotateX(Math.PI/2); mesh.rotateY(-Math.PI/2); mesh.translateY(-textbox.max.y/2); mesh.translateX(text_size*0.5);
break;
3561 case 2: mesh.rotateX(Math.PI/2); mesh.rotateZ(Math.PI/2); mesh.translateX(-textbox.max.x-text_size*0.5); mesh.translateY(-textbox.max.y/2);
break;
3565 container.add(mesh);
3569 this.changedDepthMethod(norender ?
"norender" : undefined);
3573 TGeoPainter.prototype.toggleAxesDraw =
function() {
3574 this.setAxesDraw(
"toggle");
3578 TGeoPainter.prototype.setAxesDraw =
function(on) {
3579 if (on ===
"toggle")
3580 this.ctrl._axis = this.ctrl._axis ? 0 : 1;
3582 this.ctrl._axis = (typeof on ==
'number') ? on : (on ? 1 : 0);
3583 this.drawSimpleAxis();
3587 TGeoPainter.prototype.setAutoRotate =
function(on) {
3588 if (this.ctrl.project)
return;
3589 if (on !== undefined) this.ctrl.rotate = on;
3590 this.autorotate(2.5);
3594 TGeoPainter.prototype.toggleWireFrame =
function() {
3595 this.ctrl.wireframe = !this.ctrl.wireframe;
3596 this.changedWireFrame();
3600 TGeoPainter.prototype.setWireFrame =
function(on) {
3601 this.ctrl.wireframe = on ?
true :
false;
3602 this.changedWireFrame();
3606 TGeoPainter.prototype.setShowTop =
function(on) {
3607 this.ctrl.showtop = on ?
true :
false;
3608 this.RedrawObject(
'same');
3612 TGeoPainter.prototype.changedClipping =
function(naxis) {
3613 var clip = this.ctrl.clip;
3615 if ((naxis !== undefined) && (naxis >= 0)) {
3616 if (!clip[naxis].enabled)
return;
3619 if (clip[0].enabled || clip[1].enabled || clip[2].enabled) {
3620 this.ctrl.ssao.enabled =
false;
3624 this.updateClipping(
false,
true);
3628 TGeoPainter.prototype.changedDepthTest =
function() {
3629 if (!this._toplevel)
return;
3630 var flag = this.ctrl.depthTest;
3631 this._toplevel.traverse(
function (node) {
3632 if (node instanceof THREE.Mesh) {
3633 node.material.depthTest = flag;
3641 TGeoPainter.prototype.changedDepthMethod =
function(arg) {
3643 delete this._last_camera_position;
3644 if (arg !==
"norender") this.Render3D();
3648 TGeoPainter.prototype.changedHighlight =
function() {
3649 if (!this.ctrl.highlight)
3650 this.HighlightMesh(null);
3654 TGeoPainter.prototype.updateClipping =
function(without_render, force_traverse) {
3655 if (!this._webgl)
return;
3657 var clip = this.ctrl.clip, panels = [], changed =
false,
3658 constants = [ clip[0].value, -1 * clip[1].value, (this.ctrl._yup ? -1 : 1) * clip[2].value ],
3659 clip_cfg = this.ctrl.clipIntersect ? 16 : 0;
3661 for (var k=0;k<3;++k) {
3662 if (clip[k].enabled) clip_cfg += 2 << k;
3663 if (this._clipPlanes[k].constant != constants[k]) {
3665 this._clipPlanes[k].constant = constants[k];
3669 if (!this.ctrl.ssao.enabled) {
3670 if (clip[0].enabled) panels.push(this._clipPlanes[0]);
3671 if (clip[1].enabled) panels.push(this._clipPlanes[1]);
3672 if (clip[2].enabled) panels.push(this._clipPlanes[2]);
3673 clip_cfg += panels.length*1000;
3675 if (panels.length == 0) panels = null;
3677 if (this._clipCfg !== clip_cfg) changed =
true;
3679 this._clipCfg = clip_cfg;
3681 var any_clipping = !!panels, ci = this.ctrl.clipIntersect,
3682 material_side = any_clipping ? THREE.DoubleSide : THREE.FrontSide;
3684 if (force_traverse || changed)
3685 this._scene.traverse(
function (node) {
3686 if (node.hasOwnProperty(
"material") && node.material && (node.material.clippingPlanes !== undefined)) {
3688 if (node.material.clippingPlanes !== panels) {
3689 node.material.clipIntersection = ci;
3690 node.material.clippingPlanes = panels;
3691 node.material.needsUpdate =
true;
3694 if (node.material.emissive !== undefined) {
3695 if (node.material.side != material_side) {
3696 node.material.side = material_side;
3697 node.material.needsUpdate =
true;
3703 this.ctrl.bothSides = any_clipping;
3705 if (!without_render) this.Render3D(0);
3710 TGeoPainter.prototype.setCompleteHandler =
function(callback) {
3711 this._complete_handler = callback;
3715 TGeoPainter.prototype.completeDraw =
function(close_progress) {
3717 var first_time =
false, full_redraw =
false, check_extras =
true;
3720 console.warn(
'ctrl object does not exist in completeDraw - something went wrong');
3724 if (!this._clones) {
3725 check_extras =
false;
3727 this.getExtrasContainer(
"delete");
3728 var extras = (this._main_painter ? this._main_painter._extraObjects : null) || this._extraObjects;
3729 this.drawExtras(extras,
"",
false);
3730 }
else if (this._first_drawing || this._full_redrawing) {
3731 if (this.ctrl.tracks &&
this.geo_manager)
3732 this.drawExtras(this.geo_manager.fTracks,
"<prnt>/Tracks");
3735 if (this._full_redrawing) {
3736 this._full_redrawing =
false;
3738 this.changedDepthMethod(
"norender");
3741 if (this._first_drawing) {
3742 this.adjustCameraPosition(
true);
3743 this.showDrawInfo();
3744 this._first_drawing =
false;
3749 if (this.ctrl.transparency!==0)
3750 this.changedGlobalTransparency(this.ctrl.transparency,
true);
3753 this.completeScene();
3755 if (full_redraw && (this.ctrl.trans_radial ||
this.ctrl.trans_z))
3756 this.changedTransformation(
"norender");
3758 if (full_redraw && this.ctrl._axis)
3759 this.drawSimpleAxis(
true);
3761 this._scene.overrideMaterial = null;
3763 if (this._provided_more_nodes !== undefined) {
3764 this.appendMoreNodes(this._provided_more_nodes,
true);
3765 delete this._provided_more_nodes;
3770 this.getExtrasContainer(
"delete");
3771 var extras = (this._main_painter ? this._main_painter._extraObjects : null) || this._extraObjects;
3772 this.drawExtras(extras,
"",
false);
3775 this.updateClipping(
true);
3777 this.Render3D(0,
true);
3779 if (close_progress) JSROOT.progress();
3781 this.addOrbitControls();
3783 this.addTransformControl();
3788 if (this.ctrl.highlight ===
false)
3789 this.ctrl.highlight = (this.first_render_tm < 1000);
3792 if (this.ctrl.highlight_scene ===
false)
3793 this.ctrl.highlight_scene = this.ctrl.highlight;
3796 if (this._webgl && this.ctrl.rotate && !
this.ctrl.project) this.autorotate(2.5);
3797 if (!this._usesvg && this.ctrl.show_controls && !JSROOT.BatchMode) this.showControlOptions(
true);
3801 this.DrawingReady();
3803 if (typeof this._complete_handler ==
'function')
3804 this._complete_handler(
this);
3806 if (this._draw_nodes_again)
3807 return this.startDrawGeometry();
3809 this._drawing_ready =
true;
3813 TGeoPainter.prototype.isDrawingReady =
function() {
3814 return this._drawing_ready ||
false;
3818 TGeoPainter.prototype.RemoveDrawnNode =
function(nodeid) {
3819 if (!this._draw_nodes)
return;
3823 for (var n = 0; n < this._draw_nodes.length; ++n) {
3824 var entry = this._draw_nodes[n];
3825 if ((entry.nodeid === nodeid) || this._clones.IsNodeInStack(nodeid, entry.stack)) {
3826 this._clones.CreateObject3D(entry.stack,
this._toplevel,
'delete_mesh');
3828 new_nodes.push(entry);
3832 if (new_nodes.length <
this._draw_nodes.length) {
3833 this._draw_nodes = new_nodes;
3838 TGeoPainter.prototype.Cleanup =
function(first_time) {
3844 this.AccessTopPainter(
false);
3846 var can3d = this.clear_3d_canvas();
3848 if (this._toolbar) this._toolbar.Cleanup();
3852 JSROOT.Painter.DisposeThreejsObject(this._scene);
3854 JSROOT.Painter.DisposeThreejsObject(this._full_geom);
3856 if (this._tcontrols)
3857 this._tcontrols.dispose();
3860 this._controls.Cleanup();
3862 if (this._context_menu)
3863 this._renderer.domElement.removeEventListener(
'contextmenu', this._context_menu,
false );
3866 this._datgui.destroy();
3868 if (this._worker) this._worker.terminate();
3870 delete this._animating;
3872 var obj = this.GetGeometry();
3873 if (obj && this.ctrl.is_main) {
3874 if (obj.$geo_painter===
this)
delete obj.$geo_painter;
else
3875 if (obj.fVolume && obj.fVolume.$geo_painter===
this)
delete obj.fVolume.$geo_painter;
3878 if (this._main_painter) {
3879 var pos = this._main_painter._slave_painters.indexOf(
this);
3880 if (pos>=0) this._main_painter._slave_painters.splice(pos,1);
3883 for (var k=0;k<this._slave_painters.length;++k) {
3884 var slave = this._slave_painters[k];
3885 if (slave && (slave._main_painter===
this)) slave._main_painter = null;
3888 delete this.geo_manager;
3889 delete this._highlight_handlers;
3891 JSROOT.TObjectPainter.prototype.Cleanup.call(
this);
3894 delete this.options;
3896 this.did_cleanup =
true;
3898 if (can3d < 0) this.select_main().html(
"");
3901 if (this._slave_painters)
3902 for (var k in this._slave_painters) {
3903 var slave = this._slave_painters[k];
3904 slave._main_painter = null;
3905 if (slave._clones ===
this._clones) slave._clones = null;
3908 this._main_painter = null;
3909 this._slave_painters = [];
3911 if (this._renderer) {
3912 if (this._renderer.dispose) this._renderer.dispose();
3913 if (this._renderer.context)
delete this._renderer.context;
3917 this._scene_width = 0;
3918 this._scene_height = 0;
3919 this._renderer = null;
3920 this._toplevel = null;
3921 delete this._full_geom;
3922 delete this._camera;
3923 delete this._camera0pos;
3924 delete this._lookat;
3925 delete this._selected_mesh;
3927 if (this._clones && this._clones_owner)
3928 this._clones.Cleanup(this._draw_nodes, this._build_shapes);
3929 delete this._clones;
3930 delete this._clones_owner;
3931 delete this._draw_nodes;
3932 delete this._drawing_ready;
3933 delete this._build_shapes;
3934 delete this._new_draw_nodes;
3935 delete this._new_append_nodes;
3936 delete this._last_camera_position;
3938 this.first_render_tm = 0;
3939 this.last_render_tm = 0;
3941 this.drawing_stage = 0;
3942 delete this.drawing_log;
3944 delete this._datgui;
3945 delete this._controls;
3946 delete this._context_menu;
3947 delete this._tcontrols;
3948 delete this._toolbar;
3950 delete this._worker;
3953 TGeoPainter.prototype.helpText =
function(msg) {
3954 JSROOT.progress(msg);
3957 TGeoPainter.prototype.CheckResize =
function(arg) {
3958 var pad_painter = this.canv_painter();
3963 if (!pad_painter.CheckCanvasResize(arg))
return false;
3965 var sz = this.size_for_3d();
3967 if ((this._scene_width === sz.width) && (
this._scene_height === sz.height))
return false;
3968 if ((sz.width<10) || (sz.height<10))
return false;
3970 this._scene_width = sz.width;
3971 this._scene_height = sz.height;
3973 if (this._camera && this._renderer) {
3974 if (this._camera.type ==
"PerspectiveCamera")
3975 this._camera.aspect = this._scene_width / this._scene_height;
3976 this._camera.updateProjectionMatrix();
3977 this._renderer.setSize( this._scene_width, this._scene_height, !this._fit_main_area );
3978 if (this._effectComposer)
3979 this._effectComposer.setSize( this._scene_width, this._scene_height );
3981 if (!this.drawing_stage) this.Render3D();
3987 TGeoPainter.prototype.toggleEnlarge =
function() {
3990 d3.event.preventDefault();
3991 d3.event.stopPropagation();
3994 if (this.enlarge_main(
'toggle'))
3999 TGeoPainter.prototype.ownedByTransformControls =
function(child) {
4000 var obj = child.parent;
4001 while (obj && !(obj instanceof THREE.TransformControls) ) {
4004 return (obj && (obj instanceof THREE.TransformControls));
4007 TGeoPainter.prototype.accessObjectWireFrame =
function(obj, on) {
4011 if (!obj.hasOwnProperty(
"material") || (obj instanceof THREE.GridHelper))
return;
4013 if (this.ownedByTransformControls(obj))
return;
4015 if ((on !== undefined) && obj.stack)
4016 obj.material.wireframe = on;
4018 return obj.material.wireframe;
4021 TGeoPainter.prototype.changedWireFrame =
function() {
4022 if (!this._scene)
return;
4024 var painter =
this, on = this.ctrl.wireframe;
4026 this._scene.traverse(
function(obj) { painter.accessObjectWireFrame(obj, on); });
4031 TGeoPainter.prototype.UpdateObject =
function(obj) {
4032 if (obj ===
"same")
return true;
4033 if (!obj || !obj._typename)
return false;
4034 if (obj === this.GetObject())
return true;
4036 if (this.geo_manager && (obj._typename ==
"TGeoManager")) {
4037 this.geo_manager = obj;
4038 this.AssignObject({ _typename:
"TGeoNode", fVolume: obj.fMasterVolume, fName: obj.fMasterVolume.fName, $geoh: obj.fMasterVolume.$geoh, _proxy:
true });
4042 if (!this.MatchObjectType(obj._typename))
return false;
4044 this.AssignObject(obj);
4048 TGeoPainter.prototype.ClearDrawings =
function() {
4049 if (this._clones && this._clones_owner)
4050 this._clones.Cleanup(this._draw_nodes, this._build_shapes);
4051 delete this._clones;
4052 delete this._clones_owner;
4053 delete this._draw_nodes;
4054 delete this._drawing_ready;
4055 delete this._build_shapes;
4057 delete this._extraObjects;
4058 delete this._clipCfg;
4060 JSROOT.Painter.DisposeThreejsObject(this._toplevel,
true);
4062 this._full_redrawing =
true;
4065 TGeoPainter.prototype.RedrawObject =
function(obj) {
4066 if (!this.UpdateObject(obj))
4069 this.ClearDrawings();
4071 var draw_obj = this.GetGeometry(), name_prefix =
"";
4072 if (this.geo_manager) name_prefix = draw_obj.fName;
4074 this.prepareObjectDraw(draw_obj, name_prefix);
4079 JSROOT.Painter.CreateGeoPainter =
function(divid, obj, opt) {
4080 JSROOT.GEO.GradPerSegm = JSROOT.gStyle.GeoGradPerSegm;
4081 JSROOT.GEO.CompressComp = JSROOT.gStyle.GeoCompressComp;
4083 var painter =
new TGeoPainter(obj);
4089 painter.SetDivId(divid, 5);
4091 painter._usesvg = JSROOT.Painter.UseSVGFor3D();
4093 painter._usesvgimg = !painter._usesvg && JSROOT.BatchMode;
4095 painter._webgl = !painter._usesvg && JSROOT.Painter.TestWebGL();
4097 painter.options = painter.decodeOptions(opt);
4100 JSROOT.extend(painter.ctrl, painter.options);
4102 painter.ctrl.ssao.enabled = painter.options.usessao;
4105 painter.ctrl.clip[0].enabled = painter.options.clipx;
4106 painter.ctrl.clip[1].enabled = painter.options.clipy;
4107 painter.ctrl.clip[2].enabled = painter.options.clipz;
4112 JSROOT.Painter.drawGeoObject =
function(divid, obj, opt) {
4113 if (!obj)
return null;
4115 var shape = null, extras = null, extras_path =
"", is_eve =
false;
4117 if ((
'fShapeBits' in obj) && (
'fShapeId' in obj)) {
4118 shape = obj; obj = null;
4119 }
else if ((obj._typename ===
'TGeoVolumeAssembly') || (obj._typename ===
'TGeoVolume')) {
4121 }
else if ((obj._typename ===
"TEveGeoShapeExtract") || (obj._typename ===
"ROOT::Experimental::TEveGeoShapeExtract")) {
4122 shape = obj.fShape; is_eve =
true;
4123 }
else if (obj._typename ===
'TGeoManager') {
4124 shape = obj.fMasterVolume.fShape;
4125 }
else if (obj._typename ===
'TGeoOverlap') {
4126 extras = obj.fMarker; extras_path =
"<prnt>/Marker";
4127 obj = JSROOT.GEO.buildOverlapVolume(obj);
4128 if (!opt) opt =
"wire";
4129 }
else if (
'fVolume' in obj) {
4130 if (obj.fVolume) shape = obj.fVolume.fShape;
4135 if ((typeof opt ==
"string") && opt.indexOf(
"comp")==0 && shape && (shape._typename ==
'TGeoCompositeShape') && shape.fNode) {
4137 opt = opt.substr(4);
4138 if (opt[0] ==
"x") { maxlvl = 999; opt = opt.substr(1) +
"_vislvl999"; }
4139 obj = JSROOT.GEO.buildCompositeVolume(shape, maxlvl);
4143 obj = JSROOT.extend(JSROOT.Create(
"TEveGeoShapeExtract"),
4144 { fTrans: null, fShape: shape, fRGBA: [0, 1, 0, 1], fElements: null, fRnrSelf:
true });
4146 if (!obj)
return null;
4148 var painter = JSROOT.Painter.CreateGeoPainter(divid, obj, opt);
4150 if (painter.ctrl.is_main && !obj.$geo_painter)
4151 obj.$geo_painter = painter;
4153 if (!painter.ctrl.is_main && painter.ctrl.project && obj.$geo_painter) {
4154 painter._main_painter = obj.$geo_painter;
4155 painter._main_painter._slave_painters.push(painter);
4158 if (is_eve && !painter.ctrl.vislevel || (painter.ctrl.vislevel < 9))
4159 painter.ctrl.vislevel = 9;
4162 painter._splitColors =
true;
4163 painter.addExtra(extras, extras_path);
4168 painter.checkScript(painter.ctrl.script_name, painter.prepareObjectDraw.bind(painter));
4174 JSROOT.Painter.drawGeometry = JSROOT.Painter.drawGeoObject;
4180 JSROOT.GEO.buildCompositeVolume =
function(comp, maxlvl, side) {
4182 if (maxlvl === undefined) maxlvl = 1;
4184 this.$comp_col_cnt = 0;
4188 var vol = JSROOT.Create(
"TGeoVolume");
4189 JSROOT.GEO.SetBit(vol, JSROOT.GEO.BITS.kVisThis,
true);
4190 JSROOT.GEO.SetBit(vol, JSROOT.GEO.BITS.kVisDaughters,
true);
4192 if ((side && (comp._typename!==
'TGeoCompositeShape')) || (maxlvl<=0)) {
4194 vol.fLineColor = (this.$comp_col_cnt++ % 8) + 2;
4199 if (side) side +=
"/";
4203 var node1 = JSROOT.Create(
"TGeoNodeMatrix");
4204 JSROOT.GEO.SetBit(node1, JSROOT.GEO.BITS.kVisThis,
true);
4205 JSROOT.GEO.SetBit(node1, JSROOT.GEO.BITS.kVisDaughters,
true);
4206 node1.fName =
"Left";
4207 node1.fMatrix = comp.fNode.fLeftMat;
4208 node1.fVolume = JSROOT.GEO.buildCompositeVolume(comp.fNode.fLeft, maxlvl-1, side +
"Left");
4210 var node2 = JSROOT.Create(
"TGeoNodeMatrix");
4211 JSROOT.GEO.SetBit(node2, JSROOT.GEO.BITS.kVisThis,
true);
4212 JSROOT.GEO.SetBit(node2, JSROOT.GEO.BITS.kVisDaughters,
true);
4213 node2.fName =
"Right";
4214 node2.fMatrix = comp.fNode.fRightMat;
4215 node2.fVolume = JSROOT.GEO.buildCompositeVolume(comp.fNode.fRight, maxlvl-1, side +
"Right");
4217 vol.fNodes = JSROOT.Create(
"TList");
4218 vol.fNodes.Add(node1);
4219 vol.fNodes.Add(node2);
4221 if (!side)
delete this.$comp_col_cnt;
4228 JSROOT.GEO.buildOverlapVolume =
function(overlap) {
4230 var vol = JSROOT.Create(
"TGeoVolume");
4232 JSROOT.GEO.SetBit(vol, JSROOT.GEO.BITS.kVisDaughters,
true);
4236 var node1 = JSROOT.Create(
"TGeoNodeMatrix");
4237 node1.fName = overlap.fVolume1.fName ||
"Overlap1";
4238 node1.fMatrix = overlap.fMatrix1;
4239 node1.fVolume = overlap.fVolume1;
4242 var node2 = JSROOT.Create(
"TGeoNodeMatrix");
4243 node2.fName = overlap.fVolume2.fName ||
"Overlap2";
4244 node2.fMatrix = overlap.fMatrix2;
4245 node2.fVolume = overlap.fVolume2;
4248 vol.fNodes = JSROOT.Create(
"TList");
4249 vol.fNodes.Add(node1);
4250 vol.fNodes.Add(node2);
4255 JSROOT.GEO.provideVisStyle =
function(obj) {
4256 if ((obj._typename ===
'TEveGeoShapeExtract') || (obj._typename ===
'ROOT::Experimental::TEveGeoShapeExtract'))
4257 return obj.fRnrSelf ?
" geovis_this" :
"";
4259 var vis = !JSROOT.GEO.TestBit(obj, JSROOT.GEO.BITS.kVisNone) &&
4260 JSROOT.GEO.TestBit(obj, JSROOT.GEO.BITS.kVisThis),
4261 chld = JSROOT.GEO.TestBit(obj, JSROOT.GEO.BITS.kVisDaughters);
4263 if (chld && (!obj.fNodes || (obj.fNodes.arr.length === 0))) chld =
false;
4265 if (vis && chld)
return " geovis_all";
4266 if (vis)
return " geovis_this";
4267 if (chld)
return " geovis_daughters";
4272 JSROOT.GEO.getBrowserItem =
function(item, itemname, callback) {
4274 if (item._geoobj) item._geoobj.$geoh =
true;
4276 JSROOT.CallBack(callback, item, item._geoobj);
4280 JSROOT.GEO.createItem =
function(node, obj, name) {
4282 _kind:
"ROOT." + obj._typename,
4283 _name: name ? name : JSROOT.GEO.ObjectName(obj),
4287 _get: JSROOT.GEO.getBrowserItem
4290 var volume, shape, subnodes, iseve =
false;
4292 if (obj._typename ==
"TGeoMaterial") sub._icon =
"img_geomaterial";
else
4293 if (obj._typename ==
"TGeoMedium") sub._icon =
"img_geomedium";
else
4294 if (obj._typename ==
"TGeoMixture") sub._icon =
"img_geomixture";
else
4295 if ((obj._typename.indexOf(
"TGeoNode")===0) && obj.fVolume) {
4296 sub._title =
"node:" + obj._typename;
4297 if (obj.fTitle.length > 0) sub._title +=
" " + obj.fTitle;
4298 volume = obj.fVolume;
4300 if (obj._typename.indexOf(
"TGeoVolume")===0) {
4303 if ((obj._typename ==
"TEveGeoShapeExtract") || (obj._typename ==
"ROOT::Experimental::TEveGeoShapeExtract") ) {
4306 subnodes = obj.fElements ? obj.fElements.arr : null;
4308 if ((obj.fShapeBits !== undefined) && (obj.fShapeId !== undefined)) {
4313 shape = volume.fShape;
4314 subnodes = volume.fNodes ? volume.fNodes.arr : null;
4317 if (volume || shape || subnodes) {
4318 if (volume) sub._volume = volume;
4322 sub._expand = JSROOT.GEO.expandObject;
4324 if (shape && (shape._typename ===
"TGeoCompositeShape") && shape.fNode) {
4327 sub._expand =
function(node, obj) {
4328 JSROOT.GEO.createItem(node, node._shape.fNode.fLeft,
'Left');
4329 JSROOT.GEO.createItem(node, node._shape.fNode.fRight,
'Right');
4334 if (!sub._title && (obj._typename !=
"TGeoVolume")) sub._title = obj._typename;
4337 if (sub._title ==
"")
4338 sub._title = shape._typename;
4340 sub._icon = JSROOT.GEO.getShapeIcon(shape);
4342 sub._icon = sub._more ?
"img_geocombi" :
"img_geobbox";
4346 sub._icon += JSROOT.GEO.provideVisStyle(volume);
4348 sub._icon += JSROOT.GEO.provideVisStyle(obj);
4350 sub._menu = JSROOT.GEO.provideMenu;
4351 sub._icon_click = JSROOT.GEO.browserIconClick;
4354 if (!node._childs) node._childs = [];
4357 if (typeof node._name ===
'string') {
4358 sub._name = node._name;
4359 if (sub._name.lastIndexOf(
"s")===sub._name.length-1)
4360 sub._name = sub._name.substr(0, sub._name.length-1);
4361 sub._name +=
"_" + node._childs.length;
4363 sub._name =
"item_" + node._childs.length;
4366 node._childs.push(sub);
4371 JSROOT.GEO.createList =
function(parent, lst, name, title) {
4373 if (!lst || !(
'arr' in lst) || (lst.arr.length==0))
return;
4377 _kind:
"ROOT.TList",
4384 item._get =
function(item, itemname, callback) {
4385 if (
'_geoobj' in item)
4386 return JSROOT.CallBack(callback, item, item._geoobj);
4388 JSROOT.CallBack(callback, item, null);
4391 item._expand =
function(node, lst) {
4394 if (
'fVolume' in lst)
4395 lst = lst.fVolume.fNodes;
4397 if (!(
'arr' in lst))
return false;
4401 JSROOT.GEO.CheckDuplicates(null, lst.arr);
4403 for (var n in lst.arr)
4404 JSROOT.GEO.createItem(node, lst.arr[n]);
4409 if (!parent._childs) parent._childs = [];
4410 parent._childs.push(item);
4414 JSROOT.GEO.provideMenu =
function(menu, item, hpainter) {
4416 if (!item._geoobj)
return false;
4418 var obj = item._geoobj, vol = item._volume,
4419 iseve = ((obj._typename ===
'TEveGeoShapeExtract') || (obj._typename ===
'ROOT::Experimental::TEveGeoShapeExtract'));
4421 if (!vol && !iseve)
return false;
4423 menu.add(
"separator");
4425 function ScanEveVisible(obj, arg, skip_this) {
4426 if (!arg) arg = { visible: 0, hidden: 0 };
4429 if (arg.assign!==undefined) obj.fRnrSelf = arg.assign;
else
4430 if (obj.fRnrSelf) arg.vis++;
else arg.hidden++;
4434 for (var n=0;n<obj.fElements.arr.length;++n)
4435 ScanEveVisible(obj.fElements.arr[n], arg,
false);
4440 function ToggleEveVisibility(arg) {
4441 if (arg ===
'self') {
4442 obj.fRnrSelf = !obj.fRnrSelf;
4443 item._icon = item._icon.split(
" ")[0] + JSROOT.GEO.provideVisStyle(obj);
4444 hpainter.UpdateTreeNode(item);
4446 ScanEveVisible(obj, { assign: (arg ===
"true") },
true);
4447 hpainter.ForEach(
function(m) {
4449 if (m._geoobj && m._icon) {
4450 m._icon = item._icon.split(
" ")[0] + JSROOT.GEO.provideVisStyle(m._geoobj);
4451 hpainter.UpdateTreeNode(m);
4456 JSROOT.GEO.findItemWithPainter(item,
'testGeomChanges');
4459 function ToggleMenuBit(arg) {
4460 JSROOT.GEO.ToggleBit(vol, arg);
4461 var newname = item._icon.split(
" ")[0] + JSROOT.GEO.provideVisStyle(vol);
4462 hpainter.ForEach(
function(m) {
4464 if (item._volume === m._volume) {
4466 hpainter.UpdateTreeNode(m);
4470 hpainter.UpdateTreeNode(item);
4471 JSROOT.GEO.findItemWithPainter(item,
'testGeomChanges');
4474 if ((item._geoobj._typename.indexOf(
"TGeoNode")===0) && JSROOT.GEO.findItemWithPainter(item))
4475 menu.add(
"Focus",
function() {
4477 var drawitem = JSROOT.GEO.findItemWithPainter(item);
4479 if (!drawitem)
return;
4481 var fullname = hpainter.itemFullName(item, drawitem);
4483 if (drawitem._painter && typeof drawitem._painter.focusOnItem ==
'function')
4484 drawitem._painter.focusOnItem(fullname);
4488 menu.addchk(obj.fRnrSelf,
"Visible",
"self", ToggleEveVisibility);
4489 var res = ScanEveVisible(obj, undefined,
true);
4491 if (res.hidden + res.visible > 0)
4492 menu.addchk((res.hidden==0),
"Daughters", (res.hidden!=0) ?
"true" :
"false", ToggleEveVisibility);
4495 menu.addchk(JSROOT.GEO.TestBit(vol, JSROOT.GEO.BITS.kVisNone),
"Invisible",
4496 JSROOT.GEO.BITS.kVisNone, ToggleMenuBit);
4497 menu.addchk(JSROOT.GEO.TestBit(vol, JSROOT.GEO.BITS.kVisThis),
"Visible",
4498 JSROOT.GEO.BITS.kVisThis, ToggleMenuBit);
4499 menu.addchk(JSROOT.GEO.TestBit(vol, JSROOT.GEO.BITS.kVisDaughters),
"Daughters",
4500 JSROOT.GEO.BITS.kVisDaughters, ToggleMenuBit);
4506 JSROOT.GEO.findItemWithPainter =
function(hitem, funcname) {
4508 if (hitem._painter && hitem._painter._camera) {
4509 if (funcname && typeof hitem._painter[funcname] ==
'function')
4510 hitem._painter[funcname]();
4513 hitem = hitem._parent;
4518 JSROOT.GEO.updateBrowserIcons =
function(obj, hpainter) {
4519 if (!obj || !hpainter)
return;
4521 hpainter.ForEach(
function(m) {
4523 if ((obj === m._volume) || (obj === m._geoobj)) {
4524 m._icon = m._icon.split(
" ")[0] + JSROOT.GEO.provideVisStyle(obj);
4525 hpainter.UpdateTreeNode(m);
4530 JSROOT.GEO.browserIconClick =
function(hitem, hpainter) {
4531 if (hitem._volume) {
4532 if (hitem._more && hitem._volume.fNodes && (hitem._volume.fNodes.arr.length>0))
4533 JSROOT.GEO.ToggleBit(hitem._volume, JSROOT.GEO.BITS.kVisDaughters);
4535 JSROOT.GEO.ToggleBit(hitem._volume, JSROOT.GEO.BITS.kVisThis);
4537 JSROOT.GEO.updateBrowserIcons(hitem._volume, hpainter);
4539 JSROOT.GEO.findItemWithPainter(hitem,
'testGeomChanges');
4543 if (hitem._geoobj && (( hitem._geoobj._typename ==
"TEveGeoShapeExtract") || ( hitem._geoobj._typename ==
"ROOT::Experimental::TEveGeoShapeExtract"))) {
4544 hitem._geoobj.fRnrSelf = !hitem._geoobj.fRnrSelf;
4546 JSROOT.GEO.updateBrowserIcons(hitem._geoobj, hpainter);
4547 JSROOT.GEO.findItemWithPainter(hitem,
'testGeomChanges');
4553 var drawitem = JSROOT.GEO.findItemWithPainter(hitem);
4554 if (!drawitem)
return false;
4556 var newstate = drawitem._painter.ExtraObjectVisible(hpainter, hitem,
true);
4559 return (newstate!==undefined) ?
true :
false;
4562 JSROOT.GEO.getShapeIcon =
function(shape) {
4563 switch (shape._typename) {
4564 case "TGeoArb8" :
return "img_geoarb8";
break;
4565 case "TGeoCone" :
return "img_geocone";
break;
4566 case "TGeoConeSeg" :
return "img_geoconeseg";
break;
4567 case "TGeoCompositeShape" :
return "img_geocomposite";
break;
4568 case "TGeoTube" :
return "img_geotube";
break;
4569 case "TGeoTubeSeg" :
return "img_geotubeseg";
break;
4570 case "TGeoPara" :
return "img_geopara";
break;
4571 case "TGeoParaboloid" :
return "img_geoparab";
break;
4572 case "TGeoPcon" :
return "img_geopcon";
break;
4573 case "TGeoPgon" :
return "img_geopgon";
break;
4574 case "TGeoShapeAssembly" :
return "img_geoassembly";
break;
4575 case "TGeoSphere" :
return "img_geosphere";
break;
4576 case "TGeoTorus" :
return "img_geotorus";
break;
4577 case "TGeoTrd1" :
return "img_geotrd1";
break;
4578 case "TGeoTrd2" :
return "img_geotrd2";
break;
4579 case "TGeoXtru" :
return "img_geoxtru";
break;
4580 case "TGeoTrap" :
return "img_geotrap";
break;
4581 case "TGeoGtra" :
return "img_geogtra";
break;
4582 case "TGeoEltu" :
return "img_geoeltu";
break;
4583 case "TGeoHype" :
return "img_geohype";
break;
4584 case "TGeoCtub" :
return "img_geoctub";
break;
4586 return "img_geotube";
4589 JSROOT.GEO.getBrowserIcon =
function(hitem, hpainter) {
4591 if (hitem._kind ==
'ROOT.TEveTrack') icon =
'img_evetrack';
else
4592 if (hitem._kind ==
'ROOT.TEvePointSet') icon =
'img_evepoints';
else
4593 if (hitem._kind ==
'ROOT.TPolyMarker3D') icon =
'img_evepoints';
4594 if (icon.length>0) {
4595 var drawitem = JSROOT.GEO.findItemWithPainter(hitem);
4597 if (drawitem._painter.ExtraObjectVisible(hpainter, hitem))
4598 icon +=
" geovis_this";
4603 JSROOT.GEO.expandObject =
function(parent, obj) {
4604 if (!parent || !obj)
return false;
4606 var isnode = (obj._typename.indexOf(
'TGeoNode') === 0),
4607 isvolume = (obj._typename.indexOf(
'TGeoVolume') === 0),
4608 ismanager = (obj._typename ===
'TGeoManager'),
4609 iseve = ((obj._typename ===
'TEveGeoShapeExtract') || (obj._typename ===
'ROOT::Experimental::TEveGeoShapeExtract')),
4610 isoverlap = (obj._typename ===
'TGeoOverlap');
4612 if (!isnode && !isvolume && !ismanager && !iseve && !isoverlap)
return false;
4614 if (parent._childs)
return true;
4617 JSROOT.GEO.createList(parent, obj.fMaterials,
"Materials",
"list of materials");
4618 JSROOT.GEO.createList(parent, obj.fMedia,
"Media",
"list of media");
4619 JSROOT.GEO.createList(parent, obj.fTracks,
"Tracks",
"list of tracks");
4620 JSROOT.GEO.createList(parent, obj.fOverlaps,
"Overlaps",
"list of detected overlaps");
4621 JSROOT.GEO.createItem(parent, obj.fMasterVolume);
4626 JSROOT.GEO.createItem(parent, obj.fVolume1);
4627 JSROOT.GEO.createItem(parent, obj.fVolume2);
4628 JSROOT.GEO.createItem(parent, obj.fMarker,
'Marker');
4632 var volume, subnodes, shape;
4635 subnodes = obj.fElements ? obj.fElements.arr : null;
4638 volume = (isnode ? obj.fVolume : obj);
4639 subnodes = volume && volume.fNodes ? volume.fNodes.arr : null;
4640 shape = volume ? volume.fShape : null;
4643 if (!subnodes && shape && (shape._typename ===
"TGeoCompositeShape") && shape.fNode) {
4644 if (!parent._childs) {
4645 JSROOT.GEO.createItem(parent, shape.fNode.fLeft,
'Left');
4646 JSROOT.GEO.createItem(parent, shape.fNode.fRight,
'Right');
4652 if (!subnodes)
return false;
4654 JSROOT.GEO.CheckDuplicates(obj, subnodes);
4656 for (var i=0;i<subnodes.length;++i)
4657 JSROOT.GEO.createItem(parent, subnodes[i]);
4662 JSROOT.addDrawFunc({ name:
"TGeoVolumeAssembly", icon:
'img_geoassembly', func: JSROOT.Painter.drawGeoObject, expand: JSROOT.GEO.expandObject, opt:
";more;all;count" });
4663 JSROOT.addDrawFunc({ name:
"TEvePointSet", icon_get: JSROOT.GEO.getBrowserIcon, icon_click: JSROOT.GEO.browserIconClick });
4664 JSROOT.addDrawFunc({ name:
"TEveTrack", icon_get: JSROOT.GEO.getBrowserIcon, icon_click: JSROOT.GEO.browserIconClick });
4666 JSROOT.TGeoPainter = TGeoPainter;
4668 JSROOT.Painter.GeoDrawingControl = GeoDrawingControl;
4670 return JSROOT.Painter;