简体   繁体   中英

NSAffineTransforms not being used?

I have a subclass of NSView, and in that I'm drawing an NSImage. I'm unsing NSAffineTransforms to rotate, translate and scale the image.

Most of it works fine. However, sometimes, the transforms just don't seem to get activated.

For example, when I resize the window, the rotate transform doesn't happen.

When I zoom in on the image, it puts the lower left of the image in the correct place, but doesn't zoom it, but it does zoom the part of the image that would be to the right of the original sized image. If I rotate this, it zooms correctly, but translates wrong. (The transation may be a calculation error on my part)

Here is the code of my drawRect: (sorry for the long code chunk)

- (void)drawRect:(NSRect)rect 
{
    // Drawing code here.
    double rotateDeg = -90* rotation;
    NSAffineTransform *afTrans = [[NSAffineTransform alloc] init];
    NSGraphicsContext *context = [NSGraphicsContext currentContext];
    NSSize sz;
    NSRect windowFrame = [[self window] frame];
    float deltaX, deltaY;
    NSSize superSize = [[self superview] frame].size;
    float height, width, sHeight, sWidth;

    NSRect imageRect;

    if(image)
    {
        sz = [ image size];
        imageRect.size = sz;
        imageRect.origin = NSZeroPoint;
        imageRect.size.width *= zoom;
        imageRect.size.height *= zoom;

        height = sz.height * zoom  ;
        width = sz.width *zoom ;
        sHeight = superSize.height;
        sWidth = superSize.width;
    }

I need to grab the sizes of everything early so that I can use them later when I rotate. I am not sure that I need to protect any of that, but I'm paranoid from years of C...

    [context saveGraphicsState];

// rotate
    [afTrans rotateByDegrees:rotateDeg];
// translate to account for window size;
    deltaX = 0;
    deltaY = 0;

// translate to account for rotation

// in 1 and 3, X and Y are reversed because the entire FRAME
// (inculding axes) is rotated!
    switch (rotation)
    {
        case 0:
//          NSLog(@"No rotation ");
            break;
        case 1: 
            deltaY -= (sHeight - height); 
            deltaX -= sHeight ;
            break;
        case 2:
            deltaX -= width;
            deltaY -= ( 2*sHeight - height);    
            // it's rotating around the lower left of the FRAME, so,
            // we need to move it up two frame hights, and then down
            // the hieght of the image
            break;
        case 3:
            deltaX += (sHeight - width);
            deltaY -= sHeight;
            break;
    }

Since I'm rotating around the lower left corner, and I want the image to be locked to the upper left corner, I need to move the image around. When I rotate once, the image is in the +- quadrant, so I need to shift it up one view-height, and to the left a view-height minus an image height. etc.

    [afTrans translateXBy:deltaX yBy:deltaY];

// for putting image in upper left

// zoom
    [afTrans scaleBy: zoom];
    printMatrix([afTrans  transformStruct]);
    NSLog(@"zoom %f", zoom);
    [afTrans concat];

    if(image)
    {
        NSRect drawingRect = imageRect;
        NSRect frame = imageRect;

        frame.size.height = MAX(superSize.height, imageRect.size.height) ;
        [self setFrame:frame];

        deltaY =  superSize.height - imageRect.size.height;
        drawingRect.origin.y += deltaY;

This makes the frame the correct size so that the image is in the upper left of the frame. If the image is bigger than the window, I want the frame to be big enough so scroll bars appear. If it isn't I want the frame to be big enough that it reaches the top of the window.

        [image drawInRect:drawingRect
               fromRect:imageRect
               operation:NSCompositeSourceOver
               fraction:1];

        if((rotation %2) )
        {
            float tmp;
            tmp = drawingRect.size.width;
            drawingRect.size.width = drawingRect.size.height;
            drawingRect.size.height = tmp;
        }

This code may be entirely historical, now that I look at it... the idea was to swap height andwidth if I rotated 90 or 270 degs.

    }
    else
        NSLog(@"no image"); 

    [afTrans release];
    [context restoreGraphicsState];

}

Why do you use the superview's size? That's something you should almost never need to worry about. You should make the view work on its own without dependencies on being embedded in any specific view.

Scaling the size of imageRect is probably not the right way to go. Generally when calling -drawImage you want the source rect to be the bounds of the image, and scale the destination rect to zoom it.

The problems you're reporting kind of sound like you're not redrawing the entire view after changing the transformation. Are you calling -setNeedsDisplay: YES?

How is this view embedded in the window? Is it inside an NSScrollView? Have you made sure the scroll view resizes along with the window?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM