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')
|
Import('env')
|
||||||
|
|
||||||
base = './mapnik/'
|
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']:
|
if env['SVG_RENDERER']:
|
||||||
subdirs.append('svg/output')
|
subdirs.append('svg/output')
|
||||||
|
|
|
@ -116,6 +116,9 @@ public:
|
||||||
void process(markers_symbolizer const& sym,
|
void process(markers_symbolizer const& sym,
|
||||||
mapnik::feature_impl & feature,
|
mapnik::feature_impl & feature,
|
||||||
proj_transform const& prj_trans);
|
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,
|
void process(debug_symbolizer const& sym,
|
||||||
feature_impl & feature,
|
feature_impl & feature,
|
||||||
proj_transform const& prj_trans);
|
proj_transform const& prj_trans);
|
||||||
|
|
|
@ -36,10 +36,14 @@
|
||||||
#include <mapnik/path_expression.hpp> // for path_expression_ptr
|
#include <mapnik/path_expression.hpp> // for path_expression_ptr
|
||||||
#include <mapnik/text/placements/base.hpp> // for text_placements
|
#include <mapnik/text/placements/base.hpp> // for text_placements
|
||||||
#include <mapnik/image_scaling.hpp>
|
#include <mapnik/image_scaling.hpp>
|
||||||
|
#include <mapnik/group/group_symbolizer_properties.hpp>
|
||||||
|
#include <mapnik/group/group_rule.hpp>
|
||||||
|
|
||||||
// boost
|
// boost
|
||||||
#include <boost/variant/static_visitor.hpp>
|
#include <boost/variant/static_visitor.hpp>
|
||||||
#include <boost/variant/apply_visitor.hpp>
|
#include <boost/variant/apply_visitor.hpp>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
// stl
|
// stl
|
||||||
#include <set>
|
#include <set>
|
||||||
|
@ -222,6 +226,8 @@ struct symbolizer_attributes : public boost::static_visitor<>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void operator () (group_symbolizer const& sym);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::set<std::string>& names_;
|
std::set<std::string>& names_;
|
||||||
double & filter_factor_;
|
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
|
} // namespace mapnik
|
||||||
|
|
||||||
#endif // MAPNIK_ATTRIBUTE_COLLECTOR_HPP
|
#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/base.hpp>
|
||||||
#include <mapnik/text/placements/dummy.hpp>
|
#include <mapnik/text/placements/dummy.hpp>
|
||||||
#include <mapnik/raster_colorizer.hpp>
|
#include <mapnik/raster_colorizer.hpp>
|
||||||
|
#include <mapnik/group/group_symbolizer_properties.hpp>
|
||||||
// stl
|
// stl
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -78,7 +79,6 @@ struct enumeration_wrapper
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef std::vector<std::pair<double,double> > dash_array;
|
typedef std::vector<std::pair<double,double> > dash_array;
|
||||||
|
|
||||||
struct MAPNIK_DECL symbolizer_base
|
struct MAPNIK_DECL symbolizer_base
|
||||||
|
@ -94,7 +94,8 @@ struct MAPNIK_DECL symbolizer_base
|
||||||
transform_type,
|
transform_type,
|
||||||
text_placements_ptr,
|
text_placements_ptr,
|
||||||
dash_array,
|
dash_array,
|
||||||
raster_colorizer_ptr> value_type;
|
raster_colorizer_ptr,
|
||||||
|
group_symbolizer_properties_ptr> value_type;
|
||||||
typedef mapnik::keys key_type;
|
typedef mapnik::keys key_type;
|
||||||
typedef std::map<key_type, value_type> cont_type;
|
typedef std::map<key_type, value_type> cont_type;
|
||||||
cont_type properties;
|
cont_type properties;
|
||||||
|
@ -121,7 +122,9 @@ enum class property_types : std::uint8_t
|
||||||
target_transform,
|
target_transform,
|
||||||
target_placement,
|
target_placement,
|
||||||
target_dash_array,
|
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)
|
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 markers_symbolizer : public symbolizer_base {};
|
||||||
struct MAPNIK_DECL raster_symbolizer : public symbolizer_base {};
|
struct MAPNIK_DECL raster_symbolizer : public symbolizer_base {};
|
||||||
struct MAPNIK_DECL building_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 {};
|
struct MAPNIK_DECL debug_symbolizer : public symbolizer_base {};
|
||||||
|
|
||||||
// symbolizer
|
// symbolizer
|
||||||
|
@ -428,6 +432,7 @@ typedef boost::variant<point_symbolizer,
|
||||||
text_symbolizer,
|
text_symbolizer,
|
||||||
building_symbolizer,
|
building_symbolizer,
|
||||||
markers_symbolizer,
|
markers_symbolizer,
|
||||||
|
group_symbolizer,
|
||||||
debug_symbolizer> symbolizer;
|
debug_symbolizer> symbolizer;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,10 @@ enum class keys : std::uint8_t
|
||||||
point_placement_type,
|
point_placement_type,
|
||||||
colorizer,
|
colorizer,
|
||||||
halo_transform,
|
halo_transform,
|
||||||
|
num_columns,
|
||||||
|
start_column,
|
||||||
|
repeat_key,
|
||||||
|
group_properties,
|
||||||
MAX_SYMBOLIZER_KEY
|
MAX_SYMBOLIZER_KEY
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,8 @@ class text_layout;
|
||||||
struct MAPNIK_DECL text_symbolizer_properties
|
struct MAPNIK_DECL text_symbolizer_properties
|
||||||
{
|
{
|
||||||
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. */
|
/** Load all values from XML ptree. */
|
||||||
void from_xml(xml_node const &sym, fontset_map const & fontsets);
|
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!). */
|
/** 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/dummy.cpp
|
||||||
text/placements/list.cpp
|
text/placements/list.cpp
|
||||||
text/placements/simple.cpp
|
text/placements/simple.cpp
|
||||||
|
group/group_layout_manager.cpp
|
||||||
|
group/group_rule.cpp
|
||||||
xml_tree.cpp
|
xml_tree.cpp
|
||||||
config_error.cpp
|
config_error.cpp
|
||||||
color_factory.cpp
|
color_factory.cpp
|
||||||
|
@ -297,6 +299,7 @@ source += Split(
|
||||||
agg/process_raster_symbolizer.cpp
|
agg/process_raster_symbolizer.cpp
|
||||||
agg/process_shield_symbolizer.cpp
|
agg/process_shield_symbolizer.cpp
|
||||||
agg/process_markers_symbolizer.cpp
|
agg/process_markers_symbolizer.cpp
|
||||||
|
agg/process_group_symbolizer.cpp
|
||||||
agg/process_debug_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
156
src/load_map.cpp
156
src/load_map.cpp
|
@ -54,6 +54,7 @@
|
||||||
#include <mapnik/util/fs.hpp>
|
#include <mapnik/util/fs.hpp>
|
||||||
#include <mapnik/image_filter_types.hpp>
|
#include <mapnik/image_filter_types.hpp>
|
||||||
#include <mapnik/projection.hpp>
|
#include <mapnik/projection.hpp>
|
||||||
|
#include <mapnik/group/group_rule.hpp>
|
||||||
|
|
||||||
|
|
||||||
// boost
|
// boost
|
||||||
|
@ -101,6 +102,7 @@ private:
|
||||||
|
|
||||||
void parse_rule(feature_type_style & style, xml_node const & r);
|
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_point_symbolizer(rule & rule, xml_node const& sym);
|
||||||
void parse_line_pattern_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);
|
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_building_symbolizer(rule & rule, xml_node const& sym);
|
||||||
void parse_raster_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_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_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);
|
bool parse_raster_colorizer(raster_colorizer_ptr const& rc, xml_node const& node);
|
||||||
void parse_stroke(symbolizer_base & symbol, xml_node const & sym);
|
void parse_stroke(symbolizer_base & symbol, xml_node const & sym);
|
||||||
void ensure_font_face(std::string const& face_name);
|
void ensure_font_face(std::string const& face_name);
|
||||||
|
@ -792,6 +800,22 @@ void map_parser::parse_rule(feature_type_style & style, xml_node const& node)
|
||||||
rule.set_max_scale(child->get_value<double>());
|
rule.set_max_scale(child->get_value<double>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parse_symbolizers(rule, node);
|
||||||
|
style.add_rule(rule);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (config_error const& ex)
|
||||||
|
{
|
||||||
|
if (!name.empty())
|
||||||
|
{
|
||||||
|
ex.append_context(std::string("in rule '") + name + "'", node);
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void map_parser::parse_symbolizers(rule & rule, xml_node const & node)
|
||||||
|
{
|
||||||
for (auto const& sym_node : node)
|
for (auto const& sym_node : node)
|
||||||
{
|
{
|
||||||
switch (name2int(sym_node.name().c_str()))
|
switch (name2int(sym_node.name().c_str()))
|
||||||
|
@ -836,6 +860,10 @@ void map_parser::parse_rule(feature_type_style & style, xml_node const& node)
|
||||||
parse_markers_symbolizer(rule, sym_node);
|
parse_markers_symbolizer(rule, sym_node);
|
||||||
sym_node.set_processed(true);
|
sym_node.set_processed(true);
|
||||||
break;
|
break;
|
||||||
|
case name2int("GroupSymbolizer"):
|
||||||
|
parse_group_symbolizer(rule, sym_node);
|
||||||
|
sym_node.set_processed(true);
|
||||||
|
break;
|
||||||
case name2int("DebugSymbolizer"):
|
case name2int("DebugSymbolizer"):
|
||||||
parse_debug_symbolizer(rule, sym_node);
|
parse_debug_symbolizer(rule, sym_node);
|
||||||
sym_node.set_processed(true);
|
sym_node.set_processed(true);
|
||||||
|
@ -844,17 +872,6 @@ void map_parser::parse_rule(feature_type_style & style, xml_node const& node)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
style.add_rule(rule);
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (config_error const& ex)
|
|
||||||
{
|
|
||||||
if (!name.empty())
|
|
||||||
{
|
|
||||||
ex.append_context(std::string("in rule '") + name + "'", node);
|
|
||||||
}
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper method
|
// helper method
|
||||||
|
@ -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)
|
void map_parser::parse_debug_symbolizer(rule & rule, xml_node const & sym)
|
||||||
{
|
{
|
||||||
debug_symbolizer symbol;
|
debug_symbolizer symbol;
|
||||||
|
@ -1650,6 +1719,71 @@ bool map_parser::parse_raster_colorizer(raster_colorizer_ptr const& rc,
|
||||||
return found_stops;
|
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)
|
void map_parser::ensure_font_face(std::string const& face_name)
|
||||||
{
|
{
|
||||||
if (! font_manager_.get_face(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 },
|
[](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{ "raster-colorizer", nullptr, nullptr, property_types::target_colorizer},
|
||||||
property_meta_type{ "halo-transform", false, nullptr, property_types::target_transform },
|
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)
|
property_meta_type const& get_meta(mapnik::keys key)
|
||||||
|
|
|
@ -138,7 +138,7 @@ formatting::node_ptr text_symbolizer_properties::format_tree() const
|
||||||
return tree_;
|
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");
|
optional<label_placement_e> placement_ = sym.get_opt_attr<label_placement_e>("placement");
|
||||||
if (placement_) label_placement = *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_;
|
if (allow_overlap_) allow_overlap = *allow_overlap_;
|
||||||
optional<boolean> largest_bbox_only_ = sym.get_opt_attr<boolean>("largest-bbox-only");
|
optional<boolean> largest_bbox_only_ = sym.get_opt_attr<boolean>("largest-bbox-only");
|
||||||
if (largest_bbox_only_) largest_bbox_only = *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");
|
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);
|
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");
|
optional<text_upright_e> upright_ = sym.get_opt_attr<text_upright_e>("upright");
|
||||||
|
|
Loading…
Reference in a new issue