Index: Core/Common/test/Core.Common.Base.Test/Geometry/Math2DTest.cs =================================================================== diff -u -r5b63cfab474523f97be999403eb4906a0c376a3d -rd6a913bdd073dce236a3f18d34bf415f41b54a00 --- Core/Common/test/Core.Common.Base.Test/Geometry/Math2DTest.cs (.../Math2DTest.cs) (revision 5b63cfab474523f97be999403eb4906a0c376a3d) +++ Core/Common/test/Core.Common.Base.Test/Geometry/Math2DTest.cs (.../Math2DTest.cs) (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -1074,26 +1074,5 @@ var lineLength = Math2D.ConvertLinePointsToLineSegments(lineGeometryPoints).Sum(s => s.Length); return relativeLengths.Select(l => lineLength * l).ToArray(); } - - private class Point2DComparerWithTolerance : IComparer, IComparer - { - private readonly double tolerance; - - public Point2DComparerWithTolerance(double tolerance) - { - this.tolerance = tolerance; - } - - public int Compare(object x, object y) - { - return Compare(x as Point2D, y as Point2D); - } - - public int Compare(Point2D p0, Point2D p1) - { - double diff = p0.GetEuclideanDistanceTo(p1); - return Math.Abs(diff) < tolerance ? 0 : 1; - } - } } } \ No newline at end of file Index: Core/Common/test/Core.Common.TestUtil.Test/Core.Common.TestUtil.Test.csproj =================================================================== diff -u -r2ae1c9433c3c28b32105b9778b682b5e512a0f00 -rd6a913bdd073dce236a3f18d34bf415f41b54a00 --- Core/Common/test/Core.Common.TestUtil.Test/Core.Common.TestUtil.Test.csproj (.../Core.Common.TestUtil.Test.csproj) (revision 2ae1c9433c3c28b32105b9778b682b5e512a0f00) +++ Core/Common/test/Core.Common.TestUtil.Test/Core.Common.TestUtil.Test.csproj (.../Core.Common.TestUtil.Test.csproj) (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -53,6 +53,7 @@ + True True @@ -66,6 +67,10 @@ + + {3bbfd65b-b277-4e50-ae6d-bd24c3434609} + Core.Common.Base + {D749EE4C-CE50-4C17-BF01-9A953028C126} Core.Common.TestUtil Index: Core/Common/test/Core.Common.TestUtil.Test/Point2DComparerWithToleranceTest.cs =================================================================== diff -u --- Core/Common/test/Core.Common.TestUtil.Test/Point2DComparerWithToleranceTest.cs (revision 0) +++ Core/Common/test/Core.Common.TestUtil.Test/Point2DComparerWithToleranceTest.cs (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -0,0 +1,69 @@ +using Core.Common.Base.Geometry; + +using NUnit.Framework; + +namespace Core.Common.TestUtil.Test +{ + [TestFixture] + public class Point2DComparerWithToleranceTest + { + [Test] + public void Compare_SameInstance_ReturnZero() + { + // Setup + var point = new Point2D(1.1, 2.2); + + // Call + int result = new Point2DComparerWithTolerance(0).Compare(point, point); + + // Assert + Assert.AreEqual(0, result); + } + + [Test] + public void Compare_EqualInstances_ReturnZero() + { + // Setup + const double x = 1.1; + const double y = 2.2; + var point1 = new Point2D(x, y); + var point2 = new Point2D(x, y); + + // Call + int result = new Point2DComparerWithTolerance(0).Compare(point1, point2); + + // Assert + Assert.AreEqual(0, result); + } + + [Test] + [TestCase(1.1)] + [TestCase(7.8)] + public void Compare_DistanceBetweenPointsWithinTolerance_ReturnZero(double tolerance) + { + // Setup + var point1 = new Point2D(1.1, 2.2); + var point2 = new Point2D(1.1, 3.3); + + // Call + int result = new Point2DComparerWithTolerance(tolerance).Compare(point1, point2); + + // Assert + Assert.AreEqual(0, result); + } + + [Test] + public void Compare_DistanceBetweenPointsExceedsTolerance_ReturnOne() + { + // Setup + var point1 = new Point2D(1.1, 2.2); + var point2 = new Point2D(1.1, 3.3); + + // Call + int result = new Point2DComparerWithTolerance(1.1-1e-6).Compare(point1, point2); + + // Assert + Assert.AreEqual(1, result); + } + } +} \ No newline at end of file Index: Core/Common/test/Core.Common.TestUtil/Core.Common.TestUtil.csproj =================================================================== diff -u -rfc38d18fc6ff1749476da0ea43281d5d80568283 -rd6a913bdd073dce236a3f18d34bf415f41b54a00 --- Core/Common/test/Core.Common.TestUtil/Core.Common.TestUtil.csproj (.../Core.Common.TestUtil.csproj) (revision fc38d18fc6ff1749476da0ea43281d5d80568283) +++ Core/Common/test/Core.Common.TestUtil/Core.Common.TestUtil.csproj (.../Core.Common.TestUtil.csproj) (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -89,6 +89,7 @@ + True Index: Core/Common/test/Core.Common.TestUtil/Point2DComparerWithTolerance.cs =================================================================== diff -u --- Core/Common/test/Core.Common.TestUtil/Point2DComparerWithTolerance.cs (revision 0) +++ Core/Common/test/Core.Common.TestUtil/Point2DComparerWithTolerance.cs (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -0,0 +1,37 @@ +using System.Collections; +using System.Collections.Generic; + +using Core.Common.Base.Geometry; + +namespace Core.Common.TestUtil +{ + /// + /// This class compares the distance of two instances to determine + /// if there are equal to each other or not. This class shouldn't be used to sort point + /// instances. + /// + public class Point2DComparerWithTolerance : IComparer, IComparer + { + private readonly double tolerance; + + /// + /// Initializes a new instance of the class. + /// + /// The tolerance. + public Point2DComparerWithTolerance(double tolerance) + { + this.tolerance = tolerance; + } + + public int Compare(object x, object y) + { + return Compare(x as Point2D, y as Point2D); + } + + public int Compare(Point2D p0, Point2D p1) + { + double diff = p0.GetEuclideanDistanceTo(p1); + return diff <= tolerance ? 0 : 1; + } + } +} \ No newline at end of file Index: Core/Components/src/Core.Components.DotSpatial/Converter/MapDataConverter.cs =================================================================== diff -u -r473efe5f1b2aff98ffc7ad1d826c3ef90f77a7a6 -rd6a913bdd073dce236a3f18d34bf415f41b54a00 --- Core/Components/src/Core.Components.DotSpatial/Converter/MapDataConverter.cs (.../MapDataConverter.cs) (revision 473efe5f1b2aff98ffc7ad1d826c3ef90f77a7a6) +++ Core/Components/src/Core.Components.DotSpatial/Converter/MapDataConverter.cs (.../MapDataConverter.cs) (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -21,8 +21,12 @@ using System; using System.Collections.Generic; +using System.Linq; + +using Core.Common.Base.Geometry; using Core.Components.Gis.Data; using DotSpatial.Controls; +using DotSpatial.Topology; namespace Core.Components.DotSpatial.Converter { @@ -57,5 +61,10 @@ /// The data to transform into one or more . /// A new of . protected abstract IList Convert(T data); + + protected static IEnumerable ConvertPoint2DElementsToCoordinates(IEnumerable points) + { + return points.Select(point => new Coordinate(point.X, point.Y)); + } } } \ No newline at end of file Index: Core/Components/src/Core.Components.DotSpatial/Converter/MapLineDataConverter.cs =================================================================== diff -u -r04b631b486b742c5339deb1d5504bb13ab5e248d -rd6a913bdd073dce236a3f18d34bf415f41b54a00 --- Core/Components/src/Core.Components.DotSpatial/Converter/MapLineDataConverter.cs (.../MapLineDataConverter.cs) (revision 04b631b486b742c5339deb1d5504bb13ab5e248d) +++ Core/Components/src/Core.Components.DotSpatial/Converter/MapLineDataConverter.cs (.../MapLineDataConverter.cs) (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -33,7 +33,8 @@ namespace Core.Components.DotSpatial.Converter { /// - /// The converter that converts into a containing a . + /// The converter that converts into a + /// containing a . /// public class MapLineDataConverter : MapDataConverter { @@ -48,7 +49,7 @@ foreach (var mapGeometry in mapFeature.MapGeometries) { - var coordinates = mapGeometry.PointCollections.First().Select(p => new Coordinate(p.X, p.Y)); + var coordinates = ConvertPoint2DElementsToCoordinates(mapGeometry.PointCollections.First()); IBasicLineString lineString = new LineString(coordinates); geometryList.Add(lineString); } Index: Core/Components/src/Core.Components.DotSpatial/Converter/MapPointDataConverter.cs =================================================================== diff -u -r04b631b486b742c5339deb1d5504bb13ab5e248d -rd6a913bdd073dce236a3f18d34bf415f41b54a00 --- Core/Components/src/Core.Components.DotSpatial/Converter/MapPointDataConverter.cs (.../MapPointDataConverter.cs) (revision 04b631b486b742c5339deb1d5504bb13ab5e248d) +++ Core/Components/src/Core.Components.DotSpatial/Converter/MapPointDataConverter.cs (.../MapPointDataConverter.cs) (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -22,6 +22,7 @@ using System.Collections.Generic; using System.Linq; using Core.Components.Gis.Data; +using Core.Components.Gis.Features; using Core.Components.Gis.Style; using DotSpatial.Controls; using DotSpatial.Data; @@ -31,17 +32,18 @@ namespace Core.Components.DotSpatial.Converter { /// - /// The converter that converts into a containing one or more . + /// The converter that converts into a + /// containing one or more . /// public class MapPointDataConverter : MapDataConverter { protected override IList Convert(MapPointData data) { var featureSet = new FeatureSet(FeatureType.Point); - foreach (var point in data.Features.SelectMany(features => features.MapGeometries.SelectMany(mapGeometry => mapGeometry.PointCollections.First()))) + foreach (Coordinate coordinate in GetAllPointCoordinates(data)) { - featureSet.Features.Add(new Coordinate(point.X, point.Y)); + featureSet.Features.Add(coordinate); } var layer = new MapPointLayer(featureSet) @@ -58,6 +60,16 @@ }; } + private static IEnumerable GetAllPointCoordinates(FeatureBasedMapData data) + { + return data.Features.SelectMany(GetAllMapFeatureCoordinates); + } + + private static IEnumerable GetAllMapFeatureCoordinates(MapFeature features) + { + return features.MapGeometries.SelectMany(mapGeometry => ConvertPoint2DElementsToCoordinates(mapGeometry.PointCollections.First())); + } + private void CreateStyle(MapPointLayer layer, PointStyle style) { if (style != null) Index: Core/Components/src/Core.Components.DotSpatial/Converter/MapPolygonDataConverter.cs =================================================================== diff -u -r04b631b486b742c5339deb1d5504bb13ab5e248d -rd6a913bdd073dce236a3f18d34bf415f41b54a00 --- Core/Components/src/Core.Components.DotSpatial/Converter/MapPolygonDataConverter.cs (.../MapPolygonDataConverter.cs) (revision 04b631b486b742c5339deb1d5504bb13ab5e248d) +++ Core/Components/src/Core.Components.DotSpatial/Converter/MapPolygonDataConverter.cs (.../MapPolygonDataConverter.cs) (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -20,9 +20,9 @@ // All rights reserved. using System.Collections.Generic; -using System.Drawing.Drawing2D; using System.Linq; +using Core.Common.Base.Geometry; using Core.Components.Gis.Data; using Core.Components.Gis.Style; using DotSpatial.Controls; @@ -33,7 +33,8 @@ namespace Core.Components.DotSpatial.Converter { /// - /// The converter that converts into a containing a . + /// The converter that converts into a + /// containing a . /// public class MapPolygonDataConverter : MapDataConverter { @@ -48,8 +49,19 @@ foreach (var mapGeometry in mapFeature.MapGeometries) { - var coordinates = mapGeometry.PointCollections.First().Select(p => new Coordinate(p.X, p.Y)); - IPolygon polygon = new Polygon(coordinates); + IEnumerable[] pointCollections = mapGeometry.PointCollections.ToArray(); + + IEnumerable outerRingCoordinates = ConvertPoint2DElementsToCoordinates(pointCollections[0]); + ILinearRing outerRing = new LinearRing(outerRingCoordinates); + + ILinearRing[] innerRings = new ILinearRing[pointCollections.Length - 1]; + for (int i = 1; i < pointCollections.Length; i++) + { + IEnumerable innerRingCoordinates = ConvertPoint2DElementsToCoordinates(pointCollections[i]); + innerRings[i-1] = new LinearRing(innerRingCoordinates); + } + + IPolygon polygon = new Polygon(outerRing, innerRings); geometryList.Add(polygon); } Index: Core/Components/src/Core.Components.Gis.IO/Readers/PolygonShapeFileReader.cs =================================================================== diff -u -r04b631b486b742c5339deb1d5504bb13ab5e248d -rd6a913bdd073dce236a3f18d34bf415f41b54a00 --- Core/Components/src/Core.Components.Gis.IO/Readers/PolygonShapeFileReader.cs (.../PolygonShapeFileReader.cs) (revision 04b631b486b742c5339deb1d5504bb13ab5e248d) +++ Core/Components/src/Core.Components.Gis.IO/Readers/PolygonShapeFileReader.cs (.../PolygonShapeFileReader.cs) (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -22,12 +22,14 @@ using System; using System.Collections.Generic; using System.Linq; + using Core.Common.Base.Geometry; using Core.Common.IO.Exceptions; using Core.Common.Utils.Builders; using Core.Components.Gis.Data; using Core.Components.Gis.Features; using Core.Components.Gis.Geometries; + using DotSpatial.Data; using DotSpatial.Topology; @@ -78,7 +80,8 @@ try { IFeature polygonFeature = GetFeature(readIndex); - return ConvertPolygonFeatureToMapPolygonData(polygonFeature, !string.IsNullOrWhiteSpace(name) ? name : GisIOResources.PolygonShapeFileReader_ReadLine_Polygon); + string featureName = GetFeatureName(name); + return ConvertPolygonFeatureToMapPolygonData(polygonFeature, featureName); } finally { @@ -94,14 +97,20 @@ featureList.Add(ReadFeatureLine()); } - return ConvertPolygonFeaturesToMapPointData(featureList, !string.IsNullOrWhiteSpace(name) ? name : GisIOResources.PolygonShapeFileReader_ReadLine_Polygon); + string featureName = GetFeatureName(name); + return ConvertPolygonFeaturesToMapPointData(featureList, featureName); } public override IFeature GetFeature(int index) { return ShapeFile.Features[index]; } + private static string GetFeatureName(string name) + { + return !string.IsNullOrWhiteSpace(name) ? name : GisIOResources.PolygonShapeFileReader_ReadLine_Polygon; + } + private IFeature ReadFeatureLine() { try @@ -117,7 +126,10 @@ private FeatureBasedMapData ConvertPolygonFeatureToMapPolygonData(IFeature polygonFeature, string name) { var mapFeature = CreateMapFeatureForPolygonFeature(polygonFeature); - IEnumerable mapFeatures = new [] { mapFeature }; + IEnumerable mapFeatures = new[] + { + mapFeature + }; return new MapPolygonData(mapFeatures, name); } @@ -133,21 +145,22 @@ for (int i = 0; i < polygonFeature.BasicGeometry.NumGeometries; i++) { - IBasicGeometry polygonFeatureGeometry = polygonFeature.BasicGeometry.GetBasicGeometryN(i); + var basicPolygon = (IBasicPolygon)polygonFeature.BasicGeometry.GetBasicGeometryN(i); - MapGeometry mapGeometry = new MapGeometry(GetMapGeometryPointCollections(polygonFeatureGeometry.Coordinates)); + MapGeometry mapGeometry = new MapGeometry(GetMapGeometryPointCollections(basicPolygon)); geometries.Add(mapGeometry); } return new MapFeature(geometries); } - private static IEnumerable> GetMapGeometryPointCollections(IEnumerable polygonCoordinates) + private static IEnumerable> GetMapGeometryPointCollections(IBasicPolygon polygon) { - return new[] + yield return polygon.Shell.Coordinates.Select(c => new Point2D(c.X, c.Y)); + foreach (IBasicLineString hole in polygon.Holes) { - polygonCoordinates.Select(c => new Point2D(c.X, c.Y)) - }; + yield return hole.Coordinates.Select(c => new Point2D(c.X, c.Y)); + } } } } \ No newline at end of file Index: Core/Components/src/Core.Components.Gis/Data/MapPolygonData.cs =================================================================== diff -u -r04b631b486b742c5339deb1d5504bb13ab5e248d -rd6a913bdd073dce236a3f18d34bf415f41b54a00 --- Core/Components/src/Core.Components.Gis/Data/MapPolygonData.cs (.../MapPolygonData.cs) (revision 04b631b486b742c5339deb1d5504bb13ab5e248d) +++ Core/Components/src/Core.Components.Gis/Data/MapPolygonData.cs (.../MapPolygonData.cs) (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -62,16 +62,16 @@ { base.ValidateFeatures(features); - if (HasFeatureWithMultiplePointCollections(features)) + if (HasFeatureWithEmptyPointCollections(features)) { throw new ArgumentException("MapPolygonData only accept MapFeature instances whose MapGeometries contain a single point-collection."); } } - private static bool HasFeatureWithMultiplePointCollections(IEnumerable lineFeatures) + private static bool HasFeatureWithEmptyPointCollections(IEnumerable lineFeatures) { return lineFeatures.SelectMany(feature => feature.MapGeometries) - .Any(geometry => geometry.PointCollections.Count() != 1); + .Any(geometry => !geometry.PointCollections.Any()); } } } \ No newline at end of file Index: Core/Components/test/Core.Components.DotSpatial.Test/Converter/MapPolygonDataConverterTest.cs =================================================================== diff -u -r04b631b486b742c5339deb1d5504bb13ab5e248d -rd6a913bdd073dce236a3f18d34bf415f41b54a00 --- Core/Components/test/Core.Components.DotSpatial.Test/Converter/MapPolygonDataConverterTest.cs (.../MapPolygonDataConverterTest.cs) (revision 04b631b486b742c5339deb1d5504bb13ab5e248d) +++ Core/Components/test/Core.Components.DotSpatial.Test/Converter/MapPolygonDataConverterTest.cs (.../MapPolygonDataConverterTest.cs) (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -110,6 +110,98 @@ } [Test] + public void Convert_MapFeatureWithSimplePolygon_ReturnPolygonLayerWithOnePolygonFeature() + { + // Setup + Point2D[] outerRingPoints = CreateRectangularRing(0.0, 10.0); + var feature = new List + { + new MapFeature(new List + { + new MapGeometry(new[] + { + outerRingPoints + }) + }) + }; + const string layerName = "test data"; + var polygonData = new MapPolygonData(feature, layerName); + + // Call + IList layers = new MapPolygonDataConverter().Convert(polygonData); + + // Assert + Assert.AreEqual(1, layers.Count); + var polygonLayer = (MapPolygonLayer)layers[0]; + Assert.AreEqual(polygonData.IsVisible, polygonLayer.IsVisible); + Assert.AreEqual(layerName, polygonLayer.Name); + Assert.AreEqual(FeatureType.Polygon, polygonLayer.FeatureSet.FeatureType); + Assert.AreEqual(1, polygonLayer.FeatureSet.Features.Count); + + var featureGeometry = (IMultiPolygon)polygonLayer.FeatureSet.Features[0].BasicGeometry; + Assert.AreEqual(1, featureGeometry.NumGeometries); + + var polygonGeometry = (IBasicPolygon)featureGeometry.Geometries[0]; + CollectionAssert.AreEqual(outerRingPoints, polygonGeometry.Shell.Coordinates.Select(c => new Point2D(c.X, c.Y))); + CollectionAssert.IsEmpty(polygonGeometry.Holes); + } + + [Test] + public void Convert_MapFeatureWithPolygonWithHoles_ReturnPolygonLayerWithOnePolygonFeature() + { + // Setup + Point2D[] outerRingPoints = CreateRectangularRing(0.0, 10.0); + Point2D[] innerRing1Points = CreateRectangularRing(2.0, 3.0); + Point2D[] innerRing2Points = CreateRectangularRing(8.0, 5.0); + var feature = new List + { + new MapFeature(new List + { + new MapGeometry(new[] + { + outerRingPoints, + innerRing1Points, + innerRing2Points + }) + }) + }; + const string layerName = "test data"; + var polygonData = new MapPolygonData(feature, layerName); + + // Call + IList layers = new MapPolygonDataConverter().Convert(polygonData); + + // Assert + Assert.AreEqual(1, layers.Count); + var polygonLayer = (MapPolygonLayer)layers[0]; + Assert.AreEqual(polygonData.IsVisible, polygonLayer.IsVisible); + Assert.AreEqual(layerName, polygonLayer.Name); + Assert.AreEqual(FeatureType.Polygon, polygonLayer.FeatureSet.FeatureType); + Assert.AreEqual(1, polygonLayer.FeatureSet.Features.Count); + + var featureGeometry = (IMultiPolygon)polygonLayer.FeatureSet.Features[0].BasicGeometry; + Assert.AreEqual(1, featureGeometry.NumGeometries); + + var polygonGeometry = (IBasicPolygon)featureGeometry.Geometries[0]; + CollectionAssert.AreEqual(outerRingPoints, polygonGeometry.Shell.Coordinates.Select(c => new Point2D(c.X, c.Y))); + Assert.AreEqual(2, polygonGeometry.Holes.Count); + CollectionAssert.AreEqual(innerRing1Points, polygonGeometry.Holes.ElementAt(0).Coordinates.Select(c => new Point2D(c.X, c.Y))); + CollectionAssert.AreEqual(innerRing2Points, polygonGeometry.Holes.ElementAt(1).Coordinates.Select(c => new Point2D(c.X, c.Y))); + } + + private static Point2D[] CreateRectangularRing(double xy1, double xy2) + { + return new[] + { + new Point2D(xy1, xy1), + new Point2D(xy2, xy1), + new Point2D(xy2, xy2), + new Point2D(xy1, xy2), + new Point2D(xy1, xy1) + }; + } + + [Test] public void Convert_MultipleFeatures_ConvertsAllFeatures() { // Setup Index: Core/Components/test/Core.Components.Gis.IO.Test/Readers/PolygonShapeFileReaderTest.cs =================================================================== diff -u -r04b631b486b742c5339deb1d5504bb13ab5e248d -rd6a913bdd073dce236a3f18d34bf415f41b54a00 --- Core/Components/test/Core.Components.Gis.IO.Test/Readers/PolygonShapeFileReaderTest.cs (.../PolygonShapeFileReaderTest.cs) (revision 04b631b486b742c5339deb1d5504bb13ab5e248d) +++ Core/Components/test/Core.Components.Gis.IO.Test/Readers/PolygonShapeFileReaderTest.cs (.../PolygonShapeFileReaderTest.cs) (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -90,6 +90,22 @@ } [Test] + public void GetNumberOfLines_ShapeFileWithOnePolygonWithHoles_ReturnOne() + { + // Setup + string shapeWithOnePolygonWithHoles = TestHelper.GetTestDataPath(TestDataPath.Core.Components.Gis.IO, + "Single_Polygon_with_two_holes_with_ID.shp"); + using (var reader = new PolygonShapeFileReader(shapeWithOnePolygonWithHoles)) + { + // Call + var count = reader.GetNumberOfLines(); + + // Assert + Assert.AreEqual(1, count); + } + } + + [Test] public void GetNumberOfLines_ShapeFileWithMultipleLineFeatures_ReturnThatNumberOfFeatures() { // Setup @@ -173,6 +189,68 @@ } [Test] + public void ReadLine_ShapeFileWithOnePolygonWithTwoHolesFeature_ReturnShape() + { + // Setup + string shapeWithOnePolygonWithHoles = TestHelper.GetTestDataPath(TestDataPath.Core.Components.Gis.IO, + "Single_Polygon_with_two_holes_with_ID.shp"); + using (var reader = new PolygonShapeFileReader(shapeWithOnePolygonWithHoles)) + { + // Call + MapPolygonData polygon = (MapPolygonData)reader.ReadLine(); + + // Assert + Assert.IsNotNull(polygon); + MapFeature[] polygonFeatures = polygon.Features.ToArray(); + Assert.AreEqual(1, polygonFeatures.Length); + + MapGeometry[] polygonGeometries = polygonFeatures[0].MapGeometries.ToArray(); + Assert.AreEqual(1, polygonGeometries.Length); + + IEnumerable[] polygonPointCollections = polygonGeometries[0].PointCollections.ToArray(); + Assert.AreEqual(3, polygonPointCollections.Length); + + var pointComparer = new Point2DComparerWithTolerance(1e-6); + + var outerRingPoints = polygonPointCollections[0].ToArray(); + var expectedOuterRingPoints = new[] + { + new Point2D(-866522.534211655, -5517886.97470326), + new Point2D(-569923.527795405, -5517539.26191731), + new Point2D(-565403.261578042, -5759199.6481533), + new Point2D(-865479.395853802, -5759199.6481533), + new Point2D(-866522.534211655, -5517886.97470326) + }; + CollectionAssert.AreEqual(expectedOuterRingPoints, outerRingPoints, + pointComparer); + + var innerRing1Points = polygonPointCollections[1].ToArray(); + var expectedInnerRing1Points = new[] + { + new Point2D(-829317.266114892, -5539445.16743223), + new Point2D(-831055.830044648, -5604119.74561913), + new Point2D(-746213.91027259, -5604815.17119103), + new Point2D(-747257.048630444, -5538749.74186033), + new Point2D(-829317.266114892, -5539445.16743223) + }; + CollectionAssert.AreEqual(expectedInnerRing1Points, innerRing1Points, + pointComparer); + + var innerRing2Points = polygonPointCollections[2].ToArray(); + var expectedInnerRing2Points = new[] + { + new Point2D(-715615.185108898, -5673314.59002339), + new Point2D(-657547.149855071, -5731730.33806316), + new Point2D(-591829.433310322, -5686875.38867548), + new Point2D(-648506.617420344, -5624634.79999024), + new Point2D(-715615.185108898, -5673314.59002339) + }; + CollectionAssert.AreEqual(expectedInnerRing2Points, innerRing2Points, + pointComparer); + } + } + + [Test] public void ReadLine_ShapeFileWithSingeFeatureMultiplePolygons_ReturnShapes() { // Setup Index: Core/Components/test/Core.Components.Gis.IO.Test/test-data/Single_Polygon_with_two_holes_with_ID.dbf =================================================================== diff -u Binary files differ Index: Core/Components/test/Core.Components.Gis.IO.Test/test-data/Single_Polygon_with_two_holes_with_ID.prj =================================================================== diff -u --- Core/Components/test/Core.Components.Gis.IO.Test/test-data/Single_Polygon_with_two_holes_with_ID.prj (revision 0) +++ Core/Components/test/Core.Components.Gis.IO.Test/test-data/Single_Polygon_with_two_holes_with_ID.prj (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -0,0 +1 @@ +PROJCS["Amersfoort_RD_New",GEOGCS["GCS_Amersfoort",DATUM["D_Amersfoort",SPHEROID["Bessel_1841",6377397.155,299.1528128]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Double_Stereographic"],PARAMETER["latitude_of_origin",52.15616055555555],PARAMETER["central_meridian",5.38763888888889],PARAMETER["scale_factor",0.9999079],PARAMETER["false_easting",155000],PARAMETER["false_northing",463000],UNIT["Meter",1]] \ No newline at end of file Index: Core/Components/test/Core.Components.Gis.IO.Test/test-data/Single_Polygon_with_two_holes_with_ID.qpj =================================================================== diff -u --- Core/Components/test/Core.Components.Gis.IO.Test/test-data/Single_Polygon_with_two_holes_with_ID.qpj (revision 0) +++ Core/Components/test/Core.Components.Gis.IO.Test/test-data/Single_Polygon_with_two_holes_with_ID.qpj (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -0,0 +1 @@ +PROJCS["Amersfoort / RD New",GEOGCS["Amersfoort",DATUM["Amersfoort",SPHEROID["Bessel 1841",6377397.155,299.1528128,AUTHORITY["EPSG","7004"]],TOWGS84[565.417,50.3319,465.552,-0.398957,0.343988,-1.8774,4.0725],AUTHORITY["EPSG","6289"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4289"]],PROJECTION["Oblique_Stereographic"],PARAMETER["latitude_of_origin",52.15616055555555],PARAMETER["central_meridian",5.38763888888889],PARAMETER["scale_factor",0.9999079],PARAMETER["false_easting",155000],PARAMETER["false_northing",463000],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH],AUTHORITY["EPSG","28992"]] Index: Core/Components/test/Core.Components.Gis.IO.Test/test-data/Single_Polygon_with_two_holes_with_ID.shp =================================================================== diff -u Binary files differ Index: Core/Components/test/Core.Components.Gis.IO.Test/test-data/Single_Polygon_with_two_holes_with_ID.shx =================================================================== diff -u Binary files differ Index: Core/Components/test/Core.Components.Gis.Test/Data/MapPolygonDataTest.cs =================================================================== diff -u -r04b631b486b742c5339deb1d5504bb13ab5e248d -rd6a913bdd073dce236a3f18d34bf415f41b54a00 --- Core/Components/test/Core.Components.Gis.Test/Data/MapPolygonDataTest.cs (.../MapPolygonDataTest.cs) (revision 04b631b486b742c5339deb1d5504bb13ab5e248d) +++ Core/Components/test/Core.Components.Gis.Test/Data/MapPolygonDataTest.cs (.../MapPolygonDataTest.cs) (revision d6a913bdd073dce236a3f18d34bf415f41b54a00) @@ -50,22 +50,14 @@ } [Test] - [TestCase(0)] - [TestCase(2)] - [TestCase(5)] - public void Constructor_InvalidGeometryConfiguration_ThrowArgumentException(int numberOfPointCollections) + public void Constructor_EmptyPointsCollection_ThrowArgumentException() { // Setup - var invalidPointsCollections = new IEnumerable[numberOfPointCollections]; - for (int i = 0; i < numberOfPointCollections; i++) - { - invalidPointsCollections[i] = CreateOuterRingPoint2Ds(); - } var features = new[] { new MapFeature(new[] { - new MapGeometry(invalidPointsCollections), + new MapGeometry(Enumerable.Empty>()) }) }; @@ -108,7 +100,10 @@ { new MapFeature(new Collection { - new MapGeometry(CreateTestPointsCollections()) + new MapGeometry(new[] + { + CreateOuterRingPoints() + }) }) }; @@ -118,10 +113,48 @@ // Assert Assert.IsInstanceOf(data); Assert.AreNotSame(features, data.Features); - CollectionAssert.AreEqual(CreateTestPointsCollections(), data.Features.First().MapGeometries.First().PointCollections); + CollectionAssert.AreEqual(new[] + { + CreateOuterRingPoints() + }, data.Features.First().MapGeometries.First().PointCollections); } [Test] + public void Constructor_WithOuterAndInnerRingPoints_CreatesNewMapPointData() + { + // Setup + Point2D[] outerRingPoints = CreateOuterRingPoints(); + Point2D[] innerRing1Points = CreateInnerRingPoints(2.0, 4.0); + Point2D[] innerRing2Points = CreateInnerRingPoints(8.0, 5.0); + var features = new[] + { + new MapFeature(new[] + { + new MapGeometry(new[] + { + outerRingPoints, + innerRing1Points, + innerRing2Points + }) + }) + }; + + // Call + var data = new MapPolygonData(features, "test data"); + + // Assert + Assert.IsInstanceOf(data); + Assert.AreNotSame(features, data.Features); + + MapGeometry mapFeatureGeometry = data.Features.First().MapGeometries.First(); + var pointCollections = mapFeatureGeometry.PointCollections.ToArray(); + Assert.AreEqual(3, pointCollections.Length); + CollectionAssert.AreEqual(outerRingPoints, pointCollections[0]); + CollectionAssert.AreEqual(innerRing1Points, pointCollections[1]); + CollectionAssert.AreEqual(innerRing2Points, pointCollections[2]); + } + + [Test] public void Constructor_WithName_SetsName() { // Setup @@ -144,21 +177,27 @@ Assert.AreEqual(name, data.Name); } - private static IEnumerable> CreateTestPointsCollections() + private Point2D[] CreateOuterRingPoints() { return new[] { - CreateOuterRingPoint2Ds() + new Point2D(0.0, 0.0), + new Point2D(10.0, 0.0), + new Point2D(10.0, 10.0), + new Point2D(0.0, 10.0), + new Point2D(0.0, 0.0) }; } - private static Point2D[] CreateOuterRingPoint2Ds() + private Point2D[] CreateInnerRingPoints(double lowerLeftCubeX, double upperRightCubeX) { - return new [] + return new[] { - new Point2D(0.0, 1.1), - new Point2D(1.0, 2.1), - new Point2D(1.6, 1.6) + new Point2D(lowerLeftCubeX, lowerLeftCubeX), + new Point2D(upperRightCubeX, lowerLeftCubeX), + new Point2D(upperRightCubeX, upperRightCubeX), + new Point2D(lowerLeftCubeX, upperRightCubeX), + new Point2D(lowerLeftCubeX, lowerLeftCubeX) }; } }