// ============================================================================
// ==                                                                        ==
// == AMDiS - Adaptive multidimensional simulations                          ==
// ==                                                                        ==
// ============================================================================
// ==                                                                        ==
// ==  crystal growth group                                                  ==
// ==                                                                        ==
// ==  Stiftung caesar                                                       ==
// ==  Ludwig-Erhard-Allee 2                                                 ==
// ==  53175 Bonn                                                            ==
// ==  germany                                                               ==
// ==                                                                        ==
// ============================================================================
// ==                                                                        ==
// ==  http://www.caesar.de/cg/AMDiS                                         ==
// ==                                                                        ==
// ============================================================================

/** \file CylinderProject.h */

#ifndef AMDIS_CYLINDERPROJECT_H
#define AMDIS_CYLINDERPROJECT_H

namespace AMDiS {

  // ==============================================================================
  // ===== class CylinderProject ==================================================
  // ==============================================================================

  /** \brief
   * Projects world coordinates to the surface of a cylinder with given center, 
   * radius and direction. Can be used as boundary or volume projection.
   */
  class CylinderProject : public Projection
  {
  public:
    /** \brief
     * Constructor.
     */ 
    CylinderProject(int id,
		    ProjectionType type,
		    WorldVector<double> &c,
		    WorldVector<double> &d,
		    double r) 
      : Projection(id, type),
	center_(c),
	direction_(d),
	radius_(r)
    {
      double norm = sqrt(direction_*direction_);
      direction_ *= 1.0 / norm;
    };

    /** \brief
     * Destructor.
     */
    virtual ~CylinderProject() {};

    /** \brief
     * Implementation of Projection::project();
     */
    void project(WorldVector<double> &x) {
      x -= center_;
      WorldVector<double> v1 = direction_; v1 *= (x*direction_);
      WorldVector<double> v2 = x; v2 -= v1;
      double norm = sqrt(v2 * v2);
      TEST_EXIT(norm != 0.0)("can't project vector x\n");
      v2 *= 1.0 / norm;
      x = v2; x *= radius_; x += v1;
      x += center_;
    };

  protected:
    /** \brief
     * Center of the cylinder.
     */
    WorldVector<double> center_;

    /** \brief
     * Direction of the cylinder.
     */
    WorldVector<double> direction_;

    /** \brief
     * Radius of the cylinder.
     */
    double radius_;
  };

}

#endif