Distorting UIImage into Parallelogram - ios

I have a UIImage that results from a function. It's something like the following.
image1.image = [self reflectedImage:img];
where image1 is a UIImage control. Before plugging it into image1, I want to further distort it to the right or left a little into a parallelogram as shown below. So I just want to relocate point c and d.
I've read several dozen articles here and there. I'm not sure if I can do it with CGAffineTransformMake. This web page suggests that I could. Unfortunately, there is no sample project to see how it works. Unfortunately, I haven't found a single web site that shows me how to distort a simple rectangle image into a parallelogram. So what is the easiest way of doing it? Do I need to create a layer so that I can use CATransform3D?
Thank you for your help.

I found out an alternative way which is way simpler than the other in this topic. Just apply this transformation to your view:
imgView.transform = CGAffineTransformMake(1.0, 0.0, proportion, 1.0, 0.0, 0.0);
where proportion is between -1 and 1
This is called a shear transformation, look at the link below for more
http://iphonedevelopment.blogspot.it/2008/10/cgaffinetransform-11-little-more.html

What you have to do is give your UIImageView some perspective. By default a layers transform do not have perspective, so you must also setup this: transform.m34 = 1.0 / -2000;
Also change the anchorpoint of your view so that it rotates along the top edge of the view. For you it becomes (0,0.5).
The perspective gives it that parallelogram look as if the view has depth (its also called 2.5D as its not pure 3D animation, its pseudo 3D). Set the anchor point so that it rotates along that edge and finally give it an angle. i.e. rotate by how much?
// Rotate by 30 degrees
CGAffineTransform rotationTransform = CGAffineTransformIdentity;
rotationTransform = CGAffineTransformRotate(rotationTransform, DegreesToRadians(30));
swingView.transform = rotationTransform;
all of this will give you what you want...

Related

How to map any arbitrary two points from image to mapview? In iOS overlay mapkit context

I can choose points from mapview and can overlay an image there so that image's top left and bottom right are mapped to corresponding mapview's points.
But how can I map any arbitrary two points (not those corner points) from image to mapview's two chosen points? Like the calibrate feature of this app https://itunes.apple.com/us/app/mapcha/id956671318?mt=8
Any hints either SDK specific or math involved to guide towards the solutions are appreciated.
Edited:
I didn't realize that my explanation were not making sense to you, pardon.
I thought my requirement would easily make sense by providing the reference app and reference feature (Calibrate).
OK, a bit more explanation here. I followed this tutorial to achieve result like this image. Now, all I want to do is to make my app users be able to attach their own images to the map at their desired places like that calibrate feature of the reference app.
Note:
You don't have to install the reference app to understand the calibrate feature as it can be understood by just viewing the images with title Step 1, Step 2, Step 3, Step 4 & Finish.
Here are those points' text in case reference would be no more available.
Step 1: Take a picture of your map or use a photo from your photo library. Ensure North is up.
Step 2: Choose a point on the paper map and locate it on the standard map.
Step 3: Repeat for another point. Points that are farther apart give better results.
Step 4: Preview the map and check alignment. Adjust the transparency if required.
Finish: Now you can see your current location on the paper map.
Edited:
I'm not getting the desired result as shown in the image but seem close.
And here is a snap of code I'm using.
-(void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
CGImageRef imageReference = self.overlayImage.CGImage;
MKMapRect theMapRect = self.overlay.boundingMapRect;
CGRect theRect = [self rectForMapRect:theMapRect];
double imgWidthScaleFactor = 1.0;
if (_imgWidth > 0) {
imgWidthScaleFactor = theRect.size.width / _imgWidth;
}
double imgHeightScaleFactor = 1.0;
if (_imgHeight > 0) {
imgHeightScaleFactor = theRect.size.height / _imgHeight;
}
CGPoint contextCenter = CGPointMake(CGRectGetMidX(theRect), CGRectGetMidY(theRect));
CGContextTranslateCTM(context, contextCenter.x, contextCenter.y);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextRotateCTM(context, _radian);
CGContextTranslateCTM(context, -contextCenter.x, -contextCenter.y);
CGContextTranslateCTM(context, imgWidthScaleFactor*_pivotX, imgHeightScaleFactor*_pivotY);
CGContextSetAlpha(context, 0.5);
CGContextDrawImage(context, theRect, imageReference);
}
So, let me start by explaining the intuition behind what this example app does:
image to stick on map:
/* _____
| |
| | __
|_____| |__|
(image to stick) (map)
*/
As you can see, i have made it such that the image shape and size, are different from the map. Now, the reason you have to pick two points on the map and two on the image is to provide a scale for your image.
/* _____
| * |
|* |
|_____|
(image to stick, with chosen points as *)
*/
I. calculate the distance between the two chosen points on the Image, and the two chosen points on the map, lets call them d_image and d_map.
Now you get the scaling of your image by simply doing:
float scale = (d_map/d_image);
II. Using the scale you will be able to find the upper right corner of the image on the map, and the bottom left corner of the image on the map. You can use these points and convert them to coordinates using the following:
CLLocationCoordinate2D image_corner_coordinate = [*yourMap* convertPoint:*image_corner* toCoordinateFromView:self.view];
And voila, you have your SouthWest and NorthEast coordinates to pin your overlay to!
***EDIT****
OP added additional information to the question with the explicit request to be able to handle images that are at a different angle than the chosen points on the map. Although I believe that the answer above, steps I and II should be enough to figure out how to achieve the desired effect, here we go for completeness sake:
step I (.5)
Using the scaling factor calculated in Step I. we first scale down the image to the appropriate size. Then, give than we know the two given points on the map and the two given points on the image, we calculate the rotation factor.
Given that the image is now the right scale, the way to think about this is the following: you pin down on of the two points on it's matching map point, and start to rotate the image until the other point matches up. When you find the rotation factor, continue to step II to get your final answer.

Flipping image after rotation issue (need to do both, only does one)

I have a UIImage on my storyboard, and I have just rotated it( i can rotate it any number of degrees). The code for the rotation is below:
let DegreesFloat = Double(-Degrees) * M_PI/180
self.imageView.transform = CGAffineTransformMakeRotation(CGFloat(DegreesFloat))
By the way, degrees in the first line of code, is an integer I enter into a text field. When the view loads, I have this...
self.imageView.transform = CGAffineTransformMakeScale(1, -1);
to keep the image upside down, cause that's just how I need it to be. The issue is that when I rotate the image, it cancels out the flip, and flips it back to its original flip (without the 2nd paragraph of code). I need it to keep it's upside down flip, while performing it's rotation.
When I add the flip code after the rotate code, it just cancels out the rotate code. I have no idea how to do this, but I just need it to stay upside down, while correctly performing a rotation, and NOT flipping itself back to its original right-side up orientation.
I think what you are asking is how to make multiple transform commands together. The transformations are actually a matrix telling the image later what to do. Use a CGAffineTransformConcat to apply multiple transformations. Refer to the Apple documentation

Rotate a UIView in 2D, not 3D

When I use either of the following pieces of code, the button rotates in 3D rather than 2D (flat against the screen). How can I avoid the 3D behavior? Here's what the button looks like during the rotation:
CGAffineTransform rotationTransform = CGAffineTransformIdentity;
rotationTransform = CGAffineTransformRotate(rotationTransform, (offset/(180.0 * M_PI)));
button.transform = rotationTransform;
.
button.transform = CGAffineTransformRotate(CGAffineTransformIdentity, (offset/(180.0 * M_PI)));
.
button.transform = CGAffineTransformMakeRotation(offset/(180.0 * M_PI));
Here's the answer from an Apple employee:
When you set a transform the frame becomes less well-defined, to the
point that you should no longer use it to size or position a view. Try
using the center property instead, your probably not getting a 3D
rotation, but a distortion due to the compounding effect of setting
the frame and trnsform.
I met the same problem which is really annoying, and I got it settled at last, though still have no idea why.
I got unexpected 3D rotations when I tried to perform a 2D rotation in "viewDidLayoutSubviews" method with
double radius = (degree / 180.0) * M_PI;
uiImageView.transform = CGAffineTransformMakeRotation(radius);
My solution is to perform transforming elsewhere other than "viewDidLayoutSubviews" and it is working perfectly.
Interestingly, when the annoying 3D rotation happens, and I keep orienting my iPhone for a while, the 3D rotation will disappear suddenly and 2D rotation will come back and take the place, but the image stays at a distorted shape. I guess maybe iOS is doing some internal transforming in "viewDidLayoutSubviews" and things get messed up if we impose additional transforming on it. However, my guess cannot explain why it disappears after a while. I also tried to NSLog the members of "uiImageView.transform", say, "a, b, c, d, tx, ty" in "viewDidLayoutSubviews" but got no clue.
SOLUTION: Check your code to see if you are performing the rotation in "viewDidLayoutSubviews" or some similar method, and if yes, try to move it out to elsewhere and cross fingers.

What sort of transform would give me the desired resultant image?

It feels simple really. I have an UIImageView:
and I want to apply an affine transform to get this image:
However, the particular transform in question eludes me. Rotating by 180° gets me this:
transform = CGAffineTransformMakeRotation(M_PI);
// similarly, CGAffineTransformMakeScale(-1, -1);
which is oviously quite far off. Translation is also problematic:
transform = CGAffineTransformMakeTranslation(x, y);
Reflecting over the line y = x and then rotating 180° gets me this:
transform = CGAffineTransformMake(0, 1, 1, 0, 0, 0);
transform = CGAffineTransformRotate(M_PI);
which is closer, but still not there. Is there something obvious that I'm missing, or is this really complicated? Does anyone know what sort of transform I'm looking for here?
Edit:
Twitter feedback is suggesting that affine transforms aren't the way to go. At the end of the day, I simply want the resultant image, so any suggested routes to success are greatly appreciated!
You are trying to move a sprite, whether you realize it or not. No transformation can move the star and keep the background. Your options are to:
- make a large background and clip it at the end, so that translation works
- make a sprite image on top of a separate background image. If you're using iOS7, you may want to use the Sprite Kit.

iOS Angle Right/Left 3D Effect

I'm looking to Animate a UIView and give it some 3D Effects.
I've experimented with CATransform3DMakeRotation() but can't seem to get the correct effect.
What I am trying to achieve is something like this:
Where the red view is moving from side to side with a 3d perspective.
Not the exact answer, but something to point you to right direction. Tumbljack has a nice tutorial, sample project and video on how to do 3D transformation on a view.
You can try with the following properties as mentioned in that.
layer.transform = CATransform3DMakeRotation(radian, x, y, z);
or
transform.m34 = 1.0 / -zDistance;
Try tweaking the sample code to get the desired output on your UIVIew. His tutorial is to have a complete 3D cube/sphere transformation and in your case you might need only the left and right movement from that.

Resources