public IEnumerable <Neighbour> GetNeighbours(RoomPlan room)
        {
            Contract.Requires(room != null);
            Contract.Ensures(Contract.Result <IEnumerable <Neighbour> >() != null);

            return(_neighbourhood[room]);
        }
        /// <summary>
        /// Add a room to the floorplan. This will clip the room to the outer wall and other rooms, which may result in the room being split into two or more parts
        /// </summary>
        /// <param name="roomFootprint">The footprint of the room to try and add</param>
        /// <param name="wallThickness">The thickness of the walls of this room</param>
        /// <param name="split">If true false and this room is split into two parts no room will be added</param>
        /// <returns></returns>
        public IReadOnlyList <IRoomPlan> Add(IEnumerable <Vector2> roomFootprint, float wallThickness, bool split = false)
        {
            if (_isFrozen)
            {
                throw new InvalidOperationException("Cannot add rooms to floorplan once it is frozen");
            }

            var solution = ShapesForRoom(roomFootprint, split);

            if (solution == null)
            {
                return(new IRoomPlan[0]);
            }

            var result = new List <IRoomPlan>();

            foreach (var shape in solution)
            {
                //Reject rooms with zero points
                if (shape.Count == 0)
                {
                    continue;
                }

                //Mark the neighbourhood cache as dirty...
                //...this means it will recalculate all neighbourhood relationships in the entire plan next time there is a query
                _neighbourhood.Dirty = true;

                //Try to create a room, this may fail in certain circumstances. e.g. if the wallThickness > size of room
                //We simply skip failing rooms
                RoomPlan room;
                if (!RoomPlan.TryCreate(this, shape, wallThickness, _nextId++, out room))
                {
                    continue;
                }

                //Insert the new room into the appropriate data structures
                result.Add(room);
                _rooms.Add(room);
            }

            return(result);
        }
        internal static bool TryCreate(GeometricFloorplan plan, IReadOnlyList <Vector2> footprint, float wallThickness, uint id, out RoomPlan room)
        {
            Contract.Requires(plan != null);
            Contract.Requires(footprint != null);
            Contract.Requires(wallThickness > 0);

            Vector2[] inner;
            IReadOnlyList <IReadOnlyList <Vector2> > corners;
            var sections = footprint.Sections(wallThickness, out inner, out corners).ToArray();

            //No wall sections generated means this is not a valid room shape!
            if (sections.Length == 0 || inner.Length == 0)
            {
                room = null;
                return(false);
            }

            room = new RoomPlan(plan, footprint, inner, sections, corners, wallThickness, id);
            return(true);
        }