Sistema de simulação de scripts ZenCad 3D

O trabalho que quero chamar a atenção é uma tentativa de escrever novamente um sistema de modelagem 3D com script. Escreva como eu gostaria de vê-la.


A receita para o sistema ZenCad é bastante simples. O conceito de criação de scripts de modelagem 3D do OpenScad, o núcleo geométrico do OpenCascade, python3 como cola, a biblioteca de computação preguiçosa evalcache para cache agressivo de cálculos. Adicione temperos de algumas outras ferramentas, tempere o gui com molho PyQt e sirva, mexendo, mas sem agitar.


machine.png


Sistemas CAD de script


O CAD, ou de acordo com o nosso CAD, é um sistema de design auxiliado por computador. Ao contrário dos editores 3D interativos, os sistemas CAD com script interpretam a palavra "automatizado" no sentido em que seus criadores geralmente a entendem. Ou seja, não como um conjunto de ferramentas de computação, mas como um algoritmo claro que requer intervenção humana apenas no momento de sua criação.


Trabalhando em CAD com script, não desenhamos o modelo diretamente na tela, mas construímos o programa de acordo com o qual o modelo é gerado. Para pessoas familiarizadas apenas com CAD interativo, essa abordagem pode ser descrita como uma modelagem paramétrica absoluta. A rigor, os scripts geralmente são usados ​​para complementar um ambiente interativo, para escrever ferramentas adicionais, mas trabalhar em um CAD com script paradigmaticamente limpo requer uma organização diferente do fluxo de trabalho, uma maneira de pensar e é projetado para uma variedade de tarefas ligeiramente diferente.


O CAD mais famoso e puro de script atualmente é o OpenScad.


No começo foi o OpenScad


Há um certo círculo de pessoas que prefere o conveniente Compass, SolidWorks, FreeCad, o mundano e despretensioso OpenScad. Não é fácil responder à pergunta sobre qual é o segredo do sucesso dele, mas você pode definitivamente dizer que é leve, flexível o suficiente para usar e tem um mínimo de configurações. Partes dos modelos escritos nele são fáceis de reutilizar.


No entanto, o openscad tem algumas falhas irritantes:


  • O openscad funciona apenas com redes mesh.
  • O openscad tem um limite de escalabilidade bastante baixo, e começa a ficar muito forte em modelos grandes.
  • O openscad é bastante difícil de integrar com outros sistemas, e é por isso que usa seu próprio idioma.

Infelizmente, apesar de todo o poder da abordagem de script, ir além do escopo da criação de modelos utilitários com o OpenScad é bastante problemático.


Idioma e tudo-tudo-tudo


A primeira coisa que quero corrigir aqui é usar uma linguagem de uso geral como ferramenta de combate. O uso de uma linguagem de uso geral permite que você use a integridade de seus recursos sintáticos e a totalidade das bibliotecas escritas anteriormente para resolver problemas de modelagem 3D.


Comparação de GUIs ZenCad e OpenScad

Interface ZenCad:
zencad.png


Interface OpenScad:
openscad.png


O uso de python simplifica o código do openscad, tornando o código do modelo mais transparente em comparação com o OpenScad.


Exemplo: CSG
#!/usr/bin/env python #coding: utf-8 from zencad import * lazy.diag = True c1 = 100 c2 = 130 c3 = c2/2 + 20 base = box(c1,c1,c1,center=True) f1 = ngon(r = 35, n = 3) f2 = ngon(r = 35, n = 5) f3 = circle(35) s1 = linear_extrude(f1, c2, center=True) s2 = linear_extrude(f2, c2, center=True).rotateY(deg(90)) s3 = linear_extrude(f3, c2, center=True).rotateX(deg(90)) #          3 . m1 = base - s1 - s2 - s3 m2 = base ^ s1 ^ s2 ^ s3 m3 = s1 + s2 + s3 ystep = 240 xstep = 240 fontpath = os.path.join(zencad.moduledir, "examples/fonts/testfont.ttf") #    .      . t1 = textshape("difference", fontpath, 40) t1c = t1.center() t1=t1.translate(-t1c.x, -t1c.y, 0).rotateZ(deg(45)) t2 = textshape("intersect", fontpath, 40) t2c = t2.center() t2=t2.translate(-t2c.x, -t2c.y, 0).rotateZ(deg(45)) t3 = textshape("union", fontpath, 40) t3c = t3.center() t3=t3.translate(-t3c.x, -t3c.y, 0).rotateZ(deg(45)) #  ,  . disp(base.forw(ystep)) disp(s1) disp(s2.left(xstep)) disp(s3.right(xstep)) disp(m1.back(ystep)) disp(m2.left(xstep).back(ystep)) disp(m3.right(xstep).back(ystep)) disp(t1.back(ystep).up(c3), Color(1,1,0)) disp(t2.left(xstep).back(ystep).up(c3), Color(1,1,0)) disp(t3.right(xstep).back(ystep).up(c3), Color(1,1,0)) disp(s1.left(xstep).back(ystep), Color(0.5,0,0,0.95)) disp(s2.left(xstep).back(ystep), Color(0.5,0,0,0.95)) disp(s3.left(xstep).back(ystep), Color(0.5,0,0,0.95)) disp(s1.back(ystep), Color(0.5,0,0,0.95)) disp(s2.back(ystep), Color(0.5,0,0,0.95)) disp(s3.back(ystep), Color(0.5,0,0,0.95)) show() 

boolean.png


É muito conveniente, por exemplo, filtrar uma nuvem de pontos usando a sintaxe dos geradores.


Exemplo: Filtrando uma matriz de pontos.
 #!/usr/bin/env python3 from zencad import * #  . ng = ngon(r = 10, n = 6) #      . vertices = ng.vertices() filtered_vertices = [v for v in vertices if vx < 0] #      . m = ng.fillet(4, filtered_vertices) disp(m) show() 

ngon


Graças ao python, que ocupa oficialmente o título de rei da cola no moderno ecossistema de software, o zencad se integra facilmente a outras bibliotecas e sistemas de software. Podemos usar sympy em um script para gerar uma superfície analítica, numpy para processar uma nuvem de pontos gerada nessa superfície e, é claro, o zencad para construção, visualização e pós-processamento.


Exemplo: Construção simples de superfície ponto a ponto
 from zencad import * import numpy xcoords = numpy.linspace(-10,10,50) ycoords = numpy.linspace(-10,15,50) lines = [ interpolate([point(x, y, 0.01*(x**2 + y**3)) for x in xcoords]) for y in ycoords ] wires = [] for l in lines: trans = translate(0,0,-30) sf = l.endpoints() w=sew([l, segment(sf[0], trans(sf[0])), trans(l), segment(sf[1], trans(sf[1]))]) wires.append(w) for l in lines: disp(l.left(30)) disp(loft(wires) - halfspace().down(10)) show() 

chair.png


A base sólida do OpenCascade


A matemática das malhas poligonais é muito mais simples que a matemática da representação de fronteira, mas a representação de fronteira é muito mais prática. Em particular, as malhas poligonais têm um problema de explosão combinatória, que se manifesta especialmente quando chega a hora de renderizar um modelo. No OpenScad, geralmente é necessário desenvolver um produto com uma resolução muito menor que a resolução de um modelo real, o que viola a pureza do paradigma.


Portanto, o segundo ponto de implementação é o uso de um núcleo geométrico completo que usa a representação de limite em vez do modelo de malha. Construído em torno do núcleo geométrico hacker do OpenCascade, o ZenCad, é claro, não visa fornecer a totalidade de seus recursos no ambiente python. Tentar transmitir completamente o OpenCascade levaria à criação de um segundo pythonOCC. O ZenCad assume o topo, tentando manter um equilíbrio entre funcionalidade e ergonomia.


Exemplo: garrafa de software OpenCascade reproduzida no ZenCad
 #!/usr/bin/env python3 #coding: utf-8 from zencad import * import zencad.surface as surface import zencad.curve2 as curve2 lazy.diag=True height = 70 width = 50 thickness = 30 # BASE pnt1 = point(-width/2,0,0); pnt2 = point(-width/2,-thickness/4,0); pnt3 = point(0,-thickness/2,0); pnt4 = point(width/2,-thickness/4,0); pnt5 = point(width/2,0,0); edge1 = segment(pnt1, pnt2) edge2 = circle_arc(pnt2, pnt3, pnt4) edge3 = segment(pnt4, pnt5) wire = sew([edge1, edge2, edge3]) profile = sew([wire, wire.mirrorX()]) body = profile.fill().extrude(height) body = fillet(body, thickness/12) hl(body.forw(140)) # NECK neck_radius = thickness/4.; neck_height = height/10; neck = cylinder(r=neck_radius, h=neck_height).up(height) body = body + neck hl(body.forw(100)) # THICK body = thicksolid(body, -thickness / 50, [point(0,0,height+height/10)]) hl(body.forw(60)) # THREAD ( 2       .) cylsurf1 = surface.cylinder(neck_radius * 0.99) cylsurf2 = surface.cylinder(neck_radius * 1.05) major = 2 * math.pi; minor = neck_height / 10; angle = math.atan2(neck_height / 4, 2 * math.pi) ellipse1 = curve2.ellipse(major, minor).rotate(angle) arc1 = cylsurf1.map(curve2.trimmed_curve2(ellipse1, 0, math.pi)) segment1 = cylsurf1.map(curve2.segment(ellipse1.value(0), ellipse1.value(math.pi))) ellipse2 = curve2.ellipse(major, minor/4).rotate(angle) arc2 = cylsurf2.map(curve2.trimmed_curve2(ellipse2, 0, math.pi)) segment2 = cylsurf2.map(curve2.segment(ellipse2.value(0), ellipse2.value(math.pi))) m1 = sew([arc1, segment1]) m2 = sew([arc2, segment2]) thread = loft([m1, m2]).up(height + neck_height / 2) hl(m1.up(height + neck_height / 2).right(80)) hl(m2.up(height + neck_height / 2).right(60)) hl(thread.right(40)) # FINAL m = thread + body display(m) show() 

bottle.png


Continuidade da tradição. A origem como fonte de tudo


As soluções de sintaxe zencad, seguindo o exemplo de seu irmão mais velho e professor do OpenScad, minimizam o número de entidades na biblioteca. Como o OpenScad, o ZenCad é fundamentalmente incapaz de criar uma primitiva no ponto (x, y, z), apesar do OpenCascade permitir isso. O ZenCad primeiro cria um primitivo na origem e depois define a posição necessária usando transformações. As transformações no ZenCad existem como objetos separados e como métodos de corpos.


 #  . cube(40, center=True).rotateX(deg(45)).rotateZ(deg(45)).right(20) #  . (right(20) * rotateZ(deg(45)) * rotateX(deg(45)))(cube(40, center=True)) #  . trans = right(20) * rotateZ(deg(45)) * rotateX(deg(45)) cube(40, center=True).transform(trans) 

Um conjunto de transformações é padrão e inclui translação, rotação, reflexão e zoom.


Preguiça


Para minimizar o tempo de computação, a matemática no ZenCad é esclarecida e todos os cálculos são armazenados em cache de forma agressiva. A biblioteca [del] blockchain [/ del] evalcache, sobre a qual falei nas páginas do Habrahabr há algum tempo, cuida do gerenciamento de algoritmos de lenificação: Armazenamento em cache em disco de árvores de computação preguiçosas . O Zencad salva os resultados do cálculo em um cache comum, cujo status pode ser monitorado através da interface do visualizador. O algoritmo de sha512 usado com redundância acentuada elimina a possibilidade de colisões de chaves de objetos preguiçosos (o espaço de hash é 10 ^ 74 vezes o número de átomos no universo).


Ao criar esse modelo, ele gera quatro megabytes de geometria e, durante a primeira passagem, pode ser calculado por um longo período de tempo:


bolt.png


O trabalho com superfícies roscadas é computacionalmente caro:


logo.png


O problema da topologia de reflexão. Método do ponto próximo


O OpenScad não possui operações de chanfro ou arredondamento. O OpenCascade os fornece. Essas são operações muito importantes e seria uma pena não colocá-las em serviço no ZenCad. Existem outras operações que requerem a especificação de um objeto topológico, por exemplo, a operação de obter um modelo de parede fina no exemplo de garrafa do OpenCascade. Em um sistema CAD gráfico, indicamos um objeto topológico (aresta, face, vértice) com o mouse. Ao escrever um script, não temos essa oportunidade. O OpenCascade nativo resolve o problema com reflexão e o usa para trabalhar com CAD gráfico. Embora o ZenCad ofereça suporte à reflexão do modelo, usá-lo como uma ferramenta primária apresenta várias desvantagens significativas. Primeiro, o nível de conhecimento necessário para usar essas ferramentas aumenta acentuadamente, porque você deve pelo menos entender o conceito topológico interno. Em segundo lugar, assim que aparece no script, a harmonia dos algoritmos preguiçosos quebra imediatamente, e o código do modelo também é bastante complicado. No processo de reflexão e experimentação bastante longas, decidi pelo método do ponto próximo. Em resumo, ao executar operações topologicamente dependentes, o programa ignora o objeto e encontra o objeto topológico mais próximo ao ponto especificado dentre as pessoas que entram no corpo. Este item é considerado selecionado. Essa solução é mais computacionalmente cara, mas devido ao cache, ela apresenta um bom desempenho. Essa abordagem é usada para todas as operações que dependem de elementos de topologia.


Como mencionado acima, a possibilidade de refletir o modelo, pelo senso comum, também é preservada, como mostrado no exemplo acima (Exemplo: Filtrando uma matriz de pontos).


Marcador Q e Marcador W


As dimensões do modelo podem ser difíceis de ler na tela devido à falta de óbvia escala. Em parte, os marcadores podem resolver esse problema. Com uma interface intuitiva (nada mais intuitiva), os marcadores sinalizam as coordenadas e mostram a distância, o que simplifica a análise da geometria e a seleção de pontos para operações como chanfros / arredondamentos.


marcadores


Rastrear atualizações de origem


Como o big brother (OpenScad), o ZenCad pode atualizar o modelo gerado ao modificar o arquivo de origem. Em combinação com o sistema de armazenamento em cache, isso permite que você modifique o script de maneira conveniente, tendo diante de seus olhos quase em tempo real o estado de mudança do produto.


Animação


Os méritos do zencad não terminam aí.


O ZenCad (graças à aceleração rápida do núcleo) pode redesenhar a cena em tempo real, o que permite animar um modelo 3D. A animação é implementada por uma função python comum e permite que você se trate livremente. Dado que estamos em um ambiente python, o zencad é capaz de visualizar dados de fontes externas como movimentos do modelo (por exemplo, usando multithreading + tcpsocket). Assim, o zencad pode ser usado, por exemplo, para testes semi-naturais de produtos robóticos. Oh olá Gazebo !!! Oi ROS !!! É bom ver você na platéia também. Uma biblioteca de cinemática, que simplificaria bastante a construção de cadeias cinemáticas de manipuladores robóticos, a propósito, está em desenvolvimento.


A animação no momento ainda está em uma versão semi-experimental (especialmente em termos de controle de câmera), por isso não vou me deter nela em detalhes.


Exportação - Importação


Atualmente, a exportação e importação no formato brep são suportadas, o que permite a integração com o freecad e a exportação no formato stl, o que permite gerar modelos para impressão 3D. A geração de capturas de tela também é suportada. Incluindo automático. Em particular, as capturas de tela no manual on-line são geradas automaticamente pelo ZenCad.


Status atual


No momento, o ZenCad ainda está muito longe de ser concluído e, no entanto, está totalmente operacional na parte em que está pronto.


A biblioteca está disponível no pipy para eixos compatíveis com o Debian com versões de python3.5, python3.6, python3.7


(Pode ser necessário instalar o qt5-default, devido a alguns problemas com os plugins no PyQt5)


 python3 -m pip install zencad apt install qt5-default 

Executando a GUI na linha de comando:


 python3 -m zencad 

Executando a GUI a partir de um script python:


 #!/usr/bin/env python3 import zencad m = zencad.cube(20) zencad.disp(m) zencad.show() 

Infelizmente, o progresso do sistema não está indo tão rápido quanto gostaríamos. A maior parte da API de geometria bidimensional e API de trabalhar com superfícies ainda não foi implementada, o suporte à exportação e importação de formatos padrão, o tratamento de erros nem sempre é transparente, o teste automático não foi elaborado, as bibliotecas para a construção de juntas roscadas e produtos de engrenagem foram concebidas e ainda não foram implementadas. Como editor externo, que é completamente anormal, é subitamente incondicional !!! Texto sublime ... Também quero refinar o sistema para que ele possa ser executado no Windows (isso requer bastante trabalho de inteligência especializada).


No entanto, agora o zencad permite projetar modelos 3D bastante complexos, criar modelos para impressão 3D e até visualizar a cinemática de mecanismos.


Links do Projeto


github: https://github.com/mirmik/zencad , https://github.com/mirmik/servoce


pypi: https://pypi.org/project/zencad/ , https://pypi.org/project/pyservoce/


manual


Obrigado pela atenção.


Source: https://habr.com/ru/post/pt443140/


All Articles