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

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

Сетка и ядро CSG

Замкнутые треугольные сетки из параметрических тел, логические значения BSP с выпуклым быстрым путем, очистка и проверка топологии.

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

Что такое ядро сетки

Ядро сетки работает с сетками замкнутых треугольников: оно строит их из параметрических примитивов (meshOf), измеряет их (meshVolume, meshBounds, meshTopology) и объединяет их с логическими значениями (booleanMesh, booleanAll). Это то, что показывает окно просмотра, что делает генератор CAM и что пишет экспорт STL.

Это не точное представление границ. Разрезанный цилиндр остается граненым цилиндром, и у него нет топологии грани, по которой можно было бы выполнить сопряжение или измерение. Для точных граней, скруглений, массовых свойств и STEP Ядро B-rep это отдельный фрагмент кода.

ФайлЛинииРоль
cad/solid.ts659Схемы твердого тела (Box, Cylinder, Sphere, Cone, Torus, Extrume, Revolve), meshOf, meshVolume, meshBounds
cad/csg.ts459BSP Booleans, выпуклый классификатор, перевод/поворот/объединение
cad/mesh-clean.ts626сварной шов, ремонт Т-образного соединения, копланарное слияние, повторная триангуляция
cad/mesh-topology.ts110многообразие, оболочки, род, объём, площадь
cad/triangulate.ts383триангуляция многоугольника с отверстиями
Просверленная пластина с расточенной бобышкой Перетащите на орбиту · прокрутите, чтобы увеличить · перетащите вправо, чтобы панорамировать
Реальный результат booleanMesh: коробка 60 × 40 × 10 минус четыре отверстия Ø6 (booleanAll вычитается), объединенная с выступом Ø20 × 8, а затем просверленная насквозь Ø10. 640 треугольников; meshTopology сообщает о закрытом теле, оболочка 1, род 5, V 23981.4 мм³.

Тип сетки и примитивы

solid.ts
export interface Mesh {
  readonly positions: Float32Array   // x, y, z per vertex
  readonly indices: Uint32Array      // three per triangle, counter-clockwise seen from outside
}
export const meshOf: (solid: Solid, tolerance?: number /* 0.1 mm */) => Mesh
export const meshVolume: (mesh: Mesh) => number     // signed; positive when outward-facing
export const meshBounds: (mesh: Mesh) => SolidBounds
ТвердыйПоляПределы
Коробканачало координат, размер {x, y, z}размеры > 0
Цилиндрначало координат, радиус, высота, сегменты, ось?сегменты 3–512; ось z | х | й
Сферацентр, радиус, кольцакольца 2–256
Конусначало координат, baseRadius, topRadius, высота, сегменты, ось?топРадиус ≥ 0; сегменты 3–512
Торцентр, мажорРадиус, минорРадиус, вращение?, мажорСегментс, минорСегментс, ось?3–512 и 3–256
Выдавливаниепрофиль (≥ 3 точек, не закрытый), высота, начало координат?профиль в XY
вращатьсяпрофиль (≥ 2 точек по XZ), угол, сегменты?о З; сегменты 3–512, по умолчанию 16
segments и rings являются минимумами: meshOf поднимает их до тех пор, пока ошибка аккорда не окажется в пределах tolerance, using step = 4·asin(√(min(1, tol/r)/2)). Two budgets stop runaway tolerances.
СторожитьЦенитьСообщение об ошибке
толерантность должна быть положительной и конечной—Допуск сетки должен быть положительным и конечным.
сегментов на кривую65 536Допуск сетки превышает бюджет подразделения
строки сетки × столбцы (сфера, тор, вращение)1 000 000Допуск сетки превышает бюджет вершин

Цилиндр Ø6 с segments: 24 при допуске 0.05 получилось с треугольниками 96 (стороны 24, две вершины 24-угольника); Ø20 с 128, поскольку для большего радиуса требовалось, чтобы сегменты 32 оставались в пределах 0.05 мм.

Логические значения путем разделения двоичного пространства

Каждый операнд становится классификатором. Общая сетка получает дерево BSP; Выпуклая сетка (замкнутая, связная, каждый край выпуклый) представляет собой просто отдельные плоскости ее граней, поэтому ящик состоит из шести плоскостей, а сфера из десяти тысяч треугольников классифицируется без построения квадратичной цепи, в которую вырождается BSP выпуклого твердого тела. Полигоны классифицируются как списки, и полигон, выходящий за рамки ограничивающего прямоугольника другого операнда, сохраняется или удаляется без каких-либо перемещений.

  1. If either mesh is empty, or the bounding boxes do not meet (within tolerance), answer directly: union = merge, subtract = a, intersect = empty.
  2. Постройте классификаторы A и B (выпуклые плоскости или BSP).
  3. Объединение: оставьте A снаружи B, B снаружи A и отбросьте грани B, совпадающие с гранями A, указывающими в том же направлении, чтобы общее лицо сохранялось один раз.
  4. Subtract and intersect follow the classic a.clipTo(b), b.clipTo(a), b.invert() sequence on polygon lists, without copying trees.
  5. Очистите полигональный суп: точки сварки в пределах max(10·eps, 1e-9·size), закройте Т-образные соединения, закройте зазоры размером до 1e-4·между полосками, объедините копланарные фрагменты и повторите триангуляцию.
csg.ts
export type BooleanOp = "union" | "subtract" | "intersect"
export interface CsgOptions {
  /** Distance below which a point counts as on a plane, mm. Default 1e-7 × the larger extent. */
  readonly tolerance?: number
  /** Merge coplanar fragments and re-triangulate (default true). */
  readonly mergeCoplanar?: boolean
}
export const booleanMesh: (a: Mesh, b: Mesh, op: BooleanOp, options?: CsgOptions) => Mesh
/** Union reduced as a balanced tree; subtract and intersect fold left to right. */
export const booleanAll: (meshes: ReadonlyArray<Mesh>, op: BooleanOp, options?: CsgOptions) => Mesh
export const translateMesh: (mesh: Mesh, dx: number, dy: number, dz: number) => Mesh
export const rotateMesh: (mesh: Mesh, axis: V3, radians: number, origin?: V3) => Mesh
export const mergeMeshes: (meshes: ReadonlyArray<Mesh>) => Mesh

Число треугольников растет вместе с объектами, а не с количеством логических значений: шаг слияния возвращает копланарные фрагменты обратно в целые грани. На пластине выше коробка имела треугольники 12, после четырёх отверстий 412, после бобышки 540, после отверстия 640; вся цепочка выполнялась за 96 мс.

Объединение, вычитание, пересечение на изогнутом входе

A 20 mm cube at the origin against a sphere of radius 12 centred on its far corner (20, 20, 20), meshed at tolerance 0.2 (624 triangles). Real volumes:

РезультатОбъем, мм³Треугольники
только сфера7 063.84 (точно 7 238.23)624
куб ∩ сфера882.98112
куб ∪ сфера14 180.86—
куб − сфера7 117.02—

Проверьте: 8 000 + 7 063.84 – 882.98 = 14 180.86 и 8 000 – 882.98 = 7 117.02, чтобы эти три результата согласовывались друг с другом с точки зрения сотый. Сама сетка сферы составляет 2.4 % под точной сферой, что является гранью грубого допуска, а не логической ошибки.

куб − сфера Перетащите на орбиту · прокрутите, чтобы увеличить · перетащите вправо, чтобы панорамировать
Результат вычитания: куб с вырванной из угла восьмой сферой.
куб ∩ сфера Перетащите на орбиту · прокрутите, чтобы увеличить · перетащите вправо, чтобы панорамировать
Результат пересечения: восьмая часть сферы, лежащая внутри куба.

Проверка топологии

meshTopology подсчитывает вершины, ребра и треугольники, находит границы, не многообразные и неправильно ориентированные ребра, вырожденные треугольники и оболочки, а также выводит эйлерову характеристику и род. describeTopology печатает однострочную сводку, которую использует помощник и область просмотра.
meshTopology(bored) — реальный результат
{"vertices":312,"triangles":640,"edges":960,"boundaryEdges":0,"nonManifoldEdges":0,
 "misorientedEdges":0,"degenerateTriangles":0,"shells":1,"eulerCharacteristic":-8,"genus":5,
 "closed":true,"solid":true,"volume":23981.43509870267,"area":8238.640705862534}
// describeTopology → "closed solid, 1 shell, genus 5, 640 triangles, V 23981.4 mm³, A 8238.6 mm²"

V − E + F = 312 − 960 + 640 = −8 = 2 − 2g, so g = 5: the four drilled holes plus the bore, which runs through the boss and the plate.

Триангуляция многоугольника

triangulatePolygon(outer, holes) возвращает тройки индексов в результате объединения внешнего кольца и отверстий. Квадрат 4 × 4 с отверстием 2 × 2 дает восемь треугольников:
Реальный выход
triangulatePolygon(
  [{x:0,y:0},{x:4,y:0},{x:4,y:4},{x:0,y:4}],
  [[{x:1,y:1},{x:1,y:3},{x:3,y:3},{x:3,y:1}]])
// [[0,4,5],[7,4,0],[3,0,5],[7,0,1],[2,3,5],[6,7,1],[2,5,6],[6,1,2]]
triangulatePolygonChecked возвращает undefined вместо частичного результата, когда входные данные не могут быть триангулированы (самопересекающиеся кольца, отверстия за пределами внешнего кольца).

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

СимптомПричинаИсправить
Логический результат имеет дыры или перевернутые гранивход открыт или закручен по часовой стрелкепроверьте оба входа с помощью meshTopology: borderEdges и misориентedEdges должны быть 0
лицо, общее для обоих операндов, отсутствует или дублируетсяграни почти, но не совсем совпадают (на расстоянии, превышающем допуск)привяжите операнды к одной плоскости или поднимите CsgOptions.tolerance
RangeError: допуск сетки превышает бюджет подразделениядопуск слишком мал для радиусаиспользуйте настройки допуска (от 0.1 до 0.0005 мм)
объем отличается от формулыогранка с грубым допускомсетка более мелкая или используйте ядро B-rep для точных массовых свойств
Логическое значение медленно на многих инструментахобъединение инструментов, созданных первымивычитать инструменты один за другим (booleanAll делает это): каждый выпуклый инструмент представляет собой несколько плоскостей