Merge pull request #6 from kshalnev/mapcss_dynamic_selector

[styles] Mapcss dynamic selector
This commit is contained in:
Viktor Govako 2015-09-23 19:09:21 +03:00
commit beeb153267
21 changed files with 978 additions and 370 deletions

View file

@ -8,6 +8,15 @@
#include "std/algorithm.hpp"
#include "std/iterator.hpp"
namespace
{
struct less_scales
{
bool operator() (drule::Key const & l, int r) const { return l.m_scale < r; }
bool operator() (int l, drule::Key const & r) const { return l < r.m_scale; }
bool operator() (drule::Key const & l, drule::Key const & r) const { return l.m_scale < r.m_scale; }
};
} // namespace
/////////////////////////////////////////////////////////////////////////////////////////
// ClassifObject implementation
@ -38,10 +47,11 @@ ClassifObject * ClassifObject::Find(string const & s)
void ClassifObject::AddDrawRule(drule::Key const & k)
{
for (size_t i = 0; i < m_drawRule.size(); ++i)
if (k == m_drawRule[i]) return;
m_drawRule.push_back(k);
auto i = lower_bound(m_drawRule.begin(), m_drawRule.end(), k.m_scale, less_scales());
for (; i != m_drawRule.end() && i->m_scale == k.m_scale; ++i)
if (k == *i)
return; // already exists
m_drawRule.insert(i, k);
}
ClassifObjectPtr ClassifObject::BinaryFind(string const & s) const
@ -61,16 +71,6 @@ void ClassifObject::LoadPolicy::Start(size_t i)
base_type::Start(i);
}
namespace
{
struct less_scales
{
bool operator() (drule::Key const & l, int r) const { return l.m_scale < r; }
bool operator() (int l, drule::Key const & r) const { return l < r.m_scale; }
bool operator() (drule::Key const & l, drule::Key const & r) const { return l.m_scale < r.m_scale; }
};
}
void ClassifObject::LoadPolicy::EndChilds()
{
ClassifObject * p = Current();

View file

@ -1,8 +1,8 @@
#include "indexer/drawing_rules.hpp"
#include "indexer/scales.hpp"
#include "indexer/classificator.hpp"
#include "indexer/drules_include.hpp"
#include "indexer/map_style_reader.hpp"
#include "indexer/scales.hpp"
#include "defines.hpp"
@ -89,6 +89,18 @@ ShieldRuleProto const * BaseRule::GetShield() const
return nullptr;
}
bool BaseRule::TestFeature(FeatureType const & ft, int /* zoom */) const
{
if (nullptr == m_selector)
return true;
return m_selector->Test(ft);
}
void BaseRule::SetSelector(unique_ptr<ISelector> && selector)
{
m_selector = move(selector);
}
RulesHolder::RulesHolder()
: m_bgColors(scales::UPPER_STYLE_SCALE+1, DEFAULT_BG_COLOR)
, m_cityRankTable(GetConstRankCityRankTable())
@ -330,14 +342,36 @@ namespace
RulesHolder & m_holder;
template <class TRule, class TProtoRule>
void AddRule(ClassifObject * p, int scale, rule_type_t type, TProtoRule const & rule)
void AddRule(ClassifObject * p, int scale, rule_type_t type, TProtoRule const & rule,
vector<string> const & apply_if)
{
Key k = m_holder.AddRule(scale, type, new TRule(rule));
unique_ptr<ISelector> selector;
if (!apply_if.empty())
{
selector = ParseSelector(apply_if);
if (selector == nullptr)
{
LOG(LERROR, ("Runtime selector has not been created:", apply_if));
return;
}
}
BaseRule * obj = new TRule(rule);
obj->SetSelector(move(selector));
Key k = m_holder.AddRule(scale, type, obj);
p->SetVisibilityOnScale(true, scale);
k.SetPriority(rule.priority());
p->AddDrawRule(k);
}
static void DrawElementGetApplyIf(DrawElementProto const & de, vector<string> & apply_if)
{
apply_if.clear();
apply_if.reserve(de.apply_if_size());
for (int i = 0; i < de.apply_if_size(); ++i)
apply_if.emplace_back(de.apply_if(i));
}
public:
DoSetIndex(RulesHolder & holder)
: m_holder(holder) {}
@ -349,6 +383,8 @@ namespace
int const i = FindIndex();
if (i != -1)
{
vector<string> apply_if;
ClassifElementProto const & ce = m_cont.cont(i);
for (int j = 0; j < ce.element_size(); ++j)
{
@ -356,26 +392,28 @@ namespace
using namespace proto_rules;
DrawElementGetApplyIf(de, apply_if);
for (int k = 0; k < de.lines_size(); ++k)
AddRule<Line>(p, de.scale(), line, de.lines(k));
AddRule<Line>(p, de.scale(), line, de.lines(k), apply_if);
if (de.has_area())
AddRule<Area>(p, de.scale(), area, de.area());
AddRule<Area>(p, de.scale(), area, de.area(), apply_if);
if (de.has_symbol())
AddRule<Symbol>(p, de.scale(), symbol, de.symbol());
AddRule<Symbol>(p, de.scale(), symbol, de.symbol(), apply_if);
if (de.has_caption())
AddRule<Caption>(p, de.scale(), caption, de.caption());
AddRule<Caption>(p, de.scale(), caption, de.caption(), apply_if);
if (de.has_circle())
AddRule<Circle>(p, de.scale(), circle, de.circle());
AddRule<Circle>(p, de.scale(), circle, de.circle(), apply_if);
if (de.has_path_text())
AddRule<PathText>(p, de.scale(), pathtext, de.path_text());
AddRule<PathText>(p, de.scale(), pathtext, de.path_text(), apply_if);
if (de.has_shield())
AddRule<Shield>(p, de.scale(), shield, de.shield());
AddRule<Shield>(p, de.scale(), shield, de.shield(), apply_if);
}
}

View file

@ -2,6 +2,7 @@
#include "indexer/drawing_rule_def.hpp"
#include "indexer/drules_city_rank_table.hpp"
#include "indexer/drules_selector.hpp"
#include "base/base.hpp"
#include "base/buffer_vector.hpp"
@ -21,6 +22,7 @@ class CaptionDefProto;
class CircleRuleProto;
class ShieldRuleProto;
class ContainerProto;
class FeatureType;
namespace drule
@ -30,6 +32,8 @@ namespace drule
mutable buffer_vector<uint32_t, 4> m_id1;
char m_type; // obsolete for new styles, can be removed
unique_ptr<ISelector> m_selector;
public:
static uint32_t const empty_id = 0xFFFFFFFF;
@ -53,6 +57,13 @@ namespace drule
virtual CaptionDefProto const * GetCaption(int) const;
virtual CircleRuleProto const * GetCircle() const;
virtual ShieldRuleProto const * GetShield() const;
// Test feature by runtime feature style selector
// Returns true if rule is applicable for feature, otherwise it returns false
bool TestFeature(FeatureType const & ft, int zoom) const;
// Set runtime feature style selector
void SetSelector(unique_ptr<ISelector> && selector);
};
class RulesHolder

157
indexer/drules_selector.cpp Normal file
View file

@ -0,0 +1,157 @@
#include "indexer/drules_selector.hpp"
#include "indexer/drules_selector_parser.hpp"
#include "indexer/ftypes_matcher.hpp"
#include "base/assert.hpp"
#include "base/logging.hpp"
namespace drule
{
namespace
{
class CompositeSelector : public ISelector
{
public:
explicit CompositeSelector(size_t capacity)
{
m_selectors.reserve(capacity);
}
void Add(unique_ptr<ISelector> && selector)
{
m_selectors.emplace_back(move(selector));
}
// ISelector overrides:
bool Test(FeatureType const & ft) const override
{
for (auto const & selector : m_selectors)
if (!selector->Test(ft))
return false;
return true;
}
private:
vector<unique_ptr<ISelector>> m_selectors;
};
// Runtime feature style selector implementation
template <typename TType>
class Selector : public ISelector
{
public:
// Signature of function which takes a property from a feature
typedef bool (*TGetFeatureTagValueFn)(FeatureType const &, TType & value);
Selector(TGetFeatureTagValueFn fn, SelectorOperatorType op, TType const & value)
: m_getFeatureValueFn(fn), m_evalFn(nullptr), m_value(value)
{
ASSERT(fn != nullptr, ());
switch (op)
{
case SelectorOperatorUnknown: m_evalFn = nullptr; break;
case SelectorOperatorNotEqual: m_evalFn = &Selector<TType>::NotEqual; break;
case SelectorOperatorLessOrEqual: m_evalFn = &Selector<TType>::LessOrEqual; break;
case SelectorOperatorGreaterOrEqual: m_evalFn = &Selector<TType>::GreaterOrEqual; break;
case SelectorOperatorEqual: m_evalFn = &Selector<TType>::Equal; break;
case SelectorOperatorLess: m_evalFn = &Selector<TType>::Less; break;
case SelectorOperatorGreater: m_evalFn = &Selector<TType>::Greater; break;
case SelectorOperatorIsNotSet: m_evalFn = &Selector<TType>::IsNotSet; break;
case SelectorOperatorIsSet: m_evalFn = &Selector<TType>::IsSet; break;
}
ASSERT(m_evalFn != nullptr, ("Unknown or unexpected selector operator type"));
if (nullptr == m_evalFn)
m_evalFn = &Selector<TType>::Unknown;
}
// ISelector overrides:
bool Test(FeatureType const & ft) const override
{
TType tagValue;
if (!m_getFeatureValueFn(ft, tagValue))
return false;
return (this->*m_evalFn)(tagValue);
}
private:
bool Unknown(TType const &) const { return false; }
bool NotEqual(TType const & tagValue) const { return tagValue != m_value; }
bool LessOrEqual(TType const & tagValue) const { return tagValue <= m_value; }
bool GreaterOrEqual(TType const & tagValue) const { return tagValue >= m_value; }
bool Equal(TType const & tagValue) const { return tagValue == m_value; }
bool Less(TType const & tagValue) const { return tagValue < m_value; }
bool Greater(TType const & tagValue) const { return tagValue > m_value; }
bool IsNotSet(TType const & tagValue) const { return tagValue == TType(); }
bool IsSet(TType const & tagValue) const { return tagValue != TType(); }
typedef bool (Selector<TType>::*TOperationFn)(TType const &) const;
TGetFeatureTagValueFn m_getFeatureValueFn;
TOperationFn m_evalFn;
TType const m_value;
};
// Feature tag value evaluator for tag 'population'
bool GetPopulation(FeatureType const & ft, uint32_t & population)
{
population = ftypes::GetPopulation(ft);
return true;
}
// Add new tag value evaluator here
} // namespace
unique_ptr<ISelector> ParseSelector(string const & str)
{
SelectorExpression e;
if (!ParseSelector(str, e))
{
// bad string format
LOG(LDEBUG, ("Invalid selector format: ", str));
return unique_ptr<ISelector>();
}
// Tag 'population'
if (e.m_tag == "population")
{
int value = 0;
if (!e.m_value.empty() && (!strings::to_int(e.m_value, value) || value < 0))
{
// bad string format
LOG(LDEBUG, ("Invalid selector: ", str));
return unique_ptr<ISelector>();
}
return make_unique<Selector<uint32_t>>(&GetPopulation, e.m_operator, static_cast<uint32_t>(value));
}
// Add new tag here
// unrecognized selector
LOG(LDEBUG, ("Unrecognized selector: ", str));
return unique_ptr<ISelector>();
}
unique_ptr<ISelector> ParseSelector(vector<string> const & strs)
{
unique_ptr<CompositeSelector> cs = make_unique<CompositeSelector>(strs.size());
for (string const & str : strs)
{
unique_ptr<ISelector> s = ParseSelector(str);
if (nullptr == s)
{
LOG(LDEBUG, ("Invalid composite selector: ", str));
return unique_ptr<ISelector>();
}
cs->Add(move(s));
}
return unique_ptr<ISelector>(cs.release());
}
} // namespace drule

View file

@ -0,0 +1,29 @@
#pragma once
#include "indexer/feature.hpp"
#include "std/string.hpp"
#include "std/unique_ptr.hpp"
#include "std/vector.hpp"
namespace drule
{
// Runtime feature style selector absract interface.
class ISelector
{
public:
virtual ~ISelector() = default;
// If ISelector.Test returns true then style is applicable for the feature,
// otherwise, if ISelector.Test returns false, style cannot be applied to the feature.
virtual bool Test(FeatureType const & ft) const = 0;
};
// Factory method which builds ISelector from a string.
unique_ptr<ISelector> ParseSelector(string const & str);
// Factory method which builds composite ISelector from a set of string.
unique_ptr<ISelector> ParseSelector(vector<string> const & strs);
} // namespace drule

View file

@ -0,0 +1,124 @@
#include "indexer/drules_selector_parser.hpp"
#include "base/assert.hpp"
#include "std/algorithm.hpp"
namespace drule
{
namespace
{
bool IsTag(string const & str)
{
// tag consists of a-z or A-Z letters and not empty
for (auto const c : str)
{
if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z'))
return false;
}
return !str.empty();
}
} // namespace
bool ParseSelector(string const & str, SelectorExpression & e)
{
// See http://wiki.openstreetmap.org/wiki/MapCSS/0.2
// Now we support following expressions
// [tag!=value]
// [tag>=value]
// [tag<=value]
// [tag=value]
// [tag>value]
// [tag<value]
// [!tag]
// [tag]
if (str.empty())
return false; // invalid format
// [!tag]
if (str[0] == '!')
{
string tag(str.begin() + 1, str.end());
if (!IsTag(tag))
return false; // invalid format
e.m_operator = SelectorOperatorIsNotSet;
e.m_tag = move(tag);
e.m_value.clear();
return true;
}
// [tag]
if (IsTag(str))
{
e.m_operator = SelectorOperatorIsSet;
e.m_tag = str;
e.m_value.clear();
return true;
}
// Find first entrance of >, < or =
size_t pos = string::npos;
size_t len = 0;
char const c[] = { '>', '<', '=', 0 };
for (size_t i = 0; c[i] != 0; ++i)
{
size_t p = str.find(c[i]);
if (p != string::npos)
{
pos = (pos == string::npos) ? p : min(p, pos);
len = 1;
}
}
// If there is no entrance or no space for tag or value then it is invalid format
if (pos == 0 || len == 0 || pos == str.size()-1)
return false; // invalid format
// Dedicate the operator type, real operator position and length
SelectorOperatorType op = SelectorOperatorUnknown;
if (str[pos] == '>')
{
op = SelectorOperatorGreater;
if (str[pos+1] == '=')
{
++len;
op = SelectorOperatorGreaterOrEqual;
}
}
else if (str[pos] == '<')
{
op = SelectorOperatorLess;
if (str[pos+1] == '=')
{
++len;
op = SelectorOperatorLessOrEqual;
}
}
else
{
ASSERT(str[pos] == '=', ());
op = SelectorOperatorEqual;
if (str[pos-1] == '!')
{
--pos;
++len;
op = SelectorOperatorNotEqual;
}
}
string tag(str.begin(), str.begin() + pos);
if (!IsTag(tag))
return false; // invalid format
e.m_operator = op;
e.m_tag = move(tag);
e.m_value = string(str.begin() + pos + len, str.end());
return true;
}
} // namespace drule

View file

@ -0,0 +1,48 @@
#pragma once
#include "std/string.hpp"
namespace drule
{
enum SelectorOperatorType
{
SelectorOperatorUnknown = 0,
// [tag!=value]
SelectorOperatorNotEqual,
// [tag<=value]
SelectorOperatorLessOrEqual,
// [tag>=value]
SelectorOperatorGreaterOrEqual,
// [tag=value]
SelectorOperatorEqual,
// [tag<value]
SelectorOperatorLess,
// [tag>value]
SelectorOperatorGreater,
// [!tag]
SelectorOperatorIsNotSet,
// [tag]
SelectorOperatorIsSet,
};
struct SelectorExpression
{
SelectorOperatorType m_operator;
string m_tag;
string m_value;
SelectorExpression() : m_operator(SelectorOperatorUnknown) {}
};
bool ParseSelector(string const & str, SelectorExpression & e);
} // namespace drule

View file

@ -3569,6 +3569,7 @@ const int DrawElementProto::kCaptionFieldNumber;
const int DrawElementProto::kCircleFieldNumber;
const int DrawElementProto::kPathTextFieldNumber;
const int DrawElementProto::kShieldFieldNumber;
const int DrawElementProto::kApplyIfFieldNumber;
#endif // !_MSC_VER
DrawElementProto::DrawElementProto()
@ -3624,6 +3625,7 @@ DrawElementProto::DrawElementProto(const DrawElementProto& from)
}
void DrawElementProto::SharedCtor() {
::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
scale_ = 0;
area_ = NULL;
@ -3698,6 +3700,7 @@ void DrawElementProto::Clear() {
}
}
lines_.Clear();
apply_if_.Clear();
::memset(_has_bits_, 0, sizeof(_has_bits_));
mutable_unknown_fields()->clear();
}
@ -3818,6 +3821,20 @@ bool DrawElementProto::MergePartialFromCodedStream(
} else {
goto handle_unusual;
}
if (input->ExpectTag(74)) goto parse_apply_if;
break;
}
// repeated string apply_if = 9;
case 9: {
if (tag == 74) {
parse_apply_if:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->add_apply_if()));
} else {
goto handle_unusual;
}
if (input->ExpectTag(74)) goto parse_apply_if;
if (input->ExpectAtEnd()) goto success;
break;
}
@ -3894,6 +3911,12 @@ void DrawElementProto::SerializeWithCachedSizes(
8, this->shield(), output);
}
// repeated string apply_if = 9;
for (int i = 0; i < this->apply_if_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteString(
9, this->apply_if(i), output);
}
output->WriteRaw(unknown_fields().data(),
unknown_fields().size());
// @@protoc_insertion_point(serialize_end:DrawElementProto)
@ -3961,6 +3984,13 @@ int DrawElementProto::ByteSize() const {
this->lines(i));
}
// repeated string apply_if = 9;
total_size += 1 * this->apply_if_size();
for (int i = 0; i < this->apply_if_size(); i++) {
total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
this->apply_if(i));
}
total_size += unknown_fields().size();
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
@ -3977,6 +4007,7 @@ void DrawElementProto::CheckTypeAndMergeFrom(
void DrawElementProto::MergeFrom(const DrawElementProto& from) {
GOOGLE_CHECK_NE(&from, this);
lines_.MergeFrom(from.lines_);
apply_if_.MergeFrom(from.apply_if_);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_scale()) {
set_scale(from.scale());
@ -4044,6 +4075,7 @@ void DrawElementProto::Swap(DrawElementProto* other) {
std::swap(circle_, other->circle_);
std::swap(path_text_, other->path_text_);
std::swap(shield_, other->shield_);
apply_if_.Swap(&other->apply_if_);
std::swap(_has_bits_[0], other->_has_bits_[0]);
_unknown_fields_.swap(other->_unknown_fields_);
std::swap(_cached_size_, other->_cached_size_);

View file

@ -1555,6 +1555,22 @@ class DrawElementProto : public ::google::protobuf::MessageLite {
inline ::ShieldRuleProto* release_shield();
inline void set_allocated_shield(::ShieldRuleProto* shield);
// repeated string apply_if = 9;
inline int apply_if_size() const;
inline void clear_apply_if();
static const int kApplyIfFieldNumber = 9;
inline const ::std::string& apply_if(int index) const;
inline ::std::string* mutable_apply_if(int index);
inline void set_apply_if(int index, const ::std::string& value);
inline void set_apply_if(int index, const char* value);
inline void set_apply_if(int index, const char* value, size_t size);
inline ::std::string* add_apply_if();
inline void add_apply_if(const ::std::string& value);
inline void add_apply_if(const char* value);
inline void add_apply_if(const char* value, size_t size);
inline const ::google::protobuf::RepeatedPtrField< ::std::string>& apply_if() const;
inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_apply_if();
// @@protoc_insertion_point(class_scope:DrawElementProto)
private:
inline void set_has_scale();
@ -1583,6 +1599,7 @@ class DrawElementProto : public ::google::protobuf::MessageLite {
::CircleRuleProto* circle_;
::PathTextRuleProto* path_text_;
::ShieldRuleProto* shield_;
::google::protobuf::RepeatedPtrField< ::std::string> apply_if_;
::google::protobuf::int32 scale_;
#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
friend void protobuf_AddDesc_drules_5fstruct_2eproto_impl();
@ -3529,6 +3546,60 @@ inline void DrawElementProto::set_allocated_shield(::ShieldRuleProto* shield) {
// @@protoc_insertion_point(field_set_allocated:DrawElementProto.shield)
}
// repeated string apply_if = 9;
inline int DrawElementProto::apply_if_size() const {
return apply_if_.size();
}
inline void DrawElementProto::clear_apply_if() {
apply_if_.Clear();
}
inline const ::std::string& DrawElementProto::apply_if(int index) const {
// @@protoc_insertion_point(field_get:DrawElementProto.apply_if)
return apply_if_.Get(index);
}
inline ::std::string* DrawElementProto::mutable_apply_if(int index) {
// @@protoc_insertion_point(field_mutable:DrawElementProto.apply_if)
return apply_if_.Mutable(index);
}
inline void DrawElementProto::set_apply_if(int index, const ::std::string& value) {
// @@protoc_insertion_point(field_set:DrawElementProto.apply_if)
apply_if_.Mutable(index)->assign(value);
}
inline void DrawElementProto::set_apply_if(int index, const char* value) {
apply_if_.Mutable(index)->assign(value);
// @@protoc_insertion_point(field_set_char:DrawElementProto.apply_if)
}
inline void DrawElementProto::set_apply_if(int index, const char* value, size_t size) {
apply_if_.Mutable(index)->assign(
reinterpret_cast<const char*>(value), size);
// @@protoc_insertion_point(field_set_pointer:DrawElementProto.apply_if)
}
inline ::std::string* DrawElementProto::add_apply_if() {
return apply_if_.Add();
}
inline void DrawElementProto::add_apply_if(const ::std::string& value) {
apply_if_.Add()->assign(value);
// @@protoc_insertion_point(field_add:DrawElementProto.apply_if)
}
inline void DrawElementProto::add_apply_if(const char* value) {
apply_if_.Add()->assign(value);
// @@protoc_insertion_point(field_add_char:DrawElementProto.apply_if)
}
inline void DrawElementProto::add_apply_if(const char* value, size_t size) {
apply_if_.Add()->assign(reinterpret_cast<const char*>(value), size);
// @@protoc_insertion_point(field_add_pointer:DrawElementProto.apply_if)
}
inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
DrawElementProto::apply_if() const {
// @@protoc_insertion_point(field_list:DrawElementProto.apply_if)
return apply_if_;
}
inline ::google::protobuf::RepeatedPtrField< ::std::string>*
DrawElementProto::mutable_apply_if() {
// @@protoc_insertion_point(field_mutable_list:DrawElementProto.apply_if)
return &apply_if_;
}
// -------------------------------------------------------------------
// ClassifElementProto

View file

@ -111,6 +111,7 @@ message DrawElementProto
optional CircleRuleProto circle = 6;
optional PathTextRuleProto path_text = 7;
optional ShieldRuleProto shield = 8;
repeated string apply_if = 9;
}
message ClassifElementProto

View file

@ -19,6 +19,8 @@ SOURCES += \
drawing_rule_def.cpp \
drawing_rules.cpp \
drules_city_rank_table.cpp \
drules_selector.cpp \
drules_selector_parser.cpp \
feature.cpp \
feature_algo.cpp \
feature_covering.cpp \
@ -60,6 +62,8 @@ HEADERS += \
drawing_rules.hpp \
drules_city_rank_table.hpp \
drules_include.hpp \
drules_selector.cpp \
drules_selector_parser.cpp \
feature.hpp \
feature_algo.hpp \
feature_covering.hpp \

View file

@ -0,0 +1,147 @@
#include "testing/testing.hpp"
#include "indexer/drules_selector.hpp"
#include "indexer/drules_selector_parser.hpp"
using namespace drule;
UNIT_TEST(TestDruleSelectorIsSet)
{
SelectorExpression e;
TEST(ParseSelector("name", e), ());
TEST_EQUAL("name", e.m_tag, ());
TEST_EQUAL("", e.m_value, ());
TEST_EQUAL(SelectorOperatorIsSet, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorIsNotSet)
{
SelectorExpression e;
TEST(ParseSelector("!name", e), ());
TEST_EQUAL("name", e.m_tag, ());
TEST_EQUAL("", e.m_value, ());
TEST_EQUAL(SelectorOperatorIsNotSet, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorEqual)
{
SelectorExpression e;
TEST(ParseSelector("population=1000", e), ());
TEST_EQUAL("population", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorEqual, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorNotEqual)
{
SelectorExpression e;
TEST(ParseSelector("population!=1000", e), ());
TEST_EQUAL("population", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorNotEqual, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorLess)
{
SelectorExpression e;
TEST(ParseSelector("population<1000", e), ());
TEST_EQUAL("population", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorLess, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorGreater)
{
SelectorExpression e;
TEST(ParseSelector("population>1000", e), ());
TEST_EQUAL("population", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorGreater, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorLessOrEqual)
{
SelectorExpression e;
TEST(ParseSelector("population<=1000", e), ());
TEST_EQUAL("population", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorLessOrEqual, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorGreaterOrEqual)
{
SelectorExpression e;
TEST(ParseSelector("population>=1000", e), ());
TEST_EQUAL("population", e.m_tag, ());
TEST_EQUAL("1000", e.m_value, ());
TEST_EQUAL(SelectorOperatorGreaterOrEqual, e.m_operator, ());
}
UNIT_TEST(TestDruleSelectorInvalid)
{
char const * const badFormats[] =
{
"",
"=badformat",
"!=badformat",
">badformat",
"<badformat",
">=badformat",
"<=badformat",
"bad$name",
"!bad$name",
"bad$name=1000",
};
size_t const n = sizeof(badFormats) / sizeof(badFormats[0]);
for (size_t i = 0; i < n; ++i)
{
SelectorExpression e;
TEST_EQUAL(false, ParseSelector(badFormats[i], e), ("string is", badFormats[i]));
}
}
UNIT_TEST(TestDruleParseSelectorValid1)
{
auto selector = ParseSelector("population<1000");
TEST(selector != nullptr, ());
}
UNIT_TEST(TestDruleParseSelectorValid2)
{
auto selector = ParseSelector(vector<string>({"population>1000"}));
TEST(selector != nullptr, ());
}
UNIT_TEST(TestDruleParseSelectorValid3)
{
auto selector = ParseSelector(vector<string>({"population>=1000","population<=1000000"}));
TEST(selector != nullptr, ());
}
UNIT_TEST(TestDruleParseSelectorInvalid1)
{
auto selector = ParseSelector("");
TEST(selector == nullptr, ());
}
UNIT_TEST(TestDruleParseSelectorInvalid2)
{
auto selector = ParseSelector(vector<string>({""}));
TEST(selector == nullptr, ());
}
UNIT_TEST(TestDruleParseSelectorInvalid3)
{
auto selector = ParseSelector(vector<string>({"population>=1000","population<=1000000", ""}));
TEST(selector == nullptr, ());
}

View file

@ -28,6 +28,7 @@ SOURCES += \
cell_id_test.cpp \
checker_test.cpp \
city_rank_table_test.cpp \
drules_selector_parser_test.cpp \
features_offsets_table_test.cpp \
geometry_coding_test.cpp \
geometry_serialization_test.cpp \

View file

@ -30,6 +30,16 @@ namespace
return (r1.m_depth < r2.m_depth);
}
};
void FilterRulesByRuntimeSelector(FeatureType const & ft, int zoom, drule::KeysT & keys)
{
keys.erase_if([&ft, zoom](drule::Key const & key)->bool
{
drule::BaseRule const * const rule = drule::rules().Find(key);
ASSERT(rule != nullptr, ());
return !rule->TestFeature(ft, zoom);
});
}
}
namespace di
@ -64,6 +74,8 @@ namespace di
drule::KeysT keys;
pair<int, bool> type = feature::GetDrawRule(f, zoom, keys);
FilterRulesByRuntimeSelector(f, zoom, keys);
// don't try to do anything to invisible feature
if (keys.empty())
return;

View file

@ -19,7 +19,7 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='drules_struct.proto',
package='',
serialized_pb=_b('\n\x13\x64rules_struct.proto\"*\n\x0c\x44\x61shDotProto\x12\n\n\x02\x64\x64\x18\x01 \x03(\x01\x12\x0e\n\x06offset\x18\x02 \x01(\x01\":\n\x0cPathSymProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04step\x18\x02 \x02(\x01\x12\x0e\n\x06offset\x18\x03 \x01(\x01\"\xaf\x01\n\rLineRuleProto\x12\r\n\x05width\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1e\n\x07\x64\x61shdot\x18\x03 \x01(\x0b\x32\r.DashDotProto\x12\x10\n\x08priority\x18\x04 \x02(\x05\x12\x1e\n\x07pathsym\x18\x05 \x01(\x0b\x32\r.PathSymProto\x12\x17\n\x04join\x18\x06 \x01(\x0e\x32\t.LineJoin\x12\x15\n\x03\x63\x61p\x18\x07 \x01(\x0e\x32\x08.LineCap\"\x9c\x01\n\x0cLineDefProto\x12\r\n\x05width\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1e\n\x07\x64\x61shdot\x18\x03 \x01(\x0b\x32\r.DashDotProto\x12\x1e\n\x07pathsym\x18\x04 \x01(\x0b\x32\r.PathSymProto\x12\x17\n\x04join\x18\x06 \x01(\x0e\x32\t.LineJoin\x12\x15\n\x03\x63\x61p\x18\x07 \x01(\x0e\x32\x08.LineCap\"O\n\rAreaRuleProto\x12\r\n\x05\x63olor\x18\x01 \x02(\r\x12\x1d\n\x06\x62order\x18\x02 \x01(\x0b\x32\r.LineDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"I\n\x0fSymbolRuleProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x16\n\x0e\x61pply_for_type\x18\x02 \x01(\x05\x12\x10\n\x08priority\x18\x03 \x02(\x05\"j\n\x0f\x43\x61ptionDefProto\x12\x0e\n\x06height\x18\x01 \x02(\x05\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x14\n\x0cstroke_color\x18\x03 \x01(\r\x12\x10\n\x08offset_x\x18\x04 \x01(\x05\x12\x10\n\x08offset_y\x18\x05 \x01(\x05\"l\n\x10\x43\x61ptionRuleProto\x12!\n\x07primary\x18\x01 \x02(\x0b\x32\x10.CaptionDefProto\x12#\n\tsecondary\x18\x02 \x01(\x0b\x32\x10.CaptionDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"a\n\x0f\x43ircleRuleProto\x12\x0e\n\x06radius\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1d\n\x06\x62order\x18\x03 \x01(\x0b\x32\r.LineDefProto\x12\x10\n\x08priority\x18\x04 \x02(\x05\"m\n\x11PathTextRuleProto\x12!\n\x07primary\x18\x01 \x02(\x0b\x32\x10.CaptionDefProto\x12#\n\tsecondary\x18\x02 \x01(\x0b\x32\x10.CaptionDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"X\n\x0fShieldRuleProto\x12\x0e\n\x06height\x18\x01 \x02(\x05\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x14\n\x0cstroke_color\x18\x03 \x01(\r\x12\x10\n\x08priority\x18\x04 \x02(\x05\"\x8f\x02\n\x10\x44rawElementProto\x12\r\n\x05scale\x18\x01 \x02(\x05\x12\x1d\n\x05lines\x18\x02 \x03(\x0b\x32\x0e.LineRuleProto\x12\x1c\n\x04\x61rea\x18\x03 \x01(\x0b\x32\x0e.AreaRuleProto\x12 \n\x06symbol\x18\x04 \x01(\x0b\x32\x10.SymbolRuleProto\x12\"\n\x07\x63\x61ption\x18\x05 \x01(\x0b\x32\x11.CaptionRuleProto\x12 \n\x06\x63ircle\x18\x06 \x01(\x0b\x32\x10.CircleRuleProto\x12%\n\tpath_text\x18\x07 \x01(\x0b\x32\x12.PathTextRuleProto\x12 \n\x06shield\x18\x08 \x01(\x0b\x32\x10.ShieldRuleProto\"G\n\x13\x43lassifElementProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\"\n\x07\x65lement\x18\x02 \x03(\x0b\x32\x11.DrawElementProto\"4\n\x0e\x43ontainerProto\x12\"\n\x04\x63ont\x18\x01 \x03(\x0b\x32\x14.ClassifElementProto*4\n\x08LineJoin\x12\r\n\tROUNDJOIN\x10\x00\x12\r\n\tBEVELJOIN\x10\x01\x12\n\n\x06NOJOIN\x10\x02*3\n\x07LineCap\x12\x0c\n\x08ROUNDCAP\x10\x00\x12\x0b\n\x07\x42UTTCAP\x10\x01\x12\r\n\tSQUARECAP\x10\x02\x42\x02H\x03')
serialized_pb=_b('\n\x13\x64rules_struct.proto\"*\n\x0c\x44\x61shDotProto\x12\n\n\x02\x64\x64\x18\x01 \x03(\x01\x12\x0e\n\x06offset\x18\x02 \x01(\x01\":\n\x0cPathSymProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04step\x18\x02 \x02(\x01\x12\x0e\n\x06offset\x18\x03 \x01(\x01\"\xaf\x01\n\rLineRuleProto\x12\r\n\x05width\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1e\n\x07\x64\x61shdot\x18\x03 \x01(\x0b\x32\r.DashDotProto\x12\x10\n\x08priority\x18\x04 \x02(\x05\x12\x1e\n\x07pathsym\x18\x05 \x01(\x0b\x32\r.PathSymProto\x12\x17\n\x04join\x18\x06 \x01(\x0e\x32\t.LineJoin\x12\x15\n\x03\x63\x61p\x18\x07 \x01(\x0e\x32\x08.LineCap\"\x9c\x01\n\x0cLineDefProto\x12\r\n\x05width\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1e\n\x07\x64\x61shdot\x18\x03 \x01(\x0b\x32\r.DashDotProto\x12\x1e\n\x07pathsym\x18\x04 \x01(\x0b\x32\r.PathSymProto\x12\x17\n\x04join\x18\x06 \x01(\x0e\x32\t.LineJoin\x12\x15\n\x03\x63\x61p\x18\x07 \x01(\x0e\x32\x08.LineCap\"O\n\rAreaRuleProto\x12\r\n\x05\x63olor\x18\x01 \x02(\r\x12\x1d\n\x06\x62order\x18\x02 \x01(\x0b\x32\r.LineDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"I\n\x0fSymbolRuleProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x16\n\x0e\x61pply_for_type\x18\x02 \x01(\x05\x12\x10\n\x08priority\x18\x03 \x02(\x05\"j\n\x0f\x43\x61ptionDefProto\x12\x0e\n\x06height\x18\x01 \x02(\x05\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x14\n\x0cstroke_color\x18\x03 \x01(\r\x12\x10\n\x08offset_x\x18\x04 \x01(\x05\x12\x10\n\x08offset_y\x18\x05 \x01(\x05\"l\n\x10\x43\x61ptionRuleProto\x12!\n\x07primary\x18\x01 \x02(\x0b\x32\x10.CaptionDefProto\x12#\n\tsecondary\x18\x02 \x01(\x0b\x32\x10.CaptionDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"a\n\x0f\x43ircleRuleProto\x12\x0e\n\x06radius\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1d\n\x06\x62order\x18\x03 \x01(\x0b\x32\r.LineDefProto\x12\x10\n\x08priority\x18\x04 \x02(\x05\"m\n\x11PathTextRuleProto\x12!\n\x07primary\x18\x01 \x02(\x0b\x32\x10.CaptionDefProto\x12#\n\tsecondary\x18\x02 \x01(\x0b\x32\x10.CaptionDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"X\n\x0fShieldRuleProto\x12\x0e\n\x06height\x18\x01 \x02(\x05\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x14\n\x0cstroke_color\x18\x03 \x01(\r\x12\x10\n\x08priority\x18\x04 \x02(\x05\"\xa1\x02\n\x10\x44rawElementProto\x12\r\n\x05scale\x18\x01 \x02(\x05\x12\x1d\n\x05lines\x18\x02 \x03(\x0b\x32\x0e.LineRuleProto\x12\x1c\n\x04\x61rea\x18\x03 \x01(\x0b\x32\x0e.AreaRuleProto\x12 \n\x06symbol\x18\x04 \x01(\x0b\x32\x10.SymbolRuleProto\x12\"\n\x07\x63\x61ption\x18\x05 \x01(\x0b\x32\x11.CaptionRuleProto\x12 \n\x06\x63ircle\x18\x06 \x01(\x0b\x32\x10.CircleRuleProto\x12%\n\tpath_text\x18\x07 \x01(\x0b\x32\x12.PathTextRuleProto\x12 \n\x06shield\x18\x08 \x01(\x0b\x32\x10.ShieldRuleProto\x12\x10\n\x08\x61pply_if\x18\t \x03(\t\"G\n\x13\x43lassifElementProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\"\n\x07\x65lement\x18\x02 \x03(\x0b\x32\x11.DrawElementProto\"4\n\x0e\x43ontainerProto\x12\"\n\x04\x63ont\x18\x01 \x03(\x0b\x32\x14.ClassifElementProto*4\n\x08LineJoin\x12\r\n\tROUNDJOIN\x10\x00\x12\r\n\tBEVELJOIN\x10\x01\x12\n\n\x06NOJOIN\x10\x02*3\n\x07LineCap\x12\x0c\n\x08ROUNDCAP\x10\x00\x12\x0b\n\x07\x42UTTCAP\x10\x01\x12\r\n\tSQUARECAP\x10\x02\x42\x02H\x03')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
@ -44,8 +44,8 @@ _LINEJOIN = _descriptor.EnumDescriptor(
],
containing_type=None,
options=None,
serialized_start=1539,
serialized_end=1591,
serialized_start=1557,
serialized_end=1609,
)
_sym_db.RegisterEnumDescriptor(_LINEJOIN)
@ -71,8 +71,8 @@ _LINECAP = _descriptor.EnumDescriptor(
],
containing_type=None,
options=None,
serialized_start=1593,
serialized_end=1644,
serialized_start=1611,
serialized_end=1662,
)
_sym_db.RegisterEnumDescriptor(_LINECAP)
@ -703,6 +703,13 @@ _DRAWELEMENTPROTO = _descriptor.Descriptor(
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='apply_if', full_name='DrawElementProto.apply_if', index=8,
number=9, type=9, cpp_type=9, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
@ -715,7 +722,7 @@ _DRAWELEMENTPROTO = _descriptor.Descriptor(
oneofs=[
],
serialized_start=1139,
serialized_end=1410,
serialized_end=1428,
)
@ -751,8 +758,8 @@ _CLASSIFELEMENTPROTO = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=1412,
serialized_end=1483,
serialized_start=1430,
serialized_end=1501,
)
@ -781,8 +788,8 @@ _CONTAINERPROTO = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=1485,
serialized_end=1537,
serialized_start=1503,
serialized_end=1555,
)
_LINERULEPROTO.fields_by_name['dashdot'].message_type = _DASHDOTPROTO

View file

@ -1,36 +1,48 @@
from drules_struct_pb2 import *
from timer import *
from mapcss import MapCSS
from optparse import OptionParser
import os
import csv
import sys
import json
import mapcss.webcolors
whatever_to_hex = mapcss.webcolors.webcolors.whatever_to_hex
whatever_to_cairo = mapcss.webcolors.webcolors.whatever_to_cairo
WIDTH_SCALE = 1.0
def komap_mapswithme(options, style, filename):
if options.outfile == "-":
print "Please specify base output path."
exit()
else:
ddir = os.path.dirname(options.outfile)
types_file = open(os.path.join(ddir, 'types.txt'), "w")
drules_bin = open(os.path.join(options.outfile + '.bin'), "wb")
drules_txt = open(os.path.join(options.outfile + '.txt'), "wb")
def mwm_encode_color(st, prefix='', default='black'):
if prefix:
prefix += "-"
opacity = hex(255 - int(255 * float(st.get(prefix + "opacity", 1))))
color = whatever_to_hex(st.get(prefix + 'color', default))
color = color[1] + color[1] + color[3] + color[3] + color[5] + color[5]
return int(opacity + color, 16)
def mwm_encode_image(st, prefix='icon', bgprefix='symbol'):
if prefix:
prefix += "-"
if bgprefix:
bgprefix += "-"
if prefix + "image" not in st:
return False
# strip last ".svg"
handle = st.get(prefix + "image")[:-4]
return handle, handle
def komap_mapswithme(options):
ddir = os.path.dirname(options.outfile)
drules = ContainerProto()
classificator = {}
class_order = []
class_tree = {}
visibility = {}
textures = {}
# Build classificator tree from mapcss-mapping.csv file
types_file = open(os.path.join(ddir, 'types.txt'), "w")
for row in csv.reader(open(os.path.join(ddir, 'mapcss-mapping.csv')), delimiter=';'):
cl = row[0].replace("|", "-")
pairs = [i.strip(']').split("=") for i in row[1].split(',')[0].split('[')]
kv = {}
for i in pairs:
@ -42,9 +54,9 @@ def komap_mapswithme(options, style, filename):
kv[i[0].strip('?')] = "yes"
else:
kv[i[0]] = i[1]
classificator[row[0].replace("|", "-")] = kv
classificator[cl] = kv
if row[2] != "x":
class_order.append(row[0].replace("|", "-"))
class_order.append(cl)
print >> types_file, row[0]
else:
# compatibility mode
@ -52,169 +64,130 @@ def komap_mapswithme(options, style, filename):
print >> types_file, row[6]
else:
print >> types_file, "mapswithme"
class_tree[row[0].replace("|", "-")] = row[0]
class_tree[cl] = row[0]
class_order.sort()
types_file.close()
def mwm_encode_color(st, prefix='', default='black'):
if prefix:
prefix += "-"
opacity = hex(255 - int(255 * float(st.get(prefix + "opacity", 1))))
color = whatever_to_hex(st.get(prefix + 'color', default))
color = color[1] + color[1] + color[3] + color[3] + color[5] + color[5]
return int(opacity + color, 16)
# Get all mapcss tags which are used in mapcss-mapping.csv
mapcss_mapping_tags = set()
for v in classificator.values():
for t in v.keys():
mapcss_mapping_tags.add(t)
def mwm_encode_image(st, prefix='icon', bgprefix='symbol'):
if prefix:
prefix += "-"
if bgprefix:
bgprefix += "-"
if prefix + "image" not in st:
return False
# strip last ".svg"
handle = st.get(prefix + "image")[:-4]
return handle, handle
# Parse style mapcss
style = MapCSS(options.minzoom, options.maxzoom + 1)
style.parse(filename = options.filename, mapcss_tags = mapcss_mapping_tags)
# Build optimization tree - class/type -> StyleChoosers
for cl in class_order:
clname = cl if cl.find('-') == -1 else cl[:cl.find('-')]
cltags = classificator[cl]
style.build_choosers_tree(clname, "line", cltags)
style.build_choosers_tree(clname, "area", cltags)
style.build_choosers_tree(clname, "node", cltags)
style.restore_choosers_order("line")
style.restore_choosers_order("area")
style.restore_choosers_order("node")
visibility = {}
bgpos = 0
dr_linecaps = {'none': BUTTCAP, 'butt': BUTTCAP, 'round': ROUNDCAP}
dr_linejoins = {'none': NOJOIN, 'bevel': BEVELJOIN, 'round': ROUNDJOIN}
# atbuild = AccumulativeTimer()
# atzstyles = AccumulativeTimer()
# atdrcont = AccumulativeTimer()
# atline = AccumulativeTimer()
# atarea = AccumulativeTimer()
# atnode = AccumulativeTimer()
# Build drules tree
# atbuild.Start()
drules = ContainerProto()
for cl in class_order:
clname = cl if cl.find('-') == -1 else cl[:cl.find('-')]
# clname = cl
style.build_choosers_tree(clname, "line", classificator[cl])
style.build_choosers_tree(clname, "area", classificator[cl])
style.build_choosers_tree(clname, "node", classificator[cl])
style.restore_choosers_order("line");
style.restore_choosers_order("area");
style.restore_choosers_order("node");
cltags = classificator[cl]
cltags["name"] = "name"
cltags["addr:housenumber"] = "addr:housenumber"
cltags["ref"] = "ref"
cltags["int_name"] = "int_name"
cltags["addr:flats"] = "addr:flats"
# atbuild.Stop()
dr_cont = ClassifElementProto()
dr_cont.name = cl
for cl in class_order:
visstring = ["0"] * (options.maxzoom - options.minzoom + 1)
clname = cl if cl.find('-') == -1 else cl[:cl.find('-')]
# clname = cl
txclass = classificator[cl]
txclass["name"] = "name"
txclass["addr:housenumber"] = "addr:housenumber"
txclass["ref"] = "ref"
txclass["int_name"] = "int_name"
txclass["addr:flats"] = "addr:flats"
for zoom in xrange(options.minzoom, options.maxzoom + 1):
prev_area_len = -1
prev_node_len = -1
prev_line_len = -1
check_area = True
check_node = True
check_line = True
runtime_conditions_arr = []
# atzstyles.Start()
# Get runtime conditions which are used for class 'cl' on zoom 'zoom'
if "area" not in cltags:
runtime_conditions_arr.extend( style.get_runtime_rules(clname, "line", cltags, zoom) )
runtime_conditions_arr.extend( style.get_runtime_rules(clname, "area", cltags, zoom) )
if "area" not in cltags:
runtime_conditions_arr.extend( style.get_runtime_rules(clname, "node", cltags, zoom) )
zstyles_arr = [None] * (options.maxzoom - options.minzoom + 1)
has_icons_for_areas_arr = [False] * (options.maxzoom - options.minzoom + 1)
# If there is no any runtime conditions, do not filter style by runtime conditions
if len(runtime_conditions_arr) == 0:
runtime_conditions_arr.append(None)
for zoom in xrange(options.maxzoom, options.minzoom - 1, -1):
has_icons_for_areas = False
zstyle = {}
for runtime_conditions in runtime_conditions_arr:
if check_line:
if "area" not in txclass:
# atline.Start()
linestyle = style.get_style_dict(clname, "line", txclass, zoom, olddict=zstyle, cache=False)
if prev_line_len == -1:
prev_line_len = len(linestyle)
if len(linestyle) == 0:
if prev_line_len != 0:
check_line = False
has_icons_for_areas = False
zstyle = {}
# Get style for class 'cl' on zoom 'zoom' with corresponding runtime conditions
if "area" not in cltags:
linestyle = style.get_style_dict(clname, "line", cltags, zoom, olddict=zstyle, filter_by_runtime_conditions=runtime_conditions)
zstyle = linestyle
# atline.Stop()
if check_area:
# atarea.Start()
areastyle = style.get_style_dict(clname, "area", txclass, zoom, olddict=zstyle, cache=False)
areastyle = style.get_style_dict(clname, "area", cltags, zoom, olddict=zstyle, filter_by_runtime_conditions=runtime_conditions)
for st in areastyle.values():
if "icon-image" in st or 'symbol-shape' in st or 'symbol-image' in st:
has_icons_for_areas = True
break
if prev_area_len == -1:
prev_area_len = len(areastyle)
if len(areastyle) == 0:
if prev_area_len != 0:
check_area = False
zstyle = areastyle
# atarea.Stop()
if check_node:
if "area" not in txclass:
# atnode.Start()
nodestyle = style.get_style_dict(clname, "node", txclass, zoom, olddict=zstyle, cache=False)
if prev_node_len == -1:
prev_node_len = len(nodestyle)
if len(nodestyle) == 0:
if prev_node_len != 0:
check_node = False
if "area" not in cltags:
nodestyle = style.get_style_dict(clname, "node", cltags, zoom, olddict=zstyle, filter_by_runtime_conditions=runtime_conditions)
zstyle = nodestyle
# atnode.Stop()
if not check_line and not check_area and not check_node:
break
zstyle = zstyle.values()
zstyle = zstyle.values()
if len(zstyle) == 0:
continue
zstyles_arr[zoom - options.minzoom] = zstyle
has_icons_for_areas_arr[zoom - options.minzoom]= has_icons_for_areas
has_lines = False
has_icons = False
has_fills = False
for st in zstyle:
st = dict([(k, v) for k, v in st.iteritems() if str(v).strip(" 0.")])
if 'width' in st or 'pattern-image' in st:
has_lines = True
if 'icon-image' in st or 'symbol-shape' in st or 'symbol-image' in st:
has_icons = True
if 'fill-color' in st:
has_fills = True
# atzstyles.Stop()
has_text = None
txfmt = []
for st in zstyle:
if st.get('text') and not st.get('text') in txfmt:
txfmt.append(st.get('text'))
if has_text is None:
has_text = []
has_text.append(st)
# atdrcont.Start()
if (not has_lines) and (not has_text) and (not has_fills) and (not has_icons):
continue
dr_cont = ClassifElementProto()
dr_cont.name = cl
for zoom in xrange(options.minzoom, options.maxzoom + 1):
zstyle = zstyles_arr[zoom - options.minzoom]
if zstyle is None or len(zstyle) == 0:
continue
has_icons_for_areas = has_icons_for_areas_arr[zoom - options.minzoom]
has_lines = False
has_icons = False
has_fills = False
for st in zstyle:
st = dict([(k, v) for k, v in st.iteritems() if str(v).strip(" 0.")])
if 'width' in st or 'pattern-image' in st:
has_lines = True
if 'icon-image' in st or 'symbol-shape' in st or 'symbol-image' in st:
has_icons = True
if 'fill-color' in st:
has_fills = True
has_text = None
txfmt = []
for st in zstyle:
if st.get('text') and not st.get('text') in txfmt:
txfmt.append(st.get('text'))
if has_text is None:
has_text = []
has_text.append(st)
if has_lines or has_text or has_fills or has_icons:
visstring[zoom] = "1"
dr_element = DrawElementProto()
dr_element.scale = zoom
if runtime_conditions:
for rc in runtime_conditions:
dr_element.apply_if.append(str(rc))
for st in zstyle:
if st.get('-x-kot-layer') == 'top':
st['z-index'] = float(st.get('z-index', 0)) + 15001.
@ -266,7 +239,6 @@ def komap_mapswithme(options, style, filename):
dr_line.pathsym.offset = st.get('pattern-offset', 0)
dr_line.priority = int(st.get('z-index', 0)) + 1000
dr_element.lines.extend([dr_line])
textures[icon[0]] = icon[1]
if st.get('shield-font-size'):
dr_element.shield.height = int(st.get('shield-font-size', 10))
dr_element.shield.color = mwm_encode_color(st, "shield-text")
@ -281,7 +253,6 @@ def komap_mapswithme(options, style, filename):
icon = mwm_encode_image(st)
dr_element.symbol.name = icon[0]
dr_element.symbol.priority = min(19100, (16000 + int(st.get('z-index', 0))))
textures[icon[0]] = icon[1]
has_icons = False
if st.get('symbol-shape'):
dr_element.circle.radius = float(st.get('symbol-size'))
@ -337,15 +308,18 @@ def komap_mapswithme(options, style, filename):
if dr_cont.element:
drules.cont.extend([dr_cont])
# atdrcont.Stop()
visibility["world|" + class_tree[cl] + "|"] = "".join(visstring)
# atwrite = AccumulativeTimer()
# atwrite.Start()
# Write drules_proto.bin and drules_proto.txt files
drules_bin = open(os.path.join(options.outfile + '.bin'), "wb")
drules_txt = open(os.path.join(options.outfile + '.txt'), "wb")
drules_bin.write(drules.SerializeToString())
drules_txt.write(unicode(drules))
drules_bin.close()
drules_txt.close()
# Write classificator.txt and visibility.txt files
visnodes = set()
for k, v in visibility.iteritems():
@ -373,7 +347,6 @@ def komap_mapswithme(options, style, filename):
for i in range(len(oldoffset) / 4, len(offset) / 4, -1):
print >> visibility_file, " " * i + "{}"
print >> classificator_file, " " * i + "{}"
oldoffset = offset
end = "-"
if k in visnodes:
@ -384,58 +357,31 @@ def komap_mapswithme(options, style, filename):
print >> visibility_file, " " * i + "{}"
print >> classificator_file, " " * i + "{}"
# atwrite.Stop()
# print "build, sec: %s" % (atbuild.ElapsedSec())
# print "zstyle %s times, sec: %s" % (atzstyles.Count(), atzstyles.ElapsedSec())
# print "drcont %s times, sec: %s" % (atdrcont.Count(), atdrcont.ElapsedSec())
# print "line %s times, sec: %s" % (atline.Count(), atline.ElapsedSec())
# print "area %s times, sec: %s" % (atarea.Count(), atarea.ElapsedSec())
# print "node %s times, sec: %s" % (atnode.Count(), atnode.ElapsedSec())
# print "writing files, sec: %s" % (atwrite.ElapsedSec())
visibility_file.close()
classificator_file.close()
# Main
parser = OptionParser()
parser.add_option("-s", "--stylesheet", dest="filename",
help="read MapCSS stylesheet from FILE", metavar="FILE")
parser.add_option("-f", "--minzoom", dest="minzoom", default=0, type="int",
help="minimal available zoom level", metavar="ZOOM")
parser.add_option("-t", "--maxzoom", dest="maxzoom", default=19, type="int",
help="maximal available zoom level", metavar="ZOOM")
parser.add_option("-l", "--locale", dest="locale",
help="language that should be used for labels (ru, en, be, uk..)", metavar="LANG")
parser.add_option("-o", "--output-file", dest="outfile", default="-",
help="output filename (defaults to stdout)", metavar="FILE")
parser.add_option("-p", "--osm2pgsql-style", dest="osm2pgsqlstyle", default="-",
help="osm2pgsql stylesheet filename", metavar="FILE")
parser.add_option("-b", "--background-only", dest="bgonly", action="store_true", default=False,
help="Skip rendering of icons and labels", metavar="BOOL")
parser.add_option("-T", "--text-scale", dest="textscale", default=1, type="float",
help="text size scale", metavar="SCALE")
parser.add_option("-c", "--config", dest="conffile", default="komap.conf",
help="config file name", metavar="FILE")
(options, args) = parser.parse_args()
if (options.filename is None):
parser.error("MapCSS stylesheet filename is required")
try:
# atparse = AccumulativeTimer()
# atbuild = AccumulativeTimer()
parser = OptionParser()
parser.add_option("-s", "--stylesheet", dest="filename",
help="read MapCSS stylesheet from FILE", metavar="FILE")
parser.add_option("-f", "--minzoom", dest="minzoom", default=0, type="int",
help="minimal available zoom level", metavar="ZOOM")
parser.add_option("-t", "--maxzoom", dest="maxzoom", default=19, type="int",
help="maximal available zoom level", metavar="ZOOM")
parser.add_option("-o", "--output-file", dest="outfile", default="-",
help="output filename (defaults to stdout)", metavar="FILE")
# atparse.Start()
style = MapCSS(options.minzoom, options.maxzoom + 1) # zoom levels
style.parse(filename = options.filename)
# atparse.Stop()
(options, args) = parser.parse_args()
# atbuild.Start()
komap_mapswithme(options, style, options.filename)
# atbuild.Stop()
if (options.filename is None):
parser.error("MapCSS stylesheet filename is required")
# print "mapcss parse, sec: %s" % (atparse.ElapsedSec())
# print "build, sec: %s" % (atbuild.ElapsedSec())
if options.outfile == "-":
parser.error("Please specify base output path.")
komap_mapswithme(options)
exit(0)

View file

@ -17,96 +17,19 @@
import re
# Fast conditions
class EqConditionDD:
def __init__(self, params):
self.value = params[1]
def extract_tags(self):
return set(["*"])
def test(self, tags):
return self.value
class EqCondition:
def __init__(self, params):
self.tag = params[0]
self.value = params[1]
def extract_tags(self):
return set([self.tag])
def test(self, tags):
if self.tag in tags:
return tags[self.tag] == self.value
else:
return False
class NotEqCondition:
def __init__(self, params):
self.tag = params[0]
self.value = params[1]
def extract_tags(self):
return set([self.tag])
def test(self, tags):
if self.tag in tags:
return tags[self.tag] != self.value
else:
return False
class SetCondition:
def __init__(self, params):
self.tag = params[0]
def extract_tags(self):
return set([self.tag])
def test(self, tags):
if self.tag in tags:
return tags[self.tag] != ''
return False
class UnsetCondition:
def __init__(self, params):
self.tag = params[0]
def extract_tags(self):
return set([self.tag])
def test(self, tags):
if self.tag in tags:
return tags[self.tag] == ''
return True
class TrueCondition:
def __init__(self, params):
self.tag = params[0]
def extract_tags(self):
return set([self.tag])
def test(self, tags):
if self.tag in tags:
return tags[self.tag] == 'yes'
return False
class UntrueCondition:
def __init__(self, params):
self.tag = params[0]
def extract_tags(self):
return set([self.tag])
def test(self, tags):
if self.tag in tags:
return tags[self.tag] == 'no'
return False
# Slow condition
class Condition:
def __init__(self, typez, params):
self.type = typez # eq, regex, lt, gt etc.
if type(params) == type(str()):
params = (params,)
self.params = params # e.g. ('highway','primary')
self.params = params # e.g. ('highway','primary')
if typez == "regex":
self.regex = re.compile(self.params[0], re.I)
self.compiled_regex = ""
def extract_tags(self):
def extract_tag(self):
if self.params[0][:2] == "::" or self.type == "regex":
return set(["*"]) # unknown
return set([self.params[0]])
return "*" # unknown
return self.params[0]
def test(self, tags):
"""
@ -136,7 +59,6 @@ class Condition:
if params[0] in tags:
return tags[params[0]] == ''
return True
if t == '<':
return (Number(tags[params[0]]) < Number(params[1]))
if t == '<=':
@ -150,6 +72,32 @@ class Condition:
return False
def __repr__(self):
t = self.type
params = self.params
if t == 'eq' and params[0][:2] == "::":
return "::%s" % (params[1])
if t == 'eq':
return "%s=%s" % (params[0], params[1])
if t == 'ne':
return "%s=%s" % (params[0], params[1])
if t == 'regex':
return "%s=~/%s/" % (params[0], params[1]);
if t == 'true':
return "%s?" % (params[0])
if t == 'untrue':
return "!%s?" % (params[0])
if t == 'set':
return "%s" % (params[0])
if t == 'unset':
return "!%s" % (params[0])
if t == '<':
return "%s<%s" % (params[0], params[1])
if t == '<=':
return "%s<=%s" % (params[0], params[1])
if t == '>':
return "%s>%s" % (params[0], params[1])
if t == '>=':
return "%s>=%s" % (params[0], params[1])
return "%s %s " % (self.type, repr(self.params))
def __eq__(self, a):
@ -164,23 +112,3 @@ def Number(tt):
except ValueError:
return 0
# Some conditions we can optimize by using "python polymorthism"
def OptimizeCondition(condition):
if (condition.type == "eq"):
if (condition.params[0][:2] == "::"):
return EqConditionDD(condition.params)
else:
return EqCondition(condition.params)
elif (condition.type == "ne"):
return NotEqCondition(condition.params)
elif (condition.type == "set"):
return SetCondition(condition.params)
elif (condition.type == "unset"):
return UnsetCondition(condition.params)
elif (condition.type == "true"):
return TrueCondition(condition.params)
elif (condition.type == "untrue"):
return UntrueCondition(condition.params)
else:
return condition

View file

@ -25,6 +25,7 @@ type_matches = {
class Rule():
def __init__(self, s=''):
self.runtime_conditions = []
self.conditions = []
# self.isAnd = True
self.minZoom = 0
@ -34,7 +35,7 @@ class Rule():
self.subject = s # "", "way", "node" or "relation"
def __repr__(self):
return "%s|z%s-%s %s" % (self.subject, self.minZoom, self.maxZoom, self.conditions)
return "%s|z%s-%s %s %s" % (self.subject, self.minZoom, self.maxZoom, self.conditions, self.runtime_conditions)
def test(self, obj, tags, zoom):
if (zoom < self.minZoom) or (zoom > self.maxZoom):
@ -58,8 +59,9 @@ class Rule():
def extract_tags(self):
a = set()
for condition in self.conditions:
a.update(condition.extract_tags())
a.add(condition.extract_tag())
if "*" in a:
a = set(["*"])
break
return a

View file

@ -106,21 +106,42 @@ class StyleChooser:
a.add("*")
return a
def updateStyles(self, sl, ftype, tags, zoom, scale, zscale):
def get_runtime_conditions(self, ftype, tags, zoom):
if self.selzooms:
if zoom < self.selzooms[0] or zoom > self.selzooms[1]:
return None
rule_and_object_id = self.testChain(self.ruleChains, ftype, tags, zoom)
if not rule_and_object_id:
return None
rule = rule_and_object_id[0]
if (len(rule.runtime_conditions) == 0):
return None
return rule.runtime_conditions
def updateStyles(self, sl, ftype, tags, zoom, xscale, zscale, filter_by_runtime_conditions):
# Are any of the ruleChains fulfilled?
if self.selzooms:
if zoom < self.selzooms[0] or zoom > self.selzooms[1]:
return sl
#if ftype not in self.compatible_types:
# return sl
#return sl
object_id = self.testChain(self.ruleChains, ftype, tags, zoom)
rule_and_object_id = self.testChain(self.ruleChains, ftype, tags, zoom)
if not object_id:
if not rule_and_object_id:
return sl
w = 0
rule = rule_and_object_id[0]
object_id = rule_and_object_id[1]
if filter_by_runtime_conditions and (filter_by_runtime_conditions != rule.runtime_conditions):
return sl
for r in self.styles:
if self.has_evals:
@ -134,9 +155,8 @@ class StyleChooser:
for p, q in combined_style.iteritems():
if "color" in p:
combined_style[p] = cairo_to_hex(q)
b = b.compute(tags, combined_style, scale, zscale)
b = b.compute(tags, combined_style, xscale, zscale)
ra[a] = b
#r = ra
ra = make_nice_style(ra)
else:
ra = r.copy()
@ -171,7 +191,7 @@ class StyleChooser:
for r in chain:
tt = r.test(obj, tags, zoom)
if tt:
return tt
return r, tt
return False
def newGroup(self):
@ -203,9 +223,16 @@ class StyleChooser:
"""
adds into the current ruleChain (existing Rule)
"""
c = OptimizeCondition(c)
self.ruleChains[-1].conditions.append(c)
def addRuntimeCondition(self, c):
# print "addRuntimeCondition ", c
"""
adds into the current ruleChain (existing Rule)
"""
self.ruleChains[-1].runtime_conditions.append(c)
self.ruleChains[-1].runtime_conditions.sort()
def addStyles(self, a):
# print "addStyle ", a
"""

View file

@ -18,11 +18,6 @@
import re
import os
import logging
from hashlib import md5
from copy import copy, deepcopy
from StyleChooser import StyleChooser
from Condition import Condition
@ -30,7 +25,6 @@ from Condition import Condition
NEEDED_KEYS = set(["width", "casing-width", "fill-color", "fill-image", "icon-image", "text", "extrude",
"background-image", "background-color", "pattern-image", "shield-text", "symbol-shape"])
WHITESPACE = re.compile(r'^ \s+ ', re.S | re.X)
COMMENT = re.compile(r'^ \/\* .+? \*\/ \s* ', re.S | re.X)
@ -39,6 +33,7 @@ CLASS = re.compile(r'^ ([\.:]:?[*\w]+) \s* ', re.S | re.X)
ZOOM = re.compile(r'^ \| \s* z([\d\-]+) \s* ', re.I | re.S | re.X)
GROUP = re.compile(r'^ , \s* ', re.I | re.S | re.X)
CONDITION = re.compile(r'^ \[(.+?)\] \s* ', re.S | re.X)
RUNTIME_CONDITION = re.compile(r'^ \((.+?)\) \s* ', re.S | re.X)
OBJECT = re.compile(r'^ (\*|[\w]+) \s* ', re.S | re.X)
DECLARATION = re.compile(r'^ \{(.+?)\} \s* ', re.S | re.X)
IMPORT = re.compile(r'^@import\("(.+?)"\); \s* ', re.S | re.X)
@ -139,19 +134,23 @@ class MapCSS():
tmp.append(ec)
self.choosers_by_type_and_tag[type][tag] = tmp
def get_style(self, clname, type, tags={}, zoom=0, scale=1, zscale=.5, cache=True):
def get_runtime_rules(self, clname, type, tags, zoom):
"""
Kothic styling API
Returns array of runtime_conditions which are used for clname/type/tags/zoom
"""
if cache:
shash = md5(repr(type) + repr(tags) + repr(zoom)).digest()
if shash in self.cache["style"]:
return deepcopy(self.cache["style"][shash])
runtime_rules = []
if type in self.choosers_by_type_and_tag:
for chooser in self.choosers_by_type_and_tag[type][clname]:
runtime_conditions = chooser.get_runtime_conditions(type, tags, zoom)
if runtime_conditions:
runtime_rules.append(runtime_conditions)
return runtime_rules
def get_style(self, clname, type, tags, zoom, xscale, zscale, filter_by_runtime_conditions):
style = []
if type in self.choosers_by_type_and_tag:
choosers = self.choosers_by_type_and_tag[type][clname]
for chooser in choosers:
style = chooser.updateStyles(style, type, tags, zoom, scale, zscale)
for chooser in self.choosers_by_type_and_tag[type][clname]:
style = chooser.updateStyles(style, type, tags, zoom, xscale, zscale, filter_by_runtime_conditions)
style = [x for x in style if x["object-id"] != "::*"]
for x in style:
for k, v in [('width', 0), ('casing-width', 0)]:
@ -163,13 +162,13 @@ class MapCSS():
if not NEEDED_KEYS.isdisjoint(x):
st.append(x)
style = st
if cache:
self.cache["style"][shash] = deepcopy(style)
return style
def get_style_dict(self, clname, type, tags={}, zoom=0, scale=1, zscale=.5, olddict={}, cache=True):
r = self.get_style(clname, type, tags, zoom, scale, zscale, cache)
def get_style_dict(self, clname, type, tags={}, zoom=0, xscale=1, zscale=.5, olddict={}, filter_by_runtime_conditions=None):
"""
Kothic styling API
"""
r = self.get_style(clname, type, tags, zoom, xscale, zscale, filter_by_runtime_conditions)
d = olddict
for x in r:
if x.get('object-id', '') not in d:
@ -178,7 +177,7 @@ class MapCSS():
return d
def subst_variables(self, t):
"""Expects an array from parseDeclaration."""
""" Expects an array from parseDeclaration. """
for k in t[0]:
t[0][k] = VARIABLE.sub(self.get_variable, t[0][k])
return t
@ -189,7 +188,7 @@ class MapCSS():
raise Exception("Variable not found: " + str(format(name)))
return self.variables[name] if name in self.variables else m.group()
def parse(self, css=None, clamp=True, stretch=1000, filename=None):
def parse(self, css=None, clamp=True, stretch=1000, filename=None, mapcss_tags=None):
"""
Parses MapCSS given as string
"""
@ -251,6 +250,19 @@ class MapCSS():
sc.newGroup()
previous = oGROUP
# RuntimeCondition - (population>=10000)
elif RUNTIME_CONDITION.match(css):
if (previous == oDECLARATION):
self.choosers.append(sc)
sc = StyleChooser(self.scalepair)
if (previous != oOBJECT) and (previous != oZOOM) and (previous != oCONDITION):
sc.newObject()
cond = RUNTIME_CONDITION.match(css).groups()[0]
log.debug("runtime condition found: %s" % (cond))
css = RUNTIME_CONDITION.sub("", css)
sc.addRuntimeCondition(parseCondition(cond))
previous = oCONDITION
# Condition - [highway=primary]
elif CONDITION.match(css):
if (previous == oDECLARATION):
@ -260,8 +272,12 @@ class MapCSS():
sc.newObject()
cond = CONDITION.match(css).groups()[0]
log.debug("condition found: %s" % (cond))
c = parseCondition(cond)
tag = c.extract_tag()
if (tag != "*") and (mapcss_tags != None) and (tag not in mapcss_tags):
raise Exception("Unknown tag '" + tag + "' in condition " + cond)
css = CONDITION.sub("", css)
sc.addCondition(parseCondition(cond))
sc.addCondition(c)
previous = oCONDITION
# Object - way, node, relation

View file

@ -19,7 +19,7 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='drules_struct.proto',
package='',
serialized_pb=_b('\n\x13\x64rules_struct.proto\"*\n\x0c\x44\x61shDotProto\x12\n\n\x02\x64\x64\x18\x01 \x03(\x01\x12\x0e\n\x06offset\x18\x02 \x01(\x01\":\n\x0cPathSymProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04step\x18\x02 \x02(\x01\x12\x0e\n\x06offset\x18\x03 \x01(\x01\"\xaf\x01\n\rLineRuleProto\x12\r\n\x05width\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1e\n\x07\x64\x61shdot\x18\x03 \x01(\x0b\x32\r.DashDotProto\x12\x10\n\x08priority\x18\x04 \x02(\x05\x12\x1e\n\x07pathsym\x18\x05 \x01(\x0b\x32\r.PathSymProto\x12\x17\n\x04join\x18\x06 \x01(\x0e\x32\t.LineJoin\x12\x15\n\x03\x63\x61p\x18\x07 \x01(\x0e\x32\x08.LineCap\"\x9c\x01\n\x0cLineDefProto\x12\r\n\x05width\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1e\n\x07\x64\x61shdot\x18\x03 \x01(\x0b\x32\r.DashDotProto\x12\x1e\n\x07pathsym\x18\x04 \x01(\x0b\x32\r.PathSymProto\x12\x17\n\x04join\x18\x06 \x01(\x0e\x32\t.LineJoin\x12\x15\n\x03\x63\x61p\x18\x07 \x01(\x0e\x32\x08.LineCap\"O\n\rAreaRuleProto\x12\r\n\x05\x63olor\x18\x01 \x02(\r\x12\x1d\n\x06\x62order\x18\x02 \x01(\x0b\x32\r.LineDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"I\n\x0fSymbolRuleProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x16\n\x0e\x61pply_for_type\x18\x02 \x01(\x05\x12\x10\n\x08priority\x18\x03 \x02(\x05\"j\n\x0f\x43\x61ptionDefProto\x12\x0e\n\x06height\x18\x01 \x02(\x05\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x14\n\x0cstroke_color\x18\x03 \x01(\r\x12\x10\n\x08offset_x\x18\x04 \x01(\x05\x12\x10\n\x08offset_y\x18\x05 \x01(\x05\"l\n\x10\x43\x61ptionRuleProto\x12!\n\x07primary\x18\x01 \x02(\x0b\x32\x10.CaptionDefProto\x12#\n\tsecondary\x18\x02 \x01(\x0b\x32\x10.CaptionDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"a\n\x0f\x43ircleRuleProto\x12\x0e\n\x06radius\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1d\n\x06\x62order\x18\x03 \x01(\x0b\x32\r.LineDefProto\x12\x10\n\x08priority\x18\x04 \x02(\x05\"m\n\x11PathTextRuleProto\x12!\n\x07primary\x18\x01 \x02(\x0b\x32\x10.CaptionDefProto\x12#\n\tsecondary\x18\x02 \x01(\x0b\x32\x10.CaptionDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"X\n\x0fShieldRuleProto\x12\x0e\n\x06height\x18\x01 \x02(\x05\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x14\n\x0cstroke_color\x18\x03 \x01(\r\x12\x10\n\x08priority\x18\x04 \x02(\x05\"\x8f\x02\n\x10\x44rawElementProto\x12\r\n\x05scale\x18\x01 \x02(\x05\x12\x1d\n\x05lines\x18\x02 \x03(\x0b\x32\x0e.LineRuleProto\x12\x1c\n\x04\x61rea\x18\x03 \x01(\x0b\x32\x0e.AreaRuleProto\x12 \n\x06symbol\x18\x04 \x01(\x0b\x32\x10.SymbolRuleProto\x12\"\n\x07\x63\x61ption\x18\x05 \x01(\x0b\x32\x11.CaptionRuleProto\x12 \n\x06\x63ircle\x18\x06 \x01(\x0b\x32\x10.CircleRuleProto\x12%\n\tpath_text\x18\x07 \x01(\x0b\x32\x12.PathTextRuleProto\x12 \n\x06shield\x18\x08 \x01(\x0b\x32\x10.ShieldRuleProto\"G\n\x13\x43lassifElementProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\"\n\x07\x65lement\x18\x02 \x03(\x0b\x32\x11.DrawElementProto\"4\n\x0e\x43ontainerProto\x12\"\n\x04\x63ont\x18\x01 \x03(\x0b\x32\x14.ClassifElementProto*4\n\x08LineJoin\x12\r\n\tROUNDJOIN\x10\x00\x12\r\n\tBEVELJOIN\x10\x01\x12\n\n\x06NOJOIN\x10\x02*3\n\x07LineCap\x12\x0c\n\x08ROUNDCAP\x10\x00\x12\x0b\n\x07\x42UTTCAP\x10\x01\x12\r\n\tSQUARECAP\x10\x02\x42\x02H\x03')
serialized_pb=_b('\n\x13\x64rules_struct.proto\"*\n\x0c\x44\x61shDotProto\x12\n\n\x02\x64\x64\x18\x01 \x03(\x01\x12\x0e\n\x06offset\x18\x02 \x01(\x01\":\n\x0cPathSymProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04step\x18\x02 \x02(\x01\x12\x0e\n\x06offset\x18\x03 \x01(\x01\"\xaf\x01\n\rLineRuleProto\x12\r\n\x05width\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1e\n\x07\x64\x61shdot\x18\x03 \x01(\x0b\x32\r.DashDotProto\x12\x10\n\x08priority\x18\x04 \x02(\x05\x12\x1e\n\x07pathsym\x18\x05 \x01(\x0b\x32\r.PathSymProto\x12\x17\n\x04join\x18\x06 \x01(\x0e\x32\t.LineJoin\x12\x15\n\x03\x63\x61p\x18\x07 \x01(\x0e\x32\x08.LineCap\"\x9c\x01\n\x0cLineDefProto\x12\r\n\x05width\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1e\n\x07\x64\x61shdot\x18\x03 \x01(\x0b\x32\r.DashDotProto\x12\x1e\n\x07pathsym\x18\x04 \x01(\x0b\x32\r.PathSymProto\x12\x17\n\x04join\x18\x06 \x01(\x0e\x32\t.LineJoin\x12\x15\n\x03\x63\x61p\x18\x07 \x01(\x0e\x32\x08.LineCap\"O\n\rAreaRuleProto\x12\r\n\x05\x63olor\x18\x01 \x02(\r\x12\x1d\n\x06\x62order\x18\x02 \x01(\x0b\x32\r.LineDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"I\n\x0fSymbolRuleProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x16\n\x0e\x61pply_for_type\x18\x02 \x01(\x05\x12\x10\n\x08priority\x18\x03 \x02(\x05\"j\n\x0f\x43\x61ptionDefProto\x12\x0e\n\x06height\x18\x01 \x02(\x05\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x14\n\x0cstroke_color\x18\x03 \x01(\r\x12\x10\n\x08offset_x\x18\x04 \x01(\x05\x12\x10\n\x08offset_y\x18\x05 \x01(\x05\"l\n\x10\x43\x61ptionRuleProto\x12!\n\x07primary\x18\x01 \x02(\x0b\x32\x10.CaptionDefProto\x12#\n\tsecondary\x18\x02 \x01(\x0b\x32\x10.CaptionDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"a\n\x0f\x43ircleRuleProto\x12\x0e\n\x06radius\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1d\n\x06\x62order\x18\x03 \x01(\x0b\x32\r.LineDefProto\x12\x10\n\x08priority\x18\x04 \x02(\x05\"m\n\x11PathTextRuleProto\x12!\n\x07primary\x18\x01 \x02(\x0b\x32\x10.CaptionDefProto\x12#\n\tsecondary\x18\x02 \x01(\x0b\x32\x10.CaptionDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"X\n\x0fShieldRuleProto\x12\x0e\n\x06height\x18\x01 \x02(\x05\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x14\n\x0cstroke_color\x18\x03 \x01(\r\x12\x10\n\x08priority\x18\x04 \x02(\x05\"\xa1\x02\n\x10\x44rawElementProto\x12\r\n\x05scale\x18\x01 \x02(\x05\x12\x1d\n\x05lines\x18\x02 \x03(\x0b\x32\x0e.LineRuleProto\x12\x1c\n\x04\x61rea\x18\x03 \x01(\x0b\x32\x0e.AreaRuleProto\x12 \n\x06symbol\x18\x04 \x01(\x0b\x32\x10.SymbolRuleProto\x12\"\n\x07\x63\x61ption\x18\x05 \x01(\x0b\x32\x11.CaptionRuleProto\x12 \n\x06\x63ircle\x18\x06 \x01(\x0b\x32\x10.CircleRuleProto\x12%\n\tpath_text\x18\x07 \x01(\x0b\x32\x12.PathTextRuleProto\x12 \n\x06shield\x18\x08 \x01(\x0b\x32\x10.ShieldRuleProto\x12\x10\n\x08\x61pply_if\x18\t \x03(\t\"G\n\x13\x43lassifElementProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\"\n\x07\x65lement\x18\x02 \x03(\x0b\x32\x11.DrawElementProto\"4\n\x0e\x43ontainerProto\x12\"\n\x04\x63ont\x18\x01 \x03(\x0b\x32\x14.ClassifElementProto*4\n\x08LineJoin\x12\r\n\tROUNDJOIN\x10\x00\x12\r\n\tBEVELJOIN\x10\x01\x12\n\n\x06NOJOIN\x10\x02*3\n\x07LineCap\x12\x0c\n\x08ROUNDCAP\x10\x00\x12\x0b\n\x07\x42UTTCAP\x10\x01\x12\r\n\tSQUARECAP\x10\x02\x42\x02H\x03')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
@ -44,8 +44,8 @@ _LINEJOIN = _descriptor.EnumDescriptor(
],
containing_type=None,
options=None,
serialized_start=1539,
serialized_end=1591,
serialized_start=1557,
serialized_end=1609,
)
_sym_db.RegisterEnumDescriptor(_LINEJOIN)
@ -71,8 +71,8 @@ _LINECAP = _descriptor.EnumDescriptor(
],
containing_type=None,
options=None,
serialized_start=1593,
serialized_end=1644,
serialized_start=1611,
serialized_end=1662,
)
_sym_db.RegisterEnumDescriptor(_LINECAP)
@ -703,6 +703,13 @@ _DRAWELEMENTPROTO = _descriptor.Descriptor(
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='apply_if', full_name='DrawElementProto.apply_if', index=8,
number=9, type=9, cpp_type=9, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
@ -715,7 +722,7 @@ _DRAWELEMENTPROTO = _descriptor.Descriptor(
oneofs=[
],
serialized_start=1139,
serialized_end=1410,
serialized_end=1428,
)
@ -751,8 +758,8 @@ _CLASSIFELEMENTPROTO = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=1412,
serialized_end=1483,
serialized_start=1430,
serialized_end=1501,
)
@ -781,8 +788,8 @@ _CONTAINERPROTO = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=1485,
serialized_end=1537,
serialized_start=1503,
serialized_end=1555,
)
_LINERULEPROTO.fields_by_name['dashdot'].message_type = _DASHDOTPROTO