特定の座標系で2Dディスプレイのデータを受け取るソフトウェアをプログラミングしています。ここで、(0,0) は左上隅、x 軸は右方向、y 軸は下方向です。
私のグラフ作成ライブラリは、 (0,0) を左下隅と見なすPython ライブラリpygletです。x 軸は右に伸びますが (変換は必要ありません)、y 軸は上に伸びます。したがって、受け取ったデータの座標をグラフ ライブラリに直接渡すことはできません。
y 軸成分をどのように変換できますか?
特定の座標系で2Dディスプレイのデータを受け取るソフトウェアをプログラミングしています。ここで、(0,0) は左上隅、x 軸は右方向、y 軸は下方向です。
私のグラフ作成ライブラリは、 (0,0) を左下隅と見なすPython ライブラリpygletです。x 軸は右に伸びますが (変換は必要ありません)、y 軸は上に伸びます。したがって、受け取ったデータの座標をグラフ ライブラリに直接渡すことはできません。
y 軸成分をどのように変換できますか?
graphing_heightグラフ ライブラリがビューをサポートしている場合は、をに設定できるはずです-non_graphing_height。ビューの位置が中央にある場合は変更する必要はありません。左下にある場合は、に設定graphic_bottom_leftするnon_graphing_top_left + non_graphing_height必要があります。
C++ で SFML ライブラリを使用すると、次のようになります。
const auto& current_view = window.getView();
const auto& current_view_size = current_view.getSize();
window.setView(sf::View(current_view.getCenter(), { current_view_size.x, -current_view_size.y }));
3D の場合、代わりに射影行列に適用できます。
ビューがない場合は、ビュー マトリックスを使用して再作成できるはずです。その後、そのビュー マトリックスをグラフィック ライブラリに渡すことができるはずです。
ビューマトリックスを渡すことができない場合は、それらを非グラフ変換に適用して、グラフ変換を取得します。これを取得すると、グラフィック ライブラリに渡すことができる変換マトリックスが得られます。
グラフィックス ライブラリがそれを渡すことをサポートしていない場合は、変換された行列を変換、回転、およびスケールに分解できます。
非グラフィック ライブラリの 0,0 から 200,200 までのビューでこれを行う、SFML ライブラリを使用しない C++ の関数の例を次に示します。
/// transform the passed in position, rotation and scale
/// \param rotation radians
void transform(Vector2& position, float& rotation, Vector2& scale) {
// create a transformation matrix from the position, rotation and scale
const Matrix transform_matrix{ position, rotation, scale };
// create a upside down view matrix at origin of size 200x200
const Vector2 view_position{
0.f,
0.f
};
const Vector2 view_size{
200.f,
200.f
};
const Matrix view_matrix =
Matrix::translation({ -view_position.x, -(view_position.y + view_size.y) }) *
Matrix::scale({ 1.f / view_size.x, -1.f / view_size.y });
// multiply the transformation matrix with the view matrix
const auto multiplied = transform_matrix * view_matrix;
// update the passed in values
position = multiplied.getTranslation();
rotation = multiplied.getAngle();
scale = multiplied.getScale();
}
3D では、回転は複数の値またはクォータニオンである可能性があるため、それをサポートする Matrix クラスがあることを確認してください。
上記の例で使用した Vector2 および Matrix クラスの例を次に示します。
struct Vector2 {
float x;
float y;
};
class Matrix {
public:
/// creates a matrix using passed in matrix
Matrix(const std::vector<std::vector<float>>& matrix) :
matrix_{ matrix }
{}
/// creates 2d transformation matrix
/// \param angle radians
Matrix(const Vector2& translation, const float angle, const Vector2& scale) :
Matrix({
{ scale.x * cos(angle), scale.y * sin(angle), 0.f },
{ -scale.x * sin(angle), scale.x * cos(angle), 0.f },
{ translation.x, translation.y, 1.f }
})
{}
/// create 2d translation matrix
static Matrix translation(const Vector2& translation) {
return Matrix({
{ 1.f, 0.f, 0.f },
{ 0.f, 1.f, 0.f },
{ translation.x, translation.y, 1.f }
});
}
/// create 2d scale matrix
static Matrix scale(const Vector2& scale) {
return Matrix({
{ scale.x, 0.f, 0.f },
{ 0.f, scale.y, 0.f },
{ 0.f, 0.f, 1.f }
});
}
/// multiplies two matrices together
Matrix operator*(const Matrix& rhs) const {
// get number of rows, columns and elements
const auto rows = matrix_.size();
const auto columns = rhs.matrix_[0].size();
const auto elements = rhs.matrix_.size();
// create a new matrix of the correct size, filled with zeroes
Matrix new_matrix(
std::vector<std::vector<float>>(
rows, std::vector<float>(columns, 0.f)
)
);
// go through each row of the new matrix
for (size_t row = 0; row < rows; ++row) {
// go through each column of the new matrix
for (size_t column = 0; column < columns; ++column) {
// set element in the new matrix to the dot product of this matrix's row and the rhs matrix's column
for (size_t element = 0; element < elements; ++element) {
new_matrix.matrix_[row][column] +=
matrix_[row][element] * rhs.matrix_[element][column];
}
}
}
return new_matrix;
}
/// gets the translation from the matrix
Vector2 getTranslation() const {
return { matrix_[2][0], matrix_[2][1] };
}
/// gets the positive scale from the matrix
Vector2 getScale() const {
Vector2 scale{
sqrt(pow(matrix_[0][0], 2) + pow(matrix_[0][1], 2)),
sqrt(pow(matrix_[1][0], 2) + pow(matrix_[1][1], 2))
};
if (matrix_[0][0] < 0) {
scale.x = -scale.x;
}
if (matrix_[1][1] < 0) {
scale.y = -scale.y;
}
return scale;
}
/// gets the angle from the matrix
/// \returns radians
float getAngle() const {
return atan2(matrix_[0][1], std::abs(matrix_[1][1]));
}
private:
std::vector<std::vector<float>> matrix_;
};