All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.octo.android.robospice.sample.offline.MandelbrotView Maven / Gradle / Ivy

The newest version!
package com.octo.android.robospice.sample.offline;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;

import com.octo.android.robospice.SpiceManager;
import com.octo.android.robospice.persistence.exception.SpiceException;
import com.octo.android.robospice.request.SpiceRequest;
import com.octo.android.robospice.request.listener.RequestListener;
import com.octo.android.robospice.sample.model.FractalOperator;
import com.octo.android.robospice.sample.model.OptimizedMandelbrotOperator;
import com.octo.android.robospice.sample.request.FractalRequest;

/**
 * From
 * http://www.java2s.com/Open-Source/Android/UnTagged/android-mandelbrot-set/org/girino/frac/android/MandelbrotView.
 * java.htm
 * 
 * @author sni
 */
public class MandelbrotView extends ImageView implements OnTouchListener {
    private static final int ROW_HEIGHT = 32;

    private static final int VERTICAL_MARGIN = 50;

    private static final String TAG = "Touch";

    private double x0 = 0.0;
    private double y0 = 0.0;
    private int width = 320;
    private int height = 480;
    private double scale = 100.0 * 300.0 / width;
    private float xoffset = 0;
    private float yoffset = 0;

    private Bitmap mBitmap;
    private Canvas mCanvas;
    private Paint mBitmapPaint;

    // The 3 states (events) which the user is trying to perform
    static final int NONE = 0;
    static final int DRAG = 1;
    static final int ZOOM = 2;
    int mode = NONE;

    // these PointF objects are used to record the point(s) the user is touching
    PointF start = new PointF();
    PointF mid = new PointF();
    float oldDist = 1f;
    private float scaleFactor = 1.0f;

    private FractalOperator fractalOperator = new OptimizedMandelbrotOperator();

    private SpiceManager spiceManager;

    private double oldScale = scale;

    private SpiceRequest< Bitmap > fractalRequest;

    public MandelbrotView( Context context, AttributeSet attrs, int defStyle ) {
        super( context, attrs, defStyle );
        initialize();
    }

    public MandelbrotView( Context context, AttributeSet attrs ) {
        super( context, attrs );
        initialize();
    }

    public MandelbrotView( Context context ) {
        super( context );
        initialize();
    }

    private void initialize() {
        rescale( getWidth(), getHeight() );
        mBitmapPaint = new Paint( Paint.DITHER_FLAG );

        // draws first mandelbrot
        mCanvas.drawARGB( 0xff, 10, 10, 10 );

        setOnTouchListener( this );
    }

    public void setSpiceManager( SpiceManager spiceManager ) {
        this.spiceManager = spiceManager;
    }

    private void rescale( int w, int h ) {
        w = w > 0 ? w : 1;
        width = w;
        scale *= (double) w / (double) width;
        height = h > 0 ? h : 1;

        mBitmap = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 );
        mCanvas = new Canvas( mBitmap );
    }

    public void start() {
        Log.d( "MandelbrotView", "starting..." );
        fractalRequest = new FractalRequest( x0, y0, width, height, scale, fractalOperator, mBitmap );

        // spiceManager.execute( fractalRequest, "fractal", DurationInMillis.ALWAYS, new FractalResultListener() );
        spiceManager.execute( fractalRequest, new FractalResultListener() );
        invalidate();
        Log.d( "MandelbrotView", "started..." );
    }

    public void stop() {
        Log.d( "MandelbrotView", "stoping..." );
        if ( fractalRequest != null ) {
            fractalRequest.cancel();
        }
        Log.d( "MandelbrotView", "stoped..." );
    }

    @Override
    protected void onSizeChanged( int w, int h, int oldw, int oldh ) {
        Log.d( "MandelbrotView", "onSizeChanged begin..." );
        Log.d( "MandelbrotView", "Size: " + w + "x" + h );
        super.onSizeChanged( w, h, oldw, oldh );
        stop();
        rescale( w, h );
        start();
        Log.d( "MandelbrotView", "onSizeChanged end..." );
    }

    @Override
    protected void onDraw( Canvas canvas ) {
        // avoids drawing too much
        canvas.drawBitmap( mBitmap, xoffset, yoffset, mBitmapPaint );
        Paint paintBlue = new Paint();
        paintBlue.setStyle( Paint.Style.STROKE );
        paintBlue.setStrokeWidth( 3 );
        paintBlue.setTextSize( ROW_HEIGHT );
        paintBlue.setColor( Color.WHITE );
        canvas.drawText( "X:" + x0, 10, VERTICAL_MARGIN, paintBlue );
        canvas.drawText( "Y:" + y0, 10, VERTICAL_MARGIN + 32, paintBlue );
        canvas.drawText( "scale:" + scale, 10, VERTICAL_MARGIN + 32 * 2, paintBlue );

        if ( mode == ZOOM ) {
            float w = width / scaleFactor;
            float h = height / scaleFactor;
            Paint paint = new Paint();
            paint.setStyle( Paint.Style.STROKE );
            paint.setStrokeWidth( 3 );
            paint.setTextSize( ROW_HEIGHT );
            paint.setColor( Color.RED );
            canvas.drawCircle( mid.x, mid.y, Math.min( w, h ), paint );
            canvas.drawCircle( mid.x, mid.y, 5, paint );
            canvas.drawText( "Scale:" + scale * scaleFactor, width / 2, height * 0.95f, paint );
            canvas.drawText( "Mid:" + mid.x + "," + mid.y, width / 2, height * 0.95f + ROW_HEIGHT, paint );
        }
        // stops only after drawing a last time
        invalidate();
    }

    @Override
    public boolean onTouch( View v, MotionEvent event ) {
        ImageView view = (ImageView) v;
        view.setScaleType( ImageView.ScaleType.MATRIX );
        dumpState();
        dumpEvent( event );
        // Handle touch events here...

        switch ( event.getAction() & MotionEvent.ACTION_MASK ) {
            case MotionEvent.ACTION_DOWN: // first finger down only
                start.set( event.getX(), event.getY() );
                Log.d( TAG, "mode=DRAG" ); // write to LogCat
                mode = DRAG;
                break;

            case MotionEvent.ACTION_UP: // first finger lifted

            case MotionEvent.ACTION_POINTER_UP: // second finger lifted
                if ( mode == ZOOM ) {
                    stop();
                    zoom( scaleFactor );
                    moveTo( mid.x, mid.y );
                    scaleFactor = 1.0f;
                    start();
                } else if ( mode == DRAG ) {
                    stop();
                    moveBy( event.getX(), event.getY() );
                    Log.d( TAG, "x0=" + x0 );
                    Log.d( TAG, "y0=" + y0 );
                    start();
                }

                mode = NONE;
                Log.d( TAG, "mode=NONE" );
                break;

            case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down

                oldDist = spacing( event );
                Log.d( TAG, "oldDist=" + oldDist );
                if ( oldDist > 5f ) {
                    mode = ZOOM;
                    oldScale = scale;
                    Log.d( TAG, "mode=ZOOM" );
                }
                break;

            case MotionEvent.ACTION_MOVE:

                if ( mode == DRAG ) {
                    // in the matrix of points
                } else if ( mode == ZOOM ) {
                    // pinch zooming
                    float newDist = spacing( event );
                    Log.d( TAG, "newDist=" + newDist );
                    if ( newDist > 5f ) {
                        midPoint( mid, event );
                        scaleFactor = newDist / oldDist; // setting the scaling of the
                    }
                }
                break;
        }

        return true; // indicate event was handled
    }

    private void moveTo( float x, float y ) {
        x0 += (float) ( ( x - width / 2 ) / scale );
        y0 += (float) ( ( y - height / 2 ) / scale );
    }

    private void moveBy( float x, float y ) {
        float translateX = (float) ( ( x - start.x ) / scale );
        float translateY = (float) ( ( y - start.y ) / scale );
        x0 -= translateX;
        y0 -= translateY;
    }

    /*
     * -------------------------------------------------------------------------- Method: spacing Parameters:
     * MotionEvent Returns: float Description: checks the spacing between the two fingers on touch
     * ----------------------------------------------------
     */

    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 );
    }

    /*
     * -------------------------------------------------------------------------- Method: midPoint Parameters: PointF
     * object, MotionEvent Returns: void Description: calculates the midpoint between the 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 );
    }

    /** Show an event in the LogCat view, for debugging */
    private void dumpEvent( MotionEvent event ) {
        String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE", "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
        StringBuilder sb = new StringBuilder();
        int action = event.getAction();
        int actionCode = action & MotionEvent.ACTION_MASK;
        sb.append( "event ACTION_" ).append( names[ actionCode ] );

        if ( actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP ) {
            sb.append( "(pid " ).append( action >> MotionEvent.ACTION_POINTER_ID_SHIFT );
            sb.append( ")" );
        }

        sb.append( "[" );
        for ( int i = 0; i < event.getPointerCount(); i++ ) {
            sb.append( "#" ).append( i );
            sb.append( "(pid " ).append( event.getPointerId( i ) );
            sb.append( ")=" ).append( (int) event.getX( i ) );
            sb.append( "," ).append( (int) event.getY( i ) );
            if ( i + 1 < event.getPointerCount() ) {
                sb.append( ";" );
            }
        }

        sb.append( "]" );
        Log.d( "Touch Events ---------", sb.toString() );
    }

    /** Show an event in the LogCat view, for debugging */
    private void dumpState() {
        StringBuilder sb = new StringBuilder();
        sb.append( "x0=" + x0 ).append( "\ny0=" + y0 );
        sb.append( "\nscale=" + scale ).append( "\noldScale=" + oldScale );
        sb.append( "\nscaleFactor=" + scaleFactor );
        sb.append( "\nmidPoint=" + mid.x + " " + mid.y );
        Log.d( "Fractal state ---------", sb.toString() );
    }

    public void zoom( double factor ) {
        scale *= factor;
        Log.d( TAG, "Zooming factor :" + factor );
    }

    public void reset() {
        stop();
        x0 = 0;
        y0 = 0;
        scale = 100.0 * 300.0 / width;
        start();
    }

    private class FractalResultListener implements RequestListener< Bitmap > {

        @Override
        public void onRequestFailure( SpiceException spiceException ) {

        }

        @Override
        public void onRequestSuccess( Bitmap result ) {
            mBitmap = result;
            invalidate();
        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy