Beispiel #1
0
        public void MinkowskiSumAlgorithmBufferTest()
        {
            // two triangles
            IBasicPolygon buffer = new BasicPolygon(
                new Coordinate[] { new Coordinate(5, 5), new Coordinate(5, 7), new Coordinate(4, 6) });

            List <Coordinate> sourceShellCoordinates = new List <Coordinate>
            {
                new Coordinate(2, 1), new Coordinate(4, 1),
                new Coordinate(3, 3)
            };

            List <Coordinate> expectedCoordinates = new List <Coordinate>
            {
                new Coordinate(6, 7), new Coordinate(7, 6),
                new Coordinate(9, 6), new Coordinate(9, 8),
                new Coordinate(8, 10), new Coordinate(7, 9),
            };

            IBasicPolygon expectedResult = new BasicPolygon(expectedCoordinates);
            IBasicPolygon actualResult   = MinkowskiSumAlgorithm.Buffer(sourceShellCoordinates, buffer);

            Assert.IsTrue(PolygonAlgorithms.IsConvex(actualResult));
            Assert.AreEqual(expectedResult.Shell.Count, actualResult.Shell.Count);
            for (Int32 i = 0; i < expectedResult.Shell.Count; i++)
            {
                Assert.AreEqual(expectedResult.Shell.Coordinates[i], actualResult.Shell.Coordinates[i]);
            }

            // triangle and a square
            buffer = new BasicPolygon(
                new Coordinate[] { new Coordinate(8, 6), new Coordinate(9, 6), new Coordinate(9, 7), new Coordinate(8, 7) });

            sourceShellCoordinates = new List <Coordinate>
            {
                new Coordinate(3, 4), new Coordinate(5, 4),
                new Coordinate(4, 6)
            };

            expectedCoordinates = new List <Coordinate>
            {
                new Coordinate(11, 11), new Coordinate(11, 10),
                new Coordinate(13, 10), new Coordinate(14, 10),
                new Coordinate(14, 11), new Coordinate(13, 13),
                new Coordinate(12, 13), new Coordinate(11, 11)
            };

            expectedResult = new BasicPolygon(expectedCoordinates);
            actualResult   = MinkowskiSumAlgorithm.Buffer(sourceShellCoordinates, buffer);

            Assert.IsTrue(PolygonAlgorithms.IsConvex(actualResult));
            Assert.AreEqual(expectedResult.Shell.Count, actualResult.Shell.Count);
            for (Int32 i = 0; i < expectedResult.Shell.Count; i++)
            {
                Assert.AreEqual(expectedResult.Shell.Coordinates[i], actualResult.Shell.Coordinates[i]);
            }

            // square and circle of 4 points (square)
            buffer = new BasicPolygon(
                new Coordinate[] { new Coordinate(8, 6), new Coordinate(9, 6), new Coordinate(9, 7), new Coordinate(8, 7) });

            expectedCoordinates = new List <Coordinate>
            {
                new Coordinate(6, 6), new Coordinate(8, 4),
                new Coordinate(9, 4), new Coordinate(11, 6),
                new Coordinate(11, 7), new Coordinate(9, 9),
                new Coordinate(8, 9), new Coordinate(6, 7),
                new Coordinate(6, 6)
            };

            expectedResult = new BasicPolygon(expectedCoordinates);
            actualResult   = MinkowskiSumAlgorithm.Buffer(buffer, 2, 4);

            Assert.IsTrue(PolygonAlgorithms.IsConvex(actualResult));
            Assert.AreEqual(expectedResult.Shell.Count, actualResult.Shell.Count);
            for (Int32 i = 0; i < expectedResult.Shell.Count; i++)
            {
                Assert.AreEqual(expectedResult.Shell.Coordinates[i].X, Math.Round(actualResult.Shell.Coordinates[i].X, 2));
                Assert.AreEqual(expectedResult.Shell.Coordinates[i].Y, Math.Round(actualResult.Shell.Coordinates[i].Y, 2));
            }

            // point and circle (of 4 points)
            IBasicPoint point = _factory.CreatePoint(1, 1, 0);

            actualResult = MinkowskiSumAlgorithm.Buffer(point, 2, 4);

            expectedCoordinates = new List <Coordinate>
            {
                new Coordinate(3, 1), new Coordinate(1, 3),
                new Coordinate(-1, 1), new Coordinate(1, -1)
            };

            expectedResult = new BasicPolygon(expectedCoordinates);
            Assert.AreEqual(expectedResult.Shell.Count, actualResult.Shell.Count);
            for (Int32 i = 0; i < expectedResult.Shell.Count; i++)
            {
                Assert.AreEqual(expectedResult.Shell.Coordinates[i].X, Math.Round(actualResult.Shell.Coordinates[i].X, 2));
                Assert.AreEqual(expectedResult.Shell.Coordinates[i].Y, Math.Round(actualResult.Shell.Coordinates[i].Y, 2));
            }

            // square with a square hole and circle (of 8 points)
            sourceShellCoordinates = new List <Coordinate>
            {
                new Coordinate(1, 1),
                new Coordinate(9, 1),
                new Coordinate(9, 9),
                new Coordinate(1, 9),
                new Coordinate(1, 1)
            };
            List <List <Coordinate> > holes = new List <List <Coordinate> >();

            holes.Add(new List <Coordinate>());
            holes[0] = new List <Coordinate>();
            holes[0].Add(new Coordinate(3, 3));
            holes[0].Add(new Coordinate(3, 7));
            holes[0].Add(new Coordinate(7, 7));
            holes[0].Add(new Coordinate(7, 3));
            holes[0].Add(new Coordinate(3, 3));

            BasicPolygon source = new BasicPolygon(sourceShellCoordinates, holes);

            actualResult = MinkowskiSumAlgorithm.Buffer(source, 1, 8);

            expectedCoordinates = new List <Coordinate>
            {
                new Coordinate(0, 1), new Coordinate(0.3, 0.3),
                new Coordinate(1, 0), new Coordinate(9, 0),
                new Coordinate(9.7, 0.3), new Coordinate(10, 1),
                new Coordinate(10, 9), new Coordinate(9.7, 9.7),
                new Coordinate(9, 10), new Coordinate(1, 10),
                new Coordinate(0.3, 9.7), new Coordinate(0, 9)
            };
            List <List <Coordinate> > expectedHoleCoordinates = new List <List <Coordinate> >();

            expectedHoleCoordinates.Add(new List <Coordinate>()
            {
                new Coordinate(4, 3), new Coordinate(3.7, 3.7),
                new Coordinate(3, 4), new Coordinate(3, 6),
                new Coordinate(3.7, 6.3), new Coordinate(4, 7),
                new Coordinate(6, 7), new Coordinate(6.3, 6.3),
                new Coordinate(7, 6), new Coordinate(7, 4),
                new Coordinate(6.3, 3.7), new Coordinate(6, 3)
            });

            expectedResult = new BasicPolygon(expectedCoordinates);
            Assert.AreEqual(expectedResult.Shell.Count, actualResult.Shell.Count);
            Assert.AreEqual(expectedResult.Shell.Count, actualResult.Shell.Count);
            for (Int32 i = 0; i < expectedResult.Shell.Count; i++)
            {
                Assert.AreEqual(expectedResult.Shell.Coordinates[i].X, Math.Round(actualResult.Shell.Coordinates[i].X, 1));
                Assert.AreEqual(expectedResult.Shell.Coordinates[i].Y, Math.Round(actualResult.Shell.Coordinates[i].Y, 1));
            }

            Assert.AreEqual(expectedHoleCoordinates.Count, actualResult.HoleCount);
            for (Int32 i = 0; i < expectedHoleCoordinates.Count; i++)
            {
                for (Int32 j = 0; j < expectedHoleCoordinates[i].Count; j++)
                {
                    Assert.AreEqual(expectedHoleCoordinates[i][j].X, Math.Round(actualResult.Holes[i].Coordinates[j].X, 1));
                    Assert.AreEqual(expectedHoleCoordinates[i][j].Y, Math.Round(actualResult.Holes[i].Coordinates[j].Y, 1));
                }
            }

            // line string (2 points) and square
            buffer = new BasicPolygon(
                new Coordinate[] { new Coordinate(0, 2), new Coordinate(0, 0), new Coordinate(2, 0), new Coordinate(2, 2) });

            actualResult = MinkowskiSumAlgorithm.Buffer(new BasicLineString(new List <Coordinate>()
            {
                new Coordinate(0, 4), new Coordinate(2, 4)
            }), buffer);
            expectedCoordinates = new List <Coordinate>
            {
                new Coordinate(0, 6), new Coordinate(0, 4),
                new Coordinate(2, 4), new Coordinate(4, 4),
                new Coordinate(4, 6), new Coordinate(2, 6)
            };
            expectedResult = new BasicPolygon(expectedCoordinates);
            Assert.AreEqual(expectedResult.Shell.Count, actualResult.Shell.Count);
            for (Int32 i = 0; i < expectedResult.Shell.Count; i++)
            {
                Assert.AreEqual(expectedResult.Shell.Coordinates[i], actualResult.Shell.Coordinates[i]);
            }

            // line string (4 points) and square
            buffer = new BasicPolygon(
                new Coordinate[] { new Coordinate(0, 2), new Coordinate(0, 0), new Coordinate(2, 0), new Coordinate(2, 2) });

            actualResult = MinkowskiSumAlgorithm.Buffer(new BasicLineString(new List <Coordinate>()
            {
                new Coordinate(1, 1), new Coordinate(3, 3), new Coordinate(5, 6), new Coordinate(3, 8)
            }), buffer);
            expectedCoordinates = new List <Coordinate>
            {
                new Coordinate(1, 3), new Coordinate(1, 1),
                new Coordinate(3, 1), new Coordinate(5, 3),
                new Coordinate(7, 6), new Coordinate(7, 8),
                new Coordinate(5, 10), new Coordinate(3, 10)
            };
            expectedResult = new BasicPolygon(expectedCoordinates);
            Assert.AreEqual(expectedResult.Shell.Count, actualResult.Shell.Count);
            for (Int32 i = 0; i < expectedResult.Shell.Count; i++)
            {
                Assert.AreEqual(expectedResult.Shell.Coordinates[i], actualResult.Shell.Coordinates[i]);
            }

            // concave and convex with no hole in the result
            buffer = new BasicPolygon(
                new Coordinate[] { new Coordinate(13, 2), new Coordinate(14, 3), new Coordinate(13, 4), new Coordinate(12, 3) });

            sourceShellCoordinates = new List <Coordinate>
            {
                new Coordinate(1, 1), new Coordinate(11, 1),
                new Coordinate(11, 6), new Coordinate(8, 6),
                new Coordinate(9, 3), new Coordinate(3, 3),
                new Coordinate(4, 6), new Coordinate(1, 6)
            };

            actualResult = MinkowskiSumAlgorithm.Buffer(sourceShellCoordinates, buffer);

            expectedCoordinates = new List <Coordinate>
            {
                new Coordinate(13, 4), new Coordinate(14, 3),
                new Coordinate(24, 3), new Coordinate(25, 4),
                new Coordinate(25, 9), new Coordinate(24, 10),
                new Coordinate(21, 10), new Coordinate(20, 9),
                new Coordinate(20.67, 7), new Coordinate(17.33, 7),
                new Coordinate(18, 9), new Coordinate(17, 10),
                new Coordinate(14, 10), new Coordinate(13, 9)
            };

            expectedResult = new BasicPolygon(expectedCoordinates);
            Assert.AreEqual(expectedResult.Shell.Count, actualResult.Shell.Count);
            for (Int32 i = 0; i < expectedResult.Shell.Count; i++)
            {
                Assert.AreEqual(expectedResult.Shell.Coordinates[i].X, Math.Round(actualResult.Shell.Coordinates[i].X, 2));
                Assert.AreEqual(expectedResult.Shell.Coordinates[i].Y, Math.Round(actualResult.Shell.Coordinates[i].Y, 2));
            }

            // convex and concave with no hole in the result
            buffer = new BasicPolygon(
                new Coordinate[] { new Coordinate(0, 3), new Coordinate(-3, 0), new Coordinate(0, -3), new Coordinate(3, 0) });

            sourceShellCoordinates = new List <Coordinate>
            {
                new Coordinate(1, 1), new Coordinate(11, 1),
                new Coordinate(11, 6), new Coordinate(8, 6),
                new Coordinate(9, 3), new Coordinate(3, 3),
                new Coordinate(4, 6), new Coordinate(1, 6)
            };

            actualResult = MinkowskiSumAlgorithm.Buffer(sourceShellCoordinates, buffer);

            expectedCoordinates = new List <Coordinate>
            {
                new Coordinate(-2, 1), new Coordinate(1, -2),
                new Coordinate(11, -2), new Coordinate(14, 1),
                new Coordinate(14, 6), new Coordinate(11, 9),
                new Coordinate(8, 9), new Coordinate(6, 7),
                new Coordinate(4, 9), new Coordinate(1, 9),
                new Coordinate(-2, 6)
            };

            expectedResult = new BasicPolygon(expectedCoordinates);
            Assert.AreEqual(expectedResult.Shell.Count, actualResult.Shell.Count);
            for (Int32 i = 0; i < expectedResult.Shell.Count; i++)
            {
                Assert.AreEqual(expectedResult.Shell.Coordinates[i].X, Math.Round(actualResult.Shell.Coordinates[i].X, 2));
                Assert.AreEqual(expectedResult.Shell.Coordinates[i].Y, Math.Round(actualResult.Shell.Coordinates[i].Y, 2));
            }

            // convex and concave with hole in the result
            buffer = new BasicPolygon(
                new Coordinate[] { new Coordinate(13, 4), new Coordinate(12, 3), new Coordinate(13, 2), new Coordinate(14, 3) });

            sourceShellCoordinates = new List <Coordinate>
            {
                new Coordinate(1, 1), new Coordinate(11, 1),
                new Coordinate(11, 6), new Coordinate(7, 6),
                new Coordinate(9, 3), new Coordinate(4, 3),
                new Coordinate(6, 6), new Coordinate(1, 6)
            };

            actualResult        = MinkowskiSumAlgorithm.Buffer(sourceShellCoordinates, buffer);
            expectedCoordinates = new List <Coordinate>
            {
                new Coordinate(13, 4), new Coordinate(14, 3),
                new Coordinate(24, 3), new Coordinate(25, 4),
                new Coordinate(25, 9), new Coordinate(24, 10),
                new Coordinate(20, 10), new Coordinate(19.5, 9.5),
                new Coordinate(19, 10), new Coordinate(14, 10),
                new Coordinate(13, 9)
            };

            expectedHoleCoordinates = new List <List <Coordinate> >();
            expectedHoleCoordinates.Add(new List <Coordinate>()
            {
                new Coordinate(19.5, 8.25), new Coordinate(20.3, 7),
                new Coordinate(18.6, 7)
            });

            expectedResult = new BasicPolygon(expectedCoordinates);
            Assert.AreEqual(expectedResult.Shell.Count, actualResult.Shell.Count);
            for (Int32 i = 0; i < expectedResult.Shell.Count; i++)
            {
                Assert.AreEqual(expectedResult.Shell.Coordinates[i], actualResult.Shell.Coordinates[i]);
            }

            Assert.AreEqual(expectedHoleCoordinates.Count, actualResult.HoleCount);
            for (Int32 i = 0; i < expectedHoleCoordinates.Count; i++)
            {
                for (Int32 j = 0; j < expectedHoleCoordinates[i].Count; j++)
                {
                    Assert.AreEqual(expectedHoleCoordinates[i][j].X, Math.Round(actualResult.Holes[i].Coordinates[j].X), 2);
                    Assert.AreEqual(expectedHoleCoordinates[i][j].Y, Math.Round(actualResult.Holes[i].Coordinates[j].Y), 2);
                }
            }

            // convex source polygon with hole and a rhombus
            buffer = _factory.CreatePolygon(
                _factory.CreatePoint(10, 2),
                _factory.CreatePoint(11, 3),
                _factory.CreatePoint(10, 4),
                _factory.CreatePoint(9, 3));

            sourceShellCoordinates = new List <Coordinate>
            {
                new Coordinate(1, 1),
                new Coordinate(9, 1),
                new Coordinate(9, 9),
                new Coordinate(1, 9),
                new Coordinate(1, 1)
            };

            holes = new List <List <Coordinate> >();
            holes.Add(new List <Coordinate>());
            holes[0] = new List <Coordinate>();
            holes[0].Add(new Coordinate(3, 3));
            holes[0].Add(new Coordinate(3, 7));
            holes[0].Add(new Coordinate(7, 7));
            holes[0].Add(new Coordinate(7, 3));
            holes[0].Add(new Coordinate(3, 3));

            source       = new BasicPolygon(sourceShellCoordinates, holes);
            actualResult = MinkowskiSumAlgorithm.Buffer(source, buffer);

            expectedCoordinates = new List <Coordinate>
            {
                new Coordinate(10, 4), new Coordinate(11, 3),
                new Coordinate(19, 3), new Coordinate(20, 4),
                new Coordinate(20, 12), new Coordinate(19, 13),
                new Coordinate(11, 13), new Coordinate(10, 12)
            };

            expectedHoleCoordinates = new List <List <Coordinate> >();
            expectedHoleCoordinates.Add(new List <Coordinate>()
            {
                new Coordinate(14, 6), new Coordinate(13, 7),
                new Coordinate(13, 9), new Coordinate(14, 10),
                new Coordinate(16, 10), new Coordinate(17, 9),
                new Coordinate(17, 7), new Coordinate(16, 6)
            });

            expectedResult = new BasicPolygon(expectedCoordinates);
            Assert.AreEqual(expectedResult.Shell.Count, actualResult.Shell.Count);
            for (Int32 i = 0; i < expectedResult.Shell.Count; i++)
            {
                Assert.AreEqual(expectedResult.Shell.Coordinates[i], actualResult.Shell.Coordinates[i]);
            }

            Assert.AreEqual(expectedHoleCoordinates.Count, actualResult.HoleCount);
            for (Int32 i = 0; i < expectedHoleCoordinates.Count; i++)
            {
                for (Int32 j = 0; j < expectedHoleCoordinates[i].Count; j++)
                {
                    Assert.AreEqual(expectedHoleCoordinates[i][j], actualResult.Holes[i].Coordinates[j]);
                }
            }

            // ArgumentNullException: null source
            Assert.Throws <ArgumentNullException>(() => MinkowskiSumAlgorithm.Buffer((IBasicPolygon)null, buffer));

            // ArgumentNullException: null buffer polygon
            Assert.Throws <ArgumentNullException>(() => MinkowskiSumAlgorithm.Buffer(source, null));

            // ArgumentException: source polygon with clockwise orientation
            sourceShellCoordinates = new List <Coordinate>
            {
                new Coordinate(1, 1),
                new Coordinate(1, 9),
                new Coordinate(9, 9),
                new Coordinate(9, 1),
                new Coordinate(1, 1)
            };
            source = new BasicPolygon(sourceShellCoordinates);
            Assert.Throws <ArgumentException>(() => MinkowskiSumAlgorithm.Buffer(source, buffer));
        }
Beispiel #2
0
        public void MinkowskiSumAlgorithmBufferTest()
        {
            // two triangles
            Coordinate[] buffer        = new[] { new Coordinate(5, 5), new Coordinate(5, 7), new Coordinate(4, 6) };
            Coordinate[] sourceShell   = new[] { new Coordinate(2, 1), new Coordinate(4, 1), new Coordinate(3, 3), new Coordinate(2, 1) };
            Coordinate[] expectedShell = new[]
            {
                new Coordinate(6, 7),
                new Coordinate(7, 6),
                new Coordinate(9, 6),
                new Coordinate(9, 8),
                new Coordinate(8, 10),
                new Coordinate(7, 9),
            };

            IBasicPolygon expected = new BasicPolygon(expectedShell);
            IBasicPolygon actual   = MinkowskiSumAlgorithm.Buffer(sourceShell, buffer);

            PolygonAlgorithms.IsConvex(actual).ShouldBeTrue();
            actual.Shell.ShouldBe(expected.Shell);

            // triangle and a square
            buffer = new[] { new Coordinate(8, 6), new Coordinate(9, 6), new Coordinate(9, 7), new Coordinate(8, 7) };

            sourceShell = new[] { new Coordinate(3, 4), new Coordinate(5, 4), new Coordinate(4, 6), new Coordinate(3, 4) };

            expectedShell = new[]
            {
                new Coordinate(11, 11),
                new Coordinate(11, 10),
                new Coordinate(13, 10),
                new Coordinate(14, 10),
                new Coordinate(14, 11),
                new Coordinate(13, 13),
                new Coordinate(12, 13),
                new Coordinate(11, 11)
            };

            expected = new BasicPolygon(expectedShell);
            actual   = MinkowskiSumAlgorithm.Buffer(sourceShell, buffer);

            PolygonAlgorithms.IsConvex(actual).ShouldBeTrue();
            actual.Shell.ShouldBe(expected.Shell);

            // square and circle of 4 points (square)
            buffer = new[] { new Coordinate(8, 6), new Coordinate(9, 6), new Coordinate(9, 7), new Coordinate(8, 7), new Coordinate(8, 6) };

            expectedShell = new[]
            {
                new Coordinate(6, 6),
                new Coordinate(8, 4),
                new Coordinate(9, 4),
                new Coordinate(11, 6),
                new Coordinate(11, 7),
                new Coordinate(9, 9),
                new Coordinate(8, 9),
                new Coordinate(6, 7),
                new Coordinate(6, 6)
            };

            expected = new BasicPolygon(expectedShell);
            actual   = MinkowskiSumAlgorithm.Buffer(buffer, 2, 4);

            PolygonAlgorithms.IsConvex(actual).ShouldBeTrue();
            actual.Shell.Count.ShouldBe(expected.Shell.Count);
            for (Int32 coordIndex = 0; coordIndex < expected.Shell.Count; coordIndex++)
            {
                actual.Shell[coordIndex].X.ShouldBe(expected.Shell[coordIndex].X, 0.01);
                actual.Shell[coordIndex].Y.ShouldBe(expected.Shell[coordIndex].Y, 0.01);
            }

            // point and circle (of 4 points)
            IBasicPoint point = new BasicPoint(new Coordinate(1, 1, 0));

            actual = MinkowskiSumAlgorithm.Buffer(point, 2, 4);

            expectedShell = new[]
            {
                new Coordinate(3, 1), new Coordinate(1, 3),
                new Coordinate(-1, 1), new Coordinate(1, -1)
            };

            expected = new BasicPolygon(expectedShell);

            PolygonAlgorithms.IsConvex(actual).ShouldBeTrue();
            actual.Shell.Count.ShouldBe(expected.Shell.Count);
            for (Int32 coordIndex = 0; coordIndex < expected.Shell.Count; coordIndex++)
            {
                actual.Shell[coordIndex].X.ShouldBe(expected.Shell[coordIndex].X, 0.01);
                actual.Shell[coordIndex].Y.ShouldBe(expected.Shell[coordIndex].Y, 0.01);
            }

            // square with a square hole and circle (of 8 points)
            sourceShell = new[]
            {
                new Coordinate(1, 1),
                new Coordinate(9, 1),
                new Coordinate(9, 9),
                new Coordinate(1, 9),
                new Coordinate(1, 1)
            };
            Coordinate[][] sourceHoles = new[]
            {
                new[]
                {
                    new Coordinate(3, 3),
                    new Coordinate(3, 7),
                    new Coordinate(7, 7),
                    new Coordinate(7, 3),
                    new Coordinate(3, 3)
                }
            };

            actual = MinkowskiSumAlgorithm.Buffer(new BasicPolygon(sourceShell, sourceHoles), 1, 8);

            expectedShell = new[]
            {
                new Coordinate(0, 1), new Coordinate(0.3, 0.3),
                new Coordinate(1, 0), new Coordinate(9, 0),
                new Coordinate(9.7, 0.3), new Coordinate(10, 1),
                new Coordinate(10, 9), new Coordinate(9.7, 9.7),
                new Coordinate(9, 10), new Coordinate(1, 10),
                new Coordinate(0.3, 9.7), new Coordinate(0, 9)
            };
            Coordinate[][] expectedHoles = new[]
            {
                new[]
                {
                    new Coordinate(4, 3), new Coordinate(3.7, 3.7),
                    new Coordinate(3, 4), new Coordinate(3, 6),
                    new Coordinate(3.7, 6.3), new Coordinate(4, 7),
                    new Coordinate(6, 7), new Coordinate(6.3, 6.3),
                    new Coordinate(7, 6), new Coordinate(7, 4),
                    new Coordinate(6.3, 3.7), new Coordinate(6, 3)
                }
            };

            expected = new BasicPolygon(expectedShell, expectedHoles);

            actual.Shell.Count.ShouldBe(expected.Shell.Count);
            for (Int32 coordIndex = 0; coordIndex < expected.Shell.Count; coordIndex++)
            {
                actual.Shell[coordIndex].X.ShouldBe(expected.Shell[coordIndex].X, 0.01);
                actual.Shell[coordIndex].Y.ShouldBe(expected.Shell[coordIndex].Y, 0.01);
            }

            actual.HoleCount.ShouldBe(expected.HoleCount);
            for (Int32 holeIndex = 0; holeIndex < expected.HoleCount; holeIndex++)
            {
                actual.Holes[holeIndex].Count.ShouldBe(expected.Holes[holeIndex].Count);
                for (Int32 coordIndex = 0; coordIndex < expected.Holes[holeIndex].Count; coordIndex++)
                {
                    actual.Holes[holeIndex][coordIndex].X.ShouldBe(expected.Holes[holeIndex][coordIndex].X, 0.01);
                    actual.Holes[holeIndex][coordIndex].Y.ShouldBe(expected.Holes[holeIndex][coordIndex].Y, 0.01);
                }
            }

            // line string (2 points) and square
            buffer = new[] { new Coordinate(0, 2), new Coordinate(0, 0), new Coordinate(2, 0), new Coordinate(2, 2) };

            actual        = MinkowskiSumAlgorithm.Buffer(new[] { new Coordinate(0, 4), new Coordinate(2, 4) }, buffer);
            expectedShell = new[]
            {
                new Coordinate(0, 6), new Coordinate(0, 4),
                new Coordinate(2, 4), new Coordinate(4, 4),
                new Coordinate(4, 6), new Coordinate(2, 6)
            };
            expected = new BasicPolygon(expectedShell);

            actual.Shell.ShouldBe(expected.Shell);

            // line string (4 points) and square
            buffer = new[] { new Coordinate(0, 2), new Coordinate(0, 0), new Coordinate(2, 0), new Coordinate(2, 2) };

            actual        = MinkowskiSumAlgorithm.Buffer(new[] { new Coordinate(1, 1), new Coordinate(3, 3), new Coordinate(5, 6), new Coordinate(3, 8) }, buffer);
            expectedShell = new[]
            {
                new Coordinate(1, 3), new Coordinate(1, 1),
                new Coordinate(3, 1), new Coordinate(5, 3),
                new Coordinate(7, 6), new Coordinate(7, 8),
                new Coordinate(5, 10), new Coordinate(3, 10)
            };
            expected = new BasicPolygon(expectedShell);

            actual.Shell.ShouldBe(expected.Shell);

            // concave and convex with no hole in the result
            buffer = new[] { new Coordinate(13, 2), new Coordinate(14, 3), new Coordinate(13, 4), new Coordinate(12, 3) };

            sourceShell = new[]
            {
                new Coordinate(1, 1), new Coordinate(11, 1),
                new Coordinate(11, 6), new Coordinate(8, 6),
                new Coordinate(9, 3), new Coordinate(3, 3),
                new Coordinate(4, 6), new Coordinate(1, 6)
            };

            actual = MinkowskiSumAlgorithm.Buffer(sourceShell, buffer);

            expectedShell = new[]
            {
                new Coordinate(13, 4), new Coordinate(14, 3),
                new Coordinate(24, 3), new Coordinate(25, 4),
                new Coordinate(25, 9), new Coordinate(24, 10),
                new Coordinate(21, 10), new Coordinate(20, 9),
                new Coordinate(20.67, 7), new Coordinate(17.33, 7),
                new Coordinate(18, 9), new Coordinate(17, 10),
                new Coordinate(14, 10), new Coordinate(13, 9)
            };

            expected = new BasicPolygon(expectedShell);
            actual.Shell.Count.ShouldBe(expected.Shell.Count);
            for (Int32 coordIndex = 0; coordIndex < expected.Shell.Count; coordIndex++)
            {
                actual.Shell[coordIndex].X.ShouldBe(expected.Shell[coordIndex].X, 0.01);
                actual.Shell[coordIndex].Y.ShouldBe(expected.Shell[coordIndex].Y, 0.01);
            }

            // convex and concave with no hole in the result
            buffer = new[] { new Coordinate(0, 3), new Coordinate(-3, 0), new Coordinate(0, -3), new Coordinate(3, 0) };

            sourceShell = new[]
            {
                new Coordinate(1, 1), new Coordinate(11, 1),
                new Coordinate(11, 6), new Coordinate(8, 6),
                new Coordinate(9, 3), new Coordinate(3, 3),
                new Coordinate(4, 6), new Coordinate(1, 6)
            };

            actual = MinkowskiSumAlgorithm.Buffer(sourceShell, buffer);

            expectedShell = new[]
            {
                new Coordinate(-2, 1), new Coordinate(1, -2),
                new Coordinate(11, -2), new Coordinate(14, 1),
                new Coordinate(14, 6), new Coordinate(11, 9),
                new Coordinate(8, 9), new Coordinate(6, 7),
                new Coordinate(4, 9), new Coordinate(1, 9),
                new Coordinate(-2, 6)
            };

            expected = new BasicPolygon(expectedShell);
            actual.Shell.Count.ShouldBe(expected.Shell.Count);
            for (Int32 coordIndex = 0; coordIndex < expected.Shell.Count; coordIndex++)
            {
                actual.Shell[coordIndex].X.ShouldBe(expected.Shell[coordIndex].X, 0.01);
                actual.Shell[coordIndex].Y.ShouldBe(expected.Shell[coordIndex].Y, 0.01);
            }

            // convex and concave with hole in the result
            buffer = new[] { new Coordinate(13, 4), new Coordinate(12, 3), new Coordinate(13, 2), new Coordinate(14, 3) };

            sourceShell = new[]
            {
                new Coordinate(1, 1), new Coordinate(11, 1),
                new Coordinate(11, 6), new Coordinate(7, 6),
                new Coordinate(9, 3), new Coordinate(4, 3),
                new Coordinate(6, 6), new Coordinate(1, 6)
            };

            actual        = MinkowskiSumAlgorithm.Buffer(sourceShell, buffer);
            expectedShell = new[]
            {
                new Coordinate(13, 4), new Coordinate(14, 3),
                new Coordinate(24, 3), new Coordinate(25, 4),
                new Coordinate(25, 9), new Coordinate(24, 10),
                new Coordinate(20, 10), new Coordinate(19.5, 9.5),
                new Coordinate(19, 10), new Coordinate(14, 10),
                new Coordinate(13, 9)
            };

            expectedHoles = new[]
            {
                new[]
                {
                    new Coordinate(19.5, 8.25),
                    new Coordinate(20.3, 7),
                    new Coordinate(18.6, 7)
                }
            };

            expected = new BasicPolygon(expectedShell, expectedHoles);
            actual.Shell.Count.ShouldBe(expected.Shell.Count);
            for (Int32 coordIndex = 0; coordIndex < expected.Shell.Count; coordIndex++)
            {
                actual.Shell[coordIndex].X.ShouldBe(expected.Shell[coordIndex].X, 0.01);
                actual.Shell[coordIndex].Y.ShouldBe(expected.Shell[coordIndex].Y, 0.01);
            }

            actual.HoleCount.ShouldBe(expected.HoleCount);
            for (Int32 holeIndex = 0; holeIndex < expected.HoleCount; holeIndex++)
            {
                actual.Holes[holeIndex].Count.ShouldBe(expected.Holes[holeIndex].Count);
                for (Int32 coordIndex = 0; coordIndex < expected.Holes[holeIndex].Count; coordIndex++)
                {
                    actual.Holes[holeIndex][coordIndex].X.ShouldBe(expected.Holes[holeIndex][coordIndex].X, 0.1);
                    actual.Holes[holeIndex][coordIndex].Y.ShouldBe(expected.Holes[holeIndex][coordIndex].Y, 0.1);
                }
            }

            // convex source polygon with hole and a rhombus
            buffer = new[]
            {
                new Coordinate(10, 2),
                new Coordinate(11, 3),
                new Coordinate(10, 4),
                new Coordinate(9, 3)
            };

            sourceShell = new[]
            {
                new Coordinate(1, 1),
                new Coordinate(9, 1),
                new Coordinate(9, 9),
                new Coordinate(1, 9),
                new Coordinate(1, 1)
            };

            sourceHoles = new[]
            {
                new[]
                {
                    new Coordinate(3, 3),
                    new Coordinate(3, 7),
                    new Coordinate(7, 7),
                    new Coordinate(7, 3),
                    new Coordinate(3, 3)
                }
            };

            actual = MinkowskiSumAlgorithm.Buffer(new BasicPolygon(sourceShell, sourceHoles), new BasicPolygon(buffer));

            expectedShell = new[]
            {
                new Coordinate(10, 4), new Coordinate(11, 3),
                new Coordinate(19, 3), new Coordinate(20, 4),
                new Coordinate(20, 12), new Coordinate(19, 13),
                new Coordinate(11, 13), new Coordinate(10, 12)
            };

            expectedHoles = new[]
            {
                new[]
                {
                    new Coordinate(14, 6), new Coordinate(13, 7),
                    new Coordinate(13, 9), new Coordinate(14, 10),
                    new Coordinate(16, 10), new Coordinate(17, 9),
                    new Coordinate(17, 7), new Coordinate(16, 6)
                }
            };

            expected = new BasicPolygon(expectedShell, expectedHoles);

            actual.Shell.Count.ShouldBe(expected.Shell.Count);
            for (Int32 coordIndex = 0; coordIndex < expected.Shell.Count; coordIndex++)
            {
                actual.Shell[coordIndex].X.ShouldBe(expected.Shell[coordIndex].X, 0.01);
                actual.Shell[coordIndex].Y.ShouldBe(expected.Shell[coordIndex].Y, 0.01);
            }

            actual.HoleCount.ShouldBe(expected.HoleCount);
            for (Int32 holeIndex = 0; holeIndex < expected.HoleCount; holeIndex++)
            {
                actual.Shell.Count.ShouldBe(expected.Holes[holeIndex].Count);
                for (Int32 coordIndex = 0; coordIndex < expected.Holes[holeIndex].Count; coordIndex++)
                {
                    actual.Holes[holeIndex][coordIndex].X.ShouldBe(expected.Holes[holeIndex][coordIndex].X, 0.01);
                    actual.Holes[holeIndex][coordIndex].Y.ShouldBe(expected.Holes[holeIndex][coordIndex].Y, 0.01);
                }
            }

            // exceptions
            Should.Throw <ArgumentNullException>(() => MinkowskiSumAlgorithm.Buffer((IBasicPolygon)null, new BasicPolygon(buffer)));
            Should.Throw <ArgumentNullException>(() => MinkowskiSumAlgorithm.Buffer(new BasicPolygon(sourceShell, sourceHoles), null));
        }