editor/AdvancedMappingTools/Core/WallTops.cs

Editor helper that collects the corner and end points of finished walls, both linked walls and single-mesh walls, as foot/top pairs with a half thickness. Also resolves the nearest corner to a point within a docking radius so roofs and slabs can be drawn from wall to wall.

namespace AdvancedMappingTools;
/// <summary>
/// The corners of finished walls at their foot and their top, of connected walls and of walls
/// built as one mesh alike. A roof or a slab drawn from corner to corner then fits the walls.
/// </summary>
public static class WallTops
{
	public readonly record struct Corner( Vector3 Foot, Vector3 Top, float Half );

	/// <summary>
	/// Every corner and end of every finished wall.
	/// </summary>
	public static IEnumerable<Corner> All( Scene scene )
	{
		foreach ( var wall in WallLinker.Walls( scene ) )
		{
			if ( PartService.Read( wall ).Settings is not ConnectedWallSettings s || s.Path is null )
				continue;
			var world = wall.WorldTransform;
			foreach ( var node in s.Path.Nodes )
			{
				var foot = world.PointToWorld( node.Position );
				var end = world.PointToWorld( node.Position + Vector3.Up * s.Height );
				var half = s.Thickness * .5f * MathF.Max( MathF.Abs( world.Scale.x ), MathF.Abs( world.Scale.y ) );
				yield return foot.z <= end.z ? new Corner( foot, end, half ) : new Corner( end, foot, half );
			}
		}

		foreach ( var corner in LineSnap.Corners( scene ) )
			yield return corner;
	}

	/// <summary>
	/// The nearest corner in 3D, within the horizontal docking radius.
	/// </summary>
	public static Corner? Nearest( Scene scene, Vector3 point, float radius )
	{
		Corner? best = null;
		var nearest = float.MaxValue;
		foreach ( var corner in All( scene ) )
		{
			var horizontal = corner.Top.WithZ( 0.0f ).Distance( point.WithZ( 0.0f ) );
			var distance = corner.Top.Distance( point );
			if ( horizontal > radius + corner.Half * 2.0f || distance >= nearest )
				continue;
			nearest = distance;
			best = corner;
		}

		return best;
	}
}