From ba58b46b55527c23cd23b34c2ca13be945c4bf4e Mon Sep 17 00:00:00 2001
From: eleanor-park <eleanor_park@brown.edu>
Date: Sun, 7 Apr 2024 13:35:40 -0400
Subject: radius erase changes

---
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 165 ++++++++++-----------
 1 file changed, 82 insertions(+), 83 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 18b75d8ff..da4c53d66 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -610,10 +610,21 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 // group freeforms don't pan when dragged -- instead let the event go through to allow the group itself to drag
                 // prettier-ignore
                 switch (Doc.ActiveTool) {
-                    case InkTool.Highlighter: break;
-                    case InkTool.Write: break;
-                    case InkTool.Pen: break; // the GestureOverlay handles ink stroke input -- either as gestures, or drying as ink strokes that are added to document views
-                    case InkTool.Eraser:
+                    case InkTool.Highlighter:
+                        break;
+                    case InkTool.Write:
+                        break;
+                    case InkTool.Pen:
+                        break; // the GestureOverlay handles ink stroke input -- either as gestures, or drying as ink strokes that are added to document views
+                    case InkTool.StrokeEraser:
+                        this._batch = UndoManager.StartBatch('collectionErase');
+                        setupMoveUpEvents(this, e, this.onEraserMove, this.onEraserUp, emptyFunction);
+                        break;
+                    case InkTool.SegmentEraser:
+                        this._batch = UndoManager.StartBatch('collectionErase');
+                        setupMoveUpEvents(this, e, this.onEraserMove, this.onEraserUp, emptyFunction);
+                        break;
+                    case InkTool.RadiusEraser:
                         this._batch = UndoManager.StartBatch('collectionErase');
                         setupMoveUpEvents(this, e, this.onEraserMove, this.onEraserUp, emptyFunction);
                         break;
@@ -738,28 +749,19 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 SetActiveInkWidth(StrCast(intersect.inkView.Document.stroke_width?.toString()) || '1');
                 SetActiveInkColor(StrCast(intersect.inkView.Document.color?.toString()) || 'black');
                 // create a new curve by appending all curves of the current segment together in order to render a single new stroke.
-                if (!e.shiftKey) {
+                if (Doc.ActiveTool !== InkTool.StrokeEraser) {
                     this._eraserLock++;
-                    const segments = this.segmentInkStroke(intersect.inkView, intersect.t); // intersect.t is where the eraser intersected the ink stroke - want to remove the segment that starts at the intersection just before this t value and goes to the one just after it
-                    // we delete the original ink stroke, then create new strokes for each of the remaining segments
-                    // we do this through the hack of calling the stroke Gesture code as if the strokes had just be drawn by hand
-                    // [[(0,0), (3,7), (9,4), (4,5)],[(4,5), (13,17), (19,14), (14,15)],       [(23,19),(...}]]
-                    // [[(0,0), (3,7), (9,4), (4,5), (13,17), (19,14), (14,15)],       [(23,19),(...}]]
-                    // segments.map(segment => segment.map(pt => pt))
-                    // segments[0][3].x === segments[1][0].x
-
-                    //   3 == "3"   true
-                    //   3 === "3" falsen   !==
-
-                    // for (var i = 0; i < segments.length; i ++) {
-                    //     if (segments[i][0].points.lastElement().x === segments[i+1][0].points.lastElement().x && segments[i][0].points.lastElement().y === segments[i+1][0].points.lastElement().y) {
-                    //         segments[i][0].points.pop();
-                    //         segments[i][0].points = segments[i][0].points.concat(segments[i+1][0].points);
-                    //         segments.splice(i+1, 1);
-                    //     }
-                    //     i++;
+                    var segments;
+                    if (Doc.ActiveTool === InkTool.SegmentEraser) {
+                        segments = this.segmentErase(intersect.inkView, intersect.t); // intersect.t is where the eraser intersected the ink stroke - want to remove the segment that starts at the intersection just before this t value and goes to the one just after it
+                    } else if (Doc.ActiveTool === InkTool.RadiusEraser) {
+                        console.log("RADIUS");
+                        segments = this.radiusErase(intersect.inkView, intersect.t);
+                    }
+                        // } else if (Doc.ActiveTool === InkTool.RadiusEraser) {
+                    //     segments = undefined;
                     // }
-                    segments.forEach(segment =>
+                    segments?.forEach(segment =>
                         this.forceStrokeGesture(
                             e,
                             GestureUtils.Gestures.Stroke,
@@ -837,6 +839,42 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             );
     };
 
+    @action
+    radiusErase = (ink: DocumentView, eraseT: number): Segment[] => {
+        const segments: Segment[] = [];
+        var segment1: Segment = [];
+        var segment2: Segment = [];
+        const eraseWidth = ActiveInkWidth() / 100;
+        const { inkData } = (ink?.ComponentView as InkingStroke).inkScaledData();
+        for (var i = 0; i < inkData.length - 3; i += 4) {
+            const currCurveT = Math.floor(i/4);
+            const inkSegment: Bezier = InkField.Segment(inkData, i);
+            if (eraseT >= currCurveT && eraseT < currCurveT+1) {
+                if (eraseT - eraseWidth > currCurveT && eraseT + eraseWidth < currCurveT + 1) {
+                    segment1.push(inkSegment.split(0, eraseT - currCurveT - eraseWidth));
+                    segment2.push(inkSegment.split(eraseT - currCurveT + eraseWidth, 1));
+                } else if (eraseT - eraseWidth < currCurveT) {
+                    segment2.push(inkSegment.split(eraseT - currCurveT + eraseWidth, 1));
+                } else if (eraseT + eraseWidth > currCurveT + 1) {
+                    segment1.push(inkSegment.split(0, eraseT - currCurveT - eraseWidth));
+                }
+            } else if (eraseT > currCurveT + 1) {
+                segment1.push(inkSegment);
+            } else {
+                segment2.push(inkSegment);
+            }
+        }
+
+        // push 1 or both segments if they are not empty
+        if (segment1.length && (Math.abs(segment1[0].points[0].x - segment1[0].points.lastElement().x) > 0.5 || Math.abs(segment1[0].points[0].y - segment1[0].points.lastElement().y) > 0.5)) {
+            segments.push(segment1);
+        }
+        if (segment2.length && (Math.abs(segment2[0].points[0].x - segment2[0].points.lastElement().x) > 0.5 || Math.abs(segment2[0].points[0].y - segment2[0].points.lastElement().y) > 0.5)) {
+            segments.push(segment2);
+        }
+        return segments;
+    }
+
     /**
      * Erases ink strokes by segments. Locates intersections of the current ink stroke with all other ink strokes (including itself),
      * then erases the segment that was intersected by the eraser. This is done by creating either 1 or two resulting segments
@@ -846,7 +884,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
      * @returns The ink stroke represented as a list of segments, excluding the segment in which the eraser intersection occurred.
      */
     @action
-    segmentInkStroke = (ink: DocumentView, excludeT: number): Segment[] => {
+    segmentErase = (ink: DocumentView, excludeT: number): Segment[] => {
 
         const segments: Segment[] = [];
         var segment1: Segment = [];
@@ -873,8 +911,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         var isClosedCurve = false;
         if (intersections[0] === 0) {
             isClosedCurve = true;
-            intersections = intersections.slice(1, intersections.length ); // take the 0 intersection out
-            segmentIndexes = segmentIndexes.slice(1, segmentIndexes.length); // same for indexes
+
+            // now reduce intersections list to the actual intersections because closed curves have additional ones with itself
+            const indices = intersections
+                .map((value, index) => value > 0.0001 && value < Math.floor(inkData.length / 4) ? index : -1)
+                .filter(index => index !== -1);
+
+            // Filter intersections and segmentIndexes based on validIndices
+            intersections = indices.map(index => intersections[index]);
+            segmentIndexes = indices.map(index => segmentIndexes[index]);
+            // intersections = intersections.slice(1, intersections.length ); // take the 0 intersection out
+            // segmentIndexes = segmentIndexes.slice(1, segmentIndexes.length); // same for indexes
         }
 
         if (intersections.length) {
@@ -938,13 +985,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                         }
                     }
                 } else { // case where right end is erased
-                    if (currCurveT === splitSegment1) {
-                        segment1.push(inkSegment.split(0, intersections[closestTs[0]] - currCurveT));
-                        hasSplit = true;
-                    } else if (isClosedCurve && currCurveT === segmentIndexes[1]) {
+                    if (currCurveT === segmentIndexes[0] && isClosedCurve) {
                         segment1.push(inkSegment.split(intersections[0] - currCurveT, 1));
+                        hasSplit = true;
+                    } else if (currCurveT === splitSegment1) {
+                        segment1.push(inkSegment.split(0, intersections[closestTs[0]] - currCurveT));
+                        hasSplit = false; // although this is not technically true, we set to false so the segments after don't get added
+                    // } else if (isClosedCurve && currCurveT === segmentIndexes[1]) {
+                    //     segment1.push(inkSegment.split(intersections[0] - currCurveT, 1));
                     } else {
-                        if (!hasSplit && !isClosedCurve) {
+                        if ((isClosedCurve && hasSplit) || (!isClosedCurve && !hasSplit)) {
                             segment1.push(inkSegment);
                         }
                     }
@@ -961,57 +1011,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         }
 
         return segments;
-
-
-        // const segments: Segment[] = [];
-        // var segment1: Segment = [];
-        // var segment2: Segment = [];
-        // var startSegmentT = 0;
-        // var hasSplit = false;
-        // const { inkData } = (ink?.ComponentView as InkingStroke).inkScaledData();
-        // // This iterates through all segments of the curve and splits them where they intersect another curve.
-        // // if 'excludeT' is specified, then any segment containing excludeT will be skipped (ie, deleted)
-        // for (var i = 0; i < inkData.length - 3; i += 4) {
-        //     const inkSegment = InkField.Segment(inkData, i);
-        //     // Getting all t-value intersections of the current curve with all other curves.
-        //     const tVals = this.getInkIntersections(i, ink, inkSegment).sort();
-        //     if (tVals.length) {
-        //         tVals.forEach((t, index) => {
-        //             const docCurveTVal = t + Math.floor(i / 4);
-        //             if (excludeT < startSegmentT || excludeT > docCurveTVal) {
-        //                 const localStartTVal = startSegmentT - Math.floor(i / 4);
-        //                 if (!hasSplit) {
-        //                     t !== (localStartTVal < 0 ? 0 : localStartTVal) && segment1.push(inkSegment.split(localStartTVal < 0 ? 0 : localStartTVal, t));
-        //                 } else {
-        //                     t !== (localStartTVal < 0 ? 0 : localStartTVal) && segment2.push(inkSegment.split(localStartTVal < 0 ? 0 : localStartTVal, t));
-        //                 }
-        //                 // if (segment.length && (Math.abs(segment[0].points[0].x - segment[0].points.lastElement().x) > 0.5 || Math.abs(segment[0].points[0].y - segment[0].points.lastElement().y) > 0.5)) segments.push(segment);
-        //             }
-        //             // start a new segment from the intersection t value
-        //             if (tVals.length - 1 === index) {
-        //                 const split = inkSegment.split(t).right;
-        //                 if (!hasSplit) {
-        //                     if (split && (Math.abs(split.points[0].x - split.points.lastElement().x) > 0.5 || Math.abs(split.points[0].y - split.points.lastElement().y) > 0.5)) segment1.push(split);
-        //                 } else {
-        //                     if (split && (Math.abs(split.points[0].x - split.points.lastElement().x) > 0.5 || Math.abs(split.points[0].y - split.points.lastElement().y) > 0.5)) segment2.push(split);
-        //                 }
-        //             }
-        //             startSegmentT = docCurveTVal;
-        //         });
-        //     } else {
-        //         if (!hasSplit) {
-        //             segment1.push(inkSegment);
-        //         } else {
-        //             segment2.push(inkSegment);
-        //         }
-        //     }
-        // }
-        // if (segment1.length && (Math.abs(segment1[0].points[0].x - segment1[0].points.lastElement().x) > 0.5 || Math.abs(segment1[0].points[0].y - segment1[0].points.lastElement().y) > 0.5)) {
-        //     segments.push(segment1);
-        // }
-        // if (segment2.length && (Math.abs(segment2[0].points[0].x - segment2[0].points.lastElement().x) > 0.5 || Math.abs(segment2[0].points[0].y - segment2[0].points.lastElement().y) > 0.5)) {
-        //     segments.push(segment2);
-        // }
     };
 
     /**
-- 
cgit v1.2.3-70-g09d2

