How to add circle annotation in pdfkit swift? - swift3

I am using pdfkit and added circle annotation with fixed size and width but i want to draw with dynamic height and width. Here is my code :
Here : start is my CGPoint from where i start to finger
end is second CGPoint where i ended to move finger.
Used start.x and end.y
let circle = PDFAnnotation(bounds: CGRect(x: start.x, y: end.y, width: 100, height: 100), forType: .circle, withProperties: nil)
circle.color = hexStringToUIColor(hex: "#0000FF")
let border = PDFBorder()
border.lineWidth = 3.0
circle.border = border
page?.addAnnotation(circle)
This is second approach to draw circle with dynamic height and width:
Here is code :
let centerX = (start!.x + end!.x)/2
let centerY = (start!.y + end!.y)/2
var distance = (end!.x - centerX) * 2
if distance < 0 {
distance = (start!.x - centerX) * 2
}
let halfDistance = distance/2
self.annotation = PDFAnnotation(bounds: CGRect(x: centerX - halfDistance, y: centerY - halfDistance, width: distance, height: distance), forType: .circle, withProperties: nil)
let page = self.pdfview.currentPage
annotation.color = hexStringToUIColor(hex: "#0000FF")
let border = PDFBorder()
border.lineWidth = 3.0
annotation.border = border
page?.addAnnotation(annotation)
Second approach draws circle with dynamic height and width but not as i want. if i draw circle their are 8 cases :
Finger swiped from left to right - It draw circle on proper position.
Finger swiped from right to left - It draw circle on proper position.
Finger swiped from top left to bottom right - It draw circle half of size
Finger swiped from bottom right to top left - It draw circle half of size
Finger swiped from top to bottom - circle radius value is 2 or 3 width and height
Finger swiped from bottom to top - circle radius value is 2 or 3 width and height
Finger swiped from top right to bottom left - It draw circle half of size
Finger swiped from bottom left to top right - It draw circle half of size

You can use this code to draw circle over a pdfpage
let size = CGSize(width: abs(point.x - startPoint.x), height: abs(point.y - startPoint.y))
var rect = CGRect(origin: startPoint, size: size)
if point.y - startPoint.y < 0 && point.x - startPoint.x < 0
{
rect = CGRect(origin: point, size: size)
}
else if point.y - startPoint.y > 0 && point.x - startPoint.x < 0
{
rect = CGRect(origin: CGPoint(x: point.x, y: startPoint.y), size: size)
}
else if point.y - startPoint.y < 0 && point.x - startPoint.x > 0
{
rect = CGRect(origin: CGPoint(x: startPoint.x, y: point.y), size: size)
}
let page = docView.currentPage
let pageBounds = page!.bounds(for: .cropBox)
let newAnnotation = PDFAnnotation(bounds: pageBounds, forType: .circle,withProperties:nil)
newAnnotation.setRect(rect, forAnnotationKey: .rect)
newAnnotation.color = UIColor.black
page!.addAnnotation(newAnnotation)

Related

extension file making image flip upside down (swift3)

The following extension file generates my image upside down. All i need to do is flip my image by 180 degrees.
case .landscapeLeft:
var transform: CGAffineTransform = CGAffineTransform.identity
transform = transform.translatedBy(x: self.size.width, y: self.size.height)
transform = transform.rotated(by: CGFloat(Double.pi/2))
guard let cgImage = self.cgImage, let colorSpace = cgImage.colorSpace, let context: CGContext = CGContext(data: nil, width: Int(self.size.width), height: Int(self.size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else { return self }
context.concatenate(transform)
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
guard let transformed = context.makeImage() else { return self }
return UIImage(cgImage: transformed)
return imageResult!
I have tried to use 3 * Double.pi / 2 but that makes no image appear on the image view. The only math formula that gets a image on the image view is double.pi / 2 for my code.
Your code rotates the image about the origin of the image which happens to be the top left hand corner. You need to translate the origin to be the centre of the image before applying the rotation and then after translate the origin back to the top left corner. If you replace your transform construction with the following it should work
var transform: CGAffineTransform = CGAffineTransform.identity
transform = transform.translatedBy(x: self.size.width/2, y: self.size.height/2)
transform = transform.rotated(by: angle)
transform = transform.translatedBy(x: -self.size.width/2, y: -self.size.height/2)

How to scale CAShapeLayer to different UIImageView

I have a UIImageView that you can tap on and it draws a circle. I store the location of the circles in an Array of Dictionaries. This allows me to "replay" the drawing of the circles. However, when the UIImageView is a different size from the original, the circles don't scale to the new UIImageView.
How can I get the circles to scale? For demonstration purposes, the top picture is the size of the UIImageView used for input and the second one is the size for replay.
Inputing the circles:
Replay the circles (the circles should be in the blue UIImageView
import Foundation
import UIKit
class DrawPuck {
func drawPuck(circle: CGPoint, circleColour: CGColor, circleSize: CGFloat, imageView: UIImageView) {
let circleBezierPath = UIBezierPath(arcCenter: CGPoint(x: circle.x,y: circle.y), radius: CGFloat(circleSize), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circleBezierPath.cgPath
//change the fill color
shapeLayer.fillColor = circleColour
//you can change the stroke color
shapeLayer.strokeColor = UIColor.white.cgColor
//you can change the line width
shapeLayer.lineWidth = 0.5
imageView.layer.addSublayer(shapeLayer)
}
}
I was able to resolve this with CATransform3DMakeScale As long as I keep the original aspect ratio of the original image it works great.
let width = yellowImageView.frame.width / blueImageView.frame.width
let height = yellowImageView.frame.height / blueImageView.frame.height
shapeLayer.transform = CATransform3DMakeScale(height, width, 1.0)
view.layer.addSublayer(shapeLayer)

How to animate a UI Element (label) to the top of the screen?

The logic I want to use is below, just not sure the exact code to pull this info in order to execute. I think I only need to figure out how to get the label height.
let labelHeight = ???
let screenHeight = self.view.bounds.height
let yPosition = ((screenHeight-labelHeight) / 2 ) - ~20
UIView.animate(withDuration: 3, animations: {
self.movingButton.center.y -= yPosition
}
A main question also is how do I pull the height of a specific label, if there are multiple on the screen.
Thanks!
Figured it out after much trial and error!
let buttonHeight = self.movingButton.bounds.height
let screenHeight = self.view.bounds.height
let buttonEndHeight = (screenHeight / 2) - (buttonHeight / 2)
UIView.animate(withDuration: 2, animations: {
self.movingButton.center.y -= buttonEndHeight - 30
I expect this to place the label 30 pixels below the top of the screen on any device.

mouse press projection (c++ openGL)

I'm making a simple tutorial game with openGL and have a question about touch method. Please checkout my code:
My (0,0) point is in center of a screen:
void Init()
{
glClearColor(0.3,0.3,0.3,0.0);
glMatrixMode(GL_PROJECTION);
glOrtho(-400.0,400.0,-300.0,300.0,0,1.0); //сетка, середина в точке 0
}
Before this i'm call mouse methods:
glutPassiveMotionFunc(Mouse);
glutMouseFunc(MousePress);
And in method MousePress when touch is coming, it's another system coordinate with (0,0) point in top left corner of a screen. Please can you tell me better approach then make something like x-300;y-400 in MousePress method.
Given the simpler orthographic projection, your "x-300;y-400" is the correct approach, although you might want to do some scaling too...
float x = mouseX/(float)windowWidth;
float y = 1.0f - mouseY/(float)windowHeight; //flip since y=0 is at the top
//x and y are now 0 to 1, bottom left to top right
x = left + x * (right - left);
y = bottom + y * (top - bottom);
//x and y are now in 3D coordinates
Here, left/right/bottom/top are from glOrtho, which in your case can be substituted as follows (but of course storing in a variable is better)...
x = -400 + x * (400 - (-400));
y = -300 + y * (300 - (-300));
If you were using a perspective projection it gets a bit more complicated, as I've described here.
[EDIT]
Assuming the window size is 800x600, the above cancels to {x-400,300-y}. For example,
mouseY = 50;
windowHeight = 600;
float y = 1.0f - (50/(float)600); //1.0 - 0.08333 = 0.91667
y = -300 + y * (300 - (-300)); //-300 + 0.91667 * 600 = 250, also 300-50

Tiled Rendering glFrustum Clipping Planes Calculations

I was trying to get a tiled renderer working (the idea is to render one large view frustum by breaking it down into chunks and rendering individually).
I had code that transforms a standard perspective projection with a viewing angle into left, right, top, and bottom clipping planes that can then be passed into glFrustum.
I was stuck on properly breaking this down.
After several missteps, I produced the following:
//"int rect[4]" is the pixel rectangle of the original view
//"int rect2[4]" is the pixel subrectangle within rect corresponding to the new view
//"left", "right", "bottom", and "top" are the left, right, bottom, and top clipping
// planes of the old view, respectively.
float diff_x = right - left;
float diff_y = top - bottom;
result_left = (float)(rect2[0] ) / (float)(rect[2]) * diff_x + left;
result_right = (float)(rect2[0]+rect2[2]) / (float)(rect[2]) * diff_x + left;
result_bottom = (float)(rect2[1] ) / (float)(rect[3]) * diff_y + bottom;
result_top = (float)(rect2[1]+rect2[3]) / (float)(rect[3]) * diff_y + bottom;