WSL/SLF GitLab Repository

Commit 8efa9e6a authored by Mathias Bavay's avatar Mathias Bavay
Browse files

Now, the plots are fitted/optimized depending on the meteo parameter (if...

Now, the plots are fitted/optimized depending on the meteo parameter (if available). The proper metadata is written into the file (again, if available). More gradients have been implemented.
parent ae40b649
......@@ -99,7 +99,7 @@ void legend::writeLine(const double& val, const unsigned int& px_row)
{
std::stringstream ss;
const unsigned int precision = text_chars_nb-6; //full width - (sgn, dot, "e", sgn, two digits exponent)
ss << setfill (' ') << setw(text_chars_nb) << left << setprecision(precision) << val << endl;
ss << setfill (' ') << setw(text_chars_nb) << left << setprecision(precision) << val << endl; //improve this format...
const unsigned int x_offset = legend_plot_space+sample_width+sample_text_space;
......@@ -240,6 +240,11 @@ void Color::HSVtoRGB(const double h, const double s, const double v, double &r,
/////////////////////////////////////////////////////////////////////////////////////////////////
Gradient::Gradient(const Type& type, const double& i_min, const double& i_max, const bool& i_autoscale)
{
set(type, i_min, i_max, i_autoscale);
}
void Gradient::set(const Type& type, const double& i_min, const double& i_max, const bool& i_autoscale)
{
delta_val = i_max - i_min;
......@@ -252,7 +257,7 @@ Gradient::Gradient(const Type& type, const double& i_min, const double& i_max, c
//val between min_val and max_val
//return values between 0 and 255 per channel
void Gradient::getColor(const double& val, unsigned char& r, unsigned char& g, unsigned char& b, unsigned char& a)
void Gradient::getColor(const double& val, unsigned char& r, unsigned char& g, unsigned char& b, unsigned char& a) const
{
if(val==IOUtils::nodata) {
r=0; g=0; b=0; a=0;
......@@ -285,7 +290,7 @@ void Gradient_model::setMinMax(const double& i_min, const double& i_max, const b
}
//we assume that the vectors are sorted by X
double Gradient_model::getInterpol(const double& val, const std::vector<double>& X, const std::vector<double>& Y)
double Gradient_model::getInterpol(const double& val, const std::vector<double>& X, const std::vector<double>& Y) const
{
if(X.size()!=Y.size()) {
std::stringstream ss;
......@@ -293,9 +298,12 @@ double Gradient_model::getInterpol(const double& val, const std::vector<double>&
ss << "There are " << X.size() << " abscissa for " << Y.size() << " ordinates.";
throw IOException(ss.str(), AT);
}
size_t i=0;
while(X[i]<val && i<X.size()) i++;
if(X.size()==0) {
throw IOException("Empty vector of control points for color gradient interpolation", AT);
}
size_t i=0;
while(i<X.size() && X[i]<val) i++;
if(X[i]==val) return Y[i];
if(i==0) return Y[0];
if(i==Y.size()) return Y[ Y.size()-1 ];
......@@ -304,7 +312,7 @@ double Gradient_model::getInterpol(const double& val, const std::vector<double>&
return y;
}
void Gradient_model::HSV2RGB(const double& h, const double& s, const double& v, unsigned char &r, unsigned char &g, unsigned char &b)
void Gradient_model::HSV2RGB(const double& h, const double& s, const double& v, unsigned char &r, unsigned char &g, unsigned char &b) const
{
double r_d, g_d, b_d;
Color::HSVtoRGB(h, s, v, r_d, g_d, b_d);
......@@ -313,7 +321,7 @@ void Gradient_model::HSV2RGB(const double& h, const double& s, const double& v,
b = static_cast<unsigned char>(b_d*255);
}
void Gradient_model::getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a)
void Gradient_model::getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a) const
{
double val;
if(autoscale)
......@@ -329,7 +337,7 @@ void Gradient_model::getColor(const double &i_val, unsigned char &r, unsigned ch
a = 255; //no alpha for valid values
}
void heat_gradient::getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a)
void heat_gradient::getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a) const
{
const double val = (i_val-min_val)/delta_val; //autoscale
......@@ -345,24 +353,27 @@ water_gradient::water_gradient(const double& i_min, const double& i_max, const b
setMinMax(i_min, i_max, i_autoscale);
//write gradient control points
if(autoscale) {
X.push_back(0.); v_h.push_back(0.); v_s.push_back(0.); v_v.push_back(.99); //
X.push_back(.1429); v_h.push_back(180.); v_s.push_back(.2); v_v.push_back(.99); //
X.push_back(.2857); v_h.push_back(193.); v_s.push_back(.32); v_v.push_back(.97); //
X.push_back(.429); v_h.push_back(205.); v_s.push_back(.43); v_v.push_back(.94); //
X.push_back(.5714); v_h.push_back(219.); v_s.push_back(.55); v_v.push_back(.91); //
X.push_back(.7143); v_h.push_back(231.); v_s.push_back(.66); v_v.push_back(.88); //
X.push_back(.857); v_h.push_back(244.); v_s.push_back(.78); v_v.push_back(.85); //
X.push_back(1.); v_h.push_back(270.); v_s.push_back(1.); v_v.push_back(.8); //
} else {
X.push_back(5.); v_h.push_back(0.); v_s.push_back(0.); v_v.push_back(.99); //
X.push_back(10.); v_h.push_back(180.); v_s.push_back(.2); v_v.push_back(.99); //
X.push_back(20.); v_h.push_back(193.); v_s.push_back(.32); v_v.push_back(.97); //
X.push_back(50.); v_h.push_back(205.); v_s.push_back(.43); v_v.push_back(.94); //
X.push_back(80.); v_h.push_back(219.); v_s.push_back(.55); v_v.push_back(.91); //
X.push_back(120.); v_h.push_back(231.); v_s.push_back(.66); v_v.push_back(.88); //
X.push_back(200.); v_h.push_back(244.); v_s.push_back(.78); v_v.push_back(.85); //
X.push_back(200.); v_h.push_back(270.); v_s.push_back(1.); v_v.push_back(.8); //
//if(autoscale) {
X.push_back(0.); v_h.push_back(0.); v_s.push_back(0.); v_v.push_back(.99);
X.push_back(.1429); v_h.push_back(180.); v_s.push_back(.2); v_v.push_back(.99);
X.push_back(.2857); v_h.push_back(193.); v_s.push_back(.32); v_v.push_back(.97);
X.push_back(.429); v_h.push_back(205.); v_s.push_back(.43); v_v.push_back(.94);
X.push_back(.5714); v_h.push_back(219.); v_s.push_back(.55); v_v.push_back(.91);
X.push_back(.7143); v_h.push_back(231.); v_s.push_back(.66); v_v.push_back(.88);
X.push_back(.857); v_h.push_back(244.); v_s.push_back(.78); v_v.push_back(.85);
X.push_back(1.); v_h.push_back(270.); v_s.push_back(1.); v_v.push_back(.8);
/*} else {
X.push_back(5.); v_h.push_back(0.); v_s.push_back(0.); v_v.push_back(.99);
X.push_back(10.); v_h.push_back(180.); v_s.push_back(.2); v_v.push_back(.99);
X.push_back(20.); v_h.push_back(193.); v_s.push_back(.32); v_v.push_back(.97);
X.push_back(50.); v_h.push_back(205.); v_s.push_back(.43); v_v.push_back(.94);
X.push_back(80.); v_h.push_back(219.); v_s.push_back(.55); v_v.push_back(.91);
X.push_back(120.); v_h.push_back(231.); v_s.push_back(.66); v_v.push_back(.88);
X.push_back(200.); v_h.push_back(244.); v_s.push_back(.78); v_v.push_back(.85);
X.push_back(200.); v_h.push_back(270.); v_s.push_back(1.); v_v.push_back(.8);
}*/
if(!autoscale) {
for(size_t i=0; i<X.size(); i++) X[i] *= i_max;
}
}
......
......@@ -87,11 +87,11 @@ class Gradient_model {
//setFgColor()
//val must be between 0 and 1 -> check + in doc? TODO
void getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a);
virtual void getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a) const;
protected:
double getInterpol(const double& val, const std::vector<double>& X, const std::vector<double>& Y);
double getInterpol(const double& val, const std::vector<double>& X, const std::vector<double>& Y) const;
void setMinMax(const double& i_min, const double& i_max, const bool& i_autoscale);
void HSV2RGB(const double& h, const double& s, const double& v, unsigned char &r, unsigned char &g, unsigned char &b);
void HSV2RGB(const double& h, const double& s, const double& v, unsigned char &r, unsigned char &g, unsigned char &b) const;
double max_val, min_val, delta_val;
bool autoscale;
......@@ -101,31 +101,27 @@ class Gradient_model {
class heat_gradient : public Gradient_model {
public:
heat_gradient(const double& i_min, const double& i_max, const bool& i_autoscale) {setMinMax(i_min, i_max, i_autoscale);};
void getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a);
void getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a) const;
};
class water_gradient : public Gradient_model {
public:
water_gradient(const double& i_min, const double& i_max, const bool& i_autoscale);
void getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a);
};
class terrain_gradient : public Gradient_model {
public:
terrain_gradient(const double& i_min, const double& i_max, const bool& i_autoscale);
void getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a);
};
class slope_gradient : public Gradient_model {
public:
slope_gradient(const double& i_min, const double& i_max, const bool& i_autoscale);
void getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a);
};
class azi_gradient : public Gradient_model {
public:
azi_gradient(const double& i_min, const double& i_max, const bool& i_autoscale);
void getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a);
};
class Gradient {
......@@ -139,14 +135,16 @@ class Gradient {
water
} Type;
Gradient() {model=NULL; delta_val=0.;}; //do not use this empty constructor!
Gradient() {model=NULL; delta_val=0.;};
Gradient(const Type& type, const double& min_val, const double &max_val, const bool& i_autoscale);
~Gradient() {delete model;};
void set(const Type& type, const double& min_val, const double &max_val, const bool& i_autoscale);
//setBgColor()
//setFgColor()
//val must be between 0 and 1 -> check + in doc? TODO
void getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a);
void getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a) const;
private:
double delta_val;
......
......@@ -47,6 +47,7 @@ bool MeteoGrids::initStaticData()
paramname.push_back("U");
paramname.push_back("V");
paramname.push_back("W");
paramname.push_back("SWE");
paramname.push_back("DEM");
paramname.push_back("SLOPE");
paramname.push_back("AZI");
......
......@@ -59,6 +59,7 @@ class MeteoGrids {
U, ///< East component of wind
V, ///< North component of wind
W, ///< Vertical component of wind
SWE, ///< Snow Water Equivalent
DEM, ///< Digital Elevation Model
SLOPE, ///< DEM slope angle
AZI, ///< DEM slope azimuth
......
......@@ -206,30 +206,22 @@ void PNGIO::readSpecialPoints(std::vector<Coords>&)
throw IOException("Nothing implemented here", AT);
}
void PNGIO::write2DGrid(const Grid2DObject& grid_in, const std::string& filename)
{
FILE *fp;
png_structp png_ptr=NULL;
png_infop info_ptr=NULL;
png_bytep row=NULL;
//scale input image
Grid2DObject PNGIO::scaleGrid(const Grid2DObject& grid_in)
{ //scale input image
const double factor = getScaleFactor(grid_in.ncols, grid_in.nrows);
Grid2DObject grid;
if(scaling=="nearest")
grid = ResamplingAlgorithms2D::NearestNeighbour(grid_in, factor);
return ResamplingAlgorithms2D::NearestNeighbour(grid_in, factor);
else if(scaling=="bilinear")
grid = ResamplingAlgorithms2D::BilinearResampling(grid_in, factor);
return ResamplingAlgorithms2D::BilinearResampling(grid_in, factor);
else {
stringstream ss;
ss << "Grid scaling algorithm \"" << scaling << "\" unknown";
throw UnknownValueException(ss.str(), AT);
}
}
const double ncols = grid.ncols, nrows = grid.nrows;
const double min = grid.grid2D.getMin();
const double max = grid.grid2D.getMax();
void PNGIO::setFile(const std::string& filename, FILE *fp, png_structp& png_ptr, png_infop& info_ptr, const unsigned int &width, const unsigned int &height)
{
// Open file for writing (binary mode)
if (!IOUtils::validFileName(filename)) {
throw InvalidFileNameException(filename, AT);
......@@ -256,43 +248,49 @@ void PNGIO::write2DGrid(const Grid2DObject& grid_in, const std::string& filename
// Setup Exception handling
if (setjmp(png_jmpbuf(png_ptr))) {
cleanup(fp, png_ptr, info_ptr, row);
cleanup(fp, png_ptr, info_ptr);
throw IOException("Error during png creation", AT);
}
png_init_io(png_ptr, fp);
unsigned int full_width=ncols;
Array2D<double> legend_array;
// Write header (8 bit colour depth)
png_set_IHDR(png_ptr, info_ptr, width, height,
8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
}
unsigned int PNGIO::setLegend(const unsigned int &ncols, const unsigned int &nrows, const double &min, const double &max, Array2D<double> &legend_array)
{
if(has_legend) {
legend leg(nrows, min, max);
legend_array = leg.getLegend();
unsigned int nx, ny;
legend_array.size(nx,ny);
full_width += nx;
return (ncols+nx);
} else {
return ncols;
}
// Write header (8 bit colour depth)
png_set_IHDR(png_ptr, info_ptr, full_width, nrows,
8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
createMetadata(grid);
writeMetadata(png_ptr, info_ptr);
png_write_info(png_ptr, info_ptr);
}
void PNGIO::writeDataSection(const Grid2DObject &grid, const Array2D<double> &legend_array, const Gradient &gradient, const unsigned int &full_width, png_structp &png_ptr)
{
const double ncols = grid.ncols, nrows = grid.nrows;
// Allocate memory for one row (4 bytes per pixel - RGBA)
png_bytep row=NULL;
row = (png_bytep) malloc(4 * full_width * sizeof(png_byte));
// Write image data
Gradient gradient(Gradient::terrain, min, max, autoscale);
for(int y=nrows-1 ; y>=0 ; y--) {
for(unsigned int x=0 ; x<ncols ; x++) {
//unsigned int x=0;
for(unsigned int x=0; x<ncols ; x++) {
const unsigned int i=x*4;
unsigned char r,g,b,a;
gradient.getColor(grid(x,y), r,g,b,a);
row[i]=r; row[i+1]=g; row[i+2]=b; row[i+3]=a;
}
for(unsigned int x=ncols; x<full_width; x++) {
//setRGB( legend_array(x-ncols,y), min, max, &(row[x*4]) );
const unsigned int i=x*4;
unsigned char r,g,b,a;
gradient.getColor(legend_array(x-ncols,y), r,g,b,a);
......@@ -301,20 +299,89 @@ void PNGIO::write2DGrid(const Grid2DObject& grid_in, const std::string& filename
png_write_row(png_ptr, row);
}
png_write_end(png_ptr, NULL);
cleanup(fp, png_ptr, info_ptr, row);
free(row);
}
void PNGIO::write2DGrid(const Grid2DObject& grid_in, const MeteoGrids::Parameters& parameter, const Date& date)
void PNGIO::write2DGrid(const Grid2DObject& grid_in, const std::string& filename)
{
std::stringstream ss;
ss << date.toString(Date::NUM) << "_" << MeteoGrids::getParameterName(parameter) << ".png";
write2DGrid(grid_in, ss.str());
FILE *fp=NULL;
png_structp png_ptr=NULL;
png_infop info_ptr=NULL;
//scale input image
const Grid2DObject grid = scaleGrid(grid_in);
const double ncols = grid.ncols, nrows = grid.nrows;
const double min = grid.grid2D.getMin();
const double max = grid.grid2D.getMax();
Gradient gradient(Gradient::heat, min, max, autoscale);
Array2D<double> legend_array; //it will remain empty if there is no legend
const unsigned int full_width = setLegend(ncols, nrows, min, max, legend_array);
setFile(filename, fp, png_ptr, info_ptr, full_width, nrows);
createMetadata(grid);
metadata_key.push_back("Title"); //adding generic title
metadata_text.push_back("Unknown Gridded data");
writeMetadata(png_ptr, info_ptr);
writeDataSection(grid, legend_array, gradient, full_width, png_ptr);
png_write_end(png_ptr, NULL);
cleanup(fp, png_ptr, info_ptr);
}
void PNGIO::cleanup() throw()
void PNGIO::write2DGrid(const Grid2DObject& grid_in, const MeteoGrids::Parameters& parameter, const Date& date)
{
const std::string filename = date.toString(Date::NUM) + "_" + MeteoGrids::getParameterName(parameter) + ".png";
FILE *fp=NULL;
png_structp png_ptr=NULL;
png_infop info_ptr=NULL;
//scale input image
Grid2DObject grid = scaleGrid(grid_in);
const double ncols = grid.ncols, nrows = grid.nrows;
double min = grid.grid2D.getMin();
double max = grid.grid2D.getMax();
Gradient gradient;
if(parameter==MeteoGrids::DEM) {
gradient.set(Gradient::terrain, min, max, autoscale);
} else if(parameter==MeteoGrids::SLOPE) {
gradient.set(Gradient::slope, min, max, autoscale);
} else if(parameter==MeteoGrids::AZI) {
gradient.set(Gradient::azi, min, max, autoscale);
} else if(parameter==MeteoGrids::HS) {
if(!autoscale) gradient.set(Gradient::water, 0., 3.5, autoscale);
else gradient.set(Gradient::water, min, max, autoscale);
} else if(parameter==MeteoGrids::TA) {
grid.grid2D -= Cst::t_water_freezing_pt; //convert to celsius
min -= Cst::t_water_freezing_pt;
max -= Cst::t_water_freezing_pt;
gradient.set(Gradient::heat, min, max, autoscale);
} else if(parameter==MeteoGrids::RH) {
if(!autoscale) gradient.set(Gradient::water, 0., 1., autoscale);
else gradient.set(Gradient::water, min, max, autoscale);
} else {
gradient.set(Gradient::heat, min, max, autoscale);
}
Array2D<double> legend_array; //it will remain empty if there is no legend
const unsigned int full_width = setLegend(ncols, nrows, min, max, legend_array); //set different scales for different params! TODO
setFile(filename, fp, png_ptr, info_ptr, full_width, nrows);
createMetadata(grid);
metadata_key.push_back("Title"); //adding title
metadata_text.push_back( MeteoGrids::getParameterName(parameter)+" on "+date.toString(Date::ISO) );
writeMetadata(png_ptr, info_ptr);
writeDataSection(grid, legend_array, gradient, full_width, png_ptr);
png_write_end(png_ptr, NULL);
cleanup(fp, png_ptr, info_ptr);
}
void PNGIO::createMetadata(const Grid2DObject& grid)
......@@ -323,8 +390,10 @@ void PNGIO::createMetadata(const Grid2DObject& grid)
const double lon = grid.llcorner.getLon();
stringstream ss;
metadata_key.push_back("Title");
metadata_text.push_back("Gridded data"); //HACK: write meteogrid parameter, date
metadata_key.push_back("Creation Time");
Date cr_date;
cr_date.setFromSys();
metadata_text.push_back( cr_date.toString(Date::ISO) );
metadata_key.push_back("Author");
metadata_text.push_back(IOUtils::getLogName());
metadata_key.push_back("Software");
......@@ -394,6 +463,8 @@ void PNGIO::writeMetadata(png_structp &png_ptr, png_infop &info_ptr)
}
free(key);
free(text);
png_write_info(png_ptr, info_ptr);
}
std::string PNGIO::decimal_to_dms(const double& decimal) {
......@@ -406,12 +477,11 @@ std::string PNGIO::decimal_to_dms(const double& decimal) {
return dms.str();
}
void PNGIO::cleanup(FILE *fp, png_structp png_ptr, png_infop info_ptr, png_bytep row)
void PNGIO::cleanup(FILE *fp, png_structp png_ptr, png_infop info_ptr)
{
if (fp != NULL) fclose(fp);
if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
if (row != NULL) free(row);
}
#ifndef _METEOIO_JNI
......
......@@ -20,6 +20,7 @@
#include <meteoio/IOInterface.h>
#include <meteoio/Config.h>
#include <meteoio/Graphics.h>
#include <string>
#include <png.h>
......@@ -67,8 +68,11 @@ class PNGIO : public IOInterface {
double getScaleFactor(const double& grid_w, const double& grid_h);
void createMetadata(const Grid2DObject& grid);
void writeMetadata(png_structp &png_ptr, png_infop &info_ptr);
void cleanup(FILE *fp, png_structp png_ptr, png_infop info_ptr, png_bytep row);
void cleanup() throw();
Grid2DObject scaleGrid(const Grid2DObject& grid_in);
void setFile(const std::string& filename, FILE *fp, png_structp& png_ptr, png_infop& info_ptr, const unsigned int &width, const unsigned int &height);
unsigned int setLegend(const unsigned int &ncols, const unsigned int &nrows, const double &min, const double &max, Array2D<double> &legend_array);
void writeDataSection(const Grid2DObject &grid, const Array2D<double> &legend_array, const Gradient &gradient, const unsigned int &full_width, png_structp &png_ptr);
void cleanup(FILE *fp, png_structp png_ptr, png_infop info_ptr);
std::string decimal_to_dms(const double& decimal);
Config cfg;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment