-
Notifications
You must be signed in to change notification settings - Fork 826
/
simple.cpp
182 lines (167 loc) · 5.76 KB
/
simple.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*****************************************************************************
*
* 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
*
*****************************************************************************/
// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/text_placements/simple.hpp>
#include <mapnik/ptree_helpers.hpp>
#include <mapnik/xml_node.hpp>
// boost
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/make_shared.hpp>
#include <boost/property_tree/ptree.hpp>
namespace mapnik
{
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
using phoenix::push_back;
using boost::spirit::ascii::space;
using phoenix::ref;
using qi::_1;
bool text_placement_info_simple::next()
{
while (1) {
if (state > 0)
{
if (state > parent_->text_sizes_.size()) return false;
properties.format.text_size = parent_->text_sizes_[state-1];
}
if (!next_position_only()) {
state++;
position_state = 0;
} else {
break;
}
}
return true;
}
bool text_placement_info_simple::next_position_only()
{
const position &pdisp = parent_->defaults.displacement;
position &displacement = properties.displacement;
if (position_state >= parent_->direction_.size()) return false;
directions_t dir = parent_->direction_[position_state];
switch (dir) {
case EXACT_POSITION:
displacement = pdisp;
break;
case NORTH:
displacement = std::make_pair(0, -abs(pdisp.second));
break;
case EAST:
displacement = std::make_pair(abs(pdisp.first), 0);
break;
case SOUTH:
displacement = std::make_pair(0, abs(pdisp.second));
break;
case WEST:
displacement = std::make_pair(-abs(pdisp.first), 0);
break;
case NORTHEAST:
displacement = std::make_pair(abs(pdisp.first), -abs(pdisp.second));
break;
case SOUTHEAST:
displacement = std::make_pair(abs(pdisp.first), abs(pdisp.second));
break;
case NORTHWEST:
displacement = std::make_pair(-abs(pdisp.first), -abs(pdisp.second));
break;
case SOUTHWEST:
displacement = std::make_pair(-abs(pdisp.first), abs(pdisp.second));
break;
default:
MAPNIK_LOG_WARN(text_placements) << "Unknown placement";
}
position_state++;
return true;
}
text_placement_info_ptr text_placements_simple::get_placement_info(
double scale_factor) const
{
return boost::make_shared<text_placement_info_simple>(this, scale_factor);
}
/** Position string: [POS][SIZE]
* [POS] is any combination of
* N, E, S, W, NE, SE, NW, SW, X (exact position) (separated by commas)
* [SIZE] is a list of font sizes, separated by commas. The first font size
* is always the one given in the TextSymbolizer's parameters.
* First all directions are tried, then font size is reduced
* and all directions are tried again. The process ends when a placement is
* found or the last fontsize is tried without success.
* Example: N,S,15,10,8 (tries placement above, then below and if
* that fails it tries the additional font sizes 15, 10 and 8.
*/
void text_placements_simple::set_positions(std::string positions)
{
positions_ = positions;
struct direction_name_ : qi::symbols<char, directions_t>
{
direction_name_()
{
add
("N" , NORTH)
("E" , EAST)
("S" , SOUTH)
("W" , WEST)
("NE", NORTHEAST)
("SE", SOUTHEAST)
("NW", NORTHWEST)
("SW", SOUTHWEST)
("X" , EXACT_POSITION)
;
}
} direction_name;
std::string::iterator first = positions.begin(), last = positions.end();
qi::phrase_parse(first, last,
(direction_name[push_back(phoenix::ref(direction_), _1)] % ',') >> *(',' >> qi::float_[push_back(phoenix::ref(text_sizes_), _1)]),
space
);
if (first != last)
{
MAPNIK_LOG_WARN(text_placements) << "Could not parse text_placement_simple placement string ('" << positions << "')";
}
if (direction_.size() == 0)
{
MAPNIK_LOG_WARN(text_placements) << "text_placements_simple with no valid placements! ('"<< positions<<"')";
}
}
text_placements_simple::text_placements_simple()
{
set_positions("X");
}
text_placements_simple::text_placements_simple(std::string positions)
{
set_positions(positions);
}
std::string text_placements_simple::get_positions()
{
return positions_; //TODO: Build string from data in direction_ and text_sizes_
}
text_placements_ptr text_placements_simple::from_xml(xml_node const &xml, fontset_map const & fontsets)
{
text_placements_ptr ptr = boost::make_shared<text_placements_simple>(
xml.get_attr<std::string>("placements", "X"));
ptr->defaults.from_xml(xml, fontsets);
return ptr;
}
} //ns mapnik