2013-03-06 2 views
3

Я пытаюсь выполнить логические операции на SVG-контурах (которые содержат безье, как квадратичные, так и кубические), используя JS Clipper.Преобразование SVG-пути в полигоны для использования в Javascript Clipper

JS Clipper начинается с полигонов, затем выполняет операцию, а затем, похоже, преобразует их обратно в пути SVG.

В приведенной ниже функции показан путь SVG, но приведенный ниже пример начинается с двух полигонов.

Пример функции:

// Polygon Arrays are expanded for better readability 

function clip() { 
    var subj_polygons = [ 
    [{ 
     X: 10, 
     Y: 10 
    }, { 
     X: 110, 
     Y: 10 
    }, { 
     X: 110, 
     Y: 110 
    }, { 
     X: 10, 
     Y: 110 
    }], 
    [{ 
     X: 20, 
     Y: 20 
    }, { 
     X: 20, 
     Y: 100 
    }, { 
     X: 100, 
     Y: 100 
    }, { 
     X: 100, 
     Y: 20 
    }] 
    ]; 

    var clip_polygons = [ 
    [{ 
     X: 50, 
     Y: 50 
    }, { 
     X: 150, 
     Y: 50 
    }, { 
     X: 150, 
     Y: 150 
    }, { 
     X: 50, 
     Y: 150 
    }], 
    [{ 
     X: 60, 
     Y: 60 
    }, { 
     X: 60, 
     Y: 140 
    }, { 
     X: 140, 
     Y: 140 
    }, { 
     X: 140, 
     Y: 60 
    }] 
    ]; 

    var scale = 100; 
    subj_polygons = scaleup(subj_polygons, scale); 
    clip_polygons = scaleup(clip_polygons, scale); 

    var cpr = new ClipperLib.Clipper(); 
    cpr.AddPolygons(subj_polygons, ClipperLib.PolyType.ptSubject); 
    cpr.AddPolygons(clip_polygons, ClipperLib.PolyType.ptClip); 

    var subject_fillType = ClipperLib.PolyFillType.pftNonZero; 
    var clip_fillType = ClipperLib.PolyFillType.pftNonZero; 
    var clipTypes = [ClipperLib.ClipType.ctUnion]; 
    var clipTypesTexts = "Union"; 
    var solution_polygons, svg, cont = document.getElementById('svgcontainer'); 

    var i; 
    for (i = 0; i < clipTypes.length; i++) { 
    solution_polygons = new ClipperLib.Polygons(); 
    cpr.Execute(clipTypes[i], solution_polygons, subject_fillType, clip_fillType); 
    console.log(polys2path(solution_polygons, scale)); 
    } 

} 

// helper function to scale up polygon coordinates 
function scaleup(poly, scale) { 
    var i, j; 
    if (!scale) scale = 1; 
    for (i = 0; i < poly.length; i++) { 
    for (j = 0; j < poly[i].length; j++) { 
     poly[i][j].X *= scale; 
     poly[i][j].Y *= scale; 
    } 
    } 
    return poly; 
} 

// converts polygons to SVG path string 
function polys2path(poly, scale) { 
    var path = "", 
    i, j; 
    if (!scale) scale = 1; 
    for (i = 0; i < poly.length; i++) { 
    for (j = 0; j < poly[i].length; j++) { 
     if (!j) path += "M"; 
     else path += "L"; 
     path += (poly[i][j].X/scale) + ", " + (poly[i][j].Y/scale); 
    } 
    path += "Z"; 
    } 
    return path; 

} 

ответ

3

я предполагаю, что вы имеете в виду какой-то путь к SVG преобразования многоугольника.

Я много искал, но не нашел ничего надежного и готового решения.

Путь SVG может состоять из десяти различных сегментов или 20, если учесть как относительные, так и абсолютные координаты. Они представлены как буквы в d-атрибуте элемента пути: относительные - mhvlcqastz, а абсолютные - MHVLCQASTZ. Каждый из них имеет разные атрибуты: a (эллиптическая дуга) является самым сложным. Наиболее удобным и гибким типом является c (кубическая кривая безье), поскольку он может представлять все другие типы с довольно высокой точностью, как показывают эти примеры: http://jsbin.com/oqojan/32, http://jsbin.com/oqojan/42.

Библиотека Raphael JS имеет Path2Curve -функцию, которая может преобразовывать все сегменты пути в кубические кривые и может также обрабатывать сложную дугу до кубического преобразования. К сожалению, у него есть ошибка, так что он не может обрабатывать все возможные комбинации сегментов пути, но, к счастью, имеется доступная фиксированная версия библиотеки: http://jsbin.com/oqojan/32/edit (посмотрите на Javascript-окно).

Когда все сегменты пути преобразуются в кубические кривые, их можно преобразовать в отдельные сегменты линии. Есть несколько способов, и лучше всего выглядит an adaptive recursive subdivision method, который производит больше линейных сегментов с резкими поворотами кривой и меньше в других частях кривой, чтобы добиться баланса верности кривой и низкого количества сегментов, чтобы максимизировать скорость рендеринга, но, к сожалению, это не мог справиться со всеми коллинеарными случаями.Я удалось превратить метод AntiGrain, чтобы Javascript и добавил presplitting функциональность, которая делит кривую в локальных экстремумов (первые производные корни) и после этого метод AntiGrain обрабатывает также все возможные коллинеарных случая:

коллинеарны горизонтальная: http://jsbin.com/ivomiq/6
Набор разные случаи: http://jsbin.com/ivomiq/7
Случайные: http://jsbin.com/ivomiq/8
Коллинеарной повернуты: http://jsbin.com/ivomiq/9

всех вышеуказанные образцы имеют два пути в верхней части друг с другом, чтобы показать возможные ошибки в адаптивном алгоритме: красный кривой расщепляются с помощью ве ry медленный метод грубой силы, а зеленый - с использованием метода AntiGrain. Если вы видите не красное вообще, метод AntiGrain approximate()-function работает так, как ожидалось.

ОК, теперь мы отремонтировали Рафаэль и отремонтировали AntiGrain. Если мы объединим эти оба метода, мы можем создать функцию, которая преобразует любой элемент пути SVG в многоугольник (один или несколько подполигонов). Я не уверен на 100%, что это лучший или самый быстрый метод, но он должен использоваться. Конечно, лучше всего было бы использовать встроенный браузер ...

+0

Будет ли это решение работать в ЛЮБОЙ форме независимо от сложности? Я отказался от попыток использовать вашу библиотеку из-за перехода к преобразованию многоугольника. Мне действительно удалось использовать этот метод из Phrogz: https://gist.github.com/Phrogz/845901 для преобразования в многоугольники с одной большой проблемой. Мои пользователи должны нарисовать очень и очень сложные фигуры, которые должны быть булевыми, БЕЗ ПОТЕРИ верности на любых кривых. Для этого требуется более 800 выборок, необходимых для полигонирования, которые в большинстве случаев не работают с решением Phrogz. Считаете ли вы, что Raphael + AG будет работать намного лучше? –

+0

Мое решение предназначено только для svg-paths, поэтому вам нужно сначала преобразовать другие формы в пути (см. Https://github.com/johan/svg-js-utils/blob/master/paths.js, pathify() -функции). Я считаю, что качество конверсии очень хорошее (потому что вы можете настроить точность с помощью порога угла, а также общий масштабный параметр), используя предлагаемое мной решение. И я также опробовал решение Phrogz, которое является типичным методом грубой силы, и оно медленное, когда формы сложны и производят слишком много или слишком мало очков. Решение Antigrain дает оптимальное количество точек. Что такое AG? –

+0

Я могу попытаться помочь, если увижу достаточно вашего кода. Вы можете связаться со мной, используя [email protected] Возможно, нам лучше продолжить эту дискуссию по электронной почте, и когда решение будет найдено, для публикации необходимых шагов или функций здесь. –

0

вы можете использовать De Casteljau's algorithm разбить на более мелкие bezier curve прямые линии, и присоединиться к ним, чтобы создать polygon.

Вот некоторые ссылки на De Casteljau's algorithm

Смежные вопросы