Editor tool for the Advanced Mapping Tools package that builds a drainage channel primitive along a drawn path: floor, two side walls, and optional grate bars via MeshKit sweeps.
namespace AdvancedMappingTools;
/// <summary>
/// An open drainage channel along a path: floor, two walls and optional grate bars.
/// </summary>
[ToolCategory( "Roads & Paths" )]
[Title( "Drainage Channel" ), Icon( "water" )]
public sealed class DrainageChannelEditor( PrimitiveTool tool ) : PathEditor( tool )
{
protected override bool SnapsToLines => true;
protected override bool CanClose => true;
protected override int MinPoints => 2;
[Property, Group( "Channel" ), Range( 4, 256, slider: false ), WideMode]
public float Width { get; set; } = 24.0f;
[Property, Group( "Channel" ), Range( 4, 256, slider: false ), WideMode]
public float Depth { get; set; } = 20.0f;
[Property, Group( "Channel" ), Title( "Wall" ), Range( 0.5f, 32, slider: false ), WideMode]
public float Thickness { get; set; } = 3.0f;
[Property, Group( "Channel" ), Title( "Grate" ), WideMode]
public bool Grate { get; set; } = false;
[Property, ShowIf( nameof( Grate ), true ), Group( "Channel" ), Title( "Grate Spacing" ), Range( 4, 128, slider: false ), WideMode]
public float GrateSpacing { get; set; } = 12.0f;
protected override void BuildMesh( MeshKit kit )
{
var path = SamplePath();
if ( path.Count < 2 ) return;
var half = MathF.Max( Width, 4.0f ) * 0.5f;
var depth = MathF.Max( Depth, 4.0f );
var t = Math.Clamp( Thickness, 0.5f, 32.0f );
kit.Material = SurfaceMaterial;
// Floor only between the walls, so floor and walls do not share faces.
SweepPath( kit, path, Closed, [new( -half + t, -depth ), new( half - t, -depth ), new( half - t, -depth + t ), new( -half + t, -depth + t )] );
SweepPath( kit, path, Closed, [new( -half, -depth + t ), new( -half + t, -depth + t ), new( -half + t, 0.0f ), new( -half, 0.0f )] );
SweepPath( kit, path, Closed, [new( half - t, -depth + t ), new( half, -depth + t ), new( half, 0.0f ), new( half - t, 0.0f )] );
if ( !Grate ) return;
kit.Material = TrimMaterial;
foreach ( var (position, direction) in WalkPath( path, Closed, MathF.Max( GrateSpacing, 4.0f ) ) )
{
var n = new Vector3( -direction.y, direction.x, 0.0f ).Normal * (half - t);
kit.Beam( position + n + Vector3.Up * -1.0f, position - n + Vector3.Up * -1.0f, 2.0f, 2.0f );
}
}
}