1f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka/*
2f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka * Copyright (C) 2012 The Android Open Source Project
3f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka *
48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License.
68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at
7f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka *
88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
9f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka *
108aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and
148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under the License.
15f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka */
16f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka
17f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaokapackage com.android.inputmethod.keyboard.internal;
18f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka
19f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaokaimport android.graphics.Path;
2084ce64f2c0255c25d8e697473b3c026d62cbe74dTadashi G. Takaokaimport android.graphics.Rect;
21f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaokaimport android.graphics.RectF;
22f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka
23f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaokapublic final class RoundedLine {
24e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka    private final RectF mArc1 = new RectF();
25e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka    private final RectF mArc2 = new RectF();
26e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka    private final Path mPath = new Path();
27f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka
28e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka    private static final double RADIAN_TO_DEGREE = 180.0d / Math.PI;
29e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka    private static final double RIGHT_ANGLE = Math.PI / 2.0d;
30f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka
31e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka    /**
32e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka     * Make a rounded line path
33e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka     *
34e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka     * @param p1x the x-coordinate of the start point.
35e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka     * @param p1y the y-coordinate of the start point.
36e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka     * @param r1 the radius at the start point
37e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka     * @param p2x the x-coordinate of the end point.
38e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka     * @param p2y the y-coordinate of the end point.
39e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka     * @param r2 the radius at the end point
40dfd96be03aba78f4bdb3b64d1b5d3f55429a0c03Tadashi G. Takaoka     * @return an instance of {@link Path} that holds the result rounded line, or an instance of
41dfd96be03aba78f4bdb3b64d1b5d3f55429a0c03Tadashi G. Takaoka     * {@link Path} that holds an empty path if the start and end points are equal.
42e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka     */
43e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka    public Path makePath(final float p1x, final float p1y, final float r1,
44e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka            final float p2x, final float p2y, final float r2) {
45dfd96be03aba78f4bdb3b64d1b5d3f55429a0c03Tadashi G. Takaoka        mPath.rewind();
46e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final double dx = p2x - p1x;
47e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final double dy = p2y - p1y;
48f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        // Distance of the points.
49f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        final double l = Math.hypot(dx, dy);
50f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        if (Double.compare(0.0d, l) == 0) {
51dfd96be03aba78f4bdb3b64d1b5d3f55429a0c03Tadashi G. Takaoka            return mPath; // Return an empty path
52f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        }
53f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        // Angle of the line p1-p2
54e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final double a = Math.atan2(dy, dx);
55f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        // Difference of trail cap radius.
56e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final double dr = r2 - r1;
57f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        // Variation of angle at trail cap.
58e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final double ar = Math.asin(dr / l);
59f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        // The start angle of trail cap arc at P1.
60e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final double aa = a - (RIGHT_ANGLE + ar);
61f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        // The end angle of trail cap arc at P2.
62e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final double ab = a + (RIGHT_ANGLE + ar);
63f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        final float cosa = (float)Math.cos(aa);
64f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        final float sina = (float)Math.sin(aa);
65f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        final float cosb = (float)Math.cos(ab);
66f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        final float sinb = (float)Math.sin(ab);
67e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        // Closing point of arc at P1.
68e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final float p1ax = p1x + r1 * cosa;
69e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final float p1ay = p1y + r1 * sina;
70e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        // Opening point of arc at P1.
71e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final float p1bx = p1x + r1 * cosb;
72e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final float p1by = p1y + r1 * sinb;
73e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        // Opening point of arc at P2.
74e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final float p2ax = p2x + r2 * cosa;
75e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final float p2ay = p2y + r2 * sina;
76e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        // Closing point of arc at P2.
77e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final float p2bx = p2x + r2 * cosb;
78e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final float p2by = p2y + r2 * sinb;
79e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        // Start angle of the trail arcs.
80e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final float angle = (float)(aa * RADIAN_TO_DEGREE);
81e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final float ar2degree = (float)(ar * 2.0d * RADIAN_TO_DEGREE);
82e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        // Sweep angle of the trail arc at P1.
83e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final float a1 = -180.0f + ar2degree;
84e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        // Sweep angle of the trail arc at P2.
85e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        final float a2 = 180.0f + ar2degree;
86e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mArc1.set(p1x, p1y, p1x, p1y);
87e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mArc1.inset(-r1, -r1);
88e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mArc2.set(p2x, p2y, p2x, p2y);
89e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mArc2.inset(-r2, -r2);
90f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka
91f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        // Trail cap at P1.
92e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mPath.moveTo(p1x, p1y);
93e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mPath.arcTo(mArc1, angle, a1);
94f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        // Trail cap at P2.
95e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mPath.moveTo(p2x, p2y);
96e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mPath.arcTo(mArc2, angle, a2);
97f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka        // Two trapezoids connecting P1 and P2.
98e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mPath.moveTo(p1ax, p1ay);
99e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mPath.lineTo(p1x, p1y);
100e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mPath.lineTo(p1bx, p1by);
101e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mPath.lineTo(p2bx, p2by);
102e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mPath.lineTo(p2x, p2y);
103e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mPath.lineTo(p2ax, p2ay);
104e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        mPath.close();
105e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka        return mPath;
106f90475b5d4c2f94188ace4b7dd45160a02d1d204Tadashi G. Takaoka    }
10784ce64f2c0255c25d8e697473b3c026d62cbe74dTadashi G. Takaoka
10884ce64f2c0255c25d8e697473b3c026d62cbe74dTadashi G. Takaoka    public void getBounds(final Rect outBounds) {
10984ce64f2c0255c25d8e697473b3c026d62cbe74dTadashi G. Takaoka        // Reuse mArc1 as working variable
11084ce64f2c0255c25d8e697473b3c026d62cbe74dTadashi G. Takaoka        mPath.computeBounds(mArc1, true /* unused */);
11184ce64f2c0255c25d8e697473b3c026d62cbe74dTadashi G. Takaoka        mArc1.roundOut(outBounds);
11284ce64f2c0255c25d8e697473b3c026d62cbe74dTadashi G. Takaoka    }
113e14df775d454cb96b751cf7668df71ce5873930dTadashi G. Takaoka}
114