<commit_before>#include "components/camera.hpp"
#include "components/collision.hpp"
#include "components/player.hpp"
#include "components/render.hpp"
#include "components/transform.hpp"
#include "components/velocity.hpp"
#include "data.hpp"
#include "exception.hpp"

#include <fstream>
#include <iostream>
#include <map>

namespace core
{

const std::string component_name_camera{"camera"};
const std::string component_name_collision{"collision"};
const std::string component_name_player{"player"};
const std::string component_name_texture{"texture"};
const std::string component_name_transform{"transform"};
const std::string component_name_velocity{"velocity"};

void DataReader::factory_component_player(
    const Json::Value data, anax::Entity entity)
{
    const std::string prop_move_accel{"move_accel"};
    const std::string prop_top_speed{"top_speed"};

    check_required_component_property(
        data, component_name_player, prop_move_accel);
    float move_accel = data[prop_move_accel].asFloat();
    check_required_component_property(
        data, component_name_player, prop_top_speed);
    float top_speed = data[prop_top_speed].asFloat();
    entity.addComponent<components::PlayerComponent>(move_accel, top_speed);
}

void DataReader::factory_component_camera(
    const Json::Value data, anax::Entity entity)
{
    const std::string prop_zoom{"zoom"};
    const std::string prop_target{"target"};

    float zoom = data.get(prop_zoom, 1.0f).asFloat();

    check_required_component_property(data, component_name_camera, prop_target);
    std::string target = data[prop_target].asString();

    auto player = m_map_entities[target];

    entity.addComponent<components::CameraComponent>(player, zoom);
}

void DataReader::factory_component_collision(
    const Json::Value data, anax::Entity entity)
{
    const std::string prop_x{"x"};
    const std::string prop_y{"y"};
    const std::string prop_h{"h"};
    const std::string prop_w{"w"};
    const std::string prop_causeevents{"cancauseevents"};

    int x = data.get(prop_x, 0).asInt();
    int y = data.get(prop_y, 0).asInt();

    check_required_component_property(data, component_name_collision, prop_w);
    check_required_component_property(data, component_name_collision, prop_h);
    check_required_component_property(
        data, component_name_collision, prop_causeevents);
    int h = data[prop_h].asInt();
    int w = data[prop_w].asInt();
    bool cancauseevents = data[prop_causeevents].asBool();

    entity.addComponent<components::Collision>(x, y, h, w, cancauseevents);
}

void DataReader::factory_component_texture(
    const Json::Value data, anax::Entity entity)
{
    const std::string prop_texture_path{"texture_path"};

    check_required_component_property(
        data, component_name_texture, prop_texture_path);
    std::string texture_path = data[prop_texture_path].asString();

    entity.addComponent<components::TextureComponent>(texture_path);
}

void DataReader::factory_component_transform(
    const Json::Value data, anax::Entity entity)
{
    const std::string prop_pos_x{"pos_x"};
    const std::string prop_pos_y{"pos_y"};
    const std::string prop_size_x{"size_x"};
    const std::string prop_size_y{"size_y"};
    const std::string prop_rotation{"rotation"};
    const std::string prop_flip_horiz{"flip_horiz"};
    const std::string prop_flip_vert{"flip_vert"};

    check_required_component_property(
        data, component_name_transform, prop_pos_x);
    float pos_x = data[prop_pos_x].asFloat();

    check_required_component_property(
        data, component_name_transform, prop_pos_y);
    float pos_y = data[prop_pos_y].asFloat();

    check_required_component_property(
        data, component_name_transform, prop_size_x);
    float size_x = data[prop_size_x].asFloat();

    check_required_component_property(
        data, component_name_transform, prop_size_y);
    float size_y = data[prop_size_y].asFloat();

    check_required_component_property(
        data, component_name_transform, prop_rotation);
    float rotation = data[prop_rotation].asFloat();

    check_required_component_property(
        data, component_name_transform, prop_flip_vert);
    bool flip_vert = data[prop_flip_vert].asBool();

    check_required_component_property(
        data, component_name_transform, prop_flip_horiz);
    bool flip_horiz = data[prop_flip_horiz].asBool();

    entity.addComponent<components::TransformComponent>(
        pos_x, pos_y, size_x, size_y, rotation, flip_vert, flip_horiz);
}

void DataReader::factory_component_velocity(
    const Json::Value data, anax::Entity entity)
{
    const std::string prop_mass{"mass"};
    const std::string prop_friction{"friction"};
    const std::string prop_force_x{"force_x"};
    const std::string prop_force_y{"force_y"};
    const float prop_force_x_default = 0.0f;
    const float prop_force_y_default = 0.0f;
    const std::string prop_vel_x{"vel_x"};
    const std::string prop_vel_y{"vel_y"};
    const float prop_vel_x_default = 0.0f;
    const float prop_vel_y_default = 0.0f;

    float velocity_x = data.get(prop_vel_x, prop_vel_x_default).asFloat();
    float velocity_y = data.get(prop_vel_y, prop_vel_y_default).asFloat();
    float force_x = data.get(prop_force_x, prop_force_x_default).asFloat();
    float force_y = data.get(prop_force_y, prop_force_y_default).asFloat();
    check_required_component_property(data, component_name_velocity, prop_mass);
    float mass = data[prop_mass].asFloat();

    check_required_component_property(
        data, component_name_velocity, prop_friction);
    float friction = data[prop_friction].asFloat();

    entity.addComponent<components::VelocityComponent>(
        mass, friction, velocity_x, velocity_y, force_x, force_y);
}

DataReader::DataReader(std::string filename) : JsonFileReader(filename)
{
    m_sp_logger = logging_get_logger("data");

    component_factories.insert(std::make_pair(
        component_name_camera, &DataReader::factory_component_camera));
    component_factories.insert(std::make_pair(
        component_name_collision, &DataReader::factory_component_collision));
    component_factories.insert(std::make_pair(
        component_name_player, &DataReader::factory_component_player));
    component_factories.insert(std::make_pair(
        component_name_texture, &DataReader::factory_component_texture));
    component_factories.insert(std::make_pair(
        component_name_transform, &DataReader::factory_component_transform));
    component_factories.insert(std::make_pair(
        component_name_velocity, &DataReader::factory_component_velocity));
}

anax::Entity DataReader::makeEntity(std::string entityname, anax::World& world)
{
    const std::string prop_name_components{"components"};
    const std::string prop_name_template{"template"};

    if (!m_json_data.isMember(entityname))
    {
        m_sp_logger->error("JSON data {} missing referenced entity {}",
            m_str_description,
            entityname);
        throw ExceptionParseFailure(
            m_str_description, "Missing referenced entity");
    }

    auto entity = world.createEntity();

    Json::Value entity_data;
    if (m_json_data[entityname].isMember(prop_name_template))
    {
        std::string templatename =
            m_json_data[entityname][prop_name_template].asString();
        m_sp_logger->info(
            "Using template {} for entity {}", templatename, entityname);
        entity_data = merge_values(
            m_map_references[templatename], m_json_data[entityname]);
    }
    else
    {
        entity_data = m_json_data[entityname];
    }

    if (!entity_data.isMember(prop_name_components))
    {
        m_sp_logger->error("JSON data {} entity {} missing {}",
            m_str_description,
            entityname,
            prop_name_components);
        throw ExceptionParseFailure(
            m_str_description, "JSON data entity missing components");
    }

    auto components = entity_data[prop_name_components];

    m_sp_logger->info("Components list for entity name {} size {}",
        entityname,
        components.size());

    Json::Value::Members member_names = components.getMemberNames();
    for (auto type : member_names)
    {
        m_sp_logger->info("Creating component {}", type);

        factory_method fp = component_factories[type];
        (this->*fp)(components[type], entity);
    }

    entity.activate();
    return entity;
}

void DataReader::makeEntities(anax::World& world)
{
    const std::string object_name_world{"world"};
    const std::string prop_name_entities{"entities"};

    scan_references(m_json_data);

    if (!m_json_data.isMember(object_name_world))
    {
        m_sp_logger->error(
            "JSON data {} missing {}", m_str_description, object_name_world);
        throw ExceptionParseFailure(
            m_str_description, "JSON Data missing world");
    }
    if (!m_json_data[object_name_world].isMember(prop_name_entities))
    {
        m_sp_logger->error("JSON data {} world missing {}",
            m_str_description,
            prop_name_entities);
        throw ExceptionParseFailure(
            m_str_description, "JSON Data world missing entities");
    }

    auto entities = m_json_data[object_name_world][prop_name_entities];
    m_sp_logger->info("Entities list for world size {}", entities.size());
    for (auto value : entities)
    {
        std::string name = value.asString();
        auto entity = makeEntity(name, world);
        m_map_entities.insert({name, entity});
    }
}

LevelReader::LevelReader(std::string filename) : JsonFileReader(filename)
{
    m_sp_logger = logging_get_logger("data");
}

void LevelReader::build_level(std::unique_ptr<Level>& up_level)
{
    uint16_t size_x = m_json_data["width"].asInt();
    uint16_t size_y = m_json_data["height"].asInt();
    float tileheight = m_json_data["tileheight"].asFloat();
    float scale = m_json_data["properties"].get("scale", 1.0).asFloat();

    up_level = std::make_unique<Level>(size_x, size_y, tileheight * scale);
    auto p_level = up_level.get();

    // TODO(Keegan): Use tilewidth as well
    auto tilesets = m_json_data["tilesets"];
    std::string tileset_source;
    for (auto it = tilesets.begin(); it != tilesets.end(); ++it)
    {
        int firstgid = (*it)["firstgid"].asInt();
        tileset_source = (*it)["source"].asString();
        m_sp_logger->info(
            "Found a tileset gid {} source {}", firstgid, tileset_source);
    }
    // Only load last tileset for now
    auto p_tileset = load_tileset(tileset_source);
    p_level->set_tileset(p_tileset);

    auto layers = m_json_data["layers"];
    for (auto it = layers.begin(); it != layers.end(); ++it)
    {
        int height = (*it)["height"].asInt();
        int width = (*it)["width"].asInt();
        float opacity = (*it)["opacity"].asFloat();
        std::string name = (*it)["name"].asString();
        m_sp_logger->info(
            "found a layer named {} width {} height {} opacity {}",
            name,
            width,
            height,
            opacity);
        auto data = (*it)["data"];
        for (uint16_t index = 0; index < data.size(); ++index)
        {
            uint16_t tile_x = index % width;
            uint16_t tile_y = index / width;
            int16_t tilegid = data[index].asInt();
            p_level->set(tile_x, tile_y, tilegid);
        }
    }

    return;
}

LevelTileSet* LevelReader::load_tileset(std::string filename)
{
    Json::Reader reader_json;
    filename.insert(0, "data/");
    m_sp_logger->info("Loading data from {}", filename);
    std::ifstream config_file(filename, std::ifstream::binary);
    if (!reader_json.parse(config_file, m_json_tileset))
    {
        m_sp_logger->error(
            "Failed to parse JSON file {}:", filename, "JSON format error");
        m_sp_logger->error(reader_json.getFormattedErrorMessages());
        throw ExceptionParseFailure(
            m_str_description, std::string("JSON format error"));
    }
    std::string image_filename = m_json_tileset["image"].asString();
    std::string name = m_json_tileset["name"].asString();
    uint16_t tilewidth = m_json_tileset["tilewidth"].asInt();
    uint16_t tileheight = m_json_tileset["tilewidth"].asInt();
    uint16_t tilecount = m_json_tileset["tilecount"].asInt();
    uint16_t columns = m_json_tileset["columns"].asInt();
    uint16_t margin = m_json_tileset["margin"].asInt();
    uint16_t spacing = m_json_tileset["spacing"].asInt();
    return new LevelTileSet{name,
        image_filename,
        columns,
        tilecount,
        tilewidth,
        tileheight,
        spacing,
        margin};
}

} // namespace core
<commit_msg>Data: Add functions for dealing with path names<commit_after>#include "components/camera.hpp"
#include "components/collision.hpp"
#include "components/player.hpp"
#include "components/render.hpp"
#include "components/transform.hpp"
#include "components/velocity.hpp"
#include "data.hpp"
#include "exception.hpp"

#include <fstream>
#include <iostream>
#include <map>

namespace core
{

const std::string component_name_camera{"camera"};
const std::string component_name_collision{"collision"};
const std::string component_name_player{"player"};
const std::string component_name_texture{"texture"};
const std::string component_name_transform{"transform"};
const std::string component_name_velocity{"velocity"};

std::string basename(const std::string& pathname)
{
    // TODO(Keegan, Check if works on Windows)
    // TODO(Keegan, Test properly)
    return {std::find_if(pathname.rbegin(),
                pathname.rend(),
                [](char c) { return (c == '/' || c == '\\'); })
                .base(),
        pathname.end()};
}

std::string pathname(const std::string& pathname)
{
    // TODO(Keegan, Check if works on Windows)
    // TODO(Keegan, Test properly)
    return {pathname.begin(),
        std::find_if(pathname.rbegin(), pathname.rend(), [](char c) {
            return (c == '/' || c == '\\');
        }).base()};
}

void DataReader::factory_component_player(
    const Json::Value data, anax::Entity entity)
{
    const std::string prop_move_accel{"move_accel"};
    const std::string prop_top_speed{"top_speed"};

    check_required_component_property(
        data, component_name_player, prop_move_accel);
    float move_accel = data[prop_move_accel].asFloat();
    check_required_component_property(
        data, component_name_player, prop_top_speed);
    float top_speed = data[prop_top_speed].asFloat();
    entity.addComponent<components::PlayerComponent>(move_accel, top_speed);
}

void DataReader::factory_component_camera(
    const Json::Value data, anax::Entity entity)
{
    const std::string prop_zoom{"zoom"};
    const std::string prop_target{"target"};

    float zoom = data.get(prop_zoom, 1.0f).asFloat();

    check_required_component_property(data, component_name_camera, prop_target);
    std::string target = data[prop_target].asString();

    auto player = m_map_entities[target];

    entity.addComponent<components::CameraComponent>(player, zoom);
}

void DataReader::factory_component_collision(
    const Json::Value data, anax::Entity entity)
{
    const std::string prop_x{"x"};
    const std::string prop_y{"y"};
    const std::string prop_h{"h"};
    const std::string prop_w{"w"};
    const std::string prop_causeevents{"cancauseevents"};

    int x = data.get(prop_x, 0).asInt();
    int y = data.get(prop_y, 0).asInt();

    check_required_component_property(data, component_name_collision, prop_w);
    check_required_component_property(data, component_name_collision, prop_h);
    check_required_component_property(
        data, component_name_collision, prop_causeevents);
    int h = data[prop_h].asInt();
    int w = data[prop_w].asInt();
    bool cancauseevents = data[prop_causeevents].asBool();

    entity.addComponent<components::Collision>(x, y, h, w, cancauseevents);
}

void DataReader::factory_component_texture(
    const Json::Value data, anax::Entity entity)
{
    const std::string prop_texture_path{"texture_path"};

    check_required_component_property(
        data, component_name_texture, prop_texture_path);
    std::string texture_path = data[prop_texture_path].asString();

    entity.addComponent<components::TextureComponent>(texture_path);
}

void DataReader::factory_component_transform(
    const Json::Value data, anax::Entity entity)
{
    const std::string prop_pos_x{"pos_x"};
    const std::string prop_pos_y{"pos_y"};
    const std::string prop_size_x{"size_x"};
    const std::string prop_size_y{"size_y"};
    const std::string prop_rotation{"rotation"};
    const std::string prop_flip_horiz{"flip_horiz"};
    const std::string prop_flip_vert{"flip_vert"};

    check_required_component_property(
        data, component_name_transform, prop_pos_x);
    float pos_x = data[prop_pos_x].asFloat();

    check_required_component_property(
        data, component_name_transform, prop_pos_y);
    float pos_y = data[prop_pos_y].asFloat();

    check_required_component_property(
        data, component_name_transform, prop_size_x);
    float size_x = data[prop_size_x].asFloat();

    check_required_component_property(
        data, component_name_transform, prop_size_y);
    float size_y = data[prop_size_y].asFloat();

    check_required_component_property(
        data, component_name_transform, prop_rotation);
    float rotation = data[prop_rotation].asFloat();

    check_required_component_property(
        data, component_name_transform, prop_flip_vert);
    bool flip_vert = data[prop_flip_vert].asBool();

    check_required_component_property(
        data, component_name_transform, prop_flip_horiz);
    bool flip_horiz = data[prop_flip_horiz].asBool();

    entity.addComponent<components::TransformComponent>(
        pos_x, pos_y, size_x, size_y, rotation, flip_vert, flip_horiz);
}

void DataReader::factory_component_velocity(
    const Json::Value data, anax::Entity entity)
{
    const std::string prop_mass{"mass"};
    const std::string prop_friction{"friction"};
    const std::string prop_force_x{"force_x"};
    const std::string prop_force_y{"force_y"};
    const float prop_force_x_default = 0.0f;
    const float prop_force_y_default = 0.0f;
    const std::string prop_vel_x{"vel_x"};
    const std::string prop_vel_y{"vel_y"};
    const float prop_vel_x_default = 0.0f;
    const float prop_vel_y_default = 0.0f;

    float velocity_x = data.get(prop_vel_x, prop_vel_x_default).asFloat();
    float velocity_y = data.get(prop_vel_y, prop_vel_y_default).asFloat();
    float force_x = data.get(prop_force_x, prop_force_x_default).asFloat();
    float force_y = data.get(prop_force_y, prop_force_y_default).asFloat();
    check_required_component_property(data, component_name_velocity, prop_mass);
    float mass = data[prop_mass].asFloat();

    check_required_component_property(
        data, component_name_velocity, prop_friction);
    float friction = data[prop_friction].asFloat();

    entity.addComponent<components::VelocityComponent>(
        mass, friction, velocity_x, velocity_y, force_x, force_y);
}

DataReader::DataReader(std::string filename) : JsonFileReader(filename)
{
    m_sp_logger = logging_get_logger("data");

    component_factories.insert(std::make_pair(
        component_name_camera, &DataReader::factory_component_camera));
    component_factories.insert(std::make_pair(
        component_name_collision, &DataReader::factory_component_collision));
    component_factories.insert(std::make_pair(
        component_name_player, &DataReader::factory_component_player));
    component_factories.insert(std::make_pair(
        component_name_texture, &DataReader::factory_component_texture));
    component_factories.insert(std::make_pair(
        component_name_transform, &DataReader::factory_component_transform));
    component_factories.insert(std::make_pair(
        component_name_velocity, &DataReader::factory_component_velocity));
}

anax::Entity DataReader::makeEntity(std::string entityname, anax::World& world)
{
    const std::string prop_name_components{"components"};
    const std::string prop_name_template{"template"};

    if (!m_json_data.isMember(entityname))
    {
        m_sp_logger->error("JSON data {} missing referenced entity {}",
            m_str_description,
            entityname);
        throw ExceptionParseFailure(
            m_str_description, "Missing referenced entity");
    }

    auto entity = world.createEntity();

    Json::Value entity_data;
    if (m_json_data[entityname].isMember(prop_name_template))
    {
        std::string templatename =
            m_json_data[entityname][prop_name_template].asString();
        m_sp_logger->info(
            "Using template {} for entity {}", templatename, entityname);
        entity_data = merge_values(
            m_map_references[templatename], m_json_data[entityname]);
    }
    else
    {
        entity_data = m_json_data[entityname];
    }

    if (!entity_data.isMember(prop_name_components))
    {
        m_sp_logger->error("JSON data {} entity {} missing {}",
            m_str_description,
            entityname,
            prop_name_components);
        throw ExceptionParseFailure(
            m_str_description, "JSON data entity missing components");
    }

    auto components = entity_data[prop_name_components];

    m_sp_logger->info("Components list for entity name {} size {}",
        entityname,
        components.size());

    Json::Value::Members member_names = components.getMemberNames();
    for (auto type : member_names)
    {
        m_sp_logger->info("Creating component {}", type);

        factory_method fp = component_factories[type];
        (this->*fp)(components[type], entity);
    }

    entity.activate();
    return entity;
}

void DataReader::makeEntities(anax::World& world)
{
    const std::string object_name_world{"world"};
    const std::string prop_name_entities{"entities"};

    scan_references(m_json_data);

    if (!m_json_data.isMember(object_name_world))
    {
        m_sp_logger->error(
            "JSON data {} missing {}", m_str_description, object_name_world);
        throw ExceptionParseFailure(
            m_str_description, "JSON Data missing world");
    }
    if (!m_json_data[object_name_world].isMember(prop_name_entities))
    {
        m_sp_logger->error("JSON data {} world missing {}",
            m_str_description,
            prop_name_entities);
        throw ExceptionParseFailure(
            m_str_description, "JSON Data world missing entities");
    }

    auto entities = m_json_data[object_name_world][prop_name_entities];
    m_sp_logger->info("Entities list for world size {}", entities.size());
    for (auto value : entities)
    {
        std::string name = value.asString();
        auto entity = makeEntity(name, world);
        m_map_entities.insert({name, entity});
    }
}

LevelReader::LevelReader(std::string filename) : JsonFileReader(filename)
{
    m_sp_logger = logging_get_logger("data");
}

void LevelReader::build_level(std::unique_ptr<Level>& up_level)
{
    uint16_t size_x = m_json_data["width"].asInt();
    uint16_t size_y = m_json_data["height"].asInt();
    float tileheight = m_json_data["tileheight"].asFloat();
    float scale = m_json_data["properties"].get("scale", 1.0).asFloat();

    up_level = std::make_unique<Level>(size_x, size_y, tileheight * scale);
    auto p_level = up_level.get();

    // TODO(Keegan): Use tilewidth as well
    auto tilesets = m_json_data["tilesets"];
    std::string tileset_source;
    for (auto it = tilesets.begin(); it != tilesets.end(); ++it)
    {
        int firstgid = (*it)["firstgid"].asInt();
        tileset_source = (*it)["source"].asString();
        m_sp_logger->info(
            "Found a tileset gid {} source {}", firstgid, tileset_source);
    }
    // Only load last tileset for now
    auto p_tileset = load_tileset(tileset_source);
    p_level->set_tileset(p_tileset);

    auto layers = m_json_data["layers"];
    for (auto it = layers.begin(); it != layers.end(); ++it)
    {
        int height = (*it)["height"].asInt();
        int width = (*it)["width"].asInt();
        float opacity = (*it)["opacity"].asFloat();
        std::string name = (*it)["name"].asString();
        m_sp_logger->info(
            "found a layer named {} width {} height {} opacity {}",
            name,
            width,
            height,
            opacity);
        auto data = (*it)["data"];
        for (uint16_t index = 0; index < data.size(); ++index)
        {
            uint16_t tile_x = index % width;
            uint16_t tile_y = index / width;
            int16_t tilegid = data[index].asInt();
            p_level->set(tile_x, tile_y, tilegid);
        }
    }

    return;
}

LevelTileSet* LevelReader::load_tileset(std::string filename)
{
    Json::Reader reader_json;
    filename.insert(0, "data/");
    m_sp_logger->info("Loading data from {}", filename);
    std::ifstream config_file(filename, std::ifstream::binary);
    if (!reader_json.parse(config_file, m_json_tileset))
    {
        m_sp_logger->error(
            "Failed to parse JSON file {}:", filename, "JSON format error");
        m_sp_logger->error(reader_json.getFormattedErrorMessages());
        throw ExceptionParseFailure(
            m_str_description, std::string("JSON format error"));
    }
    std::string image_filename = m_json_tileset["image"].asString();
    std::string name = m_json_tileset["name"].asString();
    uint16_t tilewidth = m_json_tileset["tilewidth"].asInt();
    uint16_t tileheight = m_json_tileset["tilewidth"].asInt();
    uint16_t tilecount = m_json_tileset["tilecount"].asInt();
    uint16_t columns = m_json_tileset["columns"].asInt();
    uint16_t margin = m_json_tileset["margin"].asInt();
    uint16_t spacing = m_json_tileset["spacing"].asInt();
    return new LevelTileSet{name,
        image_filename,
        columns,
        tilecount,
        tilewidth,
        tileheight,
        spacing,
        margin};
}

} // namespace core
<|endoftext|>


<commit_before>// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
//
// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This library 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 2.1 of the License.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
//
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//

//  SMESH SMDS : implementaion of Salome mesh data structure
//  File   : SMDS_MeshNode.hxx
//  Module : SMESH
//
#ifndef _SMDS_MeshNode_HeaderFile
#define _SMDS_MeshNode_HeaderFile

#include "SMESH_SMDS.hxx"

#include "SMDS_MeshElement.hxx"
#include "SMDS_Position.hxx"
#include "ObjectPool.hxx"

class SMDS_EXPORT SMDS_MeshNode: public SMDS_MeshElement
{
public:
  friend class SMESHDS_Mesh;
  friend class SMDS_Mesh;
  friend class ObjectPool<SMDS_MeshNode>;
  friend class SMDS_VtkFace;

  void Print(std::ostream & OS) const;
  double X() const; // ! NOT thread safe methods !
  double Y() const;
  double Z() const;
  void   GetXYZ(double xyz[3]) const; // thread safe getting coords
  SMDS_ElemIteratorPtr    GetInverseElementIterator(SMDSAbs_ElementType type=SMDSAbs_All) const;
  int                     NbInverseElements(SMDSAbs_ElementType type=SMDSAbs_All) const;
  const SMDS_PositionPtr& GetPosition() const;
  virtual SMDSAbs_ElementType  GetType() const;
  virtual vtkIdType            GetVtkType() const;
  virtual SMDSAbs_EntityType   GetEntityType() const { return SMDSEntity_Node;}
  virtual SMDSAbs_GeometryType GetGeomType() const   { return SMDSGeom_NONE; }
  virtual int                  NbNodes() const;

  void SetPosition(const SMDS_PositionPtr& aPos);
  void setXYZ(double x, double y, double z);

  static int nbNodes;

protected:
  SMDS_MeshNode();
  SMDS_MeshNode(int id, int meshId, int shapeId = -1, double x=0, double y=0, double z=0);
  virtual ~SMDS_MeshNode();
  void init(int id, int meshId, int shapeId = -1, double x=0, double y=0, double z=0);
  inline void setVtkId(int vtkId) { myVtkID = vtkId; };
  double* getCoord() const;
  void AddInverseElement(const SMDS_MeshElement * ME);
  void RemoveInverseElement(const SMDS_MeshElement * parent);
  void ClearInverseElements();
  bool emptyInverseElements();

  SMDS_ElemIteratorPtr
  elementsIterator(SMDSAbs_ElementType type) const;

private:
  SMDS_PositionPtr myPosition;
};

#endif
<commit_msg>Rm duplicated SMDS_MeshElement::setVtkId(int vtkId)<commit_after>// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
//
// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This library 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 2.1 of the License.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
//
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//

//  SMESH SMDS : implementaion of Salome mesh data structure
//  File   : SMDS_MeshNode.hxx
//  Module : SMESH
//
#ifndef _SMDS_MeshNode_HeaderFile
#define _SMDS_MeshNode_HeaderFile

#include "SMESH_SMDS.hxx"

#include "SMDS_MeshElement.hxx"
#include "SMDS_Position.hxx"
#include "ObjectPool.hxx"

class SMDS_EXPORT SMDS_MeshNode: public SMDS_MeshElement
{
public:
  friend class SMESHDS_Mesh;
  friend class SMDS_Mesh;
  friend class ObjectPool<SMDS_MeshNode>;
  friend class SMDS_VtkFace;

  void Print(std::ostream & OS) const;
  double X() const; // ! NOT thread safe methods !
  double Y() const;
  double Z() const;
  void   GetXYZ(double xyz[3]) const; // thread safe getting coords
  SMDS_ElemIteratorPtr    GetInverseElementIterator(SMDSAbs_ElementType type=SMDSAbs_All) const;
  int                     NbInverseElements(SMDSAbs_ElementType type=SMDSAbs_All) const;
  const SMDS_PositionPtr& GetPosition() const;
  virtual SMDSAbs_ElementType  GetType() const;
  virtual vtkIdType            GetVtkType() const;
  virtual SMDSAbs_EntityType   GetEntityType() const { return SMDSEntity_Node;}
  virtual SMDSAbs_GeometryType GetGeomType() const   { return SMDSGeom_NONE; }
  virtual int                  NbNodes() const;

  void SetPosition(const SMDS_PositionPtr& aPos);
  void setXYZ(double x, double y, double z);

  static int nbNodes;

protected:
  SMDS_MeshNode();
  SMDS_MeshNode(int id, int meshId, int shapeId = -1, double x=0, double y=0, double z=0);
  virtual ~SMDS_MeshNode();
  void init(int id, int meshId, int shapeId = -1, double x=0, double y=0, double z=0);
  double* getCoord() const;
  void AddInverseElement(const SMDS_MeshElement * ME);
  void RemoveInverseElement(const SMDS_MeshElement * parent);
  void ClearInverseElements();
  bool emptyInverseElements();

  SMDS_ElemIteratorPtr
  elementsIterator(SMDSAbs_ElementType type) const;

private:
  SMDS_PositionPtr myPosition;
};

#endif
<|endoftext|>


<commit_before>/*=========================================================================

Library:   TubeTK

Copyright 2010 Kitware Inc. 28 Corporate Drive,
Clifton Park, NY, 12065, USA.

All rights reserved.

Licensed under the Apache License, Version 2.0 ( the "License" );
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

=========================================================================*/

#ifndef __itktubeTubeSpatialObjectToImageFilter_hxx
#define __itktubeTubeSpatialObjectToImageFilter_hxx

#include "itktubeTubeSpatialObjectToImageFilter.h"

#include <itkImageRegionIteratorWithIndex.h>

#include <vnl/vnl_vector.h>

/** Constructor */
template< unsigned int ObjectDimension, class TOutputImage,
  class TRadiusImage, class TTangentImage >
TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage, TRadiusImage,
  TTangentImage>
::TubeSpatialObjectToImageFilter( void )
{
  m_UseRadius = false;
  m_Cumulative = false;
  m_BuildRadiusImage = false;
  m_BuildTangentImage = false;
  m_FallOff = 0.0;

  // This is a little bit tricky since the 2nd an 3rd outputs are
  //   not always computed
  this->SetNumberOfRequiredOutputs( 3 );
  m_RadiusImage = TRadiusImage::New();
  this->SetNthOutput( 1, m_RadiusImage );

  m_TangentImage = TTangentImage::New();
  this->SetNthOutput( 2, m_TangentImage );
}

/** Destructor */
template< unsigned int ObjectDimension, class TOutputImage,
  class TRadiusImage, class TTangentImage >
TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage, TRadiusImage,
  TTangentImage >
::~TubeSpatialObjectToImageFilter( void )
{
}

/** Return the Radius Image */
template< unsigned int ObjectDimension, class TOutputImage,
  class TRadiusImage, class TTangentImage >
typename TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage,
  TRadiusImage, TTangentImage >::RadiusImagePointer
TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage, TRadiusImage,
  TTangentImage>
::GetRadiusImage( void )
{
  return dynamic_cast< TRadiusImage * >( this->ProcessObject::GetOutput( 1 ) );
}

/** Return the tangent Image */
template< unsigned int ObjectDimension, class TOutputImage,
  class TRadiusImage, class TTangentImage >
typename TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage,
  TRadiusImage, TTangentImage >::TangentImagePointer
TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage, TRadiusImage,
  TTangentImage >
::GetTangentImage( void )
{
  return dynamic_cast< TTangentImage * >(
    this->ProcessObject::GetOutput( 2 ) );
}

/** Update */
template< unsigned int ObjectDimension, class TOutputImage,
  class TRadiusImage, class TTangentImage >
void
TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage, TRadiusImage,
  TTangentImage >
::GenerateData( void )
{
  itkDebugMacro( << "TubeSpatialObjectToImageFilter::Update() called." );

  //Get the input and output pointers
  const typename SuperClass::InputSpatialObjectType   * InputTube =
    this->GetInput();
  typename SuperClass::OutputImagePointer             OutputImage =
    this->GetOutput();

  // Generate the image
  typename OutputImageType::RegionType region;
  if( this->m_Size[0] == 0 )
    {
    std::cout << "WARNING: Size not set." << std::endl;
    std::cout << "   Reverting to an incorrect method to compute region."
      << std::endl;
    SizeType size;

    typename SuperClass::InputSpatialObjectType::BoundingBoxType::PointType
      maxPoint;
    maxPoint = InputTube->GetBoundingBox()->GetMaximum();

    typename OutputImageType::PointType   physicalSize;

    unsigned int buffer = 4;

    for( unsigned int i=0; i<ObjectDimension; i++ )
      {
      maxPoint[i] = maxPoint[i] *
                    ( InputTube->GetIndexToObjectTransform() )
                      ->GetScaleComponent()[i];
      physicalSize[i] = maxPoint[i] - this->m_Origin[i];

      /** Get the origin point within the image so that the object
       * remains in the image **/
      size[i] = ( long unsigned int )(
        physicalSize[i] / this->m_Spacing[i] ) + buffer;
      }
    region.SetSize( size );
    }
  else
    {
    region.SetSize( this->m_Size );
    }

  typename OutputImageType::IndexType index;
  index.Fill( 0 );
  region.SetIndex( index );

  OutputImage->SetRegions( region );
  OutputImage->SetSpacing( this->m_Spacing );
  OutputImage->SetOrigin( this->m_Origin );
  OutputImage->Allocate();
  OutputImage->FillBuffer( 0 );

  itk::ContinuousIndex<double, ObjectDimension> point;

  m_RadiusImage = this->GetRadiusImage();
  //Build radius image for processing
  if( m_BuildRadiusImage )
    {
    m_RadiusImage->SetRegions( region );
    m_RadiusImage->SetSpacing( this->m_Spacing );
    m_RadiusImage->SetOrigin( this->m_Origin );
    m_RadiusImage->Allocate();
    m_RadiusImage->FillBuffer( 0 );
    }

  m_TangentImage = this->GetTangentImage();
  //Build radius image for processing
  if( m_BuildTangentImage )
    {
    m_TangentImage->SetRegions( region );
    m_TangentImage->SetSpacing( this->m_Spacing );
    m_TangentImage->SetOrigin( this->m_Origin );
    m_TangentImage->Allocate();
    TangentPixelType v;
    v.Fill( 0 );
    m_TangentImage->FillBuffer( v );
    }

  // Get the list of tubes
  char tubeName[] = "Tube";
  ChildrenListType* tubeList = InputTube->GetChildren(
    this->m_ChildrenDepth, tubeName );

  //int size = tubeList->size();

  typedef typename ChildrenListType::iterator ChildrenIteratorType;
  ChildrenIteratorType TubeIterator = tubeList->begin();

  typename OutputImageType::IndexType index2;

  while( TubeIterator != tubeList->end() )
    {
    TubeType * tube = ( TubeType * )TubeIterator->GetPointer();

    typename TubeType::TransformType * tubeIndexPhysTransform =
      tube->GetIndexToWorldTransform();

    // Force the computation of the tangents
    if( m_BuildTangentImage )
      {
      tube->RemoveDuplicatePoints();
      tube->ComputeTangentAndNormals();
      }

    for( unsigned int k=0; k < tube->GetNumberOfPoints(); k++ )
      {
      typedef typename TubeType::TubePointType TubePointType;
      const TubePointType* tubePoint = static_cast<const TubePointType*>(
        tube->GetPoint( k ) );
      OutputImage->TransformPhysicalPointToContinuousIndex(
	tubeIndexPhysTransform->TransformPoint( tubePoint->GetPosition() ),
	point );
      for( unsigned int i=0; i<ObjectDimension; i++ )
        {
        index[i] = ( long int )( point[i]+0.5 );
        }
      bool IsInside = OutputImage->GetLargestPossibleRegion().IsInside(index);

      if( IsInside )
        {
        // Density Image
        if( m_Cumulative )
          {
          OutputImage->SetPixel( index, OutputImage->GetPixel( index )+1 );
          }
        else
          {
          OutputImage->SetPixel( index, 1 );
          }

        // Tangent Image
        if( m_BuildTangentImage )
          {
          // Convert the tangent type to the actual tangent image pixel type
          typename TubeType::VectorType t = tubePoint->GetTangent();
          TangentPixelType tp;
          for( unsigned int tpind = 0;tpind<ObjectDimension;tpind++ )
            {
            tp[tpind] = t[tpind];
            }
          m_TangentImage->SetPixel( index, tp );
          }

        // Radius Image and Density image with radius
        if( m_UseRadius )
          {
          double phys_pt_radius = tubePoint->GetRadius() *
                                      tube
                                      ->GetIndexToObjectTransform()
                                      ->GetScaleComponent()[0];
          if( m_BuildRadiusImage )
            {
            m_RadiusImage->SetPixel( index,
                                  static_cast<RadiusPixelType>(
                                      phys_pt_radius ) );
            }

          long radius = ( long int )( phys_pt_radius / this->m_Spacing[0] );

          double step = radius/2;
          while( step > 1 )
            {
            step /= 2;
            }
          if( step < 0.5 )
            {
            step = 0.5;
            }
          if( ObjectDimension == 2 )
            {
            for( double x=-radius; x<=radius+step/2; x+=step )
              {
              for( double y=-radius; y<=radius+step/2; y+=step )
                {
                if( ( ( x*x ) +( y*y ) ) <= ( radius*radius ) )
                  // test  inside the sphere
                  {
                  index2[0]=( long )( point[0]+x+0.5 );
                  index2[1]=( long )( point[1]+y+0.5 );
                  if( OutputImage->GetLargestPossibleRegion().IsInside( index2 ) )
                    {
                    typedef typename OutputImageType::PixelType PixelType;
                    if( m_Cumulative )
                      {
                      OutputImage->SetPixel( index2,
                                            ( PixelType )( OutputImage
                                                        ->GetPixel( index2 )
                                            + 0.5 ) );
                      }
                    else
                      {
                      OutputImage->SetPixel( index2, 1 );
                      }
                    if( m_BuildRadiusImage )
                      {
                      m_RadiusImage->SetPixel( index2, phys_pt_radius );
                      }
                    }
                  }
                }
              }
            }
          else if( ObjectDimension == 3 )
            {
            for( double x=-radius; x<=radius+step/2; x+=step )
              {
              for( double y=-radius; y<=radius+step/2; y+=step )
                {
                for( double z=-radius; z<=radius+step/2; z+=step )
                  {
                  if( ( ( x*x ) +( y*y ) +( z*z ) ) <= ( radius*radius ) )
                    // test  inside the sphere
                    {
                    index2[0]=( long )( point[0]+x+0.5 );
                    index2[1]=( long )( point[1]+y+0.5 );
                    index2[2]=( long )( point[2]+z+0.5 );

                    // Test that point is within the output image boundries
                    if( OutputImage->GetLargestPossibleRegion().IsInside( index2 ) )
                      {
                      OutputImage->SetPixel( index2, 1 );
                      if( m_BuildRadiusImage )
                        {
                        m_RadiusImage->SetPixel( index2, phys_pt_radius );
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    ++TubeIterator;
    }

  delete tubeList;

  itkDebugMacro( << "TubeSpatialObjectToImageFilter::Update() finished." );

} // End update function

#endif // End !defined( __itktubeTubeSpatialObjectToImageFilter_hxx )
<commit_msg>Add TODO<commit_after>/*=========================================================================

Library:   TubeTK

Copyright 2010 Kitware Inc. 28 Corporate Drive,
Clifton Park, NY, 12065, USA.

All rights reserved.

Licensed under the Apache License, Version 2.0 ( the "License" );
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

=========================================================================*/

#ifndef __itktubeTubeSpatialObjectToImageFilter_hxx
#define __itktubeTubeSpatialObjectToImageFilter_hxx

#include "itktubeTubeSpatialObjectToImageFilter.h"

#include <itkImageRegionIteratorWithIndex.h>

#include <vnl/vnl_vector.h>

/** Constructor */
template< unsigned int ObjectDimension, class TOutputImage,
  class TRadiusImage, class TTangentImage >
TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage, TRadiusImage,
  TTangentImage>
::TubeSpatialObjectToImageFilter( void )
{
  m_UseRadius = false;
  m_Cumulative = false;
  m_BuildRadiusImage = false;
  m_BuildTangentImage = false;
  m_FallOff = 0.0;

  // This is a little bit tricky since the 2nd an 3rd outputs are
  //   not always computed
  this->SetNumberOfRequiredOutputs( 3 );
  m_RadiusImage = TRadiusImage::New();
  this->SetNthOutput( 1, m_RadiusImage );

  m_TangentImage = TTangentImage::New();
  this->SetNthOutput( 2, m_TangentImage );
}

/** Destructor */
template< unsigned int ObjectDimension, class TOutputImage,
  class TRadiusImage, class TTangentImage >
TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage, TRadiusImage,
  TTangentImage >
::~TubeSpatialObjectToImageFilter( void )
{
}

/** Return the Radius Image */
template< unsigned int ObjectDimension, class TOutputImage,
  class TRadiusImage, class TTangentImage >
typename TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage,
  TRadiusImage, TTangentImage >::RadiusImagePointer
TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage, TRadiusImage,
  TTangentImage>
::GetRadiusImage( void )
{
  return dynamic_cast< TRadiusImage * >( this->ProcessObject::GetOutput( 1 ) );
}

/** Return the tangent Image */
template< unsigned int ObjectDimension, class TOutputImage,
  class TRadiusImage, class TTangentImage >
typename TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage,
  TRadiusImage, TTangentImage >::TangentImagePointer
TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage, TRadiusImage,
  TTangentImage >
::GetTangentImage( void )
{
  return dynamic_cast< TTangentImage * >(
    this->ProcessObject::GetOutput( 2 ) );
}

/** Update */
template< unsigned int ObjectDimension, class TOutputImage,
  class TRadiusImage, class TTangentImage >
void
TubeSpatialObjectToImageFilter< ObjectDimension, TOutputImage, TRadiusImage,
  TTangentImage >
::GenerateData( void )
{
  itkDebugMacro( << "TubeSpatialObjectToImageFilter::Update() called." );

  //Get the input and output pointers
  const typename SuperClass::InputSpatialObjectType   * InputTube =
    this->GetInput();
  typename SuperClass::OutputImagePointer             OutputImage =
    this->GetOutput();

  // Generate the image
  typename OutputImageType::RegionType region;
  if( this->m_Size[0] == 0 )
    {
    std::cout << "WARNING: Size not set." << std::endl;
    std::cout << "   Reverting to an incorrect method to compute region."
      << std::endl;
    SizeType size;

    typename SuperClass::InputSpatialObjectType::BoundingBoxType::PointType
      maxPoint;
    maxPoint = InputTube->GetBoundingBox()->GetMaximum();

    typename OutputImageType::PointType   physicalSize;

    unsigned int buffer = 4;

    for( unsigned int i=0; i<ObjectDimension; i++ )
      {
      maxPoint[i] = maxPoint[i] *
                    ( InputTube->GetIndexToObjectTransform() )
                      ->GetScaleComponent()[i];
      physicalSize[i] = maxPoint[i] - this->m_Origin[i];

      /** Get the origin point within the image so that the object
       * remains in the image **/
      size[i] = ( long unsigned int )(
        physicalSize[i] / this->m_Spacing[i] ) + buffer;
      }
    region.SetSize( size );
    }
  else
    {
    region.SetSize( this->m_Size );
    }

  typename OutputImageType::IndexType index;
  index.Fill( 0 );
  region.SetIndex( index );

  OutputImage->SetRegions( region );
  OutputImage->SetSpacing( this->m_Spacing );
  OutputImage->SetOrigin( this->m_Origin );
  OutputImage->Allocate();
  OutputImage->FillBuffer( 0 );

  itk::ContinuousIndex<double, ObjectDimension> point;

  m_RadiusImage = this->GetRadiusImage();
  //Build radius image for processing
  if( m_BuildRadiusImage )
    {
    m_RadiusImage->SetRegions( region );
    m_RadiusImage->SetSpacing( this->m_Spacing );
    m_RadiusImage->SetOrigin( this->m_Origin );
    m_RadiusImage->Allocate();
    m_RadiusImage->FillBuffer( 0 );
    }

  m_TangentImage = this->GetTangentImage();
  //Build radius image for processing
  if( m_BuildTangentImage )
    {
    m_TangentImage->SetRegions( region );
    m_TangentImage->SetSpacing( this->m_Spacing );
    m_TangentImage->SetOrigin( this->m_Origin );
    m_TangentImage->Allocate();
    TangentPixelType v;
    v.Fill( 0 );
    m_TangentImage->FillBuffer( v );
    }

  // Get the list of tubes
  char tubeName[] = "Tube";
  ChildrenListType* tubeList = InputTube->GetChildren(
    this->m_ChildrenDepth, tubeName );

  //int size = tubeList->size();

  typedef typename ChildrenListType::iterator ChildrenIteratorType;
  ChildrenIteratorType TubeIterator = tubeList->begin();

  typename OutputImageType::IndexType index2;

  while( TubeIterator != tubeList->end() )
    {
    TubeType * tube = ( TubeType * )TubeIterator->GetPointer();

    typename TubeType::TransformType * tubeIndexPhysTransform =
      tube->GetIndexToWorldTransform();

    // Force the computation of the tangents
    if( m_BuildTangentImage )
      {
      tube->RemoveDuplicatePoints();
      tube->ComputeTangentAndNormals();
      }

    for( unsigned int k=0; k < tube->GetNumberOfPoints(); k++ )
      {
      typedef typename TubeType::TubePointType TubePointType;
      const TubePointType* tubePoint = static_cast<const TubePointType*>(
        tube->GetPoint( k ) );
      OutputImage->TransformPhysicalPointToContinuousIndex(
	tubeIndexPhysTransform->TransformPoint( tubePoint->GetPosition() ),
	point );
      for( unsigned int i=0; i<ObjectDimension; i++ )
        {
        index[i] = ( long int )( point[i]+0.5 );
        }
      bool IsInside = OutputImage->GetLargestPossibleRegion().IsInside(index);

      if( IsInside )
        {
        // Density Image
        if( m_Cumulative )
          {
          OutputImage->SetPixel( index, OutputImage->GetPixel( index )+1 );
          }
        else
          {
          OutputImage->SetPixel( index, 1 );
          }

        // Tangent Image
        if( m_BuildTangentImage )
          {
          // Convert the tangent type to the actual tangent image pixel type
          typename TubeType::VectorType t = tubePoint->GetTangent();
          TangentPixelType tp;
          for( unsigned int tpind = 0;tpind<ObjectDimension;tpind++ )
            {
            tp[tpind] = t[tpind];
            }
          m_TangentImage->SetPixel( index, tp );
          }

        // Radius Image and Density image with radius
        if( m_UseRadius )
          {
	  // TODO it looks like we're assuming isometry here
          double phys_pt_radius = tubePoint->GetRadius() *
                                      tube
                                      ->GetIndexToObjectTransform()
                                      ->GetScaleComponent()[0];
          if( m_BuildRadiusImage )
            {
            m_RadiusImage->SetPixel( index,
                                  static_cast<RadiusPixelType>(
                                      phys_pt_radius ) );
            }

          long radius = ( long int )( phys_pt_radius / this->m_Spacing[0] );

          double step = radius/2;
          while( step > 1 )
            {
            step /= 2;
            }
          if( step < 0.5 )
            {
            step = 0.5;
            }
          if( ObjectDimension == 2 )
            {
            for( double x=-radius; x<=radius+step/2; x+=step )
              {
              for( double y=-radius; y<=radius+step/2; y+=step )
                {
                if( ( ( x*x ) +( y*y ) ) <= ( radius*radius ) )
                  // test  inside the sphere
                  {
                  index2[0]=( long )( point[0]+x+0.5 );
                  index2[1]=( long )( point[1]+y+0.5 );
                  if( OutputImage->GetLargestPossibleRegion().IsInside( index2 ) )
                    {
                    typedef typename OutputImageType::PixelType PixelType;
                    if( m_Cumulative )
                      {
                      OutputImage->SetPixel( index2,
                                            ( PixelType )( OutputImage
                                                        ->GetPixel( index2 )
                                            + 0.5 ) );
                      }
                    else
                      {
                      OutputImage->SetPixel( index2, 1 );
                      }
                    if( m_BuildRadiusImage )
                      {
                      m_RadiusImage->SetPixel( index2, phys_pt_radius );
                      }
                    }
                  }
                }
              }
            }
          else if( ObjectDimension == 3 )
            {
            for( double x=-radius; x<=radius+step/2; x+=step )
              {
              for( double y=-radius; y<=radius+step/2; y+=step )
                {
                for( double z=-radius; z<=radius+step/2; z+=step )
                  {
                  if( ( ( x*x ) +( y*y ) +( z*z ) ) <= ( radius*radius ) )
                    // test  inside the sphere
                    {
                    index2[0]=( long )( point[0]+x+0.5 );
                    index2[1]=( long )( point[1]+y+0.5 );
                    index2[2]=( long )( point[2]+z+0.5 );

                    // Test that point is within the output image boundries
                    if( OutputImage->GetLargestPossibleRegion().IsInside( index2 ) )
                      {
                      OutputImage->SetPixel( index2, 1 );
                      if( m_BuildRadiusImage )
                        {
                        m_RadiusImage->SetPixel( index2, phys_pt_radius );
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    ++TubeIterator;
    }

  delete tubeList;

  itkDebugMacro( << "TubeSpatialObjectToImageFilter::Update() finished." );

} // End update function

#endif // End !defined( __itktubeTubeSpatialObjectToImageFilter_hxx )
<|endoftext|>


<commit_before>#include "ScaledImageFactory.h"

#include <wx/mstream.h>

#include <memory>

#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include <stb/stb_image_resize.h>

using namespace std;

const unsigned char background_png[] =
{
    0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x91, 0x68,
    0x36, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,
    0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00,
    0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, 0xC7,
    0x6F, 0xA8, 0x64, 0x00, 0x00, 0x00, 0x2B, 0x49, 0x44, 0x41, 0x54, 0x38, 0x4F, 0x63, 0xD8, 0x8F,
    0x03, 0xFC, 0xC7, 0x01, 0x46, 0x35, 0x20, 0x03, 0xA8, 0x3C, 0x06, 0x20, 0x5D, 0x03, 0x94, 0xC6,
    0x00, 0x50, 0x7D, 0x18, 0x60, 0x54, 0x03, 0x32, 0x80, 0xCA, 0x63, 0x00, 0x12, 0x35, 0xEC, 0xDF,
    0x0F, 0x00, 0xA7, 0x10, 0x9D, 0x1F, 0xC1, 0x17, 0x37, 0x45, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
    0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
};

// blends a foreground RGB triplet (fg) onto a background RGB triplet (bg)
// using the given alpha value; returns the blended result
// http://stackoverflow.com/questions/12011081/alpha-blending-2-rgba-colors-in-c/12016968#12016968
inline void BlendRgb
    (
    unsigned char* dst,
    const unsigned char* fg,
    const unsigned char* bg,
    const unsigned char alpha
    )
{
    const unsigned int intAlpha = alpha + 1;
    const unsigned int invAlpha = 256 - alpha;
    for( size_t i = 0; i < 3; ++i )
    {
        dst[i] = ( ( intAlpha * fg[i] + invAlpha * bg[i] ) >> 8 );
    }
}

// blends fg onto a repeating pattern of bg into dst
// bg dimensions must be powers-of-two
void BlendPattern
    (
    wxImage& dst,
    const wxImage& fg,
    const wxImage& bg
    )
{
    const size_t fgW = static_cast< size_t >( fg.GetWidth() );
    const size_t dstW = static_cast< size_t >( dst.GetWidth() );
    const size_t dstH = static_cast< size_t >( dst.GetHeight() );

    const size_t bgW = static_cast< size_t >( bg.GetWidth() );
    const size_t bgH = static_cast< size_t >( bg.GetHeight() );

    const unsigned char* fgData = fg.GetData();
    const unsigned char* fgAlpha = fg.GetAlpha();
    unsigned char* bgData = bg.GetData();
    unsigned char* dstData = dst.GetData();

    for( size_t y = 0; y < dstH; ++y )
    {
        unsigned char* dstPx = &dstData[ y * dstW * 3 ];

        const unsigned char* fgPx = &fgData[ y * fgW * 3 ];
        const unsigned char* fgAlphaPx = &fgAlpha[ y * fgW ];

        const size_t bgY = ( y & ( bgH-1 ) ) * bgW * 3;
        const unsigned char* bgRow = &bgData[ bgY ];

        for( size_t x = 0; x < dstW; ++x )
        {
            const size_t bgX = ( x & ( bgW-1 ) ) * 3;
            const unsigned char* bgPx = &bgRow[ bgX ];

            BlendRgb( dstPx, fgPx, bgPx, *fgAlphaPx );

            dstPx += 3;
            fgPx += 3;
            fgAlphaPx += 1;
        }
    }
}

void GetScaledSubrect( wxImage& dst, const wxImage& src, const double scale, const wxPoint& pos, const int filter )
{
    if( filter == -1 )
    {
        const size_t srcW = static_cast< size_t >( src.GetWidth() );
        const size_t dstW = static_cast< size_t >( dst.GetWidth() );
        const size_t dstH = static_cast< size_t >( dst.GetHeight() );

        const float scaleInv = 1.0f / scale;

        // color
        {
            const unsigned char* srcData = src.GetData();
            unsigned char* dstData = dst.GetData();

            for( size_t dstY = 0; dstY < dstH; ++dstY )
            {
                unsigned char* dstRow = &dstData[ dstY * dstW * 3 ];

                const size_t srcY( ( dstY + pos.y ) * scaleInv );
                const unsigned char* srcRow = &srcData[ srcY * srcW * 3 ];

                for( size_t dstX = 0; dstX < dstW; ++dstX )
                {
                    const size_t srcX( ( dstX + pos.x ) * scaleInv );
                    const unsigned char* srcPx = &srcRow[ srcX * 3 ];
                    dstRow[ dstX * 3 + 0 ] = srcPx[ 0 ];
                    dstRow[ dstX * 3 + 1 ] = srcPx[ 1 ];
                    dstRow[ dstX * 3 + 2 ] = srcPx[ 2 ];
                }
            }
        }

        if( !src.HasAlpha() )
            return;

        // alpha
        {
            const unsigned char* srcData = src.GetAlpha();
            unsigned char* dstData = dst.GetAlpha();

            for( size_t dstY = 0; dstY < dstH; ++dstY )
            {
                unsigned char* dstRow = &dstData[ dstY * dstW ];

                const size_t srcY( ( dstY + pos.y ) * scaleInv );
                const unsigned char* srcRow = &srcData[ srcY * srcW ];

                for( size_t dstX = 0; dstX < dstW; ++dstX )
                {
                    const size_t srcX( ( dstX + pos.x ) * scaleInv );
                    const unsigned char* srcPx = &srcRow[ srcX ];
                    dstRow[ dstX + 0 ] = srcPx[ 0 ];
                }
            }
        }
    }
    else
    {
        const stbir_filter filter = STBIR_FILTER_TRIANGLE;
        const stbir_edge edge = STBIR_EDGE_CLAMP;
        const stbir_colorspace colorspace = STBIR_COLORSPACE_SRGB;

        stbir_resize_subpixel
            (
            src.GetData(), src.GetWidth(), src.GetHeight(), 0,
            dst.GetData(), dst.GetWidth(), dst.GetHeight(), 0,
            STBIR_TYPE_UINT8,
            3,
            0,
            STBIR_ALPHA_CHANNEL_NONE,
            edge, edge,
            filter, filter,
            colorspace,
            NULL,
            scale, scale,
            static_cast< float >( pos.x ), static_cast< float >( pos.y )
            );

        if( !src.HasAlpha() )
            return;

        stbir_resize_subpixel
            (
            src.GetAlpha(), src.GetWidth(), src.GetHeight(), 0,
            dst.GetAlpha(), dst.GetWidth(), dst.GetHeight(), 0,
            STBIR_TYPE_UINT8,
            1,
            0,
            STBIR_FLAG_ALPHA_PREMULTIPLIED,
            edge, edge,
            filter, filter,
            colorspace,
            NULL,
            scale, scale,
            static_cast< float >( pos.x ), static_cast< float >( pos.y )
            );
    }
}

// threadland
wxThread::ExitCode ScaledImageFactory::Entry()
{
    JobItem job;
    while( wxSORTABLEMSGQUEUE_NO_ERROR == mJobPool.Receive( job ) )
    {
        if( NULL == job.second.mImage || wxThread::This()->TestDestroy() )
            break;

        const ExtRect& rect = job.first;
        Context& ctx = job.second;

        ResultItem result;
        result.mGeneration = ctx.mGeneration;
        result.mRect = rect;

        // skip this rect if it isn't currently visible
        {
            wxCriticalSectionLocker locker( mVisibleCs );
            if( !mVisible.Intersects( get<2>( rect ) ) )
            {
                mResultQueue.Post( result );
                continue;
            }
        }

        wxImagePtr temp( new wxImage( get<2>( rect ).GetSize(), false ) );
        if( ctx.mImage->HasAlpha() )
        {
            temp->SetAlpha( NULL );
        }

        GetScaledSubrect
            (
            *temp,
            *ctx.mImage,
            ctx.mScale,
            get<2>( rect ).GetPosition(),
            get<1>( rect )
            );

        if( ctx.mImage->HasAlpha() )
        {
            result.mImage = new wxImage( get<2>( rect ).GetSize(), false );
            BlendPattern( *result.mImage, *temp, mStipple );
        }
        else
        {
            result.mImage = temp;
        }

        mResultQueue.Post( result );

        wxQueueEvent( mEventSink, new wxThreadEvent( wxEVT_THREAD, mEventId ) );
    }

    return static_cast< wxThread::ExitCode >( 0 );
}

ScaledImageFactory::ScaledImageFactory( wxEvtHandler* eventSink, int id )
    : mEventSink( eventSink ), mEventId( id )
{
    size_t numThreads = wxThread::GetCPUCount();
    if( numThreads <= 0 )   numThreads = 1;
    if( numThreads > 1 )    numThreads--;

    for( size_t i = 0; i < numThreads; ++i )
    {
        CreateThread();
    }

    for( wxThread*& thread : GetThreads() )
    {
        if( NULL == thread )
            continue;

        if( thread->Run() != wxTHREAD_NO_ERROR )
        {
            delete thread;
            thread = NULL;
        }
    }

    Reset();

    mStipple.LoadFile( wxMemoryInputStream( background_png, sizeof( background_png ) ) );
}

ScaledImageFactory::~ScaledImageFactory()
{
    // clear job queue and send down "kill" jobs
    mJobPool.Clear();
    for( size_t i = 0; i < GetThreads().size(); ++i )
    {
        mJobPool.Post( JobItem( ExtRect(), Context() ) );
    }

    for( wxThread* thread : GetThreads() )
    {
        if( NULL == thread )
            continue;

        thread->Wait();
    }
}

void ScaledImageFactory::SetImage( wxImagePtr& newImage )
{
    if( NULL == newImage )
        throw std::runtime_error( "Image not set!" );

    mCurrentCtx.mImage = newImage;
    mJobPool.Clear();
}

void ScaledImageFactory::SetScale( double newScale )
{
    if( NULL == mCurrentCtx.mImage )
        throw std::runtime_error( "Image not set!" );

    mCurrentCtx.mGeneration++;
    mCurrentCtx.mScale = newScale;
    mJobPool.Clear();
}

bool ScaledImageFactory::AddRect( const ExtRect& rect )
{
    if( NULL == mCurrentCtx.mImage )
        throw std::runtime_error( "Image not set!" );

    return( wxSORTABLEMSGQUEUE_NO_ERROR == mJobPool.Post( JobItem( rect, mCurrentCtx ) ) );
}

bool ScaledImageFactory::GetImage( ExtRect& rect, wxImagePtr& image )
{
    ResultItem item;
    wxMessageQueueError err;
    while( true )
    {
        err = mResultQueue.ReceiveTimeout( 0, item );
        if( wxMSGQUEUE_TIMEOUT == err )
            return false;
        if( wxMSGQUEUE_MISC_ERROR == err )
            throw std::runtime_error( "ResultQueue misc error!" );
        if( item.mGeneration != mCurrentCtx.mGeneration )
            continue;
        break;
    }

    rect = item.mRect;
    image = item.mImage;
    return true;
}

void ScaledImageFactory::SetVisibleArea( const wxRect& visible )
{
    wxCriticalSectionLocker locker( mVisibleCs );
    mVisible = visible;
}

void ScaledImageFactory::Reset()
{
    mJobPool.Clear();
    mResultQueue.Clear();

    mCurrentCtx.mGeneration++;
    mCurrentCtx.mScale = 1.0;
    mCurrentCtx.mImage.reset();
}<commit_msg>Fix C4239 warning<commit_after>#include "ScaledImageFactory.h"

#include <wx/mstream.h>

#include <memory>

#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include <stb/stb_image_resize.h>

using namespace std;

const unsigned char background_png[] =
{
    0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x91, 0x68,
    0x36, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,
    0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00,
    0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, 0xC7,
    0x6F, 0xA8, 0x64, 0x00, 0x00, 0x00, 0x2B, 0x49, 0x44, 0x41, 0x54, 0x38, 0x4F, 0x63, 0xD8, 0x8F,
    0x03, 0xFC, 0xC7, 0x01, 0x46, 0x35, 0x20, 0x03, 0xA8, 0x3C, 0x06, 0x20, 0x5D, 0x03, 0x94, 0xC6,
    0x00, 0x50, 0x7D, 0x18, 0x60, 0x54, 0x03, 0x32, 0x80, 0xCA, 0x63, 0x00, 0x12, 0x35, 0xEC, 0xDF,
    0x0F, 0x00, 0xA7, 0x10, 0x9D, 0x1F, 0xC1, 0x17, 0x37, 0x45, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
    0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
};

// blends a foreground RGB triplet (fg) onto a background RGB triplet (bg)
// using the given alpha value; returns the blended result
// http://stackoverflow.com/questions/12011081/alpha-blending-2-rgba-colors-in-c/12016968#12016968
inline void BlendRgb
    (
    unsigned char* dst,
    const unsigned char* fg,
    const unsigned char* bg,
    const unsigned char alpha
    )
{
    const unsigned int intAlpha = alpha + 1;
    const unsigned int invAlpha = 256 - alpha;
    for( size_t i = 0; i < 3; ++i )
    {
        dst[i] = ( ( intAlpha * fg[i] + invAlpha * bg[i] ) >> 8 );
    }
}

// blends fg onto a repeating pattern of bg into dst
// bg dimensions must be powers-of-two
void BlendPattern
    (
    wxImage& dst,
    const wxImage& fg,
    const wxImage& bg
    )
{
    const size_t fgW = static_cast< size_t >( fg.GetWidth() );
    const size_t dstW = static_cast< size_t >( dst.GetWidth() );
    const size_t dstH = static_cast< size_t >( dst.GetHeight() );

    const size_t bgW = static_cast< size_t >( bg.GetWidth() );
    const size_t bgH = static_cast< size_t >( bg.GetHeight() );

    const unsigned char* fgData = fg.GetData();
    const unsigned char* fgAlpha = fg.GetAlpha();
    unsigned char* bgData = bg.GetData();
    unsigned char* dstData = dst.GetData();

    for( size_t y = 0; y < dstH; ++y )
    {
        unsigned char* dstPx = &dstData[ y * dstW * 3 ];

        const unsigned char* fgPx = &fgData[ y * fgW * 3 ];
        const unsigned char* fgAlphaPx = &fgAlpha[ y * fgW ];

        const size_t bgY = ( y & ( bgH-1 ) ) * bgW * 3;
        const unsigned char* bgRow = &bgData[ bgY ];

        for( size_t x = 0; x < dstW; ++x )
        {
            const size_t bgX = ( x & ( bgW-1 ) ) * 3;
            const unsigned char* bgPx = &bgRow[ bgX ];

            BlendRgb( dstPx, fgPx, bgPx, *fgAlphaPx );

            dstPx += 3;
            fgPx += 3;
            fgAlphaPx += 1;
        }
    }
}

void GetScaledSubrect( wxImage& dst, const wxImage& src, const double scale, const wxPoint& pos, const int filter )
{
    if( filter == -1 )
    {
        const size_t srcW = static_cast< size_t >( src.GetWidth() );
        const size_t dstW = static_cast< size_t >( dst.GetWidth() );
        const size_t dstH = static_cast< size_t >( dst.GetHeight() );

        const float scaleInv = 1.0f / scale;

        // color
        {
            const unsigned char* srcData = src.GetData();
            unsigned char* dstData = dst.GetData();

            for( size_t dstY = 0; dstY < dstH; ++dstY )
            {
                unsigned char* dstRow = &dstData[ dstY * dstW * 3 ];

                const size_t srcY( ( dstY + pos.y ) * scaleInv );
                const unsigned char* srcRow = &srcData[ srcY * srcW * 3 ];

                for( size_t dstX = 0; dstX < dstW; ++dstX )
                {
                    const size_t srcX( ( dstX + pos.x ) * scaleInv );
                    const unsigned char* srcPx = &srcRow[ srcX * 3 ];
                    dstRow[ dstX * 3 + 0 ] = srcPx[ 0 ];
                    dstRow[ dstX * 3 + 1 ] = srcPx[ 1 ];
                    dstRow[ dstX * 3 + 2 ] = srcPx[ 2 ];
                }
            }
        }

        if( !src.HasAlpha() )
            return;

        // alpha
        {
            const unsigned char* srcData = src.GetAlpha();
            unsigned char* dstData = dst.GetAlpha();

            for( size_t dstY = 0; dstY < dstH; ++dstY )
            {
                unsigned char* dstRow = &dstData[ dstY * dstW ];

                const size_t srcY( ( dstY + pos.y ) * scaleInv );
                const unsigned char* srcRow = &srcData[ srcY * srcW ];

                for( size_t dstX = 0; dstX < dstW; ++dstX )
                {
                    const size_t srcX( ( dstX + pos.x ) * scaleInv );
                    const unsigned char* srcPx = &srcRow[ srcX ];
                    dstRow[ dstX + 0 ] = srcPx[ 0 ];
                }
            }
        }
    }
    else
    {
        const stbir_filter filter = STBIR_FILTER_TRIANGLE;
        const stbir_edge edge = STBIR_EDGE_CLAMP;
        const stbir_colorspace colorspace = STBIR_COLORSPACE_SRGB;

        stbir_resize_subpixel
            (
            src.GetData(), src.GetWidth(), src.GetHeight(), 0,
            dst.GetData(), dst.GetWidth(), dst.GetHeight(), 0,
            STBIR_TYPE_UINT8,
            3,
            0,
            STBIR_ALPHA_CHANNEL_NONE,
            edge, edge,
            filter, filter,
            colorspace,
            NULL,
            scale, scale,
            static_cast< float >( pos.x ), static_cast< float >( pos.y )
            );

        if( !src.HasAlpha() )
            return;

        stbir_resize_subpixel
            (
            src.GetAlpha(), src.GetWidth(), src.GetHeight(), 0,
            dst.GetAlpha(), dst.GetWidth(), dst.GetHeight(), 0,
            STBIR_TYPE_UINT8,
            1,
            0,
            STBIR_FLAG_ALPHA_PREMULTIPLIED,
            edge, edge,
            filter, filter,
            colorspace,
            NULL,
            scale, scale,
            static_cast< float >( pos.x ), static_cast< float >( pos.y )
            );
    }
}

// threadland
wxThread::ExitCode ScaledImageFactory::Entry()
{
    JobItem job;
    while( wxSORTABLEMSGQUEUE_NO_ERROR == mJobPool.Receive( job ) )
    {
        if( NULL == job.second.mImage || wxThread::This()->TestDestroy() )
            break;

        const ExtRect& rect = job.first;
        Context& ctx = job.second;

        ResultItem result;
        result.mGeneration = ctx.mGeneration;
        result.mRect = rect;

        // skip this rect if it isn't currently visible
        {
            wxCriticalSectionLocker locker( mVisibleCs );
            if( !mVisible.Intersects( get<2>( rect ) ) )
            {
                mResultQueue.Post( result );
                continue;
            }
        }

        wxImagePtr temp( new wxImage( get<2>( rect ).GetSize(), false ) );
        if( ctx.mImage->HasAlpha() )
        {
            temp->SetAlpha( NULL );
        }

        GetScaledSubrect
            (
            *temp,
            *ctx.mImage,
            ctx.mScale,
            get<2>( rect ).GetPosition(),
            get<1>( rect )
            );

        if( ctx.mImage->HasAlpha() )
        {
            result.mImage = new wxImage( get<2>( rect ).GetSize(), false );
            BlendPattern( *result.mImage, *temp, mStipple );
        }
        else
        {
            result.mImage = temp;
        }

        mResultQueue.Post( result );

        wxQueueEvent( mEventSink, new wxThreadEvent( wxEVT_THREAD, mEventId ) );
    }

    return static_cast< wxThread::ExitCode >( 0 );
}

ScaledImageFactory::ScaledImageFactory( wxEvtHandler* eventSink, int id )
    : mEventSink( eventSink ), mEventId( id )
{
    size_t numThreads = wxThread::GetCPUCount();
    if( numThreads <= 0 )   numThreads = 1;
    if( numThreads > 1 )    numThreads--;

    for( size_t i = 0; i < numThreads; ++i )
    {
        CreateThread();
    }

    for( wxThread*& thread : GetThreads() )
    {
        if( NULL == thread )
            continue;

        if( thread->Run() != wxTHREAD_NO_ERROR )
        {
            delete thread;
            thread = NULL;
        }
    }

    Reset();

    wxMemoryInputStream memStream( background_png, sizeof( background_png ) );
    mStipple.LoadFile( memStream );
}

ScaledImageFactory::~ScaledImageFactory()
{
    // clear job queue and send down "kill" jobs
    mJobPool.Clear();
    for( size_t i = 0; i < GetThreads().size(); ++i )
    {
        mJobPool.Post( JobItem( ExtRect(), Context() ) );
    }

    for( wxThread* thread : GetThreads() )
    {
        if( NULL == thread )
            continue;

        thread->Wait();
    }
}

void ScaledImageFactory::SetImage( wxImagePtr& newImage )
{
    if( NULL == newImage )
        throw std::runtime_error( "Image not set!" );

    mCurrentCtx.mImage = newImage;
    mJobPool.Clear();
}

void ScaledImageFactory::SetScale( double newScale )
{
    if( NULL == mCurrentCtx.mImage )
        throw std::runtime_error( "Image not set!" );

    mCurrentCtx.mGeneration++;
    mCurrentCtx.mScale = newScale;
    mJobPool.Clear();
}

bool ScaledImageFactory::AddRect( const ExtRect& rect )
{
    if( NULL == mCurrentCtx.mImage )
        throw std::runtime_error( "Image not set!" );

    return( wxSORTABLEMSGQUEUE_NO_ERROR == mJobPool.Post( JobItem( rect, mCurrentCtx ) ) );
}

bool ScaledImageFactory::GetImage( ExtRect& rect, wxImagePtr& image )
{
    ResultItem item;
    wxMessageQueueError err;
    while( true )
    {
        err = mResultQueue.ReceiveTimeout( 0, item );
        if( wxMSGQUEUE_TIMEOUT == err )
            return false;
        if( wxMSGQUEUE_MISC_ERROR == err )
            throw std::runtime_error( "ResultQueue misc error!" );
        if( item.mGeneration != mCurrentCtx.mGeneration )
            continue;
        break;
    }

    rect = item.mRect;
    image = item.mImage;
    return true;
}

void ScaledImageFactory::SetVisibleArea( const wxRect& visible )
{
    wxCriticalSectionLocker locker( mVisibleCs );
    mVisible = visible;
}

void ScaledImageFactory::Reset()
{
    mJobPool.Clear();
    mResultQueue.Clear();

    mCurrentCtx.mGeneration++;
    mCurrentCtx.mScale = 1.0;
    mCurrentCtx.mImage.reset();
}<|endoftext|>


<commit_before><commit_msg>Abstract Classes - Polymorphism<commit_after><|endoftext|>


<commit_before><commit_msg>Fix creation of function definition asts<commit_after><|endoftext|>