diff --git a/firebird-ng/src/app/geometry.service.ts b/firebird-ng/src/app/geometry.service.ts index 0528cb8..81c07da 100644 --- a/firebird-ng/src/app/geometry.service.ts +++ b/firebird-ng/src/app/geometry.service.ts @@ -14,8 +14,8 @@ import {build} from 'jsrootdi/geom'; import {BehaviorSubject} from "rxjs"; import {RootGeometryProcessor} from "./root-geometry.processor"; - - +// constants.ts +export const DEFAULT_GEOMETRY = 'epic-central-optimized'; @Injectable({ providedIn: 'root' @@ -25,25 +25,36 @@ export class GeometryService { rootGeometryProcessor = new RootGeometryProcessor(); constructor() { - this.load(); + this.loadGeoConfig(); } - private stateSubject = new BehaviorSubject(this.load()); + private stateSubject = new BehaviorSubject(this.loadGeoConfig()); state$ = this.stateSubject.asObservable(); - save(state: any) { + saveGeoConfig(state: any) { localStorage.setItem('geometrySettings', JSON.stringify(state)); this.stateSubject.next(state); } - load(): any { + loadGeoConfig(): any { const settings = localStorage.getItem('geometrySettings'); - return settings ? JSON.parse(settings) : { - selectedGeometry: 'epic-central-optimized', + + let config = settings ? JSON.parse(settings) : { + selectedGeometry: DEFAULT_GEOMETRY, geoOptEnabled: true, - selectedGeoCutoff: 'Central detector', + selectedEvent: 'Central detector', geoPostEnabled: true }; + + if(!config?.selectedGeometry) { + config.selectedGeometry = DEFAULT_GEOMETRY; + } + + if(!config?.selectedEvent) { + config.selectedEvent = "Default events"; + } + + return config; } getState() { @@ -51,12 +62,18 @@ export class GeometryService { } - async loadEicGeometry() { + async loadGeometry() { //let url: string = 'assets/epic_pid_only.root'; //let url: string = 'https://eic.github.io/epic/artifacts/tgeo/epic_dirc_only.root'; - let url: string = 'https://eic.github.io/epic/artifacts/tgeo/epic_full.root'; + // let url: string = 'https://eic.github.io/epic/artifacts/tgeo/epic_full.root'; // >oO let objectName = 'default'; + let settings = this.getState(); + + const url = settings.selectedGeometry !== DEFAULT_GEOMETRY? + settings.selectedGeometry: + 'https://eic.github.io/epic/artifacts/tgeo/epic_full.root'; + console.time('[GeoSrv]: Total load geometry time'); console.log(`[GeoSrv]: Loading file ${url}`) diff --git a/firebird-ng/src/app/input-config/input-config.component.ts b/firebird-ng/src/app/input-config/input-config.component.ts index 346d8cd..c7cafa3 100644 --- a/firebird-ng/src/app/input-config/input-config.component.ts +++ b/firebird-ng/src/app/input-config/input-config.component.ts @@ -20,12 +20,12 @@ export class InputConfigComponent implements OnInit { this.geoForm = this.fb.group({ selectedGeometry: ['eic geometry'], geoOptEnabled: [false], - selectedGeoCutoff: ['Central detector'], + selectedEvent: ['Central detector'], geoPostEnabled: [false] }); this.geoForm.valueChanges.subscribe(value => { - //this.geometryService.save(value); + this.geometryService.saveGeoConfig(value); console.log(value); }); } diff --git a/firebird-ng/src/app/main-display/main-display.component.ts b/firebird-ng/src/app/main-display/main-display.component.ts index 8f72e54..bf0ac08 100644 --- a/firebird-ng/src/app/main-display/main-display.component.ts +++ b/firebird-ng/src/app/main-display/main-display.component.ts @@ -24,6 +24,7 @@ import {color} from "three/examples/jsm/nodes/shadernode/ShaderNode"; import {getGeoNodesByLevel} from "../utils/cern-root.utils"; import {produceRenderOrder} from "jsrootdi/geom"; import {wildCardCheck} from "../utils/wildcard"; +import {ThreeGeometryProcessor} from "../three-geometry.processor"; interface Colorable { color: Color; @@ -39,11 +40,6 @@ function getColorOrDefault(material:any, defaultColor: Color): Color { } else { return defaultColor; } - -} - -function ensureColor(material: any) { - } @@ -59,6 +55,8 @@ export class MainDisplayComponent implements OnInit { /** The root Phoenix menu node. */ phoenixMenuRoot = new PhoenixMenuNode("Phoenix Menu"); + threeGeometryProcessor = new ThreeGeometryProcessor(); + /** is geometry loaded */ loaded: boolean = false; @@ -75,7 +73,7 @@ export class MainDisplayComponent implements OnInit { async loadGeometry(initiallyVisible=true, scale=10) { - let {rootGeoManager, rootObject3d} = await this.geomService.loadEicGeometry(); + let {rootGeoManager, rootObject3d} = await this.geomService.loadGeometry(); let threeManager = this.eventDisplay.getThreeManager(); let uiManager = this.eventDisplay.getUIManager(); let openThreeManager: any = threeManager; @@ -84,132 +82,105 @@ export class MainDisplayComponent implements OnInit { const sceneGeometry = threeManager.getSceneManager().getGeometries(); + // Set geometry scale if (scale) { rootObject3d.scale.setScalar(scale); } - sceneGeometry.add(rootObject3d); + + // Add root geometry to scene console.log("CERN ROOT converted to Object3d: ", rootObject3d); - //rootGeometry.visible = initiallyVisible; + sceneGeometry.add(rootObject3d); - //sceneGeometry.add(rootGeometry); - let topLevelRootItems = getGeoNodesByLevel(rootGeoManager); - let topLevelObj3dNodes = rootObject3d.children[0].children; - if(topLevelRootItems.length != topLevelObj3dNodes.length) { - console.warn(`topLevelRootItems.length != topLevelObj3dNodes.length`); - console.log("Can't create Menu Items"); - } - else { - for(let i=0; i < topLevelRootItems.length; i++) { - let rootGeoNode = topLevelRootItems[i].geoNode; - let obj3dNode = topLevelObj3dNodes[i]; - obj3dNode.name = obj3dNode.userData["name"] = rootGeoNode.name; + // Add top nodes to menu + let topLevelObj3dNodes = rootObject3d.children[0].children; + for(let obj3dNode of topLevelObj3dNodes){ + obj3dNode.name = obj3dNode.userData["name"] = obj3dNode.name; // Add geometry - uiManager.addGeometry(obj3dNode, obj3dNode.name); - } + uiManager.addGeometry(obj3dNode, obj3dNode.name); } - let renderer = openThreeManager.rendererManager; - const glassMaterial = new MeshPhysicalMaterial({ - color: 0xffff00, // Yellow color - metalness: 0, - roughness: 0, - transmission: 0.7, // High transparency - opacity: 1, - transparent: true, - reflectivity: 0.5 - }); + let renderer = openThreeManager.rendererManager; // Now we want to change the materials sceneGeometry.traverse( (child: any) => { - if(child.type!=="Mesh") { - return; - } + if(child.type!=="Mesh" || !child?.material?.isMaterial) { + return; + } - if(!child?.material?.isMaterial) { - return; - } + // Assuming `getObjectSize` is correctly typed and available + child.userData["size"] = importManager.getObjectSize(child); - // Assuming `getObjectSize` is correctly typed and available - child.userData["size"] = importManager.getObjectSize(child); + // Handle the material of the child - // Handle the material of the child + const color = getColorOrDefault(child.material, this.defaultColor); + const side = doubleSided ? DoubleSide : child.material.side; - const color = getColorOrDefault(child.material, this.defaultColor); - const side = doubleSided ? DoubleSide : child.material.side; + child.material.dispose(); // Dispose the old material if it's a heavy object - child.material.dispose(); // Dispose the old material if it's a heavy object + let opacity = rootObject3d.userData.opacity ?? 1; + let transparent = opacity < 1; - let opacity = rootObject3d.userData.opacity ?? 1; - let transparent = opacity < 1; + child.material = new MeshPhongMaterial({ + color: color, + shininess: 0, + side: side, + transparent: transparent, + opacity: opacity, + clippingPlanes: openThreeManager.clipPlanes, + clipIntersection: true, + clipShadows: false + }); - child.material = new MeshPhongMaterial({ - color: color, - shininess: 0, - side: side, - transparent: transparent, - opacity: opacity, - clippingPlanes: openThreeManager.clipPlanes, - clipIntersection: true, - clipShadows: false - }); + // Material + let name:string = child.name; - // Material - let name:string = child.name; + if(! child.material?.clippingPlanes !== undefined) { + child.material.clippingPlanes = openThreeManager.clipPlanes; + } + if(! child.material?.clipIntersection !== undefined) { + child.material.clipIntersection = true; + } - if(name.startsWith("bar_") || name.startsWith("prism_")) { - child.material = glassMaterial; + if(! child.material?.clipShadows !== undefined) { + child.material.clipShadows = false; + } + }); + + // HERE WE DO POSTPROCESSING STEP + this.threeGeometryProcessor.process(rootObject3d); + + // Now we want to change the materials + sceneGeometry.traverse( (child: any) => { + + if(child.type!=="Mesh" || !child?.material?.isMaterial) { + return; } - if(! child.material?.clippingPlanes !== undefined) { + if(child.material?.clippingPlanes !== undefined) { child.material.clippingPlanes = openThreeManager.clipPlanes; } - if(! child.material?.clipIntersection !== undefined) { + if(child.material?.clipIntersection !== undefined) { child.material.clipIntersection = true; } - if(! child.material?.clipShadows !== undefined) { + if(child.material?.clipShadows !== undefined) { child.material.clipShadows = false; } - - // if (!(child instanceof Mesh)) { - // return; - // } - // child.userData["size"] = importManager.getObjectSize(child); - // if (!(child.material instanceof Material)) { - // return; - // } - // const color = child.material['color'] - // ? child.material['color'] - // : 0x2fd691; - // const side = doubleSided ? DoubleSide : child.material['side']; - // child.material.dispose(); - // let isTransparent = false; - // if (rootGeometry.userData.opacity) { - // isTransparent = true; - // } - // child.material = new MeshPhongMaterial({ - // color, - // shininess: 0, - // side: side, - // transparent: isTransparent, - // opacity: (_a = rootGeometry.userData.opacity) !== null && _a !== void 0 ? _a : 1, - // }); - // child.material.clippingPlanes = openThreeManager.clipPlanes; - // child.material.clipIntersection = true; - // child.material.clipShadows = false; }); + // Set render priority let scene = threeManager.getSceneManager().getScene(); let camera = openThreeManager.controlsManager.getMainCamera(); produceRenderOrder(scene, camera.position, 'dflt'); + } ngOnInit() { @@ -240,10 +211,23 @@ export class MainDisplayComponent implements OnInit { // Initialize the event display this.eventDisplay.init(configuration); + + + // Set default clipping this.eventDisplay.getUIManager().setClipping(true); this.eventDisplay.getUIManager().rotateOpeningAngleClipping(120); this.eventDisplay.getUIManager().rotateStartAngleClipping(45); + // Display event loader + this.eventDisplay.getLoadingManager().addLoadListenerWithCheck(() => { + console.log('Loading default configuration.'); + this.loaded = true; + }); + + this.eventDisplay + .getLoadingManager() + .addProgressListener((progress) => (this.loadingProgress = progress)); + //const events_url = "https://eic.github.io/epic/artifacts/sim_dis_10x100_minQ2=1000_epic_craterlake.edm4hep.root/sim_dis_10x100_minQ2=1000_epic_craterlake.edm4hep.root" //const events_url = "https://eic.github.io/epic/artifacts/sim_dis_10x100_minQ2=1000_epic_craterlake.edm4hep.root" @@ -259,12 +243,10 @@ export class MainDisplayComponent implements OnInit { let jsonGeometry; this.loadGeometry().then(jsonGeom => { - + jsonGeometry = jsonGeom; }); - this.eventDisplay - .getLoadingManager() - .addProgressListener((progress) => (this.loadingProgress = progress)); + document.addEventListener('keydown', (e) => { if ((e as KeyboardEvent).key === 'Enter') { @@ -279,12 +261,7 @@ export class MainDisplayComponent implements OnInit { console.log((e as KeyboardEvent).key); }); - // Load the default configuration - this.eventDisplay.getLoadingManager().addLoadListenerWithCheck(() => { - console.log('Loading default configuration.'); - this.loaded = true; - }); } diff --git a/firebird-ng/src/app/three-geometry.processor.ts b/firebird-ng/src/app/three-geometry.processor.ts new file mode 100644 index 0000000..55a05f0 --- /dev/null +++ b/firebird-ng/src/app/three-geometry.processor.ts @@ -0,0 +1,82 @@ +import { Component, OnInit } from '@angular/core'; +import { EventDisplayService } from 'phoenix-ui-components'; +import { Configuration, PhoenixLoader, PresetView, ClippingSetting, PhoenixMenuNode } from 'phoenix-event-display'; +import { + Color, + DoubleSide, + Mesh, + LineSegments, + LineBasicMaterial, + MeshPhongMaterial, + Material, + ObjectLoader, + FrontSide, + Vector3, + Matrix4, + REVISION, + MeshPhysicalMaterial, +} from "three"; +import { PhoenixUIModule } from 'phoenix-ui-components'; +import { GeometryService} from './geometry.service'; +import { Edm4hepRootEventLoader } from './edm4hep-root-event-loader'; +import { ActivatedRoute } from '@angular/router'; +import {color} from "three/examples/jsm/nodes/shadernode/ShaderNode"; +import {getGeoNodesByLevel} from "./utils/cern-root.utils"; +import {produceRenderOrder} from "jsrootdi/geom"; +import {wildCardCheck} from "./utils/wildcard"; + +interface Colorable { + color: Color; +} + +function isColorable(material: any): material is Colorable { + return 'color' in material; +} + +function getColorOrDefault(material:any, defaultColor: Color): Color { + if (isColorable(material)) { + return material.color; + } else { + return defaultColor; + } + +} + +export class ThreeGeometryProcessor { + + glassMaterial = new MeshPhysicalMaterial({ + color: 0xffff00, // Yellow color + metalness: 0, + roughness: 0, + transmission: 0.7, // High transparency + opacity: 1, + transparent: true, + reflectivity: 0.5 + }); + + constructor() { + + } + + public process(geometry: any) { + + // Now we want to change the materials + geometry.traverse( (child: any) => { + + if(child.type!=="Mesh") { + return; + } + + if(!child?.material?.isMaterial) { + return; + } + + // Material + let name:string = child.name; + + if(name.startsWith("bar_") || name.startsWith("prism_")) { + child.material = this.glassMaterial; + } + }); + } +}