예제 #1
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);
        }
예제 #2
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);
        }
예제 #3
0
        /// <summary>
        /// Cohen–Sutherland clipping algorithm clips a line from P0 = (x0, y0) to P1 = (x1, y1) against a clipBounds rectangle
        /// </summary>
        /// <param name="x0"></param>
        /// <param name="y0"></param>
        /// <param name="x1"></param>
        /// <param name="y1"></param>
        /// <param name="tileScreenBoundingBox"></param>
        /// <param name="clipState"> state of clipped line. ClipState.None if line is not clipped. If either end of the line
        /// is clipped then the clipState flag are set (ClipState.Start or ClipState.End) </param>
        /// <returns>true if clipped line is inside given clip bounds</returns>
        private static bool CohenSutherlandLineClip(ref double x0, ref double y0, ref double x1, ref double y1, ref RectangleInt tileScreenBoundingBox, out ClipState clipState)
        {
            // compute outcodes for P0, P1, and whatever point lies outside the clip rectangle
            OutCode outcode0 = ComputeOutCode(x0, y0, ref tileScreenBoundingBox);
            OutCode outcode1 = ComputeOutCode(x1, y1, ref tileScreenBoundingBox);
            bool    accept   = false;

            clipState = ClipState.None;

            while (true)
            {
                if ((outcode0 | outcode1) == OutCode.Inside)
                {
                    // bitwise OR is 0: both points inside window; trivially accept and exit loop
                    accept = true;
                    break;
                }
                else if ((outcode0 & outcode1) != OutCode.Inside)
                {
                    // bitwise AND is not 0: both points share an outside zone (LEFT, RIGHT, TOP,
                    // or BOTTOM), so both must be outside window; exit loop (accept is false)
                    break;
                }
                else
                {
                    // failed both tests, so calculate the line segment to clip
                    // from an outside point to an intersection with clip edge
                    double x = 0, y = 0;

                    // At least one endpoint is outside the clip rectangle; pick it.
                    OutCode outcodeOut = outcode0 != OutCode.Inside ? outcode0 : outcode1;

                    // Now find the intersection point;
                    // use formulas:
                    //   slope = (y1 - y0) / (x1 - x0)
                    //   x = x0 + (1 / slope) * (ym - y0), where ym is ymin or ymax
                    //   y = y0 + slope * (xm - x0), where xm is xmin or xmax
                    // No need to worry about divide-by-zero because, in each case, the
                    // outcode bit being tested guarantees the denominator is non-zero
                    if ((outcodeOut & OutCode.Top) == OutCode.Top)
                    {           // point is above the clip window
                        x = x0 + (x1 - x0) * (tileScreenBoundingBox.YMax - y0) / (y1 - y0);
                        y = tileScreenBoundingBox.YMax;
                    }
                    else if ((outcodeOut & OutCode.Bottom) == OutCode.Bottom)
                    {                                   // point is below the clip window
                        x = x0 + (x1 - x0) * (tileScreenBoundingBox.YMin - y0) / (y1 - y0);
                        y = tileScreenBoundingBox.YMin; // ymin;
                    }
                    else if ((outcodeOut & OutCode.Right) == OutCode.Right)
                    {                                   // point is to the right of clip window
                        y = y0 + (y1 - y0) * (tileScreenBoundingBox.XMax - x0) / (x1 - x0);
                        x = tileScreenBoundingBox.XMax; // xmax;
                    }
                    else if ((outcodeOut & OutCode.Left) == OutCode.Left)
                    {                                   // point is to the left of clip window
                        y = y0 + (y1 - y0) * (tileScreenBoundingBox.XMin - x0) / (x1 - x0);
                        x = tileScreenBoundingBox.XMin; // xmin;
                    }

                    // Now we move outside point to intersection point to clip
                    // and get ready for next pass.
                    if (outcodeOut == outcode0)
                    {
                        clipState |= ClipState.Start;
                        x0         = x;
                        y0         = y;
                        outcode0   = ComputeOutCode(x0, y0, ref tileScreenBoundingBox);
                    }
                    else
                    {
                        clipState |= ClipState.End;

                        x1       = x;
                        y1       = y;
                        outcode1 = ComputeOutCode(x1, y1, ref tileScreenBoundingBox);
                    }
                }
            }

            return(accept);
        }