Ejercicio obligatorio 3
Fecha de entrega: Jueves 28 de mayo
Introducción
El formato STereoLitography (STL) es un formato para representar objetos tridimensionales. En este trabajo nos vamos a centrar en la versión binaria y de polígonos del mismo.
Un archivo STL consta de tres secciones.
Cada una de estas secciones tiene un formato específico.
Si bien la mayor parte de los campos del archivo son de un solo byte, hay
números almacenados en más de un byte y en este caso esos números son números
signados almacenados según la convención little-endian. Es decir, si un campo
numérico contuviera la secuencia {0xAA, 0xBB, 0xCC, 0xDD} el número
representado sería el 0xDDCCBBAA.
Encabezado de archivo
El encabezado de archivo tendrá los siguientes campos:
Como se ve, el único valor no definido del formato es el número de versión. En
esta implementación estamos implementando la versión 3 del formato, así que
ese tendrá que ser el valor de ese número. Otro número será inválido para
nosotros.
El parámetro offset indica dónde comienzan los modelos 3D. Como en nuestro
formato el encabezado mide 13 y el formato de modelos mide 12, este número
valdrá 25.
Formato del modelos
El formato de modelos define propiedades sobre los modelos que contiene el archivo. Contiene los siguientes campos:
El tamaño de la sección será siempre 12. Las dimensiones siempre 3, mientras
que que el tipo de coordenadas valga 0 indica que cada coordenada es de tipo
float.
Las unidades responderán a la siguiente tabla:
La longitud de las etiquetas indica de qué longitud serán las etiquetas de cada uno de los modelos.
Modelos 3D
La sección de modelos será una sucesión de modelos, uno a continuación del otro hasta terminar el archivo.
Cada uno de los modelos será una sucesión:
La etiqueta será un bloque de caracteres de longitud igual al "Máx long." leído
en el formato de modelos. En ese bloque habrá una cadena, finalizada en
'\0'.
Un modelo está definido por una sucesión de líneas. Las líneas son en \(\mathbb R^3\) por lo que cada una tiene una coordenada de inicio y otra de fin.
En este formato primero se encuentran las coordenadas, y luego las líneas, que indican el índice de la coordenada de inicio y la de fin.
Por ejemplo, si tuviéramos un cuadrado de largo 1, en el plano XY, centrado en el origen:
podríamos definirlo de la siguiente manera:
float coordenadas[4][3] = {
{0.5, 0.5, 0},
{-0.5, 0.5, 0},
{-0.5, -0.5, 0},
{0.5, -0.5, 0},
};
uint32_t lineas[4][2] = {
{0, 3},
{2, 3},
{1, 2},
{0, 1},
};
En este ejemplo hay 4 coordenadas y 4 puntos.
En el archivo estarán según la tabla previa: número de coordenadas, las coordenadas, número de líneas, las líneas (indicadas por su índice de coordenada).
Trabajo
Unidades
Declarar un tipo enumerativo unidades_t para las posibles unidades de un STL.
Endianess
Escribir una función bool leer_int16_little_endian(FILE *f, int16_t *v);
que lea un entero de 16 bits en formato little-endian del archivo f y lo
escriba en v. La función debe devolver true si puede leer correctamente.
Escribir una función bool leer_int32_little_endian(FILE *f, int32_t *v);
similar a la anterior pero que lea un entero de 32 bits.
Nota
No puede asumirse que la plataforma es big/little-endian. Las funciones deben operar con los bytes a bajo nivel y ser portables a cualquier arquitectura.
Escribir una función bool leer_float_little_endian(FILE *f, float *v); que
lea un flotante.
Nota
Los flotantes tienen 32 bits y ya sabemos leer bloques de 32 bits en little endian y cargarlos en un entero.
Para copiar la memoria de un entero en la memoria de un flotante deben usarse punteros, no puede utilizarse la asignación porque eso implicaría un casteo.
Utilizar la función de lectura de enteros para implementar esta función.
Lectura
Implementar una función bool leer_encabezado_stl(FILE *f); que lea del
archivo f un encabezado STL completo y valide cada uno de sus campos según lo
ya descripto en la introducción de este enunciado. La función devolverá true
si se pudo leer un encabezado correcto, false en caso contrario.
Implementar una función
bool leer_formato_stl(FILE *f, unidades_t *unidades, size_t *maxlong);
que lea del archivo f el formato de modelos completo y devuelva las
unidades y la máxima longitud maxlong indicado por el mismo. Debe devolver
true de poder realizar la operación.
Implementar una función
bool leer_modelo_3d(FILE *f, size_t maxlong, char *etiqueta, size_t *ncoords, float **coords, size_t *nlineas, size_t **lineas);
que reciba un archivo f y una máxima longitud de etiqueta maxlong y lea un
modelo 3D del archivo. Si no hubiera ningún modelo para leer o fallara algo
deberá devolver false. La función deberá escribir en la etiqueta la
etiqueta leída (asumir que hay memoria suficiente). La función devolverá la
cantidad de coordenadas leídas ncoords y un vector de flotantes coords con
todas esas coordenadas puestas una a continuación de otras (es decir, devuelve
por la interfaz un vector de float [3 * ncoords] valores. La función
devolverá la cantidad de líneas leídas ncoords y un vector de índices
lineas con todos esos índices en secuencia (es decir devuelve por la interfaz
un vector de size_t [2 * nlineas]).
Por ejemplo, si se leyera el modelo 3D del ejemplo la función devolverá:
ncoords = 4
coords = {0.5, 0.5, 0, -0.5, 0.5, 0, -0.5, -0.5, 0, 0.5, -0.5, 0}
nlineas = 4
lineas = {0, 3, 2, 3, 1, 2, 0, 1}
Programa
Implementar un programa que permita imprimir todos los modelos 3D de un archivo dado.
El programa debe ejecutarse:
$ ./20261_ej2 <archivo>
Y generar toda la información por la interfaz según el formato propuesto`***` a continuación.
***: Ese debe ser el formato, no uno parecido, no uno más o menos, no el que
me parezca, no el que me salga: Debe ser ese.
Se provee un archivo con modelos que se descarga acá 20261_ej3.stl
Con ese archivo si se invocara la aplicación como:
$ ./20261_ej3 20261_ej3.stl
se debería generar la siguiente salida:
Nota
Deberán utilizarse tablas de búsquedas donde se considere adecuado.
Entrega
Se debe entrega el programa desarrollado.
El programa debe:
Compilar correctamente con los flags:
-Wall -Werror -std=c99 -pedantic -fno-extended-identifiers
pasar Valgrind correctamente,
La entrega se realiza a través del sistema de entregas.
El ejercicio es de entrega individual.