15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Rotating a bitmap

R. Kevin Burton -- kburton@mail.tds.net
Friday, November 15, 1996

Environment: VC++ 4.1, WinNT 3.51

I am having more trouble than I expected with rotating a bitmap. I can
rotate the bitmap by integral multiples of 90 degrees with no problem
and the other angles do rotate but I am getting what looks like a
shearing effect that I did not expect.

+-----+              +-----+
|     |               \     \
|     |    --->        \     \
|     |                 \     \
|     |                  \     \
+-----+                   +-----+

Here is the code:

The transformation:

-------------------------------------------------------

        //                       |1   0   0|  
        // |x' y' 1| = |x y 1| * |0   1   0|  
        //                       |Dx  Dy  1| 

        XFORM translateDownTransform;

        translateDownTransform.eM11 = 1.0f;
        translateDownTransform.eM12 = 0.0f;
        translateDownTransform.eM21 = translateDownTransform.eM12;
        translateDownTransform.eM22 = translateDownTransform.eM11;
        translateDownTransform.eDx = -(float)pDib->GetWidth()/2;
        translateDownTransform.eDy = -(float)pDib->GetHeight()/2;

        // |x' y'| == |x y| * | cos A   sin A|  
    //                    |-sin A   cos A|

        XFORM rotationTransform;
        rotationTransform.eM11 = (float)cos(m_fRotation);
        rotationTransform.eM12 = (float)sin(m_fRotation);
        rotationTransform.eM21 = rotationTransform.eM12;
        rotationTransform.eM22 = rotationTransform.eM11;
        rotationTransform.eDx = 0.0f;
        rotationTransform.eDy = 0.0f;

        //                       |1   0   0|  
        // |x' y' 1| = |x y 1| * |0   1   0|  
        //                       |Dx  Dy  1| 

        XFORM translateUpTransform;

        translateUpTransform.eM11 = 1.0f;
        translateUpTransform.eM12 = 0.0f;
        translateUpTransform.eM21 = translateUpTransform.eM12;
        translateUpTransform.eM22 = translateUpTransform.eM11;
        translateUpTransform.eDx = (float)pDib->GetWidth()/2;
        translateUpTransform.eDy = (float)pDib->GetHeight()/2;

        CombineTransform(&m_currentTransform, &m_originalTransform,
&translateDownTransform);
        CombineTransform(&m_currentTransform, &m_currentTransform,
&rotationTransform);
        CombineTransform(&m_currentTransform, &m_currentTransform,
&translateUpTransform);

        Invalidate();

-------------------------------------------------------

Now the Drawing:

-------------------------------------------------------
        CRect rcDraw;
        CLineAcqDoc* pDoc = GetDocument();
        CDib *pDib = pDoc->GetDIB();
        GetClientRect(rcDraw);
        // Get the clip box.
        CRect rcClip;
        pDC->GetClipBox(rcClip);

        // Create a rect for the DIB.
        CRect rcDIB;
        rcDIB.left = rcDIB.top = 0;
        rcDIB.right = pDib->GetWidth() - 1;
        rcDIB.bottom = pDib->GetHeight() - 1;

        // Find a rectangle that describes the intersection of the draw
        // rect, clip rect, and DIB rect.
        // CRect rcBlt = rcDraw & rcClip & rcDIB;

        CRect rcBlt = rcClip & rcDIB;
       // Copy the update rectangle from the off-screen DC to the
       // window DC. Note that the DIB origin is the bottom-left corner.
       int w, h, xs, xd, yd, ys;
       w = rcBlt.right - rcBlt.left;
       h = rcBlt.bottom - rcBlt.top;
       xs = xd = rcBlt.left;
       ys = rcBlt.top;
       yd = rcBlt.top;

       // If we have a palette, select and realize it.
       CPalette *pPalette = pDib->GetPalette();
       CPalette *pOldPalette = NULL;
       pOldPalette = pDC->SelectPalette(pPalette, FALSE);
       pDC->RealizePalette();

       BYTE* pBits;
       CDC dcMem;
       dcMem.CreateCompatibleDC(pDC);
       HBITMAP hbmOld = (HBITMAP)dcMem.SelectObject(pDib->GetBitmap());


        POINT destPoint[3];
        CBitmap hbmMask;
        // This is the correct settings
        destPoint[0].x = xd;
        destPoint[0].y = yd;
        destPoint[1].x = xd+w
        destPoint[1].y = yd;
        destPoint[2].x = xd;
        destPoint[2].y = yd+h;
        SetGraphicsMode(pDC->GetSafeHdc(), GM_ADVANCED);
        SetWorldTransform (pDC->GetSafeHdc(), &m_currentTransform);
        pDC->PlgBlt(destPoint,
                    &dcMem,
                    xs, ys,
                    w, h,
                    hbmMask, 0, 0);
-------------------------------------------------------

     
-- 
Kevin Burton
kburton@waun.tdsnet.com



Gajendra Prasad Yadav -- gajendra@aditi.com
Monday, November 18, 1996

[Mini-digest: 4 responses]

Hi You may want to refer to the PLGBLT sample. This sample uses PlgBlt()
API to rotate or shear bitmaps. PLGBLT is a Microsoft Win32(R) Software
Development Kit (SDK) sample and also available on MSDN.

Gajendra,
Aditi


>----------
>From: 	Kevin Burton[SMTP:kburton@mail.tds.net]
>Sent: 	Saturday, November 16, 1996 12:45 AM
>To: 	mfc-l@netcom.com
>Cc: 	kburton@mail.tds.net
>Subject: 	Rotating a bitmap
>
>Environment: VC++ 4.1, WinNT 3.51
>
>I am having more trouble than I expected with rotating a bitmap. I can
>rotate the bitmap by integral multiples of 90 degrees with no problem
>and the other angles do rotate but I am getting what looks like a
>shearing effect that I did not expect.
>
>+-----+              +-----+
>|     |               \     \
>|     |    --->        \     \
>|     |                 \     \
>|     |                  \     \
>+-----+                   +-----+
>
>Here is the code:
>
>The transformation:
>
>-------------------------------------------------------
>
>        //                       |1   0   0|  
>        // |x' y' 1| = |x y 1| * |0   1   0|  
>        //                       |Dx  Dy  1| 
>
>        XFORM translateDownTransform;
>
>        translateDownTransform.eM11 = 1.0f;
>        translateDownTransform.eM12 = 0.0f;
>        translateDownTransform.eM21 = translateDownTransform.eM12;
>        translateDownTransform.eM22 = translateDownTransform.eM11;
>        translateDownTransform.eDx = -(float)pDib->GetWidth()/2;
>        translateDownTransform.eDy = -(float)pDib->GetHeight()/2;
>
>        // |x' y'| == |x y| * | cos A   sin A|  
>    //                    |-sin A   cos A|
>
>        XFORM rotationTransform;
>        rotationTransform.eM11 = (float)cos(m_fRotation);
>        rotationTransform.eM12 = (float)sin(m_fRotation);
>        rotationTransform.eM21 = rotationTransform.eM12;
>        rotationTransform.eM22 = rotationTransform.eM11;
>        rotationTransform.eDx = 0.0f;
>        rotationTransform.eDy = 0.0f;
>
>        //                       |1   0   0|  
>        // |x' y' 1| = |x y 1| * |0   1   0|  
>        //                       |Dx  Dy  1| 
>
>        XFORM translateUpTransform;
>
>        translateUpTransform.eM11 = 1.0f;
>        translateUpTransform.eM12 = 0.0f;
>        translateUpTransform.eM21 = translateUpTransform.eM12;
>        translateUpTransform.eM22 = translateUpTransform.eM11;
>        translateUpTransform.eDx = (float)pDib->GetWidth()/2;
>        translateUpTransform.eDy = (float)pDib->GetHeight()/2;
>
>        CombineTransform(&m_currentTransform, &m_originalTransform,
>&translateDownTransform);
>        CombineTransform(&m_currentTransform, &m_currentTransform,
>&rotationTransform);
>        CombineTransform(&m_currentTransform, &m_currentTransform,
>&translateUpTransform);
>
>        Invalidate();
>
>-------------------------------------------------------
>
>Now the Drawing:
>
>-------------------------------------------------------
>        CRect rcDraw;
>        CLineAcqDoc* pDoc = GetDocument();
>        CDib *pDib = pDoc->GetDIB();
>        GetClientRect(rcDraw);
>        // Get the clip box.
>        CRect rcClip;
>        pDC->GetClipBox(rcClip);
>
>        // Create a rect for the DIB.
>        CRect rcDIB;
>        rcDIB.left = rcDIB.top = 0;
>        rcDIB.right = pDib->GetWidth() - 1;
>        rcDIB.bottom = pDib->GetHeight() - 1;
>
>        // Find a rectangle that describes the intersection of the draw
>        // rect, clip rect, and DIB rect.
>        // CRect rcBlt = rcDraw & rcClip & rcDIB;
>
>        CRect rcBlt = rcClip & rcDIB;
>       // Copy the update rectangle from the off-screen DC to the
>       // window DC. Note that the DIB origin is the bottom-left corner.
>       int w, h, xs, xd, yd, ys;
>       w = rcBlt.right - rcBlt.left;
>       h = rcBlt.bottom - rcBlt.top;
>       xs = xd = rcBlt.left;
>       ys = rcBlt.top;
>       yd = rcBlt.top;
>
>       // If we have a palette, select and realize it.
>       CPalette *pPalette = pDib->GetPalette();
>       CPalette *pOldPalette = NULL;
>       pOldPalette = pDC->SelectPalette(pPalette, FALSE);
>       pDC->RealizePalette();
>
>       BYTE* pBits;
>       CDC dcMem;
>       dcMem.CreateCompatibleDC(pDC);
>       HBITMAP hbmOld = (HBITMAP)dcMem.SelectObject(pDib->GetBitmap());
>
>
>        POINT destPoint[3];
>        CBitmap hbmMask;
>        // This is the correct settings
>        destPoint[0].x = xd;
>        destPoint[0].y = yd;
>        destPoint[1].x = xd+w
>        destPoint[1].y = yd;
>        destPoint[2].x = xd;
>        destPoint[2].y = yd+h;
>        SetGraphicsMode(pDC->GetSafeHdc(), GM_ADVANCED);
>        SetWorldTransform (pDC->GetSafeHdc(), &m_currentTransform);
>        pDC->PlgBlt(destPoint,
>                    &dcMem,
>                    xs, ys,
>                    w, h,
>                    hbmMask, 0, 0);
>-------------------------------------------------------
>
>     
>-- 
>Kevin Burton
>kburton@waun.tdsnet.com
>
-----From: "Alan J. Livingston" 

Shouldn't 
        rotationTransform.eM21 = rotationTransform.eM12;
be
        rotationTransform.eM21 = -rotationTransform.eM12;
Note the negative:              ^^^


-Alan


-----From: "KobyLev" 

In order to rotate an image you have to know 2 things:

1. you have to recalculate the image center, that is you have to know that
the rotation formula : 

	| x' |      | cos(teta)   sin(teta) |    |x|
	|    |  =  |                              | *  |  |
	|y'  |      | -sin(teta)   cos(teta)|    |y|

	where theta is the rotation angle.
	in the above formula the rotation is with respect to the Image origin that
is   
	here:
	(0,0)-------------------
	      |                  |
	      |   image      |
	      |        *         |
	      |    true         |
	      |     org.        |
	      --------------------
	in order to get the right rotation you have to rewrite the formula in this
manner:

		| x' |      | cos(teta)      sin(teta) |    |x - w/2|
		|    |  =  |                                 | * |           |
		|y'  |      | -sin(teta)    cos(teta)  |    |y - h/2 |


	where w, h are the image width, and hight respectively.

2. Dont forget to calculate the new image size pre-rotating the image, that
is the image size will be:
	
	| w' |      | cos(teta)      sin(teta) |    |w|
	|    |  =  |                                 | *  |  |
	|h'  |      | -sin(teta)    cos(teta)  |    |h|
where w, h, w', h' are the image width, and high before and after the
rotation, respectively.

+       +       ++++++      ++++++        +         +    @@@@@@@@@ @   
+    +        +  @   @+     +          +        +       +    @ Koby Lev    
        @     
+  +          +      O   +     ++++++             +   +     @
kobylev@ibm.net @    
+      +      +    ---    +     +          +               +     
@@@@@@@@@@
+         +     ++++++      ++++++  ++++++++     
      
-----From: browkl@inel.gov (Kenneth L Brown)

You're probably better off to check out a graphics oriented faq where
you're likely to find more people working directly with graphics and
graphics transformations.  It's been a few years since I did any serious
graphics work and my suggestions may be a little of date so I will only
attempt to point you in the right direction.

The shearing effect appears to be an error in your translation of the
mathematics to code.  I don't have the time to go through your code to
find it but I would recommend a close examination of the code against a
matrix based solution with known numbers first.  Check out your trig
operations since your rotations are working for primary angles.  At the
risk of insulting your intelligence, cos(0) = 1 and sin(90)=1 so when
you deviate from an angle where either the cos or sin are supposed to be
0 or 1, and the results of compound math operations using either of
those operations is 0 or 1 your image will distort or not do anything at
all.  The shear you show below tells me that probably only one equation
is wrong. Which one depends on the direction of the shear.  It is a good
idea to check for precision errors here since this is a common problem
where cos, sin and division are used together.

I would also recommend the book Computer Graphics, Principles and
Practice by Foley and van Dam.  This book is considered by many to be
the bible of computer graphics.  It runs between $60 and $75 dollars
depending on where you get it and is available from Addison Wesley.  I
have nearly worn out my copy.  It's well worth the price.  The book
covers several different methods for performing geometrical
transformations including the one your using here.

Of particular interest is the chapter on Image Storage and
Manipulation.  In this chapter is a section on Multipass
Transformations.  An image rotation can be accomplished by performing a
column shear followed by a row shear.  This is often faster and more
accurate than the matrix method.  There are also many other ways to
accomplish the same thing which you will need to research to find the
method most appropriate to your application.

I am a user of the book only and am in no way affiliated with the
publisher or authors.  I have the second edition which is almost 7 years
old now but I expect the latest edition is much the same.

Kenneth Brown
browkl@inel.gov




Jim Lawson Williams -- jimlw@mail.ccur.com.au
Thursday, November 21, 1996

At 01:15 PM 15-11-96 -0600, you wrote:
>Environment: VC++ 4.1, WinNT 3.51
>
>I am having more trouble than I expected with rotating a bitmap.
    
>        XFORM rotationTransform;
>        rotationTransform.eM11 = (float)cos(m_fRotation);
>        rotationTransform.eM12 = (float)sin(m_fRotation);
>        rotationTransform.eM21 = rotationTransform.eM12;
>        rotationTransform.eM22 = rotationTransform.eM11;
    

>From "Books Online",

eM21 Specifies the following: 

Operation	Meaning
Shear	        Vertical proportionality constant
Rotation	Negative sine of the rotation angle
                ^^^^^^^^
Now I've not used XFORM, but my reading indicates you're in error there and
elsewhere with eM22.  What values do you get when you translate the vertices
of the rectangle bounding your bitmap?


>Now the Drawing:
>
>-------------------------------------------------------
>        CRect rcDraw;
         ^^^^^^^^^^^^^
To what use, if any, is this put? 
     
...and the rest -- e.g., are you always dealing with normalized rectangles
in a consistent "logical" or "device" coordinate space? -- I am in no
position to comment about.

Regards,
Jim LW





| Вернуться в корень Архива |