Editor/Services/ArchRunSection.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;
namespace Sunless.Architecture;
// Subclass only for a shape the three below cannot make; do not re-implement the walk.
public abstract class ArchRunSection {
public abstract void Emit( ArchMesh canvas, ArchRunPath path, ArchBrush brush );
}
// Each corner belongs to the edge LEAVING it - carried past convex turns, back at reflex, none at open ends.
public sealed class ArchBandSection : ArchRunSection {
public float Shift { get; init; }
public float Depth { get; init; }
public float Bottom { get; init; }
public float Top { get; init; }
public static ArchBandSection Between( float near, float far, float bottom, float top ) {
return new ArchBandSection { Shift = near, Depth = far - near, Bottom = bottom, Top = top };
}
public override void Emit( ArchMesh canvas, ArchRunPath path, ArchBrush brush ) {
if ( Depth < 0.05f || Top - Bottom < 0.05f ) {
return;
}
var far = Shift + Depth;
for ( var edge = 0; edge < path.Edges; edge++ ) {
var start = path.At( edge );
var end = path.At( edge + 1 );
var span = end - start;
var length = span.Length;
if ( length < 0.05f ) {
continue;
}
var direction = span / length;
// -1 because ArchRegion.Outward is the right-hand normal, ArchBandGen.Outward the left.
var foldFrom = path.Continues( edge ) ? ArchBandGen.Fold( path.At( edge ) - path.At( edge - 1 ), direction, -1f ) : 0f;
var foldTo = path.Continues( edge + 1 ) ? ArchBandGen.Fold( direction, path.At( edge + 2 ) - path.At( edge + 1 ), -1f ) : 0f;
canvas.Beam( start, end, Shift, far, Bottom, Top, brush, foldFrom, foldTo );
}
}
}
// The extruder mitres closed runs itself; open ends are simply capped.
public sealed class ArchProfileSection : ArchRunSection {
public ArchProfile Profile { get; init; }
public float Height { get; init; }
public float Scale { get; init; } = 1f;
public Rotation Roll { get; init; } = Rotation.Identity;
public override void Emit( ArchMesh canvas, ArchRunPath path, ArchBrush brush ) {
if ( Profile is null || !Profile.IsUsable || path.Points.Count < 2 ) {
return;
}
canvas.Extrude( path.Raised( Height ), Profile, Scale, Roll, brush, path.Closed );
}
}