diff --git a/include/mapnik/global.hpp b/include/mapnik/global.hpp index 39a7996f1..cb36e878e 100644 --- a/include/mapnik/global.hpp +++ b/include/mapnik/global.hpp @@ -123,14 +123,6 @@ inline double round(double val) } #endif -#if defined(_MSC_VER) -#define _USE_MATH_DEFINES -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#endif - } diff --git a/include/mapnik/markers_placements/basic.hpp b/include/mapnik/markers_placements/basic.hpp index 9ffcd6fb5..84520d12d 100644 --- a/include/mapnik/markers_placements/basic.hpp +++ b/include/mapnik/markers_placements/basic.hpp @@ -75,24 +75,27 @@ protected: angle = 0; return true; case DIRECTION_DOWN: - angle = M_PI; + angle = util::pi; return true; case DIRECTION_AUTO: - if (std::fabs(util::normalize_angle(angle)) > 0.5 * M_PI) - angle += M_PI; + angle = util::normalize_angle(angle); + if (std::abs(angle) > util::pi / 2) + angle += util::pi; return true; case DIRECTION_AUTO_DOWN: - if (std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI) - angle += M_PI; + angle = util::normalize_angle(angle); + if (std::abs(angle) < util::pi / 2) + angle += util::pi; return true; case DIRECTION_LEFT: - angle += M_PI; + angle += util::pi; return true; case DIRECTION_LEFT_ONLY: - angle += M_PI; - return std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI; + angle = util::normalize_angle(angle + util::pi); + return std::fabs(angle) < util::pi / 2; case DIRECTION_RIGHT_ONLY: - return std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI; + angle = util::normalize_angle(angle); + return std::fabs(angle) < util::pi / 2; case DIRECTION_RIGHT: default: return true; diff --git a/include/mapnik/offset_converter.hpp b/include/mapnik/offset_converter.hpp index d45ffa788..3a32761d8 100644 --- a/include/mapnik/offset_converter.hpp +++ b/include/mapnik/offset_converter.hpp @@ -26,8 +26,8 @@ #ifdef MAPNIK_LOG #include #endif -#include #include +#include #include #include @@ -184,13 +184,13 @@ private: static double explement_reflex_angle(double angle) { - if (angle > M_PI) + if (angle > util::pi) { - return angle - 2 * M_PI; + return angle - util::tau; } - else if (angle < -M_PI) + else if (angle < -util::pi) { - return angle + 2 * M_PI; + return angle + util::tau; } else { @@ -244,6 +244,30 @@ private: return false; } + double joint_angle(double x1x0, double y1y0, double x1x2, double y1y2) const + { + double dot = x1x0 * x1x2 + y1y0 * y1y2; // dot product + double det = x1x0 * y1y2 - y1y0 * x1x2; // determinant + double angle = std::atan2(det, dot); // atan2(y, x) or atan2(sin, cos) + // angle in [-tau/2; tau/2] + + if (offset_ > 0.0) + { + angle = util::tau - angle; // angle in [tau/2; tau*3/2] + } + else if (angle < 0) + { + angle += util::tau; // angle in [tau/2; tau] + // angle may now be equal to tau, because if the original angle + // is very small, the addition cancels it (epsilon + tau == tau) + } + if (angle >= util::tau) + { + angle -= util::tau; + } + return angle; + } + /** * @brief Translate (vx, vy) by rotated (dx, dy). */ @@ -423,13 +447,8 @@ private: cpt++; angle_a = std::atan2(-v_y1y0, -v_x1x0); } - // dot product - double dot; - // determinate - double det; double angle_b = std::atan2(v_y1y2, v_x1x2); // Angle between the two vectors - double joint_angle; double curve_angle; if (!is_polygon) @@ -440,26 +459,15 @@ private: } else { - dot = v_x1x0 * v_x1x2 + v_y1y0 * v_y1y2; // dot product - det = v_x1x0 * v_y1y2 - v_y1y0 * v_x1x2; // determinant - - joint_angle = std::atan2(det, dot); // atan2(y, x) or atan2(sin, cos) - if (joint_angle < 0) joint_angle = joint_angle + 2 * M_PI; - joint_angle = std::fmod(joint_angle, 2 * M_PI); - - if (offset_ > 0.0) - { - joint_angle = 2 * M_PI - joint_angle; - } - + double joint_angle = this->joint_angle(v_x1x0, v_y1y0, v_x1x2, v_y1y2); int bulge_steps = 0; - if (std::abs(joint_angle) > M_PI) + if (std::abs(joint_angle) > util::pi) { curve_angle = explement_reflex_angle(angle_b - angle_a); // Bulge steps should be determined by the inverse of the joint angle. double half_turns = half_turn_segments_ * std::fabs(curve_angle); - bulge_steps = 1 + static_cast(std::floor(half_turns / M_PI)); + bulge_steps = 1 + static_cast(std::floor(half_turns / util::pi)); } if (bulge_steps == 0) @@ -545,26 +553,15 @@ private: // Calculate the new angle_b angle_b = std::atan2(v_y1y2, v_x1x2); - dot = v_x1x0 * v_x1x2 + v_y1y0 * v_y1y2; // dot product - det = v_x1x0 * v_y1y2 - v_y1y0 * v_x1x2; // determinant - - joint_angle = std::atan2(det, dot); // atan2(y, x) or atan2(sin, cos) - if (joint_angle < 0) joint_angle = joint_angle + 2 * M_PI; - joint_angle = std::fmod(joint_angle, 2 * M_PI); - - if (offset_ > 0.0) - { - joint_angle = 2 * M_PI - joint_angle; - } - + double joint_angle = this->joint_angle(v_x1x0, v_y1y0, v_x1x2, v_y1y2); int bulge_steps = 0; - if (std::abs(joint_angle) > M_PI) + if (std::abs(joint_angle) > util::pi) { curve_angle = explement_reflex_angle(angle_b - angle_a); // Bulge steps should be determined by the inverse of the joint angle. double half_turns = half_turn_segments_ * std::fabs(curve_angle); - bulge_steps = 1 + static_cast(std::floor(half_turns / M_PI)); + bulge_steps = 1 + static_cast(std::floor(half_turns / util::pi)); } #ifdef MAPNIK_LOG @@ -572,14 +569,16 @@ private: { // inside turn (sharp/obtuse angle) MAPNIK_LOG_DEBUG(ctrans) << "offset_converter:" - << " Sharp joint [<< inside turn " << int(joint_angle*180/M_PI) + << " Sharp joint [<< inside turn " + << static_cast(util::degrees(joint_angle)) << " degrees >>]"; } else { // outside turn (reflex angle) MAPNIK_LOG_DEBUG(ctrans) << "offset_converter:" - << " Bulge joint >)) outside turn " << int(joint_angle*180/M_PI) + << " Bulge joint >)) outside turn " + << static_cast(util::degrees(joint_angle)) << " degrees ((< with " << bulge_steps << " segments"; } #endif diff --git a/include/mapnik/svg/svg_grammar_config_x3.hpp b/include/mapnik/svg/svg_grammar_config_x3.hpp index 391b34420..c89388c1f 100644 --- a/include/mapnik/svg/svg_grammar_config_x3.hpp +++ b/include/mapnik/svg/svg_grammar_config_x3.hpp @@ -24,6 +24,7 @@ #define MAPNIK_SVG_GRAMMAR_CONFIG_X3_HPP #include + #pragma GCC diagnostic push #include #include @@ -52,8 +53,6 @@ using svg_parse_context_type = x3::context>; -inline double deg2rad(double deg) {return (M_PI * deg) / 180.0;} - }}} #endif // MAPNIK_SVG_GRAMMAR_CONFIG_X3_HPP diff --git a/include/mapnik/svg/svg_path_commands.hpp b/include/mapnik/svg/svg_path_commands.hpp index d4faaf7a0..e232d27ce 100644 --- a/include/mapnik/svg/svg_path_commands.hpp +++ b/include/mapnik/svg/svg_path_commands.hpp @@ -24,8 +24,8 @@ #define MAPNIK_SVG_PATH_COMMANDS_HPP // mapnik -#include #include +#include #pragma GCC diagnostic push #include @@ -35,12 +35,6 @@ namespace mapnik { namespace svg { - -inline double deg2rad(double deg) -{ - return (M_PI * deg) / 180.0; -} - struct move_to { using result_type = void; @@ -137,7 +131,7 @@ struct arc_to void operator()(PathType& path, T0 const& rv, T1 const& angle, T2 large_arc_flag, T3 sweep_flag, T4 const& v, T5 rel) const { path.arc_to(boost::fusion::at_c<0>(rv), boost::fusion::at_c<1>(rv), - deg2rad(angle), large_arc_flag, sweep_flag, + util::radians(angle), large_arc_flag, sweep_flag, boost::fusion::at_c<0>(v), boost::fusion::at_c<1>(v), rel); } diff --git a/include/mapnik/svg/svg_path_grammar_x3_def.hpp b/include/mapnik/svg/svg_path_grammar_x3_def.hpp index 50503fcfc..c0858bc25 100644 --- a/include/mapnik/svg/svg_path_grammar_x3_def.hpp +++ b/include/mapnik/svg/svg_path_grammar_x3_def.hpp @@ -24,9 +24,10 @@ #define MAPNIK_SVG_PATH_GRAMMAR_X3_DEF_HPP // mapnik -#include #include #include +#include + #pragma GCC diagnostic push #include #include @@ -123,8 +124,9 @@ auto const arc_to = [] (auto & ctx) int large_arc_flag = boost::fusion::at_c<2>(attr); int sweep_flag = boost::fusion::at_c<3>(attr); auto const& v = boost::fusion::at_c<4>(attr); - extract_path(ctx).arc_to(std::get<0>(p),std::get<1>(p), - deg2rad(angle), large_arc_flag, sweep_flag, + x3::get(ctx).get().arc_to(std::get<0>(p),std::get<1>(p), + util::radians(angle), + large_arc_flag, sweep_flag, std::get<0>(v),std::get<1>(v), x3::get(ctx)); }; diff --git a/include/mapnik/svg/svg_transform_grammar_x3_def.hpp b/include/mapnik/svg/svg_transform_grammar_x3_def.hpp index 7b8b7b8c7..e1ff3849f 100644 --- a/include/mapnik/svg/svg_transform_grammar_x3_def.hpp +++ b/include/mapnik/svg/svg_transform_grammar_x3_def.hpp @@ -25,6 +25,7 @@ // mapnik #include + // boost::fusion #pragma GCC diagnostic push #include @@ -72,12 +73,12 @@ auto const rotate_action = [] (auto const& ctx) auto cy = boost::fusion::at_c<2>(attr) ? *boost::fusion::at_c<2>(attr) : 0.0; if (cx == 0.0 && cy == 0.0) { - tr = agg::trans_affine_rotation(deg2rad(a)) * tr; + tr = agg::trans_affine_rotation(agg::deg2rad(a)) * tr; } else { agg::trans_affine t = agg::trans_affine_translation(-cx, -cy); - t *= agg::trans_affine_rotation(deg2rad(a)); + t *= agg::trans_affine_rotation(agg::deg2rad(a)); t *= agg::trans_affine_translation(cx, cy); tr = t * tr; } @@ -107,14 +108,14 @@ auto const skewX_action = [] (auto const& ctx) { auto & tr = extract_transform(ctx); auto skew_x = _attr(ctx); - tr = agg::trans_affine_skewing(deg2rad(skew_x), 0.0) * tr; + tr = agg::trans_affine_skewing(agg::deg2rad(skew_x), 0.0) * tr; }; auto const skewY_action = [] (auto const& ctx) { auto & tr = extract_transform(ctx); auto skew_y= _attr(ctx); - tr = agg::trans_affine_skewing(0.0, deg2rad(skew_y)) * tr; + tr = agg::trans_affine_skewing(0.0, agg::deg2rad(skew_y)) * tr; }; //exported rule diff --git a/include/mapnik/transform/transform_processor.hpp b/include/mapnik/transform/transform_processor.hpp index 59011d52f..164e490dc 100644 --- a/include/mapnik/transform/transform_processor.hpp +++ b/include/mapnik/transform/transform_processor.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #pragma GCC diagnostic push @@ -145,7 +146,7 @@ struct transform_processor void operator() (rotate_node const& node) const { - double angle = deg2rad(eval(node.angle_)); + double angle = agg::deg2rad(eval(node.angle_)); double cx = eval(node.cx_, 0.0); double cy = eval(node.cy_, 0.0); transform_.translate(-cx, -cy); @@ -156,28 +157,19 @@ struct transform_processor void operator() (skewX_node const& node) const { auto degrees = std::fmod(eval(node.angle_),90.0); - if (degrees < -89.0) degrees = -89.0; - else if (degrees > 89.0) degrees = 89.0; - auto angle = deg2rad(degrees); + auto angle = agg::deg2rad(util::clamp(degrees, -89.0, 89.0)); transform_.multiply(agg::trans_affine_skewing(angle, 0.0)); } void operator() (skewY_node const& node) const { auto degrees = std::fmod(eval(node.angle_),90.0); - if (degrees < -89.0) degrees = -89.0; - else if (degrees > 89.0) degrees = 89.0; - auto angle = deg2rad(degrees); + auto angle = agg::deg2rad(util::clamp(degrees, -89.0, 89.0)); transform_.multiply(agg::trans_affine_skewing(0.0, angle)); } private: - static double deg2rad(double d) - { - return d * M_PI / 180.0; - } - double eval(expr_node const& x) const { mapnik::evaluate e(feature_,vars_); diff --git a/include/mapnik/util/math.hpp b/include/mapnik/util/math.hpp index fd86238a9..e022f8c79 100644 --- a/include/mapnik/util/math.hpp +++ b/include/mapnik/util/math.hpp @@ -30,6 +30,22 @@ namespace mapnik { namespace util { constexpr double pi = 3.1415926535897932384626433832795; constexpr double tau = 6.283185307179586476925286766559; +template +constexpr T const& clamp(T const& v, T const& lo, T const& hi) +{ + return v < lo ? lo : hi < v ? hi : v; +} + +constexpr double degrees(double rad) +{ + return rad * (360 / tau); +} + +constexpr double radians(double deg) +{ + return deg * (tau / 360); +} + MAPNIK_DECL double normalize_angle(double angle); }} diff --git a/include/mapnik/well_known_srs.hpp b/include/mapnik/well_known_srs.hpp index dd3d48e36..9225a0859 100644 --- a/include/mapnik/well_known_srs.hpp +++ b/include/mapnik/well_known_srs.hpp @@ -24,9 +24,9 @@ #define MAPNIK_WELL_KNOWN_SRS_HPP // mapnik -#include // for M_PI on windows #include #include +#include #pragma GCC diagnostic push #include @@ -34,7 +34,6 @@ #pragma GCC diagnostic pop // stl -#include #include namespace mapnik { @@ -47,81 +46,27 @@ enum well_known_srs_enum : std::uint8_t { DEFINE_ENUM( well_known_srs_e, well_known_srs_enum ); -static const double EARTH_RADIUS = 6378137.0; -static const double EARTH_DIAMETER = EARTH_RADIUS * 2.0; -static const double EARTH_CIRCUMFERENCE = EARTH_DIAMETER * M_PI; -static const double MAXEXTENT = EARTH_CIRCUMFERENCE / 2.0; -static const double M_PI_by2 = M_PI / 2; -static const double D2R = M_PI / 180.0; -static const double R2D = 180.0 / M_PI; -static const double M_PIby360 = M_PI / 360.0; -static const double MAXEXTENTby180 = MAXEXTENT / 180.0; -static const double MAX_LATITUDE = R2D * (2 * std::atan(std::exp(180.0 * D2R)) - M_PI_by2); -static const std::string MAPNIK_LONGLAT_PROJ = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"; -static const std::string MAPNIK_GMERC_PROJ = "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over"; +constexpr double EARTH_RADIUS = 6378137.0; +constexpr double EARTH_CIRCUMFERENCE = EARTH_RADIUS * util::tau; +constexpr double MERC_MAX_EXTENT = EARTH_RADIUS * util::pi; +constexpr double MERC_MAX_LATITUDE = 85.0511287798065923778; + // MERC_MAX_LATITUDE = degrees(2 * atan(exp(pi)) - pi / 2) -boost::optional is_well_known_srs(std::string const& srs); +extern MAPNIK_DECL std::string const MAPNIK_LONGLAT_PROJ; +extern MAPNIK_DECL std::string const MAPNIK_GMERC_PROJ; -boost::optional is_known_geographic(std::string const& srs); +MAPNIK_DECL boost::optional is_known_geographic(std::string const& srs); +MAPNIK_DECL boost::optional is_well_known_srs(std::string const& srs); -static inline bool lonlat2merc(double * x, double * y, std::size_t point_count) -{ - for (std::size_t i = 0; i < point_count; ++i) - { - if (x[i] > 180) x[i] = 180; - else if (x[i] < -180) x[i] = -180; - if (y[i] > MAX_LATITUDE) y[i] = MAX_LATITUDE; - else if (y[i] < -MAX_LATITUDE) y[i] = -MAX_LATITUDE; - x[i] = x[i] * MAXEXTENTby180; - y[i] = std::log(std::tan((90.0 + y[i]) * M_PIby360)) * R2D * MAXEXTENTby180; - } - return true; -} +MAPNIK_DECL bool lonlat2merc(double & x, double & y); +MAPNIK_DECL bool lonlat2merc(double * x, double * y, std::size_t point_count, + std::size_t stride = 1); +MAPNIK_DECL bool lonlat2merc(std::vector> & ls); -static inline bool merc2lonlat(double * x, double * y, std::size_t point_count) -{ - for(std::size_t i = 0; i < point_count; ++i) - { - if (x[i] > MAXEXTENT) x[i] = MAXEXTENT; - else if (x[i] < -MAXEXTENT) x[i] = -MAXEXTENT; - if (y[i] > MAXEXTENT) y[i] = MAXEXTENT; - else if (y[i] < -MAXEXTENT) y[i] = -MAXEXTENT; - x[i] = (x[i] / MAXEXTENT) * 180; - y[i] = (y[i] / MAXEXTENT) * 180; - y[i] = R2D * (2 * std::atan(std::exp(y[i] * D2R)) - M_PI_by2); - } - return true; -} - -static inline bool lonlat2merc(std::vector> & ls) -{ - for (auto& p : ls) - { - if (p.x > 180) p.x = 180; - else if (p.x < -180) p.x = -180; - if (p.y > MAX_LATITUDE) p.y = MAX_LATITUDE; - else if (p.y < -MAX_LATITUDE) p.y = -MAX_LATITUDE; - p.x = p.x * MAXEXTENTby180; - p.y = std::log(std::tan((90 + p.y) * M_PIby360)) * R2D; - p.y = p.y * MAXEXTENTby180; - } - return true; -} - -static inline bool merc2lonlat(std::vector> & ls) -{ - for (auto & p : ls) - { - if (p.x > MAXEXTENT) p.x = MAXEXTENT; - else if (p.x < -MAXEXTENT) p.x = -MAXEXTENT; - if (p.y > MAXEXTENT) p.y = MAXEXTENT; - else if (p.y < -MAXEXTENT) p.y = -MAXEXTENT; - p.x = (p.x / MAXEXTENT) * 180; - p.y = (p.y / MAXEXTENT) * 180; - p.y = R2D * (2 * std::atan(std::exp(p.y * D2R)) - M_PI_by2); - } - return true; -} +MAPNIK_DECL bool merc2lonlat(double & x, double & y); +MAPNIK_DECL bool merc2lonlat(double * x, double * y, std::size_t point_count, + std::size_t stride = 1); +MAPNIK_DECL bool merc2lonlat(std::vector> & ls); } diff --git a/src/build.py b/src/build.py index 4a886d65e..32938b656 100644 --- a/src/build.py +++ b/src/build.py @@ -269,7 +269,7 @@ source = Split( renderer_common/render_markers_symbolizer.cpp renderer_common/render_pattern.cpp renderer_common/render_thunk_extractor.cpp - math.cpp + util/math.cpp value.cpp """ ) diff --git a/src/proj_transform.cpp b/src/proj_transform.cpp index 8e7719127..4afac4c54 100644 --- a/src/proj_transform.cpp +++ b/src/proj_transform.cpp @@ -195,11 +195,11 @@ bool proj_transform::forward (double * x, double * y , double * z, int point_cou if (wgs84_to_merc_) { - return lonlat2merc(x,y,point_count); + return lonlat2merc(x, y, point_count, offset); } else if (merc_to_wgs84_) { - return merc2lonlat(x,y,point_count); + return merc2lonlat(x, y, point_count, offset); } #ifdef MAPNIK_USE_PROJ4 @@ -244,11 +244,11 @@ bool proj_transform::backward (double * x, double * y , double * z, int point_co if (wgs84_to_merc_) { - return merc2lonlat(x,y,point_count); + return merc2lonlat(x, y, point_count, offset); } else if (merc_to_wgs84_) { - return lonlat2merc(x,y,point_count); + return lonlat2merc(x, y, point_count, offset); } #ifdef MAPNIK_USE_PROJ4 diff --git a/src/text/placement_finder.cpp b/src/text/placement_finder.cpp index b20be3612..7d0d73461 100644 --- a/src/text/placement_finder.cpp +++ b/src/text/placement_finder.cpp @@ -135,11 +135,13 @@ text_upright_e placement_finder::simplify_upright(text_upright_e upright, double { if (upright == UPRIGHT_AUTO) { - return (std::fabs(util::normalize_angle(angle)) > 0.5*M_PI) ? UPRIGHT_LEFT : UPRIGHT_RIGHT; + angle = util::normalize_angle(angle); + return std::abs(angle) > util::tau / 4 ? UPRIGHT_LEFT : UPRIGHT_RIGHT; } if (upright == UPRIGHT_AUTO_DOWN) { - return (std::fabs(util::normalize_angle(angle)) < 0.5*M_PI) ? UPRIGHT_LEFT : UPRIGHT_RIGHT; + angle = util::normalize_angle(angle); + return std::abs(angle) < util::tau / 4 ? UPRIGHT_LEFT : UPRIGHT_RIGHT; } if (upright == UPRIGHT_LEFT_ONLY) { @@ -332,7 +334,7 @@ bool placement_finder::single_line_placement(vertex_cache &pp, text_upright_e or last_cluster_angle = angle; } - if (std::abs(angle) > M_PI/2) + if (std::abs(angle) > util::tau / 4) { ++upside_down_glyph_count; } diff --git a/src/text/text_layout.cpp b/src/text/text_layout.cpp index ecf02ab8e..e1952677f 100644 --- a/src/text/text_layout.cpp +++ b/src/text/text_layout.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #pragma GCC diagnostic push @@ -117,7 +118,7 @@ text_layout::text_layout(face_manager_freetype & font_manager, if (!wrap_str.empty()) wrap_char_ = wrap_str[0]; wrap_width_ = util::apply_visitor(extract_value(feature,attrs), layout_properties_.wrap_width); double angle = util::apply_visitor(extract_value(feature,attrs), layout_properties_.orientation); - orientation_.init(angle * M_PI/ 180.0); + orientation_.init(util::radians(angle)); wrap_before_ = util::apply_visitor(extract_value(feature,attrs), layout_properties_.wrap_before); repeat_wrap_char_ = util::apply_visitor(extract_value(feature,attrs), layout_properties_.repeat_wrap_char); rotate_displacement_ = util::apply_visitor(extract_value(feature,attrs), layout_properties_.rotate_displacement); diff --git a/src/text/text_properties.cpp b/src/text/text_properties.cpp index f9adef602..3d4c0aad0 100644 --- a/src/text/text_properties.cpp +++ b/src/text/text_properties.cpp @@ -22,6 +22,7 @@ // mapnik #include #include +#include #include #include #include @@ -59,7 +60,7 @@ evaluated_text_properties_ptr evaluate_text_properties(text_symbolizer_propertie prop->minimum_distance = util::apply_visitor(extract_value(feature,attrs), text_prop.expressions.minimum_distance); prop->minimum_padding = util::apply_visitor(extract_value(feature,attrs), text_prop.expressions.minimum_padding); prop->minimum_path_length = util::apply_visitor(extract_value(feature,attrs), text_prop.expressions.minimum_path_length); - prop->max_char_angle_delta = util::apply_visitor(extract_value(feature,attrs), text_prop.expressions.max_char_angle_delta) * M_PI/180; + prop->max_char_angle_delta = util::radians(util::apply_visitor(extract_value(feature,attrs), text_prop.expressions.max_char_angle_delta)); prop->allow_overlap = util::apply_visitor(extract_value(feature,attrs), text_prop.expressions.allow_overlap); prop->largest_bbox_only = util::apply_visitor(extract_value(feature,attrs), text_prop.expressions.largest_bbox_only); prop->upright = util::apply_visitor(extract_value(feature,attrs), text_prop.expressions.upright); diff --git a/src/math.cpp b/src/util/math.cpp similarity index 100% rename from src/math.cpp rename to src/util/math.cpp diff --git a/src/vertex_cache.cpp b/src/vertex_cache.cpp index ac4f20274..0a55d5737 100644 --- a/src/vertex_cache.cpp +++ b/src/vertex_cache.cpp @@ -20,7 +20,7 @@ * *****************************************************************************/ // mapnik -#include +#include #include #include #include @@ -75,7 +75,7 @@ double vertex_cache::angle(double width) angle_ = current_segment_angle(); } } - return width >= 0 ? angle_ : angle_ + M_PI; + return width >= 0 ? angle_ : angle_ + util::pi; } bool vertex_cache::next_subpath() diff --git a/src/well_known_srs.cpp b/src/well_known_srs.cpp index c7ec4c5ba..df3b2fe0a 100644 --- a/src/well_known_srs.cpp +++ b/src/well_known_srs.cpp @@ -30,8 +30,18 @@ #include #pragma GCC diagnostic pop +// stl +#include + namespace mapnik { +extern std::string const MAPNIK_LONGLAT_PROJ = + "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"; + +extern std::string const MAPNIK_GMERC_PROJ = + "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0" + " +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over"; + static const char * well_known_srs_strings[] = { "mapnik-longlat", "mapnik-gmerc", @@ -82,4 +92,60 @@ boost::optional is_known_geographic(std::string const& srs) IMPLEMENT_ENUM( well_known_srs_e, well_known_srs_strings ) +bool lonlat2merc(double & x, double & y) +{ + using namespace util; + auto dx = clamp(x, -180.0, 180.0); + auto dy = clamp(y, -MERC_MAX_LATITUDE, MERC_MAX_LATITUDE); + x = EARTH_RADIUS * radians(dx); + y = EARTH_RADIUS * std::log(std::tan(radians(90 + dy) / 2)); + return true; +} + +bool lonlat2merc(double * x, double * y, std::size_t point_count, std::size_t stride) +{ + for (std::size_t i = 0; i < point_count; ++i) + { + lonlat2merc(x[i * stride], y[i * stride]); + } + return true; +} + +bool lonlat2merc(std::vector> & ls) +{ + for (auto & p : ls) + { + lonlat2merc(p.x, p.y); + } + return true; +} + +bool merc2lonlat(double & x, double & y) +{ + using namespace util; + auto rx = clamp(x / EARTH_RADIUS, -pi, pi); + auto ry = clamp(y / EARTH_RADIUS, -pi, pi); + x = degrees(rx); + y = degrees(2 * std::atan(std::exp(ry)) - pi / 2); + return true; +} + +bool merc2lonlat(double * x, double * y, std::size_t point_count, std::size_t stride) +{ + for(std::size_t i = 0; i < point_count; ++i) + { + merc2lonlat(x[i * stride], y[i * stride]); + } + return true; +} + +bool merc2lonlat(std::vector> & ls) +{ + for (auto & p : ls) + { + merc2lonlat(p.x, p.y); + } + return true; +} + } diff --git a/test/unit/projection/proj_transform.cpp b/test/unit/projection/proj_transform.cpp index 433f5cf84..289d8e70d 100644 --- a/test/unit/projection/proj_transform.cpp +++ b/test/unit/projection/proj_transform.cpp @@ -206,4 +206,73 @@ SECTION("Test proj antimeridian bbox") } } +SECTION("proj_transform of coordinate arrays with stride > 1") +{ + mapnik::projection const proj_4326("+init=epsg:4326"); + mapnik::projection const proj_3857("+init=epsg:3857"); + mapnik::projection const proj_2193("+init=epsg:2193"); + + SECTION("lonlat <-> Web Mercator") + { + // cs2cs -Ef %.10f +init=epsg:4326 +to +init=epsg:3857 < points[] = {{ 170.142139, -43.595056 }, + { 175.566667, -39.283333 }}; + // this transform is calculated by Mapnik (well_known_srs.cpp) + mapnik::proj_transform lonlat_to_webmerc(proj_4326, proj_3857); + CHECKED_IF(lonlat_to_webmerc.forward(&points[0].x, &points[0].y, nullptr, 2, 2)) + { + CHECK(points[0].x == Approx(18940136.2759583741)); + CHECK(points[0].y == Approx(-5402988.5324898539)); + CHECK(points[1].x == Approx(19543991.9707122259)); + CHECK(points[1].y == Approx(-4762338.2380718365)); + } + CHECKED_IF(lonlat_to_webmerc.backward(&points[0].x, &points[0].y, nullptr, 2, 2)) + { + CHECK(points[0].x == Approx(170.142139)); + CHECK(points[0].y == Approx(-43.595056)); + CHECK(points[1].x == Approx(175.566667)); + CHECK(points[1].y == Approx(-39.283333)); + } + } + + #ifdef MAPNIK_USE_PROJ4 + SECTION("lonlat <-> New Zealand Transverse Mercator 2000") + { + // cs2cs -Ef %.10f +init=epsg:4326 +to +init=epsg:2193 < points[] = {{ 170.142139, -43.595056 }, + { 175.566667, -39.283333 }}; + // this transform is not calculated by Mapnik (needs Proj4) + mapnik::proj_transform lonlat_to_nztm(proj_4326, proj_2193); + CHECKED_IF(lonlat_to_nztm.forward(&points[0].x, &points[0].y, nullptr, 2, 2)) + { + CHECK(points[0].x == Approx(1369316.0970041484)); + CHECK(points[0].y == Approx(5169132.9750701785)); + CHECK(points[1].x == Approx(1821377.9170061364)); + CHECK(points[1].y == Approx(5648640.2106032455)); + } + CHECKED_IF(lonlat_to_nztm.backward(&points[0].x, &points[0].y, nullptr, 2, 2)) + { + CHECK(points[0].x == Approx(170.142139)); + CHECK(points[0].y == Approx(-43.595056)); + CHECK(points[1].x == Approx(175.566667)); + CHECK(points[1].y == Approx(-39.283333)); + } + } + #endif // MAPNIK_USE_PROJ4 +} + } diff --git a/test/unit/vertex_adapter/line_offset_test.cpp b/test/unit/vertex_adapter/line_offset_test.cpp index 75bfb0799..36e399298 100644 --- a/test/unit/vertex_adapter/line_offset_test.cpp +++ b/test/unit/vertex_adapter/line_offset_test.cpp @@ -3,8 +3,8 @@ #include "fake_path.hpp" // mapnik +#include #include -#include // stl #include @@ -55,7 +55,7 @@ void test_offset_curve(double const &offset) { std::vector pos, off_pos; const size_t max_i = 1000; for (size_t i = 0; i <= max_i; ++i) { - double x = M_PI * double(i) / max_i; + double x = mapnik::util::pi * double(i) / max_i; pos.push_back(-std::cos(x)); pos.push_back(std::sin(x)); off_pos.push_back(-r * std::cos(x)); off_pos.push_back(r * std::sin(x)); } @@ -88,12 +88,12 @@ void test_s_shaped_curve(double const &offset) { std::vector pos, off_pos; const size_t max_i = 1000; for (size_t i = 0; i <= max_i; ++i) { - double x = M_PI * double(i) / max_i; + double x = mapnik::util::pi * double(i) / max_i; pos.push_back(-std::cos(x) - 1); pos.push_back(std::sin(x)); off_pos.push_back(-r * std::cos(x) - 1); off_pos.push_back(r * std::sin(x)); } for (size_t i = 0; i <= max_i; ++i) { - double x = M_PI * double(i) / max_i; + double x = mapnik::util::pi * double(i) / max_i; pos.push_back(-std::cos(x) + 1); pos.push_back(-std::sin(x)); off_pos.push_back(-r2 * std::cos(x) + 1); off_pos.push_back(-r2 * std::sin(x)); } diff --git a/test/unit/vertex_adapter/offset_converter.cpp b/test/unit/vertex_adapter/offset_converter.cpp index 1493127d4..0df728b3a 100644 --- a/test/unit/vertex_adapter/offset_converter.cpp +++ b/test/unit/vertex_adapter/offset_converter.cpp @@ -4,6 +4,7 @@ // mapnik #include +#include // stl #include @@ -134,7 +135,7 @@ void test_offset_curve(double const &offset) { std::vector pos, off_pos; const size_t max_i = 1000; for (size_t i = 0; i <= max_i; ++i) { - double x = M_PI * double(i) / max_i; + double x = mapnik::util::pi * double(i) / max_i; pos.push_back(-std::cos(x)); pos.push_back(std::sin(x)); off_pos.push_back(-r * std::cos(x)); off_pos.push_back(r * std::sin(x)); } @@ -185,12 +186,12 @@ void test_s_shaped_curve(double const &offset) { std::vector pos, off_pos; const size_t max_i = 1000; for (size_t i = 0; i <= max_i; ++i) { - double x = M_PI * double(i) / max_i; + double x = mapnik::util::pi * double(i) / max_i; pos.push_back(-std::cos(x) - 1); pos.push_back(std::sin(x)); off_pos.push_back(-r * std::cos(x) - 1); off_pos.push_back(r * std::sin(x)); } for (size_t i = 0; i <= max_i; ++i) { - double x = M_PI * double(i) / max_i; + double x = mapnik::util::pi * double(i) / max_i; pos.push_back(-std::cos(x) + 1); pos.push_back(-std::sin(x)); off_pos.push_back(-r2 * std::cos(x) + 1); off_pos.push_back(-r2 * std::sin(x)); }