December 29th, 2018

404

ура, покрыл

Я, кажется, покрыл все кейсы для getPath (прямые, кривые двух видов, круги, эллипсы, что-попало-для-дискретизации, fill). В свете этого я понял, что ошибался с моделью для класса path (M - move - это первый глагол для любой формы, которая не вырождается в другие теги (circle)).

Теперь надо понять, как это аккуратно закодить. С линией было всё просто - первая точка, M, дальше линии (L). А вот эллипс задаётся, например, двумя дугами (arc), которые тоже начинаются с M.

В класс "path" я заложил идею, что он сам знает, кто там 'M', а кто 'L'. Это сильно упрощает циклы в остальном коде, которым не надо теперь отдельно обрабатывать первую точку. Но у нас есть 'A' и прочие сложности....

Пожалуй, я оставлю этот принцип. add_line_point надо будет вызывать всегда в начале (для задачи 'M'), даже для дуг и кривых. Первая line_point (я правильно назвал это 'line point'?) становится 'M', остальные превращаются в 'L'.

... Второй вариант: add_line_point -> add_point(type, value), либо набор add_line_point, add_quardatic_point, add_arc_point, add_smooth_quadratic, etc. Первая точка всегда превращается в 'M' вне зависимости от типа.

.. Второй момент: есть места, где мне передают пачку точек. Может быть, я всегда буду принимать в класс список, а если кому-то надо передать одно значение - пусть [] его? Или добавить магии с автоопределением?

Пока что буду переписывать на add_?_points, видимо. Автодетект - вопрос открытый.

Отдельные две боли для меня:
1) Возврат круга как - в принципе, это же проблема getPath, а не Path. Ну будет у меня класс circle. Делать ли там общий класс над ними - вопрос открытый, ибо целиком libsvg я писать не собираюсь. И у меня батхёртит от отсутствия алгебраических типов в питоне. return -> Either(Circle, Path), ну круто же....

2) Кусок кода с определением "старая версия библиотеки". Буду химичить на тестах. Сейчас эта ветка вообще не может работать, потому что я случайно не добавил нужный импорт при переносе из Draft.py в getSVG.py.

UPD: В процессе борьбы за clarity, всё стало просто. Каждый метод называется по спекам (moveto, lineto, elliptical_arc, smooth_quadratic_bezier_curveto), у каждого своя конвенция по аргументам, но все они пишут в общий self.data. Поддерживается суммирование путей. Чуть-чуть сахара - первый lineto конвертируется в moveto автоматически. На выходе из контекстного менеджера проверяется, что есть moveto.

Вот код класса. За вычетом "pass" кусков, я открыт к предложениям.

https://github.com/amarao/FreeCAD/blob/3905d8974186aba43c90f429baa46a3fb8c1ad20/src/Mod/Draft/getSVG.py#L12
404

выдыхаем, выдыхаем

Уф, я перевёл getPath на контекстный менеджер. Стало меньше строк, уже, хотя я ничего, кроме контекстного менеджера и его функций не добавлял. Ощущение, как будто бежал по болоту по кочкам и, кажется, почти ничего не замочил.

Теперь можно начинать разбираться с этим ужасом в районе "if (int(occversion[0]) >= 7) and (int(occversion[1]) >= 1):"

Ужас не в этой проверке, а вот тут:
                            snip = Drawing.projectToSVG(e,drawing_plane_normal)
                            if snip:
                                try:
                                    a = "A " + snip.split("path d=\"")[1].split("\"")[0].split("A")[1]
                                except:
                                    pass
                                else:
                                    edata += a
                                    done = True


Во-первых у меня оно сейчас прикрыто raise NotImplemented, и оно не рейзится, значит, я этот кусок кода не трогаю в тестах. Это означает, что мне сейчас придётся делать соседний бранч и в нём пытаться выковырять с помощью print'ов что там приходит-уходит, чтобы таки этот тест написать.

Во-вторых, это просто какой-то ужас. Я могу сохранить его, и всего лишь передать эту "a" в path.elliptical_arc. Дополнительный фан состоит в том, что Drawing - это нифига не питон, это добрый-добрый C++, который реализует интерфейс для питона. В нём на 100+ строк написано главное:

ProjectionAlgos Alg(pShape->getTopoShapePtr()->getShape(),Vector);

И я это даже понять не могу. Либо это макрос, либо это какая-то фича С++, которой я не знаю (синтаксически).

Другими словами, "нам с этим жить". А жить будет БОЛЬНО (особенно в тестах), потому что у меня:

>>> Part.OCC_VERSION
'6.9.1.oce-0.18'
А ещё я не знаю, что такое 'occ' (oce). Примерно происходит от "OpenCASCADE Community Edition"... Ой, моки меня зовут, ой зовут...