Index: Core/Components/src/Core.Components.DotSpatial/Converter/MapLineDataConverter.cs =================================================================== diff -u -r83ac738ad69ef53eba6ca4f647657e5b7f024b96 -rc3e01df6dfac668c5e9bf1e9702cca333e1bbe19 --- Core/Components/src/Core.Components.DotSpatial/Converter/MapLineDataConverter.cs (.../MapLineDataConverter.cs) (revision 83ac738ad69ef53eba6ca4f647657e5b7f024b96) +++ Core/Components/src/Core.Components.DotSpatial/Converter/MapLineDataConverter.cs (.../MapLineDataConverter.cs) (revision c3e01df6dfac668c5e9bf1e9702cca333e1bbe19) @@ -19,12 +19,16 @@ // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. +using System; using System.Collections.Generic; +using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using Core.Common.Base.Geometry; using Core.Components.Gis.Data; using Core.Components.Gis.Features; +using Core.Components.Gis.Theme; +using Core.Components.Gis.Theme.Criteria; using DotSpatial.Controls; using DotSpatial.Data; using DotSpatial.Symbology; @@ -70,6 +74,76 @@ return GetLineString(factory, pointsToConvert); } + protected override IFeatureScheme CreateScheme(MapLineData mapData) + { + LineSymbolizer symbolizer = CreateLineSymbolizer(mapData, mapData.Style.Color); + + var scheme = new LineScheme(); + scheme.ClearCategories(); + scheme.AddCategory(new LineCategory(symbolizer)); + + MapTheme mapTheme = mapData.MapTheme; + Dictionary attributeMapping = GetAttributeMapping(mapData); + int attributeIndex = attributeMapping[mapTheme.AttributeName]; + foreach (CategoryTheme categoryTheme in mapTheme.CategoryThemes) + { + var category = new LineCategory(CreateLineSymbolizer(mapData, categoryTheme.Color)); + category.SetColor(categoryTheme.Color); + category.FilterExpression = CreateFilterExpression(attributeIndex, categoryTheme.Criteria); + scheme.AddCategory(category); + } + + return scheme; + } + + private static LineSymbolizer CreateLineSymbolizer(MapLineData mapData, Color color) + { + return new LineSymbolizer(color, + color, + mapData.Style.Width, + MapDataHelper.Convert(mapData.Style.DashStyle), + LineCap.Round); + } + + private static string CreateFilterExpression(int attributeIndex, ICriteria criteria) + { + var valueCriteria = criteria as ValueCriteria; + if (valueCriteria != null) + { + ValueCriteriaOperator valueOperator = valueCriteria.ValueOperator; + switch (valueOperator) + { + case ValueCriteriaOperator.EqualValue: + return $"[{attributeIndex}] = {valueCriteria.Value}"; + case ValueCriteriaOperator.UnequalValue: + return $"[{attributeIndex}] != {valueCriteria.Value}"; + default: + throw new NotSupportedException($"The enum value {nameof(ValueCriteriaOperator)}.{valueOperator} is not supported."); + } + } + + var rangeCriteria = criteria as RangeCriteria; + if (rangeCriteria != null) + { + RangeCriteriaOperator rangeCriteriaOperator = rangeCriteria.RangeCriteriaOperator; + switch (rangeCriteriaOperator) + { + case RangeCriteriaOperator.AllBoundsInclusive: + return $"[{attributeIndex}] >= {rangeCriteria.LowerBound} AND [{attributeIndex}] <= {rangeCriteria.UpperBound}"; + case RangeCriteriaOperator.LowerBoundInclusive: + return $"[{attributeIndex}] >= {rangeCriteria.LowerBound} AND [{attributeIndex}] < {rangeCriteria.UpperBound}"; + case RangeCriteriaOperator.UpperBoundInclusive: + return $"[{attributeIndex}] > {rangeCriteria.LowerBound} AND [{attributeIndex}] <= {rangeCriteria.UpperBound}"; + case RangeCriteriaOperator.AllBoundsExclusive: + return $"[{attributeIndex}] > {rangeCriteria.LowerBound} AND [{attributeIndex}] < {rangeCriteria.UpperBound}"; + default: + throw new NotSupportedException($"The enum value {nameof(RangeCriteriaOperator)}.{rangeCriteriaOperator} is not supported."); + } + } + + throw new NotSupportedException($"Can't convert a {nameof(ICriteria)} of type {criteria.GetType()}"); // TODO WTI-1551: Test this exception + } + private static IBasicLineString GetLineString(IGeometryFactory factory, IEnumerable points) { return factory.CreateLineString(ConvertPoint2DElementsToCoordinates(points).ToArray()); Index: Core/Components/test/Core.Components.DotSpatial.Test/Converter/MapLineDataConverterTest.cs =================================================================== diff -u -r66964d0c53eb0d904f7ada3e3bbc1e9604e241e7 -rc3e01df6dfac668c5e9bf1e9702cca333e1bbe19 --- Core/Components/test/Core.Components.DotSpatial.Test/Converter/MapLineDataConverterTest.cs (.../MapLineDataConverterTest.cs) (revision 66964d0c53eb0d904f7ada3e3bbc1e9604e241e7) +++ Core/Components/test/Core.Components.DotSpatial.Test/Converter/MapLineDataConverterTest.cs (.../MapLineDataConverterTest.cs) (revision c3e01df6dfac668c5e9bf1e9702cca333e1bbe19) @@ -30,6 +30,8 @@ using Core.Components.Gis.Features; using Core.Components.Gis.Geometries; using Core.Components.Gis.Style; +using Core.Components.Gis.Theme; +using Core.Components.Gis.Theme.Criteria; using DotSpatial.Controls; using DotSpatial.Data; using DotSpatial.Symbology; @@ -190,6 +192,201 @@ AssertAreEqual(new LineSymbolizer(expectedColor, expectedColor, width, MapDataHelper.Convert(lineStyle), LineCap.Round), mapLineLayer.Symbolizer); } + [Test] + public void ConvertLayerProperties_MapLineDataWithStyleAndValueCriteria_ConvertDataToMapPointLayer() + { + // Setup + const string metadataAttribute = "Meta"; + var random = new Random(21); + + var unequalCriteria = new ValueCriteria(ValueCriteriaOperator.UnequalValue, + random.NextDouble()); + var equalCriteria = new ValueCriteria(ValueCriteriaOperator.EqualValue, + random.NextDouble()); + var theme = new MapTheme(metadataAttribute, new[] + { + new CategoryTheme(Color.FromKnownColor(random.NextEnum()), + equalCriteria), + new CategoryTheme(Color.FromKnownColor(random.NextEnum()), + unequalCriteria) + }); + + var lineStyle = new LineStyle + { + Color = Color.FromKnownColor(random.NextEnum()), + Width = random.Next(1, 48), + DashStyle = LineDashStyle.DashDotDot + }; + var mapLineData = new MapLineData("test", lineStyle) + { + Features = new[] + { + CreateMapFeatureWithMetaData(metadataAttribute) + }, + MapTheme = theme + }; + + var mapLineLayer = new MapLineLayer(); + + var converter = new MapLineDataConverter(); + + // Call + converter.ConvertLayerProperties(mapLineData, mapLineLayer); + + // Assert + const DashStyle expectedDashStyle = DashStyle.DashDotDot; + ILineSymbolizer expectedSymbolizer = CreateExpectedSymbolizer(lineStyle, + expectedDashStyle, + lineStyle.Color); + + ILineScheme appliedScheme = mapLineLayer.Symbology; + Assert.AreEqual(3, appliedScheme.Categories.Count); + + ILineCategory baseCategory = appliedScheme.Categories[0]; + AssertAreEqual(expectedSymbolizer, baseCategory.Symbolizer); + Assert.IsNull(baseCategory.FilterExpression); + + ILineCategory equalSchemeCategory = appliedScheme.Categories[1]; + string expectedFilter = $"[1] = {equalCriteria.Value}"; + Assert.AreEqual(expectedFilter, equalSchemeCategory.FilterExpression); + expectedSymbolizer = CreateExpectedSymbolizer(lineStyle, + expectedDashStyle, + theme.CategoryThemes.ElementAt(0).Color); + AssertAreEqual(expectedSymbolizer, equalSchemeCategory.Symbolizer); + + ILineCategory unEqualSchemeCategory = appliedScheme.Categories[2]; + expectedFilter = $"[1] != {unequalCriteria.Value}"; + Assert.AreEqual(expectedFilter, unEqualSchemeCategory.FilterExpression); + expectedSymbolizer = CreateExpectedSymbolizer(lineStyle, + expectedDashStyle, + theme.CategoryThemes.ElementAt(1).Color); + AssertAreEqual(expectedSymbolizer, unEqualSchemeCategory.Symbolizer); + } + + [Test] + public void ConvertLayerProperties_MapLineDataWithStyleAndRangeCriteria_ConvertDataToMapPointLayer() + { + // Setup + const string metadataAttribute = "Meta"; + var random = new Random(21); + + var allBoundsInclusiveCriteria = new RangeCriteria(RangeCriteriaOperator.AllBoundsInclusive, + random.NextDouble(), + 1 + random.NextDouble()); + var lowerBoundInclusiveCriteria = new RangeCriteria(RangeCriteriaOperator.LowerBoundInclusive, + random.NextDouble(), + 1 + random.NextDouble()); + var upperBoundInclusiveCriteria = new RangeCriteria(RangeCriteriaOperator.UpperBoundInclusive, + random.NextDouble(), + 1 + random.NextDouble()); + var allBoundsExclusiveCriteria = new RangeCriteria(RangeCriteriaOperator.AllBoundsExclusive, + random.NextDouble(), + 1 + random.NextDouble()); + var theme = new MapTheme(metadataAttribute, new[] + { + new CategoryTheme(Color.FromKnownColor(random.NextEnum()), + allBoundsInclusiveCriteria), + new CategoryTheme(Color.FromKnownColor(random.NextEnum()), + lowerBoundInclusiveCriteria), + new CategoryTheme(Color.FromKnownColor(random.NextEnum()), + upperBoundInclusiveCriteria), + new CategoryTheme(Color.FromKnownColor(random.NextEnum()), + allBoundsExclusiveCriteria) + }); + + var lineStyle = new LineStyle + { + Color = Color.FromKnownColor(random.NextEnum()), + Width = random.Next(1, 48), + DashStyle = LineDashStyle.DashDotDot + }; + var mapLineData = new MapLineData("test", lineStyle) + { + Features = new[] + { + CreateMapFeatureWithMetaData(metadataAttribute) + }, + MapTheme = theme + }; + + var mapLineLayer = new MapLineLayer(); + + var converter = new MapLineDataConverter(); + + // Call + converter.ConvertLayerProperties(mapLineData, mapLineLayer); + + // Assert + const DashStyle expectedDashStyle = DashStyle.DashDotDot; + ILineSymbolizer expectedSymbolizer = CreateExpectedSymbolizer(lineStyle, + expectedDashStyle, + lineStyle.Color); + + ILineScheme appliedScheme = mapLineLayer.Symbology; + Assert.AreEqual(5, appliedScheme.Categories.Count); + + ILineCategory baseCategory = appliedScheme.Categories[0]; + AssertAreEqual(expectedSymbolizer, baseCategory.Symbolizer); + Assert.IsNull(baseCategory.FilterExpression); + + ILineCategory allBoundsInclusiveCategory = appliedScheme.Categories[1]; + string expectedFilter = $"[1] >= {allBoundsInclusiveCriteria.LowerBound} AND [1] <= {allBoundsInclusiveCriteria.UpperBound}"; + Assert.AreEqual(expectedFilter, allBoundsInclusiveCategory.FilterExpression); + expectedSymbolizer = CreateExpectedSymbolizer(lineStyle, + expectedDashStyle, + theme.CategoryThemes.ElementAt(0).Color); + AssertAreEqual(expectedSymbolizer, allBoundsInclusiveCategory.Symbolizer); + + ILineCategory lowerBoundInclusiveCategory = appliedScheme.Categories[2]; + expectedFilter = $"[1] >= {lowerBoundInclusiveCriteria.LowerBound} AND [1] < {lowerBoundInclusiveCriteria.UpperBound}"; + Assert.AreEqual(expectedFilter, lowerBoundInclusiveCategory.FilterExpression); + expectedSymbolizer = CreateExpectedSymbolizer(lineStyle, + expectedDashStyle, + theme.CategoryThemes.ElementAt(1).Color); + AssertAreEqual(expectedSymbolizer, lowerBoundInclusiveCategory.Symbolizer); + + ILineCategory upperBoundInclusiveCategory = appliedScheme.Categories[3]; + expectedFilter = $"[1] > {upperBoundInclusiveCriteria.LowerBound} AND [1] <= {upperBoundInclusiveCriteria.UpperBound}"; + Assert.AreEqual(expectedFilter, upperBoundInclusiveCategory.FilterExpression); + expectedSymbolizer = CreateExpectedSymbolizer(lineStyle, + expectedDashStyle, + theme.CategoryThemes.ElementAt(2).Color); + AssertAreEqual(expectedSymbolizer, upperBoundInclusiveCategory.Symbolizer); + + ILineCategory allBoundsExclusiveCategory = appliedScheme.Categories[4]; + expectedFilter = $"[1] > {allBoundsExclusiveCriteria.LowerBound} AND [1] < {allBoundsExclusiveCriteria.UpperBound}"; + Assert.AreEqual(expectedFilter, allBoundsExclusiveCategory.FilterExpression); + expectedSymbolizer = CreateExpectedSymbolizer(lineStyle, + expectedDashStyle, + theme.CategoryThemes.ElementAt(3).Color); + AssertAreEqual(expectedSymbolizer, allBoundsExclusiveCategory.Symbolizer); + } + + private static ILineSymbolizer CreateExpectedSymbolizer(LineStyle expectedLineStyle, + DashStyle expectedDashStyle, + Color expectedColor) + { + return new LineSymbolizer(expectedColor, expectedColor, expectedLineStyle.Width, expectedDashStyle, LineCap.Round); + } + + private static MapFeature CreateMapFeatureWithMetaData(string metadataAttributeName) + { + var random = new Random(21); + var mapFeature = new MapFeature(new[] + { + new MapGeometry(new[] + { + new[] + { + new Point2D(random.NextDouble(), random.NextDouble()) + } + }) + }); + mapFeature.MetaData[metadataAttributeName] = new object(); + + return mapFeature; + } + private static void AssertAreEqual(ILineSymbolizer firstSymbolizer, ILineSymbolizer secondSymbolizer) { IList firstStrokes = firstSymbolizer.Strokes; Index: Core/Components/test/Core.Components.DotSpatial.Test/Converter/MapPointDataConverterTest.cs =================================================================== diff -u -rf254b26cf9d6d3f6a172e1613740c44f2da70d3c -rc3e01df6dfac668c5e9bf1e9702cca333e1bbe19 --- Core/Components/test/Core.Components.DotSpatial.Test/Converter/MapPointDataConverterTest.cs (.../MapPointDataConverterTest.cs) (revision f254b26cf9d6d3f6a172e1613740c44f2da70d3c) +++ Core/Components/test/Core.Components.DotSpatial.Test/Converter/MapPointDataConverterTest.cs (.../MapPointDataConverterTest.cs) (revision c3e01df6dfac668c5e9bf1e9702cca333e1bbe19) @@ -259,16 +259,6 @@ AssertAreEqual(expectedSymbolizer, unEqualSchemeCategory.Symbolizer); } - private static PointSymbolizer CreateExpectedSymbolizer(PointStyle expectedPointStyle, - PointShape expectedPointShape, - Color expectedColor) - { - var expectedSymbolizer = new PointSymbolizer(expectedColor, expectedPointShape, expectedPointStyle.Size); - expectedSymbolizer.SetOutline(expectedPointStyle.StrokeColor, expectedPointStyle.StrokeThickness); - - return expectedSymbolizer; - } - [Test] public void ConvertLayerProperties_MapPointDataWithStyleAndRangeCriteria_ConvertDataToMapPointLayer() { @@ -370,6 +360,16 @@ AssertAreEqual(expectedSymbolizer, allBoundsExclusiveCategory.Symbolizer); } + private static PointSymbolizer CreateExpectedSymbolizer(PointStyle expectedPointStyle, + PointShape expectedPointShape, + Color expectedColor) + { + var expectedSymbolizer = new PointSymbolizer(expectedColor, expectedPointShape, expectedPointStyle.Size); + expectedSymbolizer.SetOutline(expectedPointStyle.StrokeColor, expectedPointStyle.StrokeThickness); + + return expectedSymbolizer; + } + private static MapFeature CreateMapFeatureWithMetaData(string metadataAttributeName) { var random = new Random(21);