@@ -101,19 +101,9 @@ export class ViewerEngine {
101101 /** Property extractors per model, keyed by modelId. Lazy initialized. */
102102 private propertyExtractors = new Map < string , PropertyExtractor > ( ) ;
103103
104- /** Cached all-GlobalIds per model for isolation mode. */
105- private allGuidsCache = new Map < string , string [ ] > ( ) ;
106-
107104 /** Whether isolation mode is active. */
108105 private _isolated = false ;
109106
110-
111- /** Saved material state for isolation restore. */
112- private savedMaterials = new Map <
113- THREE . Material ,
114- { opacity : number ; transparent : boolean }
115- > ( ) ;
116-
117107 /** Active section planes. */
118108 private sectionPlanes : THREE . Plane [ ] = [ ] ;
119109
@@ -494,79 +484,49 @@ export class ViewerEngine {
494484 }
495485
496486 /**
497- * Isolate an element: ghost everything transparent ,
498- * then highlight the selected element with an opaque overlay .
487+ * Isolate an element: ghost everything at fragment level ,
488+ * then restore the selected element to full opacity with accent color .
499489 *
500- * Material-level opacity ghosts all geometry (fast).
501- * Fragment-level highlight renders the selected element on top (per-element accurate ).
490+ * Uses FragmentsModel.setOpacity() for per-element control (works correctly
491+ * even when elements share meshes in batched IFC geometry ).
502492 */
503493 async isolateElement ( globalId : string ) : Promise < void > {
504- if ( ! this . world ) return ;
494+ if ( ! this . world || ! this . fragments ) return ;
505495
506496 // Restore any previous isolation first
507- this . restoreMaterials ( ) ;
508- await this . clearHighlights ( ) ;
509-
510- // Ghost ALL meshes at the material level
511- for ( const obj of this . modelObjects . values ( ) ) {
512- obj . traverse ( ( child ) => {
513- if ( ! ( child instanceof THREE . Mesh ) ) return ;
514- const materials = Array . isArray ( child . material )
515- ? child . material
516- : [ child . material ] ;
517- for ( const mat of materials ) {
518- if ( ! mat || this . savedMaterials . has ( mat ) ) continue ;
519- this . savedMaterials . set ( mat , {
520- opacity : mat . opacity ,
521- transparent : mat . transparent ,
522- } ) ;
523- mat . transparent = true ;
524- mat . opacity = GHOST_OPACITY ;
525- mat . needsUpdate = true ;
526- }
527- } ) ;
528- }
529-
530- // Highlight selected element with opaque overlay (fragment-level, per-element)
531- if ( this . fragments ) {
532- try {
533- const modelIdMap = await this . fragments . guidsToModelIdMap ( [ globalId ] ) ;
534- if ( Object . keys ( modelIdMap ) . length > 0 ) {
535- const style : FRAGS . MaterialDefinition = {
536- color : new THREE . Color ( "#44B6A8" ) , // Verdigris
537- renderedFaces : FRAGS . RenderedFaces . TWO ,
538- opacity : 1.0 ,
539- transparent : false ,
540- } ;
541- await this . fragments . highlight ( style , modelIdMap ) ;
542- }
543- } catch {
544- // Highlight failed — ghost-only mode still works
497+ await this . clearIsolation ( ) ;
498+
499+ // Get the selected element's model ID map
500+ const selectedMap = await this . fragments . guidsToModelIdMap ( [ globalId ] ) ;
501+
502+ // Ghost all elements, then restore + colorize the selected one
503+ for ( const [ modelId , model ] of this . fragments . list ) {
504+ // Ghost ALL items in this model at fragment level
505+ await model . setOpacity ( undefined , GHOST_OPACITY ) ;
506+
507+ // If this model contains the selected element, restore it
508+ const selectedIds = selectedMap [ modelId ] ;
509+ if ( selectedIds && selectedIds . size > 0 ) {
510+ const ids = [ ...selectedIds ] ;
511+ await model . resetOpacity ( ids ) ;
512+ await model . setColor ( ids , new THREE . Color ( "#44B6A8" ) ) ; // Verdigris accent
545513 }
546514 }
547515
548516 this . _isolated = true ;
549517 }
550518
551519 /**
552- * Restore all materials to their original state .
520+ * Clear isolation: reset all fragment opacities and colors .
553521 */
554- private restoreMaterials ( ) : void {
555- for ( const [ mat , saved ] of this . savedMaterials ) {
556- mat . opacity = saved . opacity ;
557- mat . transparent = saved . transparent ;
558- mat . needsUpdate = true ;
522+ async clearIsolation ( ) : Promise < void > {
523+ if ( ! this . _isolated || ! this . fragments ) return ;
524+
525+ for ( const [ , model ] of this . fragments . list ) {
526+ await model . resetOpacity ( undefined ) ;
527+ await model . resetColor ( undefined ) ;
559528 }
560- this . savedMaterials . clear ( ) ;
561- }
562529
563- /**
564- * Clear isolation: restore all materials and remove highlight overlay.
565- */
566- async clearIsolation ( ) : Promise < void > {
567- if ( ! this . _isolated ) return ;
568- this . restoreMaterials ( ) ;
569- await this . clearHighlights ( ) ;
570530 this . _isolated = false ;
571531 }
572532
@@ -859,7 +819,6 @@ export class ViewerEngine {
859819 this . modelObjects . clear ( ) ;
860820 this . modelBoxes . clear ( ) ;
861821 this . modelBytes . clear ( ) ;
862- this . allGuidsCache . clear ( ) ;
863822 this . _isolated = false ;
864823
865824 for ( const extractor of this . propertyExtractors . values ( ) ) {
0 commit comments