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