aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2021-11-25 21:45:06 -0500
committerbobzel <zzzman@gmail.com>2021-11-25 21:45:06 -0500
commit8405ed2e3ebaf7ba7842a5619e9b252bf5eb9c4c (patch)
treee0ab0bd3af7c77910ea36267d8238a6fb56128f0 /src
parentcc7c677399d1aafa4078741922ffcd0b81ad720f (diff)
fixed up erasing ink by segments
Diffstat (limited to 'src')
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx156
1 files changed, 65 insertions, 91 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 4aac49469..df690da49 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -34,7 +34,7 @@ import { COLLECTION_BORDER_WIDTH } from "../../../views/global/globalCssVariable
import { Timeline } from "../../animationtimeline/Timeline";
import { ContextMenu } from "../../ContextMenu";
import { DocumentDecorations } from "../../DocumentDecorations";
-import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth } from "../../InkingStroke";
+import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, InkingStroke, SetActiveInkWidth, SetActiveFillColor, SetActiveInkColor } from "../../InkingStroke";
import { LightboxView } from "../../LightboxView";
import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from "../../nodes/DocumentView";
@@ -610,11 +610,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.removeMoveListeners();
this.removeEndListeners();
if (CurrentUserUtils.SelectedTool !== InkTool.None) {
- if (this._deleteList.length > 0) {
- this._deleteList.forEach(ink => {
- ink.props.removeDocument?.(ink.props.Document);
- });
- }
+ this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.rootDoc));
this._prevPoint = this._currPoint = { X: -1, Y: -1 };
this._deleteList = [];
this._batch?.end();
@@ -650,8 +646,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if (CurrentUserUtils.SelectedTool !== InkTool.None) {
this._currPoint = { X: e.clientX, Y: e.clientY };
// Erasing ink strokes if intersections occur.
- const eraserIntersections: Intersection[] = this.getEraserIntersections();
- if (eraserIntersections) this.eraseInkStrokes(eraserIntersections);
+ this.eraseInkStrokes(this.getEraserIntersections());
}
if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) {
if (this.props.isContentActive(true)) e.stopPropagation();
@@ -676,21 +671,18 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
eraseInkStrokes = (eraserIntersections: Intersection[]) => {
eraserIntersections.forEach(intersect => {
const ink = intersect.ink;
- if (ink) {
- if (!this._deleteList.includes(ink)) {
- const segments: Segment[] = this.segmentInkStroke(ink, intersect.index ?? 0);
- segments.forEach(segment => {
- const newInkData: PointData[] = [];
- // Appending all curves of the current segment together in order to render a single new stroke.
- segment.forEach(curve => {
- newInkData.push(...curve.points.map(p => ({ X: p.x, Y: p.y })));
- });
- GestureOverlay.Instance.dispatchGesture(GestureUtils.Gestures.Stroke, newInkData);
- });
- this._deleteList.push(ink);
- // Lowering ink opacity to give the user a visual indicator of deletion.
- ink.Document.opacity = 0.5;
- }
+ if (ink && !this._deleteList.includes(ink)) {
+ this._deleteList.push(ink);
+ SetActiveInkWidth(StrCast(ink.rootDoc.strokeWidth?.toString()) || "1");
+ SetActiveInkColor(StrCast(ink.rootDoc.color?.toString()) || "black");
+ // create a new curve by appending all curves of the current segment together in order to render a single new stroke.
+ this.segmentInkStroke(ink, intersect.t ?? 0).forEach(segment =>
+ GestureOverlay.Instance.dispatchGesture(GestureUtils.Gestures.Stroke,
+ segment.reduce((data, curve) => [...data, ...curve.points
+ .map(p => ink.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })
+ ], [] as PointData[])));
+ // Lower ink opacity to give the user a visual indicator of deletion.
+ ink.layoutDoc.opacity = 0.5;
}
});
}
@@ -705,12 +697,13 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
.filter(doc => doc.type === DocumentType.INK)
.forEach(doc => {
const inkView = DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView);
- const ctrlPoints = Cast(inkView?.dataDoc[this.props.fieldKey], InkField)?.inkData ?? [];
- for (var i = 0; i < ctrlPoints.length - 3; i += 4) {
- const array = [ctrlPoints[i], ctrlPoints[i + 1], ctrlPoints[i + 2], ctrlPoints[i + 3]];
+ const inkStroke = inkView?.ComponentView as InkingStroke;
+ const { inkData } = inkStroke?.inkScaledData();
+ for (var i = 0; i < inkData.length - 3; i += 4) {
+ const array = inkData.slice(i, i + 4);
// Converting from screen space to ink space for the intersection.
- const prevPointInkSpace = inkView?.ComponentView?.ptFromScreen?.(this._prevPoint);
- const currPointInkSpace = inkView?.ComponentView?.ptFromScreen?.(this._currPoint);
+ const prevPointInkSpace = inkStroke?.ptFromScreen?.(this._prevPoint);
+ const currPointInkSpace = inkStroke?.ptFromScreen?.(this._currPoint);
if (prevPointInkSpace && currPointInkSpace) {
const curve = new Bezier(array.map(p => ({ x: p.X, y: p.Y })));
const intersects = curve.intersects({
@@ -720,7 +713,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if (inkView && intersects) {
for (const val of intersects) {
// Casting t-value from type: (string | number) to number for comparisons.
- const t = +val.toString();
+ const t = +(Number(val) + Math.floor(i / 4)).toString(); // add start of curve segment to convert from local t value to t value along complete curve
var unique: boolean = true;
// Ensuring there are no duplicate intersections in the list returned.
for (const prevIntersect of intersections) {
@@ -729,7 +722,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
break;
}
}
- if (unique) intersections.push({ t: +t.toString(), ink: inkView, curve: curve, index: i });
+ if (unique) intersections.push({ t: +t.toString(), ink: inkView, curve: curve });
}
}
}
@@ -742,57 +735,40 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
* Performs segmentation of the ink stroke - creates "segments" or subsections of the current ink stroke at points in which the
* ink stroke intersects any other ink stroke (including itself).
* @param ink The ink DocumentView intersected by the eraser.
- * @param excludeCurve The index of the curve in the ink document that the eraser intersection occurred.
+ * @param excludeT The index of the curve in the ink document that the eraser intersection occurred.
* @returns The ink stroke represented as a list of segments, excluding the segment in which the eraser intersection occurred.
*/
@action
- segmentInkStroke = (ink: DocumentView, excludeCurve: number): Segment[] => {
+ segmentInkStroke = (ink: DocumentView, excludeT: number): Segment[] => {
const segments: Segment[] = [];
var segment: Segment = [];
- var excludeSegment: boolean = false;
- const ctrlPoints = Cast(ink?.dataDoc[this.props.fieldKey], InkField)?.inkData ?? [];
- // Iterating through all of the curves of the intersected ink stroke.
- for (var i = 0; i < ctrlPoints.length - 3; i += 4) {
- // Performing "deletion" of a segment by excluding the segment in which intersection with the eraser occurred.
- if (i === excludeCurve) excludeSegment = true;
- const array = [ctrlPoints[i], ctrlPoints[i + 1], ctrlPoints[i + 2], ctrlPoints[i + 3]];
- const curve = new Bezier(array.map(p => ({ x: p.X, y: p.Y })));
+ var startSegmentT = 0;
+ 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 curve = new Bezier(inkData.slice(i, i + 4).map(p => ({ x: p.X, y: p.Y })));
// Getting all t-value intersections of the current curve with all other curves.
- const tVals: number[] = this.getInkIntersections(i, ink, curve);
- if (tVals.length > 0) {
- tVals.sort();
- const curveCopy = new Bezier(curve.points);
- // Splitting only by the first t-value.
- const pair = curveCopy.split(tVals[0]);
- segment.push(pair.left);
- if (!excludeSegment) {
- segments.push(segment);
- segment = [pair.right];
- excludeSegment = false;
- }
- // Splitting by the number of t-values returned.
- // for (var index = 0; index < tVals.length; index++) {
- // const curveCopy = new Bezier(curve.points);
- // if (index === 0) {
- // const pair = curveCopy.split(tVals[index]);
- // segment.push(pair.left);
- // segments.push(segment);
- // segment = [pair.right];
- // } else if (index === tVals.length - 1) {
- // segments.push(segment);
- // const pair = curveCopy.split(tVals[index]);
- // segment = [pair.right];
- // } else {
- // segments.push(segment);
- // const curve = curveCopy.split(index, index + 1);
- // segment = [curve];
- // }
- // }
+ const tVals = this.getInkIntersections(i, ink, curve).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);
+ segment.push(curve.split(localStartTVal < 0 ? 0 : localStartTVal, t));
+ segment.length && segments.push(segment);
+ }
+ // start a new segment from the intersection t value
+ segment = tVals.length - 1 === index ? [curve.split(t).right] : [];
+ startSegmentT = docCurveTVal;
+ });
} else {
segment.push(curve);
}
}
- if (!excludeSegment) segments.push(segment);
+ if (excludeT < startSegmentT || excludeT > (inkData.length / 4)) {
+ segment.length && segments.push(segment);
+ }
return segments;
}
@@ -810,23 +786,21 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.childDocs
.filter(doc => doc.type === DocumentType.INK)
.forEach(doc => {
- const currInk = DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView);
- const currCtrls = Cast(currInk?.dataDoc[this.props.fieldKey], InkField)?.inkData ?? [];
- for (var j = 0; j < currCtrls.length - 3; j += 4) {
- const exclude = i === j || i === j - 4 || i === j + 4;
- const sameDoc = ink?.Document === currInk?.Document;
+ const otherInk = DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)?.ComponentView as InkingStroke;
+ const { inkData: otherInkData } = otherInk.inkScaledData();
+ const otherScreenPts = otherInkData.map(point => otherInk.ptToScreen(point));
+ const otherCtrlPts = otherScreenPts.map(spt => (ink.ComponentView as InkingStroke).ptFromScreen(spt));
+ for (var j = 0; j < otherCtrlPts.length - 3; j += 4) {
+ const neighboringSegment = i === j || i === j - 4 || i === j + 4;
// Ensuring that the curve intersected by the eraser is not checked for further ink intersections.
- if (sameDoc && exclude) continue;
- const currArray = [currCtrls[j], currCtrls[j + 1], currCtrls[j + 2], currCtrls[j + 3]];
- const currCurve = new Bezier(currArray.map(p => ({ x: p.X, y: p.Y })));
- const intersect = curve.intersects(currCurve);
- if (intersect.length > 0) {
- intersect.forEach(val => {
- // Converting the Bezier.js Split type to a t-value number.
- const t = +val.toString().split("/")[0];
- if (!tVals.includes(t)) tVals.push(t);
- });
- }
+ if (ink?.Document === otherInk.props.Document && neighboringSegment) continue;
+
+ const otherCurve = new Bezier(otherCtrlPts.slice(j, j + 4).map(p => ({ x: p.X, y: p.Y })));
+ curve.intersects(otherCurve).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).
+ });
}
});
return tVals;
@@ -1006,10 +980,10 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
.filter(({ pos, size }) => pos && size).map(({ pos, size }) => ({ pos: pos!, size: size! }));
if (measuredDocs.length) {
const ranges = measuredDocs.reduce(({ xrange, yrange }, { pos, size }) => // computes range of content
- ({
- xrange: { min: Math.min(xrange.min, pos.x), max: Math.max(xrange.max, pos.x + (size.width || 0)) },
- yrange: { min: Math.min(yrange.min, pos.y), max: Math.max(yrange.max, pos.y + (size.height || 0)) }
- })
+ ({
+ xrange: { min: Math.min(xrange.min, pos.x), max: Math.max(xrange.max, pos.x + (size.width || 0)) },
+ yrange: { min: Math.min(yrange.min, pos.y), max: Math.max(yrange.max, pos.y + (size.height || 0)) }
+ })
, {
xrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE },
yrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE }