1. re-factored placement_finder to be more efficient. 'find_*' methods are templated on PathType.

2. PostGIS plug-in - optional 'multiple_geometries' parameter to control how Multi* geometries built. 
3. MarkersSymbolizer (work in progress) to render vector shapes (markers) alonh a path with collision detection.
This commit is contained in:
Artem Pavlenko 2007-11-02 12:50:15 +00:00
parent 305b76012e
commit 8d51cb421b
20 changed files with 1239 additions and 515 deletions

View File

@ -43,6 +43,7 @@ void export_rule()
using mapnik::raster_symbolizer;
using mapnik::shield_symbolizer;
using mapnik::text_symbolizer;
using mapnik::building_symbolizer;
using mapnik::symbolizer;
using mapnik::symbolizers;
@ -51,6 +52,7 @@ void export_rule()
implicitly_convertible<line_symbolizer,symbolizer>();
implicitly_convertible<line_pattern_symbolizer,symbolizer>();
implicitly_convertible<polygon_symbolizer,symbolizer>();
implicitly_convertible<building_symbolizer,symbolizer>();
implicitly_convertible<polygon_pattern_symbolizer,symbolizer>();
implicitly_convertible<raster_symbolizer,symbolizer>();
implicitly_convertible<shield_symbolizer,symbolizer>();

View File

@ -81,6 +81,9 @@ namespace mapnik {
void process(building_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans);
void process(markers_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans);
private:
T & pixmap_;
unsigned width_;
@ -91,7 +94,7 @@ namespace mapnik {
freetype_engine font_engine_;
face_manager<freetype_engine> font_manager_;
label_collision_detector4 detector_;
placement_finder<label_collision_detector4> finder_;
//placement_finder<label_collision_detector4> finder_;
agg::rasterizer_scanline_aa<> ras_;
};
}

47
include/mapnik/arrow.hpp Normal file
View File

@ -0,0 +1,47 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2006 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
*
*****************************************************************************/
//$Id$
#ifndef ARROW_HPP
#define ARROW_HPP
#include <mapnik/envelope.hpp>
namespace mapnik {
class arrow
{
public:
arrow();
void rewind(unsigned path_id);
unsigned vertex(double* x, double* y);
Envelope<double> extent() const;
private:
unsigned pos_;
double x_[7];
double y_[7];
unsigned cmd_[9];
};
}
#endif // ARROW_HPP

View File

@ -58,7 +58,7 @@ namespace mapnik
{
output_.process(sym,f_,prj_trans_);
}
Processor & output_;
Feature const& f_;
proj_transform const& prj_trans_;

View File

@ -0,0 +1,166 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2006 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
*
*****************************************************************************/
//$Id$
#ifndef MARKERS_CONVERTER_HPP
#define MARKERS_CONVERTER_HPP
#include "agg_basics.h"
#include "agg_trans_affine.h"
#include <boost/utility.hpp>
namespace mapnik {
template <typename Locator, typename Shape, typename Detector>
class markers_converter : boost::noncopyable
{
public:
markers_converter(Locator & locator,Shape & shape, Detector & detector);
void rewind(unsigned path_id);
unsigned vertex(double * x, double * y);
private:
enum status_e
{
initial,
markers,
polygon,
stop
};
Locator & locator_;
Shape & shape_;
Detector & detector_;
status_e status_;
agg::trans_affine transform_;
agg::trans_affine mtx_;
unsigned marker_;
unsigned num_markers_;
};
template <typename Locator,typename Shape,typename Detector>
markers_converter<Locator,Shape,Detector>::markers_converter(Locator & locator,Shape & shape,
Detector & detector)
: locator_(locator),
shape_(shape),
detector_(detector),
status_(initial),
num_markers_(1),
marker_(0) {}
template <typename Locator, typename Shape,typename Detector>
void markers_converter<Locator,Shape,Detector>::rewind(unsigned path_id)
{
status_ = initial;
marker_ = 0;
num_markers_ = 1;
}
template <typename Locator, typename Shape, typename Detector>
unsigned markers_converter<Locator,Shape,Detector>::vertex( double * x, double * y)
{
unsigned cmd = agg::path_cmd_move_to;
double x1, y1, x2, y2;
while (!agg::is_stop(cmd))
{
switch (status_)
{
case initial:
if (num_markers_ == 0 )
{
cmd = agg::path_cmd_stop;
break;
}
locator_.rewind(marker_++);
status_ = markers;
num_markers_ = 0;
break;
case markers:
{
unsigned cmd1;
while (agg::is_move_to(cmd1 = locator_.vertex(&x1,&y1)));
if (agg::is_stop(cmd1))
{
status_ = stop;
break;
}
unsigned cmd2 = locator_.vertex(&x2,&y2);
if (agg::is_stop(cmd2))
{
status_ = stop;
break;
}
++num_markers_;
double dx = x2 - x1;
double dy = y2 - y1;
double d = ::sqrt(dx * dx + dy * dy);
Envelope<double> ext = shape_.extent();
if (d > ext.width())
{
mtx_ = transform_;
mtx_ *= agg::trans_affine_rotation(::atan2(dy,dx));
double marker_x = x1 + dx * 0.5;
double marker_y = y1 + dy * 0.5;
mtx_ *= agg::trans_affine_translation(marker_x,marker_y);
double minx = ext.minx();
double miny = ext.miny();
double maxx = ext.maxx();
double maxy = ext.maxy();
mtx_.transform(&minx,&miny);
mtx_.transform(&maxx,&maxy);
Envelope<double> e0(minx,miny,maxx,maxy);
if (detector_.has_placement(e0))
{
shape_.rewind(0);
status_ = polygon;
detector_.insert(ext);
}
}
break;
}
case polygon:
cmd = shape_.vertex(x,y);
if (agg::is_stop(cmd))
{
cmd = agg::path_cmd_move_to;
status_ = markers;
break;
}
mtx_.transform(x,y);
return cmd;
case stop:
cmd = agg::path_cmd_stop;
break;
}
}
return cmd;
}
}
#endif // MARKERS_CONVERTER_HPP

View File

@ -0,0 +1,41 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2006 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
*
*****************************************************************************/
//$Id$
#ifndef MARKERS_SYMBOLIZER_HPP
#define MARKERS_SYMBOLIZER_HPP
namespace mapnik {
struct MAPNIK_DECL markers_symbolizer
{
public:
markers_symbolizer()
: allow_overlap_(false) {}
private:
bool allow_overlap_;
};
}
#endif // MARKERS_SYMBOLIZER_HPP

View File

@ -29,6 +29,7 @@
#include <mapnik/ctrans.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/text_symbolizer.hpp>
#include <mapnik/shield_symbolizer.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/text_path.hpp>
@ -39,33 +40,24 @@ namespace mapnik
typedef text_path placement_element;
struct placement : boost::noncopyable
{
typedef coord_transform2<CoordTransform,geometry2d> path_type;
{
placement(string_info & info_,
//path_type & shape_path_,
shield_symbolizer const& sym);
template <typename SymbolizerT>
placement(string_info *info_,
CoordTransform *ctrans_,
const proj_transform *proj_trans_,
geometry2d const& geom_,
SymbolizerT const& sym);
placement(string_info & info_,
//path_type & shape_path_,
text_symbolizer const& sym);
~placement();
//helpers
std::pair<double, double> get_position_at_distance(double target_distance);
double get_total_distance();
void clear_envelopes();
unsigned path_size() const;
//std::pair<double, double> get_position_at_distance(double target_distance);
//double get_total_distance();
string_info *info;
CoordTransform *ctrans;
const proj_transform *proj_trans;
geometry2d const& geom;
path_type shape_path;
double total_distance_; //cache for distance
string_info & info;
//path_type & shape_path;
//double total_distance_; //cache for distance
position displacement_;
label_placement_e label_placement;
@ -84,33 +76,47 @@ namespace mapnik
double max_char_angle_delta;
double minimum_distance;
bool avoid_edges;
bool has_dimensions;
std::pair<double, double> dimensions;
};
template <typename DetectorT>
class placement_finder : boost::noncopyable
{
public:
//e is the dimensions of the map, buffer is the buffer used for collission detection.
//e is the dimensions of the map, buffer is the buffer used for collision detection.
placement_finder(DetectorT & detector,Envelope<double> const& e);
void find_placements(placement *p);
template <typename T>
void find_placements(placement & p, T & path);
void find_point_placement(placement & p, double, double);
template <typename T>
void find_placements_with_spacing(placement & p, T & path);
void clear();
protected:
bool find_placement_follow(placement *p);
bool find_placement_horizontal(placement *p);
bool build_path_follow(placement *p, double target_distance);
bool build_path_horizontal(placement *p, double target_distance);
std::vector<double> get_ideal_placements(placement *p);
void update_detector(placement *p);
private:
template <typename T>
bool find_placement_follow(placement & p, T & path);
template <typename T>
bool find_placement_horizontal(placement & p, T & path);
template <typename T>
bool build_path_follow(placement & p, double target_distance, T & path);
template <typename T>
bool build_path_horizontal(placement & p, double target_distance, T & path);
void get_ideal_placements(placement & p, double distance, std::vector<double>&);
void update_detector(placement & p);
DetectorT & detector_;
Envelope<double> dimensions_;
Envelope<double> const& dimensions_;
};
}

View File

@ -31,8 +31,10 @@
#include <mapnik/raster_symbolizer.hpp>
#include <mapnik/shield_symbolizer.hpp>
#include <mapnik/text_symbolizer.hpp>
#include <mapnik/markers_symbolizer.hpp>
#include <mapnik/filter.hpp>
#include <mapnik/filter_visitor.hpp>
// boost
#include <boost/shared_ptr.hpp>
#include <boost/variant.hpp>
@ -94,6 +96,11 @@ namespace mapnik
return (&lhs == &rhs);
}
inline bool operator==(markers_symbolizer const& lhs,
markers_symbolizer const& rhs)
{
return (&lhs == &rhs);
}
typedef boost::variant<point_symbolizer,
line_symbolizer,
line_pattern_symbolizer,
@ -102,7 +109,8 @@ namespace mapnik
raster_symbolizer,
shield_symbolizer,
text_symbolizer,
building_symbolizer> symbolizer;
building_symbolizer,
markers_symbolizer> symbolizer;
typedef std::vector<symbolizer> symbolizers;

View File

@ -66,17 +66,17 @@ namespace mapnik
characters_.push_back(new character_info(c, width, height));
}
unsigned num_characters()
unsigned num_characters() const
{
return characters_.size();
}
character_info at(unsigned i)
character_info at(unsigned i) const
{
return characters_[i];
}
character_info operator[](unsigned i)
character_info operator[](unsigned i) const
{
return at(i);
}
@ -87,12 +87,13 @@ namespace mapnik
height_ = height;
}
std::pair<double, double> get_dimensions()
std::pair<double, double> get_dimensions() const
{
return std::pair<double, double>(width_, height_);
}
std::wstring get_string() {
std::wstring const& get_string() const
{
return string_;
}
};

View File

@ -33,7 +33,7 @@ namespace mapnik
class MAPNIK_DECL geometry_utils
{
public:
static void from_wkb(Feature & feature,const char* wkb, unsigned size);
static void from_wkb(Feature & feature,const char* wkb, unsigned size, bool multiple_geometries = false);
private:
geometry_utils();
geometry_utils(geometry_utils const&);

View File

@ -22,14 +22,21 @@
//$Id: postgis.cc 44 2005-04-22 18:53:54Z pavlenko $
// mapnik
#include "connection_manager.hpp"
#include "postgis.hpp"
#include <mapnik/ptree_helpers.hpp>
// boost
#include <boost/lexical_cast.hpp>
// stl
#include <string>
#include <algorithm>
#include <set>
#include <sstream>
#include <iomanip>
#include <boost/lexical_cast.hpp>
#include "connection_manager.hpp"
#include "postgis.hpp"
DATASOURCE_PLUGIN(postgis_datasource)
@ -61,7 +68,9 @@ postgis_datasource::postgis_datasource(parameters const& params)
boost::optional<int> initial_size = params_.get<int>("inital_size",1);
boost::optional<int> max_size = params_.get<int>("max_size",10);
multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false);
ConnectionManager *mgr=ConnectionManager::instance();
mgr->registerPool(creator_, *initial_size, *max_size);
@ -194,7 +203,7 @@ featureset_ptr postgis_datasource::features(const query& q) const
std::clog << s.str() << "\n";
#endif
shared_ptr<ResultSet> rs=conn->executeQuery(s.str(),1);
return featureset_ptr(new postgis_featureset(rs,desc_.get_encoding(),props.size()));
return featureset_ptr(new postgis_featureset(rs,desc_.get_encoding(),multiple_geometries_,props.size()));
}
}
return featureset_ptr();
@ -233,7 +242,7 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt) const
std::clog << s.str() << "\n";
#endif
shared_ptr<ResultSet> rs=conn->executeQuery(s.str(),1);
return featureset_ptr(new postgis_featureset(rs,desc_.get_encoding(),size));
return featureset_ptr(new postgis_featureset(rs,desc_.get_encoding(),multiple_geometries_, size));
}
}
return featureset_ptr();

View File

@ -62,6 +62,7 @@ class postgis_datasource : public datasource
mutable mapnik::Envelope<double> extent_;
layer_descriptor desc_;
ConnectionCreator<Connection> creator_;
bool multiple_geometries_;
static const std::string name_;
public:
static std::string name();
@ -82,6 +83,7 @@ class postgis_featureset : public mapnik::Featureset
{
private:
boost::shared_ptr<ResultSet> rs_;
bool multiple_geometries_;
unsigned num_attrs_;
boost::scoped_ptr<mapnik::transcoder> tr_;
mutable int totalGeomSize_;
@ -89,6 +91,7 @@ class postgis_featureset : public mapnik::Featureset
public:
postgis_featureset(boost::shared_ptr<ResultSet> const& rs,
std::string const& encoding,
bool multiple_geometries,
unsigned num_attrs);
feature_ptr next();
~postgis_featureset();

View File

@ -39,8 +39,10 @@ using mapnik::geometry_utils;
postgis_featureset::postgis_featureset(boost::shared_ptr<ResultSet> const& rs,
std::string const& encoding,
bool multiple_geometries,
unsigned num_attrs=0)
: rs_(rs),
multiple_geometries_(multiple_geometries),
num_attrs_(num_attrs),
tr_(new transcoder(encoding)),
totalGeomSize_(0),
@ -53,7 +55,7 @@ feature_ptr postgis_featureset::next()
feature_ptr feature(new Feature(count_));
int size=rs_->getFieldLength(0);
const char *data = rs_->getValue(0);
geometry_utils::from_wkb(*feature,data,size);
geometry_utils::from_wkb(*feature,data,size,multiple_geometries_);
totalGeomSize_+=size;
for (unsigned pos=1;pos<num_attrs_+1;++pos)

View File

@ -67,6 +67,7 @@ source = Split(
memory_datasource.cpp
stroke.cpp
symbolizer.cpp
arrow.cpp
"""
)

View File

@ -23,19 +23,17 @@
// mapnik
#include <mapnik/agg_renderer.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/placement_finder.hpp>
#include <mapnik/markers_converter.hpp>
#include <mapnik/arrow.hpp>
// agg
#include "agg_basics.h"
//#include "agg_rendering_buffer.h"
//#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_p.h"
#include "agg_scanline_u.h"
#include "agg_renderer_scanline.h"
//#include "agg_pixfmt_rgba.h"
#include "agg_path_storage.h"
#include "agg_span_allocator.h"
#include "agg_span_pattern_rgba.h"
@ -43,11 +41,11 @@
#include "agg_conv_stroke.h"
#include "agg_conv_dash.h"
#include "agg_conv_contour.h"
#include "agg_conv_clip_polyline.h"
#include "agg_vcgen_stroke.h"
#include "agg_conv_adaptor_vcgen.h"
#include "agg_conv_smooth_poly1.h"
#include "agg_conv_marker.h"
#include "agg_arrowhead.h"
#include "agg_vcgen_markers_term.h"
#include "agg_renderer_outline_aa.h"
#include "agg_rasterizer_outline_aa.h"
@ -59,6 +57,7 @@
#include "agg_pattern_filters_rgba.h"
#include "agg_renderer_outline_image.h"
#include "agg_vpgen_clip_polyline.h"
#include "agg_arrowhead.h"
// boost
#include <boost/utility.hpp>
@ -107,8 +106,8 @@ namespace mapnik
t_(m.getWidth(),m.getHeight(),m.getCurrentExtent(),offset_x,offset_y),
font_engine_(),
font_manager_(font_engine_),
detector_(Envelope<double>(-64 ,-64, m.getWidth() + 64 ,m.getHeight() + 64)),
finder_(detector_,Envelope<double>(0 ,0, m.getWidth(), m.getHeight()))
detector_(Envelope<double>(-64 ,-64, m.getWidth() + 64 ,m.getHeight() + 64))
//finder_(detector_,Envelope<double>(0 ,0, m.getWidth(), m.getHeight()))
{
boost::optional<Color> bg = m.background();
if (bg) pixmap_.setBackground(*bg);
@ -144,7 +143,7 @@ namespace mapnik
#endif
if (lay.clear_label_cache())
{
finder_.clear();
//finder_.clear(); // FIXME!!!!!!!!
}
}
@ -165,7 +164,7 @@ namespace mapnik
typedef agg::renderer_base<agg::pixfmt_rgba32> ren_base;
typedef agg::renderer_scanline_aa_solid<ren_base> renderer;
Color const& fill_ = sym.get_fill();
Color const& fill_ = sym.get_fill();
ras_.reset();
agg::scanline_u8 sl;
ren_base renb(pixf_);
@ -178,8 +177,12 @@ namespace mapnik
geometry2d const& geom=feature.get_geometry(i);
if (geom.num_points() > 2)
{
path_type path(t_,geom,prj_trans);
path_type path(t_,geom,prj_trans);
//agg::conv_smooth_poly1<path_type> smooth(path);
//smooth.smooth_value(0.6);
//agg::conv_curve<agg::conv_smooth_poly1<path_type> > curve(smooth);
ras_.add_path(path);
//ras_.add_path(curve);
}
}
ren.color(agg::rgba8(r, g, b, int(255 * sym.get_opacity())));
@ -229,7 +232,7 @@ namespace mapnik
for (unsigned j=1;j<geom.num_points();++j)
{
double x,y;
unsigned cm = geom.vertex(&x,&y);
cm = geom.vertex(&x,&y);
if (cm == SEG_MOVETO)
{
frame->move_to(x,y);
@ -367,7 +370,6 @@ namespace mapnik
else
{
agg::conv_stroke<path_type> stroke(path);
line_join_e join=stroke_.get_line_join();
if ( join == MITER_JOIN)
stroke.generator().line_join(agg::miter_join);
@ -437,6 +439,7 @@ namespace mapnik
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform2<CoordTransform,geometry2d> path_type;
std::wstring text = feature[sym.get_name()].to_unicode();
boost::shared_ptr<ImageData32> const& data = sym.get_image();
if (text.length() > 0 && data)
@ -449,17 +452,21 @@ namespace mapnik
ren.set_fill(sym.get_fill());
string_info info(text);
ren.get_string_info(&info);
Envelope<double> box(-64,-64,width_+64,height_+64);
placement_finder<label_collision_detector4> finder(detector_,box);
unsigned num_geom = feature.num_geometries();
for (unsigned i=0;i<num_geom;++i)
{
geometry2d const& geom = feature.get_geometry(i);
if (geom.num_points() > 0) // don't bother with empty geometries
{
placement text_placement(&info, &t_, &prj_trans, geom, sym);
path_type path(t_,geom,prj_trans);
placement text_placement(info, sym);
text_placement.avoid_edges = sym.get_avoid_edges();
finder.find_placements<path_type>(text_placement,path);
finder_.find_placements(&text_placement);
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ ii)
{
int w = data->width();
@ -589,12 +596,53 @@ namespace mapnik
}
}
template <typename T>
void agg_renderer<T>::process(markers_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform2<CoordTransform,geometry2d> path_type;
typedef agg::renderer_base<agg::pixfmt_rgba32> ren_base;
typedef agg::renderer_scanline_aa_solid<ren_base> renderer;
arrow arrow_;
//double k = ::pow(1.2, 0.7);
//arrow_.head(4 * k, 4 * k, 3 * k, 2 * k);
//Color const& fill_ = sym.get_fill();
ras_.reset();
agg::scanline_u8 sl;
ren_base renb(pixf_);
unsigned r = 0;// fill_.red();
unsigned g = 0; //fill_.green();
unsigned b = 255; //fill_.blue();
renderer ren(renb);
for (unsigned i=0;i<feature.num_geometries();++i)
{
geometry2d const& geom=feature.get_geometry(i);
if (geom.num_points() > 1)
{
path_type path(t_,geom,prj_trans);
agg::conv_dash <path_type> dash(path);
dash.add_dash(20.0,200.0);
//dash.dash_start(100.0);
markers_converter<agg::conv_dash<path_type>,
arrow,
label_collision_detector4>
marker(dash, arrow_, detector_);
ras_.add_path(marker);
}
}
ren.color(agg::rgba8(r, g, b, 255));
agg::render_scanlines(ras_, sl, ren);
}
template <typename T>
void agg_renderer<T>::process(text_symbolizer const& sym,
Feature const& feature,
proj_transform const& prj_trans)
{
typedef coord_transform2<CoordTransform,geometry2d> path_type;
std::wstring text = feature[sym.get_name()].to_unicode();
if ( text.length() > 0 )
{
@ -608,7 +656,9 @@ namespace mapnik
ren.set_halo_fill(sym.get_halo_fill());
ren.set_halo_radius(sym.get_halo_radius());
Envelope<double> ext = t_.extent();
Envelope<double> box(-64,-64,width_+64,height_+64);
placement_finder<label_collision_detector4> finder(detector_,box);
string_info info(text);
ren.get_string_info(&info);
unsigned num_geom = feature.num_geometries();
@ -617,38 +667,31 @@ namespace mapnik
geometry2d const& geom = feature.get_geometry(i);
if (geom.num_points() > 0) // don't bother with empty geometries
{
//agg::vpgen_clip_polyline clipped_path;
// clip to the bbox
path_type path(t_,geom,prj_trans);
//agg::conv_clip_polyline<path_type> clipped_path(path);
//clipped_path.clip_box(0,0,width_,height_);
//placement<agg::conv_clip_polyline<path_type> >
// text_placement(&info, &t_, &prj_trans, clipped_path, sym);
//placement_finder<agg::conv_clip_polyline<path_type>,
// label_collision_detector4> finder(detector_,box);
placement text_placement(info,sym);
if (sym.get_label_placement() == POINT_PLACEMENT)
{
double label_x, label_y, z=0.0;
geom.label_position(&label_x, &label_y);
prj_trans.backward(label_x,label_y, z);
t_.forward(&label_x,&label_y);
finder.find_point_placement(text_placement,label_x,label_y);
}
else if (sym.get_label_spacing() > 0 )
{
finder.find_placements_with_spacing<path_type>(text_placement,path);
}
else
{
finder.find_placements<path_type>(text_placement,path);
}
//clipped_path.clip_box(ext.minx(),ext.miny(),ext.maxx(),ext.maxy());
//for (unsigned j=0;j<geom.num_points();++j)
//{
// double x,y;
/// unsigned c = geom.vertex(&x,&y);
// if (c == SEG_MOVETO)
// clipped_path.move_to(x,y);
// else if (c == SEG_LINETO)
// clipped_path.line_to(x,y);
//}
//line_string_impl line;
//while (1)
//{
// double x,y;
// unsigned cmd = clipped_path.vertex(&x,&y);
// if (cmd == SEG_END) break;
// else if (cmd == SEG_MOVETO)
// {
// line.move_to(x,y);
// }
// else if (cmd == SEG_LINETO)
// {
// line.line_to(x,y);
// }
//}
placement text_placement(&info, &t_, &prj_trans, geom, sym);
finder_.find_placements(&text_placement);
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ii)
{
double x = text_placement.placements[ii].starting_x;

66
src/arrow.cpp Normal file
View File

@ -0,0 +1,66 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2006 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
*
*****************************************************************************/
//$Id$
#include <mapnik/arrow.hpp>
#include <agg_basics.h>
namespace mapnik {
arrow::arrow()
: pos_(0)
{
x_[0] = -7.0; y_[0] = 1.0; cmd_[0] = agg::path_cmd_move_to;
x_[1] = 1.0; y_[1] = 1.0; cmd_[1] = agg::path_cmd_line_to;
x_[2] = 1.0; y_[2] = 3.0; cmd_[2] = agg::path_cmd_line_to;
x_[3] = 7.0; y_[3] = 0.0; cmd_[3] = agg::path_cmd_line_to;
x_[4] = 1.0; y_[4] =-3.0; cmd_[4] = agg::path_cmd_line_to;
x_[5] = 1.0; y_[5] =-1.0; cmd_[5] = agg::path_cmd_line_to;
x_[6] = -7.0; y_[6] =-1.0; cmd_[6] = agg::path_cmd_line_to;
cmd_[7] = agg::path_cmd_end_poly | agg::path_flags_close | agg::path_flags_ccw;
cmd_[8] = agg::path_cmd_stop;
}
void arrow::rewind(unsigned )
{
pos_ = 0;
}
unsigned arrow::vertex(double* x, double* y)
{
if(pos_ < 7 )
{
*x = x_[pos_];
*y = y_[pos_];
return cmd_[pos_++];
}
return agg::path_cmd_stop;
}
Envelope<double> arrow::extent() const
{
return Envelope<double>(-7,-3,7,3);
}
}

View File

@ -77,6 +77,7 @@ namespace mapnik
void parse_line_symbolizer( rule_type & rule, ptree const & sym);
void parse_polygon_symbolizer( rule_type & rule, ptree const & sym);
void parse_building_symbolizer( rule_type & rule, ptree const & sym );
void parse_markers_symbolizer( rule_type & rule, ptree const & sym );
void ensure_font_face( const text_symbolizer & text_symbol );
@ -364,6 +365,11 @@ namespace mapnik
{
rule.append(raster_symbolizer());
}
else if ( sym.first == "MarkersSymbolizer")
{
rule.append(markers_symbolizer());
}
else if ( sym.first != "MinScaleDenominator" &&
sym.first != "MaxScaleDenominator" &&
sym.first != "Filter" &&
@ -584,7 +590,15 @@ namespace mapnik
{
text_symbol.set_allow_overlap( * allow_overlap );
}
// max_char_angle_delta
optional<double> max_char_angle_delta =
get_opt_attr<double>(sym, "max_char_angle_delta");
if (max_char_angle_delta)
{
text_symbol.set_max_char_angle_delta( * max_char_angle_delta);
}
if ( strict_ )
{
ensure_font_face( text_symbol );

File diff suppressed because it is too large Load Diff

View File

@ -176,6 +176,11 @@ namespace mapnik
set_css( sym_node, "fill-opacity", sym.get_opacity() );
}
}
void operator () ( markers_symbolizer const& )
{
// FIXME!!!!!
}
private:
serialize_symbolizer();
void add_image_attributes(ptree & node, const symbolizer_with_image & sym)

View File

@ -70,7 +70,7 @@ namespace mapnik
~wkb_reader() {}
void read(Feature & feature)
void read_multi(Feature & feature)
{
int type=read_integer();
switch (type)
@ -99,6 +99,36 @@ namespace mapnik
break;
}
}
void read(Feature & feature)
{
int type=read_integer();
switch (type)
{
case wkbPoint:
read_point(feature);
break;
case wkbLineString:
read_linestring(feature);
break;
case wkbPolygon:
read_polygon(feature);
break;
case wkbMultiPoint:
read_multipoint_2(feature);
break;
case wkbMultiLineString:
read_multilinestring_2(feature);
break;
case wkbMultiPolygon:
read_multipolygon_2(feature);
break;
case wkbGeometryCollection:
break;
default:
break;
}
}
private:
wkb_reader(const wkb_reader&);
@ -189,6 +219,20 @@ namespace mapnik
}
}
void read_multipoint_2(Feature & feature)
{
geometry2d * pt = new point<vertex2d>;
int num_points = read_integer();
for (int i=0;i<num_points;++i)
{
pos_+=5;
double x = read_double();
double y = read_double();
pt->move_to(x,y);
}
feature.add_geometry(pt);
}
void read_linestring(Feature & feature)
{
geometry2d * line = new line_string<vertex2d>;
@ -214,17 +258,41 @@ namespace mapnik
}
}
void read_multilinestring_2(Feature & feature)
{
geometry2d * line = new line_string<vertex2d>;
int num_lines=read_integer();
unsigned capacity = 0;
for (int i=0;i<num_lines;++i)
{
pos_+=5;
int num_points=read_integer();
capacity+=num_points;
CoordinateArray ar(num_points);
read_coords(ar);
line->set_capacity(capacity);
line->move_to(ar[0].x,ar[0].y);
for (int i=1;i<num_points;++i)
{
line->line_to(ar[i].x,ar[i].y);
}
}
feature.add_geometry(line);
}
void read_polygon(Feature & feature)
{
geometry2d * poly = new polygon<vertex2d>;
int num_rings=read_integer();
unsigned capacity = 0;
for (int i=0;i<num_rings;++i)
{
int num_points=read_integer();
capacity+=num_points;
CoordinateArray ar(num_points);
read_coords(ar);
poly->set_capacity(capacity);
poly->move_to(ar[0].x,ar[0].y);
for (int j=1;j<num_points;++j)
{
poly->line_to(ar[j].x,ar[j].y);
@ -243,11 +311,42 @@ namespace mapnik
read_polygon(feature);
}
}
void read_multipolygon_2(Feature & feature)
{
geometry2d * poly = new polygon<vertex2d>;
int num_polys=read_integer();
unsigned capacity = 0;
for (int i=0;i<num_polys;++i)
{
pos_+=5;
int num_rings=read_integer();
for (int i=0;i<num_rings;++i)
{
int num_points=read_integer();
capacity += num_points;
CoordinateArray ar(num_points);
read_coords(ar);
poly->set_capacity(capacity);
poly->move_to(ar[0].x,ar[0].y);
for (int j=1;j<num_points;++j)
{
poly->line_to(ar[j].x,ar[j].y);
}
poly->line_to(ar[0].x,ar[0].y);
}
}
feature.add_geometry(poly);
}
};
void geometry_utils::from_wkb(Feature & feature,const char* wkb, unsigned size)
void geometry_utils::from_wkb(Feature & feature,const char* wkb, unsigned size, bool multiple_geometries)
{
wkb_reader reader(wkb,size);
return reader.read(feature);
if (multiple_geometries)
return reader.read_multi(feature);
else
return reader.read(feature);
}
}