mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2024-12-23 14:02:50 -05:00
fix erase with holes in it, but it still doesn't work if you erase crazy path with crazy path
This commit is contained in:
parent
2be90c1633
commit
819215786f
2 changed files with 66 additions and 41 deletions
|
@ -157,7 +157,7 @@ class PaperCanvas extends React.Component {
|
||||||
PaperCanvas.propTypes = {
|
PaperCanvas.propTypes = {
|
||||||
canvasRef: PropTypes.func,
|
canvasRef: PropTypes.func,
|
||||||
clearUndo: PropTypes.func.isRequired,
|
clearUndo: PropTypes.func.isRequired,
|
||||||
mode: PropTypes.instanceOf(Modes),
|
mode: PropTypes.oneOf(Object.values(Modes)),
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
onUpdateSvg: PropTypes.func.isRequired,
|
||||||
rotationCenterX: PropTypes.number,
|
rotationCenterX: PropTypes.number,
|
||||||
rotationCenterY: PropTypes.number,
|
rotationCenterY: PropTypes.number,
|
||||||
|
|
|
@ -248,7 +248,8 @@ class Blobbiness {
|
||||||
let items = getItems({
|
let items = getItems({
|
||||||
match: function (item) {
|
match: function (item) {
|
||||||
return item.selected && blob.isMergeable(lastPath, item) && blob.touches(lastPath, item);
|
return item.selected && blob.isMergeable(lastPath, item) && blob.touches(lastPath, item);
|
||||||
}
|
},
|
||||||
|
class: paper.PathItem
|
||||||
});
|
});
|
||||||
// Eraser didn't hit anything selected, so assume they meant to erase from all instead of from subset
|
// Eraser didn't hit anything selected, so assume they meant to erase from all instead of from subset
|
||||||
// and deselect the selection
|
// and deselect the selection
|
||||||
|
@ -257,7 +258,8 @@ class Blobbiness {
|
||||||
items = getItems({
|
items = getItems({
|
||||||
match: function (item) {
|
match: function (item) {
|
||||||
return blob.isMergeable(lastPath, item) && blob.touches(lastPath, item);
|
return blob.isMergeable(lastPath, item) && blob.touches(lastPath, item);
|
||||||
}
|
},
|
||||||
|
class: paper.PathItem
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,42 +319,8 @@ class Blobbiness {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Divide topologically separate shapes into their own compound paths, instead of
|
|
||||||
// everything being stuck together.
|
|
||||||
// Assume that result of erase operation returns clockwise paths for positive shapes
|
|
||||||
const clockwiseChildren = [];
|
|
||||||
const ccwChildren = [];
|
|
||||||
if (newPath.children) {
|
if (newPath.children) {
|
||||||
for (let j = newPath.children.length - 1; j >= 0; j--) {
|
this.separateCompoundPath(newPath);
|
||||||
const child = newPath.children[j];
|
|
||||||
if (child.isClockwise()) {
|
|
||||||
clockwiseChildren.push(child);
|
|
||||||
} else {
|
|
||||||
ccwChildren.push(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let j = 0; j < clockwiseChildren.length; j++) {
|
|
||||||
const cw = clockwiseChildren[j];
|
|
||||||
cw.copyAttributes(newPath);
|
|
||||||
cw.fillColor = newPath.fillColor;
|
|
||||||
cw.strokeColor = newPath.strokeColor;
|
|
||||||
cw.strokeWidth = newPath.strokeWidth;
|
|
||||||
cw.insertAbove(items[i]);
|
|
||||||
|
|
||||||
// Go backward since we are deleting elements
|
|
||||||
let newCw = cw;
|
|
||||||
for (let k = ccwChildren.length - 1; k >= 0; k--) {
|
|
||||||
const ccw = ccwChildren[k];
|
|
||||||
if (this.firstEnclosesSecond(ccw, cw) || this.firstEnclosesSecond(cw, ccw)) {
|
|
||||||
const temp = newCw.subtract(ccw);
|
|
||||||
temp.insertAbove(newCw);
|
|
||||||
newCw.remove();
|
|
||||||
newCw = temp;
|
|
||||||
ccw.remove();
|
|
||||||
ccwChildren.splice(k, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newPath.remove();
|
newPath.remove();
|
||||||
}
|
}
|
||||||
items[i].remove();
|
items[i].remove();
|
||||||
|
@ -360,6 +328,44 @@ class Blobbiness {
|
||||||
lastPath.remove();
|
lastPath.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
separateCompoundPath (compoundPath) {
|
||||||
|
// Divide topologically separate shapes into their own compound paths, instead of
|
||||||
|
// everything being stuck together.
|
||||||
|
// Assume that result of erase operation returns clockwise paths for positive shapes
|
||||||
|
const clockwiseChildren = [];
|
||||||
|
const ccwChildren = [];
|
||||||
|
for (let j = compoundPath.children.length - 1; j >= 0; j--) {
|
||||||
|
const child = compoundPath.children[j];
|
||||||
|
if (child.isClockwise()) {
|
||||||
|
clockwiseChildren.push(child);
|
||||||
|
} else {
|
||||||
|
ccwChildren.push(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let j = 0; j < clockwiseChildren.length; j++) {
|
||||||
|
const cw = clockwiseChildren[j];
|
||||||
|
cw.copyAttributes(compoundPath);
|
||||||
|
cw.fillColor = compoundPath.fillColor;
|
||||||
|
cw.strokeColor = compoundPath.strokeColor;
|
||||||
|
cw.strokeWidth = compoundPath.strokeWidth;
|
||||||
|
cw.insertAbove(compoundPath);
|
||||||
|
|
||||||
|
// Go backward since we are deleting elements
|
||||||
|
let newCw = cw;
|
||||||
|
for (let k = ccwChildren.length - 1; k >= 0; k--) {
|
||||||
|
const ccw = ccwChildren[k];
|
||||||
|
if (this.firstEnclosesSecond(cw, ccw)) {
|
||||||
|
const temp = newCw.subtract(ccw);
|
||||||
|
temp.insertAbove(compoundPath);
|
||||||
|
newCw.remove();
|
||||||
|
newCw = temp;
|
||||||
|
ccw.remove();
|
||||||
|
ccwChildren.splice(k, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
colorMatch (existingPath, addedPath) {
|
colorMatch (existingPath, addedPath) {
|
||||||
// Note: transparent fill colors do notdetect as touching
|
// Note: transparent fill colors do notdetect as touching
|
||||||
return existingPath.getFillColor().equals(addedPath.getFillColor()) &&
|
return existingPath.getFillColor().equals(addedPath.getFillColor()) &&
|
||||||
|
@ -388,10 +394,29 @@ class Blobbiness {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
matchesAnyChild (group, path) {
|
||||||
|
for (const child of group.children) {
|
||||||
|
if (child.children && this.matchesAnyChild(path, child)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (path === child) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
isMergeable (newPath, existingPath) {
|
isMergeable (newPath, existingPath) {
|
||||||
return existingPath instanceof paper.PathItem && // path or compound path
|
// Path or compound path
|
||||||
existingPath !== this.cursorPreview && // don't merge with the mouse preview
|
if (!(existingPath instanceof paper.PathItem)) {
|
||||||
existingPath !== newPath; // don't merge with self
|
return;
|
||||||
|
}
|
||||||
|
if (newPath.children) {
|
||||||
|
if (this.matchesAnyChild(newPath, existingPath)) { // Don't merge with children of self
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return existingPath !== newPath; // don't merge with self
|
||||||
}
|
}
|
||||||
|
|
||||||
deactivateTool () {
|
deactivateTool () {
|
||||||
|
|
Loading…
Reference in a new issue