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