Using UIBeizerPath on Circle - ios

I want to make a circle which can be cut by percent, for example, 0.25 is 1/4 of the circle.
This is my code so far:
let circlePath = UIBezierPath(arcCenter: CGPoint(x: 100,y: 300), radius: CGFloat(20), startAngle: CGFloat(M_PI + M_PI_2), endAngle:CGFloat(90 * M_PI / 180, clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.CGPath
//change the fill color
shapeLayer.fillColor = UIColor.clearColor().CGColor
//you can change the stroke color
shapeLayer.strokeColor = UIColor.redColor().CGColor
//you can change the line width
shapeLayer.lineWidth = 3.0
view.layer.addSublayer(shapeLayer)
In startAngle I wrote CGFloat(M_PI + M_PI_2) because the start of the circle doesnt start in 0 but as in this picture:
In the endAngle line I wrote CGFloat(90 * M_PI / 180) because the formula from degrees to radians is: degrees*pi/180 .
BUT! In the view I get half of the circle and not quarter of the circle:
Does my endAngle formula is wrong?

I think what you want is for your start angle to be 0 and your end angle to be 90 * PI/180
What you have now is a curve that starts at the bottom 270, aka M_PI + M_PI/2 and goes to 90 (90 * M_PI / 180)
//Possibly what you want is for your endAngle = (90 * M_PI/180) + startAngle , aka a quarter more than where you started, i'm not sure which quarter of the circle you want

Because in iOS the top of the circle starts at 270 degrees, the startAngle is:
startAngle: CGFloat(M_PI + M_PI_2)
And the endAngle is:
endAngle:CGFloat((360 * 0.25 - 90)
Instead of 0.25, you can change it to any number between 0 to 1 (for example: if you want half of the circle to be full, change it to 0.5)

Related

BasicAnimation, Swift

I defined a circle like this :
let progressLayer = CAShapeLayer()
let ring = UIBezierPath(arcCenter: center, radius: 100, startAngle: -CGFloat.pi / 2 , endAngle: 2 * CGFloat.pi , clockwise: true)
progressLayer.path = ring.cgPath
progressLayer.strokeColor = UIColor.green.cgColor
progressLayer.fillColor = UIColor.clear.cgColor
view.layer.addSublayer(progressLayer)
Then I defined an animation that fill the border of my circle with a color and duration like this:
let basicAnimation = CABasicAnimation(keyPath: "strokeEnd")
basicAnimation.toValue = 1
basicAnimation.duration = 60 //Seconds !
basicAnimation.fillMode = .forwards
progressLayer.add(basicAnimation, forKey: "blablabla")
What happened is that the animation comes to the end of the circle with a delay of 12 seconds! (The circle is filled but 12 seconds left)
Why does this happened? Is it a trigonometry problem (startAngle endAngle)? I can't understand ...
There is an issue with the bezier path you are adding an extra quarter to the circle,
So Circle is filled at (60 / 5) * 4 = 48 seconds and the other 12 seconds is overdrawing on an already filled quarter.
Setting start Angle to 0 will fix the issue.
let ring = UIBezierPath(arcCenter: center, radius: 100, startAngle: CGFloat(0) , endAngle: 2 * CGFloat.pi , clockwise: true)

How can I draw line intersecting the arc perpendicularly(Core Graphics)?

I want to draw a line on the circle(intercepting the arc of the circle) perpendicularly like in the picture.
I am using this code to draw circle
let center = CGPoint(x: bounds.width / 2, y: bounds.height / 2)
let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: Conversion.degreesToRadians(value: CGFloat(0)), endAngle: Conversion.degreesToRadians(value: CGFloat(360)), clockwise: true)
path.lineWidth = 2
path.lineCapStyle = CGLineCap.square
UIColor.white.setStroke()
path.stroke()
The basic idea is that a circle has a certain radius about a center CGPoint. To figure out a point on the circle, you can calculate the x and y coordinates like so:
func point(center: CGPoint, radius: CGFloat, angle: CGFloat) -> CGPoint {
let x = center.x + radius * cos(angle)
let y = center.y + radius * sin(angle)
return CGPoint(x: x, y: y)
}
where the angle is measured in radians, starting at 3 o'clock and going clockwise.
So those perpendicular intersecting strokes are merely line segments between two CGPoint at a given angle, where the "radius" used for the start of the line segment might be, for example, something just less than the radius of the circle. For the ending point of the line, use the same angle, but then use a radius value just greater than the radius of the circle.

StrokeEnd not drawing full circle

I'm trying to build a progress view for a Music Player. I am totaly new to programming in general and now really reached a dead end here.
My progress works fine. I am animatig "strokeEnd" with the value (value/duration) of the Mediafile, but strokeEnd only ever reaches have of the circle. However, the song is then finished as well, this is why I think, somewhere it calculats wrong.
It is a very simple Shaplayer I am using.
var value: CGFloat = 0.0{
didSet {
redrawStrokeEnd() }
}
private func setupShapeLayer(shapeLayer: CAShapeLayer) {
let startAngle = CGFloat(M_PI_2)
let endAngle = CGFloat(M_PI_2 * 2 + M_PI_2)
progressLayer.path = UIBezierPath(arcCenter:centerPoint, radius: CGRectGetWidth(frame)/2 + 5, startAngle:startAngle, endAngle: endAngle, clockwise: true).CGPath
progressLayer.strokeStart = 0.0
progressLayer.strokeEnd = 0.0 }
func redrawStrokeEnd() {
progressLayer.strokeEnd = CGFloat(value / CGFloat(duration))}
value = currentTime and duration = Playbackduration.
I can't figure out, why stroke End does not move the full circle.
Perhaps you're using the wrong constant? As some of the other commenters have pointed out, a circle in radians traverses 2 * pi. However the constant M_PI_2 is equal to (pi / 2) So right now you're only traversing from (pi/2) -> (3pi/2)... or pi. If you really want to start at pi/2 try:
let startAngle = CGFloat(M_PI_2)
let endAngle = CGFloat(M_PI_2 + 2.0 * M_PI)
It's not strokeEnd the reason you see half circle. You just have wrong start and end angles for your path. You can set them as below to have a full circle :
let startAngle = CGFloat(M_PI_2)
let endAngle = CGFloat(5*M_PI_2)
Or better if you don't want to set angles by radians set them in degrees like this :
let startAngle = CGFloat(0 * M_PI / 180)
let endAngle = CGFloat(360 * M_PI / 180.0)
Just changing the start angle and end angle in your code will work for you.
let startAngle = -90.0
let endAngle = -90.01

How to make circle based on percentage?

I can create a circle, but instead I need it to start at "12:00" and go to a certain percentage.
let circlePath = UIBezierPath(arcCenter: CGPoint(x: 100,y: 100), radius: CGFloat(20), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.CGPath
//change the fill color
shapeLayer.fillColor = UIColor.clearColor().CGColor
//you can change the stroke color
shapeLayer.strokeColor = UIColor.redColor().CGColor
//you can change the line width
shapeLayer.lineWidth = 3.0
cell.progress.layer.addSublayer(shapeLayer)
You need to adjust the start and end angles to meet your criteria.
"12:00" on the circle would be 3pi/2 or -pi/2 (- CGFloat.pi / 2). A full circle is 2pi (2 * CGFloat.pi). A percentage of that is of course CGFloat.pi * 2 * percentage. So the end would be your start + that percentage.
let circlePath = UIBezierPath(
arcCenter: CGPoint(x: 100, y: 100),
radius: 20,
startAngle: - .pi / 2,
endAngle: - .pi / 2 + .pi * 2 * percentage ,
clockwise: true
)
where percentage is some CGFloat in the range 0.0 to 1.0.

how to calculate middle points on circular arc draw using UIBezierPath path ios or swift

i'm drawing arc using UIBezierPath. how can i calculate middle point of this arc.
let center = CGPoint(x: bounds.width / 2, y: bounds.height / 2)
var startValue: CGFloat = 0
var startAngle: CGFloat = 0
var endValue: CGFloat = 0
var endAngle: CGFloat = 0
startAngle = (startValue * 2 * CGFloat(M_PI)) - CGFloat(M_PI_2)
endValue = startValue + 0.20
endAngle = (endValue * 2 * CGFloat(M_PI)) -CGFloat(M_PI_2)
let path = UIBezierPath()
path.moveToPoint(center)
path.addArcWithCenter(center, radius: radius.outer, startAngle: startAngle, endAngle: endAngle, clockwise: true)
path.fill()
path.stroke()
The midPoint angle will be the average of your startAngle and your endAngle. This calculates the point based upon the center point and the radius.outer:
let midPointAngle = (startAngle + endAngle) / 2.0
let midPoint = CGPoint(x: center.x + radius.outer * cos(midPointAngle), y: center.y - radius.outer * sin(midPointAngle))

Resources