Aller au contenu
CADCAMFUN
Docs

Documentation

Fenêtre d'affichage

Les outils de dessin sur toile et le rendu Three.js partagent la géométrie de base tout en gardant l'état d'édition et de lecture explicite.

Traduit automatiquement de l'anglais. Voir l'original en anglais

Composants de la fenêtre

apps/desktop/src/viewport/index.ts exportations Editor2D, View3D, leurs types d'accessoires, les identifiants d'outils disponibles et solidsFromProfiles. Les deux composants remplissent leur parent : fournissent un conteneur avec une largeur et une hauteur non nulles. Les entités CAO de base et les programmes CAM constituent le modèle de données partagé.

L'éditeur 2D effectue le rendu sur Canvas 2D et conserve son propre historique de sélection, de caméra et de commandes. La visionneuse 3D utilise Three.js, des contrôles d'orbite et de transformation, des tâches de maillage asynchrone et la lecture de programmes. Le rendu d'un chemin ou d'un solide ne nécessite pas de l'enregistrer ou de vérifier une opération de fabrication.

Contrat d'intégration

Editor2DProps nécessite drawing, onChange, et selectedTool. Réinjectez les dessins émis dans l’accessoire. Le composant reconnaît ses propres objets document émis ; le remplacement du document en externe charge le nouveau dessin et réinitialise l'état de l'éditeur.

Éditeur 2D contrôlé
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()} />

La sélection exclut les entités verrouillées et les entités sur les calques verrouillés. Les entités invisibles et les couches cachées sont exclues de l'index spatial rendu. Les nouvelles entités reçoivent des identifiants uniques au document et sont affectées à une couche visible et déverrouillée lorsqu'elle est disponible.

Outils et gestes de dessin

Le registre d'outils comporte des usines pour la sélection, la ligne, le rectangle, le cercle, l'ellipse, la polyligne, l'arc, le texte, la dimension, le déplacement, la rotation, la mise à l'échelle, la mise en miroir, le décalage, l'ajustement et le congé. AVAILABLE_TOOLS est dérivé de ces usines enregistrées. startTool reconnaît en outre chamfer via l'usine d'outils de congé, mais le chanfrein n'est pas annoncé dans ce tableau. Les consommateurs doivent utiliser le registre lui-même pour décider quels outils activer.

  • Zooms à molette ou par pincement ; Faites glisser l’espace, faites glisser le milieu et faites glisser le panoramique vers la droite.
  • F correspond au dessin indexé. Supprimer ou Retour arrière supprime la sélection déverrouillée.
  • Cmd/Ctrl+Z annule; Cmd/Ctrl+Shift+Z ou Cmd/Ctrl+Y refait.
  • Enter valide une polyligne. L'échappement est transmis à l'outil actif pour annuler son geste en cours.
  • Avec le texte actif, tapez des caractères ou Retour arrière avant le placement ; le texte initial est Text.

Les positions du pointeur sont converties en coordonnées mondiales avant l'envoi de l'outil. La capture combine l'index spatial, les candidats géométriques et une grille dépendante de la caméra ; la tolérance de réussite de sélection correspond à huit pixels d'écran. Les machines-outils produisent des commandes et des aperçus plutôt que d'écrire des fichiers ou d'appeler l'API.

3Rendu et lecture D

View3D accepte les dessins, les solides, l'extrusion de profilés en option, un cam.Program, les dimensions du brut et les définitions d'outils. Il prend en charge les préréglages de perspective, haut, bas, avant, arrière, gauche, droite, isométrique et à quatre vues. Les modes d'affichage sont ombrés, ombrés avec bords, filaire et rayons X. L'éclairage, les propriétés des matériaux, les sections de découpage, la grille, les axes et l'origine sont configurables via les accessoires.

Contrôlez la lecture avec playing, playbackTime en quelques secondes, playbackRate, et onPlaybackTimeChange. La lecture étend les cycles de forage, mosaïque les mouvements circulaires/hélicoïdaux, préserve le temps de séjour et dessine distinctement les mouvements rapides. Cartes d'outils et géométrie de coupe, de tige et de support par défaut en option ; la géométrie supposée est visuellement distinguée.

Les rappels de sélection rapportent un index solide. Les contrôles de transformation émettent la position, la rotation et l'échelle onTransformCommit; les appelants décident comment conserver cette transformation. Les superpositions de parcours d'outil peuvent afficher des points et des étiquettes, des filtres de type de point, des centres d'arc, des rayons d'arc et la transparence du brut.

La lecture est une représentation visuelle

Le spectateur anime le programme fourni et dessine le stock et les outils. Il n’effectue pas d’enlèvement de matière. Les contrôles de collision et d'enveloppe machine font partie des modules de vérification CAM ; le visionnage d'un programme ne constitue pas une approbation de la machine.

Coordonnées et unités

Les coordonnées du dessin de base et les tailles de stock utilisent des millimètres. Les angles de dessin et les composants de rotation Three.js utilisent des radians ; n'appliquez pas cette convention aux valeurs de l'axe rotatif CAM ou aux entrées de fonctionnalités qui utilisent explicitement des degrés. viewport/units.ts contient des aides à la conversion pour les millimètres et les pouces affichés. Convertissez aux limites d'entrée/sortie afin que l'accrochage, la géométrie et le mouvement du parcours d'outil conservent un système d'unités cohérent.

La caméra 2D mappe les coordonnées du monde en pixels CSS ; Les dimensions de la toile de support intègrent le rapport de pixels de l'appareil. Le redimensionnement met à jour la caméra et le tampon de sauvegarde via ResizeObserver. L'échelle de la caméra détermine l'espacement de la grille et les tolérances d'impact sur l'espace de l'écran.

L'affichage en pouces est converti avec exactement 25,4 mm par pouce et les longueurs sont par défaut de 3 décimales (apps/desktop/src/viewport/units.ts). Dans l'éditeur 2D, chaque pas de roue effectue un zoom d'un facteur de 1.15, l'échelle est serrée entre 0.001 et 100,000, et l'ajustement à la vue laisse une marge de 10 % (editor2d/camera.ts).

Ressources et cycle de vie

Le composant 2D annule les images d'animation en file d'attente et déconnecte son observateur de redimensionnement lors du démontage. Le composant 3D propose des écouteurs de redimensionnement et de visibilité, des contrôles d'orbite et de transformation, des travailleurs de maillage, la planification d'animations, des géométries, des matériaux, des sprites, des maillages d'outils et le moteur de rendu WebGL.

Un planificateur d'images regroupe les invalidations et demande d'autres images pendant que l'amortissement ou la lecture de la caméra en a besoin. Les changements de visibilité suspendent les travaux. Il s'agit d'une politique de planification et non d'un budget de fréquence d'images garanti pour chaque modèle et appareil.

Carte des modules

  • editor2d/editor2d.tsx: composant contrôlé, envoi de pointeur, caméra, sélection, historique et peinture sur toile.
  • editor2d/tools/: machines à états gestuelles et construction de commandes.
  • editor2d/camera.ts, render.ts, et snap-pipeline.ts: transformations de coordonnées, rendu d'entités, sélection et orchestration instantanée.
  • spatial/grid.ts: dessin d'un index spatial.
  • view3d/view3d.tsx: composition de scène, commandes de caméra, sélection, transformations, stock et outils.
  • view3d/playback.ts, toolpath-overlays.ts, et modeling.ts: chronologie du mouvement, données de superposition et conversion profil-solide.
  • view3d/mesh-jobs.ts et mesh-worker.ts: construction de la géométrie de fond et appropriation du travail.

Disponibilité des outils

ToolId décrit le vocabulaire plus large des outils ; AVAILABLE_TOOLS décrit le sous-ensemble enregistré. Pour les outils interactifs, utilisez startTool(id, lookup, context, text). La recherche de sélection interroge les entités candidates ; le contexte fournit la sélection actuelle et l'accès à l'entité ; text fournit le contenu de l’annotation.

Une usine disparue revient undefined. Gérez cela explicitement plutôt que de présenter un outil désactivé ou non implémenté comme mode d'édition actif. Les outils qui modifient la géométrie existante nécessitent une sélection et un contexte d'entité actuels ; invoquer une usine sans ces dépendances est insuffisant pour une modification utile.

Maillage et vérification

Pour les solides avec un nombre de sommets estimé supérieur à 50,000 et la prise en charge du navigateur Worker, la visionneuse met en file d'attente la construction du maillage dans un module Worker. Les solides plus petits se maillent de manière synchrone. La file d'attente maillée gère l'achèvement, les tâches obsolètes, les erreurs de travail et le nettoyage. Le seuil est une estimation utilisée pour la planification, et non une limite documentée de taille de modèle.

Vérifications logiques de la fenêtre d'affichage, à partir de la racine du référentiel
bun test apps/desktop/src/viewport
bun run --filter @cadcamfun/desktop typecheck

Les tests logiques couvrent les aides au rendu, les gestes des outils, l'indexation spatiale, la lecture et les superpositions. Le comportement du navigateur/WebGL dépend également de l'environnement graphique ; inspectez l’interaction réelle de la fenêtre lors de la modification des commandes de la caméra, du cycle de vie de la scène ou du rendu.

Exemple de lecture contrôlée

Un parent peut posséder des commandes de transport sans dupliquer la chronologie des mouvements du spectateur. Ce composant accepte un programme CAM déjà construit et contrôle le temps, l'état de lecture, la vitesse et le préréglage de la fenêtre d'affichage. Ses chemins d'importation supposent un fichier directement sous apps/desktop/src.

Aperçu du programme avec commandes de transport externes
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>
}

Le générateur de lecture commence à l'origine, développe les cycles en mouvements et calcule les durées à partir de la longueur du trajet et de l'avance. Sa vitesse rapide par défaut est de 5,000 mm/min et la tolérance de pavage d'arc par défaut est de 0,1 mm. Il s’agit d’hypothèses préliminaires, et non d’accélérations mesurées de la machine ou de synchronisation du contrôleur. Les commandes Dwell conservent leurs secondes indiquées ; les commentaires et les entrées d'orientation uniquement n'ajoutent pas de déplacement linéaire.

Les couleurs des outils sont attribuées par la première occurrence de chaque identifiant d'outil et conservées sur ses chemins. Fournir une carte d'outils/un outil par défaut pour la géométrie de l'assemblage ; un tracé coloré à lui seul n'établit pas les dimensions du couteau ou du support utilisées par vérification.

Modification des recettes et limites actuelles des outils

OpérationGeste et conditions préalablesComportement actuel
CompenserSélectionnez une entité prise en charge, puis faites-la glisser ; Shift choisit à la place l'entité sous le curseur.Les lignes/polylignes/rectangles produisent un résultat polyligne. Les implémentations de cercle et d'arc traduisent le centre tout en conservant le rayon ; cet outil n'est pas une opération générale de décalage concentrique pour les courbes.
Couper/étendreSélectionnez d'abord les entités source et frontière, activez Trim et cliquez sur la cible. Alt sélectionne le mode étendu.L’implémentation recherche les intersections dans les autres entités sélectionnées. Il change les lignes et les polylignes ; Les types de cibles non pris en charge ou les intersections manquantes ne produisent aucune modification.
Congé / chanfreinChoisissez deux lignes qui se croisent. Shift passe au chanfrein.L'outil partagé utilise un rayon initial de 5 mm et remplace la paire par des lignes coupées et une polyligne de connexion. Il ne s'agit pas d'un congé à bord solide arbitraire.
Transformer un solideFournir onTransformCommit, sélectionnez un maillage, puis activez translation/rotation/scale.Le rappel rapporte les valeurs d'index solide et de transformation. Les gadgets de sélection et de transformation sont désactivés en mode quatre vues.

Ces détails proviennent des implémentations de gestes plutôt que de leurs étiquettes de palette. Inspectez l’aperçu avant de valider et utilisez Annuler si le résultat diffère de la géométrie prévue. Un outil ne renvoyant aucune commande peut signifier que ses prérequis géométriques n'ont pas été satisfaits, et non que l'éditeur a perdu l'événement de pointeur.

Échecs de rendu et de maillage

La file d'attente maillée en arrière-plan admet par défaut au maximum 128 tâches en attente, s'exécute une par une et a un délai d'expiration par défaut de 15 secondes par tâche. La réinitialisation d'une scène met fin au travailleur et efface le travail en file d'attente ; les réponses obsolètes sont ignorées. Les réponses de travailleur non valides, les erreurs de décodage de message, les délais d'attente et les échecs de capacité de file d'attente signalent les erreurs via le rappel de file d'attente.

SymptômeAction
Toile vide sans géométrieDonnez au parent une taille non nulle, vérifiez la visibilité de l'entité/couche et ajustez la vue.
Rien ne peut être sélectionnéVérifiez les verrous d'entité/couche dans 2D ; vérifiez le mode à quatre vues et l'état de transformation en 3D.
Délai d'expiration du maillage ou file d'attente pleineRéduisez la complexité de la scène ou le nombre de solides soumis simultanément et inspectez l’erreur du travailleur. Un lot ayant échoué est effacé plutôt que partiellement installé en tant que travail terminé.
La durée de lecture semble incorrecteVérifiez les flux de programme, les mouvements en attente, les hypothèses de vitesse rapide et si un programme modifié a réinitialisé l'heure parent.
WebGL n'est pas disponibleUtilisez un environnement graphique pris en charge et inspectez l'état du moteur de rendu indisponible du composant ; les tests logiques ne peuvent pas prouver la disponibilité du GPU.

Les tests pertinents incluent editor2d/tools/offset.test.ts, annotation-transform.test.ts, spatial/grid.test.ts, view3d/playback.test.ts, et toolpath-overlays.test.ts. L'implémentation de la file d'attente maillée est view3d/mesh-jobs.ts.

Présentoirs en détail

L'éditeur travaille toujours en millimètres. Seul ce que l'utilisateur lit et saisit est converti, en utilisant les facteurs exacts ci-dessous. L'unité propre d'un dessin stocké reste mm ou inch; les unités supplémentaires sont uniquement des choix d'affichage.

UnitéÉtiquettemm par unitéDécimales par défautUnité de programme G-code
mmmm13mm
umµm0.0011mm
cmcm104mm
mm10006mm
inchpouce25.44pouce
thoutu0.02542pouce
Conversion et analyse des longueurs (apps/desktop/src/viewport/units.ts)
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 supprime un suffixe alphabétique final (y compris µ et °) et interprète le numéro dans l’unité d’affichage actuelle. Le suffixe n'est pas utilisé pour choisir une unité, donc en tapant 2 mm tandis que l'affichage est en pouces donne 50.8 mm. Retours d'entrée vides, non numériques et infinis undefined, et les éditeurs doivent conserver la valeur précédente dans ce cas.

2Caméra D et grille

monde (mm, +Y vers le haut)écran (px, +Y vers le bas) centre+X+Y (largeur/2, hauteur/2)+x+y →
La caméra de l'éditeur 2D stocke le point du monde au centre de la fenêtre et une échelle en pixels par millimètre. worldToScreen retourne Y pour que le monde +Y pointe vers le haut à l'écran.
Constante / fonctionValeurComportement
ZOOM_STEP1.15Facteur par pas de roue ; zoomAt maintient le point du monde sous le curseur fixe.
MIN_SCALE / MAX_SCALE0.001 / 100,000 px par mmL'échelle est limitée à cette plage.
FIT_MARGIN0.1Fraction de la fenêtre conservée comme marge par cameraForBounds.
createCamera()centre (0, 0), échelle 1, 800 × 600Caméra initiale avant le premier redimensionnement.
gridStep(scale, major = 10, minPixels = 8)1-2-5 échellePlus petite étape qui sépare les points de la grille d'au moins 8 px.
Cartographie entre le monde et l'écran
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

Le rendu élimine les entités par rapport visibleBounds(camera). L'accrochage évite également de numériser l'intégralité du dessin : une grille spatiale uniforme renvoie les entités dont les limites se situent dans la tolérance d'accrochage plus une marge candidate de 2 mm, et seules celles-ci sont transmises au noyau. findSnap. Cela permet au pointeur de se déplacer rapidement dans les dessins comportant de nombreuses entités.

Référence d'accrochage

Les types d’accrochage sont essayés par ordre de priorité. L'ordre par défaut correspond à l'ancien éditeur : endpoint, midpoint, center, intersection, perpendicular, tangent, nearest, et quadrant. Les points finaux sont les sommets de l'entité source, pas ses pavages.

ParamètreSignification
enabledInterrupteur principal ; false désactive tout accrochage.
typesTypes d'accrochage activés, priorité la plus élevée en premier.
toleranceRayon d'accrochage en millimètres ; cela ne dépend pas du zoom.
gridEnabled, gridSpacingAccrochez-vous à la grille lorsqu'aucun accrochage aux objets ne s'applique.
referencePointLe point dont on tire. perpendicular et tangent sans cela, je ne trouve rien.

Le pipeline renvoie le snap, les ID des entités sous le curseur (le plus proche en premier, que l'outil de sélection consomme) et le nombre de candidats pris en compte.

Comment la lecture du parcours d'outil est chronométrée

buildPlayback(program, rapidRate = 5000, tolerance = 0.1) convertit un programme CAM en segments chronométrés. La durée de chaque mouvement est sa longueur divisée par son avance (ou par la vitesse rapide pour les rapides), fois 60, donnant les secondes. Les logements ajoutent leur propre temps sans bouger. Les commentaires, les mouvements d'orientation et les cycles prédéfinis ne sont pas dessinés sous forme de segments. Les arcs sont divisés en accords dont la sagitta reste à l'intérieur tolerance (entre 2 et 65,536 cordes par arc), et Z est interpolé le long de l'arc pour les hélices.
Rechercher et colorier un aperçu
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.
Aperçu de la lecture Faites glisser vers l'orbite · faites défiler pour zoomer · faites glisser vers la droite pour effectuer un panoramique
Le même programme de poche que sur la page CAM, rejoué dans la première couleur de l'outil (388bdf22). Sur le bureau, chaque outil supplémentaire obtient la couleur suivante dans la palette : 5597316c879e, 9f15, #e#f#, #facc#, etc.
segmentIndexAt trouve le segment en cours de lecture par recherche binaire, donc la recherche est bon marché, même pour les programmes longs. Rechercher au-delà de la fin renvoie la position finale, et toolAt puis signale le dernier outil. La durée de lecture est une estimation visuelle basée sur des flux programmés ; il ignore l'accélération de la machine, donc une vraie machine prend plus de temps.

Pratiques de fenêtre

  • Convertir en périphérie : stocker et calculer en millimètres et en radians, et formater uniquement pour l'affichage avec formatLength et formatAngle.
  • Ne réutilisez jamais une longueur analysée après parseLength retours undefined; conserver la valeur précédente et afficher un indice de validation.
  • Lors de l'ajout d'un outil de dessin, enregistrez-le dans la table de la fabrique d'outils afin que la barre d'outils, les raccourcis et les tests l'adressent par le même ID.
  • Gardez les requêtes des candidats instantanés spatiales. Passer chaque entité à findSnap à chaque mouvement du pointeur, l'index est vaincu.
  • Traitez la durée de lecture comme un aperçu et non comme une citation de durée de cycle.

Hit-testing à grande échelle : la grille spatiale

L'éditeur 2D cible 60 images par seconde avec 10,000 entités. Par conséquent, les tests d'impact et l'élimination n'analysent jamais chaque entité par événement de pointeur. viewport/spatial/grid.ts conserve une grille uniforme : chaque élément est enregistré dans chaque cellule touchée par son cadre de sélection, et une requête renvoie tous les éléments dont les limites coupent le cadre de requête, dans l'ordre d'insertion. Le résultat est exact, jamais un échantillon.

ParamètreValeurPourquoi
Taille de cellule par défaut50 unités mondiales (mm)Convient à un dessin d'environ 1 m de diamètre
Taille minimale des cellules1e-6Protège contre une taille nulle ou négative, qui bouclerait pour toujours
Limite de cellules par élément4,096Les éléments plus gros (une longue ligne sur la feuille) sont suivis séparément plutôt que par cellule
MéthodeComportement
build(items)Reconstruire à partir de zéro
upsert(id, item)Insérer ou remplacer un élément par identifiant
remove(id)Retirer; les identifiants inconnus sont ignorés
query(bounds)Identifiants dont les limites coupent la boîte
boîte de requêteentité ABlongue file

Les cellules touchées par la zone de requête en pointillés sont visitées ; A et la longue ligne sont renvoyés parce que leurs limites le coupent, B ne l'est pas.

3File d'attente de maillage D

Les solides sont maillés dans un Web Worker afin que le thread de l'interface utilisateur ne se bloque jamais. MeshWorkerQueue dans view3d/mesh-jobs.ts exécute une tâche à la fois :

RègleValeurMessage en cas d'échec
Capacité (en file d'attente + en cours d'exécution)128La file d'attente du maillage 3D est pleine. Réduisez la complexité de la scène.
Délai d'expiration par tâche15 s3Le délai de maillage D a expiré. Réduisez la complexité de la scène.
Erreur du travailleur—Le message du travailleur, ou "Le travailleur du maillage s'est arrêté de manière inattendue."
Réponse indécodable—Le mailleur n'a pas pu décoder sa réponse.
Mauvaise géométrieles postes doivent être Float32Array, les indices Uint32ArrayLe mailleur a renvoyé une géométrie non valide.

Tout échec met fin au travail de travail et efface toute la file d'attente, de sorte que le travail de scène obsolète n'arrive jamais après une modification plus récente ; la soumission suivante démarre un nouveau travailleur. Les réponses correspondent à l'ID de travail, donc une réponse tardive d'un travailleur terminé est ignorée.

2Implémentations d'outils D

DéposerOutils
tools/two-point.tsligne, rectangle, cercle par diamètre, ellipse
tools/chained.tspolyligne, arc à trois points
tools/fillet-chamfer.tsarrondir ou biseauter le coin entre deux lignes
tools/offset.tsdécaler une polyligne, un rectangle, un cercle ou un arc d'une distance
tools/trim.tscouper et étendre
tools/select.tscliquer, encadrer et ajouter/supprimer une sélection
tools/annotation-transform.tsdéplacer et transformer des annotations

Chaque outil est une petite machine à états avec onPointerDown, onPointerMove et onPointerUp, créé par une usine à tools/index.ts, un par entrée de palette. Les positions du pointeur passent snap-pipeline.ts avant qu'un outil ne les voie.