Example #1
0
        /// <summary>
        /// Converts the specified BitMatrix into a list of Polygons.
        /// </summary>
        /// <param name='bm'>
        /// The BitMatrix to convert from.
        /// </param>
        public static Paths Polygonize(BitMatrix bm)
        {
            #region pixels grouping
            // group pixels into separate areas, keep in mind that a polygon only stores points here
            Paths areas = new Paths();

            // current scanline
            BitArray currLineBuf = new BitArray(bm.width);

            Path[] prevLine = new Path[bm.width];

            for (int i = 0; i < bm.width; i++)
            {
                prevLine[i] = null;
            }

            // the area that current pixel belongs to
            Path currArea, prevArea;

            int left;                                   // counter for checking pixels on the left side

            for (int y = 0; y < bm.height; y++)
            {
                // scan current line
                for (int x = 0; x < bm.width; x++)
                {
                    // store current pixel in the buffer
                    currLineBuf[x] = bm.Get(x, y);
                    // index of the left pixel
                    left = x - 1;

                    // pixel connects with the pixel above it
                    if (currLineBuf[x])
                    {
                        //Debug.WriteLine("{0}, {1}: active", y, x);
                        // check pixels on top of it
                        currArea = prevLine[x];
                        if (currArea != null)
                        {
                            //Debug.WriteLine("Join top");
                            // join current pixel into top area
                            currArea.Add(new IntPoint(x, y));
                            // Checks the pixels on the left side
                            // if they are connected to current pixel,
                            //   if they belong to different area
                            //	   change all of them to current area, and merge that area into current area
                            //	 else do nothing
                            // else do nothing

                            // merge left area into top one
                            if (left >= 0)
                            {
                                prevArea = prevLine[left];
                                if (prevArea != null && prevArea != currArea)
                                {
                                    //Debug.WriteLine("Merging left to top");
                                    prevArea = prevLine[left];
                                    while (left >= 0)
                                    {
                                        // update references of pixels on the left side
                                        if (prevLine[left] == prevArea)
                                        {
                                            prevLine[left] = currArea;
                                        }
                                        left--;
                                    }
                                    // merge area into current one
                                    areas.Remove(prevArea);
                                    currArea.AddRange(prevArea);
                                }
                            }
                        }
                        else
                        {
                            // Since no active pixel on top, check left side
                            // if left side is active
                            //	 simply join to the left area
                            // else
                            //	 create a new area
                            if (left >= 0 && prevLine[left] != null)
                            {
                                //Debug.WriteLine("Join left");
                                prevLine[left].Add(new IntPoint(x, y));
                                prevLine[x] = prevLine[left];
                            }
                            else
                            {
                                //Debug.WriteLine("Create new");
                                Path newArea = new Path();
                                newArea.Add(new IntPoint(x, y));
                                areas.Add(newArea);
                                prevLine[x] = newArea;
                            }
                        }
                        // pixel not activated
                    }
                    else
                    {
                        //Debug.WriteLine("{0},{1}: not active", x, y);
                        prevLine[x] = null;
                    }
                }
            }
            #endregion

            #region polygonize each group of pixels into contour pixels
            Path p;
            //Create Polygons from given areas
            for (int i = 0; i < areas.Count; i++)
            {
                // dequeue a group of points
                p = areas[0];
                areas.RemoveAt(0);
                // convert to contour
                p = Polygonizer.FromGroup(p);
                // enqueue back
                areas.Add(p);
            }
            #endregion

            return(areas);
        }
Example #2
0
        /// <summary>
        /// Create Polygon from a group of points
        private static Path FromGroup(Path area)
        {
            Rect      box     = BoundBox(area);
            BitMatrix bm      = Polygonizer.DrawPoints(area, box);              // The matrix holding the points
            Path      polygon = new Path();                                     // the result

            // find highest & leftmost point
            int i = 0;

            for (i = 0; i < bm.bits.Length; i++)
            {
                if (bm.bits[i])
                {
                    break;
                }
                i++;
            }

            IntPoint  currP       = new IntPoint();
            IntPoint  nextP       = new IntPoint();
            IntPoint  guessP      = new IntPoint();
            Direction currDirBack = Direction.NE;               // since the first point is uppermost & leftmost, prevDirBack can never be W
            Direction nextDirBack = Direction.E;                // a random direction different from prevDirBack

            // extract the coordinate
            currP.X = i % bm.width;
            currP.Y = i / bm.width;
            IntPoint startP = new IntPoint(currP);

            // the position to look at based on the curr point
            // NE SE SE
            // NE CT SW
            // NW NW SW
            do
            {
                // make guessP the next moore neighbor
                switch (currDirBack)
                {
                case Direction.N: goto case Direction.NE;

                case Direction.NE:
                    guessP.X = currP.X + 1;
                    guessP.Y = currP.Y + 1;
                    break;

                case Direction.E: goto case Direction.SE;

                case Direction.SE:
                    guessP.X = currP.X - 1;
                    guessP.Y = currP.Y + 1;
                    break;

                case Direction.S: goto case Direction.SW;

                case Direction.SW:
                    guessP.X = currP.X - 1;
                    guessP.Y = currP.Y - 1;
                    break;

                case Direction.W: goto case Direction.NW;

                case Direction.NW:
                    guessP.X = currP.X + 1;
                    guessP.Y = currP.Y - 1;
                    break;
                }
                nextP       = bm.nextNeighbour(currP, guessP);
                nextDirBack = BitMatrix.getDirection(nextP, currP);
                // only add the curr point if it is a true vertex
                if (nextDirBack != currDirBack)
                {
                    polygon.Add(new IntPoint(currP.X + box.xMin, currP.Y + box.yMin));
                    currDirBack = nextDirBack;
                }
                currP = nextP;
            } while (nextP != startP);

            RDP(polygon);
            return(polygon);
        }