Swift creating angles on button click, but in opposit direction - ios

I am creating a circle (Using CGContext) with angle of 90, 180 & 280. As we know that 90 degree angle shape like letter 'L', but I am getting opposite shape of 'L', then Angles.
Following this image, I don't want to get it like this, so what can I do ? please let me know.
Thanks

You can fix it with one of following solution.
1) Rotate your view (button) to -90 degree.
Or
2) Trickle values of angle while drawing as following:
func drawCircle(angles : Double) {
let angleToDraw = angles - 90
let startCircleAngle = CGFloat(269.9/180 * M_PI)
let endCircleAngle = CGFloat(270/180 * M_PI)
let center = CGPointMake(self.frame.size.width / 2.0, self.frame.size.height / 2.0);
let ctx = UIGraphicsGetCurrentContext()
CGContextBeginPath(ctx!)
CGContextSetLineWidth(ctx!, 5)
CGContextSetStrokeColorWithColor(ctx!,UIColor.redColor().CGColor)
let x:CGFloat = center.x
let y:CGFloat = center.y
let radius: CGFloat = 100.0
CGContextAddArc(ctx!, x, y, radius, startCircleAngle , endCircleAngle, 1)
CGContextAddArc(ctx!, x, y, 1, startCircleAngle, startCircleAngle, 0)
CGContextSaveGState(ctx!)
CGContextTranslateCTM(ctx!, x, y)
// rotation supplied in radians
CGContextRotateCTM(ctx!, CGFloat(M_PI*(angleToDraw)/180))
CGContextStrokePath(ctx!)
let path = CGPathCreateMutable()
CGPathMoveToPoint(path, nil, 0, 0)
CGPathAddLineToPoint(path, nil, radius, 1)
CGContextAddPath(ctx!, path)
CGContextSetLineWidth(ctx!, 4)
CGContextScaleCTM(ctx!, -1.0, 1.0)
CGContextSetStrokeColorWithColor(ctx!,UIColor.blackColor().CGColor)
CGContextStrokePath(ctx!)
}

Related

Slider with curved path

I need to create custom slider which path is curved. See the image above.
I can get the x position of the path, but how can I get its y position for each x point?
The basic idea is that you can define a quadratic Bézier for that curve, e.g., with a little utility function, point(at:) to tell you for values between 0 and 1, where the point is on that Bézier:
struct QuadBezier {
var point1: CGPoint
var point2: CGPoint
var controlPoint: CGPoint
var path: UIBezierPath {
let path = UIBezierPath()
path.move(to: point1)
path.addQuadCurve(to: point2, controlPoint: controlPoint)
return path
}
func point(at t: CGFloat) -> CGPoint {
let t1 = 1 - t
return CGPoint(
x: t1 * t1 * point1.x + 2 * t * t1 * controlPoint.x + t * t * point2.x,
y: t1 * t1 * point1.y + 2 * t * t1 * controlPoint.y + t * t * point2.y
)
}
}
Then you can then use that to define the curved path:
let bounds = view.bounds
let point1 = CGPoint(x: bounds.minX, y: bounds.midY)
let point2 = CGPoint(x: bounds.maxX, y: bounds.midY)
let controlPoint = CGPoint(x: bounds.midX, y: bounds.midY + 100)
let bezier = QuadBezier(point1: point1, point2: point2, controlPoint: controlPoint)
And you can then set the center of your circular view accordingly:
circleView.center = bezier.point(at: t)
E.g., here I’ve used path computed property to render blue CAShapeLayer, and using point(at:) to set the center of the red circular view based upon a value t:
Obviously, I’m using a gesture to scrub changes of t, but you can use your custom stepper or whatever to accomplish the same thing.

Swift: make rotation of point in 2D

I want to make a rotation of point by -90 degrees
Initial
Final
Let's take a look on top left and top right points of Initial. Their coordinates are:
let topLeft = CGPoint(x: 2, y: 1)
let topRight = CGPoint(x: 3, y: 1)
And after rotation coordinates of them should become:
topLeft 1:0
topRight 2:0
How can i do it ?
I have tried several answers but none of them give me my final results.
did not work:
Rotating a CGPoint around another CGPoint
What is the best way to rotate a CGPoint on a grid?
Here are some code from my playground:
let topLeft = CGPoint(x: 2, y: 1)
let topRight = CGPoint(x: 3, y: 1)
func rotatePoint1(_ point: CGPoint, _ degrees: CGFloat) -> CGPoint {
let s = CGFloat(sinf(Float(degrees)))
let c = CGFloat(cosf(Float(degrees)));
return CGPoint(x: c * point.x - s * point.y, y: s * point.x + c * point.y)
}
func rotatePoint2(_ point: CGPoint, _ degrees: CGFloat, _ origin: CGPoint) -> CGPoint {
let dx = point.x - origin.x
let dy = point.y - origin.y
let radius = sqrt(dx * dx + dy * dy)
let azimuth = atan2(dy, dx) // in radians
let newAzimuth = azimuth + degrees * CGFloat(M_PI / 180.0) // convert it to radians
let x = origin.x + radius * cos(newAzimuth)
let y = origin.y + radius * sin(newAzimuth)
return CGPoint(x: x, y: y)
}
func rotatePoint3(_ point: CGPoint, _ degrees: CGFloat) -> CGPoint {
let translateTransform = CGAffineTransform(translationX: point.x, y: point.y)
let rotationTransform = CGAffineTransform(rotationAngle: degrees)
let customRotation = (rotationTransform.concatenating(translateTransform.inverted())).concatenating(translateTransform)
return point.applying(customRotation)
}
print(rotatePoint1(topLeft, -90))
print(rotatePoint1(topRight, -90))
You are really describing two rotations with your example:
The points are rotated by -90 degrees around the center of the 3x3 grid. When this happens, the topLeft point becomes bottomLeft, and topRight becomes topLeft.
Then you rotate those points around the center of the square 90 degrees (ie. the other direction) to make them topLeft and topRight again.
Using this function from this answer:
func rotatePoint(target: CGPoint, aroundOrigin origin: CGPoint, byDegrees: CGFloat) -> CGPoint {
let dx = target.x - origin.x
let dy = target.y - origin.y
let radius = sqrt(dx * dx + dy * dy)
let azimuth = atan2(dy, dx) // in radians
let newAzimuth = azimuth + byDegrees * .pi / 180 // convert it to radians
let x = origin.x + radius * cos(newAzimuth)
let y = origin.y + radius * sin(newAzimuth)
return CGPoint(x: x, y: y)
}
let topLeft = CGPoint(x: 2, y: 1)
let topRight = CGPoint(x: 3, y: 1)
let squareCenter = CGPoint(x: 2.5, y: 1.5)
// First rotate around the center of the 3 x 3 square
let centerOfRotation = CGPoint(x: 1.5, y: 1.5)
let tl1 = rotatePoint(target: topLeft, aroundOrigin: centerOfRotation, byDegrees: -90) // (x 1 y 1)
let tr1 = rotatePoint(target: topRight, aroundOrigin: centerOfRotation, byDegrees: -90) // (x 1 y 0)
let sc1 = rotatePoint(target: squareCenter, aroundOrigin: centerOfRotation, byDegrees: -90) // (x 1.5 y 0.5)
// Now rotate the 1x1 square the other way around new position of square center
let tl2 = rotatePoint(target: tl1, aroundOrigin: sc1, byDegrees: 90) // (x 1 y 0)
let tr2 = rotatePoint(target: tr1, aroundOrigin: sc1, byDegrees: 90) // (x 2 y 0)
Note: As #MBo noted in the comments, if your cell is always 1x1, it is sufficient to rotate the center of your cell and then just add and subtract the 0.5 offsets to find the four corners.
You can just transform you view like so
yourView.transform = CGAffineTransform(rotationAngle: -CGFloat.pi/2)
EDIT:
My bad.
Use CGFloat.pi when working with degrees
print(rotatePoint1(topLeft, -CGFloat.pi/2))
Use sin and cos functions directly
let s = sin(degrees)
let c = cos(degrees)
iOS coordinate system is a bit flipped compared to standard one so you will have to adjust the angle (you can see simulation)
print(rotatePoint1(topLeft, -CGFloat.pi/2)) // (1.0000000000000002, -2.0)
print(rotatePoint1(topRight, -CGFloat.pi/2)) // (1.0000000000000002, -3.0)

SpriteKit : Draw line using angle and Length

I want to do some drawing based on angles and lengths instead of coordinance in SpriteKit (Swift)
I have the following function that draws from 2 points but I want to create one that draws from 1 point to another place based on angle and length of line
func drawLine( start: CGPoint, end: CGPoint)
{
CGPathMoveToPoint(ref, nil, start.x * 100, start.y * 100)
let line = SKShapeNode()
CGPathAddLineToPoint(ref, nil, end.x * 100, end.y * 100)
line.path = ref
line.lineWidth = 4
line.fillColor = UIColor.redColor()
line.strokeColor = UIColor.redColor()
self.addChild(line)
}
sin and cos are your friends here and this answer isn't specific to Swift.
Given angle and radius, if you define your angle in radians rather than degrees, the end point of your line should be:
let endPoint = CGPoint(x: start.x + sin(angle) * radius,
y: start.y + cos(angle) * radius)
Simon

Finding position of pentagon inside circle

I'm trying to draw small circles over corners of pentagon inside a circle.
I know the following information.
The radius of circle is 50.
Centre of circle is x = 100, y = 100
How can I get position of pentagon corners in x and y so that I can draw a circle there.
Thanks.
I hope you are familiar with polar coordinates. I wrote simple algorithm to calculate corners:
let center = CGPoint(x: 100, y: 100)
let numberOfCorners: Int = 5
let radius = 50.0
var angle:Double = 0.0
let startAngle = M_PI_2
var points: [CGPoint] = []
angle = startAngle
while angle - startAngle < 2*M_PI {
let x = radius * cos(angle) + Double(center.x) // transform polar coordinates to XY
let y = radius * sin(angle) + Double(center.y)
let point = CGPoint(x: x, y: y)
points.append(point)
let angleIncrease = Double(2.0*M_PI)/Double(numberOfCorners)
angle += angleIncrease
}
print(points)
It should works with other polygons. You only have to specify numberOfCorners and startAngle (in radians). Correct StartAngle for iOS coordinates is I think: 3/2 PI.
But for default XY plane to achieve polygon like on your picture, pi/4 it's ok.

Strange behavior with SceneKit Node

I created a circular array objects, no problems.
When I rotate there appears to be a sinc or gaussian function at the center.
The camera is a z 60, radius of structure is 30.
Initial view, no artifacts
Rotated 90 deg up, no artifacts
Rotated 180 deg, artifact appears in center of object
Continued rotation, artifact is still there.
The code for the object is here
class func Build(scene: SCNScene) -> SCNNode {
let radius: Double = 30.0
let numberOfStrands: Int = 24
//Create the base chromosomes.
let baseChromosome = SCNBox(width: 4.0, height: 24, length: 1.0, chamferRadius: 0.5)
let baseChromosomes = DNA.buildCircleOfObjects(baseChromosome, numberOfItems: numberOfStrands, radius: radius)
baseChromosomes.position = SCNVector3(x: 0, y: 0.5, z: 0)
return baseChromosomes
}
class func buildCircleOfObjects(_geometry: SCNGeometry, numberOfItems: Int, radius: Double) -> SCNNode {
var x: Double = 0.0
var z: Double = radius
let theta: Double = (M_PI) / Double(numberOfItems / 2)
let incrementalY: Double = (M_PI) / Double(numberOfItems) * 2
let nodeCollection = SCNNode()
nodeCollection.position = SCNVector3(x: 0, y: 0.5, z: 0)
for index in 1...numberOfItems {
x = radius * sin(Double(index) * theta)
z = radius * cos(Double(index) * theta)
let node = SCNNode(geometry: _geometry)
node.position = SCNVector3(x: Float(x), y: 0, z:Float(z))
let rotation = Float(incrementalY) * Float(index)
node.rotation = SCNVector4(x: 0, y: 1, z: 0, w: rotation)
nodeCollection.addChildNode(node)
}
return nodeCollection
}
}
Using these settings
cameraNode.camera?.xFov = 60
cameraNode.camera?.yFov = 60
cameraNode.camera?.zFar = 1000
cameraNode.camera?.zNear = 0.01
the artifacts disappeared. I think this is a problem with zFar, it should have clipped the back surface uniformly not like a lens aberration.
Falling out of Viewing frustum may be the one to cause most problem. However there is another common cause by misunderstanding the behavior of SCNView's allowsCameraControl, that is when you Pinch to zoom in or zoom out (change the camera's fieldOfView), but the pointOfView's position reminds the same.
Your nodes still stand BEHIND the pointOfView, however small the camera's zNear is. Hence you see them got clipped. The code below may help you in this case, at least avoid the problem.
sceneView.pointOfView!.simdPosition
= float3(0, 0, -scene.rootNode.boundingSphere.radius)

Resources