public static VectorTileGeometry GetCCWPolygon(int factor) { // arrange var firstp = new Point() { X = factor, Y = factor }; var secondp = new Point() { X = -factor, Y = factor }; var thirdp = new Point() { X = -factor, Y = -factor }; var fourthp = new Point() { X = factor, Y = -factor }; var coords = new VectorTileGeometry(new List <Point> { firstp, secondp, thirdp, fourthp, firstp }); return(coords); }
public void SignedAreaTest() { // arrange // create a closed polygon (first point is the same as the last) var points = new VectorTileGeometry(new List <Point> { new Point() { X = 1, Y = 1 }, new Point() { X = 2, Y = 2 }, new Point() { X = 3, Y = 1 }, new Point() { X = 1, Y = 1 }, }); var polygon = new VectorTilePolygon(points); // act var area = polygon.SignedArea(); // assert // polygon is defined clock-wise so area should be negative Assert.IsTrue(area == -1); }
private void CalcRingBBox(double[] min, double[] max, VectorTileGeometry points) { for (var i = 0; i < points.Count; i++) { var p = points[i]; min[0] = Math.Min(p[0], min[0]); max[0] = Math.Max(p[0], max[0]); min[1] = Math.Min(p[1], min[1]); max[1] = Math.Max(p[1], max[1]); } }
private VectorTileGeometry NewSlice(List <VectorTileGeometry> slices, VectorTileGeometry slice, double area, double dist) { if (slice.Any()) { // we don't recalculate the area/length of the unclipped geometry because the case where it goes // below the visibility threshold as a result of clipping is rare, so we avoid doing unnecessary work slice.Area = area; slice.Distance = dist; slices.Add(slice); } return(new VectorTileGeometry()); }
private VectorTileGeometry Project(double[][] lonlats, double?tolerance = null) { var projected = new VectorTileGeometry(); for (var i = 0; i < lonlats.Length; i++) { projected.Add(ProjectPoint(lonlats[i])); } if (tolerance.HasValue && tolerance.Value > 0) { Simplifier.simplify(projected, tolerance.Value); calcSize(projected); } return(projected); }
private VectorTileGeometry ShiftCoords(VectorTileGeometry points, double offset) { var newPoints = new VectorTileGeometry() { Area = points.Area, Distance = points.Distance }; for (var i = 0; i < points.Count; i++) { newPoints.Add(new[] { points[i][0] + offset, points[i][1], points[i][2] }); } return(newPoints); }
private VectorTileGeometry[] clipPoints(VectorTileGeometry geometry, double k1, double k2, int axis) { var slice = new VectorTileGeometry(); for (var i = 0; i < geometry.Count; i++) { var a = geometry[i]; var ak = a[axis]; if (ak >= k1 && ak <= k2) { slice.Add(a); } } return(new[] { slice }); }
private void calcSize(VectorTileGeometry points) { double area = 0; double dist = 0; double[] a = null; double[] b = null; for (int i = 0; i < points.Count - 1; i++) { a = b ?? points[i]; b = points[i + 1]; area += a[0] * b[1] - b[0] * a[1]; // use Manhattan distance instead of Euclidian one to avoid expensive square root computation dist += Math.Abs(b[0] - a[0]) + Math.Abs(b[1] - a[1]); } points.Area = Math.Abs(area / 2); points.Distance = dist; }
private void AddFeature(VectorTileFeature feature, double tolerance, bool noSimplify) { // var geom = feature.Geometry; var type = feature.Type; var simplified = new List <VectorTileGeometry>(); var sqTolerance = tolerance * tolerance; // i, j, ring, p; if (type == 1) { var first = new VectorTileGeometry(); simplified.Add(first); var points = feature.GetPoints(); for (var i = 0; i < points.Count; i++) { first.Add(points[i]); NumPoints++; NumSimplified++; } } else { var geom = feature.GetRings(); // simplify and transform projected coordinates for tile geometry for (var i = 0; i < geom.Length; i++) { var ring = geom[i]; // filter out tiny polylines & polygons if (!noSimplify && ((type == 2 && ring.Distance < tolerance) || (type == 3 && ring.Area < sqTolerance))) { NumPoints += ring.Count; continue; } var simplifiedRing = new VectorTileGeometry() { Area = ring.Area, Distance = ring.Distance }; for (var j = 0; j < ring.Count; j++) { var p = ring[j]; // keep points with importance > tolerance if (noSimplify || p[2] > sqTolerance) { simplifiedRing.Add(p); NumSimplified++; } NumPoints++; } simplified.Add(simplifiedRing); } } if (simplified.Count > 0) { Features.Add(new VectorTileFeature { Geometry = type == 1? simplified.Single() : simplified.ToArray() as object, Type = type, Tags = feature.Tags }); } }
private VectorTileGeometry[] clipGeometry(VectorTileGeometry[] geometry, double k1, double k2, int axis, Func <double[], double[], double, double[]> intersect, bool closed) { var slices = new List <VectorTileGeometry>(); for (var i = 0; i < geometry.Length; i++) { double? ak = null; double? bk = null; double[] b = null; var points = geometry[i]; var area = points.Area; var dist = points.Distance; var len = points.Count; double[] a; // var j; // var last; var slice = new VectorTileGeometry(); for (var j = 0; j < len - 1; j++) { a = b ?? points[j]; b = points[j + 1]; ak = bk ?? a[axis]; bk = b[axis]; if (ak.Value < k1) { if ((bk.Value > k2)) { // ---|-----|--> slice.Add(intersect(a, b, k1)); slice.Add(intersect(a, b, k2)); if (!closed) { slice = NewSlice(slices, slice, area, dist); } } else if (bk.Value >= k1) { slice.Add(intersect(a, b, k1)); // ---|--> | } } else if (ak.Value > k2) { if ((bk.Value < k1)) { // <--|-----|--- slice.Add(intersect(a, b, k2)); slice.Add(intersect(a, b, k1)); if (!closed) { slice = NewSlice(slices, slice, area, dist); } } else if (bk.Value <= k2) { slice.Add(intersect(a, b, k2)); // | <--|--- } } else { slice.Add(a); if (bk.Value < k1) { // <--|--- | slice.Add(intersect(a, b, k1)); if (!closed) { slice = NewSlice(slices, slice, area, dist); } } else if (bk.Value > k2) { // | ---|--> slice.Add(intersect(a, b, k2)); if (!closed) { slice = NewSlice(slices, slice, area, dist); } } // | --> | } } // add the last point a = points[len - 1]; ak = a[axis]; if (ak.Value >= k1 && ak.Value <= k2) { slice.Add(a); } // close the polygon if its endpoints are not the same after clipping if (slice.Any()) { var last = slice[slice.Count - 1]; if (closed && (slice[0][0] != last[0] || slice[0][1] != last[1])) { slice.Add(slice[0]); } } // add the final slice NewSlice(slices, slice, area, dist); } return(slices.ToArray()); }