2016-11-29 19 views
0

Как найти крайний левый/правый пункт кривой пути SVG C (безье)? Я знаю, что есть getBoundingClientRect() и getBBox(), но ни один из них не применяется, поскольку они возвращают только одну координату точки.Найти самую правую/левую точку пути SVG


Просто, чтобы избежать проблем XY - Я хочу, чтобы разделить один путь, состоящий из кривых Безье на несколько дорожек каждый однообразно, идущих слева направо (или справа налево). Это означает, что на любом одном пути не должно быть двух точек, имеющих равную координату X. Я понимаю, что требуемая точка разделения потенциально может быть внутри ограничивающая рамка сегмента, таким образом, не является самой левой/самой правой, но я почти уверен, что способ найти такую ​​точку должен использовать те же методы, что и найти горизонтально экстремальную точку.

+1

Что делать вы имеете в виду 'getBBpox (0' возвращает« единственную точку »?' getBBox() 'возвращает ограничивающий прямоугольник пути. Самая левая точка должна быть' bbox.x', а крайняя справа должна быть 'bbox.x + bbox.width 'Это то, что вы хотели? –

+0

'getBBox' может сообщить мне координату« x »целевой точки, но не' y'. Это то, что я имею в виду, когда говорят только о единой координате. –

ответ

0

комментарий Пола Леб и модная анимация на the wiki вдохновила меня на решение. Она основана главным образом на следующих условиях:

  • Значение параметра t из [0, 1] может быть сопоставлено с кривой точек.

  • Для любой точки значения параметра на кривой может быть построена шаг за шагом линейно комбинируя пары соседних контрольных точек в промежуточные контрольные точки высшего «глубины». Эта операция может быть повторена до тех пор, пока только одна точка влево - точка на кривой сама.

  • Координаты промежуточных точек могут быть определены t -полины степени, равной точке «глубина». А коэффициенты эти полиномы в конечном счете зависят только от координат исходных контрольных точек .

  • Предпоследний этап строительства дает 2 точки, которые определяют тангенс к кривого в конечной точке, а также координаты этих точек контролируется квадратичным полиномом.

  • Имея направление касательной в вопросе, как вектора позволяет построить квадратное уравнение против t, где кривая требуемой касательной.

Таким образом, на самом деле, найти требуемые точки могут быть выполнены в постоянном O(1) время:

tangentPoints: function(tx, ty){ 
    var ends = this.getPolynoms(2); 
    var tangent = [ends[1][0].subtractPoly(ends[0][0]), 
        ends[1][1].subtractPoly(ends[0][1])]; 
    var eq = tangent[0].multiplyScalar(ty).subtractPoly(tangent[1].multiplyScalar(tx)); 
    return solveQuadratic(...eq.values).filter(t => t >= 0 && t <= 1); 
    } 

Полный код с помогая Polynom класса и визуальной демонстрации я помещается в this repo и fiddle

0

Вам нужно будет перебирать длину пути с помощью метода .getPointAtLength(i), а затем найти пределы. Показался, как забавная вещь, чтобы сделать, так что я сделал быструю и грязную реализацию, это важная часть:

function findLimits(path) { 

    var boundingPoints = { 
    minX: {x: dimensions.width, y: dimensions.height}, 
    minY: {x: dimensions.width, y: dimensions.height}, 
    maxX: {x: 0, y: 0}, 
    maxY: {x: 0, y: 0} 
    } 
    var l = path.getTotalLength(); 
    for (var p = 0; p < l; p++) { 
    var coords = path.getPointAtLength(p); 
    if (coords.x < boundingPoints.minX.x) boundingPoints.minX = coords; 
    if (coords.y < boundingPoints.minY.y) boundingPoints.minY = coords; 
    if (coords.x > boundingPoints.maxX.x) boundingPoints.maxX = coords; 
    if (coords.y > boundingPoints.maxY.y) boundingPoints.maxY = coords; 
    } 
    return boundingPoints 
} 

Вы можете найти реализацию здесь: https://jsfiddle.net/4gus3hks/1/

enter image description here

+0

У этого есть линейная производительность O (длина). Есть ли способ сделать это быстрее, или, может быть, некоторые из готовых продуктов? –

+1

См. Этот вопрос для математического решения вместо итеративного. http://stackoverflow.com/questions/24809978/calculating-the-bounding-box-of-cubic-bezier-curve –