Skip to content

Commit 2de8825

Browse files
author
Dan Oprea
committed
Allow to move lines too
1 parent e05696a commit 2de8825

File tree

2 files changed

+220
-90
lines changed

2 files changed

+220
-90
lines changed

app/src/main/java/com/dan/perspective/EditPerspectiveImageView.kt

Lines changed: 217 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,19 @@ class EditPerspectiveImageView @JvmOverloads constructor(
4242

4343
private val trackedOldPosition = PointF()
4444

45+
//Point edit or first point of line edit
4546
private var trackedPoint: PointF? = null
4647
private var trackedViewPoint = PointF()
4748
private var trackedAllowedRect = RectF()
4849
private var trackedMovedAlongLine: LineF? = null
4950
private var trackedMovedAlongLineHorizontal = true
5051

52+
//Second point of line edit
53+
private var trackedPoint2: PointF? = null
54+
private var trackedViewPoint2 = PointF()
55+
private var trackedAllowedRect2 = RectF()
56+
private var trackedMovedAlongLine2: LineF? = null
57+
5158
private val paint = Paint()
5259
private var onPerspectiveChanged: (()->Unit)? = null
5360
private var onEditStart: (()->Unit)? = null
@@ -158,10 +165,26 @@ class EditPerspectiveImageView @JvmOverloads constructor(
158165
paint.style = Paint.Style.FILL_AND_STROKE
159166
paint.color = Color.argb( 128, 0, 0, 255 )
160167

161-
drawPoint( viewPerspective.pointLeftTop, canvas, paint, perspectivePoints.pointLeftTop == trackedPoint )
162-
drawPoint( viewPerspective.pointLeftBottom, canvas, paint, perspectivePoints.pointLeftBottom == trackedPoint )
163-
drawPoint( viewPerspective.pointRightTop, canvas, paint, perspectivePoints.pointRightTop == trackedPoint )
164-
drawPoint( viewPerspective.pointRightBottom, canvas, paint, perspectivePoints.pointRightBottom == trackedPoint )
168+
drawPoint(
169+
viewPerspective.pointLeftTop,
170+
canvas,
171+
paint,
172+
perspectivePoints.pointLeftTop == trackedPoint || perspectivePoints.pointLeftTop == trackedPoint2)
173+
drawPoint(
174+
viewPerspective.pointLeftBottom,
175+
canvas,
176+
paint,
177+
perspectivePoints.pointLeftBottom == trackedPoint || perspectivePoints.pointLeftBottom == trackedPoint2)
178+
drawPoint(
179+
viewPerspective.pointRightTop,
180+
canvas,
181+
paint,
182+
perspectivePoints.pointRightTop == trackedPoint || perspectivePoints.pointRightTop == trackedPoint2)
183+
drawPoint(
184+
viewPerspective.pointRightBottom,
185+
canvas,
186+
paint,
187+
perspectivePoints.pointRightBottom == trackedPoint || perspectivePoints.pointRightBottom == trackedPoint2)
165188
}
166189

167190
private fun distance( pointA: PointF, pointB: PointF ): Float =
@@ -172,13 +195,26 @@ class EditPerspectiveImageView @JvmOverloads constructor(
172195
trackedViewPoint: PointF,
173196
allowedRect: RectF,
174197
moveAlongLine: LineF? = null,
175-
lineIsHorizontal: Boolean = true
198+
lineIsHorizontal: Boolean = true,
199+
trackedPoint2: PointF? = null,
200+
trackedViewPoint2: PointF? = null,
201+
allowedRect2: RectF? = null,
202+
moveAlongLine2: LineF? = null
176203
) {
177204
this.trackedPoint = trackedPoint
178205
this.trackedViewPoint.set( trackedViewPoint )
179206
this.trackedAllowedRect.set( allowedRect )
180207
this.trackedMovedAlongLine = moveAlongLine
181208
this.trackedMovedAlongLineHorizontal = lineIsHorizontal
209+
210+
if (null != trackedPoint2 && null != trackedViewPoint2 && null != allowedRect2) {
211+
this.trackedPoint2 = trackedPoint2
212+
this.trackedViewPoint2.set( trackedViewPoint2 )
213+
this.trackedAllowedRect2.set( allowedRect2 )
214+
this.trackedMovedAlongLine2 = moveAlongLine2
215+
} else {
216+
this.trackedPoint2 = null
217+
}
182218
}
183219

184220
private fun calculateNewViewPoint(
@@ -215,104 +251,195 @@ class EditPerspectiveImageView @JvmOverloads constructor(
215251
)
216252
}
217253

218-
override fun onTouchEvent(event: MotionEvent?): Boolean {
219-
if (null == event) return true
220-
val bitmap = super.getBitmap() ?: return true
254+
private fun handleActionDown( event: MotionEvent, bitmap: Bitmap ): Boolean {
255+
if (null != trackedPoint) return true
221256

222-
when( event.action ) {
223-
MotionEvent.ACTION_DOWN -> {
224-
if (null == trackedPoint) {
225-
transform.set(bitmap.width, bitmap.height, viewRect)
226-
227-
val screenPoint = PointF(event.x, event.y)
228-
val viewPerspective = transform.mapToView(perspectivePoints)
229-
val minDistance = dpToPixels(MIN_POINT_DISTANCE_TO_TRACK)
230-
231-
trackedOldPosition.set(event.x, event.y)
232-
233-
when {
234-
distance(viewPerspective.pointLeftTop, screenPoint) < minDistance -> {
235-
startEdit(
236-
perspectivePoints.pointLeftTop,
237-
viewPerspective.pointLeftTop,
238-
viewPerspective.safeRectLeftTop(),
239-
getMoveAlongLine( viewPerspective.pointLeftTop, viewPerspective.pointRightTop, viewPerspective.pointLeftBottom ),
240-
pointEditDirection == POINT_EDIT_DIRECTION_HORIZONTAL
241-
)
242-
}
243-
244-
distance(viewPerspective.pointLeftBottom, screenPoint) < minDistance -> {
245-
startEdit(
246-
perspectivePoints.pointLeftBottom,
247-
viewPerspective.pointLeftBottom,
248-
viewPerspective.safeRectLeftBottom(),
249-
getMoveAlongLine( viewPerspective.pointLeftBottom, viewPerspective.pointRightBottom, viewPerspective.pointLeftTop ),
250-
pointEditDirection == POINT_EDIT_DIRECTION_HORIZONTAL
251-
)
252-
}
253-
254-
distance(viewPerspective.pointRightTop, screenPoint) < minDistance -> {
255-
startEdit(
256-
perspectivePoints.pointRightTop,
257-
viewPerspective.pointRightTop,
258-
viewPerspective.safeRectRightTop(),
259-
getMoveAlongLine( viewPerspective.pointRightTop, viewPerspective.pointLeftTop, viewPerspective.pointRightBottom ),
260-
pointEditDirection == POINT_EDIT_DIRECTION_HORIZONTAL
261-
)
262-
}
263-
264-
distance(viewPerspective.pointRightBottom, screenPoint) < minDistance -> {
265-
startEdit(
266-
perspectivePoints.pointRightBottom,
267-
viewPerspective.pointRightBottom,
268-
viewPerspective.safeRectRightBottom(),
269-
getMoveAlongLine( viewPerspective.pointRightBottom, viewPerspective.pointLeftBottom, viewPerspective.pointRightTop ),
270-
pointEditDirection == POINT_EDIT_DIRECTION_HORIZONTAL
271-
)
272-
}
273-
}
274-
275-
if (null != trackedPoint) onEditStart?.invoke()
276-
}
257+
transform.set(bitmap.width, bitmap.height, viewRect)
258+
259+
val screenPoint = PointF(event.x, event.y)
260+
val viewPerspective = transform.mapToView(perspectivePoints)
261+
val minDistance = dpToPixels(MIN_POINT_DISTANCE_TO_TRACK)
262+
val allowEditLineHorizontal = POINT_EDIT_DIRECTION_ALL == pointEditDirection || POINT_EDIT_DIRECTION_HORIZONTAL == pointEditDirection
263+
val allowEditLineVertical = POINT_EDIT_DIRECTION_ALL == pointEditDirection || POINT_EDIT_DIRECTION_VERTICAL == pointEditDirection
264+
265+
trackedOldPosition.set(event.x, event.y)
266+
267+
when {
268+
distance(viewPerspective.pointLeftTop, screenPoint) < minDistance -> {
269+
startEdit(
270+
perspectivePoints.pointLeftTop,
271+
viewPerspective.pointLeftTop,
272+
viewPerspective.safeRectLeftTop(),
273+
getMoveAlongLine( viewPerspective.pointLeftTop, viewPerspective.pointRightTop, viewPerspective.pointLeftBottom ),
274+
pointEditDirection == POINT_EDIT_DIRECTION_HORIZONTAL
275+
)
277276
}
278277

279-
MotionEvent.ACTION_MOVE -> {
280-
val trackedPoint = this.trackedPoint
278+
distance(viewPerspective.pointLeftBottom, screenPoint) < minDistance -> {
279+
startEdit(
280+
perspectivePoints.pointLeftBottom,
281+
viewPerspective.pointLeftBottom,
282+
viewPerspective.safeRectLeftBottom(),
283+
getMoveAlongLine( viewPerspective.pointLeftBottom, viewPerspective.pointRightBottom, viewPerspective.pointLeftTop ),
284+
pointEditDirection == POINT_EDIT_DIRECTION_HORIZONTAL
285+
)
286+
}
281287

282-
if (null != trackedPoint) {
283-
transform.set(bitmap.width, bitmap.height, viewRect)
288+
distance(viewPerspective.pointRightTop, screenPoint) < minDistance -> {
289+
startEdit(
290+
perspectivePoints.pointRightTop,
291+
viewPerspective.pointRightTop,
292+
viewPerspective.safeRectRightTop(),
293+
getMoveAlongLine( viewPerspective.pointRightTop, viewPerspective.pointLeftTop, viewPerspective.pointRightBottom ),
294+
pointEditDirection == POINT_EDIT_DIRECTION_HORIZONTAL
295+
)
296+
}
284297

285-
val newTrackedViewPoint = calculateNewViewPoint(
286-
event.x - trackedOldPosition.x,
287-
event.y - trackedOldPosition.y,
288-
trackedViewPoint,
289-
trackedAllowedRect,
290-
trackedMovedAlongLine,
291-
trackedMovedAlongLineHorizontal
292-
)
298+
distance(viewPerspective.pointRightBottom, screenPoint) < minDistance -> {
299+
startEdit(
300+
perspectivePoints.pointRightBottom,
301+
viewPerspective.pointRightBottom,
302+
viewPerspective.safeRectRightBottom(),
303+
getMoveAlongLine( viewPerspective.pointRightBottom, viewPerspective.pointLeftBottom, viewPerspective.pointRightTop ),
304+
pointEditDirection == POINT_EDIT_DIRECTION_HORIZONTAL
305+
)
306+
}
293307

294-
trackedOldPosition.set(event.x, event.y)
308+
allowEditLineVertical && viewPerspective.lineTop.distanceFrom(screenPoint) < minDistance -> {
309+
startEdit(
310+
perspectivePoints.lineTop.from,
311+
viewPerspective.lineTop.from,
312+
viewPerspective.safeRectLeftTop(),
313+
viewPerspective.lineLeft.clone(),
314+
false,
315+
perspectivePoints.lineTop.to,
316+
viewPerspective.lineTop.to,
317+
viewPerspective.safeRectRightTop(),
318+
viewPerspective.lineRight.clone()
319+
)
320+
}
295321

296-
if (null != newTrackedViewPoint) {
297-
trackedViewPoint.set(newTrackedViewPoint)
298-
trackedPoint.set(transform.mapToBitmap(trackedViewPoint))
299-
invalidate()
300-
onPerspectiveChanged?.invoke()
301-
}
322+
allowEditLineVertical && viewPerspective.lineBottom.distanceFrom(screenPoint) < minDistance -> {
323+
startEdit(
324+
perspectivePoints.lineBottom.from,
325+
viewPerspective.lineBottom.from,
326+
viewPerspective.safeRectLeftBottom(),
327+
viewPerspective.lineLeft.clone(),
328+
false,
329+
perspectivePoints.lineBottom.to,
330+
viewPerspective.lineBottom.to,
331+
viewPerspective.safeRectRightBottom(),
332+
viewPerspective.lineRight.clone()
333+
)
334+
}
302335

303-
return true
304-
}
336+
allowEditLineHorizontal && viewPerspective.lineLeft.distanceFrom(screenPoint) < minDistance -> {
337+
startEdit(
338+
perspectivePoints.lineLeft.from,
339+
viewPerspective.lineLeft.from,
340+
viewPerspective.safeRectLeftTop(),
341+
viewPerspective.lineTop.clone(),
342+
true,
343+
perspectivePoints.lineLeft.to,
344+
viewPerspective.lineLeft.to,
345+
viewPerspective.safeRectLeftBottom(),
346+
viewPerspective.lineBottom.clone()
347+
)
305348
}
306349

307-
MotionEvent.ACTION_UP -> {
308-
if (null != trackedPoint) {
309-
trackedPoint = null
310-
onEditEnd?.invoke()
311-
return true
312-
}
350+
allowEditLineHorizontal && viewPerspective.lineRight.distanceFrom(screenPoint) < minDistance -> {
351+
startEdit(
352+
perspectivePoints.lineRight.from,
353+
viewPerspective.lineRight.from,
354+
viewPerspective.safeRectRightTop(),
355+
viewPerspective.lineTop.clone(),
356+
true,
357+
perspectivePoints.lineRight.to,
358+
viewPerspective.lineRight.to,
359+
viewPerspective.safeRectRightBottom(),
360+
viewPerspective.lineBottom.clone()
361+
)
313362
}
314363
}
315364

365+
if (null != trackedPoint) {
366+
onEditStart?.invoke()
367+
return true
368+
}
369+
370+
return false
371+
}
372+
373+
private fun handleActionMove(event: MotionEvent, bitmap: Bitmap): Boolean {
374+
val trackedPoint = this.trackedPoint ?: return false
375+
376+
transform.set(bitmap.width, bitmap.height, viewRect)
377+
378+
val dx = event.x - trackedOldPosition.x
379+
val dy = event.y - trackedOldPosition.y
380+
381+
trackedOldPosition.set(event.x, event.y)
382+
383+
Log.i("[PERSPECTIVE]", "dx: $dx, dy: $dy")
384+
385+
if (dx > 2) {
386+
trackedOldPosition.set(event.x, event.y)
387+
}
388+
389+
val newTrackedViewPoint = calculateNewViewPoint(
390+
dx,
391+
dy,
392+
trackedViewPoint,
393+
trackedAllowedRect,
394+
trackedMovedAlongLine,
395+
trackedMovedAlongLineHorizontal
396+
) ?: return true
397+
398+
val trackedPoint2 = this.trackedPoint2
399+
if (null != trackedPoint2) {
400+
val newTrackedViewPoint2 = calculateNewViewPoint(
401+
dx,
402+
dy,
403+
trackedViewPoint2,
404+
trackedAllowedRect2,
405+
trackedMovedAlongLine2,
406+
trackedMovedAlongLineHorizontal
407+
) ?: return true
408+
409+
trackedViewPoint2.set(newTrackedViewPoint2)
410+
trackedPoint2.set(transform.mapToBitmap(trackedViewPoint2))
411+
}
412+
413+
trackedViewPoint.set(newTrackedViewPoint)
414+
trackedPoint.set(transform.mapToBitmap(trackedViewPoint))
415+
416+
invalidate()
417+
onPerspectiveChanged?.invoke()
418+
419+
return true
420+
}
421+
422+
private fun handleActionUp(): Boolean {
423+
if (null != trackedPoint) {
424+
trackedPoint = null
425+
trackedPoint2 = null
426+
onEditEnd?.invoke()
427+
return true
428+
}
429+
430+
return false
431+
}
432+
433+
override fun onTouchEvent(event: MotionEvent?): Boolean {
434+
if (null == event) return true
435+
val bitmap = super.getBitmap() ?: return true
436+
437+
when( event.action ) {
438+
MotionEvent.ACTION_DOWN -> if (handleActionDown(event, bitmap)) return true
439+
MotionEvent.ACTION_MOVE -> if (handleActionMove(event, bitmap)) return true
440+
MotionEvent.ACTION_UP -> if (handleActionUp()) return true
441+
}
442+
316443
if (null != trackedPoint) {
317444
Log.i("EDIT", "Track is ON")
318445
return true

app/src/main/java/com/dan/perspective/LineF.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ data class LineF(val from: PointF, val to: PointF) {
1717
return sqrt(dx * dx + dy * dy)
1818
}
1919

20+
fun clone(): LineF =
21+
LineF( PointF(from.x, from.y), PointF(to.x, to.y) )
22+
2023
fun intersection( lineOther: LineF ): PointF? {
2124
val denominator = segmentDeltaX * lineOther.segmentDeltaY - segmentDeltaY * lineOther.segmentDeltaX
2225
if (abs(denominator) < EPSILON) return null

0 commit comments

Comments
 (0)