Framework for group symbolizer.
This includes XML parsing of group symbolizer and related objects and process_group_symbolizer method in the AGG renderer. This also includes code to collect group symbolizer indexed columns, create sub features, and match them to group rules.
This commit is contained in:
parent
269b038147
commit
fbc2a0d1e3
17 changed files with 1048 additions and 57 deletions
|
@ -25,7 +25,7 @@ from glob import glob
|
|||
Import('env')
|
||||
|
||||
base = './mapnik/'
|
||||
subdirs = ['','svg','wkt','grid','json','util','text','text/placements','text/formatting']
|
||||
subdirs = ['','svg','wkt','grid','json','util','group','text','text/placements','text/formatting']
|
||||
|
||||
if env['SVG_RENDERER']:
|
||||
subdirs.append('svg/output')
|
||||
|
|
|
@ -116,6 +116,9 @@ public:
|
|||
void process(markers_symbolizer const& sym,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(group_symbolizer const& sym,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(debug_symbolizer const& sym,
|
||||
feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
|
|
|
@ -36,10 +36,14 @@
|
|||
#include <mapnik/path_expression.hpp> // for path_expression_ptr
|
||||
#include <mapnik/text/placements/base.hpp> // for text_placements
|
||||
#include <mapnik/image_scaling.hpp>
|
||||
#include <mapnik/group/group_symbolizer_properties.hpp>
|
||||
#include <mapnik/group/group_rule.hpp>
|
||||
|
||||
// boost
|
||||
#include <boost/variant/static_visitor.hpp>
|
||||
#include <boost/variant/apply_visitor.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
// stl
|
||||
#include <set>
|
||||
|
@ -222,6 +226,8 @@ struct symbolizer_attributes : public boost::static_visitor<>
|
|||
}
|
||||
}
|
||||
|
||||
void operator () (group_symbolizer const& sym);
|
||||
|
||||
private:
|
||||
std::set<std::string>& names_;
|
||||
double & filter_factor_;
|
||||
|
@ -269,6 +275,62 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
inline void symbolizer_attributes::operator () (group_symbolizer const& sym)
|
||||
{
|
||||
// find all column names referenced in the group symbolizer
|
||||
std::set<std::string> group_columns;
|
||||
attribute_collector column_collector(group_columns);
|
||||
expression_attributes<std::set<std::string> > rk_attr(group_columns);
|
||||
|
||||
// get columns from symbolizer repeat key
|
||||
expression_ptr repeat_key = get<mapnik::expression_ptr>(sym, keys::repeat_key);
|
||||
if (repeat_key)
|
||||
{
|
||||
boost::apply_visitor(rk_attr, *repeat_key);
|
||||
}
|
||||
|
||||
// get columns from child rules and symbolizers
|
||||
group_symbolizer_properties_ptr props = get<group_symbolizer_properties_ptr>(sym, keys::group_properties);
|
||||
if (props) {
|
||||
for (auto const& rule : props->get_rules())
|
||||
{
|
||||
column_collector(*rule);
|
||||
if (rule->get_repeat_key())
|
||||
{
|
||||
boost::apply_visitor(rk_attr, *(rule->get_repeat_key()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get indexed column names
|
||||
for (auto const& col_name : group_columns)
|
||||
{
|
||||
if (col_name.find('%') != std::string::npos)
|
||||
{
|
||||
// Note: ignore column name if it is '%' by itself.
|
||||
// '%' is a special case to access the index value itself,
|
||||
// rather than acessing indexed columns from data source.
|
||||
if (col_name.size() > 1)
|
||||
{
|
||||
// indexed column name. add column name for each index value.
|
||||
int start = get<value_integer>(sym, keys::start_column);
|
||||
int end = start + get<value_integer>(sym, keys::num_columns);
|
||||
for (int col_idx = start; col_idx < end; ++col_idx)
|
||||
{
|
||||
std::string col_idx_name = col_name;
|
||||
boost::replace_all(col_idx_name, "%", boost::lexical_cast<std::string>(col_idx));
|
||||
names_.insert(col_idx_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// non indexed column name. insert as is.
|
||||
names_.insert(col_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mapnik
|
||||
|
||||
#endif // MAPNIK_ATTRIBUTE_COLLECTOR_HPP
|
||||
|
|
94
include/mapnik/group/group_layout.hpp
Normal file
94
include/mapnik/group/group_layout.hpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2012 Artem Pavlenko
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef MAPNIK_GROUP_LAYOUT_HPP
|
||||
#define MAPNIK_GROUP_LAYOUT_HPP
|
||||
|
||||
// boost
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
|
||||
struct simple_row_layout
|
||||
{
|
||||
public:
|
||||
simple_row_layout(double item_margin = 0.0)
|
||||
: item_margin_(item_margin)
|
||||
{
|
||||
}
|
||||
|
||||
double get_item_margin() const
|
||||
{
|
||||
return item_margin_;
|
||||
}
|
||||
|
||||
void set_item_margin(double item_margin)
|
||||
{
|
||||
item_margin_ = item_margin;
|
||||
}
|
||||
|
||||
private:
|
||||
double item_margin_;
|
||||
};
|
||||
|
||||
struct pair_layout
|
||||
{
|
||||
public:
|
||||
pair_layout(double item_margin = 1.0, double max_difference = - 1.0)
|
||||
: item_margin_(item_margin),
|
||||
max_difference_(max_difference)
|
||||
{
|
||||
}
|
||||
|
||||
double get_item_margin() const
|
||||
{
|
||||
return item_margin_;
|
||||
}
|
||||
|
||||
void set_item_margin(double item_margin)
|
||||
{
|
||||
item_margin_ = item_margin;
|
||||
}
|
||||
|
||||
double get_max_difference() const
|
||||
{
|
||||
return max_difference_;
|
||||
}
|
||||
|
||||
void set_max_difference(double max_difference)
|
||||
{
|
||||
max_difference_ = max_difference;
|
||||
}
|
||||
|
||||
private:
|
||||
double item_margin_;
|
||||
double max_difference_;
|
||||
};
|
||||
|
||||
typedef boost::variant<simple_row_layout,
|
||||
pair_layout> group_layout;
|
||||
|
||||
typedef std::shared_ptr<group_layout> group_layout_ptr;
|
||||
}
|
||||
|
||||
#endif // MAPNIK_GROUP_LAYOUT_HPP
|
104
include/mapnik/group/group_layout_manager.hpp
Normal file
104
include/mapnik/group/group_layout_manager.hpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2012 Artem Pavlenko
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef MAPNIK_GROUP_LAYOUT_MANAGER_HPP
|
||||
#define MAPNIK_GROUP_LAYOUT_MANAGER_HPP
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/pixel_position.hpp>
|
||||
#include <mapnik/box2d.hpp>
|
||||
#include <mapnik/group/group_layout.hpp>
|
||||
|
||||
// stl
|
||||
#include <vector>
|
||||
|
||||
using std::vector;
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
|
||||
typedef box2d<double> bound_box;
|
||||
|
||||
struct group_layout_manager
|
||||
{
|
||||
group_layout_manager(const group_layout &layout)
|
||||
: layout_(layout),
|
||||
input_origin_(0, 0),
|
||||
member_boxes_(vector<bound_box>()),
|
||||
member_offsets_(vector<pixel_position>()),
|
||||
update_layout_(true)
|
||||
{
|
||||
}
|
||||
|
||||
group_layout_manager(const group_layout &layout, const pixel_position &input_origin)
|
||||
: layout_(layout),
|
||||
input_origin_(input_origin),
|
||||
member_boxes_(vector<bound_box>()),
|
||||
member_offsets_(vector<pixel_position>()),
|
||||
update_layout_(true)
|
||||
{
|
||||
}
|
||||
|
||||
group_layout_manager(const group_layout &layout, const pixel_position &input_origin,
|
||||
const vector<bound_box> &item_boxes)
|
||||
: layout_(layout),
|
||||
input_origin_(input_origin),
|
||||
member_boxes_(item_boxes),
|
||||
member_offsets_(vector<pixel_position>()),
|
||||
update_layout_(true)
|
||||
{
|
||||
}
|
||||
|
||||
inline void set_layout(const group_layout &layout)
|
||||
{
|
||||
layout_ = layout;
|
||||
update_layout_ = true;
|
||||
}
|
||||
|
||||
inline void add_member_bound_box(const bound_box &member_box)
|
||||
{
|
||||
member_boxes_.push_back(member_box);
|
||||
update_layout_ = true;
|
||||
}
|
||||
|
||||
inline const pixel_position &offset_at(size_t i)
|
||||
{
|
||||
handle_update();
|
||||
return member_offsets_.at(i);
|
||||
}
|
||||
|
||||
bound_box offset_box_at(size_t i);
|
||||
|
||||
private:
|
||||
|
||||
void handle_update();
|
||||
|
||||
group_layout layout_;
|
||||
pixel_position input_origin_;
|
||||
vector<bound_box> member_boxes_;
|
||||
vector<pixel_position> member_offsets_;
|
||||
bool update_layout_;
|
||||
};
|
||||
|
||||
} // namespace mapnik
|
||||
|
||||
#endif // MAPNIK_GROUP_LAYOUT_MANAGER_HPP
|
103
include/mapnik/group/group_rule.hpp
Normal file
103
include/mapnik/group/group_rule.hpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2012 Artem Pavlenko
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef MAPNIK_GROUP_RULE_HPP
|
||||
#define MAPNIK_GROUP_RULE_HPP
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/config.hpp>
|
||||
#include <mapnik/symbolizer.hpp>
|
||||
#include <mapnik/expression.hpp>
|
||||
|
||||
// boost
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
|
||||
/**
|
||||
* group rule contains a set of symbolizers which should
|
||||
* be rendered atomically when the filter attached to
|
||||
* this rule is matched.
|
||||
*/
|
||||
struct group_rule
|
||||
{
|
||||
typedef std::vector<symbolizer> symbolizers;
|
||||
|
||||
explicit group_rule(const expression_ptr& filter, const expression_ptr& repeat_key);
|
||||
|
||||
group_rule &operator=(const group_rule &rhs);
|
||||
bool operator==(const group_rule &rhs) const;
|
||||
|
||||
void append(const symbolizer &);
|
||||
|
||||
const symbolizers &get_symbolizers() const
|
||||
{
|
||||
return symbolizers_;
|
||||
}
|
||||
|
||||
inline symbolizers::const_iterator begin() const
|
||||
{
|
||||
return symbolizers_.begin();
|
||||
}
|
||||
|
||||
inline symbolizers::const_iterator end() const
|
||||
{
|
||||
return symbolizers_.end();
|
||||
}
|
||||
|
||||
inline void set_filter(const expression_ptr& filter)
|
||||
{
|
||||
filter_ = filter;
|
||||
}
|
||||
|
||||
inline expression_ptr const& get_filter() const
|
||||
{
|
||||
return filter_;
|
||||
}
|
||||
|
||||
inline void set_repeat_key(const expression_ptr& repeat_key)
|
||||
{
|
||||
repeat_key_ = repeat_key;
|
||||
}
|
||||
|
||||
inline expression_ptr const& get_repeat_key() const
|
||||
{
|
||||
return repeat_key_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// expression filter - when data matches this then
|
||||
// the symbolizers should be drawn.
|
||||
expression_ptr filter_;
|
||||
|
||||
// expression repeat key - repeat key to be used with minimum distance
|
||||
expression_ptr repeat_key_;
|
||||
|
||||
// the atomic set of symbolizers
|
||||
symbolizers symbolizers_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MAPNIK_GROUP_RULE_HPP
|
62
include/mapnik/group/group_symbolizer_properties.hpp
Normal file
62
include/mapnik/group/group_symbolizer_properties.hpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2013 Artem Pavlenko
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
#ifndef GROUP_PROPERTIES_HPP
|
||||
#define GROUP_PROPERTIES_HPP
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/config.hpp>
|
||||
#include <mapnik/group/group_layout.hpp>
|
||||
|
||||
// stl
|
||||
#include <vector>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
struct group_rule;
|
||||
typedef std::shared_ptr<group_rule> group_rule_ptr;
|
||||
typedef std::vector<group_rule_ptr> group_rules;
|
||||
|
||||
/** Contains all group symbolizer properties related to building a group layout. */
|
||||
struct group_symbolizer_properties
|
||||
{
|
||||
inline group_symbolizer_properties() : rules_() { }
|
||||
/** Load all values from XML ptree. */
|
||||
//void from_xml(xml_node const &sym, fontset_map const & fontsets);
|
||||
/** Get the layout. */
|
||||
inline group_layout const& get_layout() const { return layout_; }
|
||||
/** Get the group rules. */
|
||||
inline group_rules const& get_rules() const { return rules_; }
|
||||
/** Set the layout. */
|
||||
inline void set_layout (group_layout && layout) { layout_ = std::move(layout); }
|
||||
/** Add add group rule. */
|
||||
inline void add_rule (group_rule_ptr rule) { rules_.push_back(rule); }
|
||||
|
||||
private:
|
||||
group_layout layout_;
|
||||
group_rules rules_;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<group_symbolizer_properties> group_symbolizer_properties_ptr;
|
||||
|
||||
} //ns mapnik
|
||||
|
||||
#endif // GROUP_PROPERTIES_HPP
|
|
@ -37,6 +37,7 @@
|
|||
#include <mapnik/text/placements/base.hpp>
|
||||
#include <mapnik/text/placements/dummy.hpp>
|
||||
#include <mapnik/raster_colorizer.hpp>
|
||||
#include <mapnik/group/group_symbolizer_properties.hpp>
|
||||
// stl
|
||||
#include <type_traits>
|
||||
#include <algorithm>
|
||||
|
@ -78,7 +79,6 @@ struct enumeration_wrapper
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<std::pair<double,double> > dash_array;
|
||||
|
||||
struct MAPNIK_DECL symbolizer_base
|
||||
|
@ -94,7 +94,8 @@ struct MAPNIK_DECL symbolizer_base
|
|||
transform_type,
|
||||
text_placements_ptr,
|
||||
dash_array,
|
||||
raster_colorizer_ptr> value_type;
|
||||
raster_colorizer_ptr,
|
||||
group_symbolizer_properties_ptr> value_type;
|
||||
typedef mapnik::keys key_type;
|
||||
typedef std::map<key_type, value_type> cont_type;
|
||||
cont_type properties;
|
||||
|
@ -121,7 +122,9 @@ enum class property_types : std::uint8_t
|
|||
target_transform,
|
||||
target_placement,
|
||||
target_dash_array,
|
||||
target_colorizer
|
||||
target_colorizer,
|
||||
target_repeat_key,
|
||||
target_group_symbolizer_properties
|
||||
};
|
||||
|
||||
inline bool operator==(symbolizer_base const& lhs, symbolizer_base const& rhs)
|
||||
|
@ -415,6 +418,7 @@ struct MAPNIK_DECL polygon_pattern_symbolizer : public symbolizer_base {};
|
|||
struct MAPNIK_DECL markers_symbolizer : public symbolizer_base {};
|
||||
struct MAPNIK_DECL raster_symbolizer : public symbolizer_base {};
|
||||
struct MAPNIK_DECL building_symbolizer : public symbolizer_base {};
|
||||
struct MAPNIK_DECL group_symbolizer : public symbolizer_base {};
|
||||
struct MAPNIK_DECL debug_symbolizer : public symbolizer_base {};
|
||||
|
||||
// symbolizer
|
||||
|
@ -428,6 +432,7 @@ typedef boost::variant<point_symbolizer,
|
|||
text_symbolizer,
|
||||
building_symbolizer,
|
||||
markers_symbolizer,
|
||||
group_symbolizer,
|
||||
debug_symbolizer> symbolizer;
|
||||
|
||||
|
||||
|
|
|
@ -78,6 +78,10 @@ enum class keys : std::uint8_t
|
|||
point_placement_type,
|
||||
colorizer,
|
||||
halo_transform,
|
||||
num_columns,
|
||||
start_column,
|
||||
repeat_key,
|
||||
group_properties,
|
||||
MAX_SYMBOLIZER_KEY
|
||||
};
|
||||
|
||||
|
|
|
@ -165,6 +165,8 @@ class text_layout;
|
|||
struct MAPNIK_DECL text_symbolizer_properties
|
||||
{
|
||||
text_symbolizer_properties();
|
||||
/** Load only placement related values from XML ptree. */
|
||||
void placement_properties_from_xml(xml_node const &sym);
|
||||
/** Load all values from XML ptree. */
|
||||
void from_xml(xml_node const &sym, fontset_map const & fontsets);
|
||||
/** Save all values to XML ptree (but does not create a new parent node!). */
|
||||
|
|
175
src/agg/process_group_symbolizer.cpp
Normal file
175
src/agg/process_group_symbolizer.cpp
Normal file
|
@ -0,0 +1,175 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2011 Artem Pavlenko
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/feature.hpp>
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
#include <mapnik/agg_rasterizer.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/feature_factory.hpp>
|
||||
#include <mapnik/attribute_collector.hpp>
|
||||
#include <mapnik/text/layout.hpp>
|
||||
#include <mapnik/group/group_layout_manager.hpp>
|
||||
|
||||
#include <mapnik/geom_util.hpp>
|
||||
#include <mapnik/symbolizer.hpp>
|
||||
#include <mapnik/parse_path.hpp>
|
||||
#include <mapnik/pixel_position.hpp>
|
||||
|
||||
// agg
|
||||
#include "agg_trans_affine.h"
|
||||
|
||||
// stl
|
||||
#include <string>
|
||||
|
||||
// boost
|
||||
#include <boost/variant/apply_visitor.hpp>
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
template <typename T0, typename T1>
|
||||
void agg_renderer<T0,T1>::process(group_symbolizer const& sym,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
// find all column names referenced in the group rules and symbolizers
|
||||
std::set<std::string> columns;
|
||||
attribute_collector column_collector(columns);
|
||||
expression_attributes<std::set<std::string> > rk_attr(columns);
|
||||
|
||||
expression_ptr repeat_key = get<mapnik::expression_ptr>(sym, keys::repeat_key);
|
||||
if (repeat_key)
|
||||
{
|
||||
boost::apply_visitor(rk_attr, *repeat_key);
|
||||
}
|
||||
|
||||
// get columns from child rules and symbolizers
|
||||
group_symbolizer_properties_ptr props = get<group_symbolizer_properties_ptr>(sym, keys::group_properties);
|
||||
if (props) {
|
||||
for (auto const& rule : props->get_rules())
|
||||
{
|
||||
// note that this recurses down on to the symbolizer
|
||||
// internals too, so we get all free variables.
|
||||
column_collector(*rule);
|
||||
// still need to collect repeat key columns
|
||||
if (rule->get_repeat_key())
|
||||
{
|
||||
boost::apply_visitor(rk_attr, *(rule->get_repeat_key()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create a new context for the sub features of this group
|
||||
context_ptr sub_feature_ctx = std::make_shared<mapnik::context_type>();
|
||||
|
||||
// populate new context with column names referenced in the group rules and symbolizers
|
||||
// and determine if any indexed columns are present
|
||||
bool has_idx_cols = false;
|
||||
for (auto const& col_name : columns)
|
||||
{
|
||||
sub_feature_ctx->push(col_name);
|
||||
if (col_name.find('%') != std::string::npos)
|
||||
{
|
||||
has_idx_cols = true;
|
||||
}
|
||||
}
|
||||
|
||||
// keep track of the sub features that we'll want to symbolize
|
||||
// along with the group rules that they matched
|
||||
std::vector< std::pair<group_rule_ptr, feature_ptr> > matches;
|
||||
|
||||
// layout manager to store and arrange bboxes of matched features
|
||||
group_layout_manager layout_manager(props->get_layout(), pixel_position(common_.width_ / 2.0, common_.height_ / 2.0));
|
||||
text_layout text(common_.font_manager_, common_.scale_factor_);
|
||||
|
||||
// run feature or sub feature through the group rules & symbolizers
|
||||
// for each index value in the range
|
||||
int start = get<value_integer>(sym, keys::start_column);
|
||||
int end = start + get<value_integer>(sym, keys::num_columns);
|
||||
for (int col_idx = start; col_idx < end; ++col_idx)
|
||||
{
|
||||
feature_ptr sub_feature;
|
||||
|
||||
if (has_idx_cols)
|
||||
{
|
||||
// create sub feature with indexed column values
|
||||
sub_feature = feature_factory::create(sub_feature_ctx, col_idx);
|
||||
|
||||
// copy the necessary columns to sub feature
|
||||
for(auto const& col_name : columns)
|
||||
{
|
||||
if (col_name.find('%') != std::string::npos)
|
||||
{
|
||||
if (col_name.size() == 1)
|
||||
{
|
||||
// column name is '%' by itself, so give the index as the value
|
||||
sub_feature->put(col_name, (value_integer)col_idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
// indexed column
|
||||
std::string col_idx_name = col_name;
|
||||
boost::replace_all(col_idx_name, "%", boost::lexical_cast<std::string>(col_idx));
|
||||
sub_feature->put(col_name, feature.get(col_idx_name));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// non-indexed column
|
||||
sub_feature->put(col_name, feature.get(col_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no indexed columns, so use the existing feature instead of copying
|
||||
sub_feature = feature_ptr(&feature);
|
||||
}
|
||||
|
||||
for (auto const& rule : props->get_rules())
|
||||
{
|
||||
if (boost::apply_visitor(evaluate<Feature,value_type>(*sub_feature),
|
||||
*(rule->get_filter())).to_bool())
|
||||
{
|
||||
// add matched rule and feature to the list of things to draw
|
||||
matches.push_back(std::make_pair(rule, sub_feature));
|
||||
|
||||
// construct a bounding box around all symbolizers for the matched rule
|
||||
bound_box bounds;
|
||||
for (auto const& sym : *rule)
|
||||
{
|
||||
// TODO: construct layout and obtain bounding box
|
||||
}
|
||||
|
||||
// add the bounding box to the layout manager
|
||||
layout_manager.add_member_bound_box(bounds);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template void agg_renderer<image_32>::process(group_symbolizer const&,
|
||||
mapnik::feature_impl &,
|
||||
proj_transform const&);
|
||||
|
||||
}
|
|
@ -233,6 +233,8 @@ source = Split(
|
|||
text/placements/dummy.cpp
|
||||
text/placements/list.cpp
|
||||
text/placements/simple.cpp
|
||||
group/group_layout_manager.cpp
|
||||
group/group_rule.cpp
|
||||
xml_tree.cpp
|
||||
config_error.cpp
|
||||
color_factory.cpp
|
||||
|
@ -297,6 +299,7 @@ source += Split(
|
|||
agg/process_raster_symbolizer.cpp
|
||||
agg/process_shield_symbolizer.cpp
|
||||
agg/process_markers_symbolizer.cpp
|
||||
agg/process_group_symbolizer.cpp
|
||||
agg/process_debug_symbolizer.cpp
|
||||
"""
|
||||
)
|
||||
|
|
171
src/group/group_layout_manager.cpp
Normal file
171
src/group/group_layout_manager.cpp
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2012 Artem Pavlenko
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/group/group_layout_manager.hpp>
|
||||
|
||||
// boost
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
// std
|
||||
#include <cmath>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
|
||||
// This visitor will process offsets for the given layout
|
||||
struct process_layout : public boost::static_visitor<>
|
||||
{
|
||||
// The vector containing the existing, centered item bounding boxes
|
||||
const vector<bound_box> &member_boxes_;
|
||||
|
||||
// The vector to populate with item offsets
|
||||
vector<pixel_position> &member_offsets_;
|
||||
|
||||
// The origin point of the member boxes
|
||||
// i.e. The member boxes are positioned around input_origin,
|
||||
// and the offset values should position them around (0,0)
|
||||
const pixel_position &input_origin_;
|
||||
|
||||
process_layout(const vector<bound_box> &member_bboxes,
|
||||
vector<pixel_position> &member_offsets,
|
||||
const pixel_position &input_origin)
|
||||
: member_boxes_(member_bboxes),
|
||||
member_offsets_(member_offsets),
|
||||
input_origin_(input_origin)
|
||||
{
|
||||
}
|
||||
|
||||
// arrange group memebers in centered, horizontal row
|
||||
void operator()(simple_row_layout const& layout) const
|
||||
{
|
||||
double total_width = (member_boxes_.size() - 1) * layout.get_item_margin();
|
||||
for (auto const& box : member_boxes_)
|
||||
{
|
||||
total_width += box.width();
|
||||
}
|
||||
|
||||
double x_offset = -(total_width / 2.0);
|
||||
for (auto const& box : member_boxes_)
|
||||
{
|
||||
member_offsets_.push_back(pixel_position(x_offset - box.minx(), -input_origin_.y));
|
||||
x_offset += box.width() + layout.get_item_margin();
|
||||
}
|
||||
}
|
||||
|
||||
// arrange group members in x horizontal pairs of 2,
|
||||
// one to the left and one to the right of center in each pair
|
||||
void operator()(pair_layout const& layout) const
|
||||
{
|
||||
member_offsets_.resize(member_boxes_.size());
|
||||
double y_margin = layout.get_item_margin();
|
||||
double x_margin = y_margin / 2.0;
|
||||
|
||||
if (member_boxes_.size() == 1)
|
||||
{
|
||||
member_offsets_[0] = pixel_position(0, 0) - input_origin_;
|
||||
return;
|
||||
}
|
||||
|
||||
bound_box layout_box;
|
||||
size_t middle_ifirst = (member_boxes_.size() - 1) >> 1, top_i = 0, bottom_i = 0;
|
||||
if (middle_ifirst % 2 == 0)
|
||||
{
|
||||
layout_box = make_horiz_pair(0, 0.0, 0, x_margin, layout.get_max_difference());
|
||||
top_i = middle_ifirst - 2;
|
||||
bottom_i = middle_ifirst + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
top_i = middle_ifirst - 1;
|
||||
bottom_i = middle_ifirst + 1;
|
||||
}
|
||||
|
||||
while (bottom_i >= 0 && top_i < member_offsets_.size())
|
||||
{
|
||||
layout_box.expand_to_include(make_horiz_pair(top_i, layout_box.miny() - y_margin, -1, x_margin, layout.get_max_difference()));
|
||||
layout_box.expand_to_include(make_horiz_pair(bottom_i, layout_box.maxy() + y_margin, 1, x_margin, layout.get_max_difference()));
|
||||
top_i -= 2;
|
||||
bottom_i += 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Place member bound boxes at [ifirst] and [ifirst + 1] in a horizontal pairi, vertically
|
||||
// align with pair_y, store corresponding offsets, and return bound box of combined pair
|
||||
// Note: x_margin is the distance between box edge and x center
|
||||
bound_box make_horiz_pair(size_t ifirst, double pair_y, int y_dir, double x_margin, double max_diff) const
|
||||
{
|
||||
// two boxes available for pair
|
||||
if (ifirst + 1 < member_boxes_.size())
|
||||
{
|
||||
double x_center = member_boxes_[ifirst].width() - member_boxes_[ifirst + 1].width();
|
||||
if (max_diff < 0.0 || std::abs(x_center) <= max_diff)
|
||||
{
|
||||
x_center = 0.0;
|
||||
}
|
||||
|
||||
bound_box pair_box = box_offset_align(ifirst, x_center - x_margin, pair_y, -1, y_dir);
|
||||
pair_box.expand_to_include(box_offset_align(ifirst + 1, x_center + x_margin, pair_y, 1, y_dir));
|
||||
return pair_box;
|
||||
}
|
||||
|
||||
// only one box available for this "pair", so keep x-centered and handle y-offset
|
||||
return box_offset_align(ifirst, 0, pair_y, 0, y_dir);
|
||||
}
|
||||
|
||||
|
||||
// Offsets member bound box at [i] and align with (x, y), in direction <x_dir, y_dir>
|
||||
// stores corresponding offset, and returns modified bounding box
|
||||
bound_box box_offset_align(size_t i, double x, double y, int x_dir, int y_dir) const
|
||||
{
|
||||
const bound_box &box = member_boxes_[i];
|
||||
pixel_position offset((x_dir == 0 ? x - input_origin_.x : x - (x_dir < 0 ? box.maxx() : box.minx())),
|
||||
(y_dir == 0 ? y - input_origin_.y : y - (y_dir < 0 ? box.maxy() : box.miny())));
|
||||
|
||||
member_offsets_[i] = offset;
|
||||
return bound_box(box.minx() + offset.x, box.miny() + offset.y, box.maxx() + offset.x, box.maxy() + offset.y);
|
||||
}
|
||||
};
|
||||
|
||||
bound_box group_layout_manager::offset_box_at(size_t i)
|
||||
{
|
||||
handle_update();
|
||||
const pixel_position &offset = member_offsets_.at(i);
|
||||
const bound_box &box = member_boxes_.at(i);
|
||||
return box2d<double>(box.minx() + offset.x, box.miny() + offset.y,
|
||||
box.maxx() + offset.x, box.maxy() + offset.y);
|
||||
}
|
||||
|
||||
void group_layout_manager::handle_update()
|
||||
{
|
||||
if (update_layout_)
|
||||
{
|
||||
member_offsets_.clear();
|
||||
boost::apply_visitor(process_layout(member_boxes_, member_offsets_, input_origin_), layout_);
|
||||
update_layout_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
59
src/group/group_rule.cpp
Normal file
59
src/group/group_rule.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2012 Artem Pavlenko
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/symbolizer.hpp>
|
||||
#include <mapnik/group/group_rule.hpp>
|
||||
|
||||
// stl
|
||||
#include <iostream>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
|
||||
group_rule::group_rule(const expression_ptr& filter = std::make_shared<mapnik::expr_node>(true),
|
||||
const expression_ptr& repeat_key = expression_ptr())
|
||||
: filter_(filter),
|
||||
repeat_key_(repeat_key)
|
||||
{
|
||||
}
|
||||
|
||||
group_rule &group_rule::operator=(const group_rule &rhs)
|
||||
{
|
||||
group_rule tmp(rhs);
|
||||
filter_.swap(tmp.filter_);
|
||||
symbolizers_.swap(tmp.symbolizers_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool group_rule::operator==(const group_rule &rhs) const
|
||||
{
|
||||
return (this == &rhs);
|
||||
}
|
||||
|
||||
void group_rule::append(const mapnik::symbolizer &sym)
|
||||
{
|
||||
symbolizers_.push_back(sym);
|
||||
}
|
||||
|
||||
}
|
||||
|
238
src/load_map.cpp
238
src/load_map.cpp
|
@ -54,6 +54,7 @@
|
|||
#include <mapnik/util/fs.hpp>
|
||||
#include <mapnik/image_filter_types.hpp>
|
||||
#include <mapnik/projection.hpp>
|
||||
#include <mapnik/group/group_rule.hpp>
|
||||
|
||||
|
||||
// boost
|
||||
|
@ -101,6 +102,7 @@ private:
|
|||
|
||||
void parse_rule(feature_type_style & style, xml_node const & r);
|
||||
|
||||
void parse_symbolizers(rule & rule, xml_node const & node);
|
||||
void parse_point_symbolizer(rule & rule, xml_node const& sym);
|
||||
void parse_line_pattern_symbolizer(rule & rule, xml_node const& sym);
|
||||
void parse_polygon_pattern_symbolizer(rule & rule, xml_node const& sym);
|
||||
|
@ -111,7 +113,13 @@ private:
|
|||
void parse_building_symbolizer(rule & rule, xml_node const& sym);
|
||||
void parse_raster_symbolizer(rule & rule, xml_node const& sym);
|
||||
void parse_markers_symbolizer(rule & rule, xml_node const& sym);
|
||||
void parse_group_symbolizer(rule &rule, xml_node const& sym);
|
||||
void parse_debug_symbolizer(rule & rule, xml_node const& sym);
|
||||
|
||||
void parse_group_rule(group_symbolizer_properties &prop, xml_node const &r);
|
||||
void parse_simple_layout(group_symbolizer_properties &prop, xml_node const &node);
|
||||
void parse_pair_layout(group_symbolizer_properties &prop, xml_node const &nd);
|
||||
|
||||
bool parse_raster_colorizer(raster_colorizer_ptr const& rc, xml_node const& node);
|
||||
void parse_stroke(symbolizer_base & symbol, xml_node const & sym);
|
||||
void ensure_font_face(std::string const& face_name);
|
||||
|
@ -792,58 +800,7 @@ void map_parser::parse_rule(feature_type_style & style, xml_node const& node)
|
|||
rule.set_max_scale(child->get_value<double>());
|
||||
}
|
||||
|
||||
for (auto const& sym_node : node)
|
||||
{
|
||||
switch (name2int(sym_node.name().c_str()))
|
||||
{
|
||||
case name2int("PointSymbolizer"):
|
||||
parse_point_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("LinePatternSymbolizer"):
|
||||
parse_line_pattern_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("PolygonPatternSymbolizer"):
|
||||
parse_polygon_pattern_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("TextSymbolizer"):
|
||||
parse_text_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("ShieldSymbolizer"):
|
||||
parse_shield_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("LineSymbolizer"):
|
||||
parse_line_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("PolygonSymbolizer"):
|
||||
parse_polygon_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("BuildingSymbolizer"):
|
||||
parse_building_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("RasterSymbolizer"):
|
||||
parse_raster_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("MarkersSymbolizer"):
|
||||
parse_markers_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("DebugSymbolizer"):
|
||||
parse_debug_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
parse_symbolizers(rule, node);
|
||||
style.add_rule(rule);
|
||||
|
||||
}
|
||||
|
@ -857,6 +814,66 @@ void map_parser::parse_rule(feature_type_style & style, xml_node const& node)
|
|||
}
|
||||
}
|
||||
|
||||
void map_parser::parse_symbolizers(rule & rule, xml_node const & node)
|
||||
{
|
||||
for (auto const& sym_node : node)
|
||||
{
|
||||
switch (name2int(sym_node.name().c_str()))
|
||||
{
|
||||
case name2int("PointSymbolizer"):
|
||||
parse_point_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("LinePatternSymbolizer"):
|
||||
parse_line_pattern_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("PolygonPatternSymbolizer"):
|
||||
parse_polygon_pattern_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("TextSymbolizer"):
|
||||
parse_text_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("ShieldSymbolizer"):
|
||||
parse_shield_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("LineSymbolizer"):
|
||||
parse_line_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("PolygonSymbolizer"):
|
||||
parse_polygon_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("BuildingSymbolizer"):
|
||||
parse_building_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("RasterSymbolizer"):
|
||||
parse_raster_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("MarkersSymbolizer"):
|
||||
parse_markers_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("GroupSymbolizer"):
|
||||
parse_group_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
case name2int("DebugSymbolizer"):
|
||||
parse_debug_symbolizer(rule, sym_node);
|
||||
sym_node.set_processed(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// helper method
|
||||
template <typename Symbolizer, typename T>
|
||||
void set_symbolizer_property(Symbolizer & sym, keys key, xml_node const & node)
|
||||
|
@ -1552,6 +1569,58 @@ void map_parser::parse_raster_symbolizer(rule & rule, xml_node const & sym)
|
|||
}
|
||||
}
|
||||
|
||||
void map_parser::parse_group_symbolizer(rule &rule, xml_node const & sym)
|
||||
{
|
||||
try
|
||||
{
|
||||
group_symbolizer symbol;
|
||||
group_symbolizer_properties_ptr prop = std::make_shared<group_symbolizer_properties>();
|
||||
|
||||
set_symbolizer_property<symbolizer_base, value_integer>(symbol, keys::num_columns, sym);
|
||||
set_symbolizer_property<symbolizer_base, value_integer>(symbol, keys::start_column, sym);
|
||||
set_symbolizer_property<symbolizer_base, expression_ptr>(symbol, keys::repeat_key, sym);
|
||||
|
||||
text_placements_ptr placements = std::make_shared<text_placements_dummy>();
|
||||
placements->defaults.placement_properties_from_xml(sym);
|
||||
put<text_placements_ptr>(symbol, keys::text_placements_, placements);
|
||||
|
||||
size_t layout_count = 0;
|
||||
for (auto const& node : sym)
|
||||
{
|
||||
if (node.is("GroupRule"))
|
||||
{
|
||||
parse_group_rule(*prop, node);
|
||||
node.set_processed(true);
|
||||
}
|
||||
else if (node.is("SimpleLayout"))
|
||||
{
|
||||
parse_simple_layout(*prop, node);
|
||||
node.set_processed(true);
|
||||
++layout_count;
|
||||
}
|
||||
else if (node.is("PairLayout"))
|
||||
{
|
||||
parse_pair_layout(*prop, node);
|
||||
node.set_processed(true);
|
||||
++layout_count;
|
||||
}
|
||||
if (layout_count > 1)
|
||||
{
|
||||
throw config_error("Provide only one layout for a GroupSymbolizer.");
|
||||
}
|
||||
}
|
||||
put(symbol, keys::group_properties, prop);
|
||||
|
||||
parse_symbolizer_base(symbol, sym);
|
||||
rule.append(symbol);
|
||||
}
|
||||
catch (const config_error & ex)
|
||||
{
|
||||
ex.append_context(sym);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void map_parser::parse_debug_symbolizer(rule & rule, xml_node const & sym)
|
||||
{
|
||||
debug_symbolizer symbol;
|
||||
|
@ -1650,6 +1719,71 @@ bool map_parser::parse_raster_colorizer(raster_colorizer_ptr const& rc,
|
|||
return found_stops;
|
||||
}
|
||||
|
||||
void map_parser::parse_group_rule(group_symbolizer_properties & prop, xml_node const & node)
|
||||
{
|
||||
try
|
||||
{
|
||||
rule fake_rule;
|
||||
expression_ptr filter, repeat_key;
|
||||
|
||||
xml_node const *filter_child = node.get_opt_child("Filter"),
|
||||
*rptkey_child = node.get_opt_child("RepeatKey");
|
||||
|
||||
if (filter_child)
|
||||
{
|
||||
filter = filter_child->get_value<expression_ptr>();
|
||||
}
|
||||
else
|
||||
{
|
||||
filter = std::make_shared<mapnik::expr_node>(true);
|
||||
}
|
||||
|
||||
if (rptkey_child)
|
||||
{
|
||||
repeat_key = rptkey_child->get_value<expression_ptr>();
|
||||
}
|
||||
|
||||
group_rule_ptr rule = std::make_shared<group_rule>(filter, repeat_key);
|
||||
|
||||
parse_symbolizers(fake_rule, node);
|
||||
|
||||
for (auto const& sym : fake_rule)
|
||||
{
|
||||
rule->append(sym);
|
||||
}
|
||||
|
||||
prop.add_rule(rule);
|
||||
}
|
||||
catch (const config_error & ex)
|
||||
{
|
||||
ex.append_context(node);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void map_parser::parse_simple_layout(group_symbolizer_properties & prop, xml_node const & node)
|
||||
{
|
||||
simple_row_layout layout;
|
||||
|
||||
optional<double> item_margin = node.get_opt_attr<double>("item-margin");
|
||||
if (item_margin) layout.set_item_margin(*item_margin);
|
||||
|
||||
prop.set_layout(std::move(layout));
|
||||
}
|
||||
|
||||
void map_parser::parse_pair_layout(group_symbolizer_properties & prop, xml_node const & node)
|
||||
{
|
||||
pair_layout layout;
|
||||
|
||||
optional<double> item_margin = node.get_opt_attr<double>("item-margin");
|
||||
if (item_margin) layout.set_item_margin(*item_margin);
|
||||
|
||||
optional<double> max_difference = node.get_opt_attr<double>("max-difference");
|
||||
if (max_difference) layout.set_max_difference(*max_difference);
|
||||
|
||||
prop.set_layout(std::move(layout));
|
||||
}
|
||||
|
||||
void map_parser::ensure_font_face(std::string const& face_name)
|
||||
{
|
||||
if (! font_manager_.get_face(face_name))
|
||||
|
|
|
@ -91,6 +91,10 @@ static const property_meta_type key_meta[to_integral(keys::MAX_SYMBOLIZER_KEY)]
|
|||
[](enumeration_wrapper e) { return enumeration<point_placement_enum,point_placement_enum_MAX>(point_placement_enum(e.value)).as_string();}, property_types::target_double },
|
||||
property_meta_type{ "raster-colorizer", nullptr, nullptr, property_types::target_colorizer},
|
||||
property_meta_type{ "halo-transform", false, nullptr, property_types::target_transform },
|
||||
property_meta_type{ "num-columns", static_cast<value_integer>(0), nullptr, property_types::target_integer},
|
||||
property_meta_type{ "start-column", static_cast<value_integer>(1), nullptr, property_types::target_integer},
|
||||
property_meta_type{ "repeat-key", nullptr, nullptr, property_types::target_repeat_key},
|
||||
property_meta_type{ "symbolizer-properties", nullptr, nullptr, property_types::target_group_symbolizer_properties}
|
||||
};
|
||||
|
||||
property_meta_type const& get_meta(mapnik::keys key)
|
||||
|
|
|
@ -138,7 +138,7 @@ formatting::node_ptr text_symbolizer_properties::format_tree() const
|
|||
return tree_;
|
||||
}
|
||||
|
||||
void text_symbolizer_properties::from_xml(xml_node const &sym, fontset_map const & fontsets)
|
||||
void text_symbolizer_properties::placement_properties_from_xml(xml_node const &sym)
|
||||
{
|
||||
optional<label_placement_e> placement_ = sym.get_opt_attr<label_placement_e>("placement");
|
||||
if (placement_) label_placement = *placement_;
|
||||
|
@ -163,6 +163,12 @@ void text_symbolizer_properties::from_xml(xml_node const &sym, fontset_map const
|
|||
if (allow_overlap_) allow_overlap = *allow_overlap_;
|
||||
optional<boolean> largest_bbox_only_ = sym.get_opt_attr<boolean>("largest-bbox-only");
|
||||
if (largest_bbox_only_) largest_bbox_only = *largest_bbox_only_;
|
||||
}
|
||||
|
||||
void text_symbolizer_properties::from_xml(xml_node const &sym, fontset_map const & fontsets)
|
||||
{
|
||||
placement_properties_from_xml(sym);
|
||||
|
||||
optional<double> max_char_angle_delta_ = sym.get_opt_attr<double>("max-char-angle-delta");
|
||||
if (max_char_angle_delta_) max_char_angle_delta=(*max_char_angle_delta_)*(M_PI/180);
|
||||
optional<text_upright_e> upright_ = sym.get_opt_attr<text_upright_e>("upright");
|
||||
|
|
Loading…
Reference in a new issue