Skip to content

Commit bb4e1ce

Browse files
authored
Merge pull request #766 from DhanashreePetare/feature/jivexml-extra-hits-268
feat: improve JiveXML extra hits handling with UI controls and RK extrapolation (#268)
2 parents 232872d + 61e4823 commit bb4e1ce

File tree

8 files changed

+313
-20
lines changed

8 files changed

+313
-20
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
1313
- New helper: `RKHelper.extrapolateFromLastPosition(track, radius)`
1414
- UI: dat.GUI and Phoenix menu controls to toggle extension and set radius
1515
- Scene update: `SceneManager.extendCollectionTracks(collectionName, radius, enable)`
16+
- Improve JiveXML extra hits handling with UI controls and RK extrapolation (#268)
17+
- New configuration interface: `JiveXMLTrackExtensionConfig` with options for extra hits and RK extrapolation
18+
- Improved extra hits filtering algorithm with angular consistency checks (theta/phi within 0.5 radians)
19+
- Configurable `minDelta` parameter for hit distance filtering (default 250mm)
20+
- Integration with RK extrapolation from #177 for truncated track extension
21+
- UI controls in both dat.GUI and Phoenix menu for all configuration options
22+
- Methods: `EventDisplay.setJiveXMLTrackExtensionConfig()`, `EventDisplay.getJiveXMLTrackExtensionConfig()`
1623

1724

1825

packages/phoenix-event-display/src/event-display.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,16 @@ export class EventDisplay {
7373
this.graphicsLibrary.init(configuration);
7474
// Initialize the UI with configuration
7575
this.ui.init(configuration);
76+
// Apply JiveXML track extension configuration and surface UI controls when available
77+
const loaderWithTrackExtension = this.configuration.eventDataLoader as any;
78+
if (loaderWithTrackExtension?.setTrackExtensionConfig) {
79+
if (this.configuration.jiveXMLTrackExtension) {
80+
loaderWithTrackExtension.setTrackExtensionConfig(
81+
this.configuration.jiveXMLTrackExtension,
82+
);
83+
}
84+
this.ui.addJiveXMLTrackExtensionUI(this);
85+
}
7686
// Set up for the state manager
7787
this.getStateManager().setEventDisplay(this);
7888

@@ -810,4 +820,43 @@ export class EventDisplay {
810820
}
811821
}
812822
}
823+
824+
/**
825+
* Set JiveXML track extension configuration.
826+
* @param config Partial configuration for JiveXML track extension.
827+
*/
828+
public setJiveXMLTrackExtensionConfig(config: any) {
829+
if (!this.configuration.eventDataLoader) {
830+
return;
831+
}
832+
// Check if the loader has the setTrackExtensionConfig method (JiveXMLLoader)
833+
if (
834+
typeof (this.configuration.eventDataLoader as any)
835+
.setTrackExtensionConfig === 'function'
836+
) {
837+
(this.configuration.eventDataLoader as any).setTrackExtensionConfig(
838+
config,
839+
);
840+
}
841+
}
842+
843+
/**
844+
* Get JiveXML track extension configuration.
845+
* @returns Current JiveXML track extension configuration or undefined if not available.
846+
*/
847+
public getJiveXMLTrackExtensionConfig(): any {
848+
if (!this.configuration.eventDataLoader) {
849+
return undefined;
850+
}
851+
// Check if the loader has the getTrackExtensionConfig method (JiveXMLLoader)
852+
if (
853+
typeof (this.configuration.eventDataLoader as any)
854+
.getTrackExtensionConfig === 'function'
855+
) {
856+
return (
857+
this.configuration.eventDataLoader as any
858+
).getTrackExtensionConfig();
859+
}
860+
return undefined;
861+
}
813862
}

packages/phoenix-event-display/src/lib/types/configuration.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { PresetView } from '../models/preset-view.model';
22
import type { EventDataLoader } from '../../loaders/event-data-loader';
33
import type { PhoenixMenuNode } from '../../managers/ui-manager/phoenix-menu/phoenix-menu-node';
44
import type { AnimationPreset } from '../../managers/three-manager/animations-manager';
5+
import type { JiveXMLTrackExtensionConfig } from '../../loaders/jivexml-loader';
56

67
/**
78
* Configuration of the event display.
@@ -27,4 +28,6 @@ export interface Configuration {
2728
allowUrlOptions?: boolean;
2829
/** Whether to force a theme ('dark' or 'light' are current options) */
2930
forceColourTheme?: string;
31+
/** Optional configuration for JiveXML track extension controls */
32+
jiveXMLTrackExtension?: Partial<JiveXMLTrackExtensionConfig>;
3033
}

packages/phoenix-event-display/src/loaders/jivexml-loader.ts

Lines changed: 127 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
import { PhoenixLoader } from './phoenix-loader';
22
import { CoordinateHelper } from '../helpers/coordinate-helper';
3+
import { RKHelper } from '../helpers/rk-helper';
4+
5+
/**
6+
* Configuration options for JiveXML track extension.
7+
*/
8+
export interface JiveXMLTrackExtensionConfig {
9+
/** Enable using extra hits for truncated tracks */
10+
useExtraHits: boolean;
11+
/** Minimum delta distance for filtering extra hits (in mm) */
12+
extraHitsMinDelta: number;
13+
/** Enable RK extrapolation for truncated tracks */
14+
useRKExtrapolation: boolean;
15+
/** Radius for RK extrapolation (in mm) */
16+
rkExtrapolationRadius: number;
17+
/** Track collections to apply extension to (empty means all) */
18+
trackCollectionsToExtend: string[];
19+
}
320

421
/**
522
* PhoenixLoader for processing and loading an event from the JiveXML data format.
@@ -9,15 +26,48 @@ export class JiveXMLLoader extends PhoenixLoader {
926
private data: any;
1027
/** List of tracks to draw with thicker tubes */
1128
thickTrackCollections: string[];
29+
/** Configuration for track extension options */
30+
private trackExtensionConfig: JiveXMLTrackExtensionConfig;
1231

1332
/**
1433
* Constructor for the JiveXMLLoader.
1534
* @param thickTrackCollections A list of names of track collections which should be drawn thicker
35+
* @param trackExtensionConfig Configuration for track extension behavior
1636
*/
17-
constructor(thickTrackCollections: string[] = []) {
37+
constructor(
38+
thickTrackCollections: string[] = [],
39+
trackExtensionConfig?: Partial<JiveXMLTrackExtensionConfig>,
40+
) {
1841
super();
1942
this.data = {};
2043
this.thickTrackCollections = thickTrackCollections;
44+
// Set default configuration
45+
this.trackExtensionConfig = {
46+
useExtraHits: false, // Disabled by default as per issue
47+
extraHitsMinDelta: 250, // Current default value
48+
useRKExtrapolation: false,
49+
rkExtrapolationRadius: 1500,
50+
trackCollectionsToExtend: [], // Empty means all collections
51+
...trackExtensionConfig, // Override with provided config
52+
};
53+
}
54+
55+
/**
56+
* Update track extension configuration.
57+
* @param config Partial configuration to update
58+
*/
59+
public setTrackExtensionConfig(
60+
config: Partial<JiveXMLTrackExtensionConfig>,
61+
): void {
62+
this.trackExtensionConfig = { ...this.trackExtensionConfig, ...config };
63+
}
64+
65+
/**
66+
* Get current track extension configuration.
67+
* @returns Current configuration
68+
*/
69+
public getTrackExtensionConfig(): JiveXMLTrackExtensionConfig {
70+
return { ...this.trackExtensionConfig };
2171
}
2272

2373
/**
@@ -367,14 +417,22 @@ export class JiveXMLLoader extends PhoenixLoader {
367417
polylineCounter += numPolyline[i];
368418
track.pos = pos;
369419
}
420+
421+
// Check if we should extend this track collection
422+
const shouldExtendTrack =
423+
(this.trackExtensionConfig.useExtraHits ||
424+
this.trackExtensionConfig.useRKExtrapolation) &&
425+
(this.trackExtensionConfig.trackCollectionsToExtend.length === 0 ||
426+
this.trackExtensionConfig.trackCollectionsToExtend.includes(
427+
trackCollectionName,
428+
));
429+
430+
// IMPROVED: Extra hits extension with better filtering
370431
if (
371-
// eslint-disable-next-line
372-
false &&
373-
numHits.length > 0 &&
374-
trackCollectionName?.includes('Muon')
432+
shouldExtendTrack &&
433+
this.trackExtensionConfig.useExtraHits &&
434+
numHits.length > 0
375435
) {
376-
// Disable for the moment.
377-
378436
// Now loop over hits, and if possible, see if we can extend the track
379437
const measurementPositions = [];
380438
if (numHits.length > 0) {
@@ -400,35 +458,84 @@ export class JiveXMLLoader extends PhoenixLoader {
400458
track.hits = listOfHits;
401459
}
402460

403-
// This seems to give pretty poor results, so try to filter.
461+
// IMPROVED: Better filtering logic
404462
// Sort radially (sorry cosmics!)
405463
const sortedMeasurements = measurementPositions.sort(
406464
(a, b) => a[3] - b[3],
407465
);
408-
const minDelta = 250; // tweaked by trial and error
466+
const minDelta = this.trackExtensionConfig.extraHitsMinDelta;
409467
let newHitCount = 0;
410468
let rejectedHitCount = 0;
411469
let lastDistance = maxR + minDelta;
470+
412471
if (sortedMeasurements.length) {
413472
for (const meas of sortedMeasurements) {
473+
// Better filtering: check distance AND angular consistency
414474
if (meas[3] > lastDistance + minDelta) {
415-
track.pos.push([meas[0], meas[1], meas[2]]);
416-
lastDistance = meas[3] + minDelta;
417-
newHitCount++;
475+
// Check angular consistency with track direction
476+
const measTheta = Math.acos(meas[2] / meas[3]);
477+
const measPhi = Math.atan2(meas[1], meas[0]);
478+
const thetaDiff = Math.abs(measTheta - theta);
479+
const phiDiff = Math.abs(measPhi - track.phi);
480+
481+
// Only add if angles are reasonably close (within 0.5 radians ~= 28 degrees)
482+
if (thetaDiff < 0.5 && phiDiff < 0.5) {
483+
track.pos.push([meas[0], meas[1], meas[2]]);
484+
lastDistance = meas[3];
485+
newHitCount++;
486+
} else {
487+
rejectedHitCount++;
488+
}
418489
} else {
419490
rejectedHitCount++;
420491
}
421492
}
422493
}
423-
console.log(
424-
'Added ' +
425-
newHitCount +
426-
' hits to ' +
427-
trackCollectionName +
428-
' (and rejected ' +
429-
rejectedHitCount +
430-
')',
494+
495+
if (newHitCount > 0) {
496+
console.log(
497+
`Extended ${trackCollectionName} with ${newHitCount} extra hits (rejected ${rejectedHitCount})`,
498+
);
499+
}
500+
}
501+
502+
// NEW: RK Extrapolation for truncated tracks
503+
if (
504+
shouldExtendTrack &&
505+
this.trackExtensionConfig.useRKExtrapolation &&
506+
track.pos.length > 0 &&
507+
track.dparams.length === 5
508+
) {
509+
const lastPos = track.pos[track.pos.length - 1];
510+
const currentRadius = Math.sqrt(
511+
lastPos[0] * lastPos[0] +
512+
lastPos[1] * lastPos[1] +
513+
lastPos[2] * lastPos[2],
431514
);
515+
const targetRadius = this.trackExtensionConfig.rkExtrapolationRadius;
516+
517+
// Only extrapolate if we're not already beyond target radius
518+
if (currentRadius < targetRadius) {
519+
try {
520+
const extrapolatedPoints = RKHelper.extrapolateFromLastPosition(
521+
track,
522+
targetRadius,
523+
);
524+
525+
if (extrapolatedPoints.length > 0) {
526+
// Add extrapolated points to track
527+
track.pos.push(...extrapolatedPoints);
528+
console.log(
529+
`Extended ${trackCollectionName} with ${extrapolatedPoints.length} RK extrapolated points to radius ${targetRadius}mm`,
530+
);
531+
}
532+
} catch (error) {
533+
console.warn(
534+
`Failed to RK extrapolate track in ${trackCollectionName}:`,
535+
error,
536+
);
537+
}
538+
}
432539
}
433540

434541
if (storeTrack) jsontracks.push(track);

packages/phoenix-event-display/src/managers/ui-manager/dat-gui-ui.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,4 +477,53 @@ export class DatGUIMenuUI implements PhoenixUI<GUI> {
477477
public getEventDataTypeFolder(typeName: string): GUI {
478478
return this.eventFolder.__folders[typeName];
479479
}
480+
481+
/**
482+
* Add JiveXML track extension controls to the menu.
483+
* @param eventDisplay The event display instance.
484+
*/
485+
public addJiveXMLTrackExtension(eventDisplay: any): void {
486+
const jiveFolder = this.gui.addFolder('JiveXML Track Extension');
487+
488+
const jiveParams = {
489+
useExtraHits: false,
490+
extraHitsMinDelta: 250,
491+
useRKExtrapolation: false,
492+
rkRadius: 1500,
493+
};
494+
495+
jiveFolder
496+
.add(jiveParams, 'useExtraHits')
497+
.name('Use Extra Hits')
498+
.onChange((value: boolean) => {
499+
eventDisplay.setJiveXMLTrackExtensionConfig({ useExtraHits: value });
500+
});
501+
502+
jiveFolder
503+
.add(jiveParams, 'extraHitsMinDelta', 50, 500)
504+
.name('Extra Hits Min Delta (mm)')
505+
.onChange((value: number) => {
506+
eventDisplay.setJiveXMLTrackExtensionConfig({
507+
extraHitsMinDelta: value,
508+
});
509+
});
510+
511+
jiveFolder
512+
.add(jiveParams, 'useRKExtrapolation')
513+
.name('Use RK Extrapolation')
514+
.onChange((value: boolean) => {
515+
eventDisplay.setJiveXMLTrackExtensionConfig({
516+
useRKExtrapolation: value,
517+
});
518+
});
519+
520+
jiveFolder
521+
.add(jiveParams, 'rkRadius', 100, 5000)
522+
.name('RK Radius (mm)')
523+
.onChange((value: number) => {
524+
eventDisplay.setJiveXMLTrackExtensionConfig({
525+
rkExtrapolationRadius: value,
526+
});
527+
});
528+
}
480529
}

packages/phoenix-event-display/src/managers/ui-manager/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,4 +609,16 @@ export class UIManager {
609609
public getUIMenus(): PhoenixUI<unknown>[] {
610610
return this.uiMenus;
611611
}
612+
613+
/**
614+
* Add JiveXML track extension controls to the UI if available.
615+
* @param eventDisplay Reference to the EventDisplay instance for configuration callbacks.
616+
*/
617+
public addJiveXMLTrackExtensionUI(eventDisplay: any) {
618+
this.uiMenus.forEach((menu) => {
619+
if (menu.addJiveXMLTrackExtension) {
620+
menu.addJiveXMLTrackExtension(eventDisplay);
621+
}
622+
});
623+
}
612624
}

0 commit comments

Comments
 (0)