apply major refactor of RasterColorizer by ben moores from https://github.com/BenMoores/mapnik-trunk/wiki/RasterColorizer - closes #523
This commit is contained in:
parent
2c275729b1
commit
d05b0c539f
14 changed files with 821 additions and 383 deletions
|
@ -27,38 +27,40 @@
|
|||
|
||||
using mapnik::raster_colorizer;
|
||||
using mapnik::raster_colorizer_ptr;
|
||||
using mapnik::color_band;
|
||||
using mapnik::color_bands;
|
||||
using mapnik::colorizer_stop;
|
||||
using mapnik::colorizer_stops;
|
||||
using mapnik::colorizer_mode_enum;
|
||||
using mapnik::color;
|
||||
using mapnik::COLORIZER_INHERIT;
|
||||
using mapnik::COLORIZER_LINEAR;
|
||||
using mapnik::COLORIZER_DISCRETE;
|
||||
using mapnik::COLORIZER_EXACT;
|
||||
|
||||
|
||||
namespace {
|
||||
void append_band1(raster_colorizer_ptr & rc, color_band b)
|
||||
void add_stop(raster_colorizer_ptr & rc, colorizer_stop & stop)
|
||||
{
|
||||
rc->append_band(b);
|
||||
rc->add_stop(stop);
|
||||
}
|
||||
void append_band2(raster_colorizer_ptr & rc, color_band b, unsigned m)
|
||||
{
|
||||
rc->append_band(b, m);
|
||||
void add_stop2(raster_colorizer_ptr & rc, float v) {
|
||||
colorizer_stop stop(v, rc->get_default_mode(), rc->get_default_color());
|
||||
rc->add_stop(stop);
|
||||
}
|
||||
void append_band3(raster_colorizer_ptr & rc, float v, color c)
|
||||
{
|
||||
rc->append_band(v, c);
|
||||
void add_stop3(raster_colorizer_ptr &rc, float v, color c) {
|
||||
colorizer_stop stop(v, rc->get_default_mode(), c);
|
||||
rc->add_stop(stop);
|
||||
}
|
||||
void append_band4(raster_colorizer_ptr & rc, float v, color c, unsigned m)
|
||||
{
|
||||
rc->append_band(v, c, m);
|
||||
void add_stop4(raster_colorizer_ptr &rc, float v, colorizer_mode_enum m) {
|
||||
colorizer_stop stop(v, m, rc->get_default_color());
|
||||
rc->add_stop(stop);
|
||||
}
|
||||
void append_band5(raster_colorizer_ptr & rc, float v, float vm, color c, unsigned m)
|
||||
{
|
||||
rc->append_band(v, vm, c, m);
|
||||
void add_stop5(raster_colorizer_ptr &rc, float v, colorizer_mode_enum m, color c) {
|
||||
colorizer_stop stop(v, m, c);
|
||||
rc->add_stop(stop);
|
||||
}
|
||||
void append_band6(raster_colorizer_ptr & rc, float v, float vm, color c)
|
||||
colorizer_stops const& get_stops(raster_colorizer_ptr & rc)
|
||||
{
|
||||
rc->append_band(v, vm, c);
|
||||
}
|
||||
color_bands const& get_color_bands(raster_colorizer_ptr & rc)
|
||||
{
|
||||
return rc->get_color_bands();
|
||||
return rc->get_stops();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,121 +68,135 @@ void export_raster_colorizer()
|
|||
{
|
||||
using namespace boost::python;
|
||||
|
||||
class_<raster_colorizer,raster_colorizer_ptr>("RasterColorizer", init<>("Default ctor."))
|
||||
class_<raster_colorizer,raster_colorizer_ptr>("RasterColorizer",
|
||||
"A Raster Colorizer object.",
|
||||
init<colorizer_mode_enum, color>(args("default_mode","default_color"))
|
||||
)
|
||||
.def(init<>())
|
||||
.add_property("default_color",
|
||||
make_function(&raster_colorizer::get_default_color, return_value_policy<reference_existing_object>()),
|
||||
&raster_colorizer::set_default_color,
|
||||
"The default color for stops added without a color (mapnik.Color).\n")
|
||||
.add_property("default_mode",
|
||||
&raster_colorizer::get_default_mode_enum,
|
||||
&raster_colorizer::set_default_mode_enum,
|
||||
"The default mode (mapnik.ColorizerMode).\n"
|
||||
"\n"
|
||||
"If a stop is added without a mode, then it will inherit this default mode\n")
|
||||
.add_property("stops",
|
||||
make_function(get_stops,return_value_policy<reference_existing_object>()),
|
||||
"The list of stops this RasterColorizer contains\n")
|
||||
.add_property("epsilon",
|
||||
&raster_colorizer::get_epsilon,
|
||||
&raster_colorizer::set_epsilon,
|
||||
"Comparison epsilon value for exact mode\n"
|
||||
"\n"
|
||||
"When comparing values in exact mode, values need only be within epsilon to match.\n")
|
||||
|
||||
.add_property("bands",make_function
|
||||
(get_color_bands,
|
||||
return_value_policy<reference_existing_object>()))
|
||||
.def("append_band", append_band1,
|
||||
(arg("color_band")),
|
||||
"Append a color band to the raster colorizer.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> colorizer = mapnik.ColorBand()\n"
|
||||
">>> color = mapnik.Color(\"#0044cc\")\n"
|
||||
">>> color_band = mapnik.ColorBand(3, color)\n"
|
||||
">>> colorizer.append_band(color_band)\n"
|
||||
)
|
||||
.def("append_band", append_band2,
|
||||
(arg("color_band"), arg("midpoints")),
|
||||
"Append a color band to the raster colorizer with midpoints "
|
||||
"lineally interpolated color bands between this one and the "
|
||||
"previous one.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> colorizer = mapnik.ColorBand()\n"
|
||||
">>> color = mapnik.Color(\"#0044cc\")\n"
|
||||
">>> color_band = mapnik.ColorBand(3, color)\n"
|
||||
">>> colorizer.append_band(color_band, 1)\n"
|
||||
)
|
||||
.def("append_band", append_band3,
|
||||
(arg("value"), arg("color")),
|
||||
"Create and append a color band to color the range "
|
||||
"[value, next_val) where next_val is the next band's color or "
|
||||
"inifinity if there is no next band.\n"
|
||||
"Usage:\n"
|
||||
">>> colorizer = mapnik.RasterColorizer()\n"
|
||||
">>> color = mapnik.Color(\"#0044cc\")\n"
|
||||
">>> colorizer.append_band(30, color)\n"
|
||||
)
|
||||
.def("append_band", append_band4,
|
||||
(arg("value"), arg("color"), arg("midpoints")),
|
||||
"Create and append a color band to the raster colorizer with "
|
||||
"midpoints lineally interpolated color bands between this one and "
|
||||
"the previous one.\n"
|
||||
"color will be applied to all values in the "
|
||||
"range [value, next_val) where next_val is the next band's color "
|
||||
"or infinity if there is no next band\n"
|
||||
|
||||
.def("add_stop", add_stop,
|
||||
(arg("ColorizerStop")),
|
||||
"Add a colorizer stop to the raster colorizer.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> colorizer = mapnik.RasterColorizer()\n"
|
||||
">>> color = mapnik.Color(\"#0044cc\")\n"
|
||||
">>> colorizer.append_band(30, color, 4)\n"
|
||||
">>> stop = mapnik.ColorizerStop(3, mapnik.COLORIZER_INHERIT, color)\n"
|
||||
">>> colorizer.add_stop(stop)\n"
|
||||
)
|
||||
.def("append_band", append_band5,
|
||||
(arg("value"), arg("value_max"), arg("color"), arg("midpoints")),
|
||||
"Create and append a color band to the raster colorizer with "
|
||||
"midpoints lineally interpolated color bands between this one and "
|
||||
"the previous one.\n"
|
||||
"color will be applied to all values in the "
|
||||
"range [value, next_val) where next_val is the next band's color "
|
||||
"or value_max if there is no next band\n"
|
||||
"\n"
|
||||
.def("add_stop", add_stop2,
|
||||
(arg("value")),
|
||||
"Add a colorizer stop to the raster colorizer, using the default mode and color.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> colorizer = mapnik.RasterColorizer()\n"
|
||||
">>> color = mapnik.Color(\"#0044cc\")\n"
|
||||
">>> colorizer.append_band(30, 40, color, 4)\n"
|
||||
">>> default_color = mapnik.Color(\"#0044cc\")\n"
|
||||
">>> colorizer = mapnik.RasterColorizer(mapnik2.COLORIZER_LINEAR, default_color)\n"
|
||||
">>> colorizer.add_stop(100)\n"
|
||||
)
|
||||
.def("append_band", append_band6,
|
||||
(arg("value"), arg("value_max"), arg("color")),
|
||||
"Create and append a color band to color the range "
|
||||
"[value, next_val) where next_val is the next band's color or "
|
||||
"value_max if there is no next band.\n"
|
||||
.def("add_stop", add_stop3,
|
||||
(arg("value")),
|
||||
"Add a colorizer stop to the raster colorizer, using the default mode.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> colorizer = mapnik.RasterColorizer()\n"
|
||||
">>> color = mapnik.Color(\"#0044cc\")\n"
|
||||
">>> colorizer.append_band(30, 40, color)\n"
|
||||
">>> default_color = mapnik.Color(\"#0044cc\")\n"
|
||||
">>> colorizer = mapnik.RasterColorizer(mapnik2.COLORIZER_LINEAR, default_color)\n"
|
||||
">>> colorizer.add_stop(100, mapnik.Color(\"#123456\"))\n"
|
||||
)
|
||||
.def("add_stop", add_stop4,
|
||||
(arg("value")),
|
||||
"Add a colorizer stop to the raster colorizer, using the default color.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> default_color = mapnik.Color(\"#0044cc\")\n"
|
||||
">>> colorizer = mapnik.RasterColorizer(mapnik2.COLORIZER_LINEAR, default_color)\n"
|
||||
">>> colorizer.add_stop(100, mapnik2.COLORIZER_EXACT)\n"
|
||||
)
|
||||
.def("add_stop", add_stop5,
|
||||
(arg("value")),
|
||||
"Add a colorizer stop to the raster colorizer.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> default_color = mapnik.Color(\"#0044cc\")\n"
|
||||
">>> colorizer = mapnik.RasterColorizer(mapnik2.COLORIZER_LINEAR, default_color)\n"
|
||||
">>> colorizer.add_stop(100, mapnik.COLORIZER_DISCRETE, mapnik.Color(\"#112233\"))\n"
|
||||
)
|
||||
.def("get_color", &raster_colorizer::get_color,
|
||||
"Get the color assigned to a certain value in raster data.\n"
|
||||
"By default, returns Color(\"transparent\")\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> colorizer = mapnik.RasterColorizer()\n"
|
||||
">>> color = mapnik.Color(\"#0044cc\")\n"
|
||||
">>> colorizer.append_band(30, 40, color)\n"
|
||||
">>> colorizer.get_color(35)\n"
|
||||
"Color('#0044cc')\n"
|
||||
">>> colorizer.add_stop(0, mapnik2.COLORIZER_DISCRETE, mapnik.Color(\"#000000\"))\n"
|
||||
">>> colorizer.add_stop(100, mapnik2.COLORIZER_DISCRETE, mapnik.Color(\"#0E0A06\"))\n"
|
||||
">>> colorizer.get_color(50)\n"
|
||||
"Color('#070503')\n"
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
class_<color_bands>("ColorBands",
|
||||
"A RasterColorizer's collection of ordered color bands.\n"
|
||||
class_<colorizer_stops>("ColorizerStops",
|
||||
"A RasterColorizer's collection of ordered color stops.\n"
|
||||
"This class is not meant to be instantiated from python. However, "
|
||||
"it can be accessed at a RasterColorizer's \"bands\" attribute for "
|
||||
"it can be accessed at a RasterColorizer's \"stops\" attribute for "
|
||||
"introspection purposes",
|
||||
no_init)
|
||||
.def(vector_indexing_suite<color_bands>())
|
||||
.def(vector_indexing_suite<colorizer_stops>())
|
||||
;
|
||||
|
||||
enum_<colorizer_mode_enum>("ColorizerMode")
|
||||
.value("COLORIZER_INHERIT", COLORIZER_INHERIT)
|
||||
.value("COLORIZER_LINEAR", COLORIZER_LINEAR)
|
||||
.value("COLORIZER_DISCRETE", COLORIZER_DISCRETE)
|
||||
.value("COLORIZER_EXACT", COLORIZER_EXACT)
|
||||
.export_values()
|
||||
;
|
||||
|
||||
|
||||
class_<color_band>("ColorBand",init<float,color const&>(
|
||||
"A Color Band object.\n"
|
||||
"Create with a value and color\n"
|
||||
class_<colorizer_stop>("ColorizerStop",init<float, colorizer_mode_enum, color const&>(
|
||||
"A Colorizer Stop object.\n"
|
||||
"Create with a value, ColorizerMode, and Color\n"
|
||||
"\n"
|
||||
"Usage:"
|
||||
">>> color = mapnik.Color(\"#fff000\")\n"
|
||||
">>> color_band = mapnik.ColorBand(4, color)\n"
|
||||
">>> stop= mapnik.ColorizerStop(42.42, mapnik.COLORIZER_LINEAR, color)\n"
|
||||
))
|
||||
.add_property("color", make_function
|
||||
(&color_band::get_color,
|
||||
return_value_policy<reference_existing_object>()))
|
||||
.add_property("value", &color_band::get_value)
|
||||
.add_property("max_value", &color_band::get_max_value)
|
||||
.add_property("color",
|
||||
make_function(&colorizer_stop::get_color, return_value_policy<reference_existing_object>()),
|
||||
&colorizer_stop::set_color,
|
||||
"The stop color (mapnik.Color).\n")
|
||||
.add_property("value",
|
||||
&colorizer_stop::get_value,
|
||||
&colorizer_stop::set_value,
|
||||
"The stop value.\n")
|
||||
.add_property("mode",
|
||||
&colorizer_stop::get_mode_enum,
|
||||
&colorizer_stop::set_mode_enum,
|
||||
"The stop mode (mapnik.ColorizerMode).\n"
|
||||
"\n"
|
||||
"If this is COLORIZER_INHERIT then it will inherit the default mode\n"
|
||||
" from the RasterColorizer it is added to.\n")
|
||||
.def(self == self)
|
||||
.def("__str__",&color_band::to_string)
|
||||
.def("__str__",&colorizer_stop::to_string)
|
||||
;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,20 @@
|
|||
*****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
/** \brief Raster Colouriser
|
||||
*
|
||||
* This class allows GDAL raster bands to be colourised. It only works with single
|
||||
* band GDAL rasters, not greyscale, alpha, or rgb (due to the GDAL featureset loading
|
||||
* single channel GDAL rasters as FLOAT32, and the others as BYTE, and not having a method
|
||||
* of figuring out which).
|
||||
*
|
||||
* Every input value is translated to an output value. The output value is determined by
|
||||
* what 'stop' the input value is in. Each stop covers the range of input values from its
|
||||
* 'value' parameter, up to the 'value' parameter of the next stop.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RASTER_COLORIZER_HPP
|
||||
#define RASTER_COLORIZER_HPP
|
||||
|
||||
|
@ -29,193 +43,171 @@
|
|||
#include <mapnik/config_error.hpp>
|
||||
#include <mapnik/color.hpp>
|
||||
#include <mapnik/feature.hpp>
|
||||
#include <mapnik/enumeration.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
struct MAPNIK_DECL color_band
|
||||
|
||||
//! \brief Enumerates the modes of interpolation
|
||||
enum colorizer_mode_enum
|
||||
{
|
||||
float value_;
|
||||
float max_value_;
|
||||
color color_;
|
||||
unsigned midpoints_;
|
||||
bool is_interpolated_;
|
||||
color_band(float value, color c)
|
||||
: value_(value),
|
||||
max_value_(value),
|
||||
color_(c),
|
||||
midpoints_(0),
|
||||
is_interpolated_(false) {}
|
||||
color_band(float value, float max_value, color c)
|
||||
: value_(value),
|
||||
max_value_(max_value),
|
||||
color_(c),
|
||||
midpoints_(0),
|
||||
is_interpolated_(false) {}
|
||||
bool is_interpolated() const
|
||||
{
|
||||
return is_interpolated_;
|
||||
}
|
||||
unsigned get_midpoints() const
|
||||
{
|
||||
return midpoints_;
|
||||
}
|
||||
float get_value() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
float get_max_value() const
|
||||
{
|
||||
return max_value_;
|
||||
}
|
||||
const color& get_color() const
|
||||
{
|
||||
return color_;
|
||||
}
|
||||
bool operator==(color_band const& other) const
|
||||
{
|
||||
return value_ == other.value_ && color_ == other.color_ && max_value_ == other.max_value_;
|
||||
}
|
||||
std::string to_string() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << color_.to_string() << " " << value_ << " " << max_value_;
|
||||
return ss.str();
|
||||
}
|
||||
COLORIZER_INHERIT = 0, //!< The stop inherits the mode from the colorizer
|
||||
COLORIZER_LINEAR = 1, //!< Linear interpolation between colors
|
||||
COLORIZER_DISCRETE = 2, //!< Single color for stop
|
||||
COLORIZER_EXACT = 3, //!< Only the exact value specified for the stop gets translated, others use the default
|
||||
colorizer_mode_enum_MAX
|
||||
};
|
||||
|
||||
typedef std::vector<color_band> color_bands;
|
||||
DEFINE_ENUM( colorizer_mode, colorizer_mode_enum );
|
||||
|
||||
struct MAPNIK_DECL raster_colorizer
|
||||
{
|
||||
explicit raster_colorizer()
|
||||
: colors_() {}
|
||||
//! \brief Structure to represent a stop position.
|
||||
class colorizer_stop {
|
||||
public:
|
||||
|
||||
raster_colorizer(const raster_colorizer &ps)
|
||||
: colors_(ps.colors_) {}
|
||||
//! \brief Constructor
|
||||
//!
|
||||
//! \param[in] value The stop value
|
||||
//! \param[in] mode The stop mode
|
||||
//! \param[in] color The stop color
|
||||
colorizer_stop(const float value = 0, const colorizer_mode mode = COLORIZER_INHERIT, const color& _color = color(0,0,0,0) );
|
||||
|
||||
raster_colorizer(color_bands &colors)
|
||||
: colors_(colors) {}
|
||||
//! \brief Copy constructor
|
||||
colorizer_stop(const colorizer_stop& stop);
|
||||
|
||||
const color_bands& get_color_bands() const
|
||||
{
|
||||
return colors_;
|
||||
}
|
||||
void append_band (color_band band)
|
||||
{
|
||||
if (colors_.size() > 0 && colors_.back().value_ > band.value_) {
|
||||
#ifdef MAPNIK_DEBUG
|
||||
std::clog << "prev.v=" << colors_.back().value_ << ". band.v=" << band.value_ << "\n";
|
||||
#endif
|
||||
throw config_error(
|
||||
"Bands must be appended in ascending value order"
|
||||
);
|
||||
}
|
||||
colors_.push_back(band);
|
||||
if (colors_.size() > 0 && colors_.back().value_ == colors_.back().max_value_)
|
||||
colors_.back().max_value_ = band.value_;
|
||||
}
|
||||
void append_band (color_band band, unsigned midpoints)
|
||||
{
|
||||
band.midpoints_ = midpoints;
|
||||
if (colors_.size() > 0 && midpoints > 0) {
|
||||
color_band lo = colors_.back();
|
||||
color_band const &hi = band;
|
||||
int steps = midpoints+1;
|
||||
float dv = (hi.value_ - lo.value_)/steps;
|
||||
float da = (float(hi.color_.alpha()) - lo.color_.alpha())/steps;
|
||||
float dr = (float(hi.color_.red()) - lo.color_.red())/steps;
|
||||
float dg = (float(hi.color_.green()) - lo.color_.green())/steps;
|
||||
float db = (float(hi.color_.blue()) - lo.color_.blue())/steps;
|
||||
|
||||
#ifdef MAPNIK_DEBUG
|
||||
std::clog << "lo.v=" << lo.value_ << ", hi.v=" << hi.value_ << ", dv="<<dv<<"\n";
|
||||
#endif
|
||||
// interpolate intermediate values and colors
|
||||
int j;
|
||||
for (j=1; j<steps; j++) {
|
||||
color_band b(
|
||||
lo.get_value() + dv*j,
|
||||
color(int(float(lo.color_.red()) + dr*j),
|
||||
int(float(lo.color_.green()) + dg*j),
|
||||
int(float(lo.color_.blue()) + db*j),
|
||||
int(float(lo.color_.alpha()) + da*j)
|
||||
)
|
||||
);
|
||||
b.is_interpolated_ = true;
|
||||
append_band(b);
|
||||
}
|
||||
}
|
||||
append_band(band);
|
||||
}
|
||||
|
||||
void append_band (float value, color c)
|
||||
{
|
||||
append_band(color_band(value, c));
|
||||
}
|
||||
|
||||
void append_band (float value, float max_value, color c)
|
||||
{
|
||||
append_band(color_band(value, max_value, c));
|
||||
}
|
||||
|
||||
void append_band (float value, color c, unsigned midpoints)
|
||||
{
|
||||
append_band(color_band(value, c), midpoints);
|
||||
}
|
||||
|
||||
void append_band (float value, float max_value, color c, unsigned midpoints)
|
||||
{
|
||||
append_band(color_band(value, max_value, c), midpoints);
|
||||
}
|
||||
//! \brief Destructor
|
||||
~colorizer_stop();
|
||||
|
||||
|
||||
/* rgba =
|
||||
* if cs[pos].value <= value < cs[pos+1].value: cs[pos].color
|
||||
* otherwise: transparent
|
||||
* where 0 <= pos < length(bands)-1
|
||||
* Last band is special, its value represents the upper bound and its
|
||||
* color will only be used if the value matches its value exactly.
|
||||
*/
|
||||
color get_color(float value) const {
|
||||
int pos=-1, last=(int)colors_.size()-1, lo=0, hi=last;
|
||||
while (lo<=hi) {
|
||||
pos = (lo+hi)/2;
|
||||
if (colors_[pos].value_<value) {
|
||||
lo = pos+1;
|
||||
} else if (colors_[pos].value_>value) {
|
||||
hi = pos-1;
|
||||
} else {
|
||||
lo = pos+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lo--;
|
||||
if ((0 <= lo && lo < last) ||
|
||||
(lo==last && (colors_[last].value_==value || value<colors_[last].max_value_)))
|
||||
return colors_[lo].color_;
|
||||
else
|
||||
return color(0,0,0,0);
|
||||
}
|
||||
//! \brief Set the stop value
|
||||
//! \param[in] value The stop value
|
||||
inline void set_value(const float value) { value_ = value; };
|
||||
|
||||
void colorize(raster_ptr const& raster) const
|
||||
{
|
||||
float *rasterData = reinterpret_cast<float*>(raster->data_.getBytes());
|
||||
unsigned *imageData = raster->data_.getData();
|
||||
unsigned i;
|
||||
for (i=0; i<raster->data_.width()*raster->data_.height(); i++)
|
||||
{
|
||||
imageData[i] = get_color(rasterData[i]).rgba();
|
||||
}
|
||||
}
|
||||
//! \brief Get the stop value
|
||||
//! \return The stop value
|
||||
inline float get_value(void) const {return value_; };
|
||||
|
||||
|
||||
//! \brief Set the stop mode
|
||||
//! \param[in] mode The stop mode
|
||||
inline void set_mode(const colorizer_mode mode) { mode_ = mode; };
|
||||
inline void set_mode_enum(const colorizer_mode_enum mode) { set_mode(mode); };
|
||||
|
||||
//! \brief Get the stop mode
|
||||
//! \return The stop mode
|
||||
inline colorizer_mode get_mode(void) const { return mode_; };
|
||||
inline colorizer_mode_enum get_mode_enum(void) const { return get_mode(); };
|
||||
|
||||
|
||||
//! \brief set the stop color
|
||||
//! \param[in] the stop color
|
||||
inline void set_color(const color& _color) { color_ = _color; };
|
||||
|
||||
//! \brief get the stop color
|
||||
//! \return The stop color
|
||||
inline const color& get_color(void) const {return color_; };
|
||||
|
||||
|
||||
//! \brief Equality operator
|
||||
//! \return True if equal, false otherwise
|
||||
bool operator==(colorizer_stop const& other) const;
|
||||
|
||||
//! \brief Print the stop to a string
|
||||
//! \return A string representing this stop.
|
||||
std::string to_string() const;
|
||||
|
||||
private:
|
||||
color_bands colors_;
|
||||
float value_; //!< The stop value
|
||||
colorizer_mode mode_; //!< The stop mode
|
||||
color color_; //!< The stop color
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<colorizer_stop> colorizer_stops;
|
||||
|
||||
|
||||
//! \brief Class representing the raster colorizer
|
||||
class raster_colorizer {
|
||||
public:
|
||||
//! \brief Constructor
|
||||
raster_colorizer(colorizer_mode mode = COLORIZER_LINEAR, const color& _color = color(0,0,0,0));
|
||||
|
||||
//! \brief Destructor
|
||||
~raster_colorizer();
|
||||
|
||||
|
||||
//! \brief Set the default mode
|
||||
//!
|
||||
//! This can not be set as INHERIT, if you do, LINEAR will be used instead.
|
||||
//! \param[in] mode The default mode
|
||||
void set_default_mode(const colorizer_mode mode) { default_mode_ = (mode == COLORIZER_INHERIT) ? COLORIZER_LINEAR:(colorizer_mode_enum)mode; };
|
||||
void set_default_mode_enum(const colorizer_mode_enum mode) { set_default_mode(mode); };
|
||||
|
||||
//! \brief Get the default mode
|
||||
//! \return The default mode
|
||||
colorizer_mode get_default_mode(void) const {return default_mode_; };
|
||||
colorizer_mode_enum get_default_mode_enum(void) const {return get_default_mode(); };
|
||||
|
||||
//! \brief Set the default color
|
||||
//! \param[in] color The default color
|
||||
void set_default_color(const color& color) { default_color_ = color; };
|
||||
|
||||
//! \brief Get the default color
|
||||
//! \return The default color
|
||||
const color& get_default_color(void) const {return default_color_; };
|
||||
|
||||
|
||||
//! \brief Add a stop
|
||||
//!
|
||||
//! \param[in] stop The stop to add
|
||||
//! \return True if added, false if error
|
||||
bool add_stop(const colorizer_stop & stop);
|
||||
|
||||
//! \brief Get the list of stops
|
||||
//! \return The list of stops
|
||||
const colorizer_stops& get_stops(void) const {return stops_; };
|
||||
|
||||
|
||||
//! \brief Colorize a raster
|
||||
//!
|
||||
//! \param[in, out] raster A raster stored in float32 single channel format, which gets colorized in place.
|
||||
//! \param[in] properties belonging to the feature, used to find 'NODATA' information if available
|
||||
void colorize(raster_ptr const& raster,const std::map<std::string,value> &Props) const;
|
||||
|
||||
|
||||
//! \brief Perform the translation of input to output
|
||||
//!
|
||||
//! \param[in] value Input value
|
||||
//! \return color associated with the value
|
||||
color get_color(float value) const;
|
||||
|
||||
|
||||
//! \brief Set the epsilon value for exact mode
|
||||
//! \param[in] e The epsilon value
|
||||
inline void set_epsilon(const float e) { if(e > 0) epsilon_ = e; };
|
||||
|
||||
//! \brief Get the epsilon value for exact mode
|
||||
//! \return The epsilon value
|
||||
inline float get_epsilon(void) const { return epsilon_; };
|
||||
|
||||
private:
|
||||
colorizer_stops stops_; //!< The vector of stops
|
||||
|
||||
colorizer_mode default_mode_; //!< The default mode inherited by stops
|
||||
color default_color_; //!< The default color
|
||||
float epsilon_; //!< The epsilon value for exact mode
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef boost::shared_ptr<raster_colorizer> raster_colorizer_ptr;
|
||||
|
||||
|
||||
} // mapnik namespace
|
||||
|
||||
#endif //RASTER_COLORIZER_HPP
|
||||
|
|
|
@ -194,13 +194,18 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
|
|||
{
|
||||
if (band_ > nbands_)
|
||||
throw datasource_exception((boost::format("GDAL Plugin: '%d' is an invalid band, dataset only has '%d' bands\n") % band_ % nbands_).str());
|
||||
|
||||
float *imageData = (float*)image.getBytes();
|
||||
GDALRasterBand * band = dataset_.GetRasterBand(band_);
|
||||
int hasNoData;
|
||||
double nodata = band->GetNoDataValue(&hasNoData);
|
||||
band->RasterIO(GF_Read, x_off, y_off, width, height,
|
||||
imageData, image.width(), image.height(),
|
||||
GDT_Float32, 0, 0);
|
||||
|
||||
feature->set_raster(mapnik::raster_ptr(new mapnik::raster(intersect,image)));
|
||||
if (hasNoData)
|
||||
feature->props()["NODATA"]=nodata;
|
||||
}
|
||||
|
||||
else // working with all bands
|
||||
|
|
|
@ -139,6 +139,7 @@ source = Split(
|
|||
glyph_symbolizer.cpp
|
||||
markers_symbolizer.cpp
|
||||
metawriter.cpp
|
||||
raster_colorizer.cpp
|
||||
text_placements.cpp
|
||||
wkt/wkt_factory.cpp
|
||||
metawriter_inmem.cpp
|
||||
|
|
|
@ -43,7 +43,7 @@ void agg_renderer<T>::process(raster_symbolizer const& sym,
|
|||
// If there's a colorizer defined, use it to color the raster in-place
|
||||
raster_colorizer_ptr colorizer = sym.get_colorizer();
|
||||
if (colorizer)
|
||||
colorizer->colorize(raster);
|
||||
colorizer->colorize(raster,feature.props());
|
||||
|
||||
box2d<double> ext=t_.forward(raster->ext_);
|
||||
|
||||
|
|
|
@ -1384,7 +1384,7 @@ void cairo_renderer_base::process(raster_symbolizer const& sym,
|
|||
// If there's a colorizer defined, use it to color the raster in-place
|
||||
raster_colorizer_ptr colorizer = sym.get_colorizer();
|
||||
if (colorizer)
|
||||
colorizer->colorize(raster);
|
||||
colorizer->colorize(raster,feature.props());
|
||||
|
||||
box2d<double> ext = t_.forward(raster->ext_);
|
||||
int start_x = (int)ext.minx();
|
||||
|
|
|
@ -1979,37 +1979,82 @@ void map_parser::parse_raster_colorizer(raster_colorizer_ptr const& rc,
|
|||
{
|
||||
try
|
||||
{
|
||||
ptree::const_iterator cbIter = node.begin();
|
||||
ptree::const_iterator endCb = node.end();
|
||||
// mode
|
||||
colorizer_mode default_mode =
|
||||
get_attr<colorizer_mode>(node, "default-mode", COLORIZER_LINEAR);
|
||||
|
||||
for(; cbIter != endCb; ++cbIter)
|
||||
{
|
||||
ptree::value_type const& cb_tag = *cbIter;
|
||||
ptree const & cb = cbIter->second;
|
||||
if(default_mode == COLORIZER_INHERIT) {
|
||||
throw config_error("RasterColorizer mode must not be INHERIT. ");
|
||||
}
|
||||
rc->set_default_mode( default_mode );
|
||||
|
||||
if (cb_tag.first == "ColorBand")
|
||||
// default colour
|
||||
optional<color> default_color = get_opt_attr<color>(node, "default-color");
|
||||
if (default_color)
|
||||
{
|
||||
ensure_attrs(cb, "ColorBand", "value,color,midpoints,max-value,label");
|
||||
std::string value_s = get_attr<string>(cb, "value");
|
||||
float value;
|
||||
std::stringstream(value_s) >> value;
|
||||
optional<color> c = get_opt_attr<color>(cb, "color");
|
||||
if (!c) {
|
||||
throw config_error("missing color");
|
||||
rc->set_default_color( *default_color );
|
||||
}
|
||||
unsigned midpoints = get_attr(cb, "midpoints", 0);
|
||||
optional<float> max_value = get_opt_attr<float>(cb, "max-value");
|
||||
if (max_value) {
|
||||
rc->append_band(value, *max_value, *c, midpoints);
|
||||
} else {
|
||||
rc->append_band(value, *c, midpoints);
|
||||
|
||||
|
||||
// epsilon
|
||||
optional<float> eps = get_opt_attr<float>(node, "epsilon");
|
||||
if (eps)
|
||||
{
|
||||
if(*eps < 0) {
|
||||
throw config_error("RasterColorizer epsilon must be > 0. ");
|
||||
}
|
||||
rc->set_epsilon( *eps );
|
||||
}
|
||||
else if (cb_tag.first != "<xmlcomment>" &&
|
||||
cb_tag.first != "<xmlattr>" )
|
||||
|
||||
|
||||
ptree::const_iterator stopIter = node.begin();
|
||||
ptree::const_iterator endStop = node.end();
|
||||
float maximumValue = -std::numeric_limits<float>::max();
|
||||
|
||||
for(; stopIter != endStop; ++stopIter)
|
||||
{
|
||||
ptree::value_type const& stop_tag = *stopIter;
|
||||
ptree const & stop = stopIter->second;
|
||||
|
||||
if (stop_tag.first == "stop")
|
||||
{
|
||||
// colour is optional.
|
||||
optional<color> stopcolor = get_opt_attr<color>(stop, "color");
|
||||
if (!stopcolor) {
|
||||
*stopcolor = *default_color;
|
||||
}
|
||||
|
||||
// mode default to INHERIT
|
||||
colorizer_mode mode =
|
||||
get_attr<colorizer_mode>(stop, "mode", COLORIZER_INHERIT);
|
||||
|
||||
// value is required, and it must be bigger than the previous
|
||||
optional<float> value =
|
||||
get_opt_attr<float>(stop, "value");
|
||||
|
||||
if(!value) {
|
||||
throw config_error("stop tag missing value");
|
||||
}
|
||||
|
||||
if(value < maximumValue) {
|
||||
throw config_error("stop tag values must be in ascending order");
|
||||
}
|
||||
maximumValue = *value;
|
||||
|
||||
|
||||
//append the stop
|
||||
colorizer_stop tmpStop;
|
||||
tmpStop.set_color(*stopcolor);
|
||||
tmpStop.set_mode(mode);
|
||||
tmpStop.set_value(*value);
|
||||
|
||||
rc->add_stop(tmpStop);
|
||||
}
|
||||
else if (stop_tag.first != "<xmlcomment>" &&
|
||||
stop_tag.first != "<xmlattr>" )
|
||||
{
|
||||
throw config_error(std::string("Unknown child node. ") +
|
||||
"Expected 'ColorBand' but got '" + cb_tag.first + "'");
|
||||
"Expected 'stop' but got '" + stop_tag.first + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
256
src/raster_colorizer.cpp
Normal file
256
src/raster_colorizer.cpp
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2006 Artem Pavlenko
|
||||
*
|
||||
* 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; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
//$Id: $
|
||||
|
||||
#include <mapnik/raster_colorizer.hpp>
|
||||
#include <limits>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace mapnik;
|
||||
|
||||
|
||||
//! \brief Strings for the colorizer_mode enumeration
|
||||
static const char *colorizer_mode_strings[] = {
|
||||
"inherit",
|
||||
"linear",
|
||||
"discrete",
|
||||
"exact",
|
||||
""
|
||||
};
|
||||
|
||||
IMPLEMENT_ENUM( colorizer_mode, colorizer_mode_strings );
|
||||
|
||||
|
||||
colorizer_stop::colorizer_stop(const float value/* = 0*/, const colorizer_mode mode/* = COLORIZER_INHERIT*/, const color& _color/* = color(0,0,0,0)*/ )
|
||||
: value_(value)
|
||||
, mode_(mode)
|
||||
, color_(_color)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
colorizer_stop::colorizer_stop(const colorizer_stop& stop)
|
||||
: value_(stop.value_)
|
||||
, mode_(stop.mode_)
|
||||
, color_(stop.color_)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
colorizer_stop::~colorizer_stop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool colorizer_stop::operator==(colorizer_stop const& other) const
|
||||
{
|
||||
return (value_ == other.value_) &&
|
||||
(color_ == other.color_) &&
|
||||
(mode_ == other.mode_);
|
||||
}
|
||||
|
||||
|
||||
std::string colorizer_stop::to_string() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << color_.to_string() << " " << value_ << " " << mode_.as_string();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
raster_colorizer::raster_colorizer(colorizer_mode mode/* = COLORIZER_LINEAR*/, const color& _color/* = color(0,0,0,0)*/)
|
||||
: default_mode_(mode)
|
||||
, default_color_(_color)
|
||||
, epsilon_(numeric_limits<float>::epsilon())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
raster_colorizer::~raster_colorizer()
|
||||
{
|
||||
}
|
||||
|
||||
bool raster_colorizer::add_stop(const colorizer_stop & stop) {
|
||||
//make sure stops are added in order of value
|
||||
if(stops_.size()) {
|
||||
if(stop.get_value() <= stops_.back().get_value()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stops_.push_back(stop);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void raster_colorizer::colorize(raster_ptr const& raster,const std::map<std::string,value> &Props) const
|
||||
{
|
||||
unsigned *imageData = raster->data_.getData();
|
||||
|
||||
int len = raster->data_.width() * raster->data_.height();
|
||||
|
||||
bool hasNoData = false;
|
||||
float noDataValue = 0;
|
||||
|
||||
if (Props.count("NODATA")>0)
|
||||
{
|
||||
hasNoData = true;
|
||||
noDataValue = Props.at("NODATA").to_double();
|
||||
}
|
||||
|
||||
for (int i=0; i<len; ++i)
|
||||
{
|
||||
// the GDAL plugin reads single bands as floats
|
||||
float value = *reinterpret_cast<float *> (&imageData[i]);
|
||||
if (hasNoData && noDataValue == value)
|
||||
imageData[i] = color(0,0,0,0).rgba();
|
||||
else
|
||||
imageData[i] = get_color(value).rgba();
|
||||
}
|
||||
}
|
||||
|
||||
inline float interpolate(float start,float end, float fraction)
|
||||
{
|
||||
return fraction * (end - start) + start;
|
||||
}
|
||||
|
||||
color raster_colorizer::get_color(float value) const {
|
||||
int stopCount = stops_.size();
|
||||
|
||||
//use default color if no stops
|
||||
if(stopCount == 0) {
|
||||
return default_color_;
|
||||
}
|
||||
|
||||
//1 - Find the stop that the value is in
|
||||
int stopIdx = -1;
|
||||
bool foundStopIdx = false;
|
||||
|
||||
for(int i=0; i<stopCount; i++) {
|
||||
if(value < stops_[i].get_value()) {
|
||||
stopIdx = i-1;
|
||||
foundStopIdx = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!foundStopIdx) {
|
||||
stopIdx = stopCount-1;
|
||||
}
|
||||
|
||||
//2 - Find the next stop
|
||||
int nextStopIdx = stopIdx + 1;
|
||||
if(nextStopIdx >= stopCount) { //there is no next stop
|
||||
nextStopIdx = stopCount - 1;
|
||||
}
|
||||
|
||||
//3 - Work out the mode
|
||||
colorizer_mode stopMode;
|
||||
if( stopIdx == -1 ) { //before the first stop
|
||||
stopMode = default_mode_;
|
||||
}
|
||||
else {
|
||||
stopMode = stops_[stopIdx].get_mode();
|
||||
if(stopMode == COLORIZER_INHERIT) {
|
||||
stopMode = default_mode_;
|
||||
}
|
||||
}
|
||||
|
||||
//4 - Calculate the colour
|
||||
color stopColor;
|
||||
color nextStopColor;
|
||||
float stopValue = 0;
|
||||
float nextStopValue = 0;
|
||||
color outputColor = get_default_color();
|
||||
if(stopIdx == -1) {
|
||||
stopColor = default_color_;
|
||||
nextStopColor = stops_[nextStopIdx].get_color();
|
||||
stopValue = value;
|
||||
nextStopValue = stops_[nextStopIdx].get_value();
|
||||
}
|
||||
else {
|
||||
stopColor = stops_[stopIdx].get_color();
|
||||
nextStopColor = stops_[nextStopIdx].get_color();
|
||||
stopValue = stops_[stopIdx].get_value();
|
||||
nextStopValue = stops_[nextStopIdx].get_value();
|
||||
}
|
||||
|
||||
switch(stopMode) {
|
||||
case COLORIZER_LINEAR:
|
||||
{
|
||||
//deal with this separately so we don't have to worry about div0
|
||||
if(nextStopValue == stopValue) {
|
||||
outputColor = stopColor;
|
||||
}
|
||||
else {
|
||||
float fraction = (value - stopValue) / (nextStopValue - stopValue);
|
||||
|
||||
float r = interpolate(stopColor.red(), nextStopColor.red(),fraction);
|
||||
float g = interpolate(stopColor.green(), nextStopColor.green(),fraction);
|
||||
float b = interpolate(stopColor.blue(), nextStopColor.blue(),fraction);
|
||||
float a = interpolate(stopColor.alpha(), nextStopColor.alpha(),fraction);
|
||||
|
||||
outputColor.set_red(r);
|
||||
outputColor.set_green(g);
|
||||
outputColor.set_blue(b);
|
||||
outputColor.set_alpha(a);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case COLORIZER_DISCRETE:
|
||||
outputColor = stopColor;
|
||||
break;
|
||||
case COLORIZER_EXACT:
|
||||
default:
|
||||
//approximately equal (within epsilon)
|
||||
if(fabs(value - stopValue) < epsilon_) {
|
||||
outputColor = stopColor;
|
||||
}
|
||||
else {
|
||||
outputColor = default_color_;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
std::clog << "get_color: " << value << "\n";
|
||||
std::clog << "\tstopIdx: " << stopIdx << "\n";
|
||||
std::clog << "\tnextStopIdx: " << nextStopIdx << "\n";
|
||||
std::clog << "\tstopValue: " << stopValue << "\n";
|
||||
std::clog << "\tnextStopValue: " << nextStopValue << "\n";
|
||||
std::clog << "\tstopColor: " << stopColor.to_string() << "\n";
|
||||
std::clog << "\tnextStopColor: " << nextStopColor.to_string() << "\n";
|
||||
std::clog << "\tstopMode: " << stopMode.as_string() << "\n";
|
||||
std::clog << "\toutputColor: " << outputColor.to_string() << "\n";
|
||||
*/
|
||||
|
||||
return outputColor;
|
||||
}
|
||||
|
||||
|
|
@ -43,30 +43,6 @@ namespace mapnik
|
|||
using boost::property_tree::ptree;
|
||||
using boost::optional;
|
||||
|
||||
void serialize_raster_colorizer(ptree & sym_node,
|
||||
raster_colorizer_ptr const& colorizer,
|
||||
bool explicit_defaults)
|
||||
{
|
||||
ptree & col_node = sym_node.push_back(
|
||||
ptree::value_type("RasterColorizer", ptree() ))->second;
|
||||
|
||||
unsigned i;
|
||||
color_bands const &cb = colorizer->get_color_bands();
|
||||
for (i=0; i<cb.size(); i++) {
|
||||
if (!cb[i].is_interpolated()) {
|
||||
ptree & band_node = col_node.push_back(
|
||||
ptree::value_type("ColorBand", ptree())
|
||||
)->second;
|
||||
set_attr(band_node, "value", cb[i].get_value());
|
||||
if (cb[i].get_value() != cb[i].get_max_value())
|
||||
set_attr(band_node, "max-value", cb[i].get_max_value());
|
||||
set_attr(band_node, "midpoints", cb[i].get_midpoints());
|
||||
optional<color> c = cb[i].get_color();
|
||||
if (c) set_attr(band_node, "color", * c);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class serialize_symbolizer : public boost::static_visitor<>
|
||||
{
|
||||
|
@ -409,6 +385,29 @@ public:
|
|||
|
||||
private:
|
||||
serialize_symbolizer();
|
||||
|
||||
void serialize_raster_colorizer(ptree & sym_node,
|
||||
raster_colorizer_ptr const& colorizer,
|
||||
bool explicit_defaults)
|
||||
{
|
||||
ptree & col_node = sym_node.push_back(
|
||||
ptree::value_type("RasterColorizer", ptree() ))->second;
|
||||
|
||||
set_attr(col_node, "default-mode", colorizer->get_default_mode());
|
||||
set_attr(col_node, "default-color", colorizer->get_default_color());
|
||||
set_attr(col_node, "epsilon", colorizer->get_epsilon());
|
||||
|
||||
unsigned i;
|
||||
colorizer_stops const &stops = colorizer->get_stops();
|
||||
for (i=0; i<stops.size(); i++) {
|
||||
ptree &stop_node = col_node.push_back( ptree::value_type("stop", ptree()) )->second;
|
||||
set_attr(stop_node, "value", stops[i].get_value());
|
||||
set_attr(stop_node, "color", stops[i].get_color());
|
||||
set_attr(stop_node, "mode", stops[i].get_mode().as_string());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void add_image_attributes(ptree & node, const symbolizer_with_image & sym)
|
||||
{
|
||||
std::string const& filename = path_processor_type::to_string( *sym.get_filename());
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
<Style name="arrows">
|
||||
<Rule>
|
||||
<GlyphSymbolizer size="10" char="'í'" value="[value]" angle="[azimuth]+90" face-name="DejaVu Sans Condensed" allow-overlap="1" avoid-edges="0" halo-fill="rgba(0%,0%,0%,.1)" halo-radius="1" angle-mode="azimuth">
|
||||
<RasterColorizer>
|
||||
<ColorBand value="0" color="#0044cc"/>
|
||||
<ColorBand value="10" color="#00cc00"/>
|
||||
<ColorBand value="20" color="#ffff00"/>
|
||||
<RasterColorizer default_mode="discrete" default_color="#000000">
|
||||
<stop value="0" color="#0044cc"/>
|
||||
<stop value="10" color="#00cc00"/>
|
||||
<stop value="20" color="#ffff00"/>
|
||||
</RasterColorizer>
|
||||
</GlyphSymbolizer>
|
||||
</Rule>
|
||||
|
|
74
tests/data/good_maps/raster_colorizer.xml
Normal file
74
tests/data/good_maps/raster_colorizer.xml
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Map background-color="white" srs="+init=epsg:32630">
|
||||
|
||||
<!-- blue yellow orange indigo green red transparent black white -->
|
||||
|
||||
<Style name="DISCRETE RAINBOW">
|
||||
<Rule>
|
||||
<RasterSymbolizer>
|
||||
<RasterColorizer default-mode="discrete" default-color="white" >
|
||||
<stop color="red" value = "0" />
|
||||
<stop color="orange" value = "5" />
|
||||
<stop color="yellow" value = "10" />
|
||||
<stop color="green" value = "15" />
|
||||
<stop color="blue" value = "20" />
|
||||
<stop color="indigo" value = "25" />
|
||||
</RasterColorizer>
|
||||
</RasterSymbolizer>
|
||||
</Rule>
|
||||
</Style>
|
||||
|
||||
<Style name="LINEAR BLEND">
|
||||
<Rule>
|
||||
<RasterSymbolizer>
|
||||
<RasterColorizer default-mode="discrete" default-color="white" >
|
||||
<stop color="#222222" value = "0" mode = "linear" />
|
||||
<stop color="#EEEEEE" value = "25" />
|
||||
</RasterColorizer>
|
||||
</RasterSymbolizer>
|
||||
</Rule>
|
||||
</Style>
|
||||
|
||||
<Style name="BANDED">
|
||||
<Rule>
|
||||
<RasterSymbolizer>
|
||||
<RasterColorizer default-mode="discrete" default-color="white" >
|
||||
<stop color="red" value = "0" mode = "exact" />
|
||||
<stop color="orange" value = "2" mode = "exact" />
|
||||
<stop color="yellow" value = "4" mode = "exact" />
|
||||
<stop color="green" value = "6" mode = "exact" />
|
||||
<stop color="blue" value = "8" mode = "exact" />
|
||||
<stop color="indigo" value = "10" mode = "exact" />
|
||||
<stop color="violet" value = "12" mode = "exact" />
|
||||
</RasterColorizer>
|
||||
</RasterSymbolizer>
|
||||
</Rule>
|
||||
</Style>
|
||||
|
||||
<Style name="MIXED">
|
||||
<Rule>
|
||||
<RasterSymbolizer>
|
||||
<RasterColorizer default-mode="discrete" default-color="white" >
|
||||
<stop color="red" value = "0" />
|
||||
<stop color="orange" value = "5" />
|
||||
<stop color="yellow" value = "10" mode = "exact" />
|
||||
<stop color="green" value = "13" mode = "exact" />
|
||||
<stop color="#222222" value = "15" mode = "linear" />
|
||||
<stop color="#EEEEEE" value = "25" />
|
||||
</RasterColorizer>
|
||||
</RasterSymbolizer>
|
||||
</Rule>
|
||||
</Style>
|
||||
|
||||
<Layer name="dataraster" srs="+init=epsg:32630">
|
||||
<StyleName>DISCRETE RAINBOW</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="file">../raster/dataraster.tif</Parameter>
|
||||
<Parameter name="type">gdal</Parameter>
|
||||
<Parameter name="band">1</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
|
||||
</Map>
|
||||
|
||||
|
|
@ -3,9 +3,9 @@
|
|||
<Style name="two-value">
|
||||
<Rule>
|
||||
<RasterSymbolizer opacity="1">
|
||||
<RasterColorizer>
|
||||
<ColorBand value="0" color="yellow" label="<0"/>
|
||||
<ColorBand value="26" color="purple" midpoints="1"/>
|
||||
<RasterColorizer default_mode="discrete" default_color="#000000">
|
||||
<stop value="0" color="yellow"></stop>
|
||||
<stop value="26" color="purple"></stop>
|
||||
</RasterColorizer>
|
||||
</RasterSymbolizer>
|
||||
</Rule>
|
||||
|
@ -14,9 +14,9 @@
|
|||
<Style name="ramped">
|
||||
<Rule>
|
||||
<RasterSymbolizer>
|
||||
<RasterColorizer>
|
||||
<ColorBand value="0" color="red" label="<0"/>
|
||||
<ColorBand value="26" color="green" midpoints="100"/>
|
||||
<RasterColorizer default_mode="linear" default_color="#000000">
|
||||
<stop value="0" color="red"></stop>
|
||||
<stop value="26" color="green"></stop>
|
||||
</RasterColorizer>
|
||||
</RasterSymbolizer>
|
||||
</Rule>
|
||||
|
|
|
@ -1,46 +1,95 @@
|
|||
import mapnik2
|
||||
from nose.tools import *
|
||||
|
||||
def test_get_color():
|
||||
colorizer = mapnik2.RasterColorizer()
|
||||
# Setup the color bands. band[N].color will apply to all
|
||||
# values 'v' if band[N].value <= v < band[N+1].color
|
||||
# If no color is found then "transparent" will be assigned
|
||||
bands = [(value, mapnik2.Color(color)) for value, color in [
|
||||
( 0, "#0044cc"),
|
||||
( 10, "#00cc00"),
|
||||
( 20, "#ffff00"),
|
||||
( 30, "#ff7f00"),
|
||||
( 40, "#ff0000"),
|
||||
( 50, "#ff007f"),
|
||||
( 60, "#ff00ff"),
|
||||
( 70, "#cc00cc"),
|
||||
( 80, "#990099"),
|
||||
( 90, "#660066"),
|
||||
( 200, "#ffffff"),
|
||||
]]
|
||||
for value, color in bands:
|
||||
colorizer.append_band(value, color)
|
||||
def test_gen_map():
|
||||
mapxmlfile = '../data/good_maps/raster_colorizer.xml'
|
||||
mapxmloutputfile = 'raster_colorizer_test_save.xml'
|
||||
outputfile = 'raster_colorizer_test.png'
|
||||
|
||||
eq_(colorizer.get_color(-1), mapnik2.Color("transparent"))
|
||||
eq_(colorizer.get_color(0), bands[0][1])
|
||||
eq_(colorizer.get_color(5), bands[0][1])
|
||||
eq_(colorizer.get_color(10), bands[1][1])
|
||||
# last value is used if it matches exactly
|
||||
eq_(colorizer.get_color(200), bands[-1][1])
|
||||
# values greater than the last value are mapped to "transparent"
|
||||
eq_(colorizer.get_color(201), mapnik2.Color("transparent"))
|
||||
m = mapnik2.Map(800, 600)
|
||||
mapnik2.load_map(m, mapxmlfile)
|
||||
mapnik2.save_map(m, mapxmloutputfile)
|
||||
m.zoom_all()
|
||||
mapnik2.render_to_file(m, outputfile)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#test discrete colorizer mode
|
||||
def test_get_color_discrete():
|
||||
#setup
|
||||
colorizer = mapnik2.RasterColorizer();
|
||||
colorizer.default_color = mapnik2.Color(0,0,0,0);
|
||||
colorizer.default_mode = mapnik2.COLORIZER_DISCRETE;
|
||||
|
||||
colorizer.add_stop(10, mapnik2.Color(100,100,100,100));
|
||||
colorizer.add_stop(20, mapnik2.Color(200,200,200,200));
|
||||
|
||||
|
||||
|
||||
#should be default colour
|
||||
eq_(colorizer.get_color(-50), mapnik2.Color(0,0,0,0));
|
||||
eq_(colorizer.get_color(0), mapnik2.Color(0,0,0,0));
|
||||
|
||||
#now in stop 1
|
||||
eq_(colorizer.get_color(10), mapnik2.Color(100,100,100,100));
|
||||
eq_(colorizer.get_color(19), mapnik2.Color(100,100,100,100));
|
||||
|
||||
#now in stop 2
|
||||
eq_(colorizer.get_color(20), mapnik2.Color(200,200,200,200));
|
||||
eq_(colorizer.get_color(1000), mapnik2.Color(200,200,200,200));
|
||||
|
||||
|
||||
|
||||
#test exact colorizer mode
|
||||
def test_get_color_exact():
|
||||
#setup
|
||||
colorizer = mapnik2.RasterColorizer();
|
||||
colorizer.default_color = mapnik2.Color(0,0,0,0);
|
||||
colorizer.default_mode = mapnik2.COLORIZER_EXACT;
|
||||
|
||||
colorizer.add_stop(10, mapnik2.Color(100,100,100,100));
|
||||
colorizer.add_stop(20, mapnik2.Color(200,200,200,200));
|
||||
|
||||
#should be default colour
|
||||
eq_(colorizer.get_color(-50), mapnik2.Color(0,0,0,0));
|
||||
eq_(colorizer.get_color(11), mapnik2.Color(0,0,0,0));
|
||||
eq_(colorizer.get_color(20.001), mapnik2.Color(0,0,0,0));
|
||||
|
||||
#should be stop 1
|
||||
eq_(colorizer.get_color(10), mapnik2.Color(100,100,100,100));
|
||||
|
||||
#should be stop 2
|
||||
eq_(colorizer.get_color(20), mapnik2.Color(200,200,200,200));
|
||||
|
||||
|
||||
|
||||
|
||||
#test linear colorizer mode
|
||||
def test_get_color_linear():
|
||||
#setup
|
||||
colorizer = mapnik2.RasterColorizer();
|
||||
colorizer.default_color = mapnik2.Color(0,0,0,0);
|
||||
colorizer.default_mode = mapnik2.COLORIZER_LINEAR;
|
||||
|
||||
colorizer.add_stop(10, mapnik2.Color(100,100,100,100));
|
||||
colorizer.add_stop(20, mapnik2.Color(200,200,200,200));
|
||||
|
||||
#should be default colour
|
||||
eq_(colorizer.get_color(-50), mapnik2.Color(0,0,0,0));
|
||||
eq_(colorizer.get_color(9.9), mapnik2.Color(0,0,0,0));
|
||||
|
||||
#should be stop 1
|
||||
eq_(colorizer.get_color(10), mapnik2.Color(100,100,100,100));
|
||||
|
||||
#should be stop 2
|
||||
eq_(colorizer.get_color(20), mapnik2.Color(200,200,200,200));
|
||||
|
||||
#half way between stops 1 and 2
|
||||
eq_(colorizer.get_color(15), mapnik2.Color(150,150,150,150));
|
||||
|
||||
#after stop 2
|
||||
eq_(colorizer.get_color(100), mapnik2.Color(200,200,200,200));
|
||||
|
||||
def test_get_color_with_max_value():
|
||||
colorizer = mapnik2.RasterColorizer()
|
||||
c1 = mapnik2.Color("#0044cc")
|
||||
colorizer.append_band(0, c1)
|
||||
c2 = mapnik2.Color("#0055dd")
|
||||
colorizer.append_band(1, 2, c2)
|
||||
|
||||
eq_(colorizer.get_color(-1), mapnik2.Color("transparent"))
|
||||
eq_(colorizer.get_color(0), c1)
|
||||
eq_(colorizer.get_color(0.5), c1)
|
||||
eq_(colorizer.get_color(1), c2)
|
||||
eq_(colorizer.get_color(1.5), c2)
|
||||
eq_(colorizer.get_color(2), mapnik2.Color("transparent"))
|
||||
|
|
|
@ -25,7 +25,8 @@ def test_dataraster_coloring():
|
|||
sym = mapnik2.RasterSymbolizer()
|
||||
# Assigning a colorizer to the RasterSymbolizer tells the later
|
||||
# that it should use it to colorize the raw data raster
|
||||
sym.colorizer = mapnik2.RasterColorizer()
|
||||
sym.colorizer = mapnik2.RasterColorizer(mapnik2.COLORIZER_DISCRETE, mapnik2.Color("transparent"))
|
||||
|
||||
for value, color in [
|
||||
( 0, "#0044cc"),
|
||||
( 10, "#00cc00"),
|
||||
|
@ -39,7 +40,7 @@ def test_dataraster_coloring():
|
|||
( 90, "#660066"),
|
||||
( 200, "transparent"),
|
||||
]:
|
||||
sym.colorizer.append_band(value, mapnik2.Color(color))
|
||||
sym.colorizer.add_stop(value, mapnik2.Color(color))
|
||||
rule.symbols.append(sym)
|
||||
style.rules.append(rule)
|
||||
_map.append_style('foo', style)
|
||||
|
@ -92,4 +93,4 @@ def test_load_save_map():
|
|||
out_map = mapnik2.save_map_to_string(map)
|
||||
assert 'RasterSymbolizer' in out_map
|
||||
assert 'RasterColorizer' in out_map
|
||||
assert 'ColorBand' in out_map
|
||||
assert 'stop' in out_map
|
||||
|
|
Loading…
Reference in a new issue