/*
      glm.c
      Nate Robins, 1997, 2000
      nate@pobox.com, http://www.pobox.com/~nate

      Wavefront OBJ model file format reader/writer/manipulator.

      Includes routines for generating smooth normals with
      preservation of edges, welding redundant vertices & texture
      coordinate generation (spheremap and planar projections) + more.

*/

#include <src/stdafx.h>
//#include <math.h>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>

#include <assert.h>
#include "glm.h"
#include <iostream>
#include <sstream>
#include <fstream>
#include <boost/algorithm/string.hpp>


#include "cv.h"
#include "highgui.h"

#include <QDebug>
#include <QPainter>
#include <QDir>
#include <QStringList>
using namespace std;

#define T(x) (model->triangles[(x)])


/* _GLMnode: general purpose node */
typedef struct _GLMnode {
    GLuint         index;
    GLboolean      averaged;
    struct _GLMnode* next;
} GLMnode;


/* glmMax: returns the maximum of two floats */
static GLfloat
glmMax(GLfloat a, GLfloat b)
{
    if (b > a)
        return b;
    return a;
}

/* glmAbs: returns the absolute value of a float */
static GLfloat
glmAbs(GLfloat f)
{
    if (f < 0)
        return -f;
    return f;
}

/* glmDot: compute the dot product of two vectors
 *
 * u - array of 3 GLfloats (GLfloat u[3])
 * v - array of 3 GLfloats (GLfloat v[3])
 */
static GLfloat
glmDot(GLfloat* u, GLfloat* v)
{
    assert(u); assert(v);

    return u[0]*v[0] + u[1]*v[1] + u[2]*v[2];
}

/* glmCross: compute the cross product of two vectors
 *
 * u - array of 3 GLfloats (GLfloat u[3])
 * v - array of 3 GLfloats (GLfloat v[3])
 * n - array of 3 GLfloats (GLfloat n[3]) to return the cross product in
 */
static GLvoid
glmCross(GLfloat* u, GLfloat* v, GLfloat* n)
{
    assert(u); assert(v); assert(n);

    n[0] = u[1]*v[2] - u[2]*v[1];
    n[1] = u[2]*v[0] - u[0]*v[2];
    n[2] = u[0]*v[1] - u[1]*v[0];
}

/* glmNormalize: normalize a vector
 *
 * v - array of 3 GLfloats (GLfloat v[3]) to be normalized
 */
static GLvoid
glmNormalize(GLfloat* v)
{
    GLfloat l;

    assert(v);

    l = (GLfloat)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
    v[0] /= l;
    v[1] /= l;
    v[2] /= l;
}

/* glmEqual: compares two vectors and returns GL_TRUE if they are
 * equal (within a certain threshold) or GL_FALSE if not. An epsilon
 * that works fairly well is 0.000001.
 *
 * u - array of 3 GLfloats (GLfloat u[3])
 * v - array of 3 GLfloats (GLfloat v[3])
 */
static GLboolean
glmEqual(GLfloat* u, GLfloat* v, GLfloat epsilon)
{
    if (glmAbs(u[0] - v[0]) < epsilon &&
            glmAbs(u[1] - v[1]) < epsilon &&
            glmAbs(u[2] - v[2]) < epsilon)
    {
        return GL_TRUE;
    }
    return GL_FALSE;
}

/* glmWeldVectors: eliminate (weld) vectors that are within an
 * epsilon of each other.
 *
 * vectors     - array of GLfloat[3]'s to be welded
 * numvectors - number of GLfloat[3]'s in vectors
 * epsilon     - maximum difference between vectors
 *
 */
GLfloat*
glmWeldVectors(GLfloat* vectors, GLuint* numvectors, GLfloat epsilon)
{
    GLfloat* copies;
    GLuint   copied;
    GLuint   i, j;

    copies = (GLfloat*)malloc(sizeof(GLfloat) * 3 * (*numvectors + 1));
    memcpy(copies, vectors, (sizeof(GLfloat) * 3 * (*numvectors + 1)));

    copied = 1;
    for (i = 1; i <= *numvectors; i++) {
        for (j = 1; j <= copied; j++) {
            if (glmEqual(&vectors[3 * i], &copies[3 * j], epsilon)) {
                goto duplicate;
            }
        }

        /* must not be any duplicates -- add to the copies array */
        copies[3 * copied + 0] = vectors[3 * i + 0];
        copies[3 * copied + 1] = vectors[3 * i + 1];
        copies[3 * copied + 2] = vectors[3 * i + 2];
        j = copied;             /* pass this along for below */
        copied++;

duplicate:
        /* set the first component of this vector to point at the correct
        index into the new copies array */
        vectors[3 * i + 0] = (GLfloat)j;
    }

    *numvectors = copied-1;
    return copies;
}

/* glmFindGroup: Find a group in the model */
GLMgroup*
glmFindGroup(GLMmodel* model, char* name)
{
    GLMgroup* group;

    assert(model);

    group = model->groups;
    while(group) {
        if (!strcmp(name, group->name))
            break;
        group = group->next;
    }

    return group;
}

/* glmAddGroup: Add a group to the model */
GLMgroup*
glmAddGroup(GLMmodel* model, char* name)
{
    GLMgroup* group;

    group = glmFindGroup(model, name);
    if (!group) {
        group = (GLMgroup*)malloc(sizeof(GLMgroup));
        group->name = strdup(name);
        group->material = 0;
        group->numtriangles = 0;
        group->triangles = NULL;
        group->next = model->groups;
        model->groups = group;
        model->numgroups++;
    }

    return group;
}

/* glmFindGroup: Find a material in the model */
GLuint
glmFindMaterial(GLMmodel* model, char* name)
{
    GLuint i;

    /* XXX doing a linear search on a string key'd list is pretty lame,
    but it works and is fast enough for now. */
    for (i = 0; i < model->nummaterials; i++) {
        if (!strcmp(model->materials[i].name, name))
            goto found;
    }

    /* didn't find the name, so print a warning and return the default
    material (0). */
    printf("glmFindMaterial():  can't find material \"%s\".\n", name);
    i = 0;

found:
    return i;
}


/* glmDirName: return the directory given a path
 *
 * path - filesystem path
 *
 * NOTE: the return value should be free'd.
 */
static char*
glmDirName(char* path)
{
    char* dir;
    char* s;

    dir = strdup(path);

    s = strrchr(dir, '/');
    if (s)
        s[1] = '\0';
    else
        dir[0] = '\0';

    return dir;
}


/* glmReadMTL: read a wavefront material library file
 *
 * model - properly initialized GLMmodel structure
 * name  - name of the material library
 */
static GLvoid
glmReadMTL(GLMmodel* model, char* name)
{
    FILE* file;
    char* dir;
    char* filename;
    char    buf[128];
    GLuint nummaterials, i;

    dir = glmDirName(model->pathname);
    filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(name) + 1));
    strcpy(filename, dir);
    strcat(filename, name);
    free(dir);

    file = fopen(filename, "r");
    if (!file) {
        fprintf(stderr, "glmReadMTL() failed: can't open material file \"%s\".\n",
                filename);
        exit(1);
    }
    free(filename);

    /* count the number of materials in the file */
    nummaterials = 1;
    while(fscanf(file, "%s", buf) != EOF) {
        switch(buf[0]) {
        case '#':               /* comment */
            /* eat up rest of line */
            if(fgets(buf, sizeof(buf), file));
            break;
        case 'n':               /* newmtl */
            if(fgets(buf, sizeof(buf), file));
            nummaterials++;
            sscanf(buf, "%s %s", buf, buf);
            break;
        default:
            /* eat up rest of line */
            if(fgets(buf, sizeof(buf), file));
            break;
        }
    }

    rewind(file);

    model->materials = (GLMmaterial*)malloc(sizeof(GLMmaterial) * nummaterials);
    model->nummaterials = nummaterials;

    /* set the default material */
    for (i = 0; i < nummaterials; i++) {
        model->materials[i].name = NULL;
        model->materials[i].shininess = 65.0;//65
        model->materials[i].diffuse[0] = 0.8;
        model->materials[i].diffuse[1] = 0.8;
        model->materials[i].diffuse[2] = 0.8;
        model->materials[i].diffuse[3] = 1.0;
        model->materials[i].ambient[0] = 0.2;
        model->materials[i].ambient[1] = 0.2;
        model->materials[i].ambient[2] = 0.2;
        model->materials[i].ambient[3] = 1.0;
        model->materials[i].specular[0] = 0.0;
        model->materials[i].specular[1] = 0.0;
        model->materials[i].specular[2] = 0.0;
        model->materials[i].specular[3] = 1.0;
    }
    model->materials[0].name = strdup("default");

    /* now, read in the data */
    nummaterials = 0;
    while(fscanf(file, "%s", buf) != EOF) {
        switch(buf[0]) {
        case '#':               /* comment */
            /* eat up rest of line */
            if(fgets(buf, sizeof(buf), file));
            break;
        case 'n':               /* newmtl */
            if(fgets(buf, sizeof(buf), file));
            sscanf(buf, "%s %s", buf, buf);
            nummaterials++;
            model->materials[nummaterials].name = strdup(buf);
            break;
        case 'N':
            if(fscanf(file, "%f", &model->materials[nummaterials].shininess));
            /* wavefront shininess is from [0, 1000], so scale for OpenGL */
            model->materials[nummaterials].shininess /= 1000.0;
            model->materials[nummaterials].shininess *= 128.0;
            break;
        case 'K':
            switch(buf[1]) {
            case 'd':
                if(fscanf(file, "%f %f %f",
                       &model->materials[nummaterials].diffuse[0],
                       &model->materials[nummaterials].diffuse[1],
                       &model->materials[nummaterials].diffuse[2]));
                break;
            case 's':
                if(fscanf(file, "%f %f %f",
                       &model->materials[nummaterials].specular[0],
                       &model->materials[nummaterials].specular[1],
                       &model->materials[nummaterials].specular[2]));
                break;
            case 'a':
                if(fscanf(file, "%f %f %f",
                       &model->materials[nummaterials].ambient[0],
                       &model->materials[nummaterials].ambient[1],
                       &model->materials[nummaterials].ambient[2]));
                break;
            default:
                /* eat up rest of line */
                if(fgets(buf, sizeof(buf), file));
                break;
            }
            break;
        default:
            /* eat up rest of line */
            if(fgets(buf, sizeof(buf), file));
            break;
        }
    }
}

/* glmWriteMTL: write a wavefront material library file
 *
 * model   - properly initialized GLMmodel structure
 * modelpath  - pathname of the model being written
 * mtllibname - name of the material library to be written
 */
static GLvoid
glmWriteMTL(GLMmodel* model, char* modelpath, char* mtllibname)
{
    FILE* file;
    char* dir;
    char* filename;
    GLMmaterial* material;
    GLuint i;

    dir = glmDirName(modelpath);
    filename = (char*)malloc(sizeof(char) * (strlen(dir)+strlen(mtllibname)));
    strcpy(filename, dir);
    strcat(filename, mtllibname);
    free(dir);

    /* open the file */
    file = fopen(filename, "w");
    if (!file) {
        fprintf(stderr, "glmWriteMTL() failed: can't open file \"%s\".\n",
                filename);
        exit(1);
    }
    free(filename);

    /* spit out a header */
    fprintf(file, "#  \n");
    fprintf(file, "#  Wavefront MTL generated by GLM library\n");
    fprintf(file, "#  \n");
    fprintf(file, "#  GLM library\n");
    fprintf(file, "#  Nate Robins\n");
    fprintf(file, "#  ndr@pobox.com\n");
    fprintf(file, "#  http://www.pobox.com/~ndr\n");
    fprintf(file, "#  \n\n");

    for (i = 0; i < model->nummaterials; i++) {
        material = &model->materials[i];
        fprintf(file, "newmtl %s\n", material->name);
        fprintf(file, "Ka %f %f %f\n",
                material->ambient[0], material->ambient[1], material->ambient[2]);
        fprintf(file, "Kd %f %f %f\n",
                material->diffuse[0], material->diffuse[1], material->diffuse[2]);
        fprintf(file, "Ks %f %f %f\n",
                material->specular[0],material->specular[1],material->specular[2]);
        fprintf(file, "Ns %f\n", material->shininess / 128.0 * 1000.0);
        fprintf(file, "\n");
    }
}


/* glmFirstPass: first pass at a Wavefront OBJ file that gets all the
 * statistics of the model (such as #vertices, #normals, etc)
 *
 * model - properly initialized GLMmodel structure
 * file  - (fopen'd) file descriptor
 */
static GLvoid
glmFirstPass(GLMmodel* model, FILE* file)
{
    GLuint  numvertices;        /* number of vertices in model */
    GLuint  numnormals;         /* number of normals in model */
    GLuint  numtexcoords;       /* number of texcoords in model */
    GLuint  numtriangles;       /* number of triangles in model */
    GLMgroup* group;            /* current group */
    unsigned    v, n, t;
    char        buf[128];

    /* make a default group */
    group = glmAddGroup(model, "default");

    numvertices = numnormals = numtexcoords = numtriangles = 0;
    while(fscanf(file, "%s", buf) != EOF) {
        switch(buf[0]) {
        case '#':               /* comment */
            /* eat up rest of line */
            if(fgets(buf, sizeof(buf), file));
            break;
        case 'v':               /* v, vn, vt */
            switch(buf[1]) {
            case '\0':          /* vertex */
                /* eat up rest of line */
                if(fgets(buf, sizeof(buf), file));
                numvertices++;
                break;
            case 'n':           /* normal */
                /* eat up rest of line */
                if(fgets(buf, sizeof(buf), file));
                numnormals++;
                break;
            case 't':           /* texcoord */
                /* eat up rest of line */
                if(fgets(buf, sizeof(buf), file));
                numtexcoords++;
                break;
            default:
                printf("glmFirstPass(): Unknown token \"%s\".\n", buf);
                exit(1);
                break;
            }
            break;
        case 'm':
            if(fgets(buf, sizeof(buf), file));
            sscanf(buf, "%s %s", buf, buf);
            model->mtllibname = strdup(buf);
            glmReadMTL(model, buf);
            break;
        case 'u':
            /* eat up rest of line */
            if(fgets(buf, sizeof(buf), file));
            break;
        case 'g':               /* group */
            /* eat up rest of line */
            if(fgets(buf, sizeof(buf), file));
#if SINGLE_STRING_GROUP_NAMES
            sscanf(buf, "%s", buf);
#else
            buf[strlen(buf)-1] = '\0';  /* nuke '\n' */
#endif
            group = glmAddGroup(model, buf);
            break;
        case 'f':               /* face */
            v = n = t = 0;
            if(fscanf(file, "%s", buf));
            /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */
            if (strstr(buf, "//")) {
                /* v//n */
                sscanf(buf, "%d//%d", &v, &n);
                if(fscanf(file, "%d//%d", &v, &n));
                if(fscanf(file, "%d//%d", &v, &n));
                numtriangles++;
                group->numtriangles++;
                while(fscanf(file, "%d//%d", &v, &n) > 0) {
                    numtriangles++;
                    group->numtriangles++;
                }
            } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) {
                /* v/t/n */
                if(fscanf(file, "%d/%d/%d", &v, &t, &n));
                if(fscanf(file, "%d/%d/%d", &v, &t, &n));
                numtriangles++;
                group->numtriangles++;
                while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) {
                    numtriangles++;
                    group->numtriangles++;
                }
            } else if (sscanf(buf, "%d/%d", &v, &t) == 2) {
                /* v/t */
                if(fscanf(file, "%d/%d", &v, &t));
                if(fscanf(file, "%d/%d", &v, &t));
                numtriangles++;
                group->numtriangles++;
                while(fscanf(file, "%d/%d", &v, &t) > 0) {
                    numtriangles++;
                    group->numtriangles++;
                }
            } else {
                /* v */
                if(fscanf(file, "%d", &v));
                if(fscanf(file, "%d", &v));
                numtriangles++;
                group->numtriangles++;
                while(fscanf(file, "%d", &v) > 0) {
                    numtriangles++;
                    group->numtriangles++;
                }
            }
            break;

        default:
            /* eat up rest of line */
            if(fgets(buf, sizeof(buf), file));
            break;
        }
    }

    /* set the stats in the model structure */
    model->numvertices  = numvertices;
    model->numnormals   = numnormals;
    model->numtexcoords = numtexcoords;
    model->numtriangles = numtriangles;

    /* allocate memory for the triangles in each group */
    group = model->groups;
    while(group) {
        group->triangles = (GLuint*)malloc(sizeof(GLuint) * group->numtriangles);
        group->numtriangles = 0;
        group = group->next;
    }
}

/* glmSecondPass: second pass at a Wavefront OBJ file that gets all
 * the data.
 *
 * model - properly initialized GLMmodel structure
 * file  - (fopen'd) file descriptor
 */
static GLvoid
glmSecondPass(GLMmodel* model, FILE* file)
{
    GLuint  numvertices;        /* number of vertices in model */
    GLuint  numnormals;         /* number of normals in model */
    GLuint  numtexcoords;       /* number of texcoords in model */
    GLuint  numtriangles;       /* number of triangles in model */
    GLfloat*    vertices;           /* array of vertices  */
    GLfloat*    normals;            /* array of normals */
    GLfloat*    texcoords;          /* array of texture coordinates */
    GLMgroup* group;            /* current group pointer */
    GLuint  material;           /* current material */
    GLuint  v, n, t;
    char        buf[128];

    /* set the pointer shortcuts */
    vertices       = model->vertices;
    normals    = model->normals;
    texcoords    = model->texcoords;
    group      = model->groups;

    /* on the second pass through the file, read all the data into the
    allocated arrays */
    numvertices = numnormals = numtexcoords = 1;
    numtriangles = 0;
    material = 0;
    while(fscanf(file, "%s", buf) != EOF) {
        switch(buf[0]) {
        case '#':               /* comment */
            /* eat up rest of line */
            if(fgets(buf, sizeof(buf), file));
            break;
        case 'v':               /* v, vn, vt */
            switch(buf[1]) {
            case '\0':          /* vertex */
                if(fscanf(file, "%f %f %f",
                       &vertices[3 * numvertices + 0],
                       &vertices[3 * numvertices + 1],
                       &vertices[3 * numvertices + 2]));
                numvertices++;
                break;
            case 'n':           /* normal */
                if(fscanf(file, "%f %f %f",
                       &normals[3 * numnormals + 0],
                       &normals[3 * numnormals + 1],
                       &normals[3 * numnormals + 2]));
                numnormals++;
                break;
            case 't':           /* texcoord */
                if(fscanf(file, "%f %f",
                       &texcoords[2 * numtexcoords + 0],
                       &texcoords[2 * numtexcoords + 1]));
                numtexcoords++;
                break;
            }
            break;
        case 'u':
            if(fgets(buf, sizeof(buf), file));
            sscanf(buf, "%s %s", buf, buf);
            group->material = material = glmFindMaterial(model, buf);
            break;
        case 'g':               /* group */
            /* eat up rest of line */
            if(fgets(buf, sizeof(buf), file));
#if SINGLE_STRING_GROUP_NAMES
            sscanf(buf, "%s", buf);
#else
            buf[strlen(buf)-1] = '\0';  /* nuke '\n' */
#endif
            group = glmFindGroup(model, buf);
            group->material = material;
            break;
        case 'f':               /* face */
            v = n = t = 0;
            if(fscanf(file, "%s", buf));
            /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */
            if (strstr(buf, "//")) {
                /* v//n */
                sscanf(buf, "%d//%d", &v, &n);
                T(numtriangles).vindices[0] = v;
                T(numtriangles).nindices[0] = n;
                if(fscanf(file, "%d//%d", &v, &n));
                T(numtriangles).vindices[1] = v;
                T(numtriangles).nindices[1] = n;
                if(fscanf(file, "%d//%d", &v, &n));
                T(numtriangles).vindices[2] = v;
                T(numtriangles).nindices[2] = n;
                group->triangles[group->numtriangles++] = numtriangles;
                numtriangles++;
                while(fscanf(file, "%d//%d", &v, &n) > 0) {
                    T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
                    T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0];
                    T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
                    T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2];
                    T(numtriangles).vindices[2] = v;
                    T(numtriangles).nindices[2] = n;
                    group->triangles[group->numtriangles++] = numtriangles;
                    numtriangles++;
                }
            } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) {
                /* v/t/n */
                T(numtriangles).vindices[0] = v;
                T(numtriangles).tindices[0] = t;
                T(numtriangles).nindices[0] = n;
                if(fscanf(file, "%d/%d/%d", &v, &t, &n));
                T(numtriangles).vindices[1] = v;
                T(numtriangles).tindices[1] = t;
                T(numtriangles).nindices[1] = n;
                if(fscanf(file, "%d/%d/%d", &v, &t, &n));
                T(numtriangles).vindices[2] = v;
                T(numtriangles).tindices[2] = t;
                T(numtriangles).nindices[2] = n;
                group->triangles[group->numtriangles++] = numtriangles;
                numtriangles++;
                while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) {
                    T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
                    T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0];
                    T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0];
                    T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
                    T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2];
                    T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2];
                    T(numtriangles).vindices[2] = v;
                    T(numtriangles).tindices[2] = t;
                    T(numtriangles).nindices[2] = n;
                    group->triangles[group->numtriangles++] = numtriangles;
                    numtriangles++;
                }
            } else if (sscanf(buf, "%d/%d", &v, &t) == 2) {
                /* v/t */
                T(numtriangles).vindices[0] = v;
                T(numtriangles).tindices[0] = t;
                if(fscanf(file, "%d/%d", &v, &t));
                T(numtriangles).vindices[1] = v;
                T(numtriangles).tindices[1] = t;
                if(fscanf(file, "%d/%d", &v, &t));
                T(numtriangles).vindices[2] = v;
                T(numtriangles).tindices[2] = t;
                group->triangles[group->numtriangles++] = numtriangles;
                numtriangles++;
                while(fscanf(file, "%d/%d", &v, &t) > 0) {
                    T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
                    T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0];
                    T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
                    T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2];
                    T(numtriangles).vindices[2] = v;
                    T(numtriangles).tindices[2] = t;
                    group->triangles[group->numtriangles++] = numtriangles;
                    numtriangles++;
                }
            } else {
                /* v */
                sscanf(buf, "%d", &v);
                T(numtriangles).vindices[0] = v;
                if(fscanf(file, "%d", &v));
                T(numtriangles).vindices[1] = v;
                if(fscanf(file, "%d", &v));
                T(numtriangles).vindices[2] = v;
                group->triangles[group->numtriangles++] = numtriangles;
                numtriangles++;
                while(fscanf(file, "%d", &v) > 0) {
                    T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
                    T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
                    T(numtriangles).vindices[2] = v;
                    group->triangles[group->numtriangles++] = numtriangles;
                    numtriangles++;
                }
            }
            break;

        default:
            /* eat up rest of line */
            if(fgets(buf, sizeof(buf), file));
            break;
        }
    }

#if 0
    /* announce the memory requirements */
    printf(" Memory: %d bytes\n",
           numvertices  * 3*sizeof(GLfloat) +
           numnormals   * 3*sizeof(GLfloat) * (numnormals ? 1 : 0) +
           numtexcoords * 3*sizeof(GLfloat) * (numtexcoords ? 1 : 0) +
           numtriangles * sizeof(GLMtriangle));
#endif
}

/* public functions */
//========================================================Split Model into sub-models==========================
GLvoid glmCorrectTexCoor(GLMmodel* l_model, GLMmodel* r_model, vector<int> seamsVertex, vector<int> seamsTriangle,
                         map<int,int> l_map, map<int,int> r_map, Mesh* l_mesh, Mesh* r_mesh){
    if(l_model->numtexcoords<=0 || r_model->numtexcoords <=0) return;

    int i=0;
    //find the seams triangle index in the left side
    vector<int> l_seams_triangle_idx;
    for(i = 0;i<l_mesh->triangle_idx.size();i++){
        for(int j = 0;j<seamsTriangle.size();j++)
        {
            if(l_mesh->triangle_idx.at(i)==seamsTriangle.at(j)){
                l_seams_triangle_idx.push_back(i);break;}
        }
    }
    vector<int> l_seams_tex_idx;
    vector<int> r_seams_tex_idx;
    map<int,int*> l_vo_v_t;
    map<int,int*> r_v_vo_t;


    for(i=0;i<seamsVertex.size();i++){
        // find seams texture coordinates index in the left side.
        map<int,int>::iterator l_it = l_map.find(seamsVertex.at(i));
        if(l_it!=l_map.end()){
            int vertex_idx  = (*l_it).second;
            for(int j=0;j<l_model->numtriangles;j++){
                for(int k = 0;k<3;k++){
                    int v_idx = l_model->triangles[j].vindices[k];
                    int t_idx = l_model->triangles[j].tindices[k];
                    if(v_idx==vertex_idx){
                        l_seams_tex_idx.push_back(t_idx);
                        int* v_t = (int*)malloc(sizeof(int)*2);
                        v_t[0] = v_idx;
                        v_t[1] = t_idx;
                        l_vo_v_t.insert(pair<int,int*>(seamsVertex.at(i),v_t));
                    }
                }
            }
        }
        // find seams texture coordinates index in the right side.
        map<int,int>::iterator r_it = r_map.find(seamsVertex.at(i));
        if(r_it!=r_map.end()){
            int vertex_idx  = (*r_it).second;
            for(int j=0;j<r_model->numtriangles;j++){
                for(int k = 0;k<3;k++){
                    int v_idx = r_model->triangles[j].vindices[k];
                    int t_idx = r_model->triangles[j].tindices[k];
                    if(v_idx==vertex_idx){

                        r_seams_tex_idx.push_back(t_idx);
                        int* vo_t = (int*)malloc(sizeof(int)*2);
                        vo_t[0] = seamsVertex.at(i);
                        vo_t[1] = t_idx;
                        r_v_vo_t.insert(pair<int,int*>(v_idx,vo_t));
                    }
                }
            }
        }
    }
    int l_min_x_seams_tex_idx = INT_MAX; GLfloat l_min_x = INT_MAX;
    int l_max_x_seams_tex_idx = INT_MIN; GLfloat l_max_x = INT_MIN;
    for(i=0;i<l_seams_tex_idx.size();i++){
        int tex_idx = l_seams_tex_idx.at(i);
        if(l_min_x> l_model->texcoords[2*tex_idx + 0]) {l_min_x = l_model->texcoords[2*tex_idx + 0]; l_min_x_seams_tex_idx=tex_idx;}
        if(l_max_x< l_model->texcoords[2*tex_idx + 0]) {l_max_x = l_model->texcoords[2*tex_idx + 0]; l_max_x_seams_tex_idx=tex_idx;}
    }

    int r_min_x_seams_tex_idx = INT_MAX; GLfloat r_min_x = INT_MAX;
    int r_max_x_seams_tex_idx = INT_MIN;GLfloat r_max_x = INT_MIN;
    for(i=0;i<r_seams_tex_idx.size();i++){
        int tex_idx = r_seams_tex_idx.at(i);
        if(r_min_x> r_model->texcoords[2*tex_idx + 0]) {r_min_x = r_model->texcoords[2*tex_idx + 0]; r_min_x_seams_tex_idx=tex_idx;}
        if(r_max_x< r_model->texcoords[2*tex_idx + 0]) {r_max_x = r_model->texcoords[2*tex_idx + 0]; r_max_x_seams_tex_idx=tex_idx;}
    }
    qDebug() << "max min x idx " << l_max_x_seams_tex_idx << " " << l_min_x_seams_tex_idx;
    qDebug() << "max min x idx " << r_max_x_seams_tex_idx << " " << r_min_x_seams_tex_idx;

    int* p_max_min_idx = (int*)malloc(sizeof(int)*4);
    p_max_min_idx[0] = l_max_x_seams_tex_idx;
    p_max_min_idx[1] = l_min_x_seams_tex_idx;
    p_max_min_idx[2] = r_max_x_seams_tex_idx;
    p_max_min_idx[3] = r_min_x_seams_tex_idx;

    Vector2 l_min_x_seam_p(l_model->texcoords[2*l_min_x_seams_tex_idx + 0],
                           l_model->texcoords[2*l_min_x_seams_tex_idx + 1]);
    Vector2 l_max_x_seam_p(l_model->texcoords[2*l_max_x_seams_tex_idx + 0],
                           l_model->texcoords[2*l_max_x_seams_tex_idx + 1]);
    Vector2 r_min_x_seam_p(r_model->texcoords[2*r_min_x_seams_tex_idx + 0],
                           r_model->texcoords[2*r_min_x_seams_tex_idx + 1]);
    Vector2 r_max_x_seam_p(r_model->texcoords[2*r_max_x_seams_tex_idx + 0],
                           r_model->texcoords[2*r_max_x_seams_tex_idx + 1]);

    Vector2 l_p12(l_max_x_seam_p.x - l_min_x_seam_p.x,
                  l_max_x_seam_p.y - l_min_x_seam_p.y);
    Vector2 r_p12(r_max_x_seam_p.x - r_min_x_seam_p.x,
                  r_max_x_seam_p.y - r_min_x_seam_p.y);
    GLfloat angle = acos((l_p12.x*r_p12.x + l_p12.y*r_p12.y)/(l_p12.length()*r_p12.length()));
    GLfloat ratio = (l_p12.length()/r_p12.length());

    qDebug() << angle << " ratio = " << ratio;

    for(i = 0;i<=r_model->numtexcoords;i++){
        r_model->texcoords[2*i+0] = ratio*r_model->texcoords[2*i+0];
        r_model->texcoords[2*i+1] = ratio * r_model->texcoords[2*i+1];
    }
    // update points
    r_min_x_seam_p.x = r_model->texcoords[2*r_min_x_seams_tex_idx + 0];
    r_min_x_seam_p.y = r_model->texcoords[2*r_min_x_seams_tex_idx + 1];

    r_max_x_seam_p.x = r_model->texcoords[2*r_max_x_seams_tex_idx + 0];
    r_max_x_seam_p.y = r_model->texcoords[2*r_max_x_seams_tex_idx + 1];

    //
    /**/
    angle = - angle;
    for(i = 0;i<=r_model->numtexcoords;i++){
        // move to Min
        float x = r_model->texcoords[2*i+0] - r_min_x_seam_p.x;
        float y = r_model->texcoords[2*i+1] - r_min_x_seam_p.y;
        // rolate around Min with the angle
        float x1 = x*cos(angle) - y*sin(angle);
        float y1 = y*cos(angle) + x*sin(angle);
        // move to Original
        r_model->texcoords[2*i+0] = x1 + r_min_x_seam_p.x;
        r_model->texcoords[2*i+1] = y1 + r_min_x_seam_p.y;
    }
    // update points
    r_min_x_seam_p.x = r_model->texcoords[2*r_min_x_seams_tex_idx + 0];
    r_min_x_seam_p.y = r_model->texcoords[2*r_min_x_seams_tex_idx + 1];

    r_max_x_seam_p.x = r_model->texcoords[2*r_max_x_seams_tex_idx + 0];
    r_max_x_seam_p.y = r_model->texcoords[2*r_max_x_seams_tex_idx + 1];
    /**/
    // move the right side to the min point of left seans line
    float dx = l_min_x_seam_p.x - r_min_x_seam_p.x;
    float dy = l_min_x_seam_p.y - r_min_x_seam_p.y;

    //    float dx = l_max_x_seam_p.x - r_max_x_seam_p.x;
    //    float dy = l_max_x_seam_p.y - r_max_x_seam_p.y;

    for(i = 0;i<=r_model->numtexcoords;i++){
        r_model->texcoords[2*i+0] = (r_model->texcoords[2*i+0] + dx);
        r_model->texcoords[2*i+1] = r_model->texcoords[2*i+1] + dy;
    }
    // update points
    r_min_x_seam_p.x = r_model->texcoords[2*r_min_x_seams_tex_idx + 0];
    r_min_x_seam_p.y = r_model->texcoords[2*r_min_x_seams_tex_idx + 1];

    r_max_x_seam_p.x = r_model->texcoords[2*r_max_x_seams_tex_idx + 0];
    r_max_x_seam_p.y = r_model->texcoords[2*r_max_x_seams_tex_idx + 1];


    testTextureCoordinates(l_model,r_model,"test_texture.png",seamsVertex,seamsTriangle,p_max_min_idx,l_map,r_map,l_mesh,r_mesh);
    //
    /* allocate a new model */
    GLMmodel* new_model = (GLMmodel*)malloc(sizeof(GLMmodel));
    new_model->pathname    = strdup("filename.obj");
    new_model->mtllibname    = NULL;
    new_model->numvertices   = l_model->numvertices + r_model->numvertices;
    new_model->vertices    = NULL;
    new_model->numnormals    = 0;
    new_model->normals     = NULL;
    new_model->numtexcoords  = l_model->numtexcoords + r_model->numtexcoords;
    new_model->texcoords       = NULL;
    new_model->numfacetnorms = 0;
    new_model->facetnorms    = NULL;
    new_model->numtriangles  = l_model->numtriangles + r_model->numtriangles;
    new_model->triangles       = NULL;
    new_model->nummaterials  = 0;
    new_model->materials       = NULL;
    new_model->numgroups       = 0;
    new_model->groups      = NULL;
    new_model->position[0]   = 0.0;
    new_model->position[1]   = 0.0;
    new_model->position[2]   = 0.0;

    /* allocate memory */
    new_model->vertices = (GLfloat*)malloc(sizeof(GLfloat) *
                                           3 * (new_model->numvertices + 1));
    new_model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) *
                                                new_model->numtriangles);
    if (new_model->numnormals) {
        new_model->normals = (GLfloat*)malloc(sizeof(GLfloat) *
                                              3 * (new_model->numnormals + 1));
    }
    if (new_model->numtexcoords) {
        new_model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) *
                                                2 * (new_model->numtexcoords + 1));
    }

    /* initilize model*/
    //int i=0;
    for(i=1;i<=new_model->numvertices;i++){
        new_model->vertices[3*i + 0] = -1;
        new_model->vertices[3*i + 1] = -1;
        new_model->vertices[3*i + 2] = -1;
    }
    for(i=1;i<=new_model->numtexcoords;i++)
    {
        new_model->texcoords[2*i + 0] = -1;
        new_model->texcoords[2*i + 1] = -1;
    }
    for(i=0;i<new_model->numtriangles;i++){
        new_model->triangles[i].vindices[0] = -1;
        new_model->triangles[i].vindices[1] = -1;
        new_model->triangles[i].vindices[2] = -1;

        new_model->triangles[i].tindices[0] = -1;
        new_model->triangles[i].tindices[1] = -1;
        new_model->triangles[i].tindices[2] = -1;
    }

    /* bind left + right for new model*/
    for(i=1;i<=l_model->numvertices;i++){
        new_model->vertices[3*i + 0] = l_model->vertices[3*i + 0];
        new_model->vertices[3*i + 1] = l_model->vertices[3*i + 1];
        new_model->vertices[3*i + 2] = l_model->vertices[3*i + 2];
    }
    for(i =1;i<=l_model->numtexcoords;i++){
        new_model->texcoords[2*i + 0] = l_model->texcoords[2*i + 0];
        new_model->texcoords[2*i + 1] = l_model->texcoords[2*i + 1];
    }
    for(i=0;i<l_model->numtriangles;i++){
        new_model->triangles[i].findex = l_model->triangles[i].findex;

        new_model->triangles[i].vindices[0] = l_model->triangles[i].vindices[0];
        new_model->triangles[i].vindices[1] = l_model->triangles[i].vindices[1];
        new_model->triangles[i].vindices[2] = l_model->triangles[i].vindices[2];

        new_model->triangles[i].tindices[0] = l_model->triangles[i].tindices[0];
        new_model->triangles[i].tindices[1] = l_model->triangles[i].tindices[1];
        new_model->triangles[i].tindices[2] = l_model->triangles[i].tindices[2];
    }
    qDebug() << "OK + 2: v=" << r_v_vo_t.size() << " check = " << l_vo_v_t.size();

    int pos_index = 1;
    map<int,int> r_vo_vn;
    for(i=1;i<=r_model->numvertices;i++){
        map<int,int*>::iterator it = r_v_vo_t.find(i);
        if(it==r_v_vo_t.end()){
            int idx = l_model->numvertices + pos_index;
            new_model->vertices[3*idx + 0] = r_model->vertices[3*i + 0];
            new_model->vertices[3*idx + 1] = r_model->vertices[3*i + 1];
            new_model->vertices[3*idx + 2] = r_model->vertices[3*i + 2];
            r_vo_vn.insert(pair<int,int>(i,idx));
            pos_index++;
        }
    }
    pos_index=1;
    map<int,int> r_to_tn;
    for(i =1;i<=r_model->numtexcoords;i++){
        bool isSeam= false;
        for(int j=0;j<r_seams_tex_idx.size();j++){if(i==r_seams_tex_idx.at(j)) isSeam=true;break;}
        if(!isSeam){
            int idx = l_model->numtexcoords + pos_index;
            new_model->texcoords[2*idx + 0] = r_model->texcoords[2*i + 0];
            new_model->texcoords[2*idx + 1] = r_model->texcoords[2*i + 1];
            r_to_tn.insert(pair<int,int>(i,idx));
            pos_index++;
        }
    }
    for(i=0;i<r_model->numtriangles;i++){
        int idx = l_model->numtriangles + i;
        new_model->triangles[idx].findex = r_model->triangles[i].findex + l_model->numtriangles;

        for(int j=0;j<3;j++){
            int v_index = r_model->triangles[i].vindices[j];
            int t_index = r_model->triangles[i].tindices[j];
            map<int,int*>::iterator it = r_v_vo_t.find(v_index);
            if(it!=r_v_vo_t.end()){
                int* vo_t = (*it).second;
                int vo = vo_t[0];
                map<int,int*>::iterator itera = l_vo_v_t.find(vo);
                if(itera!=l_vo_v_t.end()){
                    int* v_t = (*itera).second;
                    int v = v_t[0];
                    int t = v_t[1];
                    new_model->triangles[idx].vindices[j] = v;
                    new_model->triangles[idx].tindices[j] = t;
                }
            }
            else{
                map<int,int>::iterator it1 = r_vo_vn.find(v_index);
                if(it1!=r_vo_vn.end())
                    new_model->triangles[idx].vindices[j] = (*it1).second;
                map<int,int>::iterator it2 = r_to_tn.find(t_index);
                if(it2!=r_to_tn.end())
                    new_model->triangles[idx].tindices[j] = (*it2).second;
            }
        }
    }
    //
    qDebug() << "OK + 3";
    FILE* file;
    file = fopen("complete.obj", "w");
    if (!file) {
        fprintf(stderr, "glmWriteOBJ() failed: can't open file \"%s\" to write.\n",
                "complete.obj");
        exit(1);
    }
    for(i=1;i<=new_model->numvertices;i++)
        if(new_model->vertices[3*i + 0] !=-1 &&
                new_model->vertices[3*i + 1] !=-1 &&
                new_model->vertices[3*i + 2] !=-1)
            fprintf(file, "v %f %f %f\n",
                    new_model->vertices[3 * i + 0],
                    new_model->vertices[3 * i + 1],
                    new_model->vertices[3 * i + 2]);
    for(i=1;i<=new_model->numtexcoords;i++){
        if(new_model->texcoords[2*i + 0] != -1 &&
                new_model->texcoords[2*i + 1] != -1)
            fprintf(file, "vt %f %f\n",
                    new_model->texcoords[2 * i + 0],
                    new_model->texcoords[2 * i + 1]);
    }
    for(i=0;i<new_model->numtriangles;i++){

        fprintf(file, "f %d/%d %d/%d %d/%d\n",
                new_model->triangles[i].vindices[0],
                new_model->triangles[i].tindices[0],

                new_model->triangles[i].vindices[1],
                new_model->triangles[i].tindices[1],

                new_model->triangles[i].vindices[2],
                new_model->triangles[i].tindices[2]
                );
    }
    fclose(file);
}
GLvoid testTextureCoordinates(GLMmodel *l_model, GLMmodel* r_model, char *texImageName, std::vector<int> seamsVertex, std::vector<int> seamsTriangle, int* p_max_min, std::map<int, int> l_map, std::map<int, int> r_map,Mesh* l_mesh, Mesh* r_mesh){
    if(l_model->numtexcoords<=0 || r_model->numtexcoords<=0) return;
    // Left
    GLint l_min_x_index = 0;
    GLint l_min_y_index = 0;
    GLint l_max_x_index = 0;
    GLint l_max_y_index = 0;
    GLfloat* tmp_l_texcoords = (GLfloat*)malloc(sizeof(GLfloat) * 2 * (l_model->numtexcoords + 1));
    GLfloat l_scale = 500;

    Vector2* l_P0 = new Vector2; Vector2* l_P1 = new Vector2;
    Vector2* l_P2 = new Vector2; Vector2* l_P3 = new Vector2;
    int i = 0;
    int room = 1;

    getTex_Min_Max_XY_idx(l_min_x_index,l_min_y_index,l_max_x_index,l_max_y_index,l_model);

    for (i = 0 ;i<=l_model->numtexcoords;i++){
        tmp_l_texcoords[2*i + 0] = l_scale*l_model->texcoords[2*i + 0];
        tmp_l_texcoords[2*i + 1] = l_scale*l_model->texcoords[2*i + 1];
    }

    GLfloat l_tex_min_x = tmp_l_texcoords[2*l_min_x_index + 0];
    GLfloat l_tex_min_y = tmp_l_texcoords[2*l_min_y_index + 0];
    GLfloat l_tex_max_x = tmp_l_texcoords[2*l_max_x_index + 1];
    GLfloat l_tex_max_y = tmp_l_texcoords[2*l_max_y_index + 1];

    int l_width = glmAbs(l_tex_max_x - l_tex_min_x) ;
    int l_height = glmAbs(l_tex_max_y - l_tex_min_y);
    // Right
    GLint r_min_x_index = 0;
    GLint r_min_y_index = 0;
    GLint r_max_x_index = 0;
    GLint r_max_y_index = 0;
    GLfloat* tmp_r_texcoords = (GLfloat*)malloc(sizeof(GLfloat) * 2 * (r_model->numtexcoords + 1));
    GLfloat r_scale = 500;

    Vector2* r_P0 = new Vector2; Vector2* r_P1 = new Vector2;
    Vector2* r_P2 = new Vector2; Vector2* r_P3 = new Vector2;

    getTex_Min_Max_XY_idx(r_min_x_index,r_min_y_index,r_max_x_index,r_max_y_index,r_model);

    for (i = 0 ;i<=r_model->numtexcoords;i++){
        tmp_r_texcoords[2*i + 0] = r_scale*r_model->texcoords[2*i + 0];
        tmp_r_texcoords[2*i + 1] = r_scale*r_model->texcoords[2*i + 1];
    }

    GLfloat r_tex_min_x = tmp_r_texcoords[2*r_min_x_index + 0];
    GLfloat r_tex_min_y = tmp_r_texcoords[2*r_min_y_index + 0];
    GLfloat r_tex_max_x = tmp_r_texcoords[2*r_max_x_index + 1];
    GLfloat r_tex_max_y = tmp_r_texcoords[2*r_max_y_index + 1];

    int r_width = glmAbs(r_tex_max_x - r_tex_min_x) ;
    int r_height = glmAbs(r_tex_max_y - r_tex_min_y);
    //
    qDebug() << l_tex_min_x << " " << l_tex_min_y << " " << l_tex_max_x << l_tex_max_y;
    qDebug() << r_tex_min_x << " " << r_tex_min_y << " " << r_tex_max_x << r_tex_max_y;

    int w = l_width + r_width; int h = l_height + r_height + r_height + 100;

    QImage* img = new QImage(w,h ,QImage::Format_RGB32);
    for(int x =0;x<w;x++)
        for(int y=0;y<h;y++) img->setPixel(x,y,qRgb(255,255,255));

    Vector2 l_p_max_seam_x;
    Vector2 l_p_min_seam_x;
    for (i = 0 ;i<=l_model->numtexcoords;i++){
        int posX = (tmp_l_texcoords[2*i + 0]);
        int posY = (tmp_l_texcoords[2*i + 1]);

        posY = posY - h;
        posY = -posY ;
        if(i == p_max_min[0]) {l_p_max_seam_x.x = posX;l_p_max_seam_x.y = posY;}
        if(i == p_max_min[1]) {l_p_min_seam_x.x = posX;l_p_min_seam_x.y = posY;}

        if(i == l_min_x_index) {l_P0->x = posX;l_P0->y = posY;}
        if(i == l_min_y_index) {l_P1->x = posX;l_P1->y = posY;}
        if(i == l_max_x_index) {l_P2->x = posX;l_P2->y = posY;}
        if(i == l_max_y_index) {l_P3->x = posX;l_P3->y = posY;}

        if(posX>=0 && posX<w && posY>=0 && posY<h){
            QRgb rgb = qRgb(0,255,0);
            img->setPixel(posX,posY,rgb);
        }
    }

    Vector2 r_p_max_seam_x;
    Vector2 r_p_min_seam_x;

    for (i = 0 ;i<=r_model->numtexcoords;i++){
        int posX = (tmp_r_texcoords[2*i + 0]) ;
        int posY = (tmp_r_texcoords[2*i + 1]) ;

        posY = (posY - h);
        posY = -posY ;

        if(i == p_max_min[2]) {r_p_max_seam_x.x = posX;r_p_max_seam_x.y = posY;}
        if(i == p_max_min[3]) {r_p_min_seam_x.x = posX;r_p_min_seam_x.y = posY;}

        if(i == r_min_x_index) {r_P0->x = posX;r_P0->y = posY;}
        if(i == r_min_y_index) {r_P1->x = posX;r_P1->y = posY;}
        if(i == r_max_x_index) {r_P2->x = posX;r_P2->y = posY;}
        if(i == r_max_y_index) {r_P3->x = posX;r_P3->y = posY;}

        if(posX>=0 && posX<w && posY>=0 && posY<h){
            QRgb rgb = qRgb(0,0,255);
            img->setPixel(posX,posY,rgb);
        }
    }

    for(i=0;i<seamsVertex.size();i++){
        map<int,int>::iterator it = l_map.find(seamsVertex.at(i));
        if(it!=l_map.end()){
            int vertex_idx  = (*it).second;
            for(int j=0;j<=l_model->numtriangles;j++){
                for(int k = 0;k<3;k++){
                    int idx = l_model->triangles[j].vindices[k];
                    if(idx==vertex_idx){
                        int posX = (tmp_l_texcoords[2*l_model->triangles[j].tindices[k] + 0]);// - l_tex_min_x;
                        int posY = (tmp_l_texcoords[2*l_model->triangles[j].tindices[k] + 1]) ;//- l_tex_min_y;

                        posY = posY - h;
                        posY = -posY ;

                        if(posX>=0 && posX<w && posY>=0 && posY<h){
                            QRgb rgb = qRgb(255,0,0);
                            img->setPixel(posX,posY,rgb);
                        }
                    }
                }
            }
        }
    }
    for(i=0;i<seamsVertex.size();i++){
        map<int,int>::iterator it = r_map.find(seamsVertex.at(i));
        if(it!=r_map.end()){
            int vertex_idx  = (*it).second;
            for(int j=0;j<=r_model->numtriangles;j++){
                for(int k = 0;k<3;k++){
                    int idx = r_model->triangles[j].vindices[k];
                    if(idx==vertex_idx){
                        int posX = (tmp_r_texcoords[2*r_model->triangles[j].tindices[k] + 0]);// - r_tex_min_x;
                        int posY = (tmp_r_texcoords[2*r_model->triangles[j].tindices[k] + 1]);// - r_tex_min_y;

                        posY = posY - h;
                        posY = -posY ;

                        if(posX>=0 && posX<w && posY>=0 && posY<h){
                            QRgb rgb = qRgb(0,0,0);
                            img->setPixel(posX,posY,rgb);
                        }
                    }
                }
            }
        }
    }
    // draw line
    //        QPainter painter; painter.begin(img);
    //        painter.drawLine(QPointF(l_p_max_seam_x.x,l_p_max_seam_x.y),QPointF(l_p_min_seam_x.x,l_p_min_seam_x.y));
    //        painter.drawLine(QPointF(r_p_max_seam_x.x,r_p_max_seam_x.y),QPointF(r_p_min_seam_x.x,r_p_min_seam_x.y));

    //    painter.drawLine(QPointF(l_P0->x,l_P0->y),QPointF(l_P1->x,l_P1->y));
    //    painter.drawLine(QPointF(l_P1->x,l_P1->y),QPointF(l_P2->x,l_P2->y));
    //    painter.drawLine(QPointF(l_P2->x,l_P2->y),QPointF(l_P3->x,l_P3->y));
    //    painter.drawLine(QPointF(l_P3->x,l_P3->y),QPointF(l_P0->x,l_P0->y));
    //        painter.end();
    //
    QImage imgOUT = img->scaled(w*room,h*room);
    QString strName(texImageName);
    imgOUT.save(strName);

    delete img;
    delete tmp_l_texcoords;
    imgOUT = QImage();
}

GLvoid glmWriteOBJ(Mesh* mesh, GLMmodel *model, char filename[128], map<int,int> &map_old_new_index){

    filename[128];
    sprintf(filename,"tmp_%s.obj",mesh->_name);
    FILE*   file;
    /* open the file */
    file = fopen(filename, "w");
    if (!file) {
        fprintf(stderr, "glmWriteOBJ() failed: can't open file \"%s\" to write.\n",
                filename);
        exit(1);
    }

    int new_index = 1;
    foreach(int triangle_index, mesh->triangle_idx){

        GLint v1_old_index = model->triangles[triangle_index].vindices[0];
        GLint v2_old_index = model->triangles[triangle_index].vindices[1];
        GLint v3_old_index = model->triangles[triangle_index].vindices[2];

        map<int,int>::iterator iterv1 = map_old_new_index.find(v1_old_index);
        if(iterv1==map_old_new_index.end()){
            fprintf(file, "v %f %f %f\n",
                    model->vertices[3 * v1_old_index + 0],
                    model->vertices[3 * v1_old_index + 1],
                    model->vertices[3 * v1_old_index + 2]);
            map_old_new_index.insert(pair<int,int>(v1_old_index,new_index));
            new_index++;
        }
        map<int,int>::iterator iterv2 = map_old_new_index.find(v2_old_index);
        if(iterv2==map_old_new_index.end()){
            fprintf(file, "v %f %f %f\n",
                    model->vertices[3 * v2_old_index + 0],
                    model->vertices[3 * v2_old_index + 1],
                    model->vertices[3 * v2_old_index + 2]);
            map_old_new_index.insert(pair<int,int>(v2_old_index,new_index));
            new_index++;
        }
        map<int,int>::iterator iterv3 = map_old_new_index.find(v3_old_index);
        if(iterv3==map_old_new_index.end()){
            fprintf(file, "v %f %f %f\n",
                    model->vertices[3 * v3_old_index + 0],
                    model->vertices[3 * v3_old_index + 1],
                    model->vertices[3 * v3_old_index + 2]);
            map_old_new_index.insert(pair<int,int>(v3_old_index,new_index));
            new_index++;
        }
    }
    //    fprintf(file, "# %d vertices\n", new_index-1);

    foreach(int triangle_index, mesh->triangle_idx){

        int old_v1index = model->triangles[triangle_index].vindices[0];
        int old_v2index = model->triangles[triangle_index].vindices[1];
        int old_v3index = model->triangles[triangle_index].vindices[2];

        int new_v1index=0, new_v2index=0,new_v3index=0;

        //        qDebug() << "old = " << old_v1index << " " << old_v2index << " " << old_v3index;
        map<int,int>::iterator iterv1 = map_old_new_index.find(old_v1index);
        map<int,int>::iterator iterv2 = map_old_new_index.find(old_v2index);
        map<int,int>::iterator iterv3 = map_old_new_index.find(old_v3index);
        if(iterv1 !=map_old_new_index.end()) new_v1index = (*iterv1).second;
        if(iterv2 !=map_old_new_index.end()) new_v2index = (*iterv2).second;
        if(iterv3 !=map_old_new_index.end()) new_v3index = (*iterv3).second;
        //        qDebug() << "new = " << new_v1index << " " << new_v2index << " " << new_v3index;
        if((new_v1index*new_v2index*new_v3index) !=0)
            fprintf(file, "f %d %d %d\n", new_v1index, new_v2index, new_v3index);
    }

    //    fprintf(file, "# %d faces\n", faces.size());
    fclose(file);
}
//========================================Set Y is contants==========================

map<float,map<float,Vector2> > glmGetPointsInLine(GLMmodel* model){

    map<float,map<float,Vector2> > map_Y_PointsIdx;
    for(int i =1; i<=model->numvertices;i++){
        float x = model->vertices[3*i + 0];
        float y = model->vertices[3*i + 1];
        float z = model->vertices[3*i + 2];
        map<float,map<float,Vector2> >::iterator it = map_Y_PointsIdx.find(y);
        Vector2 idx_z(i,z);
        if(it == map_Y_PointsIdx.end()){

            map<float,Vector2> x_idx_z; x_idx_z.insert(pair<float,Vector2>(x,idx_z));
            map_Y_PointsIdx.insert(pair<float,map<float,Vector2> >(y,x_idx_z));
        }
        else (*it).second.insert(pair<float,Vector2>(x,idx_z));
    }
    return map_Y_PointsIdx;
}
GLfloat glmGetTriangleDistance(GLMmodel* model, int tri_id){
    int t_id_0 = model->triangles[tri_id].tindices[0];
    int t_id_1 = model->triangles[tri_id].tindices[1];
    int t_id_2 = model->triangles[tri_id].tindices[2];
    Vector2 p0(model->texcoords[2*t_id_0 + 0], model->texcoords[2*t_id_0 + 1]);
    Vector2 p1(model->texcoords[2*t_id_1 + 0], model->texcoords[2*t_id_1 + 1]);
    Vector2 p2(model->texcoords[2*t_id_2 + 0], model->texcoords[2*t_id_2 + 1]);
    float d01 = sqrt((p0.x - p1.x)*(p0.x - p1.x) + (p0.y - p1.y)*(p0.y - p1.y));
    float d12 = sqrt((p2.x - p1.x)*(p2.x - p1.x) + (p2.y - p1.y)*(p2.y - p1.y));
    float d20 = sqrt((p0.x - p2.x)*(p0.x - p2.x) + (p0.y - p2.y)*(p0.y - p2.y));

    return (d01 + d12 + d20);
}

GLvoid glmComplementPoints(float y, map<float,Vector2> &map_X_idx_z,GLMmodel* model){
    Plane p_Y(0,1,0,-y);
    int i =0;
    for(;i<model->numtriangles;i++){
        int v_id_0 = model->triangles[i].vindices[0];
        int v_id_1 = model->triangles[i].vindices[1];
        int v_id_2 = model->triangles[i].vindices[2];

        Vector3 P0(model->vertices[3*v_id_0 + 0],
                   model->vertices[3*v_id_0 + 1],
                   model->vertices[3*v_id_0 + 2]
                   );
        Vector3 P1(model->vertices[3*v_id_1 + 0],
                   model->vertices[3*v_id_1 + 1],
                   model->vertices[3*v_id_1 + 2]
                   );
        Vector3 P2(model->vertices[3*v_id_2 + 0],
                   model->vertices[3*v_id_2 + 1],
                   model->vertices[3*v_id_2 + 2]
                   );
        if((p_Y.f(P0)>0 && p_Y.f(P1)>0 && p_Y.f(P2)>0) || (p_Y.f(P0)<0 && p_Y.f(P1)<0 && p_Y.f(P2)<0)) continue;
        if(p_Y.f(P0)*p_Y.f(P1)<0){
            Line3 line(P0,P1);
            Vector3 p_intersection = line.getPoint(y);
            Vector2 idx_z(-1,p_intersection.z);
            map_X_idx_z.insert(pair<float,Vector2>(p_intersection.x,idx_z));
        }
    }
}

GLvoid glmComplementPointsInLine(float y, float* &map_xz,int &nb,GLMmodel* model){
    map<float,float> map_x_z;
    float d01_z;
    Plane p_Y(0,1,0,-y);
    int i =0, v_idx_0=-1, v_idx_1=-1, v_idx_2=-1;
    Vector3 P0(0,0,0),P1(0,0,0),P2(0,0,0);
    double f0,f1,f2,f01,f02,f12;
    for(;i<model->numtriangles;i++){

        v_idx_0 = model->triangles[i].vindices[0];
        v_idx_1 = model->triangles[i].vindices[1];
        v_idx_2 = model->triangles[i].vindices[2];
        P0.x = model->vertices[3*v_idx_0 + 0];
        P0.y = model->vertices[3*v_idx_0 + 1];
        P0.z = model->vertices[3*v_idx_0 + 2];

        P1.x = model->vertices[3*v_idx_1 + 0];
        P1.y = model->vertices[3*v_idx_1 + 1];
        P1.z = model->vertices[3*v_idx_1 + 2];

        P2.x = model->vertices[3*v_idx_2 + 0];
        P2.y = model->vertices[3*v_idx_2 + 1];
        P2.z = model->vertices[3*v_idx_2 + 2];

        f0 = p_Y.f(P0);
        f1 = p_Y.f(P1);
        f2 = p_Y.f(P2);
        f01 = f0*f1;
        f02 = f0*f2;
        f12 = f1*f2;
        if((f0>0 && f1>0 && f2>0) || (f0<0 && f1<0 && f2<0)) continue;

        // 0 1

        if(f01<0){
            Line3 line(P0,P1);
            map_x_z.insert(pair<float,float>(line.getPoint(y).x,line.getPoint(y).z));
        }
        if(IsEqualZero(f01)){
            if(IsEqualZero(f1)) map_x_z.insert(pair<float,float>(P1.x,P1.z));
            if(IsEqualZero(f0)) map_x_z.insert(pair<float,float>(P0.x,P0.z));
        }

        // 1 2

        if(f12<0){
            Line3 line(P1,P2);
            map_x_z.insert(pair<float,float>(line.getPoint(y).x,line.getPoint(y).z));
        }
        if(IsEqualZero(f12)){
            if(IsEqualZero(f2)) map_x_z.insert(pair<float,float>(P2.x,P2.z));
            if(IsEqualZero(f1)) map_x_z.insert(pair<float,float>(P1.x,P1.z));
        }

        // 2 0
        if(f02<0){
            Line3 line(P2,P0);
            map_x_z.insert(pair<float,float>(line.getPoint(y).x,line.getPoint(y).z));
        }
        if(IsEqualZero(f02)){
            if(IsEqualZero(f0)) map_x_z.insert(pair<float,float>(P0.x,P0.z));
            if(IsEqualZero(f2)) map_x_z.insert(pair<float,float>(P2.x,P2.z));
        }
    }
    //cout << "size " << map_x_z.size() << endl;

    map<float,float>::iterator it = map_x_z.begin();

    Vector2 first(0,0);
    Vector2 second(0,0);
    if((*it).first <0)
        for(;it!=map_x_z.end();it++)
        {
            first.x = (*it).first;
            first.y = (*it).second;
            if(first.x>=0) break;
            it++;
            if(it!=map_x_z.end()){
                second.x = (*it).first;
                second.y = (*it).second;
            }
            if(first.x<0 && second.x>0) break;
            else {it--; map_x_z.erase(it);}
        }

    it = map_x_z.begin();

    first.x = (*it).first;
    first.y = (*it).second;
    if(first.x>0){
        if(first.x>5) cout << " first x = " << first.x << endl;
        //        Vector2 O(0,first.y);
        map_x_z.insert(pair<float,float>(0,first.y));
    }
    else if(first.x==0) ;
    else{
        //    cout << " x,z ="<< (*it).first << " " <<(*it).second << endl;
        it++;
        second.x = (*it).first;
        second.y = (*it).second;
        //    cout << " x,z ="<< (*it).first << " " <<(*it).second << endl;
        Line2 line(first,second);
        Vector2 O = line.getPoint(0);
        //    cout << "O x,z ="<< O.x << " " << O.y << endl;
        it--;
        //remove first points
        if(first.x<0) map_x_z.erase(it);
        d01_z = (second.y-O.y)/(second.x-O.x);
        if(d01_z>=4) O.y = O.y + (second.y-O.y)/2;
        map_x_z.insert(pair<float,float>(O.x,O.y));
        //            cout << "dz = " << (second.y-O.y)<< " dx = " << (second.x-O.x) << endl;
    }

    nb = map_x_z.size();
    map_xz = (float*) malloc(sizeof(float)*2*nb);
    it = map_x_z.begin();
    int index = 0;
    for(;it!=map_x_z.end();it++,index++){

        map_xz[2*index + 0] = (*it).first;
        map_xz[2*index + 1] = (*it).second;
        if(fabs(map_xz[2*index + 0])>10e+6 || fabs(map_xz[2*index + 1])>10e+6) cout << " Error here y = " << y << endl;
        //        if(index<2)cout << index << " x,z ="<< map_xz[2*index + 0] << " " << map_xz[2*index + 1] << endl;
    }
    map_x_z.clear();

}
int* glmLoadTextureFromFile(const char* filename, int &src_width, int &src_height, int &width, int &height, float* &dh){
    string line;
    ifstream file(filename);
    int x=0,i=0,x_src,y_src;
    int* points;

    float dz=0;
    if(file.is_open()){
        //read file
        int index=0;

        while(file.good()){
            getline(file,line);
            if(line.length()>0){
                vector<string> v_str;
                boost::algorithm::split(v_str,line,boost::algorithm::is_any_of(" "));
                //                cout<< v_str.size() << endl;
                if(index==0)
                {
                    src_width = atoi(v_str.at(1).c_str());
                    src_height = atoi(v_str.at(2).c_str());
                }
                else if(index==1){
                    width = atoi(v_str.at(1).c_str());
                    height = atoi(v_str.at(2).c_str());

                    points = (int*)malloc(sizeof(int)*2*width*height);
                    dh = (float *)malloc(sizeof(float)*width*height);
                    for(i=0;i<(width*height);i++)
                    {
                        points[2*i + 0] = -1;
                        points[2*i + 1] = -1;
                        dh[i] = 0;
                    }
                }
                else{

                    int y = atoi(v_str.at(0).c_str());
                    for(i=1;i<v_str.size()-1;i++){
                        x = i-1;
                        string str = v_str.at(i);
                        if(str!="-" && str.length()>0){
                            vector<string> v_src_xy;
                            boost::algorithm::split(v_src_xy,str,boost::algorithm::is_any_of(","));
                            x_src = atoi(v_src_xy.at(0).c_str());
                            y_src = atoi(v_src_xy.at(1).c_str());
                            dz = atof(v_src_xy.at(2).c_str());
                            points[2*(y*width + x) + 0] = x_src;
                            points[2*(y*width + x) + 1] = y_src;
                            dh[y*width+x] = dz;
                        }
                    }
                }
            }
            index++;
        }
    }
    file.close();
    return points;
}
QImage blurred(const QImage& image, const QRect& rect, int radius, bool alphaOnly)
{
    int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
    int alpha = (radius < 1)  ? 16 : (radius > 17) ? 1 : tab[radius-1];

    QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
    int r1 = rect.top();
    int r2 = rect.bottom();
    int c1 = rect.left();
    int c2 = rect.right();

    int bpl = result.bytesPerLine();
    int rgba[4];
    unsigned char* p;

    int i1 = 0;
    int i2 = 3;

    if (alphaOnly)
        i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);

    for (int col = c1; col <= c2; col++) {
        p = result.scanLine(r1) + col * 4;
        for (int i = i1; i <= i2; i++)
            rgba[i] = p[i] << 4;

        p += bpl;
        for (int j = r1; j < r2; j++, p += bpl)
            for (int i = i1; i <= i2; i++)
                p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
    }

    for (int row = r1; row <= r2; row++) {
        p = result.scanLine(row) + c1 * 4;
        for (int i = i1; i <= i2; i++)
            rgba[i] = p[i] << 4;

        p += 4;
        for (int j = c1; j < c2; j++, p += 4)
            for (int i = i1; i <= i2; i++)
                p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
    }

    for (int col = c1; col <= c2; col++) {
        p = result.scanLine(r2) + col * 4;
        for (int i = i1; i <= i2; i++)
            rgba[i] = p[i] << 4;

        p -= bpl;
        for (int j = r1; j < r2; j++, p -= bpl)
            for (int i = i1; i <= i2; i++)
                p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
    }

    for (int row = r1; row <= r2; row++) {
        p = result.scanLine(row) + c2 * 4;
        for (int i = i1; i <= i2; i++)
            rgba[i] = p[i] << 4;

        p -= 4;
        for (int j = c1; j < c2; j++, p -= 4)
            for (int i = i1; i <= i2; i++)
                p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
    }

    return result;
}
void morphologyErision(QImage &src,int kenel_x, int kenel_y){

    int width = src.width();
    int height = src.height();

    int **dummy = (int**)malloc(width*sizeof(int*));
    for(int i=0; i<width;i++) dummy[i] = (int*)malloc(height*sizeof(int));

    int n2_x = kenel_x/2;
    int n2_y = kenel_y/2;
    if(kenel_y==2){
        for (int i = 0; i < width; ++i)
            for (int j = 0; j < height; ++j)
            {
                dummy[i][j] = INT_MAX;
                for (int k = -n2_x; k <= n2_x; ++k)
                    for (int l = 0; l <= n2_y; ++l)
                        if (!(i+k < 0 || i+k >= width || j+l < 0
                              || j+l >= height)
                                && qGray(src.pixel(i+k,j+l)) < dummy[i][j])
                        {
                            dummy[i][j] = qGray(src.pixel(i+k,j+l));
                        }
            }
    }
    else{
        // Erision
        for (int i = 0; i < width; ++i)
            for (int j = 0; j < height; ++j)
            {
                dummy[i][j] = INT_MAX;
                for (int k = -n2_x; k <= n2_x; ++k)
                    for (int l = -n2_y; l <= n2_y; ++l)
                        if (!(i+k < 0 || i+k >= width || j+l < 0
                              || j+l >= height)
                                && qGray(src.pixel(i+k,j+l)) < dummy[i][j])
                        {
                            dummy[i][j] = qGray(src.pixel(i+k,j+l));
                        }
            }
    }
    for (int i = 0; i < width; ++i)
        for (int j = 0; j < height; ++j)
            src.setPixel(i,j,qRgb(dummy[i][j],dummy[i][j],dummy[i][j]));

    for(int i=0;i<width;i++) {free(dummy[i]); dummy[i]=NULL;}
    free(dummy); dummy=NULL;

}
void morphologyErision(QImage &src,int kenel){

    int width = src.width();
    int height = src.height();

    int **dummy = (int**)malloc(width*sizeof(int*));
    for(int i=0; i<width;i++) dummy[i] = (int*)malloc(height*sizeof(int));

    int n2 = kenel/2;
    // Erision
    for (int i = 0; i < width; ++i)
        for (int j = 0; j < height; ++j)
        {
            dummy[i][j] = INT_MAX;
            for (int k = -n2; k <= n2; ++k)
                for (int l = -n2; l <= n2; ++l)
                    if (!(i+k < 0 || i+k >= width || j+l < 0
                          || j+l >= height)
                            && qGray(src.pixel(i+k,j+l)) < dummy[i][j])
                    {
                        dummy[i][j] = qGray(src.pixel(i+k,j+l));
                    }
        }

    for (int i = 0; i < width; ++i)
        for (int j = 0; j < height; ++j)
            src.setPixel(i,j,qRgb(dummy[i][j],dummy[i][j],dummy[i][j]));

    for(int i=0;i<width;i++) {free(dummy[i]); dummy[i]=NULL;}
    free(dummy); dummy=NULL;

}
void morphologyDilatation(QImage &src,int k){

    int width = src.width();
    int height = src.height();

    int **dummy = (int**)malloc(width*sizeof(int*));
    for(int i=0; i<width;i++) dummy[i] = (int*)malloc(height*sizeof(int));

    int n2 = k/2;

    //Dilatation
    for (int i = 0; i < width; ++i)
        for (int j = 0; j < height; ++j)
        {
            dummy[i][j] = INT_MIN;
            for (int k = -n2; k <= n2; ++k)
                for (int l = -n2; l <= n2; ++l)
                    if (!(i+k < 0 || i+k >= width || j+l < 0
                          || j+l >= height)
                            && qGray(src.pixel(i+k,j+l)) > dummy[i][j])
                        dummy[i][j] = qGray(src.pixel(i+k,j+l));
        }

    for (int i = 0; i < width; ++i)
        for (int j = 0; j < height; ++j)
            src.setPixel(i,j,qRgb(dummy[i][j],dummy[i][j],dummy[i][j]));

    for(int i=0;i<width;i++) {free(dummy[i]); dummy[i]=NULL;}
    free(dummy); dummy=NULL;
}
void morphologyClosing(QImage &src,int k){

    //Dilatation
    morphologyDilatation(src,k);
    // Erision
    morphologyErision(src,k);
}
GLvoid glmGenerateImage(const char *filename, QString folder){

    QDir dir(folder);
    QStringList filters;
    filters << "*.png";
    dir.setNameFilters(filters);
    QStringList listFileNames = dir.entryList();

    int src_width=8555,src_height=16281, width, height;
    cout << " reading...."<< endl;
    float* dh;
    int* points = glmLoadTextureFromFile(filename,src_width,src_height,width,height,dh);
    //    cout << " reading....OK src_width = " << src_width << " src_height= "<< src_height << " width = " << width << " height= " << height<< endl;
    /** Musique **/ QImage src = QImage(src_width,src_height,QImage::Format_RGB32);/**/
    QImage* out = new QImage(width,height,QImage::Format_RGB32);

    foreach(QString file, listFileNames){

        QString filePath = dir.absoluteFilePath(file);
        QImage src_in(filePath);
        int src_in_width = src_in.width();
        int src_in_height = src_in.height();

        /** Musique **/
        int h = src_in.height()*src_width/(src_in.width());
        QImage src_in_scale= src_in.scaled(src_width,h);
        // reset src
        int ex_h = src_height/3;
        int y1 = 0;
        for(int y = 0;y<src_height;y++){
            y1 = y- ex_h;
            if(y1>=0 && y1<h){
                for(int x = 0;x<src_width;x++){
                    src.setPixel(x,y,src_in_scale.pixel(x,y1));
                }
            }
            else
                for(int x = 0;x<src_width;x++){
                    //                    src.setPixel(x,y,qRgb(0,0,0));
                    src.setPixel(x,y,qRgb(255,255,255));
                }
        }
        // bind data
        int x_src,y_src,dx=0,x_src_1, out_y0_cut=-1, out_y1_cut=-1;
        for(int y = 0;y<height-1;y++){
            for(int x = 0;x<width;x++){
                x_src = points[2*(y*width + x) + 0];
                y_src = points[2*(y*width + x) + 1];
                //
                x_src_1 = points[2*((y+1)*width + x) + 0];
                dx = x_src_1 - x_src;
                if(abs(dx)>2){
                    if((x_src + dx/2)>=0) x_src = x_src + dx/2;
                    if((x_src_1 - dx/2)>=0) x_src_1 = x_src_1 - dx/2;
                    points[2*(y*width + x) + 0] = x_src;
                    points[2*((y+1)*width + x) + 0] = x_src_1;
                }
                //
                if(x_src>=0 && y_src>=0 && x_src<src_width && y_src< src_height){
                    if(y_src==ex_h) out_y0_cut = y;
                    if(y_src==(ex_h + h)) out_y1_cut=y;
                    out->setPixel(x,y,src.pixel(x_src,y_src));
                }
                else out->setPixel(x,y,qRgb(255,255,255));
            }

        }
        QImage out_cut = out->copy(0,out_y0_cut,width,(out_y1_cut-out_y0_cut));

        cout << " morphological.........." << endl;
        int k_mor = 3;
        QString outFile("method2/");outFile.append(file);
        outFile.append("_mor");outFile.append(QString::number(k_mor));

        morphologyClosing(out_cut,k_mor);

        int k_blur =2;
        outFile.append("_blur");
        outFile.append(QString::number(k_blur));
        cout << " Gausien blur............." << endl;

        QImage out_blurred = blurred(out_cut,out_cut.rect(),k_blur);

        outFile.append("_scaled.png");
        QImage out_scaled = out_blurred.scaled(src_in_width,src_in_height);
        qDebug() << outFile;
        out_scaled.save(outFile);
        /**/
    }

    delete out;
    delete points;
}

GLvoid glmGenerateImage(const char *filename, QImage* &src_in, QString outFileName){

    QString outFile("method2/");
    outFile.append(outFileName);

    int src_width,src_height, width, height;
    cout << " reading...."<< endl;
    float *dh;
    int* points = glmLoadTextureFromFile(filename,src_width,src_height,width,height,dh);
    cout << " reading....OK src_width = " << src_width << " src_height= "<< src_height << " width = " << width << " height= " << height<< endl;

    int src_in_width = src_in->width();
    int src_in_height = src_in->height();

    QImage src = src_in->scaled(src_width,src_height);
    QImage* out = new QImage(width,height,QImage::Format_ARGB32);

    int x_src,y_src,dx=0,x_src_1;
    float dz, L=4000;
    float l0=2*L/3;
    float r,g,b;
    for(int y = 0;y<height-1;y++){
        for(int x = 0;x<width;x++){
            x_src = points[2*(y*width + x) + 0];
            y_src = points[2*(y*width + x) + 1];
            dz = dh[y*width + x];
            //
            x_src_1 = points[2*((y+1)*width + x) + 0];
            dx = x_src_1 - x_src;
            if(abs(dx)>2){
                if((x_src + dx/2)>=0) x_src = x_src + dx/2;
                if((x_src_1 - dx/2)>=0) x_src_1 = x_src_1 - dx/2;
                points[2*(y*width + x) + 0] = x_src;
                points[2*((y+1)*width + x) + 0] = x_src_1;
            }
            //
            if(x_src>=0 && y_src>=0 && x_src<src_width && y_src< src_height){
                dz = L - dz;
                dz = l0/dz;
                dz = dz*dz;
                QColor rgb(src.pixel(x_src,y_src));
                r = rgb.red()*dz; if(r>255) r=255; if(r<0) r=0;
                g = rgb.green()*dz; if(g>255) r=255; if(g<0) r=0;
                b = rgb.blue()*dz; if(b>255) r=255; if(b<0) r=0;
                out->setPixel(x,y,qRgb(r,g,b));
            }
            else out->setPixel(x,y,qRgb(255,255,255));
        }
    }
    cout << " morphological.........." << endl;
    int k_mor = 3;
    outFile.append("_mor");outFile.append(QString::number(k_mor));
    //    out->save("method2/OXYZMapping_correction.txt.png");
    morphologyClosing(*out,k_mor);
    //    out->save("method2/OXYZMapping_correction_morphological.txt.png");
    int k_blur =2;
    outFile.append("_blur");
    outFile.append(QString::number(k_blur));
    cout << " Gausien blur............." << endl;

    QImage out_blurred = blurred(*out,out->rect(),k_blur);
    //    out_blurred.save(QString::fromStdString(ssFileOut.str()));
    outFile.append("_scaled.png");
    QImage out_scaled = out_blurred.scaled(src_in_width,src_in_height);
    qDebug() << outFile;
    out_scaled.save(outFile);

    delete points;
    delete out;
    delete src_in;
}
/** METHOD II*/
GLvoid glmGenerateImage(GLMmodel* model, QString outFileName, float ratewh/*rate of width and height*/){
    ratewh = 0.7070707;
    float min_x = INT_MAX;
    map<string,int> map_y;
    int i=1;
    map<string,int>::iterator it = map_y.begin();

    for(i=1;i<=model->numvertices;i++){
        if(min_x>model->vertices[3*i + 0]) {min_x = model->vertices[3*i+0];}
    }
    for(i=1;i<=model->numvertices;i++){
        model->vertices[3*i+0] = model->vertices[3*i+0] - min_x;
    }

    for(i=1;i<=model->numvertices;i++){
        stringstream ss;
        ss << model->vertices[3*i+1];
        it = map_y.find(ss.str());
        if(it==map_y.end())
            map_y.insert(pair<string,int>(ss.str(),i));
    }
    cout << " number y = " << map_y.size() << endl;
    int height = map_y.size()/50;
    int width = map_y.size()*ratewh;
    float *points = (float *)malloc(sizeof(float)*3*height*width);

    for(i=0;i<(height*width);i++) {
        points[3*i + 0] = 0;
        points[3*i + 1] = 0;
        points[3*i + 2] = 0;
    }
    cout << "height = " << height << " width = " << width << endl;
    float y;
    double Xstep= 146.048/(double)width;
    double Lmax = INT_MIN,s = 0, dx=0, dz=0;
    int ONE_PERCENT = height*0.01, index=0;
    //
    Vector3 p_perspective(width/2,0,5000);
    double f = 3500;
    Vector3 p_curved_page(0,0,0);
    Vector3 p_PXYZ(0,0,0);
    Vector3 p_perdistortion(0,0,0);
    Vector3 p_symmethic(0,0,0);
    Vector3 p_OXYZ(0,0,0);

    for(it=map_y.begin();it!=map_y.end();it++,index++){
        // parse y
        y = atof((*it).first.c_str());
        if(index%ONE_PERCENT==0) cout << (index/ONE_PERCENT) << endl;
        if(index/ONE_PERCENT==2) break;
        // get the list of intersection points = ligne 3D.
        float *map_xzidx;
        int nb, xzidx_index_max;
        glmScanline1(y,(*it).second,xzidx_index_max,map_xzidx,nb,model);
        // divide the ligne 3D by number of pixels per row = width
        double L=0.0, dL=0.0, ds=0.0;
        int idx=0;
        if(map_xzidx && nb>0){
            for(i=0;i<(nb-1);i++){
                dx = (map_xzidx[3*i+0] - map_xzidx[3*(i+1)+0]);
                dz = (map_xzidx[3*i+1] - map_xzidx[3*(i+1)+1]);
                s = sqrt( dx*dx+ dz*dz);
                L +=s;
                //                int counter = idx;
                if(IsEqualZero(dL)){
                    //                    cout << "\t L=" << L << " s=" << s << " dL=0" << endl;
                    points[3*(index*width +idx) +0] = map_xzidx[3*i+0];
                    points[3*(index*width +idx) +1] = y;
                    points[3*(index*width +idx) +2] = map_xzidx[3*i+1];
                    idx++;
                    if(s>Xstep){
                        ds = s - Xstep;
                        while(ds>Xstep){
                            points[3*(index*width +idx) +0] = map_xzidx[3*i+0]*(1 - (s - ds)/s) + (map_xzidx[3*(i+1)+0])*(s-ds)/s;
                            points[3*(index*width +idx) +1] = y;
                            points[3*(index*width +idx) +2] = map_xzidx[3*i+1]*(1 - (s - ds)/s) + (map_xzidx[3*(i+1)+1])*(s-ds)/s;;
                            idx++;
                            ds = ds - Xstep;
                        }
                    } else dL = s;
                } else { //dL > 0
                    //                    cout << "\t L=" << L << " s=" << s << " dL # 0" << endl;
                    if((s + dL)>Xstep){
                        ds = Xstep - dL;
                        points[3*(index*width +idx) +0] = map_xzidx[3*i+0]*(1 - ds/s) + (map_xzidx[3*(i+1)+0])*ds/s;
                        points[3*(index*width +idx) +1] = y;
                        points[3*(index*width +idx) +2] = map_xzidx[3*i+1]*(1 - ds/s) + (map_xzidx[3*(i+1)+1])*ds/s;
                        idx++;
                        ds = s - ds;
                        while(ds>Xstep){
                            points[3*(index*width +idx) +0] = map_xzidx[3*i+0]*(1 - (s - ds)/s) + (map_xzidx[3*(i+1)+0])*(s-ds)/s;
                            points[3*(index*width +idx) +1] = y;
                            points[3*(index*width +idx) +2] = map_xzidx[3*i+1]*(1 - (s - ds)/s) + (map_xzidx[3*(i+1)+1])*(s-ds)/s;
                            idx++;
                            ds = ds -Xstep;
                        }
                        dL = ds;
                    } else dL +=s;
                }
                //                cout << "\t p" <<i << " to p" << (i+1) <<" dis = " << s << "nb pixels ="<< (idx-counter-1)<< endl;
            }
        }
        //        cout << "y="<< y << " nb=" << nb << " L=" << L << " idx = " << idx  << " idx cal= " << (Xstep)<< endl;
        //        if(L>Lmax) Lmax = L;
        // release memory
        delete map_xzidx;
        break;
    }
    cout << Lmax << endl;
    //    delete points;
}

GLvoid glmScanline1(float y0, int v_y0_idx,int &xzidx_index, float* &map_xzidx,int &nb,GLMmodel* model){

    map<float,vector<float> > map_x_z;
    Plane p_Y(0,1,0,-y0);
    int i =0;

    int v_id_0 = -1,v_id_1 = -1,v_id_2 = -1;
    float f0,f1,f2,f01,f12,f02,f012;
    Vector3 P0(0,0,0); Vector3 P1(0,0,0); Vector3 P2(0,0,0);

    for(;i<model->numtriangles;i++){
        v_id_0 = model->triangles[i].vindices[0];
        v_id_1 = model->triangles[i].vindices[1];
        v_id_2 = model->triangles[i].vindices[2];

        P0.x = model->vertices[3*v_id_0 + 0];
        P0.y = model->vertices[3*v_id_0 + 1];
        P0.z = model->vertices[3*v_id_0 + 2];

        P1.x = model->vertices[3*v_id_1 + 0];
        P1.y = model->vertices[3*v_id_1 + 1];
        P1.z = model->vertices[3*v_id_1 + 2];

        P2.x = model->vertices[3*v_id_2 + 0];
        P2.y = model->vertices[3*v_id_2 + 1];
        P2.z = model->vertices[3*v_id_2 + 2];

        f0 = p_Y.f(P0); if(v_id_0==v_y0_idx) f0=0;
        f1 = p_Y.f(P1); if(v_id_1==v_y0_idx) f1=0;
        f2 = p_Y.f(P2); if(v_id_2==v_y0_idx) f2=0;
        f01 =f0*f1;
        f02 =f0*f2;
        f12 =f1*f2;
        f012 =f0*f1*f2;

        if((f0>0 && f1>0 && f2>0) || (f0<0 && f1<0 && f2<0)) continue;

        //        cout << "f0, f1, f2 " << f0 << " " << f1 << " " << f2 << " f01 f02 f12 " << f01 << " " << f02 << " " << f12 << endl;
        if(!IsEqualZero(f012)){
            if(f01<0){
                Line3 line01(P0,P1);
                Vector3 p_intersection01 = line01.getPoint(y0);

                vector<float> z_idx01; z_idx01.push_back(p_intersection01.z);z_idx01.push_back(-1);
                map_x_z.insert(pair<float,vector<float> >(p_intersection01.x,z_idx01));
            }
            if(f02<0){
                Line3 line02(P0,P2);
                Vector3 p_intersection02 = line02.getPoint(y0);
                vector<float> z_idx02; z_idx02.push_back(p_intersection02.z);z_idx02.push_back(-1);

                map_x_z.insert(pair<float,vector<float> >(p_intersection02.x,z_idx02));

            }
            if(f12<0){
                Line3 line12(P1,P2);
                Vector3 p_intersection12 = line12.getPoint(y0);
                vector<float> z_idx12; z_idx12.push_back(p_intersection12.z);z_idx12.push_back(-1);
                map_x_z.insert(pair<float,vector<float> >(p_intersection12.x,z_idx12));
            }
        }
        else{ // f012 = 0 => f0 = 0 || f1 = 0 || f2 = 0;
            if(IsEqualZero(f0)){
                vector<float> z_idx0; z_idx0.push_back(P0.z);z_idx0.push_back(v_id_0);
                map_x_z.insert(pair<float,vector<float> >(P0.x,z_idx0));
                if(f12<0){ // f0 = 0 && f12<0
                    Line3 line12(P1,P2);
                    Vector3 p_intersection12 = line12.getPoint(y0);
                    vector<float> z_idx12; z_idx12.push_back(p_intersection12.z);z_idx12.push_back(-1);
                    map_x_z.insert(pair<float,vector<float> >(p_intersection12.x,z_idx12));
                }
                else if(IsEqualZero(f12)){ // f0 = 0 && (f1 = 0 || f2 = 0)
                    if(IsEqualZero(f1)){
                        vector<float> z_idx1; z_idx1.push_back(P1.z);z_idx1.push_back(v_id_1);
                        map_x_z.insert(pair<float,vector<float> >(P1.x,z_idx1));
                    }
                    if(IsEqualZero(f2)){
                        vector<float> z_idx2; z_idx2.push_back(P2.z);z_idx2.push_back(v_id_2);
                        map_x_z.insert(pair<float,vector<float> >(P2.x,z_idx2));
                    }
                }
                else;
            }
            else{
                //f0 # 0 => f1 = 0 || f2 = 0 || f1=0 && f2=0;
                if(IsEqualZero(f1) && !IsEqualZero(f2)){ // f1 = 0 & f2 # 0
                    vector<float> z_idx1; z_idx1.push_back(P1.z);z_idx1.push_back(v_id_1);
                    map_x_z.insert(pair<float,vector<float> >(P1.x,z_idx1));

                    if(f02<0){
                        Line3 line02(P0,P2);
                        Vector3 p_intersection02 = line02.getPoint(y0);
                        vector<float> z_idx02; z_idx02.push_back(p_intersection02.z);z_idx02.push_back(-1);
                        map_x_z.insert(pair<float,vector<float> >(p_intersection02.x,z_idx02));
                    }
                }
                if(IsEqualZero(f2) && !IsEqualZero(f1)){ // f1 # 0 & f2 = 0
                    vector<float> z_idx2; z_idx2.push_back(P2.z);z_idx2.push_back(v_id_2);
                    map_x_z.insert(pair<float,vector<float> >(P2.x,z_idx2));

                    if(f01<0){
                        Line3 line01(P0,P1);
                        Vector3 p_intersection01 = line01.getPoint(y0);
                        vector<float> z_idx01; z_idx01.push_back(p_intersection01.z);z_idx01.push_back(-1);
                        map_x_z.insert(pair<float,vector<float> >(p_intersection01.x,z_idx01));
                    }
                }
                if(IsEqualZero(f1) && IsEqualZero(f2)){// f1 = 0 & f2 = 0
                    vector<float> z_idx1; z_idx1.push_back(P1.z);z_idx1.push_back(v_id_1);
                    map_x_z.insert(pair<float,vector<float> >(P1.x,z_idx1));
                    vector<float> z_idx2; z_idx2.push_back(P2.z);z_idx2.push_back(v_id_2);
                    map_x_z.insert(pair<float,vector<float> >(P2.x,z_idx2));

                }
            }
        }
    }

    int index=0;
    map<float,vector<float> >::iterator it = map_x_z.begin();
    //vector<float> zero_point;zero_point.push_back((*it).second.at(0));zero_point.push_back(-1);
    //map_x_z.insert(pair<float,vector<float> >(0,zero_point));

    nb = map_x_z.size();
    map_xzidx = (float*)malloc(sizeof(float)*3*nb);

    it = map_x_z.begin();
    for(;it!=map_x_z.end();it++,index++){

        map_xzidx[3*index + 0] = (*it).first;
        map_xzidx[3*index + 1] = (*it).second.at(0);
        map_xzidx[3*index + 2] =  (*it).second.at(1);
        if((*it).second.at(1)>=0) xzidx_index=index;
    }
    map_x_z.clear();
}
GLvoid glmGenerateImage(GLMmodel* model,QString outFileName){
    QString path_out("method2/"); path_out.append(outFileName);

    int i =0;
    int scale =150;
    float max_x = INT_MIN,max_y = INT_MIN;int max_x_idx = INT_MIN, max_y_idx = INT_MIN;
    float min_x = INT_MAX,min_y = INT_MAX;int min_x_idx = INT_MAX, min_y_idx = INT_MAX;
    float min_z = INT_MAX; int min_z_idx = INT_MAX;
    float max_z = INT_MIN; int max_z_idx = INT_MIN;
    for(i=1;i<=model->numvertices;i++){
        if(min_x > model->vertices[3*i + 0]) {min_x = model->vertices[3*i + 0]; min_x_idx = i;}
        if(max_x < model->vertices[3*i + 0]) {max_x = model->vertices[3*i + 0]; max_x_idx = i;}

        if(min_y > model->vertices[3*i + 1]) {min_y = model->vertices[3*i + 1]; min_y_idx = i;}
        if(max_y < model->vertices[3*i + 1]) {max_y = model->vertices[3*i + 1]; max_y_idx = i;}

        if(min_z > model->vertices[3*i + 2]) {min_z = model->vertices[3*i + 2]; min_z_idx = i;}
        if(max_z < model->vertices[3*i + 2]) {max_z = model->vertices[3*i + 2]; max_z_idx = i;}
        model->vertices[3*i+0]= scale*model->vertices[3*i+0];
        model->vertices[3*i+1]= scale*model->vertices[3*i+1];
        model->vertices[3*i+2]= scale*model->vertices[3*i+2];

    }
    glmRotateAroundMean(model->vertices,model->numvertices);
    //
    Vector3 p_min_x(model->vertices[3*min_x_idx + 0],
                    model->vertices[3*min_x_idx + 1],
                    model->vertices[3*min_x_idx + 2]);

    for(i=1;i<=model->numvertices;i++){
        model->vertices[3*i+0]= model->vertices[3*i+0] - p_min_x.x;
        model->vertices[3*i+1]= model->vertices[3*i+1] - p_min_x.y;
        model->vertices[3*i+2]= model->vertices[3*i+2] - p_min_x.z;
    }

    Vector3 p_min_z(0,0,model->vertices[3*min_z_idx + 2]);

    for(i=1;i<=model->numvertices;i++){
        model->vertices[3*i+0]= model->vertices[3*i+0] - p_min_z.x;
        model->vertices[3*i+1]= model->vertices[3*i+1] - p_min_z.y;
        model->vertices[3*i+2]= model->vertices[3*i+2] - p_min_z.z;
    }
    // For the sight page
    //    map<float,int> map_y_idx;
    Vector3 p_move_x(100,0,0);
    for(i=1;i<=model->numvertices;i++){
        model->vertices[3*i+0]= model->vertices[3*i+0] - p_move_x.x;
        //        map_y_idx.insert(pair<float,int>(model->vertices[3*i+1],i));
    }
    //    map<float,int>::iterator it = map_y_idx.begin();
    //    for(;it!=map_y_idx.end();it++){
    //        cout << (*it).first << endl;
    //    }

    max_x = model->vertices[3*max_x_idx + 0];
    min_x = model->vertices[3*min_x_idx + 0];

    max_y = model->vertices[3*max_y_idx + 1];
    min_y = model->vertices[3*min_x_idx + 1];

    max_z = model->vertices[3*max_z_idx + 2];
    min_z = model->vertices[3*min_z_idx + 2];

    cout << "max x " << model->vertices[3*max_x_idx + 0] << " y= "<< model->vertices[3*max_x_idx + 1] << endl;
    cout << min_x << " " << max_x << endl;
    cout << min_y << " " << max_y << endl;
    cout << min_z << " " << max_z << endl;

    int width_flat_page = max_x - min_x + 100;//livre23-l 9200//glmGetMaxWidth(model,(int)max_y);//15600 livre1-r////9600;//
    int height_flat_page = max_y - min_y;

    cout << "max x = "<< width_flat_page << endl;

    int nb_points = height_flat_page*width_flat_page;

    int depth  = 3;
    int index = 0, idx_iX=0,idx_iY=1,idx_fX=0,idx_fY=1,idx_fZ=2;
    float* pointsF = (float *)malloc(sizeof(float)*depth*nb_points);
    unsigned short* pointsI = ( unsigned short* )malloc(sizeof( unsigned short)*2*nb_points);

    Vector3 perspective(width_flat_page/3,height_flat_page/2,5000);//5000 for livre23_l //(max_x - min_x)/5
    float f = 3500;//3500
    float l0 = perspective.z -1000;
    float dh=0;
    Vector3 p_curved_page(0,0,0);
    Vector3 p_PXYZ(0,0,0);
    Vector3 p_perdistortion(0,0,0);
    Vector3 p_symmethic(0,0,0);
    Vector3 p_OXYZ(0,0,0);

    Vector2 first(0,0);
    Vector2 second(0,0);

    cout << " begin" << endl;
    float x_curved_max = INT_MIN, y_curved_max = INT_MIN; int  x_curved_max_idx = INT_MIN, y_curved_max_idx = INT_MIN;
    float x_curved_min = INT_MAX, y_curved_min = INT_MAX; int x_curved_min_idx = INT_MAX, y_curved_min_idx = INT_MAX;

    int y_key =0,x_key=0;
    map<int,vector<int> > region_idx;
    map<int,vector<int> >::iterator iter;

//    FILE* fdata; fdata = fopen("data.txt","w"); if(!fdata){cout << "ERROR"<<endl;}
    int per = height_flat_page*0.01;
    for(int y=0;y<=height_flat_page;y++){
        if(y%per==0) cout << (y/per) << endl;
        float* map_xz;
        int nb_elements;

        glmComplementPointsInLine(y,map_xz,nb_elements,model);

        perspective.y = y + 1000; // symmethic over plan

        p_curved_page.x = 0;
        p_curved_page.y = y;
        p_curved_page.z = map_xz[2*0 + 1];

        // tranlate to Perspective
        p_PXYZ.x = p_curved_page.x - perspective.x;
        p_PXYZ.y = p_curved_page.y - perspective.y;
        p_PXYZ.z = p_curved_page.z - perspective.z;

        // perspective distortion
        p_perdistortion.x = (f)*p_PXYZ.x/(float)p_PXYZ.z;
        p_perdistortion.y = (f)*p_PXYZ.y/(float)p_PXYZ.z;
        p_perdistortion.z = f;
        // getting the symmetric coordinates over OZ
        p_symmethic.x = - p_perdistortion.x;
        p_symmethic.y = - p_perdistortion.y;
        p_symmethic.z =   p_perdistortion.z;
        // tranlate to OXYZ
        p_OXYZ.x = p_symmethic.x + perspective.x;
        p_OXYZ.y = p_symmethic.y + perspective.y;
        p_OXYZ.z = p_symmethic.z + perspective.z;
        /**/

//        fprintf(fdata,"%d %d %0.4f %0.4f %0.4f\n", 0,y,p_OXYZ.x,p_OXYZ.y,p_curved_page.z);
//        y_key = floor(p_OXYZ.y);
//        iter = region_idx.find(y_key);
//        if(iter==region_idx.end()){
//            vector<int> idx;idx.push_back(index);
//            region_idx.insert(pair<int,vector<int> >(y_key,idx));
//        }
//        else (*iter).second.push_back(index);
        pointsI[2*index + idx_iX] = 0;
        pointsI[2*index + idx_iY] = y;
//        pointsF[depth*index + idx_iY] = y;
//        pointsF[depth*index + idx_iX] = 0;
        pointsF[depth*index + idx_fX] = p_OXYZ.x;
        pointsF[depth*index + idx_fY] = p_OXYZ.y;
        pointsF[depth*index + idx_fZ] = p_curved_page.z;

        if(x_curved_max<p_OXYZ.x) {x_curved_max = p_OXYZ.x;x_curved_max_idx=index;}
        if(x_curved_min>p_OXYZ.x) {x_curved_min = p_OXYZ.x;x_curved_min_idx=index;}
        if(y_curved_max<p_OXYZ.y) {y_curved_max = p_OXYZ.y;y_curved_max_idx=index;}
        if(y_curved_min>p_OXYZ.y) {y_curved_min = p_OXYZ.y;y_curved_min_idx=index;}

        index++;

        float ds = 0, dl=0, s = 0, dz=0;
        int x_INT=0, dL =0,x_i;
        bool is_max_x = false;

        for(i =0;i<nb_elements-1;i++)
        {
            first.x = map_xz[2*i +0] ;
            first.y = map_xz[2*i +1];
            second.x = map_xz[2*(i+1) +0];
            second.y = map_xz[2*(i+1) +1];

            dl = sqrt((second.x-first.x)*(second.x-first.x) + (second.y-first.y)*(second.y-first.y));

            s += dl;
            dL = dl + ds;

            if(dL>=1){

                x_i = x_INT + 1;
                for(;x_i<=(x_INT + dL);x_i++){
                    if(x_i>=width_flat_page){ is_max_x = true;break;}
                    //
                    dz = x_i - x_INT - ds;
                    //
                    p_curved_page.x = first.x*(1- dz/dl) + second.x*dz/dl;//line.v0.x + line.n.x*t;
                    p_curved_page.y = y;
                    p_curved_page.z = first.y*(1- dz/dl) + second.y*dz/dl;;//line.v0.y + line.n.y*t;
                    // tranlate to Perspective
                    p_PXYZ.x = p_curved_page.x - perspective.x;
                    p_PXYZ.y = p_curved_page.y - perspective.y;
                    p_PXYZ.z = p_curved_page.z - perspective.z;
                    // perspective distortion
                    p_perdistortion.x = (f)*p_PXYZ.x/(float)p_PXYZ.z;
                    p_perdistortion.y = (f)*p_PXYZ.y/(float)p_PXYZ.z;
                    p_perdistortion.z = f;
                    // getting the symmetric coordinates over OZ
                    p_symmethic.x = - p_perdistortion.x;
                    p_symmethic.y = - p_perdistortion.y;
                    p_symmethic.z =   p_perdistortion.z;
                    // tranlate to OXYZ
                    p_OXYZ.x = p_symmethic.x + perspective.x;
                    p_OXYZ.y = p_symmethic.y + perspective.y;
                    p_OXYZ.z = p_symmethic.z + perspective.z;

//                    fprintf(fdata,"%d %d %0.4f %0.4f %0.4f\n", x_i,y,p_OXYZ.x,p_OXYZ.y,p_curved_page.z);
//                    y_key = floor(p_OXYZ.y);
//                    iter = region_idx.find(y_key);
//                    if(iter==region_idx.end()){
//                        vector<int> idx;idx.push_back(index);
//                        region_idx.insert(pair<int,vector<int> >(y_key,idx));
//                    }
//                    else (*iter).second.push_back(index);

                    pointsI[2*index + idx_iX] = x_i;
                    pointsI[2*index + idx_iY] = y;
//                    pointsF[depth*index + idx_iX] = x_i;
//                    pointsF[depth*index + idx_iY] = y;
                    pointsF[depth*index + idx_fX] = p_OXYZ.x;
                    pointsF[depth*index + idx_fY] = p_OXYZ.y;
                    pointsF[depth*index + idx_fZ] = p_curved_page.z;

                    if(x_curved_max<p_OXYZ.x) {x_curved_max = p_OXYZ.x;x_curved_max_idx=index;}
                    if(x_curved_min>p_OXYZ.x) {x_curved_min = p_OXYZ.x;x_curved_min_idx=index;}
                    if(y_curved_max<p_OXYZ.y) {y_curved_max = p_OXYZ.y;y_curved_max_idx=index;}
                    if(y_curved_min>p_OXYZ.y) {y_curved_min = p_OXYZ.y;y_curved_min_idx=index;}

                    index++;
                }
                x_INT = x_i-1;
                ds = dl - dz;
            }
            if(is_max_x)break;
        }

        if((width_flat_page - x_INT-1)>0 && (width_flat_page - x_INT-1)<4500){
            x_INT++;

            for(;x_INT<width_flat_page;x_INT++){
                p_curved_page.x = p_curved_page.x + 1;
                // tranlate to Perspective
                p_PXYZ.x = p_curved_page.x - perspective.x;
                p_PXYZ.y = p_curved_page.y - perspective.y;
                p_PXYZ.z = p_curved_page.z - perspective.z;
                // perspective distortion
                p_perdistortion.x = (f)*p_PXYZ.x/(float)p_PXYZ.z;
                p_perdistortion.y = (f)*p_PXYZ.y/(float)p_PXYZ.z;
                p_perdistortion.z = f;
                // getting the symmetric coordinates over OZ
                p_symmethic.x = - p_perdistortion.x;
                p_symmethic.y = - p_perdistortion.y;
                p_symmethic.z = p_perdistortion.z;
                // tranlate to OXYZ
                p_OXYZ.x = p_symmethic.x + perspective.x;
                p_OXYZ.y = p_symmethic.y + perspective.y;
                p_OXYZ.z = p_symmethic.z + perspective.z;

//                fprintf(fdata,"%d %d %0.4f %0.4f %0.4f\n", x_INT,y,p_OXYZ.x,p_OXYZ.y,p_curved_page.z);
//                y_key = floor(p_OXYZ.y);
//                iter = region_idx.find(y_key);
//                if(iter==region_idx.end()){
//                    vector<int> idx;idx.push_back(index);
//                    region_idx.insert(pair<int,vector<int> >(y_key,idx));
//                }
//                else (*iter).second.push_back(index);

                pointsI[2*index + idx_iX] = x_INT;
                pointsI[2*index + idx_iY] = y;
//                pointsF[depth*index + idx_iX] = x_INT;
//                pointsF[depth*index + idx_iY] = y;
                pointsF[depth*index + idx_fX] = p_OXYZ.x;
                pointsF[depth*index + idx_fY] = p_OXYZ.y;
                pointsF[depth*index + idx_fZ] = p_curved_page.z;

                if(x_curved_max<p_OXYZ.x) {x_curved_max = p_OXYZ.x;x_curved_max_idx=index;}
                if(x_curved_min>p_OXYZ.x) {x_curved_min = p_OXYZ.x;x_curved_min_idx=index;}
                if(y_curved_max<p_OXYZ.y) {y_curved_max = p_OXYZ.y;y_curved_max_idx=index;}
                if(y_curved_min>p_OXYZ.y) {y_curved_min = p_OXYZ.y;y_curved_min_idx=index;}

                index++;
            }
        }
        delete map_xz;
    }
    //fclose(fdata);
    cout << " tranlate to min index = " << index << " nb=" << nb_points << endl;

    for(i =0;i<nb_points;i++){
        pointsF[depth*i + idx_fX] = pointsF[depth*i + idx_fX] - x_curved_min;
        pointsF[depth*i + idx_fY] = pointsF[depth*i + idx_fY] - y_curved_min;

        y_key = floor(pointsF[depth*i + idx_fY]);

        iter = region_idx.find(y_key);
        if(iter==region_idx.end()){
            vector<int> idx;idx.push_back(i);
            region_idx.insert(pair<int,vector<int> >(y_key,idx));
        }
        else (*iter).second.push_back(i);
    }

    int width  = x_curved_max - x_curved_min;
    int height = y_curved_max - y_curved_min;

    FILE* findex; findex= fopen("index.txt","w"); if(!findex){cout << "ERROR"<<endl;}
//    fprintf(findex,"%0.4f,%0.4f\n",x_curved_min,y_curved_min);
//    fprintf(findex,"%d,%d\n",width,height);
    iter = region_idx.begin();

    for(;iter!=region_idx.end();iter++){
        fprintf(findex,"%d ",(int)(*iter).first);
        vector<int> list_indexs= (*iter).second;
        foreach (int idx, list_indexs) {
            fprintf(findex,"%d ",idx);
        }
        fprintf(findex,"\n");
    }
    fclose(findex);
    region_idx.clear();

//    int width  = points[depth*x_curved_max_idx + idx_fX] - points[depth*x_curved_min_idx + idx_fX];
//    int height = points[depth*y_curved_max_idx + idx_fY] - points[depth*y_curved_min_idx + idx_fY];
    /**/
    cout << " tranlate to min = OK w h = " << width << " " << height << " nb points continue = " << nb_points<< endl;

    float dis =-1;
    float r = 2;

    cout << " generating color" << endl;

    FILE* file; file = fopen(path_out.toStdString().c_str(), "w"); if (!file) { exit(1); }

    fprintf(file, "in %d %d\n",width_flat_page,height_flat_page);
    fprintf(file, "out %d %d\n",width,height);

    int percent = height/100;
    int x_src,y_src;
    vector<string>::iterator vec_it;
    vector<string> idx;
    vector<string> idx_y;
    vector<string> idx_y_1;
    float* row_y = (float*)malloc(sizeof(float)*3*width);
    float dis_min = INT_MAX;

    for(int y=0;y<height;y++){

        if(y%percent==0) cout << y/percent << "%" << endl;

        fprintf(file, "%d ",y);

        // reset row_y;
        for(int x=0;x<width;x++){
            row_y[3*x + 0] = -1;
            row_y[3*x + 1] = -1;
            row_y[3*x + 2] = -1;
        }
        // one-mapping
        idx.clear();
        idx_y.clear();
        idx_y_1.clear();
        glmGetDataFromFile(y-1,"index.txt",idx_y_1);
        idx.insert(idx.begin(),idx_y_1.begin(),idx_y_1.end());
        glmGetDataFromFile(y,"index.txt",idx_y);
        idx.insert(idx.begin(),idx_y.begin(),idx_y.end());
//        iter = region_idx.find(y-1);
//        if(iter!=region_idx.end()) idx.insert(idx.begin(),(*iter).second.begin(),(*iter).second.end());
//        iter = region_idx.find(y);
//        if(iter!=region_idx.end()) idx.insert(idx.begin(),(*iter).second.begin(),(*iter).second.end());
        //
        for(int x=0;x<width;x++){

            dis_min = INT_MAX;
            index=-1;

            if(idx.size()>0){
                for(vec_it=idx.begin();vec_it!=idx.end();vec_it++){
                    i = atoi((*vec_it).c_str());

                    if( pointsF[depth*i + idx_fX]>(x+r) || pointsF[depth*i + idx_fX]<(x-r) || pointsF[depth*i + idx_fY]>(y+r) || pointsF[depth*i + idx_fY]<(y-r)) { continue;}

                    dis = sqrt((x-pointsF[depth*i + idx_fX])*(x-pointsF[depth*i + idx_fX]) + (y - pointsF[depth*i + idx_fY])*(y - pointsF[depth*i + idx_fY]));

                    if(dis==0){index=i;break;}
                    if(dis>r) {continue;}
                    if(dis_min>dis) {dis_min=dis;index=i;}
                }
                if(index>=0){
//                    x_src = pointsF[depth*index + idx_iX];
//                    y_src = pointsF[depth*index + idx_iY];
                    x_src = pointsI[2*index + idx_iX];
                    y_src = pointsI[2*index + idx_iY];

                    if(x_src>=0 && y_src>=0 && x_src<width_flat_page && y_src<height_flat_page)
                    {
                        row_y[3*x + 0] = x_src;
                        row_y[3*x + 1] = y_src;
                        row_y[3*x + 2] = pointsF[depth*index + idx_fZ];
                    }
                }
            }
        }

        for(int x=0;x<width;x++){
            if(row_y[3*x+0]<0){
                //img->setPixel(x,y,qRgb(255,255,255));
                fprintf(file, "- ");
            }
            else {
                //img->setPixel(x,y,src.pixel(row_y[2*x+0],row_y[2*x+1]));
                fprintf(file, "%d,%d,%0.4f ",row_y[3*x+0],row_y[3*x+1],row_y[3*x+2]);
            }
        }
        fprintf(file, "\n");
    }
    fclose(file);

    //    img->save("method2/ImageMapping_original.png");
    //    QImage out = img->scaled(src_width,src_height);
    //    out.save("method2/ImageMapping_scaled.png");

    cout << " finished " << endl;
    delete pointsF;
    delete row_y;
    /**/
}
//GLvoid glmGetDataFromFile(int x, int y,char* fileData, char* fileIndex, float* &points,int &nb)
GLvoid glmGetDataFromFile(int y,char* fileIndex,vector<string> &vectorIndex){

    ifstream fIndex(fileIndex);
    string line;
    if(fIndex.is_open()){
        while(fIndex.good()){
            fIndex.seekg(std::ios::beg);
            for(int i=0;i<y;i++)fIndex.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
            getline(fIndex,line);
            break;
        }
    }
    fIndex.close();

    boost::algorithm::split(vectorIndex,line,boost::algorithm::is_any_of(" "));
    vectorIndex.erase(vectorIndex.begin()+0);
    vectorIndex.erase(vectorIndex.begin()+(vectorIndex.size()-1));

//    nb = vectorIndex.size();

//     cout << nb << endl;
//    points = (float *)malloc(sizeof(float)*5*nb);
//    ifstream fData(fileData);
//    index=0;
//    int counter =0;

//    if(fData.is_open()){
//        while(fData.good()){
//            foreach(string s,vectorIndex){
//                seeking = atoi(s.c_str());
//                fData.seekg(std::ios::beg);
//                for(int i=0;i<seeking;i++)fData.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
//                getline(fData,line);
//                counter++;
//                cout << counter << endl;
//            }
//            fData.close(); cout << "close " << endl;break;

////            if(counter>=(nb)) {    fData.close(); cout << "close " << endl;break;}
////            stringstream ssIdx;ssIdx<< " " << index << " ";
////            if(strIndex.find(ssIdx.str()) != string::npos) {
////                counter++;       cout << " Found " << counter << endl;
////            }
////            index++;
//        }
//    }

//    cout << nb << endl;
}

bool IsEqualZero(double dX)
{
    return fabs(dX) <= 10E-6;
}
GLvoid glmScanline(float y0, int v_y0_idx,int &xzidx_index, float* &map_xzidx,int &nb,GLMmodel* model){

    map<float,vector<float> > map_x_z;
    Plane p_Y(0,1,0,-y0);
    int i =0;

    int v_id_0 = -1,v_id_1 = -1,v_id_2 = -1;
    float f0,f1,f2,f01,f12,f02,f012;
    Vector3 P0(0,0,0); Vector3 P1(0,0,0); Vector3 P2(0,0,0);

    for(;i<model->numtriangles;i++){
        v_id_0 = model->triangles[i].vindices[0];
        v_id_1 = model->triangles[i].vindices[1];
        v_id_2 = model->triangles[i].vindices[2];

        P0.x = model->vertices[3*v_id_0 + 0];
        P0.y = model->vertices[3*v_id_0 + 1];
        P0.z = model->vertices[3*v_id_0 + 2];

        P1.x = model->vertices[3*v_id_1 + 0];
        P1.y = model->vertices[3*v_id_1 + 1];
        P1.z = model->vertices[3*v_id_1 + 2];

        P2.x = model->vertices[3*v_id_2 + 0];
        P2.y = model->vertices[3*v_id_2 + 1];
        P2.z = model->vertices[3*v_id_2 + 2];

        f0 = p_Y.f(P0); if(v_id_0==v_y0_idx) f0=0;
        f1 = p_Y.f(P1); if(v_id_1==v_y0_idx) f1=0;
        f2 = p_Y.f(P2); if(v_id_2==v_y0_idx) f2=0;
        f01 =f0*f1;
        f02 =f0*f2;
        f12 =f1*f2;
        f012 =f0*f1*f2;

        if((f0>0 && f1>0 && f2>0) || (f0<0 && f1<0 && f2<0)) continue;

        //        cout << "f0, f1, f2 " << f0 << " " << f1 << " " << f2 << " f01 f02 f12 " << f01 << " " << f02 << " " << f12 << endl;
        if(!IsEqualZero(f012)){
            if(f01<0){
                Line3 line01(P0,P1);
                Vector3 p_intersection01 = line01.getPoint(y0);

                vector<float> z_idx01; z_idx01.push_back(p_intersection01.z);z_idx01.push_back(-1);
                map_x_z.insert(pair<float,vector<float> >(p_intersection01.x,z_idx01));
            }
            if(f02<0){
                Line3 line02(P0,P2);
                Vector3 p_intersection02 = line02.getPoint(y0);
                vector<float> z_idx02; z_idx02.push_back(p_intersection02.z);z_idx02.push_back(-1);

                map_x_z.insert(pair<float,vector<float> >(p_intersection02.x,z_idx02));

            }
            if(f12<0){
                Line3 line12(P1,P2);
                Vector3 p_intersection12 = line12.getPoint(y0);
                vector<float> z_idx12; z_idx12.push_back(p_intersection12.z);z_idx12.push_back(-1);
                map_x_z.insert(pair<float,vector<float> >(p_intersection12.x,z_idx12));
            }
        }
        else{
            if(IsEqualZero(f0)){
                vector<float> z_idx0; z_idx0.push_back(P0.z);z_idx0.push_back(v_id_0);
                map_x_z.insert(pair<float,vector<float> >(P0.x,z_idx0));
                if(f12<0){
                    Line3 line12(P1,P2);
                    Vector3 p_intersection12 = line12.getPoint(y0);
                    vector<float> z_idx12; z_idx12.push_back(p_intersection12.z);z_idx12.push_back(-1);
                    map_x_z.insert(pair<float,vector<float> >(p_intersection12.x,z_idx12));
                }
                else if(IsEqualZero(f12)){
                    if(IsEqualZero(f1)){
                        vector<float> z_idx1; z_idx1.push_back(P1.z);z_idx1.push_back(v_id_1);
                        map_x_z.insert(pair<float,vector<float> >(P1.x,z_idx1));
                    }
                    if(IsEqualZero(f2)){
                        vector<float> z_idx2; z_idx2.push_back(P2.z);z_idx2.push_back(v_id_2);
                        map_x_z.insert(pair<float,vector<float> >(P2.x,z_idx2));
                    }
                }
                else;
            }
            else{
                //f0 # 0
                if(IsEqualZero(f1)){
                    vector<float> z_idx1; z_idx1.push_back(P1.z);z_idx1.push_back(v_id_1);
                    map_x_z.insert(pair<float,vector<float> >(P1.x,z_idx1));

                    if(f02<0){
                        Line3 line02(P0,P2);
                        Vector3 p_intersection02 = line02.getPoint(y0);
                        vector<float> z_idx02; z_idx02.push_back(p_intersection02.z);z_idx02.push_back(-1);
                        map_x_z.insert(pair<float,vector<float> >(p_intersection02.x,z_idx02));
                    }
                }
                if(IsEqualZero(f2)){
                    vector<float> z_idx2; z_idx2.push_back(P2.z);z_idx2.push_back(v_id_2);

                    map_x_z.insert(pair<float,vector<float> >(P2.x,z_idx2));
                    if(f01<0){
                        Line3 line01(P0,P1);
                        Vector3 p_intersection01 = line01.getPoint(y0);
                        vector<float> z_idx01; z_idx01.push_back(p_intersection01.z);z_idx01.push_back(-1);
                        map_x_z.insert(pair<float,vector<float> >(p_intersection01.x,z_idx01));
                    }
                }
            }
        }
    }

    int index=0;
    map<float,vector<float> >::iterator it = map_x_z.begin();
    vector<float> zero_point;zero_point.push_back((*it).second.at(0));zero_point.push_back(-1);
    map_x_z.insert(pair<float,vector<float> >(0,zero_point));

    nb = map_x_z.size();
    map_xzidx = (float*)malloc(sizeof(float)*3*nb);

    it = map_x_z.begin();
    for(;it!=map_x_z.end();it++,index++){

        map_xzidx[3*index + 0] = (*it).first;
        map_xzidx[3*index + 1] = (*it).second.at(0);
        map_xzidx[3*index + 2] =  (*it).second.at(1);
        if((*it).second.at(1)>=0) xzidx_index=index;
    }
    map_x_z.clear();
}
GLvoid glmGenerateTexCoord(GLMmodel* model, QString name){
    float min_x = INT_MAX;
    map<string,int> map_y;
    int i=1;
    map<string,int>::iterator it = map_y.begin();

    for(i=1;i<=model->numvertices;i++){
        if(min_x>model->vertices[3*i + 0]) {min_x = model->vertices[3*i+0];}
    }
    for(i=1;i<=model->numvertices;i++){
        model->vertices[3*i+0] = model->vertices[3*i+0] - min_x;
    }

    for(i=1;i<=model->numvertices;i++){
        stringstream ss;
        ss << model->vertices[3*i+1];
        it = map_y.find(ss.str());
        if(it==map_y.end())
            map_y.insert(pair<string,int>(ss.str(),i));
    }
    cout << " number y = " << map_y.size() << endl;
    /**/
//    float dmin_y = INT_MAX;
//    it = map_y.begin();
//    for(;it!=map_y.end();it++){
//        float y0 = atof((*it).first.c_str());
//        float y1 = 0;
//        it++;
//        if(it!=map_y.end()){
//            y1 = atof((*it).first.c_str());
//            if(dmin_y>fabs(y1-y0)) dmin_y = y1 -y0;
//        }
//    }
//    cout << " starting...." << dmin_y << endl;

    int nb_y = map_y.size();
    nb_y = 0.01*nb_y;
    /**/

    if(model->numtexcoords==0){
        model->numtexcoords = model->numvertices;
        model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) * 2 * (model->numtexcoords + 1));
    }
    map<int,int> v_t_idx;
    map<int,int>::iterator v_t_idx_iterator;
    int t_idx=1;
    float y;
    int index=0;
    i = 0;
    it = map_y.begin();
    bool out_of_range_tex = false;
    for(;it!=map_y.end();it++,index++){
        //        if((index/nb_y)<97) continue;
        string s = (*it).first;
        y = atof(s.c_str());
        if(index%nb_y==0) cout << (index/nb_y) << "%"  << " t_idx = " << t_idx  << " nbTex= "<< model->numtexcoords << endl;
        //        y = 270.001;
        //        cout << "y = \t" << y << " v_idx =" << (*it).second << endl;
        float *map_xzidx;
        int nb;
        int xzidx_index_max;
        glmScanline(y,(*it).second,xzidx_index_max,map_xzidx,nb,model);
        if(map_xzidx && nb>0){
            float L = 0,ds = 0, dx=0, dz=0;
            for(i=0;i<(nb-1);i++){
                if(i>xzidx_index_max)break;

                dx = (map_xzidx[3*i+0] - map_xzidx[3*(i+1)+0]);
                dz = (map_xzidx[3*i+1] - map_xzidx[3*(i+1)+1]);
                ds = sqrt( dx*dx+ dz*dz);

                if(map_xzidx[3*i+2]!=-1){

                    v_t_idx_iterator = v_t_idx.find((int)map_xzidx[3*i+2]);
                    if(v_t_idx_iterator==v_t_idx.end()){
                        model->texcoords[2*t_idx + 0] = L;
                        model->texcoords[2*t_idx + 1] = y;
                        v_t_idx.insert(pair<int,int>((int)map_xzidx[3*i+2],t_idx));
                        t_idx++;
                        if(t_idx>model->numtexcoords){out_of_range_tex=true;break;}
                    }
                }
                L +=ds;
            }
            delete map_xzidx;
        }
        else {
            cout << "\t error y = "<< y << " v_idx =" << (*it).second<< " n= " << nb << endl;
        }
        if(out_of_range_tex)break;

        //        break;
    }
    //    FILE*   file;
    //    file = fopen("v_t_idx_data.txt", "w");
    //    if (!file) {
    //        cout << "file error" << endl;
    //    }
    //    v_t_idx_iterator = v_t_idx.begin();
    //    for(;v_t_idx_iterator!=v_t_idx.end();v_t_idx_iterator++){
    //        fprintf(file, "%d %d\n",
    //                (*v_t_idx_iterator).first,
    //                (*v_t_idx_iterator).second);

    //    }
    //    fclose(file);

    /** Correction*/
    cout << " t_idx = " << t_idx  << " numtex = " << model->numtexcoords << " v_t_idx= " << v_t_idx.size()<< endl;
    map_y.clear();
    for(i=1;i<=model->numvertices;i++){
        v_t_idx_iterator = v_t_idx.find(i);
        if(v_t_idx_iterator==v_t_idx.end()){
            stringstream ss;
            ss << model->vertices[3*i+1];
            it = map_y.find(ss.str());
            if(it==map_y.end())
                map_y.insert(pair<string,int>(ss.str(),i));
        }
    }
    cout << " map_y = " << map_y.size() << endl;

    i = 0;
    it = map_y.begin();
    out_of_range_tex = false;

    for(;it!=map_y.end();it++,index++){

        y = atof((*it).first.c_str());

        float *map_xzidx;
        int nb;
        int xzidx_index_max;
        glmScanline(y,(*it).second,xzidx_index_max,map_xzidx,nb,model);
        if(map_xzidx && nb>0){
            float L = 0,ds = 0, dx=0, dz=0;
            for(i=0;i<nb;i++){
                if(i>xzidx_index_max)break;

                dx = (map_xzidx[3*i+0] - map_xzidx[3*(i+1)+0]);
                dz = (map_xzidx[3*i+1] - map_xzidx[3*(i+1)+1]);
                ds = sqrt( dx*dx+ dz*dz);

                if(map_xzidx[3*i+2]!=-1){

                    v_t_idx_iterator = v_t_idx.find((int)map_xzidx[3*i+2]);
                    if(v_t_idx_iterator==v_t_idx.end()){
                        model->texcoords[2*t_idx + 0] = L;
                        model->texcoords[2*t_idx + 1] = y;
                        v_t_idx.insert(pair<int,int>((int)map_xzidx[3*i+2],t_idx));
                        t_idx++;
                        if(t_idx>model->numtexcoords){out_of_range_tex=true;break;}
                    }
                }
                L +=ds;
            }
            delete map_xzidx;
        }
        else {
            cout << "\t error y = "<< y << " v_idx =" << (*it).second<< " n= " << nb << endl;
        }
        if(out_of_range_tex)break;
    }
    cout <<  " v_t_idx=" << v_t_idx.size() << endl;
    /** END*/
    map<int,int>::iterator itera = v_t_idx.begin();
    for(int i=0;i<model->numtriangles;i++){
        for(int k=0;k<3;k++){
            itera = v_t_idx.find(model->triangles[i].vindices[k]);
            if(itera!=v_t_idx.end()){
                model->triangles[i].tindices[k] = (*itera).second;
            }
        }
    }

    /**
    map<float,map<float,Vector2> > map_Y_PointsIdx = glmGetPointsInLine(model);

    if(model->numtexcoords==0){
        model->numtexcoords = model->numvertices;
        model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) * 2 * (model->numtexcoords + 1));
    }
    map<float,map<float,Vector2> >::iterator it;
    map<int,int> v_t_idx;
    int t_idx = 1;
    float t_x_max = INT_MIN;

    for(it=map_Y_PointsIdx.begin();it!=map_Y_PointsIdx.end();it++){
        float y = (*it).first;
        map<float,Vector2> X_idx_z = (*it).second;
        //        cout << " avant = " << X_idx_z.size();
        map<float,Vector2>::iterator iter0 =X_idx_z.begin();
        float v_x_previous0 = (*iter0).first;
        //        if(v_x_previous0>-120)
        //glmComplementPoints(y,X_idx_z,model);
        //        cout << " apres = " << X_idx_z.size() << endl;
        map<float,Vector2>::iterator iter =X_idx_z.begin();
        float v_x_previous = (*iter).first;
        Vector2 v_idx_z((*iter).second.x,(*iter).second.y);
        int v_idx = v_idx_z.x;

        float v_x = v_x_previous;
        float v_z_previous = v_idx_z.y;
        float v_z = v_z_previous;
        float dx,dz,ds;


        float t_x = v_x_previous;
        float t_y = y;
        int j = 0;
        for(;iter!=X_idx_z.end();iter++){
            // next
            v_x = (*iter).first;
            v_idx = (*iter).second.x;

            v_z = (*iter).second.y;
            // coordinates texture
            dx = v_x - v_x_previous;
            dz = v_z - v_z_previous;
            ds = sqrt(dx*dx + dz*dz);
            if(ds!=0) {
                t_x +=ds;
            }
            if(t_x_max<t_x) t_x_max = t_x;
            if(v_idx>0){
                model->texcoords[2*t_idx + 0] = t_x;
                model->texcoords[2*t_idx + 1] = t_y;
                v_t_idx.insert(pair<int,int>(v_idx,t_idx));
                t_idx++;
            }

            v_x_previous = v_x;
            v_z_previous = v_z;

            j++;
        }
    }
    cout << t_x_max << endl;
    for(int i=0;i<model->numtriangles;i++){
        for(int k=0;k<3;k++){
            map<int,int>::iterator it = v_t_idx.find(model->triangles[i].vindices[k]);
            if(it!=v_t_idx.end()){
                model->triangles[i].tindices[k] = (*it).second;
            }
        }
    }
    /**/
    /**
    for(int i=1;i<=model->numtexcoords;i++){

        float t_x = model->texcoords[2*i +0];
        float t_y = model->texcoords[2*i +1];
        if(t_x<-120) continue;

        vector<int> t_polygons_idx;
        //        float total_distance_triangles_in_polygon =0;
        //        int nbTriangle=0;
        for(int j=0;j<model->numtriangles;j++){
            bool inPolygons = false;
            for(int k=0;k<3;k++){
                if(model->triangles[j].tindices[k]==i) {inPolygons=true;break;}
            }
            if(inPolygons){
                //                total_distance_triangles_in_polygon += glmGetTriangleDistance(model,j);
                //                nbTriangle++;
                for(int k=0;k<3;k++){
                    if(model->triangles[j].tindices[k]!=i) t_polygons_idx.push_back(model->triangles[j].tindices[k]);
                }
            }
        }
        //        total_distance_triangles_in_polygon /= nbTriangle;
        //        if(total_distance_triangles_in_polygon<=3) continue;

        float max_x = INT_MIN, max_y = INT_MIN;
        float min_x = INT_MAX, min_y = INT_MAX;
        float mean_x=0,mean_y=0;
        for(int j=0;j<t_polygons_idx.size();j++){
            if(max_x < model->texcoords[2*t_polygons_idx.at(j) + 0]) max_x = model->texcoords[2*t_polygons_idx.at(j) + 0];
            if(min_x > model->texcoords[2*t_polygons_idx.at(j) + 0]) min_x = model->texcoords[2*t_polygons_idx.at(j) + 0];

            if(max_y < model->texcoords[2*t_polygons_idx.at(j) + 1]) max_y = model->texcoords[2*t_polygons_idx.at(j) + 1];
            if(min_y > model->texcoords[2*t_polygons_idx.at(j) + 1]) min_y = model->texcoords[2*t_polygons_idx.at(j) + 1];

            mean_x +=model->texcoords[2*t_polygons_idx.at(j) + 0];
            mean_y +=model->texcoords[2*t_polygons_idx.at(j) + 1];
        }
        mean_x = mean_x/t_polygons_idx.size();
        mean_y = mean_y/t_polygons_idx.size();
        //        bool p_in_polygons = true;
        //        int l=0;
        //        for(;l<t_polygons_idx.size() -1;l++){
        //            Line2 line( model->texcoords[2*t_polygons_idx.at(l) +0],
        //                        model->texcoords[2*t_polygons_idx.at(l) +1],
        //                        model->texcoords[2*t_polygons_idx.at(l+1) +0],
        //                        model->texcoords[2*t_polygons_idx.at(l+1) +1]
        //                        );
        //            if((line.fxy(mean_x,mean_y)*line.fxy(t_x,t_y))<0){p_in_polygons=false;break;}
        //        }
        //        Line2 line( model->texcoords[2*t_polygons_idx.at(l) +0],
        //                    model->texcoords[2*t_polygons_idx.at(l) +1],
        //                    model->texcoords[2*t_polygons_idx.at(0) +0],
        //                    model->texcoords[2*t_polygons_idx.at(0) +1]
        //                    );
        //        if((line.fxy(mean_x,mean_y)*line.fxy(t_x,t_y))<0){p_in_polygons=false;}

        if(!(t_x<max_x && t_x >min_x && t_y< max_y && t_y > min_y)){
            //        if(!p_in_polygons ){
            model->texcoords[2*i +0] = mean_x;
            model->texcoords[2*i +1] = mean_y;
        }
    }
    /**/
    /**
    int j = 0;
    for(int i=0;i<model->numtriangles;i++){
        int t_id_0 = model->triangles[i].tindices[0];
        int t_id_1 = model->triangles[i].tindices[1];
        int t_id_2 = model->triangles[i].tindices[2];
        Vector2 p0(model->texcoords[2*t_id_0 + 0], model->texcoords[2*t_id_0 + 1]);
        Vector2 p1(model->texcoords[2*t_id_1 + 0], model->texcoords[2*t_id_1 + 1]);
        Vector2 p2(model->texcoords[2*t_id_2 + 0], model->texcoords[2*t_id_2 + 1]);
        float d01 = sqrt((p0.x - p1.x)*(p0.x - p1.x) + (p0.y - p1.y)*(p0.y - p1.y));
        float d12 = sqrt((p2.x - p1.x)*(p2.x - p1.x) + (p2.y - p1.y)*(p2.y - p1.y));
        float d20 = sqrt((p0.x - p2.x)*(p0.x - p2.x) + (p0.y - p2.y)*(p0.y - p2.y));
        float total = (d01 + d12 + d20);

        float ex_z = 0;
        float limit_down = -110;
        float limit_top = -10;
        float rate = 300;
        if(total>1.5 && ((p0.x>-limit_down && p0.x<limit_top)|| (p1.x>-limit_down && p1.x<limit_top) || (p2.x>limit_down && p2.x<limit_top)))
//        if(total>1.5)
        {
            map<float,int> tmp_x_idx;
            tmp_x_idx.insert(pair<float,int>(p0.x,t_id_0));
            tmp_x_idx.insert(pair<float,int>(p1.x,t_id_1));
            tmp_x_idx.insert(pair<float,int>(p2.x,t_id_2));
            map<float,int>::iterator tmp_it = tmp_x_idx.begin();
            int k=0;
            int x_id_0=-1;
            int x_id_1=-1;
            int x_id_2=-1;
            for(;tmp_it!=tmp_x_idx.end();tmp_it++,k++){
                if(k==0) x_id_0 = (*tmp_it).second;
                if(k==1) x_id_1 = (*tmp_it).second;
                if(k==2) x_id_2 = (*tmp_it).second;
            }
            if(x_id_0!=-1 && x_id_1!=-1&&x_id_2!=-1)
            {
                float dx01 = model->texcoords[2*x_id_1 + 0] - model->texcoords[2*x_id_0 + 0];
                float dx12 = model->texcoords[2*x_id_2 + 0] - model->texcoords[2*x_id_1 + 0];
                if(dx12>dx01){
                    //                    if((dx12/dx01)>rate)
                    model->texcoords[2*x_id_2 + 0] = model->texcoords[2*x_id_1 + 0] + (dx01);
                }
                else{
                    //                    if((dx01/dx12)>rate)
                    model->texcoords[2*x_id_0 + 0] = model->texcoords[2*x_id_1 + 0] - (dx12);
                }
            }

            j++;
            //            if(j>100)
            //            {
            //            cout << " co " << endl;
            //                model->vertices[3*model->triangles[i].vindices[0] + 2] = model->vertices[3*model->triangles[i].vindices[0] + 2] + ex_z;
            //                model->vertices[3*model->triangles[i].vindices[1] + 2] = model->vertices[3*model->triangles[i].vindices[1] + 2] + ex_z;
            //                model->vertices[3*model->triangles[i].vindices[2] + 2] = model->vertices[3*model->triangles[i].vindices[2] + 2] + ex_z;
            //                            cout << "x0 x1 x2 = " << p0.x << " " << p1.x << " " << p2.x << endl;
            //                            cout << "y0 y1 y2 = " << p0.y << " " << p1.y << " " << p2.y << endl;
            //                            cout << "01 12 20 " << d01 << " " << d12 << " " << d20 << " total= " << total << endl;
            //            }
            //            if(j>102) break;
        }

        //        if(p0.x>-105.5){
        ////            model->vertices[3*model->triangles[i].vindices[0] + 2] = model->vertices[3*model->triangles[i].vindices[0] + 2] + ex_z;
        //            if(p1.x>p2.x) model->texcoords[2*t_id_0 + 0] = model->texcoords[2*t_id_1 + 0] + d12;
        //            else model->texcoords[2*t_id_0 + 0] = model->texcoords[2*t_id_2 + 0] + d12;
        //        }
        //        if(p1.x>-105.5){
        ////            model->vertices[3*model->triangles[i].vindices[1] + 2] = model->vertices[3*model->triangles[i].vindices[1] + 2] + ex_z;
        //            if(p0.x>p2.x) model->texcoords[2*t_id_1 + 0] = model->texcoords[2*t_id_0 + 0] + d20;
        //            else model->texcoords[2*t_id_1 + 0] = model->texcoords[2*t_id_2 + 0] + d20;
        //        }
        //        if(p2.x>-105.5){
        ////            model->vertices[3*model->triangles[i].vindices[2] + 2] = model->vertices[3*model->triangles[i].vindices[2] + 2] + ex_z;
        //            if(p1.x>p0.x) model->texcoords[2*t_id_2 + 0] = model->texcoords[2*t_id_1 + 0] + d01;
        //            else model->texcoords[2*t_id_2 + 0] = model->texcoords[2*t_id_0 + 0] + d01;
        //        }
    }
    cout << "j = " <<j << endl;
    /**/
    //
    /*
    float xy_scale = 10;
    int width = 474*2;
    int height = 204*2;
    QImage* imgXY = new QImage(width,height,QImage::Format_RGB32);
    for(int x =0;x<width;x++)
        for(int y=0;y<height;y++) imgXY->setPixel(x,y,qRgb(255,255,255));

    map<float,map<float,Vector2> >::iterator it1;

    for(it1=map_Y_PointsIdx.begin();it1!=map_Y_PointsIdx.end();it1++){
        float y = (*it1).first;
        map<float,int> X_idx = (*it1).second;
        map<float,int>::iterator iter1 = X_idx.begin();
        int size = X_idx.size();
        for(;iter1!=X_idx.end();iter1++){
             float x = (*iter1).first;

             int posX = xy_scale*x -(-953.632/5)*xy_scale;
             int posY = xy_scale*y - (1255.67/5)*xy_scale;

             posY = posY - height + 50;
             posY = -posY ;


             if(posX>=0 && posX<width && posY>=0 && posY<height){
                 QRgb rgb = qRgb(255,0,0);
//                 if(size==2) rgb = qRgb(0,0,0);
                 if(size==3) rgb = qRgb(0,255,0);
                 else if(size==4) rgb = qRgb(0,0,255);
                 else ;
                 imgXY->setPixel(posX,posY,rgb);
             }
         }
    }
    imgXY->save("xy_generate.png");
    */
    //
    //    vector<int> seamsVertex,seamsTrianble;
    //    map<int,int> _map;

    //    testTextureCoordinates(model,"generate_texture.png",seamsVertex,seamsTrianble,_map,NULL,1);

    glmNormalizeTexCoor(model,1);
    glmWriteOBJ(model,(char*)name.toStdString().c_str(),GLM_TEXTURE);
}

//========================================================Split Model into sub-models==========================
/* glmUnitize: "unitize" a model by translating it to the origin and
 * scaling it to fit in a unit cube around the origin.   Returns the
 * scalefactor used.
 *
 * model - properly initialized GLMmodel structure
 */
GLfloat
glmUnitize(GLMmodel* model)
{
    GLuint  i;
    GLfloat maxx, minx, maxy, miny, maxz, minz;
    GLfloat cx, cy, cz, w, h, d;
    GLfloat scale;

    assert(model);
    assert(model->vertices);

    /* get the max/mins */
    maxx = minx = model->vertices[3 + 0];
    maxy = miny = model->vertices[3 + 1];
    maxz = minz = model->vertices[3 + 2];
    for (i = 1; i <= model->numvertices; i++) {
        if (maxx < model->vertices[3 * i + 0])
            maxx = model->vertices[3 * i + 0];
        if (minx > model->vertices[3 * i + 0])
            minx = model->vertices[3 * i + 0];

        if (maxy < model->vertices[3 * i + 1])
            maxy = model->vertices[3 * i + 1];
        if (miny > model->vertices[3 * i + 1])
            miny = model->vertices[3 * i + 1];

        if (maxz < model->vertices[3 * i + 2])
            maxz = model->vertices[3 * i + 2];
        if (minz > model->vertices[3 * i + 2])
            minz = model->vertices[3 * i + 2];
    }

    /* calculate model width, height, and depth */
    //    w = glmAbs(maxx) + glmAbs(minx);
    //    h = glmAbs(maxy) + glmAbs(miny);
    //    d = glmAbs(maxz) + glmAbs(minz);
    w = glmAbs(maxx - minx);
    h = glmAbs(maxy - miny);
    d = glmAbs(maxz - minz);
    cout << "w = " << w << " h=" << h  << " dz = " << d << endl;
    /* calculate center of the model */
    cx = (maxx + minx) / 2.0;
    cy = (maxy + miny) / 2.0;
    cz = (maxz + minz) / 2.0;

    /* calculate unitizing scale factor */
    scale = 2.0 / glmMax(glmMax(w, h), d);

    /* translate around center then scale */
    for (i = 1; i <= model->numvertices; i++) {
        model->vertices[3 * i + 0] -= cx;
        model->vertices[3 * i + 1] -= cy;
        model->vertices[3 * i + 2] -= cz;
        model->vertices[3 * i + 0] *= scale;
        model->vertices[3 * i + 1] *= scale;
        model->vertices[3 * i + 2] *= scale;
    }

    //    glmNormalizeTexCoor(model,1);

    //    vector<int> seamsVertex;vector<int> seamsTriangle;map<int,int> _map;
    //    testTextureCoordinates(model,"complete_tex.png",seamsVertex,seamsTriangle,_map,NULL,500);

    return scale;
}

/* Rotate - normalize and scale the texture coordinates*/
GLvoid glmNormalizeTexCoor(GLMmodel* model, float texScale, bool isNormalize){

    GLint tex_min_x_index = 0;
    GLint tex_min_y_index = 0;
    GLint tex_max_x_index = 0;
    GLint tex_max_y_index = 0;
    int i = 0;

    getTex_Min_Max_XY_idx(tex_min_x_index,tex_min_y_index,tex_max_x_index,tex_max_y_index,model);

    GLfloat tex_min_x = (model->texcoords[2*tex_min_x_index + 0]);
    GLfloat tex_min_y = (model->texcoords[2*tex_min_y_index + 1]);

    GLfloat tex_max_x = (model->texcoords[2*tex_max_x_index + 0]);
    GLfloat tex_max_y = (model->texcoords[2*tex_max_y_index + 1]);

    GLfloat width = glmAbs(tex_max_x - tex_min_x) ;
    GLfloat height = glmAbs(tex_max_y - tex_min_y);
    GLfloat centre_x = (tex_max_x + tex_min_x)/2;
    GLfloat centre_y = (tex_max_y + tex_min_y)/2;

    Vector2 p_max_X(model->texcoords[2*tex_max_x_index + 0],model->texcoords[2*tex_max_x_index + 1]);
    Vector2 p_min_X(model->texcoords[2*tex_min_x_index + 0],model->texcoords[2*tex_min_x_index + 1]);

    Vector2 p_max_Y(model->texcoords[2*tex_max_y_index + 0],model->texcoords[2*tex_max_y_index + 1]);
    Vector2 p_min_Y(model->texcoords[2*tex_min_y_index + 0],model->texcoords[2*tex_min_y_index + 1]);

    Vector2 p_avg1((p_min_Y.x + p_min_X.x)/2,(p_min_Y.y + p_min_X.y)/2);
    Vector2 p_avg2((p_max_Y.x + p_max_X.x)/2,(p_max_Y.y + p_max_X.y)/2);

    Vector2 p_avg12((p_avg2.x - p_avg1.x),(p_avg2.y - p_avg1.y));

    float al0 = atan2(p_avg12.y,p_avg12.x);

    qDebug() << "alo = " << al0*180/M_PI;

    GLfloat angle = 0;//0*PI/(GLfloat)180;//-10

    for (i = 0 ;i<=model->numtexcoords;i++){
        // tranlate to the centre
        GLfloat x = model->texcoords[2*i + 0] - centre_x;
        GLfloat y = model->texcoords[2*i + 1] - centre_y;

        // rotate at the centre
        model->texcoords[2*i + 0] = x*cos(angle) - y*sin(angle);
        model->texcoords[2*i + 1] = y*cos(angle) + x*sin(angle);

        // tranlate back to original
        model->texcoords[2*i + 0] = model->texcoords[2*i + 0] + centre_x;
        model->texcoords[2*i + 1] = model->texcoords[2*i + 1] + centre_y;

        // Normalize
        if(isNormalize){
            model->texcoords[2*i + 0] = model->texcoords[2*i + 0]/(GLfloat)width;
            model->texcoords[2*i + 1] = model->texcoords[2*i + 1]/(GLfloat)height;
        }

        // scale
        model->texcoords[2*i + 0] = texScale*model->texcoords[2*i + 0];
        model->texcoords[2*i + 1] = texScale*model->texcoords[2*i + 1];
    }
    // get min point
    GLfloat min_x = (model->texcoords[2 + 0]) , min_y = (model->texcoords[2 + 1]);
    for (i = 1 ;i<=model->numtexcoords;i++){
        if(min_x > (model->texcoords[2*i + 0])) min_x = (model->texcoords[2*i + 0]);
        if(min_y > (model->texcoords[2*i +1])) min_y = (model->texcoords[2*i + 1]);
    }
    // tranlate to min point.
    for (i = 0 ;i<=model->numtexcoords;i++){
        model->texcoords[2*i + 0] = model->texcoords[2*i + 0] - min_x;
        model->texcoords[2*i + 1] = model->texcoords[2*i + 1] - min_y;
    }
}
GLvoid getTex_Min_Max_XY_idx(int &tex_min_x_idx,int &tex_min_y_idx,int &tex_max_x_idx,int &tex_max_y_idx,GLMmodel* model){

    GLfloat tex_min_x = (model->texcoords[2 + 0]);  tex_min_x_idx = 0;
    GLfloat tex_min_y = (model->texcoords[2 + 1]);  tex_min_y_idx = 0;

    GLfloat tex_max_x = (model->texcoords[2 + 0]);  tex_max_x_idx = 0;
    GLfloat tex_max_y = (model->texcoords[2 + 1]);  tex_max_y_idx = 0;

    for (int i = 1 ;i<=model->numtexcoords;i++){
        if(tex_min_x > (model->texcoords[2*i + 0])){
            tex_min_x = (model->texcoords[2*i + 0]); // min X
            tex_min_x_idx = i;
        }
        if(tex_min_y > (model->texcoords[2*i +1])) {
            tex_min_y = (model->texcoords[2*i + 1]); // min Y
            tex_min_y_idx = i;
        }
        if(tex_max_x < (model->texcoords[2*i + 0])) {
            tex_max_x = (model->texcoords[2*i + 0]); // max X
            tex_max_x_idx = i;
        }
        if(tex_max_y <(model->texcoords[2*i + 1])) {
            tex_max_y = (model->texcoords[2*i + 1]); // max Y
            tex_max_y_idx = i;
        }
    }
}

/*just for test*/
GLvoid testTextureCoordinates(GLMmodel* model, char* texImageName, vector<int> seamsVertex, vector<int> seamsTriangle, map<int,int> map_old_new_vertex_idx, Mesh* mesh,int test_scale){
    if(model->numtexcoords<=0) return;

    //texture
    GLint test_tex_min_x_index = 0;
    GLint test_tex_min_y_index = 0;
    GLint test_tex_max_x_index = 0;
    GLint test_tex_max_y_index = 0;

    getTex_Min_Max_XY_idx(test_tex_min_x_index,test_tex_min_y_index,test_tex_max_x_index,test_tex_max_y_index,model);

    GLfloat* test_texcoords = (GLfloat*)malloc(sizeof(GLfloat) * 2 * (model->numtexcoords + 1));

    Vector2* P0 = new Vector2; Vector2* P1 = new Vector2;
    Vector2* P2 = new Vector2; Vector2* P3 = new Vector2;
    int i = 0;
    int room = 1;
    test_scale = 20;
    for (i = 1 ;i<=model->numtexcoords;i++){
        test_texcoords[2*i + 0] = test_scale*model->texcoords[2*i + 0];
        test_texcoords[2*i + 1] = test_scale*model->texcoords[2*i + 1];
    }

    GLfloat test_tex_min_x = test_texcoords[2*test_tex_min_x_index + 0];
    GLfloat test_tex_min_y = test_texcoords[2*test_tex_min_y_index + 0];
    GLfloat test_tex_max_x = test_texcoords[2*test_tex_max_x_index + 1];
    GLfloat test_tex_max_y = test_texcoords[2*test_tex_max_y_index + 1];

    int ex=500;
    int test_width = glmAbs(test_tex_max_x - test_tex_min_x) + ex;
    int test_height = glmAbs(test_tex_max_y - test_tex_min_y) + ex;

    QImage* img = new QImage(test_width,test_height,QImage::Format_RGB32);
    for(int x =0;x<test_width;x++)
        for(int y=0;y<test_height;y++) img->setPixel(x,y,qRgb(255,255,255));

    //    vector<int> triangle_idx;
    //    if(mesh !=NULL && seamsTriangle.size()>0)
    //        for(i = 0;i<mesh->triangle_idx.size();i++){
    //            for(int j = 0;j<seamsTriangle.size();j++)
    //            {
    //                if(mesh->triangle_idx.at(i)==seamsTriangle.at(j)){
    //                    triangle_idx.push_back(i);break;}
    //            }
    //        }
    vector<int> t_idx;
    vector<int> tri_idx;
    for (i = 0 ;i<model->numtriangles;i++){
        bool isOut = false;
        for(int k=0;k<3;k++){
            int t_id = model->triangles[i].tindices[k];
            if(test_texcoords[2*t_id + 0]>test_scale*-105.5){
                isOut = true;
                t_idx.push_back(t_id);
                tri_idx.push_back(i);
                //                test_texcoords[2*t_id + 0] = test_texcoords[2*t_id + 0];
                break;
            }
        }

        for(int k=0;k<3;k++){
            int t_id = model->triangles[i].tindices[k];
            int posX = (test_texcoords[2*t_id + 0]) - test_tex_min_x;
            int posY = (test_texcoords[2*t_id + 1]) - test_tex_min_y;

            posY = posY - test_height + ex;
            posY = -posY ;

            if(i == test_tex_min_x_index) {P0->x = posX;P0->y = posY;}
            if(i == test_tex_min_y_index) {P1->x = posX;P1->y = posY;}
            if(i == test_tex_max_x_index) {P2->x = posX;P2->y = posY;}
            if(i == test_tex_max_y_index) {P3->x = posX;P3->y = posY;}

            if(posX>=0 && posX<test_width && posY>=0 && posY<test_height){
                QRgb rgb = qRgb(255,0,0);
                if(isOut){
                    rgb = qRgb(0,0,255);

                }
                img->setPixel(posX,posY,rgb);
            }
        }
        if(isOut){
            cout << "distance = " ;
            for(int k=0;k<2;k++){
                int t_id = model->triangles[tri_idx.at(0)].tindices[k];
                int t_id_1 = model->triangles[tri_idx.at(0)].tindices[k+1];
                float x = (test_texcoords[2*t_id + 0]);
                float y = (test_texcoords[2*t_id + 1]);
                float x1 = (test_texcoords[2*t_id_1 + 0]);
                float y1 = (test_texcoords[2*t_id_1 + 1]);
                cout << sqrt((x-x1)*(x-x1) + (y-y1)*(y-y1)) << " " ;
            }
            cout << endl;

            break;}
    }
    //    if(triangle_idx.size()>0)
    //        for (i = 0 ;i<triangle_idx.size();i++){
    //            int index_triangle = triangle_idx.at(i);
    //            for(int k=0;k<2;k++){
    //                int tex_index = model->triangles[index_triangle].tindices[k];

    //                int posX = (test_texcoords[2*tex_index + 0]) - test_tex_min_x;
    //                int posY = (test_texcoords[2*tex_index + 1]) - test_tex_min_y;

    //                posY = posY - test_height;
    //                posY = -posY ;

    //                if(posX>=0 && posX<test_width && posY>=0 && posY<test_height){
    //                    QRgb rgb = qRgb(0,0,255);
    //                    img->setPixel(posX,posY,rgb);
    //                }
    //            }
    //        }
    Vector2 p_tex_seam_max_x; GLfloat seam_max_x = INT_MIN; GLint max_x_idx = INT_MIN;
    Vector2 p_tex_seam_min_x; GLfloat seam_min_x = INT_MAX; GLint min_x_idx = INT_MAX;
    if(seamsVertex.size()>0)
        for(i=0;i<seamsVertex.size();i++){
            map<int,int>::iterator it = map_old_new_vertex_idx.find(seamsVertex.at(i));
            if(it!=map_old_new_vertex_idx.end()){
                int vertex_idx  = (*it).second;
                for(int j=0;j<model->numtriangles;j++){
                    for(int k = 0;k<3;k++){
                        int idx = model->triangles[j].vindices[k];
                        int t_idx = model->triangles[j].tindices[k];
                        if(idx==vertex_idx){
                            int posX = (test_texcoords[2*t_idx + 0]) - test_tex_min_x;
                            int posY = (test_texcoords[2*t_idx + 1]) - test_tex_min_y;

                            posY = posY - test_height + ex;
                            posY = -posY ;
                            if( seam_max_x <test_texcoords[2*t_idx + 0]) {p_tex_seam_max_x.x = posX;p_tex_seam_max_x.y=posY;
                                seam_max_x=test_texcoords[2*t_idx + 0]; max_x_idx= t_idx;}
                            if( seam_min_x > test_texcoords[2*t_idx + 0]) {p_tex_seam_min_x.x = posX;p_tex_seam_min_x.y=posY;
                                seam_min_x=test_texcoords[2*t_idx + 0]; min_x_idx = t_idx;}

                            if(posX>=0 && posX<test_width && posY>=0 && posY<test_height){
                                QRgb rgb = qRgb(0,0,255);
                                img->setPixel(posX,posY,rgb);
                            }
                        }
                    }
                }
            }
        }
    qDebug() << "max min x " << max_x_idx << " " << min_x_idx;
    //    qDebug() << "min X = " << P0->x << " y = " << P0->y;
    //    qDebug() << "x = " << P0->y << " min Y = " << P1->y;
    //    qDebug() << "max X = " << P2->x << " y = " << P2->y;
    //    qDebug() << "x = " << P3->x << " max Y = " << P3->y;
    // draw line
    QPainter painter; painter.begin(img);
    //    painter.drawLine(QPointF(P0->x,P0->y),QPointF(P1->x,P1->y));
    //    painter.drawLine(QPointF(P1->x,P1->y),QPointF(P2->x,P2->y));
    //    painter.drawLine(QPointF(P2->x,P2->y),QPointF(P3->x,P3->y));
    //    painter.drawLine(QPointF(P3->x,P3->y),QPointF(P0->x,P0->y));

    painter.drawLine(QPointF(p_tex_seam_max_x.x,p_tex_seam_max_x.y),QPointF(p_tex_seam_min_x.x,p_tex_seam_min_x.y));
    painter.end();
    //
    QImage imgOUT = img->scaled(test_width*room,test_height*room);
    QString strName(texImageName);
    imgOUT.save(strName);
    // XY plane

    GLfloat maxx, minx, maxy, miny, maxz, minz;
    GLint maxx_index,minx_index,maxy_index,miny_index,maxz_index,minz_index;
    maxx = minx = model->vertices[3 + 0];
    maxy = miny = model->vertices[3 + 1];
    maxz = minz = model->vertices[3 + 2];
    maxx_index = minx_index = maxy_index = miny_index = maxz_index = minz_index = 0;
    for (int i = 1; i <= model->numvertices; i++) {
        if (maxx < model->vertices[3 * i + 0]){
            maxx = model->vertices[3 * i + 0];
            maxx_index = i;
        }
        if (minx > model->vertices[3 * i + 0]){
            minx = model->vertices[3 * i + 0];
            minx_index = i;
        }
        if (maxy < model->vertices[3 * i + 1]){
            maxy = model->vertices[3 * i + 1];
            maxy_index = i;
        }
        if (miny > model->vertices[3 * i + 1]){
            miny = model->vertices[3 * i + 1];
            miny_index = i;
        }
        if (maxz < model->vertices[3 * i + 2]){
            maxz = model->vertices[3 * i + 2];
            maxz_index = i;
        }
        if (minz > model->vertices[3 * i + 2]){
            minz = model->vertices[3 * i + 2];
            minz_index = i;
        }
    }
    Vector3 v_max_X(model->vertices[3*maxx_index + 0],
                    model->vertices[3*maxx_index + 1],
                    model->vertices[3*maxx_index + 2]
                    );
    Vector3 v_min_X(model->vertices[3*minx_index + 0],
                    model->vertices[3*minx_index + 1],
                    model->vertices[3*minx_index + 2]
                    );
    Vector3 v_max_Y(model->vertices[3*maxy_index + 0],
                    model->vertices[3*maxy_index + 1],
                    model->vertices[3*maxy_index + 2]
                    );
    Vector3 v_min_Y(model->vertices[3*miny_index + 0],
                    model->vertices[3*miny_index + 1],
                    model->vertices[3*miny_index + 2]
                    );
    float xy_scale= 5;
    int width = xy_scale*fabs(v_max_X.x - v_min_X.x) + 50;
    int height = xy_scale*fabs(v_max_Y.y - v_min_Y.y) + 50;
    cout << "w h " << width << " " << height << endl;
    cout << "min x , y " << v_min_X.x*xy_scale << " " << v_min_Y.y * xy_scale;
    QImage* imgXY = new QImage(width,height,QImage::Format_RGB32);
    for(int x =0;x<width;x++)
        for(int y=0;y<height;y++) imgXY->setPixel(x,y,qRgb(255,255,255));

    for (int i = 0 ;i<model->numtriangles;i++){
        for(int k =0;k<3;k++){
            int v_id = model->triangles[i].vindices[k];
            int t_id = model->triangles[i].tindices[k];
            bool found = false;
            for(int m=0;m<t_idx.size();m++){
                if(t_id==t_idx.at(m)) {found=true;break;}
            }

            int posX = xy_scale*(model->vertices[3*v_id + 0]) - v_min_X.x*xy_scale;
            int posY = xy_scale*(model->vertices[3*v_id + 1]) - v_min_Y.y*xy_scale;

            posY = posY - height + 50;
            posY = -posY ;


            if(posX>=0 && posX<width && posY>=0 && posY<height){
                QRgb rgb = qRgb(255,0,0);
                if(found) rgb = qRgb(0,0,255);
                imgXY->setPixel(posX,posY,rgb);
            }
        }
    }
    imgXY->save("generate_XY.png");
    //
    delete img;
    delete test_texcoords;
    imgOUT = QImage();
}

/* glmDimensions: Calculates the dimensions (width, height, depth) of
 * a model.
 *
 * model   - initialized GLMmodel structure
 * dimensions - array of 3 GLfloats (GLfloat dimensions[3])
 */
GLvoid
glmDimensions(GLMmodel* model, GLfloat* dimensions)
{
    GLuint i;
    GLfloat maxx, minx, maxy, miny, maxz, minz;

    assert(model);
    assert(model->vertices);
    assert(dimensions);

    /* get the max/mins */
    maxx = minx = model->vertices[3 + 0];
    maxy = miny = model->vertices[3 + 1];
    maxz = minz = model->vertices[3 + 2];
    for (i = 1; i <= model->numvertices; i++) {
        if (maxx < model->vertices[3 * i + 0])
            maxx = model->vertices[3 * i + 0];
        if (minx > model->vertices[3 * i + 0])
            minx = model->vertices[3 * i + 0];

        if (maxy < model->vertices[3 * i + 1])
            maxy = model->vertices[3 * i + 1];
        if (miny > model->vertices[3 * i + 1])
            miny = model->vertices[3 * i + 1];

        if (maxz < model->vertices[3 * i + 2])
            maxz = model->vertices[3 * i + 2];
        if (minz > model->vertices[3 * i + 2])
            minz = model->vertices[3 * i + 2];
    }

    /* calculate model width, height, and depth */
    dimensions[0] = glmAbs(maxx) + glmAbs(minx);
    dimensions[1] = glmAbs(maxy) + glmAbs(miny);
    dimensions[2] = glmAbs(maxz) + glmAbs(minz);
}

/* glmScale: Scales a model by a given amount.
 *
 * model - properly initialized GLMmodel structure
 * scale - scalefactor (0.5 = half as large, 2.0 = twice as large)
 */
GLvoid
glmScale(GLMmodel* model, GLfloat scale)
{
    GLuint i;

    for (i = 1; i <= model->numvertices; i++) {
        model->vertices[3 * i + 0] *= scale;
        model->vertices[3 * i + 1] *= scale;
        model->vertices[3 * i + 2] *= scale;
    }
}

/* glmReverseWinding: Reverse the polygon winding for all polygons in
 * this model.   Default winding is counter-clockwise.  Also changes
 * the direction of the normals.
 *
 * model - properly initialized GLMmodel structure
 */
GLvoid
glmReverseWinding(GLMmodel* model)
{
    GLuint i, swap;

    assert(model);

    for (i = 0; i < model->numtriangles; i++) {
        swap = T(i).vindices[0];
        T(i).vindices[0] = T(i).vindices[2];
        T(i).vindices[2] = swap;

        if (model->numnormals) {
            swap = T(i).nindices[0];
            T(i).nindices[0] = T(i).nindices[2];
            T(i).nindices[2] = swap;
        }

        if (model->numtexcoords) {
            swap = T(i).tindices[0];
            T(i).tindices[0] = T(i).tindices[2];
            T(i).tindices[2] = swap;
        }
    }

    /* reverse facet normals */
    for (i = 1; i <= model->numfacetnorms; i++) {
        model->facetnorms[3 * i + 0] = -model->facetnorms[3 * i + 0];
        model->facetnorms[3 * i + 1] = -model->facetnorms[3 * i + 1];
        model->facetnorms[3 * i + 2] = -model->facetnorms[3 * i + 2];
    }

    /* reverse vertex normals */
    for (i = 1; i <= model->numnormals; i++) {
        model->normals[3 * i + 0] = -model->normals[3 * i + 0];
        model->normals[3 * i + 1] = -model->normals[3 * i + 1];
        model->normals[3 * i + 2] = -model->normals[3 * i + 2];
    }
}

/* glmFacetNormals: Generates facet normals for a model (by taking the
 * cross product of the two vectors derived from the sides of each
 * triangle).  Assumes a counter-clockwise winding.
 *
 * model - initialized GLMmodel structure
 */
GLvoid
glmFacetNormals(GLMmodel* model)
{
    GLuint  i;
    GLfloat u[3];
    GLfloat v[3];

    assert(model);
    assert(model->vertices);

    /* clobber any old facetnormals */
    if (model->facetnorms)
        free(model->facetnorms);

    /* allocate memory for the new facet normals */
    model->numfacetnorms = model->numtriangles;
    model->facetnorms = (GLfloat*)malloc(sizeof(GLfloat) *
                                         3 * (model->numfacetnorms + 1));

    for (i = 0; i < model->numtriangles; i++) {
        model->triangles[i].findex = i+1;

        u[0] = model->vertices[3 * T(i).vindices[1] + 0] -
                model->vertices[3 * T(i).vindices[0] + 0];
        u[1] = model->vertices[3 * T(i).vindices[1] + 1] -
                model->vertices[3 * T(i).vindices[0] + 1];
        u[2] = model->vertices[3 * T(i).vindices[1] + 2] -
                model->vertices[3 * T(i).vindices[0] + 2];

        v[0] = model->vertices[3 * T(i).vindices[2] + 0] -
                model->vertices[3 * T(i).vindices[0] + 0];
        v[1] = model->vertices[3 * T(i).vindices[2] + 1] -
                model->vertices[3 * T(i).vindices[0] + 1];
        v[2] = model->vertices[3 * T(i).vindices[2] + 2] -
                model->vertices[3 * T(i).vindices[0] + 2];

        glmCross(u, v, &model->facetnorms[3 * (i+1)]);
        glmNormalize(&model->facetnorms[3 * (i+1)]);
    }
}

/* glmVertexNormals: Generates smooth vertex normals for a model.
 * First builds a list of all the triangles each vertex is in.   Then
 * loops through each vertex in the the list averaging all the facet
 * normals of the triangles each vertex is in.   Finally, sets the
 * normal index in the triangle for the vertex to the generated smooth
 * normal.   If the dot product of a facet normal and the facet normal
 * associated with the first triangle in the list of triangles the
 * current vertex is in is greater than the cosine of the angle
 * parameter to the function, that facet normal is not added into the
 * average normal calculation and the corresponding vertex is given
 * the facet normal.  This tends to preserve hard edges.  The angle to
 * use depends on the model, but 90 degrees is usually a good start.
 *
 * model - initialized GLMmodel structure
 * angle - maximum angle (in degrees) to smooth across
 */
GLvoid
glmVertexNormals(GLMmodel* model, GLfloat angle)
{
    GLMnode*    node;
    GLMnode*    tail;
    GLMnode** members;
    GLfloat*    normals;
    GLuint  numnormals;
    GLfloat average[3];
    GLfloat dot, cos_angle;
    GLuint  i, avg;

    assert(model);
    assert(model->facetnorms);

    /* calculate the cosine of the angle (in degrees) */
    cos_angle = cos(angle * M_PI / 180.0);

    /* nuke any previous normals */
    if (model->normals)
        free(model->normals);

    /* allocate space for new normals */
    model->numnormals = model->numtriangles * 3; /* 3 normals per triangle */
    model->normals = (GLfloat*)malloc(sizeof(GLfloat)* 3* (model->numnormals+1));

    /* allocate a structure that will hold a linked list of triangle
    indices for each vertex */
    members = (GLMnode**)malloc(sizeof(GLMnode*) * (model->numvertices + 1));
    for (i = 1; i <= model->numvertices; i++)
        members[i] = NULL;

    /* for every triangle, create a node for each vertex in it */
    for (i = 0; i < model->numtriangles; i++) {
        node = (GLMnode*)malloc(sizeof(GLMnode));
        node->index = i;
        node->next  = members[T(i).vindices[0]];
        members[T(i).vindices[0]] = node;

        node = (GLMnode*)malloc(sizeof(GLMnode));
        node->index = i;
        node->next  = members[T(i).vindices[1]];
        members[T(i).vindices[1]] = node;

        node = (GLMnode*)malloc(sizeof(GLMnode));
        node->index = i;
        node->next  = members[T(i).vindices[2]];
        members[T(i).vindices[2]] = node;
    }

    /* calculate the average normal for each vertex */
    numnormals = 1;
    for (i = 1; i <= model->numvertices; i++) {
        /* calculate an average normal for this vertex by averaging the
        facet normal of every triangle this vertex is in */
        node = members[i];
        if (!node)
            fprintf(stderr, "glmVertexNormals(): vertex w/o a triangle\n");
        average[0] = 0.0; average[1] = 0.0; average[2] = 0.0;
        avg = 0;
        while (node) {
            /* only average if the dot product of the angle between the two
        facet normals is greater than the cosine of the threshold
        angle -- or, said another way, the angle between the two
            facet normals is less than (or equal to) the threshold angle */
            dot = glmDot(&model->facetnorms[3 * T(node->index).findex],
                         &model->facetnorms[3 * T(members[i]->index).findex]);
            if (dot > cos_angle) {
                node->averaged = GL_TRUE;
                average[0] += model->facetnorms[3 * T(node->index).findex + 0];
                average[1] += model->facetnorms[3 * T(node->index).findex + 1];
                average[2] += model->facetnorms[3 * T(node->index).findex + 2];
                avg = 1;            /* we averaged at least one normal! */
            } else {
                node->averaged = GL_FALSE;
            }
            node = node->next;
        }

        if (avg) {
            /* normalize the averaged normal */
            glmNormalize(average);

            /* add the normal to the vertex normals list */
            model->normals[3 * numnormals + 0] = average[0];
            model->normals[3 * numnormals + 1] = average[1];
            model->normals[3 * numnormals + 2] = average[2];
            avg = numnormals;
            numnormals++;
        }

        /* set the normal of this vertex in each triangle it is in */
        node = members[i];
        while (node) {
            if (node->averaged) {
                /* if this node was averaged, use the average normal */
                if (T(node->index).vindices[0] == i)
                    T(node->index).nindices[0] = avg;
                else if (T(node->index).vindices[1] == i)
                    T(node->index).nindices[1] = avg;
                else if (T(node->index).vindices[2] == i)
                    T(node->index).nindices[2] = avg;
            } else {
                /* if this node wasn't averaged, use the facet normal */
                model->normals[3 * numnormals + 0] =
                        model->facetnorms[3 * T(node->index).findex + 0];
                model->normals[3 * numnormals + 1] =
                        model->facetnorms[3 * T(node->index).findex + 1];
                model->normals[3 * numnormals + 2] =
                        model->facetnorms[3 * T(node->index).findex + 2];
                if (T(node->index).vindices[0] == i)
                    T(node->index).nindices[0] = numnormals;
                else if (T(node->index).vindices[1] == i)
                    T(node->index).nindices[1] = numnormals;
                else if (T(node->index).vindices[2] == i)
                    T(node->index).nindices[2] = numnormals;
                numnormals++;
            }
            node = node->next;
        }
    }

    model->numnormals = numnormals - 1;

    /* free the member information */
    for (i = 1; i <= model->numvertices; i++) {
        node = members[i];
        while (node) {
            tail = node;
            node = node->next;
            free(tail);
        }
    }
    free(members);

    /* pack the normals array (we previously allocated the maximum
    number of normals that could possibly be created (numtriangles *
    3), so get rid of some of them (usually alot unless none of the
    facet normals were averaged)) */
    normals = model->normals;
    model->normals = (GLfloat*)malloc(sizeof(GLfloat)* 3* (model->numnormals+1));
    for (i = 1; i <= model->numnormals; i++) {
        model->normals[3 * i + 0] = normals[3 * i + 0];
        model->normals[3 * i + 1] = normals[3 * i + 1];
        model->normals[3 * i + 2] = normals[3 * i + 2];
    }
    free(normals);
}


/* glmLinearTexture: Generates texture coordinates according to a
 * linear projection of the texture map.  It generates these by
 * linearly mapping the vertices onto a square.
 *
 * model - pointer to initialized GLMmodel structure
 */
GLvoid
glmLinearTexture(GLMmodel* model)
{
    GLMgroup *group;
    GLfloat dimensions[3];
    GLfloat x, y, scalefactor;
    GLuint i;

    assert(model);

    if (model->texcoords)
        free(model->texcoords);
    model->numtexcoords = model->numvertices;
    model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(model->numtexcoords+1));

    glmDimensions(model, dimensions);
    scalefactor = 2.0 /
            glmAbs(glmMax(glmMax(dimensions[0], dimensions[1]), dimensions[2]));

    /* do the calculations */
    for(i = 1; i <= model->numvertices; i++) {
        x = model->vertices[3 * i + 0] * scalefactor;
        y = model->vertices[3 * i + 2] * scalefactor;
        model->texcoords[2 * i + 0] = (x + 1.0) / 2.0;
        model->texcoords[2 * i + 1] = (y + 1.0) / 2.0;
    }

    /* go through and put texture coordinate indices in all the triangles */
    group = model->groups;
    while(group) {
        for(i = 0; i < group->numtriangles; i++) {
            T(group->triangles[i]).tindices[0] = T(group->triangles[i]).vindices[0];
            T(group->triangles[i]).tindices[1] = T(group->triangles[i]).vindices[1];
            T(group->triangles[i]).tindices[2] = T(group->triangles[i]).vindices[2];
        }
        group = group->next;
    }

#if 0
    printf("glmLinearTexture(): generated %d linear texture coordinates\n",
           model->numtexcoords);
#endif
}

/* glmSpheremapTexture: Generates texture coordinates according to a
 * spherical projection of the texture map.  Sometimes referred to as
 * spheremap, or reflection map texture coordinates.  It generates
 * these by using the normal to calculate where that vertex would map
 * onto a sphere.  Since it is impossible to map something flat
 * perfectly onto something spherical, there is distortion at the
 * poles.  This particular implementation causes the poles along the X
 * axis to be distorted.
 *
 * model - pointer to initialized GLMmodel structure
 */
GLvoid
glmSpheremapTexture(GLMmodel* model)
{
    GLMgroup* group;
    GLfloat theta, phi, rho, x, y, z, r;
    GLuint i;

    assert(model);
    assert(model->normals);

    if (model->texcoords)
        free(model->texcoords);
    model->numtexcoords = model->numnormals;
    model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(model->numtexcoords+1));

    for (i = 1; i <= model->numnormals; i++) {
        z = model->normals[3 * i + 0];  /* re-arrange for pole distortion */
        y = model->normals[3 * i + 1];
        x = model->normals[3 * i + 2];
        r = sqrt((x * x) + (y * y));
        rho = sqrt((r * r) + (z * z));

        if(r == 0.0) {
            theta = 0.0;
            phi = 0.0;
        } else {
            if(z == 0.0)
                phi = 3.14159265 / 2.0;
            else
                phi = acos(z / rho);

            if(y == 0.0)
                theta = 3.141592365 / 2.0;
            else
                theta = asin(y / r) + (3.14159265 / 2.0);
        }

        model->texcoords[2 * i + 0] = theta / 3.14159265;
        model->texcoords[2 * i + 1] = phi / 3.14159265;
    }

    /* go through and put texcoord indices in all the triangles */
    group = model->groups;
    while(group) {
        for (i = 0; i < group->numtriangles; i++) {
            T(group->triangles[i]).tindices[0] = T(group->triangles[i]).nindices[0];
            T(group->triangles[i]).tindices[1] = T(group->triangles[i]).nindices[1];
            T(group->triangles[i]).tindices[2] = T(group->triangles[i]).nindices[2];
        }
        group = group->next;
    }
}

/* glmDelete: Deletes a GLMmodel structure.
 *
 * model - initialized GLMmodel structure
 */
GLvoid
glmDelete(GLMmodel* model)
{
    GLMgroup* group;
    GLuint i;

    assert(model);

    if (model->pathname)     free(model->pathname);
    if (model->mtllibname) free(model->mtllibname);
    if (model->vertices)     free(model->vertices);
    if (model->normals)  free(model->normals);
    if (model->texcoords)  free(model->texcoords);
    if (model->facetnorms) free(model->facetnorms);
    if (model->triangles)  free(model->triangles);
    if (model->materials) {
        for (i = 0; i < model->nummaterials; i++)
            free(model->materials[i].name);
    }
    free(model->materials);
    while(model->groups) {
        group = model->groups;
        model->groups = model->groups->next;
        free(group->name);
        free(group->triangles);
        free(group);
    }

    free(model);
}

/* glmReadOBJ: Reads a model description from a Wavefront .OBJ file.
 * Returns a pointer to the created object which should be free'd with
 * glmDelete().
 *
 * filename - name of the file containing the Wavefront .OBJ format data.
 */
GLMmodel*
glmReadOBJ(const char* filename)
{
    GLMmodel* model;
    FILE*   file;

    /* open the file */
    file = fopen(filename, "r");
    if (!file) {
        fprintf(stderr, "glmReadOBJ() failed: can't open data file \"%s\".\n",
                filename);
        exit(1);
    }

    /* allocate a new model */
    model = (GLMmodel*)malloc(sizeof(GLMmodel));
    model->pathname    = strdup(filename);
    model->mtllibname    = NULL;
    model->numvertices   = 0;
    model->vertices    = NULL;
    model->numnormals    = 0;
    model->normals     = NULL;
    model->numtexcoords  = 0;
    model->texcoords       = NULL;
    model->numfacetnorms = 0;
    model->facetnorms    = NULL;
    model->numtriangles  = 0;
    model->triangles       = NULL;
    model->nummaterials  = 0;
    model->materials       = NULL;
    model->numgroups       = 0;
    model->groups      = NULL;
    model->position[0]   = 0.0;
    model->position[1]   = 0.0;
    model->position[2]   = 0.0;

    /* make a first pass through the file to get a count of the number
    of vertices, normals, texcoords & triangles */
    glmFirstPass(model, file);

    /* allocate memory */
    model->vertices = (GLfloat*)malloc(sizeof(GLfloat) *
                                       3 * (model->numvertices + 1));
    model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) *
                                            model->numtriangles);
    if (model->numnormals) {
        model->normals = (GLfloat*)malloc(sizeof(GLfloat) *
                                          3 * (model->numnormals + 1));
    }
    if (model->numtexcoords) {
        model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) *
                                            2 * (model->numtexcoords + 1));
    }

    /* rewind to beginning of file and read in the data this pass */
    rewind(file);

    glmSecondPass(model, file);

    /* close the file */
    fclose(file);

//    glmNormalizeTexCoor(model,1);
//    for(int i=0;i<model->numtexcoords;i++){
//        model->texcoords[2*i + 0] = model->texcoords[2*i + 0]*1.2;
//        model->texcoords[2*i + 1] = model->texcoords[2*i + 1]*1.2;
//    }

    for(int i=0;i<model->numtriangles;i++) model->triangles[i].oindex=i;
    //
    return model;
}
GLvoid  glmRotateAroundMean(GLfloat* vertex, GLint nbVertex){
    //
    int max_x_idx = INT_MIN;GLfloat max_x = INT_MIN;
    int max_y_idx = INT_MIN;GLfloat max_y = INT_MIN;
    int min_x_idx = INT_MAX;GLfloat min_x = INT_MAX;
    int min_y_idx = INT_MAX;GLfloat min_y = INT_MAX;
    for(int i=1;i<=nbVertex;i++){
        // x
        if(max_x < vertex[3*i + 0]){ max_x = vertex[3*i + 0];max_x_idx = i;}
        if(min_x > vertex[3*i + 0]){ min_x = vertex[3*i + 0];min_x_idx = i;}
        // y
        if(max_y < vertex[3*i + 1]){ max_y = vertex[3*i + 1];max_y_idx = i;}
        if(min_y > vertex[3*i + 1]){ min_y = vertex[3*i + 1];min_y_idx = i;}
    }
    Vector3 p_max_x(vertex[3*max_x_idx + 0],vertex[3*max_x_idx + 1],vertex[3*max_x_idx + 2]);
    Vector3 p_max_y(vertex[3*max_y_idx + 0],vertex[3*max_y_idx + 1],vertex[3*max_y_idx + 2]);
    Vector3 p_min_x(vertex[3*min_x_idx + 0],vertex[3*min_x_idx + 1],vertex[3*min_x_idx + 2]);
    Vector3 p_min_y(vertex[3*min_y_idx + 0],vertex[3*min_y_idx + 1],vertex[3*min_y_idx + 2]);

    Vector3 p_avg2((p_max_x.x + p_max_y.x)/2,(p_max_x.y + p_max_y.y)/2,(p_max_x.z + p_max_y.z)/2 );
    Vector3 p_avg1((p_min_x.x + p_min_y.x)/2,(p_min_x.y + p_min_y.y)/2,(p_min_x.z + p_min_y.z)/2);

    Vector3 p_avg3((p_avg2.x + p_avg1.x)/2,(p_avg2.y + p_avg1.y)/2,(p_avg2.z + p_avg1.z)/2);

    Vector2 p12(p_avg2.x - p_avg1.x, p_avg2.y - p_avg1.y);

    float angle = M_PI/2 - atan2(p12.y,p12.x);

    //
    for(int i=1;i<=nbVertex;i++){
        vertex[3*i + 0] = vertex[3*i + 0] - p_avg3.x;
        vertex[3*i + 1] = vertex[3*i + 1] - p_avg3.y;
        vertex[3*i + 2] = vertex[3*i + 2] - p_avg3.z;

        float x = vertex[3*i + 0]*cos(angle) - vertex[3*i + 1]*sin(angle);
        float y = vertex[3*i + 0]*sin(angle) + vertex[3*i + 1]*cos(angle);
        vertex[3*i + 0] = x;
        vertex[3*i + 1] = y;
        //
        vertex[3*i + 0] = vertex[3*i + 0] + p_avg3.x;
        vertex[3*i + 1] = vertex[3*i + 1] + p_avg3.y;
        vertex[3*i + 2] = vertex[3*i + 2] + p_avg3.z;

    }
}

/* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to
 * a file.
 *
 * model - initialized GLMmodel structure
 * filename - name of the file to write the Wavefront .OBJ format data to
 * mode  - a bitwise or of values describing what is written to the file
 *             GLM_NONE     -  render with only vertices
 *             GLM_FLAT     -  render with facet normals
 *             GLM_SMOOTH   -  render with vertex normals
 *             GLM_TEXTURE  -  render with texture coords
 *             GLM_COLOR    -  render with colors (color material)
 *             GLM_MATERIAL -  render with materials
 *             GLM_COLOR and GLM_MATERIAL should not both be specified.
 *             GLM_FLAT and GLM_SMOOTH should not both be specified.
 */
GLvoid
glmWriteOBJ(GLMmodel* model, char* filename, GLuint mode)
{
    GLuint  i;
    FILE*   file;
    GLMgroup* group;

    assert(model);

    /* do a bit of warning */
    if (mode & GLM_FLAT && !model->facetnorms) {
        printf("glmWriteOBJ() warning: flat normal output requested "
               "with no facet normals defined.\n");
        mode &= ~GLM_FLAT;
    }
    if (mode & GLM_SMOOTH && !model->normals) {
        printf("glmWriteOBJ() warning: smooth normal output requested "
               "with no normals defined.\n");
        mode &= ~GLM_SMOOTH;
    }
    if (mode & GLM_TEXTURE && !model->texcoords) {
        printf("glmWriteOBJ() warning: texture coordinate output requested "
               "with no texture coordinates defined.\n");
        mode &= ~GLM_TEXTURE;
    }
    if (mode & GLM_FLAT && mode & GLM_SMOOTH) {
        printf("glmWriteOBJ() warning: flat normal output requested "
               "and smooth normal output requested (using smooth).\n");
        mode &= ~GLM_FLAT;
    }
    if (mode & GLM_COLOR && !model->materials) {
        printf("glmWriteOBJ() warning: color output requested "
               "with no colors (materials) defined.\n");
        mode &= ~GLM_COLOR;
    }
    if (mode & GLM_MATERIAL && !model->materials) {
        printf("glmWriteOBJ() warning: material output requested "
               "with no materials defined.\n");
        mode &= ~GLM_MATERIAL;
    }
    if (mode & GLM_COLOR && mode & GLM_MATERIAL) {
        printf("glmWriteOBJ() warning: color and material output requested "
               "outputting only materials.\n");
        mode &= ~GLM_COLOR;
    }


    /* open the file */
    file = fopen(filename, "w");
    if (!file) {
        fprintf(stderr, "glmWriteOBJ() failed: can't open file \"%s\" to write.\n",
                filename);
        exit(1);
    }

    /* spit out a header */
    fprintf(file, "#  \n");
    fprintf(file, "#  Wavefront OBJ generated by GLM library\n");
    fprintf(file, "#  \n");
    fprintf(file, "#  GLM library\n");
    fprintf(file, "#  Nate Robins\n");
    fprintf(file, "#  ndr@pobox.com\n");
    fprintf(file, "#  http://www.pobox.com/~ndr\n");
    fprintf(file, "#  \n");

    if (mode & GLM_MATERIAL && model->mtllibname) {
        fprintf(file, "\nmtllib %s\n\n", model->mtllibname);
        glmWriteMTL(model, filename, model->mtllibname);
    }

    /* spit out the vertices */
    fprintf(file, "\n");
    fprintf(file, "# %d vertices\n", model->numvertices);
    for (i = 1; i <= model->numvertices; i++) {
        fprintf(file, "v %f %f %f\n",
                model->vertices[3 * i + 0],
                model->vertices[3 * i + 1],
                model->vertices[3 * i + 2]);
    }

    /* spit out the smooth/flat normals */
    if (mode & GLM_SMOOTH) {
        fprintf(file, "\n");
        fprintf(file, "# %d normals\n", model->numnormals);
        for (i = 1; i <= model->numnormals; i++) {
            fprintf(file, "vn %f %f %f\n",
                    model->normals[3 * i + 0],
                    model->normals[3 * i + 1],
                    model->normals[3 * i + 2]);
        }
    } else if (mode & GLM_FLAT) {
        fprintf(file, "\n");
        fprintf(file, "# %d normals\n", model->numfacetnorms);
        for (i = 1; i <= model->numnormals; i++) {
            fprintf(file, "vn %f %f %f\n",
                    model->facetnorms[3 * i + 0],
                    model->facetnorms[3 * i + 1],
                    model->facetnorms[3 * i + 2]);
        }
    }

    /* spit out the texture coordinates */
    if (mode & GLM_TEXTURE) {
        fprintf(file, "\n");
        fprintf(file, "# %d texcoords\n", model->texcoords);
        for (i = 1; i <= model->numtexcoords; i++) {
            fprintf(file, "vt %f %f\n",
                    model->texcoords[2 * i + 0],
                    model->texcoords[2 * i + 1]);
        }
    }

    fprintf(file, "\n");
    fprintf(file, "# %d groups\n", model->numgroups);
    fprintf(file, "# %d faces (triangles)\n", model->numtriangles);
    fprintf(file, "\n");

    group = model->groups;

    while(group) {
        if(group->name == "default") break;
        fprintf(file, "g %s\n", group->name);
        if (mode & GLM_MATERIAL)
            fprintf(file, "usemtl %s\n", model->materials[group->material].name);
        for (i = 0; i < group->numtriangles; i++) {
            if (mode & GLM_SMOOTH && mode & GLM_TEXTURE) {
                fprintf(file, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
                        T(group->triangles[i]).vindices[0],
                        T(group->triangles[i]).nindices[0],
                        T(group->triangles[i]).tindices[0],
                        T(group->triangles[i]).vindices[1],
                        T(group->triangles[i]).nindices[1],
                        T(group->triangles[i]).tindices[1],
                        T(group->triangles[i]).vindices[2],
                        T(group->triangles[i]).nindices[2],
                        T(group->triangles[i]).tindices[2]);
            } else if (mode & GLM_FLAT && mode & GLM_TEXTURE) {
                fprintf(file, "f %d/%d %d/%d %d/%d\n",
                        T(group->triangles[i]).vindices[0],
                        T(group->triangles[i]).findex,
                        T(group->triangles[i]).vindices[1],
                        T(group->triangles[i]).findex,
                        T(group->triangles[i]).vindices[2],
                        T(group->triangles[i]).findex);
            } else if (mode & GLM_TEXTURE) {
                fprintf(file, "f %d/%d %d/%d %d/%d\n",
                        T(group->triangles[i]).vindices[0],
                        T(group->triangles[i]).tindices[0],
                        T(group->triangles[i]).vindices[1],
                        T(group->triangles[i]).tindices[1],
                        T(group->triangles[i]).vindices[2],
                        T(group->triangles[i]).tindices[2]);
            } else if (mode & GLM_SMOOTH) {
                fprintf(file, "f %d//%d %d//%d %d//%d\n",
                        T(group->triangles[i]).vindices[0],
                        T(group->triangles[i]).nindices[0],
                        T(group->triangles[i]).vindices[1],
                        T(group->triangles[i]).nindices[1],
                        T(group->triangles[i]).vindices[2],
                        T(group->triangles[i]).nindices[2]);
            } else if (mode & GLM_FLAT) {
                fprintf(file, "f %d//%d %d//%d %d//%d\n",
                        T(group->triangles[i]).vindices[0],
                        T(group->triangles[i]).findex,
                        T(group->triangles[i]).vindices[1],
                        T(group->triangles[i]).findex,
                        T(group->triangles[i]).vindices[2],
                        T(group->triangles[i]).findex);
            } else {
                fprintf(file, "f %d %d %d\n",
                        T(group->triangles[i]).vindices[0],
                        T(group->triangles[i]).vindices[1],
                        T(group->triangles[i]).vindices[2]);
            }
        }
        fprintf(file, "\n");
        group = group->next;
    }

    fclose(file);
}

/* glmDraw: Renders the model to the current OpenGL context using the
 * mode specified.
 *
 * model - initialized GLMmodel structure
 * mode  - a bitwise OR of values describing what is to be rendered.
 *             GLM_NONE     -  render with only vertices
 *             GLM_FLAT     -  render with facet normals
 *             GLM_SMOOTH   -  render with vertex normals
 *             GLM_TEXTURE  -  render with texture coords
 *             GLM_COLOR    -  render with colors (color material)
 *             GLM_MATERIAL -  render with materials
 *             GLM_COLOR and GLM_MATERIAL should not both be specified.
 *             GLM_FLAT and GLM_SMOOTH should not both be specified.
 */
GLvoid
glmDraw(GLMmodel* model, GLuint mode)
{
    static GLuint i;
    static GLMgroup* group;
    static GLMtriangle* triangle;
    static GLMmaterial* material;

    assert(model);
    assert(model->vertices);

    /* do a bit of warning */
    if (mode & GLM_FLAT && !model->facetnorms) {
        printf("glmDraw() warning: flat render mode requested "
               "with no facet normals defined.\n");
        mode &= ~GLM_FLAT;
    }
    if (mode & GLM_SMOOTH && !model->normals) {
        printf("glmDraw() warning: smooth render mode requested "
               "with no normals defined.\n");
        mode &= ~GLM_SMOOTH;
    }
    if (mode & GLM_TEXTURE && !model->texcoords) {
        printf("glmDraw() warning: texture render mode requested "
               "with no texture coordinates defined.\n");
        mode &= ~GLM_TEXTURE;
    }
    if (mode & GLM_FLAT && mode & GLM_SMOOTH) {
        printf("glmDraw() warning: flat render mode requested "
               "and smooth render mode requested (using smooth).\n");
        mode &= ~GLM_FLAT;
    }
    if (mode & GLM_COLOR && !model->materials) {
        printf("glmDraw() warning: color render mode requested "
               "with no materials defined.\n");
        mode &= ~GLM_COLOR;
    }
    if (mode & GLM_MATERIAL && !model->materials) {
        printf("glmDraw() warning: material render mode requested "
               "with no materials defined.\n");
        mode &= ~GLM_MATERIAL;
    }
    if (mode & GLM_COLOR && mode & GLM_MATERIAL) {
        printf("glmDraw() warning: color and material render mode requested "
               "using only material mode.\n");
        mode &= ~GLM_COLOR;
    }
    if (mode & GLM_COLOR)
        glEnable(GL_COLOR_MATERIAL);
    else if (mode & GLM_MATERIAL)
        glDisable(GL_COLOR_MATERIAL);

    /* perhaps this loop should be unrolled into material, color, flat,
       smooth, etc. loops?  since most cpu's have good branch prediction
       schemes (and these branches will always go one way), probably
       wouldn't gain too much?  */

    group = model->groups;
    while (group) {
        if (mode & GLM_MATERIAL) {
            material = &model->materials[group->material];
            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient);
            glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse);
            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material->specular);
            glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material->shininess);
        }

        if (mode & GLM_COLOR) {
            glColor3fv(material->diffuse);
        }

        glBegin(GL_TRIANGLES);
        for (i = 0; i < group->numtriangles; i++) {
            triangle = &T(group->triangles[i]);

            if (mode & GLM_FLAT)
                glNormal3fv(&model->facetnorms[3 * triangle->findex]);

            if (mode & GLM_SMOOTH)
                glNormal3fv(&model->normals[3 * triangle->nindices[0]]);
            if (mode & GLM_TEXTURE)
                glTexCoord2fv(&model->texcoords[2 * triangle->tindices[0]]);
            glVertex3fv(&model->vertices[3 * triangle->vindices[0]]);

            if (mode & GLM_SMOOTH)
                glNormal3fv(&model->normals[3 * triangle->nindices[1]]);
            if (mode & GLM_TEXTURE)
                glTexCoord2fv(&model->texcoords[2 * triangle->tindices[1]]);
            glVertex3fv(&model->vertices[3 * triangle->vindices[1]]);

            if (mode & GLM_SMOOTH)
                glNormal3fv(&model->normals[3 * triangle->nindices[2]]);
            if (mode & GLM_TEXTURE)
                glTexCoord2fv(&model->texcoords[2 * triangle->tindices[2]]);
            glVertex3fv(&model->vertices[3 * triangle->vindices[2]]);

        }
        glEnd();

        group = group->next;
    }
}

/* glmList: Generates and returns a display list for the model using
 * the mode specified.
 *
 * model - initialized GLMmodel structure
 * mode  - a bitwise OR of values describing what is to be rendered.
 *             GLM_NONE     -  render with only vertices
 *             GLM_FLAT     -  render with facet normals
 *             GLM_SMOOTH   -  render with vertex normals
 *             GLM_TEXTURE  -  render with texture coords
 *             GLM_COLOR    -  render with colors (color material)
 *             GLM_MATERIAL -  render with materials
 *             GLM_COLOR and GLM_MATERIAL should not both be specified.
 * GLM_FLAT and GLM_SMOOTH should not both be specified.
 */
GLuint
glmList(GLMmodel* model, GLuint mode)
{
    GLuint list;

    list = glGenLists(1);
    glNewList(list, GL_COMPILE);
    glmDraw(model, mode);
    glEndList();

    return list;
}

/* glmWeld: eliminate (weld) vectors that are within an epsilon of
 * each other.
 *
 * model   - initialized GLMmodel structure
 * epsilon     - maximum difference between vertices
 *               ( 0.00001 is a good start for a unitized model)
 *
 */
GLvoid
glmWeld(GLMmodel* model, GLfloat epsilon)
{
    GLfloat* vectors;
    GLfloat* copies;
    GLuint   numvectors;
    GLuint   i;

    /* vertices */
    numvectors = model->numvertices;
    vectors  = model->vertices;
    copies = glmWeldVectors(vectors, &numvectors, epsilon);

#if 0
    printf("glmWeld(): %d redundant vertices.\n",
           model->numvertices - numvectors - 1);
#endif

    for (i = 0; i < model->numtriangles; i++) {
        T(i).vindices[0] = (GLuint)vectors[3 * T(i).vindices[0] + 0];
        T(i).vindices[1] = (GLuint)vectors[3 * T(i).vindices[1] + 0];
        T(i).vindices[2] = (GLuint)vectors[3 * T(i).vindices[2] + 0];
    }

    /* free space for old vertices */
    free(vectors);

    /* allocate space for the new vertices */
    model->numvertices = numvectors;
    model->vertices = (GLfloat*)malloc(sizeof(GLfloat) *
                                       3 * (model->numvertices + 1));

    /* copy the optimized vertices into the actual vertex list */
    for (i = 1; i <= model->numvertices; i++) {
        model->vertices[3 * i + 0] = copies[3 * i + 0];
        model->vertices[3 * i + 1] = copies[3 * i + 1];
        model->vertices[3 * i + 2] = copies[3 * i + 2];
    }

    free(copies);
}

/* glmReadPPM: read a PPM raw (type P6) file.  The PPM file has a header
 * that should look something like:
 *
 *    P6
 *    # comment
 *    width height max_value
 *    rgbrgbrgb...
 *
 * where "P6" is the magic cookie which identifies the file type and
 * should be the only characters on the first line followed by a
 * carriage return.  Any line starting with a # mark will be treated
 * as a comment and discarded.   After the magic cookie, three integer
 * values are expected: width, height of the image and the maximum
 * value for a pixel (max_value must be < 256 for PPM raw files).  The
 * data section consists of width*height rgb triplets (one byte each)
 * in binary format (i.e., such as that written with fwrite() or
 * equivalent).
 *
 * The rgb data is returned as an array of unsigned chars (packed
 * rgb).  The malloc()'d memory should be free()'d by the caller.  If
 * an error occurs, an error message is sent to stderr and NULL is
 * returned.
 *
 * filename   - name of the .ppm file.
 * width      - will contain the width of the image on return.
 * height     - will contain the height of the image on return.
 *
 */
GLubyte*
glmReadPPM(char* filename, int* width, int* height)
{
    FILE* fp;
    int i, w, h, d;
    unsigned char* image;
    char head[70];          /* max line <= 70 in PPM (per spec). */

    fp = fopen(filename, "rb");
    if (!fp) {
        perror(filename);
        return NULL;
    }

    /* grab first two chars of the file and make sure that it has the
       correct magic cookie for a raw PPM file. */
    if(fgets(head, 70, fp));
    if (strncmp(head, "P6", 2)) {
        fprintf(stderr, "%s: Not a raw PPM file\n", filename);
        return NULL;
    }

    /* grab the three elements in the header (width, height, maxval). */
    i = 0;
    while(i < 3) {
        if(fgets(head, 70, fp));
        if (head[0] == '#')     /* skip comments. */
            continue;
        if (i == 0)
            i += sscanf(head, "%d %d %d", &w, &h, &d);
        else if (i == 1)
            i += sscanf(head, "%d %d", &h, &d);
        else if (i == 2)
            i += sscanf(head, "%d", &d);
    }

    /* grab all the image data in one fell swoop. */
    image = (unsigned char*)malloc(sizeof(unsigned char)*w*h*3);
    if(fread(image, sizeof(unsigned char), w*h*3, fp));
    fclose(fp);

    *width = w;
    *height = h;
    return image;
}

#if 0
/* normals */
if (model->numnormals) {
    numvectors = model->numnormals;
    vectors  = model->normals;
    copies = glmOptimizeVectors(vectors, &numvectors);

    printf("glmOptimize(): %d redundant normals.\n",
           model->numnormals - numvectors);

    for (i = 0; i < model->numtriangles; i++) {
        T(i).nindices[0] = (GLuint)vectors[3 * T(i).nindices[0] + 0];
        T(i).nindices[1] = (GLuint)vectors[3 * T(i).nindices[1] + 0];
        T(i).nindices[2] = (GLuint)vectors[3 * T(i).nindices[2] + 0];
    }

    /* free space for old normals */
    free(vectors);

    /* allocate space for the new normals */
    model->numnormals = numvectors;
    model->normals = (GLfloat*)malloc(sizeof(GLfloat) *
                                      3 * (model->numnormals + 1));

    /* copy the optimized vertices into the actual vertex list */
    for (i = 1; i <= model->numnormals; i++) {
        model->normals[3 * i + 0] = copies[3 * i + 0];
        model->normals[3 * i + 1] = copies[3 * i + 1];
        model->normals[3 * i + 2] = copies[3 * i + 2];
    }

    free(copies);
}

/* texcoords */
if (model->numtexcoords) {
    numvectors = model->numtexcoords;
    vectors  = model->texcoords;
    copies = glmOptimizeVectors(vectors, &numvectors);

    printf("glmOptimize(): %d redundant texcoords.\n",
           model->numtexcoords - numvectors);

    for (i = 0; i < model->numtriangles; i++) {
        for (j = 0; j < 3; j++) {
            T(i).tindices[j] = (GLuint)vectors[3 * T(i).tindices[j] + 0];
        }
    }

    /* free space for old texcoords */
    free(vectors);

    /* allocate space for the new texcoords */
    model->numtexcoords = numvectors;
    model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) *
                                        2 * (model->numtexcoords + 1));

    /* copy the optimized vertices into the actual vertex list */
    for (i = 1; i <= model->numtexcoords; i++) {
        model->texcoords[2 * i + 0] = copies[2 * i + 0];
        model->texcoords[2 * i + 1] = copies[2 * i + 1];
    }

    free(copies);
}
#endif

#if 0
/* look for unused vertices */
/* look for unused normals */
/* look for unused texcoords */
for (i = 1; i <= model->numvertices; i++) {
    for (j = 0; j < model->numtriangles; i++) {
        if (T(j).vindices[0] == i ||
                T(j).vindices[1] == i ||
                T(j).vindices[1] == i)
            break;
    }
}
#endif
