/// <summary>
        /// Determines if a cell is on the edges of a cell collections
        /// </summary>
        /// <param name="cellID">The ID of the cell</param>
        /// <param name="cellularFloor">The CellularFloorBaseGeometry to which this cell belongs</param>
        /// <param name="collection">Cell ID collection</param>
        /// <returns>true for being on the edge false for not being on the edge</returns>
        private static bool onEdge(int cellID, CellularFloorBaseGeometry cellularFloor, HashSet <int> collection)
        {
            var index = cellularFloor.FindIndex(cellID);

            if (index.I == 0 || index.I == cellularFloor.GridWidth - 1 || index.J == 0 || index.J == cellularFloor.GridHeight - 1)
            {
                return(true);
            }
            int iMin = (index.I == 0) ? 0 : index.I - 1;
            int iMax = (index.I == cellularFloor.GridWidth - 1) ? cellularFloor.GridWidth - 1 : index.I + 1;
            int jMin = (index.J == 0) ? 0 : index.J - 1;
            int jMax = (index.J == cellularFloor.GridHeight - 1) ? cellularFloor.GridHeight - 1 : index.J + 1;

            for (int i = iMin; i <= iMax; i++)
            {
                for (int j = jMin; j <= jMax; j++)
                {
                    if (cellularFloor.ContainsCell(i, j))
                    {
                        if (!collection.Contains(cellularFloor.Cells[i, j].ID))
                        {
                            return(true);
                        }
                    }
                }
            }
            return(false);
        }
 /// <summary>
 /// Determines if a cell is on the edges of a cell collections
 /// </summary>
 /// <param name="index">The index of the cell</param>
 /// <param name="cellularFloor">The CellularFloorBaseGeometry to which this cell belongs</param>
 /// <param name="collection">Cell ID collection</param>
 /// <returns>true for being on the edge false for not being on the edge</returns>
 private static bool onEdge(Index index, CellularFloorBaseGeometry cellularFloor, HashSet <Cell> collection)
 {
     foreach (Index item in Index.Neighbors)
     {
         Index neighbor = item + index;
         if (cellularFloor.ContainsCell(neighbor))
         {
             if (!collection.Contains(cellularFloor.Cells[neighbor.I, neighbor.J]))
             {
                 return(true);
             }
         }
     }
     return(false);
 }
        /// <summary>
        /// Checks the existence of a line of sight between two points.
        /// </summary>
        /// <param name="origin">The origin.</param>
        /// <param name="target">The target.</param>
        /// <param name="barrierType">Type of the barrier.</param>
        /// <param name="cellularFloor">The cellular floor.</param>
        /// <param name="tolerance">The tolerance.</param>
        /// <returns><c>true</c> if visible, <c>false</c> otherwise.</returns>
        public static bool Visible(UV origin, UV target, BarrierType barrierType, CellularFloorBaseGeometry cellularFloor, double tolerance = OSMDocument.AbsoluteTolerance)
        {
            UV     direction = target - origin;
            double length    = direction.GetLength();

            direction /= length;
            Ray ray = new Ray(origin, direction, cellularFloor.Origin,
                              cellularFloor.CellSize, tolerance);

            while (ray.Length + tolerance < length)
            {
                Index index = ray.NextIndex(cellularFloor.FindIndex, tolerance);
                if (cellularFloor.ContainsCell(index))
                {
                    switch (barrierType)
                    {
                    case BarrierType.Visual:
                        if (cellularFloor.Cells[index.I, index.J].VisualOverlapState == OverlapState.Overlap)
                        {
                            foreach (int item in cellularFloor.Cells[index.I, index.J].VisualBarrierEdgeIndices)
                            {
                                double?distance = ray.DistanceToForIsovist(cellularFloor.VisualBarrierEdges[item], tolerance);
                                if (distance != null && distance.Value + tolerance < length)
                                {
                                    UVLine hitEdge = cellularFloor.VisualBarrierEdges[item];
                                    return(false);
                                }
                            }
                        }
                        break;

                    case BarrierType.Physical:
                        if (cellularFloor.Cells[index.I, index.J].PhysicalOverlapState == OverlapState.Overlap)
                        {
                            foreach (int item in cellularFloor.Cells[index.I, index.J].PhysicalBarrierEdgeIndices)
                            {
                                double?distance = ray.DistanceToForIsovist(cellularFloor.PhysicalBarrierEdges[item], tolerance);
                                if (distance != null && distance.Value + tolerance < length)
                                {
                                    UVLine hitEdge = cellularFloor.PhysicalBarrierEdges[item];
                                    return(false);
                                }
                            }
                        }
                        break;

                    case BarrierType.Field:
                        if (cellularFloor.Cells[index.I, index.J].FieldOverlapState == OverlapState.Overlap)
                        {
                            foreach (int item in cellularFloor.Cells[index.I, index.J].FieldBarrierEdgeIndices)
                            {
                                double?distance = ray.DistanceToForIsovist(cellularFloor.FieldBarrierEdges[item], tolerance);
                                if (distance != null && distance.Value + tolerance < length)
                                {
                                    UVLine hitEdge = cellularFloor.FieldBarrierEdges[item];
                                    return(false);
                                }
                            }
                        }
                        break;

                    default:
                        break;
                    }
                }
            }
            return(true);
        }