Графики полярных функций с помощью UIBezierPath

Можно ли построить график полярной функции с помощью UIBezierPath? Я говорю не только о кругах, я говорю о кардиоидах, лимаконах, лемнискатах и ​​т. д. В основном у меня есть один UIView, и я хочу нарисовать форму в представлении.


person Josh Gafni    schedule 23.03.2015    source источник


Ответы (2)


Для таких фигур нет встроенных методов, но вы всегда можете аппроксимировать их серией очень коротких прямых линий. У меня была причина аппроксимировать круг таким образом, и круг с ~ 100 прямыми линиями выглядит идентично кругу, нарисованному с помощью ovalInRect. При этом было проще всего сначала создать точки в полярных координатах, а затем преобразовать их в цикле в прямоугольные координаты, прежде чем передать массив точек методу, в котором я добавляю линии к пути Безье.

person rdelmar    schedule 23.03.2015

Вот моя быстрая вспомогательная функция (полностью прокомментированная), которая генерирует координаты (x, y) в данном CGRect из функции полярных координат.

func cartesianCoordsForPolarFunc(frame: CGRect, thetaCoefficient:Double, thetaCoefficientDenominator:Double, cosScalar:Double, iPrecision:Double) -> Array<CGPoint> {

    // Frame: The frame in which to fit this curve.
    // thetaCoefficient: The number to scale theta by in the cos.
    // thetaCoefficientDenominator: The denominator of the thetaCoefficient
    // cosScalar: The number to multiply the cos by.
    // iPrecision: The step for continuity. 0 < iPrecision <= 2.pi. Defaults to 0.1

    // Clean inputs
    var precision:Double = 0.1 // Default precision
    if iPrecision != 0 {// Can't be 0.
        precision = iPrecision
    }

    // This is ther polar function
    // var theta: Double = 0 //  0 <= theta <= 2pi
    // let r = cosScalar * cos(thetaCoefficient * theta)

    var points:Array<CGPoint> = [] // We store the points here
    for theta in stride(from: 0, to: 2*Double.pi * thetaCoefficientDenominator, by: precision) { // Try to recreate continuity
        let x = cosScalar * cos(thetaCoefficient * theta) * cos(theta) // Convert to cartesian
        let y = cosScalar * cos(thetaCoefficient * theta) * sin(theta) // Convert to cartesian

        let scaled_x = (Double(frame.width) - 0)/(cosScalar*2)*(x-cosScalar)+Double(frame.width) // Scale to the frame
        let scaled_y = (Double(frame.height) - 0)/(cosScalar*2)*(y-cosScalar)+Double(frame.height) // Scale to the frame

        points.append(CGPoint(x: scaled_x, y:scaled_y)) // Add the result
    }

    return points
}

Учитывая эти точки, вот пример того, как вы могли бы нарисовать UIBezierPath. В моем примере это пользовательская функция UIView, которую я бы назвал UIPolarCurveView.

let flowerPath = UIBezierPath() // Declare my path

// Custom Polar scalars
let k: Double = 9/4
let length = 50

// Draw path
let points = cartesianCoordsForPolarFunc(frame: frame, thetaCoefficient: k, thetaCoefficientDenominator:4 cosScalar: length, iPrecision: 0.01)      flowerPath.move(to: points[0])
for i in 2...points.count {         
       flowerPath.addLine(to: points[i-1])
}

flowerPath.close()

Вот результат: График полярной кривой, приведенный в примере PS: Если вы планируете иметь несколько графиков в одном кадре, обязательно измените дополнение масштабирования, сделав второй cosScalar самым большим из используется cosScalars. Вы можете сделать это, добавив аргумент к функции в примере.

person donkey    schedule 12.10.2018