/* * Copyright 2012 AndroidPlot.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.androidplot.util; import android.content.Context; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.util.DisplayMetrics; import android.util.TypedValue; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; public class PixelUtils { private static DisplayMetrics metrics; private static final float FLOAT_INT_AVG_NUDGE = 0.5f; //private static float SCALE = 1; // pix per dp //private static int X_PIX = 1; // total display horizontal pix //private static int Y_PIX = 1; // total display vertical pix /** * Recalculates scale value etc. Should be called when an application starts or * whenever the screen is rotated. */ public static void init(Context ctx) { //DisplayMetrics dm = ctx.getResources().getDisplayMetrics(); //SCALE = dm.density; //X_PIX = dm.widthPixels; //Y_PIX = dm.heightPixels; metrics = ctx.getResources().getDisplayMetrics(); } public static PointF add(PointF lhs, PointF rhs) { return new PointF(lhs.x + rhs.x, lhs.y + rhs.y); } public static PointF sub(PointF lhs, PointF rhs) { return new PointF(lhs.x - rhs.x, lhs.y - rhs.y); } /** * Converts a sub-pixel accurate RectF to a Rect * using the closest matching full pixel vals. This is * useful for clipping operations etc. * @param rectIn The rect to be converted * @return */ /*public static Rect toRect(RectF rectIn) { return new Rect( (int) (rectIn.left + FLOAT_INT_AVG_NUDGE), (int) (rectIn.top + FLOAT_INT_AVG_NUDGE), (int) (rectIn.right + FLOAT_INT_AVG_NUDGE), (int) (rectIn.bottom + FLOAT_INT_AVG_NUDGE)); }*/ /** * Converts a sub-pixel accurate RectF to * a single pixel accurate rect. This is helpful * for clipping operations which dont do a good job with * subpixel vals. * @param in * @return */ public static RectF sink(RectF in) { return nearestPixRect(in.left, in.top, in.right, in.bottom); } public static RectF nearestPixRect(float left, float top, float right, float bottom) { return new RectF( (int) (left + FLOAT_INT_AVG_NUDGE), (int) (top + FLOAT_INT_AVG_NUDGE), (int) (right + FLOAT_INT_AVG_NUDGE), (int) (bottom + FLOAT_INT_AVG_NUDGE)); } /** * Converts a dp value to pixels. * @param dp * @return Pixel value of dp. */ public static float dpToPix(float dp) { //return SCALE * dp + FLOAT_INT_AVG_NUDGE; //InternalDimension id = new InternalDimension(dp, TypedValue.COMPLEX_UNIT_DIP); return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, metrics); } /** * Converts an sp value to pixels. * @param sp * @return Pixel value of sp. */ @SuppressWarnings("SameParameterValue") public static float spToPix(float sp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, metrics); } /** * * @param fraction A float value between 0 and 1. * @return Number of pixels fraction represents on the current device's display. */ public static float fractionToPixH(float fraction) { return metrics.heightPixels * fraction; } /** * * @param fraction A float value between 0 and 1. * @return Number of pixels fraction represents on the current device's display. */ public static float fractionToPixW(float fraction) { return metrics.widthPixels * fraction; } /** * * CODE BELOW IS ADAPTED IN PART FROM MINDRIOT'S SAMPLE CODE HERE: * http://stackoverflow.com/questions/8343971/how-to-parse-a-dimension-string-and-convert-it-to-a-dimension-value */ // -- Initialize dimension string to constant lookup. public static final Map<String, Integer> dimensionConstantLookup = initDimensionConstantLookup(); private static Map<String, Integer> initDimensionConstantLookup() { Map<String, Integer> m = new HashMap<String, Integer>(); m.put("px", TypedValue.COMPLEX_UNIT_PX); m.put("dip", TypedValue.COMPLEX_UNIT_DIP); m.put("dp", TypedValue.COMPLEX_UNIT_DIP); m.put("sp", TypedValue.COMPLEX_UNIT_SP); m.put("pt", TypedValue.COMPLEX_UNIT_PT); m.put("in", TypedValue.COMPLEX_UNIT_IN); m.put("mm", TypedValue.COMPLEX_UNIT_MM); return Collections.unmodifiableMap(m); } // -- Initialize pattern for dimension string. private static final Pattern DIMENSION_PATTERN = Pattern.compile("^\\s*(\\d+(\\.\\d+)*)\\s*([a-zA-Z]+)\\s*$"); /*public static int stringToDimensionPixelSize(String dimension, DisplayMetrics metrics) { // -- Mimics TypedValue.complexToDimensionPixelSize(int data, DisplayMetrics metrics). InternalDimension internalDimension = stringToInternalDimension(dimension); final float value = internalDimension.value; final float f = TypedValue.applyDimension(internalDimension.unit, value, metrics); final int res = (int) (f + 0.5f); if (res != 0) return res; if (value == 0) return 0; if (value > 0) return 1; return -1; }*/ public static float stringToDimension(String dimension) { // -- Mimics TypedValue.complexToDimension(int data, DisplayMetrics metrics). InternalDimension internalDimension = stringToInternalDimension(dimension); return TypedValue.applyDimension(internalDimension.unit, internalDimension.value, metrics); } private static InternalDimension stringToInternalDimension(String dimension) { // -- Match target against pattern. Matcher matcher = DIMENSION_PATTERN.matcher(dimension); if (matcher.matches()) { // -- Match found. // -- Extract value. float value = Float.valueOf(matcher.group(1)); // -- Extract dimension units. String unit = matcher.group(3).toLowerCase(); // -- Get Android dimension constant. Integer dimensionUnit = dimensionConstantLookup.get(unit); if (dimensionUnit == null) { // -- Invalid format. throw new NumberFormatException(); } else { // -- Return valid dimension. return new InternalDimension(value, dimensionUnit); } } else { // -- Invalid format. throw new NumberFormatException(); } } private static class InternalDimension { float value; int unit; public InternalDimension(float value, int unit) { this.value = value; this.unit = unit; } } }