Utility static class for resolving wall-related geometry values and helper computations. It computes resolved heights, thickness, cap dimensions, the 2D band polygon for a wall, and centers for pilasters based on room, kit, and run settings.
using System;
using System.Collections.Generic;
using Sandbox;
namespace Sunless.Architecture;
// What a wall MEASURES, resolved once and never re-derived at a caller: wall, then room, then kit. A handle, an
// elevation, a report, a damage bite and a fixture seat all need these numbers whether or not anything is installed
// to generate the wall itself.
public static class ArchWallSection
{
public static float Height( ArchWall wall, ArchRoom room, ArchKit kit ) => Resolve( wall.Height, room?.WallHeight ?? 0f, kit.WallHeight );
public static float Thickness( ArchWall wall, ArchKit kit ) => Resolve( wall.Thickness, 0f, kit.WallThickness );
// What a wall with no height of its own stands at - the ceiling a half wall is measured against.
public static float CeilingHeight( ArchRoom room, ArchKit kit ) => Resolve( 0f, room?.WallHeight ?? 0f, kit.WallHeight );
// One resolution of the coping section: generator, designer form and report read the same cap.
public static float CapHeight( IArchWallTreatment wall, ArchKit kit ) => Resolve( wall.CapHeight, 0f, kit.WallCapHeight );
public static float CapOverhang( IArchWallTreatment wall, ArchKit kit ) => Resolve( wall.CapOverhang, 0f, kit.CasingDepth );
// A wall is a band, not a line: its centreline grown by its own thickness.
public static List<Vector2> Band( ArchWall wall, ArchKit kit )
{
var side = wall.Normal * (Thickness( wall, kit ) * 0.5f);
return new List<Vector2> { wall.Start + side, wall.End + side, wall.End - side, wall.Start - side };
}
// The one resolution: generator and report agree on how many.
public static IEnumerable<float> PilasterCentres( ArchPilasterRun run, float from, float to )
{
var span = to - from;
if ( run is null || !run.Stands || span < 1f )
{
yield break;
}
var strip = MathF.Min( run.Width, span );
var division = run.Count > 0 ? ArchDivide.Into( span, Math.Max( 1, run.Count - 1 ) ) : ArchDivide.AtMost( span, run.Bay );
foreach ( var node in division.Nodes )
{
yield return run.OnCorners
? from + node
: Math.Clamp( from + node, from + strip * 0.5f, to - strip * 0.5f );
}
}
static float Resolve( float value, float roomValue, float kitValue )
{
if ( value > 0f )
{
return value;
}
return roomValue > 0f ? roomValue : kitValue;
}
}