/*
    C++ Mesh Generation Library
    Copyright (c) 2000echet <eric at bechet dot ca>

    This file is part of the C++ Mesh Generation Library.

    See the NOTICE & LICENSE files for conditions.
*/
//---------------------------------------------------------------------------
#ifndef DISCRETE_GEOMETRY_PATCH_H
#define DISCRETE_GEOMETRY_PATCH_H
//---------------------------------------------------------------------------
#include "mesh_const.h"

#include <list>

#include "simplex_base.h"
#include "geometry_patch.h"
#include "mesh_globals.h"
#include "topological_face.h"

using namespace std;


/// a discrete patch (based on a simplex)
template<int nbpts,int dim,class V> class Discrete_Geometry_Patch : public Simplex_Base<nbpts,dim,V>, public Geometry_Patch<dim,V>
{
public:
///
  typedef V Vertex_Type;
///
  typedef typename V::Iterator Vertex_Iterator;
///
//  typedef Topological_Face<Vertex_Type*,Geometry_Patch<dim,Vertex_Type>*> Topological_Face_Type;

private:
/// the connected patches
  list<Geometry_Patch<dim,V> *> geometry_patches;
/// the normal (constant over the patch)
  Vector Normal;
/// an ID of the zone to which it belongs
  int Zone;

public:

/// default constructor
  Discrete_Geometry_Patch ( void ) :Normal ( dim )
  {
    Zone=0;
  }

/// sets the vertices of the patch to those of the array VV
  Discrete_Geometry_Patch ( Vertex_Iterator VV[] ) :Normal ( dim )
  {
    for ( int j=0; j<nbpts; ++j )
    {
      this->vertex[j]=VV[j];
    }

    Zone=0;
  }

/// sets the normal
  void Set_Normal ( Vector &T )
  {
    Normal=T;
  }

/// gets the normal
  void Get_Normal ( Vector &T ) const
  {
    T=Normal;
  }

/// sets the zone (application dependent)
  void Set_Zone ( int Z )
  {
    Zone=Z;
  }

/// gets the zone
  int Get_Zone ( void ) const
  {
    return ( Zone );
  }

/// gets the normal at node Vertex (ovverriding the pure virtual func. )
  virtual void Get_Normal ( V& Vertex,Vector &T ) const
  {
    Get_Normal ( T );
  }

/// adds a connected patch
  virtual void Add_Connected_Geometry_Patch ( Geometry_Patch<dim,Vertex_Type> *EE )
  {
    geometry_patches.insert ( geometry_patches.end(),EE );
  }
/// gets the number of connected patches
  virtual int Get_Number_Connected_Geometry_Patch() const
  {
    return geometry_patches.size();
  }

/// get the connected patches in an user allocated array
  virtual void Get_Connected_Geometry_Patch ( Geometry_Patch<dim,Vertex_Type> *EE[] ) const
  {
    typename list<Geometry_Patch<dim,V> *>::const_iterator it;
    int i;

    for ( it=geometry_patches.begin(),i=0; it!=geometry_patches.end(); ++it,++i )
    {
      EE[i]=*it;
    }
  }

  /** project a node Vin on the surface. Vp is the resulting node, dir is the vector for the projection
   returns true if it can be done (is on the patch)*/
  bool Project_Point ( const Vertex_Type &Vin,Vertex_Type &VP,Vector &dir,double &t ) const
  {
    Vector n ( dim );
    typename Vertex_Type::Iterator ver;
    double num,den;
    double tampon[3];

    int i,j;


    ver=this->vertex[0];
    Get_Normal ( n );
    num=0.0;
    den=0.0;

// projection dans le plan du patch
    for ( i=0; i<3; ++i )
    {
      num+=n[i]* ( Vin[i]- ( *ver ) [i] );
      den+=n[i]*dir[i];
    }

    if ( den==0.0 )
    {
      t=0;
      VP=Vin;
      return false;
    }

    t=num/den;

    for ( i=0; i<3; ++i )
    {
      VP[i]=Vin[i]-t*dir[i];
    }

    double tampon_vertex[3],tab_vert[3][3];

    for ( j=0; j<3; ++j )
    {
      for ( i=0; i<3; ++i )
      {
        tab_vert[i][j]= ( * ( this->vertex[i] ) ) [j];
      }

      tampon_vertex[j]=VP[j];
    }

    return Is_Inside_Triangle3D ( tampon_vertex,tab_vert,tampon );
  }
  virtual ~Discrete_Geometry_Patch() {}
};

#endif // DISCRETE_GEOMETRY_PATCH_H

 
