editor/AdvancedMappingTools/Architecture/TrafficSignEditor.cs

An editor stamp tool that builds traffic sign meshes from a box panel on one or two cylinders. Exposes shape, post and panel size properties, and writes the geometry into the MeshKit in Stamp.

namespace AdvancedMappingTools;

public enum SignShape
{
	Square,
	[Title( "Wide" )] Wide,
	[Title( "Tall" )] Tall
}

/// <summary>
/// A traffic sign on one or two posts. The panel is a plain box: paint it with a sign material.
/// </summary>
[ToolCategory( "Street" )]
[Title( "Traffic Sign" ), Icon( "signpost" )]
public sealed class TrafficSignEditor( PrimitiveTool tool ) : StampEditor( tool )
{
	[Property, Group( "Sign" ), WideMode]
	public SignShape Shape { get; set; } = SignShape.Square;

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

	[Property, Group( "Sign" ), Range( 1, 16, slider: false ), WideMode]
	public float PostRadius { get; set; } = 2.0f;

	[Property, Group( "Sign" ), Title( "Panel Width" ), Range( 4, 512, slider: false ), WideMode]
	public float PanelWidth { get; set; } = 48.0f;

	[Property, Group( "Sign" ), Title( "Panel Height" ), Range( 4, 512, slider: false ), WideMode]
	public float PanelHeight { get; set; } = 48.0f;

	[Property, Group( "Sign" ), Title( "Panel Thickness" ), Range( 0.5f, 16, slider: false ), WideMode]
	public float PanelThickness { get; set; } = 2.0f;

	[Property, Group( "Sign" ), Title( "Two Posts" ), WideMode]
	public bool TwoPosts { get; set; } = false;

	protected override void Stamp( MeshKit kit, Transform frame, Random random )
	{
		var height = MathF.Max( PostHeight, 8.0f );
		var r = Math.Clamp( PostRadius, 1.0f, 16.0f );
		var w = MathF.Max( PanelWidth, 4.0f );
		var h = MathF.Max( PanelHeight, 4.0f );
		var t = MathF.Max( PanelThickness, 0.5f );

		if ( Shape == SignShape.Wide ) w = MathF.Max( w, h * 1.6f );
		if ( Shape == SignShape.Tall ) h = MathF.Max( h, w * 1.4f );
		if ( TwoPosts ) w = MathF.Max( w, 64.0f );

		var half = TwoPosts ? w * 0.35f : 0.0f;

		kit.Cylinder( new Vector3( -half, 0.0f, 0.0f ), r, r, 0.0f, height, 10 );

		if ( TwoPosts ) kit.Cylinder( new Vector3( half, 0.0f, 0.0f ), r, r, 0.0f, height, 10 );

		kit.Material = TrimMaterial;
		kit.Box( new Vector3( -w * 0.5f, -t * 0.5f, height - h * 0.5f ), new Vector3( w * 0.5f, t * 0.5f, height + h * 0.5f ) );
	}
}