From f4da02dac8ea9d92443533b82bee2557cdd8957e Mon Sep 17 00:00:00 2001
From: vkalev <vjk1883@gmail.com>
Date: Wed, 11 Aug 2021 20:02:23 -0400
Subject: added circle shape generation using only 4 Bézier curves
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/client/views/GestureOverlay.tsx | 54 +++++++++++++++++--------------------
 1 file changed, 25 insertions(+), 29 deletions(-)

(limited to 'src/client/views/GestureOverlay.tsx')

diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 6a4f55bef..f7b5cc030 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -726,39 +726,35 @@ export class GestureOverlay extends Touchable {
 
                 break;
             case "circle":
-
+                // Approximation of a circle using Bézier curves in which the constant "c" reduces the maximum radial drift to 0.019608%,
+                // making the curves indistinguishable from a circle.
+                // Source: https://spencermortensen.com/articles/bezier-circle/
+                const c = 0.551915024494;
                 const centerX = (Math.max(left, right) + Math.min(left, right)) / 2;
                 const centerY = (Math.max(top, bottom) + Math.min(top, bottom)) / 2;
                 const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom));
-                if (centerX - Math.min(left, right) < centerY - Math.min(top, bottom)) {
-                    for (var y = Math.min(top, bottom); y < Math.max(top, bottom); y++) {
-                        const x = Math.sqrt(Math.pow(radius, 2) - (Math.pow((y - centerY), 2))) + centerX;
-                        this._points.push({ X: x, Y: y });
-                    }
-                    for (var y = Math.max(top, bottom); y > Math.min(top, bottom); y--) {
-                        const x = Math.sqrt(Math.pow(radius, 2) - (Math.pow((y - centerY), 2))) + centerX;
-                        const newX = centerX - (x - centerX);
-                        this._points.push({ X: newX, Y: y });
-                    }
-                    this._points.push({ X: Math.sqrt(Math.pow(radius, 2) - (Math.pow((Math.min(top, bottom) - centerY), 2))) + centerX, Y: Math.min(top, bottom) });
-                    this._points.push({ X: Math.sqrt(Math.pow(radius, 2) - (Math.pow((Math.min(top, bottom) - centerY), 2))) + centerX, Y: Math.min(top, bottom) - 1 });
-
-
-                } else {
-                    for (var x = Math.min(left, right); x < Math.max(left, right); x++) {
-                        const y = Math.sqrt(Math.pow(radius, 2) - (Math.pow((x - centerX), 2))) + centerY;
-                        this._points.push({ X: x, Y: y });
-                    }
-                    for (var x = Math.max(left, right); x > Math.min(left, right); x--) {
-                        const y = Math.sqrt(Math.pow(radius, 2) - (Math.pow((x - centerX), 2))) + centerY;
-                        const newY = centerY - (y - centerY);
-                        this._points.push({ X: x, Y: newY });
-                    }
-                    this._points.push({ X: Math.min(left, right), Y: Math.sqrt(Math.pow(radius, 2) - (Math.pow((Math.min(left, right) - centerX), 2))) + centerY });
-                    this._points.push({ X: Math.min(left, right), Y: Math.sqrt(Math.pow(radius, 2) - (Math.pow((Math.min(left, right) - centerX), 2))) + centerY - 1 });
-
-                }
+                // Dividing the circle into four equal sections, and fiting each section to a cubic Bézier curve.   
+                this._points.push({ X: centerX - radius, Y: centerY });
+                this._points.push({ X: centerX - radius, Y: centerY + (c * radius) });
+                this._points.push({ X: centerX - (c * radius), Y: centerY + radius });
+                this._points.push({ X: centerX, Y: centerY + radius });
+
+                this._points.push({ X: centerX, Y: centerY + radius });
+                this._points.push({ X: centerX + (c * radius), Y: centerY + radius });
+                this._points.push({ X: centerX + radius, Y: centerY + (c * radius) });
+                this._points.push({ X: centerX + radius, Y: centerY });
+
+                this._points.push({ X: centerX + radius, Y: centerY });
+                this._points.push({ X: centerX + radius, Y: centerY - (c * radius) });
+                this._points.push({ X: centerX + (c * radius), Y: centerY - radius });
+                this._points.push({ X: centerX, Y: centerY - radius });
+                
+                this._points.push({ X: centerX, Y: centerY - radius });
+                this._points.push({ X: centerX - (c * radius), Y: centerY - radius });
+                this._points.push({ X: centerX - radius, Y: centerY - (c * radius) });
+                this._points.push({ X: centerX - radius, Y: centerY });
                 break;
+
             case "line":
                 if (Math.abs(firstx - lastx) < 20) {
                     lastx = firstx;
-- 
cgit v1.2.3-70-g09d2


From 8695343975decf566d8590d314a2f5c5cd89121b Mon Sep 17 00:00:00 2001
From: vkalev <vjk1883@gmail.com>
Date: Thu, 12 Aug 2021 12:48:24 -0400
Subject: fixed positioning of selection line

---
 src/client/util/InteractionUtils.tsx |  1 +
 src/client/views/GestureOverlay.tsx  | 10 ++++++++--
 src/client/views/InkHandles.tsx      |  3 +++
 src/client/views/InkingStroke.tsx    |  7 ++++++-
 4 files changed, 18 insertions(+), 3 deletions(-)

(limited to 'src/client/views/GestureOverlay.tsx')

diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index cb6a53157..32b70c4b4 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -210,6 +210,7 @@ export namespace InteractionUtils {
                 style={{
                     // filter: drawHalo ? "url(#inkSelectionHalo)" : undefined,
                     fill: fill ? fill : "none",
+                    // opacity: 1.0,
                     opacity: strokeWidth !== width ? 0.5 : undefined,
                     pointerEvents: pevents as any,
                     stroke: color ?? "rgb(0, 0, 0)",
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index f7b5cc030..cf57ac7a1 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -726,7 +726,7 @@ export class GestureOverlay extends Touchable {
 
                 break;
             case "circle":
-                // Approximation of a circle using Bézier curves in which the constant "c" reduces the maximum radial drift to 0.019608%,
+                // Approximation of a circle using 4 Bézier curves in which the constant "c" reduces the maximum radial drift to 0.019608%,
                 // making the curves indistinguishable from a circle.
                 // Source: https://spencermortensen.com/articles/bezier-circle/
                 const c = 0.551915024494;
@@ -748,11 +748,17 @@ export class GestureOverlay extends Touchable {
                 this._points.push({ X: centerX + radius, Y: centerY - (c * radius) });
                 this._points.push({ X: centerX + (c * radius), Y: centerY - radius });
                 this._points.push({ X: centerX, Y: centerY - radius });
-                
+
                 this._points.push({ X: centerX, Y: centerY - radius });
                 this._points.push({ X: centerX - (c * radius), Y: centerY - radius });
                 this._points.push({ X: centerX - radius, Y: centerY - (c * radius) });
                 this._points.push({ X: centerX - radius, Y: centerY });
+
+                // this._points.push({ X: centerX - radius, Y: centerY });
+                // this._points.push({ X: centerX - radius, Y: centerY - (c * radius) });
+                // this._points.push({ X: centerX - (c * radius), Y: centerY - radius });
+                // this._points.push({ X: centerX, Y: centerY - radius });
+
                 break;
 
             case "line":
diff --git a/src/client/views/InkHandles.tsx b/src/client/views/InkHandles.tsx
index f1eb4b9db..0b24c3c32 100644
--- a/src/client/views/InkHandles.tsx
+++ b/src/client/views/InkHandles.tsx
@@ -11,10 +11,12 @@ import { listSpec } from "../../fields/Schema";
 import { List } from "../../fields/List";
 import { Cast } from "../../fields/Types";
 import { Colors } from "./global/globalEnums";
+import { GestureOverlay } from "./GestureOverlay";
 
 export interface InkHandlesProps {
     inkDoc: Doc;
     data: InkData;
+    shape?: string;
     format: number[];
     ScreenToLocalTransform: () => Transform;
 }
@@ -68,6 +70,7 @@ export class InkHandles extends React.Component<InkHandlesProps> {
 
         // Accessing the current ink's data and extracting all handle points and handle lines.
         const data = this.props.data;
+        const shape = this.props.shape;
         const handlePoints: HandlePoint[] = [];
         const handleLines: HandleLine[] = [];
         if (data.length >= 4) {
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index d30244a8f..4beab6a62 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -20,6 +20,7 @@ import { CurrentUserUtils } from "../util/CurrentUserUtils";
 import { InkControls } from "./InkControls";
 import { InkHandles } from "./InkHandles";
 import { Colors } from "./global/globalEnums";
+import { GestureOverlay } from "./GestureOverlay";
 
 type InkDocument = makeInterface<[typeof documentSchema]>;
 const InkDocument = makeInterface(documentSchema);
@@ -28,6 +29,7 @@ const InkDocument = makeInterface(documentSchema);
 export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocument>(InkDocument) {
     static readonly MaskDim = 50000;
     @observable private _properties?: InkStrokeProperties;
+    // static InkShape = GestureOverlay.Instance.InkShape;
 
     constructor(props: FieldViewProps & InkDocument) {
         super(props);
@@ -79,6 +81,8 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         TraceMobx();
         this.toggleControlButton();
         // Extracting the ink data and formatting information of the current ink stroke.
+        // console.log(InkingStroke.InkShape);
+        const InkShape = GestureOverlay.Instance.InkShape;
         const data: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
         const inkDoc: Doc = this.layoutDoc;
         const strokeWidth = Number(this.layoutDoc.strokeWidth);
@@ -101,7 +105,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         const inkLine = InteractionUtils.CreatePolyline(data, left, top, strokeColor, strokeWidth, strokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker),
             StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5 && lineBottom - lineTop > 1 && lineRight - lineLeft > 1, false);
         // Thin blue line indicating that the current ink stroke is selected.
-        const selectedLine = InteractionUtils.CreatePolyline(data, left - strokeWidth / 3, top - strokeWidth / 3, Colors.MEDIUM_BLUE, strokeWidth / 6, strokeWidth / 6, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"),
+        const selectedLine = InteractionUtils.CreatePolyline(data, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth / 6, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"),
             StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5 && lineBottom - lineTop > 1 && lineRight - lineLeft > 1, false);
         // Invisible polygonal line that enables the ink to be selected by the user.
         const clickableLine = InteractionUtils.CreatePolyline(data, left, top, this.props.isSelected() && strokeWidth > 5 ? strokeColor : "transparent", strokeWidth, strokeWidth + 15, StrCast(this.layoutDoc.strokeBezier),
@@ -143,6 +147,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
                         <InkHandles
                             inkDoc={inkDoc}
                             data={data}
+                            shape={InkShape}
                             format={[left, top, scaleX, scaleY, strokeWidth]}
                             ScreenToLocalTransform={this.props.ScreenToLocalTransform} />
                     </> : ""}
-- 
cgit v1.2.3-70-g09d2


From b69fe78eadeb2bfa1f284e3e0333734b03b718a9 Mon Sep 17 00:00:00 2001
From: vkalev <vjk1883@gmail.com>
Date: Fri, 13 Aug 2021 10:15:31 -0400
Subject: cleaning up

---
 src/client/views/GestureOverlay.tsx     |  7 +------
 src/client/views/InkControls.tsx        | 24 +-----------------------
 src/client/views/InkStrokeProperties.ts | 12 ++++++------
 src/client/views/InkingStroke.tsx       |  3 +--
 4 files changed, 9 insertions(+), 37 deletions(-)

(limited to 'src/client/views/GestureOverlay.tsx')

diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index cf57ac7a1..bbf21f22c 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -733,7 +733,7 @@ export class GestureOverlay extends Touchable {
                 const centerX = (Math.max(left, right) + Math.min(left, right)) / 2;
                 const centerY = (Math.max(top, bottom) + Math.min(top, bottom)) / 2;
                 const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom));
-                // Dividing the circle into four equal sections, and fiting each section to a cubic Bézier curve.   
+                // Dividing the circle into four equal sections, and fitting each section to a cubic Bézier curve.   
                 this._points.push({ X: centerX - radius, Y: centerY });
                 this._points.push({ X: centerX - radius, Y: centerY + (c * radius) });
                 this._points.push({ X: centerX - (c * radius), Y: centerY + radius });
@@ -754,11 +754,6 @@ export class GestureOverlay extends Touchable {
                 this._points.push({ X: centerX - radius, Y: centerY - (c * radius) });
                 this._points.push({ X: centerX - radius, Y: centerY });
 
-                // this._points.push({ X: centerX - radius, Y: centerY });
-                // this._points.push({ X: centerX - radius, Y: centerY - (c * radius) });
-                // this._points.push({ X: centerX - (c * radius), Y: centerY - radius });
-                // this._points.push({ X: centerX, Y: centerY - radius });
-
                 break;
 
             case "line":
diff --git a/src/client/views/InkControls.tsx b/src/client/views/InkControls.tsx
index 55a70ccd2..6213a4075 100644
--- a/src/client/views/InkControls.tsx
+++ b/src/client/views/InkControls.tsx
@@ -87,38 +87,16 @@ export class InkControls extends React.Component<InkControlProps> {
         if (!formatInstance) return (null);
 
         // Accessing the current ink's data and extracting all control points.
-        // Separate case for circle shape (?)
         const data = this.props.data;
-        const [left, right, top, bottom, scaleX, scaleY, strokeWidth] = this.props.format;
-        const centerX = (Math.max(left, right) + Math.min(left, right)) / 2;
-        const centerY = (Math.max(top, bottom) + Math.min(top, bottom)) / 2;
-        const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom));
         const controlPoints: ControlPoint[] = [];
         if (data.length >= 4) {
-            // const distance = Math.sqrt((Math.pow(data[0].X - centerX, 2)) + (Math.pow(data[0].Y - centerY, 2)));
-            // if (Math.abs(distance - radius) <= 2.5) {
-            //     controlPoints.push({ X: data[0].X, Y: data[0].Y, I: 0 });
-            //     const topPoint = formatInstance.rotatePoint(data[0], { X: centerX, Y: centerY }, Math.PI / 2);
-            //     const rightPoint = formatInstance.rotatePoint(data[0], { X: centerX, Y: centerY }, Math.PI);
-            //     const bottomPoint = formatInstance.rotatePoint(data[0], { X: centerX, Y: centerY }, Math.PI * 1.5);
-            //     for (let i = 0; i <= data.length - 4; i += 4) {
-            //         const currPoint = data[i];
-            //         const isTopPoint = Math.sqrt((Math.pow(currPoint.X - topPoint.X, 2)) + (Math.pow(currPoint.Y - topPoint.Y, 2))) <= 2.5;
-            //         const isRightPoint = Math.sqrt((Math.pow(currPoint.X - rightPoint.X, 2)) + (Math.pow(currPoint.Y - rightPoint.Y, 2))) <= 2.5;
-            //         const isBottomPoint = Math.sqrt((Math.pow(currPoint.X - bottomPoint.X, 2)) + (Math.pow(currPoint.Y - bottomPoint.Y, 2))) <= 2.5;
-            //         if (isTopPoint || isRightPoint || isBottomPoint) {
-            //             controlPoints.push({ X: data[i].X, Y: data[i].Y, I: i });
-            //         }
-            //     }
-            //     controlPoints.push({ X: data[0].X, Y: data[0].Y, I: 0 });
-            // } else {
             for (let i = 0; i <= data.length - 4; i += 4) {
                 controlPoints.push({ X: data[i].X, Y: data[i].Y, I: i });
                 controlPoints.push({ X: data[i + 3].X, Y: data[i + 3].Y, I: i + 3 });
             }
-            // }
         }
         const addedPoints = this.props.addedPoints;
+        const [left, top, scaleX, scaleY, strokeWidth] = this.props.format;
 
         return (
             <>
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index 7ef6606c4..d527b2a05 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -266,12 +266,12 @@ export class InkStrokeProperties {
         this.applyFunction((doc: Doc, ink: InkData) => {
             const brokenIndices = Cast(doc.brokenInkIndices, listSpec("number"));
             if (brokenIndices) {
-                let newBrokenIndices = new List;
-                for (let i = 0; i < brokenIndices.length; i++) {
-                    if (brokenIndices[i] !== controlIndex) {
-                        newBrokenIndices.push(brokenIndices[i]);
+                const newBrokenIndices = new List;
+                brokenIndices.forEach(brokenIndex => {
+                    if (brokenIndex !== controlIndex) {
+                        newBrokenIndices.push(brokenIndex);
                     }
-                }
+                });
                 doc.brokenInkIndices = newBrokenIndices;
                 const [controlPoint, handleA, handleB] = [ink[controlIndex], ink[handleIndexA], ink[handleIndexB]];
                 const oppositeHandleA = this.rotatePoint(handleA, controlPoint, Math.PI);
@@ -288,7 +288,7 @@ export class InkStrokeProperties {
      */
     @action
     rotatePoint = (target: PointData, origin: PointData, angle: number) => {
-        let rotatedTarget = { X: target.X - origin.X, Y: target.Y - origin.Y };
+        const rotatedTarget = { X: target.X - origin.X, Y: target.Y - origin.Y };
         const newX = Math.cos(angle) * rotatedTarget.X - Math.sin(angle) * rotatedTarget.Y;
         const newY = Math.sin(angle) * rotatedTarget.X + Math.cos(angle) * rotatedTarget.Y;
         rotatedTarget.X = newX + origin.X;
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index affea61e3..834c3b745 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -29,7 +29,6 @@ const InkDocument = makeInterface(documentSchema);
 export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocument>(InkDocument) {
     static readonly MaskDim = 50000;
     @observable private _properties?: InkStrokeProperties;
-    // static InkShape = GestureOverlay.Instance.InkShape;
 
     constructor(props: FieldViewProps & InkDocument) {
         super(props);
@@ -142,7 +141,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
                             inkDoc={inkDoc}
                             data={data}
                             addedPoints={addedPoints}
-                            format={[left, right, top, bottom, scaleX, scaleY, strokeWidth]}
+                            format={[left, top, scaleX, scaleY, strokeWidth]}
                             ScreenToLocalTransform={this.props.ScreenToLocalTransform} />
                         <InkHandles
                             inkDoc={inkDoc}
-- 
cgit v1.2.3-70-g09d2

