Compare commits

..

No commits in common. "master" and "main" have entirely different histories.
master ... main

44 changed files with 156 additions and 582 deletions

View File

@ -1,8 +0,0 @@
{
"name": "rnd/dotrecastnetsim",
"description": "DotRecast",
"homepage": "https://git.bit5.ru/rnd/DotRecastNetSim.git",
"require": {
"php": ">=7.4"
}
}

View File

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
namespace DotRecast.Core.Buffers
{
// This implementation is thread unsafe
public class RcObjectPool<T> where T : class
{
private readonly Queue<T> _items = new Queue<T>();
private readonly Func<T> _createFunc;
public RcObjectPool(Func<T> createFunc)
{
_createFunc = createFunc;
}
public T Get()
{
if (_items.TryDequeue(out var result))
return result;
return _createFunc();
}
public void Return(T obj)
{
_items.Enqueue(obj);
}
}
}

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
@ -13,7 +13,7 @@ namespace DotRecast.Core.Buffers
}
}
public struct RcRentedArray<T> : IDisposable
public class RcRentedArray<T> : IDisposable
{
private ArrayPool<T> _owner;
private T[] _array;
@ -43,11 +43,6 @@ namespace DotRecast.Core.Buffers
return _array;
}
public Span<T> AsSpan()
{
return new Span<T>(_array, 0, Length);
}
public void Dispose()
{

View File

@ -45,11 +45,5 @@ namespace DotRecast.Core.Collections
(list[k], list[n]) = (list[n], list[k]);
}
}
public static void AddRange<T>(this IList<T> list, Span<T> span)
{
foreach (var i in span)
list.Add(i);
}
}
}

View File

@ -27,12 +27,12 @@ namespace DotRecast.Core.Collections
{
private bool _dirty;
private readonly List<T> _items;
private readonly Comparison<T> _comparison;
private readonly Comparer<T> _comparer;
public RcSortedQueue(Comparison<T> comp)
{
_items = new List<T>();
_comparison = (x, y) => comp(x, y) * -1;
_comparer = Comparer<T>.Create((x, y) => comp.Invoke(x, y) * -1);
}
public int Count()
@ -55,7 +55,7 @@ namespace DotRecast.Core.Collections
{
if (_dirty)
{
_items.Sort(_comparison); // reverse
_items.Sort(_comparer); // reverse
_dirty = false;
}
}
@ -88,7 +88,7 @@ namespace DotRecast.Core.Collections
return false;
//int idx = _items.BinarySearch(item, _comparer); // don't use this! Because reference types can be reused externally.
int idx = _items.LastIndexOf(item);
int idx = _items.FindLastIndex(x => item.Equals(x));
if (0 > idx)
return false;

View File

@ -1,14 +0,0 @@
{
"name": "DotRecast.Core",
"rootNamespace": "DotRecast.Core",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": true
}

View File

@ -205,7 +205,7 @@ namespace DotRecast.Core.Numerics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Dist2DSqr(RcVec3f p, Span<float> verts, int i)
public static float Dist2DSqr(RcVec3f p, float[] verts, int i)
{
float dx = verts[i] - p.X;
float dz = verts[i + 2] - p.Z;

View File

@ -1,17 +0,0 @@
{
"name": "DotRecast.Detour.Crowd",
"rootNamespace": "DotRecast.Detour.Crowd",
"references": [
"DotRecast.Core",
"DotRecast.Detour"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": true
}

View File

@ -22,7 +22,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using DotRecast.Core;
using DotRecast.Core.Buffers;
using DotRecast.Core.Collections;
using DotRecast.Core.Numerics;
@ -130,7 +129,7 @@ namespace DotRecast.Detour.Crowd
private readonly DtObstacleAvoidanceParams[] _obstacleQueryParams;
private readonly DtObstacleAvoidanceQuery _obstacleQuery;
private readonly DtProximityGrid _grid;
private DtProximityGrid _grid;
private int _maxPathResult;
private readonly RcVec3f _agentPlacementHalfExtents;
@ -175,7 +174,6 @@ namespace DotRecast.Detour.Crowd
_agentIdx = new RcAtomicInteger(0);
_agents = new Dictionary<int, DtCrowdAgent>();
_activeAgents = new List<DtCrowdAgent>();
_grid = new DtProximityGrid(_config.maxAgentRadius * 3);
// The navQuery is mostly used for local searches, no need for large node pool.
SetNavMesh(nav);
@ -566,18 +564,14 @@ namespace DotRecast.Detour.Crowd
}
}
private readonly RcSortedQueue<DtCrowdAgent> UpdateMoveRequest_queue = new RcSortedQueue<DtCrowdAgent>((a1, a2) => a2.targetReplanTime.CompareTo(a1.targetReplanTime));
private readonly List<long> UpdateMoveRequest_reqPath = new List<long>();
private void UpdateMoveRequest(IList<DtCrowdAgent> agents, float dt)
{
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.UpdateMoveRequest);
RcSortedQueue<DtCrowdAgent> queue = UpdateMoveRequest_queue;
queue.Clear();
RcSortedQueue<DtCrowdAgent> queue = new RcSortedQueue<DtCrowdAgent>((a1, a2) => a2.targetReplanTime.CompareTo(a1.targetReplanTime));
// Fire off new requests.
List<long> reqPath = UpdateMoveRequest_reqPath;
reqPath.Clear();
List<long> reqPath = new List<long>();
for (var i = 0; i < agents.Count; i++)
{
var ag = agents[i];
@ -870,7 +864,7 @@ namespace DotRecast.Detour.Crowd
{
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.BuildProximityGrid);
_grid.Clear();
_grid = new DtProximityGrid(_config.maxAgentRadius * 3);
for (var i = 0; i < agents.Count; i++)
{
@ -1057,7 +1051,7 @@ namespace DotRecast.Detour.Crowd
}
// Check
float triggerRadius = ag.option.radius * 0.25f;//todo make parameterizable
float triggerRadius = ag.option.radius * 2.25f;
if (ag.OverOffmeshConnection(triggerRadius))
{
// Prepare to off-mesh connection.
@ -1206,9 +1200,6 @@ namespace DotRecast.Detour.Crowd
for (int j = 0; j < ag.nneis; ++j)
{
DtCrowdAgent nei = ag.neis[j].agent;
if(!nei.option.contributeObstacleAvoidance || nei.option.obstacleAvoidanceWeight < ag.option.obstacleAvoidanceWeight)
continue;
_obstacleQuery.AddCircle(nei.npos, nei.option.radius, nei.vel, nei.dvel);
}

View File

@ -45,9 +45,6 @@ namespace DotRecast.Detour.Crowd
/// [Limits: 0 <= value < #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]
public int obstacleAvoidanceType;
public bool contributeObstacleAvoidance;
public float obstacleAvoidanceWeight;
/// The index of the query filter used by this agent.
public int queryFilterType;

View File

@ -33,7 +33,7 @@ namespace DotRecast.Detour.Crowd
private RcVec3f m_pos;
private RcVec3f m_target;
private List<long> m_path = new List<long>();
private List<long> m_path;
private int m_npath;
private int m_maxPath;
@ -89,8 +89,7 @@ namespace DotRecast.Detour.Crowd
/// @return True if the initialization succeeded.
public bool Init(int maxPath)
{
if (m_path.Capacity < maxPath)
m_path.Capacity = maxPath;
m_path = new List<long>(maxPath);
m_npath = 0;
m_maxPath = maxPath;
return true;
@ -219,7 +218,7 @@ namespace DotRecast.Detour.Crowd
{
if (res.Count > 1 && t > 0.99f)
{
m_npath = DtPathUtils.MergeCorridorStartShortcut(m_path, m_npath, m_maxPath, res, res.Count);
m_npath = DtPathUtils.MergeCorridorStartShortcut(ref m_path, m_npath, m_maxPath, res, res.Count);
}
}
}
@ -251,7 +250,7 @@ namespace DotRecast.Detour.Crowd
if (status.Succeeded() && res.Count > 0)
{
m_npath = DtPathUtils.MergeCorridorStartShortcut(m_path, m_npath, m_maxPath, res, res.Count);
m_npath = DtPathUtils.MergeCorridorStartShortcut(ref m_path, m_npath, m_maxPath, res, res.Count);
return true;
}
@ -277,7 +276,7 @@ namespace DotRecast.Detour.Crowd
}
// Prune path
m_path.RemoveRange(0, npos);
m_path = m_path.GetRange(npos, m_npath - npos);
m_npath -= npos;
refs[0] = prevRef;
@ -323,7 +322,7 @@ namespace DotRecast.Detour.Crowd
var status = navquery.MoveAlongSurface(m_path[0], m_pos, npos, filter, out var result, visited, out var nvisited, MAX_VISITED);
if (status.Succeeded())
{
m_npath = DtPathUtils.MergeCorridorStartMoved(m_path, m_npath, m_maxPath, visited, nvisited);
m_npath = DtPathUtils.MergeCorridorStartMoved(ref m_path, m_npath, m_maxPath, visited, nvisited);
// Adjust the position to stay on top of the navmesh.
m_pos = result;
@ -367,7 +366,7 @@ namespace DotRecast.Detour.Crowd
var status = navquery.MoveAlongSurface(m_path[^1], m_target, npos, filter, out var result, visited, out nvisited, MAX_VISITED);
if (status.Succeeded())
{
m_npath = DtPathUtils.MergeCorridorEndMoved(m_path, m_npath, m_maxPath, visited, nvisited);
m_npath = DtPathUtils.MergeCorridorEndMoved(ref m_path, m_npath, m_maxPath, visited, nvisited);
// TODO: should we do that?
// Adjust the position to stay on top of the navmesh.
@ -395,11 +394,7 @@ namespace DotRecast.Detour.Crowd
public void SetCorridor(RcVec3f target, List<long> path)
{
m_target = target;
if(path != m_path)
{
m_path.Clear();
m_path.AddRange(path);
}
m_path = new List<long>(path);
m_npath = path.Count;
}
@ -449,7 +444,7 @@ namespace DotRecast.Detour.Crowd
else if (n < m_npath)
{
// The path is partially usable.
m_path.RemoveRange(n, m_path.Count - n);
m_path = m_path.GetRange(0, n);
m_npath = n;
}

View File

@ -22,7 +22,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using DotRecast.Core.Buffers;
namespace DotRecast.Detour.Crowd
{
@ -31,14 +30,12 @@ namespace DotRecast.Detour.Crowd
private readonly float _cellSize;
private readonly float _invCellSize;
private readonly Dictionary<long, List<DtCrowdAgent>> _items;
private readonly RcObjectPool<List<DtCrowdAgent>> _listPool;
public DtProximityGrid(float cellSize)
{
_cellSize = cellSize;
_invCellSize = 1.0f / cellSize;
_items = new Dictionary<long, List<DtCrowdAgent>>();
_listPool = new RcObjectPool<List<DtCrowdAgent>>(() => new List<DtCrowdAgent>());
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -60,8 +57,6 @@ namespace DotRecast.Detour.Crowd
public void Clear()
{
foreach (var pair in _items)
_listPool.Return(pair.Value);
_items.Clear();
}
@ -79,8 +74,7 @@ namespace DotRecast.Detour.Crowd
long key = CombineKey(x, y);
if (!_items.TryGetValue(key, out var ids))
{
ids = _listPool.Get();
ids.Clear();
ids = new List<DtCrowdAgent>();
_items.Add(key, ids);
}

View File

@ -1,18 +0,0 @@
{
"name": "DotRecast.Detour.Dynamic",
"rootNamespace": "DotRecast.Detour.Dynamic",
"references": [
"DotRecast.Detour",
"DotRecast.Recast",
"DotRecast.Core"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": true
}

View File

@ -1,18 +0,0 @@
{
"name": "DotRecast.Detour.Extras",
"rootNamespace": "DotRecast.Detour.Extras",
"references": [
"DotRecast.Core",
"DotRecast.Detour",
"DotRecast.Recast"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": true
}

View File

@ -52,12 +52,25 @@ namespace DotRecast.Detour.Extras.Jumplink
RcVec3f halfExtents = new RcVec3f { X = cs, Y = heightRange, Z = cs };
float maxHeight = pt.Y + heightRange;
var query = new DtHeightSamplePolyQuery(navMeshQuery, pt, pt.Y, maxHeight);
navMeshQuery.QueryPolygons(pt, halfExtents, DtQueryNoOpFilter.Shared, ref query);
RcAtomicBoolean found = new RcAtomicBoolean();
RcAtomicFloat minHeight = new RcAtomicFloat(pt.Y);
if (query.Found)
navMeshQuery.QueryPolygons(pt, halfExtents, DtQueryNoOpFilter.Shared, new DtCallbackPolyQuery((tile, poly, refs) =>
{
height = query.MinHeight;
var status = navMeshQuery.GetPolyHeight(refs, pt, out var h);
if (status.Succeeded())
{
if (h > minHeight.Get() && h < maxHeight)
{
minHeight.Exchange(h);
found.Set(true);
}
}
}));
if (found.Get())
{
height = minHeight.Get();
return true;
}

View File

@ -1,18 +0,0 @@
{
"name": "DotRecast.Detour.TileCache",
"rootNamespace": "DotRecast.Detour.TileCache",
"references": [
"DotRecast.Core",
"DotRecast.Detour",
"DotRecast.Recast"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": true
}

View File

@ -1,16 +0,0 @@
{
"name": "DotRecast.Detour",
"rootNamespace": "DotRecast.Detour",
"references": [
"DotRecast.Core"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": true
}

View File

@ -2,7 +2,7 @@ using System;
namespace DotRecast.Detour
{
public struct DtCallbackPolyQuery : IDtPolyQuery
public class DtCallbackPolyQuery : IDtPolyQuery
{
private readonly Action<DtMeshTile, DtPoly, long> _callback;
@ -11,7 +11,7 @@ namespace DotRecast.Detour
_callback = callback;
}
public void Process(DtMeshTile tile, Span<DtPoly> poly, Span<long> refs, int count)
public void Process(DtMeshTile tile, DtPoly[] poly, Span<long> refs, int count)
{
for (int i = 0; i < count; ++i)
{

View File

@ -26,7 +26,7 @@ namespace DotRecast.Detour
return m_overflow;
}
public void Process(DtMeshTile tile, Span<DtPoly> poly, Span<long> refs, int count)
public void Process(DtMeshTile tile, DtPoly[] poly, Span<long> refs, int count)
{
int numLeft = m_maxPolys - m_numCollected;
int toCopy = count;

View File

@ -27,7 +27,7 @@ namespace DotRecast.Detour
{
private const float EPSILON = 0.0001f;
public static Span<float> Intersect(Span<float> p, Span<float> q, Span<float> buffer)
public static float[] Intersect(Span<float> p, Span<float> q)
{
int n = p.Length / 3;
int m = q.Length / 3;
@ -95,7 +95,7 @@ namespace DotRecast.Detour
/* Special case: A & B parallel and separated. */
if (parallel && aHB < 0f && bHA < 0f)
{
return Span<float>.Empty;
return null;
}
/* Special case: A & B collinear. */
else if (parallel && MathF.Abs(aHB) < EPSILON && MathF.Abs(bHA) < EPSILON)
@ -168,9 +168,8 @@ namespace DotRecast.Detour
return null;
}
Span<float> result = buffer.Slice(0, ii);
inters.Slice(0, ii).CopyTo(result);
return result;
float[] copied = inters.Slice(0, ii).ToArray();
return copied;
}
private static int AddVertex(Span<float> inters, int ii, RcVec3f p)

View File

@ -3,7 +3,7 @@ using DotRecast.Core.Numerics;
namespace DotRecast.Detour
{
public struct DtFindNearestPolyQuery : IDtPolyQuery
public class DtFindNearestPolyQuery : IDtPolyQuery
{
private readonly DtNavMeshQuery _query;
private readonly RcVec3f _center;
@ -18,12 +18,9 @@ namespace DotRecast.Detour
_center = center;
_nearestDistanceSqr = float.MaxValue;
_nearestPoint = center;
_nearestRef = default;
_overPoly = default;
}
public void Process(DtMeshTile tile, Span<DtPoly> poly, Span<long> refs, int count)
public void Process(DtMeshTile tile, DtPoly[] poly, Span<long> refs, int count)
{
for (int i = 0; i < count; ++i)
{

View File

@ -1,45 +0,0 @@
using System;
using DotRecast.Core;
using DotRecast.Core.Numerics;
namespace DotRecast.Detour
{
public struct DtHeightSamplePolyQuery : IDtPolyQuery
{
private readonly DtNavMeshQuery _navMeshQuery;
private readonly RcVec3f _pt;
private readonly float _maxHeight;
public float MinHeight { get; private set; }
public bool Found { get; private set; }
public DtHeightSamplePolyQuery(DtNavMeshQuery navMeshQuery, RcVec3f pt, float minHeight, float maxHeight)
{
_navMeshQuery = navMeshQuery;
_pt = pt;
MinHeight = minHeight;
_maxHeight = maxHeight;
Found = default;
}
public void Process(DtMeshTile tile, Span<DtPoly> poly, Span<long> refs, int count)
{
for (int i = 0; i < count; i++)
{
ProcessSingle(refs[i]);
}
}
private void ProcessSingle(long refs)
{
var status = _navMeshQuery.GetPolyHeight(refs, _pt, out var h);
if (!status.Succeeded())
return;
if (!(h > MinHeight) || !(h < _maxHeight))
return;
MinHeight = h;
Found = true;
}
}
}

View File

@ -18,11 +18,8 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
using System;
namespace DotRecast.Detour
{
[Serializable]
public class DtMeshData
{
public DtMeshHeader header; //< The tile header.

View File

@ -18,13 +18,11 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using DotRecast.Core.Numerics;
namespace DotRecast.Detour
{
/** Provides high level information related to a dtMeshTile object. */
[Serializable]
public class DtMeshHeader
{
/** Tile magic number. (Used to identify the data format.) */

View File

@ -1365,11 +1365,6 @@ namespace DotRecast.Detour
}
public int GetTilesAt(int x, int y, DtMeshTile[] tiles, int maxTiles)
{
return GetTilesAt(x, y, (Span<DtMeshTile>)tiles, maxTiles);
}
public int GetTilesAt(int x, int y, Span<DtMeshTile> tiles, int maxTiles)
{
int n = 0;

View File

@ -18,7 +18,6 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using DotRecast.Core.Numerics;
namespace DotRecast.Detour

View File

@ -21,9 +21,7 @@ freely, subject to the following restrictions:
using System;
using System.Collections.Generic;
using DotRecast.Core;
using DotRecast.Core.Buffers;
using DotRecast.Core.Numerics;
using CollectionExtensions = DotRecast.Core.Collections.CollectionExtensions;
namespace DotRecast.Detour
{
@ -34,8 +32,6 @@ namespace DotRecast.Detour
/// @ingroup detour
public class DtNavMeshQuery
{
public const int MAX_PATH_LENGTH = 256;
protected readonly DtNavMesh m_nav; //< Pointer to navmesh data.
protected DtQueryData m_query; //< Sliced query state.
@ -233,7 +229,6 @@ namespace DotRecast.Detour
IDtQueryFilter filter, IRcRand frand, IDtPolygonByCircleConstraint constraint,
out long randomRef, out RcVec3f randomPt)
{
const int MAX_VERT_BUFFER_SIZE = 128;
randomRef = startRef;
randomPt = centerPos;
@ -267,13 +262,9 @@ namespace DotRecast.Detour
float radiusSqr = maxRadius * maxRadius;
float areaSum = 0.0f;
using RcRentedArray<float> polyVertsBuffer = RcRentedArray.Rent<float>(MAX_VERT_BUFFER_SIZE);
using RcRentedArray<float> randomPolyVertsBuffer = RcRentedArray.Rent<float>(MAX_VERT_BUFFER_SIZE);
using RcRentedArray<float> constrainedVertsBuffer = RcRentedArray.Rent<float>(MAX_VERT_BUFFER_SIZE);
DtPoly randomPoly = null;
long randomPolyRef = 0;
Span<float> randomPolyVerts = Span<float>.Empty;
float[] randomPolyVerts = null;
while (!m_openList.IsEmpty())
{
@ -291,14 +282,14 @@ namespace DotRecast.Detour
{
// Calc area of the polygon.
float polyArea = 0.0f;
Span<float> polyVerts = polyVertsBuffer.AsSpan().Slice(0, bestPoly.vertCount * 3);
float[] polyVerts = new float[bestPoly.vertCount * 3];
for (int j = 0; j < bestPoly.vertCount; ++j)
{
RcSpans.Copy(bestTile.data.verts, bestPoly.verts[j] * 3, polyVerts, j * 3, 3);
RcArrays.Copy(bestTile.data.verts, bestPoly.verts[j] * 3, polyVerts, j * 3, 3);
}
Span<float> constrainedVerts = constraint.Apply(polyVerts, centerPos, maxRadius, constrainedVertsBuffer.AsSpan());
if (!constrainedVerts.IsEmpty)
float[] constrainedVerts = constraint.Apply(polyVerts, centerPos, maxRadius);
if (constrainedVerts != null)
{
int vertCount = constrainedVerts.Length / 3;
for (int j = 2; j < vertCount; ++j)
@ -316,8 +307,7 @@ namespace DotRecast.Detour
{
randomPoly = bestPoly;
randomPolyRef = bestRef;
randomPolyVerts = randomPolyVertsBuffer.AsSpan().Slice(0, constrainedVerts.Length);
constrainedVerts.CopyTo(randomPolyVerts);
randomPolyVerts = constrainedVerts;
}
}
}
@ -589,7 +579,7 @@ namespace DotRecast.Detour
// Get nearby polygons from proximity grid.
DtFindNearestPolyQuery query = new DtFindNearestPolyQuery(this, center);
DtStatus status = QueryPolygons(center, halfExtents, filter, ref query);
DtStatus status = QueryPolygons(center, halfExtents, filter, query);
if (status.Failed())
{
return status;
@ -603,13 +593,11 @@ namespace DotRecast.Detour
}
/// Queries polygons within a tile.
protected void QueryPolygonsInTile<TQuery>(DtMeshTile tile, RcVec3f qmin, RcVec3f qmax, IDtQueryFilter filter, ref TQuery query)
where TQuery : IDtPolyQuery
protected void QueryPolygonsInTile(DtMeshTile tile, RcVec3f qmin, RcVec3f qmax, IDtQueryFilter filter, IDtPolyQuery query)
{
const int batchSize = 32;
Span<long> polyRefs = stackalloc long[batchSize];
using RcRentedArray<DtPoly> polysRent = RcRentedArray.Rent<DtPoly>(batchSize);
Span<DtPoly> polys = polysRent.AsSpan();
DtPoly[] polys = new DtPoly[batchSize];
int n = 0;
if (tile.data.bvTree != null)
@ -760,7 +748,7 @@ namespace DotRecast.Detour
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
DtCollectPolysQuery collector = new DtCollectPolysQuery(polys, maxPolys);
DtStatus status = QueryPolygons(center, halfExtents, filter, ref collector);
DtStatus status = QueryPolygons(center, halfExtents, filter, collector);
if (status.Failed())
return status;
@ -782,8 +770,7 @@ namespace DotRecast.Detour
/// @param[in] halfExtents The search distance along each axis. [(x, y, z)]
/// @param[in] filter The polygon filter to apply to the query.
/// @param[in] query The query. Polygons found will be batched together and passed to this query.
public DtStatus QueryPolygons<TQuery>(RcVec3f center, RcVec3f halfExtents, IDtQueryFilter filter, ref TQuery query)
where TQuery : IDtPolyQuery
public DtStatus QueryPolygons(RcVec3f center, RcVec3f halfExtents, IDtQueryFilter filter, IDtPolyQuery query)
{
if (!center.IsFinite() || !halfExtents.IsFinite() || null == filter)
{
@ -799,8 +786,7 @@ namespace DotRecast.Detour
m_nav.CalcTileLoc(bmax, out var maxx, out var maxy);
const int MAX_NEIS = 32;
using RcRentedArray<DtMeshTile> neisRent = RcRentedArray.Rent<DtMeshTile>(MAX_NEIS);
Span<DtMeshTile> neis = neisRent.AsSpan();
DtMeshTile[] neis = new DtMeshTile[MAX_NEIS];
for (int y = miny; y <= maxy; ++y)
{
@ -809,7 +795,7 @@ namespace DotRecast.Detour
int nneis = m_nav.GetTilesAt(x, y, neis, MAX_NEIS);
for (int j = 0; j < nneis; ++j)
{
QueryPolygonsInTile(neis[j], bmin, bmax, filter, ref query);
QueryPolygonsInTile(neis[j], bmin, bmax, filter, query);
}
}
}
@ -891,8 +877,7 @@ namespace DotRecast.Detour
float lastBestNodeCost = startNode.total;
DtRaycastHit rayHit = new DtRaycastHit();
using var pathRent = RcRentedArray.Rent<long>(MAX_PATH_LENGTH);
rayHit.path = pathRent.AsArray();
rayHit.path = new List<long>();
while (!m_openList.IsEmpty())
{
// Remove node from open list and put it in closed list.
@ -1181,8 +1166,7 @@ namespace DotRecast.Detour
}
var rayHit = new DtRaycastHit();
using var pathRent = RcRentedArray.Rent<long>(MAX_PATH_LENGTH);
rayHit.path = pathRent.AsArray();
rayHit.path = new List<long>();
int iter = 0;
while (iter < maxIter && !m_openList.IsEmpty())
@ -1853,7 +1837,6 @@ namespace DotRecast.Detour
return DtStatus.DT_SUCCESS | (straightPathCount >= maxStraightPath ? DtStatus.DT_BUFFER_TOO_SMALL : DtStatus.DT_STATUS_NOTHING);
}
private readonly Queue<DtNode> MoveAlongSurface_queue = new Queue<DtNode>();
/// @par
///
/// This method is optimized for small delta movement and a small number of
@ -1909,8 +1892,8 @@ namespace DotRecast.Detour
startNode.total = 0;
startNode.id = startRef;
startNode.flags = DtNodeFlags.DT_NODE_CLOSED;
MoveAlongSurface_queue.Clear();
MoveAlongSurface_queue.Enqueue(startNode);
LinkedList<DtNode> stack = new LinkedList<DtNode>();
stack.AddLast(startNode);
RcVec3f bestPos = new RcVec3f();
float bestDist = float.MaxValue;
@ -1926,10 +1909,11 @@ namespace DotRecast.Detour
const int MAX_NEIS = 8;
Span<long> neis = stackalloc long[MAX_NEIS];
while (0 < MoveAlongSurface_queue.Count)
while (0 < stack.Count)
{
// Pop front.
DtNode curNode = MoveAlongSurface_queue.Dequeue();
DtNode curNode = stack.First?.Value;
stack.RemoveFirst();
// Get poly and tile.
// The API input has been checked already, skip checking internal data.
@ -2028,7 +2012,7 @@ namespace DotRecast.Detour
// Mark as the node as visited and push to queue.
neighbourNode.pidx = m_tinyNodePool.GetNodeIdx(curNode);
neighbourNode.flags |= DtNodeFlags.DT_NODE_CLOSED;
MoveAlongSurface_queue.Enqueue(neighbourNode);
stack.AddLast(neighbourNode);
}
}
}
@ -2274,15 +2258,13 @@ namespace DotRecast.Detour
out float t, out RcVec3f hitNormal, ref List<long> path)
{
DtRaycastHit hit = new DtRaycastHit();
using var pathRent = RcRentedArray.Rent<long>(MAX_PATH_LENGTH);
hit.path = pathRent.AsArray();
hit.path = path;
DtStatus status = Raycast(startRef, startPos, endPos, filter, 0, ref hit, 0);
t = hit.t;
hitNormal = hit.hitNormal;
path.Clear();
CollectionExtensions.AddRange(path, new Span<long>(hit.path, 0, hit.pathCount));
path = hit.path;
return status;
}
@ -2348,7 +2330,7 @@ namespace DotRecast.Detour
}
hit.t = 0;
hit.pathCount = 0;
hit.path.Clear();
hit.pathCost = 0;
Span<RcVec3f> verts = stackalloc RcVec3f[m_nav.GetMaxVertsPerPoly() + 1];
@ -2401,7 +2383,7 @@ namespace DotRecast.Detour
}
// Store visited polygons.
hit.AddPathNode(curRef);
hit.path.Add(curRef);
// Ray end is completely inside the polygon.
if (segMax == -1)
@ -2541,7 +2523,7 @@ namespace DotRecast.Detour
// int va = a * 3;
// int vb = b * 3;
float dx = verts[b].X - verts[a].X;
float dz = verts[b].Z - verts[a].Z;
float dz = verts[b].Z - verts[a].X;
hit.hitNormal = RcVec3f.Normalize(new RcVec3f(dz, 0, -dx));
return DtStatus.DT_SUCCESS;
}
@ -2921,7 +2903,6 @@ namespace DotRecast.Detour
return DtStatus.DT_SUCCESS;
}
private readonly Queue<DtNode> FindLocalNeighbourhood_queue = new Queue<DtNode>();
/// @par
///
/// This method is optimized for a small search radius and small number of result
@ -2973,8 +2954,8 @@ namespace DotRecast.Detour
startNode.pidx = 0;
startNode.id = startRef;
startNode.flags = DtNodeFlags.DT_NODE_CLOSED;
FindLocalNeighbourhood_queue.Clear();
FindLocalNeighbourhood_queue.Enqueue(startNode);
LinkedList<DtNode> stack = new LinkedList<DtNode>();
stack.AddLast(startNode);
resultRef.Add(startNode.id);
resultParent.Add(0L);
@ -2984,11 +2965,11 @@ namespace DotRecast.Detour
Span<float> pa = stackalloc float[m_nav.GetMaxVertsPerPoly() * 3];
Span<float> pb = stackalloc float[m_nav.GetMaxVertsPerPoly() * 3];
while (0 < FindLocalNeighbourhood_queue.Count)
while (0 < stack.Count)
{
// Pop front.
DtNode curNode = FindLocalNeighbourhood_queue.Dequeue();
DtNode curNode = stack.First?.Value;
stack.RemoveFirst();
// Get poly and tile.
// The API input has been checked already, skip checking internal data.
@ -3101,7 +3082,7 @@ namespace DotRecast.Detour
resultRef.Add(neighbourRef);
resultParent.Add(curRef);
FindLocalNeighbourhood_queue.Enqueue(neighbourNode);
stack.AddLast(neighbourNode);
}
}

View File

@ -1,4 +1,3 @@
using System;
using DotRecast.Core.Numerics;
namespace DotRecast.Detour
@ -11,11 +10,9 @@ namespace DotRecast.Detour
{
}
public Span<float> Apply(Span<float> polyVerts, RcVec3f circleCenter, float radius, Span<float> resultBuffer)
public float[] Apply(float[] polyVerts, RcVec3f circleCenter, float radius)
{
var result = resultBuffer.Slice(0, polyVerts.Length);
polyVerts.CopyTo(result);
return result;
return polyVerts;
}
}
}

View File

@ -18,10 +18,8 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using DotRecast.Core.Buffers;
namespace DotRecast.Detour
{
@ -29,68 +27,24 @@ namespace DotRecast.Detour
{
private readonly Dictionary<long, List<DtNode>> m_map;
private int m_usedNodesCount;
private List<DtNode[]> m_buckets;
private readonly int m_initialBufferCapacityBase;
private readonly RcObjectPool<List<DtNode>> m_listPool;
private int m_nodeCount;
private readonly List<DtNode> m_nodes;
public DtNodePool(int initialBufferCapacityBase = 6) // initial size 64
public DtNodePool()
{
m_map = new Dictionary<long, List<DtNode>>();
m_listPool = new RcObjectPool<List<DtNode>>(() => new List<DtNode>());
m_buckets = new List<DtNode[]>();
m_initialBufferCapacityBase = initialBufferCapacityBase;
}
private void AddNewBucket()
{
var bucketIndex = m_buckets.Count;
var bucket = new DtNode[1 << (bucketIndex + m_initialBufferCapacityBase)];
m_buckets.Add(bucket);
FillBucket(bucketIndex);
}
private void FillBucket(int bucketIndex)
{
var bucket = m_buckets[bucketIndex];
var startIndex = GetBucketStartIndex(bucketIndex);
for (int i = 0; i < bucket.Length; i++)
{
bucket[i] = new DtNode(startIndex + i);
}
}
private int GetBucketStartIndex(int bucketIndex)
{
return ((1 << (bucketIndex + m_initialBufferCapacityBase)) - 1) ^ ((1 << m_initialBufferCapacityBase) - 1);
}
private DtNode[] EnsureBucket(int bucketIndex)
{
if (m_buckets.Count == bucketIndex)
AddNewBucket();
else if (m_buckets.Count < bucketIndex)
throw new Exception();
return m_buckets[bucketIndex];
}
private int GetBucketIndexByElementIndex(int elementIndex)
{
return DtUtils.Ilog2((elementIndex >> m_initialBufferCapacityBase) + 1);
m_nodes = new List<DtNode>();
}
public void Clear()
{
foreach (var pair in m_map)
m_listPool.Return(pair.Value);
m_map.Clear();
m_usedNodesCount = 0;
m_nodeCount = 0;
}
public int GetNodeCount()
{
return m_usedNodesCount;
return m_nodeCount;
}
public int FindNodes(long id, out List<DtNode> nodes)
@ -130,8 +84,7 @@ namespace DotRecast.Detour
}
else
{
nodes = m_listPool.Get();
nodes.Clear();
nodes = new List<DtNode>();
m_map.Add(id, nodes);
}
@ -140,10 +93,15 @@ namespace DotRecast.Detour
private DtNode Create(long id, int state, List<DtNode> nodes)
{
int i = m_usedNodesCount++;
int bucketIndex = GetBucketIndexByElementIndex(i);
int bucketStartIndex = GetBucketStartIndex(bucketIndex);
var node = EnsureBucket(bucketIndex)[i - bucketStartIndex];
if (m_nodes.Count <= m_nodeCount)
{
var newNode = new DtNode(m_nodeCount);
m_nodes.Add(newNode);
}
int i = m_nodeCount;
m_nodeCount++;
var node = m_nodes[i];
node.pidx = 0;
node.cost = 0;
node.total = 0;
@ -165,16 +123,9 @@ namespace DotRecast.Detour
public DtNode GetNodeAtIdx(int idx)
{
if (idx == 0)
return null;
int bucketIndex = GetBucketIndexByElementIndex(idx - 1);
if (m_buckets.Count <= bucketIndex)
throw new ArgumentOutOfRangeException();
int bucketStartIndex = GetBucketStartIndex(bucketIndex);
var node = EnsureBucket(bucketIndex)[idx - bucketStartIndex - 1];
return node;
return idx != 0
? m_nodes[idx - 1]
: null;
}
public DtNode GetNode(long refs)
@ -184,7 +135,7 @@ namespace DotRecast.Detour
public IEnumerable<DtNode> AsEnumerable()
{
return m_buckets.SelectMany(x => x);
return m_nodes.Take(m_nodeCount);
}
}
}

View File

@ -18,14 +18,12 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using DotRecast.Core.Numerics;
namespace DotRecast.Detour
{
/// Defines an navigation mesh off-mesh connection within a dtMeshTile object.
/// An off-mesh connection is a user defined traversable connection made up to two vertices.
[Serializable]
public class DtOffMeshConnection
{
/// The endpoints of the connection. [(ax, ay, az, bx, by, bz)]

View File

@ -20,10 +20,7 @@ freely, subject to the following restrictions:
using System;
using System.Collections.Generic;
using DotRecast.Core.Buffers;
using DotRecast.Core.Collections;
using DotRecast.Core.Numerics;
using CollectionExtensions = DotRecast.Core.Collections.CollectionExtensions;
namespace DotRecast.Detour
{
@ -151,7 +148,7 @@ namespace DotRecast.Detour
return npath;
}
public static int MergeCorridorStartMoved(List<long> path, int npath, int maxPath, Span<long> visited, int nvisited)
public static int MergeCorridorStartMoved(ref List<long> path, int npath, int maxPath, Span<long> visited, int nvisited)
{
int furthestPath = -1;
int furthestVisited = -1;
@ -183,23 +180,22 @@ namespace DotRecast.Detour
}
// Concatenate paths.
var endIndex = nvisited - 1;
var length1 = endIndex - furthestVisited;
var length2 = npath - furthestPath;
using var result = RcRentedArray.Rent<long>(length1 + length2);
// Adjust beginning of the buffer to include the visited.
List<long> result = new List<long>();
// Store visited
for (int i = 0; i < length1; ++i)
result[i] = visited[endIndex - i];
path.CopyTo(furthestPath, result.AsArray(), length1, length2);
path.Clear();
CollectionExtensions.AddRange(path, result.AsSpan());
return result.Length;
for (int i = nvisited - 1; i > furthestVisited; --i)
{
result.Add(visited[i]);
}
public static int MergeCorridorEndMoved(List<long> path, int npath, int maxPath, Span<long> visited, int nvisited)
result.AddRange(path.GetRange(furthestPath, npath - furthestPath));
path = result;
return result.Count;
}
public static int MergeCorridorEndMoved(ref List<long> path, int npath, int maxPath, Span<long> visited, int nvisited)
{
int furthestPath = -1;
int furthestVisited = -1;
@ -231,18 +227,17 @@ namespace DotRecast.Detour
}
// Concatenate paths.
var length1 = furthestPath;
var length2 = nvisited - furthestVisited;
using var result = RcRentedArray.Rent<long>(length1 + length2);
path.CopyTo(0, result.AsArray(), 0, length1);
visited.Slice(furthestVisited, nvisited - furthestVisited).CopyTo(result.AsSpan().Slice(length1, length2));
path.Clear();
CollectionExtensions.AddRange(path, result.AsSpan());
return path.Count;
List<long> result = path.GetRange(0, furthestPath);
foreach (var v in visited.Slice(furthestVisited, nvisited - furthestVisited))
{
result.Add(v);
}
public static int MergeCorridorStartShortcut(List<long> path, int npath, int maxPath, List<long> visited, int nvisited)
path = result;
return result.Count;
}
public static int MergeCorridorStartShortcut(ref List<long> path, int npath, int maxPath, List<long> visited, int nvisited)
{
int furthestPath = -1;
int furthestVisited = -1;
@ -276,15 +271,11 @@ namespace DotRecast.Detour
// Concatenate paths.
// Adjust beginning of the buffer to include the visited.
var length1 = furthestVisited;
var length2 = npath - furthestPath;
using var result = RcRentedArray.Rent<long>(length1 + length2);
visited.CopyTo(0, result.AsArray(), 0, length1);
path.CopyTo(furthestPath, result.AsArray(), length1, length2);
List<long> result = visited.GetRange(0, furthestVisited);
result.AddRange(path.GetRange(furthestPath, npath - furthestPath));
path.Clear();
CollectionExtensions.AddRange(path, result.AsSpan());
return path.Count;
path = result;
return result.Count;
}
}
}

View File

@ -38,16 +38,9 @@ namespace DotRecast.Detour
public int hitEdgeIndex;
/// Pointer to an array of reference ids of the visited polygons. [opt]
public long[] path;
public int pathCount;
public List<long> path;
/// The cost of the path until hit.
public float pathCost;
public void AddPathNode(long nodeRef)
{
path[pathCount++] = nodeRef;
}
}
}

View File

@ -39,7 +39,8 @@ namespace DotRecast.Detour
}
}
public Span<float> Apply(Span<float> verts, RcVec3f center, float radius, Span<float> resultBuffer)
public float[] Apply(float[] verts, RcVec3f center, float radius)
{
float radiusSqr = radius * radius;
int outsideVertex = -1;
@ -55,30 +56,19 @@ namespace DotRecast.Detour
if (outsideVertex == -1)
{
// polygon inside circle
var result = resultBuffer.Slice(0, verts.Length);
verts.CopyTo(result);
return result;
return verts;
}
Span<float> qCircle = stackalloc float[UnitCircle.Length];
ScaleCircle(UnitCircle, center, radius, qCircle);
Span<float> intersection = DtConvexConvexIntersections.Intersect(verts, qCircle, resultBuffer);
if (intersection.IsEmpty && DtUtils.PointInPolygon(center, verts, verts.Length / 3))
float[] intersection = DtConvexConvexIntersections.Intersect(verts, qCircle);
if (intersection == null && DtUtils.PointInPolygon(center, verts, verts.Length / 3))
{
// circle inside polygon
var result = resultBuffer.Slice(0, qCircle.Length);
qCircle.CopyTo(result);
return result;
return qCircle.ToArray();
}
if(!intersection.IsEmpty)
{
var result = resultBuffer.Slice(0, intersection.Length);
// No need to copy, data is already in buffer
return result;
}
return Span<float>.Empty;
return intersection;
}
}
}

View File

@ -9,6 +9,6 @@ namespace DotRecast.Detour
{
/// Called for each batch of unique polygons touched by the search area in dtNavMeshQuery::queryPolygons.
/// This can be called multiple times for a single query.
void Process(DtMeshTile tile, Span<DtPoly> poly, Span<long> refs, int count);
void Process(DtMeshTile tile, DtPoly[] poly, Span<long> refs, int count);
}
}

View File

@ -24,6 +24,6 @@ namespace DotRecast.Detour
{
public interface IDtPolygonByCircleConstraint
{
Span<float> Apply(Span<float> polyVerts, RcVec3f circleCenter, float radius, Span<float> resultBuffer);
float[] Apply(float[] polyVerts, RcVec3f circleCenter, float radius);
}
}

View File

@ -1,44 +0,0 @@
{
"name": "DotRecast.Recast.Demo",
"rootNamespace": "DotRecast.Recast.Demo",
"references": [
"DotRecast.Core"
],
"includePlatforms": [],
"excludePlatforms": [
"Android",
"Editor",
"EmbeddedLinux",
"GameCoreScarlett",
"GameCoreXboxOne",
"iOS",
"LinuxStandalone64",
"CloudRendering",
"macOSStandalone",
"PS4",
"PS5",
"QNX",
"Stadia",
"Switch",
"tvOS",
"WSA",
"VisionOS",
"WebGL",
"WindowsStandalone32",
"WindowsStandalone64",
"XboxOne"
],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "Select...",
"expression": "",
"define": "USE_RECAST_DEMO"
}
],
"noEngineReferences": true
}

View File

@ -1,22 +0,0 @@
{
"name": "DotRecast.Recast.Toolset",
"rootNamespace": "DotRecast.Recast.Toolset",
"references": [
"DotRecast.Core",
"DotRecast.Recast",
"DotRecast.Detour",
"DotRecast.Detour.Crowd",
"DotRecast.Detour.Dynamic",
"DotRecast.Detour.Extras",
"DotRecast.Detour.TileCache"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": true
}

View File

@ -46,13 +46,13 @@ namespace DotRecast.Recast.Toolset.Geom
if (null != _geom)
{
var offMeshConnections = _geom.GetOffMeshConnections();
option.offMeshConCount = offMeshConnections.Count;
option.offMeshConVerts = new float[option.offMeshConCount * 6];
option.offMeshConRad = new float[option.offMeshConCount];
option.offMeshConDir = new int[option.offMeshConCount];
option.offMeshConAreas = new int[option.offMeshConCount];
option.offMeshConFlags = new int[option.offMeshConCount];
option.offMeshConUserID = new int[option.offMeshConCount];
option.offMeshConCount = offMeshConnections.Count;
for (int i = 0; i < option.offMeshConCount; i++)
{
RcOffMeshConnection offMeshCon = offMeshConnections[i];
@ -65,7 +65,7 @@ namespace DotRecast.Recast.Toolset.Geom
option.offMeshConDir[i] = offMeshCon.bidir ? 1 : 0;
option.offMeshConAreas[i] = offMeshCon.area;
option.offMeshConFlags[i] = offMeshCon.flags;
option.offMeshConUserID[i] = offMeshCon.userId;
// option.offMeshConUserID[i] = offMeshCon.userId;
}
}
}

View File

@ -98,7 +98,7 @@ namespace DotRecast.Recast.Toolset.Tools
iterPos = result;
pathIterPolyCount = DtPathUtils.MergeCorridorStartMoved(pathIterPolys, pathIterPolyCount, MAX_POLYS, visited, nvisited);
pathIterPolyCount = DtPathUtils.MergeCorridorStartMoved(ref pathIterPolys, pathIterPolyCount, MAX_POLYS, visited, nvisited);
pathIterPolyCount = DtPathUtils.FixupShortcuts(ref pathIterPolys, pathIterPolyCount, navQuery);
var status = navQuery.GetPolyHeight(pathIterPolys[0], result, out var h);

View File

@ -1,16 +0,0 @@
{
"name": "DotRecast.Recast",
"rootNamespace": "DotRecast.Recast",
"references": [
"DotRecast.Core"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": true
}

View File

@ -33,7 +33,7 @@ namespace DotRecast.Recast.Geom
public readonly int flags;
public readonly int userId;
public RcOffMeshConnection(RcVec3f start, RcVec3f end, float radius, bool bidir, int area, int flags, int userId = 0)
public RcOffMeshConnection(RcVec3f start, RcVec3f end, float radius, bool bidir, int area, int flags)
{
verts = new float[6];
verts[0] = start.X;
@ -46,7 +46,6 @@ namespace DotRecast.Recast.Geom
this.bidir = bidir;
this.area = area;
this.flags = flags;
this.userId = userId;
}
}
}

View File

@ -1,5 +0,0 @@
{
"name": "com.rnd.dotrecast",
"displayName": "DotRecast",
"version": "0.4.1"
}

View File

@ -17,7 +17,6 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using NUnit.Framework;
namespace DotRecast.Detour.Test;
@ -30,10 +29,9 @@ public class ConvexConvexIntersectionTest
{
float[] p = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
float[] q = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
float[] buffer = new float[128];
Span<float> intersection = DtConvexConvexIntersections.Intersect(p, q, buffer);
float[] intersection = DtConvexConvexIntersections.Intersect(p, q);
Assert.That(intersection.Length, Is.EqualTo(5 * 3));
Assert.That(intersection.ToArray(), Is.EquivalentTo(p));
Assert.That(intersection, Is.EqualTo(p));
}
[Test]
@ -41,9 +39,8 @@ public class ConvexConvexIntersectionTest
{
float[] p = { -5, 0, -5, -5, 0, 4, 1, 0, 4, 1, 0, -5 };
float[] q = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
float[] buffer = new float[128];
Span<float> intersection = DtConvexConvexIntersections.Intersect(p, q, buffer);
float[] intersection = DtConvexConvexIntersections.Intersect(p, q);
Assert.That(intersection.Length, Is.EqualTo(5 * 3));
Assert.That(intersection.ToArray(), Is.EquivalentTo(new[] { 1, 0, 3, 1, 0, -3.4f, -2, 0, -4, -4, 0, 0, -3, 0, 3 }));
Assert.That(intersection, Is.EqualTo(new[] { 1, 0, 3, 1, 0, -3.4f, -2, 0, -4, -4, 0, 0, -3, 0, 3 }));
}
}

View File

@ -17,7 +17,6 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using DotRecast.Core.Numerics;
using NUnit.Framework;
@ -33,12 +32,9 @@ public class PolygonByCircleConstraintTest
{
float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 };
RcVec3f center = new RcVec3f(1, 0, 1);
var radius = 6;
float[] constrained = _constraint.Apply(polygon, center, 6);
float[] buffer = new float[128];
Span<float> constrained = _constraint.Apply(polygon, center, radius, buffer);
Assert.That(constrained.ToArray(), Is.EquivalentTo(polygon));
Assert.That(constrained, Is.EqualTo(polygon));
}
[Test]
@ -47,13 +43,10 @@ public class PolygonByCircleConstraintTest
int expectedSize = 21;
float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 };
RcVec3f center = new RcVec3f(2, 0, 0);
var radius = 3;
float[] buffer = new float[128];
Span<float> constrained = _constraint.Apply(polygon, center, radius, buffer);
float[] constrained = _constraint.Apply(polygon, center, 3);
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
Assert.That(constrained.ToArray(), Is.SupersetOf(new[] { 2f, 0f, 2f, 2f, 0f, -2f }));
Assert.That(constrained, Is.SupersetOf(new[] { 2f, 0f, 2f, 2f, 0f, -2f }));
}
[Test]
@ -62,10 +55,7 @@ public class PolygonByCircleConstraintTest
int expectedSize = 12 * 3;
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
RcVec3f center = new RcVec3f(-1, 0, -1);
var radius = 2;
float[] buffer = new float[128];
Span<float> constrained = _constraint.Apply(polygon, center, radius, buffer);
float[] constrained = _constraint.Apply(polygon, center, 2);
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
@ -83,13 +73,10 @@ public class PolygonByCircleConstraintTest
int expectedSize = 9 * 3;
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
RcVec3f center = new RcVec3f(-2, 0, -1);
var radius = 3;
float[] buffer = new float[128];
Span<float> constrained = _constraint.Apply(polygon, center, radius, buffer);
float[] constrained = _constraint.Apply(polygon, center, 3);
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
Assert.That(constrained.ToArray(), Is.SupersetOf(new[] { -2f, 0f, -4f, -4f, 0f, 0f, -3.4641016f, 0.0f, 1.60769534f, -2.0f, 0.0f, 2.0f }));
Assert.That(constrained, Is.SupersetOf(new[] { -2f, 0f, -4f, -4f, 0f, 0f, -3.4641016f, 0.0f, 1.60769534f, -2.0f, 0.0f, 2.0f }));
}
[Test]
@ -98,12 +85,9 @@ public class PolygonByCircleConstraintTest
int expectedSize = 7 * 3;
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
RcVec3f center = new RcVec3f(4, 0, 0);
var radius = 4;
float[] buffer = new float[128];
Span<float> constrained = _constraint.Apply(polygon, center, radius, buffer);
float[] constrained = _constraint.Apply(polygon, center, 4);
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
Assert.That(constrained.ToArray(), Is.SupersetOf(new[] { 1.53589869f, 0f, 3f, 2f, 0f, 3f, 3f, 0f, -3f }));
Assert.That(constrained, Is.SupersetOf(new[] { 1.53589869f, 0f, 3f, 2f, 0f, 3f, 3f, 0f, -3f }));
}
}