Re: Affine Transform
Re: Affine Transform
- Subject: Re: Affine Transform
- From: Erik Buck <email@hidden>
- Date: Sun, 12 Feb 2006 17:17:06 -0500
In this case, you are not learning Cocoa as much as you are learning
very basic graphics programming. You will have the same difficulty
with any framework.
You might want an introductory graphics textbook, but you seem to
have gotten over some of the conceptual issues already without one.
There are several very nice explanations of frame and bounds
available. I will point you to page 201 in "Cocoa Programming"
because I have a self serving interest ;)
Here is complete code for a view that I just now whipped up to draw
an image with any rotation. The view automatically adjusts its own
frame to be large enough to show the whole image as it is rotated.
If you put an instance of this view in a scroll view, the scroll view
will automatically adjust its scroll bars as needed.
I will send a 48k xcode 2.2 project that build a whole test app to
anyone who requests it.
/* SimpleRotatingImageView */
#import <Cocoa/Cocoa.h>
@interface SimpleRotatingImageView : NSView
{
float angleDegrees;
NSImage *image;
BOOL shouldUseMinRect;
}
- (NSImage *)image;
- (void)setImage:(NSImage *)anImage;
- (IBAction)takeAngleFrom:(id)sender;
- (IBAction)takeImageFrom:(id)sender;
- (IBAction)takeShouldUseMinRectFrom:(id)sender;
@end
#import "SimpleRotatingImageView.h"
@implementation SimpleRotatingImageView
- (id)initWithFrame:(NSRect)frameRect
{
if ((self = [super initWithFrame:frameRect]) != nil)
{
angleDegrees = 0.0f;
}
return self;
}
- (void)dealloc
{
[self setImage: nil];
[super dealloc];
}
- (void)drawRect:(NSRect)rect
{
// Erase background
[[NSColor blackColor] set];
NSRectFill([self bounds]);
// Rotate coordinate system abount center of bounds
NSAffineTransform *newTransform = [NSAffineTransform transform];
[newTransform translateXBy:[self bounds].size.width/2.0 yBy:[self
bounds].size.height/2.0];
[newTransform rotateByDegrees:-angleDegrees];
[newTransform translateXBy:-[self bounds].size.width/2.0 yBy:-
[self bounds].size.height/2.0];
[newTransform concat];
// Draw current image centered in bounds
NSImage *currentImage = [self image];
NSRect imageRect = NSZeroRect;
imageRect.size = [currentImage size];
[currentImage drawAtPoint:NSMakePoint([self bounds].size.width/
2.0-imageRect.size.width/2.0,
[self bounds].size.height/
2.0-imageRect.size.height/2.0)
fromRect:imageRect
operation:NSCompositeSourceOver fraction:1.0f];
// Draw center point just for reference
[[NSColor redColor] set];
NSRectFill(NSMakeRect([self bounds].size.width/2.0 - 5, [self
bounds].size.height/2.0 - 5, 10, 10));
}
- (void)adjustFrame
{
// Resize the frame to be large enough to show all of the current
image even if it is rotated.
NSSize imageSize = [image size];
NSAffineTransform *newTransform = [NSAffineTransform transform];
[newTransform translateXBy:imageSize.width/2.0
yBy:imageSize.height/2.0];
if(shouldUseMinRect)
{
[newTransform rotateByDegrees:-angleDegrees];
}
else
{ // This will result in the largest frame needed for any angle
[newTransform rotateByDegrees:45.0f];
}
[newTransform translateXBy:-imageSize.width/2.0 yBy:-
imageSize.height/2.0];
// Transform all four corners of the rectangle that encloses the
current image
NSPoint point0 = [newTransform transformPoint:NSZeroPoint];
NSPoint point1 = [newTransform transformPoint:NSMakePoint(0.0f,
imageSize.height)];
NSPoint point2 = [newTransform transformPoint:NSMakePoint
(imageSize.width, imageSize.height)];
NSPoint point3 = [newTransform transformPoint:NSMakePoint
(imageSize.width, 0.0f)];
// Find the minimum and maximum coordinates of the transformed
rectangle that encloses the current image
float minX = MIN(MIN(MIN(point0.x, point1.x), point2.x),
point3.x);
float minY = MIN(MIN(MIN(point0.y, point1.y), point2.y),
point3.y);
float maxX = MAX(MAX(MAX(point0.x, point1.x), point2.x),
point3.x);
float maxY = MAX(MAX(MAX(point0.y, point1.y), point2.y),
point3.y);
// Set the frame size large enough to enclose the minimum and
maximum coordinates of the transformed rectangle
[self setFrameSize:NSMakeSize(maxX - minX, maxY - minY)];
}
- (IBAction)takeShouldUseMinRectFrom:(id)sender
{
shouldUseMinRect = (BOOL)[sender intValue];
[self adjustFrame];
[self setNeedsDisplay:YES];
}
- (IBAction)takeAngleFrom:(id)sender
{
angleDegrees = [sender floatValue];
[self adjustFrame];
[self setNeedsDisplay:YES];
}
- (NSImage *)image
{
return image;
}
- (void)setImage:(NSImage *)anImage
{
[anImage retain];
[image release];
image = anImage;
[self adjustFrame];
[self setNeedsDisplay:YES];
}
- (IBAction)takeImageFrom:(id)sender
{
[self setImage:[sender image]];
}
@end
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden