public ConfigurationSpace GetConfigurationSpaceOverCorridor(PolygonGrid2D polygon, List <DoorLineGrid2D> doorLines, PolygonGrid2D fixedPolygon, List <DoorLineGrid2D> fixedDoorLines, PolygonGrid2D corridor, List <DoorLineGrid2D> corridorDoorLines)
        {
            var fixedAndCorridorConfigurationSpace = GetConfigurationSpace(corridor, corridorDoorLines, fixedPolygon, fixedDoorLines);
            var newCorridorDoorLines = new List <DoorLineGrid2D>();

            corridorDoorLines = DoorUtils.MergeDoorLines(corridorDoorLines);

            foreach (var corridorPositionLine in fixedAndCorridorConfigurationSpace.Lines)
            {
                foreach (var corridorDoorLine in corridorDoorLines)
                {
                    var rotation            = corridorDoorLine.Line.ComputeRotation();
                    var rotatedLine         = corridorDoorLine.Line.Rotate(rotation);
                    var rotatedCorridorLine = corridorPositionLine.Rotate(rotation).GetNormalized();

                    if (rotatedCorridorLine.GetDirection() == OrthogonalLineGrid2D.Direction.Right)
                    {
                        var correctPositionLine = (rotatedCorridorLine + rotatedLine.From);
                        var correctLengthLine   = new OrthogonalLineGrid2D(correctPositionLine.From, correctPositionLine.To + rotatedLine.Length * rotatedLine.GetDirectionVector(), rotatedCorridorLine.GetDirection());
                        var correctRotationLine = correctLengthLine.Rotate(-rotation);

                        // TODO: problem with corridors overlapping
                        newCorridorDoorLines.Add(new DoorLineGrid2D(correctRotationLine, corridorDoorLine.Length, corridorDoorLine.DoorSocket));
                    }
                    else if (rotatedCorridorLine.GetDirection() == OrthogonalLineGrid2D.Direction.Top)
                    {
                        foreach (var corridorPosition in rotatedCorridorLine.GetPoints())
                        {
                            var transformedDoorLine = rotatedLine + corridorPosition;
                            var newDoorLine         = transformedDoorLine.Rotate(-rotation);

                            // TODO: problem with corridors overlapping
                            // TODO: problem with too many small lines instead of bigger lines
                            newCorridorDoorLines.Add(new DoorLineGrid2D(newDoorLine, corridorDoorLine.Length, corridorDoorLine.DoorSocket));
                        }
                    }
                }
            }

            var configurationSpace = GetConfigurationSpace(polygon, doorLines, fixedPolygon, newCorridorDoorLines);

            // configurationSpace.ReverseDoors = null;

            return(new ConfigurationSpace()
            {
                Lines = configurationSpace.Lines.ToList()
            });
        }
        public List <RoomTemplateInstanceGrid2D> GetRoomTemplateInstances(RoomTemplateGrid2D roomTemplate)
        {
            var result    = new List <RoomTemplateInstanceGrid2D>();
            var doorLines = roomTemplate.Doors.GetDoors(roomTemplate.Outline);
            var shape     = roomTemplate.Outline;

            foreach (var transformation in roomTemplate.AllowedTransformations)
            {
                var transformedShape = shape.Transform(transformation);
                var smallestPoint    = transformedShape.BoundingRectangle.A;

                // Both the shape and doors are moved so the polygon is in the first quadrant and touches axes
                transformedShape = transformedShape + (-1 * smallestPoint);
                transformedShape = polygonUtils.NormalizePolygon(transformedShape);
                var transformedDoorLines = doorLines
                                           .Select(x => DoorUtils.TransformDoorLine(x, transformation))
                                           .Select(x => new DoorLineGrid2D(x.Line + (-1 * smallestPoint), x.Length, x.DoorSocket))
                                           .ToList();

                // Check if we already have the same room shape (together with door lines)
                var sameRoomShapeFound = false;
                foreach (var roomInfo in result)
                {
                    if (roomInfo.RoomShape.Equals(transformedShape) &&
                        roomInfo.DoorLines.SequenceEqualWithoutOrder(transformedDoorLines))
                    {
                        roomInfo.Transformations.Add(transformation);

                        sameRoomShapeFound = true;
                        break;
                    }
                }

                if (sameRoomShapeFound)
                {
                    continue;
                }

                result.Add(new RoomTemplateInstanceGrid2D(roomTemplate, transformedShape, transformedDoorLines, new List <TransformationGrid2D>()
                {
                    transformation
                }));
            }

            return(result);
        }
        /// <summary>
        /// Applies all given transformation to a given room description.
        /// </summary>
        /// <remarks>
        /// Groups room shapes that are equal after transformation.
        /// </remarks>
        /// <param name="roomDescription"></param>
        /// <param name="transformations"></param>
        /// <returns></returns>
        private List <RoomInfo> TransformPolygons(RoomDescription roomDescription, IEnumerable <Transformation> transformations)
        {
            var result    = new List <RoomInfo>();
            var doorLines = doorHandler.GetDoorPositions(roomDescription.Shape, roomDescription.DoorsMode);
            var shape     = roomDescription.Shape;

            foreach (var transformation in transformations)
            {
                var transformedShape = shape.Transform(transformation);
                var smallestPoint    = transformedShape.BoundingRectangle.A;

                // Both the shape and doors are moved so the polygon is in the first quadrant and touches axes
                transformedShape = transformedShape + (-1 * smallestPoint);
                transformedShape = polygonUtils.NormalizePolygon(transformedShape);
                var transformedDoorLines = doorLines
                                           .Select(x => DoorUtils.TransformDoorLine(x, transformation))
                                           .Select(x => new DoorLine(x.Line + (-1 * smallestPoint), x.Length))
                                           .Cast <IDoorLine>()
                                           .ToList();

                // Check if we already have the same room shape (together with door lines)
                var sameRoomShapeFound = false;
                foreach (var roomInfo in result)
                {
                    if (roomInfo.RoomShape.Equals(transformedShape) &&
                        roomInfo.DoorLines.SequenceEqualWithoutOrder(transformedDoorLines))
                    {
                        roomInfo.Transformations.Add(transformation);

                        sameRoomShapeFound = true;
                        break;
                    }
                }

                if (sameRoomShapeFound)
                {
                    continue;
                }

                result.Add(new RoomInfo(roomDescription, transformedShape, transformation, transformedDoorLines));
            }

            return(result);
        }
        public void MergeDoorLines_CorrectlyMerges()
        {
            var doorLines = new List <IDoorLine>()
            {
                new DoorLine(new OrthogonalLine(new IntVector2(1, 0), new IntVector2(2, 0)), 2),
                new DoorLine(new OrthogonalLine(new IntVector2(3, 0), new IntVector2(5, 0)), 2),
                new DoorLine(new OrthogonalLine(new IntVector2(-3, 0), new IntVector2(0, 0)), 1),
                new DoorLine(new OrthogonalLine(new IntVector2(-3, 0), new IntVector2(0, 0)), 2),
                new DoorLine(new OrthogonalLine(new IntVector2(0, 0), new IntVector2(0, 3)), 2),
                new DoorLine(new OrthogonalLine(new IntVector2(0, -2), new IntVector2(0, -1)), 2),
            };

            var expectedDoorLines = new List <IDoorLine>()
            {
                new DoorLine(new OrthogonalLine(new IntVector2(-3, 0), new IntVector2(0, 0)), 1),
                new DoorLine(new OrthogonalLine(new IntVector2(-3, 0), new IntVector2(5, 0)), 2),
                new DoorLine(new OrthogonalLine(new IntVector2(0, -2), new IntVector2(0, 3)), 2),
            };

            var mergedDoorLines = DoorUtils.MergeDoorLines(doorLines);

            Assert.That(mergedDoorLines, Is.EquivalentTo(expectedDoorLines));
        }
        private ConfigurationSpace GetConfigurationSpace(GridPolygon polygon, List <IDoorLine> doorLines, GridPolygon fixedCenter, List <IDoorLine> doorLinesFixed, List <int> offsets = null)
        {
            if (offsets != null && offsets.Count == 0)
            {
                throw new ArgumentException("There must be at least one offset if they are set", nameof(offsets));
            }

            var configurationSpaceLines = new List <OrthogonalLine>();
            var reverseDoor             = new List <Tuple <OrthogonalLine, DoorLine> >();

            doorLines      = DoorUtils.MergeDoorLines(doorLines);
            doorLinesFixed = DoorUtils.MergeDoorLines(doorLinesFixed);

            // One list for every direction
            var lines = new List <IDoorLine> [4];

            // Init array
            for (var i = 0; i < lines.Length; i++)
            {
                lines[i] = new List <IDoorLine>();
            }

            // Populate lists with lines
            foreach (var line in doorLinesFixed)
            {
                lines[(int)line.Line.GetDirection()].Add(line);
            }

            foreach (var doorLine in doorLines)
            {
                var line = doorLine.Line;
                var oppositeDirection  = OrthogonalLine.GetOppositeDirection(line.GetDirection());
                var rotation           = line.ComputeRotation();
                var rotatedLine        = line.Rotate(rotation);
                var correspondingLines = lines[(int)oppositeDirection].Where(x => x.Length == doorLine.Length).Select(x => new DoorLine(x.Line.Rotate(rotation), x.Length));

                foreach (var cDoorLine in correspondingLines)
                {
                    var cline = cDoorLine.Line;
                    var y     = cline.From.Y - rotatedLine.From.Y;
                    var from  = new IntVector2(cline.From.X - rotatedLine.To.X + (rotatedLine.Length - doorLine.Length), y);
                    var to    = new IntVector2(cline.To.X - rotatedLine.From.X - (rotatedLine.Length + doorLine.Length), y);

                    if (from.X < to.X)
                    {
                        continue;
                    }

                    if (offsets == null)
                    {
                        var resultLine = new OrthogonalLine(from, to, OrthogonalLine.Direction.Left).Rotate(-rotation);
                        reverseDoor.Add(Tuple.Create(resultLine, new DoorLine(cDoorLine.Line.Rotate(-rotation), cDoorLine.Length)));
                        configurationSpaceLines.Add(resultLine);
                    }
                    else
                    {
                        foreach (var offset in offsets)
                        {
                            var offsetVector = new IntVector2(0, offset);
                            var resultLine   = new OrthogonalLine(from - offsetVector, to - offsetVector, OrthogonalLine.Direction.Left).Rotate(-rotation);
                            reverseDoor.Add(Tuple.Create(resultLine, new DoorLine(cDoorLine.Line.Rotate(-rotation), cDoorLine.Length)));
                            configurationSpaceLines.Add(resultLine);
                        }
                    }
                }
            }

            // Remove all positions when the two polygons overlap
            configurationSpaceLines = RemoveOverlapping(polygon, fixedCenter, configurationSpaceLines);

            // Remove all non-unique positions
            configurationSpaceLines = RemoveIntersections(configurationSpaceLines);

            return(new ConfigurationSpace()
            {
                Lines = configurationSpaceLines, ReverseDoors = reverseDoor
            });
        }