PixelUtils.java revision 6224eda509d436a575f801942337da92a6c18767
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
17package com.androidplot.util;
18
19import android.content.Context;
20import android.graphics.PointF;
21import android.graphics.Rect;
22import android.graphics.RectF;
23import android.util.DisplayMetrics;
24import android.util.TypedValue;
25
26import java.util.Collections;
27import java.util.HashMap;
28import java.util.Map;
29import java.util.regex.Matcher;
30import java.util.regex.Pattern;
31
32public 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