🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: es.comp.os.linux.programacion
Article #28

Re: [C/C++] Áreas, centros de gravedad, etc.

#28
From: J.A. Gutierrez
Date: Wed, 03 Sep 2003 06:44
339 lines
8202 bytes
In es.comp.lenguajes.c Han Solo <hsolo@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 spd@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)
Technical Details
Message-ID: <bj42l2$l2m$1@localhost.escomposlinux.org>
Path: arc1-ca.pugleaf.net!archiver1.google.com!news1.google.com!newsfeed.stanford.edu!canoe.uoregon.edu!logbridge.uoregon.edu!news.tele.dk!news.tele.dk!small.news.tele.dk!newsgate.cistron.nl!amsnews01.chello.com!news-hub.cableinet.net!blueyonder!marmolejo.escomposlinux.org!escomposlinux.org!not-for-mail
References: <86he4ono3e.fsf@pc147.ietcc.csic.es>

Show Full Headers
Complete Article Headers
X-Google-Language: SPANISH,ASCII
X-Google-Thread: 10f58f,7305835aa95aa4a9
X-Google-Attributes: gid10f58f,public
X-Google-Thread: f86c8,7305835aa95aa4a9
X-Google-Attributes: gidf86c8,public
X-Google-ArrivalTime: 2003-09-02 23:44:56 PST
Path: arc1-ca.pugleaf.net!archiver1.google.com!news1.google.com!newsfeed.stanford.edu!canoe.uoregon.edu!logbridge.uoregon.edu!news.tele.dk!news.tele.dk!small.news.tele.dk!newsgate.cistron.nl!amsnews01.chello.com!news-hub.cableinet.net!blueyonder!marmolejo.escomposlinux.org!escomposlinux.org!not-for-mail
From: "J.A. Gutierrez" <spd@daphne.cps.unizar.es>
Newsgroups: es.comp.os.linux.programacion,es.comp.lenguajes.c
Subject: Re: [C/C++] Áreas, centros de gravedad, etc.
Date: Wed, 3 Sep 2003 06:44:50 +0000 (UTC)
Organization: Rank
Lines: 339
Sender: "J.A. Gutierrez" <spd@shiva.cps.unizar.es>
Message-ID: <bj42l2$l2m$1@localhost.escomposlinux.org>
References: <86he4ono3e.fsf@pc147.ietcc.csic.es>
NNTP-Posting-Host: shiva.cps.unizar.es
Mime-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit
X-Trace: localhost.escomposlinux.org 1062571490 21590 155.210.152.10 (3 Sep 2003 06:44:50 GMT)
X-Complaints-To: newsmaster@marmolejo.escomposlinux.org
NNTP-Posting-Date: Wed, 3 Sep 2003 06:44:50 +0000 (UTC)
User-Agent: tin/1.4.7-20030322 ("Suggestions") (UNIX) (IRIX64/6.2 (IP19))