--- /dev/null
+#ifndef MSP_GEOMETRY_LOADER_H_
+#define MSP_GEOMETRY_LOADER_H_
+
+#include <list>
+#include <msp/datafile/loader.h>
+#include "extrudedshape.h"
+#include "halfspace.h"
+#include "hyperbox.h"
+#include "hypersphere.h"
+#include "intersection.h"
+#include "negation.h"
+#include "shape.h"
+#include "transformedshape.h"
+#include "union.h"
+
+namespace Msp {
+namespace Geometry {
+
+template<typename T, unsigned D>
+class DimensionIndependentLoader: public DataFile::Loader
+{
+protected:
+ bool single;
+ std::list<Shape<T, D> *> shapes;
+
+ DimensionIndependentLoader(bool = true);
+public:
+ virtual ~DimensionIndependentLoader();
+
+ const Shape<T, D> &get_shape() const;
+
+protected:
+ template<typename S>
+ void shape();
+};
+
+
+template<typename T, unsigned D, bool = (D>1)>
+class Loader;
+
+template<typename T, unsigned D>
+class Loader<T, D, false>: public DimensionIndependentLoader<T, D>
+{
+public:
+ Loader(bool = true);
+};
+
+template<typename T, unsigned D>
+class Loader<T, D, true>: public DimensionIndependentLoader<T, D>
+{
+public:
+ Loader(bool = true);
+};
+
+
+template<typename S>
+class ShapeLoader;
+
+template<typename T, unsigned D>
+class ShapeLoader<ExtrudedShape<T, D> >: public Loader<T, D-1>
+{
+private:
+ T length_;
+
+public:
+ ShapeLoader();
+
+ ExtrudedShape<T, D> *create() const;
+
+private:
+ void length(T);
+};
+
+template<typename T, unsigned D>
+class ShapeLoader<HalfSpace<T, D> >: public DataFile::Loader
+{
+private:
+ LinAl::Vector<T, D> normal_;
+
+public:
+ ShapeLoader();
+
+ HalfSpace<T, D> *create() const;
+
+private:
+ void normal(const std::vector<T> &);
+};
+
+template<typename T, unsigned D>
+class ShapeLoader<HyperBox<T, D> >: public DataFile::Loader
+{
+private:
+ LinAl::Vector<T, D> dimensions_;
+
+public:
+ ShapeLoader();
+
+ HyperBox<T, D> *create() const;
+
+private:
+ void dimensions(const std::vector<T> &);
+};
+
+template<typename T, unsigned D>
+class ShapeLoader<HyperSphere<T, D> >: public DataFile::Loader
+{
+private:
+ T radius_;
+
+public:
+ ShapeLoader();
+
+ HyperSphere<T, D> *create() const;
+
+private:
+ void radius(T);
+};
+
+template<typename T, unsigned D, typename S>
+class CompositeLoader: public Loader<T, D>
+{
+public:
+ CompositeLoader();
+
+ S *create() const;
+};
+
+template<typename T, unsigned D>
+class ShapeLoader<Intersection<T, D> >: public CompositeLoader<T, D, Intersection<T, D> >
+{ };
+
+template<typename T, unsigned D>
+class ShapeLoader<Negation<T, D> >: public Loader<T, D>
+{
+public:
+ Negation<T, D> *create() const;
+};
+
+template<typename T, unsigned D>
+class TransformationLoader: public Loader<T, D>
+{
+protected:
+ AffineTransformation<T, D> transformation;
+
+public:
+ TransformationLoader();
+
+ TransformedShape<T, D> *create() const;
+
+ void translate(const std::vector<T> &);
+ void scale(const std::vector<T> &);
+ void shear(const std::vector<T> &);
+};
+
+template<typename T, unsigned D>
+class ShapeLoader<TransformedShape<T, D> >: public TransformationLoader<T, D>
+{ };
+
+template<typename T>
+class ShapeLoader<TransformedShape<T, 2> >: public TransformationLoader<T, 2>
+{
+public:
+ ShapeLoader();
+
+ void rotate(T);
+};
+
+template<typename T>
+class ShapeLoader<TransformedShape<T, 3> >: public TransformationLoader<T, 3>
+{
+public:
+ ShapeLoader();
+
+ void rotate(T, T, T, T);
+};
+
+template<typename T, unsigned D>
+class ShapeLoader<Union<T, D> >: public CompositeLoader<T, D, Union<T, D> >
+{ };
+
+
+template<typename T, unsigned D>
+inline DimensionIndependentLoader<T, D>::DimensionIndependentLoader(bool s):
+ single(s)
+{
+ add("box", &DimensionIndependentLoader::shape<HyperBox<T, D> >);
+ add("halfspace", &DimensionIndependentLoader::shape<HalfSpace<T, D> >);
+ add("intersection", &DimensionIndependentLoader::shape<Intersection<T, D> >);
+ add("negation", &DimensionIndependentLoader::shape<Negation<T, D> >);
+ add("sphere", &DimensionIndependentLoader::shape<HyperSphere<T, D> >);
+ add("transformed", &DimensionIndependentLoader::shape<TransformedShape<T, D> >);
+ add("union", &DimensionIndependentLoader::shape<Union<T, D> >);
+}
+
+template<typename T, unsigned D>
+inline DimensionIndependentLoader<T, D>::~DimensionIndependentLoader()
+{
+ for(typename std::list<Shape<T, D> *>::iterator i=shapes.begin(); i!=shapes.end(); ++i)
+ delete *i;
+}
+
+template<typename T, unsigned D>
+inline const Shape<T, D> &DimensionIndependentLoader<T, D>::get_shape() const
+{
+ if(shapes.empty())
+ throw std::runtime_error("no shape");
+ return *shapes.front();
+}
+
+template<typename T, unsigned D>
+template<typename S>
+inline void DimensionIndependentLoader<T, D>::shape()
+{
+ if(single && !shapes.empty())
+ throw std::runtime_error("shape already loaded");
+
+ ShapeLoader<S> ldr;
+ load_sub_with(ldr);
+ shapes.push_back(ldr.create());
+}
+
+
+template<typename T, unsigned D>
+inline Loader<T, D, false>::Loader(bool s):
+ DimensionIndependentLoader<T, D>(s)
+{ }
+
+template<typename T, unsigned D>
+inline Loader<T, D, true>::Loader(bool s):
+ DimensionIndependentLoader<T, D>(s)
+{
+ this->add("extruded", &DimensionIndependentLoader<T, D>::template shape<ExtrudedShape<T, D> >);
+}
+
+
+template<typename T, unsigned D>
+inline ShapeLoader<ExtrudedShape<T, D> >::ShapeLoader():
+ length_(T(1))
+{
+ this->add("length", &ShapeLoader::length);
+}
+
+template<typename T, unsigned D>
+inline ExtrudedShape<T, D> *ShapeLoader<ExtrudedShape<T, D> >::create() const
+{
+ return new ExtrudedShape<T, D>(*this->shapes.front(), length_);
+}
+
+template<typename T, unsigned D>
+inline void ShapeLoader<ExtrudedShape<T, D> >::length(T l)
+{
+ length_ = l;
+}
+
+
+template<typename T, unsigned D>
+inline ShapeLoader<HalfSpace<T, D> >::ShapeLoader()
+{
+ normal_[D-1] = T(1);
+
+ add("normal", &ShapeLoader::normal);
+}
+
+template<typename T, unsigned D>
+inline HalfSpace<T, D> *ShapeLoader<HalfSpace<T, D> >::create() const
+{
+ return new HalfSpace<T, D>(normal_);
+}
+
+template<typename T, unsigned D>
+inline void ShapeLoader<HalfSpace<T, D> >::normal(const std::vector<T> &d)
+{
+ if(d.size()!=D)
+ throw std::invalid_argument("ShapeLoader<HalfSpace>::normal");
+
+ normal_ = LinAl::Vector<T, D>(&d[0]);
+}
+
+
+template<typename T, unsigned D>
+inline ShapeLoader<HyperBox<T, D> >::ShapeLoader()
+{
+ for(unsigned i=0; i<D; ++i)
+ dimensions_[i] = T(1);
+
+ add("dimensions", &ShapeLoader::dimensions);
+}
+
+template<typename T, unsigned D>
+inline HyperBox<T, D> *ShapeLoader<HyperBox<T, D> >::create() const
+{
+ return new HyperBox<T, D>(dimensions_);
+}
+
+template<typename T, unsigned D>
+inline void ShapeLoader<HyperBox<T, D> >::dimensions(const std::vector<T> &d)
+{
+ if(d.size()!=D)
+ throw std::invalid_argument("ShapeLoader<HyperBox>::dimensions");
+
+ dimensions_ = LinAl::Vector<T, D>(&d[0]);
+}
+
+
+template<typename T, unsigned D>
+inline ShapeLoader<HyperSphere<T, D> >::ShapeLoader():
+ radius_(T(1))
+{
+ add("radius", &ShapeLoader::radius);
+}
+
+template<typename T, unsigned D>
+inline HyperSphere<T, D> *ShapeLoader<HyperSphere<T, D> >::create() const
+{
+ return new HyperSphere<T, D>(radius_);
+}
+
+template<typename T, unsigned D>
+inline void ShapeLoader<HyperSphere<T, D> >::radius(T r)
+{
+ radius_ = r;
+}
+
+
+template<typename T, unsigned D>
+inline Negation<T, D> *ShapeLoader<Negation<T, D> >::create() const
+{
+ return new Negation<T, D>(*this->shapes.front());
+}
+
+
+template<typename T, unsigned D>
+inline TransformationLoader<T, D>::TransformationLoader()
+{
+ this->add("translate", &TransformationLoader::translate);
+ this->add("scale", &TransformationLoader::scale);
+ this->add("shear", &TransformationLoader::shear);
+}
+
+template<typename T, unsigned D>
+inline TransformedShape<T, D> *TransformationLoader<T, D>::create() const
+{
+ return new TransformedShape<T, D>(*this->shapes.front(), transformation);
+}
+
+template<typename T, unsigned D>
+inline void TransformationLoader<T, D>::translate(const std::vector<T> &offset)
+{
+ if(offset.size()!=D)
+ throw std::invalid_argument("TransformationLoader::translate");
+
+ transformation *= AffineTransformation<T, D>::translation(LinAl::Vector<T, D>(&offset[0]));
+}
+
+template<typename T, unsigned D>
+inline void TransformationLoader<T, D>::scale(const std::vector<T> &s)
+{
+ if(s.size()!=1 && s.size()!=D)
+ throw std::invalid_argument("TransformationLoader::scale");
+
+ if(s.size()==1)
+ {
+ LinAl::Vector<T, D> us;
+ for(unsigned i=0; i<D; ++i)
+ us[i] = s.front();
+ transformation *= AffineTransformation<T, D>::scaling(us);
+ }
+ else
+ transformation *= AffineTransformation<T, D>::scaling(LinAl::Vector<T, D>(&s[0]));
+}
+
+template<typename T, unsigned D>
+inline void TransformationLoader<T, D>::shear(const std::vector<T> &s)
+{
+ if(s.size()!=2*D)
+ throw std::invalid_argument("TransformationLoader::shear");
+
+ transformation *= AffineTransformation<T, D>::shear(LinAl::Vector<T, D>(&s[0]), LinAl::Vector<T, D>(&s[D]));
+}
+
+
+template<typename T>
+inline ShapeLoader<TransformedShape<T, 2> >::ShapeLoader()
+{
+ this->add("rotate", &ShapeLoader::rotate);
+}
+
+template<typename T>
+inline void ShapeLoader<TransformedShape<T, 2> >::rotate(T a)
+{
+ TransformationLoader<T, 2>::transformation *= AffineTransformation<T, 2>::rotation(Angle<T>::from_degrees(a));
+}
+
+
+template<typename T>
+inline ShapeLoader<TransformedShape<T, 3> >::ShapeLoader()
+{
+ this->add("rotate", &ShapeLoader::rotate);
+}
+
+template<typename T>
+inline void ShapeLoader<TransformedShape<T, 3> >::rotate(T a, T x, T y, T z)
+{
+ TransformationLoader<T, 3>::transformation *= AffineTransformation<T, 3>::rotation(Angle<T>::from_degrees(a), LinAl::Vector<T, 3>(x, y, z));
+}
+
+
+template<typename T, unsigned D, typename S>
+inline CompositeLoader<T, D, S>::CompositeLoader():
+ Loader<T, D>(false)
+{ }
+
+template<typename T, unsigned D, typename S>
+inline S *CompositeLoader<T, D, S>::create() const
+{
+ if(this->shapes.empty())
+ throw std::runtime_error("no shapes");
+ return S::from_iterator_range(this->shapes.begin(), this->shapes.end()).clone();
+}
+
+} // namespace Geometry
+} // namespace Msp
+
+#endif