简体   繁体   English

IFC.js 显示/隐藏图层和组件

[英]IFC.js show/hide layers and components

I'm wrapping "web-ifc-viewer" in an angular application.我将“web-ifc-viewer”包装在 angular 应用程序中。 I've some troubles to hide and show components inside the IFC.我在 IFC 内隐藏和显示组件时遇到了一些麻烦。

I've started from this example but I need to build a generic BIM viewer, so I can't define any category to prior.我从这个例子开始,但我需要构建一个通用的 BIM 查看器,所以我不能定义任何类别。

import {AfterViewInit, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {IfcViewerAPI} from "web-ifc-viewer";
import {Subject, takeUntil} from "rxjs";
import {AppThemes, BimViewerService} from "./bim-viewer.service";

@Component({
  selector: 'almaviva-bim-viewer',
  templateUrl: './bim-viewer.template.html',
  styleUrls: ['./bim-viewer.component.scss']
})
export class BimViewerComponent implements AfterViewInit {
  @ViewChild('viewerContainer')
  container!: ElementRef;
  viewer?: IfcViewerAPI;
  model: any;
  ifcElement: any;
  loadingValue: number = 0;


  constructor() {
  }

  ngAfterViewInit(): void {
    if (this.container) {
      this.viewer = new IfcViewerAPI({container: this.container.nativeElement});
      this.loadIfc('/assets/sample.ifc');
    }

  }

  private async loadIfc(url: string) {
    try {
      if (this.viewer) {
        await this.viewer.IFC.loader.ifcManager.useWebWorkers(true, '/assets/IFCWorker.js');
        await this.viewer.IFC.setWasmPath("wasm/");
        this.viewer.axes.setAxes(1000);
        this.viewer.grid.setGrid(1000);
        await this.viewer.IFC.loader.ifcManager.applyWebIfcConfig({
          USE_FAST_BOOLS: true,
          COORDINATE_TO_ORIGIN: true
        });
        this.viewer.IFC.loader.ifcManager.setOnProgress(
          (event) => {
            this.loadingValue = Math.floor((event.loaded * 100) / event.total);
          }
        )
        this.model = await this.viewer.IFC.loadIfcUrl(url);
        const project = await this.viewer.IFC.getSpatialStructure(this.model.modelID, true);
        this.ifcElement = project.children[0];
        await this.viewer.shadowDropper.renderShadow(this.model.modelID);
      }
    } catch (e) {
      console.log(e);
    }
  }

  async toggleLayer(event: Event, layer: any) {
      const subset = this.viewer?.IFC.loader.ifcManager.createSubset({
      modelID: this.model.modelID,
      ids: [layer.expressID],
      removePrevious: true,
      customID: `${layer.expressID}-custom-id`
    });
    if (subset) {
      this.viewer?.context.getScene().remove(subset);
    }
  }
}

When I toggle the layer ( toggleLayer() ) I receive an object from the subset like this当我切换图层( toggleLayer() )时,我从这样的子集中收到 object

子集对象

This is my html这是我的 html

<div>
  <mat-sidenav-container>
    <mat-sidenav mode="side" opened>
      <mat-toolbar>
      <span>
        BIM
      </span>
      </mat-toolbar>
      <mat-progress-bar mode="determinate" [value]="loadingValue"></mat-progress-bar>
      <mat-list role="list" *ngIf="!ifcElement">
          <mat-list-item role="listitem">
            Caricamento IFC in corso...
          </mat-list-item>
      </mat-list>
      <mat-accordion *ngIf="ifcElement">
        <mat-expansion-panel *ngFor="let arch of ifcElement?.children || []">
          <mat-expansion-panel-header>
            <mat-panel-title>
              {{arch.Name?.value || arch.LongName?.value || 'Architettura'}}
            </mat-panel-title>
          </mat-expansion-panel-header>
          <mat-list role="list">
            <mat-list-item role="listitem" *ngFor="let layer of arch.children">
              <mat-checkbox (click)="toggleLayer($event, layer)">
                {{layer.Name?.value || layer.LongName?.value || 'N/A'}}
              </mat-checkbox>
            </mat-list-item>
          </mat-list>
        </mat-expansion-panel>
      </mat-accordion>
    </mat-sidenav>
    <mat-sidenav-content>
      <div id="viewer-container" #viewerContainer></div>
      <div class="loading-spinner-wrapper" *ngIf="loadingValue!==100">
        <mat-spinner mode="indeterminate" diameter="35"></mat-spinner>
      </div>
    </mat-sidenav-content>
  </mat-sidenav-container>
</div>

Here the final result in the browser这是浏览器中的最终结果

国际金融公司查看器

The issue it's that nothing happens when I toggle the layer.问题是当我切换图层时没有任何反应。 And the subset log looks always the same.子集日志看起来总是一样的。

Subsets or createSubset() requires customID along side ids to identify the created subset from the original model without the customID you are overwriting your subset, it can be any string, in the example its was defined by category.toString()子集或createSubset()需要 customID 和边 id 来识别从原始 model 中创建的子集,而不需要覆盖子集的 customID,它可以是任何字符串,在示例中它由category.toString()定义

When you load an IFC model, it also gets added to the scene.当您加载 IFC model 时,它也会添加到场景中。 You need to remove the original model from the scene.您需要从场景中移除原来的 model。

Instead of creating a subset every time the user toggles a layer, you need to create subsets for each layer in the beginning, and just add or remove the subset from the scene when the user toggles a layer.您无需在每次用户切换图层时创建子集,而是需要在开始时为每个图层创建子集,并在用户切换图层时从场景中添加或删除子集。 You can find a tutorial about that here , the full example here and the working app here .您可以在此处找到有关该内容的教程、 此处的完整示例和此处的工作应用程序。

The structure of your logic should be similar to the following snippet.您的逻辑结构应类似于以下代码段。 This has been extracted from the minimal example linked above, so probably you need to adapt it a bit to you project:这已从上面链接的最小示例中提取,因此您可能需要对其进行一些调整以适应您的项目:

import {
    IFCWALLSTANDARDCASE,
    IFCSLAB,
    IFCDOOR,
    IFCWINDOW,
    IFCFURNISHINGELEMENT,
    IFCMEMBER,
    IFCPLATE,
} from 'web-ifc';

//Sets up the IFC loading
const ifcModels = [];
const ifcLoader = new IFCLoader();
ifcLoader.ifcManager.setWasmPath('../../../');
ifcLoader.load('../../../IFC/01.ifc', async (ifcModel) => {
    ifcModels.push(ifcModel);
    await setupAllCategories();
});


// Sets up optimized picking
ifcLoader.ifcManager.setupThreeMeshBVH(
    computeBoundsTree,
    disposeBoundsTree,
    acceleratedRaycast);

// List of categories names
const categories = {
    IFCWALLSTANDARDCASE,
    IFCSLAB,
    IFCFURNISHINGELEMENT,
    IFCDOOR,
    IFCWINDOW,
    IFCPLATE,
    IFCMEMBER,
};

// Gets the name of a category
function getName(category) {
    const names = Object.keys(categories);
    return names.find(name => categories[name] === category);
}

// Gets all the items of a category
async function getAll(category) {
    return ifcLoader.ifcManager.getAllItemsOfType(0, category, false);
}

// Creates a new subset containing all elements of a category
async function newSubsetOfType(category) {
    const ids = await getAll(category);
    return ifcLoader.ifcManager.createSubset({
        modelID: 0,
        scene,
        ids,
        removePrevious: true,
        customID: category.toString(),
    });
}

// Stores the created subsets
const subsets = {};

async function setupAllCategories() {
    const allCategories = Object.values(categories);
    for (let i = 0; i < allCategories.length; i++) {
        const category = allCategories[i];
        await setupCategory(category);
    }
}

// Creates a new subset and configures the checkbox
async function setupCategory(category) {
    subsets[category] = await newSubsetOfType(category);
    setupCheckBox(category);
}

// Sets up the checkbox event to hide / show elements
function setupCheckBox(category) {
    const name = getName(category);
    const checkBox = document.getElementById(name);
    checkBox.addEventListener('change', (event) => {
        const checked = event.target.checked;
        const subset = subsets[category];
        if (checked) scene.add(subset);
        else subset.removeFromParent();
    });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM