Page d'accueil Description du projet
/*********************************************
 *
 * Cedric Pradalier
 * DEA 2000/2001 
 * INRIA Rhones Alpes
 * http://cedric.pradalier.free.fr/index.html
 * mail : http://cedric.pradalier.free.fr/mail.html
 *
 * *******************************************/
#include "Polygon.h"
#include "Segment.h"
#include "math.h"
#include <iostream.h>

#define EQ(X,Y) (fabs(X-Y)<1e-3)

Polygon::~Polygon()
{
    //printf("*");
    gpc_free_polygon(poly);
    delete poly;
}

void Polygon::Read(FILE * fp) 
{
    gpc_free_polygon(poly);
    delete poly;
    poly = new gpc_polygon;
    gpc_init_polygon(poly);
    gpc_read_polygon(fp,true,poly);
}


Polygon * Polygon::Union(Polygon * p)
{
    Polygon * r = new Polygon();
    gpc_polygon_clip(GPC_UNION,poly,p->poly,r->poly);
    return r;
}

Polygon * Polygon::Intersection(Polygon * p)
{
    Polygon * r = new Polygon();
    gpc_polygon_clip(GPC_INT,poly,p->poly,r->poly);
    return r;
}

Polygon * Polygon::Minus(Polygon * p)
{
    Polygon * r = new Polygon();
    gpc_polygon_clip(GPC_DIFF,poly,p->poly,r->poly);
    return r;
}

Polygon * Polygon::Xor(Polygon * p)
{
    Polygon * r = new Polygon();
    gpc_polygon_clip(GPC_XOR,poly,p->poly,r->poly);
    return r;
}


void Polygon::getConnexList(Vector * list)
{
        int i;
        Polygon * P;
        gpc_polygon * gpc_P;
        if (numPartConnex()==1)
        {
                list->addElement(new Polygon(this));
                return;
        }

        for(i=0;i<poly->num_contours;i++)
        {
                if (!(poly->hole[i]))
                {
                        gpc_P = new gpc_polygon;
                        gpc_init_polygon(gpc_P);
                        gpc_add_contour(gpc_P,&(poly->contour[i]),poly->hole[i]);
                        P = new Polygon(gpc_P);
                        list->addElement(Intersection(P));
                        delete P;
                }
        }
}


void Polygon::getEdges(Vector * list)
{
    int i,j;
    for(i=0;i<poly->num_contours;i++)
    {
        int n = poly->contour[i].num_vertices;
        for(j=0;j<n-1;j++)
            list->addElement(new Segment(
                        Vector2(poly->contour[i].vertex[j].x,
                            poly->contour[i].vertex[j].y),
                        Vector2(poly->contour[i].vertex[j+1].x,
                            poly->contour[i].vertex[j+1].y)));
        list->addElement(new Segment(
                    Vector2(poly->contour[i].vertex[n-1].x,
                        poly->contour[i].vertex[n-1].y),
                    Vector2(poly->contour[i].vertex[0].x,
                        poly->contour[i].vertex[0].y)));
    }
    list->trimToSize();
}


    

bool Polygon::isAVertex(double x,double y)
{
    int i,j;
    for(i=0;i<poly->num_contours;i++)
        for(j=0;j<poly->contour[i].num_vertices;j++)
            if ((fabs(poly->contour[i].vertex[j].x - x) < 1e-6) &&
                    (fabs(poly->contour[i].vertex[j].y - y) < 1e-6))
        //  if ((poly->contour[i].vertex[j].x == x) &&
        //          (poly->contour[i].vertex[j].y == y))
                return true;
    return false;
}



void Polygon::getCenter(double * x, double * y)
{
    gpc_vertex pt;
    gpc_get_center(poly,&pt);
    *x = pt.x;
    *y = pt.y;
}
    

void Polygon::getBoundingCircle(double * x, double * y,double * r)
{
    gpc_vertex pt;
    gpc_find_bounding_circle_radius(poly,&pt,r);
    *x = pt.x;
    *y = pt.y;
}
    


double Polygon::getArea()
{
    return gpc_poly_area(poly);
}


int Polygon::numPartConnex()
{
    int i,n;
    n = 0;
    for (i=0;i<poly->num_contours;i++)
        if (poly->hole[i] == 0) n+=1;
    return n;
}
    

void Polygon::cut()
{
    gpc_polygon * result = new gpc_polygon;
    gpc_cut_polygon(poly,result);
    gpc_free_polygon(poly);
    delete poly;
    poly = result;
}   



// #define DEBUG
Polygon * Polygon::computeVisibility(double x,double y)
{
    Vector edges,obsEdges;
    double triangle[6];
    double quadri[8];
    Polygon *visibility = new Polygon();
    Polygon *T,*tmp;
    Vector2 balise(x,y);
    int i,j;
    double mu;

    triangle[0] = x;
    triangle[1] = y;
    getEdges(&edges);

    for (i=0;i<edges.size();i++)
    {
        Segment * s = (Segment*)(edges.elementAt(i));
        triangle[2]= s->A.x;
        triangle[3]= s->A.y;
        triangle[4]= s->B.x;
        triangle[5]= s->B.y;
        T = new Polygon(triangle,6);
        Polygon * V = Intersection(T);// workspace inter T
        if (V->numPartConnex() > 1) {
            delete T;delete V;continue;
        }
        if (!V->isAVertex(balise.x,balise.y))  {
            delete T;delete V;continue;
        }
        Polygon * O = T->Minus(V);
        O->getEdges(&obsEdges); 
        delete T;
        if (obsEdges.size() == 0)
        {
            tmp = visibility;
            visibility = visibility->Union(V);
            delete tmp;
            delete V;
            continue;
        }

        
        
        
        for (j=0;j<obsEdges.size();j++)
        {
            Segment * o = (Segment*)(obsEdges.elementAt(j));
            quadri[0]=o->A.x; quadri[1]=o->A.y;
            quadri[2]=o->B.x; quadri[3]=o->B.y;
            Vector2 dirA = (o->A-balise);
            if (EQ(dirA.norme(),0)) continue;
            double lambdaA=s->intersect(balise,dirA,&mu);
            if (lambdaA < 0)
            {
                if (EQ(mu,1))
                {
                    quadri[6]=s->B.x;
                    quadri[7]=s->B.y;
                }
                if EQ(mu,0)
                {
                    quadri[6]=s->A.x;
                    quadri[7]=s->A.y;
                }
            }
            else
            {
                quadri[6]=balise.x+lambdaA*dirA.x;
                quadri[7]=balise.y+lambdaA*dirA.y;
            }
            Vector2 dirB = (o->B-balise);
            if (EQ(dirB.norme(),0)) continue;
            double lambdaB=s->intersect(balise,dirB,&mu);
            if (lambdaB < 0)
            {
                if (EQ(mu,1))
                {
                    quadri[4]=s->B.x;
                    quadri[5]=s->B.y;
                }
                if EQ(mu,0)
                {
                    quadri[4]=s->A.x;
                    quadri[5]=s->A.y;
                }
            }
            else
            {
                quadri[4]=balise.x+lambdaB*dirB.x;
                quadri[5]=balise.y+lambdaB*dirB.y;
            }
            Polygon * suppr = new Polygon(quadri,8);
            T = V->Minus(suppr);
            delete suppr;
            delete V;
            V = T;
        }
        obsEdges.deleteAll();
        delete O;
        T = visibility->Union(V);
        delete V;
        delete visibility;
        visibility = T;
    }
    edges.deleteAll();

    return visibility;

}


void Polygon::collectVtkPoints(VtkPoints & points,VtkPolygons & polygons)
{
    int i,j;
    VtkPoint3D P;
    P.z = 0;
    P.c = 0;
    for (i=0;i<poly->num_contours;i++)
    {
        VtkPolygon pol;
        for (j=0;j<poly->contour[i].num_vertices;j++)
        {
            P.x = poly->contour[i].vertex[j].x;
            P.y = poly->contour[i].vertex[j].y;
            pol.push_back(points.size());
            points.push_back(P);
        }
        polygons.push_back(pol);
    }
}