Editor/Data/ArchCorniceCatalog.cs
using System;
using System.Collections.Generic;
using System.Linq;
namespace Sunless.Architecture;
// The entablatures a wall head or a parapet ring can wear. Shipped whole rather than assembled on the sheet: an
// author picks one name and gets a stack that was proportioned together, which is the only way a cornice reads.
public sealed class ArchCorniceCatalog : IArchCatalog {
public static string Directory => ArchDataRoot.For( "cornices" );
public ArchShelf Shelf => ArchShelf.Cornices;
public string Named( object entry ) => entry is ArchCorniceStyle style ? style.Name : null;
public IEnumerable<object> Shipped() => Styles();
// Written out on first read, the way a pillar type is: a cornice is tuned far more often than it is invented,
// so an author opens the folder and moves a course rather than typing a stack from nothing.
public IEnumerable<object> Authored() {
foreach ( var built in Styles() ) {
var path = PathFor( built.Name );
if ( !ArchStorage.DocumentExists( path ) ) {
ArchStorage.WriteDocument( path, built );
}
}
var loaded = new List<ArchCorniceStyle>();
foreach ( var file in ArchStorage.DocumentFiles( Directory, ".cornice.json" ) ) {
if ( ArchStorage.ReadDocument<ArchCorniceStyle>( $"{Directory}/{file}" ) is { Name.Length: > 0, Courses: not null } style ) {
loaded.Add( style );
}
}
return loaded.OrderBy( style => style.Name ).ToList();
}
public bool Save( object entry ) => entry is ArchCorniceStyle style && ArchStorage.WriteDocument( PathFor( style.Name ), style );
static string PathFor( string name ) => $"{Directory}/{name}.cornice.json";
public static List<ArchCorniceStyle> Styles() {
return new List<ArchCorniceStyle>
{
new()
{
Name = "coping",
Detail = "A single cap oversailing both faces",
Courses = new List<ArchCorniceCourse> { Coping( 4f, 2f ) }
},
new()
{
Name = "stepped_coping",
Detail = "Two caps, the upper held back",
Courses = new List<ArchCorniceCourse> { Coping( 3.5f, 2.5f ), Coping( 2.5f, 1f ) }
},
new()
{
Name = "plain_cornice",
Detail = "Bed moulding, corona and crown",
Courses = new List<ArchCorniceCourse>
{
Moulding( "bed", 3.5f, 3f ),
Band( 6f, 7f ),
Moulding( "crown", 9f, 9f ),
Coping( 4f, 2f )
}
},
new()
{
Name = "dentilled",
Detail = "A dentil course under the corona",
Courses = new List<ArchCorniceCourse>
{
Moulding( "bed", 3.5f, 3f ),
Blocks( CorniceCourse.Dentils, "", 5f, 6f, 2.6f, 2.6f ),
Band( 5f, 7.5f ),
Moulding( "crown", 9f, 9f ),
Coping( 4f, 2f )
}
},
new()
{
Name = "bracketed",
Detail = "Modillion brackets carrying the corona",
Courses = new List<ArchCorniceCourse>
{
Moulding( "bed", 3.5f, 3f ),
Blocks( CorniceCourse.Modillions, "modillion", 5f, 7f, 3f, 9f ),
Band( 5f, 8f ),
Moulding( "crown", 9f, 9f ),
Coping( 4f, 2f )
}
},
new()
{
Name = "main_street",
// The crown IS the roof edge: nothing stands over it, so there is no coping course and no pier
// stepping above - a second cap on top reads as another wall standing on the entablature.
Detail = "Dentilled, the crown finishing the wall",
Courses = new List<ArchCorniceCourse>
{
Moulding( "bed", 3.5f, 3f ),
Band( 5f, 5f ),
Blocks( CorniceCourse.Dentils, "", 5f, 6.5f, 2.6f, 2.6f ),
Moulding( "crown", 9f, 9f )
},
Bracket = new ArchCorniceBracket { Width = 6f, Drop = 0.1f, Projection = 8f }
}
};
}
static ArchCorniceCourse Moulding( string profile, float rise, float projection ) {
return new ArchCorniceCourse {
Kind = CorniceCourse.Moulding,
Profile = profile,
Rise = rise,
Projection = projection
};
}
static ArchCorniceCourse Band( float rise, float projection ) {
return new ArchCorniceCourse { Kind = CorniceCourse.Band, Rise = rise, Projection = projection };
}
static ArchCorniceCourse Coping( float rise, float projection ) {
return new ArchCorniceCourse {
Kind = CorniceCourse.Coping,
Rise = rise,
Projection = projection,
Field = ArchSurface.WallCap
};
}
static ArchCorniceCourse Blocks( CorniceCourse kind, string profile, float rise, float projection, float block, float gap ) {
return new ArchCorniceCourse {
Kind = kind,
Profile = profile,
Rise = rise,
Projection = projection,
Block = block,
Gap = gap
};
}
}