/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2012 - 2013, Geomatys
*
* This library 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;
* version 2.1 of the License.
*
* 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
* Lesser General Public License for more details.
*/
package org.geotoolkit.coverage.postgresql;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import javax.measure.Unit;
import javax.swing.ProgressMonitor;
import net.iharder.Base64;
import org.apache.sis.measure.NumberRange;
import org.apache.sis.referencing.operation.transform.TransferFunction;
import org.apache.sis.storage.DataStoreException;
import org.geotoolkit.storage.coverage.AbstractPyramidalCoverageReference;
import org.geotoolkit.coverage.Category;
import org.geotoolkit.storage.coverage.CoverageStoreContentEvent;
import org.geotoolkit.storage.coverage.CoverageStoreManagementEvent;
import org.geotoolkit.storage.coverage.GridMosaic;
import org.geotoolkit.coverage.GridSampleDimension;
import org.geotoolkit.storage.coverage.Pyramid;
import org.geotoolkit.storage.coverage.PyramidSet;
import org.geotoolkit.storage.coverage.PyramidalModelWriter;
import org.geotoolkit.coverage.grid.ViewType;
import org.geotoolkit.coverage.io.CoverageStoreException;
import org.geotoolkit.coverage.io.GridCoverageWriter;
import org.geotoolkit.coverage.postgresql.epsg.PGEPSGWriter;
import org.geotoolkit.coverage.wkb.WKBRasterConstants;
import org.geotoolkit.coverage.wkb.WKBRasterWriter;
import org.geotoolkit.internal.InternalUtilities;
import org.geotoolkit.resources.Vocabulary;
import org.geotoolkit.temporal.object.TemporalUtilities;
import org.geotoolkit.util.StringUtilities;
import org.geotoolkit.version.Version;
import org.opengis.coverage.SampleDimensionType;
import org.opengis.util.GenericName;
import org.opengis.geometry.DirectPosition;
import org.opengis.metadata.content.TransferFunctionType;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.operation.MathTransform1D;
import org.opengis.util.FactoryException;
import org.apache.sis.measure.Units;
import org.apache.sis.util.logging.Logging;
/**
*
* @author Johann Sorel (Geomatys)
* @author Cédric Briançon (Geomatys)
*/
public class PGCoverageReference extends AbstractPyramidalCoverageReference {
private final PGCoverageStore pgstore;
private final PGPyramidSet pyramidSet;
final Version version;
public PGCoverageReference(final PGCoverageStore store, final GenericName name, Version version) {
super(store,name,0);
this.pgstore = store;
this.pyramidSet = new PGPyramidSet(this);
this.version = version;
}
@Override
public boolean isWritable() throws CoverageStoreException {
return true;
}
@Override
public PGCoverageStore getStore() {
return (PGCoverageStore) pgstore;
}
@Override
public GridCoverageWriter acquireWriter() throws CoverageStoreException {
return new PyramidalModelWriter(this);
}
@Override
public PyramidSet getPyramidSet() throws DataStoreException {
return pyramidSet;
}
@Override
public Pyramid createPyramid(final CoordinateReferenceSystem crs) throws DataStoreException {
String pyramidId = "";
Connection cnx = null;
Statement stmt = null;
ResultSet rs = null;
try{
cnx = pgstore.getDataSource().getConnection();
cnx.setReadOnly(false);
//find or insert coordinate reference system
final PGEPSGWriter writer = new PGEPSGWriter(pgstore);
final String epsgCode = String.valueOf(writer.getOrCreateCoordinateReferenceSystem(crs));
stmt = cnx.createStatement();
final int layerId = pgstore.getLayerId(cnx,name.tip().toString());
StringBuilder query = new StringBuilder();
query.append("INSERT INTO ");
query.append(pgstore.encodeTableName("Pyramid"));
query.append("(\"layerId\",\"epsg\") VALUES (");
query.append(layerId);
query.append(",'");
query.append(epsgCode);
query.append("')");
stmt.executeUpdate(query.toString(), new String[]{"id"});
rs = stmt.getGeneratedKeys();
if(rs.next()){
pyramidId = String.valueOf(rs.getInt(1));
}
//write version
if(version!=null && !version.getLabel().equals(PGVersionControl.UNSET)){
query.setLength(0);
query.append("INSERT INTO ");
query.append(pgstore.encodeTableName("PyramidProperty"));
query.append("(\"pyramidId\",\"key\",\"type\",\"value\") VALUES (");
query.append(pyramidId);
query.append(",'version','date','");
query.append(TemporalUtilities.toISO8601Z(version.getDate(), TimeZone.getTimeZone("GMT+0")));
query.append("')");
stmt.executeUpdate(query.toString());
}
}catch(FactoryException ex){
throw new DataStoreException(ex);
}catch(SQLException ex){
throw new DataStoreException(ex);
}finally{
pgstore.closeSafe(cnx, stmt, rs);
}
pyramidSet.mustUpdate();
final CoverageStoreManagementEvent event = firePyramidAdded(pyramidId);
getStore().forwardStructureEvent(event);
for(Pyramid p : pyramidSet.getPyramids()){
if(p.getId().equals(pyramidId)){
return p;
}
}
//should not happen
throw new DataStoreException("Generated pyramid not found.");
}
@Override
public void deletePyramid(String pyramidId) throws DataStoreException {
Connection cnx = null;
Statement stmt = null;
ResultSet rs = null;
try{
cnx = pgstore.getDataSource().getConnection();
cnx.setReadOnly(false);
stmt = cnx.createStatement();
final int pyramidIdInt = Integer.valueOf(pyramidId);
final StringBuilder sql = new StringBuilder("DELETE FROM ");
sql.append(pgstore.encodeTableName("Pyramid"));
sql.append(" WHERE id = ");
sql.append(pyramidIdInt);
stmt.executeUpdate(sql.toString());
}catch(SQLException ex){
throw new DataStoreException(ex.getMessage(), ex);
}finally{
pgstore.closeSafe(cnx, stmt, rs);
pyramidSet.mustUpdate();
}
}
@Override
public GridMosaic createMosaic(final String pyramidId, final Dimension gridSize, final Dimension tilePixelSize,
final DirectPosition upperleft, final double pixelscale) throws DataStoreException {
long mosaicId = 0;
Connection cnx = null;
Statement stmt = null;
ResultSet rs = null;
try{
cnx = pgstore.getDataSource().getConnection();
cnx.setReadOnly(false);
stmt = cnx.createStatement();
final int pyramidIdInt = Integer.valueOf(pyramidId);
StringBuilder query = new StringBuilder();
query.append("INSERT INTO ");
query.append(pgstore.encodeTableName("Mosaic"));
query.append("(\"pyramidId\",\"upperCornerX\",\"upperCornerY\",\"gridWidth\",\"gridHeight\",\"scale\",\"tileWidth\",\"tileHeight\") VALUES (");
query.append(pyramidIdInt ).append(',');
query.append(upperleft.getOrdinate(0)).append(',');
query.append(upperleft.getOrdinate(1)).append(',');
query.append(gridSize.width ).append(',');
query.append(gridSize.height ).append(',');
query.append(pixelscale ).append(',');
query.append(tilePixelSize.width ).append(',');
query.append(tilePixelSize.height );
query.append(")");
stmt.executeUpdate(query.toString(), new String[]{"id"});
rs = stmt.getGeneratedKeys();
if(rs.next()){
mosaicId = rs.getLong(1);
}
final CoordinateReferenceSystem crs = upperleft.getCoordinateReferenceSystem();
final CoordinateSystem cs = crs.getCoordinateSystem();
for(int i=2,n=cs.getDimension();i<n;i++){
final double value = upperleft.getOrdinate(i);
query = new StringBuilder();
query.append("INSERT INTO ");
query.append(pgstore.encodeTableName("MosaicAxis"));
query.append("(\"mosaicId\",\"indice\",\"value\") VALUES (");
query.append(mosaicId).append(',');
query.append(i).append(',');
query.append(value);
query.append(")");
stmt.executeUpdate(query.toString());
}
}catch(SQLException ex){
throw new DataStoreException(ex.getMessage(), ex);
}finally{
pgstore.closeSafe(cnx, stmt, rs);
}
pyramidSet.mustUpdate();
final CoverageStoreManagementEvent event = fireMosaicAdded(pyramidId, String.valueOf(mosaicId));
getStore().forwardStructureEvent(event);
for (final Pyramid p : pyramidSet.getPyramids()) {
if (p.getId().equals(pyramidId)) {
for(GridMosaic mosaic : p.getMosaics()){
if (((PGGridMosaic)mosaic).getDatabaseId() == mosaicId) {
return mosaic;
}
}
}
}
//should not happen
throw new DataStoreException("Generated mosaic not found.");
}
/**
* {@inheritDoc}
*/
@Override
public void deleteMosaic(String pyramidId, String mosaicId) throws DataStoreException {
Connection cnx = null;
Statement stmt = null;
ResultSet rs = null;
try{
cnx = pgstore.getDataSource().getConnection();
cnx.setReadOnly(false);
stmt = cnx.createStatement();
final int mosaicdIdInt = Integer.valueOf(mosaicId);
final StringBuilder sql = new StringBuilder("DELETE FROM ");
sql.append(pgstore.encodeTableName("Mosaic"));
sql.append(" WHERE id = ");
sql.append(mosaicdIdInt);
stmt.executeUpdate(sql.toString());
}catch(SQLException ex){
throw new DataStoreException(ex.getMessage(), ex);
}finally{
pgstore.closeSafe(cnx, stmt, rs);
pyramidSet.mustUpdate();
}
}
/**
* {@inheritDoc }.
*/
@Override
public void writeTiles(final String pyramidId, final String mosaicId, final RenderedImage image, final Rectangle area,
final boolean onlyMissing, final ProgressMonitor monitor) throws DataStoreException {
final int offsetX = image.getMinTileX();
final int offsetY = image.getMinTileY();
final int startX = (int)area.getMinX();
final int startY = (int)area.getMinY();
final int endX = (int)area.getMaxX();
final int endY = (int)area.getMaxY();
assert startX >= 0;
assert startY >= 0;
assert endX > startX && endX <= image.getNumXTiles();
assert endY > startY && endY <= image.getNumYTiles();
final RejectedExecutionHandler rejectHandler = new ThreadPoolExecutor.CallerRunsPolicy();
final BlockingQueue queue = new ArrayBlockingQueue(Runtime.getRuntime().availableProcessors());
final ThreadPoolExecutor executor = new ThreadPoolExecutor(
0, Runtime.getRuntime().availableProcessors(), 1, TimeUnit.MINUTES, queue, rejectHandler);
for(int y=startY; y<endY;y++){
for(int x=startX;x<endX;x++){
final Raster raster = image.getTile(offsetX+x, offsetY+y);
final RenderedImage img = new BufferedImage(image.getColorModel(),
(WritableRaster)raster, image.getColorModel().isAlphaPremultiplied(), null);
final int tx = offsetX+x;
final int ty = offsetY+y;
executor.submit(new Runnable() {
@Override
public void run() {
if (monitor != null && monitor.isCanceled()) {
return;
}
try {
writeTile(pyramidId, mosaicId, tx, ty, img);
} catch (DataStoreException ex) {
Logging.getLogger("org.geotoolkit.coverage.postgresql").log(Level.SEVERE, null, ex);
}
}
});
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void writeTile(String pyramidId, String mosaicId, int col, int row, RenderedImage image) throws DataStoreException {
Connection cnx = null;
Statement insertStmt = null;
Statement deleteStmt = null;
Statement selectStmt = null;
ResultSet rs = null;
try{
StringBuilder query = new StringBuilder();
query.append("SELECT id,\"mosaicId\",\"positionX\",\"positionY\" FROM ")
.append(pgstore.encodeTableName("Tile"))
.append(" WHERE \"mosaicId\"=").append(Integer.valueOf(mosaicId))
.append(" AND \"positionX\"=").append(Integer.valueOf(col))
.append(" AND \"positionY\"=").append(Integer.valueOf(row));
cnx = pgstore.getDataSource().getConnection();
cnx.setReadOnly(false);
selectStmt = cnx.createStatement();
rs = selectStmt.executeQuery(query.toString());
while (rs.next()) {
final int id = rs.getInt("id");
query = new StringBuilder();
query.append("DELETE FROM ")
.append(pgstore.encodeTableName("Tile"))
.append(" WHERE id=").append(id);
deleteStmt = cnx.createStatement();
deleteStmt.executeUpdate(query.toString());
}
final WKBRasterWriter writer = new WKBRasterWriter();
final byte[] wkbimg = writer.write(image, null, 0);
final String base64 = Base64.encodeBytes(wkbimg);
query = new StringBuilder();
query.append("INSERT INTO");
query.append(pgstore.encodeTableName("Tile"));
query.append("(\"raster\",\"mosaicId\",\"positionX\",\"positionY\") VALUES ( (");
query.append("encode(").append("decode('").append(base64).append("','base64')").append(",'hex')").append(")::raster,");
query.append(Integer.valueOf(mosaicId)).append(',');
query.append(col).append(',');
query.append(row).append(')');
insertStmt = cnx.createStatement();
insertStmt.executeUpdate(query.toString());
final CoverageStoreContentEvent event = fireTileUpdated(pyramidId, mosaicId, Collections.singletonList(new Point(col,row)));
getStore().forwardContentEvent(event);
}catch(IOException ex){
throw new DataStoreException(ex.getMessage(), ex);
}catch(SQLException ex){
throw new DataStoreException(ex.getMessage(), ex);
}finally{
pgstore.closeSafe(cnx, selectStmt, rs);
pgstore.closeSafe(insertStmt);
pgstore.closeSafe(deleteStmt);
}
}
@Override
public void deleteTile(String pyramidId, String mosaicId, int col, int row) throws DataStoreException {
Connection cnx = null;
Statement stmt = null;
ResultSet rs = null;
try{
cnx = pgstore.getDataSource().getConnection();
cnx.setReadOnly(false);
stmt = cnx.createStatement();
final int mosaicdIdInt = Integer.valueOf(mosaicId);
final StringBuilder sql = new StringBuilder("DELETE FROM ");
sql.append(pgstore.encodeTableName("Tile"));
sql.append(" WHERE \"mosaicId\" = ").append(mosaicdIdInt);
sql.append(" AND \"positionX\" = ").append(col);
sql.append(" AND \"positionY\" = ").append(row);
stmt.executeUpdate(sql.toString());
}catch(SQLException ex){
throw new DataStoreException(ex.getMessage(), ex);
}finally{
pgstore.closeSafe(cnx, stmt, rs);
pyramidSet.mustUpdate();
};
}
@Override
public List<GridSampleDimension> getSampleDimensions() throws DataStoreException{
final List<GridSampleDimension> dimensions = new LinkedList<>();
boolean versionSupport = isVersionColumnExist();
Connection cnx = null;
Statement stmt = null;
ResultSet rs = null;
try {
cnx = pgstore.getDataSource().getConnection();
cnx.setReadOnly(false);
final int layerId = pgstore.getLayerId(cnx,name.tip().toString());
String versionStr;
if (version != null && !version.getLabel().equals(PGVersionControl.UNSET)) {
versionStr = TemporalUtilities.toISO8601Z(version.getDate(), TimeZone.getTimeZone("GMT+0"));
} else {
versionStr = PGVersionControl.UNSET;
}
final StringBuilder query = new StringBuilder();
if(versionSupport) {
query.append("SELECT \"id\",\"version\",\"indice\",\"description\",\"dataType\",\"unit\"");
query.append("FROM ").append(pgstore.encodeTableName("Band"));
query.append(" WHERE ");
query.append("\"layerId\"=").append(Integer.valueOf(layerId));
query.append(" AND \"version\" LIKE \'").append(versionStr).append("\' ");
query.append("ORDER BY \"indice\" ASC");
} else {
query.append("SELECT \"id\",\"indice\",\"description\",\"dataType\",\"unit\"");
query.append("FROM ").append(pgstore.encodeTableName("Band"));
query.append(" WHERE ");
query.append("\"layerId\"=").append(Integer.valueOf(layerId));
query.append("ORDER BY \"indice\" ASC");
}
stmt = cnx.createStatement();
rs = stmt.executeQuery(query.toString());
while (rs.next()) {
final int sid = rs.getInt("id");
final int indice = rs.getInt("indice");
final String description = rs.getString("description");
final SampleDimensionType type = WKBRasterConstants.getDimensionType(rs.getInt("dataType"));
final String unitStr = rs.getString("unit");
Unit unit = null;
if(unitStr != null && !unitStr.isEmpty()) {
unit = Units.valueOf(unitStr);
}
//read categories
final List<Category> categories = new ArrayList<Category>();
final StringBuilder catQuery = new StringBuilder();
catQuery.append("SELECT \"id\",\"band\",\"name\",\"lower\",\"upper\",\"c0\",\"c1\",\"function\",\"colors\" ");
catQuery.append("FROM ").append(pgstore.encodeTableName("Category"));
catQuery.append(" WHERE ");
catQuery.append("\"band\"=").append(Integer.valueOf(sid));
stmt = cnx.createStatement();
final ResultSet catrs = stmt.executeQuery(catQuery.toString());
while(catrs.next()){
final String name = catrs.getString("name");
final double lower = catrs.getDouble("lower");
final double upper = catrs.getDouble("upper");
final double c0 = catrs.getDouble("c0");
final double c1 = catrs.getDouble("c1");
final String function = catrs.getString("function");
final String[] colors = catrs.getString("colors").split(",");
final TransferFunction f = new TransferFunction();
TransferFunctionType functionType = TransferFunctionType.valueOf(function);
if (functionType != null) {
f.setType(functionType);
} else{
throw new IllegalArgumentException("Unsupported transform : "+function);
}
f.setScale(c1);
f.setOffset(c0);
final MathTransform1D sampleToGeophysics = f.getTransform();
final Color[] cols = new Color[colors.length];
for(int i=0;i<cols.length;i++){
cols[i] = new java.awt.Color(InternalUtilities.parseColor(colors[i]), true);
}
final Category cat;
if(Double.isNaN(lower) || lower == upper){
cat = new Category(name, cols[0], lower);
}else{
final NumberRange range = NumberRange.create(lower, true, upper, false);
cat = new Category(name, cols, range, sampleToGeophysics);
}
categories.add(cat);
}
final GridSampleDimension dim = new GridSampleDimension(description, categories.toArray(new Category[categories.size()]), unit);
dimensions.add(indice, dim);
}
} catch (SQLException ex) {
throw new DataStoreException(ex.getMessage(), ex);
} finally {
pgstore.closeSafe(cnx, stmt, rs);
}
return dimensions;
}
private boolean isVersionColumnExist() {
Connection cnx = null;
Statement stmt = null;
ResultSet rs = null;
try {
cnx = pgstore.getDataSource().getConnection();
cnx.setReadOnly(false);
final StringBuilder query = new StringBuilder();
query.append( "SELECT count(column_name) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = ");
query.append("'"+pgstore.getDatabaseSchema()+"'");
query.append("AND table_name = 'Band' AND column_name = 'version'");
stmt = cnx.createStatement();
rs = stmt.executeQuery(query.toString());
return rs.next();
} catch(SQLException ex) {
return false;
} finally {
pgstore.closeSafe(cnx, stmt, rs);
}
}
@Override
public ViewType getPackMode() throws DataStoreException {
return ViewType.RENDERED;
}
@Override
public void setPackMode(ViewType packMode) throws DataStoreException {
}
@Override
public void setSampleDimensions(List<GridSampleDimension> dimensions) throws DataStoreException {
boolean versionSupport = isVersionColumnExist();
if (dimensions != null) {
double[] maxDimValues = new double[dimensions.size()];
double[] minDimValues = new double[dimensions.size()];
// if (analyse != null) {
// maxDimValues = (double[]) analyse.get("max");
// minDimValues = (double[]) analyse.get("min");
// } else {
Arrays.fill(maxDimValues, Double.MAX_VALUE);
Arrays.fill(minDimValues, Double.MIN_VALUE);
// }
Connection cnx = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try{
cnx = pgstore.getDataSource().getConnection();
cnx.setReadOnly(false);
final int layerId = pgstore.getLayerId(cnx,name.tip().toString());
for (int i = 0; i < dimensions.size(); i++) {
final GridSampleDimension dim = dimensions.get(i);
String versionStr;
if (version != null && !version.getLabel().equals(PGVersionControl.UNSET)) {
versionStr = TemporalUtilities.toISO8601Z(version.getDate(), TimeZone.getTimeZone("GMT+0"));
} else {
versionStr = PGVersionControl.UNSET;
}
final String description = dim.getDescription() != null ? dim.getDescription().toString() : "";
final String unit = dim.getUnits() != null ? dim.getUnits().toString() : "";
final StringBuilder query = new StringBuilder();
if (versionSupport) {
query.append("INSERT INTO ");
query.append(pgstore.encodeTableName("Band"));
query.append(" (\"layerId\",\"version\",\"indice\",\"description\",\"dataType\",\"unit\") ");
query.append("VALUES (?, ?, ?, ?, ?, ?)");
pstmt = cnx.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS);
pstmt.setInt(1, layerId);
pstmt.setString(2, versionStr);
pstmt.setInt(3, i);
pstmt.setString(4, description);
pstmt.setInt(5, (WKBRasterConstants.getPixelType(dim.getSampleDimensionType())));
pstmt.setString(6, unit);
} else {
query.append("INSERT INTO ");
query.append(pgstore.encodeTableName("Band"));
query.append(" (\"layerId\",\"indice\",\"description\",\"dataType\",\"unit\") ");
query.append("VALUES (?, ?, ?, ?, ?)");
pstmt = cnx.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS);
pstmt.setInt(1, layerId);
pstmt.setInt(2, i);
pstmt.setString(3, description);
pstmt.setInt(4, (WKBRasterConstants.getPixelType(dim.getSampleDimensionType())));
pstmt.setString(5, unit);
}
pstmt.executeUpdate();
int sid = 0;
final ResultSet keyrs = pstmt.getGeneratedKeys();
if (keyrs.next()) {
sid = keyrs.getInt(1);
}
//create the categories
List<Category> categories = dim.getCategories();
if (categories == null || categories.isEmpty()) {
//use the statistic analyze to build categories.
categories = new ArrayList<>();
final double[] pNoData = dim.getNoDataValues();
Double[] noData;
if (pNoData != null) {
noData = new Double[pNoData.length];
for (int j = 0; j < noData.length; j++) {
noData[j] = pNoData[j];
}
}
double min = Double.isInfinite(dim.getMinimumValue()) ? minDimValues[i] : dim.getMinimumValue();
double max = Double.isInfinite(dim.getMaximumValue()) ? maxDimValues[i] : dim.getMaximumValue();
categories.add(new Category("data", Color.BLACK, NumberRange.create(min, true, max, true)));
if (pNoData != null && pNoData.length > 0) {
for (int k = 0; k < pNoData.length; k++) {
categories.add(new Category(Vocabulary.formatInternational(Vocabulary.Keys.Nodata) + String.valueOf(k), new Color(0,0,0,0), pNoData[k]));
}
}
}
for (Category category : categories) {
final double c0;
final double c1;
final String function;
final String[] colors;
double min = category.getRange().getMinDouble();
double max = category.getRange().getMaxDouble();
min = fixCloseToZero(min);
max = fixCloseToZero(max);
final Color[] cols = category.getColors();
colors = new String[cols.length];
for(int k=0;k<cols.length;k++){
colors[k] = colorToString(cols[k]);
}
final MathTransform1D trs = category.getSampleToGeophysics();
if (trs == null) {
function = TransferFunctionType.LINEAR.name();
c0 = 0;
c1 = 1;
} else {
final TransferFunction transfertFunction = new TransferFunction();
transfertFunction.setTransform(trs);
function = transfertFunction.getType().name();
c0 = transfertFunction.getOffset();
c1 = transfertFunction.getScale();
}
final StringBuilder catQuery = new StringBuilder("INSERT INTO ");
catQuery.append(pgstore.encodeTableName("Category"));
catQuery.append(" (\"band\",\"name\",\"lower\",\"upper\",\"c0\",\"c1\",\"function\",\"colors\") ");
catQuery.append("VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
PreparedStatement catstmt = cnx.prepareStatement(catQuery.toString());
catstmt.setInt( 1, sid);
catstmt.setString(2, String.valueOf(category.getName()));
catstmt.setDouble(3, min);
catstmt.setDouble(4, max);
catstmt.setDouble(5, c0);
catstmt.setDouble(6, c1);
catstmt.setString(7, function);
catstmt.setString(8, StringUtilities.toCommaSeparatedValues((Object[]) colors));
catstmt.executeUpdate();
}
}
}catch(SQLException ex){
throw new DataStoreException(ex.getMessage(), ex);
}finally{
pgstore.closeSafe(cnx, pstmt, rs);
}
}
}
/**
* Postgres do not like this value.
* Caused by : ERROR: "4.9E-324" is out of range for type double precision
* org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2103)
*
* @param d
* @return
*/
private static double fixCloseToZero(double d){
if(d == 4.9E-324){
return 0.0;
}
return d;
}
/**
* Color to hexadecimal.
*
* @param color
* @return color in hexadecimal form
*/
private static String colorToString(final Color color) {
if (color == null) {
return null;
}
String redCode = Integer.toHexString(color.getRed());
String greenCode = Integer.toHexString(color.getGreen());
String blueCode = Integer.toHexString(color.getBlue());
if (redCode.length() == 1) redCode = "0" + redCode;
if (greenCode.length() == 1) greenCode = "0" + greenCode;
if (blueCode.length() == 1) blueCode = "0" + blueCode;
final String colorCode;
int alpha = color.getAlpha();
if(alpha != 255){
String alphaCode = Integer.toHexString(alpha);
if (alphaCode.length() == 1) alphaCode = "0" + alphaCode;
colorCode = "#" + alphaCode + redCode + greenCode + blueCode;
}else{
colorCode = "#" + redCode + greenCode + blueCode;
}
return colorCode.toUpperCase();
}
}