mapnik/include/mapnik/placement_finder.hpp

147 lines
5.6 KiB
C++

/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2006 Artem Pavlenko
* Copyright (C) 2006 10East Corp.
*
* 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 __PLACEMENT_FINDER__
#define __PLACEMENT_FINDER__
#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>
#include <mapnik/text_placements.hpp>
#include <queue>
namespace mapnik
{
typedef text_path placement_element;
struct placement : boost::noncopyable
{
placement(string_info & info_, shield_symbolizer const& sym, double scale_factor, unsigned w, unsigned h, bool has_dimensions_= false);
placement(string_info & info_, text_symbolizer const& sym, double scale_factor);
~placement();
string_info & info; // should only be used for finding placement. doesn't necessarily match placements.vertex() values
double scale_factor_;
label_placement_e label_placement;
std::queue< box2d<double> > envelopes;
//output
boost::ptr_vector<placement_element> placements;
int wrap_width;
bool wrap_before; // wraps text at wrap_char immediately before current word
unsigned char wrap_char;
int text_ratio;
int label_spacing; // distance between repeated labels on a single geometry
unsigned label_position_tolerance; //distance the label can be moved on the line to fit, if 0 the default is used
bool force_odd_labels; //Always try render an odd amount of labels
double max_char_angle_delta;
double minimum_distance;
double minimum_padding;
double minimum_path_length;
bool avoid_edges;
bool has_dimensions;
bool allow_overlap;
std::pair<double, double> dimensions;
bool collect_extents;
box2d<double> extents;
};
template <typename DetectorT>
class placement_finder : boost::noncopyable
{
public:
placement_finder(DetectorT & detector);
placement_finder(DetectorT & detector, box2d<double> const& extent);
//Try place a single label at the given point
void find_point_placement(placement & p, text_placement_info_ptr po, double pos_x, double pos_y, double angle=0.0, unsigned line_spacing=0, unsigned character_spacing=0);
//Iterate over the given path, placing point labels with respect to label_spacing
template <typename T>
void find_point_placements(placement & p, text_placement_info_ptr po, T & path);
//Iterate over the given path, placing line-following labels with respect to label_spacing
template <typename T>
void find_line_placements(placement & p, text_placement_info_ptr po, T & path);
void update_detector(placement & p);
void clear();
private:
///Helpers for find_line_placement
///Returns a possible placement on the given line, does not test for collisions
//index: index of the node the current line ends on
//distance: distance along the given index that the placement should start at, this includes the offset,
// as such it may be > or < the length of the current line, so this must be checked for
//orientation: if set to != 0 the placement will be attempted with the given orientation
// otherwise it will autodetect the orientation.
// If >= 50% of the characters end up upside down, it will be retried the other way.
// RETURN: 1/-1 depending which way up the string ends up being.
std::auto_ptr<placement_element> get_placement_offset(placement & p,
const std::vector<vertex2d> & path_positions,
const std::vector<double> & path_distances,
int & orientation, unsigned index, double distance);
///Tests wether the given placement_element be placed without a collision
// Returns true if it can
// NOTE: This edits p.envelopes so it can be used afterwards (you must clear it otherwise)
bool test_placement(placement & p, const std::auto_ptr<placement_element> & current_placement, const int & orientation);
///Does a line-circle intersect calculation
// NOTE: Follow the strict pre conditions
// Pre Conditions: x1,y1 is within radius distance of cx,cy. x2,y2 is outside radius distance of cx,cy
// This means there is exactly one intersect point
// Result is returned in ix, iy
void find_line_circle_intersection(
const double &cx, const double &cy, const double &radius,
const double &x1, const double &y1, const double &x2, const double &y2,
double &ix, double &iy);
///General Internals
DetectorT & detector_;
box2d<double> const& dimensions_;
};
}
#endif