2011-04-26 21:44:52 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* This file is part of Mapnik (c++ mapping toolkit)
|
|
|
|
*
|
|
|
|
* Copyright (C) 2011 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
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#ifndef MAPNIK_GRID_HPP
|
|
|
|
#define MAPNIK_GRID_HPP
|
|
|
|
|
|
|
|
// mapnik
|
2012-02-24 02:55:20 +00:00
|
|
|
#include <mapnik/config.hpp>
|
2012-04-08 00:20:56 +00:00
|
|
|
#include <mapnik/debug.hpp>
|
2011-04-26 21:44:52 +00:00
|
|
|
#include <mapnik/image_data.hpp>
|
|
|
|
#include <mapnik/box2d.hpp>
|
2011-06-03 05:55:28 +00:00
|
|
|
#include <mapnik/grid/grid_view.hpp>
|
2011-04-26 21:44:52 +00:00
|
|
|
#include <mapnik/global.hpp>
|
|
|
|
#include <mapnik/value.hpp>
|
2011-05-27 21:00:19 +00:00
|
|
|
#include <mapnik/feature.hpp>
|
2012-06-16 02:17:26 +00:00
|
|
|
#include <mapnik/feature_factory.hpp>
|
2012-06-24 02:41:07 +00:00
|
|
|
#include <mapnik/util/conversions.hpp>
|
2011-04-26 21:44:52 +00:00
|
|
|
|
2011-10-19 14:29:24 +00:00
|
|
|
// boost
|
|
|
|
#include <boost/cstdint.hpp>
|
|
|
|
|
2011-04-26 21:44:52 +00:00
|
|
|
// stl
|
|
|
|
#include <map>
|
2011-05-27 21:00:19 +00:00
|
|
|
#include <set>
|
2011-04-26 21:44:52 +00:00
|
|
|
#include <cmath>
|
|
|
|
#include <string>
|
|
|
|
#include <cassert>
|
|
|
|
#include <vector>
|
2012-06-26 00:57:52 +00:00
|
|
|
#include <boost/integer_traits.hpp>
|
2011-04-26 21:44:52 +00:00
|
|
|
|
|
|
|
namespace mapnik
|
|
|
|
{
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class MAPNIK_DECL hit_grid
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef T value_type;
|
|
|
|
typedef mapnik::ImageData<value_type> data_type;
|
|
|
|
typedef std::string lookup_type;
|
2011-06-03 01:55:26 +00:00
|
|
|
// mapping between pixel id and key
|
2011-04-26 21:44:52 +00:00
|
|
|
typedef std::map<value_type, lookup_type> feature_key_type;
|
|
|
|
typedef std::map<lookup_type, value_type> key_type;
|
2012-06-07 14:27:42 +00:00
|
|
|
typedef std::map<lookup_type, mapnik::feature_ptr> feature_type;
|
2012-06-26 00:57:52 +00:00
|
|
|
static const value_type base_mask = boost::integer_traits<value_type>::const_min;
|
2012-02-02 01:49:28 +00:00
|
|
|
|
2011-04-26 21:44:52 +00:00
|
|
|
private:
|
|
|
|
unsigned width_;
|
|
|
|
unsigned height_;
|
2011-06-03 01:55:26 +00:00
|
|
|
std::string key_;
|
2011-04-26 21:44:52 +00:00
|
|
|
data_type data_;
|
2011-06-03 01:55:26 +00:00
|
|
|
unsigned int resolution_;
|
2012-02-01 18:43:23 +00:00
|
|
|
std::string id_name_;
|
2011-09-11 06:24:26 +00:00
|
|
|
bool painted_;
|
2012-04-17 04:57:24 +00:00
|
|
|
std::set<std::string> names_;
|
|
|
|
feature_key_type f_keys_;
|
|
|
|
feature_type features_;
|
2012-06-16 02:17:26 +00:00
|
|
|
mapnik::context_ptr ctx_;
|
2012-02-02 01:49:28 +00:00
|
|
|
|
2011-04-26 21:44:52 +00:00
|
|
|
public:
|
|
|
|
|
2011-06-03 01:55:26 +00:00
|
|
|
hit_grid(int width, int height, std::string const& key, unsigned int resolution)
|
2011-04-26 21:44:52 +00:00
|
|
|
:width_(width),
|
2012-02-02 01:49:28 +00:00
|
|
|
height_(height),
|
|
|
|
key_(key),
|
|
|
|
data_(width,height),
|
|
|
|
resolution_(resolution),
|
|
|
|
id_name_("__id__"),
|
2012-04-17 04:57:24 +00:00
|
|
|
painted_(false),
|
|
|
|
names_(),
|
|
|
|
f_keys_(),
|
2012-06-16 02:17:26 +00:00
|
|
|
features_(),
|
|
|
|
ctx_(boost::make_shared<mapnik::context_type>())
|
2012-02-02 01:49:28 +00:00
|
|
|
{
|
2012-06-24 02:41:07 +00:00
|
|
|
f_keys_[base_mask] = "";
|
|
|
|
data_.set(base_mask);
|
2012-02-02 01:49:28 +00:00
|
|
|
}
|
|
|
|
|
2011-04-26 21:44:52 +00:00
|
|
|
hit_grid(const hit_grid<T>& rhs)
|
|
|
|
:width_(rhs.width_),
|
2012-02-02 01:49:28 +00:00
|
|
|
height_(rhs.height_),
|
|
|
|
key_(rhs.key_),
|
|
|
|
data_(rhs.data_),
|
|
|
|
resolution_(rhs.resolution_),
|
|
|
|
id_name_("__id__"),
|
2012-04-17 04:57:24 +00:00
|
|
|
painted_(rhs.painted_),
|
|
|
|
names_(rhs.names_),
|
|
|
|
f_keys_(rhs.f_keys_),
|
2012-06-16 02:17:26 +00:00
|
|
|
features_(rhs.features_),
|
|
|
|
ctx_(rhs.ctx_)
|
2012-02-02 01:49:28 +00:00
|
|
|
{
|
2012-06-24 02:41:07 +00:00
|
|
|
f_keys_[base_mask] = "";
|
|
|
|
data_.set(base_mask);
|
2012-02-02 01:49:28 +00:00
|
|
|
}
|
|
|
|
|
2011-04-26 21:44:52 +00:00
|
|
|
~hit_grid() {}
|
|
|
|
|
2011-10-19 14:29:24 +00:00
|
|
|
inline void painted(bool painted)
|
2011-09-11 06:24:26 +00:00
|
|
|
{
|
|
|
|
painted_ = painted;
|
|
|
|
}
|
|
|
|
|
2011-10-19 14:29:24 +00:00
|
|
|
inline bool painted() const
|
2011-09-11 06:24:26 +00:00
|
|
|
{
|
|
|
|
return painted_;
|
|
|
|
}
|
|
|
|
|
2012-02-01 18:43:23 +00:00
|
|
|
inline std::string const& key_name() const
|
|
|
|
{
|
|
|
|
return id_name_;
|
|
|
|
}
|
|
|
|
|
2012-06-16 02:17:26 +00:00
|
|
|
inline void add_feature(mapnik::feature_impl & feature)
|
2011-04-26 21:44:52 +00:00
|
|
|
{
|
2012-06-24 02:41:07 +00:00
|
|
|
int feature_id = feature.id();
|
2012-06-16 02:17:26 +00:00
|
|
|
// avoid adding duplicate features (e.g. in the case of both a line symbolizer and a polygon symbolizer)
|
2012-06-24 02:41:07 +00:00
|
|
|
typename feature_key_type::const_iterator feature_pos = f_keys_.find(feature_id);
|
2012-06-16 02:17:26 +00:00
|
|
|
if (feature_pos != f_keys_.end())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2012-02-02 01:49:28 +00:00
|
|
|
|
2012-06-16 02:17:26 +00:00
|
|
|
if (ctx_->size() == 0) {
|
|
|
|
mapnik::feature_impl::iterator itr = feature.begin();
|
|
|
|
mapnik::feature_impl::iterator end = feature.end();
|
|
|
|
for ( ;itr!=end; ++itr)
|
|
|
|
{
|
|
|
|
ctx_->push(boost::get<0>(*itr));
|
|
|
|
}
|
|
|
|
}
|
2012-02-01 18:43:23 +00:00
|
|
|
// NOTE: currently lookup keys must be strings,
|
|
|
|
// but this should be revisited
|
2012-06-24 02:41:07 +00:00
|
|
|
lookup_type lookup_value;
|
2011-06-03 01:55:26 +00:00
|
|
|
if (key_ == id_name_)
|
2011-04-26 21:44:52 +00:00
|
|
|
{
|
2012-06-24 02:41:07 +00:00
|
|
|
mapnik::util::to_string(lookup_value,feature_id);
|
2011-04-26 21:44:52 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-06-16 02:17:26 +00:00
|
|
|
if (feature.has_key(key_))
|
2011-04-26 21:44:52 +00:00
|
|
|
{
|
2012-06-16 02:17:26 +00:00
|
|
|
lookup_value = feature.get(key_).to_string();
|
2011-04-26 21:44:52 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-04-09 19:41:56 +00:00
|
|
|
MAPNIK_LOG_DEBUG(grid) << "hit_grid: Should not get here: key '" << key_ << "' not found in feature properties";
|
2012-02-02 01:49:28 +00:00
|
|
|
}
|
2011-04-26 21:44:52 +00:00
|
|
|
}
|
|
|
|
|
2012-06-24 02:41:07 +00:00
|
|
|
if (!lookup_value.empty())
|
2011-04-26 21:44:52 +00:00
|
|
|
{
|
|
|
|
// TODO - consider shortcutting f_keys if feature_id == lookup_value
|
2011-06-03 01:55:26 +00:00
|
|
|
// create a mapping between the pixel id and the feature key
|
2012-06-24 02:41:07 +00:00
|
|
|
f_keys_.insert(std::make_pair(feature_id,lookup_value));
|
2011-04-26 21:44:52 +00:00
|
|
|
// if extra fields have been supplied, push them into grid memory
|
2012-02-01 18:43:23 +00:00
|
|
|
if (!names_.empty())
|
|
|
|
{
|
2012-06-16 02:17:26 +00:00
|
|
|
// it is ~ 2x faster to copy feature attributes compared
|
|
|
|
// to building up a in-memory cache of feature_ptrs
|
|
|
|
// https://github.com/mapnik/mapnik/issues/1198
|
2012-06-24 02:41:07 +00:00
|
|
|
mapnik::feature_ptr feature2(mapnik::feature_factory::create(ctx_,feature_id));
|
2012-06-16 02:17:26 +00:00
|
|
|
feature2->set_data(feature.get_data());
|
2012-06-24 02:41:07 +00:00
|
|
|
features_.insert(std::make_pair(lookup_value,feature2));
|
2011-04-26 21:44:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-06-16 02:17:26 +00:00
|
|
|
MAPNIK_LOG_DEBUG(grid) << "hit_grid: Warning - key '" << key_ << "' was blank for " << feature;
|
2011-04-26 21:44:52 +00:00
|
|
|
}
|
2012-02-02 01:49:28 +00:00
|
|
|
}
|
|
|
|
|
2011-10-19 14:29:24 +00:00
|
|
|
inline void add_property_name(std::string const& name)
|
2011-04-26 21:44:52 +00:00
|
|
|
{
|
|
|
|
names_.insert(name);
|
2012-02-02 01:49:28 +00:00
|
|
|
}
|
2011-04-26 21:44:52 +00:00
|
|
|
|
2011-10-19 14:29:24 +00:00
|
|
|
inline std::set<std::string> const& property_names() const
|
2011-04-26 21:44:52 +00:00
|
|
|
{
|
|
|
|
return names_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const feature_type& get_grid_features() const
|
|
|
|
{
|
|
|
|
return features_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline feature_type& get_grid_features()
|
|
|
|
{
|
|
|
|
return features_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const feature_key_type& get_feature_keys() const
|
|
|
|
{
|
|
|
|
return f_keys_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline feature_key_type& get_feature_keys()
|
|
|
|
{
|
|
|
|
return f_keys_;
|
|
|
|
}
|
|
|
|
|
2011-06-03 01:55:26 +00:00
|
|
|
inline const std::string& get_key() const
|
|
|
|
{
|
|
|
|
return key_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void set_key(std::string const& key)
|
|
|
|
{
|
|
|
|
key_ = key;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline unsigned int get_resolution() const
|
|
|
|
{
|
|
|
|
return resolution_;
|
|
|
|
}
|
|
|
|
|
2011-08-11 22:58:53 +00:00
|
|
|
inline void set_resolution(unsigned int res)
|
2011-06-03 01:55:26 +00:00
|
|
|
{
|
|
|
|
resolution_ = res;
|
2011-04-26 21:44:52 +00:00
|
|
|
}
|
2012-02-02 01:49:28 +00:00
|
|
|
|
2011-04-26 21:44:52 +00:00
|
|
|
inline const data_type& data() const
|
|
|
|
{
|
|
|
|
return data_;
|
|
|
|
}
|
2012-02-02 01:49:28 +00:00
|
|
|
|
2011-04-26 21:44:52 +00:00
|
|
|
inline data_type& data()
|
|
|
|
{
|
|
|
|
return data_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const T* raw_data() const
|
|
|
|
{
|
|
|
|
return data_.getData();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline T* raw_data()
|
|
|
|
{
|
|
|
|
return data_.getData();
|
|
|
|
}
|
|
|
|
|
2011-06-03 05:55:28 +00:00
|
|
|
inline const value_type* getRow(unsigned row) const
|
|
|
|
{
|
|
|
|
return data_.getRow(row);
|
|
|
|
}
|
2012-02-02 01:49:28 +00:00
|
|
|
|
2011-06-03 05:55:28 +00:00
|
|
|
inline mapnik::grid_view get_view(unsigned x, unsigned y, unsigned w, unsigned h)
|
2011-04-26 21:44:52 +00:00
|
|
|
{
|
2011-06-03 05:55:28 +00:00
|
|
|
return mapnik::grid_view(x,y,w,h,
|
2012-02-02 01:49:28 +00:00
|
|
|
data_,key_,id_name_,resolution_,names_,f_keys_,features_);
|
2011-04-26 21:44:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
inline bool checkBounds(unsigned x, unsigned y) const
|
|
|
|
{
|
|
|
|
return (x < width_ && y < height_);
|
|
|
|
}
|
|
|
|
|
|
|
|
hit_grid& operator=(const hit_grid&);
|
2012-02-02 01:49:28 +00:00
|
|
|
|
2011-04-26 21:44:52 +00:00
|
|
|
public:
|
|
|
|
inline void setPixel(int x,int y,value_type feature_id)
|
|
|
|
{
|
|
|
|
if (checkBounds(x,y))
|
|
|
|
{
|
|
|
|
data_(x,y) = feature_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
inline unsigned width() const
|
|
|
|
{
|
|
|
|
return width_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline unsigned height() const
|
|
|
|
{
|
|
|
|
return height_;
|
|
|
|
}
|
|
|
|
|
2011-08-30 22:26:59 +00:00
|
|
|
inline void blendPixel(value_type feature_id,int x,int y,unsigned int rgba1,int t)
|
|
|
|
{
|
2011-10-19 14:29:24 +00:00
|
|
|
blendPixel2(feature_id ,x,y,rgba1,t,1.0); // do not change opacity
|
2011-08-30 22:26:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void blendPixel2(value_type feature_id,int x,int y,unsigned int rgba1,int t,double opacity)
|
|
|
|
{
|
|
|
|
if (checkBounds(x,y))
|
|
|
|
{
|
|
|
|
|
|
|
|
#ifdef MAPNIK_BIG_ENDIAN
|
2011-10-10 21:03:43 +00:00
|
|
|
unsigned a = (int)((rgba1 & 0xff) * opacity) & 0xff; // adjust for desired opacity
|
2011-08-30 22:26:59 +00:00
|
|
|
#else
|
|
|
|
unsigned a = (int)(((rgba1 >> 24) & 0xff) * opacity) & 0xff; // adjust for desired opacity
|
2012-02-02 01:49:28 +00:00
|
|
|
#endif
|
2011-08-30 22:26:59 +00:00
|
|
|
// if the pixel is more than a tenth
|
|
|
|
// opaque then burn in the feature id
|
|
|
|
if (a >= 25)
|
|
|
|
{
|
|
|
|
data_(x,y) = feature_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-02 01:49:28 +00:00
|
|
|
|
2011-04-26 21:44:52 +00:00
|
|
|
inline void set_rectangle(value_type id,image_data_32 const& data,int x0,int y0)
|
|
|
|
{
|
|
|
|
box2d<int> ext0(0,0,width_,height_);
|
|
|
|
box2d<int> ext1(x0,y0,x0+data.width(),y0+data.height());
|
|
|
|
|
|
|
|
if (ext0.intersects(ext1))
|
|
|
|
{
|
|
|
|
box2d<int> box = ext0.intersect(ext1);
|
|
|
|
for (int y = box.miny(); y < box.maxy(); ++y)
|
|
|
|
{
|
|
|
|
value_type* row_to = data_.getRow(y);
|
|
|
|
unsigned int const * row_from = data.getRow(y-y0);
|
|
|
|
|
|
|
|
for (int x = box.minx(); x < box.maxx(); ++x)
|
|
|
|
{
|
2011-05-02 22:33:11 +00:00
|
|
|
unsigned rgba = row_from[x-x0];
|
|
|
|
#ifdef MAPNIK_BIG_ENDIAN
|
|
|
|
unsigned a = rgba & 0xff;
|
|
|
|
#else
|
|
|
|
unsigned a = (rgba >> 24) & 0xff;
|
2012-02-02 01:49:28 +00:00
|
|
|
#endif
|
2011-05-02 22:33:11 +00:00
|
|
|
// if the pixel is more than a tenth
|
|
|
|
// opaque then burn in the feature id
|
|
|
|
if (a >= 25)
|
2011-04-26 21:44:52 +00:00
|
|
|
{
|
|
|
|
row_to[x] = id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2012-06-06 23:36:38 +00:00
|
|
|
typedef MAPNIK_DECL hit_grid<int> grid;
|
2011-04-26 21:44:52 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
#endif //MAPNIK_GRID_HPP
|