How do I get rid of these magic numbers in my rotation affine transform? - iphone

I have a view that is 320x460 (standard iPhone screen) that I want to draw as if it were in landscape mode, though the phone is not oriented that way. This seems like a simple task, which I tried to solve by creating a subview of size 460x320, and then rotating it 90 degrees through setting the view transformation. This worked, except that the rotated view was not centered correctly. To 'fix' this I added a translation transformation, which ended up looking like this:
CGAffineTransform rotate = CGAffineTransformMakeRotation(M_PI / 2.0);
[landscapeView setTransform: CGAffineTransformTranslate(rotate, 70.0, 70.0)];
I don't mind having some adjustment transformation, but I have no clue where the magic number 70 came in. I just played around with it until the edges matched up correctly. How can I get rid of them, either by eliminating the translation transformation, or by deriving the number from some meaningful math related to the height and width?

Just a hunch, but I'm guessing prior to the transform that you're setting (or defaulting) the center of landscapeView to (160, 230). When it rotates, it keeps the upper left position fixed.
(320 px screen width - 460 px width) = -140 px. Divide that in half since it's centered, and you get -70 px. Same idea with the vertical.

70 is the difference between the width and height, divided by two. (460 - 320) / 2. The division by two is what centers the view.

Related

How to change length of line and rotate it dynamically?

I am trying to draw a simple straight line. For this, I am filling an UIImageView with some color with given width as, say 2 pixel and some length. Now user is provided with two UISliders out of which one is used to stretch the line and another slider to rotate. I use myImageView.frame to change the height and CGAffineTransform to rotate. It works fine until I change the rotation angle using slider. But once I rotate the imageview, The slider to stretch doesn't work properly.
I have searched and found that frames won't work after rotating using CGAffineTranfor.
Alternately bounds should work but that didn't work too.
Seeking help. Any brief code will help me.
Thanks in advance.
Give transformed bounds every time you apply a transform. This should work:
CGRect transformedBounds = CGRectApplyAffineTransform(myView.bounds, myView.transform);

How to resize a window in openGL

I'm making a game in OpenGL. I have a viewport that is multiplied by a transformation matrix using glOrthof(). I'm almost done with the game, but I've made a last minute decision to scale everything down a little bit to increase visibility. I have included a diagram depicting how my screen is currently set up (the black box) and how I would like to scale it (the red box).
given the width and height of the black box, and x and y in the diagram, would it be possible to adjust the viewport, or perhaps do some sort of matrix multiplication to increase the window size?
I don't want to actually scale the game, I just want to increase the size of the window (which I guess will ultimately scale the game, but I want to preserve the relative scale).
right now, this is how I'm setting up my view:
glViewport(0, 0, backingWidth, backingHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(-backingWidth/2.0, backingWidth/2.0, -backingHeight/2.0, backingHeight/2.0, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
where backingWidth, and backingHeight are the width and height of the black box respectively.
I'm pretty new to OpenGL, so all help is appreciated.
If you want to see more area in the same viewport size, you can just increase the values given to glOrthof.
If you multiply the top/left/bottom/right of glOrthof to be twice as large, then you will see twice as much in each direction, and everything will be half the original size in each direction, because you're putting twice as much content into the same number of pixels.
You can multiply glOrthof by any scale factor you want.
==EDIT==
Sorry, I noticed that you want to only scale X to the right, and not about the center. In that case leave the left attribute the same, and just add more to the right value of glOrthof.

iPhone iOS which CGAffineTransform does isometric transform [ _ ] to /_/

I need to make a rectangular view [ ] appear as if it's top is rotated back, while the bottom is pinned in place: / \ . The resulting image is isometric with the bottom being wider than the top.
Which CGAffineTransform do I need to accomplish this goal?
As others have pointed out, you can't do this with a CGAffineTransform.
However, it's relatively easy to do with a CATransform3D, as I describe in this answer. You'll need to adjust the m34 component of the CATransform3D to give the transform some degree of perspective, rotate the view about the X axis, and potentially scale it so that the bottom edge remains at the same width as for your original unrotated view.
Alternatively, you might be able to adjust the anchorPoint of your view's underlying layer to be at the bottom, rather than the center. Rotations will then be applied from that edge, which should keep the bottom edge length constant and give you a receding perspective effect for the view. I believe a value of (0.5, 1.0) will set the anchorPoint to the lower edge.
Brad, I found this example (by you!) on how to do a perspective transformation:
http://www.sunsetlakesoftware.com/2008/10/22/3-d-rotation-without-trackball
For some reason it does not work in my code. My buttons have the 3d transform applied, but not the scaling effect.

how to apply an imageview frame with the inclined coordinates

hi all upto now i know making rectangle with the CGrectmake and this rect(frame) i am using as imageview frame like UIImageView *someImage=[[uiimageview alloc]initwithframe:someRect]; now i can add an image with the frame of someRect. my problem here is when the coordinates like
(rectangleFirstx-coordinate,tectangleFirstY-cordinate)=(10,10)
(rectangleLastx-cordinate,rectangleLasty-cordinate)=(17,7) this, how can i give frame to the uiimageview....This is like a inclined rectangle..can any one suggest me how to apply frame through the ios library for these type of coordinates..Thanks in advance..
Your example isn't very clear because a rectangle with opposite corners at (10,10) and (10,7) can be in any one of a myriad of different orientations, including one perfectly aligned along the x and y axis.
What you can certainly do is create a UIImageView of the desired size and location and then rotate it by using one of many techniques, including animation methods.
[UIImageView animateWithDuration:0.1 animations:^
{
your_UIImageView_here.transform = CGAffineTransformMakeRotation((M_PI/180.0) * degrees);
}];
You can hide the UIImageView until the rotation is done and then show it.
If your question is about how to use the coordinates you provided to arrive at an angle I'd suggest that more data is needed because it is impossible to pick one of the billions of possible rectangles with corners at those two points without more information. Once you have more data then it is pretty basic trigonometry to figure out the angle to feed into the rotation.

How to set up a user Quartz2D coordinate system with scaling that avoids fuzzy drawing?

This topic has been scratched once or twice, but I am still puzzled. And Google was not friendly either.
Since Quartz allows for arbitrary coordinate systems using affine transforms, I want to be able to draw things such as floorplans using real-life coordinate, e.g. feet.
So basically, for the sake of an example, I want to scale the view so that when I draw a 10x10 rectangle (think a 10-inch box for example), I get a 60x60 pixels rectangle.
It works, except the rectangle I get is quite fuzzy. Another question here got an answer that explains why. However, I'm not sure I understood that reason why, and moreover, I don't know how to fix it. Here is my code:
I set my coordinate system in my awakeFromNib custom view method:
- (void) awakeFromNib {
CGAffineTransform scale = CGAffineTransformMakeScale(6.0, 6.0);
self.transform = scale;
}
And here is my draw routine:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect r = CGRectMake(10., 10., 10., 10.);
CGFloat lineWidth = 1.0;
CGContextStrokeRectWithWidth(context, r, lineWidth);
}
The square I get is scaled just fine, but totally fuzzy. Playing with lineWidth doesn't help: when lineWidth is set smaller, it gets lighter, but not crisper.
So is there a way to set up a view to have a scaled coordinate system, so that I can use my domain coordinates? Or should I go back and implementing scaling in my drawing routines?
Note that this issue doesn't occur for translation or rotation.
Thanks
the [stroked] rectangle I get is quite fuzzy.
Usually, this is because you plotted the rectangle on whole-number co-ordinates and your line width is 1.
In PostScript (and thus in its descendants: AppKit, PDF, and Quartz), drawing units default to points, 1 point being exactly 1/72 inch. The Mac and iPhone currently* treat every such point as 1 pixel, regardless of the actual resolution of the screen(s), so, in a practical sense, points (by default, on the Mac and iPhone) are equal to pixels.
In PostScript and its descendants, integral co-ordinates run between points. 0, 0, for example, is the lower-left corner of the lower-left point. 1, 0 is the lower-right corner of that same point (and the lower-left corner of the next point to the right).
A stroke is centered on the path you're stroking. Thus, half will be inside the path, half outside.
In the (conceptually) 72-dpi world of the Mac, these two facts combine to produce a problem. If 1 pt is equal to 1 pixel, and you apply a 1-pt stroke between two pixels, then half of the stroke will hit each of those pixels.
Quartz, at least, will render this by painting the current color into both pixels at one-half of the color's alpha. It determines this by how much of the pixel is covered by the conceptual stroke; if you used a 1.5-pt line width, half of that is 0.75 pt, which is three-quarters of each 1-pt pixel, so the color will be rendered at 0.75 alpha. This, of course, goes to the natural conclusion: If you use a 2-pt line width, each pixel is completely covered, so the alpha will be 1. That's why you can see this effect with a 1-pt stroke and not a 2-pt stroke.
There are several workarounds:
Half-point translation: Exactly what it says on the box, you translate up and right by half a point, compensating for the aforementioned 1-pt-cut-in-half division.
This works in simple cases, but flakes out when you involve any other co-ordinate transformations except whole-point translations. That is to say, you can translate by 30, 20 and it'll still work, but if you translate by 33+1/3, 25.252525…, or if you scale or rotate at all, your half-point translation will be useless.
Inner stroke: Clip first, then double the line width (because you're only going to draw half of it), then stroke.
This can require gstate juggling if you have a lot of other drawing to do, since you don't want that clipping path affecting your other drawing.
Outer stroke: Essentially the same as an inner stroke, except that you reverse the path before clipping.
Can be better (less gstate juggling) than an inner stroke if you're sure that the paths you want to stroke won't overlap. On the other hand, if you also want to fill the path, the gstate juggling returns.
*This won't last forever. Apple's been dropping hints for some time that they're going to change at least the Mac's drawing resolution at some point. The API foundation for such a change is pretty much all there now; it's all a matter of Apple throwing the switch.
Well, as often, explaining the issue lead me to a solution.
The problem is that the view transform property is applied to it after it has been drawn into a bit buffer. The scaling transform has to be applied before drawing, ie. in the drawRect method. So scratch the awakeFromNib I gave, and here is a correct drawRect:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform scale = CGAffineTransformMakeScale(6.0, 6.0);
CGContextConcatCTM(context, scale);
CGRect r = CGRectMake(10., 10., 10., 10.);
CGFloat lineWidth = 0.1;
CGContextStrokeRectWithWidth(context, r, lineWidth);
}