Damiano Miazzi
Damiano Miazzi

Reputation: 2315

SwiftUI, create a circle for each CGpoint in Array

I have an array of CGPoint and I'm trying to draw a little circle for each CGPoint location in this array (Using SwiftUI).

I have tried different approaches but have not been successful, I'm looking for some help.

my array : CGPoint is called "allFaceArray"

first try(doesn't working) throws an error : Generic struct 'ForEach' requires that 'CGPoint' conform to 'Hashable'

struct FaceFigure : View {
    @ObservedObject var ce : CameraEngine
    var size: CGSize
    var body: some View {
        if !ce.allFaceArray.isEmpty{
            ZStack{
                
                ForEach(ce.allFaceArray, id: \.self) { point in
                    Circle().stroke(lineWidth: 2.0).fill(Color.green)
                }

            }
        }
    }
}

second try I make a custom shape

struct MakeCircle: Shape {
    var arrayViso: [CGPoint]
    func path(in rect: CGRect) -> Path {
        var path = Path()
        for punti in arrayViso{
            
            let radius = 2
            path.addArc(
                center: punti,
                radius: CGFloat(radius),
                startAngle: Angle(degrees: 0),
                endAngle: Angle(degrees: 360),
                clockwise: true)
          
        }
        return path
    }
}

and I use it like this:

struct FaceFigure : View {
    @ObservedObject var ce : CameraEngine
    var size: CGSize
    var body: some View {
        if !ce.allFaceArray.isEmpty{
            ZStack{
               MakeCircle(arrayViso: ce.allFaceArray)
                   .stroke(lineWidth: 2.0)
                  .fill(Color.green)
            }
        }
    }
}

but like this every points is connect each other with a line I don't know why...

thanks for the help

Upvotes: 1

Views: 1506

Answers (3)

SamB
SamB

Reputation: 1710

For your second approach, you can create a separate path for each point in your array and add them to the path you already defined as var path = Path(). This way your second approach would work fine

struct MakeCircle: Shape {
    var arrayViso: [CGPoint]
    func path(in rect: CGRect) -> Path {
        var path = Path()
        for punti in arrayViso{
            var circle = Path()
            let radius = 2

            circle.addArc(
                center: punti,
                radius: CGFloat(radius),
                startAngle: Angle(degrees: 0),
                endAngle: Angle(degrees: 360),
                clockwise: true)

            path.addPath(circle)
        }
        return path
    }
}

Upvotes: 3

Visal Rajapakse
Visal Rajapakse

Reputation: 2042

The first method can be used. Although you can't directly call ForEach() for CGPoint arrays. Instead you can use ForEach with a Range<T> like follows


struct ContentView: View {

    var allFaceArray = [
        CGPoint(x: 0, y: 0),
        CGPoint(x: 30, y: 50),
        CGPoint(x: 100, y: 100),
        CGPoint(x: 100, y: 500),
    ]
    var body: some View {
        ZStack {
            ForEach(0..<allFaceArray.count) { x in //<- Passing the count of the array as a range
                Circle().stroke(lineWidth: 2.0).fill(Color.green)
                    .position(allFaceArray[x])
            }
        }
    }
}

The output of the above code is, enter image description here

Upvotes: 2

OOPer
OOPer

Reputation: 47886

When you find Generic struct 'ForEach' requires that 'CGPoint' conform to 'Hashable', making CGPoint conform to Hashable would be one way to solve it.

Please use this extension and re-try your first try:

extension CGPoint: Hashable {
    public func hash(into hasher: inout Hasher) {
        hasher.combine(x)
        hasher.combine(y)
    }
}

Upvotes: 2

Related Questions