Пример #1
0
        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)));
        }
Пример #2
0
        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);
        }
Пример #3
0
        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));
        }
Пример #4
0
        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));
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }
Пример #7
0
        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);
        }
Пример #8
0
        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)));
        }
Пример #9
0
        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);
        }
Пример #10
0
        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]));
                            }
                        }
                    }
                }
            }
        }
Пример #11
0
        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));
        }
Пример #12
0
        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);
                }
            }
        }
Пример #13
0
        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);
        }
Пример #14
0
        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);
        }
Пример #15
0
        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);
        }