I'm trying to make a UIView move and rotate at the same time.
Here's my code:
_viewToDrag.frame = CGRectMake(x, y, size, width);
_viewToDrag.transform = CGAffineTransformMakeRotation(-M_PI_2 * multiplier));
As the multiplier increases (0.0 .. 1.0) the view stretches beyond any logic.
This post seems to answer my question:
Rotating and Moving a UIImageView (CocoaTouch)
But, since I'm code-dyslexic and a bit retarded can some explain what this translates to code:
Change the "center" property instead.
I would have made a comment but my reputation doesn't allow it.
Always consult the documentation. Apple says, in a big box with an exclamation mark graphic next to it, in the section on frame:
Warning: If the transform property is not the identity transform, the
value of this property is undefined and therefore should be ignored.
Underneath centre it says:
The center is specified within the coordinate system of its superview
and is measured in points. Setting this property changes the values of
the frame properties accordingly.
So the answer you link to is incorrect. Given its one-sentence nature with no reference to sources, probably the author tried it once, on the version of iOS he happened to have installed, it looked like it worked and he jumped straight to an unsupported conclusion.
The other answer is correct. You need to build the translation into your transform. Likely by throwing in a use of CGAffineTransformTranslate.
EDIT: so, to set a transform with a translation of (1000, 0) and a rotation of -M_PI/2:
_viewToDrag.transform = CGAffineTransformRotate(
CGAffineTransformMakeTranslation(1000.0, 0.0),
-M_PI_2);
The frame has a center property as well as origin and size.
The center is a CGPoint just like origin except it marks the center of the frame instead of the upper lefthand corner.
Related
How can I get the current position of a CALayer instance in the coordinates of its super layer? (Mac application)
I would have expected this to be available from the frame property but it isn't. In particular, this CALayerinstance has been positioned using various CAConstraint types and I have not specified the (x,y) position explicitly.
The problem seems to have gone away when I check the frame "later" during the execution of the program.
In the question I was checking the bounds during the init and I can thus assume that the actual layout had not taken place yet and hence the runtime didn't know what the position actually was - it was indeterminate at that point.
I'm animating objects falling onto a board from above, and I want to animate the board 'falling back' as the objects fall upon it. Objects can fall at any point on the board, and when the board 'falls back' I am scaling the board to a smaller scale.
When using CGAffineTransformScale objects scale based on their anchor point, the centre of the object; I want to scale the board and then line up the transformed board with the object that has fallen on it, so that the object that has fallen appears to stay in the same place relative to the board (or, more correctly, the board stays in the same place relative to the position of the board).
I spent hours, and hours changing the anchor point to the position that the object fell, but this revealed a fundamental misunderstanding on my part of how layer.anchorPoint actually works.
I imagine the solution is deriving a vector from the centre of the board to the given falling object and then somehow adjusting position of the board in the transformation so it's the same place. This is where I need help!
As you'd expect in these situations, an animated gif is required.
CALayer's anchorPoint property is the correct property to use for this, with the one minor annoyance that it works in the unit coordinate space, that is, it goes from 0 to 1, not in pixels:
You specify the value for this property using the unit coordinate space. The default value of this property is (0.5, 0.5), which represents the center of the layer’s bounds rectangle. All geometric manipulations to the view occur about the specified point. For example, applying a rotation transform to a layer with the default anchor point causes the layer to rotate around its center. Changing the anchor point to a different location would cause the layer to rotate around that new point.
Because of this, setting an anchor point in pixels would obviously result in some very strange behaviour. You would need to calculate your new anchor point in the unit coordinate space for it to work properly, so, instead of doing something like this:
board.layer.anchorPoint = CGPointMake(ball.x, ball.y);
you would do this:
board.layer.anchorPoint = CGPointMake(ball.x / board.layer.bounds.size.width,
ball.y / board.layer.bounds.size.height);
UPDATE: When you change the anchorPoint property, the view will move, because the anchorPoint, which is set relative to the layer in the unit coordinate space, is anchored to the layer's position property, which is set in the superview's coordinate space. In this way, when you change the value of the anchorPoint property, the view will move such that the point at the new anchor point is at the same place as the old one. You will need to compensate for this, as described in this answer.
Is it possible to change the origin of an NSImage? If so how would I go about doing this. I have coordinates in regular cartesian system some of them with negative values and I am trying to draw them at the corresponding point in the NSImage but since the origin is at (0,0) there are some missing.
EDIT:Say I have an drawing aspect that needs to be done to an image at the point (-10,-10), currently this doesn't show up. Is there a way to fix that?
If it's like in iOS (you may have to adapt a little the code) and if my memory is still good, you have to do this, since origin is readOnly:
CGRect myFrame = yourImage.frame;
myFrame.origin.x=newX; myFrame.origin.y=newY;
yourImage.frame = myFrame;
I think you are confusing an NSImage with it's container. An NSImage has no bounds or frame, and thus no origin. It does have a size which may represent the pixel dimensions of its birtmap representation ( if it has one) or otherwise could represent it's bounding box ( if it is a vector image). Drawing in an image at a pixel location of (-10,-10) doesn't really make sense.
An NSImage is displayed in a container ( typically an NSImageView), and the container's bounds.origin will dictate the placement of the image relative to the imageView, but you can't modify pixels beyond the edge of the bitmap plane.
In any case you probably want to be using a subclassed NSView in which you would override the drawRect method for your custom drawing. NSView does have a bounds.origin but this is not relevant to your in-drawing coordinates, but rather to the position of the drawn content as a whole to the view's bounding box. The coordinate system that you will be drawing into will be referenced to your graphics context which will (usually) pin the origin (0,0) to the bottom left corner (OSX) or top left corner (iOS). If you are trying to represent negative points on a Cartesian plane, you will need to apply a translation transform to map your points into this positive coordinate space.
I'm trying to explain in a few words, badly, something which Apple explains in great detail in their Quartz 2D Programming Guide.
I've had a pretty good look around for an answer to this, and tried several solutions in my code, nothing found so far.
I have a line graph that I am plotting, a CPTScatterPlot graph, and I have got points adding to it correctly. I want to show each of these points as a dot about 3-5 pixels in diameter, and connected by lines that are about 3 pixels wide. This all works fine.
The problem is that when the plot is a straight along one of the edges of the graph hosting view, the lines and dots are clipped and don't look right at all.
This is a mockup of what it should look like:
And this is the effect I am seeing much of the time at the moment:
I apologise for the small images, but hopefully you can see that in the second one, the line and dots are rendered only a few pixels into the graph view, not fully in view. In the second one the data is actually at y=1 for the first 75%, then falls down to y=0.
How can I inset the drawing of the graph components by several pixels to prevent the clipping of any shapes?
So far:
I have tried setting the padding on the graph, but that just
contracts the area it draws to, I suppose to make room for titles
which I am not using.
I have also tried adding to the min/max x/y range settings which I
recalculate based on the data I am updating in the background. This
works, but obviously only if the amount I add to those values is
correct in relation to the drawing scale that will be used for the
data values I am inputting.
I am on Mac OS using NSView (actually CPTGraphHostingView) so clipsToBounds isn't available. Also, I tried masksToBounds and masksToBorder on CPTXYGraph.
I think the easiest way to handle this is to simply extend your ranges by a small amount. There is a method in CPTPlotRange that makes it very easy to extend a given range by a fixed percentage (e.g. 1%). I think the main test app example even shows this in action.
Another option would be to turn off the masksToBounds and/or masksToBorder on the CPTPlotArea (plotArea) and possibly the CPTPlotAreaFrame (plotAreaFrame). You access them both via properties of the graph.
This might be of help..
The default padding on the graph itself (not the plot area frame) is 20 pixels on each side. You can change that, too.
graph.paddingLeft = 0.0;
graph.paddingTop = 0.0;
graph.paddingRight = 0.0;
graph.paddingBottom = 0.0;
I am trying to draw some text via Quartz onto an NSView via CGContextShowTextAtPoint(). This worked well until I overrode (BOOL)isFlipped to return YES in my NSView subclass in order to position the origin in the upper-left for drawing. The text draws in the expected area but the letters are all inverted. I also tried the (theoretically, at least) equivalent of flipping my CGContext and translating by the context's height.
e.x.
// drawRect:
CGContextScaleCTM(theContext, 1, -1);
CGContextTranslateCTM(theContext, 0, -dirtyRect.size.height);
This yields the same result.
Many suggestions to similar problems have pointed to modifying the text matrix. I've set the text matrix to the identity matrix, performed an additional inversion on it, and done both, respectively. All these solutions have lead to even stranger rendering of the text (often just a fragment shows up.)
Another suggestion I saw was to simply steer clear of this function in favor of other means of drawing text (e.x. NSString's drawing methods.) However, this is being done amongst mostly C++ / C and I'd like to stay at those levels if possible.
Any suggestions are much appreciated and I'd be happy to post more code if needed.
Thanks,
Sam
This question has been answered here.
Basically it's because the coordinate system on iOS core graphics is fliped (x:0, y:0 in the top left) opposed to the one on the Mac (where x:0, y:0 is bottom left). The solution for this is setting the text transform matrix like this:
CGContextSetTextMatrix(context, CGAffineTransformMake(1.0,0.0, 0.0, -1.0, 0.0, 0.0));
You need to use the view's bounds rather than the dirtyRect and perform the translation before the scale:
CGContextTranslateCTM(theContext, 0, -NSHeight(self.bounds));
CGContextScaleCTM(theContext, 1, -1);
Turns out the answer was to modify the text matrix. The weird "fragments" that were showing up instead of the text was because the font size (set via CGContextSelectFont()) was too small when the "default" text matrix was replaced. The initial matrix had, for some reason, a large scale transform so smaller text sizes looked fine when the matrix was unmodified; when replaced with a inverse scale (1, -1) or an identity matrix, however, they would become unreadably small.