Perspektywa obrazka

0
package games.pokenation.client.sprite.filters;

import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;

/**
 * A filter which performs a perspective distortion on an image.
 * Coordinates are treated as if the image was a unit square, i.e. the bottom-right corner of the image is at (1, 1).
 * The filter maps the unit square onto an arbitrary convex quadrilateral or vice versa.
 */
public class PerspectiveFilter extends TransformFilter {

	private float x0, y0, x1, y1, x2, y2, x3, y3;
	private float dx1, dy1, dx2, dy2, dx3, dy3;
	private float A, B, C, D, E, F, G, H, I;
	private float a11, a12, a13, a21, a22, a23, a31, a32, a33;
    private boolean scaled;
    private boolean clip = false;
	
	/**
     * Construct a PerspectiveFilter.
     */
    public PerspectiveFilter() {
		this( 0, 0, 1, 0, 1, 1, 0, 1);
	}
	
	/**
     * Construct a PerspectiveFilter.
     * @param x0 the new position of the top left corner
     * @param y0 the new position of the top left corner
     * @param x1 the new position of the top right corner
     * @param y1 the new position of the top right corner
     * @param x2 the new position of the bottom right corner
     * @param y2 the new position of the bottom right corner
     * @param x3 the new position of the bottom left corner
     * @param y3 the new position of the bottom left corner
     */
	public PerspectiveFilter(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) {
		unitSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3);
	}
	
    public void setClip( boolean clip ) {
        this.clip = clip;
    }
    
    public boolean getClip() {
        return clip;
    }
    
	/**
     * Set the new positions of the image corners.
     * This is the same as unitSquareToQuad, but the coordinates are in image pixels, not relative to the unit square.
     * This method is provided as a convenience.
     * @param x0 the new position of the top left corner
     * @param y0 the new position of the top left corner
     * @param x1 the new position of the top right corner
     * @param y1 the new position of the top right corner
     * @param x2 the new position of the bottom right corner
     * @param y2 the new position of the bottom right corner
     * @param x3 the new position of the bottom left corner
     * @param y3 the new position of the bottom left corner
     */
	public void setCorners(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) {
		unitSquareToQuad( x0, y0, x1, y1, x2, y2, x3, y3 );
        scaled = true;
	}

    /**
     * Set the transform to map the unit square onto a quadrilateral. When filtering, all coordinates will be scaled
     * by the size of the image.
     * @param x0 the new position of the top left corner
     * @param y0 the new position of the top left corner
     * @param x1 the new position of the top right corner
     * @param y1 the new position of the top right corner
     * @param x2 the new position of the bottom right corner
     * @param y2 the new position of the bottom right corner
     * @param x3 the new position of the bottom left corner
     * @param y3 the new position of the bottom left corner
     */
	public void unitSquareToQuad( float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3 ) {
		this.x0 = x0;
		this.y0 = y0;
		this.x1 = x1;
		this.y1 = y1;
		this.x2 = x2;
		this.y2 = y2;
		this.x3 = x3;
		this.y3 = y3;
		
		dx1 = x1-x2;
		dy1 = y1-y2;
		dx2 = x3-x2;
		dy2 = y3-y2;
		dx3 = x0-x1+x2-x3;
		dy3 = y0-y1+y2-y3;
		
		if (dx3 == 0 && dy3 == 0) {
			a11 = x1-x0;
			a21 = x2-x1;
			a31 = x0;
			a12 = y1-y0;
			a22 = y2-y1;
			a32 = y0;
			a13 = a23 = 0;
		} else {
			a13 = (dx3*dy2-dx2*dy3)/(dx1*dy2-dy1*dx2);
			a23 = (dx1*dy3-dy1*dx3)/(dx1*dy2-dy1*dx2);
			a11 = x1-x0+a13*x1;
			a21 = x3-x0+a23*x3;
			a31 = x0;
			a12 = y1-y0+a13*y1;
			a22 = y3-y0+a23*y3;
			a32 = y0;
		}
        a33 = 1;
        scaled = false;
	}

    /**
     * Set the transform to map a quadrilateral onto the unit square. When filtering, all coordinates will be scaled
     * by the size of the image.
     * @param x0 the old position of the top left corner
     * @param y0 the old position of the top left corner
     * @param x1 the old position of the top right corner
     * @param y1 the old position of the top right corner
     * @param x2 the old position of the bottom right corner
     * @param y2 the old position of the bottom right corner
     * @param x3 the old position of the bottom left corner
     * @param y3 the old position of the bottom left corner
     */
	public void quadToUnitSquare( float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3 ) {
		unitSquareToQuad( x0, y0, x1, y1, x2, y2, x3, y3 );

        // Invert the transformation
        float ta11 = a22*a33 - a32*a23;
        float ta21 = a32*a13 - a12*a33;
        float ta31 = a12*a23 - a22*a13;
        float ta12 = a31*a23 - a21*a33;
        float ta22 = a11*a33 - a31*a13;
        float ta32 = a21*a13 - a11*a23;
        float ta13 = a21*a32 - a31*a22;
        float ta23 = a31*a12 - a11*a32;
        float ta33 = a11*a22 - a21*a12;
        float f = 1.0f/ta33;

        a11 = ta11*f;
        a21 = ta12*f;
        a31 = ta13*f;
        a12 = ta21*f;
        a22 = ta22*f;
        a32 = ta23*f;
        a13 = ta31*f;
        a23 = ta32*f;
        a33 = 1.0f;
	}

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
	    A = a22*a33 - a32*a23;
	    B = a31*a23 - a21*a33;
	    C = a21*a32 - a31*a22;
	    D = a32*a13 - a12*a33;
	    E = a11*a33 - a31*a13;
	    F = a31*a12 - a11*a32;
	    G = a12*a23 - a22*a13;
	    H = a21*a13 - a11*a23;
	    I = a11*a22 - a21*a12;
        if ( !scaled ) {
            int width = src.getWidth();
            int height = src.getHeight();
            float invWidth = 1.0f/width;
            float invHeight = 1.0f/height;

            A *= invWidth;
            D *= invWidth;
            G *= invWidth;
            B *= invHeight;
            E *= invHeight;
            H *= invHeight;
        }

        return super.filter( src, dst );
    }

	protected void transformSpace( Rectangle rect ) {
		if ( scaled ) {
            rect.x = (int)Math.min( Math.min( x0, x1 ), Math.min( x2, x3 ) );
            rect.y = (int)Math.min( Math.min( y0, y1 ), Math.min( y2, y3 ) );
            rect.width = (int)Math.max( Math.max( x0, x1 ), Math.max( x2, x3 ) ) - rect.x;
            rect.height = (int)Math.max( Math.max( y0, y1 ), Math.max( y2, y3 ) ) - rect.y;
            return;
        }
        if ( !clip ) {
            float w = (float)rect.getWidth(), h = (float)rect.getHeight();
            Rectangle r = new Rectangle();
            r.add( getPoint2D( new Point2D.Float(0, 0), null ) );
            r.add( getPoint2D( new Point2D.Float(w, 0), null ) );
            r.add( getPoint2D( new Point2D.Float(0, h), null ) );
            r.add( getPoint2D( new Point2D.Float(w, h), null ) );
            rect.setRect( r );
        }
	}

    /**
     * Get the origin of the output image. Use this for working out where to draw your new image.
     * @return the X origin.
     */
	public float getOriginX() {
		return x0 - (int)Math.min( Math.min( x0, x1 ), Math.min( x2, x3 ) );
	}

    /**
     * Get the origin of the output image. Use this for working out where to draw your new image.
     * @return the Y origin.
     */
	public float getOriginY() {
		return y0 - (int)Math.min( Math.min( y0, y1 ), Math.min( y2, y3 ) );
	}

    public Rectangle2D getBounds2D( BufferedImage src ) {
        if ( clip ) 
            return new Rectangle(0, 0, src.getWidth(), src.getHeight());
        float w = src.getWidth(), h = src.getHeight();
		Rectangle2D r = new Rectangle2D.Float();
        r.add( getPoint2D( new Point2D.Float(0, 0), null ) );
        r.add( getPoint2D( new Point2D.Float(w, 0), null ) );
        r.add( getPoint2D( new Point2D.Float(0, h), null ) );
        r.add( getPoint2D( new Point2D.Float(w, h), null ) );
        return r;
    }
    
    public Point2D getPoint2D( Point2D srcPt, Point2D dstPt ) {
        if ( dstPt == null )
            dstPt = new Point2D.Float();
        float x = (float)srcPt.getX();
        float y = (float)srcPt.getY();
        float f = 1.0f/(x*a13 + y*a23 + a33);
        dstPt.setLocation( (x*a11 + y*a21 + a31)*f, (x*a12 + y*a22 + a32)*f );
        return dstPt;
    }

	protected void transformInverse( int x, int y, float[] out ) {
		out[0] = originalSpace.width * (A*x+B*y+C)/(G*x+H*y+I);
		out[1] = originalSpace.height * (D*x+E*y+F)/(G*x+H*y+I);
	}

	public String toString() {
		return "Distort/Perspective...";
	}
} 

otóż mogę użyć metody unitSquareToQuad(x0,x1 ...
Ale czy jest możliwość wyciągnięcia tych punktów przez podanie kąta?

2

Wątpię, by komukolwiek chciało się to przeglądać... Wysyłaj tylko ten najważniejszy kod. Jak zrobisz projekt na pięćdziesiąt tysięcy linijek kodu i będziesz miał jakiś błąd, to chyba nie wrzucisz wszystkiego, prawda?

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.