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