From c24133813f89b89832b45c75fb5d676e53cfc517 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Thu, 3 Dec 2020 16:52:24 +1100 Subject: [PATCH] Replaced fog subtraction with fog cutting --- src/components/map/Map.js | 6 +- src/components/map/MapFog.js | 41 ++++------ src/components/map/controls/FogCutToggle.js | 21 +++++ .../map/controls/FogToolSettings.js | 34 ++------ src/helpers/drawing.js | 79 ++++++++++++++----- src/icons/FogAddIcon.js | 18 ----- src/icons/FogCutOffIcon.js | 18 +++++ src/icons/FogCutOnIcon.js | 18 +++++ src/icons/FogSubtractIcon.js | 18 ----- 9 files changed, 144 insertions(+), 109 deletions(-) create mode 100644 src/components/map/controls/FogCutToggle.js delete mode 100644 src/icons/FogAddIcon.js create mode 100644 src/icons/FogCutOffIcon.js create mode 100644 src/icons/FogCutOnIcon.js delete mode 100644 src/icons/FogSubtractIcon.js 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;