ورود

View Full Version : سوال: چرخش يك تصوير در mfc



noshin156
شنبه 16 اردیبهشت 1391, 09:58 صبح
سلام
من يك picture control دارم كه مي خوام با كليك كردن روي يك دكمه آن را يك درجه يك درجه بچرخانم
كسي در اين زمينه اطلاعاتي داره؟

pe32_64
شنبه 16 اردیبهشت 1391, 13:08 عصر
http://www.codeguru.com/cpp/g-m/bitmap/specialeffects/article.php/c1743/Rotate-a-bitmap-image.htm

ASGGSA
دوشنبه 18 اردیبهشت 1391, 18:36 عصر
سلام.
این هم یک تابع برای دوران یک تصویر در هر نقطه دلخواه که اشکالات توابع بالا را ندارد.

HBITMAP GetRotatedBitmap(HBITMAP hBitmap, int rot_x, int rot_y, float degree, COLORREF clrBack)
{
CDC sourceDC, destDC;
sourceDC.CreateCompatibleDC( NULL );
destDC.CreateCompatibleDC( NULL );
BITMAP bm;
GetObject( hBitmap, sizeof(bm), &bm );
degree = degree * 3.14f / 180.0f;
int x1 = (int)(bm.bmHeight * sin(45));
int y1 = (int)(bm.bmHeight * cos(45));
int x2 = (int)(bm.bmWidth * cos(45) + bm.bmHeight * sin(45));
int y2 = (int)(bm.bmHeight * cos(45) - bm.bmWidth * sin(45));
int x3 = (int)(bm.bmWidth * cos(45));
int y3 = (int)(-bm.bmWidth * sin(45));
int minx = min(0,min(x1, min(x2,x3)));
int miny = min(0,min(y1, min(y2,y3)));
int maxx = max(0,max(x1, max(x2,x3)));
int maxy = max(0,max(y1, max(y2,y3)));
int w = maxx - minx;
int h = maxy - miny;
int max = w >= h ? w : h;
int posx = (max - bm.bmWidth) / 2;
int posy = (max - bm.bmHeight) / 2;
HBITMAP hbmResult = CreateCompatibleBitmap(CClientDC(NULL), max, max);
HBITMAP hbmOldSource = (HBITMAP)SelectObject(sourceDC.m_hDC, hBitmap );
HBITMAP hbmOldDest = (HBITMAP)SelectObject( destDC.m_hDC, hbmResult );
HBRUSH hbrBack = CreateSolidBrush( clrBack );
HBRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );
destDC.PatBlt( 0, 0, max, max, PATCOPY );
DeleteObject(SelectObject( destDC.m_hDC, hbrOld ));
for( int y = 0; y < max; y++ )
for( int x = 0; x < max; x++ )
{
int xx = rot_x - x + posx;
int yy = rot_y - y + posy;
int sourcex = (int)(rot_x + (xx * cos(degree) - yy * sin(degree)));
int sourcey = (int)(rot_y + (xx * sin(degree) + yy * cos(degree)));
if(sourcex >= 0 && sourcex < bm.bmWidth && sourcey >= 0 && sourcey < bm.bmHeight)
destDC.SetPixel(x ,y,sourceDC.GetPixel(sourcex,sourcey));
}
SelectObject(sourceDC.m_hDC, hbmOldSource);
SelectObject(destDC.m_hDC, hbmOldDest);
return hbmResult;
}

در این تابع مقادیر rot_x و rot_y مرکز دوران را مشخص می کند که می تواند هر نقطه دلخواهی باشد و degree برحسب درجه است.
موفق باشید.

noshin156
دوشنبه 18 اردیبهشت 1391, 21:39 عصر
مرسي مشكل ثابت ماندنش حل شد فقط وقتي كليك مي كنم يك چهارم ازعكسم نمايش داده مي شودو اون هم در گوشه سمت راست picture control نمايش داده مي شودنه در وسط

86795



به نظر شما چرا اين جوري ميشه؟

ASGGSA
دوشنبه 18 اردیبهشت 1391, 22:19 عصر
من چند بار این تابع رو امتحان کردم و مشکلی نداشته حالا شما قسمتی از کدهاتون را بنویسید تا ببینم مشکل از کجاست.

noshin156
دوشنبه 18 اردیبهشت 1391, 23:35 عصر
void CMy67Dlg::OnBnClickedOk()
{
// TODO: Add your control notification handler code here
const float PI = 3.141529f;
static float degree = 0.0f;
CClientDC dc(this);
HDC hdc = CreateCompatibleDC(NULL);
HBITMAP hbm1, hbm2, hbm3;
hbm1 = LoadBitmap(::AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP1));
hbm2 = GetRotatedBitmapNT(hbm1, degree,0,0, RGB(255,255,255));
hbm3 = (HBITMAP)SelectObject(hdc, hbm2);
BitBlt(dc,100,200,600, 573,hdc,0,0, SRCAND);
degree += 2.0f / (360.0f / (2 * PI));

DeleteObject(hbm1);
DeleteObject(hbm2);
DeleteObject(hbm3);
DeleteDC(hdc);
InvalidateRect(NULL, FALSE);
}

noshin156
دوشنبه 18 اردیبهشت 1391, 23:38 عصر
بقيه كد هم عيناَ همون چيزيه كه شما گذاشتي!!!!

ASGGSA
سه شنبه 19 اردیبهشت 1391, 00:08 صبح
سلام.
مشکل تابع بالا رو پیدا کردم از این تابع جدید استفاده کنید.

HBITMAP GetRotatedBitmap(HBITMAP hBitmap, int rot_x, int rot_y, float degree, COLORREF clrBack)
{
CDC sourceDC, destDC;
sourceDC.CreateCompatibleDC( NULL );
destDC.CreateCompatibleDC( NULL );
BITMAP bm;
GetObject( hBitmap, sizeof(bm), &bm );
degree = degree * 3.14f / 180.0f;
int dis1 = (int)sqrt(pow(bm.bmWidth - rot_x, 2) + pow(bm.bmHeight - rot_y, 2));
int dis2 = (int)sqrt(pow(-rot_x, 2) + pow(-rot_y, 2));
int dis3 = (int)sqrt(pow(-rot_x, 2) + pow(bm.bmHeight - rot_y, 2));
int dis4 = (int)sqrt(pow(bm.bmWidth - rot_x, 2) + pow(-rot_y, 2));
int dis5 = dis1 >= dis2 ? dis1 : dis2;
int dis6 = dis3 >= dis4 ? dis3 : dis4;
int max = dis5 >= dis6 ? dis5 : dis6;
int posx = max - rot_x;
int posy = max - rot_y;
max *= 2;
HBITMAP hbmResult = CreateCompatibleBitmap(CClientDC(NULL), max, max);
HBITMAP hbmOldSource = (HBITMAP)SelectObject(sourceDC.m_hDC, hBitmap );
HBITMAP hbmOldDest = (HBITMAP)SelectObject( destDC.m_hDC, hbmResult );
HBRUSH hbrBack = CreateSolidBrush( clrBack );
HBRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );
destDC.PatBlt( 0, 0, max, max, PATCOPY );
DeleteObject(SelectObject( destDC.m_hDC, hbrOld ));
for( int y = 0; y < max; y++ )
for( int x = 0; x < max; x++ )
{
int xx = rot_x - x + posx;
int yy = rot_y - y + posy;
int sourcex = (int)(rot_x + (xx * cos(degree) - yy * sin(degree)));
int sourcey = (int)(rot_y + (xx * sin(degree) + yy * cos(degree)));
if(sourcex >= 0 && sourcex < bm.bmWidth && sourcey >= 0 && sourcey < bm.bmHeight)
destDC.SetPixel(x ,y,sourceDC.GetPixel(sourcex,sourcey));
}
SelectObject(sourceDC.m_hDC, hbmOldSource);
SelectObject(destDC.m_hDC, hbmOldDest);
return hbmResult;
}

noshin156
سه شنبه 19 اردیبهشت 1391, 09:25 صبح
خيلي ممنون اين مشكل هم برطرف شد فقط يه چيز ديگه سرعت اجراي اين كد خيلي كند است يعني بعد از هر بار كليك كردن حدود 5 ثانيه زمان ميبره تا دستور اجرا بشود وتابع pow ورودي هايي كه ميگيرد به ترتيب floatوint است در صورتي كه نقاط مركز دوران ما از نوع int است بنابراين مجبور شدم كدش را اينطوري بنويسم:

pow((float)-rot_y, 2))
pow((float)bm.bmHeight - rot_y, 2)

احتمالا كند شدن برنامه به خاطر همين تبديل ها باشد راهكاري به نظر شما ميرسه؟

noshin156
سه شنبه 19 اردیبهشت 1391, 14:48 عصر
داشتم به اين موضوع فكر مي كردم كه آيا روشي وجود داره كه بتونيم مقدار حركت عكس رو ببينيمبه يعني به جاي اينكه به زاويه مورد نظر پرش كند يكي يكي حركت كند تا به مختصات مورد نظر برسد؟
ياد يك فرمول فيزيك افتادم به اسم سرعت زاويه اي آيا مي توان اين فرمول رو در برنامه پياده كرد؟

ASGGSA
سه شنبه 19 اردیبهشت 1391, 19:38 عصر
سلام.
مشکل سرعت اجرای تابع بالا مربوط به حلقه های تودرتو می باشد. این هم یک تابع جدید با سرعت بالا و امیدوارم دیگه مشکلی نداشته باشه.

HBITMAP GetRotatedBitmap(HBITMAP hBitmap, int rot_x, int rot_y, float degree, COLORREF clrBack)
{
CDC sourceDC, destDC;
sourceDC.CreateCompatibleDC(NULL);
destDC.CreateCompatibleDC(NULL);
BITMAP bm;
GetObject(hBitmap, sizeof(bm), &bm);
degree = degree * 3.14f / 180.0f;
int len1 = (int)sqrt(pow((float)(bm.bmWidth - rot_x), 2) + pow((float)(bm.bmHeight - rot_y), 2));
int len2 = (int)sqrt(pow((float)(-rot_x), 2) + pow((float)(-rot_y), 2));
int len3 = (int)sqrt(pow((float)(-rot_x), 2) + pow((float)(bm.bmHeight - rot_y), 2));
int len4 = (int)sqrt(pow((float)(bm.bmWidth - rot_x), 2) + pow((float)(-rot_y), 2));
int len5 = len1 >= len2 ? len1 : len2;
int len6 = len3 >= len4 ? len3 : len4;
int max = len5 >= len6 ? len5 : len6;
HBITMAP hbmResult = CreateCompatibleBitmap(CClientDC(NULL), max * 2, max * 2);
HBITMAP hbmOldSource = (HBITMAP)SelectObject(sourceDC.m_hDC, hBitmap);
HBITMAP hbmOldDest = (HBITMAP)SelectObject(destDC.m_hDC, hbmResult);
HBRUSH hbrBack = CreateSolidBrush(clrBack);
HBRUSH hbrOld = (HBRUSH)SelectObject( destDC.m_hDC, hbrBack );
destDC.PatBlt( 0, 0, max * 2, max * 2, PATCOPY );
DeleteObject(SelectObject(destDC.m_hDC, hbrOld));
int trax = (int)((max * cos(degree) - max * sin(degree))) - rot_x;
int tray = (int)((max * sin(degree) + max * cos(degree))) - rot_y;
SetGraphicsMode(destDC.m_hDC, GM_ADVANCED);
XFORM xform;
xform.eM11 = (float)cos(degree);
xform.eM12 = (float)-sin(degree);
xform.eM21 = (float)sin(degree);
xform.eM22 = (float)cos(degree);
xform.eDx = 0;
xform.eDy = 0;
SetWorldTransform( destDC.m_hDC, &xform );
destDC.BitBlt(trax,tray,bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, SRCCOPY );
SelectObject( sourceDC.m_hDC, hbmOldSource );
SelectObject( destDC.m_hDC, hbmOldDest );
return hbmResult;
}

ASGGSA
پنج شنبه 21 اردیبهشت 1391, 14:03 عصر
این هم پرونده اجرایش :
86896

noshin156
یک شنبه 24 اردیبهشت 1391, 13:53 عصر
اين هم اون چيزي كه مي خواستيد

ASGGSA
شنبه 06 خرداد 1391, 02:38 صبح
سلام.
تابع بالا اشکالاتی داشت که اصلاحش کردم.

HBITMAP GetRotatedBitmap(HBITMAP hBitmap, int rot_x, int rot_y, float degree, COLORREF clrBack)
{
CDC sourceDC, destDC;
sourceDC.CreateCompatibleDC(NULL);
destDC.CreateCompatibleDC(NULL);
BITMAP bm;
GetObject(hBitmap, sizeof(bm), &bm);
degree = degree * 3.14f / 180.0f;
int len1 = (int)sqrt(pow((float)(bm.bmWidth - rot_x), 2) + pow((float)(bm.bmHeight - rot_y), 2));
int len2 = (int)sqrt(pow((float)(-rot_x), 2) + pow((float)(-rot_y), 2));
int len3 = (int)sqrt(pow((float)(-rot_x), 2) + pow((float)(bm.bmHeight - rot_y), 2));
int len4 = (int)sqrt(pow((float)(bm.bmWidth - rot_x), 2) + pow((float)(-rot_y), 2));
int len5 = len1 >= len2 ? len1 : len2;
int len6 = len3 >= len4 ? len3 : len4;
int max = len5 >= len6 ? len5 : len6;
HBITMAP hbmResult = CreateCompatibleBitmap(CClientDC(NULL), max * 2, max * 2);
HBITMAP hbmOldSource = (HBITMAP)SelectObject(sourceDC.m_hDC, hBitmap);
HBITMAP hbmOldDest = (HBITMAP)SelectObject(destDC.m_hDC, hbmResult);
HBRUSH hbrBack = CreateSolidBrush(clrBack);
HBRUSH hbrOld = (HBRUSH)SelectObject( destDC.m_hDC, hbrBack );
destDC.PatBlt( 0, 0, max * 2, max * 2, PATCOPY );
DeleteObject(SelectObject(destDC.m_hDC, hbrOld));
int trax = (int)((max * cos(degree) - max * sin(degree))) - rot_x;
int tray = (int)((max * sin(degree) + max * cos(degree))) - rot_y;
SetGraphicsMode(destDC.m_hDC, GM_ADVANCED);
XFORM xform;
xform.eM11 = (float)cos(degree);
xform.eM12 = (float)-sin(degree);
xform.eM21 = (float)sin(degree);
xform.eM22 = (float)cos(degree);
xform.eDx = 0;
xform.eDy = 0;
SetWorldTransform( destDC.m_hDC, &xform );
destDC.BitBlt(trax,tray,bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, SRCCOPY );
SelectObject( sourceDC.m_hDC, hbmOldSource );
SelectObject( destDC.m_hDC, hbmOldDest );
DeleteObject(hbmOldSource);
DeleteObject(hbmOldDest);
DeleteObject(hbrBack);
DeleteDC(sourceDC);
DeleteDC(destDC);
return hbmResult;
}

توجه : ظاهراً بخاطر وجود تابع SetGraphicsMode در این تابع، کد بالا با بعضی از کارت های گرافیک سازگار نیست. حالا مشکل چیه نمی دونم.

noshin156
شنبه 06 خرداد 1391, 09:53 صبح
من با كارت گرافيك 512 جواب نمي گيرم ولي با كارت گرافيك 128 خيلي خوب كار ميكنه به نظر شما چرا اينجوريه؟