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.

../_images/20261_ej3_t1.png

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:

../_images/20261_ej3_t2.png

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:

../_images/20261_ej3_t3.png

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:

../_images/20261_ej3_t4.png

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:

../_images/20261_ej3_t5.png

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:

../_images/20261_ej3.png

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:

../_images/20261_ej3_salida.png

Nota

Deberán utilizarse tablas de búsquedas donde se considere adecuado.

Entrega

Se debe entrega el programa desarrollado.

El programa debe:

  1. Compilar correctamente con los flags:

    -Wall -Werror -std=c99 -pedantic -fno-extended-identifiers
    
  2. pasar Valgrind correctamente,

La entrega se realiza a través del sistema de entregas.

El ejercicio es de entrega individual.