Problem: Single/Batch Pixel-World Coordinate Conversion

The problem focuses on developing C++ functions to convert between pixel and world coordinates, including single-point and batch operations, with support for full affine transformations (rotation, scaling, shearing) and inverse transformations, using geotransform parameters for accurate adjustments.


Input/Output: The problem accepts a 6-element const double* geotransform array (storing originX, pixelWidth, rotationX, originY, rotationY, pixelHeight) as core input. For single-point pixel-to-world conversion, it takes int line and column; for single-point world-to-pixel, double x and y. For batch operations, it takes const std::vector<int>& lines/columns (batch pixel-to-world) or const std::vector<std::pair<double, double>>& points (batch world-to-pixel). It outputs, for single-point tasks, a std::pair<double, double> (world coordinates) or std::pair<int, int> (pixel coordinates); for batch tasks, a std::vector of these pairs. Processing involves extracting geotransform parameters, applying affine (pixel-to-world) or inverse affine (world-to-pixel) transformations (with pixel center offset adjustment), looping over batch inputs, and returning the transformed coordinates.

Required dependencies:
#include <iostream>
#include <vector>
#include <cmath>
#include <utility>
using namespace std;

Sub-steps:
step_number: 1
step_description_prompt: Please write a C++ function named pixelToWorld that implements pixel to world coordinate conversion with full affine transformation (rotation, scaling, shearing). The function takes a const double* geotransform (6 elements), int line, int column, and returns a std::pair<double, double>.

Function definition: std::pair<double, double> pixelToWorld(const double* geotransform, int line, int column)

Algorithm flow:
1. Extract parameters from geotransform: originX = geotransform[0], originY = geotransform[3], pixelWidth = geotransform[1], pixelHeight = geotransform[5], rotationX = geotransform[2], rotationY = geotransform[4].
2. Compute x: column * pixelWidth + line * rotationX + originX - pixelWidth / 2.0.
3. Compute y: column * rotationY + line * pixelHeight + originY.
4. Adjust y: if pixelHeight < 0, subtract std::abs(pixelHeight)/2.0; else subtract pixelHeight/2.0.
5. Return the pair of x and y.

Used standard functions and types (e.g., std::pair, std::abs) are already defined.
function_header: std::pair<double, double> pixelToWorld(const double* geotransform, int line, int column)
test_cases: int main() {
    // Comparison function
    auto isEqual = [](double a, double b, double tolerance = 1e-6) {
        return std::abs(a - b) <= tolerance;
    };
    
    auto isEqualPair = [&isEqual](const std::pair<double, double>& a, const std::pair<double, double>& b, double tolerance = 1e-6) {
        return isEqual(a.first, b.first, tolerance) && isEqual(a.second, b.second, tolerance);
    };
    
    std::cout << "Subproblem 2.1: Pixel to world (single point)" << std::endl;
    std::cout << "===============================================" << std::endl << std::endl;
    
    int correctCount = 0;
    
    // Test case 1
    double gt1[6] = {100, 10, 0, 200, 0, -10};
    auto result1 = pixelToWorld(gt1, 0, 0);
    std::pair<double, double> expected1(95, 195);
    bool passed1 = isEqualPair(result1, expected1, 0.01);
    std::cout << "Test case 1: " << (passed1 ? "correct" : "wrong") << std::endl;
    if (passed1) correctCount++;
    
    // Test case 2
    double gt2[6] = {0, 500, 0, 0, 0, -500};
    auto result2 = pixelToWorld(gt2, 10, 20);
    // Calculation: x=20*500+0-250=9750, y=10*(-500)+0-250=-5250
    std::pair<double, double> expected2(9750, -5250);
    bool passed2 = isEqualPair(result2, expected2, 0.01);
    std::cout << "Test case 2: " << (passed2 ? "correct" : "wrong") << std::endl;
    if (passed2) correctCount++;
    
    // Test case 3
    double gt3[6] = {120, 0.01, 0, 30, 0, -0.01};
    auto result3 = pixelToWorld(gt3, 100, 200);
    std::pair<double, double> expected3(121.995, 28.995);  // Updated: 200*0.01+120-0.005=121.995, 100*(-0.01)+30-0.005=28.995
    bool passed3 = isEqualPair(result3, expected3, 0.001);
    std::cout << "Test case 3: " << (passed3 ? "correct" : "wrong") << std::endl;
    if (passed3) correctCount++;
    
    if (correctCount == 3) {
        std::cout << "Subproblem 2.1: Completely correct!" << std::endl;
    }
    
    return 0;
}



step_number: 2
step_description_prompt: Please write a C++ function named worldToPixel that converts world coordinates (x, y) to pixel coordinates (line, column) with inverse affine transformation support for rotation. The function is defined as std::pair<int, int> worldToPixel(const double* geotransform, double x, double y); where geotransform is a 6-element array containing [originX, pixelWidth, rotationX, originY, rotationY, pixelHeight]. Algorithm steps: 1. Extract originX (geotransform[0]), originY (geotransform[3]), pixelWidth (geotransform[1]), pixelHeight (geotransform[5]), rotationX (geotransform[2]), rotationY (geotransform[4]). 2. Adjust x to x_adj = x + pixelWidth / 2.0; adjust y to y_adj = y + (pixelHeight < 0 ? std::abs(pixelHeight) / 2.0 : pixelHeight / 2.0). 3. Calculate dx = x_adj - originX, dy = y_adj - originY. 4. If |rotationX| > 1e-10 or |rotationY| > 1e-10, compute det = pixelWidth * pixelHeight - rotationX * rotationY. If |det| > 1e-10, calculate col = (pixelHeight * dx - rotationX * dy) / det, lin = (-rotationY * dx + pixelWidth * dy) / det, then round col and lin to int as column and line, return {line, column}. 5. For no rotation, compute col = (x_adj - originX) / pixelWidth, lin = (y_adj - originY) / pixelHeight. Round col and lin to int as column and line. 6. Return {line, column}. Ensure std::pair, std::abs, std::round are available.
function_header: std::pair<int, int> worldToPixel(const double* geotransform, double x, double y)
test_cases: int main() {
    // Comparison function
    auto isEqual = [](const std::pair<int, int>& a, const std::pair<int, int>& b) {
        return a.first == b.first && a.second == b.second;
    };
    
    std::cout << "Subproblem 2.2: World to pixel (single point)" << std::endl;
    std::cout << "===============================================" << std::endl << std::endl;
    
    int correctCount = 0;
    
    // Test case 1
    double gt1[6] = {100, 10, 0, 200, 0, -10};
    auto result1 = worldToPixel(gt1, 95, 195);
    std::pair<int, int> expected1(0, 0);
    bool passed1 = isEqual(result1, expected1);
    std::cout << "Test case 1: " << (passed1 ? "correct" : "wrong") << std::endl;
    if (passed1) correctCount++;
    
    // Test case 2: Use the output from test case 2 of 2.1 as input
    double gt2[6] = {0, 500, 0, 0, 0, -500};
    auto result2 = worldToPixel(gt2, 9750, -5250);
    std::pair<int, int> expected2(10, 20);
    bool passed2 = isEqual(result2, expected2);
    std::cout << "Test case 2: " << (passed2 ? "correct" : "wrong") << std::endl;
    if (passed2) correctCount++;
    
    // Test case 3: Use the output from test case 3 of 2.1 as input
    double gt3[6] = {120, 0.01, 0, 30, 0, -0.01};
    auto result3 = worldToPixel(gt3, 121.995, 28.995);
    std::pair<int, int> expected3(100, 200);
    bool passed3 = isEqual(result3, expected3);
    std::cout << "Test case 3: " << (passed3 ? "correct" : "wrong") << std::endl;
    if (passed3) correctCount++;
    
    if (correctCount == 3) {
        std::cout << "Subproblem 2.2: Completely correct!" << std::endl;
    }
    
    return 0;
}



step_number: 3
step_description_prompt: Please write a C++ function named batchPixelToWorld that converts batch pixel coordinates to world coordinates with matrix-vector multiplication optimization. The function takes a const double* geotransform (contains originX, originY, pixelWidth, pixelHeight, rotationX, rotationY in order), const std::vector<int>& lines (pixel line indices), const std::vector<int>& columns (pixel column indices) as parameters, and returns a std::vector<std::pair<double, double>> (world coordinate pairs). 

Function definition: std::vector<std::pair<double, double>> batchPixelToWorld(const double* geotransform, const std::vector<int>& lines, const std::vector<int>& columns);

Algorithm flow: 1. Reserve space for results using lines.size(). 2. Extract originX=geotransform[0], originY=geotransform[3], pixelWidth=geotransform[1], pixelHeight=geotransform[5], rotationX=geotransform[2], rotationY=geotransform[4]. 3. Loop through each index i: get line=lines[i], column=columns[i]. 4. Calculate x = column*pixelWidth + line*rotationX + originX - pixelWidth/2.0. 5. Calculate y = column*rotationY + line*pixelHeight + originY; then subtract std::abs(pixelHeight)/2.0 if pixelHeight<0, else subtract pixelHeight/2.0. 6. Push {x,y} to results. 

Ensure the function uses std::vector and std::pair correctly.
function_header: std::vector<std::pair<double, double>> batchPixelToWorld( const double* geotransform, const std::vector<int>& lines, const std::vector<int>& columns )
test_cases: int main() {
    // Comparison function
    auto isEqual = [](double a, double b, double tolerance = 1e-6) {
        return std::abs(a - b) <= tolerance;
    };
    
    auto isEqualPair = [&isEqual](const std::pair<double, double>& a, const std::pair<double, double>& b, double tolerance = 1e-6) {
        return isEqual(a.first, b.first, tolerance) && isEqual(a.second, b.second, tolerance);
    };
    
    auto isEqualVec = [&isEqualPair](const std::vector<std::pair<double, double>>& a, const std::vector<std::pair<double, double>>& b, double tolerance = 1e-6) {
        if (a.size() != b.size()) return false;
        for (size_t i = 0; i < a.size(); ++i) {
            if (!isEqualPair(a[i], b[i], tolerance)) return false;
        }
        return true;
    };
    
    std::cout << "Subproblem 2.3: Batch pixel to world" << std::endl;
    std::cout << "=====================================" << std::endl << std::endl;
    
    int correctCount = 0;
    
    // Test case 1
    double gt1[6] = {100, 10, 0, 200, 0, -10};
    std::vector<int> lines1 = {0, 1, 2};
    std::vector<int> cols1 = {0, 1, 2};
    auto result1 = batchPixelToWorld(gt1, lines1, cols1);
    // Updated expected values based on enhanced formula
    std::vector<std::pair<double, double>> expected1 = {{95, 195}, {105, 185}, {115, 175}};
    bool passed1 = isEqualVec(result1, expected1, 0.01);
    std::cout << "Test case 1: " << (passed1 ? "correct" : "wrong") << std::endl;
    if (passed1) correctCount++;
    
    // Test case 2: 10 points
    std::vector<int> lines10, cols10;
    for (int i = 0; i < 10; ++i) {
        lines10.push_back(i);
        cols10.push_back(i);
    }
    auto result2 = batchPixelToWorld(gt1, lines10, cols10);
    bool passed2 = (result2.size() == 10);
    std::cout << "Test case 2: " << (passed2 ? "correct" : "wrong") << std::endl;
    if (passed2) correctCount++;
    
    // Test case 3: 100 points
    std::vector<int> lines100, cols100;
    for (int i = 0; i < 100; ++i) {
        lines100.push_back(i);
        cols100.push_back(i);
    }
    auto result3 = batchPixelToWorld(gt1, lines100, cols100);
    bool passed3 = (result3.size() == 100);
    std::cout << "Test case 3: " << (passed3 ? "correct" : "wrong") << std::endl;
    if (passed3) correctCount++;
    
    if (correctCount == 3) {
        std::cout << "Subproblem 2.3: Completely correct!" << std::endl;
    }
    
    return 0;
}



step_number: 4
step_description_prompt: Please write a C++ function named batchWorldToPixel that implements batch conversion of world coordinates to pixel coordinates with enhanced batch inverse transformation.

Function definition: std::vector<std::pair<int, int>> batchWorldToPixel(const double* geotransform, const std::vector<std::pair<double, double>>& points);

Algorithm steps: 1. Extract originX (geotransform[0]), originY (geotransform[3]), pixelWidth (geotransform[1]), pixelHeight (geotransform[5]), rotationX (geotransform[2]), rotationY (geotransform[4]) from geotransform. 2. Reserve space for results using points.size(). 3. Iterate over each point: a. Get x = point.first, y = point.second. b. Adjust x to x_adj = x + pixelWidth / 2.0; adjust y to y_adj: if pixelHeight < 0, y_adj = y + std::abs(pixelHeight)/2.0; else y_adj = y + pixelHeight/2.0. c. Calculate col = (x_adj - originX) / pixelWidth; calculate lin = (y_adj - originY) / pixelHeight. d. Convert col and lin to int using std::round, then push {line, column} (line is rounded lin, column is rounded col) to results.

Note: std::round, std::vector, and std::pair are pre-defined and do not need redefinition.
function_header: std::vector<std::pair<int, int>> batchWorldToPixel( const double* geotransform, const std::vector<std::pair<double, double>>& points )
test_cases: int main() {
    // Comparison function
    auto isEqual = [](const std::pair<int, int>& a, const std::pair<int, int>& b) {
        return a.first == b.first && a.second == b.second;
    };
    
    auto isEqualVec = [&isEqual](const std::vector<std::pair<int, int>>& a, const std::vector<std::pair<int, int>>& b) {
        if (a.size() != b.size()) return false;
        for (size_t i = 0; i < a.size(); ++i) {
            if (!isEqual(a[i], b[i])) return false;
        }
        return true;
    };
    
    std::cout << "Subproblem 2.4: Batch world to pixel" << std::endl;
    std::cout << "=====================================" << std::endl << std::endl;
    
    int correctCount = 0;
    
    // Test case 1
    double gt1[6] = {100, 10, 0, 200, 0, -10};
    std::vector<std::pair<double, double>> points1 = {{95, 195}, {105, 185}, {115, 175}};
    auto result1 = batchWorldToPixel(gt1, points1);
    std::vector<std::pair<int, int>> expected1 = {{0, 0}, {1, 1}, {2, 2}};
    bool passed1 = isEqualVec(result1, expected1);
    std::cout << "Test case 1: " << (passed1 ? "correct" : "wrong") << std::endl;
    if (passed1) correctCount++;
    
    // Test case 2: 10 points
    std::vector<std::pair<double, double>> points10;
    for (int i = 0; i < 10; ++i) {
        points10.push_back({100 + i * 10 - 5, 200 - i * 10 + 5});
    }
    auto result2 = batchWorldToPixel(gt1, points10);
    bool passed2 = (result2.size() == 10);
    std::cout << "Test case 2: " << (passed2 ? "correct" : "wrong") << std::endl;
    if (passed2) correctCount++;
    
    // Test case 3: 100 points
    std::vector<std::pair<double, double>> points100;
    for (int i = 0; i < 100; ++i) {
        points100.push_back({100 + i * 10 - 5, 200 - i * 10 + 5});
    }
    auto result3 = batchWorldToPixel(gt1, points100);
    bool passed3 = (result3.size() == 100);
    std::cout << "Test case 3: " << (passed3 ? "correct" : "wrong") << std::endl;
    if (passed3) correctCount++;
    
    if (correctCount == 3) {
        std::cout << "Subproblem 2.4: Completely correct!" << std::endl;
    }
    
    return 0;
}



General solution:

General tests: