/////////////////////////////////////////////////////////////
//                                                         //
// Copyright (c) 2007-2017 by The University of Queensland //
// Centre for Geoscience Computing                         //
// http://earth.uq.edu.au/centre-geoscience-computing      //
//                                                         //
// Primary Business: Brisbane, Queensland, Australia       //
// Licensed under the Open Software License version 3.0    //
// http://www.apache.org/licenses/LICENSE-2.0              //
//                                                         //
/////////////////////////////////////////////////////////////

#include "BoxWithJointSet.h"

// --- STL includes ---
#include <utility>
#include <map>

using std::make_pair;
using std::map;

BoxWithJointSet::BoxWithJointSet()
{}

/*!
  Construct box. Just calls constructor of base class. 

  \param pmin minimum point of bounding box
  \param pmax maximum point of bounding box
*/
BoxWithJointSet::BoxWithJointSet(const Vector3& pmin,const Vector3& pmax) : BoxWithPlanes3D(pmin,pmax)
{}

/*!
  get the n geometrical objects  closest to a given point

  \param p the point
  \param nmax the max. nr. of objects
  \return a map of [dist,*object] pairs
*/
const map<double,const AGeometricObject*> BoxWithJointSet::getClosestObjects(const Vector3& p,int nmax) const
{
  map<double,const AGeometricObject*> res;

  for(vector<Plane>::const_iterator iter=m_planes.begin();
      iter!=m_planes.end();
      iter++){
    double ndist=iter->getDist(p);
    res.insert(make_pair(ndist,&(*iter)));
  }

  for(vector<Triangle3D>::const_iterator iter=m_joints.begin();
      iter!=m_joints.end();
      iter++){
    double ndist=iter->getDist(p);
    res.insert(make_pair(ndist,&(*iter)));
  }

  return res;
}

/*!
  add a set of triangular patches as joints

  \param t the joint set
*/
void BoxWithJointSet::addJoints(const TriPatchSet& t)
{
  for(vector<Triangle3D>::const_iterator iter=t.triangles_begin();
      iter!=t.triangles_end();
      iter++){
    m_joints.push_back(*iter);
  }
}

/*!
  check if a Sphere is inside and doesn't intersect any planes or other objects

  \param S the Sphere
*/
bool BoxWithJointSet::isIn(const Sphere& S)
{
  double r=S.Radius();
  Vector3 p=S.Center();

  // check inside & planes via base class
  bool res=BoxWithPlanes3D::isIn(S);

  if(res){
    // check intersection with joints
    vector<Triangle3D>::iterator iter=m_joints.begin();
    double dist=2*r;
    while((iter!=m_joints.end()) && res){
      dist=iter->getDist(p);
      res=(dist>r);
      iter++;
    }
  }

  return res;  
}


ostream& operator<< (ostream& ost, const BoxWithJointSet& B)
{
  ost << B.m_pmin << " to " << B.m_pmax;

  return ost;
}
