1 /* 2 * Copyright 2012 AndroidPlot.com 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.androidplot.util; 18 19 import android.content.Context; 20 import android.graphics.PointF; 21 import android.graphics.Rect; 22 import android.graphics.RectF; 23 import android.util.DisplayMetrics; 24 import android.util.TypedValue; 25 26 import java.util.Collections; 27 import java.util.HashMap; 28 import java.util.Map; 29 import java.util.regex.Matcher; 30 import java.util.regex.Pattern; 31 32 public class PixelUtils { 33 private static DisplayMetrics metrics; 34 private static final float FLOAT_INT_AVG_NUDGE = 0.5f; 35 //private static float SCALE = 1; // pix per dp 36 //private static int X_PIX = 1; // total display horizontal pix 37 //private static int Y_PIX = 1; // total display vertical pix 38 39 /** 40 * Recalculates scale value etc. Should be called when an application starts or 41 * whenever the screen is rotated. 42 */ init(Context ctx)43 public static void init(Context ctx) { 44 //DisplayMetrics dm = ctx.getResources().getDisplayMetrics(); 45 //SCALE = dm.density; 46 //X_PIX = dm.widthPixels; 47 //Y_PIX = dm.heightPixels; 48 metrics = ctx.getResources().getDisplayMetrics(); 49 50 } 51 add(PointF lhs, PointF rhs)52 public static PointF add(PointF lhs, PointF rhs) { 53 return new PointF(lhs.x + rhs.x, lhs.y + rhs.y); 54 } 55 sub(PointF lhs, PointF rhs)56 public static PointF sub(PointF lhs, PointF rhs) { 57 return new PointF(lhs.x - rhs.x, lhs.y - rhs.y); 58 } 59 60 /** 61 * Converts a sub-pixel accurate RectF to a Rect 62 * using the closest matching full pixel vals. This is 63 * useful for clipping operations etc. 64 * @param rectIn The rect to be converted 65 * @return 66 */ 67 /*public static Rect toRect(RectF rectIn) { 68 return new Rect( 69 (int) (rectIn.left + FLOAT_INT_AVG_NUDGE), 70 (int) (rectIn.top + FLOAT_INT_AVG_NUDGE), 71 (int) (rectIn.right + FLOAT_INT_AVG_NUDGE), 72 (int) (rectIn.bottom + FLOAT_INT_AVG_NUDGE)); 73 }*/ 74 75 /** 76 * Converts a sub-pixel accurate RectF to 77 * a single pixel accurate rect. This is helpful 78 * for clipping operations which dont do a good job with 79 * subpixel vals. 80 * @param in 81 * @return 82 */ sink(RectF in)83 public static RectF sink(RectF in) { 84 return nearestPixRect(in.left, in.top, in.right, in.bottom); 85 } 86 nearestPixRect(float left, float top, float right, float bottom)87 public static RectF nearestPixRect(float left, float top, float right, float bottom) { 88 return new RectF( 89 (int) (left + FLOAT_INT_AVG_NUDGE), 90 (int) (top + FLOAT_INT_AVG_NUDGE), 91 (int) (right + FLOAT_INT_AVG_NUDGE), 92 (int) (bottom + FLOAT_INT_AVG_NUDGE)); 93 } 94 95 /** 96 * Converts a dp value to pixels. 97 * @param dp 98 * @return Pixel value of dp. 99 */ dpToPix(float dp)100 public static float dpToPix(float dp) { 101 //return SCALE * dp + FLOAT_INT_AVG_NUDGE; 102 //InternalDimension id = new InternalDimension(dp, TypedValue.COMPLEX_UNIT_DIP); 103 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, metrics); 104 105 } 106 107 /** 108 * Converts an sp value to pixels. 109 * @param sp 110 * @return Pixel value of sp. 111 */ 112 @SuppressWarnings("SameParameterValue") spToPix(float sp)113 public static float spToPix(float sp) { 114 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, metrics); 115 } 116 117 118 /** 119 * 120 * @param fraction A float value between 0 and 1. 121 * @return Number of pixels fraction represents on the current device's display. 122 */ fractionToPixH(float fraction)123 public static float fractionToPixH(float fraction) { 124 return metrics.heightPixels * fraction; 125 126 } 127 128 /** 129 * 130 * @param fraction A float value between 0 and 1. 131 * @return Number of pixels fraction represents on the current device's display. 132 */ fractionToPixW(float fraction)133 public static float fractionToPixW(float fraction) { 134 return metrics.widthPixels * fraction; 135 } 136 137 138 /** 139 * 140 * CODE BELOW IS ADAPTED IN PART FROM MINDRIOT'S SAMPLE CODE HERE: 141 * http://stackoverflow.com/questions/8343971/how-to-parse-a-dimension-string-and-convert-it-to-a-dimension-value 142 */ 143 // -- Initialize dimension string to constant lookup. 144 public static final Map<String, Integer> dimensionConstantLookup = initDimensionConstantLookup(); 145 initDimensionConstantLookup()146 private static Map<String, Integer> initDimensionConstantLookup() { 147 Map<String, Integer> m = new HashMap<String, Integer>(); 148 m.put("px", TypedValue.COMPLEX_UNIT_PX); 149 m.put("dip", TypedValue.COMPLEX_UNIT_DIP); 150 m.put("dp", TypedValue.COMPLEX_UNIT_DIP); 151 m.put("sp", TypedValue.COMPLEX_UNIT_SP); 152 m.put("pt", TypedValue.COMPLEX_UNIT_PT); 153 m.put("in", TypedValue.COMPLEX_UNIT_IN); 154 m.put("mm", TypedValue.COMPLEX_UNIT_MM); 155 return Collections.unmodifiableMap(m); 156 } 157 158 // -- Initialize pattern for dimension string. 159 private static final Pattern DIMENSION_PATTERN = Pattern.compile("^\\s*(\\d+(\\.\\d+)*)\\s*([a-zA-Z]+)\\s*$"); 160 161 /*public static int stringToDimensionPixelSize(String dimension, DisplayMetrics metrics) { 162 // -- Mimics TypedValue.complexToDimensionPixelSize(int data, DisplayMetrics metrics). 163 InternalDimension internalDimension = stringToInternalDimension(dimension); 164 final float value = internalDimension.value; 165 final float f = TypedValue.applyDimension(internalDimension.unit, value, metrics); 166 final int res = (int) (f + 0.5f); 167 if (res != 0) return res; 168 if (value == 0) return 0; 169 if (value > 0) return 1; 170 return -1; 171 }*/ 172 stringToDimension(String dimension)173 public static float stringToDimension(String dimension) { 174 // -- Mimics TypedValue.complexToDimension(int data, DisplayMetrics metrics). 175 InternalDimension internalDimension = stringToInternalDimension(dimension); 176 return TypedValue.applyDimension(internalDimension.unit, internalDimension.value, metrics); 177 } 178 stringToInternalDimension(String dimension)179 private static InternalDimension stringToInternalDimension(String dimension) { 180 // -- Match target against pattern. 181 Matcher matcher = DIMENSION_PATTERN.matcher(dimension); 182 if (matcher.matches()) { 183 // -- Match found. 184 // -- Extract value. 185 float value = Float.valueOf(matcher.group(1)); 186 // -- Extract dimension units. 187 String unit = matcher.group(3).toLowerCase(); 188 // -- Get Android dimension constant. 189 Integer dimensionUnit = dimensionConstantLookup.get(unit); 190 if (dimensionUnit == null) { 191 // -- Invalid format. 192 throw new NumberFormatException(); 193 } else { 194 // -- Return valid dimension. 195 return new InternalDimension(value, dimensionUnit); 196 } 197 } else { 198 // -- Invalid format. 199 throw new NumberFormatException(); 200 } 201 } 202 203 private static class InternalDimension { 204 float value; 205 int unit; 206 InternalDimension(float value, int unit)207 public InternalDimension(float value, int unit) { 208 this.value = value; 209 this.unit = unit; 210 } 211 } 212 213 214 } 215 216 217 218