Full text
MÁSTER UNIVERSITARIO EN INGENIERÍA MECÁNICA TRABAJO FIN DE MÁSTER Procedimiento Para La Generación De Modelos Geométricos Con Topologías De “Infill” Óptimas En Fabricación Aditiva Estudiante José Antonio Postigo Martín Director Dr. Rubén Ansola Loyola Departamento Ingeniería Mecánica Curso académico 2021/2022 Bilbao, 5 de julio de 2022
ii
Resumen En este trabajo se describirá el proceso de detección, trazado de contornos y exportación, automatizados, de un modelo obtenido mediante una optimización topológica a un archivo CAD, con el objetivo de usarlo para fabricar las piezas mediante fabricación aditiva. Este proceso consiste en idear un método capaz de interpretar los resultados de optimización topológica mediante un conjunto de algoritmos programados en lenguaje Python, y tomando como referencia métodos tradicionales de procesamiento de imágenes. Los algoritmos se dividirán en una serie de procesos que comenzarán por filtrar los datos para obtener una imagen binaria, distinguir cada uno de los agujeros o dominios vacíos, extraer los límites de cada contorno y aplicar las técnicas necesarias de suavizado y simplificación de los contornos. Estos algoritmos, aunque tomando su base en otros de distinta finalidad, es un método propio y específico para soluciones de optimización topológica, bidimensional y con elementos cuadrados. Por último, aprovechando que el software FreeCAD integra el lenguaje Python por defecto para crear piezas mediante código, se emplearán los datos obtenidos de los procesos anteriores para generar el modelo CAD correspondiente. Palabras claves Optimización Topológica, MEF (Método de los elementos finitos), “Infill”, CAD (computer-aided design), Vectorización, FA (Fabricación Aditiva), Píxel. iii
Abstract In this work, the process to automated detection, contour tracing and export of a model obtained by topology optimization to a CAD file, will be describe with the objective of using it to manufacture parts through additive manufacturing. This process consists of devising a method able to interpret the results of topology optimization using a set of algorithms programmed in Python language, and taking traditional image processing methods as a reference. The algorithms will be divided into a series of processes that will begin by filtering the data to obtain a binary image, distinguishing each of the holes or empty domains, extracting the limits of each contour and applying the necessary techniques for smoothing and simplifying the contours. These algorithms, although based on other algorithms with different purposes, is a specific method for two-dimensional topology optimization solutions with square elements. Finally, taking advantage of the fact that the FreeCAD software integrates the Python language by default to create parts using code, the data obtained from the previous processes will be used to generate the corresponding CAD model. Key Words Topology optimization, FEM (Finite element method), “Infill”, CAD (computeraided design), Vectorization, AD (Additive manufacturing), Pixel. v
Laburpena Lan honetan, CAD fitxategi batera optimizazio topologikoaren bidez lortutako modelo bat detektatzeko, inguruak trazatzeko eta esportatzeko prozesu automatizatua deskribatuko da. Piezak fabrikazio gehigarriaren bidez fabrikatzeko helburuarekin. Prozesu hau optimizazio topologikoaren emaitzak Python lengoaian programatutako algoritmo-multzo baten bidez interpretatzeko gai den metodo bat asmatzean datza, eta irudiak prozesatzeko metodo tradizionalak erreferentziatzat hartuta. Algoritmoak hainbat prozesutan banatuko dira. Prozesu horiek datuak filtratzen hasiko dira, irudi bitar bat lortzeko, zulo edo domeinu huts bakoitza bereizteko, inguru bakoitzaren mugak ateratzeko eta inguruak leuntzeko eta sinplifikatzeko beharrezko teknikak aplikatzeko. Algoritmo horiek, oinarria helburu desberdineko beste batzuetan hartuta ere, optimizazio topologikoko, bidimentsionaleko eta elementu karratuko soluzioetarako metodo propio eta espezifikoa dira. Azkenik, FreeCAD softwareak kode bidez piezak sortzeko Python lengoaia lehenetsia integratzen duela aprobetxatuz, aurreko prozesuetatik lortutako datuak erabiliko dira dagokion CAD eredua sortzeko. Gako-hitzak Optimizazio Topologikoa, EFM (Elementu finituen metodoa), “Infill”, CAD (computer-aided design), Bektorizazioa, FG (Fabrikazio Gehigarria), Pixel. vii
Acrónimos y Abreviaturas AM: Additive Manufacturing (fabricación aditiva) β:Factor de escarpado BR:Dominio de un radio R c:Función objetivo CAD: Computer Aided Desing Dieño asistido por ordenador D:Conjunto de elementos De:Factpr de escala OCM DLP: Procesamiento digital de la luz E:Módulo de Young FDM: Fused Deposition Modelling FEM: Finite element method (Método de los elementos finitos) f:Vector de fuerzas externas K:Matriz de rigidez k:Núcleo del filtro de convolución Kf:Matriz de rigidez filtro PDE λ:Multiplicador de Lagrange MMA: Method of moving asympotes Ne:Elementos dentro de una circunferencia de radio R Ne(x):Vector de funciones de interpolación ix
Índice de figuras 1.1 Ejemplo de dominio de diseño. . . . . . . . . . . . . . . . . . . . . . . 5 1.2 Ejemplo de viga empotrada - libre obtenida a través de OT. . . . . . 6 1.3 Tecnologías de fabricación aditiva [30]. . . . . . . . . . . . . . . . . . 7 1.4 ImpresorasFDM.............................. 8 1.5 Comparativa entre DLS y SLA . . . . . . . . . . . . . . . . . . . . . 9 1.6 Ejemplos de diferentes tipologías de estructuras «Infill» [33]. . . . . . 10 1.7 Ejemplo de viga Infill empotrada - libre. . . . . . . . . . . . . . . . . 10 1.8 Ejemplo de resultado de optimización. . . . . . . . . . . . . . . . . . 11 1.9 Objetivos de desarrollo sostenible. . . . . . . . . . . . . . . . . . . . . 14 1.10 Etapas del algoritmo para exportar resultados a CAD. . . . . . . . . 17 1.1 Dominiodediseño. ............................ 20 1.2 Muestra de la dependencia que los resultados de optimización para una viga MBB, donde en a) se muestra el problema teórico, en b) el resultado con 400 elementos y en c) con 6400 elementos [15]. . . . . . 22 1.3 Muestra del The checkerboard problem en una viga empotrada - libre, en función de la discretización del dominio. Con 2700 elementos en a), 4800 en b) y 17200 en c) [15]. . . . . . . . . . . . . . . . . . . . . . . 22 1.4 Parámetros de ajuste de la Ecuación 1.6. . . . . . . . . . . . . . . . . 24 1.5 Diagrama de flujo del algoritmo de optimización topológica. . . . . . 25 1.6 Funcionamiento de la operación de convolución aplicado en optimizacióntopológica............................... 27 1.7 Ejemplo de filtro aplicado a dominio no convexo. . . . . . . . . . . . . 29 1.8 Enfoques adoptados para el posprocesado. . . . . . . . . . . . . . . . 33 xvii
xviii Acrónimos y Abreviaturas 2.1 Ejemplo de imagen sin distinguir en (a) y distinguiendo cada agujero en(b).................................... 38 2.2 Ejemplo de tipos de conectividad entre elementos. . . . . . . . . . . . 39 2.3 Ejemplo de diferenciación de agujeros. . . . . . . . . . . . . . . . . . 39 2.4 Descripción del funcionamiento del Algoritmo 1. . . . . . . . . . . . . 40 2.5 Ejemplos de casos complejos en los que se ha aplicado el proceso distinción.................................. 43 3.1 Posibles casos del algoritmo de Pavlidis. . . . . . . . . . . . . . . . . 46 3.2 Ejemplos de interpretación del contorno. . . . . . . . . . . . . . . . . 47 3.3 Contorno con inclinaciones de 45◦..................... 48 3.4 Operador del algoritmo de trazado de contornos. . . . . . . . . . . . . 48 3.5 Ejemplo gráfico de la función RELOJ. . . . . . . . . . . . . . . . . . 49 3.6 Puntos clave del elemento. . . . . . . . . . . . . . . . . . . . . . . . . 49 3.7 Ejemplodecaso0. ............................ 51 3.8 Ejemplodecaso1. ............................ 52 3.9 Ejemplodecaso2. ............................ 52 3.10Ejemplodecaso3. ............................ 53 3.11Ejemplodecaso4. ............................ 53 3.12Ejemplodecaso5. ............................ 54 3.13Ejemplodecaso6. ............................ 54 3.14Ejemplosdecaso7 ............................ 55 3.15 Ejemplos típicos de bordes externos. . . . . . . . . . . . . . . . . . . 56 3.16 Representación de los límites del dominio. . . . . . . . . . . . . . . . 57 3.17 Muestra de casos reales resueltos por el algoritmo. . . . . . . . . . . . 60 3.18 Muestra de casos reales resueltos por el algoritmo. . . . . . . . . . . . 61 4.1 Muestra de casos reales resueltos por el algoritmo. . . . . . . . . . . . 66 4.2 Muestra de casos reales resueltos por el algoritmo. . . . . . . . . . . . 67 4.3 Ejemplo gráfico del algoritmo de Ramer–Douglas–Peucker. . . . . . . 68 4.4 Muestra de casos reales resueltos por el algoritmo. . . . . . . . . . . . 70 4.5 Muestra de casos reales resueltos por el algoritmo. . . . . . . . . . . . 71 xviii
4.6 Árbol de operaciones de FreeCAD. . . . . . . . . . . . . . . . . . . . 73 4.7 Diagrama de flujo de exportación a FreeCAD. . . . . . . . . . . . . . 74 4.8 Muestra de casos reales resueltos por el algoritmo. . . . . . . . . . . . 75 4.9 Muestra de casos reales resueltos por el algoritmo. . . . . . . . . . . . 76 5.1 Piezas fabricadas mediante FA. . . . . . . . . . . . . . . . . . . . . . 81
Índice de Tablas 3.1 Enumeración de los casos posibles . . . . . . . . . . . . . . . . . . . . 51 xxi
Parte I Memoria 1
Memoria Contenido Introducción.............................. 3 Optimización de topología . . . . . . . . . . . . . . . . . . . . . . 4 FabricaciónAditiva.......................... 6 Optimización de Topologías Infill .................. 9 Contexto................................ 10 Objetivos y alcance del trabajo . . . . . . . . . . . . . . . . . . 12 Beneficios que aporta el trabajo . . . . . . . . . . . . . . . . . . 12 Selección/Descripción de la solución propuesta . . . . . . . . . 15 Análisis de alternativas . . . . . . . . . . . . . . . . . . . . . . . 16 Método de ordenación de puntos del contorno . . . . . . . . . . . 16 Métodos de suavizado . . . . . . . . . . . . . . . . . . . . . . . . 16 Métodosdetrazado.......................... 18 Introducción Si se observan las tendencias políticas y económicas de los países desarrollados en la actualidad, cada vez se naturalizan más términos como eficiencia energética, aprovechamiento de recursos materiales o desarrollo sostenible. Dentro de estas tendencias de socioeconómicas, la optimización puede ser, y de hecho, empieza a ser una herramienta crucial. Debido al crecimiento del volumen de investigaciones, la interconexión entre ramas científicas diferentes y la enorme evolución de la capacidad de cálculo de las computadoras; la optimización comienza a ser utilizada en una gran variedad de áreas de conocimientos, ya que es posible resolver problemas de un gran volumen de datos y unas restricciones preimpuestas cumpliendo siempre con las ideas de eficiencia y aprovechamiento de recursos. 3
10 Memoria Figura 1.6: Ejemplos de diferentes tipologías de estructuras «Infill» [33]. En el artículo de Wu et al. [23], se propone una modificación del algoritmo convencional de optimización topológica, cuyo objetivo es calcular el problema de manera «local», haciendo que la distribución de masa adquiera una forma porosa. Los detalles de esta modificación se expondrán más adelante, pero el resultado obtenido por este método puede verse, por ejemplo en la Figura 1.7. Figura 1.7: Ejemplo de viga Infill empotrada - libre. Se observa como la solución presenta patrones de pequeño tamaño, que son más adecuados para aplicarlo al relleno de una pieza sin cambiar por completo su distribución de material. Esto, además, tiene como ventaja que la pieza sigue siendo aceptable si el estado de las solicitaciones mecánicas cambia, como por ejemplo, un cambio de dirección o de punto de aplicación. Contexto Si se comprueban los resultados que generan los algoritmos de optimización topológica (ver Figura 2.1(b)), se puede observar que estos forman un vector o matriz de valores comprendidos entre 0y1. Las imágenes en escala de color que se muestran, 10
Memoria 11 no son mas que una forma visual de simbolizar lo que estos resultados representan, asociando a cada elemento un color de una escala ( → 0; → 1), dependiendo del valor asociado a cada elemento finito. Figura 1.8: Ejemplo de resultado de optimización. El problema que ocupa a este proyecto parte de la necesidad de materializar estos resultados a través de un proceso de fabricación. Esto implica que a partir de ese «vector» de resultados, debe extraerse un archivo que pueda ser usado para fabricar la pieza. El proceso a priori podría resultar sencillo, sobretodo si se piensa en ejemplos como el de la Figura 2.1(b). Podría usarse la imagen a color del resultado, y con un software CAD cualquiera, dibujar las líneas de los contornos hasta crear la pieza; pero esto tiene algunos inconvenientes. En primer lugar, y esta es la causa principal por la que se propuso hacer este proyecto, son los resultados tipo Infill como el de la Figura 1.7, archivo cuenta con más de 3000 agujeros que si tuvieran que ser dibujados por el usuario del software CAD “a mano alzada”, podría tomar un tiempo inasumible. Por otro lado hay que preguntarse, ¿cómo de sistemático puede llegar a ser el usuario a la hora de “dibujar” manualmente estos resultados? ¿Qué debe ser interpretado como parte de un agujero y qué no? ¿Cómo se puede asegurar manualmente que dos líneas diferentes sigan el mismo criterio para trazarse? Todas estas preguntas podrían parecer a priori fáciles de responder, pero como se comprobará a lo largo del proyecto, responderlas puede ser complicado. Además, dependiendo de la cantidad de elementos del problema de optimización y de cómo se responda a cada una de las cuestiones, el resultado tras la interpretación de resultados podría ser muy diferente. Por último, aunque en este proyecto los algoritmos de optimización se utilizan a nivel investigación (no se parte de un algoritmo preprogramado por una marca comercial). Si se centra la atención en un usuario que los usa como diseñador, tener que dibujar manualmente los resultados podría ser bastante incómodo, sobretodo si 11
12 Memoria se tiene que reiterar en un diseño para mejorarlo. Su labor en este caso sería mucho más productiva, si se reduce su trabajo a hacer pequeños retoques sobre la pieza. De ahí la necesidad de disponer de un método veloz, que a partir de los resultados de optimización, construya un modelo CAD que el usuario pueda modificar fácilmente si fuera necesario. Objetivos y alcance del trabajo Para definir los objetivos de este proyecto, es necesario en primer lugar, observar cuales son las limitaciones del mismo. Generalmente se ha trabajado con algunos de los algoritmos de optimización que se usan en investigación, los cuales tienen unas limitaciones importantes: 1. Trabajan con elementos finitos bidimensionales, así que la interpretación estará restringida a problemas planos. 2. Los elementos finitos que discretizan el dominio, son todos del mismo tamaño y de forma cuadrada. Esto permite interpretar el vector de variables de diseño como una matriz de valores, donde la posición del elemento finito asociado, vendrá determinada por la posición del valor en la matriz. Atendiendo a lo planteado, se propondrá un método para abordar la interpretación de los resultados, basado en algoritmos de procesamiento de imágenes, que obtenga un conjunto de listas con las posiciones de los puntos del dominio situados en los bordes materiales de la pieza. El método debe obtener una representación lo más fiel posible a la visualización de la matriz de partida y hacerlo de manera rápida. Además, estas coordenadas se exportarán a un software CAD para automatizar el proceso de generación de geometrías, con la idea de poder usar fabricación aditiva para obtener una pieza física. Beneficios que aporta el trabajo Para abordar esta cuestión, es necesario observar primero, bajo qué contexto se desarrolla la optimización topológica. Pues debido a la “novedad” de esta metodología de diseño, podría ser difícil tener una visión amplia de los beneficios potenciales que tiene, y por supuesto, sería más difícil entender el contexto en el que se desarrolla el trabajo y los beneficios que aporta. 12
Memoria 13 En primer lugar, la creciente aplicación de la optimización de topología en los diferentes software CAD/CAM, podría considerarse coincidente o adherido a un cambio radical en el modo de producción, en lo que se conoce como «cuarta revolución industrial» o «industria 4.0». Autores como Daaboul et al. [19], Jiang et al. [22] o Bianchi [25], describen cómo, bajo esta nueva “revolución”, el modo de producción está cambiando de un sistema llamado “de producción flexible”, a un modelo de “personalización en masa”. Esto indica que la tendencia de las industrias desarrolladas es de mantener una producción a gran escala, como venía haciéndose tradicionalmente, pero a su vez, que esta sea personalizada a los gustos y preferencias del consumidor. Es en esta línea donde la optimización topológica podría encontrar su lugar en la industria, ya que puede reducir drásticamente los plazos de desarrollo del producto, lo que se traduce en una reducción de los costes. El proceso automatizado suele dar lugar a piezas de mejor rendimiento en mucho menos tiempo del que se necesitaría con los métodos de diseño tradicionales. La optimización topológica podría entenderse, no como un sustituto del diseñador, si no como una extensión de su capacidad creativa, que le ayuda a elaborar diseños muy complejos de manera muy rápida y eficiente. Por otra parte, en septiembre de 2015 la Asamblea General de las Naciones Unidas, establece un compromiso hacia la sostenibilidad económica, social y ambiental de los 193 Estados miembros, conocida como «Agenda 2030». La Agenda plantea 17 Objetivos con 169 metas que abarcan las esferas económica, social y ambiental (ver Figura 1.9). De entre los 17 objetivos, para la finalidad de este apartado se pueden destacar dos de ellos, el 9: Industria, innovación e infraestructura y el 12: Producción y consumo responsables; de los cuales, estas metas podrían ser las más relevantes en lo que concierne a la OT: 9.4 De aquí a 2030, modernizar la infraestructura y reconvertir las industrias para que sean sostenibles, utilizando los recursos con mayor eficacia y promoviendo la adopción de tecnologías y procesos industriales limpios y ambientalmente racionales, y logrando que todos los países tomen medidas de acuerdo con sus capacidades respectivas 12.2 De aquí a 2030, lograr la gestión sostenible y el uso eficiente de los recursos naturales 12.5 De aquí a 2030, reducir considerablemente la generación de desechos mediante actividades de prevención, reducción, reciclado y reutilización Mediante optimización topológica se puede determinar la mejor distribución de material posible, para una pieza bajo un estado de carga concreto. Esto encaja muy bien con algunos de los objetivos planteados por la Agenda 2030, ya que “determinar 13
14 Memoria https://www.un.org/sustainabledevelopment/es/ Figura 1.9: Objetivos de desarrollo sostenible. la mejor distribución de material” es equivalente a “hacer un aprovechamiento más eficiente del mismo”, con sus correspondientes beneficios en materia económica y de sostenibilidad. En negrita se resaltan las ideas que mejor podrían combinar con la adopción de la optimización topológica como metodología de diseño. Además, la optimización topológica en cierto modo, tiene muy buena sinergia con la fabricación aditiva, permitiendo así fabricar piezas con unos desechos muy moderados o incluso nulos. Esta relación simbiótica se debe a que por un lado, la AM es muy flexible en cuanto a la complejidad geométrica que admite, mientras que la OT, mediante restricciones, puede generar piezas que se adapten a las limitaciones de fabricación que la AM pudiera tener; eliminando por completo el uso de soportes y en consecuencia, la generación de desechos. A esto se le debe añadir que la optimización topológica en esencia está llamada a convertirse en una herramienta complementaria a la creatividad del diseñador, haciendo que este no requiera repetir de manera reiterativa pruebas de diseño para verificar que se cumplan los requisitos estructurales, y además, restando peso a la necesidad de poseer un conocimiento intuitivo, resultado de una amplia experiencia práctica. Esto no solo implica una mejora de la productividad del diseñador, si no que facilita la posibilidad de crear diseños mucho más complejos e innovadores con un mayor valor añadido (ODS 8). Por último, una vez presentados de manera resumida, la importancia que podría 14
Memoria 15 tener la optimización topológica en general, cabe preguntarse qué aporta el presente trabajo. Como bien se ha explicado a la hora de contextualizar este proyecto, una dificultad que podría considerarse en cierto modo un defecto de esta metodología de diseño, es que los resultados de optimización topológica no se expresan de un modo “comprensible” por un software CAD, y en consecuencia, deben ser “traducidos” a un formato “comprensible”. Por tanto, la intención aquí es automatizar la generación de archivos CAD a partir de la solución del proceso de optimización, cosa que no es ni mucho menos inmediata. El algoritmo propuesto para hacer esto, reduce considerablemente el tiempo de interpretación de resultados y facilita el proceso de diseño y/o fabricación. Por otro lado, limita la interacción del diseñador con el resultado de optimización a la hora de realizar la interpretación, haciendo que los archivos CAD generados sean una exégesis completamente sistemática de los resultados. Además, el modelo CAD puede usarse en el software correspondiente, para modificarlo o incorporarlo junto a otros diseños, cosa que no sería posible de otro modo. Selección/Descripción de la solución propuesta El algoritmo propuesto como solución de este trabajo, está basado en el procesamiento de imágenes en mapa de bits. Este se divide en las etapas mostradas en la Figura 1.10. Se comienza con el resultado de la optimización topológica, el cual es un vector que contiene las variables de diseño con valores contenidos entre 0y1. Primero, se aplica un filtrado para convertir esos valores a términos binarios 2 , para ello simplemente los elementos cuyo valor sea mayor a 0 , 5se cambia a valor 1. A continuación, se aplica un segundo filtro que ayuda a distinguir cada agujero, para ello, los valores asociados a los elementos de un agujero, se cambian por un valor n= 10,20,30,40, .... Ubicado cada agujero, se extraen los puntos límite de cada uno de ellos, y se guardan por separado. Como estos puntos presentan muchas irregularidades, se aplica un promediado para suavizar las líneas y redondear las esquinas. Tras esto, los contornos presentan un número de datos innecesario, que solo hace complicar la posterior representación en formato CAD. Por esto, se aplica un algoritmo de simplificación, que ayude a representar únicamente la información necesaria. Por último, estos puntos extraídos, se exportan a FreeCAD para representar la 2 Binario en este contexto quiere decir que un valor que es continuo [0 , 1], se va a cambiar por un valor discreto que puede ser {0,1} 15
16 Memoria pieza final. Análisis de alternativas En el desarrollo de este proyecto se han considerado diversos métodos alternativos para afrontar el problema que lo ocupa. Muchos de estos métodos se han llevado a la práctica, solo con el objetivo de compararlos con la solución adoptada. Método de ordenación de puntos del contorno Para generar el trazado de los contornos, se ha usado un algoritmo que se “autoguía” sobre los límites entre los dominios sólidos y vacíos; colocando los puntos de manera ordenada conforme avanza. Pero esta no fue la primera idea considerada para hacer esto. La primera idea para generar los contornos, fue guardar de manera desordenada las coordenadas de los elementos límite. Esto se puede hacer de manera bastante sencilla con un filtro, que sume a cada elemento, el valor de los elementos que le rodean. Los elementos de regiones sólidas tendrán un valor de 9tras el filtrado, porque todos los elementos que le rodean tienen valor 1; mientras que las regiones vacías tendrán valor 0. Aquellos elementos con valor 0 < v < 9, formarían parte del contorno. Obtenidas esas coordenadas, se calcula el centro de masas de ese conjunto de puntos, que se utiliza para hacer un cambio a coordenadas polares de cada uno de ellos. Ordenando los ángulos de menor a mayor, se obtendría un conjunto más o menos ordenado de datos. Este conjunto de datos no es un trazo en si, mas bien, es una nube de los puntos que rodean el contorno. Para convertir esta ”nube de puntos” a un trazado único, se usó una aproximación por mínimos cuadrados, para adaptar una sucesión de polinomios cúbicos a ese conjunto de coordenadas. Aunque esta alternativa fue programada de diferentes maneras, resulta muy poco robusta como para adoptarla como método final. Esto es debido a que usar las coordenadas polares para ordenar los puntos del contorno, puede causar errores en agujeros muy alargados. Además de que en general, los resultados eran bastante inestables. 16
Memoria 17 Resultado de optimización Filtrado Distinción Extracción Suavizado Simplificación Pieza CAD Figura 1.10: Etapas del algoritmo para exportar resultados a CAD. 17
Métodos de suavizado El método de suavizado elegido está basado en una media móvil. Pero también se consideró utilizar curvas de spline cúbicas para generar los contornos. Estas se descartaron por varios motivos: Frente a un algoritmo basado en promediar la línea, generar un método robusto que aproxime el contorno mediante curvas de spline, podría ser una tarea muy compleja. Insistir en el uso de este método no sería rentable si se tiene otro, que resulta igualmente efectivo, y con una programación mucho más sencilla. Exportar las curvas de spline a FreeCAD podría hacerse de dos maneras diferentes: 1. Exportando directamente los puntos de la curva, siendo equivalente a lo conseguido mediante el promediado de la línea. 2. Exportando los nudos del spline. Esta opción puede ser interesante, pero se tendría que revisar en profundidad la documentación de FreeCAD para hacer esto adecuadamente, ya que dependiendo del software, la manera de definir estos nudos por parte del usuario puede variar. Métodos de trazado Los método de trazado de contornos, se explican en profundidad en el Capítulo 3. Ahí se expone que estos utilizan un operador que evalúa los elementos circundantes. En base a los valores de los elementos sobre los que se sitúa el operador, se toman unas decisiones de avance u otras. En el proyecto se ha creado un operador propio para hacer esto, pero también se ha programado el mismo algoritmo usando el clásico operador del método de Theo Pavlidis. Aunque ambos métodos resultan igual de rápidos, mediante el operador usado en este proyecto, resulta más sencillo dar un tratamiento adecuado a contornos pequeños.
Capítulo 1 Análisis del estado del arte Contenido 1.1 Formulación del problema de optimización . . . . . . . . 19 1.1.1 Método SIMP (Material Sólido Isótropo con Penalización) 23 1.1.2 Implementación del algoritmo de optimización topológica 24 1.1.3 Optimización topológica de geometrías infill . . . . . . . . 31 1.2 Posprocesado de resultados . . . . . . . . . . . . . . . . . 32 1.1. Formulación del problema de optimización Como ya se ha mencionado, la optimización topológica trata de encontrar la mejor distribución de material en un dominio Ω, para unas condiciones de contorno determinadas (ver Figura 1.1). Para ello, se discretiza el dominio Ωmediante elementos finitos y a cada elemento, se le asigna una variable de diseño ρi que toma valores binarios (0o1). Con esto se pretende describir las regiones del dominio que son sólidas Ωmy las regiones vacías Ωv. Para determinar las zonas con y sin material, se define la función ρ(x): ρ(x) = 1 ∀x∈Ωm, ρ(x) = 0 ∀x∈Ωv.(1.1) Considerando que el material es isotrópico, lineal y que el sólido se ve solicitado bajo un único estado de cargas; el problema de optimización se formula en base a 19
26 1.1. Formulación del problema de optimización Según Choi y Kim [32], el análisis de sensibilidad puede clasificarse según tres enfoques diferentes: Enfoque de aproximación, discreto y continuo. En el enfoque de aproximación, las sensibilidades se obtienen mediante el método de las diferencias finitas centrales o progresivas. El enfoque discreto toma como variables de diseño los términos de la matriz que gobierne el problema (si es un problema elástico, tomará los valores de la matriz de rigidez). • Si los términos de las matrices se derivan de manera explícita con respecto a las variables de diseño, se clasifica como método analítico. • Si lo anterior se realizan usando el método de las diferencias finitas, se le categoriza como método semianalítico. El enfoque continuo es aquel en el que la sensibilidad se resuelve en variable continua. • Si el dominio es continuo y las ecuaciones de sensibilidad se modelizan como problema continuo, se le denomina enfoque continuo - continuo. • Si la diferenciación se resuelve en el dominio continuo, pero se discretiza, se le clasifica como enfoque continuo-discreto En los algoritmos de optimización topológica utilizados para realizar el presente trabajo, se utiliza un enfoque discreto analítico. El problema se discretiza primero mediante elementos finitos y en base a dicha discretización se estudia la sensibilidad con respecto a las variables de diseño. Filtrado Mediante este proceso se resuelven dos problemáticas de los algoritmos de optimización topológica: El llamado The checkerboard problem y la dependencia del mallado. Los primeros algoritmos de optimización topológica como por ejemplo Sigmund [13], utilizaban un enfoque basado en el procesamiento de imágenes. Este enfoque trata de utilizar la convolución para filtrar las variables de diseño: ˜ρ(x) = (F∗ρ)(x) = ZBR F(x−y)ρ(y)dy,(1.7) 26
Capítulo 1. Análisis del estado del arte 27 donde BR es una esfera en 3 D o un círculo en 2 D , con centro en x y radio R . Esta operación se hace de manera discreta a través de un operador matricial llamado kernel: k=1 n2 1 1 · · · 1 1 1 · · · 1 . . .. . ..... . . 1 1 · · · 1 .(1.8) Definiendo la matriz P∈ Mn×n ( BR ), donde cada posición de P , contiene el valor de la variable a filtrar correspondiente a un elemento incluido en BR: ˜ρ(x) = n X i=1 n X j=1 Pij ·kij.(1.9) Esta operación se entiende de manera más clara junto a la Figura 1.6, donde se observa que dependiendo del radio R, se escogen un conjunto de elementos BR. R R′ x BR BR′ Figura 1.6: Funcionamiento de la operación de convolución aplicado en optimización topológica. La matriz (1.8) puede definirse de muchas manera diferentes dependiendo del tipo de operación 1 . La opción mostrada es la que usualmente se emplea para los algoritmos de optimización topológica, conocido como filtro lineal, aunque en ocasiones se empleen filtros gausianos. Sobre la base de lo explicado anteriormente, se asientan las diferentes operaciones de filtrado usadas en optimización topológica. De entre estas se pueden destacar dos 1 En Kinser [27] se detallan los diferentes operadores y aplicaciones para procesamiento de imágenes. 27
28 1.1. Formulación del problema de optimización por su amplio uso; filtros de densidad, propuestos por Bruns y Tortorelli [12] y filtros de sensibilidad, propuestos por Sigmund [9]. Los filtros de densidad trabajan directamente modificando la densidad del elemento, definiendo la variable de diseño filtrada, que sustituye a la variable original en el proceso de optimización. Esta densidad filtrada se define como; ˜ρe=Pi∈Neω(xi)νiρi Pi∈Neω(xi)νi ,(1.10) donde: Ne={i| ||xi−xe|| ≤ R}, ω(xi) = R − ||xi−xe|| (filtro lineal), ω(xi) = e−1 2∥xi−xe∥ R/32 (filtro gausiano), edesigna el elemento sobre el que se aplica el filtro, νies el volumen del elemento. Cuando este filtro se aplica, a las densidades originales ρi se les llama variables de diseño, y a la densidad filtrada ˜ρi, densidades físicas, resaltando el hecho de que ρi deja de tener sentido físico. En consecuencia, cuando se presente el resultado del proceso de optimización, la solución será ˜ρi , las densidades físicas. Por otro lado, esta redefinición de las densidades del elemento, complica levemente el proceso de análisis de sensibilidad, debido a que las derivadas ya no solo dependen de las variables de diseño, si no también del proceso de filtrado. Entonces, teniendo en cuenta (1.10), el proceso de derivación se escribirá de la siguiente manera, de acuerdo a la regla de la cadena: ∂ψ ∂ρj =X e∈Nj ∂ψ ∂˜ρe ∂˜ρe ∂ρj =X e∈Nj ω(xi)νi Pi∈Neω(xj)νj ∂ψ ∂˜ρe ,(1.11) donde ψrepresenta: la función objetivo co el volumen de material V. Los Filtros de sensibilidad trabajan de manera algo diferente, pues en vez de definir una nueva variable de diseño, opta por modificar la sensibilidad directamente: d ∂c ∂ρe =1 m´ax(γ, ρe)Pi∈Neω(xi)νiX i∈Ne ω(xi)νiρi ∂c ∂ρi ,(1.12) donde el término γ normalmente tiene valor 10 −3 y se utiliza para definir un valor mínimo que impida la división por cero. 28
Capítulo 1. Análisis del estado del arte 29 Filtros PDE Además del enfoque basado en convolución, existe una alternativa propuesta por Lazarov y Sigmund [20], que cambia por completo la concepción del proceso de filtrado y viene a solventar algunos defectos del filtro de convolución. Estos defectos son la distinción de dominios y la problematica con dominios no convexos. Para ejemplificar esto debe mirarse la Figura 1.7, donde se obserca como al aplicar el filtro de convolución, este atribuiría al elemento, el valor de los elementos del conjunto de elementos Da y Db , pero este último conjunto no cumple realmente las condiciones conectivas con el elemento al que se le aplica al filtro, y no deberían tenerse en cuenta. R Da Db Figura 1.7: Ejemplo de filtro aplicado a dominio no convexo. Debido a lo anterior y también debido al alto coste computacional que tiene inicialmente el método a medida que crece el radio, se plantea una alternativa basada en un concepto diferente, los filtros PDE. Se parte de que el valor de la variable filtrada, es solución de una ecuación diferencial de Helmholtz: −r2∇2˜ρ(x) + ˜ρ(x) = ρ(x),(1.13) con condiciones de frontera de Neumann homogéneas, ∂˜ρ(x) ∂n,(1.14) siendo nun vector unitario normal al dominio. Este enfoque acepta una resolución mediante el método de los elementos finitos, haciendo: ˜ρ(x) = Ne(x)˜ρe,(1.15) 29
30 1.1. Formulación del problema de optimización donde Ne ( x )es el vector de funciones de interpolación y ˜ρe , el vector de densidades filtradas en los nudos del elemento. Aplicando el método de los residuos ponderados sobre (1.13): Kf˜ρ=pf,(1.16) donde Kf = Pi∈NeKf,i , pf = Pi∈Nepf,i y P denota la operación de expansión y ensamblaje. Las matrices y vectores de cada elemento vienen dados por: Kf,i =ZΩi∇NT eKd∇Ne+NT eNedΩ,(1.17) pf,i =ZΩi NT eρ dΩ = ρeZΩi NT edΩ.(1.18) Este sistema de ecuaciones tiene unas características importantes. La matriz Kf es siempre simétrica y definida positiva, admitiendo factorización de Cholesky y siendo el método del gradiente conjugado, el algoritmo iterativo más efectivo para resolver el sistema de ecuaciones. Por lo tanto, el método del gradiente conjugado podrá usarse para problemas con un gran número de grados de libertad, mientras que la factorización de la matriz, puede ser más conveniente en problemas con menor número de grados de libertad, pues solamente debe factorizarse una vez ( Kf no depende de la distribución de material). Esta técnica de filtrado, tal y como se discute en [20], presenta algunas ventajas respecto a los filtros basados en convolución. En primer lugar, resuelven algunos problemas de estos últimos, como la distinción entre dominios diferentes, la distancia entre elementos en dominios convexos y el alto coste para implementar computación paralela en el proceso de filtrado. Por otra parte, permite una implementación muy sencilla en los códigos de optimización, debido a que puede emplearse el código de resolución del problema de elementos finitos. Por último, se puede emplear un filtro anisotrópico de manera sencilla, añadiendo solamente algunos parámetros extra de control, sin incrementar de manera significativa el coste computacional. Actualización de las variables de diseño Tras resolver las sensibilidades y filtrar las variables de diseño, se requiere un proceso matemático o computacional capaz de dar nuevos valores a las variables de diseño. Existen diferentes algoritmos para resolver esto, pudiendo ser categorizados en métodos directos ymétodos indirectos, o procedimientos basados en criterios de optimalidad yalgoritmos de programación matemática., pero de entre todos los algoritmos, hay tres que suelen ser los más comunes: criterios de optimalidad (OCM)Bendsøe [6], method of moving asympotes (MMA) Svanberg [2] y métodos 30
Capítulo 1. Análisis del estado del arte 31 secuenciales de programación lineal Dunning y Kim [21]. Los dos primeros serán los que se utilizarán en el presente trabajo. Los criterios de optimalidad parten de convertir el problema de optimización restringida de la Ecuación (1.4), en uno no restringido, definiendo la siguiente función de Lagrange: L(ρ, λ) = c(ρ) + λ(V(ρ)−αVo),(1.19) aplicando las condiciones de primer orden de Karush - Kuhn - Tucker, ∂L ∂ρ=∂c(ρ) ∂ρ+λ∂V (ρ) ∂ρ= 0, ∂L ∂λ =V(ρ)−αVo= 0. (1.20) El OCM se compone de dos niveles reiterativos. En el nivel interno, las variables de diseño se actualizan buscando cumplir la primera restricción de (1.20), para un λ concreto. En el nivel externo, se actualiza el multiplicador de Lagrange λcon el fin de cumplir la restricción de volumen. Para ello se utiliza el algoritmo de la bisección, donde en cada iteración se ejecuta el nivel interno con un nuevo valor de λ . Para esto se define un «factor de escala» Deen cada elemento: De=− ∂c(ρ) ∂ρe λ∂V (ρ) ∂ρe ,(1.21) cuando De = 1, se satisface la primera restricción de (1.20). La idea es que mediante este factor de escala, se establezcan los valores de cada variable de diseño mediante el siguiente esquema condicional: m´ax(0, ρe−m)Si ρeDη e≤m´ax(0, ρe−m) m´ın(1, ρe+m)Si ρeDη e≤m´ın(1, ρe+m) ρeDη eEn caso contrario ,(1.22) donde m es un factor que limita el movimiento de las variables de diseño, y η (= 1 / 2) es un factor de amortiguamiento. 1.1.3. Optimización topológica de geometrías infill La generación de geometrías infill podría considerarse un caso particular de optimización topológica, donde se toman algunas pequeñas modificaciones al algoritmo 31
32 1.2. Posprocesado de resultados general. El punto clave del que se parte para este nuevo algoritmo es la modificación de la restricción volumétrica. Mientras que en la OT tradicional, se restringe la distribución de material a nivel global, para generar geometrías infill debe restringirse de manera local. Los principios básicos de este método fueron propuestos por Wu et al. [26], pero posteriormente se han hecho modificaciones, con diferentes objetivos, como las estructuras Shell Infill, Wu et al. [24]. El algoritmo en general, es muy similar al clásico algoritmo SIMP, únicamente cambiando la restricción volumétrica. Para ello, siendo ρ la densidad de un elemento y ¯ρ la densidad promedio para un radio de influencia R , se busca que en todo momento, ese volumen promedio sea inferior a un valor preestablecido α, es decir: m´ax ∀e( ¯ρe)≤α. (1.23) Por supuesto, esta ecuación no puede aplicarse tal cual. Como se busca emplear un método basado en gradiente, se debe buscar una expresión diferenciable. Para ello se recurre a la norma p , la cual cuando p→ ∞ , la función sea equivalente a la original: 1 nX e ¯ρep!1 p ≤α, (1.24) donde nes el número de elementos, y pnormalmente se toma (= 16). 1.2. Posprocesado de resultados El posproceso es una etapa que podría considerarse aparte del proceso de optimización. El objetivo es una vez obtenido los resultados de optimización, traducirlos a unos parámetros interpretables por el software de diseño o la máquina de fabricación. Esta tarea tiene cierta complejidad, por esto existen diversos enfoques de resolución. Estos enfoques pueden dividirse en 3 categorías (ver Figura 1.8): Iso-density contours methods, Métodos de reconstrucción, Métodos de procesamiento de imágenes Los Iso-density contours methods, se basan en pasar las densidades de cada elemento a una distribución de densidades en los nudos. A partir de aquí, se busca generar curvas de nivel de dicha solución, a través de curvas de Bézier. Esta representación con curvas de Bézier permite aplicar una optimización de forma a la 32
Capítulo 1. Análisis del estado del arte 33 Figura 1.8: Enfoques adoptados para el posprocesado. estructura para obtener una mayor definición de la misma. Una primera propuesta de este método fue la desarrollada por Maute y Ramm [8]. Por su parte, los métodos de reconstrucción, filtran las variables de diseño con el objetivo de obtener una representación binaria de la misma. Usando esta última, se extraen los límites de los contornos. A partir de estos puntos extraídos, se utiliza una aproximación de mínimos cuadrados sobre los nudos de un B-Spline. Esta alternativa se explica en mayor detalle en Tang y Chang [14]. Además, en Xia et al. [28], se propone una variante que busca mediante procesamiento de las variables de diseño, extraer una imagen esquelética de la estructura, en base a la cual identificar los elementos e iniciar una optimización de forma, para dar el tamaño necesario a dichos elementos. Los métodos basados en procesamiento de imágenes, utilizan las técnicas tradicionales de vectorización de imágenes en mapa de bits, para interpretar los resultados de optimización topológica. Una de las primeras referencias de esta alternativa podría encontrarse en Papalambros y Chirehdast [5], que desarrolló un método de tres etapas: 1. Convertir variables de diseño a imagen binaria, 2. Extraer contornos, 3. Suavizar contornos usando B-splines y segmentos lineales. 33
Parte II Metodología 35
42 2.5. Ejemplos 2.5. Ejemplos En la Figura 2.5 se muestran algunos ejemplos en los que se ha aplicado el algoritmo explicado previamente. Si se observa en primer lugar la leyenda de color (Figura 2.5(e)), y a continuación cualquiera de los ejemplos; los colores guardan simetría respecto al eje neutro de la pieza, siempre que esta tenga un eje de simetría horizontal. El motivo de esto es que para que se guarden los puntos de partida de manera que la pieza interpretada sea simétrica, en vez de hacer búsquedas en orden ascendente en el eje de ordenadas, se hacen de manera alternativa desde los extremos hasta el eje de simetría. 42
Capítulo 2. Distinción 43 (a) (b) (c) (d) 1 10 10n (e) Figura 2.5: Ejemplos de casos complejos en los que se ha aplicado el proceso distinción. 43
44 2.5. Ejemplos 44
Capítulo 3 Extracción de contornos Contenido 3.1 Introducción .......................... 45 3.2 Algoritmo de Theo Pavlidis . . . . . . . . . . . . . . . . . 46 3.3 Algoritmo de identificación de contornos . . . . . . . . . 47 3.3.1 Generalización de direcciones . . . . . . . . . . . . . . . . 48 3.3.2 Determinación de iteraciones . . . . . . . . . . . . . . . . 50 3.3.3 Elección del sentido de giro . . . . . . . . . . . . . . . . . 55 3.3.4 Tratamiento de los agujeros externos . . . . . . . . . . . . 55 3.3.5 Criterio de parada . . . . . . . . . . . . . . . . . . . . . . 56 3.3.6 Límites del dominio . . . . . . . . . . . . . . . . . . . . . 57 3.4 Sobre la necesidad de distinguir los agujeros . . . . . . . 58 3.5 Ejemplos............................. 59 3.1. Introducción El algoritmo que se ha presentado en el Capítulo 2 da como resultado una lista con las posiciones de los elementos que inician el algoritmo recursivo que cambia el valor de sus píxeles vecinos. Esto es el punto de partida de la siguiente etapa del proceso: La detección de los contornos. Este trata de aplicar una serie de axiomas, que genere un conjunto de listas de coordenadas. Cada una de las listas se compondrá de la posición de los puntos frontera de cada agujero ordenados de manera que, 45
46 3.2. Algoritmo de Theo Pavlidis al representar estos puntos unidos mediante líneas, formen la imagen vectorial del agujero de partida. En este capítulo se presentará el algoritmo usado para la generación de estas listas de coordenadas, el cual se inspira en el algoritmo de Pavlidis [1]. 3.2. Algoritmo de Theo Pavlidis La mayor dificultad de trazar los contornos de una imagen en mapa de bits, radica en saber qué información escoger. Esto se debe a que la interpretación que las personas hacen de la imagen, es un conocimiento tácito, basado en observar el conjunto de los elementos de la imagen. Sin embargo, al realizar el reconocimiento de los contornos de manera computacional, debe usarse un conocimiento explícito y limitado, ya que el número de axiomas necesarios para tomar las decisiones de interpretación, crecen de manera exponencial con el conjunto de datos escogido. El algoritmo de Theo Pavlidis, utiliza un conjunto de datos muy limitado para tomar decisiones. Estos datos son los valores de los 3 elementos que hay frente al elemento actual, en una dirección y sentido a determinar. Así pues, a partir de estos 3 valores, se toman 2 decisiones diferentes según lo mostrado en la Figura 3.1, donde ○ indica el pixel superior izquierdo, ○ el pixel superior derecho y el píxel superior central. Por último, indica el píxel actual y la dirección en la que se escogen los 3 píxeles, dependiendo de la inclinación del símbolo: ,,y. ○ ○ (a) ○ ○ (b) Figura 3.1: Posibles casos del algoritmo de Pavlidis. Este algoritmo se puede definir a derechas y a izquierdas, según el sentido de giro que quiera darse. En la Figura 3.1, se indica la versión a izquierdas, la versión a derechas sería la imagen simétrica a la misma. Se comienza con un píxel dentro del agujero o fuera, pero que esté situado en 46
Capítulo 3. Extracción de contornos 47 la frontera entre dos regiones. Se miran los tres elementos superiores, inferiores o laterales, dependiendo de la dirección y sentido de búsqueda. Si se encuentra un caso como el de Figura 3.1(a), en la siguiente iteración se realizará la operación en el píxel superior izquierdo. En caso de que se encuentre el caso Figura 3.1(b), se escogerá el píxel superior central. Si no es ninguno de los anteriores, se girará sobre la misma posición hasta encontrar uno de estos dos casos. Por último, si se gira más de 3 veces sobre el mismo píxel o se llega a la posición de partida, se considera que el algoritmo ha terminado y se inicia una nueva búsqueda de otro píxel de partida. 3.3. Algoritmo de identificación de contornos El algoritmo propuesto por Pavlidis [1], es un punto de partida interesante para abordar el problema, aunque este planteamiento se alterará levemente, para adaptarse a los requerimientos este proyecto. En primer lugar, se debe definir qué información se debe atribuir a cada una de las listas que delimitan un contorno. Esto puede hacerse de múltiples maneras, como por ejemplo, guardando el centro de cada elemento por el que se pasa en cada iteración (Figura 3.2(a) y 3.2(b)), o bien, guardando las coordenadas límite entre ambos dominios (Figura 3.2(c)). (a) (b) (c) Figura 3.2: Ejemplos de interpretación del contorno. Para este proyecto se opta por interpretar el contorno de la manera que aparece en la Figura 3.2(c), pero con una pequeña modificación. Se observa que la sucesión de dos coordenadas se da en ángulos { 0 ◦, 90 ◦} . Teniendo en cuenta que el método de suavizado que se comentará más adelante, estará basado en promediados, cuando se esté guardando información de un borde inclinado, se tendrá un escalonamiento que podría generar líneas muy irregulares. Este efecto se observaría sobretodo en líneas inclinadas a 45◦. 47
48 3.3. Algoritmo de identificación de contornos Para mejorar un poco este efecto, se puede hacer que el algoritmo guarde puntos sucedidos a una inclinación de 45 ◦ (ver Figura 3.3). Por supuesto, esto no elimina totalmente la irregularidad de líneas inclinadas, pero si que resta fuerza o gravedad al escalonamiento que se produce en estas. Figura 3.3: Contorno con inclinaciones de 45◦. Todo lo comentado se hará utilizando un operador similar al de Pavlidis [1], que se muestra en la Figura 3.4, donde los píxeles escogidos para tomar las decisiones de trazado son, el píxel frente al actual y los dos colindantes a estos. Estos dos últimos se situarán al lado derecho (como en la Figura 3.4), si se pretende trazar el agujero en sentido antihorario, y a la izquierda si el trazado es horario. ○ ○ Figura 3.4: Operador del algoritmo de trazado de contornos. 3.3.1. Generalización de direcciones El método que se utilizará, debe tomar decisiones en base a la información proporcionada por el operador, en una dirección y sentidos concretos (Figura 3.4). Para simplificar la programación de estos tres píxeles, se ha definido la función RELOJ, que se encarga de generalizar las 4 direcciónes de “observación”. En la Figura 3.5 se muestra gráficamente cómo funciona el Algoritmo 2. Se trata de que, dado un valor 0,1,2,3 , se devuelva la posición de los píxeles que forman el 48
Capítulo 3. Extracción de contornos 49 0 1 2 3 Figura 3.5: Ejemplo gráfico de la función RELOJ. operador de esa dirección. Para cambiar de orientación, solamente se tendrá que hacer reloj ± 1, y se realizará un giro de ± 90 ◦ relativo a la dirección anterior (en caso horario ∓90◦). Por otra parte, esta generalización de las direcciones, también afectará a la enumeración de los puntos clave de un elemento, los cuales vendrán dados por el criterio de la Figura 3.6. Estos puntos clave son necesarios para guardar las posiciones adecuadas de los bordes entre dominios, de acuerdo a lo expuesto en la Figura 3.3. 0 1 2 3 4 5 67 Figura 3.6: Puntos clave del elemento. 49
50 3.3. Algoritmo de identificación de contornos Algoritmo 2 Función recursiva para adimensionalizar el problema. 1: procedure RELOJ(reloj, i, j, Nelx, Nely) 2: i1= m´ax(i−1,0) 3: i2= m´ın(i+ 1, Nelx−1) 4: j1= m´ax(j−1,0) 5: j2= m´ın(j+ 1, Nely−1) 6: if reloj == 0 then 7: ik = [i1, i1, i1]▷Listas para acumular las coordenadas de los tres píxeles 8: jk = [j1, j, j2] 9: else if reloj == 1 then 10: ik = [i1, i, i2] 11: jk = [j2, j2, j2] 12: else if reloj == 2 then 13: ik = [i2, i2, i2] 14: jk = [j2, j, j1] 15: else if reloj == 3 then 16: ik = [i2, i, i1] 17: jk = [j1, j1, j1] 18: else 19: reloj =reloj m´od 4 20: ik, jk, reloj =RELOJ(reloj, i, j, dim) 21: end if 22: return ik, jk, reloj 23: end procedure 3.3.2. Determinación de iteraciones Tras generalizar las direcciones a un problema unidimensional, simplemente debe tomarse decisiones en base a los valores de 3 elementos. Como los valores que estos pueden tomar son binarios, se tiene que en total pueden encontrarse 2 3 = 8 casos, que se enumeran en la Tabla 3.1. La tarea entonces será tomar decisiones en base a qué caso se encuentre en cada iteración. El algoritmo se ha programado de manera que rodee internamente al dominio que se va a trazar. Este comienza por un elemento límite y se direcciona según reloj = 2. Por otra parte, aunque lo que se expondrá pueda parecer únicamente válido para un sentido de giro antihorario, la simetría del problema, admite el uso del mismo algoritmo, siempre y cuando se definan para el sentido correcto en lo expuesto en las Figuras 3.4, 3.5 y 3.6. 50
Capítulo 3. Extracción de contornos 51 ○○ 0 1 2 3 4 5 6 7 Tabla 3.1: Enumeración de los casos posibles Caso 0 Es un caso en el que todos los elementos tienen valor cero. Se considera un caso irrelevante o inalcanzable, ya que solo podría darse en dos situaciones: 1. Debido a un error en el sentido de giro, el operador apunta hacia el interior del agujero. 2. Se ha avanzado a un píxel interior. Este caso debería ser inalcanzable, ya que la sucesión del resto de situaciones, se resuelve de manera que no se llegue a un caso como este. Figura 3.7: Ejemplo de caso 0. Por lo tanto, la decisión más conveniente es hacer reloj + 1, intentando redirigir el operador hacia el borde, en busca de un conjunto de valores diferente. Caso 1 Esta situación es de las más recurrentes, pues mediante la misma, se explicita el avance diagonal. Este avance permite, además de generar trazados inclinados a 45 ◦ , 51
58 3.4. Sobre la necesidad de distinguir los agujeros Tras esto, para generar cada uno de las líneas, solamente hay que comenzar una búsqueda en los 4 vectores de coordenadas siguiendo las condiciones: Si se encuentra un píxel con valor 1, “se abre” un vector y se agrega el punto 4. “Abierto” un vector, este debe “cerrarse” bajo dos condiciones: 1. Se encuentra un píxel de valor 0, donde se cierra el vector con el punto 4. 2. Se llega a la última coordenada de la pared, donde se cierra con el punto 2. 3.4. Sobre la necesidad de distinguir los agujeros Si se analiza detenidamente el algoritmo que se ha presentado, podría surgir la duda de por qué es necesario el algoritmo de distinción de agujeros presentado en el Capítulo 2, ya que el algoritmo de trazado por sí mismo es capaz de evaluar la conectividad, distinguiendo entre los diferentes agujeros. Es cierto que no es absolutamente necesario incorporar este paso intermedio para hacer funcionar el conjunto del algoritmo, pero al hacerlo, surge un problema: La búsqueda del píxel de partida. Para esto se puede pensar en realizar búsquedas de píxeles que sean potenciales puntos de partida (aquellos elementos de valor cero que estén en el borde). Para ello se hacen consultas elemento a elemento en cada fila y cuando un píxel sea válido, se traza su contorno. Para no reiterar sobre un mismo contorno en el futuro, se guardan las posiciones por donde se “ha pasado” en una lista. Con esto, cuando se reinicie la búsqueda de elementos de partida, se comprueba que si una nueva posición potencialmente válida como punto de partida, se encuentra o no entre los elementos ya “visitados”, y si no está en la lista, se inicia en esta posición un nuevo trazado. Esta parece a priori, una manera sencilla de encontrar los inicios del trazado, pero la realidad es que su coste operativo es bastante alto. Al añadir los elementos visitados a un vector, y consultar si la posición actual existe en el mismo reiteradas veces para un mismo agujero; cuando el conjunto de datos es muy grande, la tarea de búsqueda empieza ser muy costosa, y se requiere un enfoque alternativo. Esto se hace especialmente importante en los resultados de Infill, donde dependiendo de la complejidad, se puede tener una densidad de agujeros altísima, que para superficies pequeñas pueden ser de miles de ellos, haciendo imposible utilizar este método de búsqueda de manera eficiente. Por este motivo, el algoritmo de distinción de agujeros explicado en el Capítulo 2 resulta mucho más efectivo. La elección del píxel solo requiere que se cumpla la 58
Capítulo 3. Extracción de contornos 59 condición de ser igual a 0, ya que al encontrarlo, los elementos de ese agujero cambiarán de valor automáticamente. Cuando se vuelva a iniciar la búsqueda, como los elementos del agujero anterior ya no tienen valor 0, el algoritmo los ignorará, llegando a otro agujero diferente. Estos píxeles serán automáticamente válidos, pues el primer píxel con valor 0de un agujero, siempre estará en el borde del mismo. 3.5. Ejemplos En las Figuras 3.17 y 3.18, se muestran algunos ejemplos prácticos resueltos por el algoritmo. Se puede apreciar como este método proporciona imágenes completamente simétricas, siempre que los datos de entrada lo sean. El único problema es que las imágenes presentan líneas muy irregulares. En este capítulo se ha presentado la segunda etapa de la interpretación de las soluciones de optimización topológica. Una vez se ha conseguido definir los contornos (aunque sea de manera irregular), se aplicarán tratamientos a los mismos suavizarlos y simplificarlos. Obteniendo una imagen más próxima a la interpretación intuitiva que se hace de la misma. 59
60 3.5. Ejemplos (a) (b) (c) Figura 3.17: Muestra de casos reales resueltos por el algoritmo. 60
Capítulo 3. Extracción de contornos 61 (a) (b) (c) Figura 3.18: Muestra de casos reales resueltos por el algoritmo. 61
62 3.5. Ejemplos 62
Capítulo 4 Tratamiento de línea Contenido 4.1 Introducción .......................... 63 4.2 Suavizado ............................ 63 4.2.1 Ejemplos ........................... 65 4.3 Simplificación.......................... 68 4.3.1 Ejemplos ........................... 69 4.4 Generación de la pieza en formato CAD . . . . . . . . . . 72 4.1. Introducción En los anteriores capítulos, se ha propuesto un método para convertir una imagen en forma de matriz de valores binarios a otra imagen vectorial dada por las coordenadas de los puntos adscritos al límite entre cada dominio. El problema de esta imagen es que las líneas pueden presentar fuertes irregularidades, además de tener información excesiva. Por este motivo, es necesario incorporar métodos que por un lado, suavicen las líneas y por otro las simplifiquen. 4.2. Suavizado El método de suavizado se basa en un promediado móvil de los puntos. La idea es que si se define la posición del punto actual, como la media de los n valores 63
64 4.2. Suavizado anteriores y posteriores, se podrá eliminar las inestabilidades de la línea y redondear las esquinas. Algoritmo 3 Algoritmo para suavizar los contornos procedure Suavizado(x,y,n[r]) x1[length(x)] y1[length(x)] for i= 0 to length(r)do for j= 0 →length(x)do Px←0 Py←0 m←0 for k=j−n(r)→j+n(r)do m←m+ 1 if 0≤k < length(x)then Px←Px+x(k) Py←Py+y(k) else if k≥length(x)then Px←Px+x(k−length(x)) Py←Py+y(k−length(x)) else Px←Px+x(k+length(x)) Py←Py+y(k+length(x)) end if x1(j)←Px m y1(j)←Py m end for end for end for return x1, y1 end procedure Para hacer esto de manera computacional se ha usado el Algoritmo 3. Este se compone de dos parámetros de ajuste: n : Este parámetro controla el número de coordenadas escogidas antes y después de la actual. Es decir, controla en número de puntos a usar para hacer la media de coordenadas. Normalmente se usa un valor ∈ [2 , 8], dependiendo del tipo de problema. Para valores muy grandes, tiende a redondear en exceso las esquinas. 64
Capítulo 4. Tratamiento de línea 65 r : Este parámetro controla el número de veces que se aplica el algoritmo de suavizado. Al repetir varias veces el proceso de suavizado sobre la línea, se realiza un suavizado mucho menos agresivo que elimina ciertas inestabilidades, sin redondear las esquinas. 4.2.1. Ejemplos En las Figuras 4.1 y 4.2 se muestran ejemplos donde se ha aplicado el suavizado de los contornos. Se puede observar que para casos con un pequeño número de elementos o agujeros pequeños, hay que ajustar con cuidado los parámetros del algoritmo para que no se altere en exceso la geometría de los contornos. Además, como el algoritmo de trazado, redondea las esquinas de contornos muy pequeños, se pone una restricción de que si la curva tiene un número de puntos < 20, no se aplicará el suavizado. 65
66 4.2. Suavizado (a) r= 2, n ={4,5} (b) r= 1, n ={5} (c) r= 2, n ={2,2} Figura 4.1: Muestra de casos reales resueltos por el algoritmo. 66
Capítulo 4. Tratamiento de línea 67 (a) r= 1, n ={5} (b) r= 1, n ={5} (c) r= 2, n ={2,2} Figura 4.2: Muestra de casos reales resueltos por el algoritmo. 67
74 4.4. Generación de la pieza en formato CAD Contorno externo Dibujar puntos Extrusión exterior nContornos internos i≤n Dibujar contorno i Extruir contirno i i = i + 1 Combinar extrusiones internas Restar sólidos internos a externos Pieza CAD yes no Figura 4.7: Diagrama de flujo de exportación a FreeCAD. 74
Capítulo 4. Tratamiento de línea 75 (a) (b) (c) Figura 4.8: Muestra de casos reales resueltos por el algoritmo. 75
76 4.4. Generación de la pieza en formato CAD (a) (b) (c) Figura 4.9: Muestra de casos reales resueltos por el algoritmo. 76
Parte III Conclusiones y líneas futuras 77
Capítulo 5 Conclusiones Contenido 5.1 Conclusiones .......................... 79 5.1.1 Piezas fabricadas . . . . . . . . . . . . . . . . . . . . . . . 81 5.2 Líneasfuturas.......................... 82 5.2.1 Exportar resultados a CAD . . . . . . . . . . . . . . . . . 82 5.2.2 Generación de modelos 3D . . . . . . . . . . . . . . . . . . 82 5.2.3 Generalización de elementos . . . . . . . . . . . . . . . . . 82 5.1. Conclusiones En este proyecto se ha propuesto un método para exportar los resultados de optimización topológica a archivos CAD, con el objetivo de fabricar estos resultados mediante fabricación aditiva. Los Capítulos 2 y 3 se proponen los algoritmos fundamentales para extraer los contornos límites entre los diferentes dominios. Lo expuesto en el Capítulo 2 permite obtener de manera eficiente los puntos de partida para trazar cada contorno. Mientras que en el Capítulo 3 se explican los axiomas necesarios, para obtener los conjuntos de coordenadas ordenadas que dibujan el contorno. Tras haber conseguido los conjuntos de coordenadas, se observan que estos se componen de un número datos muy grande y que presenta cierta irregularidad. En el Capítulo 4, se explica cómo se tratan estos conjuntos con el objetivo de que los trazos sean más regulares y simples. Para ello se utilizan dos algoritmos: el primero define la posición de cada coordenada, en función de las n coordenadas anteriores 79
80 5.1. Conclusiones y posteriores, haciendo que las líneas adquieran un aspecto mucho más regular. El segundo algoritmo, se trata del “Algoritmo de Ramer–Douglas–Peucker”, que se trata de un proceso iterativo, que elimina la información redundante de los trazados, usando como criterio la máxima distancia perpendicular y una tolerancia ϵ . Los datos extraídos de todo este proceso, se llevan a FreeCAD para crear un modelo tridimensional que pueda usarse para exportar los resultados a una impresora 3D. Todo se ha programado en el lenguaje de programación Python, creando una librería, donde, dando como entrada la matriz de resultados de optimización topológica, se obtenga como salida un conjunto de listas de puntos, que posteriormente, mediante un script de FreeCAD, generarán la pieza. Si se observa la Figura 4.4 y Figura 4.5, donde se muestran los resultados finales de aplicación del algoritmo, podría objetarse que el ajuste de los trazados no es perfecto a la pieza original. No se debe olvidar que los métodos propuestos, son métodos de interpretación de resultados de manera sistemática, no son la solución real. Lo cerca o lo lejos que esté el trazado de parecerse a la solución real, dependerá de la definición de esta misma, o en otras palabras, de la cantidad de información que se posea, materializada en la densidad de elementos finitos. Así pues, comparando las Figuras 4.4(a), 4.5(a) y 4.5(c), con las Figuras 4.4(b), 4.4(c) y 4.5(b), cuando la densidad de elementos es muy alta, la solución de optimización topológica y el trazado de los contornos es prácticamente indistinguible. Respecto a la velocidad de todos estos algoritmos, no se puede afirmar que sea más o menos eficiente, pues no se ha encontrado un similar con el que hacer comparaciones. Lo que sí se puede afirmar, es que la velocidad de generación de los trazados es satisfactoria, consiguiendo escribir los archivos de las soluciones más complejas (como la Figura 4.5(a)), en al menos 10 segundos, dependiendo de la potencia de la computadora. Además, debe recordarse que se ha usado un lenguaje de programación interpretado. Una traducción a un lenguaje compilado, como podría ser C+ +, mejoraría mucho la velocidad de generación de las piezas. Por último, sobre el uso de FreeCAD para generar las piezas (Figura 4.8 y Figura 4.9), aunque en la mayoría de los casos funciona suficientemente rápido, para los resultados de infill con una gran densidad de agujeros (ver Figura 4.8(b)), puede tomar un tiempo excesivo, siendo muy dependiente de la capacidad de la computadora. Aún así, se ha observado que en general, todos los softwares tienen dificultades para trabajar con esta pieza, posiblemente a la enorme cantidad de caras que posee. 80
Capítulo 5. Conclusiones 81 5.1.1. Piezas fabricadas Para concluir los objetivos del trabajo, los modelos CAD generados, se han exportado a STL para su posterior fabricación mediante FA. Los resultados de esto pueden verse en la Figura 5.1. Figura 5.1: Piezas fabricadas mediante FA. 81
5.2. Líneas futuras 5.2.1. Exportar resultados a CAD Uno de los mayores problemas encontrados tras la realización de este proyecto, es la generación de la pieza CAD, debido a que para piezas muy complejas puede tomar un tiempo excesivo. Además, los comandos de Script de FreeCAD, no parecen pensados para generar piezas de manera sencilla, resultando una programación algo complicada. Existen algunas alternativas a FreeCAD que podrían resultar interesantes para futuros desarrollo: OpenSCAD [29] y CADquery [31]; ambos softwares CAD basados únicamente en “scripting”. OpenSCAD utiliza un lenguaje propio, mientras que CADquery está basado en python. 5.2.2. Generación de modelos 3D Una de los desarrollos naturales de este proyecto, es ampliar el algoritmo para generar modelos 3D. Esto sería generando los trazados de cortes a la pieza por diferentes planos, y uniendo los diferentes contornos para generar el sólido. 5.2.3. Generalización de elementos Este proyecto se ha realizado bajo la suposición de que los elementos finitos son todos cuadrados y del mismo tamaño. Este algoritmo podría ampliarse también para hacerlo funcionar con cualquier tipo de elemento finito bidimensional
Parte IV Anexos 83
90 A.1. Trazado de contornos 210 v. append (x[jk [i], ik [i ]]) 211 caso = 0 212 for jin range (len(v)): 213 caso += v[j] * 2 ** (2 - j) 214 return caso 215 216 def trazar (i , j , x_ , paso , horario = False ): 217 fin = False 218 dim = (len(x_ [0]) , len(x_)) 219 x = [] 220 y = [] 221 reloj = 2 222 223 ik , jk , reloj , i_ , j_ , borde = clock (horario , reloj , i, j, dim ) 224 bc = casosbinarios (ik , jk , x_) 225 226 inicio = (i, j, reloj ) 227 228 paso . append ((i , j)) 229 230 abierto = False 231 if borde != 0: 232 abierto = True 233 if borde == 0 or borde == 9 or borde == 8: 234 x. append ( i_ [4]) 235 y. append ( j_ [4]) 236 elif borde == 1 or borde == 3: 237 x. append ( i_ [6]) 238 y. append ( j_ [6]) 239 reloj = 3 240 ik , jk , reloj , i_ , j_ , borde = clock (horario , reloj , i, j, dim ) 241 bc = casosbinarios (ik , jk , x_) 242 elif borde == 2: 243 x. append ( i_ [0]) 244 y. append ( j_ [0]) 245 reloj = 0 246 ik , jk , reloj , i_ , j_ , borde = clock (horario , reloj , i, j, dim ) 247 bc = casosbinarios (ik , jk , x_) 248 bca = pila (["p","p"], 2) 249 control = pila ([(i , j , reloj ) , "p","p"], 3) 250 while not fin : 251 paso . append ((i , j)) 252 control . agregar ((i, j, reloj )) 253 if bc == 0: 254 reloj += 1 255 elif bc == 1: 256 reloj += 1 90
Capítulo A. Código 91 257 i = ik [1] 258 j = jk [1] 259 x. append ( i_ [3]) 260 y. append ( j_ [3]) 261 elif bc == 2: 262 reloj += 1 263 i = ik [2] 264 j = jk [2] 265 x. append ( i_ [4]) 266 y. append ( j_ [4]) 267 print ("Caso 2 en", i, j) 268 elif bc == 3: 269 i = ik [0] 270 j = jk [0] 271 x. append ( i_ [3]) 272 y. append ( j_ [3]) 273 elif bc == 4: 274 i = ik [2] 275 j = jk [2] 276 x. append ( i_ [3]) 277 y. append ( j_ [3]) 278 print ("Caso 4 en", i, j) 279 elif bc == 5: 280 reloj -= 1 281 x. append ( i_ [3]) 282 y. append ( j_ [3]) 283 if bca . lista [0] != 1: 284 x. append (( i_ [3] + i_ [2] + i_ [1]) / 3) 285 y. append (( j_ [3] + j_ [2] + j_ [1]) / 3) 286 elif bc == 6: 287 reloj += 1 288 i = ik [2] 289 j = jk [2] 290 x. append ( i_ [4]) 291 y. append ( j_ [4]) 292 elif bc == 7: 293 reloj -= 1 294 if bca . lista [0] == 7 and (bca. lista [1] != 7 or bca. lista [1] != "p"): 295 x. append (( i_ [3] + i_ [4] + i_ [5]) / 3) 296 y. append (( j_ [3] + j_ [4] + j_ [5]) / 3) 297 x. append ( i_ [3]) 298 y. append ( j_ [3]) 299 if bca . lista [0] != 1: 300 x. append (( i_ [3] + i_ [2] + i_ [1]) / 3) 301 y. append (( j_ [3] + j_ [2] + j_ [1]) / 3) 302 bca . agregar (bc ) 303 ik , jk , reloj , i_ , j_ , borde = clock (horario , reloj , i, j, dim ) 91
92 A.1. Trazado de contornos 304 if borde != 0: 305 abierto = True 306 bc = casosbinarios (ik , jk , x_) 307 if not abierto and (i , j , reloj ) == inicio : 308 fin = True 309 x. append (x [0]) 310 y. append (y [0]) 311 elif abierto and len(x) > 1 and borde != 0: 312 if control . lista [0] == control . lista [1] == control . lista [2]: 313 fin = True 314 x. append ( i_ [2]) 315 y. append ( j_ [2]) 316 317 return x, y, paso 318 319 def vect (x_ , suavizar = False , factor =4 , reducir = False ): 320 nelx = len(x_ [0]) 321 nely = len(x_) 322 p, sentido = cambio (x_ , nelx , nely ) 323 paso = [] 324 contornos = [] 325 326 for kin range (len(p)): 327 x, y, paso = trazar (p[k][0] , p[k][1] , x_ , paso , horario = sentido [k ]) 328 if x [0] != x [ -1] or y [0] != y[ -1]: 329 330 contornos . append ( Contorno (x. copy () , y. copy () , True )) 331 else: 332 contornos . append ( Contorno (x. copy () , y. copy () , False )) 333 334 ii = [[k for kin range (0, nelx )], [ nelx - 1] * nely , [k for k in range (nelx - 1, -1, -1)], [0] * nely ] 335 336 jj = [[0] * nelx , [k for kin range (0, nely )], [ nely - 1] * nelx , [k for kin range ( nely - 1, -1, -1)]] 337 inicio = False 338 x = [] 339 y = [] 340 341 for kin range (len(ii)): 342 if k == 0: 343 re = 2 344 elif k == 1: 345 re = 1 346 elif k == 2: 347 re = 0 348 elif k == 3: 92
Capítulo A. Código 93 349 re = 3 350 inicio = False 351 for lin range (len(ii[k])): 352 i = ii[k][l] 353 j = jj[k][l] 354 i_ , j_ = node_coordinates (re , i, j, (nelx , nely )) 355 if x_[j, i] == 1 and not inicio: 356 x. append ( i_ [4]) 357 y. append ( j_ [4]) 358 inicio = True 359 elif inicio and x_[j, i] == 0: 360 x. append ( i_ [4]) 361 y. append ( j_ [4]) 362 inicio = False 363 contornos . append ( Contorno (x. copy () , y. copy () , True , limite = True )) 364 x = [] 365 y = [] 366 if inicio and l == len(ii[k]) - 1: 367 x. append ( i_ [2]) 368 y. append ( j_ [2]) 369 inicio = False 370 contornos . append ( Contorno (x. copy () , y. copy () , True , limite = True )) 371 x = [] 372 y = [] 373 374 return contornos 375 376 def filter( x_sol ): 377 filtered = x_sol . copy () 378 for iin range (len( x_sol )): 379 for jin range (len( x_sol [0]) ): 380 if x_sol [i , j] < 0.5: 381 filtered [i, j] = 0 382 elif x_sol [i , j] >= 0.5: 383 filtered [i, j] = 1 384 return filtered 385 386 class Contorno: 387 def __init__ (self , x, y, externo : bool, limite = False ): 388 389 self .x = np . array (x) 390 self .y = np . array (y) 391 self . externo = externo 392 self.limite = limite 393 394 def suavizado (self , dist ): 395 x = [] 93
94 A.1. Trazado de contornos 396 y = [] 397 if len ( self .x) <= 20: 398 pass 399 elif self . externo == False : 400 for iin range (len( self.x) + 1): 401 x_ , y_ = promedio_c ( self .x, self .y, i - dist , i + dist) 402 x. append ( x_) 403 y. append ( y_) 404 self .x = np . array (x) 405 self .y = np . array (y) 406 else: 407 x. append ( self .x [0]) 408 y. append ( self .y [0]) 409 for iin range (1, len(self .x) - 1): 410 x_ , y_ = promedio_e ( self .x, self .y, dist , i) 411 x. append ( x_) 412 y. append ( y_) 413 x. append ( self .x [ -1]) 414 y. append ( self .y [ -1]) 415 self .x = np . array (x) 416 self .y = np . array (y) 417 418 def simplificar (self ,ep , lim ): 419 420 if len ( self .x) <= lim : 421 if not self . externo and not self . limite : 422 n2 = int(len(self .x) / 2) 423 x, y = douglaspeucker ( self .x [0: n2 + 1], self.y[0: n2 + 1], 0.01) 424 x2 , y2 = douglaspeucker ( self .x[n2 :2 * n2 + 1], self .y[n2 :2 * n2 + 1], 0.01) 425 x += x2 [1:] 426 y += y2 [1:] 427 self .x = np . array (x) 428 self .y = np . array (y) 429 else: 430 x, y = douglaspeucker ( self .x, self .y, 0.01) 431 self .x = np . array (x) 432 self .y = np . array (y) 433 elif not self . externo and not self . limite : 434 n2 = int(len(self .x) / 2) 435 x, y = douglaspeucker ( self .x [0: n2 + 1], self.y[0: n2 + 1], ep) 436 x2 , y2 = douglaspeucker ( self .x[n2 :2 * n2 + 1], self .y[ n2 :2 * n2 + 1], ep) 437 x += x2 [1:] 438 y += y2 [1:] 439 self .x = np . array (x) 94
Capítulo A. Código 95 440 self .y = np . array (y) 441 else: 442 x, y = douglaspeucker ( self .x, self .y, ep) 443 self .x = np . array (x) 444 self .y = np . array (y) 445 446 def promedio_c (x , y, inf , sup ): 447 l = len(x) 448 N = sup - inf 449 sumx = 0 450 sumy = 0 451 t=0 452 for iin range (inf , sup + 1): 453 t += 1 454 if 0 <= i < l: 455 sumx += x[i] 456 sumy += y[i] 457 elif i >= l: 458 sumx += x[-l + i] 459 sumy += y[-l + i] 460 else: 461 sumx += x[l + i] 462 sumy += y[l + i] 463 return sumx / t, sumy / t 464 465 466 def promedio_e (x, y, N, i): 467 l = len(x) 468 inf = i - N 469 sup = i + N 470 sumx = 0 471 sumy = 0 472 t=0 473 for iin range (inf , sup + 1): 474 t += 1 475 if 0 <= i < l: 476 sumx += x[i] 477 sumy += y[i] 478 elif i >= l: 479 sumx += x [ -1] 480 sumy += y [ -1] 481 else: 482 sumx += x[0] 483 sumy += y[0] 484 return sumx / t, sumy / t 485 486 487 def douglaspeucker(x: list, y: list, epsilon ): 488 dmax = 0 95
96 A.1. Trazado de contornos 489 index = 0 490 resx = [] 491 resy = [] 492 for iin range (1, len(x)): 493 d = distancia_pl (x[i], y[i], x [0] , x [-1] , y [0] , y [ -1]) 494 if d > dmax : 495 index = i 496 dmax = d 497 if dmax > epsilon : 498 res1x , res1y = douglaspeucker (x [0: index + 1], y[0: index + 1], epsilon ) 499 res2x , res2y = douglaspeucker (x[ index : len(x)], y[ index : len ( x)], epsilon ) 500 501 resx = resx + res1x . copy () + res2x [1:]. copy () 502 resy = resy + res1y . copy () + res2y [1:]. copy () 503 else: 504 resx . append (x [0]) 505 resx . append (x [ -1]) 506 507 resy . append (y [0]) 508 resy . append (y [ -1]) 509 510 return resx . copy () , resy . copy () 511 512 513 def distancia_pl (px , py , xi , xf , yi , yf): 514 515 a1 = xf - xi 516 a2 = yf - yi 517 return abs(a2 * px - a1 * py - xi * a2 + yi * a1) / np. sqrt (a2 ** 2 + a1 ** 2) 518 519 520 class trazador: 521 def __init__ ( self , x_sol ): 522 self .x_f = filter( x_sol ) 523 self.nelx = len( x_sol [0]) 524 self . contornos = vect ( self .x_f ) 525 526 def suavizar ( self , N =2) : 527 for iin range (len( self . contornos )): 528 self . contornos [i ]. suavizado (N) 529 530 def reducir (self ,ep =0.25 , lim = 20): 531 for iin range (len( self . contornos )): 532 self . contornos [i ]. simplificar (ep , lim ) 533 534 def exportar ( self , name : string , medida_x =150.0) : 96
Capítulo A. Código 97 535 ruta_puntos = os. getcwd () + "\\" + name 536 os . mkdir ( ruta_puntos ) 537 external = dict() 538 internal = dict() 539 r=0 540 escala = medida_x / self . nelx 541 for iin range (len( self . contornos )): 542 if self . contornos [i ]. externo == True : 543 external [i] = [ self . contornos [i ].x * escala , self . contornos [i]. y * escala ] 544 545 546 else: 547 internal [i] = [ self . contornos [i ].x * escala , self . contornos [i]. y * escala ] 548 549 file1 = open(ruta_puntos + "\ external . pkl ","wb") 550 file2 = open(ruta_puntos + "\ internal . pkl ","wb") 551 pickle . dump ( external , file1 ) 552 pickle . dump ( internal , file2 ) 553 file1 . close () 554 file2 . close () A.2. FreeCAD 1import PartDesign 2import Part 3import Sketcher 4import pickle 5import numpy as np 6import math as m 7import FreeCAD 8import Draft 9 10 file1 = open(" ...\\ external . pkl ","rb") 11 file2 = open(" ...\\ internal . pkl ","rb") 12 external = pickle . load ( file1 ) 13 internal = pickle . load ( file2 ) 14 file1 . close () 15 file2 . close () 16 def line (x0 , y0 , xf , yf): 17 return Part . LineSegment ( FreeCAD . Vector (x0 ,y0 ,0) , FreeCAD . Vector ( xf ,yf ,0)) 18 19 def pad (doc ,L ,name , croquis ): 20 doc . getObject (’Body ’). newObject (’ PartDesign :: Pad ’,name) 97
98 A.2. FreeCAD 21 doc . getObject ( name ). Profile = doc . getObject ( croquis ) 22 doc . getObject ( croquis ). Visibility = False 23 doc . getObject ( name ). Length = L 24 doc . getObject ( name ). UseCustomVector = 0 25 doc . getObject ( name ). Direction = (1 , 1, 1) 26 doc . getObject ( name ). Type = 0 27 doc . getObject ( name ). UpToFace = None 28 doc . getObject ( name ). Reversed = 0 29 doc . getObject ( name ). Midplane = 0 30 doc . getObject ( name ). Offset = 0 31 32 def pocket ( doc ,L ,name , croquis ): 33 doc . getObject (’Body ’). newObject (’PartDesign :: Pocket ’,name) 34 doc . getObject ( name ). Profile = doc . getObject ( croquis ) 35 doc . getObject ( croquis ). Visibility = False 36 doc . getObject ( name ). Length = L 37 doc . getObject ( name ). UpToFace = None 38 doc . getObject ( name ). Type = 1 39 doc . getObject ( name ). UpToFace = None 40 doc . getObject ( name ). Reversed = 0 41 doc . getObject ( name ). Midplane = 1 42 doc . getObject ( name ). Offset = 0 43 44 45 doc = FreeCAD . newDocument (" Pieza_TFM ") 46 doc . addObject (’PartDesign :: Body ’,’Body ’) 47 doc . getObject (’Body ’). newObject (’Sketcher :: SketchObject ’,’external ’ ) 48 d = FreeCAD . getDocument ( ’Pieza_TFM ’). getObject (’external ’) 49 print ( external . keys ()) 50 for iin external . keys (): 51 for jin range (len( external [i ][0]) -1): 52 d. addGeometry ( line ( external [i ][0][ j], external [i ][1][ j], external [i ][0][ j +1] , external [i ][1][ j +1]) , False ) 53 doc . addObject (’Part :: Extrusion ’,’Extrude’) 54 f = doc . getObject ( ’Extrude’) 55 f. Base = doc . getObject (’external ’) 56 f. DirMode = "Normal" 57 f. DirLink = None 58 f. LengthFwd = 10.000000000000000 59 f. LengthRev = 0.000000000000000 60 f. Solid = True 61 f. Reversed = False 62 f. Symmetric = False 63 f. TaperAngle = 0.000000000000000 64 f. TaperAngleRev = 0.000000000000000 65 App . getDocument ( ’Pieza_TFM ’). recompute () 66 67 link =[] 98
68 for iin internal . keys (): 69 doc . getObject (’Body ’). newObject (’Sketcher :: SketchObject ’,f’ internal {i}’) 70 d = FreeCAD . getDocument ( ’Pieza_TFM ’). getObject (f ’internal {i}’) 71 for jin range (len( internal [i ][0]) -1): 72 73 d. addGeometry ( line ( internal [i ][0][ j], internal [i ][1][ j], internal [i ][0][ j +1] , internal [i ][1][ j +1]) , False ) 74 doc . addObject (’Part :: Extrusion ’,f’ Extrude {i}’) 75 f = doc . getObject (f ’Extrude {i} ’) 76 f. Base = doc . getObject (f ’internal {i} ’) 77 f. DirMode = "Normal" 78 f. DirLink = None 79 f. LengthFwd = 10.000000000000000 80 f. LengthRev = 0.000000000000000 81 f. Solid = True 82 f. Reversed = False 83 f. Symmetric = False 84 f. TaperAngle = 0.000000000000000 85 f. TaperAngleRev = 0.000000000000000 86 link . append ( doc. getObject (f ’Extrude {i}’)) 87 88 doc . addObject (" Part :: Compound " ," Compound ") 89 doc . Compound . Links = link 90 doc . addObject (" Part :: Cut "," Cut ") 91 doc . Cut . Base = App . activeDocument (). Extrude 92 doc .Cut . Tool = App . activeDocument () . Compound 93 94 doc . recompute ()