17

私のゲームでは、2つの座標系間で変換する関数が必要です。それは主に数学の質問ですが、私が必要としているのは、それを行うためのC ++コードと、私の問題を解決する方法についての少しの説明です。

スクリーン座標:

a)左上隅は0,0です

b)マイナス値なし

c)右+ = x(x値が多いほど、右側がポイントになります)

d)下+ = y

デカルト2D座標:

a)中間点は(0、0)です

b)マイナス値は存在します

c)右+ = x

d)下-= y(yが小さいほど、下の点が多くなります)

あるシステムから別のシステムに、またはその逆に変換する簡単な方法が必要です。そのためには、(私が思うに)デカルト座標のどこに(0、0)[画面座標の左上隅]が配置されているかなどの知識が必要です。

ただし、デカルト座標を画面座標に変換した後のある点では、画面座標の位置がマイナスになる場合があり、これはナンセンスです。画面座標の左上隅を(-inifity、+ infinity)デカルト座標に配置できません...

どうすればこれを解決できますか?私が考えることができる唯一の解決策は、画面(0、0)をデカルト(0、0)に配置し、デカルトシステムのIVクォーターのみを使用することですが、その場合、デカルトシステムを使用することは無意味です...

画面座標をデカルト座標に、またはその逆に変換する方法は確かにありますが、そのマイナスの値で私の考えが間違っています。

4

5 に答える 5

20

デカルト座標から画面座標に変換するための基本的なアルゴリズムは次のとおりです。

screenX = cartX + screen_width/2
screenY = screen_height/2 - cartY

しかし、あなたが言ったように、デカルト空間は無限であり、あなたの画面空間は無限ではありません。これは、画面スペースとデカルトスペースの間で解像度を変更することで簡単に解決できます。上記のアルゴリズムは、デカルト空間で1ユニット=画面スペースで1ユニット/ピクセルになります。他の比率を許可する場合は、画面スペースを「ズームアウト」または拡大して、必要なすべてのデカルトスペースをカバーできます。

これにより、上記のアルゴリズムが次のように変更されます。

screenX = zoom_factor*cartX + screen_width/2
screenY = screen_height/2 - zoom_factor*cartY

これで、すべてのデカルト座標が画面に収まるまでズーム係数を変更して、負の(または大きすぎる)screenXとscreenYを処理します。

また、座標空間のパンを許可することもできます。つまり、デカルト空間の中心を画面の中心から外すことができます。これは、zoom_factorを可能な限りタイトに保つのに役立つだけでなく、デカルト空間の原点の周りに均等に分散されていないデータにも適合させることができます。

これにより、アルゴリズムが次のように変更されます

screenX = zoom_factor*cartX + screen_width/2 + offsetX
screenY = screen_height/2 - zoom_factor*cartY + offsetY
于 2013-02-14T17:40:53.667 に答える
6

変換できるようにするには、画面のサイズを知っている必要があります

デカルトに変換:

cartesianx = screenx - screenwidth / 2;
cartesiany = -screeny + screenheight / 2;

画面に変換:

screenx = cartesianx + screenwidth / 2;
screeny = -cartesiany + screenheight / 2;

画面の値が負の場合:これについては心配しません。このコンテンツは単にクリップされるため、ユーザーには表示されません。これ問題になる場合は、デカルト座標が大きくなりすぎないようにするいくつかの制約を追加します。別の解決策は、エッジを+/-無限大にすることはできないため、座標をスケーリングすることです(たとえば、1ピクセル= 10デカルト)。これをと呼びましょうscalefactor。方程式は次のようになります。

スケール係数を使用してデカルトに変換します。

cartesianx = scalefactor*screenx - screenwidth / 2;
cartesiany = -scalefactor*screeny + screenheight / 2;

倍率で画面に変換:

screenx = (cartesianx + screenwidth / 2) / scalefactor;
screeny = (-cartesiany + screenheight / 2) / scalefactor;
于 2013-02-14T17:33:42.693 に答える
4

画面の幅と高さを知る必要があります。

次に、次のことができます。

cartX =   screenX - (width / 2);
cartY = -(screenY - (height / 2));

と:

screenX =  cartX + (width / 2);
screenY = -cartY + (height / 2);
于 2013-02-14T17:33:02.783 に答える
2

結果が画面外に表示される可能性があるという問題が常に発生します。負の値として、または使用可能な画面サイズよりも大きい値として表示されます。

場合によっては、それが問題にならないこともあります。たとえば、グラフィカルAPIが負の値を受け入れ、描画をクリップする場合などです。重要な場合もありますが、その場合は、一連の画面座標が画面上にあるかどうかをチェックする関数が必要です。

また、画面から外れる座標(負の画面座標を0に切り捨てたり、画面上の最大座標に対して大きすぎる座標など)で適切な処理を実行しようとする独自のクリッピング関数を作成することもできます。ただし、「合理的」は何をしようとしているかによって異なるため、実際に必要になるまでそのような関数の定義を控えるのが最善の場合があることに注意してください。


いずれにせよ、他の回答が指摘しているように、座標系間で次のように変換できます。

cart.x = screen.x - width/2;
cart.y = height/2 - screen.y;

screen.x = cart.x + width/2;
screen.y = height/2 - cart.y;
于 2013-02-14T17:38:34.817 に答える
0

マイクロソフトの記事に基づいて、私はあなたのためにいくつかのブーストC ++を持っています: https ://msdn.microsoft.com/en-us/library/jj635757(v = vs.85).aspx

座標系の2つの画面ポイントと2つのポイントを知っている必要があります。次に、ポイントをあるシステムから別のシステムに変換できます。

#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/vector_proxy.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/triangular.hpp>
#include <boost/numeric/ublas/lu.hpp>
#include <boost/numeric/ublas/io.hpp>

 /* Matrix inversion routine.
 Uses lu_factorize and lu_substitute in uBLAS to invert a matrix */
template<class T>
bool InvertMatrix(const boost::numeric::ublas::matrix<T>& input, boost::numeric::ublas::matrix<T>& inverse)
{
    typedef boost::numeric::ublas::permutation_matrix<std::size_t> pmatrix;

    // create a working copy of the input
    boost::numeric::ublas::matrix<T> A(input);

    // create a permutation matrix for the LU-factorization
    pmatrix pm(A.size1());

    // perform LU-factorization
    int res = lu_factorize(A, pm);
    if (res != 0)
        return false;

    // create identity matrix of "inverse"
    inverse.assign(boost::numeric::ublas::identity_matrix<T> (A.size1()));

    // backsubstitute to get the inverse
    lu_substitute(A, pm, inverse);

    return true;
}

PointF ConvertCoordinates(PointF pt_in,
    PointF pt1, PointF pt2, PointF pt1_, PointF pt2_)
{

    float matrix1[]={
         pt1.X,           pt1.Y,           1.0f,           0.0f,
        -pt1.Y,           pt1.X,           0.0f,           1.0f,
         pt2.X,           pt2.Y,           1.0f,           0.0f,
        -pt2.Y,           pt2.X,           0.0f,           1.0f
    };

    boost::numeric::ublas::matrix<float> M(4, 4);
    CopyMemory(&M.data()[0], matrix1, sizeof(matrix1));

    boost::numeric::ublas::matrix<float> M_1(4, 4);
    InvertMatrix<float>(M, M_1);

    double vector[] = {
        pt1_.X,
        pt1_.Y,
        pt2_.X,
        pt2_.Y
    };

    boost::numeric::ublas::vector<float> u(4);
    boost::numeric::ublas::vector<float> u1(4);
    u(0) = pt1_.X;
    u(1) = pt1_.Y;
    u(2) = pt2_.X;
    u(3) = pt2_.Y;

    u1 = boost::numeric::ublas::prod(M_1, u);

    PointF pt;
    pt.X = u1(0)*pt_in.X + u1(1)*pt_in.Y + u1(2);
    pt.Y = u1(1)*pt_in.X - u1(0)*pt_in.Y + u1(3);
    return pt;
}
于 2017-03-07T08:53:45.773 に答える