Merge branch 'textplacement-merge' into feature-text-merge
Conflicts: docs/textrendering.gv include/mapnik/building_symbolizer.hpp include/mapnik/placement_finder.hpp include/mapnik/symbolizer_helpers.hpp include/mapnik/text_placements.hpp include/mapnik/text_placements_list.hpp include/mapnik/text_placements_simple.hpp include/mapnik/text_processing.hpp plugins/input/shape/shape_utils.hpp src/agg/process_shield_symbolizer.cpp src/agg/process_text_symbolizer.cpp src/cairo_renderer.cpp src/grid/process_shield_symbolizer.cpp src/grid/process_text_symbolizer.cpp src/load_map.cpp src/placement_finder.cpp src/shield_symbolizer.cpp src/text_placements.cpp src/text_processing.cpp src/text_symbolizer.cpp tests/visual_tests/clean.sh tests/visual_tests/test.py Merge herm/textplacement-merge
|
@ -60,6 +60,7 @@ void export_polygon_symbolizer();
|
|||
void export_polygon_pattern_symbolizer();
|
||||
void export_raster_symbolizer();
|
||||
void export_text_symbolizer();
|
||||
void export_text_placement();
|
||||
void export_shield_symbolizer();
|
||||
void export_font_engine();
|
||||
void export_projection();
|
||||
|
@ -425,6 +426,7 @@ BOOST_PYTHON_MODULE(_mapnik)
|
|||
export_polygon_symbolizer();
|
||||
export_polygon_pattern_symbolizer();
|
||||
export_raster_symbolizer();
|
||||
export_text_placement();
|
||||
export_text_symbolizer();
|
||||
export_shield_symbolizer();
|
||||
export_font_engine();
|
||||
|
|
|
@ -37,6 +37,7 @@ using mapnik::path_expression_ptr;
|
|||
using mapnik::guess_type;
|
||||
using mapnik::expression_ptr;
|
||||
using mapnik::parse_path;
|
||||
using mapnik::position;
|
||||
|
||||
|
||||
namespace {
|
||||
|
@ -44,8 +45,8 @@ using namespace boost::python;
|
|||
|
||||
tuple get_shield_displacement(const shield_symbolizer& s)
|
||||
{
|
||||
boost::tuple<double,double> pos = s.get_shield_displacement();
|
||||
return boost::python::make_tuple(boost::get<0>(pos),boost::get<1>(pos));
|
||||
position const& pos = s.get_shield_displacement();
|
||||
return boost::python::make_tuple(pos.first, pos.second);
|
||||
}
|
||||
|
||||
void set_shield_displacement(shield_symbolizer & s, boost::python::tuple arg)
|
||||
|
@ -55,8 +56,8 @@ void set_shield_displacement(shield_symbolizer & s, boost::python::tuple arg)
|
|||
|
||||
tuple get_text_displacement(const shield_symbolizer& t)
|
||||
{
|
||||
boost::tuple<double,double> pos = t.get_displacement();
|
||||
return boost::python::make_tuple(boost::get<0>(pos),boost::get<1>(pos));
|
||||
position const& pos = t.get_displacement();
|
||||
return boost::python::make_tuple(pos.first, pos.second);
|
||||
}
|
||||
|
||||
void set_text_displacement(shield_symbolizer & t, boost::python::tuple arg)
|
||||
|
@ -223,9 +224,6 @@ void export_shield_symbolizer()
|
|||
.add_property("wrap_before",
|
||||
&shield_symbolizer::get_wrap_before,
|
||||
&shield_symbolizer::set_wrap_before)
|
||||
.add_property("no_text",
|
||||
&shield_symbolizer::get_no_text,
|
||||
&shield_symbolizer::set_no_text)
|
||||
.add_property("unlock_image",
|
||||
&shield_symbolizer::get_unlock_image,
|
||||
&shield_symbolizer::set_unlock_image)
|
||||
|
|
115
bindings/python/mapnik_text_placement.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* 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/text_placements.hpp>
|
||||
#include "mapnik_enumeration.hpp"
|
||||
#include <mapnik/expression_string.hpp>
|
||||
|
||||
using namespace mapnik;
|
||||
//using mapnik::color;
|
||||
//using mapnik::text_symbolizer;
|
||||
//using mapnik::expr_node;
|
||||
//using mapnik::expression_ptr;
|
||||
//using mapnik::to_expression_string;
|
||||
|
||||
namespace {
|
||||
using namespace boost::python;
|
||||
|
||||
tuple get_displacement(text_symbolizer_properties const& t)
|
||||
{
|
||||
return boost::python::make_tuple(t.displacement.first, t.displacement.second);
|
||||
}
|
||||
|
||||
void set_displacement(text_symbolizer_properties &t, boost::python::tuple arg)
|
||||
{
|
||||
double x = extract<double>(arg[0]);
|
||||
double y = extract<double>(arg[0]);
|
||||
t.displacement = std::make_pair(x, y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void export_text_placement()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
enumeration_<label_placement_e>("label_placement")
|
||||
.value("LINE_PLACEMENT",LINE_PLACEMENT)
|
||||
.value("POINT_PLACEMENT",POINT_PLACEMENT)
|
||||
.value("VERTEX_PLACEMENT",VERTEX_PLACEMENT)
|
||||
.value("INTERIOR_PLACEMENT",INTERIOR_PLACEMENT)
|
||||
;
|
||||
enumeration_<vertical_alignment_e>("vertical_alignment")
|
||||
.value("TOP",V_TOP)
|
||||
.value("MIDDLE",V_MIDDLE)
|
||||
.value("BOTTOM",V_BOTTOM)
|
||||
.value("AUTO",V_AUTO)
|
||||
;
|
||||
|
||||
enumeration_<horizontal_alignment_e>("horizontal_alignment")
|
||||
.value("LEFT",H_LEFT)
|
||||
.value("MIDDLE",H_MIDDLE)
|
||||
.value("RIGHT",H_RIGHT)
|
||||
.value("AUTO",H_AUTO)
|
||||
;
|
||||
|
||||
enumeration_<justify_alignment_e>("justify_alignment")
|
||||
.value("LEFT",J_LEFT)
|
||||
.value("MIDDLE",J_MIDDLE)
|
||||
.value("RIGHT",J_RIGHT)
|
||||
;
|
||||
|
||||
enumeration_<text_transform_e>("text_transform")
|
||||
.value("NONE",NONE)
|
||||
.value("UPPERCASE",UPPERCASE)
|
||||
.value("LOWERCASE",LOWERCASE)
|
||||
.value("CAPITALIZE",CAPITALIZE)
|
||||
;
|
||||
|
||||
|
||||
class_<text_symbolizer_properties>("TextSymbolizerProperties")
|
||||
.def_readwrite("orientation", &text_symbolizer_properties::orientation)
|
||||
.add_property("displacement",
|
||||
&get_displacement,
|
||||
&set_displacement)
|
||||
.def_readwrite("label_placement", &text_symbolizer_properties::label_placement)
|
||||
.def_readwrite("horizontal_alignment", &text_symbolizer_properties::halign)
|
||||
.def_readwrite("justify_alignment", &text_symbolizer_properties::jalign)
|
||||
.def_readwrite("vertical_alignment", &text_symbolizer_properties::valign)
|
||||
.def_readwrite("label_spacing", &text_symbolizer_properties::label_spacing)
|
||||
.def_readwrite("label_position_tolerance", &text_symbolizer_properties::label_position_tolerance)
|
||||
.def_readwrite("avoid_edges", &text_symbolizer_properties::avoid_edges)
|
||||
.def_readwrite("minimum_distance", &text_symbolizer_properties::minimum_distance)
|
||||
.def_readwrite("minimum_padding", &text_symbolizer_properties::minimum_padding)
|
||||
.def_readwrite("minimum_path_length", &text_symbolizer_properties::minimum_path_length)
|
||||
.def_readwrite("maximum_angle_char_delta", &text_symbolizer_properties::max_char_angle_delta)
|
||||
.def_readwrite("force_odd_labels", &text_symbolizer_properties::force_odd_labels)
|
||||
.def_readwrite("allow_overlap", &text_symbolizer_properties::allow_overlap)
|
||||
.def_readwrite("text_ratio", &text_symbolizer_properties::text_ratio)
|
||||
.def_readwrite("wrap_width", &text_symbolizer_properties::wrap_width)
|
||||
/* TODO: text_processor */
|
||||
/* from_xml, to_xml operate on mapnik's internal XML tree and don't make sense in python.*/
|
||||
;
|
||||
}
|
|
@ -39,8 +39,8 @@ using namespace boost::python;
|
|||
|
||||
tuple get_text_displacement(const text_symbolizer& t)
|
||||
{
|
||||
position pos = t.get_displacement();
|
||||
return boost::python::make_tuple(boost::get<0>(pos),boost::get<1>(pos));
|
||||
mapnik::position const& pos = t.get_displacement();
|
||||
return boost::python::make_tuple(pos.first, pos.second);
|
||||
}
|
||||
|
||||
void set_text_displacement(text_symbolizer & t, boost::python::tuple arg)
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#process with: dot textrendering.gv -Tpng > textrendering.png
|
||||
/* process with: dot textrendering.gv -Tsvg > textrendering.svg */
|
||||
digraph textrendering {
|
||||
# Classes without important virtual members: Round
|
||||
# Classes with important virtual members: Rect
|
||||
# Pointers [style=dashed]
|
||||
# Red: function is called
|
||||
/* Classes without important virtual members: Round
|
||||
Classes with important virtual members: Rect
|
||||
Pointers [style=dashed] */
|
||||
|
||||
Renderer [color=red]
|
||||
rankdir="TD";
|
||||
text_placements[shape=box]
|
||||
text_placement_info[shape=box]
|
||||
Renderer
|
||||
|
||||
node_ -> text_processor [label="tree_", style=dashed]
|
||||
TextSymbolizer -> text_placements [label="placement_options_", style=dashed]
|
||||
text_placements -> text_symbolizer_properties [label="properties"]
|
||||
text_placements -> text_placement_info [label="get_placement_info()", style=dashed]
|
||||
|
@ -16,9 +17,24 @@ digraph textrendering {
|
|||
text_placement_info -> text_placement_info [label="next()"]
|
||||
text_symbolizer_properties -> text_processor [label="processor"]
|
||||
text_processor -> processed_text [label="process()", style=dashed]
|
||||
processed_text -> string_info [label="get_string_info()"]
|
||||
processed_text -> string_info [label="get_string_info()", style=dashed]
|
||||
text_path -> Renderer [color=red, label="used by"]
|
||||
Renderer -> text_placement_info [color=red, label="init()"]
|
||||
Renderer -> processed_text [color=red, label="initializes"]
|
||||
processed_text -> Renderer [color=red, label="owned by"]
|
||||
Renderer -> text_symbolizer_helper [color=red, label="creates"]
|
||||
text_symbolizer_helper -> placement_finder [color=red, label="creates"]
|
||||
placement_finder -> text_path [color=red, label="creates"]
|
||||
string_info -> placement_finder [color=red, label="used by"]
|
||||
text_processor -> Renderer [color=red, label="called by"]
|
||||
text_placement_info -> Renderer [color=red, label="used by"]
|
||||
|
||||
|
||||
node_[label="node"]
|
||||
node_ -> text_node [style=dashed]
|
||||
node_ -> list_node [style=dashed]
|
||||
node_ -> format_node [style=dashed]
|
||||
list_node -> text_node [style=dashed]
|
||||
list_node -> format_node [style=dashed]
|
||||
format_node -> text_node [style=dashed]
|
||||
{ rank=same; text_path text_symbolizer_helper }
|
||||
{ rank=same; node_ TextSymbolizer}
|
||||
}
|
||||
|
|
BIN
docs/textrendering.png
Normal file
After Width: | Height: | Size: 115 KiB |
226
docs/textrendering.svg
Normal file
|
@ -0,0 +1,226 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.26.3 (20100126.1600)
|
||||
-->
|
||||
<!-- Title: textrendering Pages: 1 -->
|
||||
<svg width="733pt" height="782pt"
|
||||
viewBox="0.00 0.00 733.00 782.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph1" class="graph" transform="scale(1 1) rotate(0) translate(4 778)">
|
||||
<title>textrendering</title>
|
||||
<polygon fill="white" stroke="white" points="-4,5 -4,-778 730,-778 730,5 -4,5"/>
|
||||
<!-- Renderer -->
|
||||
<g id="node1" class="node"><title>Renderer</title>
|
||||
<ellipse fill="none" stroke="red" cx="220" cy="-216" rx="55.0898" ry="18"/>
|
||||
<text text-anchor="middle" x="220" y="-211.9" font-family="Times Roman,serif" font-size="14.00">Renderer</text>
|
||||
</g>
|
||||
<!-- text_symbolizer_helper -->
|
||||
<g id="node24" class="node"><title>text_symbolizer_helper</title>
|
||||
<ellipse fill="none" stroke="black" cx="257" cy="-108" rx="123.188" ry="18"/>
|
||||
<text text-anchor="middle" x="257" y="-103.9" font-family="Times Roman,serif" font-size="14.00">text_symbolizer_helper</text>
|
||||
</g>
|
||||
<!-- Renderer->text_symbolizer_helper -->
|
||||
<g id="edge26" class="edge"><title>Renderer->text_symbolizer_helper</title>
|
||||
<path fill="none" stroke="red" d="M226.277,-197.679C232.106,-180.665 240.865,-155.097 247.541,-135.609"/>
|
||||
<polygon fill="red" stroke="red" points="250.886,-136.645 250.816,-126.05 244.264,-134.376 250.886,-136.645"/>
|
||||
<text text-anchor="middle" x="269.5" y="-157.9" font-family="Times Roman,serif" font-size="14.00">creates</text>
|
||||
</g>
|
||||
<!-- text_placements -->
|
||||
<g id="node2" class="node"><title>text_placements</title>
|
||||
<polygon fill="none" stroke="black" points="320,-684 190,-684 190,-648 320,-648 320,-684"/>
|
||||
<text text-anchor="middle" x="255" y="-661.9" font-family="Times Roman,serif" font-size="14.00">text_placements</text>
|
||||
</g>
|
||||
<!-- text_placement_info -->
|
||||
<g id="node3" class="node"><title>text_placement_info</title>
|
||||
<polygon fill="none" stroke="black" points="245,-594 89,-594 89,-558 245,-558 245,-594"/>
|
||||
<text text-anchor="middle" x="167" y="-571.9" font-family="Times Roman,serif" font-size="14.00">text_placement_info</text>
|
||||
</g>
|
||||
<!-- text_placements->text_placement_info -->
|
||||
<g id="edge8" class="edge"><title>text_placements->text_placement_info</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M205.049,-647.841C196.813,-643.062 189.015,-637.176 183,-630 176.839,-622.65 173.05,-613.005 170.721,-603.902"/>
|
||||
<polygon fill="black" stroke="black" points="174.125,-603.084 168.661,-594.007 167.272,-604.511 174.125,-603.084"/>
|
||||
<text text-anchor="middle" x="255.5" y="-616.9" font-family="Times Roman,serif" font-size="14.00">get_placement_info()</text>
|
||||
</g>
|
||||
<!-- text_symbolizer_properties -->
|
||||
<g id="node10" class="node"><title>text_symbolizer_properties</title>
|
||||
<ellipse fill="none" stroke="black" cx="342" cy="-486" rx="141.756" ry="18"/>
|
||||
<text text-anchor="middle" x="342" y="-481.9" font-family="Times Roman,serif" font-size="14.00">text_symbolizer_properties</text>
|
||||
</g>
|
||||
<!-- text_placements->text_symbolizer_properties -->
|
||||
<g id="edge6" class="edge"><title>text_placements->text_symbolizer_properties</title>
|
||||
<path fill="none" stroke="black" d="M308.282,-647.955C315.947,-643.223 322.938,-637.323 328,-630 351.634,-595.806 350.563,-545.645 346.851,-514.45"/>
|
||||
<polygon fill="black" stroke="black" points="350.281,-513.701 345.464,-504.264 343.345,-514.645 350.281,-513.701"/>
|
||||
<text text-anchor="middle" x="383" y="-571.9" font-family="Times Roman,serif" font-size="14.00">properties</text>
|
||||
</g>
|
||||
<!-- text_placement_info->Renderer -->
|
||||
<g id="edge36" class="edge"><title>text_placement_info->Renderer</title>
|
||||
<path fill="none" stroke="red" d="M167.966,-557.734C168.843,-539.556 170,-510.858 170,-486 170,-486 170,-486 170,-306 170,-281.884 183.888,-258.188 197.026,-241.169"/>
|
||||
<polygon fill="red" stroke="red" points="199.765,-243.348 203.351,-233.378 194.331,-238.936 199.765,-243.348"/>
|
||||
<text text-anchor="middle" x="197" y="-391.9" font-family="Times Roman,serif" font-size="14.00">used by</text>
|
||||
</g>
|
||||
<!-- text_placement_info->text_placement_info -->
|
||||
<g id="edge14" class="edge"><title>text_placement_info->text_placement_info</title>
|
||||
<path fill="none" stroke="black" d="M245.347,-583.319C255.944,-582.092 263,-579.652 263,-576 263,-573.66 260.104,-571.818 255.237,-570.474"/>
|
||||
<polygon fill="black" stroke="black" points="255.811,-567.021 245.347,-568.681 254.562,-573.909 255.811,-567.021"/>
|
||||
<text text-anchor="middle" x="284.5" y="-571.9" font-family="Times Roman,serif" font-size="14.00">next()</text>
|
||||
</g>
|
||||
<!-- text_placement_info->text_symbolizer_properties -->
|
||||
<g id="edge10" class="edge"><title>text_placement_info->text_symbolizer_properties</title>
|
||||
<path fill="none" stroke="black" d="M195.152,-557.999C212.864,-547.001 236.382,-532.987 258,-522 267.963,-516.936 278.802,-511.934 289.282,-507.342"/>
|
||||
<polygon fill="black" stroke="black" points="290.973,-510.425 298.77,-503.251 288.201,-503.997 290.973,-510.425"/>
|
||||
<text text-anchor="middle" x="293" y="-526.9" font-family="Times Roman,serif" font-size="14.00">properties</text>
|
||||
</g>
|
||||
<!-- text_path -->
|
||||
<g id="node14" class="node"><title>text_path</title>
|
||||
<ellipse fill="none" stroke="black" cx="58" cy="-108" rx="57.8712" ry="18"/>
|
||||
<text text-anchor="middle" x="58" y="-103.9" font-family="Times Roman,serif" font-size="14.00">text_path</text>
|
||||
</g>
|
||||
<!-- text_placement_info->text_path -->
|
||||
<g id="edge12" class="edge"><title>text_placement_info->text_path</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M126.007,-557.868C99.1525,-542.905 69,-518.802 69,-486 69,-486 69,-486 69,-216 69,-188.913 65.5331,-158.201 62.492,-136.471"/>
|
||||
<polygon fill="black" stroke="black" points="65.9132,-135.677 61.0058,-126.287 58.9866,-136.688 65.9132,-135.677"/>
|
||||
<text text-anchor="middle" x="108.5" y="-346.9" font-family="Times Roman,serif" font-size="14.00">placements</text>
|
||||
</g>
|
||||
<!-- node_ -->
|
||||
<g id="node4" class="node"><title>node_</title>
|
||||
<ellipse fill="none" stroke="black" cx="621" cy="-756" rx="34.2406" ry="18"/>
|
||||
<text text-anchor="middle" x="621" y="-751.9" font-family="Times Roman,serif" font-size="14.00">node</text>
|
||||
</g>
|
||||
<!-- text_processor -->
|
||||
<g id="node6" class="node"><title>text_processor</title>
|
||||
<ellipse fill="none" stroke="black" cx="369" cy="-396" rx="81.9961" ry="18"/>
|
||||
<text text-anchor="middle" x="369" y="-391.9" font-family="Times Roman,serif" font-size="14.00">text_processor</text>
|
||||
</g>
|
||||
<!-- node_->text_processor -->
|
||||
<g id="edge2" class="edge"><title>node_->text_processor</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M641.466,-741.272C661.17,-725.215 688,-697.556 688,-666 688,-666 688,-666 688,-486 688,-437.627 550.415,-413.974 455.959,-403.435"/>
|
||||
<polygon fill="black" stroke="black" points="456.134,-399.933 445.814,-402.334 455.379,-406.892 456.134,-399.933"/>
|
||||
<text text-anchor="middle" x="706.5" y="-571.9" font-family="Times Roman,serif" font-size="14.00">tree_</text>
|
||||
</g>
|
||||
<!-- text_node -->
|
||||
<g id="node32" class="node"><title>text_node</title>
|
||||
<ellipse fill="none" stroke="black" cx="600" cy="-486" rx="59.7599" ry="18"/>
|
||||
<text text-anchor="middle" x="600" y="-481.9" font-family="Times Roman,serif" font-size="14.00">text_node</text>
|
||||
</g>
|
||||
<!-- node_->text_node -->
|
||||
<g id="edge38" class="edge"><title>node_->text_node</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M621.64,-737.953C622.123,-723.392 622.745,-702.38 623,-684 624.004,-611.699 620.132,-593.283 608,-522 607.568,-519.46 607.073,-516.828 606.548,-514.197"/>
|
||||
<polygon fill="black" stroke="black" points="609.934,-513.295 604.426,-504.244 603.088,-514.754 609.934,-513.295"/>
|
||||
</g>
|
||||
<!-- list_node -->
|
||||
<g id="node34" class="node"><title>list_node</title>
|
||||
<ellipse fill="none" stroke="black" cx="560" cy="-666" rx="54.2008" ry="18"/>
|
||||
<text text-anchor="middle" x="560" y="-661.9" font-family="Times Roman,serif" font-size="14.00">list_node</text>
|
||||
</g>
|
||||
<!-- node_->list_node -->
|
||||
<g id="edge40" class="edge"><title>node_->list_node</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M609.239,-738.647C600.267,-725.41 587.763,-706.962 577.602,-691.97"/>
|
||||
<polygon fill="black" stroke="black" points="580.441,-689.921 571.933,-683.607 574.647,-693.848 580.441,-689.921"/>
|
||||
</g>
|
||||
<!-- format_node -->
|
||||
<g id="node36" class="node"><title>format_node</title>
|
||||
<ellipse fill="none" stroke="black" cx="502" cy="-576" rx="71.7694" ry="18"/>
|
||||
<text text-anchor="middle" x="502" y="-571.9" font-family="Times Roman,serif" font-size="14.00">format_node</text>
|
||||
</g>
|
||||
<!-- node_->format_node -->
|
||||
<g id="edge42" class="edge"><title>node_->format_node</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M590.428,-747.872C560.614,-738.135 516.934,-718.626 497,-684 483.032,-659.737 487.038,-627.084 492.815,-604.055"/>
|
||||
<polygon fill="black" stroke="black" points="496.244,-604.787 495.536,-594.216 489.497,-602.921 496.244,-604.787"/>
|
||||
</g>
|
||||
<!-- text_processor->Renderer -->
|
||||
<g id="edge34" class="edge"><title>text_processor->Renderer</title>
|
||||
<path fill="none" stroke="red" d="M314.995,-382.308C284.546,-371.64 248.752,-353.535 229,-324 213.308,-300.537 212.917,-267.483 215.283,-244.138"/>
|
||||
<polygon fill="red" stroke="red" points="218.762,-244.519 216.518,-234.164 211.815,-243.658 218.762,-244.519"/>
|
||||
<text text-anchor="middle" x="259.5" y="-301.9" font-family="Times Roman,serif" font-size="14.00">called by</text>
|
||||
</g>
|
||||
<!-- processed_text -->
|
||||
<g id="node18" class="node"><title>processed_text</title>
|
||||
<ellipse fill="none" stroke="black" cx="382" cy="-306" rx="82.8866" ry="18"/>
|
||||
<text text-anchor="middle" x="382" y="-301.9" font-family="Times Roman,serif" font-size="14.00">processed_text</text>
|
||||
</g>
|
||||
<!-- text_processor->processed_text -->
|
||||
<g id="edge18" class="edge"><title>text_processor->processed_text</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M371.631,-377.787C373.428,-365.344 375.846,-348.605 377.895,-334.421"/>
|
||||
<polygon fill="black" stroke="black" points="381.408,-334.583 379.373,-324.186 374.479,-333.583 381.408,-334.583"/>
|
||||
<text text-anchor="middle" x="407" y="-346.9" font-family="Times Roman,serif" font-size="14.00">process()</text>
|
||||
</g>
|
||||
<!-- TextSymbolizer -->
|
||||
<g id="node7" class="node"><title>TextSymbolizer</title>
|
||||
<ellipse fill="none" stroke="black" cx="255" cy="-756" rx="84.7756" ry="18"/>
|
||||
<text text-anchor="middle" x="255" y="-751.9" font-family="Times Roman,serif" font-size="14.00">TextSymbolizer</text>
|
||||
</g>
|
||||
<!-- TextSymbolizer->text_placements -->
|
||||
<g id="edge4" class="edge"><title>TextSymbolizer->text_placements</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M255,-737.787C255,-725.344 255,-708.605 255,-694.421"/>
|
||||
<polygon fill="black" stroke="black" points="258.5,-694.186 255,-684.186 251.5,-694.186 258.5,-694.186"/>
|
||||
<text text-anchor="middle" x="323.5" y="-706.9" font-family="Times Roman,serif" font-size="14.00">placement_options_</text>
|
||||
</g>
|
||||
<!-- text_symbolizer_properties->text_processor -->
|
||||
<g id="edge16" class="edge"><title>text_symbolizer_properties->text_processor</title>
|
||||
<path fill="none" stroke="black" d="M347.464,-467.787C351.233,-455.222 356.317,-438.277 360.599,-424.005"/>
|
||||
<polygon fill="black" stroke="black" points="364.023,-424.77 363.544,-414.186 357.318,-422.758 364.023,-424.77"/>
|
||||
<text text-anchor="middle" x="390" y="-436.9" font-family="Times Roman,serif" font-size="14.00">processor</text>
|
||||
</g>
|
||||
<!-- text_path->Renderer -->
|
||||
<g id="edge22" class="edge"><title>text_path->Renderer</title>
|
||||
<path fill="none" stroke="red" d="M82.6849,-124.457C110.585,-143.056 156.131,-173.421 187.049,-194.033"/>
|
||||
<polygon fill="red" stroke="red" points="185.485,-197.196 195.747,-199.831 189.368,-191.372 185.485,-197.196"/>
|
||||
<text text-anchor="middle" x="190" y="-157.9" font-family="Times Roman,serif" font-size="14.00">used by</text>
|
||||
</g>
|
||||
<!-- processed_text->Renderer -->
|
||||
<g id="edge24" class="edge"><title>processed_text->Renderer</title>
|
||||
<path fill="none" stroke="red" d="M337.974,-290.733C323.299,-284.984 307.105,-277.902 293,-270 277.318,-261.215 261.124,-249.543 247.984,-239.299"/>
|
||||
<polygon fill="red" stroke="red" points="249.834,-236.298 239.827,-232.817 245.479,-241.779 249.834,-236.298"/>
|
||||
<text text-anchor="middle" x="327" y="-256.9" font-family="Times Roman,serif" font-size="14.00">owned by</text>
|
||||
</g>
|
||||
<!-- string_info -->
|
||||
<g id="node20" class="node"><title>string_info</title>
|
||||
<ellipse fill="none" stroke="black" cx="385" cy="-162" rx="61.8445" ry="18"/>
|
||||
<text text-anchor="middle" x="385" y="-157.9" font-family="Times Roman,serif" font-size="14.00">string_info</text>
|
||||
</g>
|
||||
<!-- processed_text->string_info -->
|
||||
<g id="edge20" class="edge"><title>processed_text->string_info</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M382.38,-287.762C382.892,-263.201 383.807,-219.247 384.409,-190.354"/>
|
||||
<polygon fill="black" stroke="black" points="387.914,-190.16 384.623,-180.09 380.916,-190.015 387.914,-190.16"/>
|
||||
<text text-anchor="middle" x="440" y="-256.9" font-family="Times Roman,serif" font-size="14.00">get_string_info()</text>
|
||||
</g>
|
||||
<!-- placement_finder -->
|
||||
<g id="node26" class="node"><title>placement_finder</title>
|
||||
<ellipse fill="none" stroke="black" cx="257" cy="-18" rx="93.8091" ry="18"/>
|
||||
<text text-anchor="middle" x="257" y="-13.9" font-family="Times Roman,serif" font-size="14.00">placement_finder</text>
|
||||
</g>
|
||||
<!-- string_info->placement_finder -->
|
||||
<g id="edge32" class="edge"><title>string_info->placement_finder</title>
|
||||
<path fill="none" stroke="red" d="M391.337,-143.803C395.524,-128.385 398.65,-106.256 389,-90 373.987,-64.7104 346.622,-47.7353 320.685,-36.6545"/>
|
||||
<polygon fill="red" stroke="red" points="321.803,-33.3312 311.22,-32.8342 319.183,-39.8225 321.803,-33.3312"/>
|
||||
<text text-anchor="middle" x="422" y="-103.9" font-family="Times Roman,serif" font-size="14.00">used by</text>
|
||||
</g>
|
||||
<!-- text_symbolizer_helper->placement_finder -->
|
||||
<g id="edge28" class="edge"><title>text_symbolizer_helper->placement_finder</title>
|
||||
<path fill="none" stroke="red" d="M257,-89.7872C257,-77.3443 257,-60.6053 257,-46.4211"/>
|
||||
<polygon fill="red" stroke="red" points="260.5,-46.1857 257,-36.1858 253.5,-46.1858 260.5,-46.1857"/>
|
||||
<text text-anchor="middle" x="282.5" y="-58.9" font-family="Times Roman,serif" font-size="14.00">creates</text>
|
||||
</g>
|
||||
<!-- placement_finder->text_path -->
|
||||
<g id="edge30" class="edge"><title>placement_finder->text_path</title>
|
||||
<path fill="none" stroke="red" d="M220.029,-34.7207C185.996,-50.1122 135.554,-72.9254 100.01,-89.0004"/>
|
||||
<polygon fill="red" stroke="red" points="98.53,-85.8285 90.8608,-93.1383 101.415,-92.2065 98.53,-85.8285"/>
|
||||
<text text-anchor="middle" x="201.5" y="-58.9" font-family="Times Roman,serif" font-size="14.00">creates</text>
|
||||
</g>
|
||||
<!-- list_node->text_node -->
|
||||
<g id="edge44" class="edge"><title>list_node->text_node</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M566.643,-647.87C571.723,-633.439 578.583,-612.642 583,-594 589.356,-567.176 593.972,-536.027 596.776,-514.095"/>
|
||||
<polygon fill="black" stroke="black" points="600.255,-514.481 598.007,-504.127 593.308,-513.623 600.255,-514.481"/>
|
||||
</g>
|
||||
<!-- list_node->format_node -->
|
||||
<g id="edge46" class="edge"><title>list_node->format_node</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M548.541,-648.219C540.175,-635.237 528.69,-617.415 519.222,-602.724"/>
|
||||
<polygon fill="black" stroke="black" points="521.993,-600.562 513.634,-594.052 516.109,-604.354 521.993,-600.562"/>
|
||||
</g>
|
||||
<!-- format_node->text_node -->
|
||||
<g id="edge48" class="edge"><title>format_node->text_node</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M521.362,-558.219C536.318,-544.483 557.176,-525.328 573.652,-510.197"/>
|
||||
<polygon fill="black" stroke="black" points="576.346,-512.475 581.344,-503.134 571.611,-507.32 576.346,-512.475"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 16 KiB |
|
@ -36,20 +36,17 @@ public:
|
|||
placement_finder(text_placement_info &p, string_info &info, DetectorT & detector);
|
||||
placement_finder(text_placement_info &p, string_info &info, DetectorT & detector, box2d<double> const& extent);
|
||||
|
||||
//Try place a single label at the given point
|
||||
/** Try place a single label at the given point. */
|
||||
void find_point_placement(double pos_x, double pos_y, double angle=0.0);
|
||||
|
||||
//Iterate over the given path, placing point labels with respect to label_spacing
|
||||
/** Iterate over the given path, placing point labels with respect to label_spacing. */
|
||||
template <typename T>
|
||||
void find_point_placements(T & path);
|
||||
|
||||
//Iterate over the given path, placing line-following labels with respect to label_spacing
|
||||
/** Iterate over the given path, placing line-following labels with respect to label_spacing. */
|
||||
template <typename T>
|
||||
void find_line_placements(T & path);
|
||||
|
||||
//Find placement, automatically select point or line placement
|
||||
void find_placement(double angle, geometry_type const& geom, CoordTransform const& t, proj_transform const& prj_trans);
|
||||
|
||||
void update_detector();
|
||||
|
||||
void clear();
|
||||
|
@ -65,14 +62,14 @@ private:
|
|||
// 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(const std::vector<vertex2d> & path_positions,
|
||||
std::auto_ptr<text_path> get_placement_offset(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
|
||||
///Tests wether the given text_path 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(const std::auto_ptr<placement_element> & current_placement, const int & orientation);
|
||||
bool test_placement(const std::auto_ptr<text_path> & current_placement, const int & orientation);
|
||||
|
||||
///Does a line-circle intersect calculation
|
||||
// NOTE: Follow the strict pre conditions
|
||||
|
@ -87,7 +84,7 @@ private:
|
|||
void find_line_breaks();
|
||||
void init_string_size();
|
||||
void init_alignment();
|
||||
void adjust_position(placement_element *current_placement, double label_x, double label_y);
|
||||
void adjust_position(text_path *current_placement, double label_x, double label_y);
|
||||
|
||||
///General Internals
|
||||
DetectorT & detector_;
|
||||
|
|
|
@ -50,15 +50,12 @@ struct MAPNIK_DECL shield_symbolizer : public text_symbolizer,
|
|||
|
||||
bool get_unlock_image() const; // image is not locked to the text placement
|
||||
void set_unlock_image(bool unlock_image);
|
||||
bool get_no_text() const; // do no render text
|
||||
void set_no_text(bool unlock_image);
|
||||
void set_shield_displacement(double shield_dx,double shield_dy);
|
||||
boost::tuple<double,double> const& get_shield_displacement() const;
|
||||
position const& get_shield_displacement() const;
|
||||
|
||||
private:
|
||||
bool unlock_image_;
|
||||
bool no_text_;
|
||||
boost::tuple<double,double> shield_displacement_;
|
||||
position shield_displacement_;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -23,163 +23,147 @@
|
|||
#define SYMBOLIZER_HELPERS_HPP
|
||||
|
||||
#include <mapnik/text_symbolizer.hpp>
|
||||
#include <mapnik/shield_symbolizer.hpp>
|
||||
#include <mapnik/text_processing.hpp>
|
||||
#include <mapnik/placement_finder.hpp>
|
||||
#include <mapnik/expression_evaluator.hpp>
|
||||
#include <mapnik/feature.hpp>
|
||||
#include <mapnik/marker.hpp>
|
||||
#include <mapnik/marker_cache.hpp>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
|
||||
struct greater_bbox_comp
|
||||
{
|
||||
bool operator() (geometry_type const* g0, geometry_type const* g1) const
|
||||
{
|
||||
box2d<double> b0 = g0->envelope();
|
||||
box2d<double> b1 = g1->envelope();
|
||||
return b0.width()*b0.height() > b1.width()*b1.height();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** Helper object that does all the TextSymbolizer placment finding
|
||||
* work except actually rendering the object. */
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
class text_symbolizer_helper
|
||||
{
|
||||
public:
|
||||
text_symbolizer_helper(unsigned width,
|
||||
text_symbolizer_helper(text_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
proj_transform const& prj_trans,
|
||||
unsigned width,
|
||||
unsigned height,
|
||||
double scale_factor,
|
||||
CoordTransform const &t,
|
||||
FaceManagerT &font_manager,
|
||||
DetectorT &detector) :
|
||||
width_(width),
|
||||
height_(height),
|
||||
scale_factor_(scale_factor),
|
||||
t_(t),
|
||||
font_manager_(font_manager),
|
||||
detector_(detector),
|
||||
text_()
|
||||
{
|
||||
DetectorT &detector)
|
||||
: sym_(sym),
|
||||
feature_(feature),
|
||||
prj_trans_(prj_trans),
|
||||
t_(t),
|
||||
font_manager_(font_manager),
|
||||
detector_(detector),
|
||||
writer_(sym.get_metawriter()),
|
||||
dims_(0, 0, width, height),
|
||||
text_(font_manager, scale_factor),
|
||||
angle_(0.0),
|
||||
placement_valid_(true)
|
||||
{
|
||||
initialize_geometries();
|
||||
if (!geometries_to_process_.size()) return; //TODO: Test this
|
||||
placement_ = sym_.get_placement_options()->get_placement_info(
|
||||
scale_factor, std::make_pair(width, height), false);
|
||||
//TODO: has_dimensions? Why? When?
|
||||
if (writer_.first) placement_->collect_extents = true;
|
||||
next_placement();
|
||||
initialize_points();
|
||||
}
|
||||
|
||||
}
|
||||
/** Return next placement.
|
||||
* If no more placements are found returns null pointer.
|
||||
*/
|
||||
text_placement_info_ptr get_placement();
|
||||
text_placement_info_ptr get_point_placement();
|
||||
text_placement_info_ptr get_line_placement();
|
||||
protected:
|
||||
bool next_placement();
|
||||
void initialize_geometries();
|
||||
void initialize_points();
|
||||
|
||||
text_placement_info_ptr get_placement(text_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
proj_transform const& prj_trans);
|
||||
private:
|
||||
bool initialize_geometries(std::vector<geometry_type*> & geometries_to_process,
|
||||
text_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
proj_transform const& prj_trans);
|
||||
|
||||
unsigned width_;
|
||||
unsigned height_;
|
||||
double scale_factor_;
|
||||
//Input
|
||||
text_symbolizer const& sym_;
|
||||
Feature const& feature_;
|
||||
proj_transform const& prj_trans_;
|
||||
CoordTransform const &t_;
|
||||
FaceManagerT &font_manager_;
|
||||
DetectorT &detector_;
|
||||
boost::shared_ptr<processed_text> text_; /*TODO: Use shared pointers for text placement so we don't need to keep a reference here! */
|
||||
metawriter_with_properties writer_;
|
||||
box2d<double> dims_;
|
||||
|
||||
//Processing
|
||||
processed_text text_;
|
||||
/* Using list instead of vector, because we delete random elements and need iterators to stay valid. */
|
||||
std::list<geometry_type*> geometries_to_process_;
|
||||
std::list<geometry_type*>::iterator geo_itr_;
|
||||
std::list<position> points_;
|
||||
std::list<position>::iterator point_itr_;
|
||||
double angle_;
|
||||
string_info *info_;
|
||||
bool placement_valid_;
|
||||
bool point_placement_;
|
||||
|
||||
//Output
|
||||
text_placement_info_ptr placement_;
|
||||
};
|
||||
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
text_placement_info_ptr text_symbolizer_helper<FaceManagerT, DetectorT>::get_placement(
|
||||
text_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
proj_transform const& prj_trans)
|
||||
class shield_symbolizer_helper: public text_symbolizer_helper<FaceManagerT, DetectorT>
|
||||
{
|
||||
|
||||
unsigned num_geom = feature.num_geometries();
|
||||
if (!num_geom) return text_placement_info_ptr(); //Nothing to do
|
||||
|
||||
std::vector<geometry_type*> geometries_to_process;
|
||||
|
||||
if (!initialize_geometries(geometries_to_process,sym, feature, prj_trans))
|
||||
return text_placement_info_ptr();
|
||||
|
||||
text_ = boost::shared_ptr<processed_text>(new processed_text(font_manager_, scale_factor_));
|
||||
metawriter_with_properties writer = sym.get_metawriter();
|
||||
|
||||
box2d<double> dims(0, 0, width_, height_);
|
||||
|
||||
text_placement_info_ptr placement = sym.get_placement_options()->get_placement_info();
|
||||
placement->init(scale_factor_, width_, height_);
|
||||
if (writer.first)
|
||||
placement->collect_extents = true;
|
||||
|
||||
|
||||
|
||||
while (placement->next())
|
||||
public:
|
||||
shield_symbolizer_helper(shield_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
proj_transform const& prj_trans,
|
||||
unsigned width,
|
||||
unsigned height,
|
||||
double scale_factor,
|
||||
CoordTransform const &t,
|
||||
FaceManagerT &font_manager,
|
||||
DetectorT &detector) :
|
||||
text_symbolizer_helper<FaceManagerT, DetectorT>(sym, feature, prj_trans, width, height, scale_factor, t, font_manager, detector),
|
||||
sym_(sym)
|
||||
{
|
||||
text_processor &processor = placement->properties.processor;
|
||||
text_symbolizer_properties const& p = placement->properties;
|
||||
/* TODO: Simplify this. */
|
||||
text_->clear();
|
||||
processor.process(*text_, feature);
|
||||
string_info &info = text_->get_string_info();
|
||||
/* END TODO */
|
||||
// text rotation
|
||||
double angle = 0.0;
|
||||
if (p.orientation)
|
||||
{
|
||||
angle = boost::apply_visitor(evaluate<Feature,value_type>(feature),*(p.orientation)).to_double();
|
||||
}
|
||||
placement_finder<DetectorT> finder(*placement, info, detector_, dims);
|
||||
|
||||
BOOST_FOREACH( geometry_type * geom, geometries_to_process )
|
||||
{
|
||||
finder.find_placement(angle, *geom, t_, prj_trans);
|
||||
//if (!placement->placements.size())
|
||||
// continue;
|
||||
//if (writer.first) writer.first->add_text(*placement, font_manager_, feature, t_, writer.second);
|
||||
//return placement;
|
||||
}
|
||||
return placement;
|
||||
}
|
||||
return text_placement_info_ptr();
|
||||
}
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
bool text_symbolizer_helper<FaceManagerT, DetectorT>::initialize_geometries(
|
||||
std::vector<geometry_type*> & geometries_to_process,
|
||||
text_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
unsigned num_geom = feature.num_geometries();
|
||||
|
||||
for (unsigned i=0; i<num_geom; ++i)
|
||||
{
|
||||
geometry_type const& geom = feature.get_geometry(i);
|
||||
|
||||
// don't bother with empty geometries
|
||||
if (geom.num_points() == 0) continue;
|
||||
|
||||
if ((geom.type() == Polygon) && sym.get_minimum_path_length() > 0)
|
||||
{
|
||||
// TODO - find less costly method than fetching full envelope
|
||||
box2d<double> gbox = t_.forward(geom.envelope(),prj_trans);
|
||||
if (gbox.width() < sym.get_minimum_path_length())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// TODO - calculate length here as well
|
||||
geometries_to_process.push_back(const_cast<geometry_type*>(&geom));
|
||||
init_marker();
|
||||
}
|
||||
|
||||
std::sort(geometries_to_process.begin(), geometries_to_process.end(), greater_bbox_comp());
|
||||
|
||||
if (!geometries_to_process.size() > 0)
|
||||
{
|
||||
// early return to avoid significant overhead of rendering setup
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
text_placement_info_ptr get_placement();
|
||||
std::pair<int, int> get_marker_position(text_path &p);
|
||||
marker &get_marker() const;
|
||||
agg::trans_affine const& get_transform() const;
|
||||
protected:
|
||||
text_placement_info_ptr get_point_placement();
|
||||
text_placement_info_ptr get_line_placement();
|
||||
void init_marker();
|
||||
shield_symbolizer const& sym_;
|
||||
box2d<double> marker_ext_;
|
||||
boost::optional<marker_ptr> marker_;
|
||||
agg::trans_affine transform_;
|
||||
int marker_w_;
|
||||
int marker_h_;
|
||||
int marker_x_;
|
||||
int marker_y_;
|
||||
// F***ing templates...
|
||||
// http://womble.decadent.org.uk/c++/template-faq.html#base-lookup
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::geometries_to_process_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::placement_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::next_placement;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::info_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::geo_itr_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::point_itr_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::points_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::writer_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::font_manager_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::feature_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::t_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::detector_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::dims_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::prj_trans_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::placement_valid_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::point_placement_;
|
||||
using text_symbolizer_helper<FaceManagerT, DetectorT>::angle_;
|
||||
};
|
||||
} //namespace
|
||||
#endif // SYMBOLIZER_HELPERS_HPP
|
||||
|
|
|
@ -46,9 +46,8 @@ namespace mapnik {
|
|||
|
||||
class text_placements;
|
||||
|
||||
typedef text_path placement_element;
|
||||
|
||||
typedef boost::tuple<double,double> position;
|
||||
typedef std::pair<double,double> position;
|
||||
typedef std::pair<double,double> dimension_type;
|
||||
|
||||
enum label_placement_enum {
|
||||
POINT_PLACEMENT,
|
||||
|
@ -97,7 +96,7 @@ struct text_symbolizer_properties
|
|||
{
|
||||
text_symbolizer_properties();
|
||||
/** Load all values and also the ```processor``` object from XML ptree. */
|
||||
void set_values_from_xml(boost::property_tree::ptree const &sym, std::map<std::string,font_set> const & fontsets);
|
||||
void from_xml(boost::property_tree::ptree const &sym, std::map<std::string,font_set> const & fontsets);
|
||||
/** Save all values to XML ptree (but does not create a new parent node!). */
|
||||
void to_xml(boost::property_tree::ptree &node, bool explicit_defaults, text_symbolizer_properties const &dfl=text_symbolizer_properties()) const;
|
||||
|
||||
|
@ -136,7 +135,8 @@ class text_placement_info : boost::noncopyable
|
|||
public:
|
||||
/** Constructor. Takes the parent text_placements object as a parameter
|
||||
* to read defaults from it. */
|
||||
text_placement_info(text_placements const* parent);
|
||||
text_placement_info(text_placements const* parent,
|
||||
double scale_factor_, dimension_type dim, bool has_dimensions_);
|
||||
/** Get next placement.
|
||||
* This function is also called before the first placement is tried.
|
||||
* Each class has to return at least one position!
|
||||
|
@ -160,7 +160,7 @@ public:
|
|||
/* TODO: Don't know what this is used for. */
|
||||
bool has_dimensions;
|
||||
/* TODO: Don't know what this is used for. */
|
||||
std::pair<double, double> dimensions;
|
||||
dimension_type dimensions;
|
||||
/** Set scale factor. */
|
||||
void set_scale_factor(double factor) { scale_factor = factor; }
|
||||
/** Get scale factor. */
|
||||
|
@ -177,10 +177,16 @@ public:
|
|||
//Output by placement finder
|
||||
/** Bounding box of all texts placed. */
|
||||
box2d<double> extents;
|
||||
/** Additional boxes to take into account when finding placement.
|
||||
* Used for finding line placements where multiple placements are returned.
|
||||
* Boxes are relative to starting point of current placement.
|
||||
*/
|
||||
std::vector<box2d<double> > additional_boxes;
|
||||
|
||||
/* TODO */
|
||||
std::queue< box2d<double> > envelopes;
|
||||
/* TODO */
|
||||
boost::ptr_vector<placement_element> placements;
|
||||
/** Used to return all placements found. */
|
||||
boost::ptr_vector<text_path> placements;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<text_placement_info> text_placement_info_ptr;
|
||||
|
@ -206,7 +212,9 @@ public:
|
|||
* return text_placement_info_ptr(new text_placement_info_XXX(this));
|
||||
* }
|
||||
*/
|
||||
virtual text_placement_info_ptr get_placement_info() const =0;
|
||||
virtual text_placement_info_ptr get_placement_info(
|
||||
double scale_factor_, dimension_type dim,
|
||||
bool has_dimensions_) const =0;
|
||||
/** Get a list of all expressions used in any placement.
|
||||
* This function is used to collect attributes.
|
||||
*/
|
||||
|
@ -229,7 +237,8 @@ class text_placements_info_dummy;
|
|||
class MAPNIK_DECL text_placements_dummy: public text_placements
|
||||
{
|
||||
public:
|
||||
text_placement_info_ptr get_placement_info() const;
|
||||
text_placement_info_ptr get_placement_info(
|
||||
double scale_factor, dimension_type dim, bool has_dimensions) const;
|
||||
friend class text_placement_info_dummy;
|
||||
};
|
||||
|
||||
|
@ -237,8 +246,10 @@ public:
|
|||
class MAPNIK_DECL text_placement_info_dummy : public text_placement_info
|
||||
{
|
||||
public:
|
||||
text_placement_info_dummy(text_placements_dummy const* parent) : text_placement_info(parent),
|
||||
state(0), parent_(parent) {}
|
||||
text_placement_info_dummy(text_placements_dummy const* parent,
|
||||
double scale_factor, dimension_type dim, bool has_dimensions)
|
||||
: text_placement_info(parent, scale_factor, dim, has_dimensions),
|
||||
state(0), parent_(parent) {}
|
||||
bool next();
|
||||
private:
|
||||
unsigned state;
|
||||
|
|
|
@ -33,7 +33,8 @@ class text_placements_list: public text_placements
|
|||
{
|
||||
public:
|
||||
text_placements_list();
|
||||
text_placement_info_ptr get_placement_info() const;
|
||||
text_placement_info_ptr get_placement_info(
|
||||
double scale_factor, dimension_type dim, bool has_dimensions) const;
|
||||
virtual std::set<expression_ptr> get_all_expressions();
|
||||
text_symbolizer_properties & add();
|
||||
text_symbolizer_properties & get(unsigned i);
|
||||
|
@ -48,8 +49,10 @@ private:
|
|||
class text_placement_info_list : public text_placement_info
|
||||
{
|
||||
public:
|
||||
text_placement_info_list(text_placements_list const* parent) :
|
||||
text_placement_info(parent), state(0), parent_(parent) {}
|
||||
text_placement_info_list(text_placements_list const* parent,
|
||||
double scale_factor, dimension_type dim, bool has_dimensions) :
|
||||
text_placement_info(parent, scale_factor, dim, has_dimensions),
|
||||
state(0), parent_(parent) {}
|
||||
bool next();
|
||||
private:
|
||||
unsigned state;
|
||||
|
|
|
@ -49,9 +49,10 @@ class text_placements_simple: public text_placements
|
|||
public:
|
||||
text_placements_simple();
|
||||
text_placements_simple(std::string positions);
|
||||
text_placement_info_ptr get_placement_info() const;
|
||||
text_placement_info_ptr get_placement_info(
|
||||
double scale_factor, dimension_type dim, bool has_dimensions) const;
|
||||
void set_positions(std::string positions);
|
||||
std::string const& get_positions() const;
|
||||
std::string get_positions();
|
||||
private:
|
||||
std::string positions_;
|
||||
std::vector<directions_t> direction_;
|
||||
|
@ -64,8 +65,12 @@ private:
|
|||
class text_placement_info_simple : public text_placement_info
|
||||
{
|
||||
public:
|
||||
text_placement_info_simple(text_placements_simple const* parent) :
|
||||
text_placement_info(parent), state(0), position_state(0), parent_(parent) {}
|
||||
text_placement_info_simple(text_placements_simple const* parent,
|
||||
double scale_factor, dimension_type dim, bool has_dimensions)
|
||||
: text_placement_info(parent, scale_factor, dim, has_dimensions),
|
||||
state(0), position_state(0), parent_(parent)
|
||||
{
|
||||
}
|
||||
bool next();
|
||||
protected:
|
||||
bool next_position_only();
|
||||
|
|
|
@ -46,14 +46,14 @@ enum text_transform
|
|||
CAPITALIZE,
|
||||
text_transform_MAX
|
||||
};
|
||||
|
||||
DEFINE_ENUM( text_transform_e, text_transform );
|
||||
|
||||
|
||||
struct char_properties
|
||||
{
|
||||
char_properties();
|
||||
/** Construct object from XML. */
|
||||
void set_values_from_xml(boost::property_tree::ptree const &sym, std::map<std::string,font_set> const & fontsets);
|
||||
void from_xml(boost::property_tree::ptree const &sym, std::map<std::string,font_set> const & fontsets);
|
||||
/** Write object to XML ptree. */
|
||||
void to_xml(boost::property_tree::ptree &node, bool explicit_defaults, char_properties const &dfl=char_properties()) const;
|
||||
std::string face_name;
|
||||
|
@ -79,7 +79,8 @@ public:
|
|||
UnicodeString str;
|
||||
};
|
||||
|
||||
class processed_text
|
||||
|
||||
class processed_text : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
processed_text(face_manager<freetype_engine> & font_manager, double scale_factor);
|
||||
|
@ -88,8 +89,8 @@ public:
|
|||
unsigned empty() const { return expr_list_.empty(); }
|
||||
void clear();
|
||||
typedef std::list<processed_expression> expression_list;
|
||||
expression_list::const_iterator begin();
|
||||
expression_list::const_iterator end();
|
||||
expression_list::const_iterator begin() const;
|
||||
expression_list::const_iterator end() const;
|
||||
string_info &get_string_info();
|
||||
private:
|
||||
expression_list expr_list_;
|
||||
|
@ -98,7 +99,86 @@ private:
|
|||
string_info info_;
|
||||
};
|
||||
|
||||
class abstract_token;
|
||||
|
||||
namespace formating {
|
||||
class node;
|
||||
typedef boost::shared_ptr<node> node_ptr;
|
||||
class node
|
||||
{
|
||||
public:
|
||||
virtual ~node() {}
|
||||
virtual void to_xml(boost::property_tree::ptree &xml) const;
|
||||
static node_ptr from_xml(boost::property_tree::ptree const& xml);
|
||||
virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const = 0;
|
||||
virtual void add_expressions(std::set<expression_ptr> &expressions) const;
|
||||
};
|
||||
|
||||
class list_node: public node {
|
||||
public:
|
||||
list_node() : node(), children_() {}
|
||||
virtual void to_xml(boost::property_tree::ptree &xml) const;
|
||||
virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const;
|
||||
virtual void add_expressions(std::set<expression_ptr> &expressions) const;
|
||||
|
||||
void push_back(node_ptr n);
|
||||
void set_children(std::vector<node_ptr> const& children);
|
||||
std::vector<node_ptr> const& get_children() const;
|
||||
void clear();
|
||||
private:
|
||||
std::vector<node_ptr> children_;
|
||||
};
|
||||
|
||||
class text_node: public node {
|
||||
public:
|
||||
text_node(expression_ptr text): node(), text_(text) {}
|
||||
void to_xml(boost::property_tree::ptree &xml) const;
|
||||
static node_ptr from_xml(boost::property_tree::ptree const& xml);
|
||||
virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const;
|
||||
virtual void add_expressions(std::set<expression_ptr> &expressions) const;
|
||||
|
||||
void set_text(expression_ptr text);
|
||||
expression_ptr get_text() const;
|
||||
private:
|
||||
expression_ptr text_;
|
||||
};
|
||||
|
||||
class format_node: public node {
|
||||
public:
|
||||
format_node();
|
||||
void to_xml(boost::property_tree::ptree &xml) const;
|
||||
static node_ptr from_xml(boost::property_tree::ptree const& xml);
|
||||
virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const;
|
||||
|
||||
void set_child(node_ptr child);
|
||||
node_ptr get_child() const;
|
||||
|
||||
void set_face_name(boost::optional<std::string> face_name);
|
||||
void set_text_size(boost::optional<unsigned> text_size);
|
||||
void set_character_spacing(boost::optional<unsigned> character_spacing);
|
||||
void set_line_spacing(boost::optional<unsigned> line_spacing);
|
||||
void set_text_opacity(boost::optional<double> opacity);
|
||||
void set_wrap_before(boost::optional<bool> wrap_before);
|
||||
void set_wrap_char(boost::optional<unsigned> wrap_char);
|
||||
void set_text_transform(boost::optional<text_transform_e> text_trans);
|
||||
void set_fill(boost::optional<color> fill);
|
||||
void set_halo_fill(boost::optional<color> halo_fill);
|
||||
void set_halo_radius(boost::optional<double> radius);
|
||||
private:
|
||||
boost::optional<std::string> face_name_;
|
||||
boost::optional<unsigned> text_size_;
|
||||
boost::optional<unsigned> character_spacing_;
|
||||
boost::optional<unsigned> line_spacing_;
|
||||
boost::optional<double> text_opacity_;
|
||||
boost::optional<bool> wrap_before_;
|
||||
boost::optional<unsigned> wrap_char_;
|
||||
boost::optional<text_transform_e> text_transform_;
|
||||
boost::optional<color> fill_;
|
||||
boost::optional<color> halo_fill_;
|
||||
boost::optional<double> halo_radius_;
|
||||
node_ptr child_;
|
||||
};
|
||||
|
||||
} //namespace formating
|
||||
|
||||
/** Stores formating information and uses this to produce formated text for a given feature. */
|
||||
class text_processor
|
||||
|
@ -113,22 +193,21 @@ public:
|
|||
/** Takes a feature and produces formated text as output.
|
||||
* The output object has to be created by the caller and passed in for thread safety.
|
||||
*/
|
||||
void process(processed_text &output, Feature const& feature);
|
||||
void process(processed_text &output, Feature const& feature) const;
|
||||
/** Automatically create processing instructions for a single expression. */
|
||||
void set_old_style_expression(expression_ptr expr);
|
||||
/** Add a new formating token. */
|
||||
void push_back(abstract_token *token);
|
||||
/** Sets new format tree. */
|
||||
void set_format_tree(formating::node_ptr tree);
|
||||
/** Get format tree. */
|
||||
formating::node_ptr get_format_tree() const;
|
||||
/** Get a list of all expressions used in any placement. This function is used to collect attributes. */
|
||||
std::set<expression_ptr> get_all_expressions() const;
|
||||
/** Default values for char_properties. */
|
||||
char_properties defaults;
|
||||
protected:
|
||||
void from_xml_recursive(boost::property_tree::ptree const& pt, std::map<std::string,font_set> const &fontsets);
|
||||
private:
|
||||
std::list<abstract_token *> list_;
|
||||
bool clear_on_write; //Clear list once
|
||||
formating::node_ptr tree_;
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
} /* namespace mapnik*/
|
||||
|
||||
#endif
|
||||
|
|
|
@ -23,17 +23,13 @@
|
|||
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
#include <mapnik/agg_rasterizer.hpp>
|
||||
#include <mapnik/expression_evaluator.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/marker_cache.hpp>
|
||||
#include <mapnik/svg/svg_converter.hpp>
|
||||
#include <mapnik/svg/svg_renderer.hpp>
|
||||
#include <mapnik/svg/svg_path_adapter.hpp>
|
||||
#include <mapnik/expression_evaluator.hpp>
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
#include "agg_scanline_u.h"
|
||||
#include <mapnik/symbolizer_helpers.hpp>
|
||||
|
||||
|
||||
// boost
|
||||
#include <boost/make_shared.hpp>
|
||||
|
@ -45,227 +41,28 @@ void agg_renderer<T>::process(shield_symbolizer const& sym,
|
|||
Feature const& feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
#if 0
|
||||
typedef coord_transform2<CoordTransform,geometry_type> path_type;
|
||||
shield_symbolizer_helper<face_manager<freetype_engine>,
|
||||
label_collision_detector4> helper(
|
||||
sym, feature, prj_trans,
|
||||
width_, height_,
|
||||
scale_factor_,
|
||||
t_, font_manager_, *detector_);
|
||||
|
||||
text_renderer<T> ren(pixmap_, font_manager_, *(font_manager_.get_stroker()));
|
||||
|
||||
text_placement_info_ptr placement_options = sym.get_placement_options()->get_placement_info();
|
||||
placement_options->next();
|
||||
placement_options->next_position_only();
|
||||
|
||||
UnicodeString text;
|
||||
if( sym.get_no_text() )
|
||||
text = UnicodeString( " " ); // TODO: fix->use 'space' as the text to render
|
||||
else
|
||||
{
|
||||
expression_ptr name_expr = sym.get_name();
|
||||
if (!name_expr) return;
|
||||
value_type result = boost::apply_visitor(evaluate<Feature,value_type>(feature),*name_expr);
|
||||
text = result.to_unicode();
|
||||
}
|
||||
|
||||
if ( sym.get_text_transform() == UPPERCASE)
|
||||
{
|
||||
text = text.toUpper();
|
||||
}
|
||||
else if ( sym.get_text_transform() == LOWERCASE)
|
||||
{
|
||||
text = text.toLower();
|
||||
}
|
||||
else if ( sym.get_text_transform() == CAPITALIZE)
|
||||
{
|
||||
text = text.toTitle(NULL);
|
||||
}
|
||||
|
||||
agg::trans_affine tr;
|
||||
boost::array<double,6> const& m = sym.get_transform();
|
||||
tr.load_from(&m[0]);
|
||||
|
||||
std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
|
||||
boost::optional<mapnik::marker_ptr> marker;
|
||||
if ( !filename.empty() )
|
||||
{
|
||||
marker = marker_cache::instance()->find(filename, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
marker.reset(boost::make_shared<mapnik::marker>());
|
||||
}
|
||||
|
||||
|
||||
if (text.length() > 0 && marker)
|
||||
{
|
||||
int w = (*marker)->width();
|
||||
int h = (*marker)->height();
|
||||
|
||||
double px0 = - 0.5 * w;
|
||||
double py0 = - 0.5 * h;
|
||||
double px1 = 0.5 * w;
|
||||
double py1 = 0.5 * h;
|
||||
double px2 = px1;
|
||||
double py2 = py0;
|
||||
double px3 = px0;
|
||||
double py3 = py1;
|
||||
tr.transform(&px0,&py0);
|
||||
tr.transform(&px1,&py1);
|
||||
tr.transform(&px2,&py2);
|
||||
tr.transform(&px3,&py3);
|
||||
box2d<double> label_ext (px0, py0, px1, py1);
|
||||
label_ext.expand_to_include(px2, py2);
|
||||
label_ext.expand_to_include(px3, py3);
|
||||
|
||||
face_set_ptr faces;
|
||||
|
||||
if (sym.get_fontset().size() > 0)
|
||||
text_placement_info_ptr placement;
|
||||
while ((placement = helper.get_placement())) {
|
||||
for (unsigned int ii = 0; ii < placement->placements.size(); ++ii)
|
||||
{
|
||||
faces = font_manager_.get_face_set(sym.get_fontset());
|
||||
}
|
||||
else
|
||||
{
|
||||
faces = font_manager_.get_face_set(sym.get_face_name());
|
||||
}
|
||||
std::pair<int, int> marker_pos = helper.get_marker_position(placement->placements[ii]);
|
||||
render_marker(marker_pos.first, marker_pos.second, helper.get_marker(), helper.get_transform(), sym.get_opacity());
|
||||
|
||||
stroker_ptr strk = font_manager_.get_stroker();
|
||||
if (strk && faces->size() > 0)
|
||||
{
|
||||
text_renderer<T> ren(pixmap_, faces, *strk);
|
||||
|
||||
ren.set_character_size(sym.get_text_size() * scale_factor_);
|
||||
ren.set_fill(sym.get_fill());
|
||||
ren.set_halo_fill(sym.get_halo_fill());
|
||||
ren.set_halo_radius(sym.get_halo_radius() * scale_factor_);
|
||||
ren.set_opacity(sym.get_text_opacity());
|
||||
|
||||
placement_finder<label_collision_detector4> finder(*detector_);
|
||||
|
||||
string_info info(text);
|
||||
|
||||
faces->get_string_info(info, text, 0);
|
||||
|
||||
metawriter_with_properties writer = sym.get_metawriter();
|
||||
|
||||
for (unsigned i = 0; i < feature.num_geometries(); ++i)
|
||||
{
|
||||
geometry_type const& geom = feature.get_geometry(i);
|
||||
if (geom.num_points() > 0 )
|
||||
{
|
||||
path_type path(t_,geom,prj_trans);
|
||||
|
||||
label_placement_enum how_placed = sym.get_label_placement();
|
||||
if (how_placed == POINT_PLACEMENT || how_placed == VERTEX_PLACEMENT || how_placed == INTERIOR_PLACEMENT)
|
||||
{
|
||||
// for every vertex, try and place a shield/text
|
||||
geom.rewind(0);
|
||||
placement text_placement(info, sym, scale_factor_, w, h, false);
|
||||
text_placement.avoid_edges = sym.get_avoid_edges();
|
||||
text_placement.allow_overlap = sym.get_allow_overlap();
|
||||
if (writer.first)
|
||||
text_placement.collect_extents =true; // needed for inmem metawriter
|
||||
position const& pos = sym.get_displacement();
|
||||
position const& shield_pos = sym.get_shield_displacement();
|
||||
for( unsigned jj = 0; jj < geom.num_points(); jj++ )
|
||||
{
|
||||
double label_x;
|
||||
double label_y;
|
||||
double z=0.0;
|
||||
|
||||
if( how_placed == VERTEX_PLACEMENT )
|
||||
geom.vertex(&label_x,&label_y); // by vertex
|
||||
else if( how_placed == INTERIOR_PLACEMENT )
|
||||
geom.label_interior_position(&label_x,&label_y);
|
||||
else
|
||||
geom.label_position(&label_x, &label_y); // by middle of line or by point
|
||||
prj_trans.backward(label_x,label_y, z);
|
||||
t_.forward(&label_x,&label_y);
|
||||
|
||||
label_x += boost::get<0>(shield_pos);
|
||||
label_y += boost::get<1>(shield_pos);
|
||||
|
||||
finder.find_point_placement( text_placement, placement_options,
|
||||
label_x, label_y, 0.0,
|
||||
sym.get_line_spacing(),
|
||||
sym.get_character_spacing());
|
||||
|
||||
// check to see if image overlaps anything too, there is only ever 1 placement found for points and verticies
|
||||
if( text_placement.placements.size() > 0)
|
||||
{
|
||||
double x = floor(text_placement.placements[0].starting_x);
|
||||
double y = floor(text_placement.placements[0].starting_y);
|
||||
int px;
|
||||
int py;
|
||||
|
||||
if( !sym.get_unlock_image() )
|
||||
{
|
||||
// center image at text center position
|
||||
// remove displacement from image label
|
||||
double lx = x - boost::get<0>(pos);
|
||||
double ly = y - boost::get<1>(pos);
|
||||
px=int(floor(lx - (0.5 * w))) + 1;
|
||||
py=int(floor(ly - (0.5 * h))) + 1;
|
||||
label_ext.re_center(lx,ly);
|
||||
}
|
||||
else
|
||||
{ // center image at reference location
|
||||
px=int(floor(label_x - 0.5 * w));
|
||||
py=int(floor(label_y - 0.5 * h));
|
||||
label_ext.re_center(label_x,label_y);
|
||||
}
|
||||
|
||||
if ( sym.get_allow_overlap() || detector_->has_placement(label_ext) )
|
||||
{
|
||||
render_marker(px,py,**marker,tr,sym.get_opacity());
|
||||
|
||||
box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[0]);
|
||||
ren.render(x,y);
|
||||
detector_->insert(label_ext);
|
||||
finder.update_detector(text_placement);
|
||||
if (writer.first) {
|
||||
writer.first->add_box(label_ext, feature, t_, writer.second);
|
||||
writer.first->add_text(text_placement, faces, feature, t_, writer.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (geom.num_points() > 1 && how_placed == LINE_PLACEMENT)
|
||||
{
|
||||
placement text_placement(info, sym, scale_factor_, w, h, false);
|
||||
position const& pos = sym.get_displacement();
|
||||
|
||||
text_placement.avoid_edges = sym.get_avoid_edges();
|
||||
text_placement.additional_boxes.push_back(
|
||||
box2d<double>(-0.5 * label_ext.width() - boost::get<0>(pos),
|
||||
-0.5 * label_ext.height() - boost::get<1>(pos),
|
||||
0.5 * label_ext.width() - boost::get<0>(pos),
|
||||
0.5 * label_ext.height() - boost::get<1>(pos)));
|
||||
finder.find_point_placements<path_type>(text_placement, placement_options, path);
|
||||
|
||||
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ ii)
|
||||
{
|
||||
double x = floor(text_placement.placements[ii].starting_x);
|
||||
double y = floor(text_placement.placements[ii].starting_y);
|
||||
|
||||
double lx = x - boost::get<0>(pos);
|
||||
double ly = y - boost::get<1>(pos);
|
||||
int px=int(floor(lx - (0.5*w))) + 1;
|
||||
int py=int(floor(ly - (0.5*h))) + 1;
|
||||
label_ext.re_center(lx, ly);
|
||||
|
||||
render_marker(px,py,**marker,tr,sym.get_opacity());
|
||||
|
||||
box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[ii]);
|
||||
ren.render(x,y);
|
||||
if (writer.first) writer.first->add_box(label_ext, feature, t_, writer.second);
|
||||
}
|
||||
finder.update_detector(text_placement);
|
||||
if (writer.first) writer.first->add_text(text_placement, faces, feature, t_, writer.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
double x = placement->placements[ii].starting_x;
|
||||
double y = placement->placements[ii].starting_y;
|
||||
ren.prepare_glyphs(&(placement->placements[ii]));
|
||||
ren.render(x, y);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -33,23 +33,24 @@ void agg_renderer<T>::process(text_symbolizer const& sym,
|
|||
Feature const& feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
/* This could also be a member of the renderer class, but I would have
|
||||
to check if any of the variables changes and notify the helper.
|
||||
It could be done at a later point, but for now keep the code simple.
|
||||
*/
|
||||
text_symbolizer_helper<face_manager<freetype_engine>, label_collision_detector4> helper(width_, height_, scale_factor_, t_, font_manager_, *detector_);
|
||||
|
||||
text_placement_info_ptr placement = helper.get_placement(sym, feature, prj_trans);
|
||||
|
||||
if (!placement) return;
|
||||
text_symbolizer_helper<face_manager<freetype_engine>,
|
||||
label_collision_detector4> helper(
|
||||
sym, feature, prj_trans,
|
||||
width_, height_,
|
||||
scale_factor_,
|
||||
t_, font_manager_, *detector_);
|
||||
|
||||
text_renderer<T> ren(pixmap_, font_manager_, *(font_manager_.get_stroker()));
|
||||
for (unsigned int ii = 0; ii < placement->placements.size(); ++ii)
|
||||
{
|
||||
double x = placement->placements[ii].starting_x;
|
||||
double y = placement->placements[ii].starting_y;
|
||||
ren.prepare_glyphs(&(placement->placements[ii]));
|
||||
ren.render(x, y);
|
||||
|
||||
text_placement_info_ptr placement;
|
||||
while ((placement = helper.get_placement())) {
|
||||
for (unsigned int ii = 0; ii < placement->placements.size(); ++ii)
|
||||
{
|
||||
double x = placement->placements[ii].starting_x;
|
||||
double y = placement->placements[ii].starting_y;
|
||||
ren.prepare_glyphs(&(placement->placements[ii]));
|
||||
ren.render(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,7 @@ source = Split(
|
|||
memory_datasource.cpp
|
||||
stroke.cpp
|
||||
symbolizer.cpp
|
||||
symbolizer_helpers.cpp
|
||||
arrow.cpp
|
||||
unicode.cpp
|
||||
markers_symbolizer.cpp
|
||||
|
|
|
@ -1051,207 +1051,26 @@ void cairo_renderer_base::process(shield_symbolizer const& sym,
|
|||
Feature const& feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
#if 0
|
||||
typedef coord_transform2<CoordTransform,geometry_type> path_type;
|
||||
shield_symbolizer_helper<face_manager<freetype_engine>,
|
||||
label_collision_detector4> helper(
|
||||
sym, feature, prj_trans,
|
||||
detector_.extent().width(), detector_.extent().height(),
|
||||
1.0 /*scale_factor*/,
|
||||
t_, font_manager_, detector_);
|
||||
|
||||
text_placement_info_ptr placement_options = sym.get_placement_options()->get_placement_info();
|
||||
placement_options->next();
|
||||
cairo_context context(context_);
|
||||
|
||||
UnicodeString text;
|
||||
if( sym.get_no_text() )
|
||||
text = UnicodeString( " " ); // TODO: fix->use 'space' as the text to render
|
||||
else
|
||||
{
|
||||
expression_ptr name_expr = sym.get_name();
|
||||
if (!name_expr) return;
|
||||
value_type result = boost::apply_visitor(evaluate<Feature,value_type>(feature),*name_expr);
|
||||
text = result.to_unicode();
|
||||
}
|
||||
|
||||
if ( sym.get_text_transform() == UPPERCASE)
|
||||
{
|
||||
text = text.toUpper();
|
||||
}
|
||||
else if ( sym.get_text_transform() == LOWERCASE)
|
||||
{
|
||||
text = text.toLower();
|
||||
}
|
||||
else if ( sym.get_text_transform() == CAPITALIZE)
|
||||
{
|
||||
text = text.toTitle(NULL);
|
||||
}
|
||||
|
||||
agg::trans_affine tr;
|
||||
boost::array<double,6> const& m = sym.get_transform();
|
||||
tr.load_from(&m[0]);
|
||||
|
||||
std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
|
||||
boost::optional<marker_ptr> marker;
|
||||
if ( !filename.empty() )
|
||||
{
|
||||
marker = marker_cache::instance()->find(filename, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
marker.reset(boost::make_shared<mapnik::marker>());
|
||||
}
|
||||
|
||||
if (text.length() > 0 && marker)
|
||||
{
|
||||
face_set_ptr faces;
|
||||
|
||||
if (sym.get_fontset().size() > 0)
|
||||
text_placement_info_ptr placement;
|
||||
while ((placement = helper.get_placement())) {
|
||||
for (unsigned int ii = 0; ii < placement->placements.size(); ++ii)
|
||||
{
|
||||
faces = font_manager_.get_face_set(sym.get_fontset());
|
||||
}
|
||||
else
|
||||
{
|
||||
faces = font_manager_.get_face_set(sym.get_face_name());
|
||||
}
|
||||
|
||||
if (faces->size() > 0)
|
||||
{
|
||||
cairo_context context(context_);
|
||||
string_info info(text);
|
||||
|
||||
placement_finder<label_collision_detector4> finder(detector_);
|
||||
|
||||
faces->set_character_sizes(placement_options->text_size);
|
||||
faces->get_string_info(info, text, 0);
|
||||
|
||||
int w = (*marker)->width();
|
||||
int h = (*marker)->height();
|
||||
|
||||
metawriter_with_properties writer = sym.get_metawriter();
|
||||
|
||||
for (unsigned i = 0; i < feature.num_geometries(); ++i)
|
||||
{
|
||||
geometry_type const& geom = feature.get_geometry(i);
|
||||
if (geom.num_points() > 0) // don't bother with empty geometries
|
||||
{
|
||||
path_type path(t_, geom, prj_trans);
|
||||
|
||||
label_placement_enum how_placed = sym.get_label_placement();
|
||||
if (how_placed == POINT_PLACEMENT || how_placed == VERTEX_PLACEMENT || how_placed == INTERIOR_PLACEMENT)
|
||||
{
|
||||
// for every vertex, try and place a shield/text
|
||||
geom.rewind(0);
|
||||
placement text_placement(info, sym, 1.0, w, h, false);
|
||||
text_placement.avoid_edges = sym.get_avoid_edges();
|
||||
text_placement.allow_overlap = sym.get_allow_overlap();
|
||||
if (writer.first)
|
||||
text_placement.collect_extents = true; // needed for inmem metawriter
|
||||
position const& pos = sym.get_displacement();
|
||||
position const& shield_pos = sym.get_shield_displacement();
|
||||
for( unsigned jj = 0; jj < geom.num_points(); jj++ )
|
||||
{
|
||||
double label_x;
|
||||
double label_y;
|
||||
double z=0.0;
|
||||
|
||||
if( how_placed == VERTEX_PLACEMENT )
|
||||
geom.vertex(&label_x,&label_y); // by vertex
|
||||
else if( how_placed == INTERIOR_PLACEMENT )
|
||||
geom.label_interior_position(&label_x,&label_y);
|
||||
else
|
||||
geom.label_position(&label_x, &label_y); // by middle of line or by point
|
||||
prj_trans.backward(label_x,label_y, z);
|
||||
t_.forward(&label_x,&label_y);
|
||||
|
||||
label_x += boost::get<0>(shield_pos);
|
||||
label_y += boost::get<1>(shield_pos);
|
||||
|
||||
finder.find_point_placement(text_placement, placement_options,
|
||||
label_x, label_y, 0.0,
|
||||
sym.get_line_spacing(),
|
||||
sym.get_character_spacing());
|
||||
|
||||
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ ii)
|
||||
{
|
||||
double x = text_placement.placements[ii].starting_x;
|
||||
double y = text_placement.placements[ii].starting_y;
|
||||
|
||||
int px;
|
||||
int py;
|
||||
box2d<double> label_ext;
|
||||
|
||||
if( !sym.get_unlock_image() )
|
||||
{
|
||||
// center image at text center position
|
||||
// remove displacement from image label
|
||||
double lx = x - boost::get<0>(pos);
|
||||
double ly = y - boost::get<1>(pos);
|
||||
px=int(floor(lx - (0.5 * w)));
|
||||
py=int(floor(ly - (0.5 * h)));
|
||||
label_ext.init( floor(lx - 0.5 * w), floor(ly - 0.5 * h), ceil (lx + 0.5 * w), ceil (ly + 0.5 * h) );
|
||||
}
|
||||
else
|
||||
{ // center image at reference location
|
||||
px=int(floor(label_x - 0.5 * w));
|
||||
py=int(floor(label_y - 0.5 * h));
|
||||
label_ext.init( floor(label_x - 0.5 * w), floor(label_y - 0.5 * h), ceil (label_x + 0.5 * w), ceil (label_y + 0.5 * h));
|
||||
}
|
||||
|
||||
if ( sym.get_allow_overlap() || detector_.has_placement(label_ext) )
|
||||
{
|
||||
render_marker(px,py,**marker, tr, sym.get_opacity());
|
||||
|
||||
context.add_text(text_placement.placements[ii],
|
||||
face_manager_,
|
||||
faces,
|
||||
placement_options->text_size,
|
||||
sym.get_fill(),
|
||||
sym.get_halo_radius(),
|
||||
sym.get_halo_fill()
|
||||
);
|
||||
if (writer.first) {
|
||||
writer.first->add_box(box2d<double>(px,py,px+w,py+h), feature, t_, writer.second);
|
||||
writer.first->add_text(text_placement, faces, feature, t_, writer.second); //Only 1 placement
|
||||
}
|
||||
detector_.insert(label_ext);
|
||||
}
|
||||
}
|
||||
|
||||
finder.update_detector(text_placement);
|
||||
}
|
||||
}
|
||||
else if (geom.num_points() > 1 && how_placed == LINE_PLACEMENT)
|
||||
{
|
||||
placement text_placement(info, sym, 1.0, w, h, true);
|
||||
|
||||
text_placement.avoid_edges = sym.get_avoid_edges();
|
||||
finder.find_point_placements<path_type>(text_placement, placement_options, path);
|
||||
|
||||
position const& pos = sym.get_displacement();
|
||||
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ ii)
|
||||
{
|
||||
double x = text_placement.placements[ii].starting_x;
|
||||
double y = text_placement.placements[ii].starting_y;
|
||||
double lx = x - boost::get<0>(pos);
|
||||
double ly = y - boost::get<1>(pos);
|
||||
int px=int(floor(lx - (0.5*w)));
|
||||
int py=int(floor(ly - (0.5*h)));
|
||||
|
||||
render_marker(px,py,**marker, tr, sym.get_opacity());
|
||||
|
||||
context.add_text(text_placement.placements[ii],
|
||||
face_manager_,
|
||||
faces,
|
||||
placement_options->text_size,
|
||||
sym.get_fill(),
|
||||
sym.get_halo_radius(),
|
||||
sym.get_halo_fill()
|
||||
);
|
||||
if (writer.first) writer.first->add_box(box2d<double>(px,py,px+w,py+h), feature, t_, writer.second);
|
||||
}
|
||||
finder.update_detector(text_placement);
|
||||
if (writer.first) writer.first->add_text(text_placement, faces, feature, t_, writer.second); //More than one placement
|
||||
}
|
||||
}
|
||||
}
|
||||
std::pair<int, int> marker_pos = helper.get_marker_position(placement->placements[ii]);
|
||||
render_marker(marker_pos.first, marker_pos.second,
|
||||
helper.get_marker(), helper.get_transform(),
|
||||
sym.get_opacity());
|
||||
context.add_text(placement->placements[ii], face_manager_, font_manager_);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void cairo_renderer_base::process(line_pattern_symbolizer const& sym,
|
||||
|
@ -1435,17 +1254,15 @@ void cairo_renderer_base::process(text_symbolizer const& sym,
|
|||
Feature const& feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
text_symbolizer_helper<face_manager<freetype_engine>, label_collision_detector4> helper(detector_.extent().width(), detector_.extent().height(), 1.0 /*scale_factor*/, t_, font_manager_, detector_);
|
||||
|
||||
text_placement_info_ptr placement = helper.get_placement(sym, feature, prj_trans);
|
||||
|
||||
if (!placement) return;
|
||||
text_symbolizer_helper<face_manager<freetype_engine>, label_collision_detector4> helper(sym, feature, prj_trans, detector_.extent().width(), detector_.extent().height(), 1.0 /*scale_factor*/, t_, font_manager_, detector_);
|
||||
|
||||
cairo_context context(context_);
|
||||
|
||||
for (unsigned int ii = 0; ii < placement->placements.size(); ++ii)
|
||||
{
|
||||
context.add_text(placement->placements[ii], face_manager_, font_manager_);
|
||||
text_placement_info_ptr placement;
|
||||
while ((placement = helper.get_placement())) {
|
||||
for (unsigned int ii = 0; ii < placement->placements.size(); ++ii)
|
||||
{
|
||||
context.add_text(placement->placements[ii], face_manager_, font_manager_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
#include <mapnik/grid/grid_pixel.hpp>
|
||||
#include <mapnik/grid/grid.hpp>
|
||||
|
||||
#include <mapnik/expression_evaluator.hpp>
|
||||
#include <mapnik/marker_cache.hpp>
|
||||
#include <mapnik/symbolizer_helpers.hpp>
|
||||
|
||||
#include <mapnik/svg/svg_converter.hpp>
|
||||
#include <mapnik/svg/svg_renderer.hpp>
|
||||
#include <mapnik/svg/svg_path_adapter.hpp>
|
||||
|
@ -44,201 +44,36 @@ void grid_renderer<T>::process(shield_symbolizer const& sym,
|
|||
Feature const& feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
#if 0
|
||||
typedef coord_transform2<CoordTransform,geometry_type> path_type;
|
||||
shield_symbolizer_helper<face_manager<freetype_engine>,
|
||||
label_collision_detector4> helper(
|
||||
sym, feature, prj_trans,
|
||||
width_, height_,
|
||||
scale_factor_,
|
||||
t_, font_manager_, detector_);
|
||||
|
||||
bool placement_found = false;
|
||||
|
||||
text_placement_info_ptr placement_options = sym.get_placement_options()->get_placement_info();
|
||||
placement_options->next();
|
||||
placement_options->next_position_only();
|
||||
text_renderer<T> ren(pixmap_, font_manager_, *(font_manager_.get_stroker()));
|
||||
|
||||
UnicodeString text;
|
||||
if( sym.get_no_text() )
|
||||
text = UnicodeString( " " ); // TODO: fix->use 'space' as the text to render
|
||||
else
|
||||
{
|
||||
expression_ptr name_expr = sym.get_name();
|
||||
if (!name_expr) return;
|
||||
value_type result = boost::apply_visitor(evaluate<Feature,value_type>(feature),*name_expr);
|
||||
text = result.to_unicode();
|
||||
}
|
||||
|
||||
if ( sym.get_text_transform() == UPPERCASE)
|
||||
{
|
||||
text = text.toUpper();
|
||||
}
|
||||
else if ( sym.get_text_transform() == LOWERCASE)
|
||||
{
|
||||
text = text.toLower();
|
||||
}
|
||||
else if ( sym.get_text_transform() == CAPITALIZE)
|
||||
{
|
||||
text = text.toTitle(NULL);
|
||||
}
|
||||
|
||||
agg::trans_affine tr;
|
||||
boost::array<double,6> const& m = sym.get_transform();
|
||||
tr.load_from(&m[0]);
|
||||
tr = agg::trans_affine_scaling(scale_factor_) * tr;
|
||||
|
||||
std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
|
||||
boost::optional<mapnik::marker_ptr> marker;
|
||||
if ( !filename.empty() )
|
||||
{
|
||||
marker = marker_cache::instance()->find(filename, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
marker.reset(boost::make_shared<mapnik::marker>());
|
||||
}
|
||||
|
||||
if (text.length() > 0 && marker)
|
||||
{
|
||||
face_set_ptr faces;
|
||||
|
||||
if (sym.get_fontset().size() > 0)
|
||||
text_placement_info_ptr placement;
|
||||
while ((placement = helper.get_placement())) {
|
||||
placement_found = true;
|
||||
for (unsigned int ii = 0; ii < placement->placements.size(); ++ii)
|
||||
{
|
||||
faces = font_manager_.get_face_set(sym.get_fontset());
|
||||
}
|
||||
else
|
||||
{
|
||||
faces = font_manager_.get_face_set(sym.get_face_name());
|
||||
}
|
||||
std::pair<int, int> marker_pos = helper.get_marker_position(placement->placements[ii]);
|
||||
render_marker(feature, pixmap_.get_resolution(),
|
||||
marker_pos.first, marker_pos.second,
|
||||
helper.get_marker(), helper.get_transform(),
|
||||
sym.get_opacity());
|
||||
|
||||
stroker_ptr strk = font_manager_.get_stroker();
|
||||
if (strk && faces->size() > 0)
|
||||
{
|
||||
text_renderer<T> ren(pixmap_, faces, *strk);
|
||||
|
||||
ren.set_character_size(sym.get_text_size() * scale_factor_ * (1.0/pixmap_.get_resolution()));
|
||||
ren.set_fill(sym.get_fill());
|
||||
ren.set_halo_fill(sym.get_halo_fill());
|
||||
ren.set_halo_radius(sym.get_halo_radius() * scale_factor_);
|
||||
ren.set_opacity(sym.get_text_opacity());
|
||||
|
||||
placement_finder<label_collision_detector4> finder(detector_);
|
||||
|
||||
string_info info(text);
|
||||
|
||||
faces->get_string_info(info, text, 0);
|
||||
|
||||
// TODO- clamp to at least 4 px otherwise interactivity is too small
|
||||
int w = (*marker)->width()/pixmap_.get_resolution();
|
||||
int h = (*marker)->height()/pixmap_.get_resolution();
|
||||
|
||||
for (unsigned i = 0; i < feature.num_geometries(); ++i)
|
||||
{
|
||||
geometry_type const& geom = feature.get_geometry(i);
|
||||
if (geom.num_points() > 0 )
|
||||
{
|
||||
path_type path(t_,geom,prj_trans);
|
||||
|
||||
label_placement_enum how_placed = sym.get_label_placement();
|
||||
if (how_placed == POINT_PLACEMENT || how_placed == VERTEX_PLACEMENT || how_placed == INTERIOR_PLACEMENT)
|
||||
{
|
||||
// for every vertex, try and place a shield/text
|
||||
geom.rewind(0);
|
||||
placement text_placement(info, sym, scale_factor_, w, h, false);
|
||||
text_placement.avoid_edges = sym.get_avoid_edges();
|
||||
text_placement.allow_overlap = sym.get_allow_overlap();
|
||||
position const& pos = sym.get_displacement();
|
||||
position const& shield_pos = sym.get_shield_displacement();
|
||||
for( unsigned jj = 0; jj < geom.num_points(); jj++ )
|
||||
{
|
||||
double label_x;
|
||||
double label_y;
|
||||
double z=0.0;
|
||||
|
||||
if( how_placed == VERTEX_PLACEMENT )
|
||||
geom.vertex(&label_x,&label_y); // by vertex
|
||||
else if( how_placed == INTERIOR_PLACEMENT )
|
||||
geom.label_interior_position(&label_x,&label_y);
|
||||
else
|
||||
geom.label_position(&label_x, &label_y); // by middle of line or by point
|
||||
prj_trans.backward(label_x,label_y, z);
|
||||
t_.forward(&label_x,&label_y);
|
||||
|
||||
label_x += boost::get<0>(shield_pos);
|
||||
label_y += boost::get<1>(shield_pos);
|
||||
|
||||
finder.find_point_placement( text_placement, placement_options, label_x, label_y, 0.0,
|
||||
sym.get_line_spacing(),
|
||||
sym.get_character_spacing());
|
||||
|
||||
// check to see if image overlaps anything too, there is only ever 1 placement found for points and verticies
|
||||
if( text_placement.placements.size() > 0)
|
||||
{
|
||||
placement_found = true;
|
||||
double x = floor(text_placement.placements[0].starting_x);
|
||||
double y = floor(text_placement.placements[0].starting_y);
|
||||
int px;
|
||||
int py;
|
||||
box2d<double> label_ext;
|
||||
|
||||
if( !sym.get_unlock_image() )
|
||||
{
|
||||
// center image at text center position
|
||||
// remove displacement from image label
|
||||
double lx = x - boost::get<0>(pos);
|
||||
double ly = y - boost::get<1>(pos);
|
||||
px=int(floor(lx - (0.5 * w)));
|
||||
py=int(floor(ly - (0.5 * h)));
|
||||
label_ext.init( floor(lx - 0.5 * w), floor(ly - 0.5 * h), ceil (lx + 0.5 * w), ceil (ly + 0.5 * h) );
|
||||
}
|
||||
else
|
||||
{ // center image at reference location
|
||||
px=int(floor(label_x - 0.5 * w));
|
||||
py=int(floor(label_y - 0.5 * h));
|
||||
label_ext.init( floor(label_x - 0.5 * w), floor(label_y - 0.5 * h), ceil (label_x + 0.5 * w), ceil (label_y + 0.5 * h));
|
||||
}
|
||||
|
||||
if ( sym.get_allow_overlap() || detector_.has_placement(label_ext) )
|
||||
{
|
||||
render_marker(feature,pixmap_.get_resolution(),px,py,**marker,tr,sym.get_opacity());
|
||||
|
||||
box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[0]);
|
||||
ren.render_id(feature.id(),x,y,2);
|
||||
detector_.insert(label_ext);
|
||||
finder.update_detector(text_placement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (geom.num_points() > 1 && how_placed == LINE_PLACEMENT)
|
||||
{
|
||||
placement text_placement(info, sym, scale_factor_, w, h, true);
|
||||
|
||||
text_placement.avoid_edges = sym.get_avoid_edges();
|
||||
finder.find_point_placements<path_type>(text_placement, placement_options, path);
|
||||
|
||||
position const& pos = sym.get_displacement();
|
||||
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ ii)
|
||||
{
|
||||
placement_found= true;
|
||||
double x = floor(text_placement.placements[ii].starting_x);
|
||||
double y = floor(text_placement.placements[ii].starting_y);
|
||||
|
||||
double lx = x - boost::get<0>(pos);
|
||||
double ly = y - boost::get<1>(pos);
|
||||
int px=int(floor(lx - (0.5*w)));
|
||||
int py=int(floor(ly - (0.5*h)));
|
||||
|
||||
render_marker(feature,pixmap_.get_resolution(),px,py,**marker,tr,sym.get_opacity());
|
||||
|
||||
box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[ii]);
|
||||
ren.render_id(feature.id(),x,y,2);
|
||||
}
|
||||
finder.update_detector(text_placement);
|
||||
}
|
||||
}
|
||||
}
|
||||
double x = floor(placement->placements[ii].starting_x);
|
||||
double y = floor(placement->placements[ii].starting_y);
|
||||
ren.prepare_glyphs(&(placement->placements[ii]));
|
||||
ren.render_id(feature.id(), x, y, 2);
|
||||
}
|
||||
}
|
||||
if (placement_found)
|
||||
pixmap_.add_feature(feature);
|
||||
#endif
|
||||
}
|
||||
|
||||
template void grid_renderer<grid>::process(shield_symbolizer const&,
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
|
||||
// mapnik
|
||||
#include <mapnik/grid/grid_renderer.hpp>
|
||||
#include <mapnik/font_engine_freetype.hpp>
|
||||
#include <mapnik/expression_evaluator.hpp>
|
||||
#include <mapnik/symbolizer_helpers.hpp>
|
||||
|
||||
namespace mapnik {
|
||||
|
@ -36,23 +34,26 @@ void grid_renderer<T>::process(text_symbolizer const& sym,
|
|||
{
|
||||
text_symbolizer_helper<face_manager<freetype_engine>,
|
||||
label_collision_detector4> helper(
|
||||
sym, feature, prj_trans,
|
||||
width_, height_,
|
||||
scale_factor_ * (1.0/pixmap_.get_resolution()),
|
||||
t_, font_manager_, detector_);
|
||||
|
||||
text_placement_info_ptr placement = helper.get_placement(sym, feature, prj_trans);
|
||||
|
||||
if (!placement) return;
|
||||
bool placement_found = false;
|
||||
|
||||
text_renderer<T> ren(pixmap_, font_manager_, *(font_manager_.get_stroker()));
|
||||
for (unsigned int ii = 0; ii < placement->placements.size(); ++ii)
|
||||
{
|
||||
double x = placement->placements[ii].starting_x;
|
||||
double y = placement->placements[ii].starting_y;
|
||||
ren.prepare_glyphs(&(placement->placements[ii]));
|
||||
ren.render_id(feature.id(),x,y,2);
|
||||
|
||||
text_placement_info_ptr placement;
|
||||
while ((placement = helper.get_placement())) {
|
||||
placement_found = true;
|
||||
for (unsigned int ii = 0; ii < placement->placements.size(); ++ii)
|
||||
{
|
||||
double x = placement->placements[ii].starting_x;
|
||||
double y = placement->placements[ii].starting_y;
|
||||
ren.prepare_glyphs(&(placement->placements[ii]));
|
||||
ren.render_id(feature.id(),x,y,2);
|
||||
}
|
||||
}
|
||||
pixmap_.add_feature(feature);
|
||||
if (placement_found) pixmap_.add_feature(feature);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1281,8 +1281,7 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym )
|
|||
placement_finder = text_placements_ptr(new text_placements_dummy());
|
||||
}
|
||||
|
||||
text_symbolizer text_symbol = text_symbolizer(placement_finder);
|
||||
placement_finder->properties.set_values_from_xml(sym, fontsets_);
|
||||
placement_finder->properties.from_xml(sym, fontsets_);
|
||||
if (strict_) ensure_font_face(placement_finder->properties.processor.defaults.face_name);
|
||||
if (list) {
|
||||
ptree::const_iterator symIter = sym.begin();
|
||||
|
@ -1296,10 +1295,12 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym )
|
|||
}
|
||||
ensure_attrs(symIter->second, "TextSymbolizer/Placement", s_common.str());
|
||||
text_symbolizer_properties & p = list->add();
|
||||
p.set_values_from_xml(symIter->second, fontsets_);
|
||||
p.from_xml(symIter->second, fontsets_);
|
||||
if (strict_) ensure_font_face(p.processor.defaults.face_name);
|
||||
}
|
||||
}
|
||||
|
||||
text_symbolizer text_symbol = text_symbolizer(placement_finder);
|
||||
parse_metawriter_in_symbolizer(text_symbol, sym);
|
||||
rule.append(text_symbol);
|
||||
}
|
||||
|
@ -1312,26 +1313,64 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym )
|
|||
|
||||
void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym )
|
||||
{
|
||||
std::string s_common(
|
||||
"name,face-name,fontset-name,size,fill,orientation,"
|
||||
"dx,dy,placement,vertical-alignment,halo-fill,"
|
||||
"halo-radius,text-ratio,wrap-width,wrap-before,"
|
||||
"wrap-character,text-transform,line-spacing,"
|
||||
"label-position-tolerance,character-spacing,"
|
||||
"spacing,minimum-distance,minimum-padding,minimum-path-length,"
|
||||
"avoid-edges,allow-overlap,opacity,max-char-angle-delta,"
|
||||
"horizontal-alignment,justify-alignment");
|
||||
|
||||
std::stringstream s;
|
||||
s << "name,face-name,fontset-name,size,fill,"
|
||||
<< "dx,dy,placement,vertical-alignment,halo-fill,"
|
||||
<< "halo-radius,text-ratio,wrap-width,wrap-before,"
|
||||
<< "wrap-character,text-transform,line-spacing,"
|
||||
<< "label-position-tolerance,character-spacing,"
|
||||
<< "spacing,minimum-distance,minimum-padding,"
|
||||
<< "avoid-edges,allow-overlap,opacity,max-char-angle-delta,"
|
||||
<< "horizontal-alignment,justify-alignment,"
|
||||
// additional for shield
|
||||
/* transform instead of orientation */
|
||||
<< "file,base,transform,shield-dx,shield-dy,"
|
||||
<< "text-opacity,unlock-image,no-text,"
|
||||
<< "meta-writer,meta-output";
|
||||
std::string s_symbolizer(s_common + ",file,base,"
|
||||
"transform,shield-dx,shield-dy,text-opacity,"
|
||||
"unlock-image"
|
||||
"placements,placement-type,meta-writer,meta-output");
|
||||
|
||||
ensure_attrs(sym, "ShieldSymbolizer", s.str());
|
||||
ensure_attrs(sym, "ShieldSymbolizer", s_symbolizer);
|
||||
try
|
||||
{
|
||||
shield_symbolizer shield_symbol = shield_symbolizer();
|
||||
text_placements_ptr placement_finder;
|
||||
text_placements_list *list = 0;
|
||||
optional<std::string> placement_type = get_opt_attr<std::string>(sym, "placement-type");
|
||||
if (placement_type) {
|
||||
if (*placement_type == "simple") {
|
||||
placement_finder = text_placements_ptr(
|
||||
new text_placements_simple(
|
||||
get_attr<std::string>(sym, "placements", "X")));
|
||||
} else if (*placement_type == "list") {
|
||||
list = new text_placements_list();
|
||||
placement_finder = text_placements_ptr(list);
|
||||
} else if (*placement_type != "dummy" && *placement_type != "") {
|
||||
throw config_error(std::string("Unknown placement type '"+*placement_type+"'"));
|
||||
}
|
||||
}
|
||||
if (!placement_finder) {
|
||||
placement_finder = text_placements_ptr(new text_placements_dummy());
|
||||
}
|
||||
|
||||
placement_finder->properties.from_xml(sym, fontsets_);
|
||||
if (strict_) ensure_font_face(placement_finder->properties.processor.defaults.face_name);
|
||||
if (list) {
|
||||
ptree::const_iterator symIter = sym.begin();
|
||||
ptree::const_iterator endSym = sym.end();
|
||||
for( ;symIter != endSym; ++symIter) {
|
||||
if (symIter->first.find('<') != std::string::npos) continue;
|
||||
if (symIter->first != "Placement")
|
||||
{
|
||||
// throw config_error("Unknown element '" + symIter->first + "'"); TODO
|
||||
continue;
|
||||
}
|
||||
ensure_attrs(symIter->second, "TextSymbolizer/Placement", s_common);
|
||||
text_symbolizer_properties & p = list->add();
|
||||
p.from_xml(symIter->second, fontsets_);
|
||||
if (strict_) ensure_font_face(p.processor.defaults.face_name);
|
||||
}
|
||||
}
|
||||
|
||||
shield_symbolizer shield_symbol = shield_symbolizer(placement_finder);
|
||||
/* Symbolizer specific attributes. */
|
||||
optional<std::string> transform_wkt = get_opt_attr<std::string>(sym, "transform");
|
||||
if (transform_wkt)
|
||||
{
|
||||
|
@ -1378,14 +1417,6 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym )
|
|||
shield_symbol.set_unlock_image( * unlock_image );
|
||||
}
|
||||
|
||||
// no text
|
||||
optional<boolean> no_text =
|
||||
get_opt_attr<boolean>(sym, "no-text");
|
||||
if (no_text)
|
||||
{
|
||||
shield_symbol.set_no_text( * no_text );
|
||||
}
|
||||
|
||||
parse_metawriter_in_symbolizer(shield_symbol, sym);
|
||||
|
||||
std::string image_file = get_attr<std::string>(sym, "file");
|
||||
|
@ -1418,8 +1449,6 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym )
|
|||
std::clog << "### WARNING: " << msg << endl;
|
||||
}
|
||||
}
|
||||
text_placements_ptr placement_finder = shield_symbol.get_placement_options();
|
||||
placement_finder->properties.set_values_from_xml(sym, fontsets_);
|
||||
rule.append(shield_symbol);
|
||||
}
|
||||
catch (const config_error & ex)
|
||||
|
|
|
@ -193,7 +193,7 @@ void metawriter_json_stream::add_text(text_placement_info const& p,
|
|||
|
||||
*/
|
||||
for (unsigned n = 0; n < p.placements.size(); n++) {
|
||||
placement_element & current_placement = const_cast<placement_element &>(p.placements[n]);
|
||||
text_path & current_placement = const_cast<text_path &>(p.placements[n]);
|
||||
|
||||
bool inside = false; /* Part of text is inside rendering region */
|
||||
bool straight = true;
|
||||
|
|
|
@ -103,6 +103,7 @@ placement_finder<DetectorT>::placement_finder(text_placement_info &placement_inf
|
|||
dimensions_(detector_.extent()),
|
||||
info_(info), p(placement_info.properties), pi(placement_info), string_width_(0), string_height_(0), first_line_space_(0), valign_(V_AUTO), halign_(H_AUTO), line_breaks_(), line_sizes_()
|
||||
{
|
||||
placement_info.placements.clear(); //Remove left overs
|
||||
}
|
||||
|
||||
template <typename DetectorT>
|
||||
|
@ -111,6 +112,7 @@ placement_finder<DetectorT>::placement_finder(text_placement_info &placement_inf
|
|||
dimensions_(extent),
|
||||
info_(info), p(placement_info.properties), pi(placement_info), string_width_(0), string_height_(0), first_line_space_(0), valign_(V_AUTO), halign_(H_AUTO), line_breaks_(), line_sizes_()
|
||||
{
|
||||
placement_info.placements.clear(); //Remove left overs
|
||||
}
|
||||
|
||||
template <typename DetectorT>
|
||||
|
@ -289,9 +291,9 @@ void placement_finder<DetectorT>::init_alignment()
|
|||
{
|
||||
valign_ = p.valign;
|
||||
if (valign_ == V_AUTO) {
|
||||
if (p.displacement.get<1>() > 0.0)
|
||||
if (p.displacement.second > 0.0)
|
||||
valign_ = V_BOTTOM;
|
||||
else if (p.displacement.get<1>() < 0.0)
|
||||
else if (p.displacement.second < 0.0)
|
||||
valign_ = V_TOP;
|
||||
else
|
||||
valign_ = V_MIDDLE;
|
||||
|
@ -299,9 +301,9 @@ void placement_finder<DetectorT>::init_alignment()
|
|||
|
||||
halign_ = p.halign;
|
||||
if (halign_ == H_AUTO) {
|
||||
if (p.displacement.get<0>() > 0.0)
|
||||
if (p.displacement.first > 0.0)
|
||||
halign_ = H_RIGHT;
|
||||
else if (p.displacement.get<0>() < 0.0)
|
||||
else if (p.displacement.first < 0.0)
|
||||
halign_ = H_LEFT;
|
||||
else
|
||||
halign_ = H_MIDDLE;
|
||||
|
@ -310,7 +312,7 @@ void placement_finder<DetectorT>::init_alignment()
|
|||
|
||||
|
||||
template <typename DetectorT>
|
||||
void placement_finder<DetectorT>::adjust_position(placement_element *current_placement, double label_x, double label_y)
|
||||
void placement_finder<DetectorT>::adjust_position(text_path *current_placement, double label_x, double label_y)
|
||||
{
|
||||
// if needed, adjust for desired vertical alignment
|
||||
current_placement->starting_y = label_y; // no adjustment, default is MIDDLE
|
||||
|
@ -331,8 +333,8 @@ void placement_finder<DetectorT>::adjust_position(placement_element *current_pla
|
|||
current_placement->starting_x += 0.5 * string_width_; // move center right by 1/2 the string width
|
||||
|
||||
// adjust text envelope position by user's x-y displacement (dx, dy)
|
||||
current_placement->starting_x += pi.get_scale_factor() * boost::tuples::get<0>(p.displacement);
|
||||
current_placement->starting_y += pi.get_scale_factor() * boost::tuples::get<1>(p.displacement);
|
||||
current_placement->starting_x += pi.get_scale_factor() * p.displacement.first;
|
||||
current_placement->starting_y += pi.get_scale_factor() * p.displacement.second;
|
||||
|
||||
}
|
||||
|
||||
|
@ -348,7 +350,7 @@ void placement_finder<DetectorT>::find_point_placement(double label_x, double la
|
|||
double sina = std::sin(rad);
|
||||
|
||||
double x, y;
|
||||
std::auto_ptr<placement_element> current_placement(new placement_element);
|
||||
std::auto_ptr<text_path> current_placement(new text_path);
|
||||
|
||||
adjust_position(current_placement.get(), label_x, label_y);
|
||||
|
||||
|
@ -456,12 +458,10 @@ void placement_finder<DetectorT>::find_point_placement(double label_x, double la
|
|||
x += cwidth; // move position to next character
|
||||
}
|
||||
|
||||
#if 0
|
||||
//TODO
|
||||
// check the placement of any additional envelopes
|
||||
if (!p.allow_overlap && !p.additional_boxes.empty())
|
||||
if (!p.allow_overlap && !pi.additional_boxes.empty())
|
||||
{
|
||||
BOOST_FOREACH(box2d<double> box, p.additional_boxes)
|
||||
BOOST_FOREACH(box2d<double> box, pi.additional_boxes)
|
||||
{
|
||||
box2d<double> pt(box.minx() + current_placement->starting_x,
|
||||
box.miny() + current_placement->starting_y,
|
||||
|
@ -474,7 +474,6 @@ void placement_finder<DetectorT>::find_point_placement(double label_x, double la
|
|||
c_envelopes.push(pt);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// since there was no early exit, add the character envelopes to the placements' envelopes
|
||||
while( !c_envelopes.empty() )
|
||||
|
@ -535,7 +534,7 @@ void placement_finder<DetectorT>::find_line_placements(PathT & shape_path)
|
|||
|
||||
double distance = 0.0;
|
||||
|
||||
double displacement = boost::tuples::get<1>(p.displacement); // displace by dy
|
||||
double displacement = p.displacement.second; // displace by dy
|
||||
|
||||
//Calculate a target_distance that will place the labels centered evenly rather than offset from the start of the linestring
|
||||
if (total_distance < string_width_) //Can't place any strings
|
||||
|
@ -595,7 +594,7 @@ void placement_finder<DetectorT>::find_line_placements(PathT & shape_path)
|
|||
{
|
||||
//Record details for the start of the string placement
|
||||
int orientation = 0;
|
||||
std::auto_ptr<placement_element> current_placement = get_placement_offset(path_positions, path_distances, orientation, index, segment_length - (distance - target_distance) + (diff*dir));
|
||||
std::auto_ptr<text_path> current_placement = get_placement_offset(path_positions, path_distances, orientation, index, segment_length - (distance - target_distance) + (diff*dir));
|
||||
|
||||
//We were unable to place here
|
||||
if (current_placement.get() == NULL)
|
||||
|
@ -657,7 +656,7 @@ void placement_finder<DetectorT>::find_line_placements(PathT & shape_path)
|
|||
}
|
||||
|
||||
template <typename DetectorT>
|
||||
std::auto_ptr<placement_element> placement_finder<DetectorT>::get_placement_offset(const std::vector<vertex2d> &path_positions, const std::vector<double> &path_distances, int &orientation, unsigned index, double distance)
|
||||
std::auto_ptr<text_path> placement_finder<DetectorT>::get_placement_offset(const std::vector<vertex2d> &path_positions, const std::vector<double> &path_distances, int &orientation, unsigned index, double distance)
|
||||
{
|
||||
//Check that the given distance is on the given index and find the correct index and distance if not
|
||||
while (distance < 0 && index > 1)
|
||||
|
@ -666,7 +665,7 @@ std::auto_ptr<placement_element> placement_finder<DetectorT>::get_placement_offs
|
|||
distance += path_distances[index];
|
||||
}
|
||||
if (index <= 1 && distance < 0) //We've gone off the start, fail out
|
||||
return std::auto_ptr<placement_element>(NULL);
|
||||
return std::auto_ptr<text_path>(NULL);
|
||||
|
||||
//Same thing, checking if we go off the end
|
||||
while (index < path_distances.size() && distance > path_distances[index])
|
||||
|
@ -675,13 +674,13 @@ std::auto_ptr<placement_element> placement_finder<DetectorT>::get_placement_offs
|
|||
index++;
|
||||
}
|
||||
if (index >= path_distances.size())
|
||||
return std::auto_ptr<placement_element>(NULL);
|
||||
return std::auto_ptr<text_path>(NULL);
|
||||
|
||||
//Keep track of the initial index,distance incase we need to re-call get_placement_offset
|
||||
const unsigned initial_index = index;
|
||||
const double initial_distance = distance;
|
||||
|
||||
std::auto_ptr<placement_element> current_placement(new placement_element);
|
||||
std::auto_ptr<text_path> current_placement(new text_path);
|
||||
|
||||
double old_x = path_positions[index-1].x;
|
||||
double old_y = path_positions[index-1].y;
|
||||
|
@ -695,7 +694,7 @@ std::auto_ptr<placement_element> placement_finder<DetectorT>::get_placement_offs
|
|||
double segment_length = path_distances[index];
|
||||
if (segment_length == 0) {
|
||||
// Not allowed to place across on 0 length segments or discontinuities
|
||||
return std::auto_ptr<placement_element>(NULL);
|
||||
return std::auto_ptr<text_path>(NULL);
|
||||
}
|
||||
|
||||
current_placement->starting_x = old_x + dx*distance/segment_length;
|
||||
|
@ -719,7 +718,7 @@ std::auto_ptr<placement_element> placement_finder<DetectorT>::get_placement_offs
|
|||
//Coordinates this character will start at
|
||||
if (segment_length == 0) {
|
||||
// Not allowed to place across on 0 length segments or discontinuities
|
||||
return std::auto_ptr<placement_element>(NULL);
|
||||
return std::auto_ptr<text_path>(NULL);
|
||||
}
|
||||
double start_x = old_x + dx*distance/segment_length;
|
||||
double start_y = old_y + dy*distance/segment_length;
|
||||
|
@ -747,7 +746,7 @@ std::auto_ptr<placement_element> placement_finder<DetectorT>::get_placement_offs
|
|||
if (index >= path_positions.size()) //Bail out if we run off the end of the shape
|
||||
{
|
||||
//std::clog << "FAIL: Out of space" << std::endl;
|
||||
return std::auto_ptr<placement_element>(NULL);
|
||||
return std::auto_ptr<text_path>(NULL);
|
||||
}
|
||||
new_x = path_positions[index].x;
|
||||
new_y = path_positions[index].y;
|
||||
|
@ -784,7 +783,7 @@ std::auto_ptr<placement_element> placement_finder<DetectorT>::get_placement_offs
|
|||
fabs(angle_delta) > p.max_char_angle_delta)
|
||||
{
|
||||
//std::clog << "FAIL: Too Bendy!" << std::endl;
|
||||
return std::auto_ptr<placement_element>(NULL);
|
||||
return std::auto_ptr<text_path>(NULL);
|
||||
}
|
||||
|
||||
double render_angle = angle;
|
||||
|
@ -833,7 +832,7 @@ std::auto_ptr<placement_element> placement_finder<DetectorT>::get_placement_offs
|
|||
{
|
||||
//Otherwise we have failed to find a placement
|
||||
//std::clog << "FAIL: Double upside-down!" << std::endl;
|
||||
return std::auto_ptr<placement_element>(NULL);
|
||||
return std::auto_ptr<text_path>(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -841,7 +840,7 @@ std::auto_ptr<placement_element> placement_finder<DetectorT>::get_placement_offs
|
|||
}
|
||||
|
||||
template <typename DetectorT>
|
||||
bool placement_finder<DetectorT>::test_placement(const std::auto_ptr<placement_element> & current_placement, const int & orientation)
|
||||
bool placement_finder<DetectorT>::test_placement(const std::auto_ptr<text_path> & current_placement, const int & orientation)
|
||||
{
|
||||
//Create and test envelopes
|
||||
bool status = true;
|
||||
|
@ -996,53 +995,6 @@ void placement_finder<DetectorT>::clear()
|
|||
detector_.clear();
|
||||
}
|
||||
|
||||
template <typename DetectorT>
|
||||
void placement_finder<DetectorT>::find_placement(double angle, geometry_type const& geom, CoordTransform const& t, proj_transform const& prj_trans)
|
||||
{
|
||||
double label_x=0.0;
|
||||
double label_y=0.0;
|
||||
double z=0.0;
|
||||
if (p.label_placement == POINT_PLACEMENT ||
|
||||
p.label_placement == VERTEX_PLACEMENT ||
|
||||
p.label_placement == INTERIOR_PLACEMENT)
|
||||
{
|
||||
unsigned iterations = 1;
|
||||
if (p.label_placement == VERTEX_PLACEMENT)
|
||||
{
|
||||
iterations = geom.num_points();
|
||||
geom.rewind(0);
|
||||
}
|
||||
for(unsigned jj = 0; jj < iterations; jj++) {
|
||||
switch (p.label_placement)
|
||||
{
|
||||
case POINT_PLACEMENT:
|
||||
geom.label_position(&label_x, &label_y);
|
||||
break;
|
||||
case INTERIOR_PLACEMENT:
|
||||
geom.label_interior_position(&label_x, &label_y);
|
||||
break;
|
||||
case VERTEX_PLACEMENT:
|
||||
geom.vertex(&label_x, &label_y);
|
||||
break;
|
||||
case LINE_PLACEMENT:
|
||||
case label_placement_enum_MAX:
|
||||
/*not handled here*/
|
||||
break;
|
||||
}
|
||||
prj_trans.backward(label_x, label_y, z);
|
||||
t.forward(&label_x, &label_y);
|
||||
|
||||
find_point_placement(label_x, label_y, angle);
|
||||
}
|
||||
update_detector();
|
||||
} else if (p.label_placement == LINE_PLACEMENT && geom.num_points() > 1)
|
||||
{
|
||||
typedef coord_transform2<CoordTransform,geometry_type> path_type;
|
||||
path_type path(t, geom, prj_trans);
|
||||
find_line_placements<path_type>(path);
|
||||
}
|
||||
}
|
||||
|
||||
typedef coord_transform2<CoordTransform,geometry_type> PathType;
|
||||
typedef label_collision_detector4 DetectorType;
|
||||
|
||||
|
|
|
@ -189,8 +189,8 @@ public:
|
|||
ptree::value_type("ShieldSymbolizer",
|
||||
ptree()))->second;
|
||||
|
||||
add_font_attributes( sym_node, sym);
|
||||
add_image_attributes( sym_node, sym);
|
||||
add_font_attributes(sym_node, sym);
|
||||
add_image_attributes(sym_node, sym);
|
||||
add_metawriter_attributes(sym_node, sym);
|
||||
|
||||
// pseudo-default-construct a shield_symbolizer. It is used
|
||||
|
@ -199,28 +199,24 @@ public:
|
|||
// maybe add a real, explicit default-ctor?
|
||||
|
||||
|
||||
shield_symbolizer dfl(expression_ptr(), "<no default>", 0, color(0,0,0), path_expression_ptr());
|
||||
shield_symbolizer dfl;
|
||||
|
||||
if (sym.get_unlock_image() != dfl.get_unlock_image() || explicit_defaults_ )
|
||||
if (sym.get_unlock_image() != dfl.get_unlock_image() || explicit_defaults_)
|
||||
{
|
||||
set_attr( sym_node, "unlock-image", sym.get_unlock_image() );
|
||||
set_attr(sym_node, "unlock-image", sym.get_unlock_image());
|
||||
}
|
||||
if (sym.get_no_text() != dfl.get_no_text() || explicit_defaults_ )
|
||||
if (sym.get_text_opacity() != dfl.get_text_opacity() || explicit_defaults_)
|
||||
{
|
||||
set_attr( sym_node, "no-text", sym.get_no_text() );
|
||||
}
|
||||
if (sym.get_text_opacity() != dfl.get_text_opacity() || explicit_defaults_ )
|
||||
{
|
||||
set_attr( sym_node, "text-opacity", sym.get_text_opacity() );
|
||||
set_attr(sym_node, "text-opacity", sym.get_text_opacity());
|
||||
}
|
||||
position displacement = sym.get_shield_displacement();
|
||||
if ( displacement.get<0>() != dfl.get_shield_displacement().get<0>() || explicit_defaults_ )
|
||||
if (displacement.first != dfl.get_shield_displacement().first || explicit_defaults_)
|
||||
{
|
||||
set_attr( sym_node, "shield-dx", displacement.get<0>() );
|
||||
set_attr(sym_node, "shield-dx", displacement.first);
|
||||
}
|
||||
if ( displacement.get<1>() != dfl.get_shield_displacement().get<1>() || explicit_defaults_ )
|
||||
if (displacement.second != dfl.get_shield_displacement().second || explicit_defaults_)
|
||||
{
|
||||
set_attr( sym_node, "shield-dy", displacement.get<1>() );
|
||||
set_attr(sym_node, "shield-dy", displacement.second);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -38,8 +38,7 @@ shield_symbolizer::shield_symbolizer(text_placements_ptr placements)
|
|||
: text_symbolizer(placements),
|
||||
symbolizer_with_image(),
|
||||
unlock_image_(false),
|
||||
no_text_(false),
|
||||
shield_displacement_(boost::make_tuple<double,double>(0,0))
|
||||
shield_displacement_(0,0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -52,8 +51,7 @@ shield_symbolizer::shield_symbolizer(
|
|||
: text_symbolizer(name, face_name, size, fill),
|
||||
symbolizer_with_image(file),
|
||||
unlock_image_(false),
|
||||
no_text_(false),
|
||||
shield_displacement_(boost::make_tuple<double,double>(0,0))
|
||||
shield_displacement_(0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -65,8 +63,7 @@ shield_symbolizer::shield_symbolizer(
|
|||
: text_symbolizer(name, size, fill),
|
||||
symbolizer_with_image(file),
|
||||
unlock_image_(false),
|
||||
no_text_(false),
|
||||
shield_displacement_(boost::make_tuple<double,double>(0,0))
|
||||
shield_displacement_(0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -80,22 +77,12 @@ bool shield_symbolizer::get_unlock_image() const
|
|||
return unlock_image_;
|
||||
}
|
||||
|
||||
void shield_symbolizer::set_no_text(bool no_text)
|
||||
{
|
||||
no_text_ = no_text;
|
||||
}
|
||||
|
||||
bool shield_symbolizer::get_no_text() const
|
||||
{
|
||||
return no_text_;
|
||||
}
|
||||
|
||||
void shield_symbolizer::set_shield_displacement(double shield_dx,double shield_dy)
|
||||
{
|
||||
shield_displacement_ = boost::make_tuple(shield_dx,shield_dy);
|
||||
shield_displacement_ = std::make_pair(shield_dx, shield_dy);
|
||||
}
|
||||
|
||||
boost::tuple<double,double> const& shield_symbolizer::get_shield_displacement() const
|
||||
position const& shield_symbolizer::get_shield_displacement() const
|
||||
{
|
||||
return shield_displacement_;
|
||||
}
|
||||
|
|
351
src/symbolizer_helpers.cpp
Normal file
|
@ -0,0 +1,351 @@
|
|||
#include <mapnik/symbolizer_helpers.hpp>
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
text_placement_info_ptr text_symbolizer_helper<FaceManagerT, DetectorT>::get_placement()
|
||||
{
|
||||
if (!placement_valid_) return text_placement_info_ptr();
|
||||
if (point_placement_)
|
||||
return get_point_placement();
|
||||
else
|
||||
return get_line_placement();
|
||||
}
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
text_placement_info_ptr text_symbolizer_helper<FaceManagerT, DetectorT>::get_line_placement()
|
||||
{
|
||||
while (geometries_to_process_.size())
|
||||
{
|
||||
if (geo_itr_ == geometries_to_process_.end())
|
||||
{
|
||||
//Just processed the last geometry. Try next placement.
|
||||
if (!next_placement()) return text_placement_info_ptr(); //No more placements
|
||||
//Start again from begin of list
|
||||
geo_itr_ = geometries_to_process_.begin();
|
||||
continue; //Reexecute size check
|
||||
}
|
||||
//TODO: Avoid calling constructor repeatedly
|
||||
placement_finder<DetectorT> finder(*placement_, *info_, detector_, dims_);
|
||||
typedef coord_transform2<CoordTransform,geometry_type> path_type;
|
||||
path_type path(t_, **geo_itr_, prj_trans_);
|
||||
finder.find_line_placements(path);
|
||||
//Keep reference to current object so we can delete it.
|
||||
std::list<geometry_type*>::iterator current_object = geo_itr_;
|
||||
geo_itr_++;
|
||||
if (placement_->placements.size())
|
||||
{
|
||||
//Found a placement
|
||||
geometries_to_process_.erase(current_object);
|
||||
if (writer_.first) writer_.first->add_text(
|
||||
*placement_, font_manager_,
|
||||
feature_, t_, writer_.second);
|
||||
return placement_;
|
||||
}
|
||||
//No placement for this geometry. Keep it in geometries_to_process_ for next try.
|
||||
}
|
||||
return text_placement_info_ptr();
|
||||
}
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
text_placement_info_ptr text_symbolizer_helper<FaceManagerT, DetectorT>::get_point_placement()
|
||||
{
|
||||
while (points_.size())
|
||||
{
|
||||
if (point_itr_ == points_.end())
|
||||
{
|
||||
//Just processed the last point. Try next placement.
|
||||
if (!next_placement()) return text_placement_info_ptr(); //No more placements
|
||||
//Start again from begin of list
|
||||
point_itr_ = points_.begin();
|
||||
continue; //Reexecute size check
|
||||
}
|
||||
placement_finder<DetectorT> finder(*placement_, *info_, detector_, dims_);
|
||||
finder.find_point_placement(point_itr_->first, point_itr_->second, angle_);
|
||||
//Keep reference to current object so we can delete it.
|
||||
std::list<position>::iterator current_object = point_itr_;
|
||||
point_itr_++;
|
||||
if (placement_->placements.size())
|
||||
{
|
||||
//Found a placement
|
||||
points_.erase(current_object);
|
||||
if (writer_.first) writer_.first->add_text(
|
||||
*placement_, font_manager_,
|
||||
feature_, t_, writer_.second);
|
||||
finder.update_detector();
|
||||
return placement_;
|
||||
}
|
||||
//No placement for this point. Keep it in points_ for next try.
|
||||
|
||||
}
|
||||
return text_placement_info_ptr();
|
||||
}
|
||||
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
void text_symbolizer_helper<FaceManagerT, DetectorT>::initialize_geometries()
|
||||
{
|
||||
unsigned num_geom = feature_.num_geometries();
|
||||
for (unsigned i=0; i<num_geom; ++i)
|
||||
{
|
||||
geometry_type const& geom = feature_.get_geometry(i);
|
||||
|
||||
// don't bother with empty geometries
|
||||
if (geom.num_points() == 0) continue;
|
||||
|
||||
if ((geom.type() == Polygon) && sym_.get_minimum_path_length() > 0)
|
||||
{
|
||||
// TODO - find less costly method than fetching full envelope
|
||||
box2d<double> gbox = t_.forward(geom.envelope(), prj_trans_);
|
||||
if (gbox.width() < sym_.get_minimum_path_length())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// TODO - calculate length here as well
|
||||
geometries_to_process_.push_back(const_cast<geometry_type*>(&geom));
|
||||
}
|
||||
geo_itr_ = geometries_to_process_.begin();
|
||||
}
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
void text_symbolizer_helper<FaceManagerT, DetectorT>::initialize_points()
|
||||
{
|
||||
label_placement_enum how_placed = placement_->properties.label_placement;
|
||||
if (how_placed == LINE_PLACEMENT) {
|
||||
point_placement_ = false;
|
||||
return;
|
||||
} else {
|
||||
point_placement_ = true;
|
||||
}
|
||||
|
||||
double label_x=0.0;
|
||||
double label_y=0.0;
|
||||
double z=0.0;
|
||||
|
||||
std::list<geometry_type*>::const_iterator itr = geometries_to_process_.begin();
|
||||
std::list<geometry_type*>::const_iterator end = geometries_to_process_.end();
|
||||
for (; itr != end; itr++)
|
||||
{
|
||||
geometry_type const& geom = **itr;
|
||||
if (how_placed == VERTEX_PLACEMENT)
|
||||
{
|
||||
geom.rewind(0);
|
||||
for(unsigned i = 0; i < geom.num_points(); i++)
|
||||
{
|
||||
geom.vertex(&label_x, &label_y);
|
||||
prj_trans_.backward(label_x, label_y, z);
|
||||
t_.forward(&label_x, &label_y);
|
||||
points_.push_back(std::make_pair(label_x, label_y));
|
||||
}
|
||||
} else {
|
||||
if (how_placed == POINT_PLACEMENT)
|
||||
{
|
||||
geom.label_position(&label_x, &label_y);
|
||||
} else if (how_placed == INTERIOR_PLACEMENT)
|
||||
{
|
||||
geom.label_interior_position(&label_x, &label_y);
|
||||
} else {
|
||||
#ifdef MAPNIK_DEBUG
|
||||
std::cerr << "ERROR: Unknown placement type in initialize_points();\n";
|
||||
#endif
|
||||
}
|
||||
prj_trans_.backward(label_x, label_y, z);
|
||||
t_.forward(&label_x, &label_y);
|
||||
points_.push_back(std::make_pair(label_x, label_y));
|
||||
}
|
||||
}
|
||||
point_itr_ = points_.begin();
|
||||
}
|
||||
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
bool text_symbolizer_helper<FaceManagerT, DetectorT>::next_placement()
|
||||
{
|
||||
if (!placement_->next()) {
|
||||
placement_valid_ = false;
|
||||
return false;
|
||||
}
|
||||
placement_->properties.processor.process(text_, feature_);
|
||||
info_ = &(text_.get_string_info());
|
||||
if (placement_->properties.orientation)
|
||||
{
|
||||
angle_ = boost::apply_visitor(
|
||||
evaluate<Feature, value_type>(feature_),
|
||||
*(placement_->properties.orientation)).to_double();
|
||||
} else {
|
||||
angle_ = 0.0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
text_placement_info_ptr shield_symbolizer_helper<FaceManagerT, DetectorT>::get_placement()
|
||||
{
|
||||
if (!placement_valid_ || !marker_) return text_placement_info_ptr();
|
||||
if (point_placement_)
|
||||
return get_point_placement();
|
||||
else
|
||||
return get_line_placement();
|
||||
}
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
text_placement_info_ptr shield_symbolizer_helper<FaceManagerT, DetectorT>::get_point_placement()
|
||||
{
|
||||
position const& shield_pos = sym_.get_shield_displacement();
|
||||
while (points_.size())
|
||||
{
|
||||
if (point_itr_ == points_.end())
|
||||
{
|
||||
//Just processed the last point. Try next placement.
|
||||
if (!next_placement()) return text_placement_info_ptr(); //No more placements
|
||||
//Start again from begin of list
|
||||
point_itr_ = points_.begin();
|
||||
continue; //Reexecute size check
|
||||
}
|
||||
position const& pos = placement_->properties.displacement;
|
||||
double label_x = point_itr_->first + shield_pos.first;
|
||||
double label_y = point_itr_->second + shield_pos.second;
|
||||
|
||||
placement_finder<DetectorT> finder(*placement_, *info_, detector_, dims_);
|
||||
finder.find_point_placement(label_x, label_y, angle_);
|
||||
//Keep reference to current object so we can delete it.
|
||||
std::list<position>::iterator current_object = point_itr_;
|
||||
point_itr_++;
|
||||
if (!placement_->placements.size())
|
||||
{
|
||||
//No placement for this point. Keep it in points_ for next try.
|
||||
continue;
|
||||
}
|
||||
//Found a label placement but not necessarily also a marker placement
|
||||
// check to see if image overlaps anything too, there is only ever 1 placement found for points and verticies
|
||||
double x = floor(placement_->placements[0].starting_x);
|
||||
double y = floor(placement_->placements[0].starting_y);
|
||||
if (!sym_.get_unlock_image())
|
||||
{
|
||||
// center image at text center position
|
||||
// remove displacement from image label
|
||||
double lx = x - pos.first;
|
||||
double ly = y - pos.second;
|
||||
marker_x_ = int(floor(lx - (0.5 * marker_w_))) + 1;
|
||||
marker_y_ = int(floor(ly - (0.5 * marker_h_))) + 1;
|
||||
marker_ext_.re_center(lx, ly);
|
||||
}
|
||||
else
|
||||
{ // center image at reference location
|
||||
marker_x_ = int(floor(label_x - 0.5 * marker_w_));
|
||||
marker_y_ = int(floor(label_y - 0.5 * marker_h_));
|
||||
marker_ext_.re_center(label_x, label_y);
|
||||
}
|
||||
|
||||
if (placement_->properties.allow_overlap || detector_.has_placement(marker_ext_))
|
||||
{
|
||||
detector_.insert(marker_ext_);
|
||||
finder.update_detector();
|
||||
if (writer_.first) {
|
||||
writer_.first->add_box(marker_ext_, feature_, t_, writer_.second);
|
||||
writer_.first->add_text(*placement_, font_manager_, feature_, t_, writer_.second);
|
||||
}
|
||||
points_.erase(current_object);
|
||||
return placement_;
|
||||
}
|
||||
}
|
||||
return text_placement_info_ptr();
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
text_placement_info_ptr shield_symbolizer_helper<FaceManagerT, DetectorT>::get_line_placement()
|
||||
{
|
||||
position const& pos = placement_->properties.displacement;
|
||||
placement_->additional_boxes.push_back(
|
||||
/*TODO: I'm not sure this is correct. It's what the old code did, but
|
||||
I think transfroms can make the marker non-centered.
|
||||
*/
|
||||
box2d<double>(-0.5 * marker_ext_.width() - pos.first,
|
||||
-0.5 * marker_ext_.height() - pos.second,
|
||||
0.5 * marker_ext_.width() - pos.first,
|
||||
0.5 * marker_ext_.height() - pos.second));
|
||||
return text_symbolizer_helper<FaceManagerT, DetectorT>::get_line_placement();
|
||||
}
|
||||
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
void shield_symbolizer_helper<FaceManagerT, DetectorT>::init_marker()
|
||||
{
|
||||
std::string filename = path_processor_type::evaluate(*sym_.get_filename(), this->feature_);
|
||||
boost::array<double,6> const& m = sym_.get_transform();
|
||||
transform_.load_from(&m[0]);
|
||||
marker_.reset();
|
||||
if (!filename.empty())
|
||||
{
|
||||
marker_ = marker_cache::instance()->find(filename, true);
|
||||
}
|
||||
if (!marker_) {
|
||||
marker_w_ = 0;
|
||||
marker_h_ = 0;
|
||||
marker_ext_.init(0, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
marker_w_ = (*marker_)->width();
|
||||
marker_h_ = (*marker_)->height();
|
||||
double px0 = - 0.5 * marker_w_;
|
||||
double py0 = - 0.5 * marker_h_;
|
||||
double px1 = 0.5 * marker_w_;
|
||||
double py1 = 0.5 * marker_h_;
|
||||
double px2 = px1;
|
||||
double py2 = py0;
|
||||
double px3 = px0;
|
||||
double py3 = py1;
|
||||
transform_.transform(&px0,&py0);
|
||||
transform_.transform(&px1,&py1);
|
||||
transform_.transform(&px2,&py2);
|
||||
transform_.transform(&px3,&py3);
|
||||
marker_ext_.init(px0, py0, px1, py1);
|
||||
marker_ext_.expand_to_include(px2, py2);
|
||||
marker_ext_.expand_to_include(px3, py3);
|
||||
}
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
std::pair<int, int> shield_symbolizer_helper<FaceManagerT, DetectorT>::get_marker_position(text_path &p)
|
||||
{
|
||||
position const& pos = placement_->properties.displacement;
|
||||
if (placement_->properties.label_placement == LINE_PLACEMENT) {
|
||||
double x = floor(p.starting_x);
|
||||
double y = floor(p.starting_y);
|
||||
|
||||
double lx = x - pos.first;
|
||||
double ly = y - pos.second;
|
||||
int px = int(floor(lx - (0.5*marker_w_))) + 1;
|
||||
int py = int(floor(ly - (0.5*marker_h_))) + 1;
|
||||
marker_ext_.re_center(lx, ly);
|
||||
// detector_->insert(label_ext); //TODO: Is this done by placement_finder?
|
||||
|
||||
if (writer_.first) writer_.first->add_box(marker_ext_, feature_, t_, writer_.second);
|
||||
return std::make_pair(px, py);
|
||||
} else {
|
||||
return std::make_pair(marker_x_, marker_y_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
marker& shield_symbolizer_helper<FaceManagerT, DetectorT>::get_marker() const
|
||||
{
|
||||
return **marker_;
|
||||
}
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
agg::trans_affine const& shield_symbolizer_helper<FaceManagerT, DetectorT>::get_transform() const
|
||||
{
|
||||
return transform_;
|
||||
}
|
||||
|
||||
template class text_symbolizer_helper<face_manager<freetype_engine>, label_collision_detector4>;
|
||||
template class shield_symbolizer_helper<face_manager<freetype_engine>, label_collision_detector4>;
|
||||
} //namespace
|
|
@ -63,7 +63,7 @@ text_symbolizer_properties::text_symbolizer_properties() :
|
|||
|
||||
}
|
||||
|
||||
void text_symbolizer_properties::set_values_from_xml(boost::property_tree::ptree const &sym, std::map<std::string,font_set> const & fontsets)
|
||||
void text_symbolizer_properties::from_xml(boost::property_tree::ptree const &sym, std::map<std::string,font_set> const & fontsets)
|
||||
{
|
||||
optional<label_placement_e> placement_ = get_opt_attr<label_placement_e>(sym, "placement");
|
||||
if (placement_) label_placement = *placement_;
|
||||
|
@ -95,9 +95,9 @@ void text_symbolizer_properties::set_values_from_xml(boost::property_tree::ptree
|
|||
optional<std::string> orientation_ = get_opt_attr<std::string>(sym, "orientation");
|
||||
if (orientation_) orientation = parse_expression(*orientation_, "utf8");
|
||||
optional<double> dx = get_opt_attr<double>(sym, "dx");
|
||||
if (dx) displacement.get<0>() = *dx;
|
||||
if (dx) displacement.first = *dx;
|
||||
optional<double> dy = get_opt_attr<double>(sym, "dy");
|
||||
if (dy) displacement.get<1>() = *dy;
|
||||
if (dy) displacement.second = *dy;
|
||||
optional<double> max_char_angle_delta_ = get_opt_attr<double>(sym, "max-char-angle-delta");
|
||||
if (max_char_angle_delta_) max_char_angle_delta=(*max_char_angle_delta_)*(M_PI/180);
|
||||
processor.from_xml(sym, fontsets);
|
||||
|
@ -118,13 +118,13 @@ void text_symbolizer_properties::to_xml(boost::property_tree::ptree &node, bool
|
|||
}
|
||||
}
|
||||
|
||||
if (displacement.get<0>() != dfl.displacement.get<0>() || explicit_defaults)
|
||||
if (displacement.first != dfl.displacement.first || explicit_defaults)
|
||||
{
|
||||
set_attr(node, "dx", displacement.get<0>());
|
||||
set_attr(node, "dx", displacement.first);
|
||||
}
|
||||
if (displacement.get<1>() != dfl.displacement.get<1>() || explicit_defaults)
|
||||
if (displacement.second != dfl.displacement.second || explicit_defaults)
|
||||
{
|
||||
set_attr(node, "dy", displacement.get<1>());
|
||||
set_attr(node, "dy", displacement.second);
|
||||
}
|
||||
if (label_placement != dfl.label_placement || explicit_defaults)
|
||||
{
|
||||
|
@ -204,7 +204,7 @@ char_properties::char_properties() :
|
|||
|
||||
}
|
||||
|
||||
void char_properties::set_values_from_xml(boost::property_tree::ptree const &sym, std::map<std::string,font_set> const & fontsets)
|
||||
void char_properties::from_xml(boost::property_tree::ptree const &sym, std::map<std::string,font_set> const & fontsets)
|
||||
{
|
||||
optional<double> text_size_ = get_opt_attr<double>(sym, "size");
|
||||
if (text_size_) text_size = *text_size_;
|
||||
|
@ -328,11 +328,13 @@ std::set<expression_ptr> text_placements::get_all_expressions()
|
|||
|
||||
/************************************************************************/
|
||||
|
||||
text_placement_info::text_placement_info(text_placements const* parent):
|
||||
properties(parent->properties),
|
||||
scale_factor(1),
|
||||
has_dimensions(false),
|
||||
collect_extents(false)
|
||||
text_placement_info::text_placement_info(text_placements const* parent,
|
||||
double scale_factor_, dimension_type dim, bool has_dimensions_)
|
||||
: properties(parent->properties),
|
||||
scale_factor(scale_factor_),
|
||||
has_dimensions(has_dimensions_),
|
||||
dimensions(dim),
|
||||
collect_extents(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -344,17 +346,11 @@ bool text_placement_info_dummy::next()
|
|||
return true;
|
||||
}
|
||||
|
||||
text_placement_info_ptr text_placements_dummy::get_placement_info() const
|
||||
text_placement_info_ptr text_placements_dummy::get_placement_info(
|
||||
double scale_factor, dimension_type dim, bool has_dimensions) const
|
||||
{
|
||||
return text_placement_info_ptr(new text_placement_info_dummy(this));
|
||||
}
|
||||
|
||||
void text_placement_info::init(double scale_factor_,
|
||||
unsigned w, unsigned h, bool has_dimensions_)
|
||||
{
|
||||
scale_factor = scale_factor_;
|
||||
dimensions = std::make_pair(w, h);
|
||||
has_dimensions = has_dimensions_;
|
||||
return text_placement_info_ptr(new text_placement_info_dummy(
|
||||
this, scale_factor, dim, has_dimensions));
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -389,36 +385,28 @@ bool text_placement_info_simple::next_position_only()
|
|||
displacement = pdisp;
|
||||
break;
|
||||
case NORTH:
|
||||
displacement = boost::make_tuple(0, -abs(pdisp.get<1>()));
|
||||
displacement = std::make_pair(0, -abs(pdisp.second));
|
||||
break;
|
||||
case EAST:
|
||||
displacement = boost::make_tuple(abs(pdisp.get<0>()), 0);
|
||||
displacement = std::make_pair(abs(pdisp.first), 0);
|
||||
break;
|
||||
case SOUTH:
|
||||
displacement = boost::make_tuple(0, abs(pdisp.get<1>()));
|
||||
displacement = std::make_pair(0, abs(pdisp.second));
|
||||
break;
|
||||
case WEST:
|
||||
displacement = boost::make_tuple(-abs(pdisp.get<0>()), 0);
|
||||
displacement = std::make_pair(-abs(pdisp.first), 0);
|
||||
break;
|
||||
case NORTHEAST:
|
||||
displacement = boost::make_tuple(
|
||||
abs(pdisp.get<0>()),
|
||||
-abs(pdisp.get<1>()));
|
||||
displacement = std::make_pair(abs(pdisp.first), -abs(pdisp.second));
|
||||
break;
|
||||
case SOUTHEAST:
|
||||
displacement = boost::make_tuple(
|
||||
abs(pdisp.get<0>()),
|
||||
abs(pdisp.get<1>()));
|
||||
displacement = std::make_pair(abs(pdisp.first), abs(pdisp.second));
|
||||
break;
|
||||
case NORTHWEST:
|
||||
displacement = boost::make_tuple(
|
||||
-abs(pdisp.get<0>()),
|
||||
-abs(pdisp.get<1>()));
|
||||
displacement = std::make_pair(-abs(pdisp.first), -abs(pdisp.second));
|
||||
break;
|
||||
case SOUTHWEST:
|
||||
displacement = boost::make_tuple(
|
||||
-abs(pdisp.get<0>()),
|
||||
abs(pdisp.get<1>()));
|
||||
displacement = std::make_pair(-abs(pdisp.first), abs(pdisp.second));
|
||||
break;
|
||||
default:
|
||||
std::cerr << "WARNING: Unknown placement\n";
|
||||
|
@ -427,22 +415,24 @@ bool text_placement_info_simple::next_position_only()
|
|||
return true;
|
||||
}
|
||||
|
||||
text_placement_info_ptr text_placements_simple::get_placement_info() const
|
||||
text_placement_info_ptr text_placements_simple::get_placement_info(
|
||||
double scale_factor, dimension_type dim, bool has_dimensions) const
|
||||
{
|
||||
return text_placement_info_ptr(new text_placement_info_simple(this));
|
||||
return text_placement_info_ptr(new text_placement_info_simple(this,
|
||||
scale_factor, dim, has_dimensions));
|
||||
}
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
* [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;
|
||||
|
@ -460,16 +450,16 @@ void text_placements_simple::set_positions(std::string positions)
|
|||
("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
|
||||
);
|
||||
(direction_name[push_back(phoenix::ref(direction_), _1)] % ',') >> *(',' >> qi::float_[push_back(phoenix::ref(text_sizes_), _1)]),
|
||||
space
|
||||
);
|
||||
if (first != last) {
|
||||
std::cerr << "WARNING: Could not parse text_placement_simple placement string ('" << positions << "').\n";
|
||||
}
|
||||
|
@ -483,16 +473,15 @@ text_placements_simple::text_placements_simple()
|
|||
set_positions("X");
|
||||
}
|
||||
|
||||
std::string const& text_placements_simple::get_positions() const
|
||||
{
|
||||
return positions_;
|
||||
}
|
||||
|
||||
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_
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
|
@ -526,9 +515,11 @@ text_symbolizer_properties & text_placements_list::get(unsigned i)
|
|||
|
||||
/***************************************************************************/
|
||||
|
||||
text_placement_info_ptr text_placements_list::get_placement_info() const
|
||||
text_placement_info_ptr text_placements_list::get_placement_info(
|
||||
double scale_factor, dimension_type dim, bool has_dimensions) const
|
||||
{
|
||||
return text_placement_info_ptr(new text_placement_info_list(this));
|
||||
return text_placement_info_ptr(new text_placement_info_list(this,
|
||||
scale_factor, dim, has_dimensions));
|
||||
}
|
||||
|
||||
text_placements_list::text_placements_list() : text_placements(), list_(0)
|
||||
|
|
|
@ -25,371 +25,378 @@
|
|||
#include <mapnik/feature.hpp>
|
||||
#include <mapnik/expression_evaluator.hpp>
|
||||
#include <mapnik/filter_factory.hpp>
|
||||
#include <mapnik/ptree_helpers.hpp>
|
||||
#include <mapnik/expression_string.hpp>
|
||||
#include <mapnik/ptree_helpers.hpp>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
namespace mapnik {
|
||||
using boost::property_tree::ptree;
|
||||
using boost::optional;
|
||||
|
||||
class abstract_token
|
||||
{
|
||||
public:
|
||||
virtual ~abstract_token() {}
|
||||
virtual ptree *to_xml(ptree *node) = 0;
|
||||
};
|
||||
namespace formating {
|
||||
|
||||
class abstract_formating_token : public abstract_token
|
||||
void node::to_xml(boost::property_tree::ptree &xml) const
|
||||
{
|
||||
public:
|
||||
virtual void apply(char_properties &p, Feature const& feature) = 0;
|
||||
};
|
||||
//TODO: Should this throw a config_error?
|
||||
#ifdef MAPNIK_DEBUG
|
||||
std::cerr << "Error: Trying to write unsupported node type to XML.\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
class abstract_text_token : public abstract_token
|
||||
node_ptr node::from_xml(boost::property_tree::ptree const& xml)
|
||||
{
|
||||
public:
|
||||
virtual UnicodeString to_string(Feature const& feature) = 0;
|
||||
};
|
||||
list_node *list = new list_node();
|
||||
node_ptr list_ptr(list);
|
||||
ptree::const_iterator itr = xml.begin();
|
||||
ptree::const_iterator end = xml.end();
|
||||
for (; itr != end; ++itr) {
|
||||
node_ptr n;
|
||||
if (itr->first == "<xmltext>") {
|
||||
n = text_node::from_xml(itr->second);
|
||||
} else if (itr->first == "Format") {
|
||||
n = format_node::from_xml(itr->second);
|
||||
} else if (itr->first != "<xmlcomment>" && itr->first != "<xmlattr>" && itr->first != "Placement") {
|
||||
throw config_error("Unknown item " + itr->first);
|
||||
}
|
||||
if (n) list->push_back(n);
|
||||
}
|
||||
if (list->get_children().size() == 1) {
|
||||
return list->get_children()[0];
|
||||
} else if (list->get_children().size() > 1) {
|
||||
return list_ptr;
|
||||
} else {
|
||||
return node_ptr();
|
||||
}
|
||||
}
|
||||
|
||||
class end_format_token : public abstract_token
|
||||
void node::add_expressions(std::set<expression_ptr> &expressions) const
|
||||
{
|
||||
public:
|
||||
end_format_token() {}
|
||||
ptree *to_xml(ptree *node);
|
||||
};
|
||||
|
||||
class expression_token: public abstract_text_token
|
||||
{
|
||||
public:
|
||||
expression_token(expression_ptr text);
|
||||
UnicodeString to_string(Feature const& feature);
|
||||
ptree *to_xml(ptree *node);
|
||||
void set_expression(expression_ptr text);
|
||||
expression_ptr get_expression();
|
||||
private:
|
||||
expression_ptr text_;
|
||||
};
|
||||
|
||||
class fixed_formating_token : public abstract_formating_token
|
||||
{
|
||||
public:
|
||||
fixed_formating_token();
|
||||
virtual void apply(char_properties &p, Feature const& feature);
|
||||
ptree* to_xml(ptree *node);
|
||||
void from_xml(ptree const& node);
|
||||
void set_face_name(optional<std::string> face_name);
|
||||
void set_text_size(optional<unsigned> text_size);
|
||||
void set_character_spacing(optional<unsigned> character_spacing);
|
||||
void set_line_spacing(optional<unsigned> line_spacing);
|
||||
void set_text_opacity(optional<double> opacity);
|
||||
void set_wrap_before(optional<boolean> wrap_before);
|
||||
void set_wrap_char(optional<unsigned> wrap_char);
|
||||
void set_text_transform(optional<text_transform_e> text_trans);
|
||||
void set_fill(optional<color> fill);
|
||||
void set_halo_fill(optional<color> halo_fill);
|
||||
void set_halo_radius(optional<double> radius);
|
||||
private:
|
||||
boost::optional<std::string> face_name_;
|
||||
// font_set fontset;
|
||||
boost::optional<unsigned> text_size_;
|
||||
boost::optional<unsigned> character_spacing_;
|
||||
boost::optional<unsigned> line_spacing_;
|
||||
boost::optional<double> text_opacity_;
|
||||
boost::optional<boolean> wrap_before_;
|
||||
boost::optional<unsigned> wrap_char_;
|
||||
boost::optional<text_transform_e> text_transform_;
|
||||
boost::optional<color> fill_;
|
||||
boost::optional<color> halo_fill_;
|
||||
boost::optional<double> halo_radius_;
|
||||
};
|
||||
//Do nothing by default
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
|
||||
expression_token::expression_token(expression_ptr text):
|
||||
text_(text)
|
||||
void list_node::to_xml(boost::property_tree::ptree &xml) const
|
||||
{
|
||||
std::vector<node_ptr>::const_iterator itr = children_.begin();
|
||||
std::vector<node_ptr>::const_iterator end = children_.end();
|
||||
for (;itr != end; itr++)
|
||||
{
|
||||
(*itr)->to_xml(xml);
|
||||
}
|
||||
}
|
||||
|
||||
void expression_token::set_expression(expression_ptr text)
|
||||
|
||||
void list_node::apply(char_properties const& p, Feature const& feature, processed_text &output) const
|
||||
{
|
||||
std::vector<node_ptr>::const_iterator itr = children_.begin();
|
||||
std::vector<node_ptr>::const_iterator end = children_.end();
|
||||
for (;itr != end; itr++)
|
||||
{
|
||||
(*itr)->apply(p, feature, output);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void list_node::add_expressions(std::set<expression_ptr> &expressions) const
|
||||
{
|
||||
std::vector<node_ptr>::const_iterator itr = children_.begin();
|
||||
std::vector<node_ptr>::const_iterator end = children_.end();
|
||||
for (;itr != end; itr++)
|
||||
{
|
||||
(*itr)->add_expressions(expressions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void list_node::push_back(node_ptr n)
|
||||
{
|
||||
children_.push_back(n);
|
||||
}
|
||||
|
||||
|
||||
void list_node::clear()
|
||||
{
|
||||
children_.clear();
|
||||
}
|
||||
|
||||
void list_node::set_children(std::vector<node_ptr> const& children)
|
||||
{
|
||||
children_ = children;
|
||||
}
|
||||
|
||||
std::vector<node_ptr> const& list_node::get_children() const
|
||||
{
|
||||
return children_;
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
|
||||
void text_node::to_xml(ptree &xml) const
|
||||
{
|
||||
ptree &new_node = xml.push_back(ptree::value_type(
|
||||
"<xmltext>", ptree()))->second;
|
||||
new_node.put_value(to_expression_string(*text_));
|
||||
}
|
||||
|
||||
|
||||
node_ptr text_node::from_xml(boost::property_tree::ptree const& xml)
|
||||
{
|
||||
std::string data = xml.data();
|
||||
boost::trim(data);
|
||||
if (data.empty()) return node_ptr(); //No text
|
||||
return node_ptr(new text_node(parse_expression(data, "utf8")));
|
||||
}
|
||||
|
||||
void text_node::apply(char_properties const& p, Feature const& feature, processed_text &output) const
|
||||
{
|
||||
UnicodeString text_str = boost::apply_visitor(evaluate<Feature,value_type>(feature), *text_).to_unicode();
|
||||
if (p.text_transform == UPPERCASE)
|
||||
{
|
||||
text_str = text_str.toUpper();
|
||||
}
|
||||
else if (p.text_transform == LOWERCASE)
|
||||
{
|
||||
text_str = text_str.toLower();
|
||||
}
|
||||
else if (p.text_transform == CAPITALIZE)
|
||||
{
|
||||
text_str = text_str.toTitle(NULL);
|
||||
}
|
||||
if (text_str.length() > 0) {
|
||||
output.push_back(processed_expression(p, text_str));
|
||||
} else {
|
||||
#ifdef MAPNIK_DEBUG
|
||||
std::cerr << "Warning: Empty expression.\n";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void text_node::add_expressions(std::set<expression_ptr> &expressions) const
|
||||
{
|
||||
if (text_) expressions.insert(text_);
|
||||
}
|
||||
|
||||
|
||||
void text_node::set_text(expression_ptr text)
|
||||
{
|
||||
text_ = text;
|
||||
}
|
||||
|
||||
expression_ptr expression_token::get_expression()
|
||||
|
||||
expression_ptr text_node::get_text() const
|
||||
{
|
||||
return text_;
|
||||
}
|
||||
|
||||
UnicodeString expression_token::to_string(const Feature &feature)
|
||||
{
|
||||
value_type result = boost::apply_visitor(evaluate<Feature,value_type>(feature), *text_);
|
||||
return result.to_unicode();
|
||||
}
|
||||
|
||||
ptree *expression_token::to_xml(ptree *node)
|
||||
{
|
||||
ptree &new_node = node->push_back(ptree::value_type(
|
||||
"<xmltext>", ptree()))->second;
|
||||
new_node.put_value(to_expression_string(*text_));
|
||||
return &new_node;
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
|
||||
fixed_formating_token::fixed_formating_token():
|
||||
fill_()
|
||||
format_node::format_node():
|
||||
node(),
|
||||
fill_(),
|
||||
child_()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void fixed_formating_token::apply(char_properties &p, const Feature &feature)
|
||||
void format_node::to_xml(ptree &xml) const
|
||||
{
|
||||
if (face_name_) p.face_name = *face_name_;
|
||||
if (text_size_) p.text_size = *text_size_;
|
||||
if (character_spacing_) p.character_spacing = *character_spacing_;
|
||||
if (line_spacing_) p.line_spacing = *line_spacing_;
|
||||
if (text_opacity_) p.text_opacity = *text_opacity_;
|
||||
if (wrap_before_) p.wrap_before = *wrap_before_;
|
||||
if (wrap_char_) p.wrap_char = *wrap_char_;
|
||||
if (text_transform_) p.text_transform = *text_transform_;
|
||||
if (fill_) p.fill = *fill_;
|
||||
if (halo_fill_) p.halo_fill = *halo_fill_;
|
||||
if (halo_radius_) p.halo_radius = *halo_radius_;
|
||||
ptree &new_node = xml.push_back(ptree::value_type("Format", ptree()))->second;
|
||||
if (face_name_) set_attr(new_node, "face-name", *face_name_);
|
||||
if (text_size_) set_attr(new_node, "size", *text_size_);
|
||||
if (character_spacing_) set_attr(new_node, "character-spacing", *character_spacing_);
|
||||
if (line_spacing_) set_attr(new_node, "line-spacing", *line_spacing_);
|
||||
if (text_opacity_) set_attr(new_node, "opacity", *text_opacity_);
|
||||
if (wrap_before_) set_attr(new_node, "wrap-before", *wrap_before_);
|
||||
if (wrap_char_) set_attr(new_node, "wrap-character", *wrap_char_);
|
||||
if (text_transform_) set_attr(new_node, "text-transform", *text_transform_);
|
||||
if (fill_) set_attr(new_node, "fill", *fill_);
|
||||
if (halo_fill_) set_attr(new_node, "halo-fill", *halo_fill_);
|
||||
if (halo_radius_) set_attr(new_node, "halo-radius", *halo_radius_);
|
||||
if (child_) child_->to_xml(new_node);
|
||||
}
|
||||
|
||||
ptree *fixed_formating_token::to_xml(ptree *node)
|
||||
{
|
||||
|
||||
ptree &new_node = node->push_back(ptree::value_type("Format", ptree()))->second;
|
||||
if (face_name_) set_attr(new_node, "face-name", face_name_);
|
||||
if (text_size_) set_attr(new_node, "size", text_size_);
|
||||
if (character_spacing_) set_attr(new_node, "character-spacing", character_spacing_);
|
||||
if (line_spacing_) set_attr(new_node, "line-spacing", line_spacing_);
|
||||
if (text_opacity_) set_attr(new_node, "opacity", text_opacity_);
|
||||
if (wrap_before_) set_attr(new_node, "wrap-before", wrap_before_);
|
||||
if (wrap_char_) set_attr(new_node, "wrap-character", wrap_char_);
|
||||
if (text_transform_) set_attr(new_node, "text-transform", text_transform_);
|
||||
if (fill_) set_attr(new_node, "fill", fill_);
|
||||
if (halo_fill_) set_attr(new_node, "halo-fill", halo_fill_);
|
||||
if (halo_radius_) set_attr(new_node, "halo-radius", halo_radius_);
|
||||
return &new_node;
|
||||
}
|
||||
|
||||
void fixed_formating_token::from_xml(ptree const& node)
|
||||
node_ptr format_node::from_xml(ptree const& xml)
|
||||
{
|
||||
set_face_name(get_opt_attr<std::string>(node, "face-name"));
|
||||
format_node *n = new format_node();
|
||||
node_ptr np(n);
|
||||
|
||||
node_ptr child = node::from_xml(xml);
|
||||
n->set_child(child);
|
||||
|
||||
n->set_face_name(get_opt_attr<std::string>(xml, "face-name"));
|
||||
/*TODO: Fontset is problematic. We don't have the fontsets pointer here... */
|
||||
set_text_size(get_opt_attr<unsigned>(node, "size"));
|
||||
set_character_spacing(get_opt_attr<unsigned>(node, "character-spacing"));
|
||||
set_line_spacing(get_opt_attr<unsigned>(node, "line-spacing"));
|
||||
set_text_opacity(get_opt_attr<double>(node, "opactity"));
|
||||
set_wrap_before(get_opt_attr<boolean>(node, "wrap-before"));
|
||||
set_wrap_char(get_opt_attr<unsigned>(node, "wrap-character"));
|
||||
set_text_transform(get_opt_attr<text_transform_e>(node, "text-transform"));
|
||||
set_fill(get_opt_attr<color>(node, "fill"));
|
||||
set_halo_fill(get_opt_attr<color>(node, "halo-fill"));
|
||||
set_halo_radius(get_opt_attr<double>(node, "halo-radius"));
|
||||
n->set_text_size(get_opt_attr<unsigned>(xml, "size"));
|
||||
n->set_character_spacing(get_opt_attr<unsigned>(xml, "character-spacing"));
|
||||
n->set_line_spacing(get_opt_attr<unsigned>(xml, "line-spacing"));
|
||||
n->set_text_opacity(get_opt_attr<double>(xml, "opactity"));
|
||||
boost::optional<boolean> wrap = get_opt_attr<boolean>(xml, "wrap-before");
|
||||
boost::optional<bool> wrap_before;
|
||||
if (wrap) wrap_before = *wrap;
|
||||
n->set_wrap_before(wrap_before);
|
||||
n->set_wrap_char(get_opt_attr<unsigned>(xml, "wrap-character"));
|
||||
n->set_text_transform(get_opt_attr<text_transform_e>(xml, "text-transform"));
|
||||
n->set_fill(get_opt_attr<color>(xml, "fill"));
|
||||
n->set_halo_fill(get_opt_attr<color>(xml, "halo-fill"));
|
||||
n->set_halo_radius(get_opt_attr<double>(xml, "halo-radius"));
|
||||
return np;
|
||||
}
|
||||
|
||||
void fixed_formating_token::set_face_name(optional<std::string> face_name)
|
||||
|
||||
void format_node::apply(char_properties const& p, const Feature &feature, processed_text &output) const
|
||||
{
|
||||
char_properties new_properties = p;
|
||||
if (face_name_) new_properties.face_name = *face_name_;
|
||||
if (text_size_) new_properties.text_size = *text_size_;
|
||||
if (character_spacing_) new_properties.character_spacing = *character_spacing_;
|
||||
if (line_spacing_) new_properties.line_spacing = *line_spacing_;
|
||||
if (text_opacity_) new_properties.text_opacity = *text_opacity_;
|
||||
if (wrap_before_) new_properties.wrap_before = *wrap_before_;
|
||||
if (wrap_char_) new_properties.wrap_char = *wrap_char_;
|
||||
if (text_transform_) new_properties.text_transform = *text_transform_;
|
||||
if (fill_) new_properties.fill = *fill_;
|
||||
if (halo_fill_) new_properties.halo_fill = *halo_fill_;
|
||||
if (halo_radius_) new_properties.halo_radius = *halo_radius_;
|
||||
|
||||
if (child_) {
|
||||
child_->apply(new_properties, feature, output);
|
||||
} else {
|
||||
#ifdef MAPNIK_DEBUG
|
||||
std::cerr << "Warning: Useless format: No text to format\n";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void format_node::set_child(node_ptr child)
|
||||
{
|
||||
child_ = child;
|
||||
}
|
||||
|
||||
|
||||
node_ptr format_node::get_child() const
|
||||
{
|
||||
return child_;
|
||||
}
|
||||
|
||||
|
||||
void format_node::set_face_name(optional<std::string> face_name)
|
||||
{
|
||||
face_name_ = face_name;
|
||||
}
|
||||
|
||||
void fixed_formating_token::set_text_size(optional<unsigned> text_size)
|
||||
void format_node::set_text_size(optional<unsigned> text_size)
|
||||
{
|
||||
text_size_ = text_size;
|
||||
}
|
||||
|
||||
void fixed_formating_token::set_character_spacing(optional<unsigned> character_spacing)
|
||||
void format_node::set_character_spacing(optional<unsigned> character_spacing)
|
||||
{
|
||||
character_spacing_ = character_spacing;
|
||||
}
|
||||
|
||||
void fixed_formating_token::set_line_spacing(optional<unsigned> line_spacing)
|
||||
void format_node::set_line_spacing(optional<unsigned> line_spacing)
|
||||
{
|
||||
line_spacing_ = line_spacing;
|
||||
}
|
||||
|
||||
void fixed_formating_token::set_text_opacity(optional<double> text_opacity)
|
||||
void format_node::set_text_opacity(optional<double> text_opacity)
|
||||
{
|
||||
text_opacity_ = text_opacity;
|
||||
}
|
||||
|
||||
void fixed_formating_token::set_wrap_before(optional<boolean> wrap_before)
|
||||
void format_node::set_wrap_before(optional<bool> wrap_before)
|
||||
{
|
||||
wrap_before_ = wrap_before;
|
||||
}
|
||||
|
||||
void fixed_formating_token::set_wrap_char(optional<unsigned> wrap_char)
|
||||
void format_node::set_wrap_char(optional<unsigned> wrap_char)
|
||||
{
|
||||
wrap_char_ = wrap_char;
|
||||
}
|
||||
|
||||
void fixed_formating_token::set_text_transform(optional<text_transform_e> text_transform)
|
||||
void format_node::set_text_transform(optional<text_transform_e> text_transform)
|
||||
{
|
||||
text_transform_ = text_transform;
|
||||
}
|
||||
|
||||
void fixed_formating_token::set_fill(optional<color> c)
|
||||
void format_node::set_fill(optional<color> c)
|
||||
{
|
||||
fill_ = c;
|
||||
}
|
||||
|
||||
void fixed_formating_token::set_halo_fill(optional<color> c)
|
||||
void format_node::set_halo_fill(optional<color> c)
|
||||
{
|
||||
halo_fill_ = c;
|
||||
}
|
||||
|
||||
void fixed_formating_token::set_halo_radius(optional<double> radius)
|
||||
void format_node::set_halo_radius(optional<double> radius)
|
||||
{
|
||||
halo_radius_ = radius;
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
|
||||
ptree *end_format_token::to_xml(ptree *node)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
} //namespace formating
|
||||
|
||||
/************************************************************/
|
||||
|
||||
text_processor::text_processor():
|
||||
list_(), clear_on_write(false)
|
||||
tree_()
|
||||
{
|
||||
}
|
||||
|
||||
void text_processor::push_back(abstract_token *token)
|
||||
void text_processor::set_format_tree(formating::node_ptr tree)
|
||||
{
|
||||
if (clear_on_write) list_.clear();
|
||||
clear_on_write = false;
|
||||
list_.push_back(token);
|
||||
tree_ = tree;
|
||||
}
|
||||
|
||||
formating::node_ptr text_processor::get_format_tree() const
|
||||
{
|
||||
return tree_;
|
||||
}
|
||||
|
||||
void text_processor::from_xml(const boost::property_tree::ptree &pt, std::map<std::string,font_set> const &fontsets)
|
||||
{
|
||||
clear_on_write = true;
|
||||
defaults.set_values_from_xml(pt, fontsets);
|
||||
from_xml_recursive(pt, fontsets);
|
||||
defaults.from_xml(pt, fontsets);
|
||||
formating::node_ptr n = formating::node::from_xml(pt);
|
||||
if (n) set_format_tree(n);
|
||||
}
|
||||
|
||||
void text_processor::from_xml_recursive(const boost::property_tree::ptree &pt, std::map<std::string,font_set> const &fontsets)
|
||||
{
|
||||
ptree::const_iterator itr = pt.begin();
|
||||
ptree::const_iterator end = pt.end();
|
||||
for (; itr != end; ++itr) {
|
||||
if (itr->first == "<xmltext>") {
|
||||
std::string data = itr->second.data();
|
||||
boost::trim(data);
|
||||
if (data.empty()) continue;
|
||||
expression_token *token = new expression_token(parse_expression(data, "utf8"));
|
||||
push_back(token);
|
||||
} else if (itr->first == "Format") {
|
||||
fixed_formating_token *token = new fixed_formating_token();
|
||||
token->from_xml(itr->second);
|
||||
push_back(token);
|
||||
from_xml_recursive(itr->second, fontsets); /* Parse children, making a list out of a tree. */
|
||||
push_back(new end_format_token());
|
||||
} else if (itr->first != "<xmlcomment>" && itr->first != "<xmlattr>" && itr->first != "Placement") {
|
||||
std::cerr << "Unknown item" << itr->first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void text_processor::to_xml(boost::property_tree::ptree &node, bool explicit_defaults, text_processor const& dfl) const
|
||||
{
|
||||
defaults.to_xml(node, explicit_defaults, dfl.defaults);
|
||||
std::list<abstract_token *>::const_iterator itr = list_.begin();
|
||||
std::list<abstract_token *>::const_iterator end = list_.end();
|
||||
std::stack<ptree *> nodes;
|
||||
ptree *current_node = &node;
|
||||
for (; itr != end; ++itr) {
|
||||
abstract_token *token = *itr;
|
||||
ptree *new_node = token->to_xml(current_node);
|
||||
if (dynamic_cast<abstract_formating_token *>(token)) {
|
||||
nodes.push(current_node);
|
||||
current_node = new_node;
|
||||
} else if (dynamic_cast<end_format_token *>(token)) {
|
||||
current_node = nodes.top();
|
||||
nodes.pop();
|
||||
}
|
||||
}
|
||||
if (tree_) tree_->to_xml(node);
|
||||
}
|
||||
|
||||
void text_processor::process(processed_text &output, Feature const& feature)
|
||||
void text_processor::process(processed_text &output, Feature const& feature) const
|
||||
{
|
||||
std::list<abstract_token *>::const_iterator itr = list_.begin();
|
||||
std::list<abstract_token *>::const_iterator end = list_.end();
|
||||
std::stack<char_properties> formats;
|
||||
formats.push(defaults);
|
||||
|
||||
for (; itr != end; ++itr) {
|
||||
abstract_text_token *text = dynamic_cast<abstract_text_token *>(*itr);
|
||||
abstract_formating_token *format = dynamic_cast<abstract_formating_token *>(*itr);;
|
||||
end_format_token *end = dynamic_cast<end_format_token *>(*itr);;
|
||||
if (text) {
|
||||
UnicodeString text_str = text->to_string(feature);
|
||||
char_properties const& p = formats.top();
|
||||
/* TODO: Make a class out of text_transform which does the work! */
|
||||
if (p.text_transform == UPPERCASE)
|
||||
{
|
||||
text_str = text_str.toUpper();
|
||||
}
|
||||
else if (p.text_transform == LOWERCASE)
|
||||
{
|
||||
text_str = text_str.toLower();
|
||||
}
|
||||
else if (p.text_transform == CAPITALIZE)
|
||||
{
|
||||
text_str = text_str.toTitle(NULL);
|
||||
}
|
||||
if (text_str.length() > 0) {
|
||||
output.push_back(processed_expression(p, text_str));
|
||||
} else {
|
||||
output.clear();
|
||||
if (tree_) {
|
||||
tree_->apply(defaults, feature, output);
|
||||
} else {
|
||||
#ifdef MAPNIK_DEBUG
|
||||
std::cerr << "Warning: Empty expression.\n";
|
||||
std::cerr << "Warning: text_processor can't produce text: No formating tree!\n";
|
||||
#endif
|
||||
}
|
||||
} else if (format) {
|
||||
char_properties next_properties = formats.top();
|
||||
format->apply(next_properties, feature);
|
||||
formats.push(next_properties);
|
||||
} else if (end) {
|
||||
/* Always keep at least the defaults_ on stack. */
|
||||
if (formats.size() > 1) {
|
||||
formats.pop();
|
||||
} else {
|
||||
std::cerr << "Warning: Internal mapnik error. More elements popped than pushed in text_processor::process()\n";
|
||||
output.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (formats.size() != 1) {
|
||||
std::cerr << "Warning: Internal mapnik error. Less elements popped than pushed in text_processor::process()\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::set<expression_ptr> text_processor::get_all_expressions() const
|
||||
{
|
||||
std::set<expression_ptr> result;
|
||||
std::list<abstract_token *>::const_iterator itr = list_.begin();
|
||||
std::list<abstract_token *>::const_iterator end = list_.end();
|
||||
for (; itr != end; ++itr) {
|
||||
expression_token *text = dynamic_cast<expression_token *>(*itr);
|
||||
if (text) result.insert(text->get_expression());
|
||||
}
|
||||
if (tree_) tree_->add_expressions(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void text_processor::set_old_style_expression(expression_ptr expr)
|
||||
{
|
||||
list_.push_back(new expression_token(expr));
|
||||
tree_ = formating::node_ptr(new formating::text_node(expr));
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
|
@ -399,12 +406,12 @@ void processed_text::push_back(processed_expression const& exp)
|
|||
expr_list_.push_back(exp);
|
||||
}
|
||||
|
||||
processed_text::expression_list::const_iterator processed_text::begin()
|
||||
processed_text::expression_list::const_iterator processed_text::begin() const
|
||||
{
|
||||
return expr_list_.begin();
|
||||
}
|
||||
|
||||
processed_text::expression_list::const_iterator processed_text::end()
|
||||
processed_text::expression_list::const_iterator processed_text::end() const
|
||||
{
|
||||
return expr_list_.end();
|
||||
}
|
||||
|
@ -424,7 +431,7 @@ void processed_text::clear()
|
|||
|
||||
string_info &processed_text::get_string_info()
|
||||
{
|
||||
//info_.clear(); TODO: if this function is called twice invalid results are returned, so clear string_info first
|
||||
info_.clear(); //if this function is called twice invalid results are returned, so clear string_info first
|
||||
expression_list::iterator itr = expr_list_.begin();
|
||||
expression_list::iterator end = expr_list_.end();
|
||||
for (; itr != end; ++itr)
|
||||
|
|
|
@ -342,7 +342,7 @@ label_placement_e text_symbolizer::get_label_placement() const
|
|||
|
||||
void text_symbolizer::set_displacement(double x, double y)
|
||||
{
|
||||
placement_options_->properties.displacement = boost::make_tuple(x,y);
|
||||
placement_options_->properties.displacement = std::make_pair(x,y);
|
||||
}
|
||||
|
||||
void text_symbolizer::set_displacement(position const& p)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<Map background-color="#b5d0d0" srs="+init=epsg:4326" minimum-version="0.7.2">
|
||||
<Style name="1">
|
||||
<Rule>
|
||||
<ShieldSymbolizer file="../images/dummy.png" size="10" transform="scale(5) translate(15, 15) rotate(20) skewX(20) skewY(5)" dy="-5" dx="-5" opacity=".5" text-opacity=".3" face-name="DejaVu Sans Book" halo-radius="1" shield-dx="10" shield-dy="10" no-text="false" allow-overlap="true" avoid-edges="false">[label]</ShieldSymbolizer>
|
||||
<ShieldSymbolizer file="../images/dummy.png" size="10" transform="scale(5) translate(15, 15) rotate(20) skewX(20) skewY(5)" dy="-5" dx="-5" opacity=".5" text-opacity=".3" face-name="DejaVu Sans Book" halo-radius="1" shield-dx="10" shield-dy="10" allow-overlap="true" avoid-edges="false">[label]</ShieldSymbolizer>
|
||||
</Rule>
|
||||
<Rule>
|
||||
<PointSymbolizer allow-overlap="true"/>
|
||||
|
@ -13,7 +13,7 @@
|
|||
<LineSymbolizer/>
|
||||
</Rule>
|
||||
<Rule>
|
||||
<ShieldSymbolizer file="../svg/ellipses.svg" size="10" opacity=".5" text-opacity=".3" spacing="50" placement="line" allow-overlap="true" face-name="DejaVu Sans Book" no-text="false" line-spacing="10">[label]</ShieldSymbolizer>
|
||||
<ShieldSymbolizer file="../svg/ellipses.svg" size="10" opacity=".5" text-opacity=".3" spacing="50" placement="line" allow-overlap="true" face-name="DejaVu Sans Book" line-spacing="10">[label]</ShieldSymbolizer>
|
||||
</Rule>
|
||||
</Style>
|
||||
|
||||
|
@ -35,4 +35,4 @@
|
|||
</Datasource>
|
||||
</Layer>
|
||||
|
||||
</Map>
|
||||
</Map>
|
||||
|
|
|
@ -24,7 +24,6 @@ def test_line_symbolizer_init():
|
|||
# ShieldSymbolizer initialization
|
||||
def test_shieldsymbolizer_init():
|
||||
s = mapnik.ShieldSymbolizer(mapnik.Expression('[Field Name]'), 'DejaVu Sans Bold', 6, mapnik.Color('#000000'), mapnik.PathExpression('../data/images/dummy.png'))
|
||||
eq_(s.anchor, (0.0,0.5,))
|
||||
eq_(s.displacement, (0.0,0.0))
|
||||
eq_(s.allow_overlap, False)
|
||||
eq_(s.avoid_edges, False)
|
||||
|
@ -41,7 +40,7 @@ def test_shieldsymbolizer_init():
|
|||
eq_(s.text_ratio, 0)
|
||||
eq_(s.text_size, 6)
|
||||
eq_(s.wrap_width, 0)
|
||||
eq_(s.vertical_alignment, mapnik.vertical_alignment.MIDDLE)
|
||||
eq_(s.vertical_alignment, mapnik.vertical_alignment.AUTO)
|
||||
eq_(s.label_spacing, 0)
|
||||
eq_(s.label_position_tolerance, 0)
|
||||
# 22.5 * M_PI/180.0 initialized by default
|
||||
|
@ -54,7 +53,7 @@ def test_shieldsymbolizer_init():
|
|||
|
||||
# r1341
|
||||
eq_(s.wrap_before, False)
|
||||
eq_(s.horizontal_alignment, mapnik.horizontal_alignment.MIDDLE)
|
||||
eq_(s.horizontal_alignment, mapnik.horizontal_alignment.AUTO)
|
||||
eq_(s.justify_alignment, mapnik.justify_alignment.MIDDLE)
|
||||
eq_(s.opacity, 1.0)
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ def test_linesymbolizer_pickle():
|
|||
|
||||
# TextSymbolizer pickling
|
||||
def test_textsymbolizer_pickle():
|
||||
raise Todo("text_symbolizer pickling currently disabled")
|
||||
ts = mapnik.TextSymbolizer(mapnik.Expression('[Field_Name]'), 'Font Name', 8, mapnik.Color('black'))
|
||||
|
||||
eq_(str(ts.name), str(mapnik.Expression('[Field_Name]')))
|
||||
|
@ -81,7 +82,6 @@ def test_textsymbolizer_pickle():
|
|||
eq_(ts.text_size, 8)
|
||||
eq_(ts.fill, mapnik.Color('black'))
|
||||
|
||||
raise Todo("text_symbolizer pickling currently disabled")
|
||||
|
||||
ts2 = pickle.loads(pickle.dumps(ts,pickle.HIGHEST_PROTOCOL))
|
||||
eq_(ts.name, ts2.name)
|
||||
|
|
|
@ -63,8 +63,9 @@ def main():
|
|||
# 3 * '-v' gets us debugging information from nose
|
||||
argv.append('-v')
|
||||
argv.append('-v')
|
||||
|
||||
argv.extend(['-w','./tests/python_tests'])
|
||||
|
||||
dirname = os.path.dirname(sys.argv[0])
|
||||
argv.extend(['-w', dirname+'/python_tests'])
|
||||
|
||||
if not nose.run(argv=argv, plugins=[TodoPlugin(), Doctest()]):
|
||||
sys.exit(1)
|
||||
|
|
BIN
tests/visual_tests/formating-1-500-reference.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
22
tests/visual_tests/formating-1.xml
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE Map>
|
||||
<Map background-color="white" srs="+proj=latlong +datum=WGS84">
|
||||
|
||||
<Layer name="layer" srs="+proj=latlong +datum=WGS84">
|
||||
<StyleName>My Style</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="type">shape</Parameter>
|
||||
<Parameter name="file">points.shp</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
|
||||
<Style name="My Style">
|
||||
<Rule>
|
||||
<PointSymbolizer/>
|
||||
<!-- Basic test -->
|
||||
<TextSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" dx="0" dy="5">
|
||||
[name]+' '<Format face-name="DejaVu Sans Oblique" size="9">'('+[name]+')'</Format></TextSymbolizer>
|
||||
</Rule>
|
||||
</Style>
|
||||
|
||||
</Map>
|
BIN
tests/visual_tests/formating-2-500-reference.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
22
tests/visual_tests/formating-2.xml
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE Map>
|
||||
<Map background-color="white" srs="+proj=latlong +datum=WGS84">
|
||||
|
||||
<Layer name="layer" srs="+proj=latlong +datum=WGS84">
|
||||
<StyleName>My Style</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="type">shape</Parameter>
|
||||
<Parameter name="file">points.shp</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
|
||||
<Style name="My Style">
|
||||
<Rule>
|
||||
<PointSymbolizer/>
|
||||
<!-- Nested formats -->
|
||||
<TextSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" dx="0" dy="5">
|
||||
[name]+' '<Format face-name="DejaVu Sans Oblique"><Format size="9">'('+[name]+')'</Format></Format></TextSymbolizer>
|
||||
</Rule>
|
||||
</Style>
|
||||
|
||||
</Map>
|
BIN
tests/visual_tests/formating-3-500-reference.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
22
tests/visual_tests/formating-3.xml
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE Map>
|
||||
<Map background-color="white" srs="+proj=latlong +datum=WGS84">
|
||||
|
||||
<Layer name="layer" srs="+proj=latlong +datum=WGS84">
|
||||
<StyleName>My Style</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="type">shape</Parameter>
|
||||
<Parameter name="file">points.shp</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
|
||||
<Style name="My Style">
|
||||
<Rule>
|
||||
<PointSymbolizer/>
|
||||
<!-- Empty formats-->
|
||||
<TextSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" dx="0" dy="5">
|
||||
[name]+' '<Format face-name="DejaVu Sans Oblique" size="9"></Format></TextSymbolizer>
|
||||
</Rule>
|
||||
</Style>
|
||||
|
||||
</Map>
|
BIN
tests/visual_tests/formating-4-500-reference.png
Normal file
After Width: | Height: | Size: 533 B |
21
tests/visual_tests/formating-4.xml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE Map>
|
||||
<Map background-color="white" srs="+proj=latlong +datum=WGS84">
|
||||
|
||||
<Layer name="layer" srs="+proj=latlong +datum=WGS84">
|
||||
<StyleName>My Style</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="type">shape</Parameter>
|
||||
<Parameter name="file">points.shp</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
|
||||
<Style name="My Style">
|
||||
<Rule>
|
||||
<PointSymbolizer/>
|
||||
<!-- Empty text -->
|
||||
<TextSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" dx="0" dy="5" />
|
||||
</Rule>
|
||||
</Style>
|
||||
|
||||
</Map>
|
BIN
tests/visual_tests/shieldsymbolizer-1-500-reference.png
Normal file
After Width: | Height: | Size: 883 B |
19
tests/visual_tests/shieldsymbolizer-1.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE Map>
|
||||
<Map background-color="white" srs="+proj=latlong +datum=WGS84">
|
||||
|
||||
<Layer name="layer" srs="+proj=latlong +datum=WGS84">
|
||||
<StyleName>My Style</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="type">shape</Parameter>
|
||||
<Parameter name="file">points.shp</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
|
||||
<Style name="My Style">
|
||||
<Rule>
|
||||
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../data/svg/rect.svg" dx="0" dy="-5">'x'</ShieldSymbolizer>
|
||||
</Rule>
|
||||
</Style>
|
||||
|
||||
</Map>
|
|
@ -11,7 +11,9 @@ dirname = os.path.dirname(sys.argv[0])
|
|||
widths = [ 800, 600, 400, 300, 250, 200, 150, 100]
|
||||
filenames = ["list", "simple"]
|
||||
filenames_one_width = ["simple-E", "simple-NE", "simple-NW", "simple-N",
|
||||
"simple-SE", "simple-SW", "simple-S", "simple-W", "formating"]
|
||||
"simple-SE", "simple-SW", "simple-S", "simple-W",
|
||||
"formating-1", "formating-2", "formating-3", "formating-4",
|
||||
"shieldsymbolizer-1"]
|
||||
|
||||
def render(filename, width):
|
||||
print "Rendering style \"%s\" with width %d" % (filename, width)
|
||||
|
@ -22,12 +24,16 @@ def render(filename, width):
|
|||
mapnik.render_to_file(m, '%s-%d-agg.png' % (filename, width))
|
||||
return m
|
||||
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
filenames = []
|
||||
filenames_one_width = sys.argv[1:]
|
||||
|
||||
for filename in filenames:
|
||||
for width in widths:
|
||||
m = render(filename, width)
|
||||
mapnik.save_map(m, "%s-out.xml" % filename)
|
||||
|
||||
for filename in filenames_one_width:
|
||||
render(filename, 500)
|
||||
m = render(filename, 500)
|
||||
mapnik.save_map(m, "%s-out.xml" % filename)
|
||||
|
||||
|
|
|
@ -196,7 +196,6 @@
|
|||
line_spacing CDATA "0"
|
||||
min_distance CDATA "0"
|
||||
name CDATA #IMPLIED
|
||||
no_text (true|false) "false"
|
||||
placement (point|line|vertex) "point"
|
||||
size CDATA "10"
|
||||
spacing CDATA "0"
|
||||
|
|