AutoCAD позволяет хранить объекты СПЛАЙНА в файлах DXF, определяемых только точками подгонки, проблема в том, что такое определение сплайна имеет бесконечное число правильных решений, а Autodesk не предоставляет необходимую информацию для вычисления требуемых параметров из заданных точек подгонки.
tl; dr - недостающая информация - это предполагаемые начальные и конечные касательные по направлению и величине для входных касательных к глобальной интерполяции B-сплайнов с конечными производными, может ли кто-нибудь помочь вычислить эти значения?
Полный исходный код на github.
Я использую BricsCAD для тестирования, но «Trueview 2020» показывает те же результаты.
1. Сценарий
Даны только подходящие точки с использованием интерполяции глобальной кривой без каких-либо ограничений для получения сплайна, определенного контрольными вершинами:
# First spline defined by control vertices interpolated from given fit points
s = global_bspline_interpolation(points, degree=3)
msp.add_spline(dxfattribs={'color': 4, 'layer': 'Global Interpolation'}).apply_construction_tool(s)
# Second spline defined only by fit points as reference
spline = msp.add_spline(points, degree=3, dxfattribs={'layer': 'BricsCAD B-spline', 'color': 2})
doc.saveas(DIR / 'fit-points-only.dxf')
Сплайн, интерполированный BricsCAD по точкам подгонки, не соответствует сплайну, заданному интерполированными контрольными вершинами:
2. Сценарий
Помимо точек подгонки, я также сохраняю значения начальной и конечной касательной в файле DXF. Интерполяция выполняется путем интерполяции глобальной кривой с конечными производными (Piegl & Tiller: «Книга NURBS» - глава 9.2.2).
Я выбрал произвольный угол (100 градусов) в качестве начального и конечного касательных, величина тангенса оценивается методом «Общая длина хорды».
m1, m2 = estimate_end_tangent_magnitude(points, method='chord')
start_tangent = Vector.from_deg_angle(100) * m1
end_tangent = Vector.from_deg_angle(-100) * m2
# First spline defined by control vertices interpolated from given fit points and end-tangents
s = global_bspline_interpolation(points, degree=3, tangents=(start_tangent, end_tangent))
msp.add_spline(dxfattribs={'color': 4, 'layer': 'Global Interpolation'}).apply_construction_tool(s)
# Result matches the BricsCAD interpolation if fit points, start- and end
# tangents are stored explicit in the DXF file.
# Second spline defined by fit points as reference
spline = msp.add_spline(points, degree=3, dxfattribs={'layer': 'BricsCAD B-spline', 'color': 2})
# set explicit start- and end tangent as unit vectors
spline.dxf.start_tangent = Vector.from_deg_angle(100)
spline.dxf.end_tangent = Vector.from_deg_angle(-100)
doc.saveas(DIR / 'fit-points-and-tangents.dxf')
Сплайн, интерполированный BricsCAD, теперь точно соответствует сплайну, заданному интерполированными контрольными вершинами:
Теперь я знаю, что метод интерполяции верен, все, что мне нужно для рендеринга одного и того же сплайна из точек подгонки, так как BricsCAD, - это конечные касательные по направлению и величине, выведенные из точек подгонки.
3. Сценарий
Мне нужны контрольные вершины для рендеринга B-сплайна, но начальные и конечные касательные не сохраняются в файле DXF, как в сценарии 1. Требуется оценка начальных и конечных касательных, лучший результат: «5-точечная интерполяция» из "Книга NURBS", Piegl & Tiller
tangents = estimate_tangents(points, method='5-points')
# Estimated tangent angles: (108.43494882292201, -108.43494882292201) degree
m1, m2 = estimate_end_tangent_magnitude(points, method='chord')
start_tangent = tangents[0].normalize(m1)
end_tangent = tangents[-1].normalize(m2)
# First spline defined by control vertices interpolated from given fit points and end-tangents
s = global_bspline_interpolation(points, degree=3, tangents=(start_tangent, end_tangent))
msp.add_spline(dxfattribs={'color': 4, 'layer': 'Global Interpolation'}).apply_construction_tool(s)
# Second spline defined by fit points as reference, but without explicit start- and end
# tangents to see if my estimations are correct.
msp.add_spline(points, degree=3, dxfattribs={'layer': 'BricsCAD B-spline', 'color': 2})
doc.saveas(DIR / 'tangents-estimated.dxf')
И удивительно, что оценки не верны, сплайн BricsCAD имеет касательные углы 101.0035408517495 и -101.0035408517495 градусов.
И действительно раздражает то, что если я использую углы BricsCAD в качестве входных данных, сплайны все равно не совпадают, поэтому я предположил, что оценка тангенциальной величины отличается от сценария 2.
4. Проверка теории
Следующие значения вычисляются из файла DXF, сохраненного BricsCAD, и SPLINE «Метод» переключен с «точек подгонки» на «контрольные вершины». По этим данным я вычислил касательные углы, а также величины tangent vector = 2nd control vertex - 1st control vertex
.
required_angle = 101.0035408517495 # angle of tangent vector in degrees
required_magnitude = m1 * 1.3097943444804256 # magnitude of tangent vector
start_tangent = Vector.from_deg_angle(required_angle, required_magnitude)
end_tangent = Vector.from_deg_angle(-required_angle, required_magnitude)
s = global_bspline_interpolation(points, degree=3, tangents=(start_tangent, end_tangent))
msp.add_spline(dxfattribs={'color': 4, 'layer': 'Global Interpolation'}).apply_construction_tool(s)
msp.add_spline(points, degree=3, dxfattribs={'layer': 'BricsCAD B-spline', 'color': 2})
doc.saveas(DIR / 'theory-check.dxf')
Теперь шлицы снова совпадают:
- Если касательные заданы (сохранены в DXF), величина входных касательных для функции интерполяции равна «общей длине хорды».
- Без заданных касательных величина будет другой, в этом примере:
m1*1.3097943444804256
, но это не постоянный коэффициент.
Большой вопрос: Как оценить начальную и конечную касательные по направлению и величине, как в AutoCAD или BricsCAD для шлицев, определяемых только точками подгонки?
Заранее спасибо,
Манфред