/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2014 Frederik Heber. 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 .
 */
/*
 * SurfaceRandomInserter.cpp
 *
 *  Created on: Sep 03, 2014
 *      Author: heber
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
//#include "CodePatterns/MemDebug.hpp"
#include "SurfaceRandomInserter.hpp"
#include "Atom/atom.hpp"
#include "CodePatterns/Log.hpp"
#include "LinearAlgebra/RealSpaceMatrix.hpp"
#include "LinearAlgebra/Vector.hpp"
#include "Shapes/Shape.hpp"
/** Constructor for class SurfaceRandomInserter.
 *
 * @param _s shape on whose surface the insertion nodes lie
 * @param _alignedAxis axis along which to be inserted cluster is aligned to
 * @param _MaxAtomComponent maximum component for random atom translations
 * @param _MaxMoleculeComponent maximum component for random molecule translations
 */
SurfaceRandomInserter::SurfaceRandomInserter(
    const Shape & _s,
    const Vector &_alignedAxis,
    const double _MaxAtomComponent,
    const double _MaxMoleculeComponent) :
    RandomInserter(_MaxAtomComponent, _MaxMoleculeComponent, false),
    shape(_s),
    alignedAxis(_alignedAxis.getNormalized())
{}
/** Destructor for class SurfaceRandomInserter.
 *
 */
SurfaceRandomInserter::~SurfaceRandomInserter()
{}
/** 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 SurfaceRandomInserter::alignedAxis and
 * the translation is done relative to origin.
 *
 * @param offset
 * @return always true
 */
bool SurfaceRandomInserter::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
  RealSpaceMatrix M;
  if (!SurfaceNormal.IsZero()) {
    SurfaceNormal.Normalize();
    LOG(4, "DEBUG: Rotation axis is " << SurfaceNormal << ".");
    M.setRotation(SurfaceNormal, alpha);
  } else {
    M.setIdentity();
  }
  // rotate cluster
  cluster->transform(M);
  // translate
  return RandomInserter::operator()(cluster, offset);
}