ThatOpen / engine_components

MIT License
344 stars 135 forks source link

Multiple Building Not in Center #457

Closed suryakumara closed 3 months ago

suryakumara commented 3 months ago

Describe the bug 📝

I am a long time user of IFC Loader, currently my database is still using IFC file so my step is to load the ifc file and directly change it to fragments

I am trying to load multiple buildings, but each building is not centered of threejs scene. It seems that the position of each building follows the position of the first loaded building.

Additionally, I don't fully understand how the classifier works. When I load multiple buildings and implement the spatial structure, not all floors appear.

Here is my code:

async loadSimpleIfc(
    name: string,
    filePath: string,
    position: { x: number; y: number; z: number },
    rotation: {
      heading: number;
      pitch: number;
      roll: number;
    },
    scale: number,
    rotationTuneParams: {
      heading: number;
      pitch: number;
      roll: number;
    } | null,
  ) {
    const file = await fetch(filePath);
    const data = await file.arrayBuffer();
    const buffer = new Uint8Array(data);
    const ifcModel = await this.fragmentIfcLoader.load(buffer, true);

    const boundingbox = new THREE.Box3().setFromObject(ifcModel);
    const centerVector = boundingbox.getCenter(new THREE.Vector3());
    const helper = new THREE.BoxHelper(ifcModel);
    this.world.scene.three.add(helper);

    const indexer = this.components.get(OBC.IfcRelationsIndexer);

    await indexer.process(ifcModel);
    const ifcProperties = ifcModel.getLocalProperties();

    const dataExport = this.fragments.export(ifcModel);

    const model = this.fragments.load(dataExport, { coordinate: true });

    const setTransparency = (object, opacity) => {
      object.traverse((child) => {
        if (child instanceof THREE.Mesh) {
          if (Array.isArray(child.material)) {
            child.material.forEach((m) => {
              m.transparent = true;
              m.opacity = opacity;
            });
          } else {
            child.material.transparent = true;
            child.material.opacity = opacity;
          }
        }
      });
    };

    setTransparency(model, 0.5);

    const posX = position.x - this.originOffset.x - centerVector.x;
    const posY = position.y - this.originOffset.y;
    const posZ = position.z - this.originOffset.z - centerVector.z;

    model.position.set(posX, posY, posZ);

    this.world.scene.three.add(model);

    if (import.meta.env.MODE === 'development') {
      const geometry = globalTracker.track(
        new THREE.SphereGeometry(0.2, 32, 16),
      );
      const material = globalTracker.track(
        new THREE.MeshBasicMaterial({ color: 0x00ff00 }),
      );
      const sphere = globalTracker.track(new THREE.Mesh(geometry, material));
      sphere.position.set(
        position.x - this.originOffset.x,
        position.y - this.originOffset.y,
        position.z - this.originOffset.z,
      );

      this.world.scene.three.add(sphere);
    }

    await indexer.process(ifcModel);
    const json = indexer.serializeModelRelations(ifcModel);

    const relations = indexer.getRelationsMapFromJSON(json ?? '');
    indexer.setRelationMap(ifcModel, relations);

    const classifier = this.components.get(OBC.Classifier);
    classifier.byEntity(ifcModel);
    await classifier.bySpatialStructure(ifcModel);

    this.ifcModelData.push({
      name,
      ifcModel: model,
      ifcProperties,
      position: {
        x: position.x - this.originOffset.x - centerVector.x,
        y: position.y - this.originOffset.y,
        z: position.z - this.originOffset.z - centerVector.z,
      },
      rotation,
      scale,
      classifier: classifier,
    });

    return this.ifcModelData;
  }```

### Reproduction ▶️

_No response_

### Steps to reproduce 🔢

_No response_

### System Info 💻

```shell
{
  "name": "dasiot-app-dsm-console",
  "version": "0.48.2-a.8",
  "private": true,
  "scripts": {
    "start": "LOCIZE_ENV=development vite",
    "build": "tsc && node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build",
    "test": "jest",
    "test:build": "jest src/test --ci --watchAll=false",
    "playwright-test": "npx playwright test",
    "format": "prettier --write \"src/**/*.ts\" \"src/**/*.tsx\"",
    "lint": "eslint \"src/**/*.ts\" \"src/**/*.tsx\" --fix",
    "prepare": "husky install",
    "analyze": "source-map-explorer 'build/assets/*.js'",
    "locize:download": "node tools/locizeDownload.mjs"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ],
    "overrides": [
      {
        "files": [
          "**/*.ts?(x)"
        ],
        "rules": {
          "react/prop-types": "off"
        }
      }
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "dependencies": {
    "@beeinventor/dasiot-react-component-lib": "^1.8.4",
    "@beeinventor/mapbox-gl-draw-scale-rotate-mode": "^0.1.2",
    "@date-io/date-fns": "^2.17.0",
    "@emotion/react": "^11.11.1",
    "@emotion/styled": "^11.11.0",
    "@livekit/react-components": "1.1.0",
    "@mapbox/mapbox-gl-draw": "^1.4.3",
    "@mapbox/mapbox-gl-language": "^1.0.1",
    "@mui/icons-material": "^5.14.18",
    "@mui/material": "^5.14.18",
    "@mui/x-date-pickers": "^5.0.20",
    "@reduxjs/toolkit": "^1.9.7",
    "@tanstack/react-query": "^4.36.1",
    "@tanstack/react-query-devtools": "^4.36.1",
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^14.5.1",
    "@thatopen/components": "~2.1.0",
    "@thatopen/components-front": "~2.1.0",
    "@thatopen/fragments": "^2.1.0",
    "@thatopen/ui": "~2.1.0",
    "@turf/turf": "^6.5.0",
    "@types/qrcode": "^1.5.5",
    "axios": "^0.27.2",
    "cesium": "1.93.0",
    "classnames": "^2.3.2",
    "d3": "^7.8.5",
    "date-fns": "^2.30.0",
    "date-fns-tz": "^2.0.0",
    "dotenv": "^16.3.1",
    "geojson": "^0.5.0",
    "history": "^5.3.0",
    "hls.js": "^1.4.12",
    "html5-qrcode": "^2.3.8",
    "http-proxy-middleware": "^2.0.6",
    "i18next": "^21.10.0",
    "i18next-chained-backend": "^3.1.0",
    "i18next-http-backend": "^1.4.5",
    "i18next-locize-backend": "^5.1.5",
    "i18next-resources-to-backend": "^1.2.0",
    "jest-transform-stub": "^2.0.0",
    "json-sort-cli": "^2.1.11",
    "livekit-client": "1.1.1",
    "locize": "^2.4.6",
    "locize-cli": "^7.14.12",
    "mapbox-gl": "^2.15.0",
    "mobile-drag-drop": "3.0.0-rc.0",
    "notistack": "^2.0.8",
    "peerjs": "^1.5.1",
    "qrcode": "^1.5.3",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-i18next": "^11.18.6",
    "react-map-gl": "^7.1.6",
    "react-redux": "^8.1.3",
    "react-router-dom": "^6.24.1",
    "react-virtualized-auto-sizer": "^1.0.20",
    "react-window": "^1.8.9",
    "react-window-infinite-loader": "^1.0.9",
    "socket.io-client": "^4.7.2",
    "source-map-explorer": "^2.5.3",
    "stats.js": "^0.17.0",
    "three": "^0.160.1",
    "three-mesh-bvh": "^0.5.24",
    "typescript": "^4.9.5",
    "web-ifc": "0.0.56",
    "web-ifc-three": "^0.0.118",
    "web-vitals": "^2.1.4",
    "workbox-core": "^6.6.0",
    "workbox-expiration": "^6.6.0",
    "workbox-precaching": "^6.6.0",
    "workbox-routing": "^6.6.0",
    "workbox-strategies": "^6.6.0",
    "xlsx": "^0.18.5"
  },
  "devDependencies": {
    "@playwright/test": "^1.44.0",
    "@types/d3": "^7.4.3",
    "@types/geojson": "^7946.0.13",
    "@types/jest": "^29.5.8",
    "@types/mapbox-gl": "^2.7.18",
    "@types/mapbox__mapbox-gl-draw": "^1.4.6",
    "@types/node": "^17.0.45",
    "@types/react": "^18.2.37",
    "@types/react-dom": "^18.2.15",
    "@types/react-redux": "^7.1.30",
    "@types/react-router": "^5.1.20",
    "@types/react-router-dom": "^5.3.3",
    "@types/react-virtualized-auto-sizer": "^1.0.3",
    "@types/react-window": "^1.8.8",
    "@types/react-window-infinite-loader": "^1.0.9",
    "@types/three": "0.160.0",
    "@typescript-eslint/eslint-plugin": "^5.62.0",
    "@typescript-eslint/parser": "^5.62.0",
    "@vitejs/plugin-basic-ssl": "^1.0.1",
    "@vitejs/plugin-react": "^2.2.0",
    "eslint": "^8.53.0",
    "eslint-config-airbnb": "^19.0.4",
    "eslint-config-airbnb-typescript": "^17.1.0",
    "eslint-config-prettier": "^8.10.0",
    "eslint-plugin-import": "^2.29.0",
    "eslint-plugin-jsx-a11y": "^6.8.0",
    "eslint-plugin-prettier": "^4.2.1",
    "eslint-plugin-react": "^7.33.2",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-simple-import-sort": "^10.0.0",
    "husky": "^8.0.3",
    "jest": "^29.7.0",
    "lint-staged": "^13.3.0",
    "prettier": "^2.8.8",
    "ts-jest": "^29.1.1",
    "vite": "^5.0.12",
    "vite-plugin-pwa": "^0.17.5",
    "vite-plugin-svgr": "^4.2.0"
  },
  "lint-staged": {
    "src/**/*.{js,ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "src/**/*.json": "npx jsonsort"
  },
  "resolutions": {
    "react-error-overlay": "^6.0.10"
  }
}

Used Package Manager 📦

pnpm

Error Trace/Logs 📃

No response

Validations ✅

agviegas commented 3 months ago

Hi @suryakumara if you don't want to coordinate the buildings with each other, you can just set the coordinate parameter of the IFCLoader to false.

As for the spatial structure, can you please open a separate issue and provide a minimal app and some models where we can reproduce it? I suggest you use the classifier tutorial as a starting point. Thanks!

suryakumara commented 3 months ago

@agviegas I have another problem, when I set the coordinate to false, the position of loaded multiple buildings will reset to 0 or the center of the three.js scene. However, the position of the y-axis is not. Not all buildings are on the same ground axis. shown in the figure bellow. I have tried to use classifiers and spatial structure however is not fit well with multiple buildings. somehow other ifcBuildingStoreys is not showing up. To debug this I have attached the codesanbox link image

https://codesandbox.io/p/sandbox/ifc-loader-minimum-fnwf79?file=%2Fsrc%2FIFCViewer.js

Structure actually need to show this storeys image image

agviegas commented 3 months ago

@suryakumara I'm not sure I'm following, but I'll do my best:

  1. Model position: when you set coordinate to false the IFC is displayed exactly in the position where it was exported, which might not be with its ground level in the plane Y=0. That said, if it's not behaving the way you expect, you can send me the models privately to antonio@thatopen.com and I'll take a look.

  2. Model tree: you mean that you are missing some storeys, right? You can send me the models privately to antonio@thatopen.com and I'll take a look.

Anyways, for traceability's sake, it's better to keep 1 problem per issue. So feel free to open a new issue ticket and send me the models, and I'll take a look.