Otimizando desperdício de material com código (sem IA, só engenharia)
Olá pessoal, tudo bem?
No meu último post sobre automação — esse aqui:
Por que aprender a programar mudou minha vida e pode mudar a sua também — eu mencionei rapidamente um algoritmo que eu estava desenvolvendo para otimização de desperdício de material.
Em algum momento, enquanto escrevia e trabalhando nisso tudo, ficou claro pra mim que a parte mais interessante não era o código em si, mas o efeito que ele causava no mundo real. Este texto existe pra registrar essa ideia, as decisões técnicas por trás dela e o que acontece quando programação deixa de ser teoria.
Antes de entrar na parte técnica, alguns pontos importantes:
- Vou usar valores fictícios para representar os dados
- A taxa de economia é real
Contexto da história
A ideia surgiu de forma totalmente casual.
Estava conversando com meu chefe sobre custos: papel, adesivo, tinta… Ele comentou que queria testar um novo fornecedor, porque os preços estavam altos. Em tom de brincadeira, soltou aquela frase clássica:
“Custo é igual unha: sempre tem que cortar.”
A conversa terminou ali, cada um voltou ao trabalho.
Mas aquilo ficou na minha cabeça.
No fim do expediente, parei alguns minutos pra processar os números que ele tinha comentado:
- Papel: R$ 2,00 / m²
- Adesivo: R$ 10,00 / m²
Não vou falar de tinta hoje. Tinta é um problema à parte, bem mais chato de medir e otimizar.
Eu resolvi isso também, mas merece um post só pra ele
O tamanho do problema
O que mais me chamou atenção foi o adesivo.
A cada 50 metros de adesivo usados, cerca de 12 metros iam direto para o lixo.
Fazendo a conta:
- 50m × R10,00 = **R500,00**
- 12m desperdiçados × R10,00 = **R120,00**
Ou seja:
A cada R500,00 gastos, R120,00 eram literalmente jogados fora.
Isso é 24% de desperdício.
E o pior: isso não acontecia por descuido ou má vontade. Era consequência direta da forma como os trabalhos chegavam e precisavam ser produzidos.
Eu já vinha coletando alguns dados sobre desperdício, mas quem trabalha em produção sabe como é:
equipe enxuta, prazo apertado, cliente esperando. Desperdício acaba ficando em segundo plano.
Por que o desperdício acontecia?
Na prática, enfrentávamos dois cenários bem claros.
Cenário 1: o trabalho urgente isolado
- 08:30 — vendedor libera um totem
- Tamanho: 30 × 30 cm
- Prazo: precisa estar pronto às 11:00
- Tempo disponível: 2h30
Nossa bobina de adesivo tem 1 metro de largura.
Para produzir um adesivo de 30 cm, automaticamente 70 cm de material útil eram desperdiçados.
A taxa de aproveitamento?
30%.
Mas com prazo apertado, você pega o material que já está na máquina e produz. Não dá pra esperar juntar com outros trabalhos ou reorganizar tudo.
Cenário 2: o quebra-cabeça diário (o mais comum)
Agora imagina isso acontecendo dezenas de vezes por dia.
Chegam 30 totens de tamanhos diferentes.
Você tem 10 minutos, no máximo, para:
- Olhar todas as medidas
- Tentar encaixar da melhor forma possível
- Aproveitar os espaços vazios
- Minimizar o desperdício
É tipo jogar Tetris, só que:
- Contra o relógio
- Com peças todas diferentes
- E cada erro custa dinheiro real
Fazer isso manualmente, sob pressão, com o setor inteiro esperando, é simplesmente impossível de fazer de forma ótima.
Você faz o melhor que dá — e segue o jogo.
A solução
A ideia era simples (na teoria):
Criar um algoritmo que organizasse automaticamente essas imagens, tentando minimizar o desperdício.
Por que não usei IA?
Dois motivos bem práticos:
- Custo — não podia gerar despesas extras com esse projeto
- Performance — usar IA para encaixar polígonos disformes seria computacionalmente caro e lento
Então segui outro caminho:
múltiplas tentativas aleatórias.
É literalmente jogar Tetris várias vezes seguidas e ficar com o melhor resultado.
Como funciona na prática
Imagine os mesmos 30 polígonos, em uma bobina de 1 metro de largura.
Tentativa 1
- Organização aleatória
- Arquivo final: 1m × 4m
- Material usado: 4m²
Tentativa 2
- Nova organização
- Arquivo final: 1m × 3,4m
- Economia: 0,6m² (15%)
Tentativa 3
- Outra organização
- Arquivo final: 1m × 3,1m
- Economia: 0,9m² (22,5%)
O algoritmo roda dezenas ou centenas dessas tentativas em poucos minutos e escolhe automaticamente a melhor.
O que antes levava 10 minutos de estresse manual agora leva segundos ou minutos, com resultados consistentemente melhores.
A taxa de otimização
A taxa de otimização vai de 0 a 7:
- Nível 0 — praticamente sem otimização (~40s)
- Nível 3 — otimização intermediária (~2min)
- Nível 7 — otimização agressiva (~6min)
É um trade-off direto:
tempo de processamento vs economia de material.
A parte técnica
Apesar de parecer simples no papel, implementar isso foi tudo menos trivial.
Linguagem: Rust + Python
O primeiro desafio foi performance.
Python puro simplesmente não aguentaria o volume de operações necessárias.
A solução foi criar uma biblioteca de manipulação de imagens em Rust, exposta para Python usando PyO3.
#[pyclass]
pub struct FenrirImage {
width: u32,
height: u32,
buffer: DynamicImage,
}
#[pymethods]
impl FenrirImage {
pub fn crop(&mut self, x: u32, y: u32, w: u32, h: u32) -> PyResult<Self> {
self.validate_rect(x, y, w, h)?;
let cropped = self.buffer.crop_imm(x, y, w, h);
let normalized = FenrirImage::normalize_dynamic(cropped);
// ...
}
pub fn rotate_90(&mut self) -> PyResult<()> {
let rotated = self.buffer.rotate90();
self.set_from_dynamic(rotated);
Ok(())
}
}
Esse tipo de operação acontece centenas de vezes por tentativa.
Se isso fosse Python puro, o algoritmo simplesmente não seria viável.
Sobre os polígonos
Cada imagem é transformada em um polígono não convencional, baseado no traçado real da imagem — não apenas quadrados ou círculos.
Esse polígono não é perfeito (e nem precisa ser), mas é bom o suficiente para:
- Cálculo de área
- Detecção de colisão
- Cache de resultados
Muitas imagens se repetem ao longo das produções, então esse cache faz muita diferença.
Técnicas usadas no algoritmo
Esse problema é uma variação prática do 2D Bin Packing Problem, que é NP-difícil.
Ou seja: não existe solução perfeita rápida — só soluções cada vez melhores.
- Estruturas de dados espaciais
- Paralelismo
- Caching inteligente
- Recursividade com backtracking
Os resultados
Mês 1 — sem script
- Produção: 240 totens
- Material usado: 210m
- Custo: R$2.100
Mês 2 — otimização nível 3
- Produção: 250 totens
- Material usado: 205m
- Economia: R$50
Mês 3 — otimização nível 5
- Material usado: 190m
- Economia: R$200
Mês 4 — otimização nível 7
- Material usado: 170m
- Economia: R$400 por mês
Conclusão
Programar só por programar é legal.
Mas criar algo que impacta diretamente o trabalho das pessoas, reduz desperdício e melhora processos reais é outra história.
Eu nunca cheguei no meu chefe dizendo:
“Olha, economizamos X reais por causa disso.”
Ele tinha coisas mais importantes para se preocupar.
Meu trabalho era resolver problemas — e explicar só se alguém perguntasse.
Talvez ele nem tenha percebido conscientemente que estávamos produzindo mais, com menos desperdício.
Mas é exatamente isso que programação é — e sempre vai ser.
Resolver problemas reais, de forma silenciosa, mensurável e eficiente.
E sim: esse “script” acabou virando um módulo conectado diretamente à Safira, que eu mencionei no último post.
Observações
Estou com alguns projetos atrasados (pra variar) e, por isso, ainda não disponibilizei a lib feita em Rust nem o script em Python no meu GitHub.
Quero melhorar a estrutura e a organização antes, porque hoje está uma bagunça honesta.
Durante o tempo em que trabalhei nessa empresa, fiz muitas automações e projetos parecidos com esse. Pretendo falar de vários deles nos próximos posts.
Obrigado por ler até aqui — e até a próxima.