/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info: http://jsynoptic.sourceforge.net/index.html
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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.
*
* (C) Copyright 2001-2005, by :
* Corporate:
* EADS Astrium SAS
* EADS CRC
* Individual:
* Claude Cazenave
*
* $Id$
*
* Changes
* -------
* 18 mai 2006 : Initial public release (CC);
*
*/
package jsynoptic.builtin;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.Collection;
import simtools.data.DataException;
import simtools.data.DataInfo;
import simtools.data.DataSource;
import simtools.data.DataSourceListener;
import simtools.data.DataSourcePool;
import simtools.data.EndNotificationListener;
import simtools.data.UnsupportedOperation;
import simtools.shapes.AbstractShape.AbstractShapePropertiesNames;
import simtools.ui.DoubleValueMapper;
import simtools.util.NamedProperties;
/**
* An AffineTransform with input values for translation and rotation
* coming from user defined inputs or data sources
*/
public class AffineTransformData implements java.io.Serializable, Cloneable,
DataSourceListener, EndNotificationListener,
NamedProperties {
static final long serialVersionUID = 3809771018128609280L;
/**
* Maximum translation value for both axes to avoid loosing shapes
* This default value can be overloaded thanks to user properties
*/
public static int MAX_TRANSLATION=1500;
/**
* The real affine transformation
*/
protected transient AffineTransform transform;
/**
* An arry of values to apply transformation on
*/
protected transient double[] transformBounds = new double[8];
/**
* The data source for the rotation
*/
protected transient DataSource rotSource;
/**
* The source value index to get the rotation value
*/
protected transient long rotSourceIndex;
/**
* The rotation value
*/
protected double rotValue;
/**
* Map rotation data source value to some rotation values
*
*/
protected DoubleValueMapper rotationMapper;
/**
* True if the rotation is enabled
*/
protected boolean rotEnabled;
/**
* Scale used for angle value : 1 means radian, PI/180 means degree
*/
protected double angleUnitScale;
/**
* The X translation data source
*/
protected transient DataSource txSource;
/**
* The X translation data source index
*/
protected transient long txSourceIndex;
/**
* The X translation value
*/
protected double txValue;
/**
* Map rotation data source value to some rotation values
*
*/
protected DoubleValueMapper txMapper;
/**
* The X translation data source
*/
protected transient DataSource tySource;
/**
* The Y translation data source index
*/
protected transient long tySourceIndex;
/**
* The Y translation value
*/
protected double tyValue;
/**
* Map rotation data source value to some rotation values
*
*/
protected DoubleValueMapper tyMapper;
/**
* True if translation is activated (both axes)
*/
protected boolean transEnabled;
/**
* Translation scale factor : 1 means 1 pixel
*/
protected double transUnitScale;
/**
* True to perform affine transform computation using translation first
*/
protected boolean translationFirst;
/**
* True if new values have not been yet taken into account in the affine transform
*/
protected transient boolean dirty;
/**
* The listener to warn in case of new transform change
*/
protected Listener listener;
/**
* The list of properties managed by this panel
*/
protected transient String[] _propertyNames=null;
/**
* Create a new AffineTransformData with an object listening on the changes
* @param listener the object to warn in case of changes
*/
public AffineTransformData(Listener listener){
rotEnabled=false;
transEnabled=false;
translationFirst=false;
transform=new AffineTransform();
transformBounds=new double[8];
angleUnitScale=1.; // use of radians
transUnitScale=1.; // use of pixels
setListener(listener);
}
/**
* Create a new AffineTransformData without object listening on the changes
*/
public AffineTransformData(){
this(null);
}
/**
* @return the current affine transform
*/
public AffineTransform getTransform(){
return transform;
}
/**
* Set the owner of the transform
* @param listener the object to warn when transform changes
*/
public void setListener(Listener listener){
this.listener=listener;
}
/**
* Clone the object
* @return a deep copy of the object
*/
public AffineTransformData cloneTransform() {
return cloneTransform(true);
}
/**
* Clone the object
* @param withDataListener true to add the listeners to all the used data
* @return a deep copy of the object
*/
public AffineTransformData cloneTransform(boolean withDataListener) {
AffineTransformData clone = null;
try{
clone = (AffineTransformData)clone();
clone.transform=new AffineTransform(transform);
clone.transformBounds=new double[8];
if (withDataListener){
clone.subscribeToDataNotifications();
}
}
catch(CloneNotSupportedException cnse){}
return clone;
}
/**
* Compute the new bounds according to the intial bounds and the current transformation
* @param x1 bounds lower left corner x coordinate
* @param y1 bounds lower left corner y coordinate
* @param x2 bounds top right corner x coordinate
* @param y2 bounds top right corner x coordinate
* @param bounds intial bounds to be updated accordingly
*/
public void updateBounds(int x1,int y1,int x2,int y2, Rectangle2D.Double bounds){
transformBounds[0]=x1;
transformBounds[1]=y1;
transformBounds[2]=x2;
transformBounds[3]=y2;
transformBounds[4]=transformBounds[2];
transformBounds[5]=transformBounds[1];
transformBounds[6]=transformBounds[0];
transformBounds[7]=transformBounds[3];
transform.transform(transformBounds,0,transformBounds,0,4);
bounds.x=Math.min(Math.min(transformBounds[0],transformBounds[2]),
Math.min(transformBounds[4],transformBounds[6]));
bounds.y=Math.min(Math.min(transformBounds[1],transformBounds[3]),
Math.min(transformBounds[5],transformBounds[7]));
bounds.width=Math.max(Math.abs(transformBounds[2]-transformBounds[0]),
Math.abs(transformBounds[6]-transformBounds[4]));
bounds.height=Math.max(Math.abs(transformBounds[3]-transformBounds[1]),
Math.abs(transformBounds[7]-transformBounds[5]));
}
/**
* Method called by the listener of the transform to update it according
* to new values (rotation and translation) and reference coordinates
* @param cx x reference coordinate (typically the center of a shape)
* @param cy y reference coordinate (typically the center of a shape)
*/
public void updateTransform(double cx, double cy){
transform.setToIdentity();
transform.translate(cx,cy);
if(transEnabled){
double tx=txValue*transUnitScale;
double ty=tyValue*transUnitScale;
if(tx<-MAX_TRANSLATION){
tx=-MAX_TRANSLATION;
}
if(tx>MAX_TRANSLATION){
tx=MAX_TRANSLATION;
}
if(ty<-MAX_TRANSLATION){
ty=-MAX_TRANSLATION;
}
if(ty>MAX_TRANSLATION){
ty=MAX_TRANSLATION;
}
if(translationFirst){
transform.translate(tx,ty);
}
if(rotEnabled){
transform.rotate(rotValue*angleUnitScale);
}
if(!translationFirst){
transform.translate(tx,ty);
}
}
else{
if(rotEnabled){
transform.rotate(rotValue*angleUnitScale);
}
}
transform.translate(-cx,-cy);
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceValueChanged(simtools.data.DataSource, long, long)
*/
public void DataSourceValueChanged(DataSource ds, long minIndex, long maxIndex) {
if (ds.equals(rotSource)) {
if ((rotSourceIndex >= minIndex) && (rotSourceIndex <= maxIndex)){
dirty = true;
}
}
if (ds.equals(txSource)) {
if ((txSourceIndex >= minIndex) && (txSourceIndex <= maxIndex)){
dirty = true;
}
}
if (ds.equals(tySource)) {
if ((tySourceIndex >= minIndex) && (tySourceIndex <= maxIndex)){
dirty = true;
}
}
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceIndexRangeChanged(simtools.data.DataSource, long, long)
*/
public void DataSourceIndexRangeChanged(DataSource ds, long startIndex, long lastIndex) {
if (ds.equals(rotSource)) {
rotSourceIndex = lastIndex;
dirty=true;
}
if (ds.equals(txSource)) {
txSourceIndex = lastIndex;
dirty=true;
}
if (ds.equals(tySource)) {
tySourceIndex = lastIndex;
dirty=true;
}
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceInfoChanged(simtools.data.DataSource, simtools.data.DataInfo)
*/
public void DataSourceInfoChanged(DataSource ds, DataInfo newInfo) {
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceValueRangeChanged(simtools.data.DataSource)
*/
public void DataSourceValueRangeChanged(DataSource ds) {
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceOrderChanged(simtools.data.DataSource, int)
*/
public void DataSourceOrderChanged(DataSource ds, int newOrder) {
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#subscribeToDataNotifications()
*/
public void subscribeToDataNotifications(){
if (rotSource!=null) {
rotSource.addListener(this);
rotSource.addEndNotificationListener(this);
try {
rotSourceIndex = rotSource.getLastIndex();
} catch (UnsupportedOperation uo1) {
rotSourceIndex = 0;
}
}
if (txSource!=null) {
txSource.addListener(this);
txSource.addEndNotificationListener(this);
try {
txSourceIndex = txSource.getLastIndex();
} catch (UnsupportedOperation uo1) {
txSourceIndex = 0;
}
}
if (tySource!=null) {
tySource.addListener(this);
tySource.addEndNotificationListener(this);
try {
tySourceIndex = tySource.getLastIndex();
} catch (UnsupportedOperation uo1) {
tySourceIndex = 0;
}
}
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#unsubscribeToDataNotifications()
*/
public void unsubscribeToDataNotifications(){
if (rotSource != null) {
rotSource.removeListener(this);
rotSource.removeEndNotificationListener(this);
}
if (txSource != null) {
txSource.removeListener(this);
txSource.removeEndNotificationListener(this);
}
if (tySource != null) {
tySource.removeListener(this);
tySource.removeEndNotificationListener(this);
}
}
/* (non-Javadoc)
* @see simtools.data.DataSourceListener#DataSourceReplaced(simtools.data.DataSource, simtools.data.DataSource)
*/
public void DataSourceReplaced(DataSource oldData, DataSource newData) {
if(oldData==rotSource){
rotSource=newData;
if (rotSource!=null){
rotSource.addListener(this);
rotSource.addEndNotificationListener(this);
try {
rotSourceIndex = rotSource.getLastIndex();
}
catch (UnsupportedOperation uo1) {
rotSourceIndex = 0;
}
}
oldData.removeListener(this);
oldData.removeEndNotificationListener(this);
dirty = true;
}
if(oldData==txSource){
txSource=newData;
if (txSource!=null){
txSource.addListener(this);
txSource.addEndNotificationListener(this);
try {
txSourceIndex = txSource.getLastIndex();
}
catch (UnsupportedOperation uo1) {
txSourceIndex = 0;
}
}
oldData.removeListener(this);
oldData.removeEndNotificationListener(this);
dirty = true;
}
if(oldData==tySource){
tySource=newData;
if (tySource!=null){
tySource.addListener(this);
tySource.addEndNotificationListener(this);
try {
tySourceIndex = tySource.getLastIndex();
}
catch (UnsupportedOperation uo1) {
tySourceIndex = 0;
}
}
oldData.removeListener(this);
oldData.removeEndNotificationListener(this);
dirty = true;
}
}
/* (non-Javadoc)
* @see simtools.data.EndNotificationListener#notificationEnd(java.lang.Object)
*/
public void notificationEnd(Object referer) {
if(dirty && referer!=null){
boolean change=false;
double value;
// read values
if ((rotSource!=null) && (referer.equals(rotSource))){
try {
// If a rotation mapper exists, get rotation value corresponding to last data source value
if ((rotationMapper!=null) && (rotSource!=null)){
Double rotationValue = ((Double)rotationMapper.getDouble(rotSource, rotSourceIndex));
if (rotationValue!=null){
value = rotationValue.doubleValue();
}else{
value=0;
}
}else{
value=rotSource.getDoubleValue(rotSourceIndex);
}
if((value!=rotValue) && (value!=Double.NaN)){
rotValue=value;
change=true;
}
}
catch (DataException de) {
}
}
if((txSource!=null) && (referer.equals(txSource))){
try {
// If a tx mapper exists, get rotation value corresponding to last data source value
if ((txMapper!=null) && (txSource!=null)){
Double tranxValue = ((Double)txMapper.getDouble(txSource, txSourceIndex));
if (tranxValue!=null){
value = tranxValue.doubleValue();
}else{
value=0;
}
}else{ // Else get the value directly from source
value=txSource.getDoubleValue(txSourceIndex);
}
if((value!=txValue) && (value!=Double.NaN)){
txValue=value;
change=true;
}
}
catch (DataException de) {
}
}
if ((tySource!=null) && (referer.equals(tySource))){
try {
// If a ty mapper exists, get rotation value corresponding to last data source value
if ((tyMapper!=null) && (tySource!=null)){
Double tranyValue = ((Double)tyMapper.getDouble(tySource, tySourceIndex));
if (tranyValue!=null){
value = tranyValue.doubleValue();
}else{
value=0;
}
}else{// Else get the value directly from source
value=tySource.getDoubleValue(tySourceIndex);
}
if((value!=tyValue) && (value!=Double.NaN)){
tyValue=value;
change=true;
}
}
catch (DataException de) {
}
}
if(change){
// notify the owner of the new value(s)
// the owner has then to call updateTransform with its parameters
if(listener!=null){
listener.updateTransform();
}
}
dirty=false;
}
}
/* (non-Javadoc)
* @see simtools.util.NamedProperties#getPropertyNames()
*/
public String[] getPropertyNames() {
if (_propertyNames==null)
_propertyNames = new AffineTransformData.AffineTransformDataPropertiesNames().getPropertyNames();
return _propertyNames;
}
/* (non-Javadoc)
* @see simtools.util.NamedProperties#getPropertyValue(java.lang.String)
*/
public Object getPropertyValue(String name) {
Object res = null;
if(name.equalsIgnoreCase("TRANS_ENABLED")) {
res = new Boolean(transEnabled);
} else if (name.equalsIgnoreCase("TX_MAPPER")) {
res = txMapper;
}else if (name.equalsIgnoreCase("TY_MAPPER")) {
res = tyMapper;
}else if(name.equalsIgnoreCase("TX_SOURCE")) {
res = txSource;
} else if(name.equalsIgnoreCase("TY_SOURCE")) {
res = tySource;
} else if(name.equalsIgnoreCase("TX_VALUE")) {
res = new Double(txValue);
} else if(name.equalsIgnoreCase("TY_VALUE")) {
res = new Double(tyValue);
} else if(name.equalsIgnoreCase("TRANSLATION_FIRST")) {
res = new Boolean(translationFirst);
} else if(name.equalsIgnoreCase("TRANS_UNIT_SCALE")) {
res = new Double(transUnitScale);
} else if(name.equalsIgnoreCase("ROT_ENABLED")) {
res = new Boolean(rotEnabled);
} else if (name.equalsIgnoreCase("ROT_MAPPER")) {
res = rotationMapper;
}else if(name.equalsIgnoreCase("ROT_SOURCE")) {
res = rotSource;
} else if(name.equalsIgnoreCase("ROT_VALUE")) {
res = new Double(rotValue);
} else if(name.equalsIgnoreCase("ANGLE_UNIT_SCALE")) {
res = new Double(angleUnitScale);
}
return res;
}
/* (non-Javadoc)
* @see simtools.util.NamedProperties#setPropertyValue(java.lang.String, java.lang.Object)
*/
public void setPropertyValue(String name, Object value) {
if(name.equalsIgnoreCase("TRANS_ENABLED") && value instanceof Boolean) {
transEnabled = ((Boolean)value).booleanValue();
} else if(name.equalsIgnoreCase("TX_MAPPER")) {
if (value instanceof DoubleValueMapper) {
txMapper = (DoubleValueMapper)value;
}
else{
txMapper = null;
}
}else if(name.equalsIgnoreCase("TY_MAPPER")) {
if (value instanceof DoubleValueMapper) {
tyMapper = (DoubleValueMapper)value;
}
else{
tyMapper = null;
}
}else if(name.equalsIgnoreCase("TX_SOURCE")) {
if (txSource!=null) {
txSource.removeListener(this);
txSource.removeEndNotificationListener(this);
txSource=null;
}
if (value instanceof DataSource) {
if ((DataSource)value!=txSource)
dirty = true;
txSource = (DataSource) value;
try {
txSourceIndex = txSource.getLastIndex();
} catch (UnsupportedOperation e) {
txSourceIndex = 0;
}
try {
// If a tx mapper exists, get rotation value corresponding to last data source value
double sourceValue;
if ((txMapper!=null) && (txSource!=null)){
Double transxValue = ((Double)txMapper.getDouble(txSource, txSourceIndex));
if (transxValue!=null){
sourceValue = transxValue.doubleValue();
}else{
sourceValue = 0;
}
}else{
sourceValue = txSource.getDoubleValue(txSourceIndex);
}
if (sourceValue != Double.NaN)
txValue = sourceValue;
} catch (DataException e) {
}
txSource.addListener(this);
txSource.addEndNotificationListener(this);
}
} else if(name.equalsIgnoreCase("TY_SOURCE")) {
if (tySource!=null) {
tySource.removeListener(this);
tySource.removeEndNotificationListener(this);
tySource=null;
}
if (value instanceof DataSource) {
if ((DataSource)value!=tySource)
dirty = true;
tySource = (DataSource) value;
try {
tySourceIndex = tySource.getLastIndex();
} catch (UnsupportedOperation e) {
tySourceIndex = 0;
}
try {
// If a ty mapper exists, get rotation value corresponding to last data source value
double sourceValue;
if ((tyMapper!=null) && (tySource!=null)){
Double transyValue = ((Double)tyMapper.getDouble(tySource, tySourceIndex));
if (transyValue!=null){
sourceValue = transyValue.doubleValue();
}else{
sourceValue=0;
}
}else{
sourceValue = tySource.getDoubleValue(tySourceIndex);
}
if (sourceValue != Double.NaN)
tyValue = sourceValue;
} catch (DataException e) {
}
tySource.addListener(this);
tySource.addEndNotificationListener(this);
}
} else if(name.equalsIgnoreCase("TX_VALUE")&& value instanceof Double) {
txValue = ((Double)value).doubleValue();
} else if(name.equalsIgnoreCase("TY_VALUE")&& value instanceof Double) {
tyValue = ((Double)value).doubleValue();
} else if(name.equalsIgnoreCase("TRANSLATION_FIRST")&& value instanceof Boolean) {
translationFirst = ((Boolean)value).booleanValue();
} else if(name.equalsIgnoreCase("TRANS_UNIT_SCALE")&& value instanceof Double) {
transUnitScale = ((Double)value).doubleValue();
} else if(name.equalsIgnoreCase("ROT_ENABLED")&& value instanceof Boolean) {
rotEnabled = ((Boolean)value).booleanValue();
} else if(name.equalsIgnoreCase("ROT_MAPPER")) {
if (value instanceof DoubleValueMapper) {
rotationMapper = (DoubleValueMapper)value;
}
else{
rotationMapper = null;
}
}else if(name.equalsIgnoreCase("ROT_SOURCE")) {
if (rotSource!=null) {
rotSource.removeListener(this);
rotSource.removeEndNotificationListener(this);
rotSource=null;
}
if (value instanceof DataSource) {
if ( (DataSource)value!=rotSource)
dirty = true;
rotSource = (DataSource) value;
try {
rotSourceIndex = rotSource.getLastIndex();
} catch (UnsupportedOperation e) {
rotSourceIndex = 0;
}
try {
double sourceValue;
// If a rotation mapper exists, get rotation value corresponding to last data source value
if ((rotationMapper!=null) && (rotSource!=null)){
Double rotationValue = ((Double)rotationMapper.getDouble(rotSource, rotSourceIndex));
if (rotationValue!=null){
sourceValue = rotationValue.doubleValue();
}else{
sourceValue=0;
}
}else{
sourceValue = rotSource.getDoubleValue(rotSourceIndex);
}
if (sourceValue != Double.NaN)
rotValue = sourceValue;
} catch (DataException e) {
}
rotSource.addListener(this);
rotSource.addEndNotificationListener(this);
}
} else if(name.equalsIgnoreCase("ROT_VALUE")&& value instanceof Double) {
rotValue = ((Double)value).doubleValue();
} else if(name.equalsIgnoreCase("ANGLE_UNIT_SCALE")&& value instanceof Double) {
angleUnitScale = ((Double)value).doubleValue();
}
}
/* (non-Javadoc)
* @see simtools.util.NamedProperties#getInnerProperties()
*/
public Collection getInnerProperties() {
return null;
}
/**
* Serialization : manage data sources
* @param out
* @throws java.io.IOException
*/
private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
out.defaultWriteObject();
DataSourcePool.global.writeDataSource(out, rotSource);
DataSourcePool.global.writeDataSource(out, txSource);
DataSourcePool.global.writeDataSource(out, tySource);
}
/**
* Serialization : manage data sources
* @param in
* @throws java.lang.ClassNotFoundException
* @throws java.io.IOException
*/
private void readObject(java.io.ObjectInputStream in)
throws java.lang.ClassNotFoundException, java.io.IOException {
in.defaultReadObject();
rotSource = DataSourcePool.global.readDataSource(in);
if (rotSource != null){
try {
rotSource.addListener(this);
rotSource.addEndNotificationListener(this);
rotSourceIndex = rotSource.getLastIndex();
} catch (UnsupportedOperation uo1) {
rotSourceIndex = 0;
}
}
// Rotation mapper
if (rotationMapper != null) {
rotationMapper = DoubleValueMapper.updateDoubleValueMapper(rotationMapper);
}
if (rotationMapper!=null && rotSource!=null) {
Double rotationValue = ((Double)rotationMapper.getDouble(rotSource, rotSourceIndex));
if (rotationValue!=null)
rotValue = ((Double)rotationMapper.getDouble(rotSource, rotSourceIndex)).doubleValue();
else
rotValue=0.;
}
else rotationMapper = null;
txSource = DataSourcePool.global.readDataSource(in);
if (txSource != null){
try {
txSource.addListener(this);
txSource.addEndNotificationListener(this);
txSourceIndex = txSource.getLastIndex();
} catch (UnsupportedOperation uo1) {
txSourceIndex = 0;
}
}
// Rotation mapper
if (txMapper != null) {
txMapper = DoubleValueMapper.updateDoubleValueMapper(txMapper);
}
if (txMapper!=null && txSource!=null) {
Double transxValue = ((Double)txMapper.getDouble(txSource, txSourceIndex));
if (transxValue!=null)
txValue = transxValue.doubleValue();
}
else txMapper = null;
tySource = DataSourcePool.global.readDataSource(in);
if (tySource != null){
try {
tySource.addListener(this);
tySource.addEndNotificationListener(this);
tySourceIndex = tySource.getLastIndex();
} catch (UnsupportedOperation uo1) {
tySourceIndex = 0;
}
}
// ty mapper
if (tyMapper != null) {
tyMapper = DoubleValueMapper.updateDoubleValueMapper(tyMapper);
}
if (tyMapper!=null && tySource!=null) {
Double transyValue = ((Double)tyMapper.getDouble(tySource, tySourceIndex));
if (transyValue!=null)
tyValue =transyValue.doubleValue();
}
else tyMapper = null;
transformBounds=new double[8];
transform=new AffineTransform();
}
/**
* An interface to warn the transform owner in case of transform change
*/
public interface Listener {
/**
* The transformation input paramters have changed it has to be updated according to
* transformation reference frame coordinates.
* Thus, the implementation has to call AffineTransformData.updateTransform(cx,cy)
* to perform this update before using the transform in the rendering process
*/
public void updateTransform();
}
public static class AffineTransformDataPropertiesNames extends AbstractShapePropertiesNames{
private static transient String[] props = new String[] {
"TRANS_ENABLED",
"TX_MAPPER",
"TX_SOURCE",
"TY_MAPPER",
"TY_SOURCE",
"TX_VALUE",
"TY_VALUE",
"TRANSLATION_FIRST",
"TRANS_UNIT_SCALE",
"ROT_ENABLED",
"ROT_MAPPER",
"ROT_SOURCE",
"ROT_VALUE",
"ANGLE_UNIT_SCALE",
};
public AffineTransformDataPropertiesNames(){
super();
for (int i=0;i<props.length;i++){
propertyNames.add(props[i]);
}
}
}
}