Vai al contenuto
CADCAMFUN
Documentazione

Documentazione

Kernel B-rep esatto

Rappresentazione esatta dei confini: geometria analitica e NURBS, booleani, raccordi, riconoscimento dei fori, proprietà di massa, validazione, tassellatura e STEP.

Tradotto automaticamente dall'inglese. Vedi l'originale in inglese

Cos'è il kernel B-rep

Il nocciolo esatto in packages/core/src/cad/brep (24 file sorgente, circa 8 660 righe, più test) rappresenta i solidi in base al loro confine esatto: superfici analitiche e NURBS, tagliate da cicli di bordi esatti. Tutto è costituito da dati semplici e funzioni pure, quindi un B-rep viene serializzato su JSON, attraversa il confine del lavoratore e si differenzia invariato nella cronologia del progetto. Booleani, raccordi e smussi, riconoscimento dei fori, proprietà di massa, convalida, tassellatura a tenuta stagna e scambio STEP funzionano tutti su questa struttura.

Piastra esatta dopo la sottrazione e il raccordo Trascina per orbitare · scorri per ingrandire · trascina con il tasto destro per eseguire la panoramica
A 60 × 40 × 15 box minus a Ø12 cylinder (booleanBrep), then the four vertical edges filleted R4 (blendBrep). Mesh from brepToMesh at chordTol 0.05. 18 vertices, 27 edges, 11 faces; exact volume 34 097.522 mm³.

Tabelle topologiche

A Brep è un insieme di tabelle indice. Le entità si riferiscono tra loro tramite indice, mai tramite riferimento a oggetto.

EntitàTieneControparte STEP
Verticepunto, tolleranzaVERTEX_POINT
Bordoexact curve, [t0, t1] with t0 < t1, v0 = C(t0), v1 = C(t1), toleranceEDGE_CURVE
Coedgeun uso di un bordo da parte di un ciclo: indice del bordo, invertito, curva p opzionale nella faccia (u, v)BORDO_ORIENTATO + PCURVA
Ciclo continuociclo chiuso dei bordi; materiale a sinistra visto dall'esterno (esterno CCW, fori CW)EDGE_LOOP
Visoregione di una superficie; invertito significa che la normale esterna è −(S_u × S_v)ADVANCED_FACE
Conchigliainsieme di facce connesso; un guscio chiuso delimita un volumeCLOSED_SHELL

Seams (an edge used twice by the same face, such as the generator line of a full cylinder) and poles (a loop through a degenerate point, such as a cone apex) need no special entities. That is why the exact sphere has 2 vertices, 1 edge and 1 face, and the torus 1 vertex, 2 edges and 1 face.

Conteggi delle primitive: output reale
makeBox(60, 40, 15)    {"V":8,"E":12,"F":6,"S":1,"surfaces":["plane"]}
makeSphere(10)         {"V":2,"E":1,"F":1,"S":1,"surfaces":["sphere"]}
makeTorus(20, 5)       {"V":1,"E":2,"F":1,"S":1,"surfaces":["torus"]}
makeCone(10, 4, 20)    {"V":2,"E":3,"F":3,"S":1,"surfaces":["cone","plane"]}

Curve e superfici

I tipi analitici utilizzano le parametrizzazioni STEP (ISO 10303-42), quindi i volti letti e scritti in STEP mantengono i propri parametri.

TipoParametrizzazione
lineaC(t) = O + t·d, d unità, t lunghezza dell'arco
cerchioC(t) = O + r(cos t·x + sin t·y)
ellisseC(t) = O + a cos t·x + b sin t·y
aereoS(u,v) = O + u·x + v·y
cilindroS(u,v) = O + r(cos u·x + sin u·y) + v·z
conoS(u,v) = O + (R + v tan α)(cos u·x + sin u·y) + v·z
sferaS(u,v) = O + r cos v(cos u·x + sin u·y) + r sin v·z
toroS(u,v) = O + (R + r cos v)(cos u·x + sin u·y) + r sin v·z
rivoluzioneS(u,v) = rotate(C(v), axis, u)
estrusioneS(u,v) = C(u) + v·d
nurbscurva o superficie razionale B-spline (algoritmi Piegl e Tiller in nurbs.ts)
Primitive esatte, tassellate Trascina per orbitare · scorri per ingrandire · trascina con il tasto destro per eseguire la panoramica
makeBox(10,10,10), makeCylinder(5,10), makeCone(5,2,10) and makeSphere(5), each tessellated by brepToMesh at chordTol 0.2 (12, 430, 122 and 1810 triangles) and placed side by side.
Toro R20 r5 Trascina per orbitare · scorri per ingrandire · trascina con il tasto destro per eseguire la panoramica
makeTorus(20, 5): una singola faccia toroidale con una cucitura e senza altri bordi, tassellata a cordaTol 1 e 30°. Il volume esatto 2π²Rr² = 9 869.604 mm³ è ciò che massProperties restituisce.

Booleani esatti

  1. Intersecare. Bordi di ciascun solido contro le facce dell'altro (punti esatti di Newton), bordi che giacciono sulle superfici dell'altro solido e curve di intersezione di ogni coppia di facce non coincidenti, rifinite su entrambe le superfici e riconosciute come linee e cerchi, altrimenti adattate come B-spline cubiche all'interno della tolleranza di adattamento.
  2. Impronta. Ogni punto di intersezione diventa un vertice in un registro per entrambi i solidi, i bordi vengono divisi lì e ciascuna faccia viene tagliata dalle curve su di essa attraverso una disposizione planare nel suo dominio (u, v).
  3. Classificare. Un punto all'interno di ciascun frammento si trova contro l'altro solido: dentro, fuori o sopra con lo stesso orientamento o opposto.
  4. Cucire. I frammenti vengono mantenuti secondo le regole dell'operazione, i pezzi coincidenti diventano un bordo, i vicini complanari si uniscono e il risultato viene convalidato. Un risultato che non è un solido collettore chiuso lancia BooleanError; non viene mai restituito.
boolean.ts
export const booleanBrep: (A: Brep, B: Brep, op: BooleanOp, options?: BooleanOptions) => BooleanResult
export interface BooleanOptions {
  tol?: number          // coincidence, default 1e-8 × model size, at least 1e-7 mm
  fitTol?: number       // fitted intersection curves, default 1e-6 × size, at least 1e-6 mm
  seedAngleDeg?: number // normal turn per seed-mesh triangle, default 10
  debug?: (stage: string, data: unknown) => void
}
export interface BooleanResult {
  brep: Brep; warnings: string[]
  stats: { intersectionCurves: number; splitPoints: number; fragments: number; keptFaces: number }
}
Scatola meno cilindro: output reale
import { brep } from "@cadcamfun/core"
const { makeBox, makeCylinder, frame, booleanBrep, validateBrep, massProperties } = brep

const box = makeBox(60, 40, 15)
const hole = makeCylinder(6, 25, frame({ x: 30, y: 20, z: -5 }))
const r = booleanBrep(box, hole, "subtract")          // 141 ms
r.stats     // {"intersectionCurves":2,"splitPoints":12,"fragments":13,"keptFaces":7}
r.warnings  // []
validateBrep(r.brep)
// {"valid":true,"manifoldSolid":true,"genus":1,"volume":34303.53996706151,"issues":[]}
massProperties(r.brep).volume   // 34303.53996706151  = 60·40·15 − π·6²·15 exactly

Proprietà di massa

Volume, area, baricentro e tensore d'inerzia (densità unitaria, attorno al baricentro, riga maggiore) derivano dal teorema della divergenza sulle facce di confine. Le facce planari sono integrate esattamente dal teorema di Green lungo le curve esatte dei bordi; le facce curve sono integrate su una tassellatura a fasi parametriche della superficie esatta.

CorpomassPropertiesForma chiusa
scatola − Ø12 foro, volume34303.5399670615134303.539967061515
stesso, zona8139.2920065876848139.292006587698
stesso, baricentro(30.000, 20.000, 7.500)(30, 20, 7.5)
sfera r10, volume4188.7902047863794188.790204786391
toro 20/5, volume9869.604401094759869.604401089358
piatto filettato, volume34097.5222039230234097.522203923065

The filleted-plate closed form is the subtracted plate minus four corner slivers of (r² − πr²/4)·h = (16 − 4π)·15 each.

Raccordi, smussi e riconoscimento fori

Firme
export const blendCandidates: (b: Brep, minAngleDegrees?: number /* 0.5 */) => BlendCandidate[]
export const selectBlendEdges: (edges: ReadonlyArray<BlendCandidate>, s?: BlendSelector) => BlendCandidate[]
// BlendSelector: parallel?: "x"|"y"|"z", within?: box, kind?: "convex"|"concave"|"both" (default convex), minLength?, curved?
export const blendBrep: (b: Brep, edges: ReadonlyArray<BlendCandidate>, size: number,
  style?: "fillet" | "chamfer", options?: BlendOptions) => BlendResult
// BlendResult: brep, blended, vertices (rolling-ball corners), rejected (edge ids), ...
export const recognizeHoles: (b: Brep, options?: HoleRecognitionOptions) => ReadonlyArray<RecognizedHole>

Sul corpo scatola − cilindro c'erano 14 candidati blend; selectBlendEdges(c, { parallel: "z" }) ho scelto i 4 bordi esterni verticali e blendBrep(b, sel, 4) compilato tutti i 4 senza rifiutare nessuno in 94 ms. Il buco si leggeva solo dai volti:

awareHoles: output reale
[{"entry":{"x":30,"y":20,"z":15},"direction":{"x":0,"y":0,"z":-1},"depth":15,"diameter":12,
  "form":"simple","bottom":"through",
  "segments":[{"kind":"cylinder","start":0,"end":15,"diameterStart":12,"diameterEnd":12,"faces":[6]}]}]

Le forme sono simple, counterbore e countersink; i fondi sono through, flat e drill-point. Il riconoscimento legge i volti, non la cronologia, quindi un'importazione STEP, un risultato booleano e una parte parametrica vengono riconosciuti allo stesso modo.

Tassellatura a tenuta stagna

Ogni bordo viene campionato una volta sulla sua curva esatta e ogni faccia che lo utilizza condivide questi campioni, quindi la rete saldata non presenta crepe. Le facce vengono triangolate da Delaunay vincolato nel loro dominio (u, v).

OpzionePredefinitoSenso
chordTol1/2000 della diagonale del modello, fissato a [0.001, 0.05] mmdistanza massima tra mesh e superficie esatta
angleTolDeg15virata normale massima attraverso un triangolo (0 disabilita)
maxEdge0 (nessuno)target di lunghezza del bordo
maxPointsPerFace200 000tappo di sicurezza
paramStep—modalità di integrazione utilizzata da massProperties

Per il piatto filettato defaultChordTol ha restituito 0.0368 mm e tessellateBrep ha prodotto 652 triangoli più mesh per faccia, polilinee di bordo e avvisi.

Scambio PASSO

writeStepBreps scrive un file AP214 (AUTOMOTIVE_DESIGN) in millimetri e radianti, un ADVANCED_BREP_SHAPE_REPRESENTATION per parte. readStepBreps legge la geometria e la topologia AP203, AP214 e AP242, inclusi gli assiemi con le relative trasformazioni e nomi di prodotto. Vengono segnalate entità sconosciute warnings e i loro volti saltarono; nulla è indovinato.
writeStepBreps([{ name: "plate", brep }]) — first lines of the real 358-line file
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('CADCAMFUN exact B-rep'),'2;1');
FILE_NAME('plate','2026-10-15T04:49:21',(''),(''),'CADCAMFUN B-rep kernel','CADCAMFUN','');
FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }'));
ENDSEC;
DATA;
#1=APPLICATION_CONTEXT('core data for automotive mechanical design processes');
#2=APPLICATION_PROTOCOL_DEFINITION('international standard','automotive_design',2000,#1);
#3=PRODUCT_CONTEXT('',#1,'mechanical');
#4=PRODUCT_DEFINITION_CONTEXT('part definition',#1,'design');
#5=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));

La rilettura di quel file ha dato una parte il cui volume era 34097.52220392303 mm³, pari al corpo scritto a 11 cifre significative.

Budget temporale

Il kernel è sincrono e viene eseguito sul thread del chiamante. withBudget(ms, f) fissa una scadenza; chiamata di cicli lunghi (coppie di facce di un booleano, suddivisione delle facce, intersezione di superfici, tassellatura). checkBudget, che lancia BudgetExceeded. I budget nidificati mantengono la scadenza precedente; senza budget un assegno costa un confronto.

Produzione reale
withBudget(1, () => booleanBrep(makeSphere(10), makeBox(10, 10, 10), "union"))
// BudgetExceeded: the exact model exceeded its time budget of 1 ms

Risoluzione dei problemi

SintomoCausaAggiustare
BooleanErroril risultato cucito non è un solido collettore chiuso (facce tangenti o quasi coincidenti)spostare un operando leggermente fuori dalla tangenza; controlla prima entrambi con validateBrep
BudgetExceededl'operazione ha richiesto più tempo del suo budgetsemplificare o assegnare al chiamante un budget maggiore
RangeError da una primitivadimensione non positiva o toro minore ≥ maggioreper esempio. "il raggio minore del toro deve essere più piccolo del raggio maggiore"
sfumare il bordo rejectedfaccia troppo stretta per il raggio, il bordo del coltello o la parete inclinataraggio più piccolo o uno smusso
Facce mancanti della parte STEPentità non supportata nel fileleggere warnings da readStepBreps
validateBrep segnala problemiindice, orientamento o errore del bordo sulla superficie in un corpo costruitol'emissione nomina l'entità; nulla viene riparato automaticamente