Calculate the REAL scale factor and the angle of rotation from an Android Matrix

After performing transformations such as rotation of a bitmap about an arbitrary point, the scale is lost. Of course, this makes sense because the bitmap is rotated inside the same bounds.

To get the real scale now, along with the most reliable degree of rotation, I had to follow this method. Hope it saves the rest of you a night or two.

float[] v = new float[9];
matrix.getValues(v);
// translation is simple
float tx = v[Matrix.MTRANS_X];
float ty = v[Matrix.MTRANS_Y];

// calculate real scale
float scalex = values[Matrix.MSCALE_X];
float skewy = values[Matrix.MSKEW_Y];
float rScale = (float) Math.sqrt(scalex * scalex + skewy * skewy);

// calculate the degree of rotation
float rAngle = Math.round(Math.atan2(v[Matrix.MSKEW_X], v[Matrix.MSCALE_X]) * (180 / Math.PI));

Multi Touch in Android – Translate, Scale, and Rotate

Here’s a quick and easy implementation of Android’s multi touch feature – one finger to move, two to zoom, and three to rotate the image.

Assuming you have a basic understanding of 2D matrix transformations, the Matrix class in Android uses a 3×3 matrix to achieve all of the 2D transformations.

The source code and pre -built APK is available. See the end of this post.

Main activity – MultiTouch.java

package com.multitouch.example;

import android.app.Activity;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.os.Bundle;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;

public class MultiTouch extends Activity implements OnTouchListener {

    // these matrices will be used to move and zoom image
    private Matrix matrix = new Matrix();
    private Matrix savedMatrix = new Matrix();
    // we can be in one of these 3 states
    private static final int NONE = 0;
    private static final int DRAG = 1;
    private static final int ZOOM = 2;
    private int mode = NONE;
    // remember some things for zooming
    private PointF start = new PointF();
    private PointF mid = new PointF();
    private float oldDist = 1f;
    private float d = 0f;
    private float newRot = 0f;
    private float[] lastEvent = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ImageView view = (ImageView) findViewById(R.id.imageView);
        view.setOnTouchListener(this);
    }

    public boolean onTouch(View v, MotionEvent event) {
        // handle touch events here
        ImageView view = (ImageView) v;
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                savedMatrix.set(matrix);
                start.set(event.getX(), event.getY());
                mode = DRAG;
                lastEvent = null;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                oldDist = spacing(event);
                if (oldDist > 10f) {
                    savedMatrix.set(matrix);
                    midPoint(mid, event);
                    mode = ZOOM;
                }
                lastEvent = new float[4];
                lastEvent[0] = event.getX(0);
                lastEvent[1] = event.getX(1);
                lastEvent[2] = event.getY(0);
                lastEvent[3] = event.getY(1);
                d = rotation(event);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                mode = NONE;
                lastEvent = null;
                break;
            case MotionEvent.ACTION_MOVE:
                if (mode == DRAG) {
                    matrix.set(savedMatrix);
                    float dx = event.getX() - start.x;
                    float dy = event.getY() - start.y;
                    matrix.postTranslate(dx, dy);
                } else if (mode == ZOOM) {
                    float newDist = spacing(event);
                    if (newDist > 10f) {
                        matrix.set(savedMatrix);
                        float scale = (newDist / oldDist);
                        matrix.postScale(scale, scale, mid.x, mid.y);
                    }
                    if (lastEvent != null && event.getPointerCount() == 3) {
                        newRot = rotation(event);
                        float r = newRot - d;
                        float[] values = new float[9];
                        matrix.getValues(values);
                        float tx = values[2];
                        float ty = values[5];
                        float sx = values[0];
                        float xc = (view.getWidth() / 2) * sx;
                        float yc = (view.getHeight() / 2) * sx;
                        matrix.postRotate(r, tx + xc, ty + yc);
                    }
                }
                break;
        }

        view.setImageMatrix(matrix);
        return true;
    }

    /**
     * Determine the space between the first two fingers
     */
    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return FloatMath.sqrt(x * x + y * y);
    }

    /**
     * Calculate the mid point of the first two fingers
     */
    private void midPoint(PointF point, MotionEvent event) {
        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);
        point.set(x / 2, y / 2);
    }

    /**
     * Calculate the degree to be rotated by.
     *
     * @param event
     * @return Degrees
     */
    private float rotation(MotionEvent event) {
        double delta_x = (event.getX(0) - event.getX(1));
        double delta_y = (event.getY(0) - event.getY(1));
        double radians = Math.atan2(delta_y, delta_x);
        return (float) Math.toDegrees(radians);
    }
}

An important function that is always used is postXx(). This function concats a new matrix of the type Xx to the existing matrix object. Using setXx() will reset the matrix’s Xx property.
Main layout – main.xml

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<ImageView android:id="@+id/imageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="@drawable/butterfly"
android:scaleType="matrix" />

</FrameLayout>

Browse and download the source code on GitHub.

Rooted? Get the most of your Android phone | A power saving strategy

The smart-phones these days are power hungry devices, and often drain the battery within six to eight hours, or even less. However, if it’s running Android, there’s a good chance that that can change. The key is to find the right set of tools, and optimize your phone to be right on the edge, there when you need it, and highly responsive. What it takes is a power saving strategy, offered by Set CPU for root users android application. This nifty little tool, worth it’s price, is by far the most essential application among several others(probably thousands). It allows you to set profiles, and depending on how well you set it up, you can extend your battery life by a couple of hours(~four).
So how do you balance phone responsiveness while saving power at the same time?
Take a look at the following two screenshots, it’s what I’ve got setup:

The settings indicated above, automatically scale the CPU frequency. The highest CPU frequency supported by your processor will take the most power, so if you’d want to scale it down, especially during low levels of battery, this application can help you do so automatically.
Read about the profile priority when setting up newer profiles for this application.

You can read about which CPU frequency governor is right for you here

The Unofficial Gentoo Linux x86 uClibC stage3s’

Update:
The catalyst spec files are available here:
https://github.com/judepereira/gentoo-development/tree/master/x86/uclibc/catalyst

Following this Gentoo bug:
https://bugs.gentoo.org/show_bug.cgi?id=441976
We have official experimental uClibC for x86 and amd64 stages.
I will not be maintaining these unofficial ones any longer.

The link to the official archives is:
http://mirrors.rit.edu/gentoo/experimental/x86/uclibc/
and
http://mirrors.rit.edu/gentoo/experimental/amd64/uclibc/

The uclibc experimental stages on the gentoo mirrors are all outdated(they go back to years), so here are my stage3s’, which have been updated. They’re very similar to, and in fact can be considered to be the same stages that the Gentoo Community provides, only updated.

As of 27th August 2011, they are now built by catalyst.

The stages are built by catalyst now, and I’m looking for the possibility of hosting them on the Gentoo mirrors.

Follow my tutorial here, to get a basic ideology on working with it

stage3-uclibc-x86-26062012 is affected by bug #423491 sys-apps/findutils-4.4.2-r1 and sys-apps/coreutils-8.14 with sys-libs/uclibc – rpmatch.c:58:1: error: redefinition of ‘rpmatch’ /// /usr/include/stdlib.h:810:28: note: previous definition of ‘rpmatch’ was here

The workaround for it right now is to comment the entire function in stdlib.h and those packages will compile well. Also comment the _wur definition, just above the function rpmatch. This is a crude workaround, and it’ll be fixed when upstream decides what’s the solution.

Files:
26th June, 2012
stage3-uclibc-x86-26062012.tar.bz2
stage3-uclibc-x86-26062012.tar.bz2.md5sum

The above stage was not build by catalyst, as it could not deal with the rpmatch bug. This stage was created manually from the last release.

5th August, 2011
stage3-uclibc-x86-02082011.tar.bz2
stage3-uclibc-x86-02082011.tar.bz2.md5sum

7th July, 2011
stage3-uclibc-x86-07072011.tar.bz2
stage3-uclibc-x86-07072011.tar.bz2.md5

1st June, 2011
stage3-uclibc-x86-01062011.tar.bz2
stage3-uclibc-x86-01062011.tar.bz2.MD5

25th April, 2011
stage3-uclibc-x86-25042011.tar.bz2
stage3-uclibc-x86-25042011.tar.bz2.md5sum

For historic releases, post a comment, as to which one you require and why a specific version.
If you want the stage1 or stage2, drop a comment and I shall have them uploaded.

For those of you who would like to build these stages themselves, here are the spec files for catalyst:
stage1.spec
stage2.spec
stage3.spec

Update:
The catalyst spec files are available here:
https://github.com/judepereira/gentoo-development/tree/master/x86/uclibc/catalyst

In addition, I’ve taken down all the stage files that I used to host here, in favour of the official stages now available from the Gentoo mirrors:

Use Ruby to Generate your Shadow Password

I was initially stumbled on creating the shadow compatible SHA-512 hash.
After a little research, the answer was obvious:

require 'digest/sha2'

password = "pass@123"
salt = rand(36**8).to_s(36)
shadow_hash = password.crypt("$6$" + salt)

And you now have a password hash which you can directly use in /etc/shadow

Hacking your GoFlex Home, #3 Ideas

Well, first off the ability to just add one USB device is a little boring, I’ve been using a Belkin 4 port USB HUB, and the results are good. For cooling the GoFlex, you may want to remove the bottom cover and keep it on a laptop cooling fan or something similar, as the processor does tend to get hot slowly.

Maybe you could throw in a WiFi USB card, and turn your Goflex into a very powerful NAS, something that I’ve done is:

  • Have a DLNA/UPnP Server running, as I have it as my NAS
  • Internet Gateway
  • Torrent Station(I use transmission daemon with the Web UI)
  • FTP Server

There are way more applications of this tiny little plug computer, I’m using it for development.

Also, it’s preferably better to have Gentoo or Arch Linux on a USB stick, as when testing several times by hard power offs and resets, you don’t want the SATA drive spinning up for no reason.

Hacking your GoFlex Home, #2 UART Serial Console

Serial console? That’s beautiful when it comes to debugging. The following images are specific to the Seagate GoFlex Home, however, you may be able to figure out the connections for other Marvell SoCs.

On the board:
Notice that according to the picture, the bottom right last three pins are used.
Connections on the SoC

The junction:
I’ve used extra wires simply for convenience, the orange, yellow and black connect to these white, black and grey wires respectively.
The Junction

On the USB UART Adapter:
I’ve used a USB2.0 to RS232 TTL Converter Module PL2102(available on eBay easily)
On The USB Adapter

PIN Configuration:
On the GoFlex Home:

10 9 8 7 6
 5 4 3 2 1

1 => GND (Ground for the serial communication)
2 => RX  (Receiving bits)
3 => TX  (Transmitting bits)

Note: The RX and TX are interchanged at one end, this is because the RX of the GoFlex becomes the TX of the USB adapter, and vice cersa.

After you connect the USB end to your desktop/laptop, you can use screen to display the serial console:

# screen /dev/ttyUSB0 115200

The serial console is especially useful for debugging the kernel boot and setting the u-boot environment.

Hacking your GoFlex Home, #1 Build your KERNEL

It’s been quite sometime that I’ve got my GoFlex Home now, and it’s only recently that I’ve received my RS232 Serial USB UART Adapter.
The pin connections are simple and easy, I’ll post that as well. As I’ve already got Gentoo Linux running on the Marvell SoC, I was still using the Archlinux ARM kernel, for lack of better options. Building the kernel seemed to be a simple task, but apparently, if you have used the Archlinux ARM kernel config as a base to build your own, you won’t see the kernel debug messages, you only see the warnings, and those are few.

To get going:
Download the kernel sources, I’ve got a successful build with vanilla sources(patched with archlinuxarm patches) 3.1.10
After patching the kernel, you can quickly generate the default config, by

# make kirkwood_defconfig

That would generate the default configuration, then you could configure it via menuconfig, and set the required options.
I’ve attached my present kernel configuration, you could use that as a base, as it took me quite a while to get the kernel working right. This kernel does not support an initrd, as I don’t think embedded devices should need one. So, if your kernel says that it can’t mount the VFS, it’s likely that your U-boot is giving it an initrd to use, and that surprisingly, took me quite a while to figure out.

Goodluck hacking your GoFlex :)

recursive get from an FTP server

As we all know, downloading a directory from an FTP server over FTP over the command line is not possible. Some, have found mget to be the holy grail, I certainly do not.

I was restoring my music backup from my NAS, and I didn’t want to do it the GUI way, so CLI is the other, obvious option.

Trying to do a recursive fetch using the FTP prompt, did not work whatsoever.

Here is the better solution: recursive wget.



$ wget -r -l 0 ftp://user:password@server/directory

wget will now recursively fetch that entire directory.

Note: In some cases, you would need to pass the –username and –password arguments to wget.

Evidently, SEED is just a kid in the corporate world

Despite several efforts to contact SEED Infotech regarding their mishap for the past two days, they do not respond. E-mails, twitter updates, facebook posts being deleted from their end, says everything: SEED Infotech is lazy. They cannot afford to sponsor an event such as this one. What’s more, today’s challenge makes no sense whatsoever! SEED tried to put up a memorial contest to pay their respects to Dennis Richie, the creator of the C. They called it a “mega-event in January“, I call it a “mega-flop in January“.

The day they came to The Wilson College, they seemed to be disorganized. They didn’t seem to know what they were doing themselves.

SEED has put down the level of computing. SEED has brought their level from zero to nil, well, to top it all off, they had an insane web programmer, who didn’t know what he was doing. Notice the actual link of the page, followed by what it’s supposed to be:

http://www.seed-iknowvention.com/PlayIKnowVation.aspx
http://www.seed-iknowvention.com/PlayIKnowVention.aspx

Clearly, they do not have the potential to host such an event, and must be never allowed to.

They haven’t even once shown a sign of improvement, answers incorrect, questions incorrect, what more is there to it? This proves SEED’s incompetence in hosting an event, which surprising should be pretty easy enough to pull off correctly.

Last but not the least, @SEEDInfotech, your just a kid in the corporate world. Congratulations on winning this title.

As Francis Pereira says, “good talent is always hard to find“, and SEED does not have such talent.