diff options
-rw-r--r-- | src/client/views/GestureOverlay.tsx | 196 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 1 |
2 files changed, 91 insertions, 106 deletions
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 935eeb251..7e396d475 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -1,4 +1,5 @@ import * as fitCurve from 'fit-curve'; +import { Bezier } from 'bezier-js'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -95,7 +96,6 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil componentDidMount() { GestureOverlay.Instance = this; } - @action onPointerDown = (e: React.PointerEvent) => { if (!(e.target as HTMLElement)?.className?.toString().startsWith('lm_')) { @@ -139,52 +139,52 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil * to be deleted and then it will delete them. * @returns */ - isScribble() { + isScribble(inkData: InkData) { const ffView = DocumentView.allViews().find(view => view.ComponentView instanceof CollectionFreeFormView); - const cuspArray = this.getCusps(); - const cuspBooleanArray: boolean[] = []; + console.log(inkData.map(ink => ({ x: ink.X, y: ink.Y }))); + let intersectArray: boolean[] = []; + const cuspArray = this.getCusps(inkData); + console.log(cuspArray.length); + for (let i = 0; i < cuspArray.length; i++) { + intersectArray[i] = false; + } const docsToDelete: Doc[] = []; - const childDocs = (ffView?.ComponentView as CollectionFreeFormView).childDocs; + const childDocs = (ffView?.ComponentView as CollectionFreeFormView).childDocs.slice(0, -1); childDocs.filter(doc => doc.type === 'ink').map(doc => DocumentView.getDocumentView(doc, DocumentView.getDocumentView(doc))); if ((ffView?.ComponentView as CollectionFreeFormView).childDocs) { //how many cusps the scribble hsa - if (cuspArray.length > 4) { - for (let i = 0; i < cuspArray.length - 2; i++) { - let hasDocInTriangle = false; - for (const doc of childDocs) { - const point1 = cuspArray[i]; - const point2 = cuspArray[i + 1]; - const point3 = cuspArray[i + 2]; - const triangleObject = { p1: { X: point1.X, Y: point1.Y }, p2: { X: point2.X, Y: point2.Y }, p3: { X: point3.X, Y: point3.Y } }; - const otherInk = DocumentView.getDocumentView(doc)?.ComponentView as InkingStroke; - if (otherInk instanceof InkingStroke) { - const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] }; - const otherScreenPts = otherInkData.map(point => otherInk.ptToScreen(point)); - if (doc.title === 'line') { - if (this.doesLineIntersectTriangle(otherScreenPts, triangleObject)) { - docsToDelete.push(doc); - hasDocInTriangle = true; - cuspBooleanArray.push(true); - } + for (const doc of childDocs) { + const otherInk = DocumentView.getDocumentView(doc)?.ComponentView as InkingStroke; + if (otherInk instanceof InkingStroke) { + const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] }; + const otherScreenPts = otherInkData.map(point => otherInk.ptToScreen(point)); + if (this.isRectangleOverlap(this.getExtremeCoordinates(otherScreenPts), this.getExtremeCoordinates(inkData))) { + console.log('somethings in'); + const intersects = this.doInksIntersect(inkData, otherScreenPts); + console.log(intersects); + intersects.forEach(intersect => { + let percentage = ''; + if (intersect.includes('/')) { + const leftOfSlash = intersect.split('/')[0]; + percentage = leftOfSlash; } else { - if (this.isAnyPointInTriangle(triangleObject, otherScreenPts)) { - docsToDelete.push(doc); - hasDocInTriangle = true; - cuspBooleanArray.push(true); - } + percentage = intersect; } - } + intersectArray[Math.floor((percentage as unknown as number) * cuspArray.length)] = true; + docsToDelete.push(doc); + }); } - cuspBooleanArray.push(hasDocInTriangle); - } - if (this.determineIfScribble(cuspBooleanArray)) { - docsToDelete.forEach(doc => { - ffView?.ComponentView?.removeDocument?.(doc); - }); - this._points = []; - return true; } } + console.log(intersectArray); + if (intersectArray.length > 3 && this.determineIfScribble(intersectArray)) { + console.log('is a scribble'); + docsToDelete.forEach(doc => { + ffView?.ComponentView?.removeDocument?.(doc); + }); + this._points = []; + return true; + } } return false; } @@ -198,7 +198,7 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil if (!cuspBooleanArray) { return false; } - const quarterArrayLength = Math.ceil((cuspBooleanArray.length - 2) * 0.25); + const quarterArrayLength = Math.ceil((cuspBooleanArray.length - 2) * 0.3); let hasObjectInFirstAndLast25 = true; for (let i = 0; i < quarterArrayLength; i++) { if (cuspBooleanArray[i] == false || cuspBooleanArray[cuspBooleanArray.length - 1 - i] == false) { @@ -207,7 +207,7 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil } const trueCount = cuspBooleanArray.filter(value => value).length; const percentageTrues = trueCount / cuspBooleanArray.length; - return percentageTrues > 0.65 || hasObjectInFirstAndLast25; + return percentageTrues > 0.5 || hasObjectInFirstAndLast25; } /** * determines if two rectangles are overlapping each other @@ -222,38 +222,6 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil return !noOverlap; } /** - * determines if there is a point in a triangle used to determine what triangles in the scribble have an object - * @param pt the point in question - * @param triangle the triangle with 3 points - * @returns true or false if point is in triangle - */ - isPointInTriangle(pt: { X: number; Y: number }, triangle: { p1: { X: number; Y: number }; p2: { X: number; Y: number }; p3: { X: number; Y: number } }): boolean { - const area = (v1: { X: number; Y: number }, v2: { X: number; Y: number }, v3: { X: number; Y: number }) => Math.abs((v1.X * (v2.Y - v3.Y) + v2.X * (v3.Y - v1.Y) + v3.X * (v1.Y - v2.Y)) / 2.0); - - const A = area(triangle.p1, triangle.p2, triangle.p3); - - const A1 = area(pt, triangle.p2, triangle.p3); - const A2 = area(triangle.p1, pt, triangle.p3); - const A3 = area(triangle.p1, triangle.p2, pt); - - return A === A1 + A2 + A3; - } - /** - * determines if any points in an array are in a triangle - * @param triangle the triangle with 3 points - * @param points the point in question - * @returns true or false if point is in triangle - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - isAnyPointInTriangle(triangle: any, points: any[]): boolean { - for (const point of points) { - if (this.isPointInTriangle(point, triangle)) { - return true; - } - } - return false; - } - /** * determines if a line intersects a triangle. used for scribble gesture since the line doesnt have a lot * of points across is so isPointInTriangle will not work for it. * @param line is pointData @@ -261,20 +229,25 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil * @returns true or false if it intersects */ // eslint-disable-next-line @typescript-eslint/no-explicit-any - doesLineIntersectTriangle(line: any, triangle: any): boolean { - const edges = [ - { start: triangle.p1, end: triangle.p2 }, - { start: triangle.p2, end: triangle.p3 }, - { start: triangle.p3, end: triangle.p1 }, - ]; - - for (const edge of edges) { - if (this.doLinesIntersect(line, edge)) { - return true; + doInksIntersect(scribble: InkData, inkStroke: InkData): string[] { + let intersectArray: string[] = []; + const ffView = DocumentView.allViews().find(view => view.ComponentView instanceof CollectionFreeFormView); + if (ffView && ffView.ComponentView instanceof CollectionFreeFormView) { + for (let i = 0; i < scribble.length - 3; i += 4) { + // iterate over each segment of bezier curve + for (let j = 0; j < inkStroke.length - 3; j += 4) { + const intersectCurve: Bezier = InkField.Segment(scribble, i); // other curve + const eraserCurve: Bezier = InkField.Segment(inkStroke, j); // eraser curve + if (ffView && ffView.ComponentView instanceof CollectionFreeFormView) { + const result = (ffView.ComponentView as CollectionFreeFormView).bintersects(intersectCurve, eraserCurve)[0]; + if (result !== undefined) { + intersectArray.push(result.toString()); + } + } + } } } - - return false; + return intersectArray; } /** * used in doesLineIntersectTriangle, splits up the triangle into 3 lines and runs this method @@ -284,20 +257,21 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil * @returns */ // eslint-disable-next-line @typescript-eslint/no-explicit-any - doLinesIntersect(line1: any, line2: any): boolean { - const A = line1[0]; - const B = line1[line1.length - 1]; - const { start: C, end: D } = line2; - const denominator = (B.X - A.X) * (D.Y - C.Y) - (B.Y - A.Y) * (D.X - C.X); - if (denominator === 0) return false; - - const numerator1 = (A.Y - C.Y) * (D.X - C.X) - (A.X - C.X) * (D.Y - C.Y); - const numerator2 = (A.Y - C.Y) * (B.X - A.X) - (A.X - C.X) * (B.Y - A.Y); - - const r = numerator1 / denominator; - const s = numerator2 / denominator; - - return r >= 0 && r <= 1 && s >= 0 && s <= 1; + doLinesIntersect(points: any, line: any): boolean { + const ffView = DocumentView.allViews().find(view => view.ComponentView instanceof CollectionFreeFormView); + if (ffView && ffView.ComponentView instanceof CollectionFreeFormView) { + for (let i = 0; i < points.length - 3; i += 4) { + // iterate over each segment of bezier curve + for (let j = 0; j < line.length - 3; j += 4) { + const intersectCurve: Bezier = InkField.Segment(points, i); // other curve + const eraserCurve: Bezier = InkField.Segment(line, j); // eraser curve + if (ffView && ffView.ComponentView instanceof CollectionFreeFormView) { + //(ffView.ComponentView as CollectionFreeFormView).bintersects(); + } + } + } + } + return false; } dryInk = () => { @@ -343,18 +317,31 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil case Gestures.Rectangle: case Gestures.Circle: this.makeBezierPolygon(Name, true); + setTimeout(() => { + const ffView = DocumentView.allViews().find(view => view.ComponentView instanceof CollectionFreeFormView); + const scribbleInk = (ffView?.ComponentView as CollectionFreeFormView).childDocs[(ffView?.ComponentView as CollectionFreeFormView).childDocs.length - 1]; + //this.isScribble((DocumentView.getDocumentView(scribbleInk)?.ComponentView as InkingStroke).inkScaledData().inkData); + }, 1); return this.dispatchGesture(name); case Gestures.RightAngle: return this.convertToText().length > 0; default: - case Gestures.Stroke: - return this.isScribble(); } })(Score < 0.7 ? Gestures.Stroke : (Name as Gestures)); // if no gesture (or if the gesture was unsuccessful), "dry" the stroke into an ink document - if (!actionPerformed) this.dryInk(); + if (!actionPerformed) { + this.dryInk(); + setTimeout(() => { + const ffView = DocumentView.allViews().find(view => view.ComponentView instanceof CollectionFreeFormView); + const scribbleInk = (ffView?.ComponentView as CollectionFreeFormView).childDocs[(ffView?.ComponentView as CollectionFreeFormView).childDocs.length - 1]; + if (this.isScribble((DocumentView.getDocumentView(scribbleInk)?.ComponentView as InkingStroke).inkScaledData().inkData)) { + ffView?.ComponentView?.removeDocument?.(scribbleInk); + } + }, 1); + } } this._points.length = 0; + //console.log((DocumentView.getDocumentView(scribbleInk)?.ComponentView as InkingStroke).inkScaledData()); }; /** * used in the rightAngle gesture to convert handwriting into text. will only work on collections @@ -374,7 +361,7 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil const bounds = DocumentView.getDocumentView(doc)?.getBounds; if (bounds) { const rect1 = { minX: bounds.left, maxX: bounds.right, minY: bounds.top, maxY: bounds.bottom }; - if (this.isRectangleOverlap(rect1, this.getExtremeCoordinates())) { + if (this.isRectangleOverlap(rect1, this.getExtremeCoordinates(this._points))) { if (doc.x < minX) { minX = doc.x; } @@ -405,8 +392,7 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil * used to determine how many cusps and where the cusps are in order * @returns will return an array containing the coordinates of the sharp cusps */ - getCusps() { - const points = this._points.map(p => ({ X: p.X, Y: p.Y })); + getCusps(points: InkData) { const arrayOfPoints: { X: number; Y: number }[] = []; arrayOfPoints.push(points[0]); for (let i = 0; i < points.length - 2; i++) { @@ -424,8 +410,8 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil * will look through an array of point data and return the coordinates of the smallest box that can fit all the points * @returns the minX,maxX,minY,maxY of the box */ - getExtremeCoordinates() { - const coordinates = this._points; + getExtremeCoordinates(points: { X: number; Y: number }[]) { + const coordinates = points; if (coordinates.length === 0) { throw new Error('Coordinates array is empty'); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 38c85edce..6ae55add3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -890,7 +890,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection strokeToTVals.set(inkView, [Math.floor(inkData.length / 4) + 1]); } } - for (let i = 0; i < inkData.length - 3; i += 4) { // iterate over each segment of bezier curve for (let j = 0; j < eraserInkData.length - 3; j += 4) { |