Saltar al contenido
CADCAMFUN
Documentos

Documentación

Núcleo B-rep exacto

Representación exacta de límites: geometría analítica y NURBS, booleanos, filetes, reconocimiento de agujeros, propiedades de masa, validación, teselación y STEP.

Traducido automáticamente del inglés. Ver el original en inglés

¿Qué es el núcleo B-rep?

El núcleo exacto en packages/core/src/cad/brep (24 archivos fuente, aproximadamente 8 660 líneas, más pruebas) representa sólidos por su límite exacto: superficies analíticas y NURBS, recortadas por bucles de bordes exactos. Todo son datos simples y funciones puras, por lo que un B-rep se serializa en JSON, cruza el límite de un trabajador y diferencia en el historial del proyecto sin cambios. Booleanos, filetes y chaflanes, reconocimiento de agujeros, propiedades de masa, validación, teselación estanca e intercambio STEP funcionan en esta única estructura.

Plato exacto después de restar y filetear Arrastrar para orbitar · desplazarse para hacer zoom · arrastrar con el botón derecho para desplazarse
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³.

Tablas de topología

A Brep es un conjunto de tablas de índice. Las entidades se refieren entre sí por índice, nunca por referencia de objeto.

EntidadSostienecontraparte PASO
Vérticepunto, toleranciaVERTEX_POINT
Bordeexact curve, [t0, t1] with t0 < t1, v0 = C(t0), v1 = C(t1), toleranceEDGE_CURVE
coedgeun uso de una arista mediante un bucle: índice de arista, invertido, curva p opcional en la cara (u, v)ORIENTADO_EDGE + PCURVA
Bucleciclo cerrado de coedges; material a la izquierda visto desde fuera (exterior en sentido horario, agujeros en sentido horario)EDGE_LOOP
Rostroregión de una superficie; invertido significa que la normal exterior es −(S_u × S_v)ADVANCED_FACE
Caparazónconjunto conectado de caras; una concha cerrada limita un volumenCLOSED_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.

Conteos de las primitivas: producción real
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"]}

Curvas y superficies

Los tipos analíticos utilizan las parametrizaciones STEP (ISO 10303-42), por lo que las caras leídas y escritas en STEP mantienen sus parámetros.

TipoParametrización
líneaC(t) = O + t·d, d unidad, t longitud del arco
círculoC(t) = O + r(cos t·x + sin t·y)
elipseC(t) = O + a cos t·x + b sen t·y
aviónS(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
esferaS(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
revoluciónS(u,v) = rotate(C(v), axis, u)
extrusiónS(u,v) = C(u) + v·d
nurbscurva o superficie racional B-spline (algoritmos de Piegl & Tiller en nurbs.ts)
Primitivas exactas, teseladas Arrastrar para orbitar · desplazarse para hacer zoom · arrastrar con el botón derecho para desplazarse
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 Arrastrar para orbitar · desplazarse para hacer zoom · arrastrar con el botón derecho para desplazarse
makeTorus(20, 5): una única cara toroidal con una costura y sin otras aristas, teselada en chordTol 1 y 30°. El volumen exacto 2π²Rr² = 9 869.604 mm³ es lo que devuelve massProperties.

Booleanos exactos

  1. Intersecarse. Bordes de cada sólido contra las caras del otro (puntos exactos de Newton), bordes que se encuentran en las superficies del otro sólido y las curvas de intersección de cada par de caras no coincidentes, refinadas en ambas superficies y reconocidas como líneas y círculos, de lo contrario ajustadas como B-splines cúbicos dentro de la tolerancia de ajuste.
  2. Imprimir. Cada punto de intersección se convierte en un vértice en un registro para ambos sólidos, los bordes se dividen allí y cada cara es cortada por las curvas a través de una disposición plana en su dominio (u, v).
  3. Clasificar. Un punto dentro de cada fragmento se ubica contra el otro sólido: adentro, afuera o adentro con la misma orientación u opuesta.
  4. Coser. Los fragmentos se mantienen según las reglas de la operación, las piezas coincidentes se convierten en un borde, los vecinos coplanares se fusionan y el resultado se valida. Un resultado que no es un sólido múltiple cerrado arroja BooleanError; nunca se devuelve.
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 }
}
Caja menos cilindro: potencia real
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

Propiedades de masa

El volumen, el área, el centroide y el tensor de inercia (densidad unitaria, alrededor del centroide, fila principal) provienen del teorema de divergencia sobre las caras límite. Las caras planas se integran exactamente según el teorema de Green a lo largo de las curvas de borde exactas; Las caras curvas se integran en un mosaico de pasos de parámetros de la superficie exacta.

CuerpomassPropertiesformulario cerrado
caja − Ø12 agujero, volumen34303.5399670615134303.539967061515
mismo, área8139.2920065876848139.292006587698
mismo, centroide(30.000, 20.000, 7.500)(30, 20, 7.5)
esfera r10, volumen4188.7902047863794188.790204786391
toro 20/5, volumen9869.604401094759869.604401089358
plato fileteado, volumen34097.5222039230234097.522203923065

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

Filetes, chaflanes y reconocimiento de agujeros

Firmas
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>

En la caja - cuerpo del cilindro había 14 mezclas candidatas; selectBlendEdges(c, { parallel: "z" }) seleccionó los 4 bordes exteriores verticales y blendBrep(b, sel, 4) fileteado todo 4 sin ninguno rechazado en 94 ms. El agujero lee solo de las caras:

reconocerHoles - salida real
[{"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]}]}]

Los formularios son simple, counterbore y countersink; los fondos son through, flat y drill-point. El reconocimiento lee rostros, no historial, por lo que una importación STEP, un resultado booleano y una parte paramétrica se reconocen por igual.

Teselado estanco

Cada borde es muestreado una vez en su curva exacta y cada cara que lo utiliza comparte esas muestras, por lo que la malla soldada no tiene grietas. Las caras son trianguladas por Delaunay restringido en su dominio (u, v).

OpciónPor defectoSignificado
chordTol1/2000 de la diagonal del modelo, sujeta a [0.001, 0.05] mmdistancia máxima entre malla y superficie exacta
angleTolDeg15giro normal máximo a través de un triángulo (0 desactiva)
maxEdge0 (ninguno)objetivo de longitud de borde
maxPointsPerFace200 000tapa de seguridad
paramStep—modo de integración utilizado por MassProperties.

Para el plato de filete defaultChordTol devolvió 0.0368 mm y tessellateBrep produjo 652 triángulos más mallas por cara, polilíneas de borde y advertencias.

intercambio PASO

writeStepBreps escribe un archivo AP214 (AUTOMOTIVE_DESIGN) en milímetros y radianes, un ADVANCED_BREP_SHAPE_REPRESENTATION por parte. readStepBreps lee la geometría y topología AP203, AP214 y AP242, incluidos los ensamblajes con sus transformaciones y nombres de productos. Se reportan entidades desconocidas en warnings y sus rostros saltaron; no se adivina nada.
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.));

Al volver a leer ese archivo se obtuvo una parte cuyo volumen era 34097.52220392303 mm³, igual al cuerpo escrito con 11 dígitos significativos.

Presupuesto de tiempo

El kernel es sincrónico y se ejecuta en el hilo de la persona que llama. withBudget(ms, f) fija una fecha límite; llamada de bucles largos (pares de caras de un booleano, división de caras, intersección de superficies, teselación) checkBudget, que arroja BudgetExceeded. Los presupuestos anidados mantienen la fecha límite anterior; sin presupuesto un cheque cuesta una comparación.

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

Solución de problemas

SíntomaCausaArreglar
BooleanErrorel resultado cosido no es un sólido múltiple cerrado (caras tangentes o casi coincidentes)mover un operando ligeramente fuera de la tangencia; verifique ambos con validarBrep primero
BudgetExceededla operación tomó más tiempo que su presupuestosimplificar o darle a la persona que llama un presupuesto mayor
RangeError de una primitivatamaño no positivo, o toro menor ≥ mayorp.ej. "El radio menor del toro debe ser menor que el radio mayor"
mezclar el borde rejectedcara demasiado estrecha para el radio, filo de cuchillo o pared inclinadaradio más pequeño o un chaflán
PASO parte faltan carasentidad no compatible en el archivoleer warnings de readStepBreps
validarBrep informa problemaserror de índice, orientación o borde en superficie en un cuerpo construido.la emisión nombra la entidad; nada se repara automáticamente