Перейти к содержанию
CADCAMFUN
Документы

Документация

Точное ядро B-rep

Точное представление границ: аналитическая и NURBS-геометрия, логические значения, скругления, распознавание отверстий, массовые свойства, проверка, тесселяция и STEP.

Автоматически переведено с английского. Смотреть оригинал на английском

Что такое ядро B-rep

Точное ядро в packages/core/src/cad/brep (Исходные файлы 24, около 8 660 линий, плюс тесты) представляют твердые тела по их точной границе: аналитические поверхности и поверхности NURBS, обрезанные контурами точных краев. Все представляет собой простые данные и чистые функции, поэтому B-представление сериализуется в JSON, пересекает рабочую границу и вносит изменения в историю проекта без изменений. Логические значения, скругления и фаски, распознавание отверстий, массовые свойства, проверка, водонепроницаемая тесселяция и обмен STEP — все это работает в одной структуре.

Точная пластина после вычитания и скругления Перетащите на орбиту · прокрутите, чтобы увеличить · перетащите вправо, чтобы панорамировать
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³.

Таблицы топологии

A Brep представляет собой набор индексных таблиц. Сущности ссылаются друг на друга по индексу, а не по ссылке на объект.

СущностьдержитСТЕП аналог
Вертексточка, толерантностьVERTEX_POINT
Крайexact curve, [t0, t1] with t0 < t1, v0 = C(t0), v1 = C(t1), toleranceEDGE_CURVE
Коэджодно использование ребра в цикле: индекс ребра, перевернутый, дополнительная p-кривая на грани (u, v)ORIENTED_EDGE + PCURVE
Петлязамкнутый цикл коребер; материал слева, вид снаружи (внешняя сторона против часовой стрелки, отверстия по часовой стрелке)EDGE_LOOP
Лицообласть одной поверхности; перевернутый означает, что внешняя нормаль равна −(S_u × S_v)ADVANCED_FACE
Оболочкасвязанный набор лиц; закрытая оболочка ограничивает объемCLOSED_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.

Подсчет примитивов — реальный результат
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"]}

Кривые и поверхности

Аналитические типы используют параметризацию STEP (ISO 10303-42), поэтому лица, считываемые и записываемые в STEP, сохраняют свои параметры.

ТипПараметризация
линияC(t) = O + t·d, единица d, длина дуги t
кругC(t) = O + r(cos t·x + sin t·y)
эллипсC(t) = O + a cos t·x + b sin t·y
самолетS(u,v) = O + u·x + v·y
цилиндрS(u,v) = O + r(cos u·x + sin u·y) + v·z
конусS(u,v) = O + (R + v tan α)(cos u·x + sin u·y) + v·z
сфераS(u,v) = O + r cos v(cos u·x + sin u·y) + r sin v·z
торS(u,v) = O + (R + r cos v)(cos u·x + sin u·y) + r sin v·z
революцияS(u,v) = rotate(C(v), axis, u)
экструзияS(u,v) = C(u) + v·d
заботитсярациональная кривая или поверхность B-сплайна (алгоритмы Пигля и Тиллера в nurbs.ts)
Точные примитивы, мозаичные Перетащите на орбиту · прокрутите, чтобы увеличить · перетащите вправо, чтобы панорамировать
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.
Тор R20 r5 Перетащите на орбиту · прокрутите, чтобы увеличить · перетащите вправо, чтобы панорамировать
makeTorus(20, 5): одна тороидальная грань со швом и без других ребер, мозаичная по координатам chordTol 1 и 30°. MassProperties возвращает точный объем 2π²Rr² = 9 869.604 мм³.

Точные логические значения

  1. Пересекаться. Края каждого твердого тела относительно граней другого тела (точные точки по Ньютону), ребра, лежащие на поверхностях другого твердого тела, и кривые пересечения каждой пары несовпадающих граней, уточненные на обеих поверхностях и распознаваемые как линии и круги, в противном случае соответствующие кубическим B-сплайнам в пределах допуска посадки.
  2. Отпечаток. Каждая точка пересечения становится вершиной в одном реестре для обоих тел, ребра там разбиваются, и каждая грань разрезается кривыми на ней через плоское расположение в своей (u, v) области.
  3. Классифицировать. Точка внутри каждого фрагмента расположена относительно другого тела: внутрь, наружу или внутрь с той же или противоположной ориентацией.
  4. Шить. Фрагменты сохраняются по правилам операции, совпадающие части становятся одним ребром, копланарные соседи сливаются, и результат проверяется. Результат, который не является закрытым многообразием твердых бросков. BooleanError; оно никогда не возвращается.
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 }
}
Коробка минус цилиндр — реальная производительность
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

Массовые свойства

Объем, площадь, центроид и тензор инерции (единичная плотность, около центроида, основная строка) берутся из теоремы о расходимости по граничным граням. Плоские грани интегрируются точно по теореме Грина вдоль точных краевых кривых; изогнутые грани интегрируются в мозаику точной поверхности с шагом по параметрам.

ТелоmassPropertiesЗакрытая форма
коробка − Ø12 отверстие, объем34303.5399670615134303.539967061515
то же, район8139.2920065876848139.292006587698
то же, центроид(30.000, 20.000, 7.500)(30, 20, 7.5)
сфера r10, объём4188.7902047863794188.790204786391
тор 20/5, объем9869.604401094759869.604401089358
филе тарелка, объем34097.5222039230234097.522203923065

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

Скругления, фаски и распознавание отверстий

Подписи
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>

На корпусе коробки − цилиндра было 14 кандидатов на смесь; selectBlendEdges(c, { parallel: "z" }) выбрал 4 вертикальные внешние края и blendBrep(b, sel, 4) скруглены все 4, и ни один из них не был отклонен в течение 94 мс. Дыра прочитала только по лицам:

распознавать отверстия — реальный результат
[{"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]}]}]

Формы simple, counterbore и countersink; низы through, flat и drill-point. При распознавании считываются лица, а не история, поэтому импорт STEP, логический результат и параметрическая часть распознаются одинаково.

Водонепроницаемая мозаика

Каждый край отбирается один раз по точной кривой, и каждая грань, которая его использует, разделяет эти образцы, поэтому сварная сетка не имеет трещин. Грани триангулируются по ограниченному Делоне в их области (u, v).

ВариантПо умолчаниюЗначение
chordTol1/2000 диагонали модели, закрепленной на [0.001, 0.05] мм.максимальное расстояние между сеткой и точной поверхностью
angleTolDeg15максимальный нормальный поворот через треугольник (0 отключает)
maxEdge0 (нет)цель с длиной ребра
maxPointsPerFace200 000защитная крышка
paramStep—режим интеграции, используемый MassProperties

Для филе тарелки defaultChordTol вернул 0.0368 мм и tessellateBrep создал треугольники 652, а также сетки для каждой грани, полилинии ребер и предупреждения.

СТЕП биржа

writeStepBreps записывает файл AP214 (AUTOMOTIVE_DESIGN) в миллиметрах и радианах, по одному ADVANCED_BREP_SHAPE_REPRESENTATION на каждую часть. readStepBreps считывает геометрию и топологию AP203, AP214 и AP242, включая сборки с их преобразованиями и названиями продуктов. О неизвестных объектах сообщается в warnings и их лица перескакивали; ничего не угадывается.
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.));

При обратном чтении этого файла была получена одна часть, объем которой составлял 34097.52220392303 мм³, что соответствует записанному телу с 11 значащими цифрами.

Бюджет времени

Ядро является синхронным и выполняется в потоке вызывающей стороны. withBudget(ms, f) устанавливает срок; длинные циклы (пары граней логического значения, разделение граней, пересечение поверхностей, тесселяция) вызов checkBudget, который выбрасывает BudgetExceeded. Вложенные бюджеты сохраняют более ранний срок; без бюджета проверка стоит одного сравнения.

Реальный выход
withBudget(1, () => booleanBrep(makeSphere(10), makeBox(10, 10, 10), "union"))
// BudgetExceeded: the exact model exceeded its time budget of 1 ms

Поиск неисправностей

СимптомПричинаИсправить
BooleanErrorрезультат сшивания не является замкнутым многообразием (касательные или почти совпадающие грани)немного отклонить операнд от касания; сначала проверьте оба с помощью validateBrep
BudgetExceededоперация заняла больше времени, чем было запланированоупростить или предоставить звонящему больший бюджет
RangeError из примитиванеположительный размер, или малый тор ≥ большогонапример «малый радиус тора должен быть меньше большого радиуса»
смешать края rejectedгрань слишком узкая для радиуса, ножевой кромки или наклонной стеныменьший радиус или фаска
В STEP-детали отсутствуют гранинеподдерживаемый объект в файлечитать warnings из readStepBreps
validateBrep сообщает о проблемахошибка индекса, ориентации или края на поверхности в построенном телев выпуске упоминается сущность; ничего не восстанавливается автоматически