dartterm/lib/wfc/overlapping.dart

134 lines
3.3 KiB
Dart

import 'dart:ui' as ui;
import 'package:dartterm/wfc/model.dart';
class Bitmap<T> {
final int sx;
final int sy;
final List<T> data;
const Bitmap(this.sx, this.sy, this.data);
}
class OverlappingModel<T> extends Model {
List<List<int>> _patterns = [];
List<T> _colors = [];
Map<T, int> _colorOf = {};
OverlappingModel(
Bitmap<T> bitmap,
int n,
int width,
int height,
bool periodicInput,
bool periodic,
int symmetry,
bool ground,
Heuristic heuristic)
: super(width, height, n, periodic, heuristic) {
List<int> sample = [];
for (var i = 0; i < bitmap.data.length; i++) {
var existing = bitmap.data[i];
var color = _colorOf[existing];
if (color == null) {
color = _colors.length;
_colorOf[existing] = color;
_colors.add(existing);
}
sample[i] = color;
}
var c = _colors.length;
List<int> pattern(int Function(int, int) f) {
return [
for (var y = 0; y < n; y++)
for (var x = 0; x < n; x++) f(x, y)
];
}
List<int> rotate(List<int> p) {
return pattern((x, y) => p[n - 1 - y + x * n]);
}
List<int> reflect(List<int> p) {
return pattern((x, y) => p[n - 1 - x + y * n]);
}
int hash(List<int> p) {
var result = 0, power = 1;
for (var i = 0; i < p.length; i++) {
result += p[p.length - 1 - i] * power;
power *= c;
}
return result;
}
var sx = bitmap.sx;
var sy = bitmap.sy;
Map<int, int> patternIndices = {};
List<double> weightList = [];
var xmax = periodicInput ? sx : sx - n + 1;
var ymax = periodicInput ? sy : sy - n + 1;
for (var y = 0; y < ymax; y++) {
for (var x = 0; x < xmax; x++) {
var ps = [
pattern((dx, dy) => sample[(x + dx) % sx + (y + dy) % sy * sx])
];
ps.add(reflect(ps[0]));
ps.add(rotate(ps[0]));
ps.add(reflect(ps[2]));
ps.add(rotate(ps[2]));
ps.add(reflect(ps[4]));
ps.add(rotate(ps[4]));
ps.add(reflect(ps[6]));
for (var k = 0; k < symmetry; k++) {
var p = ps[k];
var h = hash(p);
var ix = patternIndices[h];
if (ix != null) {
weightList[ix] = weightList[ix] + 1;
} else {
patternIndices[h] = weightList.length;
weightList.add(1.0);
_patterns.add(p);
}
}
}
}
weights = weightList;
cT = weights.length;
this.ground = ground;
bool agrees(List<int> p1, List<int> p2, int dx, int dy) {
int xmin = dx < 0 ? 0 : dx;
int xmax = dx < 0 ? dx + n : n;
int ymin = dy < 0 ? 0 : dy;
int ymax = dy < 0 ? dy + n : n;
for (var y = ymin; y < ymax; y++) {
for (var x = xmin; x < xmax; x++) {
if (p1[x + n * y] != p2[x - dx + n * (y - dy)]) {
return false;
}
}
}
return true;
}
propagator = [
for (var d = 0; d < 4; d++)
[
for (var t = 0; t < cT; t++)
[
for (var t2 = 0; t2 < cT; t2++)
if (agrees(
_patterns[t], _patterns[t2], Model.dx[d], Model.dy[d]))
t2
]
]
];
}
}