#include "myutils.h"

namespace ai_matrix
{
    const int TIME_DIFF = 28800; // 8 hour
    MyUtils *MyUtils::ins = nullptr;
    MyUtils::GarbageCollector MyUtils::gc;
    std::mutex MyUtils::mx;

    MyUtils *MyUtils::getins()
    {
        //双层锁，确保线程安全
        if (ins == nullptr)
        {
            std::lock_guard<std::mutex> guard(mx); //防止异常发生不能解锁
            if (ins == nullptr)
            {
                ins = new MyUtils();
            }
        }
        return ins;
    }

    float MyUtils::getMean(const std::vector<float> &data)
    {
        int size = data.size();

        if (size == 0)
        {
            return 0;
        }

        float sum = 0;
        for (int i = 0; i < size; i++)
        {
            sum += data[i];
        }
        return sum / size;
    }

    float MyUtils::getMax(const std::vector<float> &data)
    {
        int size = data.size();

        if (size == 0)
        {
            return 0;
        }

        float max = 0;
        for (int i = 0; i < size; i++)
        {
            if (i == 0)
            {
                max = data[i];
            }
            else if (data[i] > max)
            {
                max = data[i];
            }
        }
        return max;
    }

    float MyUtils::getMin(const std::vector<float> &data)
    {
        int size = data.size();

        if (size == 0)
        {
            return 0;
        }

        float min = 0;
        for (int i = 0; i < size; i++)
        {
            if (i == 0)
            {
                min = data[i];
            }
            else if (data[i] < min)
            {
                min = data[i];
            }
        }
        return min;
    }

    float MyUtils::getMedian(const std::vector<float> &data)
    {
        if (data.size() < 2)
        {
            return 0;
        }

        std::vector<float> data_tmp;

        int n = data.size();
        for (int i = 0; i < n; i++)
        {
            data_tmp.push_back(data[i]);
        }

        std::sort(data_tmp.begin(), data_tmp.end(), std::less<float>());

        if (n % 2 == 0)
        {
            return (data_tmp[n / 2] + data_tmp[n / 2 - 1]) / 2;
        }
        else
        {
            return data_tmp[(n - 1) / 2];
        }
    }

    std::string MyUtils::get_timestamp_file()
    {
        time_t timep = time(NULL);
        struct tm *p = localtime(&timep);

        struct timeval tv;
        gettimeofday(&tv, NULL);

        int msec = tv.tv_usec / 1000;

        char tmp[30] = {0};
        sprintf(tmp, "%04d-%02d-%02d-%02d-%02d-%02d-%03d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec, msec);

        return std::string(tmp);
    }

    std::string MyUtils::get_date()
    {
        time_t timep = time(NULL);
        struct tm *p = localtime(&timep);

        struct timeval tv;
        gettimeofday(&tv, NULL);

        int msec = tv.tv_usec / 1000;

        char tmp[12] = { 0 };
        sprintf(tmp, "%04d-%02d-%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday);

        return std::string(tmp);
    }

    std::string MyUtils::get_time()
    {
        time_t timep = time(NULL);
        struct tm *p = localtime(&timep);

        struct timeval tv;
        gettimeofday(&tv, NULL);

        int msec = tv.tv_usec / 1000;

        char tmp[10] = { 0 };
        sprintf(tmp, "%02d-%02d-%02d", p->tm_hour, p->tm_min, p->tm_sec);

        return std::string(tmp);
    }

    std::string MyUtils::get_timestamp_log()
    {
        time_t timep = time(NULL);
        struct tm *p = localtime(&timep);

        struct timeval tv;
        gettimeofday(&tv, NULL);

        int msec = tv.tv_usec / 1000;

        char tmp[30] = {0};
        sprintf(tmp, "%04d-%02d-%02d %02d:%02d:%02d.%03d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec, msec);

        return std::string(tmp);
    }

    std::string MyUtils::create_dir_name(std::string root, std::string name)
    {
        std::string dir_path = root + "/" + name;
        if (access(dir_path.c_str(), F_OK) != 0)
        {
            if (mkdir(dir_path.c_str(), 0755) != 0) //如果父目录不存在，会创建失败
            {
                perror("mkdir fail");
                return "";
            }
        }
        return dir_path;
    }

    std::string MyUtils::create_dir_date(std::string root)
    {
        time_t timep = time(NULL);
        struct tm *p = localtime(&timep);

        char tmp_date[20] = {0};
        sprintf(tmp_date, "%04d-%02d-%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday);

        std::string dir_path;

        dir_path = root + "/" + std::string(tmp_date); //创建日期目录
        if (access(dir_path.c_str(), F_OK) != 0)
        {
            if (mkdir(dir_path.c_str(), 0755) != 0) //如果父目录不存在，会创建失败
            {
                perror("mkdir fail");
                return "";
            }
        }

        return dir_path;
    }

    std::string MyUtils::create_dir_date_name_time(std::string root, std::string name)
    {
        time_t timep = time(NULL);
        struct tm *p = localtime(&timep);

        char tmp_date[20] = {0};
        sprintf(tmp_date, "%04d-%02d-%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday);

        char tmp_time[20] = {0};
        sprintf(tmp_time, "%02d-%02d-%02d", p->tm_hour, p->tm_min, p->tm_sec);

        std::string dir_path;

        dir_path = root + "/" + std::string(tmp_date); //创建日期目录
        if (access(dir_path.c_str(), F_OK) != 0)
        {
            if (mkdir(dir_path.c_str(), 0755) != 0) //如果父目录不存在，会创建失败
            {
                perror("mkdir fail");
                return "";
            }
        }

        dir_path = dir_path + "/" + name + "_" + std::string(tmp_time); //创建点云目录
        if (access(dir_path.c_str(), F_OK) != 0)
        {
            if (mkdir(dir_path.c_str(), 0755) != 0) //如果父目录不存在，会创建失败
            {
                perror("mkdir fail");
                return "";
            }
        }

        return dir_path;
    }

    std::string MyUtils::create_file_path(std::string root, std::string name, std::string suffix)
    {
        time_t timep = time(NULL);
        struct tm *p = localtime(&timep);

        char tmp_date[20] = {0};
        sprintf(tmp_date, "%04d-%02d-%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday);

        char tmp_time[20] = {0};
        sprintf(tmp_time, "%02d-%02d-%02d", p->tm_hour, p->tm_min, p->tm_sec);

        std::string file_path;

        file_path = root + "/" + std::string(tmp_date); //创建日期目录
        if (access(file_path.c_str(), F_OK) != 0)
        {
            if (mkdir(file_path.c_str(), 0755) != 0) //如果父目录不存在，会创建失败
            {
                perror("mkdir fail");
                return "";
            }
        }

        file_path = file_path + "/" + name + "_" + std::string(tmp_time) + suffix; //创建文件

        return file_path;
    }

    //字符串分割函数
    std::vector<std::string> MyUtils::split(std::string str, std::string pattern)
    {
        std::string::size_type pos;
        std::vector<std::string> result;
        str += pattern; //扩展字符串以方便操作
        int size = str.size();
        for (int i = 0; i < size; i++)
        {
            pos = str.find(pattern, i);
            if (pos < size)
            {
                std::string s = str.substr(i, pos - i);
                result.push_back(s);
                i = pos + pattern.size() - 1;
            }
        }
        return result;
    }
    std::string MyUtils::getStringFromFloat(float f)
    {
        std::ostringstream buffer;
        buffer << f;
        return buffer.str();
    }
    std::string MyUtils::getStringFromBool(bool b)
    {
        std::ostringstream buffer;
        buffer << b;
        return buffer.str();
    }

    /**
     * 拷贝文件
     * @param filePath 源文件位置
     * @param savePath 将要拷贝的新位置
     * @return
     */
    bool MyUtils::copyFile(std::string filePath, std::string savePath)
    {
        FILE *fp, *sp;
        fp = fopen(filePath.c_str(), "rb");
        sp = fopen(savePath.c_str(), "w+b");
        if (!fp || !sp)
        {
            LogError << "open fial filePath:" << filePath << " or savePath:" << savePath;
            return false;
        }
        void *buffer;
        while (!feof(fp))
        {
            fread(&buffer, 1, 1, fp);
            fwrite(&buffer, 1, 1, sp);
        }
        fclose(fp);
        fclose(sp);
        return true;
    }

    std::string& MyUtils::replace_all_distinct(std::string &str, const std::string &old_value, const std::string &new_value)
    {
        for (std::string::size_type pos(0); pos != std::string::npos; pos += new_value.length()) {
            if ((pos = str.find(old_value, pos)) != std::string::npos)
                str.replace(pos, old_value.length(), new_value);
            else break;
        }
        return str;
    }

    /**
     *  获取北京当前日期
     * inParam : N/A
     * outParam: N/A
     * return  : 日期
     */
    std::string MyUtils::GetDate()
    {
        struct timeval time = {0, 0};
        gettimeofday(&time, nullptr);
        time_t timep = time.tv_sec + TIME_DIFF;

        struct tm *p = gmtime(&timep);

        char szTmp[12] = {0};
        sprintf(szTmp, "%04d-%02d-%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday);

        return std::string(szTmp);
    }

    /**
     * 获取北京当前时间
     * inParam : N/A
     * outParam: N/A
     * return  : 时间
     */
    std::string MyUtils::GetTime()
    {
        struct timeval time = {0, 0};
        gettimeofday(&time, nullptr);
        time_t timep = time.tv_sec + TIME_DIFF;

        struct tm *p = gmtime(&timep);

        char szTmp[10] = {0};
        sprintf(szTmp, "%02d-%02d-%02d", p->tm_hour, p->tm_min, p->tm_sec);
        return std::string(szTmp);
    }

    //时间戳转化为时间 毫秒级
    std::string MyUtils::Stamp2Time(long long timestamp, bool has_msec)
    {
        int ms = timestamp % 1000;//取毫秒
        time_t tick = (time_t)(timestamp/1000);//转换时间
        struct tm tm;
        char s[40];
        tm = *localtime(&tick);
        strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", &tm);
        std::string str(s);
        if (has_msec)
        {
            str = str+ "." + std::to_string(ms);
        }
        return str;
    }

    /**
    * 获取当前时间距1970年的毫秒数
    * inParam : N/A
    * outParam: N/A
    * return  : 时间戳
    */
    uint64_t MyUtils::GetCurrentTimeMillis()
    {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        //printf("tv_sec:%ld, tv_usec:%ld\n", tv.tv_sec, tv.tv_usec);
        return tv.tv_sec * 1000 + tv.tv_usec / 1000;
    }

    /**
    * 获取指定时间距1970年的毫秒数 (入参格式：YYYY-MM-DD hh-mm-ss)
    * inParam : std::string &strDateTime    日期时间
    * outParam: N/A
    * return  : 时间戳
    */
    uint64_t MyUtils::GetParamTimeMilliSeconds(std::string &strDateTime)
    {
        LogDebug << "strDateTime:" << strDateTime;
        if (strDateTime.length() != 19)
        {
            return 0;
        }

        int iYear = atoi(strDateTime.substr(0, 4).c_str());
        int iMon = atoi(strDateTime.substr(5, 2).c_str());
        int iDay = atoi(strDateTime.substr(8, 2).c_str());
        int iHour = atoi(strDateTime.substr(11, 2).c_str());
        int iMin = atoi(strDateTime.substr(14, 2).c_str());
        int iSec = atoi(strDateTime.substr(17, 2).c_str());

        struct tm stm;
        memset(&stm, 0, sizeof(stm));
        stm.tm_year = iYear - 1900;
        stm.tm_mon = iMon - 1;
        stm.tm_mday = iDay;
        stm.tm_hour = iHour;
        stm.tm_min = iMin;
        stm.tm_sec = iSec;

        uint64_t i64Ret = (uint64_t)mktime(&stm) * 1000;
        LogDebug << iYear << " " << iMon << " " << iDay << " " << iHour << " " << iMin << " " << iSec << " " << i64Ret;
        return i64Ret;
    }

    /**
    * Anchor行分割
    * inParam : std::string &strLine                   Anchor一行内容
    *         : const std::set<char> &setDelimiters    分割符集合
    * outParam: N/A
    * return  : 分割数据
    */
    std::vector<float> MyUtils::SplitAnchor(std::string &strLine, const std::set<char> &setDelimiters)
    {
        std::vector<float> result;
        if (strLine.empty())
        {
            return result;
        }
        char const *pch = strLine.c_str();
        char const *start = pch;
        for (; *pch; ++pch)
        {
            if (setDelimiters.find(*pch) != setDelimiters.end())
            {
                if (start != pch)
                {
                    std::string tmp(start, pch);
                    result.push_back(atof(tmp.c_str())); //浮点数
                }
                start = pch + 1;
            }
        }
        result.push_back(atof(start));  //最后一个内容
        return result;
    }

    /**
    * 创建文件夹路径
    * inParam : std::string strDirPath   :文件夹路径
    * outParam: N/A
    * return  : true/false
    */
    bool MyUtils::CreateDirPath(std::string strDirPath)
    {
        if (strDirPath.back() != '/')
        {
            strDirPath += "/";
        }

        if (access(strDirPath.c_str(), F_OK) == 0)
        {
            return true;
        }

        std::string::size_type pos = strDirPath.find('/');
        while (pos != std::string::npos)
        {
            std::string strCur = strDirPath.substr(0, pos);
            if (!strCur.empty() && access(strCur.c_str(), F_OK) != 0)
            {
                if (mkdir(strCur.c_str(), 0755) != 0) //如果父目录不存在，会创建失败
                {
                    perror("mkdir fail");
                    return false;
                }

                if (chmod(strCur.c_str(), 0777) != 0)
                {
                    perror("chmod fail");
                }
            }
            pos = strDirPath.find('/', pos + 1);
        }
        return true;
    }

#ifdef ASCEND
    /**
    * 拷贝Device数据到Host
    * inParam : void *pDeviceBuffer                 device内存地址
              : uint32_t iBufferSize                device内存大小
    * outParam: std::shared_ptr<void> *pHostData    host内存地址 (size同入参)
    * return  : N/A
    */
    bool MyUtils::MemcpyDeviceToHost(std::shared_ptr<void> *pHostData, const void *pDeviceBuffer, uint32_t iBufferSize)
    {
        if (pDeviceBuffer == nullptr || iBufferSize == 0)
        {
            LogError << "MemcpyDeviceToHost fail pDeviceBuffer is null or iBufferSize is 0";
            return false;
        }

        void *pHostBuffer = nullptr;
        int iRet = aclrtMallocHost(&pHostBuffer, iBufferSize);
        if (iRet != APP_ERR_OK)
        {
            LogError << "MemcpyDeviceToHost aclrtMallocHost fail, iBufferSize:" << iBufferSize << " iRet:" << iRet;
            return false;
        }

        pHostData->reset(pHostBuffer, aclrtFreeHost);

        iRet = aclrtMemcpy(pHostData->get(), iBufferSize, pDeviceBuffer, iBufferSize, ACL_MEMCPY_DEVICE_TO_HOST);
        if (iRet != APP_ERR_OK)
        {
            LogError << "MemcpyDeviceToHost aclrtMemcpy fail, iBufferSize:" << iBufferSize << " iRet:" << iRet;
            return false;
        }
        return true;
    }

    /**
    * 拷贝Host数据到Device
    * inParam : void *pHostBuffer                   host内存地址
              : uint32_t iBufferSize                host内存大小
              : bool bDvppFlag                      是否使用dvpp方式申请device内存(默认true)
    * outParam: std::shared_ptr<void> *pDeviceData  device内存地址 (size同入参)
    * return  : N/A
    */
    bool MyUtils::MemcpyHostToDevice(std::shared_ptr<void> *pDeviceData, const void *pHostBuffer, uint32_t iBufferSize, bool bDvppFlag/*=true*/)
    {
        if (pHostBuffer == nullptr || iBufferSize == 0)
        {
            LogError << "MemcpyHostToDevice fail pHostBuffer is null or iBufferSize is 0";
            return false;
        }

        int iRet = APP_ERR_OK;
        void *pDeviceBuffer = nullptr;
        if (bDvppFlag)
        {
            int iRet = acldvppMalloc(&pDeviceBuffer, iBufferSize);
            if (iRet != APP_ERR_OK)
            {
                LogError << "MemcpyHostToDevice acldvppMalloc fail, iBufferSize:" << iBufferSize << " iRet:" << iRet;
                return false;
            }
            pDeviceData->reset(pDeviceBuffer, acldvppFree);
        }
        else
        {
            int iRet = aclrtMalloc(&pDeviceBuffer, iBufferSize, ACL_MEM_MALLOC_HUGE_FIRST);
            if (iRet != APP_ERR_OK)
            {
                LogError << "MemcpyHostToDevice aclrtMalloc fail, iBufferSize:" << iBufferSize << " iRet:" << iRet;
                return false;
            }
            pDeviceData->reset(pDeviceBuffer, aclrtFree);
        }

        iRet = aclrtMemcpy(pDeviceData->get(), iBufferSize, pHostBuffer, iBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);
        if (iRet != APP_ERR_OK)
        {
            LogError << "MemcpyHostToDevice aclrtMemcpy fail, iBufferSize:" << iBufferSize << " iRet:" << iRet;
            return false;
        }
        return true;
    }
#endif

    /**
     * 获取指定毫秒数的对应的北京日期时间
     * inParam : uint64_t i64MilliSeconds
     * outParam: N/A
     * return  : 日期时间
     */
    std::string MyUtils::GetDateTimeByMilliSeconds(uint64_t i64MilliSeconds, bool bFormatFlag/*=false*/)
    {
        time_t timep = i64MilliSeconds / 1000 + TIME_DIFF;
        struct tm *p = gmtime(&timep);

        char szTmp[32] = {0};
        if (bFormatFlag)
        {
            sprintf(szTmp, "%04d-%02d-%02d %02d:%02d:%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
        }
        else
        {
            sprintf(szTmp, "%04d-%02d-%02d %02d-%02d-%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
        }
        return std::string(szTmp);
    }

    /**
     * 校验是否识别该目标
     * inParam : std::string &strOneTarget
     * outParam: N/A
     * return  : true/false
     */
    bool MyUtils::ChkIsHaveTarget(const std::string &strOneTarget)
    {
        std::map<int, ai_matrix::DataSourceConfig> mapUseDataSouceCfg = MyYaml::GetIns()->GetUseDataSourceConfig();
        bool bFindTarget = false;
        for (auto iter = mapUseDataSouceCfg.begin(); iter != mapUseDataSouceCfg.end(); iter++)
        {
            if (iter->second.strTarget.find(strOneTarget) != std::string::npos)
            {
                bFindTarget = true;
                break;
            }
        }
        return bFindTarget;
    }

    /**
     * 读取json格式文件内容
     * inParam : std::string &strFilePath  :文件路径
     * outParam: Json::Value &jvFileInfo   :json格式内容
     * return  : true/false
     */
    bool MyUtils::ReadJsonInfo(Json::Value &jvFileInfo, std::string &strFilePath, int iRetry /*=3*/)
    {
        std::ifstream ifs(strFilePath.c_str());
        int i = 0;
        while (!ifs.is_open() && i < iRetry)
        {
            i++;
            usleep(10 * 1000);
            ifs.open(strFilePath.c_str());
        }
        if (!ifs.is_open())
        {
//            LogWarn << "txt:" << strFilePath << " open fail";
            return false;
        }

        std::string strContent;
        getline(ifs, strContent);
        ifs.close();

        Json::CharReaderBuilder jsrBuilder;
        std::shared_ptr<Json::CharReader> reader(jsrBuilder.newCharReader());
        JSONCPP_STRING errs;
        if (!reader->parse(strContent.data(), strContent.data() + strContent.size(), &jvFileInfo, &errs))
        {
            LogWarn << "json parse fail content:" << strContent;
            return false;
        }
        return true;
    }

    /**
    * json格式内容写入文件
    * inParam : Json::Value &jvFileInfo   :json格式内容
              : std::string &strFilePath  :文件路径
    * outParam: N/A
    * return  : true/false
    */
    bool MyUtils::WriteJsonInfo(Json::Value &jvFileInfo, std::string &strFilePath)
    {
        Json::StreamWriterBuilder jswBuilder;
        jswBuilder["indentation"] = "";
        std::string strFrameInfo = Json::writeString(jswBuilder, jvFileInfo);

        std::ofstream ofs(strFilePath.c_str());
        if (!ofs.is_open())
        {
            LogWarn << "txt:" << strFilePath << " open fail";
            return false;
        }
        ofs.write(strFrameInfo.c_str(), strFrameInfo.length());
        ofs.close();
        return true;
    }

    /**
     * 获取第1步得分最高框
     * inParam : std::vector<stDetection> &vecResult     推理符合结果
     * outParam: std::vector<stDetection> &vecResult     每个类别得分最高结果
     * return  : N/A
     */
    void MyUtils::GetMaxScoreResult(std::vector<stDetection> &vecResult)
    {
        if (vecResult.size() < 2)
        {
            return;
        }
        std::map<Target, std::vector<stDetection>> mapResult;
        for (size_t i = 0; i < vecResult.size(); i++)
        {
            stDetection stDTemp = vecResult.at(i);
            if (stDTemp.class_id == 0)
            {
                mapResult[HEAD].emplace_back(stDTemp);
            }
            else if (stDTemp.class_id == 1)
            {
                mapResult[PRO].emplace_back(stDTemp);
            }
            else if ((stDTemp.class_id >= 2 && stDTemp.class_id <= 6) || stDTemp.class_id == 8 || stDTemp.class_id == 15)
            {
                mapResult[NUM].emplace_back(stDTemp);
            }
            else if (stDTemp.class_id >= 9 && stDTemp.class_id <= 17 && stDTemp.class_id != 15)
            {
                mapResult[TRAINSPACE].emplace_back(stDTemp);
            }
            else if (stDTemp.class_id == 18)
            {
                mapResult[SPACE].emplace_back(stDTemp);
            }
        }

        //清空之前的结果
        vecResult.clear();
        // 每个类别中，获取得分最高的框
        for (auto iter = mapResult.begin(); iter != mapResult.end(); iter++)
        {
            int iMaxPos = -1;
            for (size_t i = 0; i < iter->second.size(); i++)
            {
                if (iMaxPos == -1)
                {
                    iMaxPos = i;
                }
                else if (iter->second.at(i).class_conf > iter->second.at(iMaxPos).class_conf)
                {
                    iMaxPos = i;
                }
            }

            if (iMaxPos >= 0)
            {
                vecResult.emplace_back(iter->second.at(iMaxPos));
            }
        }
    }

    /**
     * 获取第二步缩放比例
     * inParam : Step1Location &step1Location   第一步大框
               : int iModelWidth                模型宽
               : int iModelHeight               模型高
     * outParam: N/A
     * return  : 缩放比例
     */
    float MyUtils::GetStep2ResizeRatio(Step1Location &step1Location, int iModelWidth, int iModelHeight)
    {
        uint32_t iCropgWidth = step1Location.fRBX - step1Location.fLTX;
        uint32_t iCropHeight = step1Location.fRBY - step1Location.fLTY;
        float fRatioW = static_cast<float>(iCropgWidth) / iModelWidth;
        float fRatioH = static_cast<float>(iCropHeight) / iModelHeight;
        return (fRatioW > fRatioH) ? fRatioW : fRatioH;
    }

    /**
    * 第二步坐标还原
    * inParam : SingleData &singleData                      
              : float fResizeRatio                          比例
              : std::shared_ptr<ProcessData> pProcessData   待处理数据
              : Step1Location &step1Location                第一步大框在原图坐标
    * outParam: SingleData &singleData
    * return  : N/A
    */
    void MyUtils::Step2ResetLocation(SingleData &singleData, float fResizeRatio,
                                     std::shared_ptr<ProcessData> pProcessData, Step1Location &step1Location)
    {
        uint32_t iOrigWidth = pProcessData->iWidth;
        uint32_t iOrigHeight = pProcessData->iHeight;

        singleData.fLTX = singleData.fLTX * fResizeRatio + step1Location.fLTX;
        singleData.fLTY = singleData.fLTY * fResizeRatio + step1Location.fLTY;
        singleData.fRBX = singleData.fRBX * fResizeRatio + step1Location.fLTX;
        singleData.fRBY = singleData.fRBY * fResizeRatio + step1Location.fLTY;

        singleData.fLTX = (singleData.fLTX < iOrigWidth) ? singleData.fLTX : iOrigWidth;
        singleData.fLTY = (singleData.fLTY < iOrigHeight) ? singleData.fLTY : iOrigHeight;
        singleData.fRBX = (singleData.fRBX < iOrigWidth) ? singleData.fRBX : iOrigWidth;
        singleData.fRBY = (singleData.fRBY < iOrigHeight) ? singleData.fRBY : iOrigHeight;
    }
}
