/* MAPER SURFACE 3D Programa para ordenar los pol”gonos triangulares de un escenario 3D cuadrado y obtener los coeficientes ABCD de la ecuaci¢n del plano a partir del fichero 3D .PLY de la PlayStation, generando el fichero ASCII con el array en 'C' de los coeficientes de la normal de cada plano en formato punto flotante F Javier Ventoso Reigosa VERSION GNU C 32 bits 3/VI/98 */ #include "math.h" #include "stdio.h" #include "string.h" #define MAX_VERTICES 30000 #define MAX_POLIGONOS 50000 #define MAX_NORMALES MAX_POLIGONOS #define MAX_MEDIASX MAX_POLIGONOS #define MAX_MEDIASZ MAX_POLIGONOS float Vertices[MAX_VERTICES][3]; float Normales[MAX_NORMALES][3]; unsigned int Poligonos[MAX_POLIGONOS][4]; // v1, v2, v3, n§ normal long ValoresMx[MAX_MEDIASX]; long ValoresMz[MAX_MEDIASZ]; float Coeficientes[MAX_POLIGONOS][6]; // mediaX, mediaZ, A, B, C, D // variables p£blicas FILE *pDisk; long nVertices, nNormales, nPoligonos; long TamMedias; // tama¤o de los arrays de medias ValoresMx y // ValoresMz una vez ordenados y sin datos // repetidos long nAnchoPoligonos; // n§ de poligonos de ancho o alto char *cFicheroC; long nErrores = 0; // funciones inline para conversion a punto fijo #define ftofix( x ) ( (long) ((x) / 4096.0) ) #define fixtof( x ) ( (float) ((x) * 4096.0) ) int ObtenerContadores( void ) { char cCadena[255]; fseek( pDisk, 0L, SEEK_SET ); while( !feof( pDisk ) ) { fgets( cCadena, 13, pDisk ); // si cadena encontrada, saltar l”nea y coger valores if( !strcmp( cCadena, "# Numbers of" ) ) { // forzar salto de l”nea fgets( cCadena, 255, pDisk ); fscanf( pDisk, "%u", &nVertices ); fscanf( pDisk, "%u", &nNormales ); fscanf( pDisk, "%u", &nPoligonos ); return( 1 ); } } return( 0 ); } int CargarVertices( void ) { char cCadena[255]; long ncon; fseek( pDisk, 0L, SEEK_SET ); while( !feof( pDisk ) ) { fgets( cCadena, 11, pDisk ); // si cadena encontrada, saltar l”nea y coger valores if( !strcmp( cCadena, "# Vertices" ) ) { // forzar salto de l”nea fgets( cCadena, 255, pDisk ); // leer todos los v‚rtices for( ncon = 0; ncon < nVertices; ncon++ ) { fscanf( pDisk, "%f", &Vertices[ncon][0] ); fscanf( pDisk, "%f", &Vertices[ncon][1] ); fscanf( pDisk, "%f", &Vertices[ncon][2] ); } return( 1 ); } } return( 0 ); } int CargarNormales( void ) { char cCadena[255]; long ncon; fseek( pDisk, 0L, SEEK_SET ); while( !feof( pDisk ) ) { fgets( cCadena, 10, pDisk ); // si cadena encontrada, saltar l”nea y coger valores if( !strcmp( cCadena, "# Normals" ) ) { // forzar salto de l”nea fgets( cCadena, 255, pDisk ); // leer todas las normales for( ncon = 0; ncon < nNormales; ncon++ ) { fscanf( pDisk, "%f", &Normales[ncon][0] ); fscanf( pDisk, "%f", &Normales[ncon][1] ); fscanf( pDisk, "%f", &Normales[ncon][2] ); } return( 1 ); } } return( 0 ); } int CargarPoligonos( void ) { char cCadena[255]; unsigned int basura; // para leer los datos innecesarios long ncon; fseek( pDisk, 0L, SEEK_SET ); while( !feof( pDisk ) ) { fgets( cCadena, 11, pDisk ); // si cadena encontrada, saltar l”nea y coger valores if( !strcmp( cCadena, "# Polygons" ) ) { // forzar salto de l”nea fgets( cCadena, 255, pDisk ); // leer todos los vertices que forman los pol”gonos // y la normal de cada pol”gono for( ncon = 0; ncon < nPoligonos; ncon++ ) { // saltar primer dato fscanf( pDisk, "%u", &basura ); // leer los 3 n§ de v‚rtices fscanf( pDisk, "%u", &Poligonos[ncon][0] ); fscanf( pDisk, "%u", &Poligonos[ncon][1] ); fscanf( pDisk, "%u", &Poligonos[ncon][2] ); // saltar 5§ dato fscanf( pDisk, "%u", &basura ); // leer n§ de normal fscanf( pDisk, "%u", &Poligonos[ncon][3] ); // forzar salto de l”nea fgets( cCadena, 255, pDisk ); } return( 1 ); } } return( 0 ); } void CalculaCoeficientes( void ) { float x1, y1, z1; float x2, y2, z2; float x3, y3, z3; float mediaX, mediaZ; float A, B, C, D; long ncon; for( ncon = 0; ncon < nPoligonos; ncon++ ) { // obtener valores del primer v‚rtice x1 = Vertices[Poligonos[ncon][0]][0]; y1 = Vertices[Poligonos[ncon][0]][1]; z1 = Vertices[Poligonos[ncon][0]][2]; // obtener valores del segundo v‚rtice x2 = Vertices[Poligonos[ncon][1]][0]; y2 = Vertices[Poligonos[ncon][1]][1]; z2 = Vertices[Poligonos[ncon][1]][2]; // obtener valores del tercer v‚rtice x3 = Vertices[Poligonos[ncon][2]][0]; y3 = Vertices[Poligonos[ncon][2]][1]; z3 = Vertices[Poligonos[ncon][2]][2]; // obtener medias mediaX = ( x1+x2+x3 ) / 3; mediaZ = ( z1+z2+z3 ) / 3; // obtener normal del pol”gono A = Normales[Poligonos[ncon][3]][0]; B = Normales[Poligonos[ncon][3]][1]; C = Normales[Poligonos[ncon][3]][2]; // calcular coeficiente D // D = -( Ax + By + Cz ) D = -( A*x1 + B*y1 + C*z1 ); // almacenar las medias y los coeficientes ABCD Coeficientes[ncon][0] = (long) mediaX; Coeficientes[ncon][1] = (long) mediaZ; Coeficientes[ncon][2] = A; Coeficientes[ncon][3] = B; Coeficientes[ncon][4] = C; Coeficientes[ncon][5] = D; // almacenar, de paso, las medias para el c lculo de // ordenaci¢n ValoresMx[ncon] = (long) mediaX; ValoresMz[ncon] = (long) mediaZ; // mostrar porcentage de trabajo printf( "ž Coeficientes %ld%%... \r", ncon * 100 / nPoligonos ); } } int func_qsortMx( const long *a, const long *b ) { return( *a - *b ); } int func_qsortMz( const long *a, const long *b ) { return( *b - *a ); } void OrdenarMediasXZ( void ) { char lExiste; long ncon; long ncon2; long indiceTemp; long ValoresTemp[MAX_POLIGONOS]; // ordenar los dos arrays de medias qsort( ValoresMx, nPoligonos, sizeof( long ), func_qsortMx ); qsort( ValoresMz, nPoligonos, sizeof( long ), func_qsortMz ); // limpiar buffer temporal for( ncon = 0; ncon < MAX_POLIGONOS; ncon++ ) { ValoresTemp[ncon] = 0xFFFFFFFF; } // eliminar valores repetidos de ValoresMx indiceTemp = 0; for( ncon = 0; ncon < nPoligonos; ncon++ ) { lExiste = 0; for( ncon2 = 0; ncon2 < nPoligonos; ncon2++ ) { if( ValoresTemp[ncon2] == ValoresMx[ncon] ) lExiste = 1; } if( !lExiste ) { ValoresTemp[indiceTemp] = ValoresMx[ncon]; indiceTemp++; } // mostrar porcentage de trabajo printf( "ž Ordenando %ld%%... \r", ncon * 100 / nPoligonos ); } // copiar ValoresTemp en ValoresMx for( ncon = 0; ncon < indiceTemp; ncon++ ) { ValoresMx[ncon] = ValoresTemp[ncon]; } ValoresMx[indiceTemp] = 0x00; // marcar fin de cadena // inicializar tama¤o del arrays de medias TamMedias = indiceTemp; // eliminar valores repetidos de ValoresMz indiceTemp = 0; for( ncon = 0; ncon < nPoligonos; ncon++ ) { lExiste = 0; for( ncon2 = 0; ncon2 < nPoligonos; ncon2++ ) { if( ValoresTemp[ncon2] == ValoresMz[ncon] ) lExiste = 1; } if( !lExiste ) { ValoresTemp[indiceTemp] = ValoresMz[ncon]; indiceTemp++; } // mostrar porcentage de trabajo printf( "ž Reorganizando %ld%%... \r", ncon * 100 / nPoligonos ); } // copiar ValoresTemp en ValoresMz for( ncon = 0; ncon < indiceTemp; ncon++ ) { ValoresMz[ncon] = ValoresTemp[ncon]; } ValoresMz[indiceTemp] = 0x00; // marcar fin de cadena } long BuscarMedias( long MediaX, long MediaZ ) { long ncon; for( ncon = 0; ncon < nPoligonos; ncon++ ) { if( Coeficientes[ncon][0] == (float) MediaX && Coeficientes[ncon][1] == (float) MediaZ ) return( ncon ); } printf( "ž Fallo en funci¢n BuscarMedias(), comprobar plano 3D, N§ Errores = %ld \r", ++nErrores ); return( 0 ); // teoricamente nunca llegar  aqu” } float PromedioAlturaVertices( void ) { long ncon; float contador = 0; for( ncon = 0; ncon < nVertices; ncon++ ) { contador += Vertices[ncon][1]; } return( contador / nVertices ); } int GeneraArchivoC( void ) { long nFilas; long ncon; long indiceCoeficientes; FILE *pDiskC; if( !( pDiskC = fopen( cFicheroC, "w+t" ) ) ) { printf( "ž Error al crear archivo %d \n", cFicheroC ); return( 0 ); } // grabar cabecera fprintf( pDiskC, "/* \n\n" ); fprintf( pDiskC, " Archivo generado con MAPER SURFACE 3D V1.0 \n\n" ); fprintf( pDiskC, " Version GNU C 32 bits, PlayStation \n\n" ); fprintf( pDiskC, " (c) F Javier Ventoso Reigosa \n\n" ); fprintf( pDiskC, " ž Superficie 3D de %ldx%ld ( %ldx%ld reales ) poligonos triangulares \n", nAnchoPoligonos, nAnchoPoligonos, nAnchoPoligonos, nAnchoPoligonos / 2 ); fprintf( pDiskC, " ž Longitud lateral estimada de cada pol”gono : %f unidades \n", fabs( Vertices[Poligonos[0][0]][0] - Vertices[Poligonos[0][1]][0] ) ); fprintf( pDiskC, " ž Promedio de altura de los vertices = %f \n", PromedioAlturaVertices() ); fprintf( pDiskC, " ž Superfice 3D en sistema de coordenadas +X-Z ( PlayStation/3DStudio ) \n\n" ); fprintf( pDiskC, "*/ \n\n" ); // grabar nombre del array fprintf( pDiskC, "/* Guarda coeficientes A, B, C, D por cada plano 3D triangular */ \n" ); fprintf( pDiskC, "float aABCD[%u][4] = { \n", nNormales ); for( nFilas = 0; nFilas < nAnchoPoligonos; nFilas += 2 ) for( ncon = 0; ncon < TamMedias; ncon += 2 ) { // tri ngulo superior indiceCoeficientes = BuscarMedias( ValoresMx[ncon], ValoresMz[nFilas] ); fprintf( pDiskC, " %f, %f, %f, %f,\n", Coeficientes[indiceCoeficientes][2], Coeficientes[indiceCoeficientes][3], Coeficientes[indiceCoeficientes][4], Coeficientes[indiceCoeficientes][5] ); // tri ngulo inferior indiceCoeficientes = BuscarMedias( ValoresMx[ncon+1], ValoresMz[nFilas+1] ); // al llegar a la £ltima normal grabar el cierre del array if( nFilas == nAnchoPoligonos-2 && ncon == TamMedias-2 ) { fprintf( pDiskC, " %f, %f, %f, %f }; \n", Coeficientes[indiceCoeficientes][2], Coeficientes[indiceCoeficientes][3], Coeficientes[indiceCoeficientes][4], Coeficientes[indiceCoeficientes][5] ); } else { fprintf( pDiskC, " %f, %f, %f, %f, \n", Coeficientes[indiceCoeficientes][2], Coeficientes[indiceCoeficientes][3], Coeficientes[indiceCoeficientes][4], Coeficientes[indiceCoeficientes][5] ); } // mostrar porcentage de trabajo if( nErrores == 0 ) { printf( "ž Generando 'C' %ld%%... \r", nFilas * 100 / nAnchoPoligonos ); } } if( pDiskC ) { fclose( pDiskC ); } return( 1 ); } char params( char *param, int argc, char *argv[] ) { int ncon; for( ncon = 1; ncon < argc; ncon++ ) { if( strstr( strlwr( argv[ncon] ), strlwr( param ) ) ) return( ncon ); } return( 0 ); } int main( int argc, char *argv[] ) { long ncon; char *cFicheroPly; char lInfo = 0; clrscr(); printf( "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n" ); printf( "ž MAPER SURFACE 3D ž Mapeador-Ordenador de superficies 3D ž PlayStation ž\n" ); printf( "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n" ); printf( "ž Version 1.0 GNU C 32 bits ž (c) F Javier Ventoso Reigosa ž\n" ); printf( "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n" ); printf( "ž Par metros: -i -x[n§ poligonos ancho] -o[fichero_salida.c] -v ž\n" ); printf( "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n" ); if( !params( "-i", argc, argv ) ) { printf( "ž Falta fichero de entrada ( -i ) \n" ); return( 1 ); } else { cFicheroPly = argv[params( "-i", argc, argv )]+2; } if( !params( "-o", argc, argv ) ) { printf( "ž Falta fichero de salida, ABCD.C por defecto \n" ); cFicheroC = "ABCD.C"; } else { cFicheroC = argv[params( "-o", argc, argv )]+2; } if( params( "-v", argc, argv ) ) lInfo = 1; if( !( pDisk = fopen( cFicheroPly, "rt" ) ) ) { printf( "ž Error abriendo archivo %s \n", cFicheroPly ); return( 1 ); } if( !ObtenerContadores() ) { printf( "ž Imposible encontrar contadores \n" ); if( pDisk ) { fclose( pDisk ); } return( 1 ); } printf( "ž N§ Poligonos = %u, V‚rtices = %u, Normales = %u \n", nPoligonos, nVertices, nNormales ); if( nPoligonos > MAX_POLIGONOS ) { printf( "ž Error, hay %u pol”gonos. M ximo %u \n", nPoligonos, MAX_POLIGONOS ); if( pDisk ) { fclose( pDisk ); } return( 1 ); } if( nVertices > MAX_VERTICES ) { printf( "ž Error, hay %u v‚rtices. M ximo %u \n", nVertices, MAX_VERTICES ); if( pDisk ) { fclose( pDisk ); } return( 1 ); } if( nNormales > MAX_NORMALES ) { printf( "ž Error, hay %u normales. M ximo %u \n", nNormales, MAX_NORMALES ); if( pDisk ) { fclose( pDisk ); } return( 1 ); } if( !params( "-x", argc, argv ) ) { nAnchoPoligonos = ( long ) sqrt( nPoligonos / 2 ) * 2; printf( "ž Usando valor lateral estimado de %ldx%ld ( %ldx%ld reales )... \n", nAnchoPoligonos, nAnchoPoligonos, nAnchoPoligonos, nAnchoPoligonos / 2 ); } else { nAnchoPoligonos = atoi( argv[params( "-x", argc, argv )]+2 ); printf( "ž Usando valor lateral (-x) introducido %ldx%ld... \n", nAnchoPoligonos, nAnchoPoligonos ); } _setcursortype( 0 ); if( !CargarVertices() ) printf( "ž Imposible cargar v‚rtices \n" ); if( !CargarNormales() ) printf( "ž Imposible cargar normales \n" ); if( !CargarPoligonos() ) printf( "ž Imposible cargar poligonos \n" ); // mostrar tama¤o aproximado de cada poligono cuadrado printf( "ž Longitud lateral estimada de cada poligono cuadrado = %f \n", fabs( Vertices[Poligonos[0][0]][0] - Vertices[Poligonos[0][1]][0] ) ); // altura media de los vertices printf( "ž Altura media de los vertices = %f \n", PromedioAlturaVertices() ); CalculaCoeficientes(); if( lInfo ) { printf( "\až Pulsa una tecla para continuar... \n" ); getch(); printf( "VERTICES ******************************************************** \n" ); for( ncon = 0; ncon < nVertices; ncon++ ) { printf( "V‚rtices = %f, %f, %f \n", Vertices[ncon][0], Vertices[ncon][1], Vertices[ncon][2] ); } printf( "NORMALES ******************************************************** \n" ); for( ncon = 0; ncon < nNormales; ncon++ ) { printf( "Normales = %f, %f, %f \n", Normales[ncon][0], Normales[ncon][1], Normales[ncon][2] ); } printf( "POLIGONOS ******************************************************* \n" ); for( ncon = 0; ncon < nPoligonos; ncon++ ) { printf( "Poligonos %u, %u, %u, Normal del plano = %u \n", Poligonos[ncon][0], Poligonos[ncon][1], Poligonos[ncon][2], Poligonos[ncon][3] ); } printf( "COEFICIENTES DEL PLANO ABCD ************************************* \n" ); for( ncon = 0; ncon < nPoligonos; ncon++ ) { printf( "XZ= %f, %f ABCD= %f, %f, %f, %f \n", Coeficientes[ncon][0], Coeficientes[ncon][1], Coeficientes[ncon][2], Coeficientes[ncon][3], Coeficientes[ncon][4], Coeficientes[ncon][5] ); } printf( "MEDIAS SIN ORDENAR ********************************************** \n" ); for( ncon = 0; ncon < nPoligonos; ncon++ ) { printf( "Medias XZ Sin Ordenar = %ld, %ld \n", ValoresMx[ncon], ValoresMz[ncon] ); } } OrdenarMediasXZ(); if( lInfo ) { printf( "MEDIAS ORDENADAS ************************************************ \n" ); for( ncon = 0; ncon < TamMedias; ncon++ ) { printf( "Medias XZ Ordenadas = %ld, %ld \n", ValoresMx[ncon], ValoresMz[ncon] ); } } if( GeneraArchivoC() && !nErrores ) { printf( "\až Archivo %s creado Ok!\n", cFicheroC ); } else { printf( "\a\a\a\nž El archivo %s NO se ha creado correctamente \n", cFicheroC ); } if( pDisk ) { fclose( pDisk ); } _setcursortype( 2 ); return( 0 ); }