Editor/Geometry/ArchBrokenRun.cs

Utility for creating an ArchRun from a 2D loop where edges can be marked as broken if they 'abut' some feature. It wraps ArchRun.Around and supplies a BreakWhere predicate that uses a provided abuts callback to decide break points based on the midpoint and outward region of an edge.

Reflection
using System;
using System.Collections.Generic;
using Sandbox;

namespace Sunless.Architecture;

// A run round a loop that stops wherever the loop abuts something else. Adapted so the run service never learns
// what a roof section, a platform edge or a wall band is - it is handed a test and asked where to break.
public static class ArchBrokenRun
{
	public static ArchRun Of( IReadOnlyList<Vector2> loop, Func<Vector2, Vector2, bool> abuts )
	{
		var run = ArchRun.Around( loop );

		return abuts is null ? run : run.BreakWhere( ( from, to ) => Breaks( from, to, abuts ) );
	}

	public static bool Breaks( Vector2 from, Vector2 to, Func<Vector2, Vector2, bool> abuts )
	{
		var span = to - from;

		return span.Length > 0.05f && abuts( (from + to) * 0.5f, ArchRegion.Outward( from, to ) );
	}

	public static bool[] Blocked( IReadOnlyList<Vector2> loop, Func<Vector2, Vector2, bool> abuts )
	{
		var blocked = new bool[loop.Count];

		if ( abuts is null )
		{
			return blocked;
		}

		for ( var index = 0; index < loop.Count; index++ )
		{
			blocked[index] = Breaks( loop[index], loop[(index + 1) % loop.Count], abuts );
		}

		return blocked;
	}
}