From 5e34bd8969d41253fa7fbe0fe70fae8d2109cca2 Mon Sep 17 00:00:00 2001 From: Adil Hanney Date: Thu, 30 Nov 2023 21:44:30 +0000 Subject: [PATCH] feat: migrate to $1 unistroke recognizer --- lib/components/canvas/_canvas_painter.dart | 41 +++++++++--------- lib/components/canvas/_circle_stroke.dart | 35 +++------------ lib/components/canvas/_rectangle_stroke.dart | 32 +++----------- lib/components/canvas/_stroke.dart | 12 ++++-- lib/components/canvas/canvas.dart | 4 +- lib/components/canvas/inner_canvas.dart | 4 +- lib/data/tools/shape_pen.dart | 45 ++++++++++++-------- pubspec.lock | 32 ++++---------- pubspec.yaml | 2 +- 9 files changed, 83 insertions(+), 124 deletions(-) diff --git a/lib/components/canvas/_canvas_painter.dart b/lib/components/canvas/_canvas_painter.dart index 326c1c5c7..dd2ab266b 100644 --- a/lib/components/canvas/_canvas_painter.dart +++ b/lib/components/canvas/_canvas_painter.dart @@ -2,7 +2,7 @@ import 'dart:math'; import 'dart:ui'; import 'package:flutter/material.dart' hide TextStyle; -import 'package:interactive_shape_recognition/interactive_shape_recognition.dart'; +import 'package:one_dollar_unistroke_recognizer/one_dollar_unistroke_recognizer.dart'; import 'package:path_drawing/path_drawing.dart'; import 'package:saber/components/canvas/_circle_stroke.dart'; import 'package:saber/components/canvas/_rectangle_stroke.dart'; @@ -167,8 +167,8 @@ class CanvasPainter extends CustomPainter { } void _drawDetectedShape(Canvas canvas) { - if (ShapePen.detectedShape == null) return; - if (ShapePen.detectedShape!.shape == Shape.unknown) return; + final shape = ShapePen.detectedShape; + if (shape == null) return; final color = currentStroke?.strokeProperties.color.withInversion(invert) ?? Colors.black; @@ -177,27 +177,24 @@ class CanvasPainter extends CustomPainter { ..style = PaintingStyle.stroke ..strokeWidth = currentStroke?.strokeProperties.size ?? 3; - switch (ShapePen.detectedShape!.shape) { - case Shape.line: - canvas.drawLine( - ShapePen.detectedShape!.firstPoint, - ShapePen.detectedShape!.lastPoint, + switch (shape.name) { + case null: + break; + case DefaultUnistrokeNames.line: + final (firstPoint, lastPoint) = shape.convertToLine(); + canvas.drawLine(firstPoint, lastPoint, shapePaint); + case DefaultUnistrokeNames.rectangle: + final rect = shape.convertToRect(); + canvas.drawRect(rect, shapePaint); + case DefaultUnistrokeNames.circle: + final (center, radius) = shape.convertToCircle(); + canvas.drawCircle(center, radius, shapePaint); + case DefaultUnistrokeNames.triangle: + final polygon = shape.convertToCanonicalPolygon(); + canvas.drawPath( + Path()..addPolygon(polygon, true), shapePaint, ); - case Shape.rectangle: - canvas.drawRect( - ShapePen.detectedShape!.generateRectangle(), - shapePaint, - ); - case Shape.circle: - final circle = ShapePen.detectedShape!.generateCircle(); - canvas.drawCircle( - circle.$2, - circle.$1, - shapePaint, - ); - case Shape.unknown: - throw StateError('Shape.unknown should have an early return'); } } diff --git a/lib/components/canvas/_circle_stroke.dart b/lib/components/canvas/_circle_stroke.dart index d5570f6f5..689805d84 100644 --- a/lib/components/canvas/_circle_stroke.dart +++ b/lib/components/canvas/_circle_stroke.dart @@ -1,7 +1,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; -import 'package:interactive_shape_recognition/interactive_shape_recognition.dart'; +import 'package:one_dollar_unistroke_recognizer/one_dollar_unistroke_recognizer.dart'; import 'package:saber/components/canvas/_stroke.dart'; import 'package:saber/data/tools/shape_pen.dart'; import 'package:saber/data/tools/stroke_properties.dart'; @@ -108,31 +108,12 @@ class CircleStroke extends Stroke { @override @Deprecated('We already know the shape is a circle.') - DetectedShape getDetectedShape() { - final rect = Rect.fromCircle(center: center, radius: radius); - return DetectedShape( - shape: Shape.circle, - maybeCircle: true, - maybeLine: false, - maybeRectangle: false, - enclosingRect: [ - rect.topLeft, - rect.topRight, - rect.bottomRight, - rect.bottomLeft, - ], - convexHull: [ - rect.topLeft, - rect.topRight, - rect.bottomRight, - rect.bottomLeft, - ], - firstPoint: rect.topCenter, - lastPoint: rect.bottomCenter, - rLenPch: 0, - rThinness: 0, - rAltAch: 0, - rPchPer: 0, + RecognizedUnistroke detectShape() { + return RecognizedUnistroke( + DefaultUnistrokeNames.circle, + 1, + originalPoints: polygon, + referenceUnistrokes: default$1Unistrokes, ); } @@ -144,6 +125,4 @@ class CircleStroke extends Stroke { center: center, radius: radius, ); - - // TODO(adil192): Add HighlighterStroke class and move canvas drawing logic to Stroke. } diff --git a/lib/components/canvas/_rectangle_stroke.dart b/lib/components/canvas/_rectangle_stroke.dart index caf1e4565..8ee1368a0 100644 --- a/lib/components/canvas/_rectangle_stroke.dart +++ b/lib/components/canvas/_rectangle_stroke.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:interactive_shape_recognition/interactive_shape_recognition.dart'; +import 'package:one_dollar_unistroke_recognizer/one_dollar_unistroke_recognizer.dart'; import 'package:saber/components/canvas/_stroke.dart'; import 'package:saber/data/tools/shape_pen.dart'; import 'package:saber/data/tools/stroke_properties.dart'; @@ -124,30 +124,12 @@ class RectangleStroke extends Stroke { @override @Deprecated('We already know the shape is a rectangle.') - DetectedShape getDetectedShape() { - return DetectedShape( - shape: Shape.rectangle, - maybeCircle: false, - maybeLine: false, - maybeRectangle: true, - enclosingRect: [ - rect.topLeft, - rect.topRight, - rect.bottomRight, - rect.bottomLeft, - ], - convexHull: [ - rect.topLeft, - rect.topRight, - rect.bottomRight, - rect.bottomLeft, - ], - firstPoint: rect.topCenter, - lastPoint: rect.bottomCenter, - rLenPch: 0, - rThinness: 0, - rAltAch: 0, - rPchPer: 0, + RecognizedUnistroke detectShape() { + return RecognizedUnistroke( + DefaultUnistrokeNames.rectangle, + 1, + originalPoints: polygon, + referenceUnistrokes: default$1Unistrokes, ); } diff --git a/lib/components/canvas/_stroke.dart b/lib/components/canvas/_stroke.dart index 31eed862d..df78c290c 100644 --- a/lib/components/canvas/_stroke.dart +++ b/lib/components/canvas/_stroke.dart @@ -1,8 +1,8 @@ import 'dart:math' hide atan2; import 'package:flutter/material.dart'; -import 'package:interactive_shape_recognition/interactive_shape_recognition.dart'; import 'package:logging/logging.dart'; +import 'package:one_dollar_unistroke_recognizer/one_dollar_unistroke_recognizer.dart'; import 'package:perfect_freehand/perfect_freehand.dart'; import 'package:saber/components/canvas/_circle_stroke.dart'; import 'package:saber/components/canvas/_rectangle_stroke.dart'; @@ -126,6 +126,12 @@ class Stroke { _polygonNeedsUpdating = true; } + void addPoints(List points) { + for (final point in points) { + addPoint(point); + } + } + void popFirstPoint() { points.removeAt(0); _polygonNeedsUpdating = true; @@ -237,9 +243,9 @@ class Stroke { } } - DetectedShape? getDetectedShape() { + RecognizedUnistroke? detectShape() { if (points.length < 3) return null; - return detectShape( + return recognizeUnistroke( points.map((point) => Offset(point.x, point.y)).toList(), ); } diff --git a/lib/components/canvas/canvas.dart b/lib/components/canvas/canvas.dart index 6882ce2ab..b03ee7eac 100644 --- a/lib/components/canvas/canvas.dart +++ b/lib/components/canvas/canvas.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:interactive_shape_recognition/interactive_shape_recognition.dart'; +import 'package:one_dollar_unistroke_recognizer/one_dollar_unistroke_recognizer.dart'; import 'package:onyxsdk_pen/onyxsdk_pen_area.dart'; import 'package:saber/components/canvas/_stroke.dart'; import 'package:saber/components/canvas/image/editor_image.dart'; @@ -31,7 +31,7 @@ class Canvas extends StatelessWidget { final bool textEditing; final EditorCoreInfo coreInfo; final Stroke? currentStroke; - final DetectedShape? currentStrokeDetectedShape; + final RecognizedUnistroke? currentStrokeDetectedShape; final SelectResult? currentSelection; final void Function(EditorImage image)? setAsBackground; diff --git a/lib/components/canvas/inner_canvas.dart b/lib/components/canvas/inner_canvas.dart index 3f7fa16bb..05067fa6f 100644 --- a/lib/components/canvas/inner_canvas.dart +++ b/lib/components/canvas/inner_canvas.dart @@ -2,7 +2,7 @@ import 'package:defer_pointer/defer_pointer.dart'; import 'package:flutter/material.dart'; import 'package:flutter_quill/flutter_quill.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:interactive_shape_recognition/interactive_shape_recognition.dart'; +import 'package:one_dollar_unistroke_recognizer/one_dollar_unistroke_recognizer.dart'; import 'package:saber/components/canvas/_canvas_background_painter.dart'; import 'package:saber/components/canvas/_canvas_painter.dart'; import 'package:saber/components/canvas/_stroke.dart'; @@ -44,7 +44,7 @@ class InnerCanvas extends StatefulWidget { final bool textEditing; final EditorCoreInfo coreInfo; final Stroke? currentStroke; - final DetectedShape? currentStrokeDetectedShape; + final RecognizedUnistroke? currentStrokeDetectedShape; final SelectResult? currentSelection; final void Function(EditorImage image)? setAsBackground; final ValueChanged? onRenderObjectChange; diff --git a/lib/data/tools/shape_pen.dart b/lib/data/tools/shape_pen.dart index 1cd893af9..6a8d833db 100644 --- a/lib/data/tools/shape_pen.dart +++ b/lib/data/tools/shape_pen.dart @@ -2,8 +2,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:interactive_shape_recognition/interactive_shape_recognition.dart'; import 'package:logging/logging.dart'; +import 'package:one_dollar_unistroke_recognizer/one_dollar_unistroke_recognizer.dart'; import 'package:saber/components/canvas/_circle_stroke.dart'; import 'package:saber/components/canvas/_rectangle_stroke.dart'; import 'package:saber/components/canvas/_stroke.dart'; @@ -28,9 +28,9 @@ class ShapePen extends Pen { static const IconData shapePenIcon = FontAwesomeIcons.shapes; - static DetectedShape? detectedShape; + static RecognizedUnistroke? detectedShape; void _detectShape() { - detectedShape = Pen.currentStroke?.getDetectedShape(); + detectedShape = Pen.currentStroke?.detectShape(); } static Timer? _detectShapeDebouncer; @@ -57,23 +57,24 @@ class ShapePen extends Pen { if (detectedShape == null) return rawStroke; - switch (detectedShape.shape) { - case Shape.unknown: + switch (detectedShape.name) { + case null: log.info('Detected unknown shape'); return rawStroke; - case Shape.line: - log.info('Detected line: ${detectedShape.firstPoint} -> ${detectedShape.lastPoint}'); + case DefaultUnistrokeNames.line: + final (firstPoint, lastPoint) = detectedShape.convertToLine(); + log.info('Detected line: $firstPoint -> $lastPoint'); return Stroke( strokeProperties: rawStroke.strokeProperties, pageIndex: rawStroke.pageIndex, penType: rawStroke.penType, ) - ..addPoint(detectedShape.firstPoint) - ..addPoint(detectedShape.lastPoint) - ..addPoint(detectedShape.lastPoint) + ..addPoint(firstPoint) + ..addPoint(lastPoint) + ..addPoint(lastPoint) ..isComplete = true; - case Shape.rectangle: - final rect = detectedShape.generateRectangle(); + case DefaultUnistrokeNames.rectangle: + final rect = detectedShape.convertToRect(); log.info('Detected rectangle: $rect'); return RectangleStroke( strokeProperties: rawStroke.strokeProperties, @@ -81,16 +82,26 @@ class ShapePen extends Pen { penType: rawStroke.penType, rect: rect, ); - case Shape.circle: - final circle = detectedShape.generateCircle(); - log.info('Detected circle: $circle'); + case DefaultUnistrokeNames.circle: + final (center, radius) = detectedShape.convertToCircle(); + log.info('Detected circle: c=$center, r=$radius'); return CircleStroke( strokeProperties: rawStroke.strokeProperties, pageIndex: rawStroke.pageIndex, penType: rawStroke.penType, - radius: circle.$1, - center: circle.$2, + radius: radius, + center: center, ); + case DefaultUnistrokeNames.triangle: + final polygon = detectedShape.convertToCanonicalPolygon(); + log.info('Detected triangle'); + return Stroke( + strokeProperties: rawStroke.strokeProperties, + pageIndex: rawStroke.pageIndex, + penType: rawStroke.penType, + ) + ..addPoints(polygon) + ..isComplete = true; } } } diff --git a/pubspec.lock b/pubspec.lock index 83d60960c..0057a134d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,14 +25,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.4.9" - area_polygon: - dependency: transitive - description: - name: area_polygon - sha256: ed3072f73a922b5e7cfca79f274a750123108f0ccf3510579d2eac88424ba13a - url: "https://pub.dev" - source: hosted - version: "1.0.2" args: dependency: transitive description: @@ -162,14 +154,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" - convex_hull: - dependency: transitive - description: - name: convex_hull - sha256: "67489a600f0ae7b4a4851e896bbea01cf9f599af520ab8ab8390332d59da340d" - url: "https://pub.dev" - source: hosted - version: "1.1.2" cookie_jar: dependency: transitive description: @@ -622,14 +606,6 @@ packages: description: flutter source: sdk version: "0.0.0" - interactive_shape_recognition: - dependency: "direct main" - description: - name: interactive_shape_recognition - sha256: "9d44b70c45d60c81bc2a3340d25ee74e54bb616711d0592c274162bdc4e45742" - url: "https://pub.dev" - source: hosted - version: "1.2.0" intl: dependency: "direct main" description: @@ -760,6 +736,14 @@ packages: url: "https://github.com/nextcloud/neon" source: git version: "1.0.0" + one_dollar_unistroke_recognizer: + dependency: "direct main" + description: + name: one_dollar_unistroke_recognizer + sha256: "478ae7ccbe544d6a696c6fed222bd71f64f697f837fbbee158d5d0f6956e7f48" + url: "https://pub.dev" + source: hosted + version: "0.6.1" onyxsdk_pen: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 60268ff36..2592c6dd0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -148,7 +148,7 @@ dependencies: yaru: ^1.1.0 - interactive_shape_recognition: ^1.1.1 + one_dollar_unistroke_recognizer: ^0.6.1 meta: ^1.0.0