console
let canvas = document.getElementById("c");
let ctx = canvas.getContext("2d");
ctx.canvas.width = 804;
ctx.canvas.height = 804;
ctx.fillStyle = "#FFCC00";
const STEPS_PER_MM = 1;
const threshold = 135 * Math.PI / 180;
const smoothThreshold = 170 * Math.PI / 180;
const min_speed = 5;
const target_speed = 160;
const _acceleration = 300;
let _tx = 0;
let _ty = 0;
let _cx = 51 * STEPS_PER_MM;
let _cy = 51 * STEPS_PER_MM;
let _steps = 0;
let _xMoving = true;
let _interval = 1000;
let _targetX = 0;
let _targetY = 0;
let _total_steps = 0;
let _accel_steps = 0;
let _uniform_steps = 0;
let _deaccel_steps = 0;
let _speed = 5;
let _start_speed = 0;
let _end_speed = 0;
let _max_speed = 0;
let _longsiderate = 1.0;
let _dm = 0, _dx = 0, _dy = 0, _sx = 0, _sy = 0;
let _time = 0;
let points = [];
let n = 32;
for (let i = 0; i <= n; i++) {
addPoint(
10 + Math.floor(Math.random() * 100.0),
10 + Math.floor(Math.random() * 100.0)
)
}
function addPoint(x, y) {
let prevPt = points.length > 0 ? points[points.length - 1] : { x: 51, y: 51, k: 0 };
let dx = x - prevPt.x;
let dy = y - prevPt.y;
let angle = 0;
let k = Math.atan2(dy, dx);
prevPt.angle = Math.PI - prevPt.k + k;
prevPt.angle = prevPt.angle > Math.PI * 2.0 ? prevPt.angle - Math.PI * 2.0 : prevPt.angle;
prevPt.angle = prevPt.angle > Math.PI ? prevPt.angle - Math.PI * 2.0 : prevPt.angle;
prevPt.angle = prevPt.angle < 0 ? -prevPt.angle : prevPt.angle;
let distance = Math.sqrt(dx * dx + dy * dy);
points.push({ x, y, k, distance, angle });
}
function drawPixel(x, y) {
x = Math.floor(x);
y = Math.floor(y);
let side = 2;
let scale = side * 2;
let halfside = side / 2;
ctx.fillRect(x * scale - halfside, y * scale - halfside, side, side);
}
let _lastX = -1, _lastY = -1;
function drawPixel2(x, y) {
if (_lastX == -1 || _lastY == -1) {
_lastX = x, _lastY = y;
return;
}
ctx.strokeStyle = "#ffcc00";
ctx.moveTo(_lastX, _lastY);
ctx.lineTo(x, y);
ctx.stroke();
_lastX = x, _lastY = y;
}
function readNext() {
if (points.length > 0) {
let pt = points.shift();
moveTo(pt);
}
setTimeout(() => {
step();
}, _interval / 1000);
}
let _startX, _startY;
function moveTo(pt) {
_tx = pt.x * STEPS_PER_MM;
_ty = pt.y * STEPS_PER_MM;
_startX = _cx;
_startY = _cy;
_targetX = _tx;
_targetY = _ty;
_dx = _tx - _cx, _sx = _cx < _tx ? 1 : -1;
_dy = _ty - _cy, _sy = _cy < _ty ? 1 : -1;
_dx = _dx < 0 ? -_dx : _dx;
_dy = _dy < 0 ? -_dy : _dy;
_xMoving = _dx > _dy;
_dm = (_xMoving ? _dx : _dy);
_steps = _dm; /* maximum difference */
_tx = _ty = _dm >> 1; /* error offset */
let next_distance = 0;
let limit_speed = target_speed;
let restCount = points.length;
if (pt.angle > smoothThreshold) {
}
else if (pt.angle > threshold) {
limit_speed = Math.sin(pt.angle - threshold) * target_speed;
}
else {
limit_speed = min_speed;
}
let start_speed = _speed;
start_speed = start_speed < min_speed ? min_speed : start_speed;
let distance = 0;//Math.floor(pt.distance + start_speed * start_speed / _acceleration / 2);
let n = 0;
if (pt.angle > threshold) {
for (let i = 0; i < restCount; i++) {
let npt = points[i];
if (npt.angle < threshold) {
n = i;
break;
}
}
let angle = points[n - 1] ? points[n - 1].angle : pt.angle;
for (let i = n; i >= 0; i--) {
let npt = points[i];
if (angle > smoothThreshold) {
next_distance += npt.distance;
}
else if (angle > threshold) {
next_distance += Math.sin(angle - threshold) * npt.distance;
}
angle = npt.angle;
}
}
let prev_distance = (start_speed * start_speed - min_speed * min_speed) / (_acceleration * 2) + pt.distance;
let end_speed = 0;
let max_speed = 0;
if (prev_distance < next_distance) {
end_speed = Math.sqrt(pt.distance * _acceleration * 2.0 + start_speed * start_speed);
// end_speed = end_speed > limit_speed ? limit_speed : end_speed;
max_speed = end_speed;
}
else {
end_speed = Math.sqrt(next_distance * _acceleration * 2.0 + min_speed * min_speed);
end_speed = end_speed > limit_speed ? limit_speed : end_speed;
max_speed = Math.sqrt(pt.distance * _acceleration + (end_speed * end_speed + start_speed * start_speed) / 2);
}
distance = pt.distance * 1.0;
max_speed = Math.max(max_speed, Math.max(start_speed, end_speed));
max_speed = Math.min(max_speed, target_speed);
let accel_distance = (max_speed * max_speed - start_speed * start_speed) / (2 * _acceleration);
let deaccel_distance = (max_speed * max_speed - end_speed * end_speed) / (2 * _acceleration);
console.log("angle:" + Math.floor(pt.angle * 180 / Math.PI))
_accel_steps = Math.floor(accel_distance * _steps / pt.distance);
_accel_steps = _accel_steps < 0 ? 0 : _accel_steps;
_deaccel_steps = Math.floor(deaccel_distance * _steps / pt.distance);
_deaccel_steps = _deaccel_steps < 0 ? 0 : _deaccel_steps;
_uniform_steps = _steps - _accel_steps - _deaccel_steps;
_uniform_steps = _uniform_steps < 0 ? 0 : _uniform_steps;
_start_speed = start_speed;
_max_speed = max_speed;
_end_speed = end_speed;
_accel_steps = _deaccel_steps + _uniform_steps;
_longsiderate = distance / _steps;
_total_steps = _steps;
}
function calcInterval() {
if (_steps > _accel_steps) {
//accelerate
_speed = Math.sqrt(_longsiderate * (_total_steps - _steps) * _acceleration * 2 + _start_speed * _start_speed);
}
else if (_steps >= _deaccel_steps) {
//uniform
}
else {
//decelerate
_speed = Math.sqrt(_longsiderate * _steps * _acceleration * 2 + _end_speed * _end_speed);
}
_time += _interval / 50;
drawPixel2(_time, 650 - _speed / 2);
_interval = (2000.0 / _speed);
}
function step() {
if (_steps > 0) {
calcInterval();
_tx -= _dx;
if (_tx < 0) {
_tx += _dm;
_cx += _sx;
drawPixel(_cx / STEPS_PER_MM, _cy / STEPS_PER_MM);
if (_xMoving) {
_steps--;
}
}
_ty -= _dy;
if (_ty < 0) {
_ty += _dm;
_cy += _sy;
drawPixel(_cx / STEPS_PER_MM, _cy / STEPS_PER_MM);
if (!_xMoving) {
_steps--;
}
}
setTimeout(() => {
step();
}, _interval);
}
else {
readNext();
}
}
_time = 0;
readNext();
<canvas id="c" width=804 height=804></canvas>