Curve editing
This commit is contained in:
parent
45a055250b
commit
380fcf0c32
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { Vector } from "./vector.js";
|
||||||
|
|
||||||
// math-inlining.
|
// math-inlining.
|
||||||
const { abs, cos, sin, acos, atan2, sqrt, pow } = Math;
|
const { abs, cos, sin, acos, atan2, sqrt, pow } = Math;
|
||||||
|
|
||||||
|
|
@ -1968,6 +1970,25 @@ class Bezier {
|
||||||
} while (t_e < 1);
|
} while (t_e < 1);
|
||||||
return circles;
|
return circles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getStrutPoints(t) {
|
||||||
|
const p = this.points.map((p) => new Vector(p));
|
||||||
|
const mt = 1 - t;
|
||||||
|
|
||||||
|
let s = 0;
|
||||||
|
let n = p.length + 1;
|
||||||
|
while (--n > 1) {
|
||||||
|
let list = p.slice(s, s + n);
|
||||||
|
for (let i = 0, e = list.length - 1; i < e; i++) {
|
||||||
|
let pt = list[i + 1].subtract(list[i + 1].subtract(list[i]).scale(mt));
|
||||||
|
p.push(pt);
|
||||||
|
}
|
||||||
|
s += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Bezier };
|
export { Bezier };
|
||||||
|
|
|
||||||
295
src/main.js
295
src/main.js
|
|
@ -116,7 +116,6 @@ let actions = {
|
||||||
},
|
},
|
||||||
execute: (action) => {
|
execute: (action) => {
|
||||||
let object = pointerList[action.parent]
|
let object = pointerList[action.parent]
|
||||||
console.log(object)
|
|
||||||
let curvesList = action.curves
|
let curvesList = action.curves
|
||||||
let shape = new Shape(action.startx, action.starty, context, action.uuid)
|
let shape = new Shape(action.startx, action.starty, context, action.uuid)
|
||||||
for (let curve of curvesList) {
|
for (let curve of curvesList) {
|
||||||
|
|
@ -136,7 +135,68 @@ let actions = {
|
||||||
object.removeShape(shape)
|
object.removeShape(shape)
|
||||||
delete pointerList[action.uuid]
|
delete pointerList[action.uuid]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
editShape: {
|
||||||
|
create: (shape, newCurves) => {
|
||||||
|
let serializableNewCurves = []
|
||||||
|
for (let curve of newCurves) {
|
||||||
|
serializableNewCurves.push({ points: curve.points })
|
||||||
|
}
|
||||||
|
let serializableOldCurves = []
|
||||||
|
for (let curve of shape.curves) {
|
||||||
|
serializableOldCurves.push({ points: curve.points })
|
||||||
|
}
|
||||||
|
let action = {
|
||||||
|
shape: shape.idx,
|
||||||
|
oldCurves: serializableOldCurves,
|
||||||
|
newCurves: serializableNewCurves
|
||||||
|
}
|
||||||
|
undoStack.push({name: "editShape", action: action})
|
||||||
|
actions.editShape.execute(action)
|
||||||
|
|
||||||
|
},
|
||||||
|
execute: (action) => {
|
||||||
|
let shape = pointerList[action.shape]
|
||||||
|
let curvesList = action.newCurves
|
||||||
|
shape.curves = []
|
||||||
|
for (let curve of curvesList) {
|
||||||
|
shape.addCurve(
|
||||||
|
new Bezier(
|
||||||
|
curve.points[0].x, curve.points[0].y,
|
||||||
|
curve.points[1].x, curve.points[1].y,
|
||||||
|
curve.points[2].x, curve.points[2].y,
|
||||||
|
curve.points[3].x, curve.points[3].y
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rollback: (action) => {
|
||||||
|
let shape = pointerList[action.shape]
|
||||||
|
let curvesList = action.oldCurves
|
||||||
|
shape.curves = []
|
||||||
|
for (let curve of curvesList) {
|
||||||
|
shape.addCurve(
|
||||||
|
new Bezier(
|
||||||
|
curve.points[0].x, curve.points[0].y,
|
||||||
|
curve.points[1].x, curve.points[1].y,
|
||||||
|
curve.points[2].x, curve.points[2].y,
|
||||||
|
curve.points[3].x, curve.points[3].y
|
||||||
|
))
|
||||||
|
}}
|
||||||
|
},
|
||||||
|
addObject: {
|
||||||
|
create: () => {},
|
||||||
|
execute: (action) => {
|
||||||
|
|
||||||
|
},
|
||||||
|
rollback: (action) => {}
|
||||||
|
},
|
||||||
|
editObject: {
|
||||||
|
create: () => {},
|
||||||
|
execute: (action) => {
|
||||||
|
|
||||||
|
},
|
||||||
|
rollback: (action) => {}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
function uuidv4() {
|
function uuidv4() {
|
||||||
|
|
@ -192,7 +252,7 @@ function selectCurve(context, mouse) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (closest) {
|
if (closest) {
|
||||||
return closest
|
return {curve:closest, shape:shape}
|
||||||
} else {
|
} else {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
@ -200,6 +260,137 @@ function selectCurve(context, mouse) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function moldCurve(curve, mouse, oldmouse) {
|
||||||
|
let diff = {x: mouse.x - oldmouse.x, y: mouse.y - oldmouse.y}
|
||||||
|
let p = curve.project(mouse)
|
||||||
|
let min_influence = 0.1
|
||||||
|
console.log(p.t)
|
||||||
|
const CP1 = {
|
||||||
|
x: curve.points[1].x + diff.x*(1-p.t)*2,
|
||||||
|
y: curve.points[1].y + diff.y*(1-p.t)*2
|
||||||
|
}
|
||||||
|
const CP2 = {
|
||||||
|
x: curve.points[2].x + diff.x*(p.t)*2,
|
||||||
|
y: curve.points[2].y + diff.y*(p.t)*2
|
||||||
|
}
|
||||||
|
return new Bezier(curve.points[0], CP1, CP2, curve.points[3])
|
||||||
|
// return curve
|
||||||
|
}
|
||||||
|
|
||||||
|
function moldCurveMath(curve, mouse) {
|
||||||
|
let interpolated = true
|
||||||
|
|
||||||
|
let p = curve.project({x: mouse.x, y: mouse.y})
|
||||||
|
|
||||||
|
let t1 = p.t;
|
||||||
|
let struts = curve.getStrutPoints(t1);
|
||||||
|
let m = {
|
||||||
|
t: p.t,
|
||||||
|
B: p,
|
||||||
|
e1: struts[7],
|
||||||
|
e2: struts[8]
|
||||||
|
};
|
||||||
|
m.d1 = { x: m.e1.x - m.B.x, y: m.e1.y - m.B.y};
|
||||||
|
m.d2 = { x: m.e2.x - m.B.x, y: m.e2.y - m.B.y};
|
||||||
|
|
||||||
|
const S = curve.points[0],
|
||||||
|
E = curve.points[curve.order],
|
||||||
|
{B, t, e1, e2} = m,
|
||||||
|
org = curve.getABC(t, B),
|
||||||
|
nB = mouse,
|
||||||
|
d1 = { x: e1.x - B.x, y: e1.y - B.y },
|
||||||
|
d2 = { x: e2.x - B.x, y: e2.y - B.y },
|
||||||
|
ne1 = { x: nB.x + d1.x, y: nB.y + d1.y },
|
||||||
|
ne2 = { x: nB.x + d2.x, y: nB.y + d2.y },
|
||||||
|
{A, C} = curve.getABC(t, nB),
|
||||||
|
// The cubic case requires us to derive two control points,
|
||||||
|
// which we'll do in a separate function to keep the code
|
||||||
|
// at least somewhat manageable.
|
||||||
|
{v1, v2, C1, C2} = deriveControlPoints(S, A, E, ne1, ne2, t);
|
||||||
|
|
||||||
|
// if (interpolated) {
|
||||||
|
// For the last example, we need to show what the "ideal" curve
|
||||||
|
// looks like, in addition to the one we actually get when we
|
||||||
|
// rely on the B we picked with the `t` value and e1/e2 points
|
||||||
|
// that point B had...
|
||||||
|
const ideal = getIdealisedCurve(S, nB, E);
|
||||||
|
let idealCurve = new Bezier(ideal.S, ideal.C1, ideal.C2, ideal.E);
|
||||||
|
// }
|
||||||
|
let molded = new Bezier(S,C1,C2,E);
|
||||||
|
|
||||||
|
let falloff = 100
|
||||||
|
|
||||||
|
let d = Bezier.getUtils().dist(ideal.B, p);
|
||||||
|
let t2 = Math.min(falloff, d) / falloff;
|
||||||
|
console.log(d)
|
||||||
|
let iC1 = {
|
||||||
|
x: (1-t2) * molded.points[1].x + t2 * idealCurve.points[1].x,
|
||||||
|
y: (1-t2) * molded.points[1].y + t2 * idealCurve.points[1].y
|
||||||
|
};
|
||||||
|
let iC2 = {
|
||||||
|
x: (1-t2) * molded.points[2].x + t2 * idealCurve.points[2].x,
|
||||||
|
y: (1-t2) * molded.points[2].y + t2 * idealCurve.points[2].y
|
||||||
|
};
|
||||||
|
let interpolatedCurve = new Bezier(molded.points[0], iC1, iC2, molded.points[3]);
|
||||||
|
|
||||||
|
return interpolatedCurve
|
||||||
|
// return idealCurve
|
||||||
|
}
|
||||||
|
|
||||||
|
function deriveControlPoints(S, A, E, e1, e2, t) {
|
||||||
|
// Deriving the control points is effectively "doing what
|
||||||
|
// we talk about in the section", in code:
|
||||||
|
|
||||||
|
const v1 = {
|
||||||
|
x: A.x - (A.x - e1.x)/(1-t),
|
||||||
|
y: A.y - (A.y - e1.y)/(1-t)
|
||||||
|
};
|
||||||
|
const v2 = {
|
||||||
|
x: A.x - (A.x - e2.x)/t,
|
||||||
|
y: A.y - (A.y - e2.y)/t
|
||||||
|
};
|
||||||
|
|
||||||
|
const C1 = {
|
||||||
|
x: S.x + (v1.x - S.x) / t,
|
||||||
|
y: S.y + (v1.y - S.y) / t
|
||||||
|
};
|
||||||
|
const C2 = {
|
||||||
|
x: E.x + (v2.x - E.x) / (1-t),
|
||||||
|
y: E.y + (v2.y - E.y) / (1-t)
|
||||||
|
};
|
||||||
|
|
||||||
|
return {v1, v2, C1, C2};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIdealisedCurve(p1, p2, p3) {
|
||||||
|
// This "reruns" the curve composition, but with a `t` value
|
||||||
|
// that is unrelated to the actual point B we picked, instead
|
||||||
|
// using whatever the appropriate `t` value would be if we were
|
||||||
|
// trying to fit a circular arc, as per earlier in the section.
|
||||||
|
const utils = Bezier.getUtils()
|
||||||
|
const c = utils.getccenter(p1, p2, p3),
|
||||||
|
d1 = utils.dist(p1, p2),
|
||||||
|
d2 = utils.dist(p3, p2),
|
||||||
|
t = d1 / (d1 + d2),
|
||||||
|
{ A, B, C, S, E } = Bezier.getABC(3, p1, p2, p3, t),
|
||||||
|
angle = (Math.atan2(E.y-S.y, E.x-S.x) - Math.atan2(B.y-S.y, B.x-S.x) + utils.TAU) % utils.TAU,
|
||||||
|
bc = (angle < 0 || angle > utils.PI ? -1 : 1) * utils.dist(S, E)/3,
|
||||||
|
de1 = t * bc,
|
||||||
|
de2 = (1-t) * bc,
|
||||||
|
tangent = [
|
||||||
|
{ x: B.x - 10 * (B.y-c.y), y: B.y + 10 * (B.x-c.x) },
|
||||||
|
{ x: B.x + 10 * (B.y-c.y), y: B.y - 10 * (B.x-c.x) }
|
||||||
|
],
|
||||||
|
tlength = utils.dist(tangent[0], tangent[1]),
|
||||||
|
dx = (tangent[1].x - tangent[0].x)/tlength,
|
||||||
|
dy = (tangent[1].y - tangent[0].y)/tlength,
|
||||||
|
e1 = { x: B.x + de1 * dx, y: B.y + de1 * dy},
|
||||||
|
e2 = { x: B.x - de2 * dx, y: B.y - de2 * dy },
|
||||||
|
{v1, v2, C1, C2} = deriveControlPoints(S, A, E, e1, e2, t);
|
||||||
|
|
||||||
|
return {A,B,C,S,E,e1,e2,v1,v2,C1,C2};
|
||||||
|
}
|
||||||
|
|
||||||
function growBoundingBox(bboxa, bboxb) {
|
function growBoundingBox(bboxa, bboxb) {
|
||||||
bboxa.x.min = Math.min(bboxa.x.min, bboxb.x.min)
|
bboxa.x.min = Math.min(bboxa.x.min, bboxb.x.min)
|
||||||
bboxa.y.min = Math.min(bboxa.y.min, bboxb.y.min)
|
bboxa.y.min = Math.min(bboxa.y.min, bboxb.y.min)
|
||||||
|
|
@ -506,10 +697,10 @@ class GraphicsObject {
|
||||||
if (context.activeCurve) {
|
if (context.activeCurve) {
|
||||||
ctx.strokeStyle = "magenta"
|
ctx.strokeStyle = "magenta"
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
ctx.moveTo(context.activeCurve.points[0].x, context.activeCurve.points[0].y)
|
ctx.moveTo(context.activeCurve.current.points[0].x, context.activeCurve.current.points[0].y)
|
||||||
ctx.bezierCurveTo(context.activeCurve.points[1].x, context.activeCurve.points[1].y,
|
ctx.bezierCurveTo(context.activeCurve.current.points[1].x, context.activeCurve.current.points[1].y,
|
||||||
context.activeCurve.points[2].x, context.activeCurve.points[2].y,
|
context.activeCurve.current.points[2].x, context.activeCurve.current.points[2].y,
|
||||||
context.activeCurve.points[3].x, context.activeCurve.points[3].y
|
context.activeCurve.current.points[3].x, context.activeCurve.current.points[3].y
|
||||||
)
|
)
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
}
|
}
|
||||||
|
|
@ -638,7 +829,6 @@ function stage() {
|
||||||
imageShape.addLine(0, 0)
|
imageShape.addLine(0, 0)
|
||||||
imageShape.recalculateBoundingBox()
|
imageShape.recalculateBoundingBox()
|
||||||
imageObject.addShape(imageShape)
|
imageObject.addShape(imageShape)
|
||||||
console.log(imageObject.bbox())
|
|
||||||
context.activeObject.addObject(
|
context.activeObject.addObject(
|
||||||
imageObject,
|
imageObject,
|
||||||
mouse.x-width/2 + (20*img.ix),
|
mouse.x-width/2 + (20*img.ix),
|
||||||
|
|
@ -665,13 +855,18 @@ function stage() {
|
||||||
pushState()
|
pushState()
|
||||||
context.mouseDown = true
|
context.mouseDown = true
|
||||||
context.activeShape = new Shape(mouse.x, mouse.y, context, true, true)
|
context.activeShape = new Shape(mouse.x, mouse.y, context, true, true)
|
||||||
console.log(context.activeObject)
|
|
||||||
context.lastMouse = mouse
|
context.lastMouse = mouse
|
||||||
break;
|
break;
|
||||||
case "select":
|
case "select":
|
||||||
let curve = selectCurve(context, mouse)
|
let selection = selectCurve(context, mouse)
|
||||||
if (curve) {
|
if (selection) {
|
||||||
context.dragging = true
|
context.dragging = true
|
||||||
|
context.activeCurve = {
|
||||||
|
initial: selection.curve,
|
||||||
|
current: new Bezier(selection.curve.points),
|
||||||
|
shape: selection.shape,
|
||||||
|
startmouse: mouse
|
||||||
|
}
|
||||||
console.log("gonna move this")
|
console.log("gonna move this")
|
||||||
} else {
|
} else {
|
||||||
let selected = false
|
let selected = false
|
||||||
|
|
@ -694,7 +889,6 @@ function stage() {
|
||||||
context.selectionRect = {x1: mouse.x, x2: mouse.x, y1: mouse.y, y2:mouse.y}
|
context.selectionRect = {x1: mouse.x, x2: mouse.x, y1: mouse.y, y2:mouse.y}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(context.selection)
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -715,16 +909,29 @@ function stage() {
|
||||||
actions.addShape.create(context.activeObject, context.activeShape)
|
actions.addShape.create(context.activeObject, context.activeShape)
|
||||||
// context.activeObject.addShape(context.activeShape)
|
// context.activeObject.addShape(context.activeShape)
|
||||||
context.activeShape = undefined
|
context.activeShape = undefined
|
||||||
console.log(pointerList)
|
|
||||||
console.log(undoStack)
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "rectangle":
|
case "rectangle":
|
||||||
context.activeShape = undefined
|
context.activeShape = undefined
|
||||||
|
break;
|
||||||
|
case "select":
|
||||||
|
if (context.activeCurve) {
|
||||||
|
let newCurves = []
|
||||||
|
for (let curve of context.activeCurve.shape.curves) {
|
||||||
|
if (curve == context.activeCurve.initial) {
|
||||||
|
newCurves.push(context.activeCurve.current)
|
||||||
|
} else {
|
||||||
|
newCurves.push(curve)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
actions.editShape.create(context.activeCurve.shape, newCurves)
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
context.lastMouse = mouse
|
context.lastMouse = mouse
|
||||||
|
context.activeCurve = undefined
|
||||||
updateUI()
|
updateUI()
|
||||||
})
|
})
|
||||||
stage.addEventListener("mousemove", (e) => {
|
stage.addEventListener("mousemove", (e) => {
|
||||||
|
|
@ -752,13 +959,16 @@ function stage() {
|
||||||
break;
|
break;
|
||||||
case "select":
|
case "select":
|
||||||
if (context.dragging) {
|
if (context.dragging) {
|
||||||
let dist = vectorDist(mouse, context.activeCurve.points[1])
|
// let dist = vectorDist(mouse, context.activeCurve.points[1])
|
||||||
let cpoint = context.activeCurve.points[1]
|
// let cpoint = context.activeCurve.points[1]
|
||||||
if (vectorDist(mouse, context.activeCurve.points[2]) < dist) {
|
// if (vectorDist(mouse, context.activeCurve.points[2]) < dist) {
|
||||||
cpoint = context.activeCurve.points[2]
|
// cpoint = context.activeCurve.points[2]
|
||||||
}
|
// }
|
||||||
cpoint.x += (mouse.x - context.lastMouse.x)
|
// cpoint.x += (mouse.x - context.lastMouse.x)
|
||||||
cpoint.y += (mouse.y - context.lastMouse.y)
|
// cpoint.y += (mouse.y - context.lastMouse.y)
|
||||||
|
context.activeCurve.current.points = moldCurve(
|
||||||
|
context.activeCurve.initial, mouse, context.activeCurve.startmouse
|
||||||
|
).points
|
||||||
} else if (context.selectionRect) {
|
} else if (context.selectionRect) {
|
||||||
context.selectionRect.x2 = mouse.x
|
context.selectionRect.x2 = mouse.x
|
||||||
context.selectionRect.y2 = mouse.y
|
context.selectionRect.y2 = mouse.y
|
||||||
|
|
@ -769,7 +979,17 @@ function stage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
context.activeCurve = selectCurve(context, mouse)
|
let selection = selectCurve(context, mouse)
|
||||||
|
if (selection) {
|
||||||
|
context.activeCurve = {
|
||||||
|
current: selection.curve,
|
||||||
|
initial: new Bezier(selection.curve.points),
|
||||||
|
shape: selection.shape,
|
||||||
|
startmouse: mouse
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
context.activeCurve = undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
context.lastMouse = mouse
|
context.lastMouse = mouse
|
||||||
break;
|
break;
|
||||||
|
|
@ -927,13 +1147,6 @@ function createPane(content=undefined) {
|
||||||
icon.src = "/assets/stage.svg"
|
icon.src = "/assets/stage.svg"
|
||||||
button.appendChild(icon)
|
button.appendChild(icon)
|
||||||
|
|
||||||
|
|
||||||
// div.style.display = "grid";
|
|
||||||
// div.style.gridTemplateColumns = `var(--lineheight) 1fr`
|
|
||||||
// div.style.gridTemplateRows = "1fr"
|
|
||||||
// header.style.gridArea = "1 / 1 / 2 / 2"
|
|
||||||
// content.style.gridArea = "1 / 2 / 2 / 3"
|
|
||||||
|
|
||||||
div.className = "vertical-grid"
|
div.className = "vertical-grid"
|
||||||
header.style.height = "calc( 2 * var(--lineheight))"
|
header.style.height = "calc( 2 * var(--lineheight))"
|
||||||
content.style.height = "calc( 100% - 2 * var(--lineheight) )"
|
content.style.height = "calc( 100% - 2 * var(--lineheight) )"
|
||||||
|
|
@ -959,26 +1172,12 @@ function splitPane(div, percent, horiz, newPane=undefined) {
|
||||||
div.appendChild(div1)
|
div.appendChild(div1)
|
||||||
div.appendChild(div2)
|
div.appendChild(div2)
|
||||||
|
|
||||||
// div.style.display = "grid";
|
|
||||||
// if (horiz) {
|
|
||||||
// div.classList.add("horizontal-grid")
|
|
||||||
// div.style.gridTemplateColumns = `${percent}% 1fr`
|
|
||||||
// div1.style.gridArea = "1 / 1 / 2 / 2"
|
|
||||||
// div2.style.gridArea = "1 / 2 / 2 / 3"
|
|
||||||
// } else {
|
|
||||||
// div.classList.add("vertical-grid")
|
|
||||||
// div.style.gridTemplateRows = `${percent}% 1fr`
|
|
||||||
// div1.style.gridArea = "1 / 1 / 2 / 2"
|
|
||||||
// div2.style.gridArea = "2 / 1 / 3 / 2"
|
|
||||||
// }
|
|
||||||
if (horiz) {
|
if (horiz) {
|
||||||
div.className = "horizontal-grid"
|
div.className = "horizontal-grid"
|
||||||
} else {
|
} else {
|
||||||
div.className = "vertical-grid"
|
div.className = "vertical-grid"
|
||||||
}
|
}
|
||||||
div.setAttribute("lb-percent", percent) // TODO: better attribute name
|
div.setAttribute("lb-percent", percent) // TODO: better attribute name
|
||||||
// div1.style.flex = `0 0 ${percent}%`
|
|
||||||
// div2.style.flex = `1 1 auto`
|
|
||||||
Coloris({el: ".color-field"})
|
Coloris({el: ".color-field"})
|
||||||
updateUI()
|
updateUI()
|
||||||
updateLayout(rootPane)
|
updateLayout(rootPane)
|
||||||
|
|
@ -1016,8 +1215,6 @@ function updateUI() {
|
||||||
ctx.reset();
|
ctx.reset();
|
||||||
ctx.fillStyle = "white"
|
ctx.fillStyle = "white"
|
||||||
ctx.fillRect(0,0,canvas.width,canvas.height)
|
ctx.fillRect(0,0,canvas.width,canvas.height)
|
||||||
ctx.fillStyle = "green"
|
|
||||||
// ctx.fillRect(0,0,200,200)
|
|
||||||
|
|
||||||
context.ctx = ctx;
|
context.ctx = ctx;
|
||||||
root.draw(context)
|
root.draw(context)
|
||||||
|
|
@ -1025,13 +1222,5 @@ function updateUI() {
|
||||||
context.activeShape.draw(context)
|
context.activeShape.draw(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
// let mouse;
|
|
||||||
// if (mouseEvent) {
|
|
||||||
// mouse = getMousePos(canvas, mouseEvent);
|
|
||||||
// } else {
|
|
||||||
// mouse = {x: 0, y: 0}
|
|
||||||
// }
|
|
||||||
// ctx.fillRect(mouse.x, mouse.y, 50,50)
|
|
||||||
}
|
}
|
||||||
// requestAnimationFrame(updateUI)
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
class Vector {
|
||||||
|
constructor(x, y, z) {
|
||||||
|
if (arguments.length === 1) {
|
||||||
|
z = x.z;
|
||||||
|
y = x.y;
|
||||||
|
x = x.x;
|
||||||
|
}
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
if (z !== undefined) {
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dist(other, y, z = 0) {
|
||||||
|
if (y !== undefined) other = { x: other, y, z };
|
||||||
|
let sum = 0;
|
||||||
|
sum += (this.x - other.x) ** 2;
|
||||||
|
sum += (this.y - other.y) ** 2;
|
||||||
|
let z1 = this.z ? this.z : 0;
|
||||||
|
let z2 = other.z ? other.z : 0;
|
||||||
|
sum += (z1 - z2) ** 2;
|
||||||
|
return sum ** 0.5;
|
||||||
|
}
|
||||||
|
normalize(f) {
|
||||||
|
let mag = this.dist(0, 0, 0);
|
||||||
|
return new Vector((f * this.x) / mag, (f * this.y) / mag, (f * this.z) / mag);
|
||||||
|
}
|
||||||
|
getAngle() {
|
||||||
|
return -Math.atan2(this.y, this.x);
|
||||||
|
}
|
||||||
|
reflect(other) {
|
||||||
|
let p = new Vector(other.x - this.x, other.y - this.y);
|
||||||
|
if (other.z !== undefined) {
|
||||||
|
p.z = other.z;
|
||||||
|
if (this.z !== undefined) {
|
||||||
|
p.z -= this.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.subtract(p);
|
||||||
|
}
|
||||||
|
add(other) {
|
||||||
|
let p = new Vector(this.x + other.x, this.y + other.y);
|
||||||
|
if (this.z !== undefined) {
|
||||||
|
p.z = this.z;
|
||||||
|
if (other.z !== undefined) {
|
||||||
|
p.z += other.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
subtract(other) {
|
||||||
|
let p = new Vector(this.x - other.x, this.y - other.y);
|
||||||
|
if (this.z !== undefined) {
|
||||||
|
p.z = this.z;
|
||||||
|
if (other.z !== undefined) {
|
||||||
|
p.z -= other.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
scale(f = 1) {
|
||||||
|
if (f === 0) {
|
||||||
|
return new Vector(0, 0, this.z === undefined ? undefined : 0);
|
||||||
|
}
|
||||||
|
let p = new Vector(this.x * f, this.y * f);
|
||||||
|
if (this.z !== undefined) {
|
||||||
|
p.z = this.z * f;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Vector };
|
||||||
|
|
||||||
Loading…
Reference in New Issue