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 */ 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 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