-1

I'm working on a custom path for UIBezierPath, and I'm getting the "Cannot assign a value of type (CGFloat) to a value of type CGFloat." I think it's because there is some issue with typecasting? How can I fix this? The warnings are popping up for the "X = (b2 - b1) / (m1 - m2)" line and "Y = m1 * X + b1" line.

func lineIntersection(m1: CGFloat, b1: CGFloat, m2: CGFloat, b2: CGFloat, inout X: CGFloat, inout Y: CGFloat) -> Bool {
    if m1 == m2 {
    return false
}  else if X = (b2 - b1)/(m1 - m2) {
    return true
} else if Y = m1 * X + b1 {
    return true
    } else {
    return false
    }
}

I'll be calling this function in another function later on

func xxx() {
        var outX = CGFloat()
        var outY = CGFloat()
        lineIntersection(oldSlope, b1: oldIntercept, m2: newSlope, b2: newIntercept, X: &outX, Y: &outY)
}
James Yu
  • 23
  • 1
  • 5
  • 1
    Replace `=` with `==` in your `else if` conditions, also in this case no need for inouts. (unless you actually wanted to assign values to X and Y instead of comparing, but your code wouldn't work either for this). – Eric Aya Jul 31 '15 at 16:32
  • 1
    Are you sure you want `=` on those lines and not `==`? – Tom Harrington Jul 31 '15 at 16:33
  • 1
    You should really use `CGPoint` – Sulthan Jul 31 '15 at 16:33
  • You're probably coming from a C programming background and trying to combine assignment with conditional test. Swift finds this unsafe and doesn't allow it. – BaseZen Jul 31 '15 at 16:41
  • You really need to read at least the introduction to Swift in Apple's books. You are getting basic things totally wrong, and asking questions on Stackoverflow is no replacement for actually learning your trade. – gnasher729 Jul 31 '15 at 18:19

1 Answers1

2
  1. Swift doesn't have zero as a "false" value, you need to explicitly compare with != 0 in the ifs. Also, move the assignments to separate lines instead of doing it as part of the condition.

  2. Floating point equality comparisons are not reliable except in a few special cases, and this is not likely to be one of them.

  3. I would remove the inout parameters and return an optional CGPoint, i.e., -> CGPoint?. Return nil for false, and the CGPoint intersection for true.

Resulting function (I've removed the equality checks altogether; the floating point division by zero is not dangerous, we can check for Inf/NaN later):

func lineIntersection(m1 m1: CGFloat, b1: CGFloat, m2: CGFloat, b2: CGFloat) -> CGPoint? {
    let x = (b2 - b1) / (m1 - m2)
    let y = m1 * x + b1
    return y.isFinite ? CGPoint(x: x, y: y) : nil
}

Use at the calling location would be something like:

if let intersection = lineIntersection(m1: m1, b1: b1, m2: m2, b2: b2) {
    // use intersection.x and intersection.y
}

As for the literal question of how to typecast (although this was not the issue here), you can init even "basic types" with something like CGFloat(value), which results in a type conversion by "creating" a new CGFloat from value. Several types also have alternative ways to specify how exactly the conversion happens, e.g., Int32(truncatingBitPattern: largerInteger) takes the lowest 32 bits as they are, whereas just Int32(largerInteger) would crash if it over- or underflows. Casting as such is done with as (known to succeed at compile time), as? (try casting at runtime, nil on failure), as! (try casting at runtime, assert success).

Arkku
  • 41,011
  • 10
  • 62
  • 84