diff --git a/src/cartographerFlatXY.js b/src/cartographerFlatXY.js index 359baf0..9ee15f8 100644 --- a/src/cartographerFlatXY.js +++ b/src/cartographerFlatXY.js @@ -30,8 +30,8 @@ export default class CartographerFlatXY extends Cartographer { 'tileToPixel', '_pixelToTile', - 'teleport', + 'inBounds', 'enforceBoundries', 'boundingBox', diff --git a/src/cartographerFlatXYZ.js b/src/cartographerFlatXYZ.js index 4623b38..c1b8e42 100644 --- a/src/cartographerFlatXYZ.js +++ b/src/cartographerFlatXYZ.js @@ -1,10 +1,13 @@ 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 CartographerFlatXYZ extends Cartographer { constructor(settings) { super(settings); @@ -26,9 +29,11 @@ export default class CartographerFlatXYZ extends Cartographer { 'calculateVerticalScale', 'tileToPixel', - 'pixelToTile', + '_pixelToTile', + 'teleport', 'inBounds', + 'enforceBoundries', 'boundingBox', ].map(method => this[method] = this[method].bind(this)); } @@ -82,7 +87,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; @@ -94,45 +99,94 @@ export default class CartographerFlatXYZ 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.getOffsetHex(); + + if (this.radius) { + } + else { + 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.offsetToCube(col, row); + } + } + + inBounds ({x, y, z = -x - y}) { 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(x), Math.abs(y), Math.abs(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(x - this.radius), Math.abs(y + this.radius), Math.abs(z)) <= this.radius; } } else if (this.width || this.height) { if (this.negativeTiles) { - return (!this.width || (Math.abs(q) < this.width / 2)) - && (!this.height || (Math.abs(-r - Math.floor(q / 2)) < (this.height / 2))); + return (!this.width || (Math.abs(x) < this.width / 2)) + && (!this.height || (Math.abs(-y - Math.floor(x / 2)) < (this.height / 2))); } else { - return (!this.width || (q >= 0 && q < this.width)) - && (!this.height || (r <= (Math.floor(q / 2) * -1) && (-r - Math.floor(q / 2)) < this.height)); + return (!this.width || (x >= 0 && x < this.width)) + && (!this.height || (y <= (Math.floor(x / 2) * -1) && (-y - Math.floor(x / 2)) < this.height)); } } } + 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 upperLeftTile = this._pixelToTile(upperLeftPoint); + const lowerLeftTile = this._pixelToTile(lowerLeftPoint); + const lowerRightTile = this._pixelToTile(lowerRightPoint); + const upperRightTile = this._pixelToTile(upperRightPoint); const columns = rangeInclusive(upperLeftTile.getQ() - 1, upperRightTile.getQ() + 1); const height = lowerRightTile.getR() - upperRightTile.getR(); - return columns.map((q, index) => { + + const makeAPointPair = tilePoint => ({tilePoint, pixelPoint: this.tileToPixel(tilePoint)}); + + const processRow = (q, index) => { const top = upperLeftTile.getR() - Math.floor(index / 2); const bottom = top + height; const rows = rangeInclusive(top, bottom + 1); - return rows.map(r => ({q, r})) - .reduce((flat, list) => flat.concat(list), []) - .filter(({q, r}) => this.inBounds(q, r)) - .map(({q, r}) => new Hex(q, r)); - }); + const makeAPoint = r => ({x: q, y: r, z: -q - r}); + + return funky.chain(rows) + .map(makeAPoint) + .map(makeAPointPair) + .map(this.enforceBoundries) + .compact() + .map(tilePointToHex) + .value(); + }; + + return funky.chain(columns) + .map(processRow) + .flatten() + .value(); } } diff --git a/src/cartographerPointyXY.js b/src/cartographerPointyXY.js index 08216a8..d32f813 100644 --- a/src/cartographerPointyXY.js +++ b/src/cartographerPointyXY.js @@ -30,8 +30,8 @@ export default class CartographerPointyXY extends Cartographer { 'tileToPixel', '_pixelToTile', - 'teleport', + 'inBounds', 'enforceBoundries', 'boundingBox', @@ -151,8 +151,7 @@ export default class CartographerPointyXY extends Cartographer { const makeAPointPair = tilePoint => ({tilePoint, pixelPoint: this.tileToPixel(tilePoint)}); - return funky.chain(columns) - .map(x => { + const processRow = x => { let top = x < midway ? upperLeftIntercept + x : upperRightIntercept - x; let bottom = x < midway ? lowerRightIntercept - x : lowerLeftIntercept + x; @@ -160,18 +159,21 @@ export default class CartographerPointyXY extends Cartographer { top = Math.max(bottom, top); // push out by 1 on either end to account for interlocking tiles - const rows = rangeInclusive(bottom - 1, top + 1); + const row = rangeInclusive(bottom - 1, top + 1); const makeAPoint = y => ({x, y}); - return funky.chain(rows) + return funky.chain(row) .map(makeAPoint) .map(makeAPointPair) .map(this.enforceBoundries) .compact() .map(tilePointToSquare) .value(); - }) + }; + + return funky.chain(columns) + .map(processRow) .flatten() .value(); } diff --git a/src/funky.js b/src/funky.js index 5f6a683..ddfb9ad 100644 --- a/src/funky.js +++ b/src/funky.js @@ -1,5 +1,10 @@ export function chain (obj) { let chainInstance = { + log: function () { + console.log(obj); + return chainInstance; + }, + value: function () { return obj; } diff --git a/src/hex.js b/src/hex.js index 7f130ca..c46c4b9 100644 --- a/src/hex.js +++ b/src/hex.js @@ -35,11 +35,26 @@ function roundOff(hex) { } export default class Hex extends Point { + static offsetToCube (col, row) { + const x = col; + const z = row - (col + (col & 1)) / 2; + const y = -x - z; + + return new Hex(x, y, z); + } constructor() { super(); - if (arguments.length === 2) { // hex = Hex(q, r); + if (arguments.length === 1) { + const {q, r, s = -q - r} = arguments[0]; + const {x, y, z = -x - y} = arguments[0]; + + this.x = !isNaN(q) ? q : x; + this.y = !isNaN(s) ? s : y; + this.z = !isNaN(r) ? r : z; + } + else if (arguments.length === 2) { // hex = Hex(q, r); this.x = arguments[0]; this.z = arguments[1]; this.y = computeY(this.x, this.z); @@ -57,65 +72,76 @@ export default class Hex extends Point { getY() {return this.y;} getZ() {return this.z;} - setX(newX) {this.x = newX; return this;} - setY(newY) {this.y = newY; return this;} - setZ(newZ) {this.z = newZ; return this;} + setX (newX) {this.x = newX; return this;} + setY (newY) {this.y = newY; return this;} + setZ (newZ) {this.z = newZ; return this;} - moveX(byX) {this.x += byX; return this;} - moveY(byY) {this.y += byY; return this;} - moveZ(byZ) {this.z += byZ; return this;} + moveX (byX) {this.x += byX; return this;} + moveY (byY) {this.y += byY; return this;} + moveZ (byZ) {this.z += byZ; return this;} - getQ() {return this.x;} - getR() {return this.z;} + getQ () {return this.x;} + getR () {return this.z;} - setQ(newQ) { + setQ (newQ) { this.x = newQ; this.y = computeY(this.x, this.z); return this; } - setR(newR) { + + setR (newR) { this.z = newR; this.y = computeY(this.x, this.z); return this; } - moveQ(byQ) { + moveQ (byQ) { this.x += byQ; this.y = computeY(this.x, this.z); return this; } - moveR(byR) { + + moveR (byR) { this.z += byR; this.y = computeY(this.x, this.z); return this; } - getPoint() { return {x: this.x, y: this.y, z: this.z}; } + getPoint () { return {x: this.x, y: this.y, z: this.z}; } - setHex(newHex) { + setHex (newHex) { this.x = newHex.x; this.y = newHex.y; this.z = newHex.z; return this; } - moveHex(byHex) { + moveHex (byHex) { this.x += byHex.x; this.y += byHex.y; this.z += byHex.z; return this; } - getAxial() {return {q: this.x, r: this.z};} - setAxial(newAxial) { + getAxial () {return {q: this.x, r: this.z};} + + setAxial (newAxial) { this.x = newAxial.q; this.z = newAxial.r; this.y = computeY(this.x, this.y); return this; } - moveAxial(byAxial) { + + moveAxial (byAxial) { this.x += byAxial.q; this.z += byAxial.r; 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}; + } }