diff --git a/include/mapnik/vertex_cache.hpp b/include/mapnik/vertex_cache.hpp index 49747313e..ced9b0271 100644 --- a/include/mapnik/vertex_cache.hpp +++ b/include/mapnik/vertex_cache.hpp @@ -25,19 +25,17 @@ // mapnik #include #include -#include // agg #include "agg_basics.h" // stl #include -#include -#include +//#include +//#include //boost #include -#include namespace mapnik { @@ -62,6 +60,7 @@ class vertex_cache std::vector vector; double length; }; + public: /** This class has no public members to avoid acciedential modification. * It should only be used with save_state/restore_state. */ @@ -90,15 +89,16 @@ public: bool restored_; }; + /********************************************************************************************/ + template vertex_cache(T &path); double length() const { return current_subpath_->length; } - pixel_position const& current_position() const { return current_position_; } + pixel_position const& current_position() const { return current_position_; } double angle(double width=0.); - bool next_subpath(); /** Moves all positions to a parallel line in the specified distance. */ vertex_cache &get_offseted(double offset, double region_width); @@ -112,16 +112,19 @@ public: bool forward(double length); bool backward(double length); bool move(double length); //Move works in both directions - void rewind_subpath(); + bool next_subpath(); + // Compatibility with standard path interface void rewind(unsigned); unsigned vertex(double *x, double *y); + //State state save_state() const; void restore_state(state const& s); private: + void rewind_subpath(); bool next_segment(); bool previous_segment(); pixel_position current_position_; @@ -198,182 +201,7 @@ vertex_cache::vertex_cache(T &path) } } -double vertex_cache::angle(double width) -{ - /* IMPORTANT NOTE: See note about coordinate systems in placement_finder::find_point_placement() - * for imformation about why the y axis is inverted! */ - double tmp = width + position_in_segment_; - if ((tmp <= current_segment_->length) && (tmp >= 0)) - { - //Only calculate angle on request as it is expensive - if (!angle_valid_) - { - angle_ = atan2(-(current_segment_->pos.y - segment_starting_point_.y), - current_segment_->pos.x - segment_starting_point_.x); - } - return width >= 0 ? angle_ : angle_ + M_PI; - } else - { - scoped_state s(*this); - pixel_position const& old_pos = s.get_state().position(); - move(width); - double angle = atan2(-(current_position_.y - old_pos.y), - current_position_.x - old_pos.x); - return angle; - } -} -bool vertex_cache::next_subpath() -{ - if (first_subpath_) - { - current_subpath_ = subpaths_.begin(); - first_subpath_ = false; - } else - { - current_subpath_++; - } - if (current_subpath_ == subpaths_.end()) return false; - rewind_subpath(); - return true; -} - -bool vertex_cache::next_segment() -{ - segment_starting_point_ = current_segment_->pos; //Next segments starts at the end of the current one - if (current_segment_ == current_subpath_->vector.end()) return false; - current_segment_++; - angle_valid_ = false; - if (current_segment_ == current_subpath_->vector.end()) return false; - return true; -} - -bool vertex_cache::previous_segment() -{ - if (current_segment_ == current_subpath_->vector.begin()) return false; - current_segment_--; - angle_valid_ = false; - if (current_segment_ == current_subpath_->vector.begin()) - { - //First segment is special - segment_starting_point_ = current_segment_->pos; - return true; - } - segment_starting_point_ = (current_segment_-1)->pos; - return true; -} - -vertex_cache & vertex_cache::get_offseted(double offset, double region_width) -{ - if (fabs(offset) < 0.01) - { - return *this; - } - //TODO: Cache offseted lines - offset_converter converter(*this); - converter.set_offset(offset); - offseted_line_ = vertex_cache_ptr(new vertex_cache(converter)); - offseted_line_->rewind_subpath(); //TODO: Multiple subpath support - double seek = (position_ + region_width/2.) * offseted_line_->length() / length() - region_width/2.; - if (seek < 0) seek = 0; - if (seek > offseted_line_->length()) seek = offseted_line_->length(); - offseted_line_->move(seek); - return *offseted_line_; -} - -bool vertex_cache::forward(double length) -{ - if (length < 0) - { - MAPNIK_LOG_ERROR(vertex_cache) << "vertex_cache::forward() called with negative argument!\n"; - return false; - } - return move(length); -} - -bool vertex_cache::backward(double length) -{ - if (length < 0) - { - MAPNIK_LOG_ERROR(vertex_cache) << "vertex_cache::backward() called with negative argument!\n"; - return false; - } - return move(-length); -} - -bool vertex_cache::move(double length) -{ - position_ += length; - length += position_in_segment_; - while (length >= current_segment_->length) - { - length -= current_segment_->length; - if (!next_segment()) return false; //Skip all complete segments - } - while (length < 0) - { - if (!previous_segment()) return false; - length += current_segment_->length; - } - double factor = length / current_segment_->length; - position_in_segment_ = length; - current_position_ = segment_starting_point_ + (current_segment_->pos - segment_starting_point_) * factor; - return true; -} - -void vertex_cache::rewind_subpath() -{ - current_segment_ = current_subpath_->vector.begin(); - //All subpaths contain at least one segment - current_position_ = current_segment_->pos; - position_in_segment_ = 0; - segment_starting_point_ = current_position_; - angle_valid_ = false; - position_ = 0; -} - -void vertex_cache::rewind(unsigned) -{ - vertex_subpath_ = subpaths_.begin(); - vertex_segment_ = vertex_subpath_->vector.begin(); -} - -unsigned vertex_cache::vertex(double *x, double *y) -{ - if (vertex_segment_ == vertex_subpath_->vector.end()) - { - vertex_subpath_++; - if (vertex_subpath_ == subpaths_.end()) return agg::path_cmd_stop; - vertex_segment_ = vertex_subpath_->vector.begin(); - } - *x = vertex_segment_->pos.x; - *y = vertex_segment_->pos.y; - unsigned cmd = (vertex_segment_ == vertex_subpath_->vector.begin()) ? agg::path_cmd_move_to : agg::path_cmd_line_to; - vertex_segment_++; - return cmd; -} - - -vertex_cache::state vertex_cache::save_state() const -{ - state s; - s.current_segment = current_segment_; - s.position_in_segment = position_in_segment_; - s.current_position = current_position_; - s.segment_starting_point = segment_starting_point_; - s.position_ = position_; - return s; -} - -void vertex_cache::restore_state(state const& s) -{ - current_segment_ = s.current_segment; - position_in_segment_ = s.position_in_segment; - current_position_ = s.current_position; - segment_starting_point_ = s.segment_starting_point; - position_ = s.position_; - angle_valid_ = false; -} } diff --git a/src/build.py b/src/build.py index 2728cc011..476dfa4ab 100644 --- a/src/build.py +++ b/src/build.py @@ -179,6 +179,7 @@ source = Split( xml_tree.cpp config_error.cpp color_factory.cpp + vertex_cache.cpp warp.cpp svg/svg_parser.cpp svg/svg_path_parser.cpp diff --git a/src/vertex_cache.cpp b/src/vertex_cache.cpp new file mode 100644 index 000000000..9007d2a53 --- /dev/null +++ b/src/vertex_cache.cpp @@ -0,0 +1,187 @@ +#include +#include + +#include + +namespace mapnik +{ + +double vertex_cache::angle(double width) +{ + /* IMPORTANT NOTE: See note about coordinate systems in placement_finder::find_point_placement() + * for imformation about why the y axis is inverted! */ + double tmp = width + position_in_segment_; + if ((tmp <= current_segment_->length) && (tmp >= 0)) + { + //Only calculate angle on request as it is expensive + if (!angle_valid_) + { + angle_ = atan2(-(current_segment_->pos.y - segment_starting_point_.y), + current_segment_->pos.x - segment_starting_point_.x); + } + return width >= 0 ? angle_ : angle_ + M_PI; + } else + { + scoped_state s(*this); + pixel_position const& old_pos = s.get_state().position(); + move(width); + double angle = atan2(-(current_position_.y - old_pos.y), + current_position_.x - old_pos.x); + return angle; + } +} + +bool vertex_cache::next_subpath() +{ + if (first_subpath_) + { + current_subpath_ = subpaths_.begin(); + first_subpath_ = false; + } else + { + current_subpath_++; + } + if (current_subpath_ == subpaths_.end()) return false; + rewind_subpath(); + return true; +} + +bool vertex_cache::next_segment() +{ + segment_starting_point_ = current_segment_->pos; //Next segments starts at the end of the current one + if (current_segment_ == current_subpath_->vector.end()) return false; + current_segment_++; + angle_valid_ = false; + if (current_segment_ == current_subpath_->vector.end()) return false; + return true; +} + +bool vertex_cache::previous_segment() +{ + if (current_segment_ == current_subpath_->vector.begin()) return false; + current_segment_--; + angle_valid_ = false; + if (current_segment_ == current_subpath_->vector.begin()) + { + //First segment is special + segment_starting_point_ = current_segment_->pos; + return true; + } + segment_starting_point_ = (current_segment_-1)->pos; + return true; +} + +vertex_cache & vertex_cache::get_offseted(double offset, double region_width) +{ + if (fabs(offset) < 0.01) + { + return *this; + } + std::cout << "Creating new offseted line: " << offset << "\n"; + //TODO: Cache offseted lines + offset_converter converter(*this); + converter.set_offset(offset); + offseted_line_ = vertex_cache_ptr(new vertex_cache(converter)); + offseted_line_->rewind_subpath(); //TODO: Multiple subpath support + double seek = (position_ + region_width/2.) * offseted_line_->length() / length() - region_width/2.; + if (seek < 0) seek = 0; + if (seek > offseted_line_->length()) seek = offseted_line_->length(); + offseted_line_->move(seek); + return *offseted_line_; +} + +bool vertex_cache::forward(double length) +{ + if (length < 0) + { + MAPNIK_LOG_ERROR(vertex_cache) << "vertex_cache::forward() called with negative argument!\n"; + return false; + } + return move(length); +} + +bool vertex_cache::backward(double length) +{ + if (length < 0) + { + MAPNIK_LOG_ERROR(vertex_cache) << "vertex_cache::backward() called with negative argument!\n"; + return false; + } + return move(-length); +} + +bool vertex_cache::move(double length) +{ + position_ += length; + length += position_in_segment_; + while (length >= current_segment_->length) + { + length -= current_segment_->length; + if (!next_segment()) return false; //Skip all complete segments + } + while (length < 0) + { + if (!previous_segment()) return false; + length += current_segment_->length; + } + double factor = length / current_segment_->length; + position_in_segment_ = length; + current_position_ = segment_starting_point_ + (current_segment_->pos - segment_starting_point_) * factor; + return true; +} + +void vertex_cache::rewind_subpath() +{ + current_segment_ = current_subpath_->vector.begin(); + //All subpaths contain at least one segment + current_position_ = current_segment_->pos; + position_in_segment_ = 0; + segment_starting_point_ = current_position_; + angle_valid_ = false; + position_ = 0; +} + +void vertex_cache::rewind(unsigned) +{ + vertex_subpath_ = subpaths_.begin(); + vertex_segment_ = vertex_subpath_->vector.begin(); +} + +unsigned vertex_cache::vertex(double *x, double *y) +{ + if (vertex_segment_ == vertex_subpath_->vector.end()) + { + vertex_subpath_++; + if (vertex_subpath_ == subpaths_.end()) return agg::path_cmd_stop; + vertex_segment_ = vertex_subpath_->vector.begin(); + } + *x = vertex_segment_->pos.x; + *y = vertex_segment_->pos.y; + unsigned cmd = (vertex_segment_ == vertex_subpath_->vector.begin()) ? agg::path_cmd_move_to : agg::path_cmd_line_to; + vertex_segment_++; + return cmd; +} + + +vertex_cache::state vertex_cache::save_state() const +{ + state s; + s.current_segment = current_segment_; + s.position_in_segment = position_in_segment_; + s.current_position = current_position_; + s.segment_starting_point = segment_starting_point_; + s.position_ = position_; + return s; +} + +void vertex_cache::restore_state(state const& s) +{ + current_segment_ = s.current_segment; + position_in_segment_ = s.position_in_segment; + current_position_ = s.current_position; + segment_starting_point_ = s.segment_starting_point; + position_ = s.position_; + angle_valid_ = false; +} + +} //ns mapnik