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 
17 package com.android.inputmethod.keyboard.internal;
18 
19 import android.graphics.Path;
20 import android.graphics.Rect;
21 import android.graphics.RectF;
22 
23 public 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 an instance of {@link Path} that holds the result rounded line, or an instance of
41      * {@link Path} that holds an empty path if the start and end points are equal.
42      */
makePath(final float p1x, final float p1y, final float r1, final float p2x, final float p2y, final float r2)43     public Path makePath(final float p1x, final float p1y, final float r1,
44             final float p2x, final float p2y, final float r2) {
45         mPath.rewind();
46         final double dx = p2x - p1x;
47         final double dy = p2y - p1y;
48         // Distance of the points.
49         final double l = Math.hypot(dx, dy);
50         if (Double.compare(0.0d, l) == 0) {
51             return mPath; // Return an empty path
52         }
53         // Angle of the line p1-p2
54         final double a = Math.atan2(dy, dx);
55         // Difference of trail cap radius.
56         final double dr = r2 - r1;
57         // Variation of angle at trail cap.
58         final double ar = Math.asin(dr / l);
59         // The start angle of trail cap arc at P1.
60         final double aa = a - (RIGHT_ANGLE + ar);
61         // The end angle of trail cap arc at P2.
62         final double ab = a + (RIGHT_ANGLE + ar);
63         final float cosa = (float)Math.cos(aa);
64         final float sina = (float)Math.sin(aa);
65         final float cosb = (float)Math.cos(ab);
66         final float sinb = (float)Math.sin(ab);
67         // Closing point of arc at P1.
68         final float p1ax = p1x + r1 * cosa;
69         final float p1ay = p1y + r1 * sina;
70         // Opening point of arc at P1.
71         final float p1bx = p1x + r1 * cosb;
72         final float p1by = p1y + r1 * sinb;
73         // Opening point of arc at P2.
74         final float p2ax = p2x + r2 * cosa;
75         final float p2ay = p2y + r2 * sina;
76         // Closing point of arc at P2.
77         final float p2bx = p2x + r2 * cosb;
78         final float p2by = p2y + r2 * sinb;
79         // Start angle of the trail arcs.
80         final float angle = (float)(aa * RADIAN_TO_DEGREE);
81         final float ar2degree = (float)(ar * 2.0d * RADIAN_TO_DEGREE);
82         // Sweep angle of the trail arc at P1.
83         final float a1 = -180.0f + ar2degree;
84         // Sweep angle of the trail arc at P2.
85         final float a2 = 180.0f + ar2degree;
86         mArc1.set(p1x, p1y, p1x, p1y);
87         mArc1.inset(-r1, -r1);
88         mArc2.set(p2x, p2y, p2x, p2y);
89         mArc2.inset(-r2, -r2);
90 
91         // Trail cap at P1.
92         mPath.moveTo(p1x, p1y);
93         mPath.arcTo(mArc1, angle, a1);
94         // Trail cap at P2.
95         mPath.moveTo(p2x, p2y);
96         mPath.arcTo(mArc2, angle, a2);
97         // Two trapezoids connecting P1 and P2.
98         mPath.moveTo(p1ax, p1ay);
99         mPath.lineTo(p1x, p1y);
100         mPath.lineTo(p1bx, p1by);
101         mPath.lineTo(p2bx, p2by);
102         mPath.lineTo(p2x, p2y);
103         mPath.lineTo(p2ax, p2ay);
104         mPath.close();
105         return mPath;
106     }
107 
getBounds(final Rect outBounds)108     public void getBounds(final Rect outBounds) {
109         // Reuse mArc1 as working variable
110         mPath.computeBounds(mArc1, true /* unused */);
111         mArc1.roundOut(outBounds);
112     }
113 }
114