How to check if the model out of the viewer container?

Viewed 77

I made an info card and this card will disappear if the viewer is rotated until the model is not visible. I use isNodevisible but it always returns true.

  updateInfoCard() {
    if (this.infoCard && this.posModel) {
      const pos = this.viewer.worldToClient(this.posModel);

      console.log(pos);
      this.infoCard.style.left = `${Math.floor(
        50 + pos.x - this.infoCard.offsetWidth / 2
      )}px`;
      this.infoCard.style.top = `${Math.floor(
        50 + pos.y - this.infoCard.offsetWidth / 2
      )}px`;
      const id = this.infoCard.dataset.id;
      console.log(this.viewer.isNodeVisible(id));
      this.infoCard.style.display = this.viewer.isNodeVisible(id)
        ? "block"
        : "none";
    }
  }

enter image description here

2 Answers

If I understand your question correctly, you'll probably want to do an intersection test between the camera's frustum and the models's bounding box. That can be done like so:

    viewer.addEventListener(Autodesk.Viewing.CAMERA_CHANGE_EVENT, function () {
        if (!viewer.model) {
            return;
        }
        const camera = viewer.getCamera();
        const matrix = new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
        const frustum = new THREE.Frustum().setFromMatrix(matrix);
        const bbox = viewer.model.getBoundingBox();
        console.log('Model in the view?', frustum.intersectsBox(bbox));
    });

And if you only want to check the visibility of a specific element (based on its dbID) of your model, you can compute its bounding box like so:

    function objectBounds(model, dbId) {
        const tree = model.getInstanceTree();
        const frags = model.getFragmentList();
        const objectBounds = new THREE.Box3();
        tree.enumNodeFragments(dbId, function (fragId) {
            const fragBounds = new THREE.Box3();
            frags.getWorldBounds(fragId, fragBounds);
            objectBounds.union(fragBounds);
        }, true);
        return objectBounds;
    }

The function isNodeVisible returns the visibility status of your node in the scene. If you do something like this.viewer.hide(id, model) your function will return false.

If I well understood what you want to achieve, you want to hide an info card when the associated object is occluded by others objects, so we can't see it from our point of view ?

So I think what you need is to check for occlusion. You can take a look at the checkOcclusion function of this point cloud markup extension made by Philippe Leefsma. To check for node occlusion, you basically need to raycast from your point of view to the node that you want to check. If you hit something and it's your node, there is no occlusion. If it's not the same node, it's mean that something occlude your node.

checkOcclusion (markup) {

    const clientPoint = this.viewer.worldToClient(
      markup.point)

    const offset = $(this.viewer.container).offset()

    const rayCaster = this.pointToRaycaster(
      this.viewer.impl.canvas,
      this.viewer.impl.camera, {
        x: clientPoint.x + offset.left,
        y: clientPoint.y + offset.top
      })

    const hitTest = this.viewer.model.rayIntersect(
      rayCaster, true, this.dbIds)

    if (hitTest) {

      if (hitTest.fragId === markup.fragId) {

        const offset = {
          x: hitTest.point.x - markup.point.x,
          y: hitTest.point.y - markup.point.y,
          z: hitTest.point.z - markup.point.z
        }

        const dist = Math.sqrt(
          offset.x * offset.x +
          offset.y * offset.y +
          offset.z * offset.z)

        if (this.options.logOcclusionDist) {

          console.log(dist)
        }

        if (dist < this.options.occlusionDist) {

          return false
        }
      }

      return true
    }
  }

Related