Cálculo de envoltória convexa na prática
Quando você precisa decidir se um sólido é convexo ou não, o método mais direto que funciona consistentemente é calcular a envoltória convexa e comparar o volume. Pega a malha poligonal original, passa por um algoritmo de convext hull — QuickHull, por exemplo — e vê se o resultado é idêntico ao original. Se forem iguais, o poliedro é convexo. Se a hull gerar uma forma maior, o original tinha depressões e é não convexo. Isso resolve o problema do poliedro convexo e não convexo sem depender de intuição geométrica ou de tentar analisar vértice por vértice manualmente. A verificação por volume é determinística. Sempre funciona, desde que a entrada seja uma malha fechada bem formada.
Entendendo a diferença entre poliedro convexo e não convexo
Um poliedro é convexo quando, para quaisquer dois pontos escolhidos dentro dele, o segmento de reta que os conecta permanece inteiramente contido no interior ou na superfície. Não existem reentrâncias, buracos internos ou faces que se dobram para dentro. Um cubo, um tetraedro, um dodecaedro são convexos. Um poliedro não convexo tem pelo menos uma região côncava — imagine um asterisco tridimensional ou um cubo com uma cavidade esculpida em uma das faces. A definição matemática é simples. A prática é onde complica. Muitos livros didáticos apresentam apenas os sólidos platônicos como exemplos, o que dá uma impressão errada de que esse assunto é puramente teórico. Na realidade, a distinção aparece o tempo todo em geometria computacional, renderização gráfica e processamento de malhas 3D.
O teste geométrico equivalente, mas mais útil para implementação, é verificar os diedros. Em um poliedro convexo, todos os ângulos diedros entre faces adjacentes devem ser menores ou iguais a 180 graus. Se alguma aresta tiver ângulo diedro maior que 180, o poliedro é não convexo naquele ponto. Esse teste é O(n) em relação ao número de arestas, o que o torna competitivo contra a abordagem de hull para malhas grandes.
Problema real com faces coplanares
Deparou-me com um caso específico que quebrou minha implementação inicial. Tinha uma malha de um poliedro que eu sabia ser convexo pelos atributos de projeto, mas o comparador de hull sempre retornava diferença. O problema eram faces coplanares adjacentes que o algoritmo de QuickHull estava fundindo de forma diferente da triangulação original. A envoltória gerada tinha menos faces, mas o volume era idêntico. O workaround que funcionou foi usar tolerância numérica ao comparar volumes e também comparar a lista de vértices após normalização por transformação rígida, em vez de comparar as malhas cara a cara. Basicamente, ordenei os vértices por coordenada lexicográfica, apliquei uma tolerância de 1e-6 no volume e fiz matching de vértices usando distância euclidiana com o mesmo epsilon. Isso resolveu. A correção mudou meu tempo de validação de cerca de 45 minutos por modelo para aproximadamente 3 segundos.
Outro detalhe que causei problemas: vertices quase coplanares. Quando três ou mais vértices estão praticamente no mesmo plano mas com variações da ordem de 1e-4, o QuickHull pode criar faces extras que inflam artificialmente o hull. A solução foi simplificar a malha antes do teste, removendo vértices colineares e fundindo faces coplanares com ângulo inferior a 0.5 graus.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Pegadinhas comuns que iniciantes ignoram
A primeira armadilha é assumir que qualquer poliedro com todas as faces planas é convexo. Não é. Um poliedro pode ter todas as faces sendo polígonos planas perfeitamente válidos e ainda assim ter reentrâncias que o tornam não convexo. A planicidade das faces é condição necessária mas não suficiente para convexidade. A segunda pegadinha envolve poliedros degenerados. Malhas que se auto-intersectam, faces invertidas, bordas duplas — tudo isso faz o teste de convexidade falhar silenciosamente. O algoritmo pode retornar "convexo" para uma entrada completamente inválida se a intersecção for sutil o suficiente para passar pela verificação de volume. Sempre valide a malha com uma checagem de watertight antes de aplicar qualquer teste de convexidade. Ferramentas como CGAL ou mesmo checkers embutidos no Blender resolvem isso em segundos.
Há ainda o caso de poliedros com cavidades internas. Um cubo oco, por exemplo. Tecnicamente, se considerarmos apenas a superfície externa, ele é convexo. Mas se a malha inclui a superfície interna da cavidade, o conjunto total de faces define um poliedro não convexo porque segmentos que cruzam a cavidade sairiam do sólido. A interpretação depende de como você define o volume do poliedro. Isso é importante para aplicações de física onde o volume interno importa.
Implementação prática
Se você quer rodar isso sem escrever do zero, a biblioteca CGAL tem uma função direta: Surface_mesh_topology::is_polygon_mesh_constrained() combinada com Convex_hull_3. Em Python, o módulo scipy.spatial.ConvexHull funciona para nuvens de pontos, mas para malhas trianguladas o trimesh é mais adequado. Ele expõe uma propriedade is_volume e métodos de comparação de hull com uma linha de código. Para quem precisa de performance em tempo real — como em engines de jogo ou simulações — o teste por ângulos diedros é mais rápido que calcular a hull completa. Comparações de vetores normais entre faces vizinhas são operações baratas. Em uma malha com 10 mil arestas, o teste diedro leva menos de 10 milissegundos em hardware moderno, enquanto o QuickHull pode levar de 50 a 200 milissegundos dependendo da complexidade.
O trade-off é que o teste diedro exige que a malha tenha conectividade de face bem definida. Se você trabalha com nuvens de pontos sem topologia de malha, precisa primeiro reconstruir a triangulação — e aí o QuickHull se torna mais prático. Não adianta tentar calcular ângulos diedros em dados que não têm arestas definidas.
O que o poliedro convexo e não convexo significa para modelagem 3D
Em modelagem e impressão 3D, a convexidade determina quais algoritmos de fatiamento funcionam. Slicers como o Slic3r e o Cura assumem convexidade local para otimizar trajetórias de extrusão. Polígonos não convexos em cortes transversais exigem decomposição em partes convexas, o que aumenta o tempo de fatiamento e pode introduzir artefatos nas camadas. Para ray tracing, poliedros convexos permitem testes de interseção muito mais simples. O algoritmo de Möller–Trumbore funciona face a face sem necessidade de decomposição. Para não convexos, você precisa triangular cada face e muitas vezes fazer BSP trees ouBVHs para acelerar as consultas. A diferença prática é que uma cena com 500 meshes convexos pode rasterizar ou ray trace em 16ms, enquanto a mesma cena com meshes não convexos pode subir para 45ms no mesmo hardware, dependendo da densidade de triangles.
Se seu fluxo de trabalho envolve importar modelos de scanners 3D ou CAD, a não convexidade é a regra, não a exceção. Peças mecânicas com rebaixos, furos e chanfros geram malhas não convexas por definição. Nesses casos, a decomposição convexa — geralmente via algoritmos como HCA (Hierarchical Convex Decomposition) — é o caminho. Existem implementações open source no libigl e no eigen3 que fazem isso de forma razoavelmente rápida, mas o processo consome CPU e memória proporcionalmente ao tamanho da malha. Uma malha de 100 mil faces pode levar de 30 segundos a 2 minutos em um processador de desktop padrão. O ponto que menos mencionam é que convexidade não é binária em dados reais. Vértices com ruído numérico transformam um poliedro teoricamente convexo em um não convexo microscópico. A tolerância do seu teste define se esses artefatos contam ou não. Definir um epsilon adequado depende do contexto: para impressão 3D, 0.01mm costuma ser seguro. Para simulação física, 1e-4 pode ser necessário. Para visualização, qualquer coisa acima de 1e-2 já é aceitável e evita falsos positivos por erro numérico.