What is replace of the CGContextAddLineToPoint this is what I'm trying to do
for i in aerr {
//0.5f offset lines up line with pixel boundary
CGContextMoveToPoint(context, self.bounds.origin.x, self.font!.lineHeight * CGFloat(x) + baselineOffset)
CGContextAddLineToPoint(context, CGFloat(self.bounds.size.width), self.font!.lineHeight * CGFloat(x) + baselineOffset)
}
and I'm getting the following error. I know they clearly mention using move(to:) but how to use that?
'CGContextMoveToPoint' is unavailable: Use move(to:) instead
In Swift, you can simply use directly from your context because it methods is part of CGContext.
So CGContextMoveToPoint(context, x, y) will be context.move(to:CGPoint(x, y))
As same as, CGContextAddLineToPoint(context, x, y) will be context.addLine(to: CGPoint(x, y))
So your code will be
guard let context = UIGraphicsGetCurrentContext() else { return }
for i in aerr {
//0.5f offset lines up line with pixel boundary
context.move(to: CGPoint(x: self.bounds.origin.x, y: self.font!.lineHeight * CGFloat(x) + baselineOffset))
context.addLine(to: CGPoint(x: CGFloat(self.bounds.size.width), y: self.font!.lineHeight * CGFloat(x) + baselineOffset))
}
you can do it like this
context.move(to: .init(x: self.bounds.origin.x, y: self.font!.lineHeight * CGFloat(x) + baselineOffset))
Related
I've a QuadCurve and Line drawn using UIBezierPath in my custom view class. How can I get their intersection point as CGPoint?
For QuadCurve:
let path = UIBezierPath()
path.lineWidth = 3.0
path.move(to: CGPoint(x: 0, y: self.frame.size.height))
path.addQuadCurve(to: CGPoint(x: self.frame.size.width, y: 0), controlPoint: CGPoint(x: self.frame.size.width-self.frame.size.width/3, y: self.frame.size.height))
For Line:
let path2 = UIBezierPath()
path2.lineWidth = 3.0
path2.move(to: CGPoint(x: 250, y: 0))
path2.addLine(to: CGPoint(x: 250, y: self.frame.size.height))
If your line is always vertical, calculations are quite simple: x-coordinate is known, so you task is to find y-coordinate. Quadratic Bezier curve has parametric representation:
P(t) = P0*(1-t)^2 + 2*P1*(1-t)*t + P2*t^2 =
t^2 * (P0 - 2*P1 + P2) + t * (-2*P0 + 2*P1) + P0
where P0, P1, P2 are starting, control and ending points.
So you have to solve quadratic equation
t^2 * (P0.X - 2*P1.X + P2.X) + t * (-2*P0.X + 2*P1.X) + (P0.X - LineX) = 0
for unknown t, get root in range 0..1, and apply t value to the similar expression for Y-coordinate
Y = P0.Y*(1-t)^2 + 2*P1.Y*(1-t)*t + P2.Y*t^2
For arbitrary line make equation system for line parametric representation and curve, and solve that system
How to scale a CGontext without affecting its origin i.e only the width and height should get scaled? If I use scale like the below one directly it scales the origin also.
context.scaledBy(x: 2.0, y: 2.0)
Is there a way to construct an AffineTransform that manipulates the width and height, leaving the origin untouched?
I want an AffineTransform that can be used to both CGContext and CGRect.
For example a CGRect rect = {x, y, w, h}
var t = CGAffineTransform.identity
t = t.scaledBy(x: sx, y: sy)
let tRect = rect.applying(t)
tRect will be {x * sx, y * sy, w * sx, h * sy}
But I want {x, y, w * sx, h * sy}. Though it can be achieved by calculation, I need CGAffineTransform to do this.
You need to translate the origin, then scale, then undo the translation:
import Foundation
import CoreGraphics
let rect = CGRect(x: 1, y: 2, width: 3, height: 4) // Whatever
// Translation to move rect's origin to <0,0>
let t0 = CGAffineTransform(translationX: -rect.origin.x, y: -rect.origin.y)
// Scale - <0,0> will not move, width & height will
let ts = CGAffineTransform(scaleX: 2, y: 3) // Whatever
// Translation to restore origin
let t1 = CGAffineTransform(translationX: rect.origin.x, y: rect.origin.y)
//Compound transform:
let t = t0.concatenating(ts).concatenating(t1)
// Test it:
let tRect = rect.applying(t) // 1, 2, 6, 12 as required
Quick question: This code should produce (among others) 4 lines that are perpendicular to each other. However, when run, the lines are all off by a small amount.
for i in 0..<60 {
CGContextSaveGState(ctx)
CGContextTranslateCTM(ctx, rect.width / 2, rect.height / 2)
CGContextRotateCTM(ctx, CGFloat(6.0 * Double(i) * M_PI / 180))
CGContextSetStrokeColorWithColor(ctx, UIColor.grayColor().CGColor)
CGContextMoveToPoint(ctx, 50, 50)
if (i % 5 == 0) {
CGContextSetLineWidth(ctx, 3.0)
CGContextAddLineToPoint(ctx, 30, 30)
}
else {
CGContextSetLineWidth(ctx, 2.0)
CGContextAddLineToPoint(ctx, 40, 40)
}
CGContextStrokePath(ctx)
CGContextRestoreGState(ctx)
}
Still learnings Core Graphics, so sorry if this is simple.
Regards, Brandon
EDIT 1:
Here is what I am getting:
If I am assuming it correctly, you want to draw ticks that look like ticks on a watch face.
If you let it draw only one iteration, e.g.
for i in 0..<1
You will see that the first tick starts at some angle. This is happening because you are drawing line from (x=50, y=50) to (x=30, y=30)
Try changing it to (x=50, y=0)(x=30, y=0)
for i in 0..<60 {
CGContextSaveGState(ctx)
CGContextTranslateCTM(ctx, rect.width / 2, rect.height / 2)
CGContextRotateCTM(ctx, CGFloat(6.0 * Double(i) * M_PI / 180))
CGContextSetStrokeColorWithColor(ctx, UIColor.grayColor().CGColor)
CGContextMoveToPoint(ctx, 50, 0) // <-- changed here
if (i % 5 == 0) {
CGContextSetLineWidth(ctx, 3.0)
CGContextAddLineToPoint(ctx, 30, 0) // <-- changed here
}
else {
CGContextSetLineWidth(ctx, 2.0)
CGContextAddLineToPoint(ctx, 40, 0) // <-- changed here
}
CGContextStrokePath(ctx)
CGContextRestoreGState(ctx)
}
Result
Trying to figure out how to make this little ball spawn anywhere from the center (self.frame.width / 2) to (self.frame.width / 2 - 100) and (self.frame.width / 2 + 100)
I found this code on stackoverflow and it seems fine, but my game crashes when the ball is about to spawn
ball.position = CGPoint(x: self.frame.width / 2 + (CGFloat(arc4random_uniform(201) - 100)), y: self.frame.height)
Help would be greatly appreciated as always <3
arc4random_uniform takes UInt32 as an argument and returns UInt32 as well. Substracting 100 from it will result in underflow eventually, hence the crash.
You can try something like:
ball.position = CGPoint(
x: self.frame.width / 2 + CGFloat(arc4random_uniform(201)) - 100.0,
y: self.frame.height
)
I am getting error
fatal error: Can't unwrap Optional.None
(lldb)
with this code
var context:CGContextRef = UIGraphicsGetCurrentContext()
let radius:CGFloat = 5
CGContextSetRGBStrokeColor(context, 1, 1, 1, 1)
var tempRect:CGRect = CGRectMake(5, 5, 20, 20)
let minX = tempRect.minX, midX = tempRect.midX, maxX = tempRect.maxX
let minY = tempRect.minY, midY = tempRect.midY, maxY = tempRect.maxY
CGContextMoveToPoint(context, minX, minY)
CGContextAddArcToPoint(context, minX, minY, midX, midY, radius)
CGContextAddArcToPoint(context, maxX, minY, maxX, midY, radius)
CGContextAddArcToPoint(context, maxX, maxY, midX, maxY, radius)
CGContextAddArcToPoint(context, minX, maxY, minX, midY, radius)
CGContextClosePath(context)
CGContextDrawPath(context, kCGPathFillStroke)
I don't understand what the problem is. What I am trying to do is create a rectangle with rounded corners in Swift. Why am I getting this error and is there a much easier way to do this?
The problem is that there is no current context. Thus UIGraphicsGetCurrentContext() would like to return NULL (nil). You should test context in a conditional before going on.
Also you should type context as a CGContext!, since that is what UIGraphicsGetCurrentContext() returns — a context, or nil, wrapped up in an Optional, implicitly unwrapped. Thus, when you get a context, you will be able to use it without using question marks everywhere. Even better, don't give it an explicit type at all; Swift knows better than you do what UIGraphicsGetCurrentContext() returns.