mapnik/src/raster_colorizer.cpp

321 lines
9.7 KiB
C++
Raw Normal View History

/*****************************************************************************
2012-02-02 02:53:35 +01:00
*
* This file is part of Mapnik (c++ mapping toolkit)
*
2017-05-05 13:02:01 +02:00
* Copyright (C) 2017 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
*
*****************************************************************************/
2012-04-08 02:20:56 +02:00
// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/value/types.hpp>
2013-01-14 07:01:13 +01:00
#include <mapnik/value.hpp> // for to_double
2013-01-04 08:55:09 +01:00
#include <mapnik/feature.hpp>
#include <mapnik/raster.hpp>
#include <mapnik/raster_colorizer.hpp>
2013-05-20 21:44:55 +02:00
#include <mapnik/enumeration.hpp>
2012-04-08 02:20:56 +02:00
// stl
#include <limits>
#include <cmath>
namespace mapnik
{
//! \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 )
colorizer_stop::colorizer_stop(float val, colorizer_mode mode,
2012-02-02 02:53:35 +01:00
color const& _color,
2012-01-13 17:30:03 +01:00
std::string const& label)
: value_(val)
, mode_(mode)
, color_(_color)
, label_(label)
{
2012-02-02 02:53:35 +01:00
}
2012-01-13 17:30:03 +01:00
colorizer_stop::colorizer_stop(colorizer_stop const& stop)
: value_(stop.value_)
, mode_(stop.mode_)
, color_(stop.color_)
, label_(stop.label_)
{
}
colorizer_stop::~colorizer_stop()
{
2012-02-02 02:53:35 +01: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_);
}
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
}
2012-01-13 17:30:03 +01:00
raster_colorizer::raster_colorizer(colorizer_mode mode, color const& _color)
: default_mode_(mode)
, default_color_(_color)
, epsilon_(std::numeric_limits<float>::epsilon())
{
2012-02-02 02:53:35 +01: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
{
//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
{
return false;
}
}
2012-02-02 02:53:35 +01:00
stops_.push_back(stop);
return true;
}
template <typename T>
void raster_colorizer::colorize(image_rgba8 & out, T const& in,
2014-12-17 14:54:31 +01:00
boost::optional<double> const& nodata,
feature_impl const& f) const
{
using image_type = T;
using pixel_type = typename image_type::pixel_type;
// TODO: assuming in/out have the same width/height for now
2015-05-04 12:49:11 +02:00
std::uint32_t * out_data = out.data();
pixel_type const* in_data = in.data();
int len = out.width() * out.height();
for (int i=0; i<len; ++i)
{
pixel_type val = in_data[i];
if (nodata && (std::fabs(val - *nodata) < epsilon_))
{
2014-12-04 10:31:56 +01:00
out_data[i] = 0; // rgba(0,0,0,0)
}
else
{
out_data[i] = get_color(val);
}
}
}
2011-11-29 15:36:39 +01:00
inline unsigned interpolate(unsigned start, unsigned end, float fraction)
{
2016-03-10 20:44:23 +01:00
return static_cast<unsigned>(fraction * (static_cast<float>(end) - static_cast<float>(start)) + static_cast<float>(start));
}
unsigned raster_colorizer::get_color(float val) const
2012-01-13 17:30:03 +01:00
{
int stopCount = stops_.size();
2012-02-02 02:53:35 +01:00
//use default color if no stops
if (stopCount == 0)
2012-01-13 17:30:03 +01:00
{
return default_color_.rgba();
}
2012-02-02 02:53:35 +01:00
//1 - Find the stop that the val 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
{
if (val < stops_[i].get_value())
2012-01-13 17:30:03 +01: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
{
stopIdx = stopCount-1;
}
2012-02-02 02:53:35 +01: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
nextStopIdx = stopCount - 1;
}
2012-02-02 02:53:35 +01: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
stopMode = default_mode_;
}
2012-02-02 02:53:35 +01:00
else
2012-01-13 17:30:03 +01: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
{
stopMode = default_mode_;
}
}
2012-02-02 02:53:35 +01: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
{
stopColor = default_color_;
nextStopColor = stops_[nextStopIdx].get_color();
stopValue = val;
nextStopValue = stops_[nextStopIdx].get_value();
}
2012-02-02 02:53:35 +01:00
else
2012-01-13 17:30:03 +01: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
{
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)
{
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 = (val - 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);
}
2012-02-02 02:53:35 +01:00
2012-01-13 17:30:03 +01:00
}
break;
case COLORIZER_DISCRETE:
outputColor = stopColor;
break;
case COLORIZER_EXACT:
default:
//approximately equal (within epsilon)
if (std::fabs(val - stopValue) < epsilon_)
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
{
outputColor = default_color_;
}
break;
}
2012-02-02 02:53:35 +01:00
/*
MAPNIK_LOG_DEBUG(raster_colorizer) << "raster_colorizer: get_color " << val;
MAPNIK_LOG_DEBUG(raster_colorizer) << "\tstopIdx: " << stopIdx;
MAPNIK_LOG_DEBUG(raster_colorizer) << "\tnextStopIdx: " << nextStopIdx;
MAPNIK_LOG_DEBUG(raster_colorizer) << "\tstopValue: " << stopValue;
MAPNIK_LOG_DEBUG(raster_colorizer) << "\tnextStopValue: " << nextStopValue;
MAPNIK_LOG_DEBUG(raster_colorizer) << "\tstopColor: " << stopColor.to_string();
MAPNIK_LOG_DEBUG(raster_colorizer) << "\tnextStopColor: " << nextStopColor.to_string();
MAPNIK_LOG_DEBUG(raster_colorizer) << "\tstopMode: " << stopMode.as_string();
MAPNIK_LOG_DEBUG(raster_colorizer) << "\toutputColor: " << outputColor.to_string();
2012-01-13 17:30:03 +01:00
*/
return outputColor.rgba();
}
template void raster_colorizer::colorize(image_rgba8 & out, image_gray8 const& in,
boost::optional<double>const& nodata,
feature_impl const& f) const;
template void raster_colorizer::colorize(image_rgba8 & out, image_gray8s const& in,
boost::optional<double>const& nodata,
feature_impl const& f) const;
template void raster_colorizer::colorize(image_rgba8 & out, image_gray16 const& in,
boost::optional<double>const& nodata,
feature_impl const& f) const;
template void raster_colorizer::colorize(image_rgba8 & out, image_gray16s const& in,
boost::optional<double>const& nodata,
feature_impl const& f) const;
template void raster_colorizer::colorize(image_rgba8 & out, image_gray32 const& in,
boost::optional<double>const& nodata,
feature_impl const& f) const;
template void raster_colorizer::colorize(image_rgba8 & out, image_gray32s const& in,
boost::optional<double>const& nodata,
feature_impl const& f) const;
template void raster_colorizer::colorize(image_rgba8 & out, image_gray32f const& in,
boost::optional<double>const& nodata,
feature_impl const& f) const;
template void raster_colorizer::colorize(image_rgba8 & out, image_gray64 const& in,
boost::optional<double>const& nodata,
feature_impl const& f) const;
template void raster_colorizer::colorize(image_rgba8 & out, image_gray64s const& in,
boost::optional<double>const& nodata,
feature_impl const& f) const;
template void raster_colorizer::colorize(image_rgba8 & out, image_gray64f const& in,
boost::optional<double>const& nodata,
feature_impl const& f) const;
}