133 lines
3.9 KiB
JavaScript
133 lines
3.9 KiB
JavaScript
import Cartographer from './cartographer.js';
|
|
|
|
import {rangeInclusive, sqrt2} from './utils.js';
|
|
|
|
import Square from './square.js';
|
|
import Point from './point.js';
|
|
|
|
export default class CartographerXY extends Cartographer {
|
|
constructor(settings) {
|
|
super(settings);
|
|
|
|
[
|
|
'maxWidth',
|
|
'minWidth',
|
|
|
|
'maxDistance',
|
|
'minDistance',
|
|
|
|
'getCellWidth',
|
|
'getCellHeight',
|
|
|
|
'getHorzDistance',
|
|
'getVertDistance',
|
|
|
|
'tileToPixel',
|
|
'pixelToTile',
|
|
'boundingBox',
|
|
].map(method => this[method] = this[method].bind(this));
|
|
}
|
|
|
|
maxWidth() {
|
|
return this.minWidth() * sqrt2;
|
|
}
|
|
|
|
minWidth() {
|
|
return this.scale * 2;
|
|
}
|
|
|
|
maxDistance() {
|
|
return this.maxWidth();
|
|
}
|
|
|
|
minDistance() {
|
|
return this.minWidth();
|
|
}
|
|
|
|
getCellWidth() {return this.pointyTop ? this.maxWidth() : this.minWidth();}
|
|
getCellHeight() {return this.pointyTop ? this.maxWidth() : this.minWidth();}
|
|
|
|
getHorzDistance() {return this.pointyTop ? this.maxDistance() : this.minDistance();}
|
|
getVertDistance() {return this.pointyTop ? this.maxDistance() : this.minDistance();}
|
|
|
|
tileToPixel(square) {
|
|
const scale = this.scale;
|
|
|
|
// (above/below axis) * (distance from axis) / (size)
|
|
const pointyDistanceX = (x, y) => (x < y ? -1 : 1) * (Math.abs(y - x) / sqrt2) * this.minWidth();
|
|
const pointyDistanceY = (x, y) => (-x < y ? 1 : -1) * (Math.abs(x + y) / sqrt2) * this.minWidth();
|
|
|
|
const flatDistance = a => this.minWidth() * a;
|
|
|
|
const x = square.getX();
|
|
const y = square.getY();
|
|
|
|
let pixelX = this.pointyTop ? pointyDistanceX(x, y) : flatDistance(x);
|
|
let pixelY = this.pointyTop ? pointyDistanceY(x, y) : flatDistance(y);
|
|
|
|
pixelX += this.originX;
|
|
pixelY = this.originY - pixelY;;
|
|
|
|
return new Point(pixelX, pixelY);
|
|
}
|
|
|
|
pixelToTile(point) {
|
|
let scale = this.scale;
|
|
|
|
// (above/below axis) * (distance from axis) / (size)
|
|
const pointyDistanceX = (x, y) => (-x < y ? 1 : -1) * (Math.abs(x + y) / sqrt2) / this.minWidth();
|
|
const pointyDistanceY = (x, y) => (x < y ? 1 : -1) * (Math.abs(y - x) / sqrt2) / this.minWidth();
|
|
|
|
const flatDistance = a => a / this.minWidth();
|
|
|
|
let pixelX = point.getX() - this.originX;
|
|
let pixelY = this.originY - point.getY();
|
|
|
|
let x = this.pointyTop ? pointyDistanceX(pixelX, pixelY) : flatDistance(pixelX);
|
|
let y = this.pointyTop ? pointyDistanceY(pixelX, pixelY) : flatDistance(pixelY);
|
|
|
|
return new Square(x, y);
|
|
}
|
|
|
|
boundingBox(upperLeftPoint, upperRightPoint, lowerLeftPoint, lowerRightPoint) {
|
|
const upperLeftTile = this.pixelToTile(upperLeftPoint);
|
|
const lowerRightTile = this.pixelToTile(lowerRightPoint);
|
|
const upperRightTile = this.pixelToTile(upperRightPoint);
|
|
|
|
if (this.pointyTop) {
|
|
const lowerLeftTile = this.pixelToTile(lowerLeftPoint);
|
|
|
|
const columns = rangeInclusive(lowerLeftTile.getX(), upperRightTile.getX());
|
|
|
|
const upperLeftIntercept = upperLeftTile.getY() - upperLeftTile.getX();
|
|
const upperRightIntercept = upperLeftTile.getY() + upperLeftTile.getX();
|
|
|
|
const lowerLeftIntercept = lowerRightTile.getY() - lowerRightTile.getX();
|
|
const lowerRightIntercept = lowerRightTile.getY() + lowerRightTile.getX();
|
|
|
|
const aboutHalf = Math.floor(columns.length / 2);
|
|
const midway = columns.length % 2 ? columns[aboutHalf] :
|
|
(columns[aboutHalf - 1] + columns[aboutHalf]) / 2;
|
|
|
|
return columns.map(x => {
|
|
let top = x < midway ? upperLeftIntercept + x : upperRightIntercept - x;
|
|
let bottom = x < midway ? lowerRightIntercept - x : lowerLeftIntercept + x;
|
|
|
|
bottom = Math.min(bottom, top);
|
|
top = Math.max(bottom, top);
|
|
|
|
// push out by 1 on either end to account for interlocking tiles
|
|
const rows = rangeInclusive(bottom - 1, top + 1);
|
|
|
|
return rows.map(y => new Square(x, y));
|
|
});
|
|
}
|
|
else {
|
|
const columns = rangeInclusive(upperLeftTile.getX(), upperRightTile.getX());
|
|
const rows = rangeInclusive(lowerRightTile.getY(), upperLeftTile.getY());
|
|
|
|
return columns.map(x => rows.map(y => new Square(x, y)));
|
|
}
|
|
}
|
|
}
|