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;
}
}