lr-core
Version:
Line Rider core library
175 lines (149 loc) • 4.42 kB
JavaScript
import {hashIntPair} from '../../utils/hashNumberPair.js'
import dda from '../../utils/dda.js'
export function ddaCells ({p1, p2}, gridSize) {
return dda(p1.x / gridSize, p1.y / gridSize, p2.x / gridSize, p2.y / gridSize)
.map(({x, y}) => hashIntPair(x, y))
}
// 6.2
export function classicCells (line, gridSize) {
let cellsPos = ClassicCells.getCellsPos(line, gridSize)
return cellsPos.map(({x, y}) => hashIntPair(x, y))
}
// 6.1
export function legacyCells (line, gridSize) {
return LegacyCells.getCellsPos(line, gridSize).map(({x, y}) => hashIntPair(x, y))
}
class ClassicCells {
static getCellsPos (line, gridSize) {
var cellsPos = []
let cellPosStart = getCellPosAndOffset(line.p1.x, line.p1.y, gridSize)
let cellPosEnd = getCellPosAndOffset(line.p2.x, line.p2.y, gridSize)
cellsPos.push(cellPosStart)
if (line.c.vec.x === 0 && line.c.vec.y === 0 || cellPosStart.x === cellPosEnd.x && cellPosStart.y === cellPosEnd.y) {
return cellsPos // done
}
let box = getBox(cellPosStart.x, cellPosStart.y, cellPosEnd.x, cellPosEnd.y)
let getNextPos
if (line.c.vec.x === 0) {
getNextPos = (l, x, y, dx, dy) => { return { x: x, y: y + dy } }
} else if (line.c.vec.y === 0) {
getNextPos = (l, x, y, dx, dy) => { return { x: x + dx, y: y } }
} else {
getNextPos = this.getNextPos
}
let cellPos = cellPosStart
let pos = { x: line.p1.x, y: line.p1.y }
while (cellPos != null) {
let d = this.getDelta(line, cellPos, gridSize)
let nextPos = getNextPos(line, pos.x, pos.y, d.x, d.y)
let nextCellPos = getCellPosAndOffset(nextPos.x, nextPos.y, gridSize)
if (inBounds(nextCellPos, box)) {
cellsPos.push(nextCellPos)
cellPos = nextCellPos
pos = nextPos
} else {
cellPos = null
}
}
return cellsPos
}
static getNextPos (line, x, y, dx, dy) {
let slope = line.c.vec.y / line.c.vec.x
let yNext = y + slope * dx
if (Math.abs(yNext - y) < Math.abs(dy)) {
return {
x: x + dx,
y: yNext
}
}
if (Math.abs(yNext - y) === Math.abs(dy)) {
return {
x: x + dx,
y: y + dy
}
}
return {
x: x + line.c.vec.x * dy / line.c.vec.y,
y: y + dy
}
}
static getDelta (line, cellPos, gridSize) {
let dx, dy
if (cellPos.x < 0) {
dx = (gridSize + cellPos.gx) * (line.c.vec.x > 0 ? 1 : -1)
} else {
dx = -cellPos.gx + (line.c.vec.x > 0 ? gridSize : -1)
}
if (cellPos.y < 0) {
dy = (gridSize + cellPos.gy) * (line.c.vec.y > 0 ? 1 : -1)
} else {
dy = -cellPos.gy + (line.c.vec.y > 0 ? gridSize : -1)
}
return { x: dx, y: dy }
}
}
class LegacyCells extends ClassicCells {
static getDelta (line, cellPos, gridSize) {
return {
x: -cellPos.gx + (line.c.vec.x > 0 ? gridSize : -1),
y: -cellPos.gy + (line.c.vec.y > 0 ? gridSize : -1)
}
}
static getNextPos (line, x, y, dx, dy) {
let slope = line.c.vec.y / line.c.vec.x
let yIsThisBelowActualY0 = line.p1.y - slope * line.p1.x
let yDoesThisEvenWork = Math.round(slope * (x + dx) + yIsThisBelowActualY0)
if (Math.abs(yDoesThisEvenWork - y) < Math.abs(dy)) {
return {
x: x + dx,
y: yDoesThisEvenWork
}
}
if (Math.abs(yDoesThisEvenWork - y) === Math.abs(dy)) {
return {
x: x + dx,
y: y + dy
}
}
return {
x: Math.round((y + dy - yIsThisBelowActualY0) / slope),
y: y + dy
}
}
}
function getCellPosAndOffset (px, py, gridSize) {
let {x, y} = getCellPos(px, py, gridSize)
return {
x: x,
y: y,
gx: px - gridSize * x,
gy: py - gridSize * y
}
}
function getCellPos (x, y, gridSize) {
return {
x: getCellCor(x, gridSize),
y: getCellCor(y, gridSize)
}
}
function getCellCor (x, gridSize) {
return Math.floor(x / gridSize)
}
function getBox (x1, y1, x2, y2) {
let left = Math.min(x1, x2)
let right = Math.max(x1, x2)
let top = Math.min(y1, y2)
let bottom = Math.max(y1, y2)
return {
left: left,
right: right,
top: top,
bottom: bottom,
corners: [
[left, top], [left, bottom], [right, top], [right, bottom]
].map(c => { return {x: c[0], y: c[1]} })
}
}
function inBounds (p, box) {
return p.x >= box.left && p.x <= box.right && p.y >= box.top && p.y <= box.bottom
}