Simplify code by always returning the same data type no matter what placement type is used.

This commit is contained in:
Hermann Kraus 2012-08-03 01:42:18 +02:00
parent b062af211a
commit 2b6cc00806
9 changed files with 209 additions and 114 deletions

View file

@ -1,3 +1,24 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 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_PATH_PROCESSOR_HPP
#define MAPNIK_PATH_PROCESSOR_HPP

View file

@ -58,14 +58,13 @@ public:
/** Return next placement.
* If no more placements are found false is returned.
*/
glyph_positions_ptr next();
placements_list const& get();
protected:
glyph_positions_ptr next_point_placement();
glyph_positions_ptr next_line_placement();
bool next_point_placement();
bool next_line_placement();
void initialize_geometries();
void initialize_points();
void update_detector(glyph_positions_ptr glyphs);
//Input
text_symbolizer const& sym_;

View file

@ -25,14 +25,11 @@
//mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/text/glyph_info.hpp>
#include <mapnik/text/layout.hpp>
#include <mapnik/text_placements/base.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/text/placements_list.hpp>
//stl
#include <vector>
#include <list>
//boost
#include <boost/utility.hpp>
@ -47,48 +44,6 @@ typedef label_collision_detector4 DetectorType;
class feature_impl;
typedef feature_impl Feature;
struct glyph_position
{
glyph_position(glyph_info const& glyph, pixel_position const& pos, double angle)
: glyph(&glyph), pos(pos), angle(angle) { }
glyph_info const* glyph;
pixel_position pos;
double angle;
};
/** Stores positions of glphys.
*
* The actual glyphs and their format is stored in text_layout.
*/
class glyph_positions
{
public:
typedef std::vector<glyph_position>::const_iterator const_iterator;
glyph_positions();
const_iterator begin() const;
const_iterator end() const;
void push_back(glyph_info const& glyph, pixel_position offset, double angle);
/** Is each character rotated by the same angle?
* This function is used to avoid costly trigonometric function calls when not necessary. */
bool is_constant_angle() const;
double get_angle() const;
pixel_position const& get_base_point() const;
void set_base_point(pixel_position base_point);
private:
std::vector<glyph_position> data_;
pixel_position base_point_;
double angle_;
bool const_angle_;
};
typedef boost::shared_ptr<glyph_positions> glyph_positions_ptr;
typedef std::list<glyph_positions_ptr> placements_list;
typedef boost::shared_ptr<placements_list> placements_list_ptr;
class placement_finder_ng : boost::noncopyable
{
public:
@ -100,15 +55,17 @@ public:
double scale_factor);
/** Try to place a single label at the given point. */
glyph_positions_ptr find_point_placement(pixel_position pos);
bool find_point_placement(pixel_position pos);
/** Iterate over the given path, placing line-following labels with respect to label_spacing. */
template <typename T>
placements_list_ptr find_line_placements(T & path);
bool find_line_placements(T & path);
/** Iterate over the given path, placing point labels with respect to label_spacing. */
template <typename T>
placements_list_ptr find_point_on_line_placements(T & path);
bool find_point_on_line_placements(T & path);
/** Try next position alternative from placement_info. */
bool next_position();
placements_list const& placements() const;
private:
void init_alignment();
pixel_position alignment_offset() const;
@ -127,6 +84,8 @@ private:
horizontal_alignment_e halign_;
justify_alignment_e jalign_;
double scale_factor_;
placements_list placements_;
};
typedef boost::shared_ptr<placement_finder_ng> placement_finder_ng_ptr;

View file

@ -0,0 +1,94 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 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_PLACEMENTS_LIST_HPP
#define MAPNIK_PLACEMENTS_LIST_HPP
//mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/text/glyph_info.hpp>
//stl
#include <vector>
#include <list>
namespace mapnik
{
struct glyph_info;
struct glyph_position
{
glyph_position(glyph_info const& glyph, pixel_position const& pos, double angle)
: glyph(&glyph), pos(pos), angle(angle) { }
glyph_info const* glyph;
pixel_position pos;
double angle;
};
/** Stores positions of glphys.
*
* The actual glyphs and their format is stored in text_layout.
*/
class glyph_positions
{
public:
typedef std::vector<glyph_position>::const_iterator const_iterator;
glyph_positions();
const_iterator begin() const;
const_iterator end() const;
void push_back(glyph_info const& glyph, pixel_position offset, double angle);
/** Is each character rotated by the same angle?
* This function is used to avoid costly trigonometric function calls when not necessary. */
bool is_constant_angle() const;
double get_angle() const;
pixel_position const& get_base_point() const;
void set_base_point(pixel_position base_point);
private:
std::vector<glyph_position> data_;
pixel_position base_point_;
double angle_;
bool const_angle_;
};
typedef boost::shared_ptr<glyph_positions> glyph_positions_ptr;
#if 0
class placements_list
{
public:
placements_list();
void push_back(glyph_positions_ptr glyphs);
typedef std::list<glyph_positions_ptr> list_type;
typedef list_type::const_iterator const_iterator;
const_iterator begin() const;
const_iterator end() const;
private:
list_type placements_;
};
#endif
typedef std::list<glyph_positions_ptr> placements_list;
}
#endif // PLACEMENTS_LIST_HPP

View file

@ -25,6 +25,7 @@
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/symbolizer_helpers.hpp>
#include <mapnik/text/renderer.hpp>
#include <boost/foreach.hpp>
namespace mapnik {
@ -43,8 +44,8 @@ void agg_renderer<T>::process(text_symbolizer const& sym,
text_renderer<T> ren(*current_buffer_, font_manager_, sym.comp_op(), scale_factor_);
glyph_positions_ptr glyphs;
while ((glyphs = helper.next()))
placements_list const& placements = helper.get();
BOOST_FOREACH(glyph_positions_ptr glyphs, placements)
{
ren.render(glyphs);
}

View file

@ -1485,8 +1485,8 @@ void cairo_renderer_base::process(text_symbolizer const& sym,
cairo_context context(context_);
context.set_operator(sym.comp_op());
glyph_positions_ptr glyphs;
while ((glyphs = helper.next()))
placements_list const& placements = helper.get();
BOOST_FOREACH(glyph_positions_ptr glyphs, placements)
{
context.add_text(glyphs, face_manager_, font_manager_, scale_factor_);
}

View file

@ -50,23 +50,28 @@ text_symbolizer_helper<FaceManagerT, DetectorT>::text_symbolizer_helper(const te
}
template <typename FaceManagerT, typename DetectorT>
glyph_positions_ptr text_symbolizer_helper<FaceManagerT, DetectorT>::next()
placements_list const& text_symbolizer_helper<FaceManagerT, DetectorT>::get()
{
if (point_placement_)
return next_point_placement();
{
while (next_point_placement());
}
else
return next_line_placement();
{
while (next_line_placement());
}
return finder_.placements();
}
template <typename FaceManagerT, typename DetectorT>
glyph_positions_ptr text_symbolizer_helper<FaceManagerT, DetectorT>::next_line_placement()
bool text_symbolizer_helper<FaceManagerT, DetectorT>::next_line_placement()
{
while (!geometries_to_process_.empty())
{
if (geo_itr_ == geometries_to_process_.end())
{
//Just processed the last geometry. Try next placement.
if (!finder_.next_position()) return glyph_positions_ptr(); //No more placements
if (!finder_.next_position()) return false; //No more placements
//Start again from begin of list
geo_itr_ = geometries_to_process_.begin();
continue; //Reexecute size check
@ -79,51 +84,43 @@ glyph_positions_ptr text_symbolizer_helper<FaceManagerT, DetectorT>::next_line_p
clipped.clip_box(query_extent_.minx(), query_extent_.miny(),
query_extent_.maxx(), query_extent_.maxy());
path_type path(t_, clipped, prj_trans_);
glyph_positions_ptr glyphs;
bool success;
if (points_on_line_) {
#if 0
finder_.find_point_on_line_placements(path);
#endif
success = finder_.find_point_on_line_placements(path);
} else {
glyphs = finder_.find_line_placements(path);
success = finder_.find_line_placements(path);
}
if (glyphs)
if (success)
{
//Found a placement
#if 0
if (points_on_line_)
{
finder_->update_detector();
}
geo_itr_ = geometries_to_process_.erase(geo_itr_);
#if 0
if (writer_.first) writer_.first->add_text(
finder_->get_results(), finder_->get_extents(),
feature_, t_, writer_.second);
#endif
return glyphs;
#endif
return true;
}
//No placement for this geometry. Keep it in geometries_to_process_ for next try.
geo_itr_++;
}
return glyph_positions_ptr();
return false;
}
template <typename FaceManagerT, typename DetectorT>
glyph_positions_ptr text_symbolizer_helper<FaceManagerT, DetectorT>::next_point_placement()
bool text_symbolizer_helper<FaceManagerT, DetectorT>::next_point_placement()
{
while (!points_.empty())
{
if (point_itr_ == points_.end())
{
//Just processed the last point. Try next placement.
if (!finder_.next_position()) return glyph_positions_ptr(); //No more placements
if (!finder_.next_position()) return false; //No more placements
//Start again from begin of list
point_itr_ = points_.begin();
continue; //Reexecute size check
}
glyph_positions_ptr glyphs = finder_.find_point_placement(*point_itr_);
if (glyphs)
if (finder_.find_point_placement(*point_itr_))
{
//Found a placement
point_itr_ = points_.erase(point_itr_);
@ -132,13 +129,12 @@ glyph_positions_ptr text_symbolizer_helper<FaceManagerT, DetectorT>::next_point_
finder_->get_results(), finder_->get_extents(),
feature_, t_, writer_.second);
#endif
update_detector(glyphs);
return glyphs;
return true;
}
//No placement for this point. Keep it in points_ for next try.
point_itr_++;
}
return glyph_positions_ptr();
return false;
}
struct largest_bbox_first
@ -245,14 +241,6 @@ void text_symbolizer_helper<FaceManagerT, DetectorT>::initialize_points()
point_itr_ = points_.begin();
}
template <typename FaceManagerT, typename DetectorT>
void text_symbolizer_helper<FaceManagerT, DetectorT>::update_detector(glyph_positions_ptr glyphs)
{
//TODO
}
/*****************************************************************************/
@ -294,8 +282,7 @@ bool shield_symbolizer_helper<FaceManagerT, DetectorT>::next_point_placement()
pixel_position const& text_disp = placement_->properties.displacement;
pixel_position label_pos = *point_itr_ + shield_pos;
glyph_positions_ptr glyphs = finder_.find_point_placement(label_pos);
if (!glyphs)
if (!finder_.find_point_placement(label_pos))
{
//No placement for this point. Keep it in points_ for next try.
point_itr_++;
@ -325,7 +312,6 @@ bool shield_symbolizer_helper<FaceManagerT, DetectorT>::next_point_placement()
if (placement_->properties.allow_overlap || detector_.has_placement(marker_ext_))
{
detector_.insert(marker_ext_);
this->update_detector(glyphs);
#if 0
if (writer_.first) {
writer_.first->add_box(marker_ext_, feature_, t_, writer_.second);

View file

@ -23,10 +23,12 @@
#include <mapnik/text/placement_finder_ng.hpp>
#include <mapnik/text/layout.hpp>
#include <mapnik/text_properties.hpp>
#include <mapnik/text/placements_list.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/path_processor.hpp>
#include <mapnik/expression_evaluator.hpp>
//boost
#include <boost/make_shared.hpp>
@ -38,7 +40,7 @@ namespace mapnik
{
placement_finder_ng::placement_finder_ng(Feature const& feature, DetectorType &detector, box2d<double> const& extent, text_placement_info_ptr placement_info, face_manager_freetype &font_manager, double scale_factor)
: feature_(feature), detector_(detector), extent_(extent), layout_(font_manager), info_(placement_info), valid_(true), scale_factor_(scale_factor)
: feature_(feature), detector_(detector), extent_(extent), layout_(font_manager), info_(placement_info), valid_(true), scale_factor_(scale_factor), placements_()
{
}
@ -73,6 +75,11 @@ bool placement_finder_ng::next_position()
return true;
}
const placements_list &placement_finder_ng::placements() const
{
return placements_;
}
void placement_finder_ng::init_alignment()
{
@ -163,11 +170,10 @@ static pixel_position rotate(pixel_position pos, double sina, double cosa)
}
glyph_positions_ptr placement_finder_ng::find_point_placement(pixel_position pos)
bool placement_finder_ng::find_point_placement(pixel_position pos)
{
if (!layout_.size()) return true; //No text => placement always succeeds.
glyph_positions_ptr glyphs = boost::make_shared<glyph_positions>();
if (!layout_.size()) return glyphs; /* No data. Don't return NULL pointer, which would mean
that not enough space was available. */
pixel_position displacement = scale_factor_ * info_->properties.displacement + alignment_offset();
if (info_->properties.rotate_displacement) displacement = rotate(displacement, sina_, cosa_);
@ -181,7 +187,7 @@ glyph_positions_ptr placement_finder_ng::find_point_placement(pixel_position pos
(!info_->properties.allow_overlap &&
!detector_.has_point_placement(bbox, info_->properties.minimum_distance * scale_factor_)))
{
return glyph_positions_ptr(); //Not enough space for this text
return false; //Not enough space for this text
}
detector_.insert(bbox, layout_.get_text());
@ -218,20 +224,19 @@ glyph_positions_ptr placement_finder_ng::find_point_placement(pixel_position pos
x += glyph_itr->width + glyph_itr->format->character_spacing;
}
}
return glyphs;
placements_.push_back(glyphs);
return true;
}
template <typename T>
placements_list_ptr placement_finder_ng::find_point_on_line_placements(T & path)
bool placement_finder_ng::find_point_on_line_placements(T & path)
{
path_processor<T> pp(path);
placements_list_ptr list = boost::make_shared<placements_list>();
if (!pp.valid() || !layout_.size()) return list;
if (!pp.valid() || !layout_.size()) return true;
if (pp.length() == 0.0)
{
list->push_back(find_point_placement(pp.current_point()));
return list;
return find_point_placement(pp.current_point());
}
int num_labels = 1;
@ -245,17 +250,18 @@ placements_list_ptr placement_finder_ng::find_point_on_line_placements(T & path)
double spacing = pp.length() / num_labels;
pp.skip(spacing/2.); // first label should be placed at half the spacing
bool success = false;
do
{
list->push_back(find_point_placement(pp.current_point()));
success = find_point_placement(pp.current_point()) || success;
} while (pp.skip(spacing));
return list;
return success;
}
template <typename T>
placements_list_ptr placement_finder_ng::find_line_placements(T & path)
bool placement_finder_ng::find_line_placements(T & path)
{
return placements_list_ptr();
return false;
}
@ -316,10 +322,10 @@ void glyph_positions::set_base_point(pixel_position base_point)
typedef agg::conv_clip_polyline<geometry_type> clipped_geometry_type;
typedef coord_transform<CoordTransform,clipped_geometry_type> ClippedPathType;
typedef coord_transform<CoordTransform,geometry_type> PathType;
template placements_list_ptr placement_finder_ng::find_point_on_line_placements<ClippedPathType>(ClippedPathType &);
template placements_list_ptr placement_finder_ng::find_line_placements<ClippedPathType>(ClippedPathType &);
template placements_list_ptr placement_finder_ng::find_point_on_line_placements<PathType>(PathType &);
template placements_list_ptr placement_finder_ng::find_line_placements<PathType>(PathType &);
template bool placement_finder_ng::find_point_on_line_placements<ClippedPathType>(ClippedPathType &);
template bool placement_finder_ng::find_line_placements<ClippedPathType>(ClippedPathType &);
template bool placement_finder_ng::find_point_on_line_placements<PathType>(PathType &);
template bool placement_finder_ng::find_line_placements<PathType>(PathType &);
}// ns mapnik

View file

@ -0,0 +1,29 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 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
*
*****************************************************************************/
#include <mapnik/text/placements_list.hpp>
namespace mapnik
{
}