Skip to content

This sample demonstrates how to use a ShadowCastAnalysis to evaluate the shadow impact of a proposed building on surrounding structures, a common task in urban planning and architecture. The user can interactively adjust the building’s number of floors, width, and position using sliders, while the analysis updates in real time to show both visually and within tooltips, how much shadow the building casts on neighboring buildings. In this example, the goal is to keep the shadow impact on individual buildings low, and to keep the total shadow duration across all surrounding buildings below 30 hours. Note that the API is flexible enough to support any custom rules or thresholds.

To set up the analysis, create a ShadowCastAnalysis instance and configure it with a desired mode, time range, and options for the selected mode. In this sample, because we are using “total-duration” mode, we use totalDurationOptions for further customization.

Then add it to the scene:

const shadowAnalysis = new ShadowCastAnalysis({
mode: "total-duration",
startTimeOfDay: 29457000, // 08:10 AM (sunrise)
endTimeOfDay: 59879000, // 04:38 PM (sunset)
utcOffset: 1, // setting the correct time zone
totalDurationOptions: {
mode: "hourly",
color: [140, 226, 170, 0.65], // initial shadow color
},
});
viewElement.analyses.add(shadowAnalysis);

To query shadow duration at specific locations, retrieve the ShadowCastAnalysisView3D using the Scene component’s whenAnalysisView, then call getDurationAtScreen to get the shadow duration at a screen coordinate.

const analysisView = await viewElement.whenAnalysisView(shadowAnalysis);
// Query shadow duration at a screen point
const screenPoint = viewElement.toScreen(point);
const durationMs = await analysisView.getDurationAtScreen({
x: screenPoint.x,
y: screenPoint.y,
});

The sample builds the proposed building programmatically using Mesh.createBox for each floor and meshUtils.merge to combine them into a single mesh. This allows the building geometry to update dynamically when the user adjusts the sliders.

const floors = [];
for (let i = 0; i < numFloors; i++) {
const floorMesh = Mesh.createBox(floorOrigin, {
size: { width: 50, depth: 20, height: floorHeight },
});
floors.push(floorMesh);
}
const buildingMesh = meshUtils.merge(floors);