Пример #1
0
        // Cohen-Sutherland line clippign algorithm, adapted to efficiently
        // handle polylines rather than just segments
        public static GeoPoint[] Polyline(GeoPoint[] points, GeoBoundary bbox)
        {
            int             len      = points.Length;
            int             codeA    = BitCode(points[0], bbox);
            int             lastCode = 0;
            List <GeoPoint> ret      = new List <GeoPoint>();
            List <GeoPoint> part     = new List <GeoPoint>();

            for (int i = 1; i < len; i++)
            {
                GeoPoint a     = new GeoPoint(points[i - 1]);
                GeoPoint b     = new GeoPoint(points[i]);
                int      codeB = lastCode = BitCode(b, bbox);
                while (true)
                {
                    if ((codeA | codeB) == 0)
                    { // accept
                        part.Add(a);

                        if (codeB != lastCode)
                        { // segment went outside
                            part.Add(b);

                            if (i < len - 1)
                            { // start a new line
                                ret.AddRange(part);
                                part.Clear();
                            }
                        }
                        else if (i == len - 1)
                        {
                            part.Add(b);
                        }
                        break;
                    }
                    else if ((codeA & codeB) != 0)
                    { // trivial reject
                        break;
                    }
                    else if (codeA != 0)
                    { // a outside, intersect with clip edge
                        a     = Intersect(a, b, codeA, bbox);
                        codeA = BitCode(a, bbox);
                    }
                    else
                    { // b outside
                        b     = Intersect(a, b, codeB, bbox);
                        codeB = BitCode(b, bbox);
                    }
                }
                codeA = lastCode;
            }

            if (part.Count > 0)
            {
                ret.AddRange(part);
            }

            return(ret.ToArray());
        }
Пример #2
0
        // intersect a segment against one of the 4 lines that make up the bbox
        protected static GeoPoint Intersect(GeoPoint a, GeoPoint b, int edge, GeoBoundary bbox)
        {
            GeoPoint ret = null;

            if ((edge & 8) != 0)
            {
                ret = new GeoPoint(a.x + (b.x - a.x) * (bbox.north - a.y) / (b.y - a.y), bbox.north);// top
            }
            else if ((edge & 4) != 0)
            {
                ret = new GeoPoint(a.x + (b.x - a.x) * (bbox.south - a.y) / (b.y - a.y), bbox.south);// bottom
            }
            else if ((edge & 2) != 0)
            {
                ret = new GeoPoint(bbox.east, a.y + (b.y - a.y) * (bbox.east - a.x) / (b.x - a.x));// right
            }
            else if ((edge & 1) != 0)
            {
                ret = new GeoPoint(bbox.west, a.y + (b.y - a.y) * (bbox.west - a.x) / (b.x - a.x));// left
            }
            else
            {
                ret = null;
            }

            return(ret);
        }
Пример #3
0
        // Sutherland-Hodgeman polygon clipping algorithm
        public static GeoPoint[] Polygon(GeoPoint[] points, GeoBoundary bbox)
        {
            List <GeoPoint> ret = new List <GeoPoint>();

            // clip against each side of the clip rectangle
            for (int edge = 1; edge <= 8; edge *= 2)
            {
                ret.Clear();
                GeoPoint prev       = new GeoPoint(points[points.Length - 1]);
                bool     prevInside = (BitCode(prev, bbox) & edge) == 0;

                for (int i = 0; i < points.Length; i++)
                {
                    GeoPoint p      = new GeoPoint(points[i]);
                    bool     inside = (BitCode(p, bbox) & edge) == 0;

                    // if segment goes through the clip window, add an intersection
                    if (inside != prevInside)
                    {
                        ret.Add(Intersect(prev, p, edge, bbox));
                    }

                    if (inside)
                    {
                        ret.Add(p);         // add a point if it's inside
                    }
                    prev       = p;
                    prevInside = inside;
                }

                points = ret.ToArray();

                if (points.Length == 0)
                {
                    break;
                }
            }

            return(ret.ToArray());
        }
Пример #4
0
        // bit code reflects the point position relative to the bbox:

        //                  left  mid  right
        //        top  1001  1000  1010
        //       mid  0001  0000  0010
        // bottom  0101  0100  0110
        public static int BitCode(GeoPoint p, GeoBoundary bbox)
        {
            int code = 0;

            if (p.x < bbox.west)
            {
                code |= 1;                  // left
            }
            else if (p.x > bbox.east)
            {
                code |= 2;                       // right
            }
            if (p.y < bbox.south)
            {
                code |= 4;                   // bottom
            }
            else if (p.y > bbox.north)
            {
                code |= 8;                        // top
            }
            return(code);
        }