2011-05-04 02:20:17 +02:00
|
|
|
/*****************************************************************************
|
2012-02-02 02:53:35 +01:00
|
|
|
*
|
2011-05-04 02:20:17 +02:00
|
|
|
* This file is part of Mapnik (c++ mapping toolkit)
|
|
|
|
*
|
2011-10-23 15:04:25 +02:00
|
|
|
* Copyright (C) 2011 Artem Pavlenko
|
2011-05-04 02:20:17 +02:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2012-04-08 02:20:56 +02:00
|
|
|
// mapnik
|
|
|
|
#include <mapnik/debug.hpp>
|
2011-05-04 02:20:17 +02:00
|
|
|
#include <mapnik/raster_colorizer.hpp>
|
2012-04-08 02:20:56 +02:00
|
|
|
|
|
|
|
// stl
|
2011-05-04 02:20:17 +02:00
|
|
|
#include <limits>
|
|
|
|
|
2011-05-04 07:19:58 +02:00
|
|
|
namespace mapnik
|
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
|
|
|
|
//! \brief Strings for the colorizer_mode enumeration
|
|
|
|
static const char *colorizer_mode_strings[] = {
|
|
|
|
"inherit",
|
|
|
|
"linear",
|
|
|
|
"discrete",
|
|
|
|
"exact",
|
|
|
|
""
|
|
|
|
};
|
|
|
|
|
2011-07-06 01:39:50 +02:00
|
|
|
IMPLEMENT_ENUM( colorizer_mode, colorizer_mode_strings )
|
2011-05-04 02:20:17 +02:00
|
|
|
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
colorizer_stop::colorizer_stop(float value, colorizer_mode mode,
|
|
|
|
color const& _color,
|
2012-01-13 17:30:03 +01:00
|
|
|
std::string const& label)
|
|
|
|
: value_(value)
|
2011-05-04 02:20:17 +02:00
|
|
|
, mode_(mode)
|
|
|
|
, color_(_color)
|
2011-09-16 15:32:16 +02:00
|
|
|
, label_(label)
|
2011-05-04 02:20:17 +02:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
}
|
|
|
|
|
2012-01-13 17:30:03 +01:00
|
|
|
colorizer_stop::colorizer_stop(colorizer_stop const& stop)
|
2011-05-04 02:20:17 +02:00
|
|
|
: value_(stop.value_)
|
|
|
|
, mode_(stop.mode_)
|
|
|
|
, color_(stop.color_)
|
2011-09-16 15:32:16 +02:00
|
|
|
, label_(stop.label_)
|
2011-05-04 02:20:17 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
colorizer_stop::~colorizer_stop()
|
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool colorizer_stop::operator==(colorizer_stop const& other) const
|
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
return (value_ == other.value_) &&
|
2012-01-13 17:30:03 +01:00
|
|
|
(color_ == other.color_) &&
|
|
|
|
(mode_ == other.mode_) &&
|
|
|
|
(label_ == other.label_);
|
2011-05-04 02:20:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string colorizer_stop::to_string() const
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << color_.to_string() << " " << value_ << " " << mode_.as_string();
|
|
|
|
return ss.str();
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2011-05-04 02:20:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-01-13 17:30:03 +01:00
|
|
|
raster_colorizer::raster_colorizer(colorizer_mode mode, color const& _color)
|
2011-05-04 02:20:17 +02:00
|
|
|
: default_mode_(mode)
|
|
|
|
, default_color_(_color)
|
2011-05-04 07:19:58 +02:00
|
|
|
, epsilon_(std::numeric_limits<float>::epsilon())
|
2011-05-04 02:20:17 +02:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
raster_colorizer::~raster_colorizer()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
bool raster_colorizer::add_stop(colorizer_stop const& stop)
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
//make sure stops are added in order of value
|
2012-02-02 02:53:35 +01:00
|
|
|
if(stops_.size())
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
if(stop.get_value() <= stops_.back().get_value())
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
stops_.push_back(stop);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-01-17 20:19:38 +01:00
|
|
|
void raster_colorizer::colorize(raster_ptr const& raster, Feature const& f) const
|
2011-05-04 02:20:17 +02:00
|
|
|
{
|
|
|
|
unsigned *imageData = raster->data_.getData();
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
int len = raster->data_.width() * raster->data_.height();
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
bool hasNoData = false;
|
|
|
|
float noDataValue = 0;
|
|
|
|
|
2012-01-17 20:19:38 +01:00
|
|
|
//std::map<std::string,value>::const_iterator fi = Props.find("NODATA");
|
|
|
|
if (f.has_key("NODATA"))
|
2011-05-04 02:20:17 +02:00
|
|
|
{
|
|
|
|
hasNoData = true;
|
2012-01-17 20:19:38 +01:00
|
|
|
noDataValue = static_cast<float>(f.get("NODATA").to_double());
|
2011-05-04 02:20:17 +02:00
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-29 15:36:39 +01:00
|
|
|
inline unsigned interpolate(unsigned start, unsigned end, float fraction)
|
2011-05-04 02:20:17 +02:00
|
|
|
{
|
2011-12-23 15:01:28 +01:00
|
|
|
return static_cast<unsigned>(fraction * ((float)end - (float)start) + start);
|
2011-05-04 02:20:17 +02:00
|
|
|
}
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
color raster_colorizer::get_color(float value) const
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
int stopCount = stops_.size();
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
//use default color if no stops
|
2012-02-02 02:53:35 +01:00
|
|
|
if(stopCount == 0)
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
return default_color_;
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
//1 - Find the stop that the value is in
|
|
|
|
int stopIdx = -1;
|
|
|
|
bool foundStopIdx = false;
|
2012-02-02 02:53:35 +01:00
|
|
|
|
|
|
|
for(int i=0; i<stopCount; ++i)
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
if(value < stops_[i].get_value())
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
stopIdx = i-1;
|
|
|
|
foundStopIdx = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
|
|
|
if(!foundStopIdx)
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
stopIdx = stopCount-1;
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
//2 - Find the next stop
|
|
|
|
int nextStopIdx = stopIdx + 1;
|
2012-02-02 02:53:35 +01:00
|
|
|
if(nextStopIdx >= stopCount)
|
|
|
|
{
|
2012-01-13 17:30:03 +01:00
|
|
|
//there is no next stop
|
2011-05-04 02:20:17 +02:00
|
|
|
nextStopIdx = stopCount - 1;
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
//3 - Work out the mode
|
|
|
|
colorizer_mode stopMode;
|
2012-02-02 02:53:35 +01:00
|
|
|
if( stopIdx == -1 )
|
|
|
|
{
|
2012-01-13 17:30:03 +01:00
|
|
|
//before the first stop
|
2011-05-04 02:20:17 +02:00
|
|
|
stopMode = default_mode_;
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
else
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
stopMode = stops_[stopIdx].get_mode();
|
2012-02-02 02:53:35 +01:00
|
|
|
if(stopMode == COLORIZER_INHERIT)
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
stopMode = default_mode_;
|
|
|
|
}
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
//4 - Calculate the colour
|
|
|
|
color stopColor;
|
|
|
|
color nextStopColor;
|
|
|
|
float stopValue = 0;
|
|
|
|
float nextStopValue = 0;
|
|
|
|
color outputColor = get_default_color();
|
2012-02-02 02:53:35 +01:00
|
|
|
if(stopIdx == -1)
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
stopColor = default_color_;
|
|
|
|
nextStopColor = stops_[nextStopIdx].get_color();
|
|
|
|
stopValue = value;
|
|
|
|
nextStopValue = stops_[nextStopIdx].get_value();
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
else
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
stopColor = stops_[stopIdx].get_color();
|
|
|
|
nextStopColor = stops_[nextStopIdx].get_color();
|
|
|
|
stopValue = stops_[stopIdx].get_value();
|
|
|
|
nextStopValue = stops_[nextStopIdx].get_value();
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
|
|
|
switch(stopMode)
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
case COLORIZER_LINEAR:
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
|
|
|
//deal with this separately so we don't have to worry about div0
|
2012-02-02 02:53:35 +01:00
|
|
|
if(nextStopValue == stopValue)
|
2011-05-04 02:20:17 +02:00
|
|
|
{
|
2012-01-13 17:30:03 +01:00
|
|
|
outputColor = stopColor;
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
else
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
|
|
|
float fraction = (value - stopValue) / (nextStopValue - stopValue);
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-01-13 17:30:03 +01:00
|
|
|
unsigned r = interpolate(stopColor.red(), nextStopColor.red(),fraction);
|
|
|
|
unsigned g = interpolate(stopColor.green(), nextStopColor.green(),fraction);
|
|
|
|
unsigned b = interpolate(stopColor.blue(), nextStopColor.blue(),fraction);
|
|
|
|
unsigned a = interpolate(stopColor.alpha(), nextStopColor.alpha(),fraction);
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-01-13 17:30:03 +01:00
|
|
|
outputColor.set_red(r);
|
|
|
|
outputColor.set_green(g);
|
|
|
|
outputColor.set_blue(b);
|
|
|
|
outputColor.set_alpha(a);
|
2011-05-04 02:20:17 +02:00
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-01-13 17:30:03 +01:00
|
|
|
}
|
|
|
|
break;
|
2011-05-04 02:20:17 +02:00
|
|
|
case COLORIZER_DISCRETE:
|
|
|
|
outputColor = stopColor;
|
|
|
|
break;
|
|
|
|
case COLORIZER_EXACT:
|
|
|
|
default:
|
|
|
|
//approximately equal (within epsilon)
|
2012-02-02 02:53:35 +01:00
|
|
|
if(fabs(value - stopValue) < epsilon_)
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
outputColor = stopColor;
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
else
|
2012-01-13 17:30:03 +01:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
outputColor = default_color_;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
|
|
|
|
2012-04-08 02:20:56 +02:00
|
|
|
#ifdef MAPNIK_LOG
|
2011-05-04 02:20:17 +02:00
|
|
|
/*
|
2012-04-08 02:20:56 +02:00
|
|
|
mapnik::log() << "raster_colorizer: get_color " << value;
|
|
|
|
mapnik::log() << "\tstopIdx: " << stopIdx;
|
|
|
|
mapnik::log() << "\tnextStopIdx: " << nextStopIdx;
|
|
|
|
mapnik::log() << "\tstopValue: " << stopValue;
|
|
|
|
mapnik::log() << "\tnextStopValue: " << nextStopValue;
|
|
|
|
mapnik::log() << "\tstopColor: " << stopColor.to_string();
|
|
|
|
mapnik::log() << "\tnextStopColor: " << nextStopColor.to_string();
|
|
|
|
mapnik::log() << "\tstopMode: " << stopMode.as_string();
|
|
|
|
mapnik::log() << "\toutputColor: " << outputColor.to_string();
|
2012-01-13 17:30:03 +01:00
|
|
|
*/
|
2012-04-08 02:20:56 +02:00
|
|
|
#endif
|
2011-05-04 02:20:17 +02:00
|
|
|
|
|
|
|
return outputColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-04 07:19:58 +02:00
|
|
|
}
|
|
|
|
|