editor/AdvancedMappingTools/Architecture/SkylightEditor.cs

Editor stamp tool that generates skylight geometry from a MeshKit: a curb ring, frame and optional glass, in rectangular, round or strip shapes. Exposes width, length, curb height and frame width properties.

namespace AdvancedMappingTools;

public enum SkylightShape
{
	Rectangular,
	Round,
	Strip
}

/// <summary>
/// A roof skylight: a curb, a frame and glass. Rectangular, round or a long strip.
/// </summary>
[ToolCategory( "Roofs" )]
[Title( "Skylight" ), Icon( "window" )]
public sealed class SkylightEditor( PrimitiveTool tool ) : StampEditor( tool )
{
	[Property, Group( "Skylight" ), WideMode]
	public SkylightShape Shape { get; set; } = SkylightShape.Rectangular;

	[Property, Group( "Skylight" ), Range( 8, 1024, slider: false ), WideMode]
	public float Width { get; set; } = 64.0f;

	[Property, Group( "Skylight" ), Range( 8, 2048, slider: false ), WideMode]
	public float Length { get; set; } = 96.0f;

	[Property, Group( "Skylight" ), Title( "Curb Height" ), Range( 1, 96, slider: false ), WideMode]
	public float CurbHeight { get; set; } = 12.0f;

	[Property, Group( "Skylight" ), Title( "Frame Width" ), Range( 1, 32, slider: false ), WideMode]
	public float FrameWidth { get; set; } = 4.0f;

	[Property, Group( "Skylight" ), Title( "Glass" ), WideMode]
	public bool Glass { get; set; } = true;

	protected override void Stamp( MeshKit kit, Transform frame, Random random )
	{
		var w = Width * 0.5f;
		var l = Length * 0.5f;
		var h = MathF.Max( CurbHeight, 1.0f );
		var f = Math.Clamp( FrameWidth, 0.5f, MathF.Min( w, l ) * 0.45f );

		if ( Shape == SkylightShape.Round )
		{
			var r = MathF.Min( w, l );

			kit.Cylinder( Vector3.Zero, r, r, 0.0f, h, 16 );
			kit.Cylinder( Vector3.Zero, r - f, r - f, h, h + 1.5f, 16 );

			if ( Glass )
			{
				kit.Material = TrimMaterial;
				kit.Cylinder( Vector3.Zero, r - f * 0.5f, r - f * 0.5f, h + 0.2f, h + 1.0f, 16 );
			}

			return;
		}

		// A strip runs the whole length: two long rails, cross bars, one glass band.
		if ( Shape == SkylightShape.Strip )
		{
			// Long rails on the two long sides at x = ±w, cross bars between them.
			kit.Box( new Vector3( -w, -l, 0.0f ), new Vector3( -w + f, l, h ) );
			kit.Box( new Vector3( w - f, -l, 0.0f ), new Vector3( w, l, h ) );

			for ( var y = -l + f; y < l - f; y += 32.0f )
				kit.Box( new Vector3( -w + f, y, 0.0f ), new Vector3( w - f, MathF.Min( y + f * 0.6f, l - f ), h ) );

			if ( Glass )
			{
				kit.Material = TrimMaterial;
				kit.Box( new Vector3( -w + f, -l + f, h * 0.55f ), new Vector3( w - f, l - f, h * 0.55f + 0.6f ) );
			}

			return;
		}

		// Curb ring: four bars around the opening.
		kit.Box( new Vector3( -w, -l, 0.0f ), new Vector3( w, -l + f, h ) );
		kit.Box( new Vector3( -w, l - f, 0.0f ), new Vector3( w, l, h ) );
		kit.Box( new Vector3( -w, -l + f, 0.0f ), new Vector3( -w + f, l - f, h ) );
		kit.Box( new Vector3( w - f, -l + f, 0.0f ), new Vector3( w, l - f, h ) );

		if ( !Glass ) return;

		kit.Material = TrimMaterial;
		kit.Box( new Vector3( -w + f, -l + f, h * 0.55f ), new Vector3( w - f, l - f, h * 0.55f + 0.6f ) );
	}
}