Merge branch 'pi-is-wrong' of https://github.com/lightmare/mapnik into lightmare-pi-is-wrong

This commit is contained in:
Artem Pavlenko 2018-07-30 10:40:51 +01:00
commit af842a8bf9
21 changed files with 261 additions and 178 deletions

View file

@ -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
}

View file

@ -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;

View file

@ -26,8 +26,8 @@
#ifdef MAPNIK_LOG
#include <mapnik/debug.hpp>
#endif
#include <mapnik/global.hpp>
#include <mapnik/config.hpp>
#include <mapnik/util/math.hpp>
#include <mapnik/vertex.hpp>
#include <mapnik/vertex_cache.hpp>
@ -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<int>(std::floor(half_turns / M_PI));
bulge_steps = 1 + static_cast<int>(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<int>(std::floor(half_turns / M_PI));
bulge_steps = 1 + static_cast<int>(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<int>(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<int>(util::degrees(joint_angle))
<< " degrees ((< with " << bulge_steps << " segments";
}
#endif

View file

@ -24,6 +24,7 @@
#define MAPNIK_SVG_GRAMMAR_CONFIG_X3_HPP
#include <mapnik/svg/svg_path_parser.hpp>
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/spirit/home/x3.hpp>
@ -52,8 +53,6 @@ using svg_parse_context_type = x3::context<relative_tag, relative_type,
x3::context<svg_path_tag, svg_converter_wrapper_type,
phrase_parse_context_type>>;
inline double deg2rad(double deg) {return (M_PI * deg) / 180.0;}
}}}
#endif // MAPNIK_SVG_GRAMMAR_CONFIG_X3_HPP

View file

@ -24,8 +24,8 @@
#define MAPNIK_SVG_PATH_COMMANDS_HPP
// mapnik
#include <mapnik/global.hpp>
#include <mapnik/config.hpp>
#include <mapnik/util/math.hpp>
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
@ -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);
}

View file

@ -24,9 +24,10 @@
#define MAPNIK_SVG_PATH_GRAMMAR_X3_DEF_HPP
// mapnik
#include <mapnik/global.hpp>
#include <mapnik/config.hpp>
#include <mapnik/svg/svg_path_grammar_x3.hpp>
#include <mapnik/util/math.hpp>
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
@ -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<svg_path_tag>(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<relative_tag>(ctx));
};

View file

@ -25,6 +25,7 @@
// mapnik
#include <mapnik/svg/svg_transform_grammar_x3.hpp>
// boost::fusion
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
@ -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

View file

@ -28,6 +28,7 @@
#include <mapnik/value.hpp>
#include <mapnik/transform/transform_expression.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/util/math.hpp>
#include <mapnik/util/variant.hpp>
#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<feature_type, value_type, variable_type> e(feature_,vars_);

View file

@ -30,6 +30,22 @@ namespace mapnik { namespace util {
constexpr double pi = 3.1415926535897932384626433832795;
constexpr double tau = 6.283185307179586476925286766559;
template <typename T>
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);
}}

View file

@ -24,9 +24,9 @@
#define MAPNIK_WELL_KNOWN_SRS_HPP
// mapnik
#include <mapnik/global.hpp> // for M_PI on windows
#include <mapnik/enumeration.hpp>
#include <mapnik/geometry/point.hpp>
#include <mapnik/util/math.hpp>
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
@ -34,7 +34,6 @@
#pragma GCC diagnostic pop
// stl
#include <cmath>
#include <vector>
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<well_known_srs_e> 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<bool> is_known_geographic(std::string const& srs);
MAPNIK_DECL boost::optional<bool> is_known_geographic(std::string const& srs);
MAPNIK_DECL boost::optional<well_known_srs_e> 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<geometry::point<double>> & 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<geometry::point<double>> & 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<geometry::point<double>> & 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<geometry::point<double>> & ls);
}

View file

@ -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
"""
)

View file

@ -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

View file

@ -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;
}

View file

@ -27,6 +27,7 @@
#include <mapnik/feature.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/text/harfbuzz_shaper.hpp>
#include <mapnik/util/math.hpp>
#include <mapnik/make_unique.hpp>
#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<value_double>(feature,attrs), layout_properties_.wrap_width);
double angle = util::apply_visitor(extract_value<value_double>(feature,attrs), layout_properties_.orientation);
orientation_.init(angle * M_PI/ 180.0);
orientation_.init(util::radians(angle));
wrap_before_ = util::apply_visitor(extract_value<value_bool>(feature,attrs), layout_properties_.wrap_before);
repeat_wrap_char_ = util::apply_visitor(extract_value<value_bool>(feature,attrs), layout_properties_.repeat_wrap_char);
rotate_displacement_ = util::apply_visitor(extract_value<value_bool>(feature,attrs), layout_properties_.rotate_displacement);

View file

@ -22,6 +22,7 @@
// mapnik
#include <mapnik/text/text_properties.hpp>
#include <mapnik/text/text_layout.hpp>
#include <mapnik/util/math.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/symbolizer.hpp>
@ -59,7 +60,7 @@ evaluated_text_properties_ptr evaluate_text_properties(text_symbolizer_propertie
prop->minimum_distance = util::apply_visitor(extract_value<value_double>(feature,attrs), text_prop.expressions.minimum_distance);
prop->minimum_padding = util::apply_visitor(extract_value<value_double>(feature,attrs), text_prop.expressions.minimum_padding);
prop->minimum_path_length = util::apply_visitor(extract_value<value_double>(feature,attrs), text_prop.expressions.minimum_path_length);
prop->max_char_angle_delta = util::apply_visitor(extract_value<value_double>(feature,attrs), text_prop.expressions.max_char_angle_delta) * M_PI/180;
prop->max_char_angle_delta = util::radians(util::apply_visitor(extract_value<value_double>(feature,attrs), text_prop.expressions.max_char_angle_delta));
prop->allow_overlap = util::apply_visitor(extract_value<value_bool>(feature,attrs), text_prop.expressions.allow_overlap);
prop->largest_bbox_only = util::apply_visitor(extract_value<value_bool>(feature,attrs), text_prop.expressions.largest_bbox_only);
prop->upright = util::apply_visitor(extract_value<text_upright_enum>(feature,attrs), text_prop.expressions.upright);

View file

@ -20,7 +20,7 @@
*
*****************************************************************************/
// mapnik
#include <mapnik/global.hpp>
#include <mapnik/util/math.hpp>
#include <mapnik/vertex_cache.hpp>
#include <mapnik/offset_converter.hpp>
#include <mapnik/make_unique.hpp>
@ -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()

View file

@ -30,8 +30,18 @@
#include <boost/optional.hpp>
#pragma GCC diagnostic pop
// stl
#include <cmath>
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<bool> 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<geometry::point<double>> & 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<geometry::point<double>> & ls)
{
for (auto & p : ls)
{
merc2lonlat(p.x, p.y);
}
return true;
}
}

View file

@ -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 <<END
// 170.142139 -43.595056
// 175.566667 -39.283333
// END
//
// 170.142139 -43.595056 18940136.2759583741 -5402988.5324898539
// 175.566667 -39.283333 19543991.9707122259 -4762338.2380718365
//
mapnik::geometry::point<double> 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 <<END
// 170.142139 -43.595056
// 175.566667 -39.283333
// END
//
// 170.142139 -43.595056 1369316.0970041484 5169132.9750701785
// 175.566667 -39.283333 1821377.9170061364 5648640.2106032455
//
mapnik::geometry::point<double> 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
}
}

View file

@ -3,8 +3,8 @@
#include "fake_path.hpp"
// mapnik
#include <mapnik/util/math.hpp>
#include <mapnik/vertex_cache.hpp>
#include <mapnik/global.hpp>
// stl
#include <iostream>
@ -55,7 +55,7 @@ void test_offset_curve(double const &offset) {
std::vector<double> 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<double> 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));
}

View file

@ -4,6 +4,7 @@
// mapnik
#include <mapnik/offset_converter.hpp>
#include <mapnik/util/math.hpp>
// stl
#include <iostream>
@ -134,7 +135,7 @@ void test_offset_curve(double const &offset) {
std::vector<double> 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<double> 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));
}