[geometry] adapted transform strategies, they have points now as member-template, and calculation-type as template. Similar to what was done for Distane. This commit includes updated tests/doc/examples

[SVN r85325]
This commit is contained in:
Barend Gehrels 2013-08-12 21:22:53 +00:00
parent 17b54657fa
commit 018502c52c
10 changed files with 133 additions and 152 deletions

View File

@ -25,17 +25,17 @@ int main()
// Translate over (1.5, 1.5)
point_type p2;
trans::translate_transformer<point_type, point_type> translate(1.5, 1.5);
trans::translate_transformer<double, 2, 2> translate(1.5, 1.5);
boost::geometry::transform(p1, p2, translate);
// Scale with factor 3.0
point_type p3;
trans::scale_transformer<point_type, point_type> scale(3.0);
trans::scale_transformer<double, 2, 2> scale(3.0);
boost::geometry::transform(p1, p3, scale);
// Rotate with respect to the origin (0,0) over 90 degrees (clockwise)
point_type p4;
trans::rotate_transformer<point_type, point_type, boost::geometry::degree> rotate(90.0);
trans::rotate_transformer<boost::geometry::degree, double, 2, 2> rotate(90.0);
boost::geometry::transform(p1, p4, rotate);
std::cout

View File

@ -29,7 +29,7 @@ int main()
point_2d p2;
// Example: translate a point over (5,5)
strategy::transform::translate_transformer<point_2d, point_2d> translate(5, 5);
strategy::transform::translate_transformer<double, 2, 2> translate(5, 5);
transform(p, p2, translate);
std::cout << "transformed point " << boost::geometry::dsv(p2) << std::endl;

View File

@ -127,25 +127,25 @@ int main()
svg.put(g1, "g1");
// G1 - Translate -> G2
translate_transformer<point_2d, point_2d> translate(0, 250);
translate_transformer<double, 2, 2> translate(0, 250);
model::polygon<point_2d> g2;
transform(g1, g2, translate);
std::clog << "translated:\t" << boost::geometry::dsv(g2) << std::endl;
svg.put(g2, "g2=g1.translate(0,250)");
// G2 - Scale -> G3
scale_transformer<point_2d, point_2d> scale(0.5, 0.5);
scale_transformer<double, 2, 2> scale(0.5, 0.5);
model::polygon<point_2d> g3;
transform(g2, g3, scale);
std::clog << "scaled:\t" << boost::geometry::dsv(g3) << std::endl;
svg.put(g3, "g3=g2.scale(0.5,0.5)");
// G3 - Combine rotate and translate -> G4
rotate_transformer<point_2d, point_2d, degree> rotate(45);
rotate_transformer<degree, double, 2, 2> rotate(45);
// Compose matrix for the two transformation
// Create transformer attached to the transformation matrix
ublas_transformer<point_2d, point_2d, 2, 2>
ublas_transformer<double, 2, 2>
combined(boost::numeric::ublas::prod(rotate.matrix(), translate.matrix()));
//combined(rotate.matrix());

View File

@ -32,9 +32,9 @@ template<> struct cs_tag<cart_shifted5> { typedef cartesian_tag type; };
// 3: sample implementation of a shift
// to convert coordinate system "cart" to "cart_shirted5"
template <typename P1, typename P2>
struct shift
{
template <typename P1, typename P2>
inline bool apply(P1 const& p1, P2& p2) const
{
namespace bg = boost::geometry;
@ -52,7 +52,7 @@ namespace boost { namespace geometry { namespace strategy { namespace transform
template <typename P1, typename P2>
struct default_strategy<cartesian_tag, cartesian_tag, cart, cart_shifted5, 2, 2, P1, P2>
{
typedef shift<P1, P2> type;
typedef shift type;
};
}}}}} // namespaces

View File

@ -226,10 +226,17 @@ inline void svg_map(std::ostream& stream,
template <typename Point, bool SameScale = true>
class svg_mapper : boost::noncopyable
{
typedef typename geometry::select_most_precise
<
typename coordinate_type<Point>::type,
double
>::type calculation_type;
typedef strategy::transform::map_transformer
<
Point,
detail::svg::svg_point_type,
calculation_type,
geometry::dimension<Point>::type::value,
geometry::dimension<Point>::type::value,
true,
SameScale
> transformer_type;
@ -247,6 +254,7 @@ class svg_mapper : boost::noncopyable
m_matrix.reset(new transformer_type(m_bounding_box,
m_width, m_height));
m_stream << "<?xml version=\"1.0\" standalone=\"no\"?>"
<< std::endl
<< "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\""
@ -255,7 +263,10 @@ class svg_mapper : boost::noncopyable
<< std::endl
<< "<svg " << m_width_height << " version=\"1.1\""
<< std::endl
<< "xmlns=\"http://www.w3.org/2000/svg\">"
<< "xmlns=\"http://www.w3.org/2000/svg\""
<< std::endl
<< "xmlns:xlink=\"http://www.w3.org/1999/xlink\""
<< ">"
<< std::endl;
}
}
@ -319,18 +330,6 @@ public :
void map(Geometry const& geometry, std::string const& style,
int size = -1)
{
BOOST_MPL_ASSERT_MSG
(
( boost::is_same
<
Point,
typename point_type<Geometry>::type
>::value )
, POINT_TYPES_ARE_NOT_SAME_FOR_MAPPER_AND_MAP
, (types<Point, typename point_type<Geometry>::type>)
);
init_matrix();
svg_map(m_stream, style, size, geometry, *m_matrix);
}

View File

@ -33,20 +33,21 @@ namespace strategy { namespace transform
/*!
\brief Transformation strategy to do an inverse ransformation in Cartesian system
\ingroup strategies
\tparam P1 first point type
\tparam P2 second point type
*/
template <typename P1, typename P2>
template
<
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2
>
class inverse_transformer
: public ublas_transformer<P1, P2, dimension<P1>::type::value, dimension<P2>::type::value>
: public ublas_transformer<CalculationType, Dimension1, Dimension2>
{
typedef typename select_coordinate_type<P1, P2>::type T;
public :
template <typename Transformer>
inline inverse_transformer(Transformer const& input)
{
typedef boost::numeric::ublas::matrix<T> matrix_type;
typedef boost::numeric::ublas::matrix<CalculationType> matrix_type;
// create a working copy of the input
matrix_type copy(input.matrix());
@ -60,7 +61,7 @@ public :
if( res == 0 )
{
// create identity matrix
this->m_matrix.assign(boost::numeric::ublas::identity_matrix<T>(copy.size1()));
this->m_matrix.assign(boost::numeric::ublas::identity_matrix<CalculationType>(copy.size1()));
// backsubstitute to get the inverse
boost::numeric::ublas::lu_substitute(copy, pm, this->m_matrix);

View File

@ -34,23 +34,21 @@ namespace strategy { namespace transform
/*!
\brief Transformation strategy to do map from one to another Cartesian system
\ingroup strategies
\tparam P1 first point type
\tparam P2 second point type
\tparam Mirror if true map is mirrored upside-down (in most cases pixels
are from top to bottom, while map is from bottom to top)
*/
template
<
typename P1, typename P2,
bool Mirror = false, bool SameScale = true,
std::size_t Dimension1 = dimension<P1>::type::value,
std::size_t Dimension2 = dimension<P2>::type::value
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2,
bool Mirror = false,
bool SameScale = true
>
class map_transformer
: public ublas_transformer<P1, P2, Dimension1, Dimension2>
: public ublas_transformer<CalculationType, Dimension1, Dimension2>
{
typedef typename select_coordinate_type<P1, P2>::type T;
typedef boost::numeric::ublas::matrix<T> M;
typedef boost::numeric::ublas::matrix<CalculationType> M;
public :
template <typename B, typename D>

View File

@ -46,14 +46,12 @@ namespace strategy { namespace transform
\see http://en.wikipedia.org/wiki/Affine_transformation
and http://www.devmaster.net/wiki/Transformation_matrices
\ingroup strategies
\tparam P1 first point type (source)
\tparam P2 second point type (target)
\tparam Dimension1 number of dimensions to transform from first point
\tparam Dimension1 number of dimensions to transform to second point
\tparam Dimension1 number of dimensions to transform from
\tparam Dimension2 number of dimensions to transform to
*/
template
<
typename P1, typename P2,
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2
>
@ -62,13 +60,12 @@ class ublas_transformer
};
template <typename P1, typename P2>
class ublas_transformer<P1, P2, 2, 2>
template <typename CalculationType>
class ublas_transformer<CalculationType, 2, 2>
{
protected :
typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
typedef coordinate_type ct; // Abbreviation
typedef boost::numeric::ublas::matrix<coordinate_type> matrix_type;
typedef CalculationType ct;
typedef boost::numeric::ublas::matrix<ct> matrix_type;
matrix_type m_matrix;
public :
@ -91,17 +88,17 @@ public :
inline ublas_transformer() : m_matrix(3, 3) {}
template <typename P1, typename P2>
inline bool apply(P1 const& p1, P2& p2) const
{
assert_dimension_greater_equal<P1, 2>();
assert_dimension_greater_equal<P2, 2>();
coordinate_type const& c1 = get<0>(p1);
coordinate_type const& c2 = get<1>(p1);
ct const& c1 = get<0>(p1);
ct const& c2 = get<1>(p1);
coordinate_type p2x = c1 * m_matrix(0,0) + c2 * m_matrix(0,1) + m_matrix(0,2);
coordinate_type p2y = c1 * m_matrix(1,0) + c2 * m_matrix(1,1) + m_matrix(1,2);
ct p2x = c1 * m_matrix(0,0) + c2 * m_matrix(0,1) + m_matrix(0,2);
ct p2y = c1 * m_matrix(1,0) + c2 * m_matrix(1,1) + m_matrix(1,2);
typedef typename geometry::coordinate_type<P2>::type ct2;
set<0>(p2, boost::numeric_cast<ct2>(p2x));
@ -115,36 +112,34 @@ public :
// It IS possible to go from 3 to 2 coordinates
template <typename P1, typename P2>
class ublas_transformer<P1, P2, 3, 2> : public ublas_transformer<P1, P2, 2, 2>
template <typename CalculationType>
class ublas_transformer<CalculationType, 3, 2> : public ublas_transformer<CalculationType, 2, 2>
{
typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
typedef coordinate_type ct; // Abbreviation
typedef CalculationType ct;
public :
inline ublas_transformer(
ct const& m_0_0, ct const& m_0_1, ct const& m_0_2,
ct const& m_1_0, ct const& m_1_1, ct const& m_1_2,
ct const& m_2_0, ct const& m_2_1, ct const& m_2_2)
: ublas_transformer<P1, P2, 2, 2>(
: ublas_transformer<CalculationType, 2, 2>(
m_0_0, m_0_1, m_0_2,
m_1_0, m_1_1, m_1_2,
m_2_0, m_2_1, m_2_2)
{}
inline ublas_transformer()
: ublas_transformer<P1, P2, 2, 2>()
: ublas_transformer<CalculationType, 2, 2>()
{}
};
template <typename P1, typename P2>
class ublas_transformer<P1, P2, 3, 3>
template <typename CalculationType>
class ublas_transformer<CalculationType, 3, 3>
{
protected :
typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
typedef coordinate_type ct; // Abbreviation
typedef boost::numeric::ublas::matrix<coordinate_type> matrix_type;
typedef CalculationType ct;
typedef boost::numeric::ublas::matrix<ct> matrix_type;
matrix_type m_matrix;
public :
@ -164,11 +159,12 @@ public :
inline ublas_transformer() : m_matrix(4, 4) {}
template <typename P1, typename P2>
inline bool apply(P1 const& p1, P2& p2) const
{
coordinate_type const& c1 = get<0>(p1);
coordinate_type const& c2 = get<1>(p1);
coordinate_type const& c3 = get<2>(p1);
ct const& c1 = get<0>(p1);
ct const& c2 = get<1>(p1);
ct const& c3 = get<2>(p1);
typedef typename geometry::coordinate_type<P2>::type ct2;
@ -191,34 +187,30 @@ public :
\details Translate moves a geometry a fixed distance in 2 or 3 dimensions.
\see http://en.wikipedia.org/wiki/Translation_%28geometry%29
\ingroup strategies
\tparam P1 first point type
\tparam P2 second point type
\tparam Dimension1 number of dimensions to transform from first point
\tparam Dimension1 number of dimensions to transform to second point
\tparam Dimension1 number of dimensions to transform from
\tparam Dimension2 number of dimensions to transform to
*/
template
<
typename P1, typename P2,
std::size_t Dimension1 = geometry::dimension<P1>::type::value,
std::size_t Dimension2 = geometry::dimension<P2>::type::value
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2
>
class translate_transformer
{
};
template <typename P1, typename P2>
class translate_transformer<P1, P2, 2, 2> : public ublas_transformer<P1, P2, 2, 2>
template<typename CalculationType>
class translate_transformer<CalculationType, 2, 2> : public ublas_transformer<CalculationType, 2, 2>
{
typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
public :
// To have translate transformers compatible for 2/3 dimensions, the
// constructor takes an optional third argument doing nothing.
inline translate_transformer(coordinate_type const& translate_x,
coordinate_type const& translate_y,
coordinate_type const& = 0)
: ublas_transformer<P1, P2, 2, 2>(
inline translate_transformer(CalculationType const& translate_x,
CalculationType const& translate_y,
CalculationType const& = 0)
: ublas_transformer<CalculationType, 2, 2>(
1, 0, translate_x,
0, 1, translate_y,
0, 0, 1)
@ -226,16 +218,14 @@ public :
};
template <typename P1, typename P2>
class translate_transformer<P1, P2, 3, 3> : public ublas_transformer<P1, P2, 3, 3>
template <typename CalculationType>
class translate_transformer<CalculationType, 3, 3> : public ublas_transformer<CalculationType, 3, 3>
{
typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
public :
inline translate_transformer(coordinate_type const& translate_x,
coordinate_type const& translate_y,
coordinate_type const& translate_z)
: ublas_transformer<P1, P2, 3, 3>(
inline translate_transformer(CalculationType const& translate_x,
CalculationType const& translate_y,
CalculationType const& translate_z)
: ublas_transformer<CalculationType, 3, 3>(
1, 0, 0, translate_x,
0, 1, 0, translate_y,
0, 0, 1, translate_z,
@ -250,40 +240,37 @@ public :
\details Scale scales a geometry up or down in all its dimensions.
\see http://en.wikipedia.org/wiki/Scaling_%28geometry%29
\ingroup strategies
\tparam P1 first point type
\tparam P2 second point type
\tparam Dimension1 number of dimensions to transform from first point
\tparam Dimension1 number of dimensions to transform to second point
\tparam Dimension1 number of dimensions to transform from
\tparam Dimension2 number of dimensions to transform to
*/
template
<
typename P1, typename P2 = P1,
std::size_t Dimension1 = geometry::dimension<P1>::type::value,
std::size_t Dimension2 = geometry::dimension<P2>::type::value
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2
>
class scale_transformer
{
};
template <typename P1, typename P2>
class scale_transformer<P1, P2, 2, 2> : public ublas_transformer<P1, P2, 2, 2>
template <typename CalculationType>
class scale_transformer<CalculationType, 2, 2> : public ublas_transformer<CalculationType, 2, 2>
{
typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
public :
inline scale_transformer(coordinate_type const& scale_x,
coordinate_type const& scale_y,
coordinate_type const& = 0)
: ublas_transformer<P1, P2, 2, 2>(
inline scale_transformer(CalculationType const& scale_x,
CalculationType const& scale_y,
CalculationType const& = 0)
: ublas_transformer<CalculationType, 2, 2>(
scale_x, 0, 0,
0, scale_y, 0,
0, 0, 1)
{}
inline scale_transformer(coordinate_type const& scale)
: ublas_transformer<P1, P2, 2, 2>(
inline scale_transformer(CalculationType const& scale)
: ublas_transformer<CalculationType, 2, 2>(
scale, 0, 0,
0, scale, 0,
0, 0, 1)
@ -291,16 +278,14 @@ public :
};
template <typename P1, typename P2>
class scale_transformer<P1, P2, 3, 3> : public ublas_transformer<P1, P2, 3, 3>
template <typename CalculationType>
class scale_transformer<CalculationType, 3, 3> : public ublas_transformer<CalculationType, 3, 3>
{
typedef typename select_coordinate_type<P1, P2>::type coordinate_type;
public :
inline scale_transformer(coordinate_type const& scale_x,
coordinate_type const& scale_y,
coordinate_type const& scale_z)
: ublas_transformer<P1, P2, 3, 3>(
inline scale_transformer(CalculationType const& scale_x,
CalculationType const& scale_y,
CalculationType const& scale_z)
: ublas_transformer<CalculationType, 3, 3>(
scale_x, 0, 0, 0,
0, scale_y, 0, 0,
0, 0, scale_z, 0,
@ -308,8 +293,8 @@ public :
{}
inline scale_transformer(coordinate_type const& scale)
: ublas_transformer<P1, P2, 3, 3>(
inline scale_transformer(CalculationType const& scale)
: ublas_transformer<CalculationType, 3, 3>(
scale, 0, 0, 0,
0, scale, 0, 0,
0, 0, scale, 0,
@ -352,23 +337,16 @@ struct as_radian<degree>
template
<
typename P1, typename P2,
std::size_t Dimension1 = geometry::dimension<P1>::type::value,
std::size_t Dimension2 = geometry::dimension<P2>::type::value
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2
>
class rad_rotate_transformer
: public ublas_transformer<P1, P2, Dimension1, Dimension2>
: public ublas_transformer<CalculationType, Dimension1, Dimension2>
{
// Angle has type of coordinate type, but at least a double
typedef typename select_most_precise
<
typename select_coordinate_type<P1, P2>::type,
double
>::type angle_type;
public :
inline rad_rotate_transformer(angle_type const& angle)
: ublas_transformer<P1, P2, Dimension1, Dimension2>(
inline rad_rotate_transformer(CalculationType const& angle)
: ublas_transformer<CalculationType, Dimension1, Dimension2>(
cos(angle), sin(angle), 0,
-sin(angle), cos(angle), 0,
0, 0, 1)
@ -385,29 +363,27 @@ public :
\details Rotate rotates a geometry of specified angle about a fixed point (e.g. origin).
\see http://en.wikipedia.org/wiki/Rotation_%28mathematics%29
\ingroup strategies
\tparam P1 first point type
\tparam P2 second point type
\tparam DegreeOrRadian degree/or/radian, type of rotation angle specification
\note A single angle is needed to specify a rotation in 2D.
Not yet in 3D, the 3D version requires special things to allow
for rotation around X, Y, Z or arbitrary axis.
\todo The 3D version will not compile.
*/
template <typename P1, typename P2, typename DegreeOrRadian>
class rotate_transformer : public detail::rad_rotate_transformer<P1, P2>
template
<
typename DegreeOrRadian,
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2
>
class rotate_transformer : public detail::rad_rotate_transformer<CalculationType, Dimension1, Dimension2>
{
// Angle has type of coordinate type, but at least a double
typedef typename select_most_precise
<
typename select_coordinate_type<P1, P2>::type,
double
>::type angle_type;
public :
inline rotate_transformer(angle_type const& angle)
inline rotate_transformer(CalculationType const& angle)
: detail::rad_rotate_transformer
<
P1, P2
CalculationType, Dimension1, Dimension2
>(detail::as_radian<DegreeOrRadian>::get(angle))
{}
};

View File

@ -39,12 +39,13 @@
template <typename Geometry>
void test_transform(std::string const& wkt, std::string const& expected)
{
typedef typename bg::point_type<Geometry>::type point_type;
typedef typename bg::coordinate_type<Geometry>::type coordinate_type;
const std::size_t dim = bg::dimension<Geometry>::value;
Geometry geometry_in, geometry_out;
bg::read_wkt(wkt, geometry_in);
bg::transform(geometry_in, geometry_out,
bg::strategy::transform::scale_transformer<point_type>(2, 2));
bg::strategy::transform::scale_transformer<coordinate_type, dim, dim>(2, 2));
std::ostringstream detected;
detected << bg::wkt(geometry_out);
BOOST_CHECK_EQUAL(detected.str(), expected);

View File

@ -34,7 +34,10 @@ BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)
template <typename P, typename T>
void check_inverse(P const& p, T const& trans)
{
bg::strategy::transform::inverse_transformer<P, P> inverse(trans);
typedef typename bg::coordinate_type<P>::type coordinate_type;
const std::size_t dim = bg::dimension<P>::value;
bg::strategy::transform::inverse_transformer<coordinate_type, dim, dim> inverse(trans);
P i;
bg::transform(p, i, inverse);
@ -46,11 +49,14 @@ void check_inverse(P const& p, T const& trans)
template <typename P>
void test_all()
{
typedef typename bg::coordinate_type<P>::type coordinate_type;
const std::size_t dim = bg::dimension<P>::value;
P p;
bg::assign_values(p, 1, 1);
{
bg::strategy::transform::translate_transformer<P, P> trans(1, 1);
bg::strategy::transform::translate_transformer<coordinate_type, dim, dim> trans(1, 1);
P tp;
bg::transform(p, tp, trans);
@ -61,7 +67,7 @@ void test_all()
}
{
bg::strategy::transform::scale_transformer<P, P> trans(10, 10);
bg::strategy::transform::scale_transformer<coordinate_type, dim, dim> trans(10, 10);
P tp;
bg::transform(p, tp, trans);
@ -72,7 +78,7 @@ void test_all()
}
{
bg::strategy::transform::rotate_transformer<P, P, bg::degree> trans(90.0);
bg::strategy::transform::rotate_transformer<bg::degree, double, dim, dim> trans(90.0);
P tp;
bg::transform(p, tp, trans);
@ -83,7 +89,7 @@ void test_all()
{
// Map from 0,0,2,2 to 0,0,500,500
bg::strategy::transform::map_transformer<P, P, false> trans
bg::strategy::transform::map_transformer<coordinate_type, dim, dim, false> trans
(
0.0, 0.0, 2.0, 2.0, 500, 500
);