Cast shadow

Cast shadow

Shadows indeed add a beautiful depth to objects. We architects love casting shadows on buildings; it enhances the perception of the structure and adds an artistic touch.

I wondered if it was possible to extract the geometry of shadows for further analysis. This curiosity was resolved when I discovered the ExtrusionAnalyzer class.

The methodology of this class is straightforward: submit the solid, the plane where the shadows will be cast, and the direction of the shadow. By following these steps, you can obtain the geometric shape of the shadow cast by an object.

Extracting Solid Geometry

To begin, you can get the solid from an element using the Geometry(Options) function. Here are the recommended settings for the Options:

  new Options { 
                ComputeReferences = false, // not required
                IncludeNonVisibleObjects = false // not required 
              }

When retrieving a GeometryElement from instances such as Families or DirectShapes, the solids within may appear merged. For example, DirectShapes return a collection of faces as a single solid, even if multiple solids are present. An interesting case occurs with a Model in Place component containing three geometric shapes: using GeometryInstance.GetGeometry() results in two solids. One solid includes all necessary information combined with the faces of all three geometries and has a non-zero volume. The second solid contains empty faces with zero volume.

To separate these combined solids, you can use the static function SolidUtils.SplitVolumes(Solid). This function returns separated transformed solids and, when used with ExtrusionAnalyzer, provides the expected results.

Example Code

Below is an example of how to generate model lines that reflect the outer edges of shadows:

foreach (GeometryObject geomObj in ge)
{
    if (geomObj is Solid combinedSolids)
    {
        if (combinedSolids.Volume == 0)
            continue;
        var solidSplits = SolidUtils.SplitVolumes(combinedSolids);
        foreach (var solid in solidSplits)
        { 
            ExtrusionAnalyzer ea = ExtrusionAnalyzer.Create(solid, Plane.CreateByNormalAndOrigin(XYZ.BasisZ, XYZ.Zero), XYZ.BasisZ);
            List<CurveLoop> loops = ea.GetExtrusionBase().GetEdgesAsCurveLoops().ToList();
            foreach (CurveLoop loop in loops)
            {
                foreach (Curve curve in loop)
                {
                    makeLine(doc, curve.GetEndPoint(0), curve.GetEndPoint(1));
                }
            }
        }
    }
}

While this approach effectively addresses the task, it does not fully explain why ExtrusionAnalyzer fails to identify all solid geometries, selecting only the initial one.

this topic was also raised on Autodeskforum

Did you find this article valuable?

Support Moustafa Khalil by becoming a sponsor. Any amount is appreciated!