<commit_before>
//by ZouZhiZhang

#include "tetris_core.h"
#include "integer_utils.h"
#include "ai_tag.h"
#include <cstdint>

using namespace m_tetris;
using namespace zzz;

namespace ai_tag
{

    bool the_ai_games::Status::operator < (Status const &other) const
    {
        return value < other.value;
    }

    void the_ai_games::init(m_tetris::TetrisContext const *context)
    {
        context_ = context;
        map_danger_data_.resize(context->type_max());
        for(size_t i = 0; i < context->type_max(); ++i)
        {
            TetrisMap map(context->width(), context->height());
            TetrisNode const *node = context->generate(i);
            node->move_down->attach(map);
            memcpy(map_danger_data_[i].data, &map.row[map.height - 4], sizeof map_danger_data_[i].data);
            for(int y = 0; y < 3; ++y)
            {
                map_danger_data_[i].data[y + 1] |= map_danger_data_[i].data[y];
            }
        }
        col_mask_ = context->full() & ~1;
        row_mask_ = context->full();
    }

    std::string the_ai_games::ai_name() const
    {
        return "The AI Games (SetoSan) v0.1";
    }

    the_ai_games::Result the_ai_games::eval(TetrisNode const *node, TetrisMap const &map, TetrisMap const &src_map, size_t clear) const
    {
        double LandHeight = node->row + node->height;
        double Middle = std::abs((int(node->status.x) + 1) * 2 - int(map.width));
        double EraseCount = clear;

        const int width_m1 = map.width - 1;
        int ColTrans = 2 * (map.height - map.roof);
        int RowTrans = map.roof == map.height ? 0 : map.width;
        for(int y = 0; y < map.roof; ++y)
        {
            if(!map.full(0, y))
            {
                ++ColTrans;
            }
            if(!map.full(width_m1, y))
            {
                ++ColTrans;
            }
            ColTrans += BitCount((map.row[y] ^ (map.row[y] << 1)) & col_mask_);
            if(y != 0)
            {
                RowTrans += BitCount(map.row[y - 1] ^ map.row[y]);
            }
        }
        RowTrans += BitCount(row_mask_ & ~map.row[0]);
        RowTrans += BitCount(map.roof == map.height ? row_mask_ & ~map.row[map.roof - 1] : map.row[map.roof - 1]);
        struct
        {
            int HoleCount;
            int HoleLine;

            int WideWellDepth[6];
            int WellDepth[32];
            int WellDepthTotle;

            int LineCoverBits;
            int HoleBits0;
            int ClearWidth0;
            int HoleBits1;
            int ClearWidth1;
            int HoleBits2;
            int ClearWidth2;
        } v;
        memset(&v, 0, sizeof v);
        int HolePosy0 = -1;
        int HolePosy1 = -1;
        int HolePosy2 = -1;

        for(int y = map.roof - 1; y >= 0; --y)
        {
            v.LineCoverBits |= map.row[y];
            int LineHole = v.LineCoverBits ^ map.row[y];
            if(LineHole != 0)
            {
                v.HoleCount += BitCount(LineHole);
                v.HoleLine++;
                if(HolePosy0 == -1)
                {
                    HolePosy0 = y + 1;
                    v.HoleBits0 = LineHole;
                }
                else if(HolePosy1 == -1)
                {
                    HolePosy1 = y + 1;
                    v.HoleBits1 = LineHole;
                }
                else if(HolePosy2 == -1)
                {
                    HolePosy2 = y + 1;
                    v.HoleBits2 = LineHole;
                }
            }
            int WellWidth = 0;
            int MaxWellWidth = 0;
            for(int x = 0; x < map.width; ++x)
            {
                if((v.LineCoverBits >> x) & 1)
                {
                    if(WellWidth > MaxWellWidth)
                    {
                        MaxWellWidth = WellWidth;
                    }
                    WellWidth = 0;
                }
                else
                {
                    ++WellWidth;
                    if(x > 0 && x < width_m1)
                    {
                        if(((v.LineCoverBits >> (x - 1)) & 7) == 5)
                        {
                            v.WellDepthTotle += ++v.WellDepth[x];
                        }
                    }
                    else if(x == 0)
                    {
                        if((v.LineCoverBits & 3) == 2)
                        {
                            v.WellDepthTotle += ++v.WellDepth[0];
                        }
                    }
                    else
                    {
                        if(((v.LineCoverBits >> (width_m1 - 1)) & 3) == 1)
                        {
                            v.WellDepthTotle += ++v.WellDepth[width_m1];
                        }
                    }
                }
            }
            if(WellWidth > MaxWellWidth)
            {
                MaxWellWidth = WellWidth;
            }
            if(MaxWellWidth >= 1 && MaxWellWidth <= 6)
            {
                if(zzz::BitCount(map.row[y]) + MaxWellWidth == map.width)
                {
                    v.WideWellDepth[MaxWellWidth - 1] += 2;
                }
                else
                {
                    v.WideWellDepth[MaxWellWidth - 1] -= 1;
                }
            }
        }
        if(HolePosy0 >= 0)
        {
            for(int y = HolePosy0; y < map.roof; ++y)
            {
                int CheckLine = v.HoleBits0 & map.row[y];
                if(CheckLine == 0)
                {
                    break;
                }
                v.ClearWidth0 += (y + 1) * BitCount(CheckLine);
            }
            if(HolePosy1 >= 0)
            {
                for(int y = HolePosy1; y < map.roof; ++y)
                {
                    int CheckLine = v.HoleBits1 & map.row[y];
                    if(CheckLine == 0)
                    {
                        break;
                    }
                    v.ClearWidth1 += (y + 1) * BitCount(CheckLine);
                }
                if(HolePosy2 >= 0)
                {
                    for(int y = HolePosy2; y < map.roof; ++y)
                    {
                        int CheckLine = v.HoleBits2 & map.row[y];
                        if(CheckLine == 0)
                        {
                            break;
                        }
                        v.ClearWidth2 += (y + 1) * BitCount(CheckLine);
                    }
                }
            }
        }
        int low_x = 1;
        for(int x = 2; x < width_m1; ++x)
        {
            if(map.top[x] < map.top[low_x])
            {
                low_x = x;
            }
        }
        if(map.top[0] <= map.top[low_x])
        {
            low_x = 0;
        }
        if(map.top[width_m1] <= map.top[low_x])
        {
            low_x = width_m1;
        }
        int low_y = map.top[low_x];
        int full = 0;
        for(int y = map.roof - 1; y >= 0; --y)
        {
            if(map.row[y] == context_->full())
            {
                full = y + 1;
                low_y -= y;
                break;
            }
        }
        int tilt = 0;
        for(int x = low_x, ex = std::max(0, low_x - 5); x > ex; --x)
        {
            if(map.top[x] > map.top[x + 1])
            {
                tilt += 2;
            }
            else if(map.top[x] == map.top[x + 1])
            {
                tilt += 1;
            }
        }
        for(int x = low_x, ex = std::min(width_m1, low_x + 5); x < ex; ++x)
        {
            if(map.top[x] > map.top[x - 1])
            {
                tilt += 2;
            }
            else if(map.top[x] == map.top[x - 1])
            {
                tilt += 1;
            }
        }
        Result result;
        result.land_point = (0.
                             - LandHeight * 1750 / map.height
                             + Middle * 2
                             + EraseCount * 60
                             );
        result.map = (0.
                      - ColTrans * 80
                      - RowTrans * 80
                      - v.HoleCount * 160
                      - v.HoleLine * 380
                      - v.ClearWidth0 * 8
                      - v.ClearWidth1 * 4
                      - v.ClearWidth2 * 1
                      - v.WellDepthTotle * 160
                      + v.WideWellDepth[5] * 2
                      + v.WideWellDepth[4] * 8
                      + v.WideWellDepth[3] * 4
                      + v.WideWellDepth[2] * 16
                      + v.WideWellDepth[1] * -8
                      + v.WideWellDepth[0] * 2
                      + (low_x == 0 ? 200 : 0)
                      );
        result.tilt = tilt;
        result.full = full;
        result.count = map.count - v.HoleCount;
        result.clear = clear;
        result.low_y = low_y;
        result.save_map = ↦
        return result;
    }

    the_ai_games::Status the_ai_games::get(Result const &eval_result, size_t depth, Status const &status) const
    {
        Status result = status;
        double BoardDeadZone = map_in_danger_(*eval_result.save_map, status.up);
        if(eval_result.save_map->roof + status.up >= context_->height())
        {
            BoardDeadZone += 70;
        }
        result.land_point -= BoardDeadZone * 50000000;
        bool building = (eval_result.count - eval_result.full * context_->width()) * 3 / 2 < std::max(0, (context_->height() - 5) - (eval_result.full + status.up)) * context_->width();
        if(eval_result.clear > 0)
        {
            if(eval_result.clear == 4)
            {
                result.land_point += 1000;
            }
            if(status.combo == 0 && building)
            {
                result.land_point -= (4 - std::min<int>(4, eval_result.low_y)) * 1600;
            }
            else if(status.combo > 0)
            {
                result.land_point += status.combo * 1000;
                if(eval_result.tilt > 2)
                {
                    result.land_point += 500;
                }
            }
            ++result.combo;
        }
        else
        {
            if(status.combo > 0 && building && eval_result.low_y > 4)
            {
                result.land_point -= status.combo * 500 + 500;
            }
            result.combo = 0;
        }
        double rate = (depth - 1.f) / 5 + 1;
        result.value = result.land_point + eval_result.map * rate;
        return result;
    }

    the_ai_games::Status the_ai_games::iterate(Status const **status, size_t status_length) const
    {
        Status result;
        result.combo = 0;
        result.up = 0;
        result.land_point = 0;
        result.value = 0;
        for(size_t i = 0; i < status_length; ++i)
        {
            if(status[i] == nullptr)
            {
                result.value += -9999999999;
            }
            else
            {
                result.value += status[i]->value;
            }
        }
        result.value /= status_length;
        return result;
    }

    size_t the_ai_games::map_in_danger_(m_tetris::TetrisMap const &map, size_t up) const
    {
        size_t danger = 0;
        do
        {
            size_t height = map.height - up;
            for(size_t i = 0; i < context_->type_max(); ++i)
            {
                if(map_danger_data_[i].data[0] & map.row[height - 4] || map_danger_data_[i].data[1] & map.row[height - 3] || map_danger_data_[i].data[2] & map.row[height - 2] || map_danger_data_[i].data[3] & map.row[height - 1])
                {
                    ++danger;
                }
            }
        }
        while(up-- > 0);
        return danger;
    }

    bool the_ai_games_enemy::Status::operator < (Status const &other) const
    {
        return point < other.point;
    }

    void the_ai_games_enemy::init(m_tetris::TetrisContext const *context, Config const *config)
    {
        config_ = config;
    }

    std::string the_ai_games_enemy::ai_name() const
    {
        return "The AI Games (SetoSan) v0.1";
    }

    size_t the_ai_games_enemy::eval(TetrisNode const *node, TetrisMap const &map, TetrisMap const &src_map, size_t clear) const
    {
        return clear;
    }

    the_ai_games_enemy::Status the_ai_games_enemy::get(size_t clear, size_t depth, Status const &status) const
    {
        Status result;
        result.point = status.point + clear;
        if(clear > 0)
        {
            if(clear == 4)
            {
                result.point += 4;
            }
            result.point += status.combo;
            result.combo = status.combo + 1;
        }
        else
        {
            result.combo = 0;
        }
        if(result.point > *config_->point_ptr)
        {
            *config_->point_ptr = result.point;
        }
        return result;
    }

    the_ai_games_enemy::Status the_ai_games_enemy::iterate(Status const **status, size_t status_length) const
    {
        Status result;
        result.combo = 0;
        result.point = 0;
        for(size_t i = 0; i < status_length; ++i)
        {
            if(status[i] != nullptr && status[i]->point > result.point)
            {
                result.point += status[i]->point;
            }
        }
        return result;
    }

}<commit_msg>调整TAG<commit_after>
//by ZouZhiZhang

#include "tetris_core.h"
#include "integer_utils.h"
#include "ai_tag.h"
#include <cstdint>

using namespace m_tetris;
using namespace zzz;

namespace ai_tag
{

    bool the_ai_games::Status::operator < (Status const &other) const
    {
        return value < other.value;
    }

    void the_ai_games::init(m_tetris::TetrisContext const *context)
    {
        context_ = context;
        map_danger_data_.resize(context->type_max());
        for(size_t i = 0; i < context->type_max(); ++i)
        {
            TetrisMap map(context->width(), context->height());
            TetrisNode const *node = context->generate(i);
            node->move_down->attach(map);
            memcpy(map_danger_data_[i].data, &map.row[map.height - 4], sizeof map_danger_data_[i].data);
            for(int y = 0; y < 3; ++y)
            {
                map_danger_data_[i].data[y + 1] |= map_danger_data_[i].data[y];
            }
        }
        col_mask_ = context->full() & ~1;
        row_mask_ = context->full();
    }

    std::string the_ai_games::ai_name() const
    {
        return "The AI Games (SetoSan) v0.1";
    }

    the_ai_games::Result the_ai_games::eval(TetrisNode const *node, TetrisMap const &map, TetrisMap const &src_map, size_t clear) const
    {
        double LandHeight = node->row + node->height;
        double Middle = std::abs((int(node->status.x) + 1) * 2 - int(map.width));
        double EraseCount = clear;

        const int width_m1 = map.width - 1;
        int ColTrans = 2 * (map.height - map.roof);
        int RowTrans = map.roof == map.height ? 0 : map.width;
        for(int y = 0; y < map.roof; ++y)
        {
            if(!map.full(0, y))
            {
                ++ColTrans;
            }
            if(!map.full(width_m1, y))
            {
                ++ColTrans;
            }
            ColTrans += BitCount((map.row[y] ^ (map.row[y] << 1)) & col_mask_);
            if(y != 0)
            {
                RowTrans += BitCount(map.row[y - 1] ^ map.row[y]);
            }
        }
        RowTrans += BitCount(row_mask_ & ~map.row[0]);
        RowTrans += BitCount(map.roof == map.height ? row_mask_ & ~map.row[map.roof - 1] : map.row[map.roof - 1]);
        struct
        {
            int HoleCount;
            int HoleLine;

            int WideWellDepth[6];
            int WellDepth[32];
            int WellDepthTotle;

            int LineCoverBits;
            int HoleBits0;
            int ClearWidth0;
            int HoleBits1;
            int ClearWidth1;
            int HoleBits2;
            int ClearWidth2;
        } v;
        memset(&v, 0, sizeof v);
        int HolePosy0 = -1;
        int HolePosy1 = -1;
        int HolePosy2 = -1;

        for(int y = map.roof - 1; y >= 0; --y)
        {
            v.LineCoverBits |= map.row[y];
            int LineHole = v.LineCoverBits ^ map.row[y];
            if(LineHole != 0)
            {
                v.HoleCount += BitCount(LineHole);
                v.HoleLine++;
                if(HolePosy0 == -1)
                {
                    HolePosy0 = y + 1;
                    v.HoleBits0 = LineHole;
                }
                else if(HolePosy1 == -1)
                {
                    HolePosy1 = y + 1;
                    v.HoleBits1 = LineHole;
                }
                else if(HolePosy2 == -1)
                {
                    HolePosy2 = y + 1;
                    v.HoleBits2 = LineHole;
                }
            }
            int WellWidth = 0;
            int MaxWellWidth = 0;
            for(int x = 0; x < map.width; ++x)
            {
                if((v.LineCoverBits >> x) & 1)
                {
                    if(WellWidth > MaxWellWidth)
                    {
                        MaxWellWidth = WellWidth;
                    }
                    WellWidth = 0;
                }
                else
                {
                    ++WellWidth;
                    if(x > 0 && x < width_m1)
                    {
                        if(((v.LineCoverBits >> (x - 1)) & 7) == 5)
                        {
                            v.WellDepthTotle += ++v.WellDepth[x];
                        }
                    }
                    else if(x == 0)
                    {
                        if((v.LineCoverBits & 3) == 2)
                        {
                            v.WellDepthTotle += ++v.WellDepth[0];
                        }
                    }
                    else
                    {
                        if(((v.LineCoverBits >> (width_m1 - 1)) & 3) == 1)
                        {
                            v.WellDepthTotle += ++v.WellDepth[width_m1];
                        }
                    }
                }
            }
            if(WellWidth > MaxWellWidth)
            {
                MaxWellWidth = WellWidth;
            }
            if(MaxWellWidth >= 1 && MaxWellWidth <= 6)
            {
                if(zzz::BitCount(map.row[y]) + MaxWellWidth == map.width)
                {
                    v.WideWellDepth[MaxWellWidth - 1] += 2;
                }
                else
                {
                    v.WideWellDepth[MaxWellWidth - 1] -= 1;
                }
            }
        }
        if(HolePosy0 >= 0)
        {
            for(int y = HolePosy0; y < map.roof; ++y)
            {
                int CheckLine = v.HoleBits0 & map.row[y];
                if(CheckLine == 0)
                {
                    break;
                }
                v.ClearWidth0 += (y + 1) * BitCount(CheckLine);
            }
            if(HolePosy1 >= 0)
            {
                for(int y = HolePosy1; y < map.roof; ++y)
                {
                    int CheckLine = v.HoleBits1 & map.row[y];
                    if(CheckLine == 0)
                    {
                        break;
                    }
                    v.ClearWidth1 += (y + 1) * BitCount(CheckLine);
                }
                if(HolePosy2 >= 0)
                {
                    for(int y = HolePosy2; y < map.roof; ++y)
                    {
                        int CheckLine = v.HoleBits2 & map.row[y];
                        if(CheckLine == 0)
                        {
                            break;
                        }
                        v.ClearWidth2 += (y + 1) * BitCount(CheckLine);
                    }
                }
            }
        }
        int low_x = 1;
        for(int x = 2; x < width_m1; ++x)
        {
            if(map.top[x] < map.top[low_x])
            {
                low_x = x;
            }
        }
        if(map.top[0] <= map.top[low_x])
        {
            low_x = 0;
        }
        if(map.top[width_m1] <= map.top[low_x])
        {
            low_x = width_m1;
        }
        int low_y = map.top[low_x];
        int full = 0;
        for(int y = map.roof - 1; y >= 0; --y)
        {
            if(map.row[y] == context_->full())
            {
                full = y + 1;
                low_y -= y;
                break;
            }
        }
        int tilt = 0;
        for(int x = low_x, ex = std::max(0, low_x - 5); x > ex; --x)
        {
            if(map.top[x] > map.top[x + 1])
            {
                tilt += 2;
            }
            else if(map.top[x] == map.top[x + 1])
            {
                tilt += 1;
            }
        }
        for(int x = low_x, ex = std::min(width_m1, low_x + 5); x < ex; ++x)
        {
            if(map.top[x] > map.top[x - 1])
            {
                tilt += 2;
            }
            else if(map.top[x] == map.top[x - 1])
            {
                tilt += 1;
            }
        }
        Result result;
        result.land_point = (0.
                             - LandHeight * 1750 / map.height
                             + Middle * 2
                             + EraseCount * 60
                             );
        result.map = (0.
                      - ColTrans * 80
                      - RowTrans * 80
                      - v.HoleCount * 160
                      - v.HoleLine * 380
                      - v.ClearWidth0 * 8
                      - v.ClearWidth1 * 4
                      - v.ClearWidth2 * 1
                      - v.WellDepthTotle * 160
                      + v.WideWellDepth[5] * 1
                      + v.WideWellDepth[4] * 2
                      + v.WideWellDepth[3] * 1
                      + v.WideWellDepth[2] * 48
                      + v.WideWellDepth[1] * -8
                      + v.WideWellDepth[0] * 2
                      + (low_x == 0 ? 200 : 0)
                      );
        result.tilt = tilt;
        result.full = full;
        result.count = map.count;
        result.clear = clear;
        result.low_y = low_y;
        result.save_map = ↦
        return result;
    }

    the_ai_games::Status the_ai_games::get(Result const &eval_result, size_t depth, Status const &status) const
    {
        Status result = status;
        double BoardDeadZone = 0;
        if(eval_result.save_map->roof + status.up >= context_->height())
        {
            BoardDeadZone = context_->type_max();
        }
        else
        {
            BoardDeadZone = map_in_danger_(*eval_result.save_map, status.up);
        }
        result.land_point -= BoardDeadZone * 50000000;
        bool building = (eval_result.count - eval_result.full * context_->width()) * 3 / 2 < std::max(0, (context_->height() - 6) - (eval_result.full + status.up)) * context_->width();
        if(eval_result.clear > 0)
        {
            if(eval_result.clear == 4)
            {
                result.land_point += 1000;
            }
            if(status.combo == 0 && building)
            {
                result.land_point -= (4 - std::min<int>(4, eval_result.low_y)) * 2000;
            }
            else if(status.combo > 0)
            {
                result.land_point += status.combo * 1200;
                if(eval_result.tilt > 5)
                {
                    result.land_point += 100;
                }
            }
            ++result.combo;
        }
        else
        {
            if(status.combo > 0 && building && eval_result.low_y > 4)
            {
                result.land_point -= status.combo * 600 + 600;
            }
            result.combo = 0;
        }
        double rate = (depth - 1.f) / 5 + 1;
        result.value = result.land_point + eval_result.map * rate;
        return result;
    }

    the_ai_games::Status the_ai_games::iterate(Status const **status, size_t status_length) const
    {
        Status result;
        result.combo = 0;
        result.up = 0;
        result.land_point = 0;
        result.value = 0;
        for(size_t i = 0; i < status_length; ++i)
        {
            if(status[i] == nullptr)
            {
                result.value -= 9999999999;
            }
            else
            {
                result.value += status[i]->value;
            }
        }
        result.value /= status_length;
        return result;
    }

    size_t the_ai_games::map_in_danger_(m_tetris::TetrisMap const &map, size_t up) const
    {
        size_t danger = 0;
        for(size_t i = 0; i < context_->type_max(); ++i)
        {
            size_t check_up = up;
            do
            {
                size_t height = map.height - check_up;
                if(map_danger_data_[i].data[0] & map.row[height - 4] || map_danger_data_[i].data[1] & map.row[height - 3] || map_danger_data_[i].data[2] & map.row[height - 2] || map_danger_data_[i].data[3] & map.row[height - 1])
                {
                    ++danger;
                    break;
                }
            }
            while(check_up-- > 0);
        }
        return danger;
    }

    bool the_ai_games_enemy::Status::operator < (Status const &other) const
    {
        return point < other.point;
    }

    void the_ai_games_enemy::init(m_tetris::TetrisContext const *context, Config const *config)
    {
        config_ = config;
    }

    std::string the_ai_games_enemy::ai_name() const
    {
        return "The AI Games (SetoSan) v0.1";
    }

    size_t the_ai_games_enemy::eval(TetrisNode const *node, TetrisMap const &map, TetrisMap const &src_map, size_t clear) const
    {
        return clear;
    }

    the_ai_games_enemy::Status the_ai_games_enemy::get(size_t clear, size_t depth, Status const &status) const
    {
        Status result;
        result.point = status.point + clear;
        if(clear > 0)
        {
            if(clear == 4)
            {
                result.point += 4;
            }
            result.point += status.combo;
            result.combo = status.combo + 1;
        }
        else
        {
            result.combo = 0;
        }
        if(result.point > *config_->point_ptr)
        {
            *config_->point_ptr = result.point;
        }
        return result;
    }

    the_ai_games_enemy::Status the_ai_games_enemy::iterate(Status const **status, size_t status_length) const
    {
        Status result;
        result.combo = 0;
        result.point = 0;
        for(size_t i = 0; i < status_length; ++i)
        {
            if(status[i] != nullptr && status[i]->point > result.point)
            {
                result.point += status[i]->point;
            }
        }
        return result;
    }

}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011, Willow Garage, Inc.
 * 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 Willow Garage, Inc. 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.
 */
#pragma once

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <ecto/util.hpp>
#include <ecto/tendril.hpp>
#include <boost/tuple/tuple.hpp>
#include <map>
#include <ecto/log.hpp>
namespace ecto
{
  namespace serialization
  {
    template<typename T, typename Archive>
    struct writer_
    {
      typedef T value_type;
      void
      operator()(Archive& ar, const tendril& t) const
      {
        ar << t.get<T>();
      }
    };

    template<typename T, typename Archive>
    struct reader_
    {
      typedef T value_type;
      void
      operator()(Archive& ar, tendril& t) const
      {
        if (!t.is_type<T>())
        {
          t << tendril(T(), ""); //don't want to loose docs.
        }
        ar >> t.get<T>();
      }
    };

    template<typename Archive>
    struct registry: boost::noncopyable
    {
      typedef boost::function<void(Archive&, tendril&)> serial_fn_t;
      typedef std::map<std::string, serial_fn_t> serail_map_t;

      template<typename Serializer>
      void
      add(const Serializer& s)
      {
        typedef typename Serializer::value_type value_type;
        const std::string& name = name_of<value_type>();
        serial_fn_t fnc = serial_fn_t(s);
        add(name, fnc);
      }

      void
      add(const std::string& name, serial_fn_t fnc);
      void
      serialize(const std::string& key, Archive& ar, tendril& t) const;

      serail_map_t serial_map;

      static registry<Archive>&
      instance();

    private:
      registry();
    };

    extern template class registry<boost::archive::binary_oarchive> ;
    extern template class registry<boost::archive::binary_iarchive> ;
    extern template class registry<boost::archive::text_oarchive> ;
    extern template class registry<boost::archive::text_iarchive> ;

    typedef registry<boost::archive::binary_oarchive> registry_binary_oa;
    typedef registry<boost::archive::binary_iarchive> registry_binary_ia;
    typedef registry<boost::archive::text_oarchive> registry_text_oa;
    typedef registry<boost::archive::text_iarchive> registry_text_ia;

    template<typename T>
    struct register_serializer: boost::noncopyable
    {
      typedef writer_<T, boost::archive::binary_oarchive> writer_binary_oa;
      typedef reader_<T, boost::archive::binary_iarchive> reader_binary_ia;
      typedef writer_<T, boost::archive::text_oarchive> writer_text_oa;
      typedef reader_<T, boost::archive::text_iarchive> reader_text_ia;
    private:
      static const register_serializer instance;
      register_serializer()
      {
        serialization::registry_binary_oa::instance().add(writer_binary_oa());
        serialization::registry_binary_ia::instance().add(reader_binary_ia());
        serialization::registry_text_oa::instance().add(writer_text_oa());
        serialization::registry_text_ia::instance().add(reader_text_ia());
      }
    };

    template<typename T>
    const register_serializer<T> register_serializer<T>::instance;

  }

}

#define ECTO_REGISTER_SERIALIZERS(Type)       \
namespace ecto{                               \
  namespace serialization{                    \
    template class register_serializer<Type>; \
  }                                           \
}
<commit_msg>spelling.<commit_after>/*
 * Copyright (c) 2011, Willow Garage, Inc.
 * 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 Willow Garage, Inc. 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.
 */
#pragma once

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <ecto/util.hpp>
#include <ecto/tendril.hpp>
#include <boost/tuple/tuple.hpp>
#include <map>
#include <ecto/log.hpp>
namespace ecto
{
  namespace serialization
  {
    template<typename T, typename Archive>
    struct writer_
    {
      typedef T value_type;
      void
      operator()(Archive& ar, const tendril& t) const
      {
        ar << t.get<T>();
      }
    };

    template<typename T, typename Archive>
    struct reader_
    {
      typedef T value_type;
      void
      operator()(Archive& ar, tendril& t) const
      {
        if (!t.is_type<T>())
          t << tendril(T(), ""); //don't want to lose docs.
        ar >> t.get<T>();
      }
    };

    template<typename Archive>
    struct registry: boost::noncopyable
    {
      typedef boost::function<void(Archive&, tendril&)> serial_fn_t;
      typedef std::map<std::string, serial_fn_t> serail_map_t;

      template<typename Serializer>
      void
      add(const Serializer& s)
      {
        typedef typename Serializer::value_type value_type;
        const std::string& name = name_of<value_type>();
        serial_fn_t fnc = serial_fn_t(s);
        add(name, fnc);
      }

      void
      add(const std::string& name, serial_fn_t fnc);
      void
      serialize(const std::string& key, Archive& ar, tendril& t) const;

      serail_map_t serial_map;

      static registry<Archive>&
      instance();

    private:
      registry();
    };

    extern template class registry<boost::archive::binary_oarchive> ;
    extern template class registry<boost::archive::binary_iarchive> ;
    extern template class registry<boost::archive::text_oarchive> ;
    extern template class registry<boost::archive::text_iarchive> ;

    typedef registry<boost::archive::binary_oarchive> registry_binary_oa;
    typedef registry<boost::archive::binary_iarchive> registry_binary_ia;
    typedef registry<boost::archive::text_oarchive> registry_text_oa;
    typedef registry<boost::archive::text_iarchive> registry_text_ia;

    template<typename T>
    struct register_serializer: boost::noncopyable
    {
      typedef writer_<T, boost::archive::binary_oarchive> writer_binary_oa;
      typedef reader_<T, boost::archive::binary_iarchive> reader_binary_ia;
      typedef writer_<T, boost::archive::text_oarchive> writer_text_oa;
      typedef reader_<T, boost::archive::text_iarchive> reader_text_ia;
    private:
      static const register_serializer instance;
      register_serializer()
      {
        serialization::registry_binary_oa::instance().add(writer_binary_oa());
        serialization::registry_binary_ia::instance().add(reader_binary_ia());
        serialization::registry_text_oa::instance().add(writer_text_oa());
        serialization::registry_text_ia::instance().add(reader_text_ia());
      }
    };

    template<typename T>
    const register_serializer<T> register_serializer<T>::instance;

  }

}

#define ECTO_REGISTER_SERIALIZERS(Type)       \
namespace ecto{                               \
  namespace serialization{                    \
    template class register_serializer<Type>; \
  }                                           \
}
<|endoftext|>


<commit_before>// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "StdAfx.h"
#include "..\BatchEncoder.h"
#include "..\utilities\Utilities.h"
#include "..\dialogs\BatchEncoderDlg.h"
#include "WorkThread.h"

DWORD WINAPI ReadThread(LPVOID lpParam)
{
    PipeContext* pContext = (PipeContext*)lpParam;
    HANDLE hFile = INVALID_HANDLE_VALUE;
    BYTE pReadBuff[4096];
    BOOL bRes = FALSE;
    DWORD dwReadBytes = 0;
    DWORD dwWriteBytes = 0;
    ULONGLONG nTotalBytesRead = 0;
    ULONGLONG nFileSize = 0;
    int nProgress = -1;
    bool bRunning = true;

    pContext->bError = false;
    pContext->bFinished = false;

    // open existing source file with read-only flag
    hFile = ::CreateFile(pContext->szFileName,
        GENERIC_READ,
        0,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        pContext->bError = true;
        pContext->bFinished = true;
        return(1);
    }

    nFileSize = ::GetFileSize64(hFile);
    if (nFileSize == 0)
    {
        pContext->bError = true;
        pContext->bFinished = true;
        ::CloseHandle(hFile);
        return(1);
    }

    // read/write loop
    do
    {
        // read data from source file
        bRes = ::ReadFile(hFile, pReadBuff, 4096, &dwReadBytes, 0);
        if ((bRes == FALSE) || (dwReadBytes == 0))
            break;

        // NOTE: Sleep(0) solves problem writing to pipe errors
        ::Sleep(0);

        // write data to write pipe
        bRes = ::WriteFile(pContext->hPipe, pReadBuff, dwReadBytes, &dwWriteBytes, 0);
        if ((bRes == FALSE) || (dwWriteBytes == 0) || (dwReadBytes != dwWriteBytes))
            break;

        // count read/write bytes
        nTotalBytesRead += dwReadBytes;
        nProgress = (int)((nTotalBytesRead * 100) / nFileSize);
        bRunning = pContext->pDlg->WorkerCallback(nProgress, false);
        if (bRunning == false)
            break;
    } while (bRes != FALSE);

    // clean up memory
    ::CloseHandle(hFile);

    // check if all data was processed
    if (nTotalBytesRead != nFileSize)
    {
        pContext->bError = true;
        pContext->bFinished = true;
        return(1);
    }

    pContext->bError = false;
    pContext->bFinished = true;
    return(0);
}
<commit_msg>Share input file for reading<commit_after>// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "StdAfx.h"
#include "..\BatchEncoder.h"
#include "..\utilities\Utilities.h"
#include "..\dialogs\BatchEncoderDlg.h"
#include "WorkThread.h"

DWORD WINAPI ReadThread(LPVOID lpParam)
{
    PipeContext* pContext = (PipeContext*)lpParam;
    HANDLE hFile = INVALID_HANDLE_VALUE;
    BYTE pReadBuff[4096];
    BOOL bRes = FALSE;
    DWORD dwReadBytes = 0;
    DWORD dwWriteBytes = 0;
    ULONGLONG nTotalBytesRead = 0;
    ULONGLONG nFileSize = 0;
    int nProgress = -1;
    bool bRunning = true;

    pContext->bError = false;
    pContext->bFinished = false;

    // open existing source file with read-only flag
    hFile = ::CreateFile(pContext->szFileName,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        pContext->bError = true;
        pContext->bFinished = true;
        return(1);
    }

    nFileSize = ::GetFileSize64(hFile);
    if (nFileSize == 0)
    {
        pContext->bError = true;
        pContext->bFinished = true;
        ::CloseHandle(hFile);
        return(1);
    }

    // read/write loop
    do
    {
        // read data from source file
        bRes = ::ReadFile(hFile, pReadBuff, 4096, &dwReadBytes, 0);
        if ((bRes == FALSE) || (dwReadBytes == 0))
            break;

        // NOTE: Sleep(0) solves problem writing to pipe errors
        ::Sleep(0);

        // write data to write pipe
        bRes = ::WriteFile(pContext->hPipe, pReadBuff, dwReadBytes, &dwWriteBytes, 0);
        if ((bRes == FALSE) || (dwWriteBytes == 0) || (dwReadBytes != dwWriteBytes))
            break;

        // count read/write bytes
        nTotalBytesRead += dwReadBytes;
        nProgress = (int)((nTotalBytesRead * 100) / nFileSize);
        bRunning = pContext->pDlg->WorkerCallback(nProgress, false);
        if (bRunning == false)
            break;
    } while (bRes != FALSE);

    // clean up memory
    ::CloseHandle(hFile);

    // check if all data was processed
    if (nTotalBytesRead != nFileSize)
    {
        pContext->bError = true;
        pContext->bFinished = true;
        return(1);
    }

    pContext->bError = false;
    pContext->bFinished = true;
    return(0);
}
<|endoftext|>


<commit_before>//=============================================================================================================
/**
* @file     collectorsocket.h
* @author   Christoph Dinh <chdinh@nmr.mgh.harvard.edu>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>;
* @version  1.0
* @date     July, 2012
*
* @section  LICENSE
*
* Copyright (C) 2012, Christoph Dinh and Matti Hamalainen. 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 Massachusetts General Hospital 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 MASSACHUSETTS GENERAL HOSPITAL 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.
*
*
* @brief    Contains the implementation of the CollectorSocket Class.
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "collectorsocket.h"

//*************************************************************************************************************
//=============================================================================================================
// Qt INCLUDES
//=============================================================================================================

#include <QtNetwork>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace NeuromagPlugin;

//*************************************************************************************************************
//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

CollectorSocket::CollectorSocket(QObject *parent)
: QTcpSocket(parent)
, m_sCollectorHost(QHostAddress(QHostAddress::LocalHost).toString())
, m_bIsMeasuring(false)
{

}

//*************************************************************************************************************

bool CollectorSocket::open()
{
    printf("About to connect to collector... ");
    if(this->state() == QAbstractSocket::ConnectedState)
    {
        printf("Note: Tried to re-open an open connection... [done]\r\n");//dacq_log("Note: Tried to re-open an open connection\n");
        return true;
    }
    this->abort();
    this->connectToHost(m_sCollectorHost, COLLECTOR_PORT);
    this->waitForConnected( -1 );//qDebug() << "Socket Stat: " << this->state();
    printf("[done]\r\n");

    if (!this->server_login(QString(COLLECTOR_PASS), QString("mne_rt_server"))) {
        printf("Neuromag collector connection: Error\r\n");//dacq_log("Neuromag collector connection: %s\n", err_get_error());
        return false;
    }

    return true;
}

//*************************************************************************************************************

//int CollectorSocket::close()
//{

//    qDebug() << "DacqServer::collector_close()";

//    if (this == NULL)
//        return(0);
////    if (dacq_server_close(&this, NULL)) {
////        printf("Neuromag collector connection: Eror\n");//dacq_log("Neuromag collector connection: %s\n", err_get_error());
////        return(-1);
////    }

//    this->waitForReadyRead(100);

//    this->close();

////    m_iCollectorSock = -1;
//    return(0);
//}

//*************************************************************************************************************
// ToDo doesn't work without setting first buffersize first
int CollectorSocket::getMaxBuflen()
{

    int maxbuflen = -1;

    QString t_sSend = QString("%1\r\n").arg(COLLECTOR_GETVARS);

    QByteArray t_buf;
    if (!this->server_send(t_sSend, t_buf, DACQ_KEEP_INPUT)) {
        printf("Neuromag collector connection: Error\r\n");//dacq_log("Neuromag collector connection: %s\n", err_get_error());
        return -1;
    }

    QList<QByteArray> t_lLinesBuffer = t_buf.split('\n');

    QByteArray bufVar1(COLLECTOR_BUFVAR);
    QByteArray bufVar2("Vectors in a buffer");
    for(qint32 i = 0; i < t_lLinesBuffer.size(); ++i)
    {
        if(t_lLinesBuffer[i].contains(bufVar1)) //option 1
        {
            char var_name[1024];
            char var_value[1024];
            char var_type[1024];
            sscanf(t_lLinesBuffer[i].data()+4, "%s %s %s", var_name, var_value, var_type);
            maxbuflen = QString(var_value).toInt();
            return maxbuflen;
        }
        else if(t_lLinesBuffer[i].contains(bufVar2)) //option 2
        {
            QList<QByteArray> t_lMaxBuflen = t_lLinesBuffer[i].split(':');
            maxbuflen = t_lMaxBuflen[t_lMaxBuflen.size()-1].trimmed().toInt();
            return maxbuflen;
        }
    }

    return -1;
}

//*************************************************************************************************************

int CollectorSocket::setMaxBuflen(int maxbuflen)
{
    if (maxbuflen < 1)
        return(0);

    if (!this->server_command(QString("%1 %2 %3\n").arg(COLLECTOR_SETVARS).arg(COLLECTOR_BUFVAR).arg(maxbuflen)) ||
            !this->server_command(QString("%1\n").arg(COLLECTOR_DOSETUP)))
    {
        printf("Neuromag collector connection: Error\n");//dacq_log("Neuromag collector connection: %s\n", err_get_error());
        return(-1);
    }

    return(0);
}

//*************************************************************************************************************
// ToDo doesn't work without setting first buffersize first
int CollectorSocket::getStat()
{

    int maxbuflen = -1;

    QString t_sSend = QString("%1\r\n").arg(COLLECTOR_STAT);

    QByteArray t_buf;
    if (!this->server_send(t_sSend, t_buf, DACQ_KEEP_INPUT)) {
        printf("Neuromag collector connection: Error\r\n");//dacq_log("Neuromag collector connection: %s\n", err_get_error());
        return -1;
    }

    QList<QByteArray> t_sBuffer = t_buf.split(' ');

    qDebug() << "int CollectorSocket::getStat() " << t_sBuffer[0];

    return -1;
}

//*************************************************************************************************************

bool CollectorSocket::server_command(const QString& p_sCommand)
{

    if (this->state() != QAbstractSocket::ConnectedState)
        return false;

    //ToDo Command Check
    QByteArray t_arrCommand = p_sCommand.toLocal8Bit();

    if(t_arrCommand.size() > 0)
    {
        this->write(t_arrCommand);
        this->flush();
    }

    //ToDo check if command was succefull processed by the collector
    this->waitForReadyRead(-1);
    this->readAll();//readAll that QTcpSocket is empty again

    return true;
}

//*************************************************************************************************************

bool CollectorSocket::server_login(const QString& p_sCollectorPass, const QString& p_sMyName)
{
    printf("Login... ");

    QString t_sCommand = QString("%1 %2\r\n").arg(DACQ_CMD_PASSWORD).arg(p_sCollectorPass);
    this->server_command(t_sCommand);

    t_sCommand = QString("%1 %2\r\n").arg(DACQ_CMD_NAME).arg(p_sMyName);
    this->server_command(t_sCommand);

    printf("[done]\r\n");

    return true;
}

//*************************************************************************************************************

bool CollectorSocket::server_send(QString& p_sDataSend, QByteArray& p_dataOut, int p_iInputFlag)
{
    if (this->state() != QAbstractSocket::ConnectedState)
        return false;

    QByteArray t_arrSend = p_sDataSend.toLocal8Bit();

    if(t_arrSend.size() > 0)
    {
        this->write(t_arrSend);
        this->flush();
    }

    this->waitForReadyRead(-1);
    if ( p_iInputFlag == DACQ_DRAIN_INPUT )
    {
        this->readAll();//readAll that QTcpSocket is empty again -> prevent overflow
    }
    else if( p_iInputFlag == DACQ_KEEP_INPUT )
    {
        p_dataOut = this->readAll();//readAll that QTcpSocket is empty again -> prevent overflow
    }

    return true;
}

//*************************************************************************************************************

bool CollectorSocket::server_start()
{
    if(!m_bIsMeasuring)
    {
        printf("Start measurement... ");

        QString t_sCommand = QString("%1\r\n").arg("meas");
        this->server_command(t_sCommand);

        m_bIsMeasuring = true;
    }

    return true;
}

//*************************************************************************************************************

bool CollectorSocket::server_stop()
{
    if(m_bIsMeasuring)
    {
        printf("Stop measurement... ");

        QString t_sCommand = QString("%1\r\n").arg("stop");
        this->server_command(t_sCommand);

        m_bIsMeasuring = false;
        printf("[done]\r\n");
    }

    return true;
}

<commit_msg>stat fix<commit_after>//=============================================================================================================
/**
* @file     collectorsocket.h
* @author   Christoph Dinh <chdinh@nmr.mgh.harvard.edu>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>;
* @version  1.0
* @date     July, 2012
*
* @section  LICENSE
*
* Copyright (C) 2012, Christoph Dinh and Matti Hamalainen. 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 Massachusetts General Hospital 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 MASSACHUSETTS GENERAL HOSPITAL 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.
*
*
* @brief    Contains the implementation of the CollectorSocket Class.
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "collectorsocket.h"

//*************************************************************************************************************
//=============================================================================================================
// Qt INCLUDES
//=============================================================================================================

#include <QtNetwork>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace NeuromagPlugin;

//*************************************************************************************************************
//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

CollectorSocket::CollectorSocket(QObject *parent)
: QTcpSocket(parent)
, m_sCollectorHost(QHostAddress(QHostAddress::LocalHost).toString())
, m_bIsMeasuring(false)
{

}

//*************************************************************************************************************

bool CollectorSocket::open()
{
    printf("About to connect to collector... ");
    if(this->state() == QAbstractSocket::ConnectedState)
    {
        printf("Note: Tried to re-open an open connection... [done]\r\n");//dacq_log("Note: Tried to re-open an open connection\n");
        return true;
    }
    this->abort();
    this->connectToHost(m_sCollectorHost, COLLECTOR_PORT);
    this->waitForConnected( -1 );//qDebug() << "Socket Stat: " << this->state();
    printf("[done]\r\n");

    if (!this->server_login(QString(COLLECTOR_PASS), QString("mne_rt_server"))) {
        printf("Neuromag collector connection: Error\r\n");//dacq_log("Neuromag collector connection: %s\n", err_get_error());
        return false;
    }

    return true;
}

//*************************************************************************************************************

//int CollectorSocket::close()
//{

//    qDebug() << "DacqServer::collector_close()";

//    if (this == NULL)
//        return(0);
////    if (dacq_server_close(&this, NULL)) {
////        printf("Neuromag collector connection: Eror\n");//dacq_log("Neuromag collector connection: %s\n", err_get_error());
////        return(-1);
////    }

//    this->waitForReadyRead(100);

//    this->close();

////    m_iCollectorSock = -1;
//    return(0);
//}

//*************************************************************************************************************
// ToDo doesn't work without setting first buffersize first
int CollectorSocket::getMaxBuflen()
{

    int maxbuflen = -1;

    QString t_sSend = QString("%1\r\n").arg(COLLECTOR_GETVARS);

    QByteArray t_buf;
    if (!this->server_send(t_sSend, t_buf, DACQ_KEEP_INPUT)) {
        printf("Neuromag collector connection: Error\r\n");//dacq_log("Neuromag collector connection: %s\n", err_get_error());
        return -1;
    }

    QList<QByteArray> t_lLinesBuffer = t_buf.split('\n');

    QByteArray bufVar1(COLLECTOR_BUFVAR);
    QByteArray bufVar2("Vectors in a buffer");
    for(qint32 i = 0; i < t_lLinesBuffer.size(); ++i)
    {
        if(t_lLinesBuffer[i].contains(bufVar1)) //option 1
        {
            char var_name[1024];
            char var_value[1024];
            char var_type[1024];
            sscanf(t_lLinesBuffer[i].data()+4, "%s %s %s", var_name, var_value, var_type);
            maxbuflen = QString(var_value).toInt();
            return maxbuflen;
        }
        else if(t_lLinesBuffer[i].contains(bufVar2)) //option 2
        {
            QList<QByteArray> t_lMaxBuflen = t_lLinesBuffer[i].split(':');
            maxbuflen = t_lMaxBuflen[t_lMaxBuflen.size()-1].trimmed().toInt();
            return maxbuflen;
        }
    }

    return -1;
}

//*************************************************************************************************************

int CollectorSocket::setMaxBuflen(int maxbuflen)
{
    if (maxbuflen < 1)
        return(0);

    if (!this->server_command(QString("%1 %2 %3\n").arg(COLLECTOR_SETVARS).arg(COLLECTOR_BUFVAR).arg(maxbuflen)) ||
            !this->server_command(QString("%1\n").arg(COLLECTOR_DOSETUP)))
    {
        printf("Neuromag collector connection: Error\n");//dacq_log("Neuromag collector connection: %s\n", err_get_error());
        return(-1);
    }

    return(0);
}

//*************************************************************************************************************
// ToDo doesn't work without setting first buffersize first
int CollectorSocket::getStat()
{
    QString t_sSend = QString("%1\r\n").arg(COLLECTOR_STAT);

    this->readAll();

    QByteArray t_buf;
    if (!this->server_send(t_sSend, t_buf, DACQ_KEEP_INPUT)) {
        printf("Neuromag collector connection: Error\r\n");//dacq_log("Neuromag collector connection: %s\n", err_get_error());
        return -1;
    }

//    QList<QByteArray> t_sBuffer = t_buf.split(' ');

    qDebug() << "int CollectorSocket::getStat() " << t_buf;//t_sBuffer[0];

    return -1;
}

//*************************************************************************************************************

bool CollectorSocket::server_command(const QString& p_sCommand)
{

    if (this->state() != QAbstractSocket::ConnectedState)
        return false;

    //ToDo Command Check
    QByteArray t_arrCommand = p_sCommand.toLocal8Bit();

    if(t_arrCommand.size() > 0)
    {
        this->write(t_arrCommand);
        this->flush();
    }

    //ToDo check if command was succefull processed by the collector
    this->waitForReadyRead(-1);
    this->readAll();//readAll that QTcpSocket is empty again

    return true;
}

//*************************************************************************************************************

bool CollectorSocket::server_login(const QString& p_sCollectorPass, const QString& p_sMyName)
{
    printf("Login... ");

    QString t_sCommand = QString("%1 %2\r\n").arg(DACQ_CMD_PASSWORD).arg(p_sCollectorPass);
    this->server_command(t_sCommand);

    t_sCommand = QString("%1 %2\r\n").arg(DACQ_CMD_NAME).arg(p_sMyName);
    this->server_command(t_sCommand);

    printf("[done]\r\n");

    return true;
}

//*************************************************************************************************************

bool CollectorSocket::server_send(QString& p_sDataSend, QByteArray& p_dataOut, int p_iInputFlag)
{
    if (this->state() != QAbstractSocket::ConnectedState)
        return false;

    QByteArray t_arrSend = p_sDataSend.toLocal8Bit();

    if(t_arrSend.size() > 0)
    {
        this->write(t_arrSend);
        this->flush();
    }

    this->waitForReadyRead(-1);
    if ( p_iInputFlag == DACQ_DRAIN_INPUT )
    {
        this->readAll();//readAll that QTcpSocket is empty again -> prevent overflow
    }
    else if( p_iInputFlag == DACQ_KEEP_INPUT )
    {
        p_dataOut = this->readAll();//readAll that QTcpSocket is empty again -> prevent overflow
    }

    return true;
}

//*************************************************************************************************************

bool CollectorSocket::server_start()
{
    if(!m_bIsMeasuring)
    {
        printf("Start measurement... ");

        QString t_sCommand = QString("%1\r\n").arg("meas");
        this->server_command(t_sCommand);

        m_bIsMeasuring = true;
    }

    return true;
}

//*************************************************************************************************************

bool CollectorSocket::server_stop()
{
    if(m_bIsMeasuring)
    {
        printf("Stop measurement... ");

        QString t_sCommand = QString("%1\r\n").arg("stop");
        this->server_command(t_sCommand);

        m_bIsMeasuring = false;
        printf("[done]\r\n");
    }

    return true;
}

<|endoftext|>


<commit_before>//
// Copyright (c) 2014 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#ifndef HPP_CORE_CONNECTED_COMPONENT_HH
# define HPP_CORE_CONNECTED_COMPONENT_HH

# include <hpp/core/fwd.hh>
# include <hpp/core/config.hh>
# include <hpp/core/node.hh>

namespace hpp {
  namespace core {
    /// Connected component
    ///
    /// Set of nodes reachable from one another.
    class HPP_CORE_DLLAPI ConnectedComponent {
    public:
      // List of nodes within the connected component
      typedef std::list <NodePtr_t> Nodes_t;
      // variable for ranking connected components
      static unsigned int globalFinishTime_;
      static ConnectedComponentPtr_t create ()
      {
	ConnectedComponent* ptr = new ConnectedComponent ();
	ConnectedComponentPtr_t shPtr (ptr);
	ptr->init (shPtr);
	return shPtr;
      }
      /// Merge two connected components.
      ///
      /// \param other connected component to merge into this one.
      /// \note other will be empty after calling this method.
      void merge (const ConnectedComponentPtr_t& other);

      /// Add node in connected component
      /// \param node node to add.
      void addNode (const NodePtr_t& node)
      {
	nodes_.push_back (node);
      }
      /// Access to the nodes
      const Nodes_t& nodes () const
      {
	return nodes_;
      }

      /// \name Reachability
      /// \{

      /// Whether this connected component can reach cc
      /// \param cc a connected component
      bool canReach (const ConnectedComponentPtr_t& cc);

      /// Whether this connected component can reach cc
      /// \param cc a connected component
      /// \retval cc2Tocc1 list of connected components between cc2 and cc1
      ///         that should be merged.
      bool canReach (const ConnectedComponentPtr_t& cc,
		     ConnectedComponents_t& cc2Tocc1);

      // Get connected components reachable from this
      const ConnectedComponents_t& reachableTo () const
      {
	return reachableTo_;
      }

      // Get connected components that can reach this
      const ConnectedComponents_t& reachableFrom () const
      {
	return reachableFrom_;
      }
      /// \}
    protected:
      /// Constructor
      ConnectedComponent () : nodes_ (), explored_ (false), weak_ ()
	  {
	  }
      void init (const ConnectedComponentPtr_t& shPtr){
	weak_ = shPtr;
      }
    private:
      Nodes_t nodes_;
      // List of CCs from which this connected component can be reached
      ConnectedComponents_t reachableFrom_;
      // List of CCs that can be reached from this connected component
      ConnectedComponents_t reachableTo_;
      // status variable to indicate whether or not CC has been visited
      mutable bool explored_;
      ConnectedComponentWkPtr_t weak_;
      friend class Roadmap;
      friend void clean (ConnectedComponents_t& set);
    }; // class ConnectedComponent
  } //   namespace core
} // namespace hpp
#endif // HPP_CORE_CONNECTED_COMPONENT_HH
<commit_msg>made addNode and merge virtual to reimplement them in manipulation<commit_after>//
// Copyright (c) 2014 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#ifndef HPP_CORE_CONNECTED_COMPONENT_HH
# define HPP_CORE_CONNECTED_COMPONENT_HH

# include <hpp/core/fwd.hh>
# include <hpp/core/config.hh>
# include <hpp/core/node.hh>

namespace hpp {
  namespace core {
    /// Connected component
    ///
    /// Set of nodes reachable from one another.
    class HPP_CORE_DLLAPI ConnectedComponent {
    public:
      // List of nodes within the connected component
      typedef std::list <NodePtr_t> Nodes_t;
      // variable for ranking connected components
      static unsigned int globalFinishTime_;
      static ConnectedComponentPtr_t create ()
      {
	ConnectedComponent* ptr = new ConnectedComponent ();
	ConnectedComponentPtr_t shPtr (ptr);
	ptr->init (shPtr);
	return shPtr;
      }
      /// Merge two connected components.
      ///
      /// \param other connected component to merge into this one.
      /// \note other will be empty after calling this method.
      virtual void merge (const ConnectedComponentPtr_t& other);

      /// Add node in connected component
      /// \param node node to add.
      virtual void addNode (const NodePtr_t& node)
      {
	nodes_.push_back (node);
      }
      /// Access to the nodes
      const Nodes_t& nodes () const
      {
	return nodes_;
      }

      /// \name Reachability
      /// \{

      /// Whether this connected component can reach cc
      /// \param cc a connected component
      bool canReach (const ConnectedComponentPtr_t& cc);

      /// Whether this connected component can reach cc
      /// \param cc a connected component
      /// \retval cc2Tocc1 list of connected components between cc2 and cc1
      ///         that should be merged.
      bool canReach (const ConnectedComponentPtr_t& cc,
		     ConnectedComponents_t& cc2Tocc1);

      // Get connected components reachable from this
      const ConnectedComponents_t& reachableTo () const
      {
	return reachableTo_;
      }

      // Get connected components that can reach this
      const ConnectedComponents_t& reachableFrom () const
      {
	return reachableFrom_;
      }
      /// \}
    protected:
      /// Constructor
      ConnectedComponent () : nodes_ (), explored_ (false), weak_ ()
	  {
	  }
      void init (const ConnectedComponentPtr_t& shPtr){
	weak_ = shPtr;
      }
    private:
      Nodes_t nodes_;
      // List of CCs from which this connected component can be reached
      ConnectedComponents_t reachableFrom_;
      // List of CCs that can be reached from this connected component
      ConnectedComponents_t reachableTo_;
      // status variable to indicate whether or not CC has been visited
      mutable bool explored_;
      ConnectedComponentWkPtr_t weak_;
      friend class Roadmap;
      friend void clean (ConnectedComponents_t& set);
    }; // class ConnectedComponent
  } //   namespace core
} // namespace hpp
#endif // HPP_CORE_CONNECTED_COMPONENT_HH
<|endoftext|>


<commit_before>#pragma once
#include <Internal/SubModule/PotentialFieldSubModuleImpl.hpp>
#include <Internal/PotentialField/PotentialFieldImpl.hpp>
#include <Internal/PotentialField/PotentialGroupImpl.hpp>
#include <Internal/PotentialField/PotentialFieldActorImpl.hpp>
namespace DoremiEngine
{
    namespace AI
    {
        PotentialFieldSubModuleImpl::PotentialFieldSubModuleImpl() {}
        PotentialFieldSubModuleImpl::~PotentialFieldSubModuleImpl() {}
        PotentialField* PotentialFieldSubModuleImpl::CreateNewField(const float& p_width, const float& p_height, const int& p_numberOfQuadsWidth,
                                                                    const int& p_numberOfQuadsHeight, const DirectX::XMFLOAT3& p_center)
        {
            // TODOKO review if we need to create a 3d grid or if a 2d grid is enough just to see where they can move in x and z
            using namespace std;
            using namespace DirectX;
            PotentialField* newField = new PotentialFieldImpl();
            vector<vector<PotentialFieldGridPoint>> grid;
            float quadWidth = p_width / (float)p_numberOfQuadsWidth;
            float quadHeight = p_height / (float)p_numberOfQuadsHeight;
            float halfWidth = p_width / 2.0f;
            float halfHeight = p_height / 2.0f;
            XMFLOAT2 bottomLeft = XMFLOAT2(p_center.x - halfWidth, p_center.z - halfHeight);
            grid.resize(p_numberOfQuadsWidth);
            for(size_t x = 0; x < p_numberOfQuadsWidth; x++)
            {
                for(size_t y = 0; y < p_numberOfQuadsHeight; y++)
                {
                    PotentialFieldGridPoint newPoint;
                    newPoint.position = XMFLOAT2((float)x * quadWidth + bottomLeft.x + quadWidth * 0.5f , (float)y * quadHeight + bottomLeft.y + quadHeight * 0.5f);
                    grid[x].push_back(newPoint);
                }
            }
            newField->SetGrid(grid);
            newField->SetCenter(p_center);
            newField->SetHeight(p_height);
            newField->SetWidth(p_width);
            newField->SetQuadSize(XMFLOAT2(quadWidth, quadHeight));
            m_fields.push_back(newField);
            return newField;
        }
        PotentialGroup* PotentialFieldSubModuleImpl::CreateNewPotentialGroup()
        {
            PotentialGroup* newGroup = new PotentialGroupImpl();
            return newGroup;
        }
        PotentialFieldActor*
        PotentialFieldSubModuleImpl::CreateNewActor(const DirectX::XMFLOAT3& p_position, const float& p_charge, const float& p_range, const bool& p_static) // TODOKO position should possibly be float2. Pointer so we dont need to send pos every frame?
        {
            PotentialFieldActor* newActor = new PotentialFieldActorImpl();
            newActor->SetStatic(p_static); // needs to be done first since set position is dependent on static or not
            newActor->SetPosition(p_position); // TODOKO Might produce a error since no static objects will have a good position
            newActor->SetCharge(p_charge);
            newActor->SetRange(p_range);

            return newActor;
        }
        void PotentialFieldSubModuleImpl::AttachActor(PotentialField& o_field, PotentialFieldActor* p_actor) { o_field.AddActor(p_actor); }
        int PotentialFieldSubModuleImpl::GetNextStep() { return 0; }
        PotentialField* PotentialFieldSubModuleImpl::FindBestPotentialField(const DirectX::XMFLOAT3& p_position)
        {
            // Take out all PF that you are within
            using namespace std;
            using namespace DirectX;
            vector<PotentialField*> possibleMatches;
            PotentialField* returnField = nullptr;
            for (size_t i = 0; i < m_fields.size(); i++)
            {
                XMFLOAT3 fieldCenter = m_fields[i]->GetCenter();
                XMFLOAT2 quadSize = m_fields[i]->GetQuadSize();
                int quadsX = m_fields[i]->GetGrid().size(); // Get number of quads in x and y
                int quadsY = m_fields[i]->GetGrid()[0].size();
                float fieldHalfWidth = quadSize.x * (float)quadsX * 0.5f; // Half the fields width and height
                float fieldHalfHeight = quadSize.y * (float)quadsY * 0.5f;
                float fieldLeftBoundary = fieldCenter.x - fieldHalfWidth; // takes out the fields left, right and top, bottom boundary positions
                float fieldRightBoundary = fieldCenter.x + fieldHalfWidth;
                float fieldTopBoundary = fieldCenter.y + fieldHalfHeight;
                float fieldBottomBoundary = fieldCenter.y - fieldHalfHeight;
                if (p_position.x <= fieldRightBoundary && p_position.x >= fieldLeftBoundary &&
                    p_position.y <= fieldTopBoundary && p_position.y >= fieldBottomBoundary) // If inside the field
                {
                    possibleMatches.push_back(m_fields[i]); // Still need to check which field is closest in Y
                }
            }
            // Check which possible field is closest in Y
            float closestY = 1000000;
            for (size_t i = 0; i < possibleMatches.size(); i++)
            {
                XMFLOAT3 fieldCenter = possibleMatches[i]->GetCenter();
                float distanceY = p_position.y - fieldCenter.y;
                distanceY = abs(distanceY);
                if (distanceY < closestY)
                {
                    returnField = possibleMatches[i];
                }
            }
            if (returnField == nullptr)
            {
                // TODOKO log error / message
            }
            return returnField;
        }
    }
}<commit_msg>Fixed cast warning in PotentialFieldSubModuleImpl<commit_after>#pragma once
#include <Internal/SubModule/PotentialFieldSubModuleImpl.hpp>
#include <Internal/PotentialField/PotentialFieldImpl.hpp>
#include <Internal/PotentialField/PotentialGroupImpl.hpp>
#include <Internal/PotentialField/PotentialFieldActorImpl.hpp>
namespace DoremiEngine
{
    namespace AI
    {
        PotentialFieldSubModuleImpl::PotentialFieldSubModuleImpl() {}
        PotentialFieldSubModuleImpl::~PotentialFieldSubModuleImpl() {}
        PotentialField* PotentialFieldSubModuleImpl::CreateNewField(const float& p_width, const float& p_height, const int& p_numberOfQuadsWidth,
                                                                    const int& p_numberOfQuadsHeight, const DirectX::XMFLOAT3& p_center)
        {
            // TODOKO review if we need to create a 3d grid or if a 2d grid is enough just to see where they can move in x and z
            using namespace std;
            using namespace DirectX;
            PotentialField* newField = new PotentialFieldImpl();
            vector<vector<PotentialFieldGridPoint>> grid;
            float quadWidth = p_width / static_cast<float>(p_numberOfQuadsWidth);
            float quadHeight = p_height / static_cast<float>(p_numberOfQuadsHeight);
            float halfWidth = p_width / 2.0f;
            float halfHeight = p_height / 2.0f;
            XMFLOAT2 bottomLeft = XMFLOAT2(p_center.x - halfWidth, p_center.z - halfHeight);
            grid.resize(p_numberOfQuadsWidth);
            for(size_t x = 0; x < p_numberOfQuadsWidth; x++)
            {
                for(size_t y = 0; y < p_numberOfQuadsHeight; y++)
                {
                    PotentialFieldGridPoint newPoint;
                    newPoint.position = XMFLOAT2((float)x * quadWidth + bottomLeft.x + quadWidth * 0.5f , (float)y * quadHeight + bottomLeft.y + quadHeight * 0.5f);
                    grid[x].push_back(newPoint);
                }
            }
            newField->SetGrid(grid);
            newField->SetCenter(p_center);
            newField->SetHeight(p_height);
            newField->SetWidth(p_width);
            newField->SetQuadSize(XMFLOAT2(quadWidth, quadHeight));
            m_fields.push_back(newField);
            return newField;
        }
        PotentialGroup* PotentialFieldSubModuleImpl::CreateNewPotentialGroup()
        {
            PotentialGroup* newGroup = new PotentialGroupImpl();
            return newGroup;
        }
        PotentialFieldActor*
        PotentialFieldSubModuleImpl::CreateNewActor(const DirectX::XMFLOAT3& p_position, const float& p_charge, const float& p_range, const bool& p_static) // TODOKO position should possibly be float2. Pointer so we dont need to send pos every frame?
        {
            PotentialFieldActor* newActor = new PotentialFieldActorImpl();
            newActor->SetStatic(p_static); // needs to be done first since set position is dependent on static or not
            newActor->SetPosition(p_position); // TODOKO Might produce a error since no static objects will have a good position
            newActor->SetCharge(p_charge);
            newActor->SetRange(p_range);

            return newActor;
        }
        void PotentialFieldSubModuleImpl::AttachActor(PotentialField& o_field, PotentialFieldActor* p_actor) { o_field.AddActor(p_actor); }
        int PotentialFieldSubModuleImpl::GetNextStep() { return 0; }
        PotentialField* PotentialFieldSubModuleImpl::FindBestPotentialField(const DirectX::XMFLOAT3& p_position)
        {
            // Take out all PF that you are within
            using namespace std;
            using namespace DirectX;
            vector<PotentialField*> possibleMatches;
            PotentialField* returnField = nullptr;
            for (size_t i = 0; i < m_fields.size(); i++)
            {
                XMFLOAT3 fieldCenter = m_fields[i]->GetCenter();
                XMFLOAT2 quadSize = m_fields[i]->GetQuadSize();
                int quadsX = m_fields[i]->GetGrid().size(); // Get number of quads in x and y
                int quadsY = m_fields[i]->GetGrid()[0].size();
                float fieldHalfWidth = quadSize.x * (float)quadsX * 0.5f; // Half the fields width and height
                float fieldHalfHeight = quadSize.y * (float)quadsY * 0.5f;
                float fieldLeftBoundary = fieldCenter.x - fieldHalfWidth; // takes out the fields left, right and top, bottom boundary positions
                float fieldRightBoundary = fieldCenter.x + fieldHalfWidth;
                float fieldTopBoundary = fieldCenter.y + fieldHalfHeight;
                float fieldBottomBoundary = fieldCenter.y - fieldHalfHeight;
                if (p_position.x <= fieldRightBoundary && p_position.x >= fieldLeftBoundary &&
                    p_position.y <= fieldTopBoundary && p_position.y >= fieldBottomBoundary) // If inside the field
                {
                    possibleMatches.push_back(m_fields[i]); // Still need to check which field is closest in Y
                }
            }
            // Check which possible field is closest in Y
            float closestY = 1000000;
            for (size_t i = 0; i < possibleMatches.size(); i++)
            {
                XMFLOAT3 fieldCenter = possibleMatches[i]->GetCenter();
                float distanceY = p_position.y - fieldCenter.y;
                distanceY = abs(distanceY);
                if (distanceY < closestY)
                {
                    returnField = possibleMatches[i];
                }
            }
            if (returnField == nullptr)
            {
                // TODOKO log error / message
            }
            return returnField;
        }
    }
}<|endoftext|>