1.added projection transformation support based on proj4 (new dependency!!!)

Map and Layer objects both have a new parameter 'srs', initialized to "+proj=latlong +datum=WGS84" by default. 
    
  Basic usage (Python):
    p = Projection("+proj=merc +datum=WGS84")
    point = p.forward(Coord(-2,51))
    ...        
2.reflected arithmetic operators for Envelope/Coord into Python
3.altered return policies for python objects
4.modified build system to require proj4 lib and headers
This commit is contained in:
Artem Pavlenko 2006-10-16 13:44:52 +00:00
parent 52033ad4e8
commit bb235fa316
24 changed files with 670 additions and 167 deletions

View file

@ -45,7 +45,6 @@ opts.Add(PathOption('PROJ_LIBS', 'Search path for PROJ.4 include files', '/usr/l
opts.Add(PathOption('PYTHON','Python executable', sys.executable))
opts.Add(ListOption('INPUT_PLUGINS','Input drivers to include','all',['postgis','shape','raster']))
opts.Add(ListOption('BINDINGS','Language bindings to build','all',['python']))
opts.Add('DEBUG', 'Compile a debug version of mapnik', '')
env = Environment(ENV=os.environ, options=opts)
@ -59,14 +58,24 @@ conf = Configure(env)
env['CPPPATH'] = ['#agg/include', '#include', '#']
for path in [env['BOOST_INCLUDES'], env['PNG_INCLUDES'], env['JPEG_INCLUDES'], env['TIFF_INCLUDES'], env['PGSQL_INCLUDES'], env['PROJ_INCLUDES']]:
for path in [env['BOOST_INCLUDES'],
env['PNG_INCLUDES'],
env['JPEG_INCLUDES'],
env['TIFF_INCLUDES'],
env['PGSQL_INCLUDES'],
env['PROJ_INCLUDES']]:
if path not in env['CPPPATH']: env['CPPPATH'].append(path)
env['LIBPATH'] = ['#agg', '#src']
for path in [env['BOOST_LIBS'], env['PNG_LIBS'], env['JPEG_LIBS'], env['TIFF_LIBS'], env['PGSQL_LIBS'], env['PROJ_LIBS']]:
for path in [env['BOOST_LIBS'],
env['PNG_LIBS'],
env['JPEG_LIBS'],
env['TIFF_LIBS'],
env['PGSQL_LIBS'],
env['PROJ_LIBS']]:
if path not in env['LIBPATH']: env['LIBPATH'].append(path)
env.ParseConfig(env['FREETYPE_CONFIG'] + ' --libs --cflags')
C_LIBSHEADERS = [
@ -76,8 +85,8 @@ C_LIBSHEADERS = [
['tiff', 'tiff.h', True],
['z', 'zlib.h', True],
['jpeg', ['stdio.h', 'jpeglib.h'], True],
['pq', 'libpq-fe.h', False],
['proj', 'proj_api.h', False]
['proj', 'proj_api.h', True],
['pq', 'libpq-fe.h', False]
]
BOOST_LIBSHEADERS = [
@ -130,10 +139,7 @@ if 'python' in env['BINDINGS']:
SConscript('bindings/python/SConscript')
if 'proj' in env['LIBS']:
SConscript('bindings/python/pyprojection/SConscript')
env['LIBS'].remove('proj')
env = conf.Finish()
# Setup the c++ args for our own codebase

View file

@ -21,4 +21,4 @@ import glob
Import('env')
env.StaticLibrary('agg', glob.glob('./src/' + '*.cpp'), LIBS=[], CPPPATH='./include', CXXFLAGS='-O3 -fPIC ')
env.StaticLibrary('agg', glob.glob('./src/' + '*.cpp'), LIBS=[], CPPPATH='./include', CXXFLAGS='-O3 -fPIC -DNDEBUG')

View file

@ -55,10 +55,16 @@ class _Coord(Coord,_injector):
return 'Coord(%s,%s)' % (self.x, self.y)
class _Envelope(Envelope,_injector):
def __repr__(self):
return 'Envelope(%s,%s,%s,%s)' % \
(self.minx,self.miny,self.maxx,self.maxy)
def __repr__(self):
return 'Envelope(%s,%s,%s,%s)' % \
(self.minx,self.miny,self.maxx,self.maxy)
class _Projection(Projection,_injector):
def forward(self,pt):
return forward(pt,self)
def inverse(self,pt):
return inverse(pt,self)
def Datasource (**keywords):
return CreateDatasource(keywords)

View file

@ -0,0 +1,45 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <boost/python.hpp>
#include <mapnik/coord.hpp>
void export_coord()
{
using namespace boost::python;
using mapnik::coord;
class_<coord<double,2> >("Coord",init<double,double>())
.def_readwrite("x", &coord<double,2>::x)
.def_readwrite("y", &coord<double,2>::y)
.def(self == self) // __eq__
.def(self + self) // __add__
.def(self + float())
.def(float() + self)
.def(self - self) // __sub__
.def(self - float())
.def(self * float()) //__mult__
.def(float() * self)
.def(self / float()) // __div__
;
}

View file

@ -0,0 +1,68 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <boost/python.hpp>
#include <mapnik/envelope.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>
namespace
{
//user-friendly wrapper that uses Python dictionary
using namespace boost::python;
boost::shared_ptr<mapnik::datasource> create_datasource(const dict& d)
{
mapnik::parameters params;
boost::python::list keys=d.keys();
for (int i=0; i<len(keys); ++i)
{
std::string key = extract<std::string>(keys[i]);
object obj = d[key];
extract<std::string> ex(obj);
if (ex.check())
{
params[key] = ex();
}
}
return mapnik::datasource_cache::create(params);
}
}
void export_datasource()
{
using namespace boost::python;
using mapnik::datasource;
class_<datasource,boost::shared_ptr<datasource>,
boost::noncopyable>("Datasource",no_init)
.def("envelope",&datasource::envelope,
return_value_policy<copy_const_reference>())
.def("features",&datasource::features)
.def("params",&datasource::params,return_value_policy<copy_const_reference>(),
"The configuration parameters of the data source. "
"These vary depending on the type of data source.")
;
def("CreateDatasource",&create_datasource);
}

View file

@ -85,7 +85,12 @@ void export_envelope()
.def("intersects",intersects_p1)
.def("intersects",intersects_p2)
.def("intersects",intersects_p3)
.def(self == self)
.def(self == self) // __eq__
.def(self + self) // __add__
.def(self - self) // __sub__
.def(self * float()) // __mult__
.def(float() * self)
.def(self / float()) // __div__
.def_pickle(envelope_pickle_suite())
;
}

View file

@ -37,22 +37,27 @@ void export_layer()
.def(vector_indexing_suite<std::vector<std::string>,true >())
;
class_<Layer>("Layer","A map layer.", init<std::string const&>())
class_<Layer>("Layer", "A map layer.", init<std::string const&,optional<std::string const&> >())
.add_property("name",
make_function(&Layer::name, return_value_policy<reference_existing_object>()),
make_function(&Layer::name, return_value_policy<copy_const_reference>()),
&Layer::set_name,
"Get/Set the name of the layer.")
.add_property("title",
make_function(&Layer::title, return_value_policy<reference_existing_object>()),
make_function(&Layer::title, return_value_policy<copy_const_reference>()),
&Layer::set_title,
"Get/Set the title of the layer.")
.add_property("abstract",
make_function(&Layer::abstract,return_value_policy<reference_existing_object>()),
make_function(&Layer::abstract,return_value_policy<copy_const_reference>()),
&Layer::set_abstract,
"Get/Set the abstract of the layer.")
.add_property("src",
make_function(&Layer::srs,return_value_policy<copy_const_reference>()),
&Layer::set_srs,
"Get/Set the SRS of the layer.")
.add_property("minzoom",
&Layer::getMinZoom,
&Layer::setMinZoom)

View file

@ -38,7 +38,7 @@ void export_line_symbolizer()
.def(init<Color const& ,float>())
.add_property("stroke",make_function
(&line_symbolizer::get_stroke,
return_value_policy<reference_existing_object>()),
return_value_policy<copy_const_reference>()),
&line_symbolizer::set_stroke)
;
}

View file

@ -40,7 +40,7 @@ struct map_pickle_suite : boost::python::pickle_suite
static boost::python::tuple
getinitargs(const Map& m)
{
return boost::python::make_tuple(m.getWidth(),m.getHeight(),m.srid());
return boost::python::make_tuple(m.getWidth(),m.getHeight(),m.srs());
}
static boost::python::tuple
@ -85,10 +85,11 @@ void export_map()
.def(vector_indexing_suite<std::vector<Layer> >())
;
class_<Map>("Map","The map object.",init<int,int,boost::python::optional<int> >())
class_<Map>("Map","The map object.",init<int,int,optional<std::string const&> >())
.add_property("width",&Map::getWidth,"The width of the map image.")
.add_property("height",&Map::getHeight,"The height of the map image.")
.add_property("srid",&Map::srid)
.add_property("srs",make_function(&Map::srs,return_value_policy<copy_const_reference>()),
&Map::set_srs,"Spatial reference in proj4 format e.g. \"+proj=latlong +datum=WGS84\"")
.add_property("background",make_function
(&Map::getBackground,return_value_policy<copy_const_reference>()),
&Map::setBackground, "The background color of the map.")
@ -102,6 +103,7 @@ void export_map()
.def("zoom_to_box",&Map::zoomToBox, "Set the geographical extent of the map.")
.def("pan",&Map::pan)
.def("zoom",&Map::zoom)
.def("zoom_all",&Map::zoom_all)
.def("pan_and_zoom",&Map::pan_and_zoom)
.def("append_style",&Map::insert_style)
.def("remove_style",&Map::remove_style)

View file

@ -35,7 +35,7 @@ void export_polygon_symbolizer()
.def(init<Color const&>("TODO"))
.add_property("fill",make_function
(&polygon_symbolizer::get_fill,
return_value_policy<reference_existing_object>()),
return_value_policy<copy_const_reference>()),
&polygon_symbolizer::set_fill)
.add_property("fill_opacity",
&polygon_symbolizer::get_opacity,

View file

@ -0,0 +1,64 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <boost/python.hpp>
#include <mapnik/coord.hpp>
#include <mapnik/projection.hpp>
namespace {
mapnik::coord2d forward(mapnik::coord2d const& pt,
mapnik::projection const& prj)
{
double x = pt.x;
double y = pt.y;
prj.forward(x,y);
return mapnik::coord2d(x,y);
}
mapnik::coord2d inverse(mapnik::coord2d const& pt,
mapnik::projection const& prj)
{
double x = pt.x;
double y = pt.y;
prj.inverse(x,y);
return mapnik::coord2d(x,y);
}
}
void export_projection ()
{
using namespace boost::python;
using mapnik::projection;
class_<projection>("Projection", init<optional<std::string const&> >())
.def ("forward",&projection::forward)
.def ("inverse",&projection::inverse)
.def ("params", make_function(&projection::params,
return_value_policy<copy_const_reference>()))
;
def("forward",&forward);
def("inverse",&inverse);
}

View file

@ -26,6 +26,7 @@
#include <boost/python/detail/api_placeholder.hpp>
void export_color();
void export_coord();
void export_layer();
void export_parameters();
void export_envelope();
@ -37,6 +38,7 @@ void export_filter();
void export_rule();
void export_style();
void export_stroke();
void export_datasource();
void export_datasource_cache();
void export_point_symbolizer();
void export_line_symbolizer();
@ -46,6 +48,7 @@ void export_polygon_pattern_symbolizer();
void export_raster_symbolizer();
void export_text_symbolizer();
void export_font_engine();
void export_projection();
#include <mapnik/map.hpp>
#include <mapnik/agg_renderer.hpp>
@ -70,28 +73,6 @@ void render(const mapnik::Map& map,mapnik::Image32& image)
ren.apply();
}
namespace
{
//user-friendly wrapper that uses Python dictionary
using namespace boost::python;
boost::shared_ptr<mapnik::datasource> create_datasource(const dict& d)
{
mapnik::parameters params;
boost::python::list keys=d.keys();
for (int i=0; i<len(keys); ++i)
{
std::string key = extract<std::string>(keys[i]);
object obj = d[key];
extract<std::string> ex(obj);
if (ex.check())
{
params[key] = ex();
}
}
return mapnik::datasource_cache::create(params);
}
}
BOOST_PYTHON_MODULE(_mapnik)
{
@ -109,18 +90,7 @@ BOOST_PYTHON_MODULE(_mapnik)
class_<Featureset,featureset_ptr,boost::noncopyable>("FeatureSet",no_init)
;
class_<datasource,boost::shared_ptr<datasource>,
boost::noncopyable>("Datasource",no_init)
.def("envelope",&datasource::envelope,
return_value_policy<reference_existing_object>())
.def("features",&datasource::features)
.def("params",&datasource::params,return_value_policy<reference_existing_object>(),
"The configuration parameters of the data source. "
"These vary depending on the type of data source.")
;
def("CreateDatasource",&create_datasource);
export_datasource();
export_parameters();
export_color();
export_envelope();
@ -139,12 +109,8 @@ BOOST_PYTHON_MODULE(_mapnik)
export_raster_symbolizer();
export_text_symbolizer();
export_font_engine();
class_<coord<double,2> >("Coord",init<double,double>())
.def_readwrite("x", &coord<double,2>::x)
.def_readwrite("y", &coord<double,2>::y)
;
export_projection();
export_coord();
export_map();
def("render_to_file",&render_to_file);

View file

@ -45,7 +45,7 @@ void export_stroke ()
class_<stroke>("Stroke",init<>())
.def(init<Color,float>())
.add_property("color",make_function
(&stroke::get_color,return_value_policy<reference_existing_object>()),
(&stroke::get_color,return_value_policy<copy_const_reference>()),
&stroke::set_color)
.add_property("width",&stroke::get_width,&stroke::set_width)
.add_property("opacity",&stroke::get_opacity,&stroke::set_opacity)

View file

@ -30,7 +30,7 @@ installed successfully before running this script.\n\n'
# Instanciate a map, giving it a width and height. Remember: the word "map" is
# reserved in Python! :)
m = Map(800,600)
m = Map(800,600,"+proj=latlong")
# Set its background colour. More on colours later ...

View file

@ -45,13 +45,27 @@ namespace mapnik {
void end_map_processing(Map const& map);
void start_layer_processing(Layer const& lay);
void end_layer_processing(Layer const& lay);
void process(point_symbolizer const& sym,Feature const& feature);
void process(line_symbolizer const& sym,Feature const& feature);
void process(line_pattern_symbolizer const& sym,Feature const& feature);
void process(polygon_symbolizer const& sym,Feature const& feature);
void process(polygon_pattern_symbolizer const& sym,Feature const& feature);
void process(raster_symbolizer const& sym,Feature const& feature);
void process(text_symbolizer const& sym,Feature const& feature);
void process(point_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans);
void process(line_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans);
void process(line_pattern_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans);
void process(polygon_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans);
void process(polygon_pattern_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans);
void process(raster_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans);
void process(text_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans);
private:
T & pixmap_;
CoordTransform t_;

View file

@ -27,6 +27,7 @@
#include <mapnik/envelope.hpp>
#include <mapnik/coord_array.hpp>
#include <mapnik/projection.hpp>
namespace mapnik {
typedef coord_array<coord2d> CoordinateArray;
@ -53,7 +54,38 @@ namespace mapnik {
Transform const& t_;
Geometry& geom_;
};
template <typename Transform,typename Geometry>
struct MAPNIK_DECL coord_transform2
{
coord_transform2(Transform const& t,
Geometry& geom,
proj_transform const& prj_trans)
: t_(t),
geom_(geom),
prj_trans_(prj_trans) {}
unsigned vertex(double * x , double * y) const
{
unsigned command = geom_.vertex(x,y);
double z=0;
prj_trans_.backward(*x,*y,z);
t_.forward(x,y);
return command;
}
void rewind (unsigned pos)
{
geom_.rewind(pos);
}
private:
Transform const& t_;
Geometry& geom_;
proj_transform const& prj_trans_;
};
class CoordTransform
{
private:

View file

@ -36,6 +36,7 @@
#include <mapnik/map.hpp>
#include <mapnik/attribute_collector.hpp>
#include <mapnik/utils.hpp>
#include <mapnik/projection.hpp>
namespace mapnik
{
@ -44,17 +45,22 @@ namespace mapnik
{
struct symbol_dispatch : public boost::static_visitor<>
{
symbol_dispatch (Processor & output,Feature const& f)
: output_(output),f_(f) {}
symbol_dispatch (Processor & output,
Feature const& f,
proj_transform const& prj_trans)
: output_(output),
f_(f),
prj_trans_(prj_trans) {}
template <typename T>
void operator () (T const& sym) const
{
output_.process(sym,f_);
output_.process(sym,f_,prj_trans_);
}
Processor & output_;
Feature const& f_;
proj_transform const& prj_trans_;
};
public:
feature_style_processor(Map const& m)
@ -63,52 +69,82 @@ namespace mapnik
void apply()
{
boost::progress_timer t;
Processor & p = static_cast<Processor&>(*this);
p.start_map_processing(m_);
std::vector<Layer>::const_iterator itr = m_.layers().begin();
std::vector<Layer>::const_iterator end = m_.layers().end();
while (itr != end)
{
if (itr->isVisible(m_.scale()) &&
itr->envelope().intersects(m_.getCurrentExtent()))
{
apply_to_layer(*itr,p);
}
++itr;
}
try
{
projection proj(m_.srs()); // map projection
while (itr != end)
{
if (itr->isVisible(m_.scale()))// &&
//itr->envelope().intersects(m_.getCurrentExtent())) TODO
{
apply_to_layer(*itr, p, proj);
}
++itr;
}
}
catch (proj_init_error& ex)
{
std::clog << ex.what() << "\n";
}
p.end_map_processing(m_);
}
private:
void apply_to_layer(Layer const& lay,Processor & p)
void apply_to_layer(Layer const& lay, Processor & p, projection const& proj0)
{
p.start_layer_processing(lay);
boost::shared_ptr<datasource> ds=lay.datasource();
if (ds)
{
Envelope<double> const& bbox=m_.getCurrentExtent();
Envelope<double> const& ext=m_.getCurrentExtent();
projection proj1(lay.srs());
proj_transform prj_trans(proj0,proj1);
double x0 = ext.minx();
double y0 = ext.miny();
double z0 = 0.0;
double x1 = ext.maxx();
double y1 = ext.maxy();
double z1 = 0.0;
prj_trans.forward(x0,y0,z0);
prj_trans.forward(x1,y1,z1);
Envelope<double> bbox(x0,y0,x1,y1);
std::clog << bbox << "\n";
double scale = m_.scale();
std::vector<std::string> const& style_names = lay.styles();
std::vector<std::string>::const_iterator stylesIter = style_names.begin();
while (stylesIter != style_names.end())
std::vector<std::string>::const_iterator stylesEnd = style_names.end();
while (stylesIter != stylesEnd)
{
std::set<std::string> names;
attribute_collector<Feature> collector(names);
std::vector<rule_type*> if_rules;
std::vector<rule_type*> else_rules;
bool active_rules=false;
feature_type_style const& style=m_.find_style(*stylesIter++);
query q(bbox); //BBOX query
const std::vector<rule_type>& rules=style.get_rules();
std::vector<rule_type>::const_iterator ruleIter=rules.begin();
query q(bbox); //BBOX query
while (ruleIter!=rules.end())
std::vector<rule_type>::const_iterator ruleEnd=rules.end();
while (ruleIter!=ruleEnd)
{
if (ruleIter->active(scale))
{
@ -127,8 +163,10 @@ namespace mapnik
++ruleIter;
}
std::set<std::string>::const_iterator namesIter=names.begin();
std::set<std::string>::const_iterator namesEnd =names.end();
// push all property names
while (namesIter!=names.end())
while (namesIter!=namesEnd)
{
q.add_property_name(*namesIter);
++namesIter;
@ -143,7 +181,8 @@ namespace mapnik
{
bool do_else=true;
std::vector<rule_type*>::const_iterator itr=if_rules.begin();
while (itr!=if_rules.end())
std::vector<rule_type*>::const_iterator end=if_rules.end();
while (itr != end)
{
filter_ptr const& filter=(*itr)->get_filter();
if (filter->pass(*feature))
@ -151,10 +190,11 @@ namespace mapnik
do_else=false;
const symbolizers& symbols = (*itr)->get_symbolizers();
symbolizers::const_iterator symIter=symbols.begin();
while (symIter!=symbols.end())
symbolizers::const_iterator symEnd =symbols.end();
while (symIter != symEnd)
{
boost::apply_visitor
(symbol_dispatch(p,*feature),*symIter++);
(symbol_dispatch(p,*feature,prj_trans),*symIter++);
}
}
++itr;
@ -164,14 +204,19 @@ namespace mapnik
//else filter
std::vector<rule_type*>::const_iterator itr=
else_rules.begin();
while (itr != else_rules.end())
std::vector<rule_type*>::const_iterator end=
else_rules.end();
while (itr != end)
{
const symbolizers& symbols = (*itr)->get_symbolizers();
symbolizers::const_iterator symIter=symbols.begin();
while (symIter!=symbols.end())
symbolizers::const_iterator symIter= symbols.begin();
symbolizers::const_iterator symEnd = symbols.end();
while (symIter!=symEnd)
{
boost::apply_visitor
(symbol_dispatch(p,*feature),*symIter++);
(symbol_dispatch(p,*feature,prj_trans),
*symIter++);
}
++itr;
}
@ -180,10 +225,10 @@ namespace mapnik
}
}
}
}
p.end_layer_processing(lay);
}
}
Map const& m_;
};
}

View file

@ -38,6 +38,8 @@ namespace mapnik
std::string name_;
std::string title_;
std::string abstract_;
std::string srs_;
double minZoom_;
double maxZoom_;
bool active_;
@ -49,7 +51,7 @@ namespace mapnik
mutable std::vector<boost::shared_ptr<Feature> > selection_;
public:
explicit Layer(std::string const& name);
explicit Layer(std::string const& name, std::string const& srs="+proj=latlong +datum=WGS84");
Layer(Layer const& l);
Layer& operator=(Layer const& l);
bool operator==(Layer const& other) const;
@ -59,6 +61,8 @@ namespace mapnik
const std::string& title() const;
void set_abstract(std::string const& abstract);
const std::string& abstract() const;
void set_srs(std::string const& srs);
std::string const& srs() const;
void add_style(std::string const& stylename);
std::vector<std::string> const& styles() const;
void selection_style(const std::string& name);

View file

@ -36,18 +36,17 @@ namespace mapnik
static const unsigned MAX_MAPSIZE=2048;
unsigned width_;
unsigned height_;
int srid_;
std::string srs_;
Color background_;
std::map<std::string,feature_type_style> styles_;
std::vector<Layer> layers_;
Envelope<double> currentExtent_;
public:
typedef std::map<std::string,feature_type_style>::const_iterator style_iterator;
Map();
Map(int width,int height,int srid=-1);
Map(int width, int height, std::string const& srs="+proj=latlong +datum=WGS84");
Map(const Map& rhs);
Map& operator=(const Map& rhs);
style_iterator begin_styles() const;
@ -67,7 +66,8 @@ namespace mapnik
void setWidth(unsigned width);
void setHeight(unsigned height);
void resize(unsigned width,unsigned height);
int srid() const;
std::string const& srs() const;
void set_srs(std::string const& srs);
void setBackground(const Color& c);
const Color& getBackground() const;
void zoom(double zoom);

View file

@ -0,0 +1,174 @@
#ifndef PROJECTION_HPP
#define PROJECTION_HPP
#include <string>
#include <iostream>
#include <stdexcept>
#include <boost/utility.hpp>
#include <mapnik/envelope.hpp>
#include <proj_api.h>
namespace mapnik
{
class proj_init_error : public std::runtime_error
{
public:
proj_init_error(std::string const& params)
: std::runtime_error("failed to initialize projection with:" + params) {}
};
class projection
{
friend class proj_transform;
public:
explicit projection(std::string params = "+proj=latlong +ellps=WGS84")
: params_(params)
{
init(); //
}
projection(projection const& rhs)
: params_(rhs.params_)
{
init(); //
}
projection& operator=(projection const& rhs)
{
projection tmp(rhs);
swap(tmp);
return *this;
}
bool is_initialized() const
{
return proj_ ? true : false;
}
std::string const& params() const
{
return params_;
}
void forward(double & x, double &y ) const
{
projUV p;
p.u = x * DEG_TO_RAD;
p.v = y * DEG_TO_RAD;
p = pj_fwd(p,proj_);
x = p.u;
y = p.v;
}
void inverse(double & x,double & y) const
{
projUV p;
p.u = x;
p.v = y;
p = pj_inv(p,proj_);
x = RAD_TO_DEG * p.u;
y = RAD_TO_DEG * p.v;
}
~projection()
{
if (proj_) pj_free(proj_);
}
private:
void init()
{
proj_=pj_init_plus(params_.c_str());
if (!proj_) throw proj_init_error(params_);
}
void swap (projection& rhs)
{
std::swap(params_,rhs.params_);
init ();
}
private:
std::string params_;
projPJ proj_;
};
class proj_transform : private boost::noncopyable
{
public:
proj_transform(projection const& source,
projection const& dest)
: source_(source),
dest_(dest)
{
is_source_latlong_ = pj_is_latlong(source_.proj_);
is_dest_latlong_ = pj_is_latlong(dest_.proj_);
}
bool forward (double & x, double & y , double & z) const
{
if (is_source_latlong_)
{
x *= DEG_TO_RAD;
y *= DEG_TO_RAD;
}
if (pj_transform( source_.proj_, dest_.proj_, 1,
0, &x,&y,&z) != 0)
{
return false;
}
if (is_dest_latlong_)
{
x *= RAD_TO_DEG;
y *= RAD_TO_DEG;
}
return true;
}
bool forward (Envelope<double> & ext) const
{
if (is_source_latlong_)
{
ext = ext.intersect(Envelope<double>(-180,-90,180,90));
}
// TODO
return true;
}
bool backward (double & x, double & y , double & z) const
{
if (is_dest_latlong_)
{
x *= DEG_TO_RAD;
y *= DEG_TO_RAD;
}
if (pj_transform( dest_.proj_, source_.proj_, 1,
0, &x,&y,&z) != 0)
{
return false;
}
if (is_source_latlong_)
{
x *= RAD_TO_DEG;
y *= RAD_TO_DEG;
}
return true;
}
private:
projection const& source_;
projection const& dest_;
bool is_source_latlong_;
bool is_dest_latlong_;
};
}
#endif //PROJECTION_HPP

View file

@ -126,9 +126,11 @@ namespace mapnik
}
template <typename T>
void agg_renderer<T>::process(polygon_symbolizer const& sym,Feature const& feature)
void agg_renderer<T>::process(polygon_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform<CoordTransform,geometry_type> path_type;
typedef coord_transform2<CoordTransform,geometry_type> path_type;
typedef agg::renderer_base<agg::pixfmt_rgba32> ren_base;
typedef agg::renderer_scanline_aa_solid<ren_base> renderer;
@ -139,7 +141,7 @@ namespace mapnik
{
unsigned width = pixmap_.width();
unsigned height = pixmap_.height();
path_type path(t_,*geom);
path_type path(t_,*geom,prj_trans);
agg::row_ptr_cache<agg::int8u> buf(pixmap_.raw_data(),width,height,width * 4);
agg::pixfmt_rgba32 pixf(buf);
ren_base renb(pixf);
@ -147,9 +149,8 @@ namespace mapnik
unsigned r=fill_.red();
unsigned g=fill_.green();
unsigned b=fill_.blue();
//unsigned a=fill_.alpha();
renderer ren(renb);
agg::rasterizer_scanline_aa<> ras;
agg::scanline_u8 sl;
ras.clip_box(0,0,width,height);
@ -160,10 +161,12 @@ namespace mapnik
}
template <typename T>
void agg_renderer<T>::process(line_symbolizer const& sym,Feature const& feature)
void agg_renderer<T>::process(line_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef agg::renderer_base<agg::pixfmt_rgba32> ren_base;
typedef coord_transform<CoordTransform,geometry_type> path_type;
typedef coord_transform2<CoordTransform,geometry_type> path_type;
typedef agg::renderer_outline_aa<ren_base> renderer_oaa;
typedef agg::rasterizer_outline_aa<renderer_oaa> rasterizer_outline_aa;
typedef agg::renderer_scanline_aa_solid<ren_base> renderer;
@ -171,7 +174,7 @@ namespace mapnik
geometry_ptr const& geom=feature.get_geometry();
if (geom && geom->num_points() > 1)
{
path_type path(t_,*geom);
path_type path(t_,*geom,prj_trans);
agg::row_ptr_cache<agg::int8u> buf(pixmap_.raw_data(),
pixmap_.width(),
pixmap_.height(),
@ -277,17 +280,21 @@ namespace mapnik
}
template <typename T>
void agg_renderer<T>::process(point_symbolizer const& sym,Feature const& feature)
void agg_renderer<T>::process(point_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
geometry_ptr const& geom=feature.get_geometry();
if (geom)
{
double x;
double y;
double z=0;
boost::shared_ptr<ImageData32> const& data = sym.get_data();
if ( data )
{
geom->label_position(&x,&y);
prj_trans.backward(x,y,z);
t_.forward(&x,&y);
int w = data->width();
int h = data->height();
@ -307,9 +314,11 @@ namespace mapnik
}
template <typename T>
void agg_renderer<T>::process(line_pattern_symbolizer const& sym,Feature const& feature)
void agg_renderer<T>::process(line_pattern_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform<CoordTransform,geometry_type> path_type;
typedef coord_transform2<CoordTransform,geometry_type> path_type;
typedef agg::line_image_pattern<agg::pattern_filter_bilinear_rgba8> pattern_type;
typedef agg::renderer_base<agg::pixfmt_rgba32> renderer_base;
typedef agg::renderer_outline_image<renderer_base, pattern_type> renderer_type;
@ -321,7 +330,7 @@ namespace mapnik
unsigned width = pixmap_.width();
unsigned height = pixmap_.height();
ImageData32 const& pat = sym.get_pattern();
path_type path(t_,*geom);
path_type path(t_,*geom,prj_trans);
agg::row_ptr_cache<agg::int8u> buf(pixmap_.raw_data(), width, height,width*4);
agg::pixfmt_rgba32 pixf(buf);
renderer_base ren_base(pixf);
@ -336,9 +345,11 @@ namespace mapnik
}
template <typename T>
void agg_renderer<T>::process(polygon_pattern_symbolizer const& sym,Feature const& feature)
void agg_renderer<T>::process(polygon_pattern_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform<CoordTransform,geometry_type> path_type;
typedef coord_transform2<CoordTransform,geometry_type> path_type;
typedef agg::renderer_base<agg::pixfmt_rgba32> ren_base;
typedef agg::wrap_mode_repeat wrap_x_type;
typedef agg::wrap_mode_repeat wrap_y_type;
@ -358,7 +369,7 @@ namespace mapnik
unsigned width = pixmap_.width();
unsigned height = pixmap_.height();
path_type path(t_,*geom);
path_type path(t_,*geom,prj_trans);
agg::row_ptr_cache<agg::int8u> buf(pixmap_.raw_data(),width,height,width * 4);
agg::pixfmt_rgba32 pixf(buf);
@ -389,7 +400,9 @@ namespace mapnik
}
template <typename T>
void agg_renderer<T>::process(raster_symbolizer const& ,Feature const& feature)
void agg_renderer<T>::process(raster_symbolizer const&,
Feature const& feature,
proj_transform const& prj_trans)
{
// TODO -- at the moment raster_symbolizer is an empty class
// used for type dispatching, but we can have some fancy raster
@ -405,9 +418,11 @@ namespace mapnik
}
template <typename T>
void agg_renderer<T>::process(text_symbolizer const& sym ,Feature const& feature)
void agg_renderer<T>::process(text_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform<CoordTransform,geometry_type> path_type;
typedef coord_transform2<CoordTransform,geometry_type> path_type;
geometry_ptr const& geom=feature.get_geometry();
if (geom)
{
@ -416,7 +431,7 @@ namespace mapnik
geom->num_points() > 1)
{
path_type path(t_,*geom);
path_type path(t_,*geom,prj_trans);
double x0,y0,x1,y1;
path.vertex(&x0,&y0);
path.vertex(&x1,&y1);

View file

@ -38,10 +38,11 @@ using boost::shared_ptr;
namespace mapnik
{
Layer::Layer(std::string const& name)
Layer::Layer(std::string const& name, std::string const& srs)
: name_(name),
title_(""),
abstract_(""),
srs_(srs),
minZoom_(0),
maxZoom_(std::numeric_limits<double>::max()),
active_(true),
@ -53,6 +54,7 @@ namespace mapnik
: name_(rhs.name_),
title_(rhs.title_),
abstract_(rhs.abstract_),
srs_(rhs.srs_),
minZoom_(rhs.minZoom_),
maxZoom_(rhs.maxZoom_),
active_(rhs.active_),
@ -119,11 +121,21 @@ namespace mapnik
return abstract_;
}
void Layer::set_srs(std::string const& srs)
{
srs_ = srs;
}
std::string const& Layer::srs() const
{
return srs_;
}
void Layer::add_style(std::string const& stylename)
{
styles_.push_back(stylename);
}
std::vector<std::string> const& Layer::styles() const
{
return styles_;

View file

@ -47,19 +47,24 @@ namespace mapnik
{
using boost::property_tree::ptree;
ptree pt;
read_xml(filename,pt);
boost::optional<std::string> bgcolor =
pt.get_optional<std::string>("Map.<xmlattr>.bgcolor");
if ( bgcolor)
if (bgcolor)
{
Color bg = color_factory::from_string(bgcolor->c_str());
map.setBackground(bg);
}
std::string srs = pt.get<std::string>("Map.<xmlattr>.srs",
"+proj=latlong +datum=WGS84");
map.set_srs(srs);
ptree::const_iterator itr = pt.get_child("Map").begin();
ptree::const_iterator end = pt.get_child("Map").end();
for (; itr != end; ++itr)
{
ptree::value_type const& v = *itr;
@ -284,18 +289,19 @@ namespace mapnik
else if (v.first == "Layer")
{
std::string name = v.second.get<std::string>("<xmlattr>.name","");
Layer lyr(name);
std::string name = v.second.get<std::string>("<xmlattr>.name","Unnamed");
std::string srs = v.second.get<std::string>("<xmlattr>.srs","+proj=latlong +datum=WGS84");
Layer lyr(name, srs);
boost::optional<std::string> status =
v.second.get<std::string>("<xmlattr>.status");
v.second.get_optional<std::string>("<xmlattr>.status");
if (status && *status == "off")
{
lyr.setActive(false);
}
ptree::const_iterator itr2 = v.second.begin();
ptree::const_iterator end2 = v.second.end();

View file

@ -24,6 +24,7 @@
#include <mapnik/style.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/map.hpp>
@ -32,17 +33,18 @@ namespace mapnik
Map::Map()
: width_(400),
height_(400),
srid_(-1) {}
Map::Map(int width,int height,int srid)
srs_("+proj=latlong +datum=WGS84") {}
Map::Map(int width,int height, std::string const& srs)
: width_(width),
height_(height),
srid_(srid),
srs_(srs),
background_(Color(255,255,255)) {}
Map::Map(const Map& rhs)
: width_(rhs.width_),
height_(rhs.height_),
srid_(rhs.srid_),
srs_(rhs.srs_),
background_(rhs.background_),
styles_(rhs.styles_),
layers_(rhs.layers_),
@ -53,12 +55,13 @@ namespace mapnik
if (this==&rhs) return *this;
width_=rhs.width_;
height_=rhs.height_;
srid_=rhs.srid_;
srs_=rhs.srs_;
background_=rhs.background_;
styles_=rhs.styles_;
layers_=rhs.layers_;
return *this;
}
Map::style_iterator Map::begin_styles() const
{
return styles_.begin();
@ -78,10 +81,9 @@ namespace mapnik
styles_.erase(name);
}
feature_type_style const& Map::find_style(std::string const& name) const
feature_type_style const& Map::find_style(std::string const& name) const
{
std::map<std::string,feature_type_style>::const_iterator itr
= styles_.find(name);
std::map<std::string,feature_type_style>::const_iterator itr = styles_.find(name);
if (itr!=styles_.end())
return itr->second;
static feature_type_style default_style;
@ -118,7 +120,6 @@ namespace mapnik
return layers_[index];
}
std::vector<Layer> const& Map::layers() const
{
return layers_;
@ -151,6 +152,7 @@ namespace mapnik
fixAspectRatio();
}
}
void Map::resize(unsigned width,unsigned height)
{
if (width >= MIN_MAPSIZE && width <= MAX_MAPSIZE &&
@ -162,11 +164,16 @@ namespace mapnik
}
}
int Map::srid() const
std::string const& Map::srs() const
{
return srid_;
return srs_;
}
void Map::set_srs(std::string const& srs)
{
srs_ = srs;
}
void Map::setBackground(const Color& c)
{
background_=c;
@ -176,7 +183,7 @@ namespace mapnik
{
return background_;
}
void Map::zoom(double factor)
{
coord2d center = currentExtent_.center();
@ -191,23 +198,50 @@ namespace mapnik
void Map::zoom_all()
{
std::vector<Layer>::const_iterator itr = layers_.begin();
Envelope<double> ext;
bool first = true;
while (itr != layers_.end())
try
{
if (first)
projection proj0(srs_);
Envelope<double> ext;
bool first = true;
std::vector<Layer>::const_iterator itr = layers_.begin();
std::vector<Layer>::const_iterator end = layers_.end();
while (itr != end)
{
ext = itr->envelope();
first = false;
std::string const& layer_srs = itr->srs();
projection proj1(layer_srs);
proj_transform prj_trans(proj0,proj1);
Envelope<double> layerExt = itr->envelope();
double x0 = layerExt.minx();
double y0 = layerExt.miny();
double z0 = 0.0;
double x1 = layerExt.maxx();
double y1 = layerExt.maxy();
double z1 = 0.0;
prj_trans.backward(x0,y0,z0);
prj_trans.backward(x1,y1,z1);
Envelope<double> layerExt2(x0,y0,x1,y1);
std::clog << " layer1 - > " << layerExt << "\n";
std::clog << " layer2 - > " << layerExt2 << "\n";
if (first)
{
ext = layerExt2;
first = false;
}
else
{
ext.expand_to_include(layerExt2);
}
++itr;
}
else
{
ext.expand_to_include(itr->envelope());
}
++itr;
zoomToBox(ext);
}
catch (proj_init_error & ex)
{
std::clog << ex.what() << '\n';
}
zoomToBox(ext);
}
void Map::zoomToBox(const Envelope<double> &box)