/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad.data.fits;
import java.rmi.RemoteException;
import nom.tam.fits.BasicHDU;
import nom.tam.fits.BinaryTableHDU;
import nom.tam.fits.Column;
import nom.tam.fits.Fits;
import nom.tam.fits.FitsException;
import nom.tam.fits.ImageHDU;
import nom.tam.fits.PrimaryHDU;
import nom.tam.util.ArrayFuncs;
import visad.FieldImpl;
import visad.FlatField;
import visad.Function;
import visad.FunctionType;
import visad.GriddedSet;
import visad.MathType;
import visad.RealTupleType;
import visad.Scalar;
import visad.ScalarType;
import visad.Set;
import visad.VisADException;
import visad.UnimplementedException;
public class TourWriter
extends Tourist
{
private Fits fits;
public TourWriter(boolean replace, Fits fits)
{
super(replace);
this.fits = fits;
}
private String[] getNames(RealTupleType rtt)
throws VisADException
{
int dim = rtt.getDimension();
if (dim == 0) {
return null;
}
String[] list = new String[dim];
for (int i = 0; i < dim; i++) {
MathType type = rtt.getComponent(i);
if (!(type instanceof ScalarType)) {
throw new VisADException("Expected a ScalarType name, got " +
type.getClass().getName());
}
list[i] = ((ScalarType )type).getName();
}
return list;
}
private String[] getNames(ScalarType st)
throws VisADException
{
String[] list = new String[1];
list[0] = st.getName();
return list;
}
private String[] getNames(MathType mt)
throws VisADException
{
if (mt instanceof RealTupleType) {
return getNames((RealTupleType )mt);
}
if (mt instanceof ScalarType) {
return getNames((ScalarType )mt);
}
throw new VisADException("Couldn't get list of names from " +
mt.getClass().getName());
}
private void saveBinaryTable(FlatField fld, int domainDim, int rangeDim)
throws VisADException
{
System.err.println("TourWriter.saveBinaryTable(" + domainDim + ", " + rangeDim + "):");
FunctionType funcType = (FunctionType )fld.getType();
String[] rangeNames = getNames(funcType.getRange());
BinaryTableHDU hdu;
try {
hdu = new BinaryTableHDU();
} catch (FitsException e) {
throw new VisADException("Couldn't create BinaryTableHDU: " +
e.getMessage());
}
double[][] values = fld.getValues();
System.err.println("\tvalues: " + values.length + "x" + values[0].length);
double[][] column = new double[1][];
int[] lengths = new int[2];
Object[][] table = new Object[values.length][];
lengths[0] = 1;
for (int i = 0; i < table.length; i++) {
column[0] = values[i];
lengths[1] = column[0].length;
ConvertDoubleArray cvtArray = new ConvertDoubleArray(lengths, column);
Object o = cvtArray.getConverter().getRowMajor(column);
if (o == null) {
throw new VisADException("Couldn't extract array from column #" + i);
}
try {
Column col = new Column();
col.setData((Object[] )o);
String num = "" + i;
StringBuffer buf = new StringBuffer(8);
if (rangeNames != null) {
buf.setLength(0);
buf.append("TTYPE");
buf.append(num);
buf.append(" ");
buf.setLength(8);
buf.append("= '");
buf.append(rangeNames[i]);
buf.append("'");
col.addKey(buf.toString());
}
hdu.addColumn(col);
} catch (FitsException e) {
System.err.println("Couldn't add binary table column #" + i + ": " +
e.getMessage());
}
}
try {
fits.addHDU(hdu);
} catch (FitsException e) {
throw new VisADException("Couldn't add FITS binary table HDU : " +
e.getMessage());
}
}
private void saveImage(FlatField fld, int domainDim, int rangeDim)
throws VisADException
{
Set set = fld.getDomainSet();
if (!(set instanceof GriddedSet)) {
throw new VisADException("Cannot build FITS Image" +
" from non-Gridded domain");
}
int size;
try {
size = fits.size();
} catch (FitsException e) {
System.err.println("TourWriter.saveImage: Yikes! Fits.size() threw");
e.printStackTrace(System.err);
throw new VisADException("Couldn't get size of FITS file");
}
final int[] lengths = ((GriddedSet )set).getLengths();
if (lengths.length != 2) {
throw new VisADException("Don't know how to decipher " + lengths.length +
"-dimension FlatField!");
}
double[][] values = fld.getValues();
if (values[0].length != lengths[0]*lengths[1]) {
throw new VisADException("Mismatch between FlatField length array" +
" and value array length");
} else if (values.length != 1 && values.length != 3) {
throw new VisADException("Don't know how to decipher " + values.length +
"-dimension FlatField values!");
}
// create 8-bit color value array
final int len = values[0].length;
byte[] colorVals = new byte[len];
// fill in 8-bit color values
int colRow, valIndex;
valIndex = 0;
for (int i = lengths[1] - 1; i >= 0; i--) {
colRow = i * lengths[0];
for (int j = 0; j < lengths[0]; j++) {
int v;
if (values.length == 3) {
// map to RGB
v = (int )((0.299 * values[0][valIndex]) +
(0.587 * values[1][valIndex]) +
(0.114 * values[2][valIndex]));
} else {
v = (int )values[0][valIndex];
}
colorVals[colRow+j] = (byte )v;
valIndex++;
}
}
byte[][] image = (byte[][] )ArrayFuncs.curl(colorVals, lengths);
try {
BasicHDU hdu;
if (size == 0) {
hdu = new PrimaryHDU((Object )image);
} else {
hdu = new ImageHDU((Object )image);
}
fits.addHDU(hdu);
} catch (FitsException e) {
throw new VisADException("Couldn't build " +
(size == 0 ? "primary" : "image") +
" FITS HDU : " + e.getMessage());
}
}
private void save(FlatField fld)
throws RemoteException, VisADException
{
MathType type = fld.getType();
if (!(type instanceof FunctionType)) {
throw new VisADException("Confused Data object" +
" (FlatField with non-FunctionType)");
}
int domainDim = fld.getDomainSet().getDimension();
if (domainDim > 2) {
throw new VisADException("Can't write FITS file with" +
" domain dimension of " + domainDim);
}
int rangeDim = fld.getRangeDimension();
if (rangeDim != 1 && rangeDim != 3) {
throw new VisADException("Can't write FITS file with" +
" range dimension of " + rangeDim);
}
if (domainDim != 2) {
saveBinaryTable(fld, domainDim, rangeDim);
} else {
saveImage(fld, domainDim, rangeDim);
}
}
private void save(FieldImpl fld)
throws RemoteException, VisADException
{
if (fld instanceof FlatField) {
save((FlatField )fld);
return;
}
throw new UnimplementedException("Can only save FlatField data");
}
public boolean visit(Function func, int depth)
throws RemoteException, VisADException
{
if (!(func instanceof FieldImpl)) {
throw new UnimplementedException("Can only save FieldImpl data");
}
save((FieldImpl )func);
return true;
}
public boolean visit(Scalar scalar, int depth)
throws VisADException
{
return false;
}
public boolean visit(Set set, int depth)
throws VisADException
{
throw new UnimplementedException("Cannot write Set data to FITS files yet");
}
}