editor/AdvancedMappingTools/Geometry/HarborBollardsEditor.cs

Editor path tool that places rows of harbor bollards along a drawn path. Each bollard is three stacked cylinders (base, shaft, cap) built into a mesh kit, with an optional beam chain connecting successive posts.

namespace AdvancedMappingTools;

/// <summary>
/// A row of harbor bollards along a path, with caps and an optional chain between them.
/// </summary>
[ToolCategory( "Tunnels & Bridges" )]
[Title( "Harbor Bollards" ), Icon( "anchor" )]
public sealed class HarborBollardsEditor( PrimitiveTool tool ) : PathEditor( tool )
{
	protected override int MinPoints => 2;

	[Property, Group( "Bollards" ), Title( "Spacing" ), Range( 8, 1024, slider: false ), WideMode]
	public float Spacing { get; set; } = 96.0f;

	[Property, Group( "Bollards" ), Title( "Radius" ), Range( 1, 32, slider: false ), WideMode]
	public float Radius { get; set; } = 8.0f;

	[Property, Group( "Bollards" ), Range( 4, 128, slider: false ), WideMode]
	public float Height { get; set; } = 28.0f;

	[Property, Group( "Bollards" ), Title( "Chain" ), WideMode]
	public bool Chain { get; set; } = false;

	protected override void BuildMesh( MeshKit kit )
	{
		var path = SamplePath();

		if ( path.Count < 2 ) return;

		var radius = MathF.Max( Radius, 1.0f );
		var height = MathF.Max( Height, 4.0f );
		var previous = Vector3.Zero;
		var first = true;

		foreach ( var (position, _) in WalkPath( path, Closed, MathF.Max( Spacing, 8.0f ) ) )
		{
			kit.Material = TrimMaterial;
			kit.Cylinder( position, radius * 1.8f, radius * 1.8f, 0.0f, 4.0f, 12 );
			kit.Cylinder( position, radius, radius * 0.9f, 4.0f, height, 12 );
			kit.Cylinder( position, radius * 1.3f, radius * 1.3f, height, height + 4.0f, 12 );

			if ( Chain && !first )
				kit.Beam( previous + Vector3.Up * (height + 2.0f), position + Vector3.Up * (height + 2.0f), 1.5f, 3.0f );

			previous = position;
			first = false;
		}
	}
}