undo points based on order added to polygon (#11035)

This commit is contained in:
Josh Hawkins 2024-04-19 08:59:28 -05:00 committed by GitHub
parent 5f15641b1b
commit d6dfa596de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 64 additions and 51 deletions

View File

@ -61,9 +61,20 @@ export function PolygonCanvas({
const addPointToPolygon = (polygon: Polygon, newPoint: number[]) => { const addPointToPolygon = (polygon: Polygon, newPoint: number[]) => {
const points = polygon.points; const points = polygon.points;
const pointsOrder = polygon.pointsOrder;
const [newPointX, newPointY] = newPoint; const [newPointX, newPointY] = newPoint;
const updatedPoints = [...points]; const updatedPoints = [...points];
let updatedPointsOrder: number[];
if (!pointsOrder) {
updatedPointsOrder = [];
} else {
updatedPointsOrder = [...pointsOrder];
}
let insertIndex = points.length;
for (let i = 0; i < points.length; i++) { for (let i = 0; i < points.length; i++) {
const [x1, y1] = points[i]; const [x1, y1] = points[i];
const [x2, y2] = i === points.length - 1 ? points[0] : points[i + 1]; const [x2, y2] = i === points.length - 1 ? points[0] : points[i + 1];
@ -76,48 +87,16 @@ export function PolygonCanvas({
(y1 <= newPointY && newPointY <= y2) || (y1 <= newPointY && newPointY <= y2) ||
(y2 <= newPointY && newPointY <= y1) (y2 <= newPointY && newPointY <= y1)
) { ) {
const insertIndex = i + 1; insertIndex = i + 1;
updatedPoints.splice(insertIndex, 0, [newPointX, newPointY]);
break; break;
} }
} }
} }
return updatedPoints; updatedPoints.splice(insertIndex, 0, [newPointX, newPointY]);
}; updatedPointsOrder.splice(insertIndex, 0, updatedPoints.length);
const isPointNearLineSegment = ( return { updatedPoints, updatedPointsOrder };
polygon: Polygon,
mousePos: number[],
radius = 10,
) => {
const points = polygon.points;
const [x, y] = mousePos;
for (let i = 0; i < points.length; i++) {
const [x1, y1] = points[i];
const [x2, y2] = i === points.length - 1 ? points[0] : points[i + 1];
const crossProduct = (x - x1) * (x2 - x1) + (y - y1) * (y2 - y1);
if (crossProduct > 0) {
const lengthSquared = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
const dot = (x - x1) * (x2 - x1) + (y - y1) * (y2 - y1);
if (dot < 0 || dot > lengthSquared) {
continue;
}
const lineSegmentDistance = Math.abs(
((y2 - y1) * x - (x2 - x1) * y + x2 * y1 - y2 * x1) /
Math.sqrt(Math.pow(y2 - y1, 2) + Math.pow(x2 - x1, 2)),
);
if (lineSegmentDistance <= radius) {
const midPointX = (x1 + x2) / 2;
const midPointY = (y1 + y2) / 2;
return [midPointX, midPointY];
}
}
}
return null;
}; };
const isMouseOverFirstPoint = (polygon: Polygon, mousePos: number[]) => { const isMouseOverFirstPoint = (polygon: Polygon, mousePos: number[]) => {
@ -176,18 +155,15 @@ export function PolygonCanvas({
!activePolygon.isFinished && !activePolygon.isFinished &&
!isMouseOverAnyPoint(activePolygon, mousePos) !isMouseOverAnyPoint(activePolygon, mousePos)
) { ) {
let updatedPoints; const { updatedPoints, updatedPointsOrder } = addPointToPolygon(
activePolygon,
mousePos,
);
if (isPointNearLineSegment(activePolygon, mousePos)) {
// we've clicked near a line segment, so add a new point in the right position
updatedPoints = addPointToPolygon(activePolygon, mousePos);
} else {
// Add a new point to the active polygon
updatedPoints = [...activePolygon.points, mousePos];
}
updatedPolygons[activePolygonIndex] = { updatedPolygons[activePolygonIndex] = {
...activePolygon, ...activePolygon,
points: updatedPoints, points: updatedPoints,
pointsOrder: updatedPointsOrder,
}; };
setPolygons(updatedPolygons); setPolygons(updatedPolygons);
} }
@ -318,6 +294,24 @@ export function PolygonCanvas({
e.target.getStage()!.container().style.cursor = "crosshair"; e.target.getStage()!.container().style.cursor = "crosshair";
}; };
useEffect(() => {
if (activePolygonIndex === undefined || !polygons) {
return;
}
const updatedPolygons = [...polygons];
const activePolygon = updatedPolygons[activePolygonIndex];
// add default points order for already completed polygons
if (!activePolygon.pointsOrder && activePolygon.isFinished) {
updatedPolygons[activePolygonIndex] = {
...activePolygon,
pointsOrder: activePolygon.points.map((_, index) => index),
};
setPolygons(updatedPolygons);
}
}, [activePolygonIndex, polygons, setPolygons]);
return ( return (
<Stage <Stage
ref={stageRef} ref={stageRef}

View File

@ -21,12 +21,31 @@ export default function PolygonEditControls({
const updatedPolygons = [...polygons]; const updatedPolygons = [...polygons];
const activePolygon = updatedPolygons[activePolygonIndex]; const activePolygon = updatedPolygons[activePolygonIndex];
if (
activePolygon.points.length > 0 &&
activePolygon.pointsOrder &&
activePolygon.pointsOrder.length > 0
) {
const lastPointOrderIndex = activePolygon.pointsOrder.indexOf(
Math.max(...activePolygon.pointsOrder),
);
updatedPolygons[activePolygonIndex] = { updatedPolygons[activePolygonIndex] = {
...activePolygon, ...activePolygon,
points: [...activePolygon.points.slice(0, -1)], points: [
...activePolygon.points.slice(0, lastPointOrderIndex),
...activePolygon.points.slice(lastPointOrderIndex + 1),
],
pointsOrder: [
...activePolygon.pointsOrder.slice(0, lastPointOrderIndex),
...activePolygon.pointsOrder.slice(lastPointOrderIndex + 1),
],
isFinished: false, isFinished: false,
}; };
setPolygons(updatedPolygons); setPolygons(updatedPolygons);
}
}; };
const reset = () => { const reset = () => {

View File

@ -7,8 +7,8 @@ export type Polygon = {
type: PolygonType; type: PolygonType;
objects: string[]; objects: string[];
points: number[][]; points: number[][];
pointsOrder?: number[];
isFinished: boolean; isFinished: boolean;
// isUnsaved: boolean;
color: number[]; color: number[];
}; };