/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2012 University of Bonn. All rights reserved.
 * 
 *
 *   This file is part of MoleCuilder.
 *
 *    MoleCuilder is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    MoleCuilder is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoleCuilder.  If not, see .
 */
/*
 * SurfaceInserter.cpp
 *
 *  Created on: Apr 03, 2012
 *      Author: heber
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include "CodePatterns/MemDebug.hpp"
#include "SurfaceInserter.hpp"
#include "Atom/atom.hpp"
#include "CodePatterns/Log.hpp"
#include "LinearAlgebra/RealSpaceMatrix.hpp"
#include "LinearAlgebra/Vector.hpp"
#include "Shapes/Shape.hpp"
/** Constructor for class SurfaceInserter.
 *
 * @param _s shape on whose surface the insertion nodes lie
 * @param _alignedAxis axis along which to be inserted cluster is aligned to
 */
SurfaceInserter::SurfaceInserter(const Shape & _s, const Vector &_alignedAxis) :
    shape(_s),
    alignedAxis(_alignedAxis.getNormalized())
{}
/** Destructor for class SurfaceInserter.
 *
 */
SurfaceInserter::~SurfaceInserter()
{}
/** Inserter operator that rotates the cluster to be perpendicular on surface at
 *  desired \a offset and translates it there.
 *
 * \note We assume that cluster is aligned along \a SurfaceInserter::alignedAxis and
 * the translation is done relative to origin.
 *
 * @param offset
 * @return always true
 */
bool SurfaceInserter::operator()(ClusterInterface::Cluster_impl cluster, const Vector &offset) const
{
  // create rotation matrix, assuming cluster is aligned along z axis
  Vector SurfaceNormal = shape.getNormal(offset); // get normal at desired point
  LOG(3, "DEBUG: Normal vector at " << offset << " is " << SurfaceNormal << ".");
  const double alpha = - alignedAxis.Angle(SurfaceNormal); // we have to rotate back
  LOG(4, "DEBUG: Rotation angle is " << alpha << ".");
  SurfaceNormal.VectorProduct(alignedAxis);  // get the rotation axis as normal direction to both
  SurfaceNormal.Normalize();
  LOG(4, "DEBUG: Rotation axis is " << SurfaceNormal << ".");
  RealSpaceMatrix M;
  M.setRotation(SurfaceNormal, alpha);
  // rotate cluster
  cluster->transform(M);
  // translate
  cluster->translate(offset);
  return true;
}