Merge commit 'f8b1520d1a0626f3e16e88ecf641be7222a9ceb6' into harfbuzz

Conflicts:
	include/mapnik/map.hpp
This commit is contained in:
Hermann Kraus 2013-03-16 16:20:58 +01:00
commit b61500494b
11 changed files with 326 additions and 114 deletions

View file

@ -40,7 +40,7 @@ void benchmark(T test, std::string const& name)
if (!test_set.empty()) {
should_run_test = test_set.find(test_num) != test_set.end();
}
if (should_run_test) {
if (should_run_test || dry_run) {
if (!test.validate()) {
std::clog << "test did not validate: " << name << "\n";
//throw std::runtime_error(std::string("test did not validate: ") + name);
@ -282,23 +282,26 @@ struct test6
std::string dest_;
mapnik::box2d<double> from_;
mapnik::box2d<double> to_;
bool defer_proj4_init_;
explicit test6(unsigned iterations,
unsigned threads,
std::string const& src,
std::string const& dest,
mapnik::box2d<double> from,
mapnik::box2d<double> to) :
mapnik::box2d<double> to,
bool defer_proj) :
iter_(iterations),
threads_(threads),
src_(src),
dest_(dest),
from_(from),
to_(to) {}
to_(to),
defer_proj4_init_(defer_proj) {}
bool validate()
{
mapnik::projection src(src_);
mapnik::projection dest(dest_);
mapnik::projection src(src_,defer_proj4_init_);
mapnik::projection dest(dest_,defer_proj4_init_);
mapnik::proj_transform tr(src,dest);
mapnik::box2d<double> bbox = from_;
if (!tr.forward(bbox)) return false;
@ -310,17 +313,17 @@ struct test6
}
void operator()()
{
mapnik::projection src(src_);
mapnik::projection dest(dest_);
mapnik::proj_transform tr(src,dest);
unsigned count=0;
for (int i=-180;i<180;i=++i)
{
for (int j=-85;j<85;++j)
{
mapnik::box2d<double> box(i,j,i,j);
if (!tr.forward(box)) throw std::runtime_error("could not transform coords");
++count;
mapnik::projection src(src_,defer_proj4_init_);
mapnik::projection dest(dest_,defer_proj4_init_);
mapnik::proj_transform tr(src,dest);
mapnik::box2d<double> box(i,j,i,j);
if (!tr.forward(box)) throw std::runtime_error("could not transform coords");
++count;
}
}
}
@ -398,12 +401,29 @@ int main( int argc, char** argv)
mapnik::box2d<double> from(-180,-80,180,80);
mapnik::box2d<double> to(-20037508.3427892476,-15538711.0963092316,20037508.3427892476,15538711.0963092316);
{
test6 runner(1,5,
"+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs",
"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over",
from,to,false);
benchmark(runner,"lonlat -> merc coord transformation with proj4 init (literal)");
}
{
test6 runner(1,5,
"+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs",
"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over",
from,to,true);
benchmark(runner,"lonlat -> merc coord transformation with lazy proj4 init (literal)");
}
/*{
// echo -180 -60 | cs2cs -f "%.10f" +init=epsg:4326 +to +init=epsg:3857
test6 runner(100000000,100,
"+init=epsg:4326",
"+init=epsg:3857",
from,to);
from,to,false);
benchmark(runner,"lonlat -> merc coord transformation (epsg)");
}
@ -411,25 +431,17 @@ int main( int argc, char** argv)
test6 runner(100000000,100,
"+init=epsg:3857",
"+init=epsg:4326",
to,from);
to,from,false);
benchmark(runner,"merc -> lonlat coord transformation (epsg)");
}
}*/
{
test6 runner(100000000,100,
"+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs",
"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over",
from,to);
benchmark(runner,"lonlat -> merc coord transformation (literal)");
}
{
test6 runner(100000000,100,
/*{
test6 runner(10,2,
"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over",
"+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs",
to,from);
to,from,false);
benchmark(runner,"merc -> lonlat coord transformation (literal)");
}
}*/
std::cout << "...benchmark done\n";
return 0;

View file

@ -26,6 +26,7 @@
// mapnik
#include <mapnik/feature.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/well_known_srs.hpp>
// stl
#include <vector>
@ -44,7 +45,7 @@ class MAPNIK_DECL layer
{
public:
layer(std::string const& name,
std::string const& srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
std::string const& srs=MAPNIK_LONGLAT_PROJ);
layer(layer const& l);
layer& operator=(layer const& rhs);

View file

@ -31,6 +31,7 @@
#include <mapnik/layer.hpp>
#include <mapnik/params.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/well_known_srs.hpp>
// boost
#include <boost/optional/optional.hpp>
@ -106,7 +107,7 @@ public:
* @param height Initial map height.
* @param srs Initial map projection.
*/
Map(int width, int height, std::string const& srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
Map(int width, int height, std::string const& srs=MAPNIK_LONGLAT_PROJ);
/*! \brief Copy Constructur.
*

View file

@ -49,12 +49,13 @@ public:
mapnik::projection const& dest() const;
private:
projection const source_;
projection const dest_;
projection const& source_;
projection const& dest_;
bool is_source_longlat_;
bool is_dest_longlat_;
bool is_source_equal_dest_;
bool wgs84_to_merc_;
bool merc_to_wgs84_;
};
}

View file

@ -24,16 +24,14 @@
#define MAPNIK_PROJECTION_HPP
// mapnik
#include <mapnik/box2d.hpp>
// proj4
#include <proj_api.h>
#include <mapnik/config.hpp>
#include <mapnik/well_known_srs.hpp>
// boost
#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480
#include <boost/thread/mutex.hpp>
#endif
#include <boost/utility.hpp>
#include <boost/optional.hpp>
// stl
#include <string>
@ -52,7 +50,9 @@ class MAPNIK_DECL projection
{
friend class proj_transform;
public:
explicit projection(std::string const& params = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
explicit projection(std::string const& params = MAPNIK_LONGLAT_PROJ,
bool defer_proj_init = false);
projection(projection const& rhs);
~projection();
@ -61,24 +61,25 @@ public:
bool operator!=(const projection& other) const;
bool is_initialized() const;
bool is_geographic() const;
boost::optional<well_known_srs_e> well_known() const;
std::string const& params() const;
void forward(double & x, double &y ) const;
void forward(double & x, double & y) const;
void inverse(double & x,double & y) const;
std::string expanded() const;
void init_proj4() const;
private:
void init();
void swap (projection& rhs);
private:
std::string params_;
projPJ proj_;
bool is_geographic_;
#if PJ_VERSION >= 480
projCtx proj_ctx_;
#elif defined(MAPNIK_THREADSAFE)
bool defer_proj_init_;
mutable bool is_geographic_;
mutable void * proj_;
mutable void * proj_ctx_;
#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480
static boost::mutex mutex_;
#endif
};

View file

@ -0,0 +1,94 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2013 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_WELL_KNOWN_SRS_HPP
#define MAPNIK_WELL_KNOWN_SRS_HPP
// mapnik
#include <mapnik/enumeration.hpp>
// boost
#include <boost/optional.hpp>
// stl
#include <cmath>
namespace mapnik {
enum well_known_srs_enum {
WGS_84,
G_MERC,
well_known_srs_enum_MAX
};
DEFINE_ENUM( well_known_srs_e, well_known_srs_enum );
static const double EARTH_RADIUS = 6378137.0;
static const double EARTH_DIAMETER = EARTH_RADIUS * 2.0;
static const double EARTH_CIRCUMFERENCE = EARTH_DIAMETER * M_PI;
static const double MAXEXTENT = EARTH_CIRCUMFERENCE / 2.0;
static const double M_PI_by2 = M_PI / 2;
static const double D2R = M_PI / 180;
static const double R2D = 180 / M_PI;
static const double M_PIby360 = M_PI / 360;
static const double MAXEXTENTby180 = MAXEXTENT / 180;
static const std::string MAPNIK_LONGLAT_PROJ = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs";
static const std::string MAPNIK_GMERC_PROJ = "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over";
boost::optional<well_known_srs_e> is_well_known_srs(std::string const& srs);
boost::optional<bool> is_known_geographic(std::string const& srs);
static inline bool lonlat2merc(double * x, double * y , int point_count)
{
int i;
for(i=0; i<point_count; i++) {
x[i] = x[i] * MAXEXTENTby180;
y[i] = std::log(std::tan((90 + y[i]) * M_PIby360)) * R2D;
y[i] = y[i] * MAXEXTENTby180;
if (x[i] > MAXEXTENT) x[i] = MAXEXTENT;
if (x[i] < -MAXEXTENT) x[i] = -MAXEXTENT;
if (y[i] > MAXEXTENT) y[i] = MAXEXTENT;
if (y[i] < -MAXEXTENT) y[i] = -MAXEXTENT;
}
return true;
}
static inline bool merc2lonlat(double * x, double * y , int point_count)
{
int i;
for(i=0; i<point_count; i++)
{
x[i] = (x[i] / MAXEXTENT) * 180;
y[i] = (y[i] / MAXEXTENT) * 180;
y[i] = R2D * (2 * std::atan(std::exp(y[i] * D2R)) - M_PI_by2);
if (x[i] > 180) x[i] = 180;
if (x[i] < -180) x[i] = -180;
if (y[i] > 85.0511) y[i] = 85.0511;
if (y[i] < -85.0511) y[i] = -85.0511;
}
return true;
}
}
#endif // MAPNIK_WELL_KNOWN_SRS_HPP

View file

@ -100,6 +100,7 @@ else: # unix, non-macos
source = Split(
"""
well_known_srs.cpp
params.cpp
image_filter_types.cpp
miniz_png.cpp

View file

@ -62,7 +62,7 @@ IMPLEMENT_ENUM( aspect_fix_mode_e, aspect_fix_mode_strings )
Map::Map()
: width_(400),
height_(400),
srs_("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"),
srs_(MAPNIK_LONGLAT_PROJ),
buffer_size_(0),
aspectFixMode_(GROW_BBOX),
base_path_("") {}

View file

@ -32,30 +32,34 @@
// stl
#include <vector>
static const float MAXEXTENT = 20037508.34;
static const float M_PI_by2 = M_PI / 2;
static const float D2R = M_PI / 180;
static const float R2D = 180 / M_PI;
static const float M_PIby360 = M_PI / 360;
static const float MAXEXTENTby180 = MAXEXTENT/180;
namespace mapnik {
proj_transform::proj_transform(projection const& source,
projection const& dest)
: source_(source),
dest_(dest)
dest_(dest),
is_source_longlat_(false),
is_dest_longlat_(false),
wgs84_to_merc_(false),
merc_to_wgs84_(false)
{
is_source_longlat_ = source_.is_geographic();
is_dest_longlat_ = dest_.is_geographic();
is_source_equal_dest_ = (source_ == dest_);
if (source.params() == "+init=epsg:3857" && dest.params() == "+init=epsg:4326")
if (!is_source_equal_dest_)
{
wgs84_to_merc_ = true;
}
else
{
wgs84_to_merc_ = false;
is_source_longlat_ = source_.is_geographic();
is_dest_longlat_ = dest_.is_geographic();
boost::optional<well_known_srs_e> src_k = source.well_known();
boost::optional<well_known_srs_e> dest_k = dest.well_known();
if (src_k && dest_k)
{
if (*src_k == WGS_84) wgs84_to_merc_ = true;
else merc_to_wgs84_ = true;
}
else
{
source_.init_proj4();
dest_.init_proj4();
}
}
}
@ -76,18 +80,13 @@ bool proj_transform::forward (double * x, double * y , double * z, int point_cou
if (is_source_equal_dest_)
return true;
if (wgs84_to_merc_) {
int i;
for(i=0; i<point_count; i++) {
x[i] = (x[i] / MAXEXTENT) * 180;
y[i] = (y[i] / MAXEXTENT) * 180;
y[i] = R2D * (2 * atan(exp(y[i] * D2R)) - M_PI_by2);
if (x[i] > 180) x[i] = 180;
if (x[i] < -180) x[i] = -180;
if (y[i] > 85.0511) y[i] = 85.0511;
if (y[i] < -85.0511) y[i] = -85.0511;
}
return true;
if (wgs84_to_merc_)
{
return lonlat2merc(x,y,point_count);
}
else if (merc_to_wgs84_)
{
return merc2lonlat(x,y,point_count);
}
if (is_source_longlat_)
@ -127,18 +126,13 @@ bool proj_transform::backward (double * x, double * y , double * z, int point_co
if (is_source_equal_dest_)
return true;
if (wgs84_to_merc_) {
int i;
for(i=0; i<point_count; i++) {
x[i] = x[i] * MAXEXTENTby180;
y[i] = std::log(tan((90 + y[i]) * M_PIby360)) / D2R;
y[i] = y[i] * MAXEXTENTby180;
if (x[i] > MAXEXTENT) x[i] = MAXEXTENT;
if (x[i] < -MAXEXTENT) x[i] = -MAXEXTENT;
if (y[i] > MAXEXTENT) y[i] = MAXEXTENT;
if (y[i] < -MAXEXTENT) y[i] = -MAXEXTENT;
}
return true;
if (wgs84_to_merc_)
{
return merc2lonlat(x,y,point_count);
}
else if (merc_to_wgs84_)
{
return lonlat2merc(x,y,point_count);
}
if (is_dest_longlat_)

View file

@ -24,6 +24,7 @@
#include <mapnik/projection.hpp>
#include <mapnik/utils.hpp>
#include <mapnik/util/trim.hpp>
#include <mapnik/well_known_srs.hpp>
// proj4
#include <proj_api.h>
@ -35,16 +36,31 @@ namespace mapnik {
boost::mutex projection::mutex_;
#endif
projection::projection(std::string const& params)
: params_(params)
projection::projection(std::string const& params, bool defer_proj_init)
: params_(params),
defer_proj_init_(defer_proj_init),
proj_(NULL),
proj_ctx_(NULL)
{
init();
boost::optional<bool> is_known = is_known_geographic(params_);
if (is_known){
is_geographic_ = *is_known;
}
else
{
init_proj4();
}
if (!defer_proj_init_) init_proj4();
}
projection::projection(projection const& rhs)
: params_(rhs.params_)
: params_(rhs.params_),
defer_proj_init_(rhs.defer_proj_init_),
is_geographic_(rhs.is_geographic_),
proj_(NULL),
proj_ctx_(NULL)
{
init();
if (!rhs.defer_proj_init_) init_proj4();
}
projection& projection::operator=(projection const& rhs)
@ -64,6 +80,30 @@ bool projection::operator!=(const projection& other) const
return !(*this == other);
}
void projection::init_proj4() const
{
if (!proj_)
{
#if PJ_VERSION >= 480
proj_ctx_ = pj_ctx_alloc();
proj_ = pj_init_plus_ctx(proj_ctx_, params_.c_str());
if (!proj_)
{
if (proj_ctx_) pj_ctx_free(proj_ctx_);
throw proj_init_error(params_);
}
#else
#if defined(MAPNIK_THREADSAFE)
mutex::scoped_lock lock(mutex_);
#endif
proj_ = pj_init_plus(params_.c_str());
if (!proj_) throw proj_init_error(params_);
#endif
is_geographic_ = pj_is_latlong(proj_) ? true : false;
}
}
bool projection::is_initialized() const
{
return proj_ ? true : false;
@ -74,6 +114,11 @@ bool projection::is_geographic() const
return is_geographic_;
}
boost::optional<well_known_srs_e> projection::well_known() const
{
return is_well_known_srs(params_);
}
std::string const& projection::params() const
{
return params_;
@ -81,6 +126,7 @@ std::string const& projection::params() const
void projection::forward(double & x, double &y ) const
{
if (!proj_) return;
#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480
mutex::scoped_lock lock(mutex_);
#endif
@ -99,6 +145,7 @@ void projection::forward(double & x, double &y ) const
void projection::inverse(double & x,double & y) const
{
if (!proj_) return;
#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480
mutex::scoped_lock lock(mutex_);
#endif
@ -126,37 +173,15 @@ projection::~projection()
#endif
}
void projection::init()
{
#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480
mutex::scoped_lock lock(mutex_);
#endif
#if PJ_VERSION >= 480
proj_ctx_ = pj_ctx_alloc();
proj_ = pj_init_plus_ctx(proj_ctx_, params_.c_str());
if (!proj_)
{
if (proj_ctx_) pj_ctx_free(proj_ctx_);
throw proj_init_error(params_);
}
#else
proj_ = pj_init_plus(params_.c_str());
if (!proj_) throw proj_init_error(params_);
#endif
is_geographic_ = pj_is_latlong(proj_) ? true : false;
}
std::string projection::expanded() const
{
if (proj_) {
return mapnik::util::trim_copy(pj_get_def( proj_, 0 ));
}
return std::string("");
if (proj_) return mapnik::util::trim_copy(pj_get_def( proj_, 0 ));
return "";
}
void projection::swap(projection& rhs)
{
std::swap(params_,rhs.params_);
init();
}
}

82
src/well_known_srs.cpp Normal file
View file

@ -0,0 +1,82 @@
/*****************************************************************************
*
* 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
*
*****************************************************************************/
// mapnik
#include <mapnik/well_known_srs.hpp>
#include <mapnik/util/trim.hpp>
// boost
#include <boost/optional.hpp>
namespace mapnik {
static const char * well_known_srs_strings[] = {
"mapnik-longlat",
"mapnik-gmerc",
""
};
boost::optional<well_known_srs_e> is_well_known_srs(std::string const& srs)
{
if (srs == "+init=epsg:4326" || srs == MAPNIK_LONGLAT_PROJ)
{
return boost::optional<well_known_srs_e>(mapnik::WGS_84);
}
else if (srs == "+init=epsg:3857" || srs == MAPNIK_GMERC_PROJ)
{
return boost::optional<well_known_srs_e>(mapnik::G_MERC);
}
return boost::optional<well_known_srs_e>();
}
boost::optional<bool> is_known_geographic(std::string const& srs)
{
std::string trimmed = util::trim_copy(srs);
if (trimmed == "+init=epsg:3857")
{
return boost::optional<bool>(false);
}
else if (trimmed == "+init=epsg:4326")
{
return boost::optional<bool>(true);
}
else if (srs.find("+proj=") != std::string::npos)
{
if ((srs.find("+proj=longlat") != std::string::npos) ||
(srs.find("+proj=latlong") != std::string::npos) ||
(srs.find("+proj=lonlat") != std::string::npos) ||
(srs.find("+proj=latlon") != std::string::npos)
)
{
return boost::optional<bool>(true);
}
else
{
return boost::optional<bool>(false);
}
}
return boost::optional<bool>();
}
IMPLEMENT_ENUM( well_known_srs_e, well_known_srs_strings )
}