public static WangTile[] WangTile(WangTile[] wangTiles, Size wangTileSize, 
			Bitmap[] sourceBitmaps, int sourceBitmapBorderWidth, 
			int maxAttempts, 
			long maximumMatchingError,
			bool onePixelOverlapBetweenTiles)
        {
            Size sampleTileSize = new Size(wangTileSize.Width*3/2 + (onePixelOverlapBetweenTiles ? 1 : 0),
                wangTileSize.Height*3/2 + (onePixelOverlapBetweenTiles ? 1 : 0));

            // determine the number of Sample Portions you'll need
            int numSamplePortions = 0;
            foreach (WangTile wt in wangTiles) numSamplePortions = Math.Max(numSamplePortions, wt.MaxColorNumber);
            numSamplePortions++;

            int numAttempts = 0;
            int numSourceBitmaps = sourceBitmaps.Length;

            WangTileSpecification bestSpecification = null;
            // while you haven't found an appropriate wang tiling..
            while (numAttempts < maxAttempts && (bestSpecification == null || bestSpecification.MatchingError > maximumMatchingError) )
            {
                Util.Spew("Generating Wang Tiles, attempt " + (numAttempts+1) + " of a maximum " + maxAttempts+"...");
                Application.DoEvents();

                WangTileSpecification wts = new WangTileSpecification(wangTiles, sourceBitmaps, onePixelOverlapBetweenTiles);
                numAttempts ++;

                wts.WangTileSize = wangTileSize;
                wts.SamplePortions = new Rectangle[numSourceBitmaps, numSamplePortions];
                // Randomly select new sample portions from each bitmap.
                for (int bmp = 0; bmp < numSourceBitmaps; bmp++)
                {
                    int maxX = sourceBitmaps[bmp].Width - sampleTileSize.Width - (2*sourceBitmapBorderWidth);
                    int maxY = sourceBitmaps[bmp].Height - sampleTileSize.Height - (2*sourceBitmapBorderWidth);
                    for (int i = 0; i < numSamplePortions; i++)
                    {
                        wts.SamplePortions[bmp, i] = new Rectangle(new Point(sourceBitmapBorderWidth+r.Next(maxX), sourceBitmapBorderWidth+r.Next(maxY)), sampleTileSize);
                    }
                }

                wts.RecalcScanLines();
                if (bestSpecification == null || wts.MatchingError < bestSpecification.MatchingError)
                {
                    bestSpecification = wts;
                }
            }

            Util.Spew("Synthesizing bitmaps for best Wang Tile specification...");
            Application.DoEvents();

            bestSpecification.SynthesizeBitmaps();

            Util.Spew("Finished generating Wang Tiles.");
            Application.DoEvents();

            return bestSpecification.WangTiles;
        }
        public static WangTile[] WangTile(WangTile[] wangTiles, Size wangTileSize,
                                          Bitmap[] sourceBitmaps, int sourceBitmapBorderWidth,
                                          int maxAttempts,
                                          long maximumMatchingError,
                                          bool onePixelOverlapBetweenTiles)
        {
            Size sampleTileSize = new Size(wangTileSize.Width * 3 / 2 + (onePixelOverlapBetweenTiles ? 1 : 0),
                                           wangTileSize.Height * 3 / 2 + (onePixelOverlapBetweenTiles ? 1 : 0));

            // determine the number of Sample Portions you'll need
            int numSamplePortions = 0;

            foreach (WangTile wt in wangTiles)
            {
                numSamplePortions = Math.Max(numSamplePortions, wt.MaxColorNumber);
            }
            numSamplePortions++;

            int numAttempts      = 0;
            int numSourceBitmaps = sourceBitmaps.Length;

            WangTileSpecification bestSpecification = null;

            // while you haven't found an appropriate wang tiling..
            while (numAttempts < maxAttempts && (bestSpecification == null || bestSpecification.MatchingError > maximumMatchingError))
            {
                Util.Spew("Generating Wang Tiles, attempt " + (numAttempts + 1) + " of a maximum " + maxAttempts + "...");
                Application.DoEvents();

                WangTileSpecification wts = new WangTileSpecification(wangTiles, sourceBitmaps, onePixelOverlapBetweenTiles);
                numAttempts++;

                wts.WangTileSize   = wangTileSize;
                wts.SamplePortions = new Rectangle[numSourceBitmaps, numSamplePortions];
                // Randomly select new sample portions from each bitmap.
                for (int bmp = 0; bmp < numSourceBitmaps; bmp++)
                {
                    int maxX = sourceBitmaps[bmp].Width - sampleTileSize.Width - (2 * sourceBitmapBorderWidth);
                    int maxY = sourceBitmaps[bmp].Height - sampleTileSize.Height - (2 * sourceBitmapBorderWidth);
                    for (int i = 0; i < numSamplePortions; i++)
                    {
                        wts.SamplePortions[bmp, i] = new Rectangle(new Point(sourceBitmapBorderWidth + r.Next(maxX), sourceBitmapBorderWidth + r.Next(maxY)), sampleTileSize);
                    }
                }

                wts.RecalcScanLines();
                if (bestSpecification == null || wts.MatchingError < bestSpecification.MatchingError)
                {
                    bestSpecification = wts;
                }
            }

            Util.Spew("Synthesizing bitmaps for best Wang Tile specification...");
            Application.DoEvents();

            bestSpecification.SynthesizeBitmaps();

            Util.Spew("Finished generating Wang Tiles.");
            Application.DoEvents();


            return(bestSpecification.WangTiles);
        }