From 13cad714d3ee4c03de852fb0dc22c502e26683bb Mon Sep 17 00:00:00 2001 From: Michal Wolski Date: Wed, 4 Jan 2023 16:32:01 +0100 Subject: [PATCH 01/12] Add arrow shape --- .../photoediting/ShapeBSFragment.kt | 11 ++-- .../layout/fragment_bottom_shapes_dialog.xml | 6 +++ app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + .../burhanrashid52/photoeditor/DrawingView.kt | 13 +++-- .../photoeditor/shape/ArrowPointerPosition.kt | 3 ++ .../photoeditor/shape/LineShape.kt | 53 ++++++++++++++++++- .../photoeditor/shape/ShapeBuilder.kt | 2 +- .../photoeditor/shape/ShapeType.kt | 16 ++++-- .../ja/burhanrashid52/photoeditor/EnumTest.kt | 5 -- 10 files changed, 90 insertions(+), 21 deletions(-) create mode 100644 photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ArrowPointerPosition.kt diff --git a/app/src/main/java/com/burhanrashid52/photoediting/ShapeBSFragment.kt b/app/src/main/java/com/burhanrashid52/photoediting/ShapeBSFragment.kt index 4ba057b1..ffc755fc 100644 --- a/app/src/main/java/com/burhanrashid52/photoediting/ShapeBSFragment.kt +++ b/app/src/main/java/com/burhanrashid52/photoediting/ShapeBSFragment.kt @@ -41,16 +41,19 @@ class ShapeBSFragment : BottomSheetDialogFragment(), SeekBar.OnSeekBarChangeList shapeGroup.setOnCheckedChangeListener { _: RadioGroup?, checkedId: Int -> when(checkedId) { R.id.lineRadioButton -> { - mProperties!!.onShapePicked(ShapeType.LINE) + mProperties!!.onShapePicked(ShapeType.Line) + } + R.id.arrowRadioButton -> { + mProperties!!.onShapePicked(ShapeType.Arrow()) } R.id.ovalRadioButton -> { - mProperties!!.onShapePicked(ShapeType.OVAL) + mProperties!!.onShapePicked(ShapeType.Oval) } R.id.rectRadioButton -> { - mProperties!!.onShapePicked(ShapeType.RECTANGLE) + mProperties!!.onShapePicked(ShapeType.Rectangle) } else -> { - mProperties!!.onShapePicked(ShapeType.BRUSH) + mProperties!!.onShapePicked(ShapeType.Brush) } } } diff --git a/app/src/main/res/layout/fragment_bottom_shapes_dialog.xml b/app/src/main/res/layout/fragment_bottom_shapes_dialog.xml index 70ac2e23..d8e5b1a9 100644 --- a/app/src/main/res/layout/fragment_bottom_shapes_dialog.xml +++ b/app/src/main/res/layout/fragment_bottom_shapes_dialog.xml @@ -29,6 +29,12 @@ android:layout_height="wrap_content" android:text="@string/label_line" /> + + Ovale Rectangle Ligne + Flèche Frimousses Autocollant Gomme diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 669247d1..52b0bf3e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,6 +5,7 @@ Oval Rectangle Line + Arrow Emoji Sticker Eraser diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/DrawingView.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/DrawingView.kt index af21aa0a..20758865 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/DrawingView.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/DrawingView.kt @@ -136,19 +136,22 @@ class DrawingView @JvmOverloads constructor( if (isErasing) { paint = createEraserPaint() } else { - when(currentShapeBuilder?.shapeType){ - ShapeType.OVAL -> { + when (val shapeType = currentShapeBuilder?.shapeType) { + ShapeType.Oval -> { shape = OvalShape() } - ShapeType.BRUSH -> { + ShapeType.Brush -> { shape = BrushShape() } - ShapeType.RECTANGLE -> { + ShapeType.Rectangle -> { shape = RectangleShape() } - ShapeType.LINE -> { + ShapeType.Line -> { shape = LineShape() } + is ShapeType.Arrow -> { + shape = LineShape(shapeType.pointerPosition) + } } } diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ArrowPointerPosition.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ArrowPointerPosition.kt new file mode 100644 index 00000000..2e40488e --- /dev/null +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ArrowPointerPosition.kt @@ -0,0 +1,3 @@ +package ja.burhanrashid52.photoeditor.shape + +enum class ArrowPointerPosition { START, END, BOTH } \ No newline at end of file diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt index 17b4b95b..b96d3b2b 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt @@ -2,9 +2,17 @@ package ja.burhanrashid52.photoeditor.shape import android.graphics.Path import android.util.Log +import kotlin.math.PI import kotlin.math.abs +import kotlin.math.atan2 +import kotlin.math.cos +import kotlin.math.sin + + +class LineShape( + private val pointerPosition: ArrowPointerPosition? = null +) : AbstractShape("LineShape") { -class LineShape : AbstractShape("LineShape") { private var lastX = 0f private var lastY = 0f @@ -28,13 +36,56 @@ class LineShape : AbstractShape("LineShape") { private fun createLinePath(): Path { val path = Path() + + if (pointerPosition == ArrowPointerPosition.START || pointerPosition == ArrowPointerPosition.BOTH) { + drawArrow(path, left.toDouble(), top.toDouble(), right.toDouble(), bottom.toDouble()) + } + + if (pointerPosition == ArrowPointerPosition.END || pointerPosition == ArrowPointerPosition.BOTH) { + drawArrow(path, right.toDouble(), bottom.toDouble(), left.toDouble(), top.toDouble()) + } + path.moveTo(left, top) path.lineTo(right, bottom) path.close() + return path } + private fun drawArrow( + path: Path, + fromX: Double, + fromY: Double, + toX: Double, + toY: Double + ) { + // Based on: https://stackoverflow.com/a/41734848/1219654 + + val angleRad = (PI * ARROW_ANGLE / 180.0) + val lineAngle = atan2(toY - fromY, toX - fromX) + + path.moveTo(toX.toFloat(), toY.toFloat()) + path.lineTo( + (toX - ARROW_RADIUS * cos(lineAngle - angleRad / 2.0)).toFloat(), + (toY - ARROW_RADIUS * sin(lineAngle - angleRad / 2.0)).toFloat() + ) + + path.moveTo(toX.toFloat(), toY.toFloat()) + path.lineTo( + (toX - ARROW_RADIUS * cos(lineAngle + angleRad / 2.0)).toFloat(), + (toY - ARROW_RADIUS * sin(lineAngle + angleRad / 2.0)).toFloat() + ) + } + override fun stopShape() { Log.d(tag, "stopShape") } + + private companion object { + + const val ARROW_ANGLE = 60.0 + const val ARROW_RADIUS = 80.0 + + } + } \ No newline at end of file diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeBuilder.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeBuilder.kt index 3eb2d156..072f914f 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeBuilder.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeBuilder.kt @@ -57,7 +57,7 @@ class ShapeBuilder { init { // default values - withShapeType(ShapeType.BRUSH) + withShapeType(ShapeType.Brush) withShapeSize(DEFAULT_SHAPE_SIZE) withShapeOpacity(DEFAULT_SHAPE_OPACITY) withShapeColor(DEFAULT_SHAPE_COLOR) diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeType.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeType.kt index 89bb3f29..a6fca7ba 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeType.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeType.kt @@ -3,9 +3,15 @@ package ja.burhanrashid52.photoeditor.shape /** * The different kind of known Shapes. */ -enum class ShapeType { - BRUSH, - OVAL, - RECTANGLE, - LINE +sealed class ShapeType { + + object Brush : ShapeType() + object Oval : ShapeType() + object Rectangle : ShapeType() + object Line : ShapeType() + + class Arrow( + val pointerPosition: ArrowPointerPosition = ArrowPointerPosition.START + ) : ShapeType() + } \ No newline at end of file diff --git a/photoeditor/src/test/java/ja/burhanrashid52/photoeditor/EnumTest.kt b/photoeditor/src/test/java/ja/burhanrashid52/photoeditor/EnumTest.kt index 126b91c6..3373d734 100644 --- a/photoeditor/src/test/java/ja/burhanrashid52/photoeditor/EnumTest.kt +++ b/photoeditor/src/test/java/ja/burhanrashid52/photoeditor/EnumTest.kt @@ -11,11 +11,6 @@ class EnumTest { assertEquals(ViewType.values().size.toLong(), 4) } - @Test - fun testNumberOfShapeTypes() { - assertEquals(ShapeType.values().size.toLong(), 4) - } - @Test fun testNumberOfPhotoFilterTypes() { assertEquals(PhotoFilter.values().size.toLong(), 24) From 7748ee8caaf4f7207ed5d5f2c2fa8d9d3672a300 Mon Sep 17 00:00:00 2001 From: Michal Wolski Date: Thu, 5 Jan 2023 21:33:19 +0100 Subject: [PATCH 02/12] Change ShapeType class to interface --- .../burhanrashid52/photoeditor/shape/ShapeType.kt | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeType.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeType.kt index a6fca7ba..9ceedf58 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeType.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeType.kt @@ -3,15 +3,12 @@ package ja.burhanrashid52.photoeditor.shape /** * The different kind of known Shapes. */ -sealed class ShapeType { +sealed interface ShapeType { - object Brush : ShapeType() - object Oval : ShapeType() - object Rectangle : ShapeType() - object Line : ShapeType() - - class Arrow( - val pointerPosition: ArrowPointerPosition = ArrowPointerPosition.START - ) : ShapeType() + object Brush : ShapeType + object Oval : ShapeType + object Rectangle : ShapeType + object Line : ShapeType + class Arrow(val pointerPosition: ArrowPointerPosition = ArrowPointerPosition.START) : ShapeType } \ No newline at end of file From 5dc287de0225b7bbb97d195f03b12b770d3e231e Mon Sep 17 00:00:00 2001 From: Michal Wolski Date: Fri, 6 Jan 2023 16:35:39 +0100 Subject: [PATCH 03/12] Make arrow pointer length dependent on main line length --- .../burhanrashid52/photoeditor/shape/LineShape.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt index b96d3b2b..6a1bcc99 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt @@ -6,6 +6,7 @@ import kotlin.math.PI import kotlin.math.abs import kotlin.math.atan2 import kotlin.math.cos +import kotlin.math.max import kotlin.math.sin @@ -63,17 +64,19 @@ class LineShape( val angleRad = (PI * ARROW_ANGLE / 180.0) val lineAngle = atan2(toY - fromY, toX - fromX) + val arrowRadius = + (max(abs(toX - fromX), abs(toY - fromY)) / 2).coerceAtMost(ARROW_MAX_RADIUS) path.moveTo(toX.toFloat(), toY.toFloat()) path.lineTo( - (toX - ARROW_RADIUS * cos(lineAngle - angleRad / 2.0)).toFloat(), - (toY - ARROW_RADIUS * sin(lineAngle - angleRad / 2.0)).toFloat() + (toX - arrowRadius * cos(lineAngle - angleRad / 2.0)).toFloat(), + (toY - arrowRadius * sin(lineAngle - angleRad / 2.0)).toFloat() ) path.moveTo(toX.toFloat(), toY.toFloat()) path.lineTo( - (toX - ARROW_RADIUS * cos(lineAngle + angleRad / 2.0)).toFloat(), - (toY - ARROW_RADIUS * sin(lineAngle + angleRad / 2.0)).toFloat() + (toX - arrowRadius * cos(lineAngle + angleRad / 2.0)).toFloat(), + (toY - arrowRadius * sin(lineAngle + angleRad / 2.0)).toFloat() ) } @@ -84,7 +87,7 @@ class LineShape( private companion object { const val ARROW_ANGLE = 60.0 - const val ARROW_RADIUS = 80.0 + const val ARROW_MAX_RADIUS = 80.0 } From e3e4d510d2cfeaa4d0b1d3d4eadc05f996b350dc Mon Sep 17 00:00:00 2001 From: Michal Wolski Date: Fri, 6 Jan 2023 16:57:00 +0100 Subject: [PATCH 04/12] Change default arrow pointer location Change meaning of ArrowPointerLocation.START and ArrowPointerLocation.END. START point is first touched point and END is the last touched. This was inverted in initial commit. After few days of testing I realised that it's easier to draw arrow when pointer is placed on arrow's START, so I decided to change default pointer location. Because START and END meaning was changed in the commit, default pointer location value in ShapeType.Arrow() don't have to be changed. Also "pointer location" sounds better than "pointer position" so the name was also changed. --- .../java/ja/burhanrashid52/photoeditor/DrawingView.kt | 2 +- .../photoeditor/shape/ArrowPointerLocation.kt | 3 +++ .../photoeditor/shape/ArrowPointerPosition.kt | 3 --- .../ja/burhanrashid52/photoeditor/shape/LineShape.kt | 10 +++++----- .../ja/burhanrashid52/photoeditor/shape/ShapeType.kt | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ArrowPointerLocation.kt delete mode 100644 photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ArrowPointerPosition.kt diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/DrawingView.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/DrawingView.kt index 20758865..6b69c6d9 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/DrawingView.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/DrawingView.kt @@ -150,7 +150,7 @@ class DrawingView @JvmOverloads constructor( shape = LineShape() } is ShapeType.Arrow -> { - shape = LineShape(shapeType.pointerPosition) + shape = LineShape(shapeType.pointerLocation) } } } diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ArrowPointerLocation.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ArrowPointerLocation.kt new file mode 100644 index 00000000..7d5d79e2 --- /dev/null +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ArrowPointerLocation.kt @@ -0,0 +1,3 @@ +package ja.burhanrashid52.photoeditor.shape + +enum class ArrowPointerLocation { START, END, BOTH } \ No newline at end of file diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ArrowPointerPosition.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ArrowPointerPosition.kt deleted file mode 100644 index 2e40488e..00000000 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ArrowPointerPosition.kt +++ /dev/null @@ -1,3 +0,0 @@ -package ja.burhanrashid52.photoeditor.shape - -enum class ArrowPointerPosition { START, END, BOTH } \ No newline at end of file diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt index 6a1bcc99..5a47d612 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt @@ -11,7 +11,7 @@ import kotlin.math.sin class LineShape( - private val pointerPosition: ArrowPointerPosition? = null + private val pointerLocation: ArrowPointerLocation? = null ) : AbstractShape("LineShape") { private var lastX = 0f @@ -38,12 +38,12 @@ class LineShape( private fun createLinePath(): Path { val path = Path() - if (pointerPosition == ArrowPointerPosition.START || pointerPosition == ArrowPointerPosition.BOTH) { - drawArrow(path, left.toDouble(), top.toDouble(), right.toDouble(), bottom.toDouble()) + if (pointerLocation == ArrowPointerLocation.START || pointerLocation == ArrowPointerLocation.BOTH) { + drawArrow(path, right.toDouble(), bottom.toDouble(), left.toDouble(), top.toDouble()) } - if (pointerPosition == ArrowPointerPosition.END || pointerPosition == ArrowPointerPosition.BOTH) { - drawArrow(path, right.toDouble(), bottom.toDouble(), left.toDouble(), top.toDouble()) + if (pointerLocation == ArrowPointerLocation.END || pointerLocation == ArrowPointerLocation.BOTH) { + drawArrow(path, left.toDouble(), top.toDouble(), right.toDouble(), bottom.toDouble()) } path.moveTo(left, top) diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeType.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeType.kt index 9ceedf58..d9640cee 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeType.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/ShapeType.kt @@ -9,6 +9,6 @@ sealed interface ShapeType { object Oval : ShapeType object Rectangle : ShapeType object Line : ShapeType - class Arrow(val pointerPosition: ArrowPointerPosition = ArrowPointerPosition.START) : ShapeType + class Arrow(val pointerLocation: ArrowPointerLocation = ArrowPointerLocation.START) : ShapeType } \ No newline at end of file From 4acbd81817f8bc60a00a373262da9629fea911c1 Mon Sep 17 00:00:00 2001 From: Michal Wolski Date: Fri, 6 Jan 2023 18:00:29 +0100 Subject: [PATCH 05/12] Fix code format of LineShape.drawArrow() --- .../java/ja/burhanrashid52/photoeditor/shape/LineShape.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt index 5a47d612..72b9b209 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt @@ -53,13 +53,7 @@ class LineShape( return path } - private fun drawArrow( - path: Path, - fromX: Double, - fromY: Double, - toX: Double, - toY: Double - ) { + private fun drawArrow(path: Path, fromX: Double, fromY: Double, toX: Double, toY: Double) { // Based on: https://stackoverflow.com/a/41734848/1219654 val angleRad = (PI * ARROW_ANGLE / 180.0) From c9f0558b48b64cada84c6db8e07fab2a3781cc74 Mon Sep 17 00:00:00 2001 From: Michal Wolski Date: Sat, 7 Jan 2023 12:06:31 +0100 Subject: [PATCH 06/12] Optimize arrow drawing --- .../photoeditor/shape/LineShape.kt | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt index 72b9b209..a4ca60e1 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt @@ -39,11 +39,11 @@ class LineShape( val path = Path() if (pointerLocation == ArrowPointerLocation.START || pointerLocation == ArrowPointerLocation.BOTH) { - drawArrow(path, right.toDouble(), bottom.toDouble(), left.toDouble(), top.toDouble()) + drawArrow(path, right, bottom, left, top) } if (pointerLocation == ArrowPointerLocation.END || pointerLocation == ArrowPointerLocation.BOTH) { - drawArrow(path, left.toDouble(), top.toDouble(), right.toDouble(), bottom.toDouble()) + drawArrow(path, left, top, right, bottom) } path.moveTo(left, top) @@ -53,24 +53,23 @@ class LineShape( return path } - private fun drawArrow(path: Path, fromX: Double, fromY: Double, toX: Double, toY: Double) { + private fun drawArrow(path: Path, fromX: Float, fromY: Float, toX: Float, toY: Float) { // Based on: https://stackoverflow.com/a/41734848/1219654 - val angleRad = (PI * ARROW_ANGLE / 180.0) val lineAngle = atan2(toY - fromY, toX - fromX) val arrowRadius = - (max(abs(toX - fromX), abs(toY - fromY)) / 2).coerceAtMost(ARROW_MAX_RADIUS) + (max(abs(toX - fromX), abs(toY - fromY)) / 2.0f).coerceAtMost(ARROW_MAX_RADIUS) - path.moveTo(toX.toFloat(), toY.toFloat()) + path.moveTo(toX, toY) path.lineTo( - (toX - arrowRadius * cos(lineAngle - angleRad / 2.0)).toFloat(), - (toY - arrowRadius * sin(lineAngle - angleRad / 2.0)).toFloat() + (toX - arrowRadius * cos(lineAngle - ANGLE_RAD / 2.0f)), + (toY - arrowRadius * sin(lineAngle - ANGLE_RAD / 2.0f)) ) - path.moveTo(toX.toFloat(), toY.toFloat()) + path.moveTo(toX, toY) path.lineTo( - (toX - arrowRadius * cos(lineAngle + angleRad / 2.0)).toFloat(), - (toY - arrowRadius * sin(lineAngle + angleRad / 2.0)).toFloat() + (toX - arrowRadius * cos(lineAngle + ANGLE_RAD / 2.0f)), + (toY - arrowRadius * sin(lineAngle + ANGLE_RAD / 2.0f)) ) } @@ -81,7 +80,8 @@ class LineShape( private companion object { const val ARROW_ANGLE = 60.0 - const val ARROW_MAX_RADIUS = 80.0 + const val ANGLE_RAD = (PI * ARROW_ANGLE / 180.0).toFloat() + const val ARROW_MAX_RADIUS = 80.0f } From 105ecbd8fb65ed8c82eff7b9441a6cf7dc93087b Mon Sep 17 00:00:00 2001 From: Michal Wolski Date: Sat, 7 Jan 2023 13:23:35 +0100 Subject: [PATCH 07/12] Optimize angle calculation when drawing arrow --- .../burhanrashid52/photoeditor/shape/LineShape.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt index a4ca60e1..e72eb339 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt @@ -60,16 +60,19 @@ class LineShape( val arrowRadius = (max(abs(toX - fromX), abs(toY - fromY)) / 2.0f).coerceAtMost(ARROW_MAX_RADIUS) + val anglePointerA = lineAngle - ANGLE_RAD + val anglePointerB = lineAngle + ANGLE_RAD + path.moveTo(toX, toY) path.lineTo( - (toX - arrowRadius * cos(lineAngle - ANGLE_RAD / 2.0f)), - (toY - arrowRadius * sin(lineAngle - ANGLE_RAD / 2.0f)) + (toX - arrowRadius * cos(anglePointerA)), + (toY - arrowRadius * sin(anglePointerA)) ) path.moveTo(toX, toY) path.lineTo( - (toX - arrowRadius * cos(lineAngle + ANGLE_RAD / 2.0f)), - (toY - arrowRadius * sin(lineAngle + ANGLE_RAD / 2.0f)) + (toX - arrowRadius * cos(anglePointerB)), + (toY - arrowRadius * sin(anglePointerB)) ) } @@ -79,7 +82,7 @@ class LineShape( private companion object { - const val ARROW_ANGLE = 60.0 + const val ARROW_ANGLE = 30.0 const val ANGLE_RAD = (PI * ARROW_ANGLE / 180.0).toFloat() const val ARROW_MAX_RADIUS = 80.0f From 325523a61427a5c2b804741053a62e1bf701aa33 Mon Sep 17 00:00:00 2001 From: Michal Wolski Date: Sat, 7 Jan 2023 14:45:45 +0100 Subject: [PATCH 08/12] Fix arrow radius calculation --- .../java/ja/burhanrashid52/photoeditor/shape/LineShape.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt index e72eb339..8bfcab97 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt @@ -6,7 +6,7 @@ import kotlin.math.PI import kotlin.math.abs import kotlin.math.atan2 import kotlin.math.cos -import kotlin.math.max +import kotlin.math.hypot import kotlin.math.sin @@ -57,8 +57,7 @@ class LineShape( // Based on: https://stackoverflow.com/a/41734848/1219654 val lineAngle = atan2(toY - fromY, toX - fromX) - val arrowRadius = - (max(abs(toX - fromX), abs(toY - fromY)) / 2.0f).coerceAtMost(ARROW_MAX_RADIUS) + val arrowRadius = (hypot(toX - fromX, toY - fromY) / 2.0f).coerceAtMost(MAX_ARROW_RADIUS) val anglePointerA = lineAngle - ANGLE_RAD val anglePointerB = lineAngle + ANGLE_RAD @@ -84,7 +83,7 @@ class LineShape( const val ARROW_ANGLE = 30.0 const val ANGLE_RAD = (PI * ARROW_ANGLE / 180.0).toFloat() - const val ARROW_MAX_RADIUS = 80.0f + const val MAX_ARROW_RADIUS = 80.0f } From 59a2d616de3bb526ce30c44635a35e8d090f8aa2 Mon Sep 17 00:00:00 2001 From: Michal Wolski Date: Sat, 7 Jan 2023 15:07:45 +0100 Subject: [PATCH 09/12] Optimize arrow drawing --- .../java/ja/burhanrashid52/photoeditor/shape/LineShape.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt index 8bfcab97..41a82065 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt @@ -56,8 +56,11 @@ class LineShape( private fun drawArrow(path: Path, fromX: Float, fromY: Float, toX: Float, toY: Float) { // Based on: https://stackoverflow.com/a/41734848/1219654 - val lineAngle = atan2(toY - fromY, toX - fromX) - val arrowRadius = (hypot(toX - fromX, toY - fromY) / 2.0f).coerceAtMost(MAX_ARROW_RADIUS) + val xDistance = toX - fromX + val yDistance = toY - fromY + + val lineAngle = atan2(yDistance, xDistance) + val arrowRadius = (hypot(xDistance, yDistance) / 2.0f).coerceAtMost(MAX_ARROW_RADIUS) val anglePointerA = lineAngle - ANGLE_RAD val anglePointerB = lineAngle + ANGLE_RAD From 58d16a62907902b59cb34a1c84ffff0948ec3206 Mon Sep 17 00:00:00 2001 From: Michal Wolski Date: Wed, 11 Jan 2023 22:38:06 +0100 Subject: [PATCH 10/12] Use dp instead of px for max arrow radius --- .../ja/burhanrashid52/photoeditor/DrawingView.kt | 4 ++-- .../photoeditor/shape/LineShape.kt | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/DrawingView.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/DrawingView.kt index 6b69c6d9..7deee3a9 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/DrawingView.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/DrawingView.kt @@ -147,10 +147,10 @@ class DrawingView @JvmOverloads constructor( shape = RectangleShape() } ShapeType.Line -> { - shape = LineShape() + shape = LineShape(context) } is ShapeType.Arrow -> { - shape = LineShape(shapeType.pointerLocation) + shape = LineShape(context, shapeType.pointerLocation) } } } diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt index 41a82065..fea1354c 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt @@ -1,5 +1,6 @@ package ja.burhanrashid52.photoeditor.shape +import android.content.Context import android.graphics.Path import android.util.Log import kotlin.math.PI @@ -9,11 +10,13 @@ import kotlin.math.cos import kotlin.math.hypot import kotlin.math.sin - class LineShape( + context: Context, private val pointerLocation: ArrowPointerLocation? = null ) : AbstractShape("LineShape") { + private val maxArrowRadius = convertDpsToPixels(context, MAX_ARROW_RADIUS_DP).toFloat() + private var lastX = 0f private var lastY = 0f @@ -60,7 +63,7 @@ class LineShape( val yDistance = toY - fromY val lineAngle = atan2(yDistance, xDistance) - val arrowRadius = (hypot(xDistance, yDistance) / 2.0f).coerceAtMost(MAX_ARROW_RADIUS) + val arrowRadius = (hypot(xDistance, yDistance) / 2.0f).coerceAtMost(maxArrowRadius) val anglePointerA = lineAngle - ANGLE_RAD val anglePointerB = lineAngle + ANGLE_RAD @@ -86,7 +89,14 @@ class LineShape( const val ARROW_ANGLE = 30.0 const val ANGLE_RAD = (PI * ARROW_ANGLE / 180.0).toFloat() - const val MAX_ARROW_RADIUS = 80.0f + const val MAX_ARROW_RADIUS_DP = 32.0f + + fun convertDpsToPixels(context: Context, sizeDp: Float): Int { + // Convert the dps to pixels + val scale = context.resources.displayMetrics.density + // Use sizePx as a size in pixels + return (sizeDp * scale + 0.5f).toInt() + } } From f1041b9531b17f01371adc8aaff2373b4e0d979e Mon Sep 17 00:00:00 2001 From: Michal Wolski Date: Thu, 12 Jan 2023 20:27:05 +0100 Subject: [PATCH 11/12] Update calculation of arrow radius --- .../main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt index fea1354c..dd466baf 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt @@ -63,7 +63,7 @@ class LineShape( val yDistance = toY - fromY val lineAngle = atan2(yDistance, xDistance) - val arrowRadius = (hypot(xDistance, yDistance) / 2.0f).coerceAtMost(maxArrowRadius) + val arrowRadius = (hypot(xDistance, yDistance) / 2.5f).coerceAtMost(maxArrowRadius) val anglePointerA = lineAngle - ANGLE_RAD val anglePointerB = lineAngle + ANGLE_RAD From 61bbcf4922c35f61d5c77b7b0c607ea9f66177fb Mon Sep 17 00:00:00 2001 From: Michal Wolski Date: Mon, 16 Jan 2023 10:21:54 +0100 Subject: [PATCH 12/12] Change conditions order when checking if arrow pointer should be drawn --- .../java/ja/burhanrashid52/photoeditor/shape/LineShape.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt index dd466baf..54002157 100644 --- a/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt +++ b/photoeditor/src/main/java/ja/burhanrashid52/photoeditor/shape/LineShape.kt @@ -41,11 +41,11 @@ class LineShape( private fun createLinePath(): Path { val path = Path() - if (pointerLocation == ArrowPointerLocation.START || pointerLocation == ArrowPointerLocation.BOTH) { + if (pointerLocation == ArrowPointerLocation.BOTH || pointerLocation == ArrowPointerLocation.START) { drawArrow(path, right, bottom, left, top) } - if (pointerLocation == ArrowPointerLocation.END || pointerLocation == ArrowPointerLocation.BOTH) { + if (pointerLocation == ArrowPointerLocation.BOTH || pointerLocation == ArrowPointerLocation.END) { drawArrow(path, left, top, right, bottom) }