カーソルの位置がズレないように画像を拡縮したい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
xドリアンx

カーソルの位置がズレないように画像を拡縮したい

#1

投稿記事 by xドリアンx » 11年前

こんばんわ、質問します。

今DXライブラリでプログラムを組んでいます。

白い四角形をキャンバスと見立てて絵を描くようなアプリケーションを作りたいのですが

マウスカーソルを当てた位置がずれないように画像(キャンバス)を拡大縮小するにはどうしたらいいでしょうか。

現在拡大縮小にはDrawRotaGraph()を使っているのですが、やっぱりMakeScreen()等を使って

実際のキャンバスとは別に表示窓を作ってそっちを操作するべきなのでしょうか。

その場合どのような関数でどんな処理をしたらいいのでしょうか。

アドバイスお願いします。

アバター
ookami
記事: 214
登録日時: 14年前
住所: 東京都

Re: カーソルの位置がズレないように画像を拡縮したい

#2

投稿記事 by ookami » 11年前

xドリアンxさん、
この場合は自力で換算するしかないですね。
画像をm倍した状態なら、マウス座標を1/m倍します。あとはどこを中心に拡大縮小しているかによって、差し引き必要です。

「拡大縮小」とありますが、DrawRotaGraphを使っているということは回転もするのでしょうか?
その場合は回転行列を使う必要があります。

MakeScreen等使っても座標の換算部分は同じです。

xドリアンx

Re: カーソルの位置がズレないように画像を拡縮したい

#3

投稿記事 by xドリアンx » 11年前

ookami さんが書きました:xドリアンxさん、
この場合は自力で換算するしかないですね。
画像をm倍した状態なら、マウス座標を1/m倍します。あとはどこを中心に拡大縮小しているかによって、差し引き必要です。
今マウスホイールで拡大率を操作しているのですが

もしcanvas.ExRate(キャンバスの拡大率)をプラス0.05倍したら

canvas.x0(キャンバスの中心X)+=mouse.x*(1/0.05)*GetMouseWheelRoVol()

canbas.y0(キャンバスの中心Y)+=mouse.y*(1/0.05)*GetMouseWheelRoVol()

にすれば良いと言う解釈で良いですか?

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: カーソルの位置がズレないように画像を拡縮したい

#4

投稿記事 by みけCAT » 11年前

xドリアンx さんが書きました:
ookami さんが書きました:xドリアンxさん、
この場合は自力で換算するしかないですね。
画像をm倍した状態なら、マウス座標を1/m倍します。あとはどこを中心に拡大縮小しているかによって、差し引き必要です。
今マウスホイールで拡大率を操作しているのですが

もしcanvas.ExRate(キャンバスの拡大率)をプラス0.05倍したら

canvas.x0(キャンバスの中心X)+=mouse.x*(1/0.05)*GetMouseWheelRoVol()

canbas.y0(キャンバスの中心Y)+=mouse.y*(1/0.05)*GetMouseWheelRoVol()

にすれば良いと言う解釈で良いですか?
違う気がします。
mは画像の拡大率で、今回の0.05は拡大率の差分なので、

canvas.x0(キャンバスの中心X)+=mouse.x*(1/(前の拡大率+0.05))*GetMouseWheelRoVol()

canbas.y0(キャンバスの中心Y)+=mouse.y*(1/(前の拡大率+0.05))*GetMouseWheelRoVol()

という感じになると思います。(GetMouseWheelRoVol()が必要かはわかりません)
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: カーソルの位置がズレないように画像を拡縮したい

#5

投稿記事 by みけCAT » 11年前

xドリアンx さんが書きました:もしcanvas.ExRate(キャンバスの拡大率)をプラス0.05倍したら
それとも、+(0.05倍)ではなくて(+0.05)倍でしょうか?

canvas.x0(キャンバスの中心X)+=mouse.x*(1/(前の拡大率*(+0.05)))*GetMouseWheelRoVol()

canbas.y0(キャンバスの中心Y)+=mouse.y*(1/(前の拡大率*(+0.05)))*GetMouseWheelRoVol()

どっちが適切か、もしくはどっちも適切ではないか、実験してみてください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

xドリアンx

Re: カーソルの位置がズレないように画像を拡縮したい

#6

投稿記事 by xドリアンx » 11年前

すいません、+(0.05)という意味でした。

理解はしているつもりなのですが(1/拡大率)をマウス座標に掛けてcanvasの座標から差し引きしても

意図した動きになりませんでした。以下ソースコードになります。

コード:

#include "main.h"

typedef struct{
	double ExRate;
	double x, y;
	int    w, h;
}CANVAS;

int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ){
	Window_Create();
			
	// ファイルダイアログから画像読み込み
	FileInfo file = OpenFileToDialog("画像の選択", "画像ファイル(*.jpg,*.png,*.bmp)\0*.jpg;*.png;*.bmp\0全て(*.*)\0*.*\0\0");
	
	// 画像読み込み
	int Graph = LoadGraph( file.path );
	
	CANVAS canvas;
	canvas.x = window.w/2, canvas.y = window.h/2, canvas.ExRate = 1.0;

	// マウス関連
	int mx, my, bmx, bmy, wheel;
	int dx = (int)canvas.x, dy = (int)canvas.y;

	// ループ
	while( SetLoopProcess()==0 && InputKey()==0 && CheckKey( KEY_INPUT_ESCAPE )==0 ){
	
		GetMousePoint( &mx, &my );

		// マウスホイールでドラッグ処理
		if( GetMouseInput() != MOUSE_INPUT_MIDDLE ){
			dx  = (int)canvas.x;
			dy  = (int)canvas.y;
			bmx = mx;
			bmy = my;
		}else{
			canvas.x = (double)dx+(mx-bmx);
			canvas.y = (double)dy+(my-bmy);
		}
		
		// マウスホイールで拡縮処理
		wheel=GetMouseWheelRotVol();
		if( wheel != 0 ){
			if( canvas.ExRate < 0 ){
				canvas.ExRate = 0;
			}else{
				canvas.ExRate += 0.05*wheel;
				canvas.x += mx*(1.0/canvas.ExRate)*wheel;
				canvas.y += my*(1.0/canvas.ExRate)*wheel;
			}
		}

		// 表示
		DrawRotaGraphF( (float)canvas.x, (float)canvas.y, canvas.ExRate, 0.0, Graph, FALSE );
	}

	DxLib_End();

	return 0;

}
ペイントソフトというより、画像ビューワみたいな感じですが・・・

ウィンドウのサイズは640x480で、window.w, window.hに格納されています。

FileInfo構造体はファイル名とファイルパスをOpenFileToDialog()からファイルダイアログを開いて取得するものです。

問題は48,49行目の部分ですが、皆さんの仰っていたマウス座標はもしかしてウィンドウ上のマウス座標ではなく

画像上(キャンバス上)のマウス座標だったのでしょうか・・・?

改めてアドバイスお願いします。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: カーソルの位置がズレないように画像を拡縮したい

#7

投稿記事 by みけCAT » 11年前

・キャンバスの中心座標の計算には、mx/myもwheelも入れない方がいいかもしれません。
・誤差の関係で、一回ずつ足し算するのではなく、キャンバスの中心座標を拡大率の(数学的な)関数として計算する方がいいかもしれません。
添付ファイル
kakudai.png
拡大した時の位置の補正(仕様をよく理解していないので、見当違いかも)
kakudai.png (2.33 KiB) 閲覧数: 5538 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

xドリアンx

Re: カーソルの位置がズレないように画像を拡縮したい

#8

投稿記事 by xドリアンx » 11年前

やっぱり誤差を出さないためにもココらへんの計算式はしっかりした記述が必要になりますよね・・・

今の自分にはまだまだ敷居が高いようですので、座標の変換についてきっちり勉強してから

改めて挑みたいと思います。

アドバイスしてくださいましたookamiさんとみけCATさんに感謝します。

ありがとうございました。

アバター
ookami
記事: 214
登録日時: 14年前
住所: 東京都

Re: カーソルの位置がズレないように画像を拡縮したい

#9

投稿記事 by ookami » 11年前

遅かった^^;

最初書いたのと同じなのですが、別な書き方にしてみます。
図解がないと伝わりづらいかもしれませんが...

長方形ABCDを考えます。マウス座標をMとします。
AとMの中点をA'とします。同様に、B'、C'、D'をそれぞれ B、C、D と M との中点に取ります。
新しい長方形A'B'C'D'は、「マウスカーソルを当てた位置がずれないように拡大縮小」されています。

説明のため頂点ABCDと比較しましたが、DrawRotaGraphFは中心点を入力とするので、画像の中心Pとマウス座標Mの中点をP'とすればよいかと。
また、上記は1/2倍にした場合なので 中点(1:1) を取りましたが、
1/m倍にする場合は、1/m : (1-1/m) の比をとります。

よかったら紙に書いてご確認いただければと。

みけCATさんも仰るとおり誤差はありますが、
1倍だったのが1.00000001倍になる、程度の誤差なので、最初は気にしなくてもいいのかなという気がします。

xドリアンx

Re: カーソルの位置がズレないように画像を拡縮したい

#10

投稿記事 by xドリアンx » 11年前

出来ました!!

とりあえずDrawRotaGraphF()での拡縮じゃなくてDrawExtendGraphFで端四点を指定することで拡縮させる方法を取り

ookamiさんとみけCATさんのアドバイスの元以下のように処理した所、マウスの座標がずれること無く

拡縮させることが出来ました。

コード:

#include "main.h"

int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ){
	Window_Create();
			
	// ファイルダイアログから画像読み込み
	FileInfo file = OpenFileToDialog("画像の選択", "画像ファイル(*.jpg,*.png,*.bmp)\0*.jpg;*.png;*.bmp\0全て(*.*)\0*.*\0\0");
	
	// 画像読み込み
	int Graph = LoadGraph( file.path );
	// 指定した画像と中心座標(左上)から、四点と画像のサイズを取得
	GrInfoF_t canvas = GetNowImageInfoF( 0.0, 0.0, Graph );

	// マウス関連
	int mx, my, bmx, bmy, wheel; 
	GrInfoF_t d = canvas;

	// ループ
	while( SetLoopProcess()==0 && InputKey()==0 && CheckKey( KEY_INPUT_ESCAPE )==0 ){
	
		GetMousePoint( &mx, &my );

		// マウスホイールでドラッグ処理
		if( GetMouseInput() != MOUSE_INPUT_MIDDLE ){
			d.x1 = canvas.x1; d.y1 = canvas.y1;
			d.x2 = canvas.x2; d.y2 = canvas.y2;
			d.x3 = canvas.x3; d.y3 = canvas.y3;
			d.x4 = canvas.x4; d.y4 = canvas.y4;
			bmx = mx;
			bmy = my;
		}else{
			canvas.x1 = (double)d.x1+(mx-bmx); canvas.y1 = (double)d.y1+(my-bmy);
			canvas.x2 = (double)d.x2+(mx-bmx); canvas.y2 = (double)d.y2+(my-bmy);
			canvas.x3 = (double)d.x3+(mx-bmx); canvas.y3 = (double)d.y3+(my-bmy);
			canvas.x4 = (double)d.x4+(mx-bmx); canvas.y4 = (double)d.y4+(my-bmy);
		}
		
		// マウスホイールで拡縮処理
		wheel = GetMouseWheelRotVol();
		if( wheel != 0 ){
			if( canvas.ExRate < 0 ){
				canvas.ExRate = 0;
			}else{
				canvas.ExRate += 0.05*wheel;
				canvas.x1 += (canvas.x1-mx)*(1/canvas.ExRate)*wheel;
				canvas.y1 += (canvas.y1-my)*(1/canvas.ExRate)*wheel;
				canvas.x2 += (canvas.x2-mx)*(1/canvas.ExRate)*wheel;
				canvas.y2 += (canvas.y2-my)*(1/canvas.ExRate)*wheel;
				canvas.x3 += (canvas.x3-mx)*(1/canvas.ExRate)*wheel;
				canvas.y3 += (canvas.y3-my)*(1/canvas.ExRate)*wheel;
				canvas.x4 += (canvas.x4-mx)*(1/canvas.ExRate)*wheel;
				canvas.y4 += (canvas.y4-my)*(1/canvas.ExRate)*wheel;
			} 
		}

		// 表示
		int Work = DrawExtendGraphF( canvas.x1, canvas.y1, canvas.x3, canvas.y3, Graph, FALSE );
		DrawGraphF( (float)canvas.x1, (float)canvas.y1, Work, FALSE );
	}

	DxLib_End();

	return 0;

}
まだ動作は不安定で、アドバイスを完全に理解出来てない部分もありますが

中心PとマウスMの中点P'からの方法も試したりと試行錯誤を繰り返しつつ勉強しようと思います。

改めてookamiさんとみけCATさんに感謝します、最後までありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る