Calculate position of NSScrollView relative to main image - objective-c

Assume I load an NSImage of dimensions 2000x2000 and display only a portion of the picture inside an NSScrollView with frame size 500x300. How can I calculate the distance between the images 0,0 origin and the views 0,0 origin (so I can determine the x,y coordinates of the view relative to the whole image)?
Thanks in advance :-)

Use the documentVisibleRect method:
NSRect rect=[scrollView documentVisibleRect];
CGFloat x=rect.origin.x;
CGFloat y=rect.origin.y;
x and y will be the coordinate on the image that's currently at the top left corner.

Related

Objective C - Adjust height of image in image view automatically after original size

I am developing an app that will show flags for countries some places, but after looking at flags I realized that the flags format was different for almost every country. Therefor I would like the height of the image view to automatically adjust it self to the width i set. Example:
Standard width for all flags: 100 px
USA : Height: 50px
UK: Height 56 px
Russia: Height 34px
I have no idea how to solve this, thanks for help! The best would be if this could be done automatically - without me needing to create example arrays or something for every flag to adjust size.
This is a ratio problem. Suppose your English flag is 120x80px. You want it to be 100px wide. How tall will it be? You have to scale the width and height by the same ratio.
First of all, calculate the ratio between the desired width of the flag and its actual width:
CGFloat ratio = 100.0f / 120.0f;
That gives us a ratio of 0.83. Now we can calculate the display height by multiplying the actual height by the ratio:
CGFloat height = 80.0f * 0.83;
The display height is 66.4px.
Here's the neat thing: UIImageView does this for you. If you specify the width of the image view and set its content mode to UIViewContentModeScaleAspectFit it does the hard work automatically.
See this question:
How to scale a UIImageView proportionally?
You could set the size of the image view from the size of the image as follows:
UIImage* flagImage = [UIImage imageNamed:"flagimage.png"];
CGRect flagImageRect = flagImageView.frame;
flagImageRect.size = flagImage.size;
flagImageView.frame = flagImageRect;
flagImageView.image = flagImage;
I guess you would do the above in a loop where you are setting the flag images for all your image views. You could also take the opportunity to scale your images (if desired).

How to change the anchor point from the top-left corner of a transformation matrix to the bottom-left corner?

Say, I have an image on an HTML page.
I apply an affine transformation to the image using CSS3 matrix function.
It looks like:
img#myimage {
transform: matrix(a, b, c, d, tx, ty);
/* use -webkit-transform, -moz-transform etc. */
}
The origin of an HTML page is the top-left corner and the y-axis is inverted.
I'm trying to put the same image in an environment (cocos2d) where the origin is the bottom-left corner and the y-axis is upright.
To get the same result in the other environment, I need to transform the origin somehow and reflect that in the resulting CGAffineTransform.
It would be great if I can get some help with the matrix math that goes here. (I'm not so good with matrices.)
The following formula would work,
for converting the position from CSS3 to Cocos2d:
(screen Size - "y" position in CSS3 - height of object)
Explanation:
To make the origin for the Cocos environment same as for the CSS3 environment we would only have to add the screen size to the cocos2d's bodies y co-ordinate.
Eg. The screen size is (100,100) and the body is a point object if you place it at (0,0) in CSS3 it would be at the top left corner. If we add the screen size to the y co-ordinates for cocos2d the object would be placed at (0,100) which is the top-left corner for cocos2d as well
To make the co-ordinates same, since the Y axis is inverted, we have to subtract the "Y" co-ordinate given in CSS3 from the Screen Size for Cocos2d. Suppose we place the same point object in the previous example at (0,10) in CSS3 we would place it at (0, 100 - 10) in cocos2d which would be the same positions on the screen
Since our body would NOT always be a point object we have to take care of its anchor point as well. If suppose the body's height is 20 and we place it at (0,10) in CSS3 then it would be placed at the top-left position and would be coming down because the Y axis is inverted
Hence we would also have to subtract the body's total height from the screen size and "y" co-ordinate to place it at the same position which would be (0, 100 - 10 - 20) putting the body at the same place in cocos2d environment
I hope I am correct and clear :)

How to set MKPinAnnotation so that bottom of image points to location instead of center of image

How can I move the pin image so that the bottom of the image points to the location (like the default pin). Currently the center of the image points to that location (San Francisco).
You'll need to calculate the number of pixels to offset and then set the centerOffset property.
By default, the center point of an annotation view is placed at the
coordinate point of the associated annotation. You can use this
property to reposition the annotation view as needed. This x and y
offset values are measured in pixels. Positive offset values move the
annotation view down and to the right, while negative values move it
up and to the left.

Visualizing the Anchor Point of a UIImageView

Is there an easy way of putting a mark (like a cross for example) on the anchor point of an UIImageView? I'm trying to line up several rotating images by their anchor point, and being able to see these points would make the job a lot easier.
Many thanks.
You are asking how to visualize the anchor point within a view but it seem to me that you are asking for it so that you can help align the anchor points. I'll try and answer both questions.
Visualizing the anchor point.
Every view on iOS have an underlying layer that has an anchor point. The anchor point is in unit coordinate space of the layer (x and y goes from 0 to 1). This means that you can multiply x by the width and y by the height to get the position of the anchor point inside the layer in the coordinate space of the view/layer. You can then place a subview/sublayer there to show the location of the anchor point.
In code you could do something like this to display a small black dot where the anchor point is.
CALayer *anchorPointLayer = [CALayer layer];
anchorPointLayer.backgroundColor = [UIColor blackColor].CGColor;
anchorPointLayer.bounds = CGRectMake(0, 0, 6, 6);
anchorPointLayer.cornerRadius = 3;
CGPoint anchor = viewWithVisibleAnchorPoint.layer.anchorPoint;
CGSize size = viewWithVisibleAnchorPoint.layer.bounds.size;
anchorPointLayer.position = CGPointMake(anchor.x * size.width,
anchor.y * size.height);
[viewWithVisibleAnchorPoint.layer addSublayer:anchorPointLayer];
You can see the result in the image below for four different rotations.
Aligning layers by their anchor point
That is cool and all but it's actually easier then that to align anchor points.
The key trick is that the position and the anchorPoint is always the same point, only in two different coordinate spaces. The position is specified in the coordinate space of the super layer. The anchor point is specified in the unit coordinate space of the layer.
The nice thing about this is that views that have their position property aligned will automatically have their anchorPoint aligned. Note that the content is drawn relative to the anchor point. Below is an example of a bunch of views that all have the same y component of their position, thus they are aligned in y.
There really isn't any special code to do this. Just make sure that the position properties are aligned.

Position Subviews Relative to Screen Estate

I'd like to display multiple small UIViews as Subviews relative to the screen estate. This should work across different screen sizes (iPad, iPhone)/portrait/landscape modes.
Each subview to display has two NSNumber objects with an unsigned int ranging from -100 (min) to 100 (max) which needs to be mapped to the correct x and y coordinates for positioning.
What's the best way to translate those values (-100...100) to use them for positioning UIViews on the screen?
How do I position them in a relative rather then an absolute way, so that the code works across screen rotation and screen sizes?
Ok, so if I understand correctly you want a -100 in the x direction to map to the left most point on the screen, 100 in the x to map to the right most point on the screen, -100 in the y direction to map to the lowest point on the screen, and 100 in the y to map to the highest point on screen (or maybe you want the y inverted from what I have so that it agrees with the screen coordinate system in which y becomes bigger the lower on the screen you get?).
And we also want to account for rotation.
As far as I understand it, asking UIScreen for its height and width:
CGFloat width = [UIScreen mainScreen].bounds.size.width;
CGFloat height = [UIScreen mainScreen].bounds.size.height;
but this does not account for rotation. The only other way I am aware of that is pretty straightforward would be to ask a UIView covering the screen for its width and height (most simply, you could make your viewcontroller's view cover the whole screen).
If you had a UIView that perfectly covered the whole screen (let's call it myView), you could try:
CGFloat width = myView.frame.size.width;
CGFloat height = myView.frame.size.height;
these should adjust for orientation by themselves (from my experience, it should definitely work if you get the height and width in viewDidAppear:animated: or anything after. also the UIView needs to either be the UIViewControllers view property or a subview of this view. if not, you'll have to implement didRotateFromInterfaceOrientation: or find some other way to tell your view about any rotations). Once we have the 'width' and 'height' of the screen, we can convert from your int's to screen position. Try something like:
(CGPoint)convertX:(NSNumber *)x andY:(NSNumber *)y intoPoint
{
pointX = ([x intValue] + 100.0)*width/200.0;
pointY = (-[y intValue] + 100.0)*height/200.0; // remove the - sign at the front of the expression for y to grow as you move down the screen
return CGPointMake(pointX, pointY);
}
to convert from -100 to 100 in x and y to their respective points on the screen.
If you're working with a range of +/-100, then you may want to use the underlying CALayers to position your views. The nice part about CALayers, is that their anchor points are mapped to a device-agnostic grid that ranges from 0.0 to +1.0 on a Cartesian plane.