public void SimpleSimplifyPointF2DCurveTests() { double epsilon = 0.1; // simple 2-point line should remain identical. PointF2D[] testCurve = new PointF2D[] { new PointF2D(0, 0), new PointF2D(1, 1) }; PointF2D[] simpleTestCurve = SimplifyCurve.Simplify(testCurve, epsilon); Assert.AreEqual(0, simpleTestCurve [0] [0]); Assert.AreEqual(0, simpleTestCurve [0] [1]); Assert.AreEqual(1, simpleTestCurve [1] [0]); Assert.AreEqual(1, simpleTestCurve [1] [1]); // simple 1-point line should remain identical. testCurve = new PointF2D[] { new PointF2D(0, 0), new PointF2D(1, 1) }; //PointF2D[] simpleTextCurve = SimplifyCurve.SimplifyBetween(testCurve, epsilon, 0, 0); // simple straight line should be simplified to only 2 points. testCurve = new PointF2D[] { new PointF2D(0, 0), new PointF2D(0.5, 0.5), new PointF2D(1, 1) }; simpleTestCurve = SimplifyCurve.Simplify(testCurve, epsilon); Assert.AreEqual(0, simpleTestCurve [0] [0]); Assert.AreEqual(0, simpleTestCurve [0] [1]); Assert.AreEqual(1, simpleTestCurve [1] [0]); Assert.AreEqual(1, simpleTestCurve [1] [1]); // this line should retain all points. testCurve = new PointF2D[] { new PointF2D(0, 0), new PointF2D(1, 1), new PointF2D(0, 1) }; simpleTestCurve = SimplifyCurve.Simplify(testCurve, epsilon); Assert.AreEqual(0, simpleTestCurve [0] [0]); Assert.AreEqual(0, simpleTestCurve [0] [1]); Assert.AreEqual(1, simpleTestCurve [1] [0]); Assert.AreEqual(1, simpleTestCurve [1] [1]); Assert.AreEqual(0, simpleTestCurve [2] [0]); Assert.AreEqual(1, simpleTestCurve [2] [1]); // this line should be simplified. testCurve = new PointF2D[] { new PointF2D(0, 0), new PointF2D(0.2, 0.21), new PointF2D(0.52, 0.5), new PointF2D(0.75, 0.76), new PointF2D(1, 1) }; simpleTestCurve = SimplifyCurve.Simplify(testCurve, epsilon); Assert.AreEqual(0, simpleTestCurve [0] [0]); Assert.AreEqual(0, simpleTestCurve [0] [1]); Assert.AreEqual(1, simpleTestCurve [1] [0]); Assert.AreEqual(1, simpleTestCurve [1] [1]); }
public void SimpleSimplifyCurveTests() { double epsilon = 0.1; // simple 2-point line should remain identical. var testCurve = new double[][] { new double[] { 0, 1 }, new double[] { 0, 1 } }; double[][] simpleTestCurve = SimplifyCurve.Simplify(testCurve, epsilon); Assert.AreEqual(0, simpleTestCurve[0][0]); Assert.AreEqual(0, simpleTestCurve[1][0]); Assert.AreEqual(1, simpleTestCurve[0][1]); Assert.AreEqual(1, simpleTestCurve[1][1]); // between with identical start-end should return one point. testCurve = new double[][] { new double[] { 0, 1 }, new double[] { 0, 1 } }; simpleTestCurve = SimplifyCurve.SimplifyBetween(testCurve, epsilon, 0, 0); Assert.AreEqual(0, simpleTestCurve[0][0]); Assert.AreEqual(0, simpleTestCurve[1][0]); // simple straight line should be simplified to only 2 points. testCurve = new double[][] { new double[] { 0, 0.5, 1 }, new double[] { 0, 0.5, 1 } }; simpleTestCurve = SimplifyCurve.Simplify(testCurve, epsilon); Assert.AreEqual(0, simpleTestCurve[0][0]); Assert.AreEqual(0, simpleTestCurve[1][0]); Assert.AreEqual(1, simpleTestCurve[0][1]); Assert.AreEqual(1, simpleTestCurve[1][1]); // this line should retain all points. testCurve = new double[][] { new double[] { 0, 1, 0 }, new double[] { 0, 1, 1 } }; simpleTestCurve = SimplifyCurve.Simplify(testCurve, epsilon); Assert.AreEqual(0, simpleTestCurve[0][0]); Assert.AreEqual(0, simpleTestCurve[1][0]); Assert.AreEqual(1, simpleTestCurve[0][1]); Assert.AreEqual(1, simpleTestCurve[1][1]); Assert.AreEqual(0, simpleTestCurve[0][2]); Assert.AreEqual(1, simpleTestCurve[1][2]); // this line should be simplified. testCurve = new double[][] { new double[] { 0, 0.2, 0.52, 0.75, 1 }, new double[] { 0, 0.21, 0.5, 0.76, 1 } }; simpleTestCurve = SimplifyCurve.Simplify(testCurve, epsilon); Assert.AreEqual(0, simpleTestCurve[0][0]); Assert.AreEqual(0, simpleTestCurve[1][0]); Assert.AreEqual(1, simpleTestCurve[0][1]); Assert.AreEqual(1, simpleTestCurve[1][1]); // this 'area' should not be simplified. testCurve = new double[][] { new double[] { 0, 1, 1, 0, 0 }, new double[] { 0, 0, 1, 1, 0 } }; simpleTestCurve = SimplifyCurve.Simplify(testCurve, epsilon); Assert.AreEqual(0, simpleTestCurve[0][0]); Assert.AreEqual(0, simpleTestCurve[1][0]); Assert.AreEqual(1, simpleTestCurve[0][1]); Assert.AreEqual(0, simpleTestCurve[1][1]); Assert.AreEqual(1, simpleTestCurve[0][2]); Assert.AreEqual(1, simpleTestCurve[1][2]); Assert.AreEqual(0, simpleTestCurve[0][3]); Assert.AreEqual(1, simpleTestCurve[1][3]); Assert.AreEqual(0, simpleTestCurve[0][4]); Assert.AreEqual(0, simpleTestCurve[1][4]); }
/// <summary> /// Translates a way. /// </summary> /// <param name="scene">The scene to add primitives to.</param> /// <param name="projection">The projection used to convert the objects.</param> /// <param name="way"></param> private void TranslateWay(Scene2D scene, IProjection projection, CompleteWay way) { // build the rules. List <MapCSSRuleProperties> rules = this.BuildRules(new MapCSSObject(way)); // validate what's there. if (rules.Count == 0) { return; } // get x/y. double[] x = null, y = null; if (x == null) { // pre-calculate x/y. x = new double[way.Nodes.Count]; y = new double[way.Nodes.Count]; for (int idx = 0; idx < way.Nodes.Count; idx++) { x[idx] = projection.LongitudeToX( way.Nodes[idx].Coordinate.Longitude); y[idx] = projection.LatitudeToY( way.Nodes[idx].Coordinate.Latitude); } // simplify. if (x.Length > 2) { double[][] simplified = SimplifyCurve.Simplify(new double[][] { x, y }, 0.0001); x = simplified[0]; y = simplified[1]; } } // add the z-index. foreach (var rule in rules) { float minZoom = (float)projection.ToZoomFactor(rule.MinZoom); float maxZoom = (float)projection.ToZoomFactor(rule.MaxZoom); int zIndex; if (!rule.TryGetProperty <int>("zIndex", out zIndex)) { zIndex = 0; } // interpret the results. if (x != null) { // there is a valid interpretation of this way. int color; bool renderAsLine = true; if (way.IsOfType(MapCSSTypes.Area)) { // the way is an area. check if it can be rendered as an area. int fillColor; if (rule.TryGetProperty("fillColor", out fillColor)) { // render as an area. uint?pointsId = scene.AddPoints(x, y); if (pointsId.HasValue) { scene.AddStylePolygon(pointsId.Value, this.CalculateSceneLayer(OffsetArea, zIndex), minZoom, maxZoom, fillColor, 1, true); if (rule.TryGetProperty("color", out color)) { scene.AddStylePolygon(pointsId.Value, this.CalculateSceneLayer(OffsetCasing, zIndex), minZoom, maxZoom, color, 1, false); } } renderAsLine = false; // was validly rendered als a line. } } if (renderAsLine) { // was not rendered as an area. // the way has to rendered as a line. LineJoin lineJoin; if (!rule.TryGetProperty("lineJoin", out lineJoin)) { lineJoin = LineJoin.Miter; } int[] dashes; if (!rule.TryGetProperty("dashes", out dashes)) { dashes = null; } if (rule.TryGetProperty("color", out color)) { float casingWidth; int casingColor; if (!rule.TryGetProperty("casingWidth", out casingWidth)) { casingWidth = 0; } if (!rule.TryGetProperty("casingColor", out casingColor)) { // casing: use the casing layer. casingColor = -1; } float width; if (!rule.TryGetProperty("width", out width)) { width = 1; } uint?pointsId = scene.AddPoints(x, y); if (pointsId.HasValue) { if (casingWidth > 0) { // adds the casing scene.AddStyleLine(pointsId.Value, this.CalculateSceneLayer(OffsetCasing, zIndex), minZoom, maxZoom, casingColor, width + (casingWidth * 2), lineJoin, dashes); } if (dashes == null) { // dashes not set, use line offset. scene.AddStyleLine(pointsId.Value, this.CalculateSceneLayer(OffsetLine, zIndex), minZoom, maxZoom, color, width, lineJoin, dashes); } else { // dashes set, use line pattern offset. scene.AddStyleLine(pointsId.Value, this.CalculateSceneLayer(OffsetLinePattern, zIndex), minZoom, maxZoom, color, width, lineJoin, dashes); } int textColor; int fontSize; string nameTag; if (!rule.TryGetProperty("fontSize", out fontSize)) { fontSize = 10; } if (rule.TryGetProperty("text", out nameTag) && rule.TryGetProperty("textColor", out textColor)) { int haloColor; int?haloColorNullable = null; if (rule.TryGetProperty("textHaloColor", out haloColor)) { haloColorNullable = haloColor; } int haloRadius; int?haloRadiusNullable = null; if (rule.TryGetProperty("textHaloRadius", out haloRadius)) { haloRadiusNullable = haloRadius; } string fontFamily; if (!rule.TryGetProperty("fontFamily", out fontFamily)) { fontFamily = "Arial"; // just some default font. } string name; if (way.Tags.TryGetValue(nameTag, out name)) { scene.AddStyleLineText(pointsId.Value, this.CalculateSceneLayer(OffsetLineText, zIndex), minZoom, maxZoom, textColor, fontSize, name, fontFamily, haloColorNullable, haloRadiusNullable); } } } } } } } }
/// <summary> /// Translates a lineair ring. /// </summary> /// <param name="scene">The scene to add primitives to.</param> /// <param name="projection">The projection used to convert the objects.</param> /// <param name="lineairRing"></param> private void TranslateLineairRing(Scene2D scene, IProjection projection, LineairRing lineairRing) { // build the rules. List <MapCSSRuleProperties> rules = this.BuildRules(new MapCSSObject(lineairRing)); // validate what's there. if (rules.Count == 0) { return; } // get x/y. double[] x = null, y = null; if (lineairRing.Coordinates != null && lineairRing.Coordinates.Count > 0) { // pre-calculate x/y. x = new double[lineairRing.Coordinates.Count]; y = new double[lineairRing.Coordinates.Count]; for (int idx = 0; idx < lineairRing.Coordinates.Count; idx++) { x[idx] = projection.LongitudeToX( lineairRing.Coordinates[idx].Longitude); y[idx] = projection.LatitudeToY( lineairRing.Coordinates[idx].Latitude); } // simplify. if (x.Length > 2) { double[][] simplified = SimplifyCurve.Simplify(new double[][] { x, y }, 0.0001); x = simplified[0]; y = simplified[1]; } } // add the z-index. foreach (var rule in rules) { float minZoom = (float)projection.ToZoomFactor(rule.MinZoom); float maxZoom = (float)projection.ToZoomFactor(rule.MaxZoom); int zIndex; if (!rule.TryGetProperty <int>("zIndex", out zIndex)) { zIndex = 0; } // interpret the results. if (x != null) { // there is a valid interpretation of this way. int color; int fillColor; if (rule.TryGetProperty("fillColor", out fillColor)) { // render as an area. float fillOpacity; if (rule.TryGetProperty("fillOpacity", out fillOpacity)) { SimpleColor simpleFillColor = new SimpleColor() { Value = fillColor }; fillColor = SimpleColor.FromArgb((int)(255 * fillOpacity), simpleFillColor.R, simpleFillColor.G, simpleFillColor.B).Value; } uint?pointsId = scene.AddPoints(x, y); if (pointsId.HasValue) { scene.AddStylePolygon(pointsId.Value, this.CalculateSceneLayer(OffsetArea, zIndex), minZoom, maxZoom, fillColor, 1, true); if (rule.TryGetProperty("color", out color)) { scene.AddStylePolygon(pointsId.Value, this.CalculateSceneLayer(OffsetCasing, zIndex), minZoom, maxZoom, color, 1, false); } } } } } }
/// <summary> /// Translates OSM objects into basic renderable primitives. /// </summary> /// <param name="scene">The scene to add primitives to.</param> /// <param name="projection">The projection used to convert the objects.</param> /// <param name="osmGeo">The osm object.</param> /// <returns></returns> public override void Translate(Scene2D scene, IProjection projection, CompleteOsmGeo osmGeo) { // set the scene backcolor. scene.BackColor = this.GetCanvasColor().Value; if (osmGeo == null) { return; } // store the object count. int countBefore = scene.Count; // interpret the osm-objects. switch (osmGeo.Type) { case CompleteOsmType.Node: this.TranslateNode(scene, projection, osmGeo as CompleteNode); break; case CompleteOsmType.Way: this.TranslateWay(scene, projection, osmGeo as CompleteWay); break; case CompleteOsmType.Relation: this.TranslateRelation(scene, projection, osmGeo as CompleteRelation); break; case CompleteOsmType.ChangeSet: break; default: throw new ArgumentOutOfRangeException(); } // interpret the osmGeo object and check if it makes up an area. GeometryCollection collection = _geometryInterpreter.Interpret(osmGeo); foreach (Geometry geometry in collection) { if (geometry is LineairRing) { // a simple lineair ring. this.TranslateLineairRing(scene, projection, geometry as LineairRing); } else if (geometry is Polygon) { // a simple polygon. this.TranslatePolygon(scene, projection, geometry as Polygon); } else if (geometry is MultiPolygon) { // a multipolygon. this.TranslateMultiPolygon(scene, projection, geometry as MultiPolygon); } } // check if any objects have been added to the scene. if (scene.Count <= countBefore) { // no objects have been added. Apply default styles if needed. if (osmGeo.Type == CompleteOsmType.Node && _mapCSSFile != null && _mapCSSFile.DefaultPoints) { // apply default points style. CompleteNode node = (osmGeo as CompleteNode); uint pointId = scene.AddPoint(projection.LongitudeToX(node.Coordinate.Longitude), projection.LatitudeToY(node.Coordinate.Latitude)); scene.AddStylePoint(pointId, this.CalculateSceneLayer(OffsetPoint, 0), float.MinValue, float.MaxValue, SimpleColor.FromKnownColor(KnownColor.Black).Value, 2); } else if (osmGeo.Type == CompleteOsmType.Way && _mapCSSFile != null && _mapCSSFile.DefaultLines) { // apply default lines style. CompleteWay way = (osmGeo as CompleteWay); // get x/y. double[] x = null, y = null; if (x == null) { // pre-calculate x/y. x = new double[way.Nodes.Count]; y = new double[way.Nodes.Count]; for (int idx = 0; idx < way.Nodes.Count; idx++) { x[idx] = projection.LongitudeToX( way.Nodes[idx].Coordinate.Longitude); y[idx] = projection.LatitudeToY( way.Nodes[idx].Coordinate.Latitude); } // simplify. if (x.Length > 2) { double[][] simplified = SimplifyCurve.Simplify(new double[][] { x, y }, 0.0001); x = simplified[0]; y = simplified[1]; } } uint?points = scene.AddPoints(x, y); if (points.HasValue) { scene.AddStyleLine(points.Value, this.CalculateSceneLayer(OffsetLine, 0), float.MinValue, float.MaxValue, SimpleColor.FromKnownColor(KnownColor.Red).Value, 1, LineJoin.Round, null); } } } }