Code/PolygonMeshBuilder.Validate.cs
using System;
using System.Collections.Generic;
namespace Sandbox.Polygons;
partial class PolygonMeshBuilder
{
[ThreadStatic]
private static List<int> Validate_EdgeList;
private void Validate()
{
if ( _validated )
{
return;
}
// Check active edge loops:
// * Referenced edges must also be active
// * Make sure references are correct in both directions
// * Edges can't reference themselves
foreach ( var edgeIndex in _activeEdges )
{
ref var edge = ref _allEdges[edgeIndex];
if ( !_activeEdges.Contains( edge.NextEdge ) )
{
throw InvalidPolygonException();
}
if ( !_activeEdges.Contains( edge.PrevEdge ) )
{
throw InvalidPolygonException();
}
if ( edge.NextEdge == edge.Index )
{
throw InvalidPolygonException();
}
ref var next = ref _allEdges[edge.NextEdge];
if ( next.PrevEdge != edge.Index )
{
throw InvalidPolygonException();
}
}
// Check for intersecting edges
// TODO: Bentley–Ottmann?
Validate_EdgeList ??= new List<int>();
Validate_EdgeList.Clear();
Validate_EdgeList.AddRange( _activeEdges );
for ( var i = 0; i < Validate_EdgeList.Count; ++i )
{
ref var edgeA0 = ref _allEdges[Validate_EdgeList[i]];
ref var edgeA1 = ref _allEdges[edgeA0.NextEdge];
var a0 = edgeA0.Origin;
var a1 = edgeA1.Origin;
var minA = Vector2.Min( a0 ,a1 );
var maxA = Vector2.Max( a0, a1 );
for ( var j = i + 1; j < Validate_EdgeList.Count; ++j )
{
ref var edgeB0 = ref _allEdges[Validate_EdgeList[j]];
if ( edgeA0.NextEdge == edgeB0.Index || edgeA0.PrevEdge == edgeB0.Index )
{
continue;
}
ref var edgeB1 = ref _allEdges[edgeB0.NextEdge];
var b0 = edgeA0.Origin;
var b1 = edgeA1.Origin;
var minB = Vector2.Min( b0, b1 );
var maxB = Vector2.Max( b0, b1 );
if ( minA.x >= maxB.x || minA.y >= maxB.y || minB.x >= maxA.x || minB.y >= maxA.y )
{
continue;
}
if ( Helpers.LineSegmentsIntersect( a0, a1, b0, b1 ) )
{
throw InvalidPolygonException();
}
}
}
_validated = true;
}
private static Exception InvalidPolygonException()
{
return new Exception( "Invalid polygon" );
}
}