Exemple #1
0
        /// <summary>
        /// Reports all edges intersecting disc while IDiscCast.RegisterCollision returns true, this includes fully contained edges.
        /// </summary>
        /// <param name="discCast">Cast data</param>
        /// <param name="open">NativeQueue for internal use, is cleared before use</param>
        /// <param name="closed">NativeHashSet for internal use, is cleared before use</param>
        public static void CastDisc <T>(this Navmesh.Navmesh navmesh, T discCast, NativeList <IntPtr> open, NativeHashSet <int> closed) where T : IDiscCast
        {
            var o   = discCast.Origin;
            var r   = discCast.Radius;
            var tri = navmesh.FindTriangleContainingPoint(o);

            open.Clear();
            closed.Clear();

            Check(tri);
            Check(tri->LNext);
            Check(tri->LPrev);

            while (open.Length > 0)
            {
                tri = (Edge *)open[open.Length - 1];
                open.Resize(open.Length - 1, NativeArrayOptions.UninitializedMemory);
                Check(tri->LNext);
                Check(tri->LPrev);
            }

            void Check(Edge *edge)
            {
                if (closed.Contains(edge->QuadEdgeId))
                {
                    return;
                }

                if (IntersectSegDisc(edge->Org->Point, edge->Dest->Point, o, r))
                {
                    open.Add((IntPtr)edge->Sym);
                    if (edge->Constrained)
                    {
                        discCast.RegisterCollision(edge);
                    }
                }

                closed.Add(edge->QuadEdgeId);
            }
        }
Exemple #2
0
        /// <summary>
        /// Reports all edges intersecting specified line segment while ISegmentCast.RegisterCollision returns true.
        /// Collisions are reported in order of their distance from ISegmentCast.Origin.
        /// </summary>
        /// <param name="segmentCast">Cast data</param>
        /// <param name="open">NativeList for internal use, is cleared before use</param>
        public static void CastSegment <T>(this Navmesh.Navmesh navmesh, T segmentCast, NativeList <IntPtr> open) where T : ISegmentCast
        {
            var o        = segmentCast.Origin;
            var d        = segmentCast.Destination;
            var tri      = navmesh.FindTriangleContainingPoint(o, out var startCollinear);
            var goalEdge = navmesh.FindTriangleContainingPoint(d, out var goalCollinear);

            if (ReachedGoal(tri) || startCollinear && ReachedGoal(tri->Sym))
            {
                RegisterCollinearGoal();
                return;
            }

            open.Clear();

            if (math.all(o == tri->Org->Point))
            {
                if (ExpandVertex(tri->Org))
                {
                    RegisterCollinearGoal();
                    return;
                }
            }
            else if (math.all(o == tri->Dest->Point))
            {
                if (ExpandVertex(tri->Dest))
                {
                    RegisterCollinearGoal();
                    return;
                }
            }
            else if (startCollinear)
            {
                open.Add((IntPtr)tri->LNext);
                open.Add((IntPtr)tri->LPrev);
                open.Add((IntPtr)tri->Sym->LNext);
                open.Add((IntPtr)tri->Sym->LPrev);
            }
            else
            {
                open.Add((IntPtr)tri);
                open.Add((IntPtr)tri->LNext);
                open.Add((IntPtr)tri->LPrev);
            }

            do
            {
                var found = false;

                for (int i = 0; i < open.Length; i++)
                {
                    var e = (Edge *)open[i];
                    if (IntersectSegSeg(o, d, e->Org->Point, e->Dest->Point, out var p))
                    {
                        if (e->Constrained)
                        {
                            if (!segmentCast.RegisterCollision(p, e))
                            {
                                return;
                            }
                        }
                        tri = e->Sym;

                        open.Clear();

                        if (math.all(p == tri->Org->Point))
                        {
                            o = p;
                            if (ExpandVertex(tri->Org))
                            {
                                RegisterCollinearGoal();
                                return;
                            }
                        }
                        else if (math.all(p == tri->Dest->Point))
                        {
                            o = p;
                            if (ExpandVertex(tri->Dest))
                            {
                                RegisterCollinearGoal();
                                return;
                            }
                        }
                        else
                        {
                            open.Add((IntPtr)tri->LNext);
                            open.Add((IntPtr)tri->LPrev);
                        }

                        found = true;
                        break;
                    }
                }

                Assert.IsTrue(found);
            } while (!ReachedGoal(tri));

            RegisterCollinearGoal();

            bool ExpandVertex(Vertex *vertex)
            {
                var enumerator = vertex->GetEdgeEnumerator();

                while (enumerator.MoveNext())
                {
                    if (ReachedGoal(enumerator.Current))
                    {
                        return(true);
                    }
                    open.Add((IntPtr)enumerator.Current->LNext);
                }

                return(false);
            }

            bool ReachedGoal(Edge *edge) => edge->TriangleId == goalEdge->TriangleId || goalCollinear && edge->TriangleId == goalEdge->Sym->TriangleId;

            void RegisterCollinearGoal()
            {
                if (goalCollinear)
                {
                    segmentCast.RegisterCollision(segmentCast.Destination, goalEdge);
                }
            }
        }