Example #1
0
        private int FindTile(int[] colors)
        {
            List <int> candidates = new List <int>();

            for (int i = 0; i < this.tiles.Count; i++)
            {
                WangTile t     = tiles[i];
                bool     match = true;
                for (int j = 0; j < (int)WangTile.neighbour_e.NUM; j++)
                {
                    if (colors[j] < 0)
                    {
                        continue;
                    }
                    if (t.edgeColors[j] != colors[j])
                    {
                        match = false;
                        break;
                    }
                }
                if (match)
                {
                    candidates.Add(i);
                }
            }

            if (candidates.Count == 0)
            {
                return(-1);
            }
            return(candidates[random.Next(candidates.Count)]);
        }
Example #2
0
        private void ToImage(Image img, Size tileSize, List <Bitmap> tileImgs)
        {
            Graphics g      = Graphics.FromImage(img);
            int      tilesW = img.Width / tileSize.Width;
            int      tilesH = img.Height / tileSize.Height;

            WangTile lastTile = null;
            int      last     = -1;

            int[] lastRow    = new int[tilesW];
            int[] currentRow = new int[tilesW];
            for (int i = 0; i < tilesW; i++)
            {
                lastRow[i]    = -1;
                currentRow[i] = -1;
            }
            for (int j = 0; j < tilesH; j++)
            {
                for (int i = 0; i < tilesW; i++)
                {
                    int        current;
                    List <int> availableTiles = null;
                    if (last == -1)
                    {
                        // no restrictions
                        current = random.Next(tiles.Count);
                    }
                    else
                    {
                        if (j == 0)
                        {
                            // only restriction is west edge, which has to match
                            // the east edge of the last tile placed
                            availableTiles = tilesSortedByWest[lastTile.edgeColors[(int)WangTile.neighbour_e.EAST]];
                        }
                        else
                        {
                            int east  = (i == 0 ? random.Next(numColors) : lastTile.edgeColors[(int)WangTile.neighbour_e.EAST]);
                            int north = tiles[lastRow[i]].edgeColors[(int)WangTile.neighbour_e.SOUTH];
                            // restrict by west and north edges
                            availableTiles = tilesSortedByWestNorth[east, north];
                        }
                        current = availableTiles[random.Next(availableTiles.Count)];;
                    }

                    currentRow[i] = current;

                    g.DrawImage(tileImgs[current], new Point(i * tileSize.Width, j * tileSize.Height));
                    last     = current;
                    lastTile = tiles[last];
                }
                for (int k = 0; k < tilesW; k++)
                {
                    lastRow[k] = currentRow[k];
                }
            }
        }
Example #3
0
        private void Subdivide(WangTile tile, int subdivisions, List<int>[] rules, out int[,] result)
        {
            result = new int[subdivisions, subdivisions];

            // the rules determine, for each edge color on the source tile, a
            // list of colors it is substituted with in the subdivided tile set

            /*
             *
             *                              _a__b__c__d_         _______________
             *   -------cN--------        m|\ /\ /\ /\ /|i      |\ /|\ /|\ /|\ /|
             *  |\               /|        |/          \|       |/_\|/_\|/_\|/_\|
             *  |  \           /  |       n|\          /|j      |\ /|\ /|\ /|\ /|
             *  |    \       /    |        |/          \|       |/_\|/_\|/_\|/_\|
             *  |      \   /      |       o|\          /|k      |\ /|\ /|\ /|\ /|
             *  cW       X       cE  -->   |/          \|  -->  |/_\|/_\|/_\|/_\|
             *  |      /   \      |       p|\          /|l      |\ /|\ /|\ /|\ /|
             *  |    /       \    |        |/_\/_\/_\/_\|       |/_\|/_\|/_\|/_\|
             *  |  /           \  |          e  f  g  h
             *  | /              \|
             *  |/------cS--------
             *
             *  cN --> a,b,c,d
             *  cS --> e,f,g,h
             *  cE --> i,j,k,l
             *  cW --> m,n,o,p
             *
             * Only corners have 2 restrictions (m-a, d-i, p-e, l-h), remaining
             * edges have 1 restriction then we use the scanline algorithm to
             * fill-in the gaps
             */
            int[] restrictions = new int[(int)WangTile.neighbour_e.NUM];
            int previous = -1;
            int[] upperRow = new int[subdivisions];

            for (int i = 0; i < subdivisions; i++)
            {
                for (int j = 0; j < subdivisions; j++)
                {
                    restrictions[(int)WangTile.neighbour_e.NORTH] = -1;
                    restrictions[(int)WangTile.neighbour_e.SOUTH] = -1;
                    restrictions[(int)WangTile.neighbour_e.EAST] = -1;
                    restrictions[(int)WangTile.neighbour_e.WEST] = -1;

                    if (i == 0) restrictions[(int)WangTile.neighbour_e.NORTH] = rules[tile.edgeColors[(int)WangTile.neighbour_e.NORTH]][j];
                    if (i == subdivisions - 1 ) restrictions[(int)WangTile.neighbour_e.SOUTH] = rules[tile.edgeColors[(int)WangTile.neighbour_e.SOUTH]][j];
                    if (j == 0) restrictions[(int)WangTile.neighbour_e.WEST] = rules[tile.edgeColors[(int)WangTile.neighbour_e.WEST]][i];
                    if (j == subdivisions - 1 ) restrictions[(int)WangTile.neighbour_e.EAST] = rules[tile.edgeColors[(int)WangTile.neighbour_e.EAST]][i];

                    if (i > 0)
                        restrictions[(int)WangTile.neighbour_e.NORTH] = tiles[upperRow[j]].edgeColors[(int)WangTile.neighbour_e.SOUTH];
                    if (j > 0)
                        restrictions[(int)WangTile.neighbour_e.WEST] = tiles[upperRow[j]].edgeColors[(int)WangTile.neighbour_e.EAST];

                    result[i, j] = FindTile(restrictions);
                    previous = result[i, j];
                }
                for (int j = 0; j < subdivisions; j++) upperRow[j] = result[i, j];
            }
        }
Example #4
0
        public void Generate(int numColors, int samplesPerTile, int numThreads )
        {
            random = new Random();
            this.numColors = numColors;
            tiles = new List<WangTile>();

            const int numEdges = 4;
            int numTiles = (int)Math.Pow(numColors, numEdges);

            #region generate Poisson distributions
            List<PoissonSample>[] distributions = new List<PoissonSample>[numTiles];
            generatePoissonDistParam_t[] threadParams = new generatePoissonDistParam_t[numThreads];
            PoissonDistribution[] generators = new PoissonDistribution[numThreads];
            AutoResetEvent[] waitHandles = new AutoResetEvent[numThreads];

            for (int i = 0; i < numThreads; i++)
            {
                threadParams[i].dist = new PoissonDistribution();
                threadParams[i].numSamples = samplesPerTile;
                waitHandles[i] = new AutoResetEvent(false);
                threadParams[i].autoResetEvent = waitHandles[i];
            }
            int t = 0;
            Queue<int> availableThreads = new Queue<int>();
            for (int i = 0; i < numThreads; i++) availableThreads.Enqueue(i);

            if (OnConsoleMessage != null) OnConsoleMessage("Generating " + numTiles + " source Poisson Distributions with " + samplesPerTile + " samples each...");

            Image debugImage = null;
            if (OnDebugStep != null) debugImage = new Bitmap(800, 800);

            while (t < numTiles || availableThreads.Count < numThreads)
            {
                while (availableThreads.Count > 0 && t < numTiles)
                {
                    int i = availableThreads.Dequeue();
                    if (OnProgressReport != null) OnProgressReport((float)(t + 1) / numTiles);
                    distributions[t] = new List<PoissonSample>(samplesPerTile);
                    threadParams[i].result = distributions[t];
                    ThreadPool.QueueUserWorkItem(new WaitCallback(GeneratePoissonDistThreaded), threadParams[i]);
                    t++;
                }
                int index = WaitHandle.WaitAny(waitHandles);
                if (debugImage != null)
                {
                    PoissonDistribution.ToImage( threadParams[index].dist.Samples, Color.Black, debugImage, 1);
                    OnDebugStep(debugImage, "Poisson Distribution " + t);
                }
                availableThreads.Enqueue(index);
            }

            #endregion

            #region generate seam tiles
            List<SourceTile> seamTiles = new List<SourceTile>();
            #if DEBUG
            Color[] colors = new Color[numColors];
            for( int i = 0; i < numColors; i++ ) colors[i] = Color.FromArgb(random.Next(256), random.Next(256), random.Next(256));
            #endif
            for (int i = 0; i < numColors; i++)
            {
                PoissonDistribution distribution = new PoissonDistribution();
                distribution.Generate(samplesPerTile);
            #if DEBUG
                foreach (PoissonSample p in distribution.Samples) p.color = colors[i];
            #endif
                seamTiles.Add(new SourceTile(distribution.Samples, i));
            }
            #endregion

            #region generate all edge permutations
            /*
             * 0000 0001 0002 ... 000n
             * 0010 0011 0012 ... 001n
             * 0020 0021 0022 ... 002n
             * ...
             * 00n0 00n1 00n2 ... 00nn
             *
             * 0100 0101 0102 ... 010n
             * 0110 0111 0112 ... 011n
             * ...
             * 01n0 01n1 01n2 ... 01nn
             *
             * ...
             *
             * nnn0 nnn1 nnn2 ... nnnn
             */
            int[,] edgeCol = new int[numTiles,numEdges];
            for (int i = 0; i < numEdges; i++) edgeCol[0, i] = 0;
            for (int i = 1; i < numTiles; i++)
            {
                for (int j = 0; j < numEdges; j++)
                {
                    edgeCol[i,j] = (edgeCol[i-1,j] + (i % (int)Math.Pow(numColors, j) == 0 ? 1 : 0)) % numColors;
                }
            }
            #endregion

            #region generate wang tiles
            WangTile[] tileArray = new WangTile[numTiles];
            t = 0;
            availableThreads.Clear();
            createWangTileParam_t[] createWangTileParams = new createWangTileParam_t[numThreads];
            for (int i = 0; i < numThreads; i++)
            {
                availableThreads.Enqueue(i);
                createWangTileParams[i] = new createWangTileParam_t();
                createWangTileParams[i].autoResetEvent = waitHandles[i];
                createWangTileParams[i].autoResetEvent.Reset();
                createWangTileParams[i].tileArray = tileArray;
            }

            if (OnConsoleMessage != null) OnConsoleMessage("Merging distributions to generate Wang Tiles..." );

            while (t < numTiles || availableThreads.Count < numThreads)
            {
                while (availableThreads.Count > 0 && t < numTiles)
                {
                    int i = availableThreads.Dequeue();
                    if (OnProgressReport != null) OnProgressReport((float)( t + 1 ) / numTiles);

                    createWangTileParams[i].tileBaseDistribution = distributions[t];
                    createWangTileParams[i].neighbours = new List<SourceTile>();
                    createWangTileParams[i].tileIndex = t;
                    if (numColors > 1)
                    {
                        for (int j = 0; j < numEdges; j++)
                            createWangTileParams[i].neighbours.Add(seamTiles[edgeCol[t, j]]);
                    }
                    ThreadPool.QueueUserWorkItem(new WaitCallback(CreateWangTileThreaded), createWangTileParams[i]);
                    t++;
                }
                int index = WaitHandle.WaitAny(waitHandles);
                availableThreads.Enqueue(index);
            }
            tiles = tileArray.ToList();

            SortTiles();
            MakeRecursive();

            if (OnDebugStep != null)
            {
                ToColorTiles(debugImage, new Size(8, 8));
                OnDebugStep(debugImage, "Sample coverage of the generated Wang Tiles" );
            }

            #endregion
        }
Example #5
0
        private void Subdivide(WangTile tile, int subdivisions, List <int>[] rules, out int[,] result)
        {
            result = new int[subdivisions, subdivisions];

            // the rules determine, for each edge color on the source tile, a
            // list of colors it is substituted with in the subdivided tile set

            /*
             *
             *                              _a__b__c__d_         _______________
             *   -------cN--------        m|\ /\ /\ /\ /|i      |\ /|\ /|\ /|\ /|
             *  |\               /|        |/          \|       |/_\|/_\|/_\|/_\|
             *  |  \           /  |       n|\          /|j      |\ /|\ /|\ /|\ /|
             *  |    \       /    |        |/          \|       |/_\|/_\|/_\|/_\|
             *  |      \   /      |       o|\          /|k      |\ /|\ /|\ /|\ /|
             *  cW       X       cE  -->   |/          \|  -->  |/_\|/_\|/_\|/_\|
             *  |      /   \      |       p|\          /|l      |\ /|\ /|\ /|\ /|
             *  |    /       \    |        |/_\/_\/_\/_\|       |/_\|/_\|/_\|/_\|
             *  |  /           \  |          e  f  g  h
             *  | /              \|
             *  |/------cS--------
             *
             *  cN --> a,b,c,d
             *  cS --> e,f,g,h
             *  cE --> i,j,k,l
             *  cW --> m,n,o,p
             *
             * Only corners have 2 restrictions (m-a, d-i, p-e, l-h), remaining
             * edges have 1 restriction then we use the scanline algorithm to
             * fill-in the gaps
             */
            int[] restrictions = new int[(int)WangTile.neighbour_e.NUM];
            int   previous     = -1;

            int[] upperRow = new int[subdivisions];

            for (int i = 0; i < subdivisions; i++)
            {
                for (int j = 0; j < subdivisions; j++)
                {
                    restrictions[(int)WangTile.neighbour_e.NORTH] = -1;
                    restrictions[(int)WangTile.neighbour_e.SOUTH] = -1;
                    restrictions[(int)WangTile.neighbour_e.EAST]  = -1;
                    restrictions[(int)WangTile.neighbour_e.WEST]  = -1;

                    if (i == 0)
                    {
                        restrictions[(int)WangTile.neighbour_e.NORTH] = rules[tile.edgeColors[(int)WangTile.neighbour_e.NORTH]][j];
                    }
                    if (i == subdivisions - 1)
                    {
                        restrictions[(int)WangTile.neighbour_e.SOUTH] = rules[tile.edgeColors[(int)WangTile.neighbour_e.SOUTH]][j];
                    }
                    if (j == 0)
                    {
                        restrictions[(int)WangTile.neighbour_e.WEST] = rules[tile.edgeColors[(int)WangTile.neighbour_e.WEST]][i];
                    }
                    if (j == subdivisions - 1)
                    {
                        restrictions[(int)WangTile.neighbour_e.EAST] = rules[tile.edgeColors[(int)WangTile.neighbour_e.EAST]][i];
                    }

                    if (i > 0)
                    {
                        restrictions[(int)WangTile.neighbour_e.NORTH] = tiles[upperRow[j]].edgeColors[(int)WangTile.neighbour_e.SOUTH];
                    }
                    if (j > 0)
                    {
                        restrictions[(int)WangTile.neighbour_e.WEST] = tiles[upperRow[j]].edgeColors[(int)WangTile.neighbour_e.EAST];
                    }

                    result[i, j] = FindTile(restrictions);
                    previous     = result[i, j];
                }
                for (int j = 0; j < subdivisions; j++)
                {
                    upperRow[j] = result[i, j];
                }
            }
        }
Example #6
0
        public void Generate(int numColors, int samplesPerTile, int numThreads)
        {
            random         = new Random();
            this.numColors = numColors;
            tiles          = new List <WangTile>();

            const int numEdges = 4;
            int       numTiles = (int)Math.Pow(numColors, numEdges);

            #region generate Poisson distributions
            List <PoissonSample>[]       distributions = new List <PoissonSample> [numTiles];
            generatePoissonDistParam_t[] threadParams  = new generatePoissonDistParam_t[numThreads];
            PoissonDistribution[]        generators    = new PoissonDistribution[numThreads];
            AutoResetEvent[]             waitHandles   = new AutoResetEvent[numThreads];

            for (int i = 0; i < numThreads; i++)
            {
                threadParams[i].dist           = new PoissonDistribution();
                threadParams[i].numSamples     = samplesPerTile;
                waitHandles[i]                 = new AutoResetEvent(false);
                threadParams[i].autoResetEvent = waitHandles[i];
            }
            int         t = 0;
            Queue <int> availableThreads = new Queue <int>();
            for (int i = 0; i < numThreads; i++)
            {
                availableThreads.Enqueue(i);
            }

            if (OnConsoleMessage != null)
            {
                OnConsoleMessage("Generating " + numTiles + " source Poisson Distributions with " + samplesPerTile + " samples each...");
            }

            Image debugImage = null;
            if (OnDebugStep != null)
            {
                debugImage = new Bitmap(800, 800);
            }

            while (t < numTiles || availableThreads.Count < numThreads)
            {
                while (availableThreads.Count > 0 && t < numTiles)
                {
                    int i = availableThreads.Dequeue();
                    if (OnProgressReport != null)
                    {
                        OnProgressReport((float)(t + 1) / numTiles);
                    }
                    distributions[t]       = new List <PoissonSample>(samplesPerTile);
                    threadParams[i].result = distributions[t];
                    ThreadPool.QueueUserWorkItem(new WaitCallback(GeneratePoissonDistThreaded), threadParams[i]);
                    t++;
                }
                int index = WaitHandle.WaitAny(waitHandles);
                if (debugImage != null)
                {
                    PoissonDistribution.ToImage(threadParams[index].dist.Samples, Color.Black, debugImage, 1);
                    OnDebugStep(debugImage, "Poisson Distribution " + t);
                }
                availableThreads.Enqueue(index);
            }

            #endregion

            #region generate seam tiles
            List <SourceTile> seamTiles = new List <SourceTile>();
#if DEBUG
            Color[] colors = new Color[numColors];
            for (int i = 0; i < numColors; i++)
            {
                colors[i] = Color.FromArgb(random.Next(256), random.Next(256), random.Next(256));
            }
#endif
            for (int i = 0; i < numColors; i++)
            {
                PoissonDistribution distribution = new PoissonDistribution();
                distribution.Generate(samplesPerTile);
#if DEBUG
                foreach (PoissonSample p in distribution.Samples)
                {
                    p.color = colors[i];
                }
#endif
                seamTiles.Add(new SourceTile(distribution.Samples, i));
            }
            #endregion

            #region generate all edge permutations

            /*
             * 0000 0001 0002 ... 000n
             * 0010 0011 0012 ... 001n
             * 0020 0021 0022 ... 002n
             * ...
             * 00n0 00n1 00n2 ... 00nn
             *
             * 0100 0101 0102 ... 010n
             * 0110 0111 0112 ... 011n
             * ...
             * 01n0 01n1 01n2 ... 01nn
             *
             * ...
             *
             * nnn0 nnn1 nnn2 ... nnnn
             */
            int[,] edgeCol = new int[numTiles, numEdges];
            for (int i = 0; i < numEdges; i++)
            {
                edgeCol[0, i] = 0;
            }
            for (int i = 1; i < numTiles; i++)
            {
                for (int j = 0; j < numEdges; j++)
                {
                    edgeCol[i, j] = (edgeCol[i - 1, j] + (i % (int)Math.Pow(numColors, j) == 0 ? 1 : 0)) % numColors;
                }
            }
            #endregion

            #region generate wang tiles
            WangTile[] tileArray = new WangTile[numTiles];
            t = 0;
            availableThreads.Clear();
            createWangTileParam_t[] createWangTileParams = new createWangTileParam_t[numThreads];
            for (int i = 0; i < numThreads; i++)
            {
                availableThreads.Enqueue(i);
                createWangTileParams[i] = new createWangTileParam_t();
                createWangTileParams[i].autoResetEvent = waitHandles[i];
                createWangTileParams[i].autoResetEvent.Reset();
                createWangTileParams[i].tileArray = tileArray;
            }

            if (OnConsoleMessage != null)
            {
                OnConsoleMessage("Merging distributions to generate Wang Tiles...");
            }

            while (t < numTiles || availableThreads.Count < numThreads)
            {
                while (availableThreads.Count > 0 && t < numTiles)
                {
                    int i = availableThreads.Dequeue();
                    if (OnProgressReport != null)
                    {
                        OnProgressReport((float)(t + 1) / numTiles);
                    }

                    createWangTileParams[i].tileBaseDistribution = distributions[t];
                    createWangTileParams[i].neighbours           = new List <SourceTile>();
                    createWangTileParams[i].tileIndex            = t;
                    if (numColors > 1)
                    {
                        for (int j = 0; j < numEdges; j++)
                        {
                            createWangTileParams[i].neighbours.Add(seamTiles[edgeCol[t, j]]);
                        }
                    }
                    ThreadPool.QueueUserWorkItem(new WaitCallback(CreateWangTileThreaded), createWangTileParams[i]);
                    t++;
                }
                int index = WaitHandle.WaitAny(waitHandles);
                availableThreads.Enqueue(index);
            }
            tiles = tileArray.ToList();

            SortTiles();
            MakeRecursive();

            if (OnDebugStep != null)
            {
                ToColorTiles(debugImage, new Size(8, 8));
                OnDebugStep(debugImage, "Sample coverage of the generated Wang Tiles");
            }

            #endregion
        }