/*HEAD Geogram.h */
/*==================================================================================================

                    Copyright Siemens 2019
               Published - All rights reserved

====================================================================================================
File description:
        A wrapper API for geogram dll.

        Version 1.0

$HISTORY$
==================================================================================================*/

#ifndef GEOGRAM_H_INCLUDE
#define GEOGRAM_H_INCLUDE

#include <ostream>

#ifndef GEOGRAM_API

#if defined(GEOGRAM_EXPORTS)
#   if defined(_WIN32)
#       define GEOGRAM_API       __declspec(dllexport)
#   elif __GNUC__ >= 4
#       define GEOGRAM_API       __attribute__ ((visibility("default")))
#   else
#       define GEOGRAM_API
#   endif
#else
#   if defined(_WIN32) && !defined(WNT_STATIC_LINK)
#       define GEOGRAM_API       __declspec(dllimport)
#   else
#       define GEOGRAM_API
#   endif
#endif

#endif // GEOGRAM_API

//////////////////////////////////////////////////////////////////////////
// Forward declare Geogram types
namespace GEO
{
	class Mesh;
	class NearestNeighborSearch;
}

typedef class GEO::Mesh GEOMesh;
typedef class GEO::NearestNeighborSearch GEONearestNeighborSearch;

//////////////////////////////////////////////////////////////////////////
// GEO::Mesh function call dispatch table
struct GeoMeshFnTable
{
    GEOMesh* ( *Construct )( std::ostream* );

    void( *Destroy )( GEOMesh* );

    bool( *InitGeogram )( );

    bool( *LoadMeshFromFile )( const char* fileName, GEOMesh* mesh );

    /*! Combine close vertices and fix some defects on the mesh.
        @param[in] searchRadius     -- tolerance used to collocate vertices. If 0, look for exact matching vertices.
        @param[in] vertexOnly       -- specify mode for co-locating vertices only.
    */
    bool( *RepairMesh )( double searchRadius, bool vertexOnly, GEOMesh* mesh );

    /*! Smooth point set by projecting points onto the nearest approximated plane
        @param[in] smoothFactor -- number of iteration cycles
        @param[in] nbNeighbors  -- number of points used for the best approximating plane
    */
    bool( *SmoothMesh )( int smoothFactor, int numNeighbors, GEOMesh* mesh );

    /*! Reconstruct triangle mesh from point set
    * @param[in]: searchRadius maximum distance used to connect points
    */
    bool( *ReconstructSurface )( double searchRadius, int smoothFactor, unsigned int maxHoleEdges,
                                 double maxHoleArea, unsigned int minCompFacets, double minCompArea, GEOMesh* mesh );

    /*! Computes the total surface area of a mesh.
        @param[in] M    --  the mesh

        @return Area of the mesh
    */
    bool( *MeshSurfaceArea )( const GEOMesh* mesh, double* surfaceArea );

    /*! Removes the connected components that are smaller than the given thresholds.    
        @param[in]      minComponentArea    -- the connected components with an area smaller than this threshold are removed
        @param[in]      minNumFacets        -- the connected components with less than minNumFacets facets are removed 
        @param[in,out]  M                   -- the mesh to be processed
    */
    bool( *RemoveSmallConnectedComponents )( double minComponentArea, unsigned int minComponentFacets, GEOMesh* mesh );

    /*! Fills holes in a mesh by generating new triangles

        This fills specific holes in mesh \p M with new triangles:
        * for which the total area of the generated triangles is smaller than \p max_area, and 
        * for which the number of edges is smaller than \p max_edges
    
        @param[in] max_area     -- maximum area of a hole ignoring larger holes
        @param[in] max_edges    -- maximum number of edges around a hole ignoring larger holes
        @param[in] repair       -- if true (default), then the newly generated triangles are 
                                   connected to their neighbors and zero-length edges are discarded
        @param[in,out] M        -- the mesh to modify

        \note This does not generate new vertices.
    */
    bool( *FillHoles )( double maxArea, unsigned int maxNumEdges, bool repair, GEOMesh* mesh );

    /*! Post-processes a Restricted Delaunay Triangulation.
    
        Reconstructs the triangle-triangle connectivity and removes some degeneracies 
        (vertices with a unique triangle incident to them)
    */
    bool( *PostProcessRDT )( GEOMesh* mesh );

    //! Returns the number of vertices in the mesh
    int( *GetNumVertices )( const GEOMesh* mesh );

    //! Returns location of the vertex
    double* ( *GetVertex )( int vertexId, GEOMesh* mesh );

    //! Returns number of facets in the mesh
    int( *GetNumFacets )( const GEOMesh* mesh );

    //! Returns vertex location specified by facetId (0..numFacet) and local vertex index (0..2)
    double* ( *GetVertexOnFacet )( int facetId, int vertexLocalId, GEOMesh* mesh );

    //! Returns vertex Id specified by facetId and local vertex index (0..2)
    int( *GetVertexIdOnFacet )( int facetId, int vertexLocalId, const GEOMesh* mesh );

    //! Clear current mesh. All vertices, facets, and attributes will be removed.
    bool( *ClearMesh )( GEOMesh* mesh );

    /*! Add a new vertex to the Mesh
        @param[in] point -- xyz stored as double point[3]
        
        @return Id of the new vertex
    */
    int( *AddVertex )( double* point, GEOMesh* mesh );

    /*! Update vertex locations
        @param [in] pointArray    -- array of 3D points, each point is represented by xyz values
        @param [in] numPoint      -- number of array points
    */
    bool( *CreateVerticesFromArray )( const double* pointArray, int numPoint, GEOMesh* mesh );

    /*! Re-populate the mesh with new vertices and triangles
        @param[in] pointArray       -- array of 3D points, each point is given by respective xyz values, 3 contagious points belong to one triangle
        @param[in] numTriangles     -- number of triangles, size of pointArray = 3 * numTriangles
    */
    bool( *CreateMeshTrianglesFromArray )( const double* pointArray, int numTriangles, GEOMesh* mesh );

    //! Return pointer to vertex locations
    double* ( *GetVertexPtr )( GEOMesh* mesh );

    //! return pointer to the first vertex of the first facet for iterating on the pointer
    int* ( *GetVertexConnectionsPtr )( GEOMesh* mesh );

    //! Laplacian smoothing
    bool( *LaplacianSmooth )( unsigned int smoothIter, bool normalsonly, GEOMesh* mesh );

    //! Compute sizing field using estimates of local features estimated over numbSamples neighborhood.
    bool( *ComputeSizingField )( double sizeAdapter, unsigned int numbSamples, GEOMesh* mesh );

    //! Normalize ans scaled stored vertexes by a factor
    bool( *SetAnisotropy )( double shapeAdapter, GEOMesh* mesh );

    //! Remesh smooth shape
    bool( *RemeshSmooth )( unsigned int numbVertOut, unsigned int numbLloydIter, unsigned int numbNewtonIter, unsigned int numbNewtonInnerIter, GEOMesh* mesh );

    //! Compute normals to the vertices and store
    bool( *ComputeNormals )( GEOMesh* mesh );

    //! Get the dimension of mesh
    int( *GetDimension )( const GEOMesh* mesh );

    //! Set the dimension of mesh
    bool( *SetDimension )( unsigned int vertDdimension, GEOMesh* mesh );
};

//////////////////////////////////////////////////////////////////////////
// GEO::NearestNeighborSearch function call dispatch table
struct NearestNeighborSearchFnTable
{
	GEONearestNeighborSearch* (*Construct)(std::ostream*);

	void(*Destroy)(GEONearestNeighborSearch*);

    /*! Initialize the searcher data structure
    @param[in] executeSearch -- if true, run exact otherwise approximate (faster) search
    
    \warning Duplicated vertices MUST BE removed before using it.
    */
	bool (*InitNNSearch)(bool executeSearch, unsigned int numPoints, const double* points, GEONearestNeighborSearch* nnSearch);

    /*! Find distance from query point to nearest neighbor point
        @param[in] queryPoint        -- xyz values of the query point
        @param[in] queryFromThisMesh -- if true query belong to this mesh. 
                                        In that case, first nearest neighbor is ignored as it is the query point itself, and 
                                        returns SECOND nearest neighbor.
        
        \warning Duplicated vertices MUST BE removed before using it.
    */
	bool(*GetNNSqDistance)(const double* queryPoint, bool queryFromThisMesh, GEONearestNeighborSearch* nnSearch, double* sqrDist);
};

//////////////////////////////////////////////////////////////////////////
//! Function call dispatch tables
struct GeogramDispatchTables
{
    //! Dispatch table for Geo::Mesh
    GeoMeshFnTable const* geoMesh = NULL;

	//! Dispatch table for Geo::NearestNeighborSearch
	NearestNeighborSearchFnTable const* nnSearch = NULL;

};

//////////////////////////////////////////////////////////////////////////
// Main communication line with Geogram
extern "C" { GEOGRAM_API GeogramDispatchTables const* GetGeogramDispatchTables();}

#endif //GEOGRAM_H_INCLUDE