Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/firebird-ng/src/app/components/object-raycast/object-raycast.component.ts is written in an unsupported language. File is not indexed.

0001 import {Component, ElementRef, OnDestroy, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
0002 import {MatDialog, MatDialogClose, MatDialogRef} from "@angular/material/dialog";
0003 import {MatMenuItem} from "@angular/material/menu";
0004 import {MatCheckbox, MatCheckboxChange} from "@angular/material/checkbox";
0005 import {MatIcon} from "@angular/material/icon";
0006 import {MatIconButton} from "@angular/material/button";
0007 import {Subscription} from "rxjs";
0008 import {ThreeService} from "../../services/three.service";
0009 import * as THREE from 'three';
0010 import {MatTooltip} from "@angular/material/tooltip";
0011 import {NgIf} from "@angular/common";
0012 
0013 @Component({
0014   selector: 'app-object-raycast',
0015   imports: [
0016     MatIcon,
0017     MatDialogClose,
0018     MatMenuItem,
0019     MatCheckbox,
0020     MatTooltip,
0021     MatIconButton,
0022     NgIf
0023   ],
0024   templateUrl: './object-raycast.component.html',
0025   styleUrl: './object-raycast.component.scss'
0026 })
0027 export class ObjectRaycastComponent implements OnDestroy {
0028 
0029   @ViewChild('openRayBtn', { read: ElementRef }) openRayBtn!: ElementRef;
0030   @ViewChild('raycastDialogTmpl') raycastDialogTmpl!: TemplateRef<any>;
0031   dialogRef: MatDialogRef<any> | null = null;
0032 
0033   /** UI state */
0034 
0035   coordsEnabled    = false;
0036   distanceEnabled  = false;
0037 
0038   coordsText   = '';
0039   distanceText = '';
0040 
0041   private coordsSub?: Subscription;
0042   private distSub?: Subscription;
0043   private distLine?: THREE.Line;
0044 
0045 
0046   /** internals */
0047   private firstPoint: THREE.Vector3 | null = null;
0048   private clickSub?: Subscription;
0049   private hoverSub?: Subscription;
0050 
0051   constructor(
0052     private dialog: MatDialog,
0053     private three: ThreeService,
0054     private viewContainerRef: ViewContainerRef
0055   ) {}
0056 
0057   /* ------------ UI ------------- */
0058   openRaycastDialog() {
0059     if (this.dialogRef) {
0060       this.dialogRef.close();
0061       return;
0062     }
0063 
0064     const rect = this.openRayBtn.nativeElement.getBoundingClientRect();
0065     const dialogWidth = 320;
0066 
0067     const left = Math.max(rect.right - dialogWidth, 8);
0068     const top = rect.bottom + 12;
0069 
0070     this.dialogRef = this.dialog.open(this.raycastDialogTmpl, {
0071       position: {
0072         top: `${top}px`,
0073         left: `${left}px`
0074       },
0075       hasBackdrop: false,
0076       panelClass: 'custom-position-dialog',
0077       autoFocus: false,
0078       viewContainerRef: this.viewContainerRef
0079     });
0080 
0081     this.dialogRef.afterClosed().subscribe(() => {
0082       this.dialogRef = null;
0083     });
0084   }
0085 
0086   /* ---------- checkbox handlers ---------- */
0087 
0088 
0089   toggleShowCoords(e: MatCheckboxChange): void {
0090     this.coordsEnabled = e.checked;
0091     this.updateSubscriptions();
0092     this.updateRaycastActivation();
0093   }
0094 
0095   toggleShowDistance(e: MatCheckboxChange): void {
0096     this.distanceEnabled = e.checked;
0097     this.three.measureMode = e.checked;
0098     if (!e.checked) this.firstPoint = null;
0099     this.updateSubscriptions();
0100     this.updateRaycastActivation();
0101   }
0102 
0103   /* ---------- central switch ---------- */
0104   /** Ensures ThreeService raycast state matches UI needs */
0105   private updateRaycastActivation(): void {
0106     const needRaycast =  this.coordsEnabled || this.distanceEnabled;
0107     const isOn        = this.three.isRaycastEnabledState();
0108     if (needRaycast && !isOn) this.three.toggleRaycast();
0109     if (!needRaycast && isOn) this.three.toggleRaycast();
0110   }
0111 
0112   /* ---------- RxJS subscriptions ---------- */
0113   private updateSubscriptions(): void {
0114 
0115     /* XYZ overlay */
0116     if (this.coordsEnabled && !this.coordsSub) {
0117       this.coordsSub = this.three.pointHovered.subscribe(pt => {
0118         this.coordsText = `X:${pt.x.toFixed(2)}  Y:${pt.y.toFixed(2)}  Z:${pt.z.toFixed(2)}`;
0119       });
0120     } else if (!this.coordsEnabled && this.coordsSub) {
0121       this.coordsSub.unsubscribe();
0122       this.coordsSub = undefined;
0123       this.coordsText = '';
0124     }
0125 
0126     /* distance overlay */
0127     if (this.distanceEnabled && !this.distSub) {
0128       this.distSub = this.three.distanceReady.subscribe(({ p1, p2, dist }) => {
0129         this.distanceText = `${dist.toFixed(2)} units`;
0130 
0131         // draw / update line helper
0132         if (!this.distLine) {
0133           const g = new THREE.BufferGeometry().setFromPoints([p1, p2]);
0134           const m = new THREE.LineBasicMaterial({ color: 0xffff00 });
0135           this.distLine = new THREE.Line(g, m);
0136           this.three.sceneHelpers.add(this.distLine);
0137         } else {
0138           (this.distLine.geometry as THREE.BufferGeometry).setFromPoints([p1, p2]);
0139         }
0140       });
0141     } else if (!this.distanceEnabled && this.distSub) {
0142       this.distSub.unsubscribe();
0143       this.distSub = undefined;
0144       this.distanceText = '';
0145 
0146       // remove helper line
0147       if (this.distLine) {
0148         this.three.sceneHelpers.remove(this.distLine);
0149         this.distLine.geometry.dispose();
0150         (this.distLine.material as THREE.Material).dispose();
0151         this.distLine = undefined!;
0152       }
0153     }
0154 
0155   }
0156 
0157   /* ---------- cleanup ---------- */
0158   ngOnDestroy(): void {
0159     this.hoverSub?.unsubscribe();
0160     this.clickSub?.unsubscribe();
0161   }
0162 }