Editor/Pipe/ArchPipeFittings.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;
namespace Sunless.Architecture;
public enum ArchPipeFittingKind {
Flange,
Coupling,
Elbow,
Tee,
Reducer
}
public sealed class ArchPipeFitting {
public int NodeId { get; init; }
public Vector3 Position { get; init; }
public ArchPipeFittingKind Kind { get; init; }
public List<int> Runs { get; init; } = new();
}
public static class ArchPipeFittings {
readonly record struct Leg( ArchPipePart Run, Vector3 Direction );
public static List<ArchPipeFitting> Resolve( ArchPlan plan, ArchPipePart part ) {
return part.Nodes
.Where( node => node.Id != 0 )
.Select( node => At( plan, node.Id ) )
.Where( fitting => fitting is not null )
.DistinctBy( fitting => fitting.NodeId )
.ToList();
}
public static ArchPipeFitting At( ArchPlan plan, int nodeId ) {
var legs = new List<Leg>();
var position = Vector3.Zero;
var found = false;
foreach ( var run in ArchPipe.All( plan ) ) {
for ( var index = 0; index < run.Nodes.Count; index++ ) {
if ( run.Nodes[index].Id != nodeId ) {
continue;
}
position = run.Nodes[index].Position;
found = true;
if ( index > 0 ) {
legs.Add( new Leg( run, (run.Nodes[index - 1].Position - position).Normal ) );
}
if ( index < run.Nodes.Count - 1 ) {
legs.Add( new Leg( run, (run.Nodes[index + 1].Position - position).Normal ) );
}
}
}
if ( !found || legs.Count == 0 ) {
return null;
}
var runs = legs.Select( leg => leg.Run ).Distinct().ToList();
var diameters = runs.Select( run => run.Diameter ).Distinct().Count();
var kind = legs.Count switch {
1 => ArchPipeFittingKind.Flange,
>= 3 => ArchPipeFittingKind.Tee,
_ when diameters > 1 => ArchPipeFittingKind.Reducer,
_ when Vector3.Dot( legs[0].Direction, legs[1].Direction ) > -0.999f => ArchPipeFittingKind.Elbow,
_ => ArchPipeFittingKind.Coupling
};
return new ArchPipeFitting {
NodeId = nodeId,
Position = position,
Kind = kind,
Runs = runs.Select( run => run.Id ).ToList()
};
}
}