Грань (обрезанная поверхность)
Из поверхности можно вырезать ограниченный участок — грань (обрезанную поверхность) — и добавить его в геометрическое дерево как самостоятельный объект, либо как часть оболочки. Грань состоит из базовой поверхности и одного или нескольких контуров (петель), которые ограничивают вырезаемую область. Тем самым грань связывает два вида геометрии: несущую поверхность (её строят методами главы Поверхности) и кривые рёбер контура вместе с их вершинами (глава Кривые и точки).
Как это устроено.
- Базовая поверхность. Грань строится поверх ранее сохранённой поверхности (любой из Поверхности). Она открывается вызовом
StartFace(ID, SurfaceID, NormalOrientation), гдеSurfaceID— идентификатор этой поверхности, аNormalOrientationзадаёт, совпадает ли нормаль грани с нормалью поверхности. - Контур (петля). Это замкнутая последовательность рёбер, идущая по границе вырезаемой области; открывается
StartFaceLoopи закрываетсяCloseFaceLoop. Контуров может быть несколько: первый, как правило, — внешняя граница, остальные — отверстия внутри грани. - Направление обхода петли. Оставляемая область (тело грани) должна находиться слева от направления обхода (если смотреть навстречу нормали грани). Поэтому внешний контур обходится против часовой стрелки, а контуры-отверстия — по часовой. Направление задаётся как порядком добавления рёбер, так и флагом
Orientationу каждого ребра (совпадает ли направление обхода с направлением опорной кривой). - Ребро = обрезанная кривая между двумя вершинами. Концы ребра — вершины — создаются как 3D-точки вызовом
CreatePoint(ID, P)(на нихAddFaceEdge3dссылается по идентификатору). Геометрия самого ребра — обрезанная кривая: берётся опорная 3D-кривая (отрезок, дуга, NURBS, кривая пересечения и т.п., уже сохранённая в SGF) и усекается между концевыми точками ребра вызовомCreateTrimmedCurve2(ID, SourceCurveID, p1, p2)(для прямого ребра можно сразуCreateLineSeg). Если ребро направлено против опорной кривой, кривую предварительно разворачиваютCreateInversedCurveлибо передаютOrientation = false. Готовое ребро добавляется в текущую петлю:AddFaceEdge3d— для пространственной кривой,AddFaceEdge2d— для кривой, заданной в параметрах UV поверхности (см.CreateCurveOnSurface). - Завершение и добавление в дерево. Грань закрывается
CloseFace(возвращает признак успешного «замыкания»). Чтобы обрезанная поверхность появилась в геометрическом дереве как самостоятельный объект, её регистрируют вызовомAddEntity(ID, EntityName)— гдеIDсовпадает с идентификатором грани изStartFace.
StartFace(ID, SurfaceID: string; NormalOrientation: boolean) — начать грань на основе ранее сохранённой поверхности.
ID— идентификатор создаваемой грани;SurfaceID— идентификатор опорной (базовой) поверхности;NormalOrientation— совпадает ли нормаль грани с нормалью базовой поверхности (true— совпадает,false— противоположна).
StartFaceLoop() — начать контур (петлю) грани.
AddFaceEdge2d(CurveID: string; Orientation: boolean; svID, tvID: string) — добавить ребро в текущий контур по кривой, заданной в параметрах UV поверхности (см. Кривая на поверхности).
CurveID— идентификатор опорной кривой ребра;Orientation— совпадает ли направление обхода контура с направлением кривой (false— кривая проходится в обратную сторону);svID— идентификатор начальной вершины ребра;tvID— идентификатор конечной вершины ребра.
AddFaceEdge3d(CurveID: string; Orientation: boolean; svID, tvID: string) — то же, что AddFaceEdge2d, но ребро задано пространственной (3D) кривой; svID и tvID ссылаются на вершины — 3D-точки, созданные вызовом CreatePoint.
CurveID— идентификатор опорной 3D-кривой ребра;Orientation— совпадает ли направление обхода контура с направлением кривой;svID— идентификатор начальной вершины ребра;tvID— идентификатор конечной вершины ребра.
CloseFaceLoop() — завершить текущий контур.
CloseFace() — завершить грань (возвращает признак успешного замыкания).
Цвет грани. Цвет грани задаётся так же, как для прочих объектов — вызовом SetCurrentColor перед StartFace; о действии текущего цвета (состояние, наследование, формат значения) см. Кривые и точки.
Пример: импорт грани CAD-модели в SGF. Метод SaveTrimmedFace получает грань CADFace, сохраняет её несущую поверхность, а затем открывает грань поверх неё и обходит её контуры.
bool SaveTrimmedFace(CADFace face)
{
if (!SaveSurface(face.Surface))
return false;
// цвет грани задаётся перед StartFace — по аналогии с кривыми (см. «Кривые и точки»)
sgr.SetCurrentColor(face.Color);
sgr.StartFace(face.Id, face.Surface.Id, face.SameSense);
try
{
for (int i = 0; i < face.Loops.Length; i++)
{
CADLoop loop = face.Loops[i];
sgr.StartFaceLoop();
try
{
// порядок рёбер задаёт направление обхода:
// внешний контур — против часовой, отверстия — по часовой
for (int j = 0; j < loop.Edges.Length; j++)
{
// составной идентификатор ребра: грань.луп.ребро
string edgeId = $"{face.Id}.{i}.{j}";
SaveFaceEdge(edgeId, loop.Edges[j]);
}
}
finally
{
sgr.CloseFaceLoop();
}
}
}
finally
{
sgr.CloseFace();
}
return true;
}
// Сохранение одного ребра контура
bool SaveFaceEdge(string edgeId, CADEdge edge)
{
if (!SaveCurve(edge.Curve))
return false;
// геометрия ребра — опорная кривая, обрезанная между вершинами (координаты приводим к TST3DPoint)
sgr.CreateTrimmedCurve2(edgeId, edge.Curve.Id,
ToPoint(edge.Start.Point), ToPoint(edge.End.Point));
// ребро в петлю (3D); SameSense — совпадает ли обход с направлением кривой
return sgr.AddFaceEdge3d(edgeId, edge.SameSense, edge.Start.Id, edge.End.Id);
}
Вспомогательные методы SaveSurface(CADSurface) и SaveCurve(CADCurve) выбирают вызов по типу геометрии (плоскость, цилиндр, NURBS, отрезок, дуга и т.д. — см. Поверхности–Кривые и точки), записывают её в SGF и возвращают признак успеха; идентификатор берётся из самого объекта (поле Id).