/**
 * The MIT License (MIT)
 *
 * Copyright © 2018-2019 Ruben Van Boxem
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 **/

#ifndef SKUI_CSS_GRAMMAR_NUMERIC_H
#define SKUI_CSS_GRAMMAR_NUMERIC_H

#include "css/grammar/as.h++"
#include "css/grammar/semantic_checks.h++"
#include "css/grammar/semantic_math.h++"

#include <core/debug.h++>

#include <boost/spirit/home/x3.hpp>

#include <cmath>

namespace skui::css::grammar
{
  namespace x3 = boost::spirit::x3;

  template<int max_value>
  constexpr auto clamp_and_normalize = [](auto& context)
  {
    using value_type = std::remove_reference_t<decltype(x3::_val(context))>;
    using attribute_type = std::remove_reference_t<decltype(x3::_attr(context))>;

    x3::_val(context) = value_type(std::clamp<attribute_type>(x3::_attr(context), 0, max_value)/attribute_type(max_value));
  };

  constexpr auto uint8_hex = x3::uint_parser<std::uint8_t, 16, 2, 2>{};
  const auto ufloat = x3::real_parser<float, x3::ureal_policies<float>>{};

  template<typename ValueType>
  struct non_scientific_real_policies : x3::real_policies<ValueType>
  {
    template<typename Iterator>
    static bool parse_exp(Iterator&, const Iterator&)
    {
      return false;
    }
  };
  const auto non_scientific_float = x3::real_parser<float, non_scientific_real_policies<float>>{};

  const auto percentage = x3::rule<struct percentage, float>{"percentage"}
                       %= (x3::float_ >> '%')[divide{100.f}];

  const auto percentage_or_uint8 = x3::rule<struct percentage_or_uint8, std::uint8_t>{"percentage or uint8"}
                                %= as<float>(percentage[clamp{1.f}][multiply{255.f}][round])
                                 | as<float>(ufloat[clamp{255.f}])
                                 ;
  const auto percentage_or_normalized = x3::rule<struct percentage_or_normalized, float>{"percentage or normalized"}
                                     %= percentage[clamp{1.f}]
                                      | ufloat[clamp{1.f}]
                                      ;
  const auto degrees_normalized = x3::rule<struct degrees_normalized, float>{"degrees [0,360] normalized to [0,1]"}
                               %= ufloat[clamp_and_normalize<360>];
}

#endif


/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2012, Rice University
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Rice University nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/

/* Author: Ryan Luna, Luis G. Torres */

#include <ompl/base/PlannerData.h>
#include <ompl/base/PlannerDataStorage.h>
#include <ompl/base/PlannerDataGraph.h>
#include <ompl/base/spaces/SE3StateSpace.h>
#include <ompl/base/objectives/PathLengthOptimizationObjective.h>
#include <ompl/geometric/SimpleSetup.h>
#include <ompl/base/goals/GoalState.h>

#include <boost/graph/astar_search.hpp>
#include <iostream>

namespace ob = ompl::base;
namespace og = ompl::geometric;

bool isStateValid(const ob::State *state)
{
    // cast the abstract state type to the type we expect
    const auto *se3state = state->as<ob::SE3StateSpace::StateType>();

    // extract the first component of the state and cast it to what we expect
    const auto *pos = se3state->as<ob::RealVectorStateSpace::StateType>(0);

    // extract the second component of the state and cast it to what we expect
    const auto *rot = se3state->as<ob::SO3StateSpace::StateType>(1);

    // check validity of state defined by pos & rot

    // return a value that is always true but uses the two variables we define, so we avoid compiler warnings
    return (const void*)rot != (const void*)pos;
}

void planWithSimpleSetup()
{
    // construct the state space we are planning in
    auto space(std::make_shared<ob::SE3StateSpace>());

    // set the bounds for the R^3 part of SE(3)
    ob::RealVectorBounds bounds(3);
    bounds.setLow(-10);
    bounds.setHigh(10);

    space->setBounds(bounds);

    // define a simple setup class
    og::SimpleSetup ss(space);

    // set state validity checking for this space
    ss.setStateValidityChecker([](const ob::State *state) { return isStateValid(state); });

    // create a random start state
    ob::ScopedState<> start(space);
    start.random();

    // create a random goal state
    ob::ScopedState<> goal(space);
    goal.random();

    // set the start and goal states
    ss.setStartAndGoalStates(start, goal);

    // this call is optional, but we put it in to get more output information
    ss.setup();
    ss.print();

    // attempt to find an exact solution within five seconds
    if (ss.solve(5.0) == ob::PlannerStatus::EXACT_SOLUTION)
    {
        og::PathGeometric slnPath = ss.getSolutionPath();

        std::cout << std::endl;
        std::cout << "Found solution with " << slnPath.getStateCount() << " states and length " << slnPath.length() << std::endl;
        // print the path to screen
        //slnPath.print(std::cout);

        std::cout << "Writing PlannerData to file './myPlannerData'" << std::endl;
        ob::PlannerData data(ss.getSpaceInformation());
        ss.getPlannerData(data);

        ob::PlannerDataStorage dataStorage;
        dataStorage.store(data, "myPlannerData");
    }
    else
        std::cout << "No solution found" << std::endl;
}

// Used for A* search.  Computes the heuristic distance from vertex v1 to the goal
ob::Cost distanceHeuristic(ob::PlannerData::Graph::Vertex v1,
                           const ob::GoalState* goal,
                           const ob::OptimizationObjective* obj,
                           const boost::property_map<ob::PlannerData::Graph::Type,
                           vertex_type_t>::type& plannerDataVertices)
{
    return ob::Cost(obj->costToGo(plannerDataVertices[v1]->getState(), goal));
}

void readPlannerData()
{
    std::cout << std::endl;
    std::cout << "Reading PlannerData from './myPlannerData'" << std::endl;

    // Recreating the space information from the stored planner data instance
    auto space(std::make_shared<ob::SE3StateSpace>());
    auto si(std::make_shared<ob::SpaceInformation>(space));

    ob::PlannerDataStorage dataStorage;
    ob::PlannerData data(si);

    // Loading an instance of PlannerData from disk.
    dataStorage.load("myPlannerData", data);

    // Re-extract the shortest path from the loaded planner data
    if (data.numStartVertices() > 0 && data.numGoalVertices() > 0)
    {
        // Create an optimization objective for optimizing path length in A*
        ob::PathLengthOptimizationObjective opt(si);

        // Computing the weights of all edges based on the state space distance
        // This is not done by default for efficiency
        data.computeEdgeWeights(opt);

        // Getting a handle to the raw Boost.Graph data
        ob::PlannerData::Graph::Type& graph = data.toBoostGraph();

        // Now we can apply any Boost.Graph algorithm.  How about A*!

        // create a predecessor map to store A* results in
        boost::vector_property_map<ob::PlannerData::Graph::Vertex> prev(data.numVertices());

        // Retrieve a property map with the PlannerDataVertex object pointers for quick lookup
        boost::property_map<ob::PlannerData::Graph::Type, vertex_type_t>::type vertices = get(vertex_type_t(), graph);

        // Run A* search over our planner data
        ob::GoalState goal(si);
        goal.setState(data.getGoalVertex(0).getState());
        ob::PlannerData::Graph::Vertex start = boost::vertex(data.getStartIndex(0), graph);
        boost::astar_visitor<boost::null_visitor> dummy_visitor;
        boost::astar_search(graph, start,
            [&goal, &opt, &vertices](ob::PlannerData::Graph::Vertex v1) { return distanceHeuristic(v1, &goal, &opt, vertices); },
            boost::predecessor_map(prev).
            distance_compare([&opt](ob::Cost c1, ob::Cost c2) { return opt.isCostBetterThan(c1, c2); }).
            distance_combine([&opt](ob::Cost c1, ob::Cost c2) { return opt.combineCosts(c1, c2); }).
            distance_inf(opt.infiniteCost()).
            distance_zero(opt.identityCost()).
            visitor(dummy_visitor));

        // Extracting the path
        og::PathGeometric path(si);
        for (ob::PlannerData::Graph::Vertex pos = boost::vertex(data.getGoalIndex(0), graph);
             prev[pos] != pos;
             pos = prev[pos])
        {
            path.append(vertices[pos]->getState());
        }
        path.append(vertices[start]->getState());
        path.reverse();

        // print the path to screen
        //path.print(std::cout);
        std::cout << "Found stored solution with " << path.getStateCount() << " states and length " << path.length() << std::endl;
    }
}

int main(int /*argc*/, char ** /*argv*/)
{
    // Plan and save all of the planner data to disk
    planWithSimpleSetup();

    // Read in the saved planner data and extract the solution path
    readPlannerData();

    return 0;
}


#ifndef SEQUENTIAL_LINE_SEARCH_PREFERENCE_DATA_MANAGER_HPP
#define SEQUENTIAL_LINE_SEARCH_PREFERENCE_DATA_MANAGER_HPP

#include <Eigen/Core>
#include <sequential-line-search/preference.hpp>
#include <vector>

namespace sequential_line_search
{
    /// \brief Utility class for managing preferential data observed during optimization.
    class PreferenceDataManager
    {
    public:
        Eigen::MatrixXd         m_X;
        std::vector<Preference> m_D;

        /// \brief Add a new preference observation.
        ///
        /// \details If merge_close_points is true, this method will merge data points (including both existing and new
        /// ones) that are sufficiently close to each other with the threshold of epsilon.
        void AddNewPoints(const Eigen::VectorXd&              x_preferable,
                          const std::vector<Eigen::VectorXd>& xs_other,
                          const bool                          merge_close_points = true,
                          const double                        epsilon            = 1e-04);

        /// \brief Get the last preferential feedback data sample
        const Preference& GetLastDataSample() const { return m_D.back(); }

        /// \brief Get the number of data points
        int GetNumDataPoints() const { return m_X.cols(); }
    };
} // namespace sequential_line_search

#endif // SEQUENTIAL_LINE_SEARCH_PREFERENCE_DATA_MANAGER_HPP


#include <boost/test/unit_test.hpp>

#include "logs.h"
#include "route.h"
#include "track.h"

//see Test Suite Designs for information on the functions

using namespace GPS;

BOOST_AUTO_TEST_SUITE( N0692013_routeMinLongitude )

const bool isFileName = true;

BOOST_AUTO_TEST_CASE( checkCorrectHorizontal )
{
   Route route = Route(LogFiles::GPXRoutesDir + "N0692013_correctHorizontalRoute.gpx", isFileName);
   BOOST_CHECK_EQUAL( route.minLongitude(), 49.7205);
}

BOOST_AUTO_TEST_CASE( checkCorrectVertical )
{
   Route route = Route(LogFiles::GPXRoutesDir + "N0692013_correctVertical.gpx", isFileName);
   BOOST_CHECK_EQUAL( route.minLongitude(), 25);
}

BOOST_AUTO_TEST_CASE( checkCorrectUnordered )
{
   Route route = Route(LogFiles::GPXRoutesDir + "N0692013_correctUnorderedRoute.gpx", isFileName);
   BOOST_CHECK_EQUAL( route.minLongitude(), 49.8602);
}

BOOST_AUTO_TEST_CASE( checkCorrectNegatives )
{
   Route route = Route(LogFiles::GPXRoutesDir + "N0692013_correctNegatives.gpx", isFileName);
   BOOST_CHECK_EQUAL( route.minLongitude(), -10.0091);
}

BOOST_AUTO_TEST_CASE( checkCorrectBoundary )
{
   Route route = Route(LogFiles::GPXRoutesDir + "N0692013_correctBoundary.gpx", isFileName);
   BOOST_CHECK_EQUAL( route.minLongitude(), 179.102);
}

BOOST_AUTO_TEST_CASE( checkCorrectDiffAs0 )
{
   Route route = Route(LogFiles::GPXRoutesDir + "N0692013_correctDiffAs0.gpx", isFileName);
   BOOST_CHECK_EQUAL( route.minLongitude(), 0);
}

BOOST_AUTO_TEST_SUITE_END()


/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2020-2022 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/
#include <miopen/handle.hpp>
#include <miopen/miopen.h>
#include <miopen/tensor_reorder_util.hpp>
#include <miopen/tensor.hpp>
#include <miopen/tensor_layout.hpp>
#include <miopen/general_tensor_reorder_sol.hpp>
#include <miopen/invoker.hpp>
#include <miopen/invoke_params.hpp>
#include <boost/optional.hpp>
#include <vector>
#include <cstdlib>
#include <ctime>
#include "test.hpp"
#include "driver.hpp"
#include "random.hpp"

template <>
struct miopen_type<uint8_t> : std::integral_constant<miopenDataType_t, miopenInt8>
{
};

template <>
struct miopen_type<uint16_t> : std::integral_constant<miopenDataType_t, miopenHalf>
{
};

template <typename T>
void cpu_tensor_reorder(T* dst,
                        T* src,
                        uint64_t dim_0,
                        uint64_t dim_1,
                        uint64_t dim_2,
                        uint64_t dim_3,
                        uint64_t order_0,
                        uint64_t order_1,
                        uint64_t order_2,
                        uint64_t order_3)
{
    const uint64_t src_dim[4] = {dim_0, dim_1, dim_2, dim_3};
    const uint64_t dst_dim[4] = {
        src_dim[order_0], src_dim[order_1], src_dim[order_2], src_dim[order_3]};

    const uint64_t src_stride[4] = {
        src_dim[1] * src_dim[2] * src_dim[3], src_dim[2] * src_dim[3], src_dim[3], 1};
    const uint64_t dst_stride[4] = {
        dst_dim[1] * dst_dim[2] * dst_dim[3], dst_dim[2] * dst_dim[3], dst_dim[3], 1};

    uint64_t itr_src_dim[4] = {0, 0, 0, 0};
    uint64_t itr_dst_dim[4] = {0, 0, 0, 0};

    for(itr_src_dim[0] = 0; itr_src_dim[0] < src_dim[0]; itr_src_dim[0]++)
    {
        for(itr_src_dim[1] = 0; itr_src_dim[1] < src_dim[1]; itr_src_dim[1]++)
        {
            for(itr_src_dim[2] = 0; itr_src_dim[2] < src_dim[2]; itr_src_dim[2]++)
            {
                for(itr_src_dim[3] = 0; itr_src_dim[3] < src_dim[3]; itr_src_dim[3]++)
                {
                    itr_dst_dim[0] = itr_src_dim[order_0];
                    itr_dst_dim[1] = itr_src_dim[order_1];
                    itr_dst_dim[2] = itr_src_dim[order_2];
                    itr_dst_dim[3] = itr_src_dim[order_3];

                    uint64_t idx_src =
                        itr_src_dim[0] * src_stride[0] + itr_src_dim[1] * src_stride[1] +
                        itr_src_dim[2] * src_stride[2] + itr_src_dim[3] * src_stride[3];
                    uint64_t idx_dst =
                        itr_dst_dim[0] * dst_stride[0] + itr_dst_dim[1] * dst_stride[1] +
                        itr_dst_dim[2] * dst_stride[2] + itr_dst_dim[3] * dst_stride[3];

                    dst[idx_dst] = src[idx_src];
                }
            }
        }
    }
}

template <typename T>
struct cpu_reorder
{
    static void run(T* dst,
                    T* src,
                    uint64_t dim_0,
                    uint64_t dim_1,
                    uint64_t dim_2,
                    uint64_t dim_3,
                    uint64_t order_0,
                    uint64_t order_1,
                    uint64_t order_2,
                    uint64_t order_3)
    {
        cpu_tensor_reorder<T>(
            dst, src, dim_0, dim_1, dim_2, dim_3, order_0, order_1, order_2, order_3);
    }
};

struct reorder_str
{
    static std::string get(uint32_t order_0, uint32_t order_1, uint32_t order_2, uint32_t order_3)
    {
        return ("r" + std::to_string(order_0) + std::to_string(order_1) + std::to_string(order_2) +
                std::to_string(order_3));
    }
};

enum tensor_layout_t
{
    miopen_tensor_layout_nchw,
    miopen_tensor_layout_ncdhw,
    miopen_tensor_layout_nhwc,
    miopen_tensor_layout_ndhwc,
};

std::string tensor_layout_to_string(tensor_layout_t layout)
{
    std::string layout_string("N/A");
    if(layout == miopen_tensor_layout_nchw)
        layout_string = "NCHW";
    else if(layout == miopen_tensor_layout_ncdhw)
        layout_string = "NCDHW";
    else if(layout == miopen_tensor_layout_nhwc)
        layout_string = "NHWC";
    else if(layout == miopen_tensor_layout_ndhwc)
        layout_string = "NDHWC";
    else
        MIOPEN_THROW("Unsupported tensor layout");
    return layout_string;
}

std::string
supported_reorder_to_string(uint32_t order_0, uint32_t order_1, uint32_t order_2, uint32_t order_3)
{
    std::string layout_string("N/A");
    if((order_0 == 0) && (order_1 == 1) && (order_2 == 3) && (order_3 == 2))
        layout_string = "r0132";
    else if((order_0 == 0) && (order_1 == 2) && (order_2 == 1) && (order_3 == 3))
        layout_string = "r0213";
    else if((order_0 == 0) && (order_1 == 2) && (order_2 == 3) && (order_3 == 1))
        layout_string = "r0231";
    else if((order_0 == 0) && (order_1 == 3) && (order_2 == 1) && (order_3 == 2))
        layout_string = "r0312";
    else if((order_0 == 0) && (order_1 == 3) && (order_2 == 2) && (order_3 == 1))
        layout_string = "r0321";
    else if((order_0 == 1) && (order_1 == 0) && (order_2 == 2) && (order_3 == 3))
        layout_string = "r1023";
    else if((order_0 == 1) && (order_1 == 0) && (order_2 == 3) && (order_3 == 2))
        layout_string = "r1032";
    else if((order_0 == 1) && (order_1 == 2) && (order_2 == 0) && (order_3 == 3))
        layout_string = "r1203";
    else if((order_0 == 1) && (order_1 == 2) && (order_2 == 3) && (order_3 == 0))
        layout_string = "r1230";
    else if((order_0 == 1) && (order_1 == 3) && (order_2 == 0) && (order_3 == 2))
        layout_string = "r1302";
    else if((order_0 == 1) && (order_1 == 3) && (order_2 == 2) && (order_3 == 0))
        layout_string = "r1320";
    else if((order_0 == 2) && (order_1 == 0) && (order_2 == 1) && (order_3 == 3))
        layout_string = "r2013";
    else if((order_0 == 2) && (order_1 == 0) && (order_2 == 3) && (order_3 == 1))
        layout_string = "r2031";
    else if((order_0 == 2) && (order_1 == 1) && (order_2 == 0) && (order_3 == 3))
        layout_string = "r2103";
    else if((order_0 == 2) && (order_1 == 1) && (order_2 == 3) && (order_3 == 0))
        layout_string = "r2130";
    else if((order_0 == 2) && (order_1 == 3) && (order_2 == 0) && (order_3 == 1))
        layout_string = "r2301";
    else if((order_0 == 2) && (order_1 == 3) && (order_2 == 1) && (order_3 == 0))
        layout_string = "r2310";
    else if((order_0 == 3) && (order_1 == 0) && (order_2 == 1) && (order_3 == 2))
        layout_string = "r3012";
    else if((order_0 == 3) && (order_1 == 0) && (order_2 == 2) && (order_3 == 1))
        layout_string = "r3021";
    else if((order_0 == 3) && (order_1 == 1) && (order_2 == 0) && (order_3 == 2))
        layout_string = "r3102";
    else if((order_0 == 3) && (order_1 == 1) && (order_2 == 2) && (order_3 == 0))
        layout_string = "r3120";
    else if((order_0 == 3) && (order_1 == 2) && (order_2 == 0) && (order_3 == 1))
        layout_string = "r3201";
    else if((order_0 == 3) && (order_1 == 2) && (order_2 == 1) && (order_3 == 0))
        layout_string = "r3210";
    else
        MIOPEN_THROW("Unsupported reorder layout");
    return layout_string;
}

template <typename T>
struct to_miopen_data_type
{
};

template <>
struct to_miopen_data_type<double>
{
    static miopenDataType_t get() { return miopenDouble; }
};

template <>
struct to_miopen_data_type<float>
{
    static miopenDataType_t get() { return miopenFloat; }
};

template <>
struct to_miopen_data_type<uint16_t>
{
    static miopenDataType_t get() { return miopenHalf; } // we actually didn't calculate 16bit float
};

template <>
struct to_miopen_data_type<uint8_t>
{
    static miopenDataType_t get() { return miopenInt8; }
};

#define RAND_INTEGER_MAX 120
#define RAND_INTEGER_MIN -88

static int gen_rand_integer()
{
    // NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
    static int inited = 0;
    if(inited == 0)
    {
        std::srand(std::time(nullptr));
        inited = 1;
    }
    return GET_RAND();
}

template <typename T>
void rand_tensor_integer(tensor<T>& t, int max = RAND_INTEGER_MAX, int min = RAND_INTEGER_MIN)
{
    // use integer to random.
    for(int i = 0; i < t.data.size(); i++)
        t[i] = static_cast<T>(gen_rand_integer() % (max - min) + min);
}

template <typename T>
bool compare_equal(T r1, T r2)
{
    return r1 == r2;
}

template <>
bool compare_equal<double>(double r1, double r2)
{
    return miopen::float_equal(r1, r2);
}

template <>
bool compare_equal<float>(float r1, float r2)
{
    return miopen::float_equal(r1, r2);
}

template <typename T>
bool verify_tensor(tensor<T>& t_gpu, tensor<T>& t_cpu)
{
    if(t_gpu.data.size() != t_cpu.data.size())
    {
        MIOPEN_LOG_E("size not equal, should not happen");
        return false;
    }
    auto idx          = miopen::mismatch_idx(t_gpu.data, t_cpu.data, compare_equal<T>);
    bool valid_result = idx >= miopen::range_distance(t_cpu);

    if(!valid_result)
    {
        std::cout << "diff at:" << idx << ", gpu:" << t_gpu[idx] << ", cpu:" << t_cpu[idx]
                  << std::endl;
    }
    return valid_result;
}

struct reorder_base
{
    miopenHandle_t handle{};
#if MIOPEN_BACKEND_OPENCL
    cl_command_queue q{};
#endif

    reorder_base()
    {
        miopenCreate(&handle);
#if MIOPEN_BACKEND_OPENCL
        miopenGetStream(handle, &q);
#endif
    }
    ~reorder_base() { miopenDestroy(handle); }

    static std::vector<uint32_t> get_dim_3_size() { return {1, 9, 14}; }
    static std::vector<uint32_t> get_dim_2_size() { return {1, 9, 14}; }
    static std::vector<uint32_t> get_dim_1_size() { return {3, 8, 14}; }
    static std::vector<uint32_t> get_dim_0_size() { return {1, 2}; }

    template <typename F>
    void iterate_reorder(F f)
    {
        std::vector<uint32_t> dim_3_list = get_dim_3_size();
        std::vector<uint32_t> dim_2_list = get_dim_2_size();
        std::vector<uint32_t> dim_1_list = get_dim_1_size();
        std::vector<uint32_t> dim_0_list = get_dim_0_size();

        dim_3_list.push_back(gen_rand_integer() % 13 + 29);
        dim_2_list.push_back(gen_rand_integer() % 13 + 29);
        dim_1_list.push_back(gen_rand_integer() % 13 + 15);
        dim_0_list.push_back(gen_rand_integer() % 4 + 3);

        constexpr int all_possible_order[23][4] = {
            {0, 1, 3, 2}, {0, 2, 1, 3}, {0, 2, 3, 1}, {0, 3, 1, 2}, {0, 3, 2, 1}, {1, 0, 2, 3},
            {1, 0, 3, 2}, {1, 2, 0, 3}, {1, 2, 3, 0}, {1, 3, 0, 2}, {1, 3, 2, 0}, {2, 0, 1, 3},
            {2, 0, 3, 1}, {2, 1, 0, 3}, {2, 1, 3, 0}, {2, 3, 0, 1}, {2, 3, 1, 0}, {3, 0, 1, 2},
            {3, 0, 2, 1}, {3, 1, 0, 2}, {3, 1, 2, 0}, {3, 2, 0, 1}, {3, 2, 1, 0}};

        for(auto order : all_possible_order)
        {
            for(uint32_t dim_3 : dim_3_list)
            {
                for(uint32_t dim_2 : dim_2_list)
                {
                    for(uint32_t dim_1 : dim_1_list)
                    {
                        for(uint32_t dim_0 : dim_0_list)
                        {
                            f(dim_0, dim_1, dim_2, dim_3, order[0], order[1], order[2], order[3]);
                        }
                    }
                }
            }
        }
    }
};

struct reorder_invoke_param : public miopen::InvokeParams
{
    ConstData_t src = nullptr;
    Data_t dst      = nullptr;

    reorder_invoke_param(ConstData_t src_, Data_t dst_) : src(src_), dst(dst_) {}
    reorder_invoke_param(miopen::InvokeType type_, ConstData_t src_, Data_t dst_)
        : InvokeParams{type_}, src(src_), dst(dst_)
    {
    }
};
template <typename T, typename REORDER_SOL>
struct reorder_test : reorder_base
{
    void run()
    {
        auto run_reorder = [this](uint32_t dim_0,
                                  uint32_t dim_1,
                                  uint32_t dim_2,
                                  uint32_t dim_3,
                                  uint32_t order_0,
                                  uint32_t order_1,
                                  uint32_t order_2,
                                  uint32_t order_3) {
            int tensor_sz = dim_0 * dim_1 * dim_2 * dim_3;
            std::vector<int> tensor_len({static_cast<int>(dim_0),
                                         static_cast<int>(dim_1),
                                         static_cast<int>(dim_2),
                                         static_cast<int>(dim_3)});

            std::vector<int> tensor_strides;

            std::string layout_default = miopen::tensor_layout_get_default(4);
            std::string layout_string  = tensor_layout_to_string(miopen_tensor_layout_nchw);
            std::string reorder_string =
                supported_reorder_to_string(order_0, order_1, order_2, order_3);

            miopen::tensor_layout_to_strides(
                tensor_len, layout_default, layout_string, tensor_strides);

            tensor<T> t_src(tensor_len, tensor_strides);
            tensor<T> t_dst(tensor_len, tensor_strides);
            tensor<T> t_dst_gpu(tensor_len, tensor_strides);
            rand_tensor_integer(t_src);
#if MIOPEN_BACKEND_OPENCL
            cl_context cl_ctx;
            clGetCommandQueueInfo(q, CL_QUEUE_CONTEXT, sizeof(cl_context), &cl_ctx, nullptr);
            cl_int status = CL_SUCCESS;
            cl_mem src_dev =
                clCreateBuffer(cl_ctx, CL_MEM_READ_WRITE, sizeof(T) * tensor_sz, nullptr, &status);
            cl_mem dst_dev =
                clCreateBuffer(cl_ctx, CL_MEM_READ_WRITE, sizeof(T) * tensor_sz, nullptr, nullptr);
            status |= clEnqueueWriteBuffer(q,
                                           src_dev,
                                           CL_TRUE,
                                           0,
                                           sizeof(T) * tensor_sz,
                                           t_src.data.data(),
                                           0,
                                           nullptr,
                                           nullptr);
            EXPECT(status == CL_SUCCESS);
#elif MIOPEN_BACKEND_HIP
            void* src_dev;
            void* dst_dev;
            EXPECT(hipMalloc(&src_dev, sizeof(T) * tensor_sz) == hipSuccess);
            EXPECT(hipMalloc(&dst_dev, sizeof(T) * tensor_sz) == hipSuccess);
            EXPECT(hipMemcpy(
                       src_dev, t_src.data.data(), sizeof(T) * tensor_sz, hipMemcpyHostToDevice) ==
                   hipSuccess);
#endif

            const auto invoke_param = reorder_invoke_param{
                DataCast(static_cast<const void*>(src_dev)), DataCast(dst_dev)};

            miopen::ExecutionContext ctx;
            ctx.SetStream(&miopen::deref(this->handle));
            ctx.DetectRocm();
            // ctx.SetupFloats();
            auto reorder_sol                = TensorReorderSolutionConstructor(ctx,
                                                                to_miopen_data_type<T>::get(),
                                                                dim_0,
                                                                dim_1,
                                                                dim_2,
                                                                dim_3,
                                                                order_0,
                                                                order_1,
                                                                order_2,
                                                                order_3);
            std::vector<OpKernelArg> opArgs = reorder_sol->GetKernelArg();
            boost::optional<miopen::InvokerFactory> invoker_factory(
                [=](const std::vector<miopen::Kernel>& kernels) mutable {
                    return [=](const miopen::Handle& handle,
                               const miopen::AnyInvokeParams& primitive_param) mutable {
                        decltype(auto) invoke_params =
                            primitive_param.CastTo<reorder_invoke_param>();

                        const auto k = handle.Run(kernels[0]);

                        opArgs[0] = OpKernelArg(invoke_params.dst);
                        opArgs[1] = OpKernelArg(invoke_params.src);

                        k(opArgs);
                    };
                });
            std::vector<miopen::solver::KernelInfo> construction_params{reorder_sol->GetKernel()};
            const auto invoker =
                miopen::deref(this->handle).PrepareInvoker(*invoker_factory, construction_params);
            // run gpu
            invoker(miopen::deref(this->handle), invoke_param);
            // run cpu
            cpu_reorder<T>::run(t_dst.data.data(),
                                t_src.data.data(),
                                dim_0,
                                dim_1,
                                dim_2,
                                dim_3,
                                order_0,
                                order_1,
                                order_2,
                                order_3);

#if MIOPEN_BACKEND_OPENCL
            status = clEnqueueReadBuffer(q,
                                         dst_dev,
                                         CL_TRUE,
                                         0,
                                         sizeof(T) * tensor_sz,
                                         t_dst_gpu.data.data(),
                                         0,
                                         nullptr,
                                         nullptr);
            EXPECT(status == CL_SUCCESS);
#elif MIOPEN_BACKEND_HIP
            EXPECT(hipMemcpy(t_dst_gpu.data.data(),
                             dst_dev,
                             sizeof(T) * tensor_sz,
                             hipMemcpyDeviceToHost) == hipSuccess);
#endif

            // we expect excact match, since use integer
            bool valid_result = verify_tensor(t_dst_gpu, t_dst);
            std::cout << "[" << reorder_str::get(order_0, order_1, order_2, order_3) << ", b"
                      << (sizeof(T) * 8) << " ] "
                      << "dim_0:" << dim_0 << ", dim_1:" << dim_1 << ", dim_2:" << dim_2
                      << ", dim_3:" << dim_3 << ", valid:" << valid_result << std::endl;
            EXPECT(valid_result == true);

#if MIOPEN_BACKEND_OPENCL
            clReleaseMemObject(src_dev);
            clReleaseMemObject(dst_dev);
#elif MIOPEN_BACKEND_HIP
            hipFree(src_dev);
            hipFree(dst_dev);
#endif
        };

        iterate_reorder(run_reorder);
    }
};

int main()
{
    run_test<reorder_test<double, miopen::TensorReorderSolution>>(); // DOUBLE only support general
                                                                     // reorder solution, do not
                                                                     // support batched transpose.
    run_test<reorder_test<float, miopen::TensorReorderSolution>>();
    run_test<reorder_test<uint16_t, miopen::TensorReorderSolution>>();
    run_test<reorder_test<uint8_t, miopen::TensorReorderSolution>>();
}


/* ----------------------------------------------------------------------------

 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
 * Atlanta, Georgia 30332-0415
 * All Rights Reserved
 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)

 * See LICENSE for the license information

 * -------------------------------------------------------------------------- */

/**
 * @brief wraps BetweenFactor for several values to python
 * @author Andrew Melim
 * @author Ellon Paiva Mendes (LAAS-CNRS)
 **/

#include <boost/python.hpp>

#define NO_IMPORT_ARRAY
#include <numpy_eigen/NumpyEigenConverter.hpp>

#include "gtsam/slam/BetweenFactor.h"
#include "gtsam/geometry/Point2.h"
#include "gtsam/geometry/Rot2.h"
#include "gtsam/geometry/Pose2.h"
#include "gtsam/geometry/Point3.h"
#include "gtsam/geometry/Rot3.h"
#include "gtsam/geometry/Pose3.h"

using namespace boost::python;
using namespace gtsam;

using namespace std;

// template<class T>
// void exportBetweenFactor(const std::string& name){
//   class_<T>(name, init<>())
//   .def(init<Key, Key, T, SharedNoiseModel>())
//   ;
// }

#define BETWEENFACTOR(T) \
  class_< BetweenFactor<T>, bases<NonlinearFactor>, std::shared_ptr< BetweenFactor<T> > >("BetweenFactor"#T) \
  .def(init<Key,Key,T,noiseModel::Base::shared_ptr>()) \
  .def("measured", &BetweenFactor<T>::measured, return_internal_reference<>()) \
;

void exportBetweenFactors()
{
  BETWEENFACTOR(Point2)
  BETWEENFACTOR(Rot2)
  BETWEENFACTOR(Pose2)
  BETWEENFACTOR(Point3)
  BETWEENFACTOR(Rot3)
  BETWEENFACTOR(Pose3)
}


#include <contract/contract.hpp>

#include <boost/test/unit_test.hpp>

#include <iostream>
#include <cstring>
#include <cassert>

// example 1: class and method contracts

namespace
{

class account
{
public:
    account(int deposit)
        : balance_(-1)
    {
        contract(ctor) { precondition(deposit >= 0); };

        balance_ = deposit;
    }

    ~account()
    {
        int closing_balance = balance_;
        contract(dtor) { postcondition(closing_balance >= 0); };

        balance_ = -1;
    }

    int withdraw(int ammount)
    {
        int withdrawn = 0;

        contract(this)
        {
            precondition(ammount >= 0);
            postcondition(withdrawn >= 0);
        };

        withdrawn = ammount >= balance_ ? balance_ : ammount;
        balance_ -= withdrawn;
        return withdrawn;
    }

    int deposit(int ammount)
    {
        contract(this) { precondition(ammount >= 0); };

        balance_ += ammount;
        return balance_;
    }

    int balance() const
    {
        contract(this) {};
        return balance_;
    }

private:
    contract(class) { invariant(balance_ >= 0, "balance can't be negative"); };

private:
    int balance_;
};

// example 2: function contracts

account make_account_with_fee(int balance)
{
    int const fee = 5;
    contract(fun) { precondition(balance > fee); };

    return account(balance - fee);
}

// example 3: function contracts

std::size_t my_strlen(char const * str)
{
    std::size_t len = 0;

    contract(fun)
    {
        precondition(str, "invalid argument");
        postcondition(len == std::strlen(str), "incorrect return value");
    };

    for (char const * p = str; *p; ++len, ++p)
        ;

    return len;
}

// example 4: custom contract violation handler

contract::violation_handler old_handler;
void my_contract_violation_handler(contract::violation_context const & context)
{
    std::cerr << "in my_contract_violation_handler:\n";
    old_handler(context);
}

// example 5: loop invariant

int hash(char const * str)
{
    char const * end = str + std::strlen(str);

    int hash = 743;
    for (char const * p = str; p != end; ++p)
    {
        contract(loop)
        {
            invariant(p >= str);
            invariant(p < end);
            invariant(hash < 0x10000);
        }

        hash = ((hash << 5) ^ *p) & 0xffff;
    }

    return hash;
}

}

BOOST_AUTO_TEST_CASE(examples)
{
    // example 4
    old_handler = contract::set_handler(my_contract_violation_handler);

    // example 3
    my_strlen("a string");

    // example 1
    account acc(100);
    acc.withdraw(10);
    acc.deposit(20);
    assert(acc.balance() == 110);

    // example 2
    acc = make_account_with_fee(15);

    // example 5
    hash("abcde");
}

// Copyright Alexei Zakharov, 2013.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)


#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <map>
#include <algorithm>
#include <stdint.h>

#include "gflags/gflags.h"
#include "glog/logging.h"
#include <boost/shared_ptr.hpp>

#include "caffe/proto/caffe.pb.h"
#include "caffe/blob.hpp"
#include "caffe/util/benchmark.hpp"
#include "caffe/util/io.hpp"
#include "caffe/util/math_functions.hpp"
#include "caffe/util/rng.hpp"
#include "caffe/layer.hpp"
#include "caffe/layers/roi_align_layer.hpp"
#include "caffe/filler.hpp"

#include "gtest/gtest.h"
#include "caffe/test/test_caffe_main.hpp"
#include "caffe/test/test_gradient_check_util.hpp"

#include <Eigen/Dense>

#include "caffe/nhwc/pooling_nhwc_layer.hpp"

using namespace std;
using namespace caffe;

int main(int nargc, char** args) {
  // set caffe::GPU
  caffe::Caffe::SetDevice(0);
  caffe::Caffe::set_mode(caffe::Caffe::CPU);

  int channels = 8;    //input
  int num_output = 8;  // output
  int dim = 8;          // size
  // define input & output blobs
  Blob<float>* input = new Blob<float>(1, dim, dim, channels);
  Blob<float>* output = new Blob<float>(1, dim, dim, num_output);
  vector<Blob<float>*> bottom_vec;
  vector<Blob<float>*> top_vec;

  // set the bottom blob data
  // FillerParameter filler_param;
  // filler_param.set_std(0.5);
  // GaussianFiller<float> filler(filler_param);
  // filler.Fill(input);

  for (int i = 0; i < input->count(); ++i) {
    input->mutable_cpu_data()[i] = sin(i) + tan(i) + tanh(i) + exp(-i);
  }

  // set the bottom and top data-pointer
  bottom_vec.push_back(input);
  top_vec.push_back(output);

  LayerParameter layer_param;
  layer_param.set_name("PoolingNHWC");
  layer_param.set_type("PoolingNHWC");
  PoolingParameter* pooling_param = layer_param.mutable_pooling_param();
  pooling_param->set_kernel_h(2);
  pooling_param->set_kernel_w(2);
  pooling_param->set_stride_h(2);
  pooling_param->set_stride_w(2);
  pooling_param->set_pad_h(0);
  pooling_param->set_pad_w(0);
  pooling_param->set_pool(caffe::PoolingParameter_PoolMethod_MAX);

  LOG(INFO) << layer_param.pooling_param().has_kernel_size();
  LOG(INFO) << layer_param.pooling_param().has_kernel_h();
  LOG(INFO) << layer_param.pooling_param().has_kernel_w();

  boost::shared_ptr<Layer<float> > PoolNHWC_layer = LayerRegistry<float>::CreateLayer(layer_param);
  PoolNHWC_layer->SetUp(bottom_vec, top_vec);

  PoolNHWC_layer->Forward(bottom_vec, top_vec);

  for (int i = 0; i < output->count(); ++i) {
    LOG(INFO) << output->cpu_data()[i];
  }

  // GradientChecker<float> checker(1e-4, 1e-3);
  // checker.CheckGradientExhaustive(PoolNHWC_layer.get(), bottom_vec, top_vec);

  LOG(INFO) << "Gradient Check Finished.";

  return 0;
}


/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#pragma once
#include <program.hpp>
#include <traits.hpp>
#include <string>
#include <mutex>
#include <dispatch.hpp>
#include <Param.hpp>
#include <debug_opencl.hpp>
#include <boost/compute/core.hpp>
#include <boost/compute/algorithm/stable_sort.hpp>
#include <boost/compute/functional/operator.hpp>
#include <boost/compute/iterator/buffer_iterator.hpp>

namespace compute = boost::compute;

using cl::Buffer;
using cl::Program;
using cl::Kernel;
using cl::make_kernel;
using cl::EnqueueArgs;
using cl::NDRange;
using std::string;

namespace opencl
{
    namespace kernel
    {
        // Kernel Launch Config Values
        static const dim_type TX = 32;
        static const dim_type TY = 8;

        template<typename T, bool isAscending>
        void sort0(Param val)
        {
            try {
                compute::command_queue c_queue(getQueue()());

                compute::buffer val_buf((*val.data)());

                for(dim_type w = 0; w < val.info.dims[3]; w++) {
                    dim_type valW = w * val.info.strides[3];
                    for(dim_type z = 0; z < val.info.dims[2]; z++) {
                        dim_type valWZ = valW + z * val.info.strides[2];
                        for(dim_type y = 0; y < val.info.dims[1]; y++) {

                            dim_type valOffset = valWZ + y * val.info.strides[1];

                            if(isAscending) {
                                compute::stable_sort(
                                        compute::make_buffer_iterator<T>(val_buf, valOffset),
                                        compute::make_buffer_iterator<T>(val_buf, valOffset + val.info.dims[0]),
                                        compute::less<T>(), c_queue);
                            } else {
                                compute::stable_sort(
                                        compute::make_buffer_iterator<T>(val_buf, valOffset),
                                        compute::make_buffer_iterator<T>(val_buf, valOffset + val.info.dims[0]),
                                        compute::greater<T>(), c_queue);
                            }
                        }
                    }
                }

                CL_DEBUG_FINISH(getQueue());
            } catch (cl::Error err) {
                CL_TO_AF_ERROR(err);
                throw;
            }
        }
    }
}


#define BOOST_TEST_MODULE VectorView
#include <valarray>
#include <boost/test/unit_test.hpp>
#include <vexcl/vector.hpp>
#include <vexcl/vector_view.hpp>
#include <vexcl/element_index.hpp>
#include <vexcl/temporary.hpp>
#include <vexcl/reductor.hpp>
#include <vexcl/function.hpp>
#include "context_setup.hpp"

BOOST_AUTO_TEST_CASE(vector_view_1d)
{
    const size_t N = 1024;

    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    std::vector<double> x = random_vector<double>(2 * N);
    vex::vector<double> X(queue, x);
    vex::vector<double> Y(queue, N);

    size_t size   = N;
    size_t stride = 2;

    vex::gslice<1> slice(0, &size, &stride);

    Y = slice(X);
    check_sample(Y, [&](size_t idx, double v) { BOOST_CHECK(v == x[idx * 2]); });

    Y = slice(X * X);
    check_sample(Y, [&](size_t idx, double v) { BOOST_CHECK(v == x[idx * 2] * x[idx * 2]); });
}

BOOST_AUTO_TEST_CASE(vector_view_2)
{
    const size_t N = 32;

    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    std::valarray<double> x(N * N);
    std::iota(&x[0], &x[N * N], 0);

    // Select every even point from sub-block [(2,4) - (10,10)]:
    size_t start    = 2 * N + 4;
    size_t size[]   = {5, 4};
    size_t stride[] = {2 * N, 2};

    std::gslice std_slice(start, std::valarray<size_t>(size, 2), std::valarray<size_t>(stride, 2));

    std::valarray<double> y = x[std_slice];

    vex::vector<double> X(queue, N * N, &x[0]);
    vex::vector<double> Y(queue, size[0] * size[1]);

    vex::gslice<2> vex_slice(start, size, stride);

    Y = vex_slice(X);

    check_sample(Y, [&](size_t idx, double v) { BOOST_CHECK_EQUAL(v, y[idx]); });
}

BOOST_AUTO_TEST_CASE(vector_slicer_2d)
{
    using vex::range;
    using vex::_;

    const size_t N = 32;

    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    std::valarray<double> x(N * N);
    std::iota(&x[0], &x[N * N], 0);

    // Select every even point from sub-block [(2,4) - (10,10)]:
    size_t start    = 2 * N + 4;
    size_t size[]   = {5, 4};
    size_t stride[] = {2 * N, 2};

    std::gslice std_slice(start, std::valarray<size_t>(size, 2), std::valarray<size_t>(stride, 2));
    std::valarray<double> y = x[std_slice];

    vex::vector<double> X(queue, N * N, &x[0]);
    vex::vector<double> Y(queue, size[0] * size[1]);
    vex::vector<double> Z(queue, N);

    size_t dim[2] = {N, N};

    vex::slicer<2> slicer(dim);

    auto slice = slicer[range(2, 2, 11)][range(4, 2, 11)];

    Y = slice(X);

    check_sample(Y, [&](size_t idx, double v) { BOOST_CHECK_EQUAL(v, y[idx]); });

    Z = slicer[5](X); // Put fith row of X into Z;

    check_sample(Z, [&](size_t idx, double v) { BOOST_CHECK_EQUAL(v, x[5 * N + idx]); });

    Z = slicer[_][5](X); // Puth fith column of X into Z;

    check_sample(Z, [&](size_t idx, double v) { BOOST_CHECK_EQUAL(v, x[5 + N * idx]); });
}

BOOST_AUTO_TEST_CASE(negative_stride)
{
    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    float v[] = {
        0, 5,
        1, 4,
        2, 3,
        3, 2,
        4, 1,
        5, 0,
    };

    const size_t rows = 6;
    const size_t cols = 2;

    vex::vector<float> x(queue, rows * cols, v);
    vex::vector<float> z(queue, rows / 2 * cols);

    vex::slicer<2> slice(vex::extents[rows][cols]);
    z = slice[vex::range(5, -2, 0)](x);

    for(size_t i = 0; i < rows/2; ++i)
        for(size_t j = 0; j < cols; ++j)
            BOOST_CHECK_EQUAL(static_cast<float>(z[i * cols + j]), v[(rows - i * 2 - 1) * cols + j]);
}

BOOST_AUTO_TEST_CASE(vector_permutation)
{
    const size_t N = 1024;

    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    std::vector<double> x = random_vector<double>(N);
    vex::vector<double> X(queue, x);
    vex::vector<double> Y(queue, N);

    {
        vex::vector<size_t> I(queue, N);
        I = N - 1 - vex::element_index();
        auto reverse = vex::permutation(I);

        Y = reverse(X);
        check_sample(Y, [&](size_t idx, double v) { BOOST_CHECK_EQUAL(v, x[N - 1 - idx]); });

        Y = reverse(X * X);
        check_sample(Y, [&](size_t idx, double v) {
                double t = x[N - 1 - idx];
                BOOST_CHECK_EQUAL(v, t * t);
                });
    }

    Y = 0;

    {
        auto reverse = vex::permutation(N - 1 - vex::element_index(0, N));

        Y = reverse(X);
        check_sample(Y, [&](size_t idx, double v) { BOOST_CHECK_EQUAL(v, x[N - 1 - idx]); });

        Y = 0;

        reverse(Y) = X;
        check_sample(Y, [&](size_t idx, double v) { BOOST_CHECK_EQUAL(v, x[N - 1 - idx]); });
    }

    Y = 0;

    {
        auto i = vex::make_temp<1>( vex::element_index() + 1);
        Y = vex::permutation( N - i )(X);

        check_sample(Y, [&](size_t idx, double v) { BOOST_CHECK_EQUAL(v, x[N - 1 - idx]); });
    }
}

BOOST_AUTO_TEST_CASE(reduce_slice)
{
    const size_t N = 1024;

    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    vex::vector<int> X(queue, N);
    vex::Reductor<int, vex::SUM> sum(queue);
    vex::slicer<1> slice(&N);

    X = 1;

    BOOST_CHECK_EQUAL(static_cast<int>(N / 2), sum( slice[vex::range(0, 2, N)](X) ));
}

BOOST_AUTO_TEST_CASE(assign_to_view) {
    using vex::range;
    using vex::_;

    const size_t m = 32;
    const size_t n = m * m;

    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    vex::vector<int> x(queue, n);
    vex::slicer<1> slicer1(vex::extents[n]);
    vex::slicer<2> slicer2(vex::extents[m][m]);

    x = 1;

    slicer1[range(1, 2, n)](x) = 2;

    check_sample(x, [&](size_t idx, int v) {
            BOOST_CHECK_EQUAL(v, static_cast<int>(idx % 2 + 1));
            });

    for(size_t i = 0; i < m; ++i)
        slicer2[_][i](x) = i;

    check_sample(x, [&](size_t idx, int v) {
            BOOST_CHECK_EQUAL(v, static_cast<int>(idx % m));
            });

    vex::tie(slicer2[1](x), slicer2[2](x)) = std::make_tuple(1, 2);

    for(size_t i = 0; i < m; ++i) {
        BOOST_CHECK_EQUAL(x[1 * m + i], 1);
        BOOST_CHECK_EQUAL(x[2 * m + i], 2);
    }

    vex::vector<size_t> I(queue, m);

    I = vex::element_index() * m;

    auto first_col = vex::permutation(I);

    first_col(x) = 42;

    for(size_t i = 0; i < m; ++i)
        BOOST_CHECK_EQUAL(x[i * m], 42);
}

BOOST_AUTO_TEST_CASE(slice_reductor_to_scalar)
{
    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    using vex::extents;

    vex::vector<int> x(queue, 32);
    vex::vector<int> y(queue, 1);

    x = 1;
    y = vex::reduce<vex::SUM>(extents[32], x, 0);
    BOOST_CHECK_EQUAL(y[0], 32);

    x = 2;
    y = vex::reduce<vex::SUM>(extents[4][8], x, extents[0][1]);
    BOOST_CHECK_EQUAL(y[0], 64);
}

BOOST_AUTO_TEST_CASE(slice_reductor_single_dim)
{
    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    using vex::extents;
    using vex::_;

    vex::vector<int> x(queue, 32 * 32);
    vex::vector<int> y(queue, 32);

    vex::slicer<2> slice(extents[32][32]);

    int isum = 0;
    int i2sum = 0;
    for(int i = 0; i < 32; ++i) {
        slice[i](x) = i;
        isum += i;
        i2sum += i * i;
    }

    y = vex::reduce<vex::SUM>(slice[_][_](x), 1);

    for(int i = 0; i < 32; ++i)
        BOOST_CHECK_EQUAL(y[i], i * 32);

    y = vex::reduce<vex::SUM>(slice[_][_](x), 0);

    for(size_t i = 0; i < 32; ++i)
        BOOST_CHECK_EQUAL(y[i], isum);

    auto t = vex::make_temp<1>(x);
    y = vex::reduce<vex::SUM>(slice[_][_], t * t, 1);

    for(int i = 0; i < 32; ++i)
        BOOST_CHECK_EQUAL(y[i], i * i * 32);

    y = vex::reduce<vex::SUM>(slice[_][_], t * t, 0);

    for(size_t i = 0; i < 32; ++i)
        BOOST_CHECK_EQUAL(y[i], i2sum);
}

BOOST_AUTO_TEST_CASE(slice_reductor_multi_dim)
{
    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    using vex::extents;
    using vex::_;

    vex::vector<int> x(queue, 32 * 32 * 32);
    vex::vector<int> y(queue, 32);

    vex::slicer<3> slice(extents[32][32][32]);

    x = 1;

    auto test = [&](size_t d1, size_t d2) {
        std::array<size_t,2> dim = {{d1, d2}};

        y = vex::reduce<vex::SUM>(slice[_][_][_](x), dim);

        check_sample(y, [&](size_t, int sum) { BOOST_CHECK_EQUAL(sum, 1024); });
    };

    test(0, 1);
    test(1, 2);
    test(0, 2);
}

BOOST_AUTO_TEST_CASE(nested_reduce)
{
    using vex::extents;
    using vex::_;

    const size_t n = 32;

    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    std::vector<double> X = random_vector<double>(n * n * n);

    vex::vector<double> x(queue, X);
    vex::vector<double> y(queue, n);

    vex::slicer<2> s2(extents[n][n]);
    vex::slicer<3> s3(extents[n][n][n]);

    y = vex::reduce<vex::MAX>( s2[_], vex::reduce<vex::SUM>(s3[_], sin(x), 2), 1 );

    check_sample(y, [&](size_t k, double Y) {
            double ms = -std::numeric_limits<double>::max();
            for(size_t j = 0, idx = k * n * n; j < n; ++j) {
                double sum = 0;
                for(size_t i = 0; i < n; ++i, ++idx) {
                    sum += sin(X[idx]);
                }
                ms = std::max(ms, sum);
            }
            BOOST_CHECK_CLOSE(ms, Y, 1e-8);
            });
}

BOOST_AUTO_TEST_CASE(reshape)
{
    auto dim_out = vex::make_array<size_t>(4, 2);
    auto dim_in  = vex::make_array<size_t>(1, 0);

    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    vex::vector<int> x(queue, std::accumulate(
                dim_out.begin(), dim_out.end(),
                static_cast<size_t>(1), std::multiplies<size_t>()
                ));

    x = vex::element_index();

    vex::vector<int> y = vex::reshape(
            x, dim_out, dim_in
            );

    check_sample(y, [&](size_t k, int v) {
            size_t i = k % dim_out[1];
            size_t j = k / dim_out[1];
            BOOST_CHECK_EQUAL(i, v / dim_out[0]);
            BOOST_CHECK_EQUAL(j, v % dim_out[0]);
            });
}

#if (VEXCL_CHECK_SIZES > 0)
BOOST_AUTO_TEST_CASE(check_slice_correctness)
{
    const size_t n = 32;

    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    vex::vector<int> x(queue, n);
    vex::vector<int> y(queue, n);

    vex::slicer<2> slicer(vex::make_array<size_t>(n, n));

    BOOST_CHECK_NO_THROW(y = slicer[0](x));
    BOOST_CHECK_THROW(y = slicer[1](x), std::runtime_error);
}
#endif

#if (VEXCL_CHECK_SIZES > 1)
BOOST_AUTO_TEST_CASE(check_perm_correctness)
{
    const size_t n = 32;

    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    vex::vector<int> x(queue, n);
    vex::vector<int> y(queue, n);

    BOOST_CHECK_NO_THROW(
            y = vex::permutation(vex::element_index(0, n))(x)
            );

    BOOST_CHECK_THROW(
            y = vex::permutation(vex::element_index(0, n + 1))(x),
            std::runtime_error
            );
}

BOOST_AUTO_TEST_CASE(check_zero_size_perm)
{
    std::vector<vex::command_queue> queue(1, ctx.queue(0));

    vex::vector<int> x(queue, 0);
    vex::vector<int> y(queue, 0);

    BOOST_CHECK_NO_THROW(
            y = vex::reshape(x,
                vex::make_array<size_t>(100, 4, 4, 0),
                vex::make_array<size_t>(0, 1, 2, 3)
                )
            );
}
#endif

BOOST_AUTO_TEST_SUITE_END()


/** currency_test.cc                                 -*- C++ -*-
    Eric Robert, 31 May 2013
    Copyright (c) 2013 Datacratic.  All rights reserved.

    Tests for currency code.

*/

#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK

#include "rtbkit/common/currency.h"

#include <boost/test/unit_test.hpp>
#include <iostream>

using namespace std;
using namespace RTBKIT;

BOOST_AUTO_TEST_CASE( currencyValues )
{
    // 1$
    auto a0 = USD(1);

    // should be a million u$
    auto a1 = MicroUSD(1000000);

    BOOST_CHECK_EQUAL(a0, a1);

    // 1$
    auto b0 = USD(1);

    // should be the same as 1000$ for a thousand
    auto b1 = USD_CPM(1000);

    BOOST_CHECK_EQUAL(b0, b1);

    // 1u$
    auto c0 = MicroUSD(1);

    // should be the same as 1000u$ for a thousand
    auto c1 = MicroUSD_CPM(1000);

    BOOST_CHECK_EQUAL(c0, c1);

    // 1$ CPM
    auto d0 = USD_CPM(1);

    // should be the same as a million u$ CPM
    auto d1 = MicroUSD_CPM(1000000);

    BOOST_CHECK_EQUAL(d0, d1);

    // and check conversion
    BOOST_CHECK_EQUAL(1, (double) USD(1));
    BOOST_CHECK_EQUAL(1, (double) USD_CPM(1));
    BOOST_CHECK_EQUAL(1, (int64_t) MicroUSD(1));

    // precision issue i.e. the value is rounded to the closed 1K
    BOOST_CHECK_EQUAL(1000, (int64_t) MicroUSD_CPM(1000));
}

static inline void test2(CurrencyPool)
{
}

BOOST_AUTO_TEST_CASE( currencyConversion)
{
    {
        USD_CPM price;
        double value = price;
        (void)value;
    }

    {
        MicroUSD_CPM price;
        int64_t value = price;
        (void)value;
    }

    {
        USD price;
        double value = price;
        (void)value;
    }

    {
        MicroUSD price;
        int64_t value = price;
        (void)value;
    }

    {
        USD price;
        test2(price);
    }
}


/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          http://www.mrpt.org/                          |
   |                                                                        |
   | Copyright (c) 2005-2018, Individual contributors, see AUTHORS file     |
   | See: http://www.mrpt.org/Authors - All rights reserved.                |
   | Released under BSD License. See details in http://www.mrpt.org/License |
   +------------------------------------------------------------------------+ */

/*---------------------------------------------------------------
	APPLICATION: Camera calibration GUI
	AUTHOR: Jose Luis Blanco, based on code from the OpenCV library.
  ---------------------------------------------------------------*/

#include "camera_calib_guiMain.h"
#include "CDlgCalibWizardOnline.h"
#include "CDlgPoseEst.h"

//(*InternalHeaders(camera_calib_guiDialog)
#include <wx/settings.h>
#include <wx/font.h>
#include <wx/intl.h>
#include <wx/string.h>
//*)

#include <wx/filedlg.h>
#include <wx/msgdlg.h>
#include <wx/progdlg.h>

#include <mrpt/gui/WxUtils.h>
#include <mrpt/system/filesystem.h>
#include <mrpt/opengl/CGridPlaneXY.h>
#include <mrpt/opengl/stock_objects.h>

#include <fstream>
#include <iostream>

#include <Eigen/Dense>
#include <mrpt/vision/pnp_algos.h>

using namespace mrpt;
using namespace mrpt::math;
using namespace mrpt::img;
using namespace mrpt::vision;
using namespace mrpt::gui;
using namespace std;

#include <mrpt/gui/CMyRedirector.h>
#include <mrpt/gui/about_box.h>

#define USE_EXTERNAL_STORAGE_IMGS 1

// VARIABLES  ================================

TCalibrationImageList lst_images;  // Here are all the images: file_name -> data
mrpt::img::TCamera camera_params;

// END VARIABLES  ============================

#include "imgs/icono_main.xpm"
#include "../wx-common/mrpt_logo.xpm"

// A custom Art provider for customizing the icons:
class MyArtProvider : public wxArtProvider
{
   protected:
	wxBitmap CreateBitmap(
		const wxArtID& id, const wxArtClient& client,
		const wxSize& size) override;
};

// CreateBitmap function
wxBitmap MyArtProvider::CreateBitmap(
	const wxArtID& id, const wxArtClient& client, const wxSize& size)
{
	if (id == wxART_MAKE_ART_ID(MAIN_ICON)) return wxBitmap(icono_main_xpm);
	if (id == wxART_MAKE_ART_ID(IMG_MRPT_LOGO)) return wxBitmap(mrpt_logo_xpm);

	// Any wxWidgets icons not implemented here
	// will be provided by the default art provider.
	return wxNullBitmap;
}

//(*IdInit(camera_calib_guiDialog)
const long camera_calib_guiDialog::ID_BUTTON8 = wxNewId();
const long camera_calib_guiDialog::ID_BUTTON1 = wxNewId();
const long camera_calib_guiDialog::ID_BUTTON2 = wxNewId();
const long camera_calib_guiDialog::ID_BUTTON9 = wxNewId();
const long camera_calib_guiDialog::ID_LISTBOX1 = wxNewId();
const long camera_calib_guiDialog::ID_STATICTEXT5 = wxNewId();
const long camera_calib_guiDialog::ID_CHOICE1 = wxNewId();
const long camera_calib_guiDialog::ID_STATICTEXT1 = wxNewId();
const long camera_calib_guiDialog::ID_SPINCTRL1 = wxNewId();
const long camera_calib_guiDialog::ID_STATICTEXT2 = wxNewId();
const long camera_calib_guiDialog::ID_SPINCTRL2 = wxNewId();
const long camera_calib_guiDialog::ID_RADIOBOX1 = wxNewId();
const long camera_calib_guiDialog::ID_STATICTEXT3 = wxNewId();
const long camera_calib_guiDialog::ID_TEXTCTRL1 = wxNewId();
const long camera_calib_guiDialog::ID_STATICTEXT6 = wxNewId();
const long camera_calib_guiDialog::ID_TEXTCTRL3 = wxNewId();
const long camera_calib_guiDialog::ID_CHECKBOX1 = wxNewId();
const long camera_calib_guiDialog::ID_TEXTCTRL2 = wxNewId();
const long camera_calib_guiDialog::ID_BUTTON3 = wxNewId();
const long camera_calib_guiDialog::ID_BUTTON6 = wxNewId();
const long camera_calib_guiDialog::ID_BUTTON7 = wxNewId();
const long camera_calib_guiDialog::ID_BUTTON5 = wxNewId();
const long camera_calib_guiDialog::ID_BUTTON4 = wxNewId();
const long camera_calib_guiDialog::ID_CUSTOM2 = wxNewId();
const long camera_calib_guiDialog::ID_SCROLLEDWINDOW2 = wxNewId();
const long camera_calib_guiDialog::ID_PANEL2 = wxNewId();
const long camera_calib_guiDialog::ID_CUSTOM1 = wxNewId();
const long camera_calib_guiDialog::ID_SCROLLEDWINDOW3 = wxNewId();
const long camera_calib_guiDialog::ID_PANEL3 = wxNewId();
const long camera_calib_guiDialog::ID_XY_GLCANVAS = wxNewId();
const long camera_calib_guiDialog::ID_PANEL1 = wxNewId();
const long camera_calib_guiDialog::ID_NOTEBOOK1 = wxNewId();
const long camera_calib_guiDialog::ID_BUTTON10 = wxNewId();
//*)

BEGIN_EVENT_TABLE(camera_calib_guiDialog, wxDialog)
//(*EventTable(camera_calib_guiDialog)
//*)
END_EVENT_TABLE()

camera_calib_guiDialog::camera_calib_guiDialog(wxWindow* parent, wxWindowID id)
{
// Load my custom icons:
#if wxCHECK_VERSION(2, 8, 0)
	wxArtProvider::Push(new MyArtProvider);
#else
	wxArtProvider::PushProvider(new MyArtProvider);
#endif

	//(*Initialize(camera_calib_guiDialog)
	wxStaticBoxSizer* StaticBoxSizer2;
	wxFlexGridSizer* FlexGridSizer4;
	wxFlexGridSizer* FlexGridSizer16;
	wxStaticBoxSizer* StaticBoxSizer4;
	wxFlexGridSizer* FlexGridSizer10;
	wxFlexGridSizer* FlexGridSizer3;
	wxFlexGridSizer* FlexGridSizer5;
	wxFlexGridSizer* FlexGridSizer9;
	wxFlexGridSizer* FlexGridSizer2;
	wxFlexGridSizer* FlexGridSizer7;
	wxStaticBoxSizer* StaticBoxSizer3;
	wxFlexGridSizer* FlexGridSizer15;
	wxFlexGridSizer* FlexGridSizer18;
	wxFlexGridSizer* FlexGridSizer8;
	wxFlexGridSizer* FlexGridSizer13;
	wxFlexGridSizer* FlexGridSizer12;
	wxFlexGridSizer* FlexGridSizer6;
	wxStaticBoxSizer* StaticBoxSizer1;
	wxFlexGridSizer* FlexGridSizer1;
	wxFlexGridSizer* FlexGridSizer17;
	wxStaticBoxSizer* StaticBoxSizer5;

	Create(
		parent, id, _("Camera calibration GUI - Part of the MRPT project"),
		wxDefaultPosition, wxDefaultSize,
		wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX, _T("id"));
	FlexGridSizer1 = new wxFlexGridSizer(1, 2, 0, 0);
	FlexGridSizer1->AddGrowableCol(1);
	FlexGridSizer1->AddGrowableRow(0);
	FlexGridSizer2 = new wxFlexGridSizer(3, 1, 0, 0);
	FlexGridSizer2->AddGrowableCol(0);
	FlexGridSizer2->AddGrowableRow(0);
	FlexGridSizer2->AddGrowableRow(2);
	StaticBoxSizer1 =
		new wxStaticBoxSizer(wxHORIZONTAL, this, _("List of images"));
	FlexGridSizer4 = new wxFlexGridSizer(2, 1, 0, 0);
	FlexGridSizer4->AddGrowableCol(0);
	FlexGridSizer4->AddGrowableRow(1);
	FlexGridSizer5 = new wxFlexGridSizer(0, 4, 0, 0);
	btnCaptureNow = new wxButton(
		this, ID_BUTTON8, _("Grab now..."), wxDefaultPosition, wxDefaultSize, 0,
		wxDefaultValidator, _T("ID_BUTTON8"));
	wxFont btnCaptureNowFont(
		wxDEFAULT, wxDEFAULT, wxFONTSTYLE_NORMAL, wxBOLD, false, wxEmptyString,
		wxFONTENCODING_DEFAULT);
	btnCaptureNow->SetFont(btnCaptureNowFont);
	FlexGridSizer5->Add(
		btnCaptureNow, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
	btnPoseEstimateNow = new wxButton(
		this, ID_BUTTON10, _("Pose Est. now..."), wxDefaultPosition,
		wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON10"));
	wxFont btnPoseEstimateNowFont(
		wxDEFAULT, wxDEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false,
		wxEmptyString, wxFONTENCODING_DEFAULT);
	btnPoseEstimateNow->SetFont(btnPoseEstimateNowFont);
	FlexGridSizer5->Add(
		btnPoseEstimateNow, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP,
		5);
	Button11 = new wxButton(
		this, ID_BUTTON1, _("Add image(s)..."), wxDefaultPosition,
		wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON1"));
	FlexGridSizer5->Add(
		Button11, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
	Button22 = new wxButton(
		this, ID_BUTTON2, _("Clear all"), wxDefaultPosition, wxDefaultSize, 0,
		wxDefaultValidator, _T("ID_BUTTON2"));
	FlexGridSizer5->Add(
		Button22, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
	btnSaveImages = new wxButton(
		this, ID_BUTTON9, _("Save all..."), wxDefaultPosition, wxDefaultSize, 0,
		wxDefaultValidator, _T("ID_BUTTON9"));
	btnSaveImages->Disable();
	FlexGridSizer5->Add(
		btnSaveImages, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
	FlexGridSizer4->Add(
		FlexGridSizer5, 1,
		wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 0);
	FlexGridSizer15 = new wxFlexGridSizer(1, 2, 0, 0);
	FlexGridSizer15->AddGrowableCol(0);
	FlexGridSizer15->AddGrowableRow(0);
	lbFiles = new wxListBox(
		this, ID_LISTBOX1, wxDefaultPosition, wxSize(294, 84), 0, nullptr,
		wxLB_ALWAYS_SB | wxVSCROLL | wxHSCROLL | wxALWAYS_SHOW_SB,
		wxDefaultValidator, _T("ID_LISTBOX1"));
	FlexGridSizer15->Add(
		lbFiles, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
	FlexGridSizer16 = new wxFlexGridSizer(0, 1, 0, 0);
	StaticText5 = new wxStaticText(
		this, ID_STATICTEXT5, _("Zoom:"), wxDefaultPosition, wxDefaultSize, 0,
		_T("ID_STATICTEXT5"));
	FlexGridSizer16->Add(
		StaticText5, 1,
		wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
	cbZoom = new wxChoice(
		this, ID_CHOICE1, wxDefaultPosition, wxDefaultSize, 0, nullptr, 0,
		wxDefaultValidator, _T("ID_CHOICE1"));
	cbZoom->Append(_("25%"));
	cbZoom->Append(_("50%"));
	cbZoom->Append(_("75%"));
	cbZoom->SetSelection(cbZoom->Append(_("100%")));
	cbZoom->Append(_("150%"));
	cbZoom->Append(_("200%"));
	cbZoom->Append(_("300%"));
	cbZoom->Append(_("400%"));
	cbZoom->Append(_("500%"));
	FlexGridSizer16->Add(
		cbZoom, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,
		5);
	FlexGridSizer15->Add(
		FlexGridSizer16, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	FlexGridSizer4->Add(
		FlexGridSizer15, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	StaticBoxSizer1->Add(
		FlexGridSizer4, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	FlexGridSizer2->Add(
		StaticBoxSizer1, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 2);
	StaticBoxSizer3 = new wxStaticBoxSizer(
		wxHORIZONTAL, this, _("Checkerboard detection parameters"));
	FlexGridSizer6 = new wxFlexGridSizer(2, 2, 0, 0);
	FlexGridSizer6->AddGrowableCol(0);
	FlexGridSizer6->AddGrowableCol(1);
	StaticBoxSizer4 = new wxStaticBoxSizer(
		wxHORIZONTAL, this, _("Number of inner corners: "));
	FlexGridSizer17 = new wxFlexGridSizer(1, 4, 0, 0);
	StaticText1 = new wxStaticText(
		this, ID_STATICTEXT1, _("In X:"), wxDefaultPosition, wxDefaultSize, 0,
		_T("ID_STATICTEXT1"));
	FlexGridSizer17->Add(
		StaticText1, 1,
		wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
	edSizeX = new wxSpinCtrl(
		this, ID_SPINCTRL1, _T("9"), wxDefaultPosition, wxSize(50, -1), 0, 1,
		200, 5, _T("ID_SPINCTRL1"));
	edSizeX->SetValue(_T("9"));
	FlexGridSizer17->Add(
		edSizeX, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,
		5);
	StaticText2 = new wxStaticText(
		this, ID_STATICTEXT2, _("In Y:"), wxDefaultPosition, wxDefaultSize, 0,
		_T("ID_STATICTEXT2"));
	FlexGridSizer17->Add(
		StaticText2, 1,
		wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
	edSizeY = new wxSpinCtrl(
		this, ID_SPINCTRL2, _T("6"), wxDefaultPosition, wxSize(50, -1), 0, 1,
		200, 8, _T("ID_SPINCTRL2"));
	edSizeY->SetValue(_T("6"));
	FlexGridSizer17->Add(
		edSizeY, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,
		5);
	StaticBoxSizer4->Add(
		FlexGridSizer17, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	FlexGridSizer6->Add(
		StaticBoxSizer4, 1, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
	wxString __wxRadioBoxChoices_1[2] = {_("OpenCV\'s default"),
										 _("Scaramuzza et al.\'s")};
	rbMethod = new wxRadioBox(
		this, ID_RADIOBOX1, _(" Detector method: "), wxDefaultPosition,
		wxDefaultSize, 2, __wxRadioBoxChoices_1, 1, 0, wxDefaultValidator,
		_T("ID_RADIOBOX1"));
	FlexGridSizer6->Add(
		rbMethod, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 2);
	StaticBoxSizer5 =
		new wxStaticBoxSizer(wxHORIZONTAL, this, _(" Size of quads (in mm): "));
	FlexGridSizer18 = new wxFlexGridSizer(1, 4, 0, 0);
	StaticText3 = new wxStaticText(
		this, ID_STATICTEXT3, _("In X:"), wxDefaultPosition, wxDefaultSize, 0,
		_T("ID_STATICTEXT3"));
	FlexGridSizer18->Add(
		StaticText3, 1,
		wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
	edLengthX = new wxTextCtrl(
		this, ID_TEXTCTRL1, _("25.0"), wxDefaultPosition, wxSize(40, -1), 0,
		wxDefaultValidator, _T("ID_TEXTCTRL1"));
	FlexGridSizer18->Add(
		edLengthX, 1,
		wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
	StaticText6 = new wxStaticText(
		this, ID_STATICTEXT6, _("In Y:"), wxDefaultPosition, wxDefaultSize, 0,
		_T("ID_STATICTEXT6"));
	FlexGridSizer18->Add(
		StaticText6, 1,
		wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
	edLengthY = new wxTextCtrl(
		this, ID_TEXTCTRL3, _("25.0"), wxDefaultPosition, wxSize(40, -1), 0,
		wxDefaultValidator, _T("ID_TEXTCTRL3"));
	FlexGridSizer18->Add(
		edLengthY, 1,
		wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
	StaticBoxSizer5->Add(
		FlexGridSizer18, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	FlexGridSizer6->Add(
		StaticBoxSizer5, 1, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 2);
	cbNormalize = new wxCheckBox(
		this, ID_CHECKBOX1, _("Normalize image"), wxDefaultPosition,
		wxDefaultSize, 0, wxDefaultValidator, _T("ID_CHECKBOX1"));
	cbNormalize->SetValue(true);
	FlexGridSizer6->Add(
		cbNormalize, 1,
		wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5);
	StaticBoxSizer3->Add(
		FlexGridSizer6, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	FlexGridSizer2->Add(
		StaticBoxSizer3, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 2);
	StaticBoxSizer2 =
		new wxStaticBoxSizer(wxHORIZONTAL, this, _("Calibration"));
	FlexGridSizer7 = new wxFlexGridSizer(2, 1, 0, 0);
	FlexGridSizer7->AddGrowableCol(0);
	FlexGridSizer7->AddGrowableRow(0);
	FlexGridSizer9 = new wxFlexGridSizer(1, 1, 0, 0);
	FlexGridSizer9->AddGrowableCol(0);
	FlexGridSizer9->AddGrowableRow(0);
	txtLog = new wxTextCtrl(
		this, ID_TEXTCTRL2, _("(Calibration results)"), wxDefaultPosition,
		wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxHSCROLL | wxVSCROLL,
		wxDefaultValidator, _T("ID_TEXTCTRL2"));
	wxFont txtLogFont = wxSystemSettings::GetFont(wxSYS_OEM_FIXED_FONT);
	if (!txtLogFont.Ok())
		txtLogFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
	txtLogFont.SetPointSize(9);
	txtLog->SetFont(txtLogFont);
	FlexGridSizer9->Add(
		txtLog, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
	FlexGridSizer7->Add(
		FlexGridSizer9, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	FlexGridSizer8 = new wxFlexGridSizer(2, 3, 0, 0);
	FlexGridSizer8->AddGrowableCol(0);
	FlexGridSizer8->AddGrowableCol(1);
	btnRunCalib = new wxButton(
		this, ID_BUTTON3, _("Calibrate"), wxDefaultPosition, wxDefaultSize, 0,
		wxDefaultValidator, _T("ID_BUTTON3"));
	btnRunCalib->SetDefault();
	wxFont btnRunCalibFont(
		wxDEFAULT, wxDEFAULT, wxFONTSTYLE_NORMAL, wxBOLD, false, wxEmptyString,
		wxFONTENCODING_DEFAULT);
	btnRunCalib->SetFont(btnRunCalibFont);
	FlexGridSizer8->Add(
		btnRunCalib, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
	btnSave = new wxButton(
		this, ID_BUTTON6, _("Save matrices..."), wxDefaultPosition,
		wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON6"));
	FlexGridSizer8->Add(
		btnSave, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
	FlexGridSizer8->Add(
		-1, -1, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,
		5);
	btnManualRect = new wxButton(
		this, ID_BUTTON7, _("Manual params..."), wxDefaultPosition,
		wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON7"));
	FlexGridSizer8->Add(
		btnManualRect, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
	btnAbout = new wxButton(
		this, ID_BUTTON5, _("About"), wxDefaultPosition, wxDefaultSize, 0,
		wxDefaultValidator, _T("ID_BUTTON5"));
	FlexGridSizer8->Add(
		btnAbout, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
	btnClose = new wxButton(
		this, ID_BUTTON4, _("Quit"), wxDefaultPosition, wxDefaultSize, 0,
		wxDefaultValidator, _T("ID_BUTTON4"));
	FlexGridSizer8->Add(
		btnClose, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
	FlexGridSizer7->Add(
		FlexGridSizer8, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	StaticBoxSizer2->Add(
		FlexGridSizer7, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	FlexGridSizer2->Add(
		StaticBoxSizer2, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 2);
	FlexGridSizer1->Add(
		FlexGridSizer2, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	FlexGridSizer3 = new wxFlexGridSizer(1, 1, 0, 0);
	FlexGridSizer3->AddGrowableCol(0);
	FlexGridSizer3->AddGrowableRow(0);
	Notebook1 = new wxNotebook(
		this, ID_NOTEBOOK1, wxDefaultPosition, wxSize(719, 570), 0,
		_T("ID_NOTEBOOK1"));
	Panel2 = new wxPanel(
		Notebook1, ID_PANEL2, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL,
		_T("ID_PANEL2"));
	FlexGridSizer13 = new wxFlexGridSizer(1, 1, 0, 0);
	FlexGridSizer13->AddGrowableCol(0);
	FlexGridSizer13->AddGrowableRow(0);
	ScrolledWindow2 = new wxScrolledWindow(
		Panel2, ID_SCROLLEDWINDOW2, wxDefaultPosition, wxDefaultSize,
		wxHSCROLL | wxVSCROLL, _T("ID_SCROLLEDWINDOW2"));
	FlexGridSizer11 = new wxFlexGridSizer(0, 1, 0, 0);
	FlexGridSizer11->AddGrowableCol(0);
	FlexGridSizer11->AddGrowableRow(0);
	bmpOriginal = new mrpt::gui::wxMRPTImageControl(
		ScrolledWindow2, ID_CUSTOM2, wxDefaultPosition.x, wxDefaultPosition.y,
		wxSize(640, 480).GetWidth(), wxSize(640, 480).GetHeight());
	FlexGridSizer11->Add(bmpOriginal, 1, wxALL | wxALIGN_LEFT | wxALIGN_TOP, 0);
	ScrolledWindow2->SetSizer(FlexGridSizer11);
	FlexGridSizer11->Fit(ScrolledWindow2);
	FlexGridSizer11->SetSizeHints(ScrolledWindow2);
	FlexGridSizer13->Add(
		ScrolledWindow2, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	Panel2->SetSizer(FlexGridSizer13);
	FlexGridSizer13->Fit(Panel2);
	FlexGridSizer13->SetSizeHints(Panel2);
	Panel3 = new wxPanel(
		Notebook1, ID_PANEL3, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL,
		_T("ID_PANEL3"));
	FlexGridSizer10 = new wxFlexGridSizer(1, 1, 0, 0);
	FlexGridSizer10->AddGrowableCol(0);
	FlexGridSizer10->AddGrowableRow(0);
	ScrolledWindow3 = new wxScrolledWindow(
		Panel3, ID_SCROLLEDWINDOW3, wxDefaultPosition, wxDefaultSize,
		wxHSCROLL | wxVSCROLL, _T("ID_SCROLLEDWINDOW3"));
	FlexGridSizer14 = new wxFlexGridSizer(1, 1, 0, 0);
	FlexGridSizer14->AddGrowableCol(0);
	FlexGridSizer14->AddGrowableRow(0);
	bmpRectified = new mrpt::gui::wxMRPTImageControl(
		ScrolledWindow3, ID_CUSTOM1, wxDefaultPosition.x, wxDefaultPosition.y,
		wxSize(640, 480).GetWidth(), wxSize(640, 480).GetHeight());
	FlexGridSizer14->Add(
		bmpRectified, 1, wxALL | wxALIGN_LEFT | wxALIGN_TOP, 0);
	ScrolledWindow3->SetSizer(FlexGridSizer14);
	FlexGridSizer14->Fit(ScrolledWindow3);
	FlexGridSizer14->SetSizeHints(ScrolledWindow3);
	FlexGridSizer10->Add(
		ScrolledWindow3, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	Panel3->SetSizer(FlexGridSizer10);
	FlexGridSizer10->Fit(Panel3);
	FlexGridSizer10->SetSizeHints(Panel3);
	Panel1 = new wxPanel(
		Notebook1, ID_PANEL1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL,
		_T("ID_PANEL1"));
	FlexGridSizer12 = new wxFlexGridSizer(1, 1, 0, 0);
	FlexGridSizer12->AddGrowableCol(0);
	FlexGridSizer12->AddGrowableRow(0);
	m_3Dview = new CMyGLCanvas(
		Panel1, ID_XY_GLCANVAS, wxDefaultPosition, wxSize(-1, 300),
		wxTAB_TRAVERSAL, _T("ID_XY_GLCANVAS"));
	FlexGridSizer12->Add(
		m_3Dview, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	Panel1->SetSizer(FlexGridSizer12);
	FlexGridSizer12->Fit(Panel1);
	FlexGridSizer12->SetSizeHints(Panel1);
	Notebook1->AddPage(Panel2, _("Original Image"), false);
	Notebook1->AddPage(
		Panel3, _("Rectified image and reprojected points"), true);
	Notebook1->AddPage(Panel1, _("3D view"), false);
	FlexGridSizer3->Add(
		Notebook1, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 2);
	FlexGridSizer1->Add(
		FlexGridSizer3, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 0);
	SetSizer(FlexGridSizer1);
	FlexGridSizer1->Fit(this);
	FlexGridSizer1->SetSizeHints(this);

	Connect(
		ID_BUTTON8, wxEVT_COMMAND_BUTTON_CLICKED,
		(wxObjectEventFunction)&camera_calib_guiDialog::OnbtnCaptureNowClick);
	Connect(
		ID_BUTTON1, wxEVT_COMMAND_BUTTON_CLICKED,
		(wxObjectEventFunction)&camera_calib_guiDialog::OnAddImage);
	Connect(
		ID_BUTTON2, wxEVT_COMMAND_BUTTON_CLICKED,
		(wxObjectEventFunction)&camera_calib_guiDialog::OnListClear);
	Connect(
		ID_BUTTON9, wxEVT_COMMAND_BUTTON_CLICKED,
		(wxObjectEventFunction)&camera_calib_guiDialog::OnbtnSaveImagesClick);
	Connect(
		ID_LISTBOX1, wxEVT_COMMAND_LISTBOX_SELECTED,
		(wxObjectEventFunction)&camera_calib_guiDialog::OnlbFilesSelect);
	Connect(
		ID_CHOICE1, wxEVT_COMMAND_CHOICE_SELECTED,
		(wxObjectEventFunction)&camera_calib_guiDialog::OncbZoomSelect);
	Connect(
		ID_BUTTON3, wxEVT_COMMAND_BUTTON_CLICKED,
		(wxObjectEventFunction)&camera_calib_guiDialog::OnbtnRunCalibClick);
	Connect(
		ID_BUTTON6, wxEVT_COMMAND_BUTTON_CLICKED,
		(wxObjectEventFunction)&camera_calib_guiDialog::OnbtnSaveClick);
	Connect(
		ID_BUTTON7, wxEVT_COMMAND_BUTTON_CLICKED,
		(wxObjectEventFunction)&camera_calib_guiDialog::OnbtnManualRectClick);
	Connect(
		ID_BUTTON5, wxEVT_COMMAND_BUTTON_CLICKED,
		(wxObjectEventFunction)&camera_calib_guiDialog::OnbtnAboutClick);
	Connect(
		ID_BUTTON4, wxEVT_COMMAND_BUTTON_CLICKED,
		(wxObjectEventFunction)&camera_calib_guiDialog::OnbtnCloseClick);
	Connect(
		ID_BUTTON10, wxEVT_COMMAND_BUTTON_CLICKED,
		(wxObjectEventFunction)&camera_calib_guiDialog::
			OnbtnPoseEstimateNowClick);
	//*)

	camera_params.intrinsicParams(0, 0) = 0;  // Indicate calib didn't run yet.

	wxIcon icon;
	icon.CopyFromBitmap(wxBitmap(wxImage(icono_main_xpm)));
	this->SetIcon(icon);

	this->show3Dview();  // Empty 3D scene

	Center();
	this->SetTitle(format(
					   "Camera calibration %s - Part of the MRPT project",
					   CAMERA_CALIB_GUI_VERSION)
					   .c_str());
	Maximize();
}

camera_calib_guiDialog::~camera_calib_guiDialog()
{
	//(*Destroy(camera_calib_guiDialog)
	//*)
	this->clearListImages();
}

// Ask the user for new files to add to the list:
void camera_calib_guiDialog::OnAddImage(wxCommandEvent& event)
{
	try
	{
		wxFileDialog dlg(
			this, _("Select image(s) to open"), _("."), _(""),
			_("Image files (*.bmp;*.png;*.jpg)|*.bmp;*.png;*.jpg|All files "
			  "(*.*)|*.*"),
			wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE | wxFD_PREVIEW);

		if (wxID_OK != dlg.ShowModal()) return;

		wxBusyCursor waitcur;

		wxArrayString files;
		dlg.GetPaths(files);

		wxProgressDialog progDia(
			wxT("Adding image files"), wxT("Processing..."),
			files.Count(),  // range
			this,  // parent
			wxPD_CAN_ABORT | wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_AUTO_HIDE |
				wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME);

		wxTheApp->Yield();  // Let the app. process messages

		int counter_loops = 0;

		for (unsigned int i = 0; i < files.Count(); i++)
		{
			if (counter_loops++ % 5 == 0)
			{
				if (!progDia.Update(i)) break;
				wxTheApp->Yield();  // Let the app. process messages
			}

			const string fil = string(files[i].mb_str());

			TImageCalibData dat;

#if USE_EXTERNAL_STORAGE_IMGS
			// Optimization: Use external storage:
			// ---------------------------------------
			// string tmp_check     = mrpt::system::getTempFileName()+".jpg";
			// string tmp_rectified = mrpt::system::getTempFileName()+".jpg";
			// dat.img_original.saveToFile(tmp_check);
			// dat.img_original.saveToFile(tmp_rectified);

			// mark all imgs. as external storage:
			dat.img_original.setExternalStorage(fil);
			// dat.img_checkboard.setExternalStorage(tmp_check);
			// dat.img_rectified.setExternalStorage(tmp_rectified);

			dat.img_original.unload();
// dat.img_checkboard.unload();
// dat.img_rectified.unload();
#else
			// All in memory:
			if (!dat.img_original.loadFromFile(fil))
			{
				wxMessageBox(
					format("Error loading file: %s", fil.c_str()).c_str()),
					_("Error");
				this->updateListOfImages();
				return;
			}

#endif

			lst_images[fil] = dat;
		}

		this->updateListOfImages();
	}
	catch (const std::exception& e)
	{
		wxMessageBox(
			mrpt::exception_to_str(e), _("Error"), wxICON_INFORMATION, this);
	}
}

void camera_calib_guiDialog::clearListImages() { lst_images.clear(); }
// Clear list of images.
void camera_calib_guiDialog::OnListClear(wxCommandEvent& event)
{
	this->clearListImages();
	this->updateListOfImages();
}

void camera_calib_guiDialog::OnbtnRunCalibClick(wxCommandEvent& event)
{
	try
	{
		txtLog->Clear();

		CMyRedirector redire(txtLog, true, 10);

		const unsigned int check_size_x = edSizeX->GetValue();
		const unsigned int check_size_y = edSizeY->GetValue();
		const double check_squares_length_X_meters =
			0.001 * atof(string(edLengthX->GetValue().mb_str()).c_str());
		const double check_squares_length_Y_meters =
			0.001 * atof(string(edLengthY->GetValue().mb_str()).c_str());

		const bool normalize_image = cbNormalize->GetValue();

		const bool useScaramuzzaAlternativeDetector =
			rbMethod->GetSelection() == 1;

		wxBusyCursor waitcur;

		bool res = mrpt::vision::checkerBoardCameraCalibration(
			lst_images, check_size_x, check_size_y,
			check_squares_length_X_meters, check_squares_length_Y_meters,
			camera_params, normalize_image, nullptr /* MSE */,
			false /* skip draw */, useScaramuzzaAlternativeDetector);

		refreshDisplayedImage();

		if (!res)
			wxMessageBox(
				_("Calibration finished with error: Please check the text log "
				  "to see what's wrong"),
				_("Error"));

		if (res) show3Dview();
	}
	catch (const std::exception& e)
	{
		wxMessageBox(
			mrpt::exception_to_str(e), _("Error"), wxICON_INFORMATION, this);
	}
}

void camera_calib_guiDialog::OnbtnCloseClick(wxCommandEvent&) { Close(); }
void camera_calib_guiDialog::OnbtnAboutClick(wxCommandEvent&)
{
	mrpt::gui::show_mrpt_about_box_wxWidgets(this, "camera-calib");
}

// save matrices:
void camera_calib_guiDialog::OnbtnSaveClick(wxCommandEvent& event)
{
	if (camera_params.intrinsicParams(0, 0) == 0)
	{
		wxMessageBox(_("Run the calibration first"), _("Error"));
		return;
	}

	{
		wxFileDialog dlg(
			this, _("Save intrinsic parameters matrix"), _("."),
			_("intrinsic_matrix.txt"),
			_("Text files (*.txt)|*.txt|All files (*.*)|*.*"),
			wxFD_SAVE | wxFD_OVERWRITE_PROMPT);

		if (wxID_OK != dlg.ShowModal()) return;

		camera_params.intrinsicParams.saveToTextFile(
			string(dlg.GetPath().mb_str()));
	}

	{
		wxFileDialog dlg(
			this, _("Save distortion parameters"), _("."),
			_("distortion_matrix.txt"),
			_("Text files (*.txt)|*.txt|All files (*.*)|*.*"),
			wxFD_SAVE | wxFD_OVERWRITE_PROMPT);

		if (wxID_OK != dlg.ShowModal()) return;

		CMatrixDouble M(1, 5);
		for (unsigned i = 0; i < 5; i++) M(0, i) = camera_params.dist[i];

		M.saveToTextFile(string(dlg.GetPath().mb_str()));
	}
}

// Update the listbox from lst_img_files
void camera_calib_guiDialog::updateListOfImages()
{
	lbFiles->Clear();
	for (auto s = lst_images.begin(); s != lst_images.end(); ++s)
		lbFiles->Append(s->first.c_str());

	btnSaveImages->Enable(!lst_images.empty());

	refreshDisplayedImage();
}

// Shows the image selected in the listbox:
void camera_calib_guiDialog::refreshDisplayedImage()
{
	try
	{
		if (!lbFiles->GetCount())
		{
			// No images:
			return;
		}

		// Assure there's one selected:
		if (lbFiles->GetSelection() == wxNOT_FOUND) lbFiles->SetSelection(0);

		const string selFile = string(lbFiles->GetStringSelection().mb_str());

		auto it = lst_images.find(selFile);
		if (it == lst_images.end()) return;

		// Zoom:
		const std::string strZoom =
			string(cbZoom->GetStringSelection().mb_str());
		const double zoomVal = 0.01 * atof(strZoom.c_str());

		ASSERT_(zoomVal > 0 && zoomVal < 30);

		TImageSize imgSizes(0, 0);

		// Generate the images on-the-fly:
		CImage imgOrgColor;
		it->second.img_original.colorImage(imgOrgColor);

		imgSizes = imgOrgColor.getSize();

		// Rectify:
		CImage imgRect;
		if (camera_params.intrinsicParams(0, 0) == 0)
		{
			// Not calibrated yet:
			imgRect = imgOrgColor;
			imgRect.scaleImage(
				imgRect, imgSizes.x * zoomVal, imgSizes.y * zoomVal,
				IMG_INTERP_NN);
		}
		else
		{
			imgOrgColor.undistort(imgRect, camera_params);
			imgRect.scaleImage(
				imgRect, imgSizes.x * zoomVal, imgSizes.y * zoomVal,
				IMG_INTERP_NN);

			// Draw reprojected:
			for (auto& k : it->second.projectedPoints_undistorted)
				imgRect.drawCircle(
					zoomVal * k.x, zoomVal * k.y, 4, TColor(0, 255, 64));

			imgRect.drawCircle(10, 10, 4, TColor(0, 255, 64));
			imgRect.textOut(18, 4, "Reprojected corners", TColor::white());
		}

		// Zoom images:
		imgOrgColor.scaleImage(
			imgOrgColor, imgSizes.x * zoomVal, imgSizes.y * zoomVal,
			IMG_INTERP_NN);

		imgSizes = imgOrgColor.getSize();

		CImage imgCheck = imgOrgColor;

		// Draw the board:
		for (unsigned int k = 0; k < it->second.detected_corners.size(); k++)
		{
			imgCheck.cross(
				it->second.detected_corners[k].x * zoomVal,
				it->second.detected_corners[k].y * zoomVal, TColor::blue(), '+',
				3);
			imgCheck.drawCircle(
				it->second.projectedPoints_distorted[k].x * zoomVal,
				it->second.projectedPoints_distorted[k].y * zoomVal, 4,
				TColor(0, 255, 64));
		}
		imgCheck.drawCircle(10, 10, 4, TColor(0, 255, 64));
		imgCheck.textOut(18, 4, "Reprojected corners", TColor::white());

		imgCheck.cross(10, 30, TColor::blue(), '+', 3);
		imgCheck.textOut(18, 24, "Detected corners", TColor::white());

		this->bmpOriginal->AssignImage(imgCheck);
		this->bmpRectified->AssignImage(imgRect);

		it->second.img_original.unload();

		// Plot:

		this->bmpOriginal->SetMinSize(wxSize(imgSizes.x, imgSizes.y));
		this->bmpOriginal->SetMaxSize(wxSize(imgSizes.x, imgSizes.y));
		this->bmpOriginal->SetSize(imgSizes.x, imgSizes.y);

		this->bmpRectified->SetMinSize(wxSize(imgSizes.x, imgSizes.y));
		this->bmpRectified->SetMaxSize(wxSize(imgSizes.x, imgSizes.y));
		this->bmpRectified->SetSize(imgSizes.x, imgSizes.y);

		this->FlexGridSizer11->RecalcSizes();
		this->FlexGridSizer14->RecalcSizes();

		// this->ScrolledWindow2->SetVirtualSize(wxSize(imgSizes.x,imgSizes.y));
		// this->ScrolledWindow3->SetVirtualSize(wxSize(imgSizes.x,imgSizes.y));
		this->ScrolledWindow2->SetScrollbars(1, 1, imgSizes.x, imgSizes.y);
		this->ScrolledWindow3->SetScrollbars(1, 1, imgSizes.x, imgSizes.y);

		this->bmpOriginal->Refresh(false);
		this->bmpRectified->Refresh(false);
	}
	catch (const std::exception& e)
	{
		wxMessageBox(
			mrpt::exception_to_str(e), _("Error"), wxICON_INFORMATION, this);
	}
}

void camera_calib_guiDialog::OnlbFilesSelect(wxCommandEvent& event)
{
	refreshDisplayedImage();
}

void camera_calib_guiDialog::show3Dview()
{
	mrpt::opengl::COpenGLScene::Ptr scene =
		mrpt::make_aligned_shared<mrpt::opengl::COpenGLScene>();

	const unsigned int check_size_x = edSizeX->GetValue();
	const unsigned int check_size_y = edSizeY->GetValue();
	const double check_squares_length_X_meters =
		0.001 * atof(string(edLengthX->GetValue().mb_str()).c_str());
	const double check_squares_length_Y_meters =
		0.001 * atof(string(edLengthY->GetValue().mb_str()).c_str());

	if (!check_squares_length_X_meters || !check_squares_length_Y_meters)
		return;

	opengl::CGridPlaneXY::Ptr grid =
		mrpt::make_aligned_shared<opengl::CGridPlaneXY>(
			0, check_size_x * check_squares_length_X_meters, 0,
			check_size_y * check_squares_length_Y_meters, 0,
			check_squares_length_X_meters);
	scene->insert(grid);

	for (auto& lst_image : lst_images)
	{
		if (!lst_image.second.detected_corners.empty())
		{
			mrpt::opengl::CSetOfObjects::Ptr cor =
				mrpt::opengl::stock_objects::CornerXYZ();
			cor->setName(mrpt::system::extractFileName(lst_image.first));
			cor->enableShowName(true);
			cor->setScale(0.1f);
			cor->setPose(lst_image.second.reconstructed_camera_pose);

			scene->insert(cor);
		}
	}

	// scene->insert( mrpt::opengl::stock_objects::CornerXYZ() );

	this->m_3Dview->setOpenGLSceneRef(scene);
	this->m_3Dview->Refresh();
}

// Enter calib. params manually:
void camera_calib_guiDialog::OnbtnManualRectClick(wxCommandEvent& event)
{
	wxMessageBox(
		_("Please, enter calibration parameters manually next to overpass "
		  "automatically obtained parameters."),
		_("Manual parameters"));

	wxString s;

	if (camera_params.intrinsicParams(0, 0) == 0)
	{
		wxMessageBox(_("Run the calibration first"), _("Error"));
		return;
	}

	s = wxGetTextFromUser(
		_("Focus length in X pixel size (fx):"), _("Manual parameters"),
		wxString::Format(wxT("%.07f"), camera_params.intrinsicParams(0, 0)),
		this);
	if (s.IsEmpty()) return;
	if (!s.ToDouble(&camera_params.intrinsicParams(0, 0)))
	{
		wxMessageBox(_("Invalid number"));
		return;
	}

	s = wxGetTextFromUser(
		_("Focus length in Y pixel size (fy):"), _("Manual parameters"),
		wxString::Format(wxT("%.07f"), camera_params.intrinsicParams(1, 1)),
		this);
	if (s.IsEmpty()) return;
	if (!s.ToDouble(&camera_params.intrinsicParams(1, 1)))
	{
		wxMessageBox(_("Invalid number"));
		return;
	}

	s = wxGetTextFromUser(
		_("Image center X (cx):"), _("Manual parameters"),
		wxString::Format(wxT("%.07f"), camera_params.intrinsicParams(0, 2)),
		this);
	if (s.IsEmpty()) return;
	if (!s.ToDouble(&camera_params.intrinsicParams(0, 2)))
	{
		wxMessageBox(_("Invalid number"));
		return;
	}

	s = wxGetTextFromUser(
		_("Image center Y (cy):"), _("Manual parameters"),
		wxString::Format(wxT("%.07f"), camera_params.intrinsicParams(1, 2)),
		this);
	if (s.IsEmpty()) return;
	if (!s.ToDouble(&camera_params.intrinsicParams(1, 2)))
	{
		wxMessageBox(_("Invalid number"));
		return;
	}

	s = wxGetTextFromUser(
		_("Distortion param p1:"), _("Manual parameters"),
		wxString::Format(wxT("%.07f"), camera_params.dist[0]), this);
	if (s.IsEmpty()) return;
	if (!s.ToDouble(&camera_params.dist[0]))
	{
		wxMessageBox(_("Invalid number"));
		return;
	}

	s = wxGetTextFromUser(
		_("Distortion param p2:"), _("Manual parameters"),
		wxString::Format(wxT("%.07f"), camera_params.dist[1]), this);
	if (s.IsEmpty()) return;
	if (!s.ToDouble(&camera_params.dist[1]))
	{
		wxMessageBox(_("Invalid number"));
		return;
	}

	s = wxGetTextFromUser(
		_("Distortion param k1:"), _("Manual parameters"),
		wxString::Format(wxT("%.07f"), camera_params.dist[2]), this);
	if (s.IsEmpty()) return;
	if (!s.ToDouble(&camera_params.dist[2]))
	{
		wxMessageBox(_("Invalid number"));
		return;
	}

	s = wxGetTextFromUser(
		_("Distortion param k2:"), _("Manual parameters"),
		wxString::Format(wxT("%.07f"), camera_params.dist[3]), this);
	if (s.IsEmpty()) return;
	if (!s.ToDouble(&camera_params.dist[3]))
	{
		wxMessageBox(_("Invalid number"));
		return;
	}

	refreshDisplayedImage();
}

void camera_calib_guiDialog::OnbtnCaptureNowClick(wxCommandEvent& event)
{
	CDlgCalibWizardOnline dlg(this);

	// Set pattern params:
	dlg.edLengthX->SetValue(this->edLengthX->GetValue());
	dlg.edLengthY->SetValue(this->edLengthY->GetValue());
	dlg.edSizeX->SetValue(this->edSizeX->GetValue());
	dlg.edSizeY->SetValue(this->edSizeY->GetValue());
	dlg.cbNormalize->SetValue(this->cbNormalize->GetValue());

	// Run:
	dlg.ShowModal();

	// Get params:
	this->edLengthX->SetValue(dlg.edLengthX->GetValue());
	this->edLengthY->SetValue(dlg.edLengthY->GetValue());
	this->edSizeX->SetValue(dlg.edSizeX->GetValue());
	this->edSizeY->SetValue(dlg.edSizeY->GetValue());
	this->cbNormalize->SetValue(dlg.cbNormalize->GetValue());

	// Get images:
	lst_images = dlg.m_calibFrames;
	this->updateListOfImages();
}

void camera_calib_guiDialog::OnbtnPoseEstimateNowClick(wxCommandEvent& event)
{
	// Compute pose using PnP Algorithms toolkit

	CDlgPoseEst dlg(this);

	// Set pattern params:
	dlg.edLengthX->SetValue(this->edLengthX->GetValue());
	dlg.edLengthY->SetValue(this->edLengthY->GetValue());
	dlg.edSizeX->SetValue(this->edSizeX->GetValue());
	dlg.edSizeY->SetValue(this->edSizeY->GetValue());
	dlg.cbNormalize->SetValue(this->cbNormalize->GetValue());

	// Run:
	dlg.ShowModal();

	// Get params:
	this->edLengthX->SetValue(dlg.edLengthX->GetValue());
	this->edLengthY->SetValue(dlg.edLengthY->GetValue());
	this->edSizeX->SetValue(dlg.edSizeX->GetValue());
	this->edSizeY->SetValue(dlg.edSizeY->GetValue());
	this->cbNormalize->SetValue(dlg.cbNormalize->GetValue());

	// Get images:
	lst_images = dlg.m_calibFrames;
	this->updateListOfImages();
}

void camera_calib_guiDialog::OnbtnSaveImagesClick(wxCommandEvent& event)
{
	try
	{
		if (lst_images.empty()) return;

		wxDirDialog dlg(
			this, _("Select the directory where to save the images"), _("."));

		if (dlg.ShowModal() == wxID_OK)
		{
			string dir = string(dlg.GetPath().mb_str());

			for (auto& lst_image : lst_images)
				lst_image.second.img_original.saveToFile(
					dir + string("/") + lst_image.first + string(".png"));
		}
	}
	catch (const std::exception& e)
	{
		wxMessageBox(
			mrpt::exception_to_str(e), _("Error"), wxICON_INFORMATION, this);
	}
}

void camera_calib_guiDialog::OncbZoomSelect(wxCommandEvent& event)
{
	refreshDisplayedImage();
}