Поверхность скругления
Поверхность точного скругления перекатом шара (rolling ball blend) между двумя поверхностями. Соответствует поверхности blended_edge формата Parasolid XT и обычно возникает при скруглении ребра между двумя гранями.
Спайн строится как кривая пересечения двух эквидистант — опорных поверхностей, смещённых на величины Range1 и Range2. Смещение откладывается вдоль единичной нормали поверхности, умноженной на Range (и на −1, если ориентация поверхности отрицательна); значения Range могут быть и отрицательными. Для скругления постоянного радиуса обе величины равны радиусу шара.
По возможности скругления моделируются более простыми поверхностями — цилиндрической, тороидальной или сферической, а сложные (переменный радиус, некруговое сечение) — NURBS-поверхностями. Отдельная поверхность скругления (
blended_edge) применяется только тогда, когда более простое представление невозможно.
CreateBlendedSurface(ID, FirstSurfID, SecondSurfID, Spine: string; Range1, Range2: STFloat; BlendedType: TSTBlendedType; p1: TST3DPoint; L1: TSTLimitType; p2: TST3DPoint; L2: TSTLimitType) — создать поверхность скругления.
ID— идентификатор создаваемой сущности;FirstSurfID,SecondSurfID— две опорные поверхности (смежные с исходным ребром), между которыми строится скругление;Spine— спайн: осевая кривая скругления, путь центра катящегося шара; строится как кривая пересечения двух эквидистант;Range1,Range2— смещения (offsets), применяемые к первой и второй поверхностям соответственно; на рисунке задают эквидистанты «Offset» (пунктирные), пересечение которых и даёт спайн; для постоянного радиуса равны радиусу шара;BlendedType— тип скругления (TSTBlendedType):R— перекатом шара (rolling ball); шар на рисунке подписан «Rolling sphere», его радиус равенRange, а центр катится по спайну;E— «обрыв» (cliff edge), когда одна из поверхностей сама является скруглением с диапазоном[0, 0], а спайн совпадает с кромкой обрыва;p1,L1— начальная точка и тип её границы (TSTLimitType, см. Кривая пересечения);p2,L2— конечная точка и тип её границы.
Поля p1/L1 и p2/L2 задаются (тип границы L) только в вырожденных случаях — когда спайн периодический, а скругляемое ребро имеет концы (например, спайн эллиптический, а скругление вырождается). В обычном случае границы не ограничены (тип U).

TSTBlendedType и TSTLimitType — это типы SGF, а не CAD-системы. Поэтому в классе параметров используются собственные перечисления Дополнения, а перед вызовом CreateBlendedSurface они приводятся к типам SGF (так же, как точки приводятся к TST3DPoint).
Пример сохранения поверхности скругления.
// собственные перечисления Дополнения (CAD-сторона, без типов SGF)
enum CADBlendKind { RollingBall, Cliff } // соответствует R / E
enum CADBorderKind { NotSet, Terminator, ArbLimit } // соответствует U / T / L
// Параметры поверхности скругления CAD-системы
class CADBlendParam
{
public CADSurface Surface1, Surface2; // две опорные поверхности
public CADCurve Spine; // спайн (осевая кривая скругления)
public double Range1, Range2; // смещения эквидистант (для постоянного радиуса = радиусу шара)
public CADBlendKind Kind; // тип скругления (CAD-сторона)
public CADPoint P1, P2; // граничные точки (обычно не используются)
public CADBorderKind L1, L2; // типы границ (в обычном случае NotSet)
}
bool SaveBlendedSurface(string id, CADBlendParam param)
{
// сначала сохраняем опорные объекты: обе поверхности и спайн
if (!SaveSurface(param.Surface1) || !SaveSurface(param.Surface2) || !SaveCurve(param.Spine))
return false;
// приведение CAD-перечислений к типам SGF через switch
TSTBlendedType blendedType;
switch (param.Kind)
{
case CADBlendKind.Cliff: blendedType = TSTBlendedType.E; break; // «обрыв»
default: blendedType = TSTBlendedType.R; break; // перекатом шара
}
// поверхность скругления (точки приводятся к TST3DPoint)
return sgr.CreateBlendedSurface(id, param.Surface1.Id, param.Surface2.Id, param.Spine.Id,
param.Range1, param.Range2, blendedType,
ToPoint(param.P1), ToLimit(param.L1),
ToPoint(param.P2), ToLimit(param.L2));
}
// функция приведения типа границы (используется для L1 и L2)
TSTLimitType ToLimit(CADBorderKind k)
{
switch (k)
{
case CADBorderKind.Terminator: return TSTLimitType.T;
case CADBorderKind.ArbLimit: return TSTLimitType.L;
default: return TSTLimitType.U; // не задано
}
}