X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;ds=sidebyside;f=source%2Fgeometry%2Faffinetransform.h;fp=source%2Fgeometry%2Faffinetransform.h;h=1cd40119a04d8c211c1313486641b1320990e0b2;hb=d0534789125d5ef8c44743b1fd9eaff21b9e7e0d;hp=0000000000000000000000000000000000000000;hpb=60caa19c84877c89d750140a90e5d891bce30ee7;p=libs%2Fmath.git diff --git a/source/geometry/affinetransform.h b/source/geometry/affinetransform.h new file mode 100644 index 0000000..1cd4011 --- /dev/null +++ b/source/geometry/affinetransform.h @@ -0,0 +1,228 @@ +#ifndef MSP_GEOMETRY_AFFINETRANSFORM_H_ +#define MSP_GEOMETRY_AFFINETRANSFORM_H_ + +#include +#include "angle.h" +#include "boundingbox.h" +#include "ray.h" + +namespace Msp { +namespace Geometry { + +template +class AffineTransform; + + +/** +Helper class to provide specialized operations for AffineTransform. +*/ +template +class AffineTransformOps +{ +protected: + AffineTransformOps() { } +}; + +template +class AffineTransformOps +{ +protected: + AffineTransformOps() { } + +public: + static AffineTransform rotation(const Angle &); +}; + +template +class AffineTransformOps +{ +protected: + AffineTransformOps() { } + +public: + static AffineTransform rotation(const Angle &, const LinAl::Vector &); +}; + + +/** +An affine transformation in D dimensions. Affine transformations preserve +straightness of lines and ratios of distances. Angles and distances themselves +may change. Internally this is represented by a square matrix of size D+1. +*/ +template +class AffineTransform: public AffineTransformOps +{ + friend class AffineTransformOps; + +private: + LinAl::Matrix matrix; + +public: + AffineTransform(); + + static AffineTransform translation(const LinAl::Vector &); + static AffineTransform scaling(const LinAl::Vector &); + static AffineTransform shear(const LinAl::Vector &, const LinAl::Vector &); + + AffineTransform &operator*=(const AffineTransform &); + AffineTransform &invert(); + + const LinAl::Matrix &get_matrix() const { return matrix; } + operator const LinAl::Matrix &() const { return matrix; } + + LinAl::Vector transform(const LinAl::Vector &) const; + LinAl::Vector transform_linear(const LinAl::Vector &) const; + Ray transform(const Ray &) const; + BoundingBox transform(const BoundingBox &) const; +}; + +template +inline AffineTransform::AffineTransform() +{ + this->matrix = LinAl::Matrix::identity(); +} + + +template +AffineTransform AffineTransform::translation(const LinAl::Vector &v) +{ + AffineTransform r; + for(unsigned i=0; i +AffineTransform AffineTransform::scaling(const LinAl::Vector &factors) +{ + AffineTransform r; + for(unsigned i=0; i +AffineTransform AffineTransform::shear(const LinAl::Vector &normal, const LinAl::Vector &shift) +{ + AffineTransform r; + for(unsigned i=0; i +AffineTransform AffineTransformOps::rotation(const Angle &angle) +{ + AffineTransform r; + T c = cos(angle); + T s = sin(angle); + r.matrix(0, 0) = c; + r.matrix(0, 1) = -s; + r.matrix(1, 0) = s; + r.matrix(1, 1) = c; + return r; +} + +template +AffineTransform AffineTransformOps::rotation(const Angle &angle, const LinAl::Vector &axis) +{ + AffineTransform r; + LinAl::Vector axn = normalize(axis); + T c = cos(angle); + T s = sin(angle); + // http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle + r.matrix(0, 0) = c+axn.x*axn.x*(1-c); + r.matrix(0, 1) = axn.x*axn.y*(1-c)-axn.z*s; + r.matrix(0, 2) = axn.x*axn.z*(1-c)+axn.y*s; + r.matrix(1, 0) = axn.y*axn.x*(1-c)+axn.z*s; + r.matrix(1, 1) = c+axn.y*axn.y*(1-c); + r.matrix(1, 2) = axn.y*axn.z*(1-c)-axn.x*s; + r.matrix(2, 0) = axn.z*axn.x*(1-c)-axn.y*s; + r.matrix(2, 1) = axn.z*axn.y*(1-c)+axn.x*s; + r.matrix(2, 2) = c+axn.z*axn.z*(1-c); + return r; +} + +template +inline AffineTransform &AffineTransform::operator*=(const AffineTransform &other) +{ + matrix *= other.get_matrix(); + return *this; +} + +template +inline AffineTransform operator*(const AffineTransform &at1, const AffineTransform &at2) +{ + AffineTransform r = at1; + return r *= at2; +} + +template +inline AffineTransform &AffineTransform::invert() +{ + matrix.invert(); + return *this; +} + +template +inline AffineTransform invert(const AffineTransform &at) +{ + AffineTransform r = at; + return r.invert(); +} + +template +inline LinAl::Vector AffineTransform::transform(const LinAl::Vector &v) const +{ + return (matrix*compose(v, T(1))).template slice(0); +} + +template +inline LinAl::Vector AffineTransform::transform_linear(const LinAl::Vector &v) const +{ + return (matrix*compose(v, T(0))).template slice(0); +} + +template +inline Ray AffineTransform::transform(const Ray &ray) const +{ + LinAl::Vector dir = transform_linear(ray.get_direction()); + return Ray(transform(ray.get_start()), dir, ray.get_limit()*dir.norm()); +} + +template +inline BoundingBox AffineTransform::transform(const BoundingBox &bbox) const +{ + LinAl::Vector min_pt; + LinAl::Vector max_pt; + for(unsigned i=0; i<(1< point; + for(unsigned j=0; j>j)&1 ? bbox.get_maximum_coordinate(j) : bbox.get_minimum_coordinate(j)); + + point = transform(point); + + if(i==0) + { + min_pt = point; + max_pt = point; + } + else + { + for(unsigned j=0; j(min_pt, max_pt); +} + +} // namespace Geometry +} // namespace Msp + +#endif