private static double Distance(ref PointInt a, ref PointInt b) { double d1 = a.X - b.X; double d2 = a.Y - b.Y; return(Math.Sqrt((d1 * d1) + (d2 * d2))); }
private static List <uint> EncodePointGeometry(List <List <PointInt> > coordList) { List <uint> geometry = new List <uint>(); PointInt prevCoord = new PointInt() { X = 0, Y = 0 }; foreach (List <PointInt> points in coordList) { if (points.Count == 0) { throw new Exception("Encoding with no points. "); } uint commandInteger = (MoveTo & 0x7) | ((uint)points.Count << 3); geometry.Add(commandInteger); for (int n = 0; n < points.Count; ++n) { int dx = points[n].X - prevCoord.X; int dy = points[n].Y - prevCoord.Y; int parameter = ZigZag.Encode(dx); geometry.Add((uint)parameter); parameter = ZigZag.Encode(dy); geometry.Add((uint)parameter); prevCoord = points[n]; } } return(geometry); }
private static double Cross(ref PointInt a, ref PointInt b, ref PointInt c) { PointShape ab = new PointShape(b.X - a.X, b.Y - a.Y); PointShape ac = new PointShape(c.X - a.X, c.Y - a.Y); return((ab.X * ac.Y) - (ab.Y * ac.X)); }
private static double Dot(ref PointInt a, ref PointInt b, ref PointInt c) { Vertex ab = new Vertex(b.X - a.X, b.Y - a.Y); Vertex bc = new Vertex(c.X - b.X, c.Y - b.Y); return((ab.X * bc.X) + (ab.Y * bc.Y)); }
private static List <List <PointInt> > GetGeometry(List <uint> geom, GeometryType geomType) { int x = 0; int y = 0; var coordsList = new List <List <PointInt> >(); List <PointInt> coords = null; var geometryCount = geom.Count; uint length = 0; uint command = 0; var i = 0; while (i < geometryCount) { if (length <= 0) { length = geom[i++]; command = length & ((1 << 3) - 1); length = length >> 3; } if (length > 0) { if (command == MoveTo) { coords = new List <PointInt>(); coordsList.Add(coords); } } if (command == ClosePath) { if (geomType != GeometryType.Point && !(coords.Count == 0)) { coords.Add(coords[0]); } length--; continue; } var dx = geom[i++]; var dy = geom[i++]; length--; var ldx = ZigZag.Decode((int)dx); var ldy = ZigZag.Decode((int)dy); x = x + ldx; y = y + ldy; var coord = new PointInt() { X = x, Y = y }; coords.Add(coord); } return(coordsList); }
private static PointInt WorldPointToTilePoint(double pointX, double pointY, int zoomLevel, int tileSize, RectangleShape tileBoundingBox) { double scale = ((double)tileSize / MaxExtents.SphericalMercator.Width) * (1 << zoomLevel); PointInt result = new PointInt() { X = (int)Math.Round((pointX - tileBoundingBox.LowerLeftPoint.X) * scale), Y = (int)Math.Round((tileBoundingBox.UpperLeftPoint.Y - pointY) * scale) }; return(result); }
private static List <uint> EncodePolygonGeometry(List <List <PointInt> > coordList) { List <uint> geometry = new List <uint>(); PointInt prevCoord = new PointInt() { X = 0, Y = 0 }; foreach (List <PointInt> points in coordList) { if (points.Count == 0) { throw new Exception("Encoding with no points. "); } //start of ring uint commandInteger = (MoveTo & 0x7) | (1 << 3); geometry.Add(commandInteger); int dx = points[0].X - prevCoord.X; int dy = points[0].Y - prevCoord.Y; int parameter = ZigZag.Encode(dx); geometry.Add((uint)parameter); parameter = ZigZag.Encode(dy); geometry.Add((uint)parameter); bool lastPointRepeated = (points[points.Count - 1].X == points[0].X && points[points.Count - 1].Y == points[0].Y); int pointCount = lastPointRepeated ? points.Count - 2 : points.Count - 1; //encode the rest of the points commandInteger = (LineTo & 0x7) | ((uint)(pointCount) << 3); geometry.Add(commandInteger); for (int n = 1; n <= pointCount; ++n) { dx = points[n].X - points[n - 1].X; dy = points[n].Y - points[n - 1].Y; parameter = ZigZag.Encode(dx); geometry.Add((uint)parameter); parameter = ZigZag.Encode(dy); geometry.Add((uint)parameter); } //close path commandInteger = (ClosePath & 0x7) | (1 << 3); geometry.Add(commandInteger); prevCoord = points[pointCount]; } return(geometry); }
private static double LineSegPointDist(ref PointInt a, ref PointInt b, ref PointInt c) { //float dist = cross(a,b,c) / distance(a,b); if (Dot(ref a, ref b, ref c) > 0) { return(Distance(ref b, ref c)); } if (Dot(ref b, ref a, ref c) > 0) { return(Distance(ref a, ref c)); } return(Math.Abs(Cross(ref a, ref b, ref c) / Distance(ref a, ref b))); }
private static List <uint> EncodeLineGeometry(List <List <PointInt> > coordList) { List <uint> geometry = new List <uint>(); PointInt prevCoord = new PointInt() { X = 0, Y = 0 }; foreach (List <PointInt> points in coordList) { if (points.Count == 0) { throw new Exception("Encoding with no points. "); } //start of linestring uint commandInteger = (MoveTo & 0x7) | (1 << 3); geometry.Add(commandInteger); int dx = points[0].X - prevCoord.X; int dy = points[0].Y - prevCoord.Y; int parameter = ZigZag.Encode(dx); geometry.Add((uint)parameter); parameter = ZigZag.Encode(dy); geometry.Add((uint)parameter); //encode the rest of the points commandInteger = (LineTo & 0x7) | ((uint)(points.Count - 1) << 3); geometry.Add(commandInteger); for (int n = 1; n < points.Count; ++n) { dx = points[n].X - points[n - 1].X; dy = points[n].Y - points[n - 1].Y; parameter = ZigZag.Encode(dx); geometry.Add((uint)parameter); parameter = ZigZag.Encode(dy); geometry.Add((uint)parameter); } prevCoord = points[points.Count - 1]; } return(geometry); }
private static void ProcessLineShape(int zoom, int tileSize, RectangleInt tileScreenBoundingBox, TileFeature tileFeature, MultilineShape multiLineShape, int simplificationFactor, RectangleShape tileBoundingBox) { foreach (LineShape line in multiLineShape.Lines) { PointInt[] pixelPoints = new PointInt[line.Vertices.Count]; for (int n = 0; n < line.Vertices.Count; ++n) { pixelPoints[n] = WorldPointToTilePoint(line.Vertices[n].X, line.Vertices[n].Y, zoom, tileSize, tileBoundingBox); } PointInt[] simplifiedPixelPoints = SimplifyPointData(pixelPoints, simplificationFactor); //output count may be zero for short records at low zoom levels as //the pixel coordinates wil be a single point after simplification if (simplifiedPixelPoints.Length > 0) { List <int> clippedPoints = new List <int>(); List <int> parts = new List <int>(); ClipPolyline(simplifiedPixelPoints, tileScreenBoundingBox, clippedPoints, parts); if (parts.Count > 0) { //output the clipped polyline for (int n = 0; n < parts.Count; ++n) { int index1 = parts[n]; int index2 = n < parts.Count - 1 ? parts[n + 1] : clippedPoints.Count; List <PointInt> lineString = new List <PointInt>(); tileFeature.Geometry.Add(lineString); //clipped points store separate x/y pairs so there will be two values per measure for (int i = index1; i < index2; i += 2) { lineString.Add(new PointInt(clippedPoints[i], clippedPoints[i + 1])); } } } } } }
private static PointInt[] SimplifyPointData(PointInt[] points, int simplificationFactor) { // Check for duplicates points at end after they have been converted to pixel coordinates(PointInt) int pointCount = points.Length; while (pointCount > 2 && (points[pointCount - 1] == points[0])) { --pointCount; } PointInt[] resultPoints; if (pointCount <= 2) { resultPoints = new PointInt[pointCount]; for (int i = 0; i < resultPoints.Length; i++) { resultPoints[i] = points[i]; } return(resultPoints); } return(SimplifyDouglasPeucker(points, simplificationFactor)); }
private static void ProcessRingShape(int zoom, int tileSize, RectangleInt tileScreenBoundingBox, TileFeature tileFeature, RingShape ringShape, int simplificationFactor, RectangleShape tileBoundingBox) { PointInt[] tilePoints = new PointInt[ringShape.Vertices.Count]; for (int n = 0; n < ringShape.Vertices.Count; ++n) { tilePoints[n] = WorldPointToTilePoint(ringShape.Vertices[n].X, ringShape.Vertices[n].Y, zoom, tileSize, tileBoundingBox); } PointInt[] simplifiedTilePoints = SimplifyPointData(tilePoints, simplificationFactor); //output count may be zero for short records at low zoom levels as //the pixel coordinates wil be a single point after simplification if (simplifiedTilePoints.Length > 3) { if (simplifiedTilePoints[0] != simplifiedTilePoints[simplifiedTilePoints.Length - 1]) { Console.WriteLine("Not Closed"); } List <PointInt> clippedRing = ClipRingShape(simplifiedTilePoints, tileScreenBoundingBox); if (clippedRing.Count > 3) { tileFeature.Geometry.Add(clippedRing); } } }
private static TileFeature GetVectorTileFeature(Feature feature, int zoom, int tileSize, RectangleInt tileScreenBoundingBox, int simplificationFactor, RectangleShape tileBoundingBox) { TileFeature tileFeature = new TileFeature(); switch (feature.GetWellKnownType()) { case WellKnownType.Line: case WellKnownType.Multiline: tileFeature.Type = GeometryType.LineString; MultilineShape multiLineShape = new MultilineShape(feature.GetWellKnownBinary()); ProcessLineShape(zoom, tileSize, tileScreenBoundingBox, tileFeature, multiLineShape, simplificationFactor, tileBoundingBox); break; case WellKnownType.Polygon: case WellKnownType.Multipolygon: tileFeature.Type = GeometryType.Polygon; MultipolygonShape multiPolygonShape = new MultipolygonShape(feature.GetWellKnownBinary()); foreach (PolygonShape polygonShape in multiPolygonShape.Polygons) { ProcessRingShape(zoom, tileSize, tileScreenBoundingBox, tileFeature, polygonShape.OuterRing, simplificationFactor, tileBoundingBox); foreach (RingShape ringShape in polygonShape.InnerRings) { ProcessRingShape(zoom, tileSize, tileScreenBoundingBox, tileFeature, ringShape, simplificationFactor, tileBoundingBox); } } break; case WellKnownType.Point: case WellKnownType.Multipoint: tileFeature.Type = GeometryType.Point; List <PointInt> coordinates = new List <PointInt>(); MultipointShape multiPointShape = new MultipointShape(); if (feature.GetWellKnownType() == WellKnownType.Point) { PointShape pointShape = new PointShape(feature.GetWellKnownBinary()); multiPointShape.Points.Add(pointShape); } else if (feature.GetWellKnownType() == WellKnownType.Multipoint) { multiPointShape = new MultipointShape(feature.GetWellKnownBinary()); } foreach (PointShape point in multiPointShape.Points) { PointInt pointI = WorldPointToTilePoint(point.X, point.Y, zoom, tileSize, tileBoundingBox); coordinates.Add(new PointInt(pointI.X, pointI.Y)); } if (coordinates.Count > 0) { tileFeature.Geometry.Add(coordinates); } break; default: tileFeature.Type = GeometryType.Unknown; break; } //add the record attributes foreach (var attributes in feature.ColumnValues) { tileFeature.Attributes.Add(new TileAttribute(attributes.Key, attributes.Value)); } return(tileFeature); }
private static List <PointInt> ClipRingShape(PointInt[] inputPoints, RectangleInt tileScreenBoundingBox) { List <PointInt> outputList = new List <PointInt>(); List <PointInt> inputList = new List <PointInt>(inputPoints.Length); bool previousInside; for (int n = 0; n < inputPoints.Length; ++n) { inputList.Add(inputPoints[n]); } bool inputPolygonIsHole = IsPolygonHole(inputPoints, inputPoints.Length); //test left previousInside = inputList[inputList.Count - 1].X >= tileScreenBoundingBox.XMin; for (int n = 0; n < inputList.Count; ++n) { PointInt currentPoint = inputList[n]; bool currentInside = currentPoint.X >= tileScreenBoundingBox.XMin; if (currentInside != previousInside) { //add intersection PointInt prevPoint = n == 0 ? inputList[inputList.Count - 1] : inputList[n - 1]; int x = tileScreenBoundingBox.XMin; int y = prevPoint.Y + (currentPoint.Y - prevPoint.Y) * (x - prevPoint.X) / (currentPoint.X - prevPoint.X); outputList.Add(new PointInt(x, y)); } if (currentInside) { outputList.Add(currentPoint); } previousInside = currentInside; } if (outputList.Count == 0) { return(outputList); } //test top inputList = outputList.ToList(); previousInside = inputList[inputList.Count - 1].Y <= tileScreenBoundingBox.YMax;; outputList.Clear(); for (int n = 0; n < inputList.Count; ++n) { PointInt currentPoint = inputList[n]; bool currentInside = currentPoint.Y <= tileScreenBoundingBox.YMax; if (currentInside != previousInside) { //add intersection PointInt prevPoint = n == 0 ? inputList[inputList.Count - 1] : inputList[n - 1]; int y = tileScreenBoundingBox.YMax; int x = prevPoint.X + (currentPoint.X - prevPoint.X) * (y - prevPoint.Y) / (currentPoint.Y - prevPoint.Y); outputList.Add(new PointInt(x, y)); } if (currentInside) { outputList.Add(currentPoint); } previousInside = currentInside; } if (outputList.Count == 0) { return(outputList); } //test right inputList = outputList.ToList(); previousInside = inputList[inputList.Count - 1].X <= tileScreenBoundingBox.XMax; outputList.Clear(); for (int n = 0; n < inputList.Count; ++n) { PointInt currentPoint = inputList[n]; bool currentInside = currentPoint.X <= tileScreenBoundingBox.XMax; if (currentInside != previousInside) { //add intersection PointInt prevPoint = n == 0 ? inputList[inputList.Count - 1] : inputList[n - 1]; int x = tileScreenBoundingBox.XMax; int y = prevPoint.Y + (currentPoint.Y - prevPoint.Y) * (x - prevPoint.X) / (currentPoint.X - prevPoint.X); outputList.Add(new PointInt(x, y)); } if (currentInside) { outputList.Add(currentPoint); } previousInside = currentInside; } if (outputList.Count == 0) { return(outputList); } //test bottom inputList = outputList.ToList(); previousInside = inputList[inputList.Count - 1].Y >= tileScreenBoundingBox.YMin; outputList.Clear(); for (int n = 0; n < inputList.Count; ++n) { PointInt currentPoint = inputList[n]; bool currentInside = currentPoint.Y >= tileScreenBoundingBox.YMin; if (currentInside != previousInside) { //add intersection PointInt prevPoint = n == 0 ? inputList[inputList.Count - 1] : inputList[n - 1]; int y = tileScreenBoundingBox.YMin; int x = prevPoint.X + (currentPoint.X - prevPoint.X) * (y - prevPoint.Y) / (currentPoint.Y - prevPoint.Y); outputList.Add(new PointInt(x, y)); } if (currentInside) { outputList.Add(currentPoint); } previousInside = currentInside; } if (outputList.Count == 0) { return(outputList); } bool clippedPolygonIsHole = IsPolygonHole(outputList, outputList.Count); if (clippedPolygonIsHole == inputPolygonIsHole) { outputList.Reverse(); } if (outputList.Count > 3 && outputList[0] != outputList[outputList.Count - 1]) { outputList.Insert(0, outputList[0]); } return(outputList); }
private static PointInt[] SimplifyDouglasPeucker(PointInt[] inputPoints, double tolerance) { PointInt[] resultPoints = new PointInt[inputPoints.Length]; if (inputPoints.Length < 3) { for (int i = 0; i < inputPoints.Length; ++i) { resultPoints[i] = inputPoints[i]; } return(resultPoints); } Int32 firstPoint = 0; Int32 lastPoint = inputPoints.Length - 1; //Add the first and last index to the keepers var reducedPointIndicies = new List <int>(); reducedPointIndicies.Add(firstPoint); reducedPointIndicies.Add(lastPoint); //ensure first and last point not the same while (lastPoint >= 0 && inputPoints[firstPoint].Equals(inputPoints[lastPoint])) { lastPoint--; } DouglasPeuckerReduction(inputPoints, firstPoint, lastPoint, tolerance, reducedPointIndicies); reducedPointIndicies.Sort(); //if only two points check if both points the same if (reducedPointIndicies.Count == 2) { if (inputPoints[reducedPointIndicies[0]] == inputPoints[reducedPointIndicies[1]]) { return(new PointInt[0]); } } PointInt endPoint = inputPoints[inputPoints.Length - 1]; bool addEndpoint = endPoint == inputPoints[0]; if (addEndpoint) { resultPoints = new PointInt[reducedPointIndicies.Count + 1]; } else { resultPoints = new PointInt[reducedPointIndicies.Count]; } for (int n = 0; n < reducedPointIndicies.Count; ++n) { resultPoints[n] = inputPoints[reducedPointIndicies[n]]; } if (addEndpoint) { resultPoints[reducedPointIndicies.Count] = endPoint; } return(resultPoints); }