以下は、私がこれを解決した方法です。TL;DR: 回転変換は 0, 0 を中心に行われるため、画像座標が 0,0 を左下に設定している場合は、最初に画像を 0,0 の中心に移動する必要があります。また、sin と cos は度ではなくラジアンを想定しているため、最初に変換することを忘れないでください。
長い道のり: 私は、問題がどこで起こっているのかを見つけるために、答えを簡単に検証できる単純なプログラムを作成することから始めました。
最初に気付いたのは、90.0f では何も出力されないということでした。それは奇妙に思えたので、「出力イメージ サイズ」printf に割り込んで、出力の高さが -87 として計算されていることに気付きました。明らかにそれは正しくないので、なぜそうなるのか見てみましょう。
少し上に行くoutHeight=(int)ceil(fabs(maxy)-miny);
ので、maxy と miny を差し引いたときに出力の高さが負になる理由を考えてみましょう。maxy は -0.896... で、miny は 88.503 のように見えます... しかし、maxy の絶対値は miny を引く前に取られます。つまり、0.896 - 88.503 になります。おっと、それは良くありません。引き算をしてから絶対値を取ってみましょう。
幅と高さの両方をそのまま再コンパイル: outWidth=(int)ceil(fabs(maxx-minx)); outHeight=(int)ceil(fabs(maxy-miny));
はるかに優れた値を取得します。現在、outWidth と outHeight はそれぞれ 2 と 90 です。これは大幅に改善されましたが、高さは 100 にする必要があります。これについては後で説明します。
数学のどこが間違っているのかを理解するために、x と x、y と y のように用語を再編成します。次に、スペースを調整し、かっこを追加して、読みやすくし、操作の順序を確保しました (OoO テーブルを見ようとするのは確実です ;))。回転行列の乗算を分解しているのは明らかなので、x1、x2 などよりももう少し直感的な名前を変数に付けます。これからは、x1 は topLeftTransformedX、x2 は topRightTransformedX、x3 は bottomLeftTransformedX として存在します。 (常に 0)、x4 は bottomRightTransformedX になります。Y も同じです。
これを使用すると、この時点で、あなたが行うのと同じことがわかります...そして、このよりクリーンなコードから見た数字に基づいて、何かを思い出しました(あなたのものと同じ数学ですが、デバッグはまだ簡単です)。
突然、X の計算は次のようになります。 // x = x cos - y sin float topLeftTransformedX = (-midX * cosine) - (midY * sine); float topRightTransformedX = (midX * コサイン) - (midY * サイン); float bottomLeftTransformedX = (-midX * コサイン) - (-midY * サイン); float bottomRightTransformedX = (midX * コサイン) - (-midY * サイン);
回転行列は中心点を中心に回転します。適切に回転させるには、画像をその中心に移動する必要があります。
次に、これが値を与える理由を理解しようとすると、別のことを思い出しました-角度はラジアンである必要があります。
突然、ほとんどすべてが機能します。やるべきことはまだいくつかありますが、これで 95% 以上は達成できるはずです。それが役に立てば幸い!
// bmprotate.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <math.h>
#define min(x,y) x < y ? x : y
#define max(x,y) x > y ? x : y
#define PI 3.14159
void rotate(int width, int height, float angleInDeg)
{
float angle = angleInDeg * (PI/180.0f);
float midX = ((float)width) / 2.0f;
float midY = ((float)height) / 2.0f;
float sine = sin(angle);
float cosine = cos(angle);
// x = x cos - y sin
float topLeftTransformedX = (-midX * cosine) - (midY * sine);
float topRightTransformedX = (midX * cosine) - (midY * sine);
float bottomLeftTransformedX = (-midX * cosine) - (-midY * sine);
float bottomRightTransformedX = (midX * cosine) - (-midY * sine);
float minx = min( topLeftTransformedX, min(topRightTransformedX, min(bottomLeftTransformedX, bottomRightTransformedX)) );
float maxx = max( topLeftTransformedX, max(topRightTransformedX, max(bottomLeftTransformedX, bottomRightTransformedX)) );
// y = x sin + y cos
float topLeftTransformedY = (-midX * sine) + (midY * cosine);
float topRightTransformedY = (midX * sine) + (midY * cosine);
float bottomLeftTransformedY = (-midX * sine) + (-midY * cosine);
float bottomRightTransformedY = (midX * sine) + (-midY * cosine);
float miny = min( topLeftTransformedY, min(topRightTransformedY, min(bottomLeftTransformedY, bottomRightTransformedY)) );
float maxy = max( topLeftTransformedY, max(topRightTransformedY, max(bottomLeftTransformedY, bottomRightTransformedY)) );
int outWidth;
int outHeight;
printf("(%f,%f) , (%f,%f) , (%f,%f) , (%f,%f)\n",
topLeftTransformedX, topLeftTransformedY,
topRightTransformedX, topRightTransformedY,
bottomLeftTransformedX, bottomLeftTransformedY,
bottomRightTransformedX, bottomRightTransformedY);
outWidth = (int) ceil( fabs(maxx) + fabs(minx));
outHeight = (int) ceil( fabs(maxy) + fabs(miny) );
printf("output image size: (%d,%d)\n",outWidth,outHeight);
for(int x=0; x<outWidth; x++)
{
for(int y=0; y<outHeight; y++)
{
int srcX=(int)((x+minx)*cosine+(y+miny)*sine);
int srcY=(int)((y+miny)*cosine-(x+minx)*sine);
if(srcX >=0 && srcX < width && srcY >= 0 && srcY < height)
{
printf("(x,y) = (%d,%d)\n",srcX, srcY);
}
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
rotate(100,2,90.0f);
for (int i = 0; i < 360; i++)
{
}
return 0;
}