diff options
author | vkalev <vjk1883@gmail.com> | 2021-08-11 20:02:23 -0400 |
---|---|---|
committer | vkalev <vjk1883@gmail.com> | 2021-08-11 20:02:23 -0400 |
commit | f4da02dac8ea9d92443533b82bee2557cdd8957e (patch) | |
tree | 9f7aedd8fff62ec7a99b003e1c1e16245614f9ae /src | |
parent | 61d01ac7e7a2ff2df3a083aaa87ca5d8edbf71e8 (diff) |
added circle shape generation using only 4 Bézier curves
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/InteractionUtils.tsx | 4 | ||||
-rw-r--r-- | src/client/views/GestureOverlay.tsx | 54 | ||||
-rw-r--r-- | src/client/views/InkControls.tsx | 24 | ||||
-rw-r--r-- | src/client/views/InkStrokeProperties.ts | 9 | ||||
-rw-r--r-- | src/client/views/InkingStroke.tsx | 2 |
5 files changed, 56 insertions, 37 deletions
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index ba935e3bf..cb6a53157 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -299,8 +299,6 @@ export namespace InteractionUtils { return points; case "circle": - - 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)); @@ -315,7 +313,6 @@ export namespace InteractionUtils { points.push({ X: newX, Y: y }); } points.push({ X: Math.sqrt(Math.pow(radius, 2) - (Math.pow((Math.min(top, bottom) - centerY), 2))) + centerX, Y: Math.min(top, bottom) }); - } 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; @@ -327,7 +324,6 @@ export namespace InteractionUtils { points.push({ X: x, Y: newY }); } points.push({ X: Math.min(left, right), Y: Math.sqrt(Math.pow(radius, 2) - (Math.pow((Math.min(left, right) - centerX), 2))) + centerY }); - } return points; // case "arrow": 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; diff --git a/src/client/views/InkControls.tsx b/src/client/views/InkControls.tsx index 6213a4075..55a70ccd2 100644 --- a/src/client/views/InkControls.tsx +++ b/src/client/views/InkControls.tsx @@ -87,16 +87,38 @@ 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 76ca5b5ec..7ef6606c4 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -266,8 +266,13 @@ export class InkStrokeProperties { this.applyFunction((doc: Doc, ink: InkData) => { const brokenIndices = Cast(doc.brokenInkIndices, listSpec("number")); if (brokenIndices) { - brokenIndices.splice(brokenIndices.indexOf(controlIndex), 1); - doc.brokenInkIndices = brokenIndices; + let newBrokenIndices = new List; + for (let i = 0; i < brokenIndices.length; i++) { + if (brokenIndices[i] !== controlIndex) { + newBrokenIndices.push(brokenIndices[i]); + } + } + doc.brokenInkIndices = newBrokenIndices; const [controlPoint, handleA, handleB] = [ink[controlIndex], ink[handleIndexA], ink[handleIndexB]]; const oppositeHandleA = this.rotatePoint(handleA, controlPoint, Math.PI); const angleDifference = this.angleChange(handleB, oppositeHandleA, controlPoint); diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 21059b330..d30244a8f 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -138,7 +138,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume inkDoc={inkDoc} data={data} addedPoints={addedPoints} - format={[left, top, scaleX, scaleY, strokeWidth]} + format={[left, right, top, bottom, scaleX, scaleY, strokeWidth]} ScreenToLocalTransform={this.props.ScreenToLocalTransform} /> <InkHandles inkDoc={inkDoc} |