From e7c83428fc7ac815c6c5e9c315c6771d8aa7de90 Mon Sep 17 00:00:00 2001 From: Dmitry Romanov Date: Fri, 18 Oct 2024 20:46:45 -0400 Subject: [PATCH] Correct work with edm4eic files from remote API --- firebird-ng/package-lock.json | 4 +- firebird-ng/package.json | 4 +- .../nav-config/nav-config.component.html | 19 ++- .../nav-config/nav-config.component.scss | 8 ++ .../nav-config/nav-config.component.ts | 19 ++- .../input-config/input-config.component.html | 24 +--- .../main-display/main-display.component.ts | 29 ++++- .../box-tracker-hit-simple.painter.ts | 119 ++++++++++++++++++ .../src/app/painters/component-painter.ts | 6 +- .../src/app/painters/data-model-painter.ts | 10 +- .../src/app/services/data-model.service.ts | 10 +- .../src/app/utils/data-fetching.utils.ts | 6 +- .../src/assets/icons/github-mark-white.svg | 2 + firebird-ng/src/assets/icons/github-mark.svg | 2 + firebird-ng/tsconfig.json | 1 + 15 files changed, 224 insertions(+), 39 deletions(-) create mode 100644 firebird-ng/src/app/painters/box-tracker-hit-simple.painter.ts create mode 100644 firebird-ng/src/assets/icons/github-mark-white.svg create mode 100644 firebird-ng/src/assets/icons/github-mark.svg diff --git a/firebird-ng/package-lock.json b/firebird-ng/package-lock.json index 26797a0..8c756bb 100644 --- a/firebird-ng/package-lock.json +++ b/firebird-ng/package-lock.json @@ -1,12 +1,12 @@ { "name": "firebird", - "version": "0.0.5", + "version": "0.1.20", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "firebird", - "version": "0.0.5", + "version": "0.1.20", "dependencies": { "@angular/animations": "^17.3.12", "@angular/cdk": "~17.3.10", diff --git a/firebird-ng/package.json b/firebird-ng/package.json index be2afaa..8d5f76c 100644 --- a/firebird-ng/package.json +++ b/firebird-ng/package.json @@ -1,6 +1,6 @@ { "name": "firebird", - "version": "0.0.5", + "version": "0.1.23", "scripts": { "ng": "ng", "serve": "ng serve", @@ -11,7 +11,7 @@ "test": "ng test", "test:headless": "ng test --browsers=ChromeHeadless --watch=false --code-coverage --progress=false" }, - "private": true, + "private": false, "dependencies": { "@angular/animations": "^17.3.12", "@angular/cdk": "~17.3.10", diff --git a/firebird-ng/src/app/components/nav-config/nav-config.component.html b/firebird-ng/src/app/components/nav-config/nav-config.component.html index c18d53b..7971d71 100644 --- a/firebird-ng/src/app/components/nav-config/nav-config.component.html +++ b/firebird-ng/src/app/components/nav-config/nav-config.component.html @@ -2,10 +2,25 @@ {{ isNavConfigOpen ? 'close' : 'menu' }} - + diff --git a/firebird-ng/src/app/components/nav-config/nav-config.component.scss b/firebird-ng/src/app/components/nav-config/nav-config.component.scss index 7bbcf35..a42d94d 100644 --- a/firebird-ng/src/app/components/nav-config/nav-config.component.scss +++ b/firebird-ng/src/app/components/nav-config/nav-config.component.scss @@ -16,3 +16,11 @@ top: 0; padding-top: -3px; } + +.logo-button { + background: none; + border: none; + padding: 0; + margin: 0; + cursor: pointer; +} diff --git a/firebird-ng/src/app/components/nav-config/nav-config.component.ts b/firebird-ng/src/app/components/nav-config/nav-config.component.ts index ffcf020..0a553a9 100644 --- a/firebird-ng/src/app/components/nav-config/nav-config.component.ts +++ b/firebird-ng/src/app/components/nav-config/nav-config.component.ts @@ -4,6 +4,10 @@ import {MatIcon} from "@angular/material/icon"; import {NgIf} from "@angular/common"; import {MatIconButton} from "@angular/material/button"; import {MatTooltip} from "@angular/material/tooltip"; +import {MatMenu, MatMenuItem, MatMenuTrigger} from "@angular/material/menu"; +import { MatIconRegistry } from '@angular/material/icon'; +import { DomSanitizer } from '@angular/platform-browser'; +import packageInfo from '../../../../package.json'; @Component({ selector: 'app-nav-config', @@ -14,7 +18,10 @@ import {MatTooltip} from "@angular/material/tooltip"; MatIcon, NgIf, MatIconButton, - MatTooltip + MatTooltip, + MatMenu, + MatMenuItem, + MatMenuTrigger ], templateUrl: './nav-config.component.html', styleUrl: './nav-config.component.scss' @@ -22,6 +29,16 @@ import {MatTooltip} from "@angular/material/tooltip"; export class NavConfigComponent { isNavConfigOpen: boolean = false; isSmallScreen: boolean = window.innerWidth < 992; + packageVersion: string; + + constructor(private matIconRegistry: MatIconRegistry, + private domSanitizer: DomSanitizer) { + this.matIconRegistry.addSvgIcon( + 'github', + this.domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/github-mark-white.svg') + ); + this.packageVersion = packageInfo.version; + } @HostListener('window:resize', ['$event']) onResize(event: any) { diff --git a/firebird-ng/src/app/pages/input-config/input-config.component.html b/firebird-ng/src/app/pages/input-config/input-config.component.html index db310ae..a7af0b0 100644 --- a/firebird-ng/src/app/pages/input-config/input-config.component.html +++ b/firebird-ng/src/app/pages/input-config/input-config.component.html @@ -3,9 +3,10 @@

Configure geometry pipeline

- geometry-pipeline + + geometry-pipeline -
+
@@ -85,11 +86,11 @@
Merge geometries if possible
Server API Configuration
- +
-
API URL:
+
Base API URL:
@@ -98,21 +99,6 @@
API URL:
- - - - - - - - - - - - - - -
diff --git a/firebird-ng/src/app/pages/main-display/main-display.component.ts b/firebird-ng/src/app/pages/main-display/main-display.component.ts index e8c4485..a444f2a 100644 --- a/firebird-ng/src/app/pages/main-display/main-display.component.ts +++ b/firebird-ng/src/app/pages/main-display/main-display.component.ts @@ -49,6 +49,7 @@ import {DataModelPainter} from "../../painters/data-model-painter"; import {AppComponent} from "../../app.component"; import {ToolPanelComponent} from "../../components/tool-panel/tool-panel.component"; import {NavConfigComponent} from "../../components/nav-config/nav-config.component"; +import {UrlService} from "../../services/url.service"; // import { LineMaterial } from 'three/addons/lines/LineMaterial.js'; @@ -57,7 +58,7 @@ import {NavConfigComponent} from "../../components/nav-config/nav-config.compone @Component({ selector: 'app-test-experiment', templateUrl: './main-display.component.html', - imports: [PhoenixUIModule, IoOptionsComponent, MatSlider, MatIcon, MatButton, MatSliderThumb, DecimalPipe, MatTooltip, MatFormField, MatSelect, MatOption, NgForOf, AngularSplitModule, SceneTreeComponent, NgClass, MatIconButton, DisplayShellComponent, AppComponent, RouterOutlet, RouterLink, ToolPanelComponent, NavConfigComponent, NgIf], + imports: [PhoenixUIModule, IoOptionsComponent, MatSlider, MatIcon, MatButton, MatSliderThumb, DecimalPipe, MatTooltip, MatFormField, MatSelect, MatOption, NgForOf, AngularSplitModule, SceneTreeComponent, NgClass, MatIconButton, DisplayShellComponent, ToolPanelComponent, NavConfigComponent, NgIf], standalone: true, styleUrls: ['./main-display.component.scss'] }) @@ -121,7 +122,9 @@ export class MainDisplayComponent implements OnInit, AfterViewInit { private route: ActivatedRoute, private settings: UserConfigService, private dataService: DataModelService, - private elRef: ElementRef, private renderer2: Renderer2, + private elRef: ElementRef, + private renderer2: Renderer2, + private urlService: UrlService, private _snackBar: MatSnackBar) { this.threeFacade = new PhoenixThreeFacade(this.eventDisplay); } @@ -443,6 +446,7 @@ export class MainDisplayComponent implements OnInit, AfterViewInit { ngOnInit() { let eventSource = this.settings.trajectoryEventSource.value; + eventSource = this.urlService.resolveDownloadUrl(eventSource); let eventConfig = {eventFile: "https://firebird-eic.org/py8_all_dis-cc_beam-5x41_minq2-100_nevt-5.evt.json.zip", eventType: "zip"}; if( eventSource != "no-events" && !eventSource.endsWith("edm4hep.json")) { let eventType = eventSource.endsWith("zip") ? "zip" : "json"; @@ -641,10 +645,24 @@ export class MainDisplayComponent implements OnInit, AfterViewInit { this.dataService.loadEdm4EicData().then(data => { this.updateSceneTreeComponent(); - console.log("loaded data model"); + console.log("loadEdm4EicData data:"); console.log(data); - }) + if(data == null) { + console.warn("DataService.loadEdm4EicData() Received data is null or undefined"); + return; + } + if(data.entries?.length ?? 0 > 0) { + this.painter.setThreeSceneParent(openThreeManager.sceneManager.getEventData()); + this.painter.setEntry(data.entries[0]); + this.painter.paint(this.currentTime); + this.updateSceneTreeComponent(); + } else { + console.warn("DataService.loadEdm4EicData() Received data had no entries"); + console.log(data); + } + }) + // this.dataService.loadDexData().then(data => { this.updateSceneTreeComponent(); if(data == null) { @@ -653,8 +671,10 @@ export class MainDisplayComponent implements OnInit, AfterViewInit { } if(data.entries?.length ?? 0 > 0) { + this.painter.setThreeSceneParent(openThreeManager.sceneManager.getEventData()); this.painter.setEntry(data.entries[0]); this.painter.paint(this.currentTime); + this.updateSceneTreeComponent(); } else { console.warn("DataService.loadDexData() Received data had no entries"); console.log(data); @@ -878,6 +898,7 @@ export class MainDisplayComponent implements OnInit, AfterViewInit { exitTimedDisplay() { this.stopAnimation(); this.rewindTime(); + this.painter.paint(null); this.animateEventAfterLoad = false; if(this.trackInfos) { for (let trackInfo of this.trackInfos) { diff --git a/firebird-ng/src/app/painters/box-tracker-hit-simple.painter.ts b/firebird-ng/src/app/painters/box-tracker-hit-simple.painter.ts new file mode 100644 index 0000000..b8423df --- /dev/null +++ b/firebird-ng/src/app/painters/box-tracker-hit-simple.painter.ts @@ -0,0 +1,119 @@ +import { + Object3D, + Mesh, + BoxGeometry, + MeshBasicMaterial, + Color, +} from 'three'; +import { ComponentPainter } from './component-painter'; +import { BoxTrackerHitComponent } from '../model/box-tracker-hit.component'; +import { EntryComponent } from '../model/entry-component'; + +/** + * Alternative Painter class for rendering BoxTrackerHitComponent using individual Meshes. + */ +export class BoxTrackerHitSimplePainter extends ComponentPainter { + /** Array of Mesh objects representing hits */ + private hitMeshes: Mesh[] = []; + + private boxComponent: BoxTrackerHitComponent; + + /** + * Constructs a new BoxTrackerHitAlternativePainter. + * + * @param parentNode - The Object3D node where the hit meshes will be added. + * @param component - The BoxTrackerHitComponent containing the hit data. + */ + constructor(parentNode: Object3D, component: EntryComponent) { + super(parentNode, component); + + // Runtime type check + if (component.type !== BoxTrackerHitComponent.type) { + throw new Error('Invalid component type for BoxTrackerHitAlternativePainter'); + } + + this.boxComponent = component as BoxTrackerHitComponent; + + // Create a bright random color for this component collection + const hue = Math.random(); + const randomColor = new Color().setHSL(hue, 1, 0.5); // Bright color + + // Create a material with the random color + const material = new MeshBasicMaterial({ color: randomColor }); + + // Create a mesh for each hit using the same material + this.createHitMeshes(material); + } + + /** + * Creates Mesh instances for each hit and adds them to the parent node. + * + * @param material - The material to use for the hit meshes. + */ + private createHitMeshes(material: MeshBasicMaterial): void { + for (const hit of this.boxComponent.hits) { + // Create geometry for the box + const geometry = new BoxGeometry(10,10,10 + // hit.dimensions[0], + // hit.dimensions[1], + // hit.dimensions[2] + ); + + // Create the mesh + const mesh = new Mesh(geometry, material); + + // Set position + mesh.position.set(hit.position[0], hit.position[1], hit.position[2]); + + // Store the hit time + mesh.userData['appearanceTime'] = hit.time[0]; + + // Initially make the mesh invisible + mesh.visible = false; + + // Add the mesh to the parent node and to the array + this.parentNode.add(mesh); + this.hitMeshes.push(mesh); + } + } + + /** + * Paint method to update the visibility of the hits based on time. + * + * @param time - The current time in nanoseconds or null for static rendering. + */ + public paint(time: number | null): void { + for (const mesh of this.hitMeshes) { + if (time !== null) { + // Show the mesh if its appearance time is less than or equal to the current time + mesh.visible = mesh.userData['appearanceTime'] <= time; + } else { + // In static mode, make all meshes visible + mesh.visible = true; + } + } + } + + /** + * Dispose of resources used by the painter. + */ + override dispose(): void { + for (const mesh of this.hitMeshes) { + // Dispose of geometry and material + mesh.geometry.dispose(); + + // Dispose of the material only if it's not shared with other meshes + if (mesh.material instanceof MeshBasicMaterial) { + mesh.material.dispose(); + } + + // Remove the mesh from the parent node + this.parentNode.remove(mesh); + } + + // Clear the array + this.hitMeshes = []; + + super.dispose(); + } +} diff --git a/firebird-ng/src/app/painters/component-painter.ts b/firebird-ng/src/app/painters/component-painter.ts index c1f6574..e30d0c5 100644 --- a/firebird-ng/src/app/painters/component-painter.ts +++ b/firebird-ng/src/app/painters/component-painter.ts @@ -10,7 +10,7 @@ export type ComponentPainterConstructor = new (node: Object3D, component: EntryC export abstract class ComponentPainter { /** Constructor is public since we can instantiate directly */ - constructor(protected node: Object3D, protected component: EntryComponent) {} + constructor(protected parentNode: Object3D, protected component: EntryComponent) {} /** Gets the `type` identifier for the component this class works with */ public get componentType() { @@ -26,8 +26,8 @@ export abstract class ComponentPainter { /** Dispose method to clean up resources */ public dispose(): void { // Remove node from the scene - if (this.node) { - disposeNode(this.node); + if (this.parentNode) { + disposeNode(this.parentNode); } } } diff --git a/firebird-ng/src/app/painters/data-model-painter.ts b/firebird-ng/src/app/painters/data-model-painter.ts index f498525..5620f68 100644 --- a/firebird-ng/src/app/painters/data-model-painter.ts +++ b/firebird-ng/src/app/painters/data-model-painter.ts @@ -1,8 +1,15 @@ +/** + * This class is responsible in rendering Event or Frame data. + * It first takes event components and manipulates three.js Scene + * Then responsible for correct rendering at a given time + */ + import { Entry } from "../model/entry"; import { Object3D, Group } from "three"; import {ComponentPainter, ComponentPainterConstructor} from "./component-painter"; import {BoxTrackerHitComponent} from "../model/box-tracker-hit.component"; import {BoxTrackerHitPainter} from "./box-tracker-hit.painter"; +import {BoxTrackerHitSimplePainter} from "./box-tracker-hit-simple.painter"; export class DataModelPainter { @@ -14,7 +21,8 @@ export class DataModelPainter { public constructor() { // Register builtin painters - this.registerPainter(BoxTrackerHitComponent.type, BoxTrackerHitPainter); + //this.registerPainter(BoxTrackerHitComponent.type, BoxTrackerHitPainter); + this.registerPainter(BoxTrackerHitComponent.type, BoxTrackerHitSimplePainter); } diff --git a/firebird-ng/src/app/services/data-model.service.ts b/firebird-ng/src/app/services/data-model.service.ts index a2fded2..767b7fe 100644 --- a/firebird-ng/src/app/services/data-model.service.ts +++ b/firebird-ng/src/app/services/data-model.service.ts @@ -7,7 +7,7 @@ import {HttpClient} from "@angular/common/http"; import {firstValueFrom} from "rxjs"; import {UrlService} from "./url.service"; import {DataExchange} from "../model/data-exchange"; -import {loadJSONFileEvents, loadZipFileEvents} from "../utils/data-fetching.utils"; +import {fetchTextFile, loadJSONFileEvents, loadZipFileEvents} from "../utils/data-fetching.utils"; @Injectable({ providedIn: 'root' @@ -50,9 +50,11 @@ export class DataModelService { // userInput = this.urlService.resolveLocalhostUrl(userInput); // } - const jsonData = await firstValueFrom( - this.http.get(url, { responseType: 'text' }) - ); + const jsonData = await fetchTextFile(url); + // //this.http.get(url, { responseType: 'text' }) + // ); + + const dexData = JSON.parse(jsonData); let data = DataExchange.fromDexObj(dexData); diff --git a/firebird-ng/src/app/utils/data-fetching.utils.ts b/firebird-ng/src/app/utils/data-fetching.utils.ts index b172892..e65b0cc 100644 --- a/firebird-ng/src/app/utils/data-fetching.utils.ts +++ b/firebird-ng/src/app/utils/data-fetching.utils.ts @@ -28,7 +28,11 @@ export async function fetchTextFile(fileURL: string): Promise { try{ const loadingTimeMessage = `${fetchTextFile.name}: fetching ${fileURL}`; console.time(loadingTimeMessage); - const fileText = await (await fetch(fileURL)).text(); + const response = await fetch(fileURL); + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + const fileText = await response.text(); console.timeEnd(loadingTimeMessage); return fileText; } diff --git a/firebird-ng/src/assets/icons/github-mark-white.svg b/firebird-ng/src/assets/icons/github-mark-white.svg new file mode 100644 index 0000000..e294208 --- /dev/null +++ b/firebird-ng/src/assets/icons/github-mark-white.svg @@ -0,0 +1,2 @@ + + diff --git a/firebird-ng/src/assets/icons/github-mark.svg b/firebird-ng/src/assets/icons/github-mark.svg new file mode 100644 index 0000000..e6b695c --- /dev/null +++ b/firebird-ng/src/assets/icons/github-mark.svg @@ -0,0 +1,2 @@ + + diff --git a/firebird-ng/tsconfig.json b/firebird-ng/tsconfig.json index c018c49..46af714 100644 --- a/firebird-ng/tsconfig.json +++ b/firebird-ng/tsconfig.json @@ -18,6 +18,7 @@ "target": "ES2022", "module": "ES2022", "useDefineForClassFields": false, + "resolveJsonModule": true, "lib": [ "ES2022", "dom"