Search code examples
javaandroidimage-processingandroid-custom-viewdimensions

Dot game failed , cannot identify and draw dots around image correctly


What i am trying to achieve is to draw dot at the exact same location as black dot already present in image , but there are problem that i have to face regarding image:

  1. Image can change its densities in multiple screens(so no fixed size)
  2. Given image can be of any size , i have to convert it to appropriate size to show on custom View.
  3. and How to show image in custom view so its density remain the same ?

Now problems regarding dots drawing:

  1. How can i identify black dots x,y axis dynamically to draw at the same exact black dot drawn in image of custom view.
  2. Is there a good way to achieve question 1 dynamically or i should hard code dots.

What i have done so far:

  1. I have moved all images to drawable folder and done layout_width = wrap_content and height the same as width.

    <com.jutt.dotbot.ConnectDotsView
    android:id="@+id/gfxImage"
    android:layout_width="500dpi"
    android:layout_height="600dpi"
    android:layout_marginTop="100dip"
    android:layout_centerHorizontal="true"/>
    
  2. I've look hard coded points by Toast the point on each ACTION_DOWN in onTouchEvent and then noted then and given to the class ConnectDotsView .

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        touch_start(x, y);
        invalidate();
        L.s(getContext(), "x = "+x+"y = "+y);
        break;
    
  3. After i've noted all points drawn , i am giving this class back that same points to draw , by calling:

    public void setPoints(List<Point> points) {
        this.mPoints = points;
    }
    
  4. Now Biggest problem [which i think still persist] , (x,y) on screen 1152w*720h may not be same on 480w*600h , so what i've done is who a function to actually convert those points.

    private static final int OLDSCREENX = 1152;
    private static final int OLDSCREENY = 720;
    
    private int[] makeDimentionGeneric(float oldScreenX, float oldScreenY,
            float oldX, float oldY) {
        // get screen size
        DisplayMetrics displaymetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
        final float y = displaymetrics.heightPixels;
        final float x = displaymetrics.widthPixels;
        int[] i = new int[] { (int) ((oldX / oldScreenX) * x),
                (int) ((oldY / oldScreenY) * y) };
        return i;
    }
    

and i am calling this while setting the points like makeDimentionGeneric(OLDSCREENX, OLDSCREENY, p.x, p.y); when p.x and p.y are hardcoded stored value from screen.

Now what happens when i try to run it in different devices.

Right side is emulator and left is bluestack

When am i doing it wrong and how can i achieve it correctly ? please guys i've worked hard studied but can't seems to find a better approach than i've mentioned.

[Update] as requested(21 jul 2015):

private int[] makeDimentionGeneric(float oldScreenX, float oldScreenY,
        float oldX, float oldY) {
    // convert all px to dp
    oldScreenY = convertPixelsToDp(oldScreenY, this);
    oldScreenX = convertPixelsToDp(oldScreenX,this);
    oldX = convertPixelsToDp(oldX,this);
    oldY = convertPixelsToDp(oldY,this);

    // get screen size
    DisplayMetrics displaymetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    final float y = convertPixelsToDp(displaymetrics.heightPixels, this);
    final float x = convertPixelsToDp(displaymetrics.widthPixels, this);

    int[] i = new int[] { (int)((oldX / oldScreenX) * x),
            (int) ((oldY / oldScreenY) * y) };

    return i;

}

Solution

  • Since your image differs depending on DPI your pixel calculations must also differ depending on DPI. Consider the following question:

    Converting pixels to dp

    In your case (copied from answer in above question) you probably want to use this method:

    /**
     * This method converts device specific pixels to density independent pixels.
     *
     * @param px A value in px (pixels) unit. Which we need to convert into db
     * @param context Context to get resources and device specific display metrics
     * @return A float value to represent dp equivalent to px value
     */
    public static float convertPixelsToDp(float px, Context context){
        Resources resources = context.getResources();
        DisplayMetrics metrics = resources.getDisplayMetrics();
        float dp = px / (metrics.densityDpi / 160f);
        return dp;
    }