Fix paint bucket coordinates inside objects
This commit is contained in:
parent
9205205ecd
commit
112de7ed1a
349
src/main.js
349
src/main.js
|
|
@ -40,6 +40,7 @@ import {
|
||||||
rotateAroundPointIncremental,
|
rotateAroundPointIncremental,
|
||||||
rgbToHsv,
|
rgbToHsv,
|
||||||
multiplyMatrices,
|
multiplyMatrices,
|
||||||
|
growBoundingBox,
|
||||||
} from "./utils.js";
|
} from "./utils.js";
|
||||||
import {
|
import {
|
||||||
backgroundColor,
|
backgroundColor,
|
||||||
|
|
@ -1976,13 +1977,6 @@ function deriveControlPoints(S, A, E, e1, e2, t) {
|
||||||
return { v1, v2, C1, C2 };
|
return { v1, v2, C1, C2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
function growBoundingBox(bboxa, bboxb) {
|
|
||||||
bboxa.x.min = Math.min(bboxa.x.min, bboxb.x.min);
|
|
||||||
bboxa.y.min = Math.min(bboxa.y.min, bboxb.y.min);
|
|
||||||
bboxa.x.max = Math.max(bboxa.x.max, bboxb.x.max);
|
|
||||||
bboxa.y.max = Math.max(bboxa.y.max, bboxb.y.max);
|
|
||||||
}
|
|
||||||
|
|
||||||
function regionToBbox(region) {
|
function regionToBbox(region) {
|
||||||
return {
|
return {
|
||||||
x: {
|
x: {
|
||||||
|
|
@ -2633,176 +2627,182 @@ class Layer extends Widget {
|
||||||
}
|
}
|
||||||
mousedown(x, y) {
|
mousedown(x, y) {
|
||||||
const mouse = {x: x, y: y}
|
const mouse = {x: x, y: y}
|
||||||
switch(mode) {
|
if (this==context.activeLayer) {
|
||||||
case "rectangle":
|
switch(mode) {
|
||||||
case "ellipse":
|
case "rectangle":
|
||||||
case "draw":
|
case "ellipse":
|
||||||
this.clicked = true
|
case "draw":
|
||||||
this.activeShape = new Shape(x, y, context, uuidv4())
|
this.clicked = true
|
||||||
this.lastMouse = mouse;
|
this.activeShape = new Shape(x, y, context, uuidv4())
|
||||||
break;
|
this.lastMouse = mouse;
|
||||||
case "select":
|
|
||||||
case "transform":
|
|
||||||
break;
|
|
||||||
case "paint_bucket":
|
|
||||||
debugCurves = [];
|
|
||||||
debugPoints = [];
|
|
||||||
let epsilon = context.fillGaps;
|
|
||||||
let regionPoints;
|
|
||||||
|
|
||||||
// First, see if there's an existing shape to change the color of
|
|
||||||
// TODO: get this from self
|
|
||||||
let pointShape = getShapeAtPoint(
|
|
||||||
mouse,
|
|
||||||
context.activeObject.currentFrame.shapes,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (pointShape) {
|
|
||||||
actions.colorShape.create(pointShape, context.fillStyle);
|
|
||||||
break;
|
break;
|
||||||
}
|
case "select":
|
||||||
|
case "transform":
|
||||||
|
break;
|
||||||
|
case "paint_bucket":
|
||||||
|
debugCurves = [];
|
||||||
|
debugPoints = [];
|
||||||
|
let epsilon = context.fillGaps;
|
||||||
|
let regionPoints;
|
||||||
|
|
||||||
// We didn't find an existing region to paintbucket, see if we can make one
|
// First, see if there's an existing shape to change the color of
|
||||||
try {
|
// TODO: get this from self
|
||||||
regionPoints = floodFillRegion(
|
let pointShape = getShapeAtPoint(
|
||||||
mouse,
|
mouse,
|
||||||
epsilon,
|
context.activeObject.currentFrame.shapes,
|
||||||
config.fileWidth,
|
|
||||||
config.fileHeight,
|
|
||||||
context,
|
|
||||||
debugPoints,
|
|
||||||
debugPaintbucket,
|
|
||||||
);
|
);
|
||||||
} catch (e) {
|
|
||||||
updateUI();
|
if (pointShape) {
|
||||||
throw e;
|
actions.colorShape.create(pointShape, context.fillStyle);
|
||||||
}
|
break;
|
||||||
if (regionPoints.length > 0 && regionPoints.length < 10) {
|
}
|
||||||
// probably a very small area, rerun with minimum epsilon
|
|
||||||
regionPoints = floodFillRegion(
|
// We didn't find an existing region to paintbucket, see if we can make one
|
||||||
mouse,
|
try {
|
||||||
1,
|
regionPoints = floodFillRegion(
|
||||||
config.fileWidth,
|
mouse,
|
||||||
config.fileHeight,
|
epsilon,
|
||||||
context,
|
config.fileWidth,
|
||||||
debugPoints,
|
config.fileHeight,
|
||||||
);
|
context,
|
||||||
}
|
debugPoints,
|
||||||
let points = [];
|
debugPaintbucket,
|
||||||
for (let point of regionPoints) {
|
);
|
||||||
points.push([point.x, point.y]);
|
} catch (e) {
|
||||||
}
|
updateUI();
|
||||||
let cxt = {
|
throw e;
|
||||||
...context,
|
}
|
||||||
fillShape: true,
|
if (regionPoints.length > 0 && regionPoints.length < 10) {
|
||||||
strokeShape: false,
|
// probably a very small area, rerun with minimum epsilon
|
||||||
sendToBack: true,
|
regionPoints = floodFillRegion(
|
||||||
};
|
mouse,
|
||||||
let shape = new Shape(regionPoints[0].x, regionPoints[0].y, cxt);
|
1,
|
||||||
shape.fromPoints(points, 1);
|
config.fileWidth,
|
||||||
actions.addShape.create(context.activeObject, shape, cxt);
|
config.fileHeight,
|
||||||
break;
|
context,
|
||||||
|
debugPoints,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let points = [];
|
||||||
|
for (let point of regionPoints) {
|
||||||
|
points.push([point.x, point.y]);
|
||||||
|
}
|
||||||
|
let cxt = {
|
||||||
|
...context,
|
||||||
|
fillShape: true,
|
||||||
|
strokeShape: false,
|
||||||
|
sendToBack: true,
|
||||||
|
};
|
||||||
|
let shape = new Shape(regionPoints[0].x, regionPoints[0].y, cxt);
|
||||||
|
shape.fromPoints(points, 1);
|
||||||
|
actions.addShape.create(context.activeObject, shape, cxt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mousemove(x, y) {
|
mousemove(x, y) {
|
||||||
const mouse = {x: x, y: y}
|
const mouse = {x: x, y: y}
|
||||||
switch (mode) {
|
if (this==context.activeLayer) {
|
||||||
case "draw":
|
switch (mode) {
|
||||||
if (this.activeShape) {
|
case "draw":
|
||||||
if (vectorDist(mouse, context.lastMouse) > minSegmentSize) {
|
if (this.activeShape) {
|
||||||
this.activeShape.addLine(x, y);
|
if (vectorDist(mouse, context.lastMouse) > minSegmentSize) {
|
||||||
this.lastMouse = mouse;
|
this.activeShape.addLine(x, y);
|
||||||
|
this.lastMouse = mouse;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
case "rectangle":
|
||||||
case "rectangle":
|
if (this.activeShape) {
|
||||||
if (this.activeShape) {
|
this.activeShape.clear();
|
||||||
this.activeShape.clear();
|
this.activeShape.addLine(x, this.activeShape.starty);
|
||||||
this.activeShape.addLine(x, this.activeShape.starty);
|
this.activeShape.addLine(x, y);
|
||||||
this.activeShape.addLine(x, y);
|
this.activeShape.addLine(this.activeShape.startx, y);
|
||||||
this.activeShape.addLine(this.activeShape.startx, y);
|
this.activeShape.addLine(
|
||||||
this.activeShape.addLine(
|
|
||||||
this.activeShape.startx,
|
|
||||||
this.activeShape.starty,
|
|
||||||
);
|
|
||||||
this.activeShape.update();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "ellipse":
|
|
||||||
if (this.activeShape) {
|
|
||||||
let midX = (mouse.x + this.activeShape.startx) / 2;
|
|
||||||
let midY = (mouse.y + this.activeShape.starty) / 2;
|
|
||||||
let xDiff = (mouse.x - this.activeShape.startx) / 2;
|
|
||||||
let yDiff = (mouse.y - this.activeShape.starty) / 2;
|
|
||||||
let ellipseConst = 0.552284749831; // (4/3)*tan(pi/(2n)) where n=4
|
|
||||||
this.activeShape.clear();
|
|
||||||
this.activeShape.addCurve(
|
|
||||||
new Bezier(
|
|
||||||
midX,
|
|
||||||
this.activeShape.starty,
|
|
||||||
midX + ellipseConst * xDiff,
|
|
||||||
this.activeShape.starty,
|
|
||||||
mouse.x,
|
|
||||||
midY - ellipseConst * yDiff,
|
|
||||||
mouse.x,
|
|
||||||
midY,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
this.activeShape.addCurve(
|
|
||||||
new Bezier(
|
|
||||||
mouse.x,
|
|
||||||
midY,
|
|
||||||
mouse.x,
|
|
||||||
midY + ellipseConst * yDiff,
|
|
||||||
midX + ellipseConst * xDiff,
|
|
||||||
mouse.y,
|
|
||||||
midX,
|
|
||||||
mouse.y,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
this.activeShape.addCurve(
|
|
||||||
new Bezier(
|
|
||||||
midX,
|
|
||||||
mouse.y,
|
|
||||||
midX - ellipseConst * xDiff,
|
|
||||||
mouse.y,
|
|
||||||
this.activeShape.startx,
|
this.activeShape.startx,
|
||||||
midY + ellipseConst * yDiff,
|
|
||||||
this.activeShape.startx,
|
|
||||||
midY,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
this.activeShape.addCurve(
|
|
||||||
new Bezier(
|
|
||||||
this.activeShape.startx,
|
|
||||||
midY,
|
|
||||||
this.activeShape.startx,
|
|
||||||
midY - ellipseConst * yDiff,
|
|
||||||
midX - ellipseConst * xDiff,
|
|
||||||
this.activeShape.starty,
|
this.activeShape.starty,
|
||||||
midX,
|
);
|
||||||
this.activeShape.starty,
|
this.activeShape.update();
|
||||||
),
|
}
|
||||||
);
|
break;
|
||||||
}
|
case "ellipse":
|
||||||
break;
|
if (this.activeShape) {
|
||||||
|
let midX = (mouse.x + this.activeShape.startx) / 2;
|
||||||
|
let midY = (mouse.y + this.activeShape.starty) / 2;
|
||||||
|
let xDiff = (mouse.x - this.activeShape.startx) / 2;
|
||||||
|
let yDiff = (mouse.y - this.activeShape.starty) / 2;
|
||||||
|
let ellipseConst = 0.552284749831; // (4/3)*tan(pi/(2n)) where n=4
|
||||||
|
this.activeShape.clear();
|
||||||
|
this.activeShape.addCurve(
|
||||||
|
new Bezier(
|
||||||
|
midX,
|
||||||
|
this.activeShape.starty,
|
||||||
|
midX + ellipseConst * xDiff,
|
||||||
|
this.activeShape.starty,
|
||||||
|
mouse.x,
|
||||||
|
midY - ellipseConst * yDiff,
|
||||||
|
mouse.x,
|
||||||
|
midY,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
this.activeShape.addCurve(
|
||||||
|
new Bezier(
|
||||||
|
mouse.x,
|
||||||
|
midY,
|
||||||
|
mouse.x,
|
||||||
|
midY + ellipseConst * yDiff,
|
||||||
|
midX + ellipseConst * xDiff,
|
||||||
|
mouse.y,
|
||||||
|
midX,
|
||||||
|
mouse.y,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
this.activeShape.addCurve(
|
||||||
|
new Bezier(
|
||||||
|
midX,
|
||||||
|
mouse.y,
|
||||||
|
midX - ellipseConst * xDiff,
|
||||||
|
mouse.y,
|
||||||
|
this.activeShape.startx,
|
||||||
|
midY + ellipseConst * yDiff,
|
||||||
|
this.activeShape.startx,
|
||||||
|
midY,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
this.activeShape.addCurve(
|
||||||
|
new Bezier(
|
||||||
|
this.activeShape.startx,
|
||||||
|
midY,
|
||||||
|
this.activeShape.startx,
|
||||||
|
midY - ellipseConst * yDiff,
|
||||||
|
midX - ellipseConst * xDiff,
|
||||||
|
this.activeShape.starty,
|
||||||
|
midX,
|
||||||
|
this.activeShape.starty,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mouseup(x, y) {
|
mouseup(x, y) {
|
||||||
this.clicked = false
|
this.clicked = false
|
||||||
switch (mode) {
|
if (this==context.activeLayer) {
|
||||||
case "draw":
|
switch (mode) {
|
||||||
if (this.activeShape) {
|
case "draw":
|
||||||
this.activeShape.addLine(x, y);
|
if (this.activeShape) {
|
||||||
this.activeShape.simplify(context.simplifyMode);
|
this.activeShape.addLine(x, y);
|
||||||
}
|
this.activeShape.simplify(context.simplifyMode);
|
||||||
case "rectangle":
|
}
|
||||||
case "ellipse":
|
case "rectangle":
|
||||||
if (this.activeShape) {
|
case "ellipse":
|
||||||
actions.addShape.create(context.activeObject, this.activeShape);
|
if (this.activeShape) {
|
||||||
this.activeShape = undefined;
|
actions.addShape.create(context.activeObject, this.activeShape);
|
||||||
}
|
this.activeShape = undefined;
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3579,6 +3579,10 @@ class GraphicsObject extends Widget {
|
||||||
// this.children = []
|
// this.children = []
|
||||||
|
|
||||||
this.shapes = [];
|
this.shapes = [];
|
||||||
|
|
||||||
|
this._globalEvents.add("mousedown")
|
||||||
|
this._globalEvents.add("mousemove")
|
||||||
|
this._globalEvents.add("mouseup")
|
||||||
}
|
}
|
||||||
static fromJSON(json) {
|
static fromJSON(json) {
|
||||||
const graphicsObject = new GraphicsObject(json.idx);
|
const graphicsObject = new GraphicsObject(json.idx);
|
||||||
|
|
@ -4059,6 +4063,11 @@ Object.defineProperty(context, "activeObject", {
|
||||||
return this.objectStack.at(-1);
|
return this.objectStack.at(-1);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
Object.defineProperty(context, "activeLayer", {
|
||||||
|
get: function () {
|
||||||
|
return this.objectStack.at(-1).activeLayer
|
||||||
|
}
|
||||||
|
})
|
||||||
context.objectStack = [root];
|
context.objectStack = [root];
|
||||||
|
|
||||||
async function greet() {
|
async function greet() {
|
||||||
|
|
@ -6875,6 +6884,22 @@ function renderLayers() {
|
||||||
2 * Math.PI,
|
2 * Math.PI,
|
||||||
);
|
);
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
|
if (frameInfo.valueAtN.keyTypes.has("motion")) {
|
||||||
|
ctx.strokeStyle = "#7a00b3";
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(j*frameWidth, layerHeight*0.25)
|
||||||
|
ctx.lineTo((j+1)*frameWidth, layerHeight*0.25)
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
|
if (frameInfo.valueAtN.keyTypes.has("shape")) {
|
||||||
|
ctx.strokeStyle = "#9bff9b";
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(j*frameWidth, layerHeight*0.35)
|
||||||
|
ctx.lineTo((j+1)*frameWidth, layerHeight*0.35)
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
} else if (frameInfo.prev && frameInfo.next) {
|
} else if (frameInfo.prev && frameInfo.next) {
|
||||||
ctx.fillStyle = foregroundColor;
|
ctx.fillStyle = foregroundColor;
|
||||||
drawBorderedRect(
|
drawBorderedRect(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue