Editor handler for span parts in the architecture editor. It draws and updates a span widget, handles re-aiming span endpoints, adjusts springing, beam depth or arch rise based on user gestures and plan/kit context.
namespace Sunless.Architecture;
public sealed class ArchSpanHandler : IArchHandler
{
public ArchKind Kind => ArchKind.Span;
// An end square per pier and, in an elevation, how far the span reaches down. Dragging an end re-asks what it
// landed on, so a span is re-aimed at another column by pulling it there rather than by placing a new one.
public bool Draw( ArchTool tool, ArchSelection picked )
{
if ( picked.Item is not ArchSpanPart span )
{
return false;
}
var room = tool.Plan.RoomStanding( span );
if ( !ArchSpanShape.Resolve( tool.Plan, tool.Kit, room, span, out var run ) )
{
return false;
}
var gesture = ArchGesture.On( ArchKind.Span, span.Id );
// The part is authored on the flat plan and poured onto the building's grade, so a widget drawn at the
// authored height stands a foundation below the span it is meant to be holding.
var lift = picked.Lift( tool.Plan, tool.Kit );
if ( Reaimed( tool, room, span, run, gesture, lift ) )
{
return true;
}
var middle = Vector2.Lerp( run.From, run.To, 0.5f );
if ( !ArchShapeHandles.Height( tool, gesture.At( "spring" ), middle, run.Springing + lift, out var pulled, Gizmo.Colors.Roll ) )
{
return false;
}
var band = MathF.Max( 2f, run.Top + lift - pulled );
// A pinned springing is the number the shape reads, so the widget writes THAT rather than a rise nothing
// would look at.
if ( span.Springing > 0.5f )
{
span.Springing = MathF.Max( 2f, pulled - lift - room.BaseHeight );
return true;
}
if ( span.Form == PillarSpan.Beam )
{
span.BeamDepth = band;
return true;
}
// An arch spends its band on the ring as well, so pulling the springing down leaves the ring where the
// author set it and grows the rise.
span.Rise = span.Form == PillarSpan.Arch ? MathF.Max( 2f, band - MathF.Max( 2f, span.Ring ) ) : band;
return true;
}
static bool Reaimed( ArchTool tool, ArchRoom room, ArchSpanPart span, ArchSpanRun run, ArchGesture gesture, float lift )
{
if ( Pulled( tool, gesture.At( "from" ), run.From, run.Springing + lift, out var start ) )
{
span.From = ArchSpanShape.Anchored( tool.Plan, room, start );
return true;
}
if ( Pulled( tool, gesture.At( "to" ), run.To, run.Springing + lift, out var end ) )
{
span.To = ArchSpanShape.Anchored( tool.Plan, room, end );
return true;
}
return false;
}
static bool Pulled( ArchTool tool, ArchGesture gesture, Vector2 at, float height, out Vector2 moved )
{
return ArchShapeHandles.Placed( tool, gesture, new Vector3( at.x, at.y, height ), out moved, Gizmo.Colors.Active );
}
}