user3069232
user3069232

Reputation: 8995

SwiftUI rotate together with addArc doesn't work correctly in some cases

Swift 5, iOS 13

Using addArc to draw a semi-circle and then using rotation3DEffect to rotate it. On the y axis it works perfectly, but in the x axis is seems broken. Am I doing something wrong here.

I got this code to work. But it is a kludge.

I want to us the x axis on the MyArc2 and not have to use an offset+rotationEffect. The first image is what you see with this code as is.

However if I do use x axis it doesn't draw it correctly.

import SwiftUI

struct ContentView: View {
  @State var turn:Double = 0
  var body: some View {
    return VStack {
    Image(systemName: "circle")
      .foregroundColor(Color.blue)
      .onTapGesture {
        withAnimation(.linear(duration: 36)) {
          self.turn = 360
       }
     }
     Globe2View(turn: $turn)
    } // VStack
  }
 }

 struct Globe2View: View {
  struct MyArc : Shape {
    func path(in rect: CGRect) -> Path {
    var p = Path()
    p.addArc(center: CGPoint(x: UIScreen.screenWidth/2, y:UIScreen.screenHeight/2), radius: 64, startAngle: .degrees(90), endAngle: .degrees(270), clockwise: true)
    return p
}
}
   struct MyArc2 : Shape {
   func path(in rect: CGRect) -> Path {
    var p = Path()
    p.addArc(center: CGPoint(x: UIScreen.screenWidth/2, y:UIScreen.screenHeight/2), radius: 64, startAngle: .degrees(90), endAngle: .degrees(270), clockwise: true)
  return p
  }
  }
  @Binding var turn:Double
  var body: some View {
    ZStack {
     ForEach(0..<12) { loop in
      MyArc()
        .stroke(Color.blue, lineWidth: 2)
        .rotation3DEffect(.degrees(self.turn + Double((loop * 30))), axis: (x: 0, y: -1, z: 0), anchor: UnitPoint.center, anchorZ: 0, perspective: 0)
  }
      ForEach(0..<12) { loop in
       MyArc2()
         .stroke(Color.green, lineWidth: 2)
        .rotation3DEffect(.degrees(self.turn + Double((loop * 30))), axis: (x: 0, y: -1, z: 0), anchor: UnitPoint.center, anchorZ: 0, perspective: 0)
        .rotationEffect(.degrees(90))
        .offset(x: 20, y: 20)
    }
  }
 }
}

enter image description here

If I change the last few lines so they look like this...

struct MyArc2 : Shape {
func path(in rect: CGRect) -> Path {
    var p = Path()
    p.addArc(center: CGPoint(x: UIScreen.screenWidth/2, y:UIScreen.screenHeight/2), radius: 64, startAngle: .degrees(0), endAngle: .degrees(180), clockwise: true)
  return p
}
}

 ForEach(0..<12) { loop in
    MyArc2()
      .stroke(Color.green, lineWidth: 2)
      .rotation3DEffect(.degrees(self.turn + Double((loop * 30))), axis: (x: 1, y: 0, z: 0), anchor: UnitPoint.center, anchorZ: 0, perspective: 0)
//          .rotationEffect(.degrees(90))
//          .offset(x: 20, y: 20)
   }

enter image description here

Upvotes: 1

Views: 328

Answers (1)

Asperi
Asperi

Reputation: 258147

It is not clear why it is needed MyArc2 as it is the same, but the following, with simple fix in shape, just works as expected (to my mind).

Tested with Xcode 11.4 / iOS 13.4

demo

struct Globe2View: View {
    struct MyArc : Shape {
        func path(in rect: CGRect) -> Path {
            var p = Path()
            // used provided dynamic rect instead of hardcoded NSScreen
            p.addArc(center: CGPoint(x: rect.width/2, y:rect.height/2), radius: 64, startAngle: .degrees(90), endAngle: .degrees(270), clockwise: true)
            return p
        }
    }

    @Binding var turn:Double
    var body: some View {
        ZStack {
            ForEach(0..<12) { loop in
                MyArc()
                    .stroke(Color.blue, lineWidth: 2)
                    .rotation3DEffect(.degrees(self.turn + Double((loop * 30))), axis: (x: 0, y: -1, z: 0), anchor: UnitPoint.center, anchorZ: 0, perspective: 0)
            }
            ForEach(0..<12) { loop in
                MyArc()
                    .stroke(Color.green, lineWidth: 2)
                    .rotation3DEffect(.degrees(self.turn + Double((loop * 30))), axis: (x: 0, y: -1, z: 0), anchor: UnitPoint.center, anchorZ: 0, perspective: 0)
                    .rotationEffect(.degrees(90))
            }
        }
    }
}

Upvotes: 1

Related Questions