Warning, /firebird/firebird-ng/src/app/components/geometry-clipping/geometry-clipping.component.ts is written in an unsupported language. File is not indexed.
0001 import {
0002 Component,
0003 OnInit,
0004 OnDestroy,
0005 ViewChild,
0006 TemplateRef,
0007 ElementRef,
0008 ViewContainerRef,
0009 ChangeDetectorRef,
0010 effect,
0011 Signal
0012 } from '@angular/core';
0013 import {MatCheckbox, MatCheckboxChange} from '@angular/material/checkbox';
0014 import {MatSlideToggleChange} from '@angular/material/slide-toggle';
0015 import { toSignal } from '@angular/core/rxjs-interop';
0016
0017 import { ThreeService } from '../../services/three.service';
0018 import { ConfigService } from '../../services/config.service';
0019 import {MatMenuItem} from "@angular/material/menu";
0020 import {MatSlider, MatSliderThumb} from "@angular/material/slider";
0021
0022 import {MatButton, MatIconButton} from "@angular/material/button";
0023
0024 import {MatDialog, MatDialogClose, MatDialogRef} from "@angular/material/dialog";
0025 import {MatIcon} from "@angular/material/icon";
0026 import {MatTooltip} from "@angular/material/tooltip";
0027 import {FormsModule} from "@angular/forms";
0028 import {MatSlideToggle} from "@angular/material/slide-toggle";
0029
0030
0031
0032 @Component({
0033 selector: 'app-geometry-clipping',
0034 templateUrl: './geometry-clipping.component.html',
0035 styleUrls: ['./geometry-clipping.component.scss'],
0036 imports: [
0037 MatSlider,
0038 MatMenuItem,
0039 MatSliderThumb,
0040 MatCheckbox,
0041 MatButton,
0042 MatIcon,
0043 MatDialogClose,
0044 MatIconButton,
0045 MatTooltip,
0046 FormsModule,
0047 MatSlideToggle,
0048 ]
0049 })
0050 export class GeometryClippingComponent implements OnInit {
0051 /** Local copies that reflect the config property values. */
0052
0053 clippingEnabled!: Signal<boolean>;
0054 startAngle!: Signal<number>;
0055 openingAngle!: Signal<number>;
0056 zClippingEnabled!: Signal<boolean>;
0057 zClippingPosition!: Signal<number>;
0058 zClippingForward!: Signal<boolean>;
0059
0060 @ViewChild('openBtn', { read: ElementRef }) openBtn!: ElementRef;
0061 @ViewChild('dialogTemplate') dialogTemplate!: TemplateRef<any>;
0062 dialogRef: MatDialogRef<any> | null = null;
0063
0064 constructor(
0065 private threeService: ThreeService,
0066 private config: ConfigService,
0067 private dialog: MatDialog,
0068 private viewContainerRef: ViewContainerRef,
0069 private cdr: ChangeDetectorRef
0070 ) {
0071
0072 // Get configs
0073 const configClippingEnabled = this.config.getConfigOrCreate<boolean>('clippingEnabled', true);
0074 const configStartAngle = this.config.getConfigOrCreate<number>('clippingStartAngle', 0);
0075 const configOpeningAngle = this.config.getConfigOrCreate<number>('clippingOpeningAngle', 180);
0076 const configZClippingEnabled = this.config.getConfigOrCreate<boolean>('zClippingEnabled', false);
0077 const configZClippingPosition = this.config.getConfigOrCreate<number>('zClippingPosition', 0);
0078 const configZClippingForward = this.config.getConfigOrCreate<boolean>('zClippingForward', true);
0079
0080 this.clippingEnabled = toSignal(configClippingEnabled.subject, { requireSync: true });
0081 this.startAngle = toSignal(configStartAngle.subject, { requireSync: true });
0082 this.openingAngle = toSignal(configOpeningAngle.subject, { requireSync: true });
0083 this.zClippingEnabled = toSignal(configZClippingEnabled.subject, { requireSync: true });
0084 this.zClippingPosition = toSignal(configZClippingPosition.subject, { requireSync: true });
0085 this.zClippingForward = toSignal(configZClippingForward.subject, { requireSync: true });
0086
0087 // Changes in enable/disable clipping
0088 effect(() => {
0089 this.threeService.enableClipping(this.clippingEnabled());
0090 if(this.clippingEnabled()) {
0091 this.threeService.setClippingAngle(this.startAngle(), this.openingAngle());
0092 }
0093 });
0094
0095 // changes in start or opening angles
0096 effect(()=> {
0097 this.threeService.setClippingAngle(this.startAngle(), this.openingAngle());
0098 });
0099
0100 // Z clipping enable/disable
0101 effect(() => {
0102 this.threeService.enableZClipping(this.zClippingEnabled());
0103 if (this.zClippingEnabled()) {
0104 this.threeService.updateZClipping(this.zClippingPosition(), this.zClippingForward());
0105 }
0106 });
0107
0108 // Z clipping position or direction changes
0109 effect(() => {
0110 this.threeService.updateZClipping(this.zClippingPosition(), this.zClippingForward());
0111 });
0112
0113 }
0114
0115 // In your ObjectClippingComponent ngOnInit, replace the getConfigOrThrow calls with:
0116
0117 ngOnInit(): void {
0118
0119
0120 }
0121
0122 /**
0123 * User toggles clipping in the UI checkbox.
0124 */
0125 toggleClipping(change: MatCheckboxChange): void {
0126 // Update the config property. This automatically saves to localStorage
0127 // and triggers the subscription above, which updates the ThreeService.
0128 this.config.getConfigOrThrow<boolean>('clippingEnabled').value = change.checked;
0129 }
0130
0131 /**
0132 * User changes the start angle. Use the config property setter to persist and update the scene.
0133 */
0134 changeStartClippingAngle(angle: number): void {
0135 this.config.getConfigOrThrow<number>('clippingStartAngle').value = angle;
0136 }
0137
0138 /**
0139 * User changes the opening angle. Use the config property setter to persist and update the scene.
0140 */
0141 changeOpeningClippingAngle(angle: number): void {
0142 this.config.getConfigOrThrow<number>('clippingOpeningAngle').value = angle;
0143 }
0144
0145 /**
0146 * User toggles Z clipping.
0147 */
0148 toggleZClipping(change: MatCheckboxChange): void {
0149 this.config.getConfigOrThrow<boolean>('zClippingEnabled').value = change.checked;
0150 }
0151
0152 /**
0153 * User changes the Z clipping position.
0154 */
0155 changeZClippingPosition(z: number): void {
0156 if (!isNaN(z)) {
0157 this.config.getConfigOrThrow<number>('zClippingPosition').value = z;
0158 }
0159 }
0160
0161 /**
0162 * User toggles Z clipping direction.
0163 */
0164 toggleZClippingDirection(change: MatSlideToggleChange): void {
0165 this.config.getConfigOrThrow<boolean>('zClippingForward').value = change.checked;
0166 }
0167
0168
0169 openDialog(): void {
0170 if (this.dialogRef) {
0171 this.dialogRef.close();
0172 return;
0173 }
0174
0175 const rect = this.openBtn.nativeElement.getBoundingClientRect();
0176 const dialogWidth = 320;
0177
0178 const left = Math.max(rect.right - dialogWidth, 8);
0179 const top = rect.bottom + 12;
0180
0181 this.dialogRef = this.dialog.open(this.dialogTemplate, {
0182 position: {
0183 top: `${top}px`,
0184 left: `${left}px`
0185 },
0186 hasBackdrop: false,
0187 panelClass: 'custom-position-dialog',
0188 autoFocus: false,
0189 viewContainerRef: this.viewContainerRef
0190 });
0191
0192 this.dialogRef.afterClosed().subscribe(() => {
0193 this.dialogRef = null;
0194 });
0195 }
0196
0197
0198 /**
0199 * Updates angle value in real-time as any slider moves
0200 * @param event The slider input event
0201 * @param sliderType Identifier for which slider is being updated ('start' or 'opening')
0202 */
0203 onSliderInput(event: any, sliderType: 'start' | 'opening'): void {
0204 // Extract the value safely from the event
0205 let newValue: number | null = null;
0206
0207 // Try different ways to get the value based on Angular Material version
0208 if (event && event.value !== undefined) {
0209 newValue = event.value;
0210 } else if (event && event.source && event.source.value !== undefined) {
0211 newValue = event.source.value;
0212 } else if (event && event.target && event.target.value !== undefined) {
0213 newValue = Number(event.target.value);
0214 }
0215
0216 // Only update if we got a valid number
0217 if (newValue !== null && !isNaN(newValue)) {
0218 // Update the appropriate property based on which slider was moved
0219 if (sliderType === 'start') {
0220 // this.startAngle..(newValue);
0221 } else if (sliderType === 'opening') {
0222 // this.openingAngle = newValue;
0223 }
0224 }
0225 }
0226 }