wrapping for pointy hexagons
This commit is contained in:
@@ -161,7 +161,7 @@ const positiveFarEast3x3 = [{
|
||||
}];
|
||||
|
||||
export default class CartographerFlatXYZ extends Cartographer {
|
||||
constructor(settings) {
|
||||
constructor (settings) {
|
||||
super(settings);
|
||||
|
||||
[
|
||||
@@ -190,47 +190,47 @@ export default class CartographerFlatXYZ extends Cartographer {
|
||||
].map(method => this[method] = this[method].bind(this));
|
||||
}
|
||||
|
||||
tileHeight() {
|
||||
tileHeight () {
|
||||
return this.minWidth();
|
||||
}
|
||||
|
||||
tileWidth() {
|
||||
tileWidth () {
|
||||
return this.maxWidth();
|
||||
}
|
||||
|
||||
maxWidth() {
|
||||
maxWidth () {
|
||||
return this.scale * 2;
|
||||
}
|
||||
|
||||
minWidth() {
|
||||
minWidth () {
|
||||
return this.scale * sqrt3;
|
||||
}
|
||||
|
||||
horizontalOverhang() {
|
||||
horizontalOverhang () {
|
||||
return this.maxWidth() * 0.25;
|
||||
}
|
||||
|
||||
verticalOverhang() {
|
||||
verticalOverhang () {
|
||||
return 0;
|
||||
}
|
||||
|
||||
horizontalDistance() {
|
||||
horizontalDistance () {
|
||||
return this.maxWidth() * (3/4);
|
||||
}
|
||||
|
||||
verticalDistance() {
|
||||
verticalDistance () {
|
||||
return this.minWidth();
|
||||
}
|
||||
|
||||
calculateHorizontalScale(pixels, tiles) {
|
||||
calculateHorizontalScale (pixels, tiles) {
|
||||
return pixels / (tiles * 0.75 + 0.25) / 2;
|
||||
}
|
||||
|
||||
calculateVerticalScale(pixels, tiles) {
|
||||
calculateVerticalScale (pixels, tiles) {
|
||||
return pixels / tiles / sqrt3;
|
||||
}
|
||||
|
||||
tileToPixel(hex) {
|
||||
tileToPixel (hex) {
|
||||
hex = hex instanceof Hex ? hex : new Hex(...arguments);
|
||||
|
||||
const pixelX = this.scale * 3/2 * hex.getQ();
|
||||
@@ -239,7 +239,7 @@ export default class CartographerFlatXYZ extends Cartographer {
|
||||
return new Point(pixelX + this.originX, pixelY + this.originY);
|
||||
}
|
||||
|
||||
_pixelToTile(point) {
|
||||
_pixelToTile (point) {
|
||||
point = point instanceof Point ? point : new Point(...arguments);
|
||||
|
||||
const pixelX = point.getX() - this.originX;
|
||||
@@ -253,7 +253,7 @@ export default class CartographerFlatXYZ extends Cartographer {
|
||||
|
||||
teleport (hex) {
|
||||
hex = hex instanceof Hex ? hex : new Hex(hex);
|
||||
let {col, row} = hex.getOffsetHex();
|
||||
let {col, row} = Hex.cubeToEvenQ(hex);
|
||||
|
||||
if (this.radius) {
|
||||
}
|
||||
@@ -289,11 +289,11 @@ export default class CartographerFlatXYZ extends Cartographer {
|
||||
row -= halfHeight;
|
||||
}
|
||||
|
||||
return Hex.offsetToCube(col, row);
|
||||
return Hex.evenQToCube(col, row);
|
||||
}
|
||||
}
|
||||
|
||||
inBounds ({x, y, z = -x - y}) {
|
||||
inBounds ({x, z, y = -x - z}) {
|
||||
if (this.radius) {
|
||||
if (this.negativeTiles) {
|
||||
return Math.max(Math.abs(x), Math.abs(y), Math.abs(z)) <= Math.floor(this.radius);
|
||||
@@ -320,7 +320,7 @@ export default class CartographerFlatXYZ extends Cartographer {
|
||||
null;
|
||||
}
|
||||
|
||||
boundingBox(upperLeftPoint, upperRightPoint, lowerLeftPoint, lowerRightPoint) {
|
||||
boundingBox (upperLeftPoint, upperRightPoint, lowerLeftPoint, lowerRightPoint) {
|
||||
const upperLeftTile = this._pixelToTile(upperLeftPoint);
|
||||
const lowerLeftTile = this._pixelToTile(lowerLeftPoint);
|
||||
const lowerRightTile = this._pixelToTile(lowerRightPoint);
|
||||
@@ -337,7 +337,7 @@ export default class CartographerFlatXYZ extends Cartographer {
|
||||
const bottom = top + height;
|
||||
const rows = rangeInclusive(top, bottom + 1);
|
||||
|
||||
const makeAPoint = r => ({x: q, z: r, y: -q - r});
|
||||
const makeAPoint = r => Hex.qrToCube(q, r);
|
||||
|
||||
return funky.chain(rows)
|
||||
.map(makeAPoint)
|
||||
@@ -348,21 +348,6 @@ export default class CartographerFlatXYZ extends Cartographer {
|
||||
.value();
|
||||
};
|
||||
|
||||
// if (debugged < 1) {
|
||||
//
|
||||
// [positive3x3, positiveEast3x3, positiveMiddleEast3x3, positiveFarEast3x3].forEach(set => {
|
||||
// set.forEach((input, index) => {
|
||||
// const result = this.teleport(input, true);
|
||||
//
|
||||
// if (result.x === positive3x3[index].x && result.y === positive3x3[index].y && result.z === positive3x3[index].z) console.log(input, '->', positive3x3[index]);
|
||||
// else console.log(input, '><', positive3x3[index], result);
|
||||
// console.log('---------------------------------------------------');
|
||||
// });
|
||||
//
|
||||
// console.log('-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-');
|
||||
// });
|
||||
// }
|
||||
|
||||
return funky.chain(columns)
|
||||
.map(processRow)
|
||||
.flatten()
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import Cartographer from './cartographer.js';
|
||||
|
||||
import * as funky from './funky';
|
||||
import {rangeInclusive, sqrt3} from './utils.js';
|
||||
|
||||
import Hex from './hex.js';
|
||||
import Point from './point.js';
|
||||
|
||||
const tilePointToHex = ({tilePoint, pixelPoint}) => ({tilePoint: new Hex(tilePoint), pixelPoint});
|
||||
|
||||
export default class CartographerPointyXYZ extends Cartographer {
|
||||
constructor(settings) {
|
||||
constructor (settings) {
|
||||
super(settings);
|
||||
|
||||
[
|
||||
@@ -26,54 +29,56 @@ export default class CartographerPointyXYZ extends Cartographer {
|
||||
'calculateVerticalScale',
|
||||
|
||||
'tileToPixel',
|
||||
'pixelToTile',
|
||||
'_pixelToTile',
|
||||
'teleport',
|
||||
|
||||
'inBounds',
|
||||
'enforceBoundries',
|
||||
'boundingBox',
|
||||
].map(method => this[method] = this[method].bind(this));
|
||||
}
|
||||
|
||||
tileHeight() {
|
||||
tileHeight () {
|
||||
return this.maxWidth();
|
||||
}
|
||||
|
||||
tileWidth() {
|
||||
tileWidth () {
|
||||
return this.minWidth();
|
||||
}
|
||||
|
||||
maxWidth() {
|
||||
maxWidth () {
|
||||
return this.scale * 2;
|
||||
}
|
||||
|
||||
minWidth() {
|
||||
minWidth () {
|
||||
return this.scale * sqrt3;
|
||||
}
|
||||
|
||||
horizontalOverhang() {
|
||||
horizontalOverhang () {
|
||||
return 0;
|
||||
}
|
||||
|
||||
verticalOverhang() {
|
||||
verticalOverhang () {
|
||||
return this.maxWidth() * 0.25;
|
||||
}
|
||||
|
||||
horizontalDistance() {
|
||||
horizontalDistance () {
|
||||
return this.minWidth();
|
||||
}
|
||||
|
||||
verticalDistance() {
|
||||
verticalDistance () {
|
||||
return this.maxWidth() * (3/4);
|
||||
}
|
||||
|
||||
calculateHorizontalScale(pixels, tiles) {
|
||||
calculateHorizontalScale (pixels, tiles) {
|
||||
return pixels / tiles / sqrt3;
|
||||
}
|
||||
|
||||
calculateVerticalScale(pixels, tiles) {
|
||||
calculateVerticalScale (pixels, tiles) {
|
||||
return pixels / (tiles * 0.75 + 0.25) / 2;
|
||||
}
|
||||
|
||||
tileToPixel(hex) {
|
||||
tileToPixel (hex) {
|
||||
hex = hex instanceof Hex ? hex : new Hex(...arguments);
|
||||
|
||||
const pixelX = this.scale * sqrt3 * (hex.getQ() + (hex.getR() / 2));
|
||||
@@ -82,7 +87,7 @@ export default class CartographerPointyXYZ extends Cartographer {
|
||||
return new Point(pixelX + this.originX, pixelY + this.originY);
|
||||
}
|
||||
|
||||
pixelToTile(point) {
|
||||
_pixelToTile (point) {
|
||||
point = point instanceof Point ? point : new Point(...arguments);
|
||||
|
||||
const pixelX = point.getX() - this.originX;
|
||||
@@ -94,45 +99,108 @@ export default class CartographerPointyXYZ extends Cartographer {
|
||||
return new Hex(q, r);
|
||||
}
|
||||
|
||||
inBounds (q, r, s = -q - r) {
|
||||
teleport (hex) {
|
||||
hex = hex instanceof Hex ? hex : new Hex(hex);
|
||||
let {col, row} = Hex.cubeToEvenR(hex);
|
||||
|
||||
if (this.radius) {
|
||||
}
|
||||
else {
|
||||
// ensure odd-width maps wrap properly
|
||||
if (this.height % 2) {
|
||||
const offset = Math.floor(row / this.height);
|
||||
|
||||
let horizontalAdjust = offset / 2;
|
||||
horizontalAdjust = offset % 2 === 0 ? horizontalAdjust :
|
||||
row % 2 ? Math.ceil(horizontalAdjust) :
|
||||
Math.floor(horizontalAdjust);
|
||||
|
||||
col -= horizontalAdjust;
|
||||
}
|
||||
|
||||
const halfWidth = Math.floor(this.width / 2);
|
||||
const halfHeight = Math.floor(this.height / 2);
|
||||
|
||||
if (this.negativeTiles) {
|
||||
col += halfWidth;
|
||||
row += halfHeight;
|
||||
}
|
||||
|
||||
col = col % this.width;
|
||||
row = row % this.height;
|
||||
|
||||
col = col < 0 ? col + this.width : col;
|
||||
row = row < 0 ? row + this.height : row;
|
||||
|
||||
if (this.negativeTiles) {
|
||||
col -= halfWidth;
|
||||
row -= halfHeight;
|
||||
}
|
||||
|
||||
return Hex.evenRToCube(col, row);
|
||||
}
|
||||
}
|
||||
|
||||
inBounds (hex) {
|
||||
hex = hex instanceof Hex ? hex : new Hex(hex);
|
||||
|
||||
if (this.radius) {
|
||||
if (this.negativeTiles) {
|
||||
return Math.max(Math.abs(q), Math.abs(r), Math.abs(s)) <= Math.floor(this.radius);
|
||||
return Math.max(Math.abs(hex.x), Math.abs(hex.y), Math.abs(hex.z)) <= Math.floor(this.radius);
|
||||
}
|
||||
else {
|
||||
return Math.max(Math.abs(q - this.radius), Math.abs(r + this.radius), Math.abs(s)) <= this.radius;
|
||||
return Math.max(Math.abs(hex.x - this.radius), Math.abs(hex.y + this.radius), Math.abs(hex.z)) <= this.radius;
|
||||
}
|
||||
}
|
||||
else if (this.width || this.height) {
|
||||
if (this.negativeTiles) {
|
||||
return (!this.height || (Math.abs(r) < this.height / 2))
|
||||
&& (!this.width || (Math.abs(-q - Math.floor(r / 2)) < (this.width / 2)));
|
||||
return (!this.width || (Math.abs(hex.x) < this.width / 2))
|
||||
&& (!this.height || (Math.abs(-hex.y - Math.floor(hex.x / 2)) < (this.height / 2)));
|
||||
}
|
||||
else {
|
||||
return (!this.height || (r >= 0 && r < this.height))
|
||||
&& (!this.width || (q <= (Math.floor(r / 2)) && (q - Math.floor(r / 2)) < this.width));
|
||||
return (!this.width || (hex.x >= 0 && hex.x < this.width))
|
||||
&& (!this.height || (hex.y <= (Math.floor(hex.x / 2) * -1) && (-hex.y - Math.floor(hex.x / 2)) < this.height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boundingBox(upperLeftPoint, upperRightPoint, lowerLeftPoint, lowerRightPoint) {
|
||||
const upperLeftTile = this.pixelToTile(upperLeftPoint);
|
||||
const lowerLeftTile = this.pixelToTile(lowerLeftPoint);
|
||||
const lowerRightTile = this.pixelToTile(lowerRightPoint);
|
||||
const upperRightTile = this.pixelToTile(upperRightPoint);
|
||||
enforceBoundries ({tilePoint, pixelPoint}) {
|
||||
return this.wrap ? ({tilePoint: this.teleport(tilePoint), pixelPoint}) :
|
||||
this.inBounds(tilePoint) ? ({tilePoint, pixelPoint}) :
|
||||
null;
|
||||
}
|
||||
|
||||
boundingBox (upperLeftPoint, upperRightPoint, lowerLeftPoint, lowerRightPoint) {
|
||||
const upperLeftTile = this._pixelToTile(upperLeftPoint);
|
||||
const lowerLeftTile = this._pixelToTile(lowerLeftPoint);
|
||||
const lowerRightTile = this._pixelToTile(lowerRightPoint);
|
||||
const upperRightTile = this._pixelToTile(upperRightPoint);
|
||||
|
||||
const rows = rangeInclusive(upperLeftTile.getR() -1 , lowerLeftTile.getR() + 1);
|
||||
|
||||
const width = upperRightTile.getQ() - upperLeftTile.getQ();
|
||||
return rows.map((r, index) => {
|
||||
|
||||
const makeAPointPair = tilePoint => ({tilePoint, pixelPoint: this.tileToPixel(tilePoint)});
|
||||
|
||||
const processColumn = (r, index) => {
|
||||
const left = upperLeftTile.getQ() - Math.floor(index / 2);
|
||||
const right = left + width;
|
||||
const columns = rangeInclusive(left, right + 1);
|
||||
|
||||
return columns.map(q => ({q, r}))
|
||||
.reduce((flat, list) => flat.concat(list), [])
|
||||
.filter(({q, r}) => this.inBounds(q, r))
|
||||
.map(({q, r}) => new Hex(q, r));
|
||||
});
|
||||
const makeAPoint = q => Hex.qrToCube(q, r); //({x: q, z: r, y: -q - r});
|
||||
|
||||
return funky.chain(columns)
|
||||
.map(makeAPoint)
|
||||
.map(makeAPointPair)
|
||||
.map(this.enforceBoundries)
|
||||
.compact()
|
||||
.map(tilePointToHex)
|
||||
.value();
|
||||
};
|
||||
|
||||
return funky.chain(rows)
|
||||
.map(processColumn)
|
||||
.flatten()
|
||||
.value();
|
||||
}
|
||||
}
|
||||
|
||||
39
src/hex.js
39
src/hex.js
@@ -35,7 +35,37 @@ function roundOff(hex) {
|
||||
}
|
||||
|
||||
export default class Hex extends Point {
|
||||
static offsetToCube (col, row) {
|
||||
static qrToCube (q, r) {
|
||||
return {
|
||||
x: q,
|
||||
y: computeY(q, r),
|
||||
z: r,
|
||||
};
|
||||
}
|
||||
|
||||
static cubeToEvenR ({x, y, z}) {
|
||||
const col = x + (z + (z & 1)) / 2;;
|
||||
const row = z;
|
||||
|
||||
return {col, row};
|
||||
}
|
||||
|
||||
static evenRToCube (col, row) {
|
||||
const x = col - (row + (row & 1)) / 2;;
|
||||
const z = row;
|
||||
const y = -x - z;
|
||||
|
||||
return new Hex(x, y, z);
|
||||
}
|
||||
|
||||
static cubeToEvenQ ({x, y, z}) {
|
||||
const col = x;
|
||||
const row = z + (x + (x & 1)) / 2;
|
||||
|
||||
return {col, row};
|
||||
}
|
||||
|
||||
static evenQToCube (col, row) {
|
||||
const x = col;
|
||||
const z = row - (col + (col & 1)) / 2;
|
||||
const y = -x - z;
|
||||
@@ -137,11 +167,4 @@ export default class Hex extends Point {
|
||||
this.y = computeY(this.x, this.z);
|
||||
return this;
|
||||
}
|
||||
|
||||
getOffsetHex () {
|
||||
const col = this.x;
|
||||
const row = this.z + (this.x + (this.x & 1)) / 2;
|
||||
|
||||
return {col, row};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user