Exemple #1
0
    void TestDisturbances(Navmesh *lct)
    {
        _disturbances.Clear();

        var e = lct->GetEdgeEnumerator(true);

        while (e.MoveNext())
        {
            if (e.Current->Constrained)
            {
                continue;
            }

            lct->CheckEdgeForDisturbances(e.Current, _disturbances);

            for (int j = 0; j < _disturbances.Length; j++)
            {
                var p = _disturbances[j].Vertex->Point;
                var o = _disturbances[j].Edge->Org->Point;
                var d = _disturbances[j].Edge->Dest->Point;
                Debug.Log($"Edge {o} => {d} disturbed by {p}");
            }

            Assert.IsTrue(_disturbances.Length == 0);
        }
    }
Exemple #2
0
    void IsCdt(Navmesh *lct, int constraint = -1, int vertex = -1)
    {
        var e = lct->GetEdgeEnumerator(true);

        while (e.MoveNext())
        {
            if (e.Current->Constrained)
            {
                continue;
            }

            var o = e.Current->Org->Point;
            var d = e.Current->Dest->Point;
            if (Math.Contains(o, -lct->Extent, lct->Extent) && Math.Contains(d, -lct->Extent, lct->Extent))
            {
                var on = e.Current->ONext->Dest->Point;
                var dn = e.Current->DNext->Org->Point;
                if (Math.CircumcircleContains(o, d, on, dn) && Math.Ccw(dn, d, on) && Math.Ccw(on, o, dn))
                {
                    Debug.Log($"delaunay fail, constraint: {constraint}, vertex:{vertex}, from: {o}, to: {d}");
                    throw new Exception();
                }
            }
        }
    }
Exemple #3
0
 public LctValidator(Navmesh *navmesh, Allocator allocator)
 {
     _triangles           = new HashSet <int>(1024, allocator);
     _removedTriangles    = new NativeList <int>(1024, allocator);
     _closed              = new HashSet <IntPtr>(1024, allocator);
     _disturbances        = new NativeList <Disturbance>(allocator);
     _unconstrained       = new NativeList <IntPtr>(allocator);
     _clearanceCalculated = new NativeArray <int>(1, allocator);
     _previousTriangles   = default;
     InitTriangles(navmesh);
 }
Exemple #4
0
    void InitTriangles(Navmesh *lct)
    {
        var e = lct->GetEdgeEnumerator(true);

        while (e.MoveNext())
        {
            if (!Math.Contains(e.Current->Org->Point, -lct->Extent, lct->Extent))
            {
                continue;
            }

            _triangles.TryAdd(e.Current->TriangleId);
            _closed.TryAdd((IntPtr)e.Current);
            _closed.TryAdd((IntPtr)e.Current->LNext);
            _closed.TryAdd((IntPtr)e.Current->LPrev);
        }
    }
Exemple #5
0
 public void Validate(Navmesh *navmesh, Profile profile)
 {
     if (profile.CDT)
     {
         IsCdt(navmesh);
     }
     if (profile.LCT)
     {
         TestDisturbances(navmesh);
     }
     if (profile.Triangles)
     {
         TestTriangleIds(navmesh);
     }
     if (profile.Clearance)
     {
         _clearanceCalculated[0] += TestLocalClearance(navmesh);
     }
 }
Exemple #6
0
    int TestLocalClearance(Navmesh *lct)
    {
        var clearanceCalculated = 0;

        var e = lct->GetEdgeEnumerator(true);

        while (e.MoveNext())
        {
            if (e.Current->Constrained)
            {
                continue;
            }

            var edge = e.Current;
            var b    = edge->Org->Point;
            var c    = edge->Dest->Point;

            if (!Math.Contains(b, -lct->Extent, lct->Extent) || !Math.Contains(c, -lct->Extent, lct->Extent))
            {
                continue;
            }

            var entrance = edge->ONext;
            if (!entrance->Constrained)
            {
                var clearance = GetLocalClearance(entrance->Dest->Point, b, c, edge, false);
                if (edge->ClearanceRight == -1)
                {
                    edge->ClearanceRight = clearance;
                    ++clearanceCalculated;
                }
                else if (!Approx(edge->ClearanceRight, clearance, 1e-6f))
                {
                    var a   = entrance->Dest->Point;
                    var was = edge->ClearanceRight;
                    Debug.Log($"TestLocalClearance failed. a: {a}, b: {b}, c: {c}, rhs, was: {was}, is: {clearance}");
                    Assert.IsTrue(false);
                }
            }

            entrance = edge->OPrev;
            if (!entrance->Constrained)
            {
                var clearance = GetLocalClearance(entrance->Dest->Point, b, c, edge, true);
                if (edge->ClearanceLeft == -1)
                {
                    edge->ClearanceLeft = clearance;
                    ++clearanceCalculated;
                }
                else if (!Approx(edge->ClearanceLeft, clearance, 1e-6f))
                {
                    var a   = entrance->Dest->Point;
                    var was = edge->ClearanceLeft;
                    Debug.Log($"TestLocalClearance failed. a: {a}, b: {b}, c: {c}, lhs, was: {was}, is: {clearance}");
                    Assert.IsTrue(false);
                }
            }
        }

        return(clearanceCalculated);
    }
Exemple #7
0
    void TestTriangleIds(Navmesh *lct)
    {
        if (_previousTriangles.IsCreated)
        {
            _previousTriangles.Dispose();
        }

        _previousTriangles = _triangles.ToNativeArray();
        _triangles.Clear();
        _closed.Clear();
        _removedTriangles.Clear();

        var e = lct->GetEdgeEnumerator(true);

        while (e.MoveNext())
        {
            if (!Math.Contains(e.Current->Org->Point, -lct->Extent, lct->Extent))
            {
                continue;
            }

            if (_closed.Contains((IntPtr)e.Current))
            {
                continue;
            }

            if (e.Current->TriangleId == 0)
            {
                Debug.Log("unset Triangle Id");
                Assert.IsTrue(false);
            }

            if (!_triangles.TryAdd(e.Current->TriangleId))
            {
                Debug.Log("duplicate Triangle Id");
                Assert.IsTrue(false);
            }

            if (e.Current->TriangleId != e.Current->LNext->TriangleId || e.Current->TriangleId != e.Current->LPrev->TriangleId)
            {
                Debug.Log("inconsistent triangle ids");
                Assert.IsTrue(false);
            }

            _closed.TryAdd((IntPtr)e.Current);
            _closed.TryAdd((IntPtr)e.Current->LNext);
            _closed.TryAdd((IntPtr)e.Current->LPrev);
        }

        for (int i = 0; i < _previousTriangles.Length; i++)
        {
            if (!_triangles.Contains(_previousTriangles[i]))
            {
                _removedTriangles.Add(_previousTriangles[i]);
            }
        }

        var destroyed  = new HashSet <int>(64, Allocator.Temp);
        var enumerator = lct->DestroyedTriangles.GetEnumerator();

        while (enumerator.MoveNext())
        {
            destroyed.TryAdd(enumerator.Current);
        }

        for (int i = 0; i < _removedTriangles.Length; i++)
        {
            var id = _removedTriangles[i];
            if (!destroyed.Remove(id))
            {
                Debug.Log($"Destroyed triangle {id} not reported");
                Assert.IsTrue(false);
            }
        }

        var remaining = destroyed.GetEnumerator();

        while (remaining.MoveNext())
        {
            if (_triangles.Contains(remaining.Current))
            {
                Debug.Log($"Triangle {remaining.Current} incorrectly reported as destroyed");
                Assert.IsTrue(false);
            }
        }

        destroyed.Dispose();
    }