Editor/Output/ArchLocate.Extents.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;
namespace Sunless.Architecture;
public static partial class ArchLocate {
static ArchExtent BuildingExtent( ArchBuilding building, ArchKit kit, int? level = null ) {
var extent = new ArchExtent();
foreach ( var room in building.Rooms.Where( room => !level.HasValue || room.Floor == level ) ) {
extent.Add( RoomExtent( room, kit ) );
}
foreach ( var roof in building.Roofs.Where( roof => !level.HasValue || roof.Level == level ) ) {
extent.Add( RoofExtent( roof ) );
}
foreach ( var fence in building.Fences ) {
extent.Add( FenceExtent( fence ) );
}
return extent;
}
public static ArchExtent RoomExtent( ArchRoom room, ArchKit kit ) {
var extent = new ArchExtent();
var providers = ArchExtents.Load();
var top = room.BaseHeight + ArchFloorGen.WallHeight( room, kit );
extent.Add( ArchFloorGen.Footprint( room ), room.BaseHeight - kit.FloorThickness, top );
foreach ( var wall in room.Walls ) {
extent.Add( WallExtent( wall, room, kit ) );
}
foreach ( var stair in room.Stairs ) {
extent.Add( providers.Measure( ArchKind.Stair, stair,
new ArchExtentContext( null, kit, room, null ) ) );
}
foreach ( var porch in room.Porches ) {
extent.Add( providers.Measure( ArchKind.Porch, porch,
new ArchExtentContext( null, kit, room, null ) ) );
}
return extent;
}
static ArchExtent WallExtent( ArchWall wall, ArchRoom room, ArchKit kit ) {
var extent = new ArchExtent();
var half = WallThickness( wall, kit ) * 0.5f;
var side = wall.Normal * half;
var top = room.BaseHeight + WallHeight( wall, room, kit );
extent.Add( wall.Start + side, room.BaseHeight, top );
extent.Add( wall.Start - side, room.BaseHeight, top );
extent.Add( wall.End + side, room.BaseHeight, top );
extent.Add( wall.End - side, room.BaseHeight, top );
return extent;
}
static ArchExtent OpeningExtent( ArchOpening opening, ArchWall wall, ArchRoom room, ArchKit kit ) {
var extent = new ArchExtent();
var half = WallThickness( wall, kit ) * 0.5f;
var side = wall.Normal * half;
var bottom = room.BaseHeight + opening.SillHeight;
var top = room.BaseHeight + opening.Top;
foreach ( var along in new[] { opening.Left, opening.Right } ) {
var point = wall.PointAt( along );
extent.Add( point + side, bottom, top );
extent.Add( point - side, bottom, top );
}
return extent;
}
static ArchExtent RoofExtent( ArchRoofPart roof ) {
var extent = new ArchExtent();
var outline = roof.Outline();
var span = MathF.Max( roof.Size.x, roof.Size.y ) * 0.5f;
var rise = roof.Style is RoofStyle.Flat ? roof.ParapetHeight : span * ArchPitch.Slope( roof.Pitch );
extent.Add( ArchFootprint.Grow( new List<List<Vector2>> { ArchFootprint.Wind( outline ) }, roof.Overhang )
.SelectMany( loop => loop ), roof.BaseHeight - 24f, roof.BaseHeight + rise + roof.Thickness );
return extent;
}
static ArchExtent PlatformExtent( ArchPlatformPart platform ) {
var extent = new ArchExtent();
// A ramp wears no coping, so counting one in leaves the audit reporting an envelope nothing ever fills.
var band = ArchRamp.Rakes( platform ) ? 0f : platform.CopingHeight;
extent.Add( platform.Outline(), platform.GradeHeight, platform.TopHeight + band );
return extent;
}
static ArchExtent BeamExtent( ArchBeamPart beam ) {
var extent = new ArchExtent();
extent.Add( beam.Outline(), beam.Soffit, beam.TopHeight );
return extent;
}
// Off the same resolve the generator reads, so a run trimmed to nothing at a corner reports the empty extent
// it really has rather than the stretch it was drawn over.
static ArchExtent CabinetExtent( ArchPlan plan, ArchKit kit, ArchRoom room, ArchBuilding building, ArchCabinetPart part ) {
return ArchExtents.Load().Measure( ArchKind.Cabinet, part, new ArchExtentContext( plan, kit, room, building ) );
}
static ArchExtent CutExtent( ArchCutPart cut ) {
var extent = new ArchExtent();
foreach ( var segment in cut.Segments.Where( leg => leg.Length > 1f ) ) {
extent.Add( segment.Outline(), segment.BaseHeight, segment.TopHeight );
}
return extent;
}
static ArchExtent DownpipeExtent( ArchDownpipePart pipe ) {
var extent = new ArchExtent();
extent.Add( pipe.Outlet, pipe.BaseHeight, pipe.TopHeight );
extent.Add( pipe.Wall, pipe.BaseHeight, pipe.TopHeight );
return extent.Grown( 6f );
}
// The line between the ends - the elevation a road is actually read from.
static float RoadYaw( ArchRoadPart road ) {
if ( road.Nodes.Count < 2 ) {
return 0f;
}
var run = road.Nodes[^1].Position - road.Nodes[0].Position;
return MathF.Atan2( run.y, run.x ).RadianToDegree();
}
static ArchExtent FenceExtent( ArchFencePart fence ) {
var extent = new ArchExtent();
var top = fence.Barrier.Height + fence.Barrier.PostOverhang + fence.Barrier.DropperLength;
foreach ( var node in fence.Nodes ) {
extent.Add( node.Position );
extent.Add( node.Position + Vector3.Up * top );
}
return extent.Grown( 4f );
}
static ArchExtent TrimExtent( ArchTrimPart trim ) {
var extent = new ArchExtent();
foreach ( var point in trim.Path ) {
extent.Add( point );
}
return extent.Grown( 8f );
}
}