Переход с ZenCad 1

При переносе скриптов учитывайте изменения типов, материализации и доступных обёрток геометрических операций. Сверяйте пользовательские скрипты с этой таблицей, а не переносите старые настройки lazy.

Раньше ZenCad 2
shape.unlazy() перед вызовом OCCT shape.native() возвращает объект OCP; сама форма уже имеет устойчивый тип
Раскрытие числового результата shape.mass().value() или float(shape.mass())
zencad.lazy.onplace = True zencad.set_evaluation_mode("immediate") в начале скрипта
Настройки чтения/записи через zencad.lazy zencad.configure(cache_enabled=False) отключает дисковый кэш
Runtime с CAD-методами Модульные функции zencad.box(...) и методы объектов
Наследование Point/Vector от NumPy point.to_numpy(), vector.to_numpy() или .value()
faces()[:4] как «четыре боковые грани» Геометрический селектор, например filter_by_position(Axis.Z, height / 2)
Callback с доступом к DisplayWidget state.input, state.camera и контроллеры display()
Вызов zencad.color(...) zencad.Color(...); zencad.color — модуль
Имена time, math, numpy, случайно попавшие через import * Явные импорты соответствующих модулей

Совместимость с zencad.lazy намеренно не поддерживается в ZenCad 2. Старый пользовательский @lazy не имеет автоматической совместимой замены. Новые доменные операции используют @zencad.operation; описание деклараций находится в исходнике zencad/operation.py и development-документах. Не следует механически переименовывать декоратор.

Геометрические массивы и сборки

Аргумент unit=True удалён из multitrans, multitransform, sqrmirror, sqrtrans, rotate_array и rotate_array2. Геометрические функции работают с формами и не создают сборочные или кинематические объекты. При array=True они возвращают отдельные копии; по умолчанию — их булево объединение.

Для сохранения отдельных деталей в сборке создайте юнит явно:

from zencad import *
from zencad.assemble import unit

part = box(2).right(5)
copies = rotate_array(4, array=True)(part)
assembly = unit(parts=copies)
body = union(copies)
assert len(copies) == 4
assert abs(float(body.mass()) - 32) < 1e-7

Сборка зависит от геометрии, а геометрия не зависит от сборок. Вместо передачи интерактивного объекта или юнита в массив преобразований передавайте геометрическую форму и затем добавляйте её копии в сборку. multitransform — строчная функция создания MultiTransform, sqrtrans — синоним sqrmirror.

Граф и явные границы

import zencad as z

z.configure(cache_enabled=False)
body = z.box(10)
volume = body.mass()                  # Scalar, а не float
moved = body.right(volume / 100)      # зависимость остаётся в графе
assert isinstance(volume, z.Scalar)
assert abs(float(volume) - 1000) < 1e-7
ocp_shape = moved.native()            # вычисление для интеграции с OCP

native() возвращает native-значение, а не «старую оболочку Shape». Для последующих операций ZenCad сохраняйте исходный handle. Point + Point недопустимо; Point - Point возвращает Vector, Vector + VectorVector. Координаты .x/.y/.z имеют тип Scalar.

len() и итерация коллекций топологии вычисляют их; индексирование, срезы и селекторы сохраняют граф. Индексы не являются постоянными идентификаторами граней после редактирования геометрии.

Анимация и кэш

В managed callback нельзя добавлять или заменять геометрию после начального show(). Создавайте объекты заранее, затем меняйте их размещение, цвет и видимость. preanimate и произвольный доступ к Qt не входят в managed-контракт. Подробности.

Кэш общий для процессов текущего пользователя. Старые записи кэша не являются совместимым форматом и могут быть отброшены. set_evaluation_mode() — обычная функция, не context manager; ранее предложенные eager()/immediate()/evaluation() context managers удалены. Вычисления.

Исторические операции кривых

В старых руководствах встречаются curve.length(), curve.linoff(u, dist) и curve.linoff_point(u, dist). Они обозначали длину кривой, параметр после смещения на заданную длину и соответствующую точку. В текущем Curve таких методов нет. Для равномерного разбиения используйте uniform() или uniform_points(); это не замена смещению на произвольное расстояние.

Длину и смещение по длине можно вычислить через OCP. curve.native() материализует кривую, результат вычисления OCP — обычное число, не зависимый Scalar. Начальный параметр и расстояние выбирайте внутри диапазона конечной кривой; перед чтением результата проверяйте IsDone().

import math
from zencad import *
from OCP.GeomAdaptor import GeomAdaptor_Curve
from OCP.GCPnts import GCPnts_AbscissaPoint

curve = circle(5, wire=True).curve()
interval = curve.range()
start, end = float(interval.lower), float(interval.upper)
adaptor = GeomAdaptor_Curve(curve.native(), start, end)
length = GCPnts_AbscissaPoint.Length_s(adaptor, start, end)
solver = GCPnts_AbscissaPoint(adaptor, length / 4, start)
assert solver.IsDone()
parameter = solver.Parameter()
point = curve.point(parameter)
assert abs(length - 10 * math.pi) < 1e-7
assert abs(float(point.x)) < 1e-7
assert abs(float(point.y) - 5) < 1e-7

Историческая функция tube

Старая tube(spine, r) строила боковую оболочку круглого профиля, а не трубу с толщиной стенки. Для такой поверхности используйте pipe_shell([profile], spine, solid=False). Профиль должен находиться в начале траектории и быть перпендикулярен её касательной. В примере ниже траектория направлена по Z, а круг лежит в XY.

solid=True создаёт закрытое тело. Для трубы с толщиной стенки вычтите развёртку меньшего радиуса, как в разделе Траекторная развёртка. Старые bounds=True и параметры аппроксимации tol, cont, maxdegree, maxsegm не имеют одноимённой автоматической замены: pipe_shell возвращает одну форму, не кортеж с граничными рёбрами.

from zencad import *

spine = segment((0, 0, 0), (0, 0, 20))
profile = circle(3, wire=True)
surface = pipe_shell([profile], spine, solid=False)
body = pipe_shell([profile], spine)
assert isinstance(surface, Shell)
assert isinstance(body, Solid)
surface.assert_valid()
body.assert_valid()