From 0c33bc8033c9877abbe6e4074a687559bc4948d0 Mon Sep 17 00:00:00 2001 From: eleanor-park Date: Tue, 23 Apr 2024 15:16:06 -0400 Subject: erase multiple segments bug --- src/client/documents/Documents.ts | 4 +- src/client/util/CurrentUserUtils.ts | 7 +- src/client/views/InkingStroke.tsx | 110 +++++++++++--- src/client/views/MainView.tsx | 3 + .../collectionFreeForm/CollectionFreeFormView.tsx | 167 ++++++++++++++------- src/client/views/global/globalScripts.ts | 19 ++- 6 files changed, 226 insertions(+), 84 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index b160379df..61a58caaa 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -26,7 +26,7 @@ import { ScriptingGlobals } from '../util/ScriptingGlobals'; import { UndoManager, undoable } from '../util/UndoManager'; import { ContextMenu } from '../views/ContextMenu'; import { ContextMenuProps } from '../views/ContextMenuItem'; -import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke } from '../views/InkingStroke'; +import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveEraserWidth, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveEraserWidth, ActiveIsInkMask, InkingStroke } from '../views/InkingStroke'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { CollectionView } from '../views/collections/CollectionView'; import { DimUnit } from '../views/collections/collectionMulticolumn/CollectionMulticolumnView'; @@ -1123,6 +1123,7 @@ export namespace Docs { points: PointData[], options: DocumentOptions = {}, strokeWidth = ActiveInkWidth(), + eraserWidth = ActiveEraserWidth(), color = ActiveInkColor(), stroke_bezier = ActiveInkBezierApprox(), fillColor = ActiveFillColor(), @@ -1138,6 +1139,7 @@ export namespace Docs { I.fillColor = fillColor; I.stroke = new InkField(points); I.stroke_width = strokeWidth; + I.eraser_width = eraserWidth; I.stroke_bezier = stroke_bezier; I.stroke_startMarker = arrowStart; I.stroke_endMarker = arrowEnd; diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 031b79b25..59fc30635 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -34,6 +34,7 @@ import { SnappingManager } from "./SnappingManager"; import { UndoManager } from "./UndoManager"; import { LabelBox } from "../views/nodes/LabelBox"; import { ImageBox } from "../views/nodes/ImageBox"; +import { PiEraser } from "react-icons/pi"; interface Button { // DocumentOptions fields a button can set @@ -756,9 +757,8 @@ pie title Minerals in my tap water { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.MultiToggleButton, toolType:"eraser", scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'}, subMenu: [ { title: "Stroke", toolTip: "Stroke Erase", btnType: ButtonType.ToggleButton, icon: "eraser", toolType:"strokeeraser", ignoreClick: true, scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'} }, - { title: "Segment", toolTip: "Segment Erase", btnType: ButtonType.ToggleButton, icon: "minus", toolType:"segmenteraser",ignoreClick: true, scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'} }, - { title: "Radius", toolTip: "Radius Erase", btnType: ButtonType.ToggleButton, icon: "circle", toolType:"radiuseraser", ignoreClick: true, scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'} }, - // { title: "Width", toolTip: "Eraser Width", btnType: ButtonType.NumberSliderButton, toolType:"strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, numBtnMin: 1}, + { title: "Segment", toolTip: "Segment Erase", btnType: ButtonType.ToggleButton, icon: "xmarks-lines", toolType:"segmenteraser",ignoreClick: true, scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'} }, + { title: "Radius", toolTip: "Radius Erase", btnType: ButtonType.ToggleButton, icon: "circle-xmark", toolType:"radiuseraser", ignoreClick: true, scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'} }, ]}, { title: "Circle", toolTip: "Circle (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "circle", toolType:GestureUtils.Gestures.Circle, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} }, { title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square", toolType:GestureUtils.Gestures.Rectangle, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} }, @@ -766,6 +766,7 @@ pie title Minerals in my tap water { title: "Mask", toolTip: "Mask", btnType: ButtonType.ToggleButton, icon: "user-circle",toolType: "inkMask", scripts: {onClick:'{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"IsNoviceMode()" } }, { title: "Labels", toolTip: "Lab els", btnType: ButtonType.ToggleButton, icon: "text-width", toolType: "labels", scripts: {onClick:'{ return setInkProperty(this.toolType, value, _readOnly_);}'}, }, { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberSliderButton, toolType: "strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, numBtnMin: 1}, + { title: "Eraser Width", toolTip: "Eraser Width", btnType: ButtonType.NumberSliderButton, toolType: "eraserWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, numBtnMin: 1}, { title: "Ink", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", toolType: "strokeColor", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'} }, ]; } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 1c24a4903..1ae96edfd 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -45,6 +45,7 @@ import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { PinProps, PresBox } from './nodes/trails'; import { StyleProp } from './StyleProvider'; const { INK_MASK_SIZE } = require('./global/globalCssVariables.module.scss'); // prettier-ignore + @observer export class InkingStroke extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { static readonly MaskDim = INK_MASK_SIZE; // choose a really big number to make sure mask fits over container (which in theory can be arbitrarily big) @@ -330,31 +331,86 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() ); }; - splitByEraser = (inkCoords: {X: number; Y: number}, radius: number) => { - // const ptsXscale = (NumCast(radius) - NumCast(radius)) / (oldXrange.max - oldXrange.min || 1) || 1; - // const ptsYscale = (NumCast(doc._height) - NumCast(doc.stroke_width)) / (oldYrange.max - oldYrange.min || 1) || 1; - // const newPoints = func(this.DocumentView?.(), ink, ptsXscale, ptsYscale, NumCast(radius)); - const controlPointDistance = 0.552284749831 * radius; // (4/3) * tan(pi / 8) * radius - const points: { X: number; Y: number }[] = [ - { X: inkCoords.X + radius, Y: inkCoords.Y }, // right point - { X: inkCoords.X + radius, Y: inkCoords.Y - controlPointDistance }, // right's top ctrl point - { X: inkCoords.X + controlPointDistance, Y: inkCoords.Y - radius }, // top's right ctrl point - { X: inkCoords.X, Y: inkCoords.Y - radius }, // top - { X: inkCoords.X, Y: inkCoords.Y - radius }, // top again - { X: inkCoords.X - controlPointDistance, Y: inkCoords.Y - radius }, // top's left ctrl point - { X: inkCoords.X - radius, Y: inkCoords.Y - controlPointDistance }, // left's top ctrl point - { X: inkCoords.X - radius, Y: inkCoords.Y }, // left - { X: inkCoords.X - radius, Y: inkCoords.Y }, // left again - { X: inkCoords.X - radius, Y: inkCoords.Y + controlPointDistance }, // left's bottom ctrl point - { X: inkCoords.X - controlPointDistance, Y: inkCoords.Y + radius }, // bottom's left ctrl point - { X: inkCoords.X, Y: inkCoords.Y + radius }, // bottom - { X: inkCoords.X, Y: inkCoords.Y + radius }, // bottom again - { X: inkCoords.X + controlPointDistance, Y: inkCoords.Y + radius }, // bottom's right ctrl point - { X: inkCoords.X + radius, Y: inkCoords.Y + controlPointDistance }, // right's bottom ctrl point - { X: inkCoords.X + radius, Y: inkCoords.Y }, // right again - ]; + coordWithSlope = (distance: number, slope: number) => { + return Math.sqrt((distance * distance) / (1 + slope * slope)) + } + + + splitByEraser = (startInkCoords: {X: number; Y: number}, inkCoords: {X: number; Y: number}) => { + + const radius = ActiveEraserWidth() / 2 + 3; // reduce values to avoid extreme radii + console.log("radius", radius); + const ctrlPtDist = 0.552284749831 * radius; // (4/3) * tan(pi / 8) * radius + + var perpSlope = (inkCoords.Y - startInkCoords.Y) / (inkCoords.X - startInkCoords.X); + if (perpSlope > 500) { + perpSlope = 500; // avoid ridiculously high/infinity slopes + } else if (perpSlope < -500) { + perpSlope = -500 + } else if (perpSlope === 0) { + perpSlope = 0.002 + } + const slope = - 1 / perpSlope + console.log("slope", slope); + var points: { X: number; Y: number }[] = [] + if (startInkCoords.X > inkCoords.X) { + points = [ + { X: startInkCoords.X, Y: startInkCoords.Y }, + { X: startInkCoords.X, Y: startInkCoords.Y }, + // { X: startInkCoords.X + this.coordWithSlope(ctrlPtDist, slope), Y: startInkCoords.Y + slope * this.coordWithSlope(ctrlPtDist, slope)}, + + { X: inkCoords.X + this.coordWithSlope(radius, slope) + this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) + perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) }, + { X: inkCoords.X + this.coordWithSlope(radius, slope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) }, + { X: inkCoords.X + this.coordWithSlope(radius, slope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) }, + { X: inkCoords.X + this.coordWithSlope(radius, slope) - this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) - perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) }, + + // { X: inkCoords.X - this.coordWithSlope(radius, perpSlope) + this.coordWithSlope(ctrlPtDist, slope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) - perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) }, + { X: inkCoords.X - this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) }, + { X: inkCoords.X - this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) }, + { X: inkCoords.X - this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) }, + { X: inkCoords.X - this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) }, + // { X: inkCoords.X - this.coordWithSlope(radius, perpSlope) - this.coordWithSlope(ctrlPtDist, slope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) + perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) }, + + { X: inkCoords.X - this.coordWithSlope(radius, slope) - this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) - perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) }, + { X: inkCoords.X - this.coordWithSlope(radius, slope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) }, + { X: inkCoords.X - this.coordWithSlope(radius, slope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) }, + { X: inkCoords.X - this.coordWithSlope(radius, slope) + this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) + perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) }, + + // { X: startInkCoords.X - this.coordWithSlope(ctrlPtDist, slope), Y: startInkCoords.Y - slope * this.coordWithSlope(ctrlPtDist, slope) }, + { X: startInkCoords.X, Y: startInkCoords.Y }, + { X: startInkCoords.X, Y: startInkCoords.Y }, + ]; + } else { + points = [ + { X: startInkCoords.X, Y: startInkCoords.Y }, + { X: startInkCoords.X, Y: startInkCoords.Y }, + // { X: startInkCoords.X + this.coordWithSlope(ctrlPtDist, slope), Y: startInkCoords.Y + slope * this.coordWithSlope(ctrlPtDist, slope)}, + + { X: inkCoords.X + this.coordWithSlope(radius, slope) - this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) - perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) }, + { X: inkCoords.X + this.coordWithSlope(radius, slope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) }, + { X: inkCoords.X + this.coordWithSlope(radius, slope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) }, + { X: inkCoords.X + this.coordWithSlope(radius, slope) + this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) + perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) }, + + // { X: inkCoords.X - this.coordWithSlope(radius, perpSlope) + this.coordWithSlope(ctrlPtDist, slope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) - perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) }, + { X: inkCoords.X + this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y + perpSlope * this.coordWithSlope(radius, perpSlope) }, + { X: inkCoords.X + this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y + perpSlope * this.coordWithSlope(radius, perpSlope) }, + { X: inkCoords.X + this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y + perpSlope * this.coordWithSlope(radius, perpSlope) }, + { X: inkCoords.X + this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y + perpSlope * this.coordWithSlope(radius, perpSlope) }, + // { X: inkCoords.X - this.coordWithSlope(radius, perpSlope) - this.coordWithSlope(ctrlPtDist, slope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) + perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) }, + + { X: inkCoords.X - this.coordWithSlope(radius, slope) + this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) + perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) }, + { X: inkCoords.X - this.coordWithSlope(radius, slope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) }, + { X: inkCoords.X - this.coordWithSlope(radius, slope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) }, + { X: inkCoords.X - this.coordWithSlope(radius, slope) - this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) - perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) }, + + // { X: startInkCoords.X - this.coordWithSlope(ctrlPtDist, slope), Y: startInkCoords.Y - slope * this.coordWithSlope(ctrlPtDist, slope) }, + { X: startInkCoords.X, Y: startInkCoords.Y }, + { X: startInkCoords.X, Y: startInkCoords.Y }, + ]; + } + const eraserCircle = new InkField(points); - return points; + return eraserCircle; } _subContentView: ViewBoxInterface | undefined; @@ -533,6 +589,9 @@ export function SetActiveArrowScale(value: number) { export function SetActiveDash(dash: string): void { !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash); } +export function SetEraserWidth(radius: string): void { + !isNaN(parseInt(radius)) && ActiveInkPen() && (ActiveInkPen().eraserWidth = radius); +} export function ActiveInkPen(): Doc { return Doc.UserDoc(); } @@ -566,3 +625,6 @@ export function ActiveInkWidth(): number { export function ActiveInkBezierApprox(): string { return StrCast(ActiveInkPen()?.activeInkBezier); } +export function ActiveEraserWidth(): number { + return Number(ActiveInkPen()?.eraserWidth); +} \ No newline at end of file diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 58b8d255a..56db0c488 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -358,6 +358,9 @@ export class MainView extends ObservableReactComponent<{}> { fa.faCut, fa.faEllipsisV, fa.faEraser, + fa.faDeleteLeft, + fa.faXmarksLines, + fa.faCircleXmark, fa.faExclamation, fa.faFileAlt, fa.faFileAudio, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 60f7662ff..78dae87c3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -749,10 +749,7 @@ export class CollectionFreeFormView extends CollectionSubView this.forceStrokeGesture( e, @@ -763,7 +760,7 @@ export class CollectionFreeFormView extends CollectionSubView this._eraserLock--); } // Lower ink opacity to give the user a visual indicator of deletion. - intersect.inkView.layoutDoc.opacity = 0.0; + intersect.inkView.layoutDoc.opacity = 0.2; intersect.inkView.layoutDoc.dontIntersect = true; } }); @@ -831,63 +828,86 @@ export class CollectionFreeFormView extends CollectionSubView { + radiusErase = (ink: DocumentView, startPt: { X: number; Y: number }, screenEraserPt: { X: number; Y: number }): Segment[] => { const segments: Segment[] = []; + const startInkCoords = ink.ComponentView?.ptFromScreen?.(startPt); const inkCoords = ink.ComponentView?.ptFromScreen?.(screenEraserPt); // coordinates in ink space if (!inkCoords) return []; - var segment1: Segment = []; - var segment2: Segment = []; - const eraseRadius = ActiveInkWidth() / 2; + var eraseSegment: Segment = []; // for eraser visualization const inkStroke = ink?.ComponentView as InkingStroke; - const { inkData } = inkStroke.inkScaledData(); - - const eraserInkData = inkStroke.splitByEraser(inkCoords, eraseRadius); - const tVals: number[] = []; // should be the tvals of the intersections + const eraserStroke: InkData = inkStroke.splitByEraser(startInkCoords, inkCoords).inkData; + const strokeToTVals: Map = new Map(); + for (var i = 0; i < eraserStroke.length - 3; i +=4) { + eraseSegment.push(InkField.Segment(eraserStroke, i)); // for eraser visualization + this.getOtherInkIntersections(i, eraserStroke, strokeToTVals); + } + strokeToTVals.forEach((tVals, inkStroke) => { + var segment1: Segment = []; + var segment2: Segment = []; + const { inkData } = inkStroke.inkScaledData(); + tVals.sort(); + console.log('TVALS', inkStroke, tVals); - for (var i = 0; i < eraserInkData.length - 3; i += 4) { - const eraserBezier: Bezier = InkField.Segment(eraserInkData, i); - segment1.push(eraserBezier); - for (var j = 0; j < inkData.length; j += 4) { - const inkSegment: Bezier = InkField.Segment(inkData, i); - // this.bintersects(inkSegment, eraserBezier).forEach((val: string | number, i: number) => { - // // Converting the Bezier.js Split type to a t-value number. - // const t = +val.toString().split('/')[0]; - // if (i % 2 === 0 && !tVals.includes(t)) tVals.push(t); // bcz: Hack! don't know why but intersection points are doubled from bezier.js (but not identical). - // }); + var hasSplit = false; + var continueErasing = false; + + // below is curve splitting logic + if (tVals.length) { + for (var i = 0; i < inkData.length - 3; i += 4) { + const inkSegment: Bezier = InkField.Segment(inkData, i); + const currCurveT = Math.floor(i / 4); + + if (tVals.length === 2) { + if (tVals[0] > currCurveT && tVals[0] < currCurveT + 1) { + segment1.push(inkSegment.split(0, tVals[0] - currCurveT)); + continueErasing = true; + if (tVals[1] > currCurveT && tVals[1] < currCurveT + 1) { + segment2.push(inkSegment.split(tVals[1] - currCurveT, 1)); + continueErasing = false; + hasSplit = true; + } + } else if (tVals[1] > currCurveT && tVals[1] < currCurveT + 1) { + segment2.push(inkSegment.split(tVals[1] - currCurveT, 1)); + continueErasing = false; + hasSplit = true; + } else if (!continueErasing) { + if (hasSplit) { + segment2.push(inkSegment); + } else { + segment1.push(inkSegment); + } + } + } else if (tVals.length === 1) { + if (tVals[0] > currCurveT && tVals[0] < currCurveT + 1) { + if (tVals[0] < Math.floor(inkData.length / 4) - tVals[0]) { + // if it's on the first end + segment1.push(inkSegment.split(tVals[0] - currCurveT, 1)); + hasSplit = true; + } else { + segment1.push(inkSegment.split(0, tVals[0] - currCurveT)); + hasSplit = true; + } + } else { + if (tVals[0] < Math.floor(inkData.length / 4) - tVals[0] && hasSplit) { + segment1.push(inkSegment); + } else if (tVals[0] >= Math.floor(inkData.length / 4) - tVals[0] && !hasSplit) { + segment1.push(inkSegment); + } + } + } + } } - } - // segment1.push(eraserBezier); - - // for (var i = 0; i < inkData.length - 3; i += 4) { - // const currCurveT = Math.floor(i/4); - // const inkSegment: Bezier = InkField.Segment(inkData, i); - // if (tVals[0] >= currCurveT && tVals[0] < currCurveT+1) { - // tVals.shift() - // i -= 4; - // 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); - // } - // } + 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); + } + }); - // 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); - } + segments.push(eraseSegment); // for eraser visualization return segments; }; @@ -1114,6 +1134,47 @@ export class CollectionFreeFormView extends CollectionSubView): Map => { + // const tVals: [InkingStroke, number[]] = []; + // Iterating through all ink strokes in the current freeform collection. + this.childDocs + .filter(doc => doc.type === DocumentType.INK && !doc.dontIntersect) + .forEach(doc => { + // InkingStroke of other ink strokes + const otherInk = DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())?.ComponentView as InkingStroke; + // ink Data of other ink strokes + const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] }; + for (var j = 0; j < otherInkData.length - 3; j += 4) { + const curve: Bezier = InkField.Segment(points, i); // eraser curve + const otherCurve: Bezier = InkField.Segment(otherInkData, j); // other curve + this.bintersects(otherCurve, curve).forEach((val: string | number, k: number) => { + // Converting the Bezier.js Split type to a t-value number. + const t = +val.toString().split('/')[0]; + if (k % 2 === 0) { + // here, add to the map + const inkList = strokeToTVals.get(otherInk); + if (inkList !== undefined) { + const inList = inkList.some(val => Math.abs(val - (t + Math.floor(j / 4))) <= 0.01); + if (!inList) { + inkList.push(t + Math.floor(j/4)); + } + } else { + strokeToTVals.set(otherInk, [t + Math.floor(j/4)]); + } + } + }); + } + }); + return strokeToTVals; + }; + @action zoom = (pointX: number, pointY: number, deltaY: number): void => { if (this.Document.isGroup || this.Document[(this._props.viewField ?? '_') + 'freeform_noZoom']) return; diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 2a5732708..279d3c24c 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -12,7 +12,7 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SelectionManager } from '../../util/SelectionManager'; import { UndoManager, undoable } from '../../util/UndoManager'; import { GestureOverlay } from '../GestureOverlay'; -import { ActiveFillColor, ActiveInkColor, ActiveInkHideTextLabels, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveFillColor, SetActiveInkColor, SetActiveInkHideTextLabels, SetActiveInkWidth, SetActiveIsInkMask } from '../InkingStroke'; +import { ActiveFillColor, ActiveInkColor, ActiveInkHideTextLabels, ActiveInkWidth, ActiveIsInkMask, ActiveEraserWidth, InkingStroke, SetActiveFillColor, SetActiveInkColor, SetActiveInkHideTextLabels, SetActiveInkWidth, SetActiveIsInkMask, SetEraserWidth } from '../InkingStroke'; import { CollectionFreeFormView } from '../collections/collectionFreeForm'; // import { InkTranscription } from '../InkTranscription'; import { DocData } from '../../../fields/DocSymbols'; @@ -338,11 +338,19 @@ function setActiveTool(tool: InkTool | GestureUtils.Gestures, keepPrim: boolean, ScriptingGlobals.add(setActiveTool, 'sets the active ink tool mode'); +// ScriptingGlobals.add(function setEraserProperty(option: 'eraseWidth', value: any, checkResult?: boolean) { +// setInk: (doc: Doc) => (doc[DocData].eraserWidth = NumCast(value)) +// InkingStroke.setEraserRadius(NumCast(value)); +// }) + // toggle: Set overlay status of selected document -ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor', value: any, checkResult?: boolean) { +ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor' | 'eraserWidth', value: any, checkResult?: boolean) { const selected = SelectionManager.Docs.lastElement() ?? Doc.UserDoc(); + if (option === 'eraserWidth') { + console.log('eraserWidth', value) + } // prettier-ignore - const map: Map<'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor', { checkResult: () => any; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([ + const map: Map<'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor' | 'eraserWidth', { checkResult: () => any; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([ ['inkMask', { checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected[DocData].stroke_isInkMask) : ActiveIsInkMask())), setInk: (doc: Doc) => (doc[DocData].stroke_isInkMask = !doc.stroke_isInkMask), @@ -368,6 +376,11 @@ ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'labels' | 'fil setInk: (doc: Doc) => (doc[DocData].color = String(value)), setMode: () => { SetActiveInkColor(StrCast(value)); selected?.type === DocumentType.INK && setActiveTool(GestureOverlay.Instance.InkShape ?? InkTool.Pen, true, false);}, }], + [ 'eraserWidth', { + checkResult: () => (selected?._layout_isSvg ? NumCast(selected[DocData].eraser_width) : ActiveEraserWidth()), + setInk: (doc: Doc) => (doc[DocData].eraserWidth = NumCast(value)), + setMode: () => { SetEraserWidth(value.toString());}, + }] ]); if (checkResult) { -- cgit v1.2.3-70-g09d2