こんばんわ、質問します。
今DXライブラリでプログラムを組んでいます。
白い四角形をキャンバスと見立てて絵を描くようなアプリケーションを作りたいのですが
マウスカーソルを当てた位置がずれないように画像(キャンバス)を拡大縮小するにはどうしたらいいでしょうか。
現在拡大縮小にはDrawRotaGraph()を使っているのですが、やっぱりMakeScreen()等を使って
実際のキャンバスとは別に表示窓を作ってそっちを操作するべきなのでしょうか。
その場合どのような関数でどんな処理をしたらいいのでしょうか。
アドバイスお願いします。
カーソルの位置がズレないように画像を拡縮したい
Re: カーソルの位置がズレないように画像を拡縮したい
xドリアンxさん、
この場合は自力で換算するしかないですね。
画像をm倍した状態なら、マウス座標を1/m倍します。あとはどこを中心に拡大縮小しているかによって、差し引き必要です。
「拡大縮小」とありますが、DrawRotaGraphを使っているということは回転もするのでしょうか?
その場合は回転行列を使う必要があります。
MakeScreen等使っても座標の換算部分は同じです。
この場合は自力で換算するしかないですね。
画像をm倍した状態なら、マウス座標を1/m倍します。あとはどこを中心に拡大縮小しているかによって、差し引き必要です。
「拡大縮小」とありますが、DrawRotaGraphを使っているということは回転もするのでしょうか?
その場合は回転行列を使う必要があります。
MakeScreen等使っても座標の換算部分は同じです。
Re: カーソルの位置がズレないように画像を拡縮したい
今マウスホイールで拡大率を操作しているのですが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()
にすれば良いと言う解釈で良いですか?
Re: カーソルの位置がズレないように画像を拡縮したい
違う気がします。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で殴ればいい!(死亡フラグ)
Re: カーソルの位置がズレないように画像を拡縮したい
それとも、+(0.05倍)ではなくて(+0.05)倍でしょうか?xドリアンx さんが書きました:もしcanvas.ExRate(キャンバスの拡大率)をプラス0.05倍したら
canvas.x0(キャンバスの中心X)+=mouse.x*(1/(前の拡大率*(+0.05)))*GetMouseWheelRoVol()
canbas.y0(キャンバスの中心Y)+=mouse.y*(1/(前の拡大率*(+0.05)))*GetMouseWheelRoVol()
どっちが適切か、もしくはどっちも適切ではないか、実験してみてください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: カーソルの位置がズレないように画像を拡縮したい
すいません、+(0.05)という意味でした。
理解はしているつもりなのですが(1/拡大率)をマウス座標に掛けてcanvasの座標から差し引きしても
意図した動きになりませんでした。以下ソースコードになります。
ペイントソフトというより、画像ビューワみたいな感じですが・・・
ウィンドウのサイズは640x480で、window.w, window.hに格納されています。
FileInfo構造体はファイル名とファイルパスをOpenFileToDialog()からファイルダイアログを開いて取得するものです。
問題は48,49行目の部分ですが、皆さんの仰っていたマウス座標はもしかしてウィンドウ上のマウス座標ではなく
画像上(キャンバス上)のマウス座標だったのでしょうか・・・?
改めてアドバイスお願いします。
理解はしているつもりなのですが(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行目の部分ですが、皆さんの仰っていたマウス座標はもしかしてウィンドウ上のマウス座標ではなく
画像上(キャンバス上)のマウス座標だったのでしょうか・・・?
改めてアドバイスお願いします。
Re: カーソルの位置がズレないように画像を拡縮したい
・キャンバスの中心座標の計算には、mx/myもwheelも入れない方がいいかもしれません。
・誤差の関係で、一回ずつ足し算するのではなく、キャンバスの中心座標を拡大率の(数学的な)関数として計算する方がいいかもしれません。
・誤差の関係で、一回ずつ足し算するのではなく、キャンバスの中心座標を拡大率の(数学的な)関数として計算する方がいいかもしれません。
- 添付ファイル
-
- 拡大した時の位置の補正(仕様をよく理解していないので、見当違いかも)
- kakudai.png (2.33 KiB) 閲覧数: 5540 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: カーソルの位置がズレないように画像を拡縮したい
やっぱり誤差を出さないためにもココらへんの計算式はしっかりした記述が必要になりますよね・・・
今の自分にはまだまだ敷居が高いようですので、座標の変換についてきっちり勉強してから
改めて挑みたいと思います。
アドバイスしてくださいましたookamiさんとみけCATさんに感謝します。
ありがとうございました。
今の自分にはまだまだ敷居が高いようですので、座標の変換についてきっちり勉強してから
改めて挑みたいと思います。
アドバイスしてくださいましたookamiさんとみけCATさんに感謝します。
ありがとうございました。
Re: カーソルの位置がズレないように画像を拡縮したい
遅かった^^;
最初書いたのと同じなのですが、別な書き方にしてみます。
図解がないと伝わりづらいかもしれませんが...
長方形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倍になる、程度の誤差なので、最初は気にしなくてもいいのかなという気がします。
最初書いたのと同じなのですが、別な書き方にしてみます。
図解がないと伝わりづらいかもしれませんが...
長方形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倍になる、程度の誤差なので、最初は気にしなくてもいいのかなという気がします。
Re: カーソルの位置がズレないように画像を拡縮したい
出来ました!!
とりあえずDrawRotaGraphF()での拡縮じゃなくてDrawExtendGraphFで端四点を指定することで拡縮させる方法を取り
ookamiさんとみけCATさんのアドバイスの元以下のように処理した所、マウスの座標がずれること無く
拡縮させることが出来ました。
まだ動作は不安定で、アドバイスを完全に理解出来てない部分もありますが
中心PとマウスMの中点P'からの方法も試したりと試行錯誤を繰り返しつつ勉強しようと思います。
改めてookamiさんとみけCATさんに感謝します、最後までありがとうございました。
とりあえず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さんに感謝します、最後までありがとうございました。