diff options
Diffstat (limited to 'java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java')
-rw-r--r-- | java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java | 135 |
1 files changed, 119 insertions, 16 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java index 4311fa775..699aaeaef 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java @@ -17,7 +17,9 @@ package com.android.inputmethod.keyboard.internal; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.Rect; +import android.graphics.RectF; import android.os.SystemClock; import com.android.inputmethod.latin.Constants; @@ -25,7 +27,7 @@ import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.ResizableIntArray; final class GesturePreviewTrail { - private static final int DEFAULT_CAPACITY = GestureStrokeWithPreviewTrail.PREVIEW_CAPACITY; + private static final int DEFAULT_CAPACITY = GestureStrokeWithPreviewPoints.PREVIEW_CAPACITY; private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); @@ -78,7 +80,7 @@ final class GesturePreviewTrail { ? DOWN_EVENT_MARKER - xCoordOrMark : xCoordOrMark; } - public void addStroke(final GestureStrokeWithPreviewTrail stroke, final long downTime) { + public void addStroke(final GestureStrokeWithPreviewPoints stroke, final long downTime) { final int trailSize = mEventTimes.getLength(); stroke.appendPreviewStroke(mEventTimes, mXCoordinates, mYCoordinates); if (mEventTimes.getLength() == trailSize) { @@ -116,6 +118,99 @@ final class GesturePreviewTrail { / params.mTrailLingerDuration, 0.0f); } + static final class WorkingSet { + // Input + // Previous point (P1) coordinates and trail radius. + public float p1x, p1y; + public float r1; + // Current point (P2) coordinates and trail radius. + public float p2x, p2y; + public float r2; + + // Output + // Closing point of arc at P1. + public float p1ax, p1ay; + // Opening point of arc at P1. + public float p1bx, p1by; + // Opening point of arc at P2. + public float p2ax, p2ay; + // Closing point of arc at P2. + public float p2bx, p2by; + // Start angle of the trail arcs. + public float aa; + // Sweep angle of the trail arc at P1. + public float a1; + public RectF arc1 = new RectF(); + // Sweep angle of the trail arc at P2. + public float a2; + public RectF arc2 = new RectF(); + } + + private static final float RIGHT_ANGLE = (float)(Math.PI / 2.0d); + private static final float RADIAN_TO_DEGREE = (float)(180.0d / Math.PI); + + private static boolean calculatePathPoints(final WorkingSet w) { + final float dx = w.p2x - w.p1x; + final float dy = w.p2y - w.p1y; + // Distance of the points. + final double l = Math.hypot(dx, dy); + if (Double.compare(0.0d, l) == 0) { + return false; + } + // Angle of the line p1-p2 + final float a = (float)Math.atan2(dy, dx); + // Difference of trail cap radius. + final float dr = w.r2 - w.r1; + // Variation of angle at trail cap. + final float ar = (float)Math.asin(dr / l); + // The start angle of trail cap arc at P1. + final float aa = a - (RIGHT_ANGLE + ar); + // The end angle of trail cap arc at P2. + final float ab = a + (RIGHT_ANGLE + ar); + final float cosa = (float)Math.cos(aa); + final float sina = (float)Math.sin(aa); + final float cosb = (float)Math.cos(ab); + final float sinb = (float)Math.sin(ab); + w.p1ax = w.p1x + w.r1 * cosa; + w.p1ay = w.p1y + w.r1 * sina; + w.p1bx = w.p1x + w.r1 * cosb; + w.p1by = w.p1y + w.r1 * sinb; + w.p2ax = w.p2x + w.r2 * cosa; + w.p2ay = w.p2y + w.r2 * sina; + w.p2bx = w.p2x + w.r2 * cosb; + w.p2by = w.p2y + w.r2 * sinb; + w.aa = aa * RADIAN_TO_DEGREE; + final float ar2degree = ar * 2.0f * RADIAN_TO_DEGREE; + w.a1 = -180.0f + ar2degree; + w.a2 = 180.0f + ar2degree; + w.arc1.set(w.p1x, w.p1y, w.p1x, w.p1y); + w.arc1.inset(-w.r1, -w.r1); + w.arc2.set(w.p2x, w.p2y, w.p2x, w.p2y); + w.arc2.inset(-w.r2, -w.r2); + return true; + } + + private static void createPath(final Path path, final WorkingSet w) { + path.rewind(); + // Trail cap at P1. + path.moveTo(w.p1x, w.p1y); + path.arcTo(w.arc1, w.aa, w.a1); + // Trail cap at P2. + path.moveTo(w.p2x, w.p2y); + path.arcTo(w.arc2, w.aa, w.a2); + // Two trapezoids connecting P1 and P2. + path.moveTo(w.p1ax, w.p1ay); + path.lineTo(w.p1x, w.p1y); + path.lineTo(w.p1bx, w.p1by); + path.lineTo(w.p2bx, w.p2by); + path.lineTo(w.p2x, w.p2y); + path.lineTo(w.p2ax, w.p2ay); + path.close(); + } + + private final WorkingSet mWorkingSet = new WorkingSet(); + private final Path mPath = new Path(); + /** * Draw gesture preview trail * @param canvas The canvas to draw the gesture preview trail @@ -147,30 +242,38 @@ final class GesturePreviewTrail { if (startIndex < trailSize) { paint.setColor(params.mTrailColor); - paint.setStyle(Paint.Style.STROKE); - paint.setStrokeCap(Paint.Cap.ROUND); - int lastX = getXCoordValue(xCoords[startIndex]); - int lastY = yCoords[startIndex]; - float maxWidth = getWidth(sinceDown - eventTimes[startIndex], params); + paint.setStyle(Paint.Style.FILL); + final Path path = mPath; + final WorkingSet w = mWorkingSet; + w.p1x = getXCoordValue(xCoords[startIndex]); + w.p1y = yCoords[startIndex]; + int lastTime = sinceDown - eventTimes[startIndex]; + float maxWidth = getWidth(lastTime, params); + w.r1 = maxWidth / 2.0f; // Initialize bounds rectangle. - outBoundsRect.set(lastX, lastY, lastX, lastY); + outBoundsRect.set((int)w.p1x, (int)w.p1y, (int)w.p1x, (int)w.p1y); for (int i = startIndex + 1; i < trailSize - 1; i++) { - final int x = xCoords[i]; - final int y = yCoords[i]; final int elapsedTime = sinceDown - eventTimes[i]; + w.p2x = getXCoordValue(xCoords[i]); + w.p2y = yCoords[i]; // Draw trail line only when the current point isn't a down point. - if (!isDownEventXCoord(x)) { + if (!isDownEventXCoord(xCoords[i])) { final int alpha = getAlpha(elapsedTime, params); paint.setAlpha(alpha); final float width = getWidth(elapsedTime, params); - paint.setStrokeWidth(width); - canvas.drawLine(lastX, lastY, x, y, paint); + w.r2 = width / 2.0f; + if (calculatePathPoints(w)) { + createPath(path, w); + canvas.drawPath(path, paint); + outBoundsRect.union((int)w.p2x, (int)w.p2y); + } // Take union for the bounds. - outBoundsRect.union(x, y); maxWidth = Math.max(maxWidth, width); } - lastX = getXCoordValue(x); - lastY = y; + w.p1x = w.p2x; + w.p1y = w.p2y; + w.r1 = w.r2; + lastTime = elapsedTime; } // Take care of trail line width. final int inset = -((int)maxWidth + 1); |