/*
* JSwiff is an open source Java API for Macromedia Flash file generation
* and manipulation
*
* Copyright (C) 2004-2005 Ralf Terdic (contact@jswiff.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.jswiff.swfrecords;
import com.jswiff.io.InputBitStream;
import com.jswiff.io.OutputBitStream;
import java.io.IOException;
import java.io.Serializable;
/**
* This class is used to represent a standard 2D transform matrix (used for
* affine transforms).
*/
public final class Matrix implements Serializable {
private double scaleX = 1.0;
private double scaleY = 1.0;
private double rotateSkew0 = 0.0;
private double rotateSkew1 = 0.0;
private int translateX = 0;
private int translateY = 0;
private boolean hasScale;
private boolean hasRotateSkew;
/**
* Creates a new Matrix instance. Specify the translate values. If the matrix
* also has scale or rotate/skew values, use the appropriate setters for
* setting these values.
*
* @param translateX x translate value in twips
* @param translateY y translate value in twips
*/
public Matrix(int translateX, int translateY) {
this.translateX = translateX;
this.translateY = translateY;
}
/**
* Reads a Matrix instance from a bit stream.
*
* @param stream source bit stream
*
* @throws IOException if an I/O error has occured
*/
public Matrix(InputBitStream stream) throws IOException {
hasScale = stream.readBooleanBit();
if (hasScale) {
int nScaleBits = (int) stream.readUnsignedBits(5);
scaleX = stream.readFPBits(nScaleBits);
scaleY = stream.readFPBits(nScaleBits);
}
hasRotateSkew = stream.readBooleanBit();
if (hasRotateSkew) {
int nRotateBits = (int) stream.readUnsignedBits(5);
rotateSkew0 = stream.readFPBits(nRotateBits);
rotateSkew1 = stream.readFPBits(nRotateBits);
}
int nTranslateBits = (int) stream.readUnsignedBits(5);
translateX = (int) stream.readSignedBits(nTranslateBits);
translateY = (int) stream.readSignedBits(nTranslateBits);
stream.align();
}
/**
* Sets the rotate and skew values
*
* @param rotateSkew0 rotate/skew value 0
* @param rotateSkew1 rotate/skew value 1
*/
public void setRotateSkew(double rotateSkew0, double rotateSkew1) {
this.rotateSkew0 = rotateSkew0;
this.rotateSkew1 = rotateSkew1;
hasRotateSkew = true;
}
/**
* Returns the rotate/skew 0 value. Check with <code>hasRotateSkew()</code>
* first if value is set.
*
* @return rotate/skew 0 value
*/
public double getRotateSkew0() {
return rotateSkew0;
}
/**
* Returns the rotate/skew 1 value. Check with <code>hasRotateSkew()</code>
* first if value is set.
*
* @return rotate/skew 1 value
*/
public double getRotateSkew1() {
return rotateSkew1;
}
/**
* Sets the scale values.
*
* @param scaleX x scale value
* @param scaleY y scale value
*/
public void setScale(double scaleX, double scaleY) {
this.scaleX = scaleX;
this.scaleY = scaleY;
hasScale = true;
}
/**
* Returns the x scale value. Check with <code>hasScale()</code> first if
* value is set.
*
* @return x scale
*/
public double getScaleX() {
return scaleX;
}
/**
* Returns the y scale value. Check with <code>hasScale()</code> first if
* value is set.
*
* @return y scale
*/
public double getScaleY() {
return scaleY;
}
/**
* Returns the x translation value in twips (1/20 px).
*
* @return x translate value in twips
*/
public int getTranslateX() {
return translateX;
}
/**
* Returns the y translation value in twips (1/20 px).
*
* @return y translate value in twips
*/
public int getTranslateY() {
return translateY;
}
/**
* Checks if the rotate/skew values have been set.
*
* @return <code>true</code> if rotate/skew values set, else
* <code>false</code>
*/
public boolean hasRotateSkew() {
return hasRotateSkew;
}
/**
* Checks if the scale values have been set.
*
* @return <code>true</code> if scale values set, else <code>false</code>
*/
public boolean hasScale() {
return hasScale;
}
/**
* Returns the string representation of the matrix.
*
* @return string representation of matrix
*/
public String toString() {
return "Matrix (" + "scaleX=" + scaleX + " scaleY=" + scaleY +
" rotateSkew0=" + rotateSkew0 + " rotateSkew1=" + rotateSkew1 +
" translateX=" + translateX + " translateY=" + translateY + ")";
}
/**
* Writes the matrix to a bit stream.
*
* @param stream the target bit stream
*
* @throws IOException if an I/O error has occured
*/
public void write(OutputBitStream stream) throws IOException {
stream.writeBooleanBit(hasScale);
if (hasScale) {
int nScaleBits = OutputBitStream.getFPBitsLength(scaleX);
nScaleBits = Math.max(
nScaleBits, OutputBitStream.getFPBitsLength(scaleY));
stream.writeUnsignedBits(nScaleBits, 5);
stream.writeFPBits(scaleX, nScaleBits);
stream.writeFPBits(scaleY, nScaleBits);
}
stream.writeBooleanBit(hasRotateSkew);
if (hasRotateSkew) {
int nRotateBits = OutputBitStream.getFPBitsLength(rotateSkew0);
nRotateBits = Math.max(
nRotateBits, OutputBitStream.getFPBitsLength(rotateSkew1));
stream.writeUnsignedBits(nRotateBits, 5);
stream.writeFPBits(rotateSkew0, nRotateBits);
stream.writeFPBits(rotateSkew1, nRotateBits);
}
int nTranslateBits = OutputBitStream.getSignedBitsLength(translateX);
nTranslateBits = Math.max(
nTranslateBits, OutputBitStream.getSignedBitsLength(translateY));
stream.writeUnsignedBits(nTranslateBits, 5);
stream.writeSignedBits(translateX, nTranslateBits);
stream.writeSignedBits(translateY, nTranslateBits);
stream.align();
}
}