//generic version
        public static void Raycast(Vector3 origin, Vector3 direction, AgentProperties properties, out RaycastHitNavMesh hit,
                                   float length = 1000f, bool triggeredByPassabilityChange = true, bool triggeredByAreaChange = true, int maxIterations = 100)
        {
            //try get cell at target position
            Cell cell;
            bool outsideCell;

            if (TryGetCell(origin, properties, out cell, out outsideCell) == false || outsideCell)
            {
                hit = new RaycastHitNavMesh(origin, false);
                return;
            }

            Raycast(origin, direction, properties, out hit, length, triggeredByPassabilityChange, triggeredByAreaChange, maxIterations, cell.passability, cell.area, cell);
        }
        //targeted by area and passability
        public static void Raycast(Vector3 origin, Vector3 direction, AgentProperties properties, out RaycastHitNavMesh hit,
                                   Area expectedArea, Passability expectedPassability,
                                   float length = 1000f, int maxIterations = 100)
        {
            //try get cell at target position
            Cell cell;
            bool outsideCell;

            if (TryGetCell(origin, properties, out cell, out outsideCell) == false || outsideCell)
            {
                hit = new RaycastHitNavMesh(origin, false);
                return;
            }

            //cell we found are not with expected area or passability
            if (cell.area != expectedArea | cell.passability != expectedPassability)
            {
                hit = new RaycastHitNavMesh(origin, true);
                return;
            }

            Raycast(origin, direction, properties, out hit, length, true, true, maxIterations, expectedPassability, expectedArea, cell);
        }
        //private raycasting to take input by things upside
        private static void Raycast(Vector3 origin, Vector3 direction,
                                    AgentProperties properties, out RaycastHitNavMesh hit,
                                    float length, bool triggeredByPassabilityChange, bool triggeredByAreaChange,
                                    int maxIterations, Passability expectedPassability, Area expectedArea, Cell cell)
        {
            raycastExclude.Clear();//excluded list of edges
            float maxLengthSqr = length * length;

            for (int iteration = 0; iteration < maxIterations; iteration++)
            {
                raycastTempData.Clear();//iteration data cleared

                foreach (var pair in cell.dataContentPairs)
                {
                    CellContentData curData = pair.Key;
                    if (!raycastExclude.Add(curData))//mean it's already contain this
                    {
                        continue;
                    }

                    Vector3 intersect;
                    if (SomeMath.RayIntersectXZ(origin, direction, curData.leftV3, curData.rightV3, out intersect))
                    {
                        if (pair.Value != null)
                        {
                            Cell otherCell = pair.Value.connection;
                            if (otherCell == cell | !otherCell.canBeUsed)
                            {
                                continue;
                            }

                            if ((triggeredByPassabilityChange && cell.passability != otherCell.passability) ||
                                (triggeredByAreaChange && cell.area != otherCell.area))
                            {
                                hit = new RaycastHitNavMesh(intersect, SomeMath.SqrDistance(origin, intersect) < maxLengthSqr);
                                return;
                            }
                            raycastTempData.Add(new RaycastSomeData(intersect, otherCell));
                        }
                        else
                        {
                            raycastTempData.Add(new RaycastSomeData(intersect, null));
                        }
                    }
                }

                //check if there possible connection
                for (int i = 0; i < raycastTempData.Count; i++)
                {
                    if (raycastTempData[i].cell != null)
                    {
                        cell = raycastTempData[i].cell;
                        goto CONTINUE;
                    }
                }

                //now we definetly hit something and now find furthest
                float   furthestSqrDist = 0f;
                Vector3 furthest        = origin;
                for (int i = 0; i < raycastTempData.Count; i++)
                {
                    float curSqrDist = SomeMath.SqrDistance(raycastTempData[i].point, origin);

                    if (curSqrDist > furthestSqrDist)
                    {
                        furthestSqrDist = curSqrDist;
                        furthest        = raycastTempData[i].point;
                    }
                }

                hit = new RaycastHitNavMesh(furthest, SomeMath.SqrDistance(origin, furthest) < maxLengthSqr);
                return;

                CONTINUE : { continue; }
            }
            hit = new RaycastHitNavMesh(origin, true, true);
            return;
        }