Swift Swift - 4 months ago 31
Swift Question

How to access a sequence of all elements in Array of CGPoints in Swift

I have an array named Trapezoid containing CGPoints from 0 to n. How to get all the elements of this array and feed them to For-In loop?

In my code I have an error at first line: Cannot convert value of type '[Trapezoid].Type' (aka 'Array<[Trapezoid]>.Type') to specified type '[CGPoint]'.

let printedArray: [CGPoint] = [Trapezoid]

for (index, calculatedPoint) in printedArray.enumerate() {

let pointElement = NSXMLElement(name: "point")
let xx = calculatedPoint.x
let yy = calculatedPoint.y

pointElement.attributes = [
xmlAttributeWithName("id", value: "\(index)"),
xmlAttributeWithName("x", value: "\(xx)"),
xmlAttributeWithName("y", value: "\(yy)") ]
}


//Declaration of Trapezoid

enum Trapezoid {

case vertexOne(point: CGPoint)
case vertexTwo(point: CGPoint)
case vertexThree(point: CGPoint)
case vertexFour(point: CGPoint)

func controlPointCoordinates() -> [CGPoint] {

switch self {

case .vertexOne(let point): return [point]
case .vertexTwo(let point): return [point]
case .vertexThree(let point): return [point]
case .vertexFour(let point): return [point]
}
}


func segmentedPath(path: CGMutablePath) {

switch self {

case .vertexOne(let point): CGPathMoveToPoint(path, nil, point.x, point.y)
case .vertexTwo(let point): CGPathAddLineToPoint(path, nil, point.x, point.y)
case .vertexThree(let point): CGPathAddLineToPoint(path, nil, point.x, point.y)
case .vertexFour(let point): CGPathAddLineToPoint(path, nil, point.x, point.y)

CGPathCloseSubpath(path)
NSColor.darkGrayColor().setStroke()
}
}
}

Rob Rob
Answer

Presumably you have some array that is an array of Trapezoid that you want to convert to an array of CGPoint?

var someArrayOfTrapezoids = [Trapezoid]()
// add some Trapezoid values

Given that controlPointCoordinates returns an array with a single CGPoint, you could convert that to an array of CGPoint with either:

let printedArray = someArrayOfTrapezoids.map { $0.controlPointCoordinates()[0] }

or

let printedArray = someArrayOfTrapezoids.flatMap { $0.controlPointCoordinates() }

There is some dissonance here, though, given that a type called Trapezoid sounds like it should be a full trapezoid, but it's only one coordinate of a trapezoid. I'd either redefine it to be a single point, e.g.

enum TrapezoidPoint {

    case vertexOne(point: CGPoint)
    case vertexTwo(point: CGPoint)
    case vertexThree(point: CGPoint)
    case vertexFour(point: CGPoint)

    func controlPointCoordinate() -> CGPoint {      // note, not [CGPoint], and not `controlPointCoordinates`, but rather `controlPointCoordinate`
        switch self {
        case .vertexOne(let point): return point
        case .vertexTwo(let point): return point
        case .vertexThree(let point): return point
        case .vertexFour(let point): return point
        }
    }

    ...
}

In which case you'd do:

let printedArray = arrayOfTrapezoidPoints.map { $0.controlPointCoordinate() } // the `[0]` is no longer needed

Or define it to be all four points:

struct Trapezoid {

    let vertexOne: CGPoint
    let vertexTwo: CGPoint
    let vertexThree: CGPoint
    let vertexFour: CGPoint

    func controlPointCoordinates() -> [CGPoint] {
        return [vertexOne, vertexTwo, vertexThree, vertexFour]
    }
    ...
}

And then you could do:

let printedArray = someSingleTrapezoidWithFourPoints.controlPointCoordinates()