editor/AdvancedMappingTools/Architecture/PergolaEditor.cs
namespace AdvancedMappingTools;
/// <summary>
/// A pergola along a path: post pairs, two side beams and slats across. The path is the middle line.
/// </summary>
[ToolCategory( "Buildings" )]
[Title( "Pergola" ), Icon( "deck" )]
public sealed class PergolaEditor( PrimitiveTool tool ) : PathEditor( tool )
{
protected override bool SnapsToLines => true;
protected override bool CanClose => true;
protected override int MinPoints => 2;
[Property, Group( "Pergola" ), Range( 16, 1024, slider: false ), WideMode]
public float Width { get; set; } = 160.0f;
[Property, Group( "Pergola" ), Range( 16, 1024, slider: false ), WideMode]
public float Height { get; set; } = 128.0f;
[Property, Group( "Pergola" ), Title( "Post Spacing" ), Range( 16, 1024, slider: false ), WideMode]
public float PostSpacing { get; set; } = 128.0f;
[Property, Group( "Pergola" ), Title( "Post Size" ), Range( 1, 32, slider: false ), WideMode]
public float PostSize { get; set; } = 8.0f;
[Property, Group( "Pergola" ), Title( "Slats" ), WideMode]
public bool Slats { get; set; } = true;
[Property, ShowIf( nameof( Slats ), true ), Group( "Pergola" ), Title( "Slat Spacing" ), Range( 4, 128, slider: false ), WideMode]
public float SlatSpacing { get; set; } = 24.0f;
protected override void BuildMesh( MeshKit kit )
{
var path = SamplePath();
if ( path.Count < 2 ) return;
var half = MathF.Max( Width, 8.0f ) * 0.5f;
var height = MathF.Max( Height, 8.0f );
var size = Math.Clamp( PostSize, 1.0f, 32.0f );
var spacing = MathF.Max( PostSpacing, 8.0f );
var posts = WalkPath( path, Closed, spacing );
var left = posts.Select( x => x.Position + Normal( x.Direction ) * half ).ToList();
var right = posts.Select( x => x.Position - Normal( x.Direction ) * half ).ToList();
kit.Material = SurfaceMaterial;
foreach ( var point in left )
kit.Box( point + new Vector3( -size * 0.5f, -size * 0.5f, 0.0f ), point + new Vector3( size * 0.5f, size * 0.5f, height ) );
foreach ( var point in right )
kit.Box( point + new Vector3( -size * 0.5f, -size * 0.5f, 0.0f ), point + new Vector3( size * 0.5f, size * 0.5f, height ) );
kit.Material = TrimMaterial;
for ( var i = 0; i + 1 < left.Count; i++ )
{
kit.Beam( left[i].WithZ( height ), left[i + 1].WithZ( height ), 6.0f, 10.0f );
kit.Beam( right[i].WithZ( height ), right[i + 1].WithZ( height ), 6.0f, 10.0f );
}
if ( !Slats ) return;
var step = MathF.Max( SlatSpacing, 4.0f );
foreach ( var (position, direction) in WalkPath( path, Closed, step ) )
{
var n = Normal( direction ) * half;
kit.Beam( position + n + Vector3.Up * (height + 10.0f), position - n + Vector3.Up * (height + 10.0f), 3.0f, 4.0f );
}
}
static Vector3 Normal( Vector3 direction )
{
var flat = direction.WithZ( 0.0f ).Normal;
return new Vector3( -flat.y, flat.x, 0.0f );
}
}