diff --git a/src/components/map/Map.js b/src/components/map/Map.js
index 0d4e8e3..368fcaa 100644
--- a/src/components/map/Map.js
+++ b/src/components/map/Map.js
@@ -105,8 +105,8 @@ function Map({
onFogDraw({ type: "add", shapes: [shape] });
}
- function handleFogShapeSubtract(shape) {
- onFogDraw({ type: "subtract", shapes: [shape] });
+ function handleFogShapeCut(shape) {
+ onFogDraw({ type: "cut", shapes: [shape] });
}
function handleFogShapesRemove(shapeIds) {
@@ -327,7 +327,7 @@ function Map({
map={map}
shapes={fogShapes}
onShapeAdd={handleFogShapeAdd}
- onShapeSubtract={handleFogShapeSubtract}
+ onShapeCut={handleFogShapeCut}
onShapesRemove={handleFogShapesRemove}
onShapesEdit={handleFogShapesEdit}
active={selectedToolId === "fog"}
diff --git a/src/components/map/MapFog.js b/src/components/map/MapFog.js
index a157163..a872edd 100644
--- a/src/components/map/MapFog.js
+++ b/src/components/map/MapFog.js
@@ -26,7 +26,7 @@ function MapFog({
map,
shapes,
onShapeAdd,
- onShapeSubtract,
+ onShapeCut,
onShapesRemove,
onShapesEdit,
active,
@@ -77,7 +77,7 @@ function MapFog({
holes: [],
},
strokeWidth: 0.5,
- color: toolSettings.useFogSubtract ? "red" : "black",
+ color: toolSettings.useFogCut ? "red" : "black",
blend: false,
id: shortid.generate(),
visible: true,
@@ -113,11 +113,10 @@ function MapFog({
function handleBrushUp() {
if (toolSettings.type === "brush" && drawingShape) {
- const subtract = toolSettings.useFogSubtract;
-
+ const cut = toolSettings.useFogCut;
if (drawingShape.data.points.length > 1) {
let shapeData = {};
- if (subtract) {
+ if (cut) {
shapeData = { id: drawingShape.id, type: drawingShape.type };
} else {
shapeData = { ...drawingShape, color: "black" };
@@ -134,8 +133,8 @@ function MapFog({
),
},
};
- if (subtract) {
- onShapeSubtract(shape);
+ if (cut) {
+ onShapeCut(shape);
} else {
onShapeAdd(shape);
}
@@ -168,7 +167,7 @@ function MapFog({
holes: [],
},
strokeWidth: 0.5,
- color: toolSettings.useFogSubtract ? "red" : "black",
+ color: toolSettings.useFogCut ? "red" : "black",
blend: false,
id: shortid.generate(),
visible: true,
@@ -215,14 +214,14 @@ function MapFog({
});
const finishDrawingPolygon = useCallback(() => {
- const subtract = toolSettings.useFogSubtract;
+ const cut = toolSettings.useFogCut;
const data = {
...drawingShape.data,
// Remove the last point as it hasn't been placed yet
points: drawingShape.data.points.slice(0, -1),
};
- if (subtract) {
- onShapeSubtract({
+ if (cut) {
+ onShapeCut({
id: drawingShape.id,
type: drawingShape.type,
data: data,
@@ -232,7 +231,7 @@ function MapFog({
}
setDrawingShape(null);
- }, [toolSettings, drawingShape, onShapeSubtract, onShapeAdd]);
+ }, [toolSettings, drawingShape, onShapeCut, onShapeAdd]);
// Add keyboard shortcuts
function handleKeyDown({ key }) {
@@ -242,30 +241,22 @@ function MapFog({
if (key === "Escape" && drawingShape) {
setDrawingShape(null);
}
- if (key === "Alt" && drawingShape) {
- updateShapeColor();
- }
}
- function handleKeyUp({ key }) {
- if (key === "Alt" && drawingShape) {
- updateShapeColor();
- }
- }
+ useKeyboard(handleKeyDown);
- function updateShapeColor() {
+ // Update shape color when useFogCut changes
+ useEffect(() => {
setDrawingShape((prevShape) => {
if (!prevShape) {
return;
}
return {
...prevShape,
- color: toolSettings.useFogSubtract ? "black" : "red",
+ color: toolSettings.useFogCut ? "red" : "black",
};
});
- }
-
- useKeyboard(handleKeyDown, handleKeyUp);
+ }, [toolSettings.useFogCut]);
function eraseHoveredShapes() {
// Erase
diff --git a/src/components/map/controls/FogCutToggle.js b/src/components/map/controls/FogCutToggle.js
new file mode 100644
index 0000000..34c3726
--- /dev/null
+++ b/src/components/map/controls/FogCutToggle.js
@@ -0,0 +1,21 @@
+import React from "react";
+import { IconButton } from "theme-ui";
+
+import CutOnIcon from "../../../icons/FogCutOnIcon";
+import CutOffIcon from "../../../icons/FogCutOffIcon";
+
+function FogCutToggle({ useFogCut, onFogCutChange }) {
+ return (
+ onFogCutChange(!useFogCut)}
+ >
+ {useFogCut ? : }
+
+ );
+}
+
+export default FogCutToggle;
diff --git a/src/components/map/controls/FogToolSettings.js b/src/components/map/controls/FogToolSettings.js
index 3ee8a28..9176dc9 100644
--- a/src/components/map/controls/FogToolSettings.js
+++ b/src/components/map/controls/FogToolSettings.js
@@ -6,13 +6,12 @@ import RadioIconButton from "../../RadioIconButton";
import EdgeSnappingToggle from "./EdgeSnappingToggle";
import FogPreviewToggle from "./FogPreviewToggle";
+import FogCutToggle from "./FogCutToggle";
import FogBrushIcon from "../../../icons/FogBrushIcon";
import FogPolygonIcon from "../../../icons/FogPolygonIcon";
import FogRemoveIcon from "../../../icons/FogRemoveIcon";
import FogToggleIcon from "../../../icons/FogToggleIcon";
-import FogAddIcon from "../../../icons/FogAddIcon";
-import FogSubtractIcon from "../../../icons/FogSubtractIcon";
import UndoButton from "./UndoButton";
import RedoButton from "./RedoButton";
@@ -31,7 +30,7 @@ function BrushToolSettings({
// Keyboard shortcuts
function handleKeyDown({ key, ctrlKey, metaKey, shiftKey }) {
if (key === "Alt") {
- onSettingChange({ useFogSubtract: !settings.useFogSubtract });
+ onSettingChange({ useFogCut: !settings.useFogCut });
} else if (key === "p") {
onSettingChange({ type: "polygon" });
} else if (key === "b") {
@@ -44,6 +43,8 @@ function BrushToolSettings({
onSettingChange({ useEdgeSnapping: !settings.useEdgeSnapping });
} else if (key === "f") {
onSettingChange({ preview: !settings.preview });
+ } else if (key === "c") {
+ onSettingChange({ useFogCut: !settings.useFogCut });
} else if (
(key === "z" || key === "Z") &&
(ctrlKey || metaKey) &&
@@ -63,7 +64,7 @@ function BrushToolSettings({
function handleKeyUp({ key }) {
if (key === "Alt") {
- onSettingChange({ useFogSubtract: !settings.useFogSubtract });
+ onSettingChange({ useFogCut: !settings.useFogCut });
}
}
@@ -85,21 +86,6 @@ function BrushToolSettings({
},
];
- const modeTools = [
- {
- id: "add",
- title: "Add Fog",
- isSelected: !settings.useFogSubtract,
- icon: ,
- },
- {
- id: "subtract",
- title: "Subtract Fog",
- isSelected: settings.useFogSubtract,
- icon: ,
- },
- ];
-
return (
-
- onSettingChange({ useFogSubtract: tool.id === "subtract" })
- }
- collapse={isSmallScreen}
+ onSettingChange({ useFogCut })}
/>
-
diff --git a/src/helpers/drawing.js b/src/helpers/drawing.js
index 8ab54bf..8dca66b 100644
--- a/src/helpers/drawing.js
+++ b/src/helpers/drawing.js
@@ -228,28 +228,69 @@ export function drawActionsToShapes(actions, actionIndex) {
);
let shapeGeom = [[shapePoints, ...shapeHoles]];
const difference = polygonClipping.difference(shapeGeom, actionGeom);
- for (let i = 0; i < difference.length; i++) {
- let newId = difference.length > 1 ? `${shape.id}-${i}` : shape.id;
- // Holes detected
- let holes = [];
- if (difference[i].length > 1) {
- for (let j = 1; j < difference[i].length; j++) {
- holes.push(difference[i][j].map(([x, y]) => ({ x, y })));
- }
- }
-
- subtractedShapes[newId] = {
- ...shape,
- id: newId,
- data: {
- points: difference[i][0].map(([x, y]) => ({ x, y })),
- holes,
- },
- };
- }
+ addPolygonDifferenceToShapes(shape, difference, subtractedShapes);
}
shapesById = subtractedShapes;
}
+ if (action.type === "cut") {
+ const actionGeom = action.shapes.map((actionShape) => [
+ actionShape.data.points.map(({ x, y }) => [x, y]),
+ ]);
+ let cutShapes = {};
+ for (let shape of Object.values(shapesById)) {
+ const shapePoints = shape.data.points.map(({ x, y }) => [x, y]);
+ const shapeHoles = shape.data.holes.map((hole) =>
+ hole.map(({ x, y }) => [x, y])
+ );
+ let shapeGeom = [[shapePoints, ...shapeHoles]];
+ const difference = polygonClipping.difference(shapeGeom, actionGeom);
+ const intersection = polygonClipping.intersection(
+ shapeGeom,
+ actionGeom
+ );
+ addPolygonDifferenceToShapes(shape, difference, cutShapes);
+ addPolygonIntersectionToShapes(shape, intersection, cutShapes);
+ }
+ shapesById = cutShapes;
+ }
}
return Object.values(shapesById);
}
+
+function addPolygonDifferenceToShapes(shape, difference, shapes) {
+ for (let i = 0; i < difference.length; i++) {
+ let newId = `${shape.id}-dif-${i}`;
+ // Holes detected
+ let holes = [];
+ if (difference[i].length > 1) {
+ for (let j = 1; j < difference[i].length; j++) {
+ holes.push(difference[i][j].map(([x, y]) => ({ x, y })));
+ }
+ }
+
+ shapes[newId] = {
+ ...shape,
+ id: newId,
+ data: {
+ points: difference[i][0].map(([x, y]) => ({ x, y })),
+ holes,
+ },
+ };
+ }
+}
+
+function addPolygonIntersectionToShapes(shape, intersection, shapes) {
+ for (let i = 0; i < intersection.length; i++) {
+ let newId = `${shape.id}-int-${i}`;
+ shapes[newId] = {
+ ...shape,
+ id: newId,
+ data: {
+ points: intersection[i][0].map(([x, y]) => ({ x, y })),
+ holes: [],
+ },
+ // Default intersection visibility to false
+ visible: false,
+ };
+ }
+}
diff --git a/src/icons/FogAddIcon.js b/src/icons/FogAddIcon.js
deleted file mode 100644
index aa21d79..0000000
--- a/src/icons/FogAddIcon.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from "react";
-
-function FogAddIcon() {
- return (
-
- );
-}
-
-export default FogAddIcon;
diff --git a/src/icons/FogCutOffIcon.js b/src/icons/FogCutOffIcon.js
new file mode 100644
index 0000000..76ef28c
--- /dev/null
+++ b/src/icons/FogCutOffIcon.js
@@ -0,0 +1,18 @@
+import React from "react";
+
+function FogCutOffIcon() {
+ return (
+
+ );
+}
+
+export default FogCutOffIcon;
diff --git a/src/icons/FogCutOnIcon.js b/src/icons/FogCutOnIcon.js
new file mode 100644
index 0000000..fef6529
--- /dev/null
+++ b/src/icons/FogCutOnIcon.js
@@ -0,0 +1,18 @@
+import React from "react";
+
+function FogCutOnIcon() {
+ return (
+
+ );
+}
+
+export default FogCutOnIcon;
diff --git a/src/icons/FogSubtractIcon.js b/src/icons/FogSubtractIcon.js
deleted file mode 100644
index af6c2e6..0000000
--- a/src/icons/FogSubtractIcon.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from "react";
-
-function FogRemoveIcon() {
- return (
-
- );
-}
-
-export default FogRemoveIcon;