Steven said:
Nothing wrong with creating a new class to perform an operation which can
easily be done in one line of code, and not even eliminating the original
line of code? There are times when it makes sense to use a visitor pattern
with function objects, but there are also many times when it serves no
other purpose than the complicate the code.
Yeah!
Hows about this. Grabs fixed size arrays and turns them into containers
and does compile time loop unrolling ;-)
(Uses later version of my Quan lib which I havent got round to updating
on sourceforge for a while... whatever)
Can also work on arbitrary transform matrices of course, but lets keep
it simple...
#include <quan/two_d/out/vect.hpp>
#include <quan/out/angle.hpp>
#include <quan_matters/src/constant.cpp>
#include <quan_matters/src/angle.cpp>
#include <quan/out/length.hpp>
#include <algorithm>
#include <vector>
#include <boost/static_assert.hpp>
#include <iterator>
// class to adapt a static array ( ar[N])
// for use as a container
// inpired by a recent post on comp.lang.c++.moderated
// who I will be happy to acknowledge
// if I can find it
template <typename T,int N>
class array_wrapper{
T * data_ ;
public:
const static std::size_t size = N;
array_wrapper(T (&a) [N]): data_(a){}
typedef T * iterator;
typedef T const * const_iterator;
iterator begin() {return data_;}
const_iterator begin()const {return data_;}
iterator end() {return data_ + N;}
const_iterator end()const {return data_ + N;}
template<int N1>
T& at(){ return data_[N1];}
T const & at()const{ return data_[N1];}
};
// compile time loop unrolling impl
template <int N>
struct for_x_in_wrapper;
template <>
struct for_x_in_wrapper<0>{
template <typename ArrayWrapper, typename F>
void operator()(ArrayWrapper& a, F const & f)const
{
f(a.at<0>());
}
};
template <int N>
struct for_x_in_wrapper{
template<typename ArrayWrapper, typename F>
void operator()(ArrayWrapper& a, F const & f)const
{
BOOST_STATIC_ASSERT(( ArrayWrapper::size >= N ) );
for_x_in_wrapper<N-1> prev;
prev(a,f);
f(a.at<N>());
}
};
template <typename T,int N,typename F>
void for_each(array_wrapper<T,N> & ar,F const & f)
{
for_x_in_wrapper<N-1> ff;
ff(ar,f);
}
template <typename T,int N,typename F>
void for_each(T (&ar)[N],F const & f)
{
array_wrapper<T,N> arw(ar);
for_each(arw,f);
}
// functor to rotate a vector
// calls sin, cos once irrespective of
// number of vertices
struct rotate{
rotate(double const & angle)
: cos_theta (std::cos(angle)), sin_theta(std::sin(angle)){}
double cos_theta, sin_theta;
template <typename Vect>
Vect & operator()(Vect & in)const
{
in = in * cos_theta + perp_vector(in) * sin_theta;
return in;
}
};
// functor to translate a vector
template <typename T>
struct translate{
translate(quan::two_d::vect<T> const & trans_in)
: trans(trans_in){}
quan::two_d::vect<T> trans;
template <typename Vect>
Vect & operator()(Vect & in)const
{
return in += trans;
}
};
// combine above
template <typename T>
struct point_rotate{
translate<T> to_origin;
rotate do_rotate;
translate<T> from_origin;
point_rotate(quan::two_d::vect<T> const & translation,double angle)
:
to_origin(-translation),do_rotate(angle),from_origin(translation){}
template <typename Vect>
void operator()(Vect & in)const
{
to_origin(in);
do_rotate(in);
from_origin(in);
}
};
// rotate_by_point adaptor for static arrays
template <typename T, int N, typename Point,typename Angle>
void rotate_by_point(T (&ar)[N], Point const & point, Angle const &
angle)
{
array_wrapper<T,N> arw(ar);
for_each(arw,point_rotate<typename Point::value_type>(point,angle));
}
struct output{
std:
![Eek! :eek: :eek:](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
stream & os;
output(std:
![Eek! :eek: :eek:](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
stream & os_in)
![Eek! :eek: :eek:](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
s(os_in){}
template <typename T>
void operator()(T const & t)const
{
os << t <<'\n';
}
};
int main()
{
std::cout.setf(std::ios_base::fixed,std::ios_base::floatfield);
std::cout.precision(2);
typedef double d;
std::cout << "using 2d vects of doubles\n";
quan::angle::rad angle = quan::angle:
![Stick Out Tongue :p :p](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
i/2;
using quan::two_d::vect;
vect<d> box[] = {
vect<d>(0,0),
vect<d>(1,0),
vect<d>(1,1),
vect<d>(0,1)
};
for_each(box,output(std::cout));
vect<d> point(2,0);
std::cout << "rotation angle = " << quan::angle::deg(angle) <<'\n';
std::cout << "rotation point = " << point <<'\n';
rotate_by_point(box,point,angle);
for_each(box,output(std::cout));
// works for any type of points...
std::cout << "\n Now using 2d vects of length::mm\n";
typedef quan::length::mm mm;
vect<mm> box_mm[] = {
vect<mm>(mm(0),mm(0)),
vect<mm>(mm(1),mm(0)),
vect<mm>(mm(1),mm(1)),
vect<mm>(mm(0),mm(1))
};
for_each(box_mm,output(std::cout));
vect<mm> point_mm(mm(1),mm(1));
std::cout << "rotation angle = " << quan::angle::deg(angle) <<'\n';
std::cout << "rotation point = " << point_mm <<'\n';
rotate_by_point(box_mm,point_mm,quan::angle:
![Stick Out Tongue :p :p](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
i/2);
for_each(box_mm,output(std::cout));
return 0;
}
output:
using 2d vects of doubles
[0.00, 0.00]
[1.00, 0.00]
[1.00, 1.00]
[0.00, 1.00]
rotation angle = 90.00 deg
rotation point = [2.00, 0.00]
[2.00, -2.00]
[2.00, -1.00]
[1.00, -1.00]
[1.00, -2.00]
Now using 2d vects of length::mm
[0.00 mm, 0.00 mm]
[1.00 mm, 0.00 mm]
[1.00 mm, 1.00 mm]
[0.00 mm, 1.00 mm]
rotation angle = 90.00 deg
rotation point = [1.00 mm, 1.00 mm]
[2.00 mm, 0.00 mm]
[2.00 mm, 1.00 mm]
[1.00 mm, 1.00 mm]
[1.00 mm, 0.00 mm]
regards
Andy Little