Warning, /firebird/firebird-ng/src/app/data-pipelines/three-geometry.processor.ts is written in an unsupported language. File is not indexed.
0001 import * as THREE from "three";
0002 import {wildCardCheck} from "../utils/wildcard";
0003 import {CalorimetryGeometryPrettifier} from "./calorimetry.prettifier";
0004 import {editThreeNodeContent, EditThreeNodeRule} from "../utils/three-geometry-editor";
0005 import {Subdetector} from "../model/subdetector";
0006
0007 /**
0008 * A typed object that associates a name (or multiple names) with an array of edit rules.
0009 * E.g. { name: "DIRC_14", rules: [ { patterns: [...], ... } ] }
0010 */
0011 export interface DetectorThreeRuleSet {
0012 names?: string[];
0013 name?: string;
0014 rules: EditThreeNodeRule[];
0015 }
0016
0017 /**
0018 * Converts a raw JSON/JSONC array into typed DetectorThreeRuleSet objects.
0019 * If an EditThreeNodeRule has "materialJson", we parse it using THREE.MaterialLoader.
0020 */
0021 export function ruleSetsFromObj(obj: any): DetectorThreeRuleSet[] {
0022 // Not an array => return empty
0023 if (!Array.isArray(obj)) {
0024 console.warn('ruleSetsFromObj: top-level object is not an array. Returning empty.');
0025 return [];
0026 }
0027
0028 // Create a single MaterialLoader we can reuse for all materialJson objects
0029 const materialLoader = new THREE.MaterialLoader();
0030
0031 return obj.map((item: any) => {
0032 // Ensure we have a rules array
0033 if (!item.rules || !Array.isArray(item.rules)) {
0034 console.warn('ruleSetsFromObj: missing or invalid "rules" array in item:', item);
0035 return { rules: [] };
0036 }
0037
0038 // Convert each rule
0039 const convertedRules: EditThreeNodeRule[] = item.rules.map((r: any) => {
0040 const rule: EditThreeNodeRule = { ...r };
0041
0042 // 1) Convert a color from string hex "0xabcdef" => number
0043 if (typeof rule.color === 'string') {
0044 rule.color = parseInt(rule.color, 16);
0045 }
0046
0047 // 2) If there's "materialJson", parse it using THREE.MaterialLoader
0048 if (r.materialJson && typeof r.materialJson === 'object') {
0049 try {
0050 // Convert raw JSON to real material
0051 const loadedMaterial = materialLoader.parse(r.materialJson);
0052 rule.material = loadedMaterial;
0053 } catch (err) {
0054 console.error('Failed to parse materialJson:', err, r.materialJson);
0055 }
0056 }
0057
0058 return rule;
0059 });
0060
0061 return {
0062 names: item.names,
0063 name: item.name,
0064 rules: convertedRules,
0065 };
0066 });
0067 }
0068
0069
0070 /**
0071 * Matches which set of rules should be applied to which detectors
0072 *
0073 * - Detectors are matched based on their `sourceGeometryName` against the names specified in the rulesets.
0074 * - Rule lists are matched to detectors in the order they appear in the rulesets
0075 * - Once a rule is applied to a detector, that detector is excluded from further rule matching, ensuring each detector is processed only once.
0076 * - If both `names` and `name` are provided in a ruleset, the function treats it as a user error in JSON rule editing but processes both without raising an exception.
0077 * - If a ruleset contains a wildcard name (`"*"`), it will apply its rules to any detectors not already matched by previous rulesets. So it should be placed in
0078 *
0079 * @param {Subdetector[]} detectors - The list of detectors to which the rules will be applied.
0080 * @param {DetectorThreeRuleSet[]} ruleSets - The set of rules to be applied, processed sequentially.
0081 * @return {Map<Subdetector, EditThreeNodeRule[]>} - A map associating each detector with an array of the rules applied to it.
0082 */
0083 export function matchRulesToDetectors(ruleSets: DetectorThreeRuleSet[], detectors: Subdetector[]): Map<Subdetector, EditThreeNodeRule[]> {
0084 const unassignedDetectors = new Set(detectors);
0085 const detectorRulesMap = new Map<Subdetector, EditThreeNodeRule[]>();
0086
0087 for(let ruleSet of ruleSets) {
0088 const targets = new Set<Subdetector>();
0089 let names = new Set<string>(ruleSet.names || []);
0090
0091 // Handle possible user error where both 'name' and 'names' are provided.
0092 if (ruleSet.name) {
0093 names.add(ruleSet.name);
0094 }
0095
0096 for(let name of names) {
0097 for(let det of unassignedDetectors) {
0098 if (wildCardCheck(det.sourceGeometryName, name)) {
0099 targets.add(det);
0100 detectorRulesMap.set(det, ruleSet.rules || []);
0101 unassignedDetectors.delete(det); // Move deletion here to optimize
0102 }
0103 }
0104 }
0105 }
0106
0107 return detectorRulesMap;
0108 }
0109
0110 export class ThreeGeometryProcessor {
0111
0112
0113 constructor() {
0114
0115 }
0116
0117 public processRuleSets(ruleSets: DetectorThreeRuleSet[], detectors: Subdetector[]) {
0118 let detRulesMap = matchRulesToDetectors(ruleSets, detectors);
0119 for (let [detector, ruleSet] of detRulesMap) {
0120 for(let rule of ruleSet) {
0121 editThreeNodeContent(detector.geometry, rule);
0122 }
0123 }
0124 }
0125 }