Editor-side handlers for porch architecture parts. Implements interaction drawing (height gizmos), picking (hit testing against porch bounds), and extent measurement (spatial extents for legs) for ArchKind.Porch.
namespace Sunless.Architecture;
public sealed class ArchPorchHandler : IArchHandler
{
public ArchKind Kind => ArchKind.Porch;
public bool Draw( ArchTool tool, ArchSelection picked )
{
if ( picked.Item is not ArchPorchPart porch )
{
return false;
}
var outline = ArchPorch.Footprint( porch );
var middle = Middle( outline );
var gesture = ArchGesture.On( ArchKind.Porch, porch.Id );
var changed = false;
if ( ArchShapeHandles.Height( tool, gesture.At( "head" ), middle, porch.BaseHeight + porch.HeadHeight, out var head, Gizmo.Colors.Roll ) )
{
porch.HeadHeight = MathF.Max( 24f, head - porch.BaseHeight );
changed = true;
}
if ( ArchShapeHandles.Height( tool, gesture.At( "deck" ), middle, porch.BaseHeight, out var deck, Gizmo.Colors.Pitch ) )
{
porch.BaseHeight = deck;
changed = true;
}
return changed;
}
static Vector2 Middle( IReadOnlyList<Vector2> outline )
{
if ( outline is not { Count: > 0 } )
{
return Vector2.Zero;
}
ArchFootprint.Bounds( outline, out var min, out var max );
return (min + max) * 0.5f;
}
}
public sealed class ArchPorchPicker : IArchPicker
{
public ArchKind Kind => ArchKind.Porch;
public void Under( ArchPicking picking )
{
if ( picking.Node.Payload is not ArchPorchPart porch )
{
return;
}
ArchPorch.Bounds( porch, out var min, out var max );
if ( ArchFootprint.Contains( ArchFootprint.Rect( min, max ), picking.Point ) )
{
picking.Hit( ArchHitChannel.Volume, 0f, true );
}
}
}
public sealed class ArchPorchExtentProvider : IArchExtentProvider
{
public ArchKind Kind => ArchKind.Porch;
public ArchExtent Measure( object payload, ArchExtentContext context )
{
var extent = new ArchExtent();
if ( payload is not ArchPorchPart porch )
{
return extent;
}
foreach ( var leg in porch.Legs )
{
extent.Add( ArchFootprint.Rect( leg.Min, leg.Max ), porch.GradeHeight - 8f, porch.BaseHeight + porch.HeadHeight + 48f );
}
return extent;
}
}