Editor/Road/ArchRoadExtentProviders.cs
namespace Sunless.Architecture;
public sealed class ArchRoadExtentProvider : IArchExtentProvider {
public ArchKind Kind => ArchKind.Road;
public ArchExtent Measure( object payload, ArchExtentContext context ) {
if ( payload is not ArchRoadPart road ) {
return new ArchExtent();
}
var extent = new ArchExtent();
var curve = road.Curve();
var reach = road.Reach();
var stand = road.KerbHeight + (road.Barriers == RoadSide.None ? 0f : road.Barrier.Height + road.Barrier.PostOverhang);
var frames = ArchRoadGen.Frames( road, curve );
foreach ( var frame in frames ) {
extent.Add( frame.Side( -reach ) );
extent.Add( frame.Side( reach ) );
extent.Add( frame.Position - Vector3.Up * (road.Thickness + road.KerbHeight + road.Camber) );
extent.Add( frame.Position + Vector3.Up * stand );
}
foreach ( var bridge in ArchLayerGate.Enabled( road.Bridges ) ) {
extent.Add( new ArchBridgeExtentProvider().Measure( bridge, context ) );
}
foreach ( var tunnel in road.Tunnels ) {
extent.Add( new ArchTunnelExtentProvider().Measure( tunnel, context ) );
}
return extent.Grown( 4f );
}
}
public sealed class ArchBridgeExtentProvider : IArchExtentProvider {
public ArchKind Kind => ArchKind.Bridge;
public ArchExtent Measure( object payload, ArchExtentContext context ) {
if ( payload is not ArchBridgePart bridge || context.Plan?.RoadCarrying( bridge ) is not { } road ) {
return new ArchExtent();
}
var extent = new ArchExtent();
var curve = road.Curve();
var frames = ArchRoadGen.Frames( road, curve );
var ground = new ArchGround( context.Tool?.Scene );
var shape = ArchBridge.Resolve( road, bridge, context.Plan, curve, frames, context.Kit ?? new ArchKit(), ground );
if ( !shape.IsUsable ) {
return extent;
}
extent.Add( shape.Near.Frame.Position.WithZ( shape.Near.Ground ) );
extent.Add( shape.Far.Frame.Position.WithZ( shape.Far.Ground ) );
foreach ( var bent in shape.Bents ) {
extent.Add( bent.Frame.Position.WithZ( bent.Ground ) );
}
return extent;
}
}
public sealed class ArchTunnelExtentProvider : IArchExtentProvider {
public ArchKind Kind => ArchKind.Tunnel;
public ArchExtent Measure( object payload, ArchExtentContext context ) {
if ( payload is not ArchTunnelPart tunnel || context.Plan?.RoadHolding( tunnel ) is not { } road ) {
return new ArchExtent();
}
var extent = new ArchExtent();
var curve = road.Curve();
var kit = context.Kit ?? new ArchKit();
var shape = ArchTunnel.Resolve( road, tunnel, curve, ArchRoadGen.Frames( road, curve ), kit,
new ArchGround( context.Tool?.Scene ) );
if ( !shape.IsUsable ) {
return extent;
}
var reach = ArchTunnel.Reach( tunnel, shape.Section );
foreach ( var frame in shape.Frames ) {
extent.Add( frame.Side( -reach ).WithZ( frame.Position.z + shape.Section.Floor - tunnel.Invert ) );
extent.Add( frame.Side( reach ).WithZ( frame.Position.z + shape.Section.Crown + tunnel.Lining ) );
}
foreach ( var mouth in new[] { shape.Near, shape.Far } ) {
extent.Add( mouth.Frame.Side( -reach ).WithZ( mouth.Foot ) );
extent.Add( mouth.Frame.Side( reach ).WithZ( mouth.Head ) );
}
return extent;
}
}