Naloga 2: Changed coordinates from array to object

This commit is contained in:
Gašper Dobrovoljc 2024-11-24 20:20:39 +01:00
parent 8dee22b65f
commit 7ad330422b
No known key found for this signature in database
GPG Key ID: 0E7E037018CFA5A5

View File

@ -12,7 +12,7 @@ let mouseDown = false;
/** @type {number|null} */
let movePointIndex = null;
/** @type {number[][][]} */
/** @type {{x: number, y: number}[][]} */
const curves = [];
addButton.addEventListener('click', () => {
@ -31,15 +31,13 @@ removeButton.addEventListener('click', () => {
c0Button.addEventListener('click', () => {
if (curves.length <= 1 || selected === null) return;
let p = getClosestEndPoint(curves[selected][0][0], curves[selected][0][1]);
if (p === null) return;
let [curveIndex, pointIndex] = p;
curves[selected][0] = curves[curveIndex][pointIndex];
let [ci, pi] = getClosestEndPoint(curves[selected][0]);
if (ci === null || pi === null) return;
curves[selected][0] = curves[ci][pi];
p = getClosestEndPoint(curves[selected][3][0], curves[selected][3][1]);
if (p === null) return;
[curveIndex, pointIndex] = p;
curves[selected][3] = curves[curveIndex][pointIndex];
[ci, pi] = getClosestEndPoint(curves[selected][3]);
if (ci === null || pi === null) return;
curves[selected][3] = curves[ci][pi];
draw();
});
@ -47,30 +45,26 @@ c0Button.addEventListener('click', () => {
c1Button.addEventListener('click', () => {
if (curves.length <= 1 || selected === null) return;
let [curveIndex, pointIndex] = getClosestEndPoint(
curves[selected][0][0],
curves[selected][0][1],
);
let [ci, pi] = getClosestEndPoint(curves[selected][0]);
if (ci === null || pi === null) return;
// Move first point of selected curve to closest found point
curves[selected][0] = curves[curveIndex][pointIndex];
// Get control point of found point
const h1 = curves[curveIndex][pointIndex === 0 ? 1 : 2];
// Set control point to location mirrored over the first point
curves[selected][1] = [
2 * curves[selected][0][0] - h1[0],
2 * curves[selected][0][1] - h1[1],
];
curves[selected][0] = curves[ci][pi];
// Get control point of found end point
const handle1 = curves[ci][pi === 0 ? 1 : 2];
// Set control point to location mirrored over the point
curves[selected][1] = {
x: 2 * curves[selected][0].x - handle1.x,
y: 2 * curves[selected][0].y - handle1.y,
};
[curveIndex, pointIndex] = getClosestEndPoint(
curves[selected][3][0],
curves[selected][3][1],
);
curves[selected][3] = curves[curveIndex][pointIndex];
const h2 = curves[curveIndex][pointIndex === 0 ? 1 : 2];
curves[selected][2] = [
2 * curves[selected][3][0] - h2[0],
2 * curves[selected][3][1] - h2[1],
];
[ci, pi] = getClosestEndPoint(curves[selected][3]);
if (ci === null || pi === null) return;
curves[selected][3] = curves[ci][pi];
const handle2 = curves[ci][pi === 0 ? 1 : 2];
curves[selected][2] = {
x: 2 * curves[selected][3].x - handle2.x,
y: 2 * curves[selected][3].y - handle2.y,
};
draw();
});
@ -81,7 +75,7 @@ c1Button.addEventListener('click', () => {
*/
function addPoint(x, y) {
const curve = curves[curves.length - 1];
curve.push([x, y]);
curve.push({ x, y });
if (curve.length === 4) {
adding = false;
}
@ -99,42 +93,44 @@ function lerp(t, a, b) {
}
/**
* interpolates the points
* interpolates the values
* @param {number} t
* @param {number[]} p array of points
* @param {number[]} v array of values
*/
function lerpCurve(t, p) {
if (p.length === 1) return p[0];
return lerp(t, lerpCurve(t, p.slice(0, -1)), lerpCurve(t, p.slice(1)));
function lerpArray(t, v) {
if (v.length === 1) return v[0];
return lerp(t, lerpArray(t, v.slice(0, -1)), lerpArray(t, v.slice(1)));
}
function drawCircles() {
if (selected === null) return;
for (const [x, y] of curves[selected]) {
for (const { x, y } of curves[selected]) {
context.beginPath();
context.ellipse(x, y, 10, 10, 0, 0, Math.PI * 2);
context.stroke();
}
}
// Failed attempt at adaptive line length
/**
* @param {number} tStart
* @param {number} tEnd
* @param {number[][]} points
* @param {{x: number, y: number}[]} points
* @returns {{x: number, y: number}[]}
*/
function calcPoints(tStart, tEnd, points) {
const xPoints = points.map((p) => p[0]);
const yPoints = points.map((p) => p[1]);
const xPoints = points.map((p) => p.x);
const yPoints = points.map((p) => p.y);
const x1 = lerpCurve(tStart, xPoints);
const y1 = lerpCurve(tStart, yPoints);
const x2 = lerpCurve((tStart + tEnd) / 2, xPoints);
const y2 = lerpCurve((tStart + tEnd) / 2, yPoints);
const x3 = lerpCurve(tEnd, xPoints);
const y3 = lerpCurve(tEnd, yPoints);
const x1 = lerpArray(tStart, xPoints);
const y1 = lerpArray(tStart, yPoints);
const x2 = lerpArray((tStart + tEnd) / 2, xPoints);
const y2 = lerpArray((tStart + tEnd) / 2, yPoints);
const x3 = lerpArray(tEnd, xPoints);
const y3 = lerpArray(tEnd, yPoints);
const s =
const surface =
(1 / 2) * Math.abs(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2));
// const d12 = Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2);
@ -143,7 +139,7 @@ function calcPoints(tStart, tEnd, points) {
//
// const angle = Math.acos((d12 ** 2 + d13 ** 2 - d23 ** 2) / (2 * d12 * d13));
if (s < 20) {
if (surface < 20) {
return [{ x: x3, y: y3 }];
}
@ -157,22 +153,19 @@ function drawLines() {
for (let i = 0; i < curves.length; i++) {
const curve = curves[i];
for (let j = 0; j < curve.length - 3; j += 3) {
const p1 = curve[j];
const p2 = curve[j + 1];
const p3 = curve[j + 2];
const p4 = curve[j + 3];
const points = curve.slice(j, j + 4);
context.beginPath();
if (selected === i) {
context.moveTo(p1[0], p1[1]);
context.lineTo(p2[0], p2[1]);
context.moveTo(points[0].x, points[0].y);
context.lineTo(points[1].x, points[1].y);
context.moveTo(p3[0], p3[1]);
context.lineTo(p4[0], p4[1]);
context.moveTo(points[2].x, points[2].y);
context.lineTo(points[3].x, points[3].y);
}
context.moveTo(p1[0], p1[1]);
context.moveTo(points[0].x, points[0].y);
//
// const points = calcPoints(0, 1, curve);
//
@ -182,8 +175,14 @@ function drawLines() {
for (let t = 0; t <= 100; t++) {
const tt = t / 100;
const x = lerpCurve(tt, [p1[0], p2[0], p3[0], p4[0]]);
const y = lerpCurve(tt, [p1[1], p2[1], p3[1], p4[1]]);
const x = lerpArray(
tt,
points.map((p) => p.x),
);
const y = lerpArray(
tt,
points.map((p) => p.y),
);
context.lineTo(x, y);
}
@ -221,7 +220,7 @@ function getClosestCurveIndex(x, y) {
for (let i = 0; i < curves.length; i++) {
for (const point of curves[i]) {
const dist = Math.abs(
Math.sqrt((x - point[0]) ** 2 + (y - point[1]) ** 2),
Math.sqrt((x - point.x) ** 2 + (y - point.y) ** 2),
);
if (!minDist || dist < minDist) {
minDist = dist;
@ -244,7 +243,7 @@ function getSelectedPoint(x, y) {
for (let i = 0; i < curves[selected].length; i++) {
const point = curves[selected][i];
const dist = Math.abs(
Math.sqrt((x - point[0]) ** 2 + (y - point[1]) ** 2),
Math.sqrt((x - point.x) ** 2 + (y - point.y) ** 2),
);
if (dist <= 10) {
return i;
@ -255,11 +254,10 @@ function getSelectedPoint(x, y) {
/**
* Gets the closest end point
* @param {number} x
* @param {number} y
* @returns {number[]|null}
* @param {{x: number, y: number}} point
* @returns {[number|null, number|null]} curveIndex and pointIndex
*/
function getClosestEndPoint(x, y) {
function getClosestEndPoint(point) {
/** @type {number|null} */
let minDist = null,
minCurveIndex = null,
@ -268,7 +266,10 @@ function getClosestEndPoint(x, y) {
for (let i = 0; i < curves.length; i++) {
if (i === selected) continue;
let dist = Math.abs(
Math.sqrt((x - curves[i][0][0]) ** 2 + (y - curves[i][0][1]) ** 2),
Math.sqrt(
(point.x - curves[i][0].x) ** 2 +
(point.y - curves[i][0].y) ** 2,
),
);
if (minDist === null || dist < minDist) {
minDist = dist;
@ -277,7 +278,10 @@ function getClosestEndPoint(x, y) {
}
dist = Math.abs(
Math.sqrt((x - curves[i][3][0]) ** 2 + (y - curves[i][3][1]) ** 2),
Math.sqrt(
(point.x - curves[i][3].x) ** 2 +
(point.y - curves[i][3].y) ** 2,
),
);
if (minDist === null || dist < minDist) {
minDist = dist;
@ -312,7 +316,7 @@ canvas.addEventListener('mousedown', (e) => {
canvas.addEventListener('mousemove', (e) => {
if (!mouseDown) return;
if (movePointIndex === null) return;
curves[selected][movePointIndex] = [e.pageX, e.pageY];
curves[selected][movePointIndex] = { x: e.pageX, y: e.pageY };
draw();
});