autodesk-forgerevit-api

How to map Forge SectionBox back to Revit


I would like to know how could I restore a SectionBox from Forge back to Revit.

In Forge Viwer, I have a SectionBox defined by its 6 planes. As far as I know, for clipping in a Revit 3d view we need to define a BoudingBox (not planes). Is that correct ?

I could manage in the other way around like this :

private List<double[]> GetCutPlanes(BoundingBoxXYZ bbox)
    {
        List<double[]> planesList = new List<double[]>();
        Autodesk.Revit.DB.Transform t = bbox.Transform;
        XYZ min = bbox.Min;
        XYZ max = bbox.Max;

        // Conversion factor from feet to meters
        const double conversionFactor = 0.3048;

        // Local helper function to create a plane in the [nx, ny, nz, d] format.
        double[] CreatePlane(XYZ normal, XYZ point)
        {
            // Transform the point and the normal using the bounding box's transform.
            XYZ pt = t.OfPoint(point);
            XYZ n = normal;

            double d = -(n.X * pt.X + n.Y * pt.Y + n.Z * pt.Z) * conversionFactor;

            return new double[] { -normal.X, -normal.Y, -normal.Z, d };
        }

        // Corrected reference points for each plane
        planesList.Add(CreatePlane(new XYZ(-1, 0, 0), new XYZ(min.X, min.Y, min.Z))); // X-min
        planesList.Add(CreatePlane(new XYZ(1, 0, 0), new XYZ(max.X, min.Y, min.Z)));  // X-max
        planesList.Add(CreatePlane(new XYZ(0, -1, 0), new XYZ(min.X, min.Y, max.Z))); // Y-min
        planesList.Add(CreatePlane(new XYZ(0, 1, 0), new XYZ(min.X, max.Y, max.Z)));  // Y-max 
        planesList.Add(CreatePlane(new XYZ(0, 0, -1), new XYZ(min.X, min.Y, min.Z))); // Z-min
        planesList.Add(CreatePlane(new XYZ(0, 0, 1), new XYZ(min.X, min.Y, max.Z)));  // Z-max

        return planesList;
    }

How could I go from Forge to Revit ?


Solution

  • We can convert the viewer's section box to a Revit one like the following.

    const cutPlanes = this.viewer.getCutPlanes();
    
    if (cutPlanes.length <= 6) return;
    
    let planes = cutPlanes.map(p => new THREE.Plane().setComponents(p.x, p.y, p.z, p.w))
    let frustum = new THREE.Frustum(
        planes[3],
        planes[1],
        planes[0],
        planes[4],
        planes[5],
        planes[2]
    );
    
    let pts = this.getCorners(frustum);
    let boundingBox = new THREE.Box3().setFromPoints(pts); //!<<< Bounding box of the viwer section box
    
    // Do necessary coordinate mapping here. e.g., to Revit space apply the `model.getInverseModelToViewerTransform()` to `boundingBox.max` and `boundingBox.min`
    
    let model = viewer.getAllModels()[0];
    let boundingBoxInRevitSpace = boundingBoxapplyMatrix4 (model.getInverseModelToViewerTransform());
    
    let boundingBoxStringInRevitSpace = JSON.stringfy(boundingBoxInRevitSpace);
    

    In Revit, we set bounding box like this way

    // Suppose we can a custom class for mapping BoundingBox from APS Viewer called ApsBoundingBox
    
    var boundingBox = JsonConvert.DeserializeObject<ApsBoundingBox>(boundingBoxStringInRevitSpace);
    
    view3D.SetSectionBox(new BoundingBoxXYZ() {
      Max = new XYZ(boundingBox.Max.X, boundingBox.Max.Y, boundingBox.Max.Z), 
      Min = new XYZ(boundingBox.Min.X, boundingBox.Min.Y, boundingBox.Min.Z) 
    });
    

    Related readings: