Raphael.path2curve не поддерживает первоначальный путь

У меня проблема с Raphael.path2curve(). Функция изменяет строку пути SVG, так что все команды пути преобразуются в абсолютные кубические кривые (C). Функция поддерживает все команды пути (mlcqahvstMLCQAHVSTсм. SVG SPEC).

Raphael.path2curve() может обрабатывать пути скважин во многих случаях, например. Он может даже правильно преобразовать дуги в кубики, что не является простым вычислением. Я сделал много тестов и понял, что пути, которые состоят из команд QT, CS или же HT хорошо конвертирует Нет проблем и со следующим:MS, HS, VS, LS, TC, TH, TL, TV, QA, TA,

Но он не может обрабатывать команды QS, TS, AS, TT (в этой последовательности).

Если мы, например. Иметь такой путь, преобразование не удается:

M 0 0  T 205.4 112.9  S 260.8 23.36 82.45 72.86 

Но это преобразует правильно:

M 0 0  S 211.9 54.20 52.14 144.4  T 98.85 44.45 

Итак, МТС не в порядке, но MST в порядке. Проблемными являются S и T, потому что они всегда под вопросом, когда что-то не получается.

Я создал генератор случайных путей (медленно, но для скорости использую jsbin), где вы можете получить случайный путь и преобразовать его в кубические команды, используя Raphael.path2curve(). В скрипте щелкните SVG или нажмите ввод в поле ввода, чтобы получить новый случайный путь. Повторяйте, пока не найдете неправильный. В jsfiddle в окне HTML есть параметр var list = "st"; где вы можете установить команды пути для рандомизации.

Это пример изображения. Синий - это исходный путь, а красный - преобразованный путь. Они должны быть идентичны.

дорожка

Что я должен сделать с кодом Рафаэля, чтобы получить правильное преобразование?

(Я сделал сообщение об ошибке, но теперь пытался решить проблему несколько часов без удачи.

1 ответ

Решение

Кажется, я наконец-то все исправил. Пожалуйста, проверьте! Я сделал две версии JSBIN:

1) НЕ ФИКСИРОВАННАЯ версия, которая использует неизмененный Raphael lib: http://jsbin.com/oqojan/33.
2) ИСПРАВЛЕННАЯ версия, в которой модифицирована функция path2curve(): http://jsbin.com/oqojan/32.

В обеих версиях есть черный (оригинал) и белый (нормализованный) путь. Если все работает хорошо, вы не должны видеть белый путь ниже черного пути. Если вы видите белый путь, в коде lib есть ошибка (см. Ниже объяснение небольшого мерцания).

Пожалуйста, удерживайте кнопку ENTER в поле ввода около минуты. Код генерирует случайные пути многократно, пока ENTER не работает. Изменить атрибут var list = "mlcqahvstz"; изменить базовые буквы для рандомизации.

И вот объяснение того, что я должен был сделать с кодом lib. В оригинальном lib-коде Raphaël 2.1.0 есть функция path2curve(), которая имеет следующие строки:

case "S":
    nx = d.x + (d.x - (d.bx || d.x));
    ny = d.y + (d.y - (d.by || d.y));
    path = ["C", nx, ny][concat](path.slice(1));
    break;
case "T":
    d.qx = d.x + (d.x - (d.qx || d.x));
    d.qy = d.y + (d.y - (d.qy || d.y));
    path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
    break;

Когда я изменил их на:

case "S":
    if (pcom == "C" || pcom == "S") { // In "S" case we have to take into
                                      // account, if the previous command
                                      // is C/S.
        nx = d.x * 2 - d.bx;          // And reflect the previous 
        ny = d.y * 2 - d.by;          // command's control point relative
                                      // to the current point.  
    }
    else {                            // or some else or nothing
        nx = d.x;
        ny = d.y;
    }
    path = ["C", nx, ny][concat](path.slice(1));
    break;
case "T":
    if (pcom == "Q" || pcom == "T") { // In "T" case we have to take
                                      // into account, if the
                                      // previous command is Q/T.
        d.qx = d.x * 2 - d.qx;        // And make a reflection similar 
        d.qy = d.y * 2 - d.qy;        // to case "S".
    }
    else {                            // or something else or nothing
        d.qx = d.x;
        d.qy = d.y;
    }
    path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
    break;

функция работала как ожидалось (т.е. учитывает исходную форму пути при каждой возможной комбинации команд пути). pcom Переменная относится к предыдущему сегменту ОРИГИНАЛЬНОГО пути, и мне пришлось также добавить способ получить pcom, что было довольно легко, потому что в отношении всех других команд пути, кроме A, преобразование из исходного типа сегмента пути в кубическую кривую (C) дает только одну кубическую команду. В случае A функция может выдавать более одной команды C (короткие углы дают один или несколько сегментов C, а большие углы дают больше).

Единственное незначительное несоответствие исходит от команд Z, потому что Raphaël конвертирует каждый Z в C. Это влияет на визуальное отображение начала (или конца) пути, но разница невелика. Я предполагаю, что он конвертирует Z в C, чтобы сделать пути анимируемыми. Если анимация не нужна, то вы можете отредактировать функцию, чтобы оставить Z:s неконвертированным, и в этом случае точность преобразования будет превосходной.

Я поражен, что все команды пути могут быть представлены в виде кубических кривых так надежно!

Я надеюсь, что эта ошибка будет исправлена ​​в будущем выпуске Raphaël.

РЕДАКТИРОВАТЬ: Сделал испытательный стенд также для анимации пути:
1) НЕ УСТАНОВЛЕНО: http://jsbin.com/oqojan/44
2) ИСПРАВЛЕНО: http://jsbin.com/oqojan/42

После тщательного тестирования с неанимированными и анимированными путями я могу подтвердить, что мое исправление функции path2curve стабильно и может быть реализовано в рабочем коде. Если вы хотите быть уверены, пожалуйста, используйте вышеупомянутые испытательные стенды.

Другие вопросы по тегам