Skip to content

Commit

Permalink
code simplification, faster image io, better project file
Browse files Browse the repository at this point in the history
  • Loading branch information
mxgmn committed Jul 21, 2022
1 parent 3e8debe commit 29ffad9
Show file tree
Hide file tree
Showing 121 changed files with 186 additions and 213 deletions.
34 changes: 27 additions & 7 deletions Helper.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
/*
The MIT License(MIT)
Copyright(c) mxgmn 2016.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software.
*/
// Copyright (C) 2016 Maxim Gumin, The MIT License (MIT)

using System.Linq;
using System.Xml.Linq;
using System.ComponentModel;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;

static class Helper
{
Expand Down Expand Up @@ -43,3 +39,27 @@ public static T Get<T>(this XElement xelem, string attribute, T defaultT = defau

public static IEnumerable<XElement> Elements(this XElement xelement, params string[] names) => xelement.Elements().Where(e => names.Any(n => n == e.Name));
}

static class BitmapHelper
{
public static (int[] bitmap, int width, int height) LoadBitmap(string filename)
{
Bitmap bitmap = new(filename);
int width = bitmap.Width, height = bitmap.Height;
var bits = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
int[] result = new int[bitmap.Width * bitmap.Height];
System.Runtime.InteropServices.Marshal.Copy(bits.Scan0, result, 0, result.Length);
bitmap.UnlockBits(bits);
bitmap.Dispose();
return (result, width, height);
}

public static void SaveBitmap(int[] data, int width, int height, string filename)
{
Bitmap result = new(width, height);
var bits = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
System.Runtime.InteropServices.Marshal.Copy(data, 0, bits.Scan0, data.Length);
result.UnlockBits(bits);
result.Save(filename);
}
}
23 changes: 23 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
MIT License

Copyright (c) 2016 Maxim Gumin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Provided image samples and tiles are not part of WaveFunctionCollapse software.
1 change: 0 additions & 1 deletion LICENSE.md

This file was deleted.

14 changes: 4 additions & 10 deletions Model.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
/*
The MIT License(MIT)
Copyright(c) mxgmn 2016.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software.
*/
// Copyright (C) 2016 Maxim Gumin, The MIT License (MIT)

using System;

Expand All @@ -25,9 +19,9 @@ abstract class Model
protected double[] weights;
double[] weightLogWeights, distribution;

int[] sumsOfOnes;
protected int[] sumsOfOnes;
double sumOfWeights, sumOfWeightLogWeights, startingEntropy;
double[] sumsOfWeights, sumsOfWeightLogWeights, entropies;
protected double[] sumsOfWeights, sumsOfWeightLogWeights, entropies;

public enum Heuristic { Entropy, MRV, Scanline };
Heuristic heuristic;
Expand Down Expand Up @@ -231,7 +225,7 @@ void Clear()
}
}

public abstract System.Drawing.Bitmap Graphics();
public abstract void Save(string filename);

protected static int[] dx = { -1, 0, 1, 0 };
protected static int[] dy = { 0, 1, 0, -1 };
Expand Down
160 changes: 52 additions & 108 deletions OverlappingModel.cs
Original file line number Diff line number Diff line change
@@ -1,59 +1,38 @@
/*
The MIT License(MIT)
Copyright(c) mxgmn 2016.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software.
*/
// Copyright (C) 2016 Maxim Gumin, The MIT License (MIT)

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections.Generic;

class OverlappingModel : Model
{
byte[][] patterns;
List<Color> colors;
List<byte[]> patterns;
List<int> colors;

public OverlappingModel(string name, int N, int width, int height, bool periodicInput, bool periodic, int symmetry, bool ground, Heuristic heuristic)
: base(width, height, N, periodic, heuristic)
{
var bitmap = new Bitmap($"samples/{name}.png");
int SX = bitmap.Width, SY = bitmap.Height;
byte[,] sample = new byte[SX, SY];
colors = new List<Color>();

for (int y = 0; y < SY; y++) for (int x = 0; x < SX; x++)
{
Color color = bitmap.GetPixel(x, y);

int i = 0;
foreach (var c in colors)
{
if (c == color) break;
i++;
}

if (i == colors.Count) colors.Add(color);
sample[x, y] = (byte)i;
}

int C = colors.Count;
long W = C.ToPower(N * N);
var (bitmap, SX, SY) = BitmapHelper.LoadBitmap($"samples/{name}.png");
byte[] sample = new byte[bitmap.Length];
colors = new List<int>();
for (int i = 0; i < sample.Length; i++)
{
int color = bitmap[i];
int k = 0;
for (; k < colors.Count; k++) if (colors[k] == color) break;
if (k == colors.Count) colors.Add(color);
sample[i] = (byte)k;
}

byte[] pattern(Func<int, int, byte> f)
static byte[] pattern(Func<int, int, byte> f, int N)
{
byte[] result = new byte[N * N];
for (int y = 0; y < N; y++) for (int x = 0; x < N; x++) result[x + y * N] = f(x, y);
return result;
};
static byte[] rotate(byte[] p, int N) => pattern((x, y) => p[N - 1 - y + x * N], N);
static byte[] reflect(byte[] p, int N) => pattern((x, y) => p[N - 1 - x + y * N], N);

byte[] patternFromSample(int x, int y) => pattern((dx, dy) => sample[(x + dx) % SX, (y + dy) % SY]);
byte[] rotate(byte[] p) => pattern((x, y) => p[N - 1 - y + x * N]);
byte[] reflect(byte[] p) => pattern((x, y) => p[N - 1 - x + y * N]);

long index(byte[] p)
static long hash(byte[] p, int C)
{
long result = 0, power = 1;
for (int i = 0; i < p.Length; i++)
Expand All @@ -64,70 +43,45 @@ long index(byte[] p)
return result;
};

byte[] patternFromIndex(long ind)
{
long residue = ind, power = W;
byte[] result = new byte[N * N];

for (int i = 0; i < result.Length; i++)
{
power /= C;
int count = 0;

while (residue >= power)
{
residue -= power;
count++;
}

result[i] = (byte)count;
}

return result;
};

var weights = new Dictionary<long, int>();
var ordering = new List<long>();
patterns = new();
Dictionary<long, int> patternIndices = new();
List<double> weightList = new();

for (int y = 0; y < (periodicInput ? SY : SY - N + 1); y++) for (int x = 0; x < (periodicInput ? SX : SX - N + 1); x++)
int C = colors.Count;
int xmax = periodicInput ? SX : SX - N + 1;
int ymax = periodicInput ? SY : SY - N + 1;
for (int y = 0; y < ymax; y++) for (int x = 0; x < xmax; x++)
{
byte[][] ps = new byte[8][];

ps[0] = patternFromSample(x, y);
ps[1] = reflect(ps[0]);
ps[2] = rotate(ps[0]);
ps[3] = reflect(ps[2]);
ps[4] = rotate(ps[2]);
ps[5] = reflect(ps[4]);
ps[6] = rotate(ps[4]);
ps[7] = reflect(ps[6]);
ps[0] = pattern((dx, dy) => sample[(x + dx) % SX + (y + dy) % SY * SX], N);
ps[1] = reflect(ps[0], N);
ps[2] = rotate(ps[0], N);
ps[3] = reflect(ps[2], N);
ps[4] = rotate(ps[2], N);
ps[5] = reflect(ps[4], N);
ps[6] = rotate(ps[4], N);
ps[7] = reflect(ps[6], N);

for (int k = 0; k < symmetry; k++)
{
long ind = index(ps[k]);
if (weights.ContainsKey(ind)) weights[ind]++;
byte[] p = ps[k];
long h = hash(p, C);
if (patternIndices.TryGetValue(h, out int index)) weightList[index] = weightList[index] + 1;
else
{
weights.Add(ind, 1);
ordering.Add(ind);
patternIndices.Add(h, weightList.Count);
weightList.Add(1.0);
patterns.Add(p);
}
}
}

T = weights.Count;
weights = weightList.ToArray();
T = weights.Length;
this.ground = ground;
patterns = new byte[T][];
base.weights = new double[T];

int counter = 0;
foreach (long w in ordering)
{
patterns[counter] = patternFromIndex(w);
base.weights[counter] = weights[w];
counter++;
}

bool agrees(byte[] p1, byte[] p2, int dx, int dy)
static bool agrees(byte[] p1, byte[] p2, int dx, int dy, int N)
{
int xmin = dx < 0 ? 0 : dx, xmax = dx < 0 ? dx + N : N, ymin = dy < 0 ? 0 : dy, ymax = dy < 0 ? dy + N : N;
for (int y = ymin; y < ymax; y++) for (int x = xmin; x < xmax; x++) if (p1[x + N * y] != p2[x - dx + N * (y - dy)]) return false;
Expand All @@ -141,18 +95,16 @@ bool agrees(byte[] p1, byte[] p2, int dx, int dy)
for (int t = 0; t < T; t++)
{
List<int> list = new();
for (int t2 = 0; t2 < T; t2++) if (agrees(patterns[t], patterns[t2], dx[d], dy[d])) list.Add(t2);
for (int t2 = 0; t2 < T; t2++) if (agrees(patterns[t], patterns[t2], dx[d], dy[d], N)) list.Add(t2);
propagator[d][t] = new int[list.Count];
for (int c = 0; c < list.Count; c++) propagator[d][t][c] = list[c];
}
}
}

public override Bitmap Graphics()
public override void Save(string filename)
{
Bitmap result = new(MX, MY);
int[] bitmapData = new int[result.Height * result.Width];

int[] bitmap = new int[MX * MY];
if (observed[0] >= 0)
{
for (int y = 0; y < MY; y++)
Expand All @@ -161,8 +113,7 @@ public override Bitmap Graphics()
for (int x = 0; x < MX; x++)
{
int dx = x < MX - N + 1 ? 0 : N - 1;
Color c = colors[patterns[observed[x - dx + (y - dy) * MX]][dx + dy * N]];
bitmapData[x + y * MX] = unchecked((int)0xff000000 | (c.R << 16) | (c.G << 8) | c.B);
bitmap[x + y * MX] = colors[patterns[observed[x - dx + (y - dy) * MX]][dx + dy * N]];
}
}
}
Expand All @@ -172,7 +123,6 @@ public override Bitmap Graphics()
{
int contributors = 0, r = 0, g = 0, b = 0;
int x = i % MX, y = i / MX;

for (int dy = 0; dy < N; dy++) for (int dx = 0; dx < N; dx++)
{
int sx = x - dx;
Expand All @@ -186,21 +136,15 @@ public override Bitmap Graphics()
for (int t = 0; t < T; t++) if (wave[s][t])
{
contributors++;
Color color = colors[patterns[t][dx + dy * N]];
r += color.R;
g += color.G;
b += color.B;
int argb = colors[patterns[t][dx + dy * N]];
r += (argb & 0xff0000) >> 16;
g += (argb & 0xff00) >> 8;
b += argb & 0xff;
}
}

bitmapData[i] = unchecked((int)0xff000000 | ((r / contributors) << 16) | ((g / contributors) << 8) | b / contributors);
bitmap[i] = unchecked((int)0xff000000 | ((r / contributors) << 16) | ((g / contributors) << 8) | b / contributors);
}
}

var bits = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
System.Runtime.InteropServices.Marshal.Copy(bitmapData, 0, bits.Scan0, bitmapData.Length);
result.UnlockBits(bits);

return result;
BitmapHelper.SaveBitmap(bitmap, MX, MY, filename);
}
}
15 changes: 6 additions & 9 deletions Program.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
/*
The MIT License(MIT)
Copyright(c) mxgmn 2016.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software.
*/
// Copyright (C) 2016 Maxim Gumin, The MIT License (MIT)

using System;
using System.Xml.Linq;
Expand All @@ -15,6 +9,8 @@ static class Program
static void Main()
{
Stopwatch sw = Stopwatch.StartNew();
var folder = System.IO.Directory.CreateDirectory("output");
foreach (var file in folder.GetFiles()) file.Delete();

Random random = new();
XDocument xdoc = XDocument.Load("samples.xml");
Expand Down Expand Up @@ -60,8 +56,9 @@ static void Main()
if (success)
{
Console.WriteLine("DONE");
model.Graphics().Save($"{name} {seed}.png");
if (model is SimpleTiledModel stmodel && xelem.Get("textOutput", false)) System.IO.File.WriteAllText($"{name} {seed}.txt", stmodel.TextOutput());
model.Save($"output/{name} {seed}.png");
if (model is SimpleTiledModel stmodel && xelem.Get("textOutput", false))
System.IO.File.WriteAllText($"output/{name} {seed}.txt", stmodel.TextOutput());
break;
}
else Console.WriteLine("CONTRADICTION");
Expand Down
Loading

0 comments on commit 29ffad9

Please sign in to comment.