Home | History | Annotate | Download | only in util
      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      */
     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 
     52     public static PointF add(PointF lhs, PointF rhs) {
     53         return new PointF(lhs.x + rhs.x, lhs.y + rhs.y);
     54     }
     55 
     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      */
     83     public static RectF sink(RectF in) {
     84         return nearestPixRect(in.left, in.top, in.right, in.bottom);
     85     }
     86 
     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      */
    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")
    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      */
    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      */
    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 
    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 
    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 
    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 
    207         public InternalDimension(float value, int unit) {
    208             this.value = value;
    209             this.unit = unit;
    210         }
    211     }
    212 
    213 
    214 }
    215 
    216 
    217 
    218