home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.disi.unige.it
/
2015-02-11.ftp.disi.unige.it.tar
/
ftp.disi.unige.it
/
pub
/
.person
/
MagilloP
/
GEOMOD99
/
build.c
next >
Wrap
C/C++ Source or Header
|
1999-05-04
|
10KB
|
374 lines
/***********************************************************************/
/* FILE: build.c */
/***********************************************************************/
/*
Costruzione di quadtree per triangolazione.
Per metterci al riparo da casi particolari assumiamo che i vertici
della triangolazione abbiano coordinate intere o terminanti per 0.5,
ed utilizziamo nel quadtree coordinate terminanti per 0.3
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "point.h"
#include "stack.h"
#include "tree.h"
/***********************************************************************/
/* triangolazione letta da file */
COMPLETARE: dichiarazione variabile globale per la triangulazione tau;
/* radice dell'albero da costruire */
QTree root;
/* massima profondita' ammessa per il quadtree (determina la minima
dimensione per un nodo) */
#define MAXDEPTH 6
void ReadTriangulation(void)
{
int i;
int vrtNum, trgNum; /* per leggere numero di vertici e triangoli */
float x, y; /* per leggere coordinate di un vertice */
int v1, v2, v3; /* per leggere vertici di un triangolo */
int ad1, ad2, ad3; /* per leggere adiacenti di un triangolo */
int t; /* per leggere triangolo associato a un vertice */
COMPLETARE con allocazione dello spazio per la struttura dati per
la triangolazione e copia nella struttura dati delle informazioni
lette.
/* legge il numero di vertici */
scanf("%d",&vrtNum);
/* legge i vertici */
for (i=0; i<vrtNum; i++)
{
scanf("%f %f", &x, &y);
}
/* legge il numero di triangoli */
scanf("%d",&trgNum);
/* legge la relazione TV */
for (i=0; i<trgNum; i++)
{
scanf("%d %d %d", &v1, &v2, &v3);
}
/* legge la relazione VT parziale */
for (i=0; i<vrtNum; i++)
{
scanf("%d", &t);
}
/* legge la relazione TT */
for (i=0; i<trgNum; i++)
{
scanf("%d %d %d", &ad1, &ad2, &ad3);
}
}
/***********************************************************************/
double log2(double x)
{
return (log(x)/log(2.0));
}
/* controlla se il punto p si trova strettamente all'interno del
rettangolo con angolo in basso a sinistra (x0,y0), larghezza
dx ed altezza dy */
int pointInBox(Point p, float x0, float y0, float dx, float dy)
{
if (p[X]<=x0) return 0;
if (p[X]>=x0+dx) return 0;
if (p[Y]<=y0) return 0;
if (p[Y]>=y0+dy) return 0;
return 1;
}
/* controlla se il lato di estremi p1 e p2 interseca propriamente
il rettangolo con angolo in basso a sinistra (x0,y0), larghezza
dx ed altezza dy */
int edgeInBox(Point p1, Point p2,
float x0, float y0, float dx, float dy)
{
int is_left, is_right;
Point aux;
int i, j;
/* almeno uno dei due estremi deve essere a destra della retta x=x0 */
if ( (p1[X]<=x0) && (p2[X]<=x0) ) return 0;
/* almeno uno dei due estremi deve essere a sinistra di x=x0+dx */
if ( (p1[X]>=x0+dx) && (p2[X]>=x0+dx) ) return 0;
/* almeno uno dei due estremi deve essere sopra la retta y=y0 */
if ( (p1[Y]<=y0) && (p2[Y]<=y0) ) return 0;
/* almeno uno dei due estremi deve essere sotto la retta y=y0+dy */
if ( (p1[Y]>=y0+dy) && (p2[Y]>=y0+dy) ) return 0;
/* almeno due vertici del box devono giacere da parti opposte
rispetto al segmento p1 p2 */
is_left = is_right = 0;
for (i=0; i<2; i++)
for (j=0; j<2; j++)
{
aux[X] = x0; aux[Y] = y0;
if (i) aux[X] += dx;
if (j) aux[Y] += dy;
is_left = is_left || Left(aux, p1, p2);
is_right = is_right || (!LeftOn(aux, p1, p2));
}
if (is_left && is_right) return 1;
return 0;
}
/* controlla se il triangolo t interseca propriamente il rettangolo
con angolo in basso a sinistra (x0,y0), larghezza dx ed altezza dy */
int triangleInBox(int t, /* indice del triangolo */
float x0, float y0, float dx, float dy)
{
Point *p1, *p2, *p3, aux;
COMPLETARE:
p1 = primo vertice del triangolo di indice t
p2 = secondo vertice
p3 = terzo vertice
/* se almeno un vertice e' propriamente dentro --> t interseca */
if (pointInBox(*p1,x0,y0,dx,dy)) return 1;
if (pointInBox(*p2,x0,y0,dx,dy)) return 1;
if (pointInBox(*p3,x0,y0,dx,dy)) return 1;
/* se almeno un lato interseca propriamente --> t interseca */
if (edgeInBox(*p1,*p2,x0,y0,dx,dy)) return 1;
if (edgeInBox(*p2,*p3,x0,y0,dx,dy)) return 1;
if (edgeInBox(*p3,*p1,x0,y0,dx,dy)) return 1;
/* controllo se t ricopre interamente il box (uso contenimento
del baricentro in t */
aux[X] = x0 + 0.5*dx;
aux[Y] = y0 + 0.5*dy;
if (InTriangle(aux, *p1, *p2, *p3)) return 1;
return 0;
}
void clipElements(QTree n, /* nodo corrente */
int vNum, Stack vl, /* numero e vertici da collocare */
int tNum, Stack tl, /* numero e triangoli da collocare */
int *vNum1, Stack *vl1,
int *tNum1, Stack *tl1)
{
int i;
float x0, y0, dx, dy;
Point p;
NodeBox(n, &x0, &y0, &dx, &dy);
(*tNum1) = (*vNum1) = 0;
EmptyStack(vl1);
EmptyStack(tl1);
for (i=0; i<vNum; i++)
{
COMPLETARE: ricavare dalla struttura dati il punto p
corrispondente al vertice di indice vl->content
if (pointInBox(p, x0,y0,dx,dy))
{ PushStack(vl->content, vl1);
(*vNum1)++;
}
vl = StackPop(vl);
}
for (i=0; i<tNum; i++)
{
if (triangleInBox(tl->content, x0,y0,dx,dy))
{ PushStack(tl->content, tl1);
(*tNum1)++;
}
tl = StackPop(tl);
}
}
void Build (QTree root, /* nodo corrente */
int depth, /* profondita' del nodo corrente */
int vNum, Stack vl, /* numero e vertici da collocare */
int tNum, Stack tl) /* numero e triangoli da collocare */
{
Stack aux;
if ( (vNum==0) && (tNum==0) ) /* quadrante vuoto */
{
SetEmptyLeaf(root);
return;
}
if ( tNum==1 ) /* un solo triangolo */
{
SetOneTriangLeaf(root, StackTop(tl));
return;
}
if ( tNum==2 ) /* due soli triangoli */
{
SetTwoTriangLeaf(root, StackTop(tl), StackTop(StackPop(tl)));
return;
}
if (vNum==1) /* un solo vertice */
{
/* controllo che tutti i triangoli presenti siano incidenti in
quel vertice */
for (aux = tl; aux; aux = StackPop(aux))
{
COMPLETARE:
ricavare dalla struttura dati gli indici tv1, tv2, tv3 del primo,
secondo e terzo vertice del triangolo di indice StackTop(aux)
if ( (tv1 != StackTop(vl)) &&
(tv2 != StackTop(vl)) &&
(tv3 != StackTop(vl)) ) break;
}
/* qui aux==NULL solo se tutti i triangoli erano incidenti,
altrimenti il ciclo si e' interrotto prima */
if (!aux)
{
SetVertexLeaf(root, StackTop(vl));
return;
}
/* altrimenti andro' al caso generale */
}
/* caso generale, il nodo va suddiviso,
prima pero' controllo che non sia troppo piccolo */
if (depth == MAXDEPTH)
{
int i;
Stack aux;
SetStopLeaf(root, tNum);
aux = tl;
for (i=0; i<tNum; i++)
{
AddTriToStopLeaf(root, i, StackTop(aux));
aux = StackPop(aux);
}
}
else /* suddivido il nodo */
{
int i;
Stack vli, tli;
int vni, tni;
MakeChildren(root);
for (i=NE;i<=SW;i++)
{
/* per ogni sotto-quadrante, calcolo vertici e triangoli
rilevanti, e costruisco ricorsivamente */
clipElements(NodeChild(root,i), vNum,vl, tNum,tl,
&vni,&vli, &tni,&tli);
Build(NodeChild(root,i), depth+1, vni,vli,tni,tli);
deleteStack(&vli);
deleteStack(&tli);
}
}
}
/*
Costruisce quadtree sulla triangolazione tau.
*/
void BuildQuadtree (void)
{
int i;
/* insieme dei vertici e dei triangoli da collocare */
Stack vStack;
Stack tStack;
/* numero di vertici e di triangoli da collocare */
int vNum;
int tNum;
/* coordinate estreme della scena */
float x1, y1, x2, y2;
/* angolo in basso a sinistra, larghezza e altezza del
rettangolo iniziale */
float x0, y0, dx, dy;
/* inizializza le informazioni ausiliarie */
EmptyStack(&vStack);
EmptyStack(&tStack);
vNum = tNum = 0;
COMPLETARE:
vrtNum = numero di vertici della triangolazione tau
trgNum = numero di triangoli della triangolazione tau
for (i=0; i<vrtNum; i++)
{
PushStack(i,&vStack); vNum++;
}
for (i=0; i<trgNum; i++)
{
PushStack(i,&tStack); tNum++;
}
/* calcola le coordinate estreme della triangolazione,
che servono per determinare il rettangolo iniziale */
COMPLETARE ritrovando dalla struttura dati le info
corrispondenti alle parti scritte in italiano
x1 = x2 = ascissa del primo vertice di tau
y1 = y2 = ordinata del primo vertice di tau
for (i=1; i<vrtNum; i++)
{
x = ascissa dell'i-esimo vertice di tau
y = ordinata dell'i-esimo vertice di tau
if (x < x1) x1 = xi;
else if (x > x2) x2 = x;
if (y < y1) y1 = y;
else if (y > y2) y2 = y;
}
/* calcola il rettangolo iniziale. L'ampiezza di tale
rettangolo e' la piu' piccola potenza di due tale da
contenere tutta la triangolazione */
x0 = floor(x1)-0.3;
dx = pow(2.0, ceil(log2(x2-x0)));
y0 = floor(y1)-0.3;
dy = pow(2.0, ceil(log2(y2-y0)));
/* inizializza e riempie l'albero */
MakeRoot(&root, x0,y0,dx,dy);
Build(root,0, vNum,vStack,tNum,tStack);
deleteStack(&vStack);
deleteStack(&tStack);
}
/***********************************************************************/
void PrintQuadtree(QTree n)
{
int i;
writeNode(n);
switch (NodeType(n))
{
case UNKNOWN:
printf("ERRORE"); break;
case INTERNAL:
for (i=NE;i<=SW;i++)
{
PrintQuadtree( NodeChild(n,i));
}
break;
case VERTEX:
case TWOTRI:
case ONETRI:
case EMPTY:
case STOP:
writeNode(n);
break;
}
}
void main(void)
{
ReadTriangulation();
BuildQuadtree();
PrintQuadtree(root);
}