Documentação
Janela de visualização
As ferramentas de desenho de tela e a renderização Three.js compartilham a geometria central enquanto mantêm o estado de edição e reprodução explícito.
Traduzido automaticamente do inglês. Ver o original em inglês
Componentes da janela de visualização
apps/desktop/src/viewport/index.ts exportações Editor2D, View3D, seus tipos de acessórios, identificadores de ferramentas disponíveis e solidsFromProfiles. Ambos os componentes preenchem seu pai: fornecem um contêiner com largura e altura diferentes de zero. As principais entidades CAD e programas CAM são o modelo de dados compartilhado.
O editor 2D é renderizado no Canvas 2D e mantém seu próprio histórico de seleção, câmera e comando. O visualizador 3D usa Three.js, controles de órbita e transformação, trabalhos de malha assíncronos e reprodução de programa. A renderização de um caminho ou sólido independe de salvá-lo ou verificar uma operação de fabricação.
Contrato de integração
Editor2DProps requer drawing, onChange, e selectedTool. Alimente os desenhos emitidos de volta ao suporte. O componente reconhece seus próprios objetos de documento emitidos; substituir o documento carrega externamente o novo desenho e redefine o estado do editor.
import { createSignal } from "solid-js"
import { Editor2D, type ToolId } from "./viewport/index.ts"
const [drawing, setDrawing] = createSignal(initialDrawing)
const [tool, setTool] = createSignal<ToolId>("select")
<Editor2D drawing={drawing()} onChange={setDrawing} selectedTool={tool()} /> A seleção exclui entidades bloqueadas e entidades em camadas bloqueadas. Entidades invisíveis e camadas ocultas são excluídas do índice espacial renderizado. Novas entidades recebem identificadores exclusivos do documento e são atribuídas a uma camada visível e desbloqueada quando houver uma disponível.
Ferramentas e gestos de desenho
O registro de ferramentas possui fábricas para seleção, linha, retângulo, círculo, elipse, polilinha, arco, texto, dimensão, movimento, rotação, escala, espelhamento, deslocamento, corte e filete. AVAILABLE_TOOLS é derivado dessas fábricas registradas. startTool reconhece adicionalmente chamfer através da fábrica de ferramentas de filete, mas o chanfro não é anunciado nessa matriz. Os consumidores devem usar o registro real para decidir quais ferramentas ativar.
- Rodar ou apertar zoom; Arrastar espaço, arrastar o meio e arrastar para a direita.
Fse ajusta ao desenho indexado. Excluir ou Backspace remove a seleção desbloqueada.Cmd/Ctrl+Zdesfaz;Cmd/Ctrl+Shift+ZouCmd/Ctrl+Yrefaz.- Enter confirma uma polilinha. Escape é entregue à ferramenta ativa para cancelar seu gesto atual.
- Com o texto ativo, digite caracteres ou Backspace antes da colocação; o texto inicial é
Text.
As posições dos ponteiros são convertidas em coordenadas mundiais antes do envio da ferramenta. O snap combina o índice espacial, os candidatos geométricos e uma grade dependente da câmera; a tolerância de acerto de seleção corresponde a oito pixels da tela. As máquinas-ferramenta produzem comandos e visualizações em vez de gravar arquivos ou chamar a API.
3Renderização e reprodução D
View3D aceita desenhos, sólidos, extrusão de perfil opcional, um cam.Program, dimensões de estoque e definições de ferramentas. Ele suporta predefinições de perspectiva, superior, inferior, frontal, traseira, esquerda, direita, isométrica e de quatro visualizações. Os modos de exibição são sombreados, sombreados com bordas, estrutura de arame e raio-x. Iluminação, propriedades do material, seções de recorte, grade, eixos e origem são configuráveis por meio de acessórios.
Controle a reprodução com playing, playbackTime em segundos, playbackRate, e onPlaybackTimeChange. A reprodução expande os ciclos de perfuração, faz o mosaico do movimento circular/helicoidal, preserva o tempo de permanência e desenha movimentos rápidos de forma distinta. Mapas de ferramentas e uma fresa padrão opcional fornecem geometria da fresa, da haste e do suporte; a geometria assumida é visualmente distinta.
Os retornos de chamada de seleção relatam um índice sólido. Os controles de transformação emitem posição, rotação e escala através onTransformCommit; os chamadores decidem como persistir essa transformação. As sobreposições de percurso podem mostrar pontos e rótulos, filtros de tipo de ponto, centros de arco, raios de arco e transparência de estoque.
A reprodução é uma representação visual
O visualizador anima o programa fornecido e desenha materiais e ferramentas. Não realiza remoção de material. As verificações de colisão e de envelope de máquina pertencem aos módulos de verificação CAM; visualizar um programa não constitui aprovação da máquina.
Coordenadas e unidades
As coordenadas do desenho central e os tamanhos do material usam milímetros. Os ângulos de desenho e os componentes de rotação do Three.js usam radianos; não aplique essa convenção a valores de eixo rotativo CAM ou entradas de recursos que usam graus explicitamente. viewport/units.ts contém auxiliares de conversão para milímetros e polegadas exibidos. Converta nos limites de entrada/saída para que o snap, a geometria e o movimento do percurso mantenham um sistema de unidades consistente.
A câmera 2D mapeia as coordenadas mundiais para pixels CSS; as dimensões da tela de apoio incorporam a proporção de pixels do dispositivo. O redimensionamento atualiza a câmera e o buffer de apoio por meio ResizeObserver. A escala da câmera determina o espaçamento da grade e as tolerâncias de acerto no espaço da tela.
A exibição em polegadas converte exatamente 25.4 mm por polegada e os comprimentos são padronizados para 3 decimais (apps/desktop/src/viewport/units.ts). No editor 2D, cada passo da roda é ampliado por um fator de 1.15, a escala é fixada entre 0.001 e 100,000, e o ajuste à visualização deixa uma margem de 10% (editor2d/camera.ts).
Recursos e ciclo de vida
O componente 2D cancela quadros de animação enfileirados e desconecta seu observador de redimensionamento ao desmontar. O componente 3D libera ouvintes de redimensionamento e visibilidade, controles de órbita e transformação, trabalhadores de malha, agendamento de animação, geometrias, materiais, sprites, malhas de ferramentas e o renderizador WebGL.
Um agendador de quadros reúne invalidações e solicita quadros adicionais enquanto o amortecimento ou a reprodução da câmera precisa deles. Mudanças na visibilidade suspendem o trabalho. Esta é uma política de agendamento, não um orçamento de taxa de quadros garantido para cada modelo e dispositivo.
Mapa do módulo
editor2d/editor2d.tsx: componente controlado, envio de ponteiro, câmera, seleção, histórico e pintura em tela.editor2d/tools/: máquinas de estado de gestos e construção de comandos.editor2d/camera.ts,render.ts, esnap-pipeline.ts: transformações de coordenadas, renderização de entidade, seleção e orquestração de snap.spatial/grid.ts: desenho de índice espacial.view3d/view3d.tsx: composição de cena, controles de câmera, seleção, transformações, estoque e ferramentas.view3d/playback.ts,toolpath-overlays.ts, emodeling.ts: linha do tempo de movimento, dados de sobreposição e conversão de perfil em sólido.view3d/mesh-jobs.tsemesh-worker.ts: construção da geometria de fundo e propriedade do trabalho.
Disponibilidade da ferramenta
ToolId descreve o vocabulário mais amplo da ferramenta; AVAILABLE_TOOLS descreve o subconjunto registrado. Para ferramentas interativas, use startTool(id, lookup, context, text). A pesquisa de seleção consulta entidades candidatas; o contexto fornece a seleção atual e o acesso à entidade; o texto fornece o conteúdo da anotação.
Uma fábrica desaparecida retorna undefined. Lide com isso explicitamente, em vez de apresentar uma ferramenta desabilitada ou não implementada como um modo de edição ativo. Ferramentas que modificam a geometria existente requerem seleção atual e contexto de entidade; invocar uma fábrica sem essas dependências é insuficiente para uma edição útil.
Malha e verificação
Para sólidos com uma contagem de vértices estimada acima de 50,000 e suporte ao trabalhador do navegador, o visualizador enfileira a construção da malha em um trabalhador do módulo. Sólidos menores se engrenam de forma síncrona. A fila mesh lida com conclusão, trabalhos obsoletos, erros de trabalho e limpeza. O limite é uma estimativa usada para agendamento, não um limite de tamanho de modelo documentado.
bun test apps/desktop/src/viewport
bun run --filter @cadcamfun/desktop typecheck Os testes lógicos abrangem auxiliares de renderização, gestos de ferramentas, indexação espacial, reprodução e sobreposições. O comportamento do navegador/WebGL também depende do ambiente gráfico; inspecione a interação real da janela de visualização ao alterar os controles da câmera, o ciclo de vida da cena ou a renderização.
Exemplo de reprodução controlada
Um pai pode possuir controles de transporte sem duplicar a linha do tempo de movimento do visualizador. Este componente aceita um programa CAM já construído e controla o tempo, o estado de reprodução, a velocidade e a predefinição da janela de visualização. Seus caminhos de importação assumem um arquivo diretamente abaixo apps/desktop/src.
import { createSignal } from "solid-js"
import { cam } from "@cadcamfun/core"
import { View3D } from "./viewport/index.ts"
export function ProgramPreview(props: { program: cam.Program }) {
const [seconds, setSeconds] = createSignal(0)
const [playing, setPlaying] = createSignal(false)
return <div style={{ height: "600px" }}>
<button onClick={() => setPlaying(value => !value)}>Play / pause</button>
<button onClick={() => { setSeconds(0); setPlaying(true) }}>Restart</button>
<View3D
program={props.program}
preset="isometric"
playing={playing()}
playbackTime={seconds()}
playbackRate={1}
onPlaybackTimeChange={setSeconds}
stock={{ origin: { x: 0, y: 0, z: -10 }, size: { x: 100, y: 80, z: 10 } }}
/>
</div>
} O construtor de reprodução começa na origem, expande os ciclos em movimentos e calcula as durações a partir da duração da viagem e do avanço. Sua velocidade rápida padrão é 5,000 mm/min e a tolerância padrão de mosaico de arco é 0,1 mm. Estas são suposições prévias, não a aceleração da máquina ou o tempo do controlador medido. Os comandos de espera mantêm os segundos indicados; comentários e entradas somente de orientação não adicionam deslocamento linear.
As cores das ferramentas são atribuídas pela primeira ocorrência de cada identificador de ferramenta e mantidas em seus caminhos. Forneça um mapa de ferramentas/ferramenta padrão para geometria de montagem; um caminho colorido por si só não estabelece as dimensões do cortador ou do suporte usado na verificação.
Edição de receitas e limites atuais de ferramentas
| Operação | Gesto e pré-condições | Comportamento atual |
|---|---|---|
| Desvio | Selecione uma entidade suportada e arraste; Shift escolhe a entidade sob o cursor. | Linhas/polilinhas/retângulos produzem um resultado de polilinha. Implementações de círculo e arco traduzem o centro enquanto mantêm o raio; esta ferramenta não é uma operação geral de deslocamento concêntrico para curvas. |
| Cortar / estender | Selecione primeiro as entidades de origem e limite, ative Cortar e clique no destino. Alt seleciona o modo de extensão. | A implementação procura interseções nas outras entidades selecionadas. Altera linhas e polilinhas; tipos de destino não suportados ou interseções ausentes não produzem edição. |
| Filete / chanfro | Escolha duas linhas que se cruzam. Shift muda para chanfro. | A ferramenta compartilhada utiliza um raio inicial de 5 mm e substitui o par por linhas recortadas e uma polilinha de conexão. Não é um filete arbitrário de aresta sólida. |
| Transformar um sólido | Fornecer onTransformCommit, selecione uma malha e ative traduzir/girar/escalar. | O retorno de chamada relata o índice sólido e os valores de transformação. Os gizmos de seleção e transformação são desativados no modo de quatro visualizações. |
Esses detalhes vêm das implementações de gestos, e não dos rótulos das paletas. Inspecione a visualização antes de confirmar e use Desfazer se o resultado for diferente da geometria pretendida. Uma ferramenta que não retorna nenhum comando pode significar que seus pré-requisitos geométricos não foram satisfeitos, e não que o editor perdeu o evento de ponteiro.
Falhas de renderização e geração de malha
A fila de malha em segundo plano admite no máximo 128 trabalhos pendentes por padrão, executa um de cada vez e tem um tempo limite padrão de 15 segundos por trabalho. A redefinição de uma cena encerra o trabalhador e limpa o trabalho na fila; respostas obsoletas são ignoradas. Respostas inválidas do trabalhador, erros de decodificação de mensagens, tempos limite e falhas de capacidade da fila relatam erros por meio do retorno de chamada da fila.
| Sintoma | Ação |
|---|---|
| Tela vazia sem geometria | Dê ao pai um tamanho diferente de zero, verifique a visibilidade da entidade/camada e ajuste a visualização. |
| Nada pode ser selecionado | Verifique os bloqueios de entidade/camada em 2D; verifique o modo de quatro visualizações e transforme o estado em 3D. |
| Tempo limite da malha ou fila cheia | Reduza a complexidade da cena ou o número de sólidos enviados simultaneamente e inspecione o erro do trabalhador. Um lote com falha é limpo em vez de instalado parcialmente como um trabalho concluído. |
| O tempo de reprodução parece errado | Verifique a alimentação do programa, os movimentos de permanência, as suposições de velocidade rápida e se um programa alterado redefine o tempo pai. |
| WebGL não está disponível | Use um ambiente gráfico compatível e inspecione o estado do renderizador indisponível do componente; os testes lógicos não podem provar a disponibilidade da GPU. |
Testes relevantes incluem editor2d/tools/offset.test.ts, annotation-transform.test.ts, spatial/grid.test.ts, view3d/playback.test.ts, e toolpath-overlays.test.ts. A implementação da fila mesh é view3d/mesh-jobs.ts.
Exibir unidades em detalhes
O editor sempre trabalha em milímetros. Somente o que o usuário lê e digita é convertido, usando os fatores exatos abaixo. A própria unidade de um desenho armazenado permanece mm ou inch; as unidades extras são apenas opções de exibição.
| Unidade | Rótulo | mm por unidade | Decimais padrão | Unidade de programa de código G |
|---|---|---|---|---|
mm | milímetros | 1 | 3 | milímetros |
um | µm | 0.001 | 1 | milímetros |
cm | cm | 10 | 4 | milímetros |
m | m | 1000 | 6 | milímetros |
inch | polegada | 25.4 | 4 | polegada |
thou | porém | 0.0254 | 2 | polegada |
import { formatLength, parseLength, formatAngle, programUnitsOf } from "./units"
formatLength(25.4, "inch") // "1.0000 inch"
formatLength(12.5) // "12.500 mm"
formatLength(0.0254, "thou") // "1.00 thou"
parseLength("2 in", "inch") // 50.8 (a trailing unit word is ignored)
parseLength("abc") // undefined
formatAngle(Math.PI / 2) // "90.0°"
programUnitsOf("thou") // "inch" parseLength remove um sufixo alfabético final (incluindo µ e °) e interpreta o número na unidade de exibição atual. O sufixo não é usado para escolher uma unidade, então digitar 2 mm enquanto a exibição está em polegadas produz 50.8 mm. Retornos de entrada vazios, não numéricos e infinitos undefined, e os editores devem manter o valor anterior nesse caso.
2Câmera D e grade
worldToScreen vira Y para que o mundo +Y aponte para cima na tela.| Constante/função | Valor | Comportamento |
|---|---|---|
ZOOM_STEP | 1.15 | Fator por passo da roda; zoomAt mantém o ponto mundial sob o cursor fixo. |
MIN_SCALE / MAX_SCALE | 0.001 / 100,000 px por mm | A escala está fixada neste intervalo. |
FIT_MARGIN | 0.1 | Fração da janela de visualização mantida como margem por cameraForBounds. |
createCamera() | centro (0, 0), escala 1, 800 × 600 | Câmera inicial antes do primeiro redimensionamento. |
gridStep(scale, major = 10, minPixels = 8) | 1-2-5 escada | A menor etapa que mantém os pontos da grade separados por pelo menos 8 px. |
const camera = createCamera({ x: 0, y: 0 }, 2, 800, 600) // 2 px per mm
worldToScreen(camera, { x: 10, y: 10 }) // { x: 420, y: 280 }
screenToWorld(camera, { x: 420, y: 280 }) // { x: 10, y: 10 }
gridStep(2) // 5 -> 5 mm apart = 10 px
gridStep(0.5) // 20 -> 20 mm apart = 10 px A renderização seleciona entidades contra visibleBounds(camera). O snap também evita a varredura de todo o desenho: uma grade espacial uniforme retorna entidades cujos limites estão dentro da tolerância do snap mais uma margem candidata de 2 mm, e somente essas são passadas para o núcleo findSnap. Isso mantém o ponteiro se movendo rapidamente em desenhos com muitas entidades.
Referência de ajuste
Os tipos de snap são testados em ordem de prioridade. A ordem padrão corresponde ao editor legado: endpoint, midpoint, center, intersection, perpendicular, tangent, nearest, e quadrant. Os pontos finais são os vértices da entidade de origem, não os do seu mosaico.
| Contexto | Significado |
|---|---|
enabled | Chave mestre; false desativa todos os ajustes. |
types | Tipos de snap ativados, prioridade mais alta primeiro. |
tolerance | Raio do snap em milímetros; não depende de zoom. |
gridEnabled, gridSpacing | Ajustar à grade quando nenhum ajuste de objeto for aplicado. |
referencePoint | O ponto de partida. perpendicular e tangent não encontre nada sem ele. |
O pipeline retorna o snap, os IDs das entidades sob o cursor (a mais próxima primeiro, que a ferramenta de seleção consome) e o número de candidatos considerados.
Como a reprodução do percurso é cronometrada
buildPlayback(program, rapidRate = 5000, tolerance = 0.1) converte um programa CAM em segmentos temporizados. A duração de cada movimento é seu comprimento dividido por seu avanço (ou pela taxa rápida para corredeiras), vezes 60, dando segundos. As moradias adicionam seu próprio tempo sem se mover. Comentários, movimentos de orientação e ciclos fixos não são desenhados como segmentos. Os arcos são divididos em acordes cuja sagitta permanece dentro tolerance (entre 2 e 65,536 cordas por arco), e Z é interpolado ao longo do arco para hélices.
const playback = buildPlayback(program) // rapids at 5000 mm/min
playback.duration // total seconds
positionAt(playback, 12.5) // tool position at t = 12.5 s
toolAt(playback, 12.5) // toolId cutting at that time
toolColors(program) // Map toolId -> colour, first use order
// A 10 mm feed move at 600 mm/min lasts 10 / 600 × 60 = 1 s.
// The same 10 mm as a rapid lasts 10 / 5000 × 60 = 0.12 s. segmentIndexAt encontra o segmento de jogo por pesquisa binária, portanto a busca é barata mesmo para programas longos. Procurar além do fim retorna a posição final, e toolAt em seguida, relata a última ferramenta. O tempo de reprodução é uma estimativa visual baseada em feeds programados; ele ignora a aceleração da máquina, então uma máquina real leva mais tempo.
Práticas de viewport
- Converter na borda: armazene e calcule em milímetros e radianos e formate apenas para exibição com
formatLengtheformatAngle. - Nunca reutilize um comprimento analisado depois
parseLengthretornaundefined; mantenha o valor anterior e mostre uma dica de validação. - Ao adicionar uma ferramenta de desenho, registre-a na tabela de fábrica de ferramentas para que a barra de ferramentas, os atalhos e os testes a enderecem pelo mesmo ID.
- Mantenha as consultas dos candidatos instantâneos espaciais. Passando cada entidade para
findSnapem cada movimento do ponteiro derrota o índice. - Trate a duração da reprodução como uma visualização, não como uma cotação de tempo de ciclo.
Teste de sucesso em escala: a grade espacial
O editor 2D tem como alvo 60 fps com 10,000 entidades, portanto, o teste de acerto e a seleção nunca verificam cada entidade por evento de ponteiro. viewport/spatial/grid.ts mantém uma grade uniforme: cada item é registrado em cada célula que sua caixa delimitadora toca, e uma consulta retorna todos os itens cujos limites cruzam a caixa de consulta, na ordem de inserção. O resultado é exato, nunca uma amostra.
| Contexto | Valor | Por que |
|---|---|---|
| Tamanho de célula padrão | 50 unidades mundiais (mm) | Adequado para um desenho com cerca de 1 m de diâmetro |
| Tamanho mínimo da célula | 1e-6 | Protege contra um tamanho zero ou negativo, que faria um loop para sempre |
| Limite de células por item | 4,096 | Itens maiores (uma longa linha na planilha) são rastreados de lado em vez de por célula |
| Método | Comportamento |
|---|---|
build(items) | Reconstruir do zero |
upsert(id, item) | Insira ou substitua um item por id |
remove(id) | Remover; IDs desconhecidos são ignorados |
query(bounds) | IDs cujos limites cruzam a caixa |
As células tocadas pela caixa de consulta tracejada são visitadas; A e a linha longa são retornadas porque seus limites a cruzam, B não.
3Fila de malha D
Os sólidos são mesclados em um Web Worker para que o thread da UI nunca seja bloqueado. MeshWorkerQueue em view3d/mesh-jobs.ts executa um trabalho por vez:
| Regra | Valor | Mensagem sobre falha |
|---|---|---|
| Capacidade (em fila + em execução) | 128 | A fila de malha 3D está cheia. Reduza a complexidade da cena. |
| Tempo limite por trabalho | 15 s | 3Tempo limite da malha D expirou. Reduza a complexidade da cena. |
| Erro do trabalhador | — | A mensagem do trabalhador ou "O trabalhador mesh parou inesperadamente". |
| Resposta indecodificável | — | O trabalhador mesh não conseguiu decodificar sua resposta. |
| Geometria ruim | as posições devem ser Float32Array, índices Uint32Array | O trabalhador da malha retornou uma geometria inválida. |
Qualquer falha encerra o trabalhador e limpa toda a fila, de modo que o trabalho de cena obsoleto nunca chega após uma edição mais recente; o próximo envio inicia um novo trabalhador. As respostas são correspondidas por ID do trabalho, portanto, uma resposta tardia de um trabalhador demitido é ignorada.
2Implementações de ferramentas D
| Arquivo | Ferramentas |
|---|---|
tools/two-point.ts | linha, retângulo, círculo por diâmetro, elipse |
tools/chained.ts | polilinha, arco de três pontos |
tools/fillet-chamfer.ts | arredondar ou chanfrar o canto entre duas linhas |
tools/offset.ts | deslocar uma polilinha, retângulo, círculo ou arco por uma distância |
tools/trim.ts | aparar e estender |
tools/select.ts | clique, marque e adicione/remova seleção |
tools/annotation-transform.ts | mover e transformar anotações |
Cada ferramenta é uma pequena máquina de estado com onPointerDown, onPointerMove e onPointerUp, criado por uma fábrica em tools/index.ts, um por entrada de paleta. As posições do ponteiro passam snap-pipeline.ts antes que uma ferramenta os veja.