In es.comp.lenguajes.c Han Solo <***@escomposlinux.org> wrote:
: Alguien sabe si existe alguna biblioteca de funciones en C/C++ (en
: linux), para calcular áreas, centros de gravedad, inercias... ese tipo
: de cosas. Es que me da una pereza horrible ponerme a programarlo...
Para areas y centros de gravedad (suponiendo que hablas de
poligonos planos), lo mas sencillo es descomponer primero
el poligono en triangulos. Luego, es inmediato.
Si el poligono tiene agujeros, necesitaras una fase previa
de eliminacion de los mismos; si te interesa, tambien tengo
codigo para eso.
En el codigo siguiente la unica parte no portable es (creo)
la funcion redraw().
---------------------------------------------------------------------------
/*
* (c) SPDsoft 1995
* Split a polygon.
*/
#include <stdlib.h>
#include <math.h>
#define EZERO
#define xcomp(p,i) (*(p+2*i))
#define ycomp(p,i) (*(p+2*i+1))
#define xpdrw(x) (short)((((x) - xmin)*scale) + MARGIN)
#define ypdrw(y) (short)(wh - MARGIN - ((y)-ymin) * scale )
#ifdef EZERO
# define EPSILLON 0
# define eq_zero(x) ((x) == EPSILLON)
#else
# define EPSILLON 1e-5
# define eq_zero(x) (fabs(x) <= EPSILLON)
#endif
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
static float test_rect( int a,int b,int c);
static int getprev(int i );
static int getpost(int i );
float _p1[] = { 0,0,-10,10,-10,-15,8,-20,-10,-5,15,5,10,-7,20,0,5,20 };
float _p[] = { 0,0 ,-8,8,0,5,8,8,0,3,0,-10,5,-20,20,20,15,15,-20,10,18,18,20,20,-30,15,0,-10 };
float _p2[] = { 5,-5,10,-10,5,5,10,10,-5,5,-10,10,-5,-5,-10,-10 };
float _p3[] = { 0,0,0,5,5,10,0,10,0,5,-5,5,-5,0 };
int tri[50][3];
int ntri;
float *p = _p, *endp = (_p+sizeof(_p)/sizeof(float));
char *p_out;
float xmin, xmax,
ymin, ymax;
float lx, ly, scale;
int nvert=sizeof(_p)/sizeof(float)/2;
void init_geom(void)
{
float *f;
int j_prev,
j_post,
i_prev,
i_post,
i,j;
float fj1_prev,
fj2_prev,
fj3_prev,
fj1_post,
fj2_post,
fj3_post,
f1,f2,f3;
int nrest,
n_hits,
n_hits_out,
valid,
found;
/*
* Bounding box
*/
xmin=xmax=*p;
ymin=ymax=*(p+1);
for(f=p; f<endp; f++)
{
if ( *f > xmax ) xmax = *f;
if ( *f < xmin ) xmin = *f;
f++;
if ( *f > ymax ) ymax = *f;
if ( *f < ymin ) ymin = *f;
}
lx = xmax - xmin;
ly = ymax - ymin;
if (NULL==( p_out = calloc((size_t)nvert, sizeof(char))))
exit(1);
ntri = 0;
for( nrest = nvert; nrest > 2 ; )
{
/*
* Skip aligned
*/
found = 0;
for( i=0; i<nvert; i++ )
{
if (! *(p_out+i))
if ( eq_zero(test_rect( getprev(i),i,getpost(i))) )
{
*(p_out+i) = 1;
nrest --;
found = 1;
break;
}
}
if ( i!= nvert)
continue;
for( i=0; i<nvert; i++ )
{
/*
* Try to make tr(i-1,i,i+1)
*
* If tr is convex, discard it and try next
*/
valid = 0;
if(*(p_out+i))
continue;
i_prev = getprev(i);
i_post = getpost(i);
/*
* Discard left handed triangles
*/
if (test_rect( i_prev,i,i_post) < 0.0 )
continue;
/*
* Test against every other vertex
*/
valid = 1;
for( j=0; j<nvert; j++ )
{
if(
(*(p_out+j)) ||
(j==i_post) || (j==i_prev) || (j==i)
)
continue;
f1 = test_rect( i_post,i_prev, j);
f2 = test_rect( i_prev,i, j);
f3 = test_rect( i,i_post, j);
if ( (f1 < 0) || (f2 < 0) || (f3 < 0))
continue; /* it is outside */
if ( (f1 > 0) && (f2 > 0) && (f3 > 0))
{ /* it is inside */
valid = 0;
break;
}
j_prev = getprev(j);
j_post = getpost(j);
fj1_prev = test_rect ( i_post,i_prev, j_prev);
fj2_prev = test_rect ( i_prev,i, j_prev);
fj3_prev = test_rect ( i,i_post, j_prev);
fj1_post = test_rect ( i_post,i_prev, j_post);
fj2_post = test_rect ( i_prev,i, j_post);
fj3_post = test_rect ( i,i_post, j_post);
n_hits = 0;
n_hits_out = 0;
if ( eq_zero(f1) )
{
n_hits ++;
if (( fj1_prev > 0 ) || ( fj1_post > 0 ))
n_hits_out++;
}
if ( eq_zero(f2) )
{
n_hits ++;
if (( fj2_prev > 0 ) || ( fj2_post > 0 ))
n_hits_out++;
}
if ( eq_zero(f3) )
{
n_hits ++;
if (( fj3_prev > 0 ) || ( fj3_post > 0 ))
n_hits_out++;
}
if ( n_hits == n_hits_out )
{
valid = 0;
break;
}
}
/*
* all vertex tested
*/
if ( valid )
{
/*
* Make new triangle
*/
tri[ntri][0] = i_prev;
tri[ntri][1] = i;
tri[ntri][2] = i_post;
ntri ++;
nrest --;
*(p_out+i) = 1;
found = 1;
break;
}
}
if ( ! found )
{
exit(2);
/* PANIC!!!! Input Error */
}
}
return;
}
#define MARGIN 20
void redraw(WindowPtr theWindow)
{
short ww, wh;
float *f;
int i;
PenState PnSt;
GetPenState(&PnSt);
ShowPen();
PenSize(2,2);
ww = theWindow->portRect.right - theWindow->portRect.left ;
wh = theWindow->portRect.bottom - theWindow->portRect.top ;
scale = MIN((float) (ww- 2*MARGIN)/lx, (float)(wh- 2*MARGIN)/ly) ;
MoveTo( xpdrw(*p), ypdrw(*(p+1)) );
for(f=p; f<endp; f+=2)
LineTo( xpdrw(*f), ypdrw(*(f+1)) );
LineTo( xpdrw(*p), ypdrw(*(p+1)) );
PenSize(1,1);
for(i=0; i<ntri; i++)
{
MoveTo( xpdrw(xcomp(p , tri[i][2])), ypdrw(ycomp(p , tri[i][2])) );
LineTo( xpdrw(xcomp(p , tri[i][0])), ypdrw(ycomp(p , tri[i][0])) );
}
SetPenState(&PnSt);
}
static float test_rect(int a,int b,int c)
{
float ddd=xcomp(p,b);
return (
(xcomp(p,b)-xcomp(p,a))*(ycomp(p,c)-ycomp(p,a))+
(ycomp(p,a)-ycomp(p,b))*(xcomp(p,c)-xcomp(p,a))
);
}
static int getprev( int i )
{
int prev=i;
do
{
if (--prev==-1) prev = nvert -1;
}while( *(p_out+prev) );
return(prev);
}
static int getpost( int i )
{
int post=i;
do
{
if (++post==nvert) post = 0;
}while( *(p_out+post) );
return(post);
}
---------------------------------------------------------------------------
--
finger ***@shiva.cps.unizar.es for PGP /
.mailcap tip of the day: / La vida es una carcel
application/ms-tnef; cat '%s' > /dev/null / con las puertas abiertas
text/x-vcard; cat '%s' > /dev/null / (A. Calamaro)