<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * 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, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/util/fs.hpp>
#include <mapnik/utils.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>

// stl
#include <algorithm>
#include <stdexcept>
#include <cstdlib>

// freetype2
extern "C"
{
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_STROKER_H
#include FT_MODULE_H
}

void* _Alloc_Func(FT_Memory memory, long size)
{
    return std::malloc(size);
}

void _Free_Func(FT_Memory memory, void *block)
{
    std::free(block);
}

void* _Realloc_Func(FT_Memory memory, long cur_size, long new_size, void* block)
{
    return std::realloc(block, new_size);
}

namespace mapnik
{

void init_freetype(FT_Memory memory, FT_Library & library)
{
    memory->alloc = _Alloc_Func;
    memory->free = _Free_Func;
    memory->realloc = _Realloc_Func;
    FT_Error error = FT_New_Library(memory, &library );
    if (error) throw std::runtime_error("can not initalise FreeType2 library");
    FT_Add_Default_Modules(library);
}

freetype_engine::freetype_engine()
    : library_(nullptr),
      memory_(new FT_MemoryRec_)
{
    init_freetype(&*memory_, library_);
}

freetype_engine::~freetype_engine()
{
    FT_Done_Library(library_);
}

bool freetype_engine::is_font_file(std::string const& file_name)
{
    // only accept files that will be matched by freetype2's `figurefiletype()`
    std::string fn = file_name;
    std::transform(fn.begin(), fn.end(), fn.begin(), ::tolower);
    return boost::algorithm::ends_with(fn,std::string(".ttf")) ||
        boost::algorithm::ends_with(fn,std::string(".otf")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".pfa")) ||
        boost::algorithm::ends_with(fn,std::string(".pfb")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".woff"))||
        // Plus OSX custom ext
        boost::algorithm::ends_with(fn,std::string(".dfont"));
}

unsigned long ft_read_cb(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count)
{
    if (count <= 0) return 0;
    FILE * file = static_cast<FILE *>(stream->descriptor.pointer);
    fseek (file , offset , SEEK_SET);
    return fread ((char*)buffer, 1, count, file);
}

void ft_close_cb(FT_Stream stream)
{
    fclose (static_cast<FILE *>(stream->descriptor.pointer));
}

bool freetype_engine::register_font(std::string const& file_name)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif

    FT_Library library = 0;
    std::unique_ptr<FT_MemoryRec_> memory(new FT_MemoryRec_);
    init_freetype(&*memory, library);
    bool result = register_font_impl(file_name, library);
    FT_Done_Library(library);
    return result;
}

bool freetype_engine::register_font_impl(std::string const& file_name, FT_LibraryRec_ * library)
{
#ifdef _WINDOWS
    FILE * file = fopen(mapnik::utf8_to_utf16(file_name).c_str(),"rb");
#else
    FILE * file = fopen(file_name.c_str(),"rb");
#endif
    if (file == nullptr) return false;
    FT_Face face = 0;
    FT_Open_Args args;
    FT_StreamRec streamRec;
    memset(&args, 0, sizeof(args));
    memset(&streamRec, 0, sizeof(streamRec));
    fseek(file, 0, SEEK_END);
    std::size_t file_size = ftell(file);
    fseek(file, 0, SEEK_SET);
    streamRec.base = 0;
    streamRec.pos = 0;
    streamRec.size = file_size;
    streamRec.descriptor.pointer = file;
    streamRec.read  = ft_read_cb;
    streamRec.close = ft_close_cb;
    args.flags = FT_OPEN_STREAM;
    args.stream = &streamRec;
    int num_faces = 0;
    bool success = false;
    // some font files have multiple fonts in a file
    // the count is in the 'root' face library[0]
    // see the FT_FaceRec in freetype.h
    for ( int i = 0; face == 0 || i < num_faces; i++ ) {
        // if face is null then this is the first face
        FT_Error error = FT_Open_Face(library, &args, i, &face);
        if (error)
        {
            break;
        }
        // store num_faces locally, after FT_Done_Face it can not be accessed any more
        if (!num_faces)
            num_faces = face->num_faces;
        // some fonts can lack names, skip them
        // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec
        if (face->family_name && face->style_name)
        {
            std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
            // skip fonts with leading . in the name
            if (!boost::algorithm::starts_with(name,"."))
            {
                name2file_.insert(std::make_pair(name, std::make_pair(i,file_name)));
                success = true;
            }
        }
        else
        {
            std::ostringstream s;
            s << "Warning: unable to load font file '" << file_name << "' ";
            if (!face->family_name && !face->style_name)
                s << "which lacks both a family name and style name";
            else if (face->family_name)
                s << "which reports a family name of '" << std::string(face->family_name) << "' and lacks a style name";
            else if (face->style_name)
                s << "which reports a style name of '" << std::string(face->style_name) << "' and lacks a family name";

            MAPNIK_LOG_ERROR(font_engine_freetype) << "register_font: " << s.str();
        }
    }

    if (face) FT_Done_Face(face);

    return success;
}

bool freetype_engine::register_fonts(std::string const& dir, bool recurse)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif
    std::unique_ptr<FT_MemoryRec_> memory(new FT_MemoryRec_);
    FT_Library library = 0;
    init_freetype(&*memory, library);
    bool result = register_fonts_impl(dir, library, recurse);
    FT_Done_Library(library);
    return result;
}

bool freetype_engine::register_fonts_impl(std::string const& dir, FT_LibraryRec_ * library, bool recurse)
{
    if (!mapnik::util::exists(dir))
    {
        return false;
    }
    if (!mapnik::util::is_directory(dir))
    {
        return mapnik::freetype_engine::register_font_impl(dir, library);
    }
    bool success = false;
    try
    {
        boost::filesystem::directory_iterator end_itr;
#ifdef _WINDOWS
        std::wstring wide_dir(mapnik::utf8_to_utf16(dir));
        for (boost::filesystem::directory_iterator itr(wide_dir); itr != end_itr; ++itr)
        {
    #if (BOOST_FILESYSTEM_VERSION == 3)
            std::string file_name = mapnik::utf16_to_utf8(itr->path().wstring());
    #else // v2
            std::string file_name = mapnik::utf16_to_utf8(itr->wstring());
    #endif
#else
        for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr)
        {
#if (BOOST_FILESYSTEM_VERSION == 3)
            std::string file_name = itr->path().string();
#else // v2
            std::string file_name = itr->string();
#endif
#endif
            if (boost::filesystem::is_directory(*itr) && recurse)
            {
                if (register_fonts_impl(file_name, library, true))
                {
                    success = true;
                }
            }
            else
            {
#if (BOOST_FILESYSTEM_VERSION == 3)
                std::string base_name = itr->path().filename().string();
#else // v2
                std::string base_name = itr->filename();
#endif
                if (!boost::algorithm::starts_with(base_name,".") &&
                    mapnik::util::is_regular_file(file_name) &&
                    is_font_file(file_name))
                {
                    if (mapnik::freetype_engine::register_font_impl(file_name, library))
                    {
                        success = true;
                    }
                }
            }
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(font_engine_freetype) << "register_fonts: " << ex.what();
    }
    return success;
}

std::vector<std::string> freetype_engine::face_names ()
{
    std::vector<std::string> names;
    for (auto const& kv : name2file_)
    {
        names.push_back(kv.first);
    }
    return names;
}

std::map<std::string,std::pair<int,std::string> > const& freetype_engine::get_mapping()
{
    return name2file_;
}

face_ptr freetype_engine::create_face(std::string const& family_name)
{
    auto itr = name2file_.find(family_name);
    if (itr != name2file_.end())
    {
        FT_Face face;

        auto mem_font_itr = memory_fonts_.find(itr->second.second);

        if (mem_font_itr != memory_fonts_.end()) // memory font
        {
            FT_Error error = FT_New_Memory_Face(library_,
                                                reinterpret_cast<FT_Byte const*>(mem_font_itr->second.c_str()),
                                                static_cast<FT_Long>(mem_font_itr->second.size()), // size
                                                itr->second.first, // face index
                                                &face);

            if (!error) return std::make_shared<font_face>(face);
        }
        else
        {
            // load font into memory
#ifdef MAPNIK_THREADSAFE
            mapnik::scoped_lock lock(mutex_);
#endif
            FILE * file = fopen(itr->second.second.c_str(),"rb");
            if (file != nullptr)
            {
                fseek(file, 0, SEEK_END);
                unsigned long file_size = ftell(file);
                fseek(file, 0, SEEK_SET);
                boost::scoped_array<char> buffer(new char[file_size]);
                fread(buffer.get(), file_size, 1, file);
                auto result = memory_fonts_.insert(std::make_pair(itr->second.second, std::string(buffer.get(),file_size)));

                FT_Error error = FT_New_Memory_Face (library_,
                                                     reinterpret_cast<FT_Byte const*>(result.first->second.c_str()),
                                                     static_cast<FT_Long>(result.first->second.size()),
                                                     itr->second.first,
                                                     &face);
                if (!error) return std::make_shared<font_face>(face);
                else
                {
                    // we can't load font, erase it.
                    memory_fonts_.erase(result.first);
                }
            }
        }
    }
    return face_ptr();
}

stroker_ptr freetype_engine::create_stroker()
{
    FT_Stroker s;
    FT_Error error = FT_Stroker_New(library_, &s);
    if (!error)
    {
        return std::make_shared<stroker>(s);
    }
    return stroker_ptr();
}

template <typename T>
face_ptr face_manager<T>::get_face(std::string const& name)
{
    auto itr = face_ptr_cache_.find(name);
    if (itr != face_ptr_cache_.end())
    {
        return itr->second;
    }
    else
    {
        face_ptr face = engine_.create_face(name);
        if (face)
        {
            face_ptr_cache_.insert(make_pair(name,face));
        }
        return face;
    }
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(std::string const& name)
{
    face_set_ptr face_set = std::make_shared<font_face_set>();
    if (face_ptr face = get_face(name))
    {
        face_set->add(face);
    }
    return face_set;
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(font_set const& fset)
{
    std::vector<std::string> const& names = fset.get_face_names();
    face_set_ptr face_set = std::make_shared<font_face_set>();
    for (auto const& name  : names)
    {
        face_ptr face = get_face(name);
        if (face)
        {
            face_set->add(face);
        }
#ifdef MAPNIK_LOG
        else
        {
            MAPNIK_LOG_DEBUG(font_engine_freetype)
                << "Failed to find face '" << name
                << "' in font set '" << fset.get_name() << "'\n";
        }
#endif
    }
    return face_set;
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(const std::string &name, boost::optional<font_set> fset)
{
    if (fset && fset->size() > 0)
    {
        return get_face_set(*fset);
    }
    else
    {
        return get_face_set(name);
    }
}

#ifdef MAPNIK_THREADSAFE
std::mutex freetype_engine::mutex_;
#endif
std::map<std::string,std::pair<int,std::string> > freetype_engine::name2file_;
std::map<std::string,std::string> freetype_engine::memory_fonts_;
template class face_manager<freetype_engine>;

}
<commit_msg>wrap FILE* in std::unique_ptr (RAII) pull C-i/o from std:: namespace<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * 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, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/util/fs.hpp>
#include <mapnik/utils.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>

// stl
#include <algorithm>
#include <stdexcept>
#include <cstdlib>

// freetype2
extern "C"
{
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_STROKER_H
#include FT_MODULE_H
}

void* _Alloc_Func(FT_Memory memory, long size)
{
    return std::malloc(size);
}

void _Free_Func(FT_Memory memory, void *block)
{
    std::free(block);
}

void* _Realloc_Func(FT_Memory memory, long cur_size, long new_size, void* block)
{
    return std::realloc(block, new_size);
}

namespace mapnik
{

void init_freetype(FT_Memory memory, FT_Library & library)
{
    memory->alloc = _Alloc_Func;
    memory->free = _Free_Func;
    memory->realloc = _Realloc_Func;
    FT_Error error = FT_New_Library(memory, &library );
    if (error) throw std::runtime_error("can not initalise FreeType2 library");
    FT_Add_Default_Modules(library);
}

freetype_engine::freetype_engine()
    : library_(nullptr),
      memory_(new FT_MemoryRec_)
{
    init_freetype(&*memory_, library_);
}

freetype_engine::~freetype_engine()
{
    FT_Done_Library(library_);
}

bool freetype_engine::is_font_file(std::string const& file_name)
{
    // only accept files that will be matched by freetype2's `figurefiletype()`
    std::string fn = file_name;
    std::transform(fn.begin(), fn.end(), fn.begin(), ::tolower);
    return boost::algorithm::ends_with(fn,std::string(".ttf")) ||
        boost::algorithm::ends_with(fn,std::string(".otf")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".pfa")) ||
        boost::algorithm::ends_with(fn,std::string(".pfb")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".woff"))||
        // Plus OSX custom ext
        boost::algorithm::ends_with(fn,std::string(".dfont"));
}

unsigned long ft_read_cb(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count)
{
    if (count <= 0) return 0;
    FILE * file = static_cast<FILE *>(stream->descriptor.pointer);
    std::fseek (file , offset , SEEK_SET);
    return std::fread ((char*)buffer, 1, count, file);
}

void ft_close_cb(FT_Stream stream)
{
    std::fclose (static_cast<std::FILE *>(stream->descriptor.pointer));
}

bool freetype_engine::register_font(std::string const& file_name)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif

    FT_Library library = 0;
    std::unique_ptr<FT_MemoryRec_> memory(new FT_MemoryRec_);
    init_freetype(&*memory, library);
    bool result = register_font_impl(file_name, library);
    FT_Done_Library(library);
    return result;
}

bool freetype_engine::register_font_impl(std::string const& file_name, FT_LibraryRec_ * library)
{
#ifdef _WINDOWS
    FILE * file = fopen(mapnik::utf8_to_utf16(file_name).c_str(),"rb");
#else
    FILE * file = fopen(file_name.c_str(),"rb");
#endif
    if (file == nullptr) return false;
    FT_Face face = 0;
    FT_Open_Args args;
    FT_StreamRec streamRec;
    memset(&args, 0, sizeof(args));
    memset(&streamRec, 0, sizeof(streamRec));
    fseek(file, 0, SEEK_END);
    std::size_t file_size = std::ftell(file);
    fseek(file, 0, SEEK_SET);
    streamRec.base = 0;
    streamRec.pos = 0;
    streamRec.size = file_size;
    streamRec.descriptor.pointer = file;
    streamRec.read  = ft_read_cb;
    streamRec.close = ft_close_cb;
    args.flags = FT_OPEN_STREAM;
    args.stream = &streamRec;
    int num_faces = 0;
    bool success = false;
    // some font files have multiple fonts in a file
    // the count is in the 'root' face library[0]
    // see the FT_FaceRec in freetype.h
    for ( int i = 0; face == 0 || i < num_faces; i++ ) {
        // if face is null then this is the first face
        FT_Error error = FT_Open_Face(library, &args, i, &face);
        if (error)
        {
            break;
        }
        // store num_faces locally, after FT_Done_Face it can not be accessed any more
        if (!num_faces)
            num_faces = face->num_faces;
        // some fonts can lack names, skip them
        // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec
        if (face->family_name && face->style_name)
        {
            std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
            // skip fonts with leading . in the name
            if (!boost::algorithm::starts_with(name,"."))
            {
                name2file_.insert(std::make_pair(name, std::make_pair(i,file_name)));
                success = true;
            }
        }
        else
        {
            std::ostringstream s;
            s << "Warning: unable to load font file '" << file_name << "' ";
            if (!face->family_name && !face->style_name)
                s << "which lacks both a family name and style name";
            else if (face->family_name)
                s << "which reports a family name of '" << std::string(face->family_name) << "' and lacks a style name";
            else if (face->style_name)
                s << "which reports a style name of '" << std::string(face->style_name) << "' and lacks a family name";

            MAPNIK_LOG_ERROR(font_engine_freetype) << "register_font: " << s.str();
        }
    }

    if (face) FT_Done_Face(face);

    return success;
}

bool freetype_engine::register_fonts(std::string const& dir, bool recurse)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif
    std::unique_ptr<FT_MemoryRec_> memory(new FT_MemoryRec_);
    FT_Library library = 0;
    init_freetype(&*memory, library);
    bool result = register_fonts_impl(dir, library, recurse);
    FT_Done_Library(library);
    return result;
}

bool freetype_engine::register_fonts_impl(std::string const& dir, FT_LibraryRec_ * library, bool recurse)
{
    if (!mapnik::util::exists(dir))
    {
        return false;
    }
    if (!mapnik::util::is_directory(dir))
    {
        return mapnik::freetype_engine::register_font_impl(dir, library);
    }
    bool success = false;
    try
    {
        boost::filesystem::directory_iterator end_itr;
#ifdef _WINDOWS
        std::wstring wide_dir(mapnik::utf8_to_utf16(dir));
        for (boost::filesystem::directory_iterator itr(wide_dir); itr != end_itr; ++itr)
        {
    #if (BOOST_FILESYSTEM_VERSION == 3)
            std::string file_name = mapnik::utf16_to_utf8(itr->path().wstring());
    #else // v2
            std::string file_name = mapnik::utf16_to_utf8(itr->wstring());
    #endif
#else
        for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr)
        {
#if (BOOST_FILESYSTEM_VERSION == 3)
            std::string file_name = itr->path().string();
#else // v2
            std::string file_name = itr->string();
#endif
#endif
            if (boost::filesystem::is_directory(*itr) && recurse)
            {
                if (register_fonts_impl(file_name, library, true))
                {
                    success = true;
                }
            }
            else
            {
#if (BOOST_FILESYSTEM_VERSION == 3)
                std::string base_name = itr->path().filename().string();
#else // v2
                std::string base_name = itr->filename();
#endif
                if (!boost::algorithm::starts_with(base_name,".") &&
                    mapnik::util::is_regular_file(file_name) &&
                    is_font_file(file_name))
                {
                    if (mapnik::freetype_engine::register_font_impl(file_name, library))
                    {
                        success = true;
                    }
                }
            }
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(font_engine_freetype) << "register_fonts: " << ex.what();
    }
    return success;
}

std::vector<std::string> freetype_engine::face_names ()
{
    std::vector<std::string> names;
    for (auto const& kv : name2file_)
    {
        names.push_back(kv.first);
    }
    return names;
}

std::map<std::string,std::pair<int,std::string> > const& freetype_engine::get_mapping()
{
    return name2file_;
}

face_ptr freetype_engine::create_face(std::string const& family_name)
{
    auto itr = name2file_.find(family_name);
    if (itr != name2file_.end())
    {
        FT_Face face;

        auto mem_font_itr = memory_fonts_.find(itr->second.second);

        if (mem_font_itr != memory_fonts_.end()) // memory font
        {
            FT_Error error = FT_New_Memory_Face(library_,
                                                reinterpret_cast<FT_Byte const*>(mem_font_itr->second.c_str()),
                                                static_cast<FT_Long>(mem_font_itr->second.size()), // size
                                                itr->second.first, // face index
                                                &face);

            if (!error) return std::make_shared<font_face>(face);
        }
        else
        {
            // load font into memory
#ifdef MAPNIK_THREADSAFE
            mapnik::scoped_lock lock(mutex_);
#endif
            std::unique_ptr<std::FILE, int (*)(std::FILE *)> file(std::fopen(itr->second.second.c_str(),"rb"), std::fclose);
            if (file != nullptr)
            {
                std::fseek(file.get(), 0, SEEK_END);
                unsigned long file_size = std::ftell(file.get());
                std::fseek(file.get(), 0, SEEK_SET);
                boost::scoped_array<char> buffer(new char[file_size]);
                std::fread(buffer.get(), file_size, 1, file.get());
                auto result = memory_fonts_.insert(std::make_pair(itr->second.second, std::string(buffer.get(),file_size)));
                FT_Error error = FT_New_Memory_Face (library_,
                                                     reinterpret_cast<FT_Byte const*>(result.first->second.c_str()),
                                                     static_cast<FT_Long>(result.first->second.size()),
                                                     itr->second.first,
                                                     &face);
                if (!error) return std::make_shared<font_face>(face);
                else
                {
                    // we can't load font, erase it.
                    memory_fonts_.erase(result.first);
                }
            }
        }
    }
    return face_ptr();
}

stroker_ptr freetype_engine::create_stroker()
{
    FT_Stroker s;
    FT_Error error = FT_Stroker_New(library_, &s);
    if (!error)
    {
        return std::make_shared<stroker>(s);
    }
    return stroker_ptr();
}

template <typename T>
face_ptr face_manager<T>::get_face(std::string const& name)
{
    auto itr = face_ptr_cache_.find(name);
    if (itr != face_ptr_cache_.end())
    {
        return itr->second;
    }
    else
    {
        face_ptr face = engine_.create_face(name);
        if (face)
        {
            face_ptr_cache_.insert(make_pair(name,face));
        }
        return face;
    }
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(std::string const& name)
{
    face_set_ptr face_set = std::make_shared<font_face_set>();
    if (face_ptr face = get_face(name))
    {
        face_set->add(face);
    }
    return face_set;
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(font_set const& fset)
{
    std::vector<std::string> const& names = fset.get_face_names();
    face_set_ptr face_set = std::make_shared<font_face_set>();
    for (auto const& name  : names)
    {
        face_ptr face = get_face(name);
        if (face)
        {
            face_set->add(face);
        }
#ifdef MAPNIK_LOG
        else
        {
            MAPNIK_LOG_DEBUG(font_engine_freetype)
                << "Failed to find face '" << name
                << "' in font set '" << fset.get_name() << "'\n";
        }
#endif
    }
    return face_set;
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(const std::string &name, boost::optional<font_set> fset)
{
    if (fset && fset->size() > 0)
    {
        return get_face_set(*fset);
    }
    else
    {
        return get_face_set(name);
    }
}

#ifdef MAPNIK_THREADSAFE
std::mutex freetype_engine::mutex_;
#endif
std::map<std::string,std::pair<int,std::string> > freetype_engine::name2file_;
std::map<std::string,std::string> freetype_engine::memory_fonts_;
template class face_manager<freetype_engine>;

}
<|endoftext|>


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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

// Testing
#include <mitkTestingMacros.h>
#include <mitkTestFixture.h>

// other
#include <mitkExtractSliceFilter.h>
#include <mitkImage.h>
#include <mitkIOUtil.h>
#include <mitkSegmentationInterpolationController.h>

class mitkSegmentationInterpolationTestSuite : public mitk::TestFixture
{
  CPPUNIT_TEST_SUITE(mitkSegmentationInterpolationTestSuite);
  MITK_TEST(Equal_Axial_TestInterpolationAndReferenceInterpolation_ReturnsTrue);
  CPPUNIT_TEST_SUITE_END();

private:

  // Load data into these
  mitk::Image::Pointer m_ReferenceImage;
  mitk::Image::Pointer m_AxialBase;
  mitk::Surface::Pointer m_AxialFeedback;
  mitk::Image::Pointer m_AxialInterpolated;

  // Plane indices
  int m_AxialPlaneIndex;

  mitk::SegmentationInterpolationController::Pointer m_InterpolationController;

public:

  void setUp() override
  {
    m_AxialPlaneIndex = 22;

    m_ReferenceImage = mitk::IOUtil::LoadImage(GetTestDataFilePath("Pic3D.nrrd"));
    CPPUNIT_ASSERT_MESSAGE("Failed to load image for test: [Pic3D.nrrd]", m_ReferenceImage.IsNotNull());
    m_AxialBase = mitk::IOUtil::LoadImage(GetTestDataFilePath("SegmentationInterpolation/AxialBase.nrrd"));
    CPPUNIT_ASSERT_MESSAGE("Failed to load image for test: [AxialBase.nrrd]", m_AxialBase.IsNotNull());
    m_AxialFeedback = mitk::IOUtil::LoadSurface(GetTestDataFilePath("SegmentationInterpolation/AxialFeedback.vtp"));
    CPPUNIT_ASSERT_MESSAGE("Failed to load image for test: [AxialFeedback.nrrd]", m_AxialFeedback.IsNotNull());
    m_AxialInterpolated = mitk::IOUtil::LoadImage(GetTestDataFilePath("SegmentationInterpolation/AxialInterpolated.nrrd"));
    CPPUNIT_ASSERT_MESSAGE("Failed to load image for test: [AxialInterpolated.nrrd]", m_AxialInterpolated.IsNotNull());

    m_InterpolationController = mitk::SegmentationInterpolationController::GetInstance();
    m_InterpolationController->SetReferenceVolume(m_ReferenceImage);
  }

  void tearDown() override
  {
    m_ReferenceImage = nullptr;
    m_AxialBase = nullptr;
    m_AxialFeedback = nullptr;
    m_AxialInterpolated = nullptr;
  }

  void Equal_Axial_TestInterpolationAndReferenceInterpolation_ReturnsTrue()
  {
    // Create Interpolation from base segmentation
    m_InterpolationController->SetSegmentationVolume(m_AxialBase);
    mitk::PlaneGeometry* plane = dynamic_cast<mitk::PlaneGeometry*>(m_ReferenceImage->GetSlicedGeometry()->GetPlaneGeometry(m_AxialPlaneIndex));
    mitk::Image::Pointer resultTestInterpolation = m_InterpolationController->Interpolate(0, m_AxialPlaneIndex, plane, 0);
    MITK_ASSERT_EQUAL(resultTestInterpolation, m_AxialInterpolated, "The created interpolation should fit the reference interpolation.");
  }

};

MITK_TEST_SUITE_REGISTRATION(mitkSegmentationInterpolation);

//#include "mitkSegmentationInterpolationController.h"
//#include "mitkCoreObjectFactory.h"
//#include "mitkStandardFileLocations.h"
////#include "mitkDataNodeFactory.h"
//#include "ipSegmentation.h"
//#include "mitkCompareImageSliceTestHelper.h"

//class mitkSegmentationInterpolationTestClass
//{
//  public:
//    mitkSegmentationInterpolationTestClass() {}
//    ~mitkSegmentationInterpolationTestClass() {}

//    bool Test(std::string filename1, std::string filename2)
//    {
//      return CreateNewInterpolator()
//          && CreateSegmentation()
//          && ClearSegmentation()
//          && CreateTwoSlices(2)
//          && TestInterpolation(2)
//          && ClearSegmentation()
//          && CreateTwoSlices(1)
//          && TestInterpolation(1)
//          && ClearSegmentation()
//          && CreateTwoSlices(0)
//          && TestInterpolation(0)
//          && DeleteInterpolator()
//          && CreateNewInterpolator()
//          && LoadTestImages(filename1, filename2)
//          && CompareInterpolationsToDefinedReference();
//    }

//  protected:

//    bool CreateNewInterpolator();
//    bool CreateSegmentation();
//    bool ClearSegmentation();
//    bool CreateTwoSlices(int);
//    bool TestInterpolation(int);
//    bool DeleteInterpolator();
//    bool LoadTestImages(std::string filename1, std::string filename2);
//    bool CompareInterpolationsToDefinedReference();

//    mitk::Image::Pointer LoadImage(const std::string& filename);

//    mitk::SegmentationInterpolationController::Pointer m_Interpolator;
//    mitk::Image::Pointer m_Image;

//    mitk::Image::Pointer m_ManualSlices;
//    mitk::Image::Pointer m_InterpolatedSlices;

//    unsigned int dim[3];
//    int pad[3];
//};

//bool mitkSegmentationInterpolationTestClass::CreateNewInterpolator()
//{
//  std::cout << "Instantiation" << std::endl;

//// instantiation
//  m_Interpolator = mitk::SegmentationInterpolationController::New();
//  if (m_Interpolator.IsNotNull())
//  {
//    std::cout << "  (II) Instantiation works." << std::endl;
//  }
//  else
//  {
//    std::cout << " Instantiation test failed!" << std::endl;
//    return false;
//  }

//  return true;
//}

//bool mitkSegmentationInterpolationTestClass::CreateSegmentation()
//{
//  m_Image = mitk::Image::New();
//  dim[0]=15;
//  dim[1]=20;
//  dim[2]=25;
//  pad[0]=2;
//  pad[1]=3;
//  pad[2]=4;

//  m_Image->Initialize( mitk::MakeScalarPixelType<int>(), 3, dim);

//  return true;
//}

//bool mitkSegmentationInterpolationTestClass::ClearSegmentation()
//{
//  int* p = (int*)m_Image->GetData(); // pointer to pixel data
//  int size = dim[0]*dim[1]*dim[2];
//  for(int i=0; i<size; ++i, ++p) *p=0; // fill image with zeros

//  return true;
//}

///**
// * Creates a square segmentation in slices 0 and 2.
//*/
//bool mitkSegmentationInterpolationTestClass::CreateTwoSlices(int slicedim)
//{
//  int* p = (int*)m_Image->GetData(); // pointer to pixel data

//  int size = dim[0]*dim[1]*dim[2];
//  for(int i=0; i<size; ++i, ++p)
//  {
//    int x,y,z;
//    int xdim,ydim;
//    switch (slicedim)
//    {
//      case 0:
//        z = i % dim[0];
//        y = i / dim[0] %  dim[1];
//        x = i / (dim[1]*dim[0]);
//        xdim = 2;
//        ydim = 1;
//        break;
//      case 1:
//        x = i % dim[0];
//        z = i / dim[0] %  dim[1];
//        y = i / (dim[1]*dim[0]);
//        xdim = 0;
//        ydim = 2;
//        break;
//      case 2:
//      default:
//        x = i % dim[0];
//        y = i / dim[0] %  dim[1];
//        z = i / (dim[1]*dim[0]);
//        xdim = 0;
//        ydim = 1;
//        break;
//    }

//    if ( ((z == 0) || (z == 2)) && (x >= pad[xdim]) && (x < ( (signed) dim[xdim]-pad[xdim])) && (y >= pad[ydim]) && (y < ( (signed) dim[ydim]-pad[ydim])) )
//    {
//      *p = 1;
//    }
//    else
//    {
//      *p = 0;
//    }
//  }

//  m_Interpolator->SetSegmentationVolume( m_Image );
//  std::cout << "  (II) SetSegmentationVolume works (slicedim " << slicedim << ")" << std::endl;

//  return true;
//}

///**
// * Checks if interpolation would create a square in slice 1
//*/
//bool mitkSegmentationInterpolationTestClass::TestInterpolation(int slicedim)
//{
//  int slice = 1;
//  mitk::Image::Pointer interpolated = m_Interpolator->Interpolate( slicedim, slice, 0 ); // interpolate second slice axial
//  if (interpolated.IsNull())
//  {
//    std::cerr << "  (EE) Interpolation did not return anything for slicedim == " << slicedim << " (although it should)." << std::endl;
//    return false;
//  }

//  int xdim,ydim;
//  switch (slicedim)
//  {
//    case 0:
//      xdim = 1;
//      ydim = 2; // different than above!
//      break;
//    case 1:
//      xdim = 0;
//      ydim = 2;
//      break;
//    case 2:
//    default:
//      xdim = 0;
//      ydim = 1;
//      break;
//  }

//  ipMITKSegmentationTYPE* p = (ipMITKSegmentationTYPE*)interpolated->GetData(); // pointer to pixel data

//  int size = dim[xdim]*dim[ydim];
//  if ( (signed) interpolated->GetDimension(0) * (signed) interpolated->GetDimension(1) != size )
//  {
//    std::cout << "  (EE) Size of interpolated image differs from original segmentation..." << std::endl;
//    return false;
//  }

//  for(int i=0; i<size; ++i, ++p)
//  {
//    int x,y;
//    x = i % dim[xdim];
//    y = i / dim[xdim];

//    //if (x == 0) std::cout << std::endl;

//    ipMITKSegmentationTYPE value = *p;

//    //if (value == 1) std::cout << "O"; else std::cout << ".";

//    if ( (x >= pad[xdim]) && (x < ((signed) dim[xdim]-pad[xdim])) && (y >= pad[ydim]) && (y < ((signed) dim[ydim]-pad[ydim])) && (value != 1) )
//    {
//      std::cout << "  (EE) Interpolation of a square figure failed" << std::endl;
//      std::cout << "  Value at " << x << " " << y << ": " << (int)value << std::endl;
//      return false;
//    }
//  }

//  std::cout << "  (II) Interpolation of a square figure works like expected (slicedim " << slicedim << ")" << std::endl;
//  return true;
//}

//bool mitkSegmentationInterpolationTestClass::DeleteInterpolator()
//{
//  std::cout << "Object destruction" << std::endl;

//// freeing
//  m_Interpolator = NULL;

//  std::cout << "  (II) Freeing works." << std::endl;
//  return true;
//}

//bool mitkSegmentationInterpolationTestClass::LoadTestImages(std::string filename1, std::string filename2)
//{
//  m_ManualSlices = LoadImage( filename1 );
//  m_InterpolatedSlices = LoadImage( filename2 );

//  return ( m_ManualSlices.IsNotNull() && m_InterpolatedSlices.IsNotNull() );
//}

//mitk::Image::Pointer mitkSegmentationInterpolationTestClass::LoadImage(const std::string& filename)
//{
//  mitk::Image::Pointer image = NULL;
//  mitk::DataNodeFactory::Pointer factory = mitk::DataNodeFactory::New();
//  try
//  {
//    factory->SetFileName( filename );
//    factory->Update();

//    if(factory->GetNumberOfOutputs()<1)
//    {
//      std::cerr<<"File " << filename << " could not be loaded [FAILED]"<<std::endl;
//      return NULL;
//    }
//    mitk::DataNode::Pointer node = factory->GetOutput( 0 );
//    image = dynamic_cast<mitk::Image*>(node->GetData());
//    if(image.IsNull())
//    {
//      std::cout<<"File " << filename << " is not an image! [FAILED]"<<std::endl;
//      return NULL;
//    }
//  }
//  catch ( itk::ExceptionObject & ex )
//  {
//    std::cerr << "Exception: " << ex << "[FAILED]" << std::endl;
//    return NULL;
//  }

//  return image;
//}

//bool mitkSegmentationInterpolationTestClass::CompareInterpolationsToDefinedReference()
//{
//  std::cout << "  (II) Setting segmentation volume... " << std::flush;

//  m_Interpolator->SetSegmentationVolume( m_ManualSlices );

//  std::cout << "OK" << std::endl;

//  std::cout << "  (II) Testing interpolation result for slice " << std::flush;

//  for (unsigned int slice = 1; slice < 98; ++slice)
//  {
//    if (slice % 2 == 0) continue; // these were manually drawn, no interpolation possible

//    std::cout << slice << " " << std::flush;

//    mitk::Image::Pointer interpolation = m_Interpolator->Interpolate( 2, slice, 0 );

//    if ( interpolation.IsNull() )
//    {
//      std::cerr << "  (EE) Interpolated image is NULL." << std::endl;
//      return false;
//    }

//    if ( !CompareImageSliceTestHelper::CompareSlice( m_InterpolatedSlices, 2, slice, interpolation ) )
//    {
//      std::cerr << "  (EE) interpolated image is not identical to reference in slice " << slice << std::endl;
//      return false;
//    }
//  }

//  std::cout << std::endl;
//  std::cout << "  (II) Interpolations are the same as the saved references." << std::endl;

//  return true;
//}

///// ctest entry point
//int mitkSegmentationInterpolationTest(int argc, char* argv[])
//{
//// one big variable to tell if anything went wrong
////  std::cout << "Creating CoreObjectFactory" << std::endl;
////  itk::ObjectFactoryBase::RegisterFactory(mitk::CoreObjectFactory::New());
//  if (argc < 3)
//  {
//    std::cerr << " (EE) Missing arguments for testing" << std::endl;
//  }
//  mitkSegmentationInterpolationTestClass test;
//  if ( test.Test(argv[1], argv[2]) )
//  {
//    std::cout << "[PASSED]" << std::endl;
//    return EXIT_SUCCESS;
//  }
//  else
//  {
//    std::cout << "[FAILED]" << std::endl;
//    return EXIT_FAILURE;
//  }
//}

<commit_msg>Minor changes<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

// Testing
#include <mitkTestingMacros.h>
#include <mitkTestFixture.h>

// other
#include <mitkImage.h>
#include <mitkImageWriteAccessor.h>
#include <mitkIOUtil.h>
#include <mitkSegmentationInterpolationController.h>

class mitkSegmentationInterpolationTestSuite : public mitk::TestFixture
{
  CPPUNIT_TEST_SUITE(mitkSegmentationInterpolationTestSuite);
  MITK_TEST(Equal_Axial_TestInterpolationAndReferenceInterpolation_ReturnsTrue);
  CPPUNIT_TEST_SUITE_END();

private:

  // Load data into these
  mitk::Image::Pointer m_ReferenceImage;
  mitk::Image::Pointer m_InputImageAxial;
  mitk::Image::Pointer m_FeedbackImageAxial;
  mitk::Image::Pointer m_ResultImageAxial;

  // Plane index (the slice to be interpolated)
  int m_PlaneIndexAxial;

  mitk::SegmentationInterpolationController::Pointer m_InterpolationController;

public:

  void setUp() override
  {
    m_PlaneIndexAxial = 23;

    m_ReferenceImage = mitk::IOUtil::LoadImage(GetTestDataFilePath("Pic3D.nrrd"));
    CPPUNIT_ASSERT_MESSAGE("Failed to load image for test: [Pic3D.nrrd]", m_ReferenceImage.IsNotNull());
    m_InputImageAxial = mitk::IOUtil::LoadImage(GetTestDataFilePath("SegmentationInterpolation/InterpolationTestInputAxial.nrrd"));
    CPPUNIT_ASSERT_MESSAGE("Failed to load image for test: [InterpolationTestInputAxial.nrrd]", m_InputImageAxial.IsNotNull());
//    m_FeedbackImageAxial = mitk::IOUtil::LoadImage(GetTestDataFilePath("SegmentationInterpolation/InterpolationTestFeedbackAxial.nrrd"));
//    CPPUNIT_ASSERT_MESSAGE("Failed to load image for test: [InterpolationTestFeedbackAxial.nrrd]", m_FeedbackImageAxial.IsNotNull());
    m_ResultImageAxial = mitk::IOUtil::LoadImage(GetTestDataFilePath("SegmentationInterpolation/InterpolationTestResultAxial.nrrd"));
    CPPUNIT_ASSERT_MESSAGE("Failed to load image for test: [InterpolationTestResultAxial.nrrd]", m_ResultImageAxial.IsNotNull());

    m_InterpolationController = mitk::SegmentationInterpolationController::GetInstance();
  }

  void tearDown() override
  {
    m_ReferenceImage = nullptr;
    m_InputImageAxial = nullptr;
//    m_FeedbackImageAxial = nullptr;
    m_ResultImageAxial = nullptr;
  }

  void Equal_Axial_TestInterpolationAndReferenceInterpolation_ReturnsTrue()
  {
    m_InterpolationController->SetSegmentationVolume(m_InputImageAxial);
    m_InterpolationController->SetReferenceVolume(m_ReferenceImage);

    // read and write accessor to the input segmentation

    mitk::IOUtil::Save(interpolationResult, "/home/jenspetersen/Desktop/interpolationtest.nrrd");
    MITK_ASSERT_EQUAL(interpolationResult, m_ResultImageAxial, "The created interpolation should fit the reference interpolation.");
  }

};

MITK_TEST_SUITE_REGISTRATION(mitkSegmentationInterpolation);

//#include "mitkSegmentationInterpolationController.h"
//#include "mitkCoreObjectFactory.h"
//#include "mitkStandardFileLocations.h"
////#include "mitkDataNodeFactory.h"
//#include "ipSegmentation.h"
//#include "mitkCompareImageSliceTestHelper.h"

//class mitkSegmentationInterpolationTestClass
//{
//  public:
//    mitkSegmentationInterpolationTestClass() {}
//    ~mitkSegmentationInterpolationTestClass() {}

//    bool Test(std::string filename1, std::string filename2)
//    {
//      return CreateNewInterpolator()
//          && CreateSegmentation()
//          && ClearSegmentation()
//          && CreateTwoSlices(2)
//          && TestInterpolation(2)
//          && ClearSegmentation()
//          && CreateTwoSlices(1)
//          && TestInterpolation(1)
//          && ClearSegmentation()
//          && CreateTwoSlices(0)
//          && TestInterpolation(0)
//          && DeleteInterpolator()
//          && CreateNewInterpolator()
//          && LoadTestImages(filename1, filename2)
//          && CompareInterpolationsToDefinedReference();
//    }

//  protected:

//    bool CreateNewInterpolator();
//    bool CreateSegmentation();
//    bool ClearSegmentation();
//    bool CreateTwoSlices(int);
//    bool TestInterpolation(int);
//    bool DeleteInterpolator();
//    bool LoadTestImages(std::string filename1, std::string filename2);
//    bool CompareInterpolationsToDefinedReference();

//    mitk::Image::Pointer LoadImage(const std::string& filename);

//    mitk::SegmentationInterpolationController::Pointer m_Interpolator;
//    mitk::Image::Pointer m_Image;

//    mitk::Image::Pointer m_ManualSlices;
//    mitk::Image::Pointer m_InterpolatedSlices;

//    unsigned int dim[3];
//    int pad[3];
//};

//bool mitkSegmentationInterpolationTestClass::CreateNewInterpolator()
//{
//  std::cout << "Instantiation" << std::endl;

//// instantiation
//  m_Interpolator = mitk::SegmentationInterpolationController::New();
//  if (m_Interpolator.IsNotNull())
//  {
//    std::cout << "  (II) Instantiation works." << std::endl;
//  }
//  else
//  {
//    std::cout << " Instantiation test failed!" << std::endl;
//    return false;
//  }

//  return true;
//}

//bool mitkSegmentationInterpolationTestClass::CreateSegmentation()
//{
//  m_Image = mitk::Image::New();
//  dim[0]=15;
//  dim[1]=20;
//  dim[2]=25;
//  pad[0]=2;
//  pad[1]=3;
//  pad[2]=4;

//  m_Image->Initialize( mitk::MakeScalarPixelType<int>(), 3, dim);

//  return true;
//}

//bool mitkSegmentationInterpolationTestClass::ClearSegmentation()
//{
//  int* p = (int*)m_Image->GetData(); // pointer to pixel data
//  int size = dim[0]*dim[1]*dim[2];
//  for(int i=0; i<size; ++i, ++p) *p=0; // fill image with zeros

//  return true;
//}

///**
// * Creates a square segmentation in slices 0 and 2.
//*/
//bool mitkSegmentationInterpolationTestClass::CreateTwoSlices(int slicedim)
//{
//  int* p = (int*)m_Image->GetData(); // pointer to pixel data

//  int size = dim[0]*dim[1]*dim[2];
//  for(int i=0; i<size; ++i, ++p)
//  {
//    int x,y,z;
//    int xdim,ydim;
//    switch (slicedim)
//    {
//      case 0:
//        z = i % dim[0];
//        y = i / dim[0] %  dim[1];
//        x = i / (dim[1]*dim[0]);
//        xdim = 2;
//        ydim = 1;
//        break;
//      case 1:
//        x = i % dim[0];
//        z = i / dim[0] %  dim[1];
//        y = i / (dim[1]*dim[0]);
//        xdim = 0;
//        ydim = 2;
//        break;
//      case 2:
//      default:
//        x = i % dim[0];
//        y = i / dim[0] %  dim[1];
//        z = i / (dim[1]*dim[0]);
//        xdim = 0;
//        ydim = 1;
//        break;
//    }

//    if ( ((z == 0) || (z == 2)) && (x >= pad[xdim]) && (x < ( (signed) dim[xdim]-pad[xdim])) && (y >= pad[ydim]) && (y < ( (signed) dim[ydim]-pad[ydim])) )
//    {
//      *p = 1;
//    }
//    else
//    {
//      *p = 0;
//    }
//  }

//  m_Interpolator->SetSegmentationVolume( m_Image );
//  std::cout << "  (II) SetSegmentationVolume works (slicedim " << slicedim << ")" << std::endl;

//  return true;
//}

///**
// * Checks if interpolation would create a square in slice 1
//*/
//bool mitkSegmentationInterpolationTestClass::TestInterpolation(int slicedim)
//{
//  int slice = 1;
//  mitk::Image::Pointer interpolated = m_Interpolator->Interpolate( slicedim, slice, 0 ); // interpolate second slice axial
//  if (interpolated.IsNull())
//  {
//    std::cerr << "  (EE) Interpolation did not return anything for slicedim == " << slicedim << " (although it should)." << std::endl;
//    return false;
//  }

//  int xdim,ydim;
//  switch (slicedim)
//  {
//    case 0:
//      xdim = 1;
//      ydim = 2; // different than above!
//      break;
//    case 1:
//      xdim = 0;
//      ydim = 2;
//      break;
//    case 2:
//    default:
//      xdim = 0;
//      ydim = 1;
//      break;
//  }

//  ipMITKSegmentationTYPE* p = (ipMITKSegmentationTYPE*)interpolated->GetData(); // pointer to pixel data

//  int size = dim[xdim]*dim[ydim];
//  if ( (signed) interpolated->GetDimension(0) * (signed) interpolated->GetDimension(1) != size )
//  {
//    std::cout << "  (EE) Size of interpolated image differs from original segmentation..." << std::endl;
//    return false;
//  }

//  for(int i=0; i<size; ++i, ++p)
//  {
//    int x,y;
//    x = i % dim[xdim];
//    y = i / dim[xdim];

//    //if (x == 0) std::cout << std::endl;

//    ipMITKSegmentationTYPE value = *p;

//    //if (value == 1) std::cout << "O"; else std::cout << ".";

//    if ( (x >= pad[xdim]) && (x < ((signed) dim[xdim]-pad[xdim])) && (y >= pad[ydim]) && (y < ((signed) dim[ydim]-pad[ydim])) && (value != 1) )
//    {
//      std::cout << "  (EE) Interpolation of a square figure failed" << std::endl;
//      std::cout << "  Value at " << x << " " << y << ": " << (int)value << std::endl;
//      return false;
//    }
//  }

//  std::cout << "  (II) Interpolation of a square figure works like expected (slicedim " << slicedim << ")" << std::endl;
//  return true;
//}

//bool mitkSegmentationInterpolationTestClass::DeleteInterpolator()
//{
//  std::cout << "Object destruction" << std::endl;

//// freeing
//  m_Interpolator = NULL;

//  std::cout << "  (II) Freeing works." << std::endl;
//  return true;
//}

//bool mitkSegmentationInterpolationTestClass::LoadTestImages(std::string filename1, std::string filename2)
//{
//  m_ManualSlices = LoadImage( filename1 );
//  m_InterpolatedSlices = LoadImage( filename2 );

//  return ( m_ManualSlices.IsNotNull() && m_InterpolatedSlices.IsNotNull() );
//}

//mitk::Image::Pointer mitkSegmentationInterpolationTestClass::LoadImage(const std::string& filename)
//{
//  mitk::Image::Pointer image = NULL;
//  mitk::DataNodeFactory::Pointer factory = mitk::DataNodeFactory::New();
//  try
//  {
//    factory->SetFileName( filename );
//    factory->Update();

//    if(factory->GetNumberOfOutputs()<1)
//    {
//      std::cerr<<"File " << filename << " could not be loaded [FAILED]"<<std::endl;
//      return NULL;
//    }
//    mitk::DataNode::Pointer node = factory->GetOutput( 0 );
//    image = dynamic_cast<mitk::Image*>(node->GetData());
//    if(image.IsNull())
//    {
//      std::cout<<"File " << filename << " is not an image! [FAILED]"<<std::endl;
//      return NULL;
//    }
//  }
//  catch ( itk::ExceptionObject & ex )
//  {
//    std::cerr << "Exception: " << ex << "[FAILED]" << std::endl;
//    return NULL;
//  }

//  return image;
//}

//bool mitkSegmentationInterpolationTestClass::CompareInterpolationsToDefinedReference()
//{
//  std::cout << "  (II) Setting segmentation volume... " << std::flush;

//  m_Interpolator->SetSegmentationVolume( m_ManualSlices );

//  std::cout << "OK" << std::endl;

//  std::cout << "  (II) Testing interpolation result for slice " << std::flush;

//  for (unsigned int slice = 1; slice < 98; ++slice)
//  {
//    if (slice % 2 == 0) continue; // these were manually drawn, no interpolation possible

//    std::cout << slice << " " << std::flush;

//    mitk::Image::Pointer interpolation = m_Interpolator->Interpolate( 2, slice, 0 );

//    if ( interpolation.IsNull() )
//    {
//      std::cerr << "  (EE) Interpolated image is NULL." << std::endl;
//      return false;
//    }

//    if ( !CompareImageSliceTestHelper::CompareSlice( m_InterpolatedSlices, 2, slice, interpolation ) )
//    {
//      std::cerr << "  (EE) interpolated image is not identical to reference in slice " << slice << std::endl;
//      return false;
//    }
//  }

//  std::cout << std::endl;
//  std::cout << "  (II) Interpolations are the same as the saved references." << std::endl;

//  return true;
//}

///// ctest entry point
//int mitkSegmentationInterpolationTest(int argc, char* argv[])
//{
//// one big variable to tell if anything went wrong
////  std::cout << "Creating CoreObjectFactory" << std::endl;
////  itk::ObjectFactoryBase::RegisterFactory(mitk::CoreObjectFactory::New());
//  if (argc < 3)
//  {
//    std::cerr << " (EE) Missing arguments for testing" << std::endl;
//  }
//  mitkSegmentationInterpolationTestClass test;
//  if ( test.Test(argv[1], argv[2]) )
//  {
//    std::cout << "[PASSED]" << std::endl;
//    return EXIT_SUCCESS;
//  }
//  else
//  {
//    std::cout << "[FAILED]" << std::endl;
//    return EXIT_FAILURE;
//  }
//}

<|endoftext|>


<commit_before>/**
* @file       t_integration_Indexer.cpp
* @author     Jun
* @version    SF1 v5.0
* @brief Integration test suites for index manager.
*
*/

#include <vector>
#include <sstream> // std::ostringstream
#include <cstdlib> //getenv
#include <boost/test/unit_test.hpp>
#include <boost/test/parameterized_test.hpp>
#include <boost/program_options.hpp>
#include <boost/foreach.hpp>
#include <boost/test/output/xml_log_formatter.hpp>

#include <glog/logging.h>

#include <TestHelper.h> //MyXmlLogFormatter
#include "IndexerTestFixture.h"
#include "t_IndexReader.h"
#include "t_BarrelsInfo.h"
#include "t_TermDocFreqs.h"

using namespace std;
using namespace boost::unit_test;
namespace po = boost::program_options;

namespace {
/** the parameters for each test case */
const IndexerTestConfig INDEXER_TEST_CONFIGS[] = {
    {0, 1, 1, "default", true},
    {1, 1, 1, "realtime", true},
    {2, 5, 3, "default", true},
    {3, 5, 3, "realtime", true},
    {4, 10, 6, "default", true},
    {5, 10, 6, "realtime", true},
    {6, 300, 1, "default", true},
    {7, 300, 1, "realtime", true},
    {8, 100, 23, "default", true},
    {9, 100, 23, "realtime", true},
    {10, 1000, 10, "default", true},
    {11, 1000, 10, "realtime", true},
    {12, 1, 1, "default:chunk", true},
    {13, 5, 3, "default:chunk", true},
    {14, 10, 6, "default:chunk", true},
    {15, 300, 1, "default:chunk", true},
    {16, 100, 23, "default:chunk", true},
    {17, 1, 1, "default:block", true},
    {18, 5, 3, "default:block", true},
    {19, 10, 6, "default:block", true},
    {20, 300, 1, "default:block", true},
    {21, 100, 23, "default:block", true},
};

/** the parameter number */
const int INDEXER_TEST_CONFIG_NUM = sizeof(INDEXER_TEST_CONFIGS) / sizeof(IndexerTestConfig);

/** if the command options of "--run_config_list" or "--run_config_range" are not specified, run configs of range [0, DEFAULT_CONFIG_RANGE] */
const int DEFAULT_CONFIG_RANGE = 5;

/** the command option to specify a list of config numbers, such as "--run_config_list 0 1 2 3" */
const char* OPTION_CONFIG_LIST = "run_config_list";

/** the command option to specify a range of config numbers, such as "--run_config_range 4 7" */
const char* OPTION_CONFIG_RANGE = "run_config_range";

/** the environment variable name for boost test log */
const char* ENV_NAME_LOG_FILE = "BOOST_TEST_LOG_FILE";
}

static std::ofstream* gOutStream = 0;

/**
 * Load command line option "run_config_list" or "run_config_range" to decide which configs to run.
 * @param configVec the loaded configs to run
 * @return true for load success, false for fail
 */
bool loadConfigOption(vector<IndexerTestConfig>& configVec)
{
    try
    {
        vector<int> runConfigListVec;
        vector<int> runConfigRangeVec;
        po::options_description desp("Allowed options");
        desp.add_options()
            ("build_info,i", "this option is not used, it is just in case of boost test didn't filter out this option")
            (OPTION_CONFIG_LIST, po::value<std::vector<int> >(&runConfigListVec)->multitoken(), "specify the list of config parameters to run")
            (OPTION_CONFIG_RANGE, po::value<std::vector<int> >(&runConfigRangeVec)->multitoken(), "specify the range of config parameters to run")
            ;

        po::options_description cmdline_options;
        cmdline_options.add(desp);

        po::variables_map vm;
        store(po::command_line_parser(framework::master_test_suite().argc, framework::master_test_suite().argv).options(cmdline_options).run(), vm);
        po::notify(vm);

        if(vm.count(OPTION_CONFIG_LIST))
        {
            cout << OPTION_CONFIG_LIST << ": ";
            BOOST_FOREACH(int i, runConfigListVec)
            {
                cout << i << ", ";
                if(i >= 0 && i < INDEXER_TEST_CONFIG_NUM)
                    configVec.push_back(INDEXER_TEST_CONFIGS[i]);
                else
                {
                    cout << endl;
                    ostringstream oss;
                    oss << "unknown config number " << i;
                    throw std::runtime_error(oss.str());
                }
            }
            cout << endl;
        }
        else if(vm.count(OPTION_CONFIG_RANGE))
        {
            cout << OPTION_CONFIG_RANGE << ": ";
            BOOST_FOREACH(int i, runConfigRangeVec)
                cout << i << ", ";
            cout << endl;

            if(runConfigRangeVec.size() == 2
                    && runConfigRangeVec[0] >= 0
                    && runConfigRangeVec[0] <= runConfigRangeVec[1]
                    && runConfigRangeVec[1] < INDEXER_TEST_CONFIG_NUM)
                configVec.insert(configVec.begin(), INDEXER_TEST_CONFIGS + runConfigRangeVec[0],
                                                    INDEXER_TEST_CONFIGS + runConfigRangeVec[1] + 1);
            else
            {
                ostringstream oss;
                oss << "the config range is invalid";
                throw std::runtime_error(oss.str());
            }
        }
        else
        {
            cout << "run default configs range: [0, " << DEFAULT_CONFIG_RANGE << "]" << endl;
            configVec.insert(configVec.begin(), INDEXER_TEST_CONFIGS,
                                                INDEXER_TEST_CONFIGS + DEFAULT_CONFIG_RANGE + 1);
        }
    }
    catch(std::exception& e)
    {
        cerr << "error: " << e.what() << endl;
        return false;
    }

    return true;
}

/**
 * Boost test module initialize function, it regsiters the test cases to run.
 * @return true for success, false for failure
 */
bool my_init_unit_test()
{
    if(const char* const gEnvValue = std::getenv(ENV_NAME_LOG_FILE))
    {
        cout << ENV_NAME_LOG_FILE << ": " << gEnvValue << endl;
        gOutStream = new std::ofstream(gEnvValue);
        boost::unit_test::unit_test_log.set_stream(*gOutStream);
        boost::unit_test::unit_test_log.set_formatter(new MyXmlLogFormatter());
    }

    vector<IndexerTestConfig> configVec;
    if(! loadConfigOption(configVec))
        return false;

    framework::master_test_suite().p_name.value = "t_integration_Indexer";

    const IndexerTestConfig* const pConfigStart = &configVec[0];
    const IndexerTestConfig* const pConfigEnd = pConfigStart + configVec.size();

    test_suite* tsIndexReader = BOOST_TEST_SUITE("t_IndexReader");
    tsIndexReader->add(BOOST_PARAM_TEST_CASE(&t_IndexReader::index, pConfigStart, pConfigEnd));
    tsIndexReader->add(BOOST_PARAM_TEST_CASE(&t_IndexReader::update, pConfigStart, pConfigEnd));
    tsIndexReader->add(BOOST_PARAM_TEST_CASE(&t_IndexReader::remove, pConfigStart, pConfigEnd));
    tsIndexReader->add(BOOST_PARAM_TEST_CASE(&t_IndexReader::empty, pConfigStart, pConfigEnd));
    framework::master_test_suite().add(tsIndexReader);

    test_suite* tsBarrelsInfo = BOOST_TEST_SUITE("t_BarrelsInfo");
    tsBarrelsInfo->add(BOOST_PARAM_TEST_CASE(&t_BarrelsInfo::index, pConfigStart, pConfigEnd));
    tsBarrelsInfo->add(BOOST_PARAM_TEST_CASE(&t_BarrelsInfo::optimize, pConfigStart, pConfigEnd));
    tsBarrelsInfo->add(BOOST_PARAM_TEST_CASE(&t_BarrelsInfo::createAfterOptimize, pConfigStart, pConfigEnd));
    tsBarrelsInfo->add(BOOST_PARAM_TEST_CASE(&t_BarrelsInfo::pauseResumeMerge, pConfigStart, pConfigEnd));
    tsBarrelsInfo->add(BOOST_PARAM_TEST_CASE(&t_BarrelsInfo::empty, pConfigStart, pConfigEnd));
    tsBarrelsInfo->add(BOOST_PARAM_TEST_CASE(&t_BarrelsInfo::resumeMergeAtStartUp, pConfigStart, pConfigEnd));
    framework::master_test_suite().add(tsBarrelsInfo);

    test_suite* tsTermDocFreqs = BOOST_TEST_SUITE("t_TermDocFreqs");
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::index, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::remove, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::update, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::empty, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::removeDocAndOptimize, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::optimizeAndRemoveDoc, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::removeOneTerm, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::checkRemoveAtStartUp, pConfigStart, pConfigEnd));
    framework::master_test_suite().add(tsTermDocFreqs);

    return true;
}

int main( int argc, char* argv[] )
{
    google::InitGoogleLogging(argv[0]);

    int status = ::boost::unit_test::unit_test_main( &my_init_unit_test, argc, argv );

    // delete global stream to flush
    delete gOutStream;

    return status;
}
<commit_msg>adjust test parameters in t_integration_Indexer.<commit_after>/**
* @file       t_integration_Indexer.cpp
* @author     Jun
* @version    SF1 v5.0
* @brief Integration test suites for index manager.
*
*/

#include <vector>
#include <sstream> // std::ostringstream
#include <cstdlib> //getenv
#include <boost/test/unit_test.hpp>
#include <boost/test/parameterized_test.hpp>
#include <boost/program_options.hpp>
#include <boost/foreach.hpp>
#include <boost/test/output/xml_log_formatter.hpp>

#include <glog/logging.h>

#include <TestHelper.h> //MyXmlLogFormatter
#include "IndexerTestFixture.h"
#include "t_IndexReader.h"
#include "t_BarrelsInfo.h"
#include "t_TermDocFreqs.h"

using namespace std;
using namespace boost::unit_test;
namespace po = boost::program_options;

namespace {
/** the parameters for each test case */
const IndexerTestConfig INDEXER_TEST_CONFIGS[] = {
    {0, 1, 1, "default", true},
    {1, 1, 1, "realtime", true},
    {2, 1, 1, "default:chunk", true},
    {3, 1, 1, "default:block", true},
    {4, 5, 3, "default", true},
    {5, 5, 3, "realtime", true},
    {6, 5, 3, "default:chunk", true},
    {7, 5, 3, "default:block", true},
    {8, 10, 6, "default", true},
    {9, 10, 6, "realtime", true},
    {10, 10, 6, "default:chunk", true},
    {11, 10, 6, "default:block", true},
    {12, 300, 1, "default", true},
    {13, 300, 1, "realtime", true},
    {14, 300, 1, "default:chunk", true},
    {15, 300, 1, "default:block", true},
    {16, 100, 23, "default", true},
    {17, 100, 23, "realtime", true},
    {18, 100, 23, "default:chunk", true},
    {19, 100, 23, "default:block", true},
    {20, 1000, 10, "default", true},
    {21, 1000, 10, "realtime", true},
    {22, 1000, 10, "default:chunk", true},
    {23, 1000, 10, "default:block", true},
};

/** the parameter number */
const int INDEXER_TEST_CONFIG_NUM = sizeof(INDEXER_TEST_CONFIGS) / sizeof(IndexerTestConfig);

/** if the command options of "--run_config_list" or "--run_config_range" are not specified, run configs of range [0, DEFAULT_CONFIG_RANGE] */
const int DEFAULT_CONFIG_RANGE = 7;

/** the command option to specify a list of config numbers, such as "--run_config_list 0 1 2 3" */
const char* OPTION_CONFIG_LIST = "run_config_list";

/** the command option to specify a range of config numbers, such as "--run_config_range 4 7" */
const char* OPTION_CONFIG_RANGE = "run_config_range";

/** the environment variable name for boost test log */
const char* ENV_NAME_LOG_FILE = "BOOST_TEST_LOG_FILE";
}

static std::ofstream* gOutStream = 0;

/**
 * Load command line option "run_config_list" or "run_config_range" to decide which configs to run.
 * @param configVec the loaded configs to run
 * @return true for load success, false for fail
 */
bool loadConfigOption(vector<IndexerTestConfig>& configVec)
{
    try
    {
        vector<int> runConfigListVec;
        vector<int> runConfigRangeVec;
        po::options_description desp("Allowed options");
        desp.add_options()
            ("build_info,i", "this option is not used, it is just in case of boost test didn't filter out this option")
            (OPTION_CONFIG_LIST, po::value<std::vector<int> >(&runConfigListVec)->multitoken(), "specify the list of config parameters to run")
            (OPTION_CONFIG_RANGE, po::value<std::vector<int> >(&runConfigRangeVec)->multitoken(), "specify the range of config parameters to run")
            ;

        po::options_description cmdline_options;
        cmdline_options.add(desp);

        po::variables_map vm;
        store(po::command_line_parser(framework::master_test_suite().argc, framework::master_test_suite().argv).options(cmdline_options).run(), vm);
        po::notify(vm);

        if(vm.count(OPTION_CONFIG_LIST))
        {
            cout << OPTION_CONFIG_LIST << ": ";
            BOOST_FOREACH(int i, runConfigListVec)
            {
                cout << i << ", ";
                if(i >= 0 && i < INDEXER_TEST_CONFIG_NUM)
                    configVec.push_back(INDEXER_TEST_CONFIGS[i]);
                else
                {
                    cout << endl;
                    ostringstream oss;
                    oss << "unknown config number " << i;
                    throw std::runtime_error(oss.str());
                }
            }
            cout << endl;
        }
        else if(vm.count(OPTION_CONFIG_RANGE))
        {
            cout << OPTION_CONFIG_RANGE << ": ";
            BOOST_FOREACH(int i, runConfigRangeVec)
                cout << i << ", ";
            cout << endl;

            if(runConfigRangeVec.size() == 2
                    && runConfigRangeVec[0] >= 0
                    && runConfigRangeVec[0] <= runConfigRangeVec[1]
                    && runConfigRangeVec[1] < INDEXER_TEST_CONFIG_NUM)
                configVec.insert(configVec.begin(), INDEXER_TEST_CONFIGS + runConfigRangeVec[0],
                                                    INDEXER_TEST_CONFIGS + runConfigRangeVec[1] + 1);
            else
            {
                ostringstream oss;
                oss << "the config range is invalid";
                throw std::runtime_error(oss.str());
            }
        }
        else
        {
            cout << "run default configs range: [0, " << DEFAULT_CONFIG_RANGE << "]" << endl;
            configVec.insert(configVec.begin(), INDEXER_TEST_CONFIGS,
                                                INDEXER_TEST_CONFIGS + DEFAULT_CONFIG_RANGE + 1);
        }
    }
    catch(std::exception& e)
    {
        cerr << "error: " << e.what() << endl;
        return false;
    }

    return true;
}

/**
 * Boost test module initialize function, it regsiters the test cases to run.
 * @return true for success, false for failure
 */
bool my_init_unit_test()
{
    if(const char* const gEnvValue = std::getenv(ENV_NAME_LOG_FILE))
    {
        cout << ENV_NAME_LOG_FILE << ": " << gEnvValue << endl;
        gOutStream = new std::ofstream(gEnvValue);
        boost::unit_test::unit_test_log.set_stream(*gOutStream);
        boost::unit_test::unit_test_log.set_formatter(new MyXmlLogFormatter());
    }

    vector<IndexerTestConfig> configVec;
    if(! loadConfigOption(configVec))
        return false;

    framework::master_test_suite().p_name.value = "t_integration_Indexer";

    const IndexerTestConfig* const pConfigStart = &configVec[0];
    const IndexerTestConfig* const pConfigEnd = pConfigStart + configVec.size();

    test_suite* tsIndexReader = BOOST_TEST_SUITE("t_IndexReader");
    tsIndexReader->add(BOOST_PARAM_TEST_CASE(&t_IndexReader::index, pConfigStart, pConfigEnd));
    tsIndexReader->add(BOOST_PARAM_TEST_CASE(&t_IndexReader::update, pConfigStart, pConfigEnd));
    tsIndexReader->add(BOOST_PARAM_TEST_CASE(&t_IndexReader::remove, pConfigStart, pConfigEnd));
    tsIndexReader->add(BOOST_PARAM_TEST_CASE(&t_IndexReader::empty, pConfigStart, pConfigEnd));
    framework::master_test_suite().add(tsIndexReader);

    test_suite* tsBarrelsInfo = BOOST_TEST_SUITE("t_BarrelsInfo");
    tsBarrelsInfo->add(BOOST_PARAM_TEST_CASE(&t_BarrelsInfo::index, pConfigStart, pConfigEnd));
    tsBarrelsInfo->add(BOOST_PARAM_TEST_CASE(&t_BarrelsInfo::optimize, pConfigStart, pConfigEnd));
    tsBarrelsInfo->add(BOOST_PARAM_TEST_CASE(&t_BarrelsInfo::createAfterOptimize, pConfigStart, pConfigEnd));
    tsBarrelsInfo->add(BOOST_PARAM_TEST_CASE(&t_BarrelsInfo::pauseResumeMerge, pConfigStart, pConfigEnd));
    tsBarrelsInfo->add(BOOST_PARAM_TEST_CASE(&t_BarrelsInfo::empty, pConfigStart, pConfigEnd));
    tsBarrelsInfo->add(BOOST_PARAM_TEST_CASE(&t_BarrelsInfo::resumeMergeAtStartUp, pConfigStart, pConfigEnd));
    framework::master_test_suite().add(tsBarrelsInfo);

    test_suite* tsTermDocFreqs = BOOST_TEST_SUITE("t_TermDocFreqs");
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::index, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::remove, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::update, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::empty, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::removeDocAndOptimize, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::optimizeAndRemoveDoc, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::removeOneTerm, pConfigStart, pConfigEnd));
    tsTermDocFreqs->add(BOOST_PARAM_TEST_CASE(&t_TermDocFreqs::checkRemoveAtStartUp, pConfigStart, pConfigEnd));
    framework::master_test_suite().add(tsTermDocFreqs);

    return true;
}

int main( int argc, char* argv[] )
{
    google::InitGoogleLogging(argv[0]);

    int status = ::boost::unit_test::unit_test_main( &my_init_unit_test, argc, argv );

    // delete global stream to flush
    delete gOutStream;

    return status;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003-2005 The Regents of The University of Michigan
 * 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 copyright holders 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.
 *
 * Authors: Gabe Black
 *          Ali Saidi
 */

#ifndef __ARCH_SPARC_MISCREGS_HH__
#define __ARCH_SPARC_MISCREGS_HH__

#include "base/bitunion.hh"
#include "base/types.hh"

namespace SparcISA
{
enum MiscRegIndex
{
    /** Ancillary State Registers */
//    MISCREG_Y,
//    MISCREG_CCR,
    MISCREG_ASI,
    MISCREG_TICK,
    MISCREG_FPRS,
    MISCREG_PCR,
    MISCREG_PIC,
    MISCREG_GSR,
    MISCREG_SOFTINT_SET,
    MISCREG_SOFTINT_CLR,
    MISCREG_SOFTINT, /* 10 */
    MISCREG_TICK_CMPR,
    MISCREG_STICK,
    MISCREG_STICK_CMPR,

    /** Privilged Registers */
    MISCREG_TPC,
    MISCREG_TNPC,
    MISCREG_TSTATE,
    MISCREG_TT,
    MISCREG_PRIVTICK,
    MISCREG_TBA,
    MISCREG_PSTATE, /* 20 */
    MISCREG_TL,
    MISCREG_PIL,
    MISCREG_CWP,
//    MISCREG_CANSAVE,
//    MISCREG_CANRESTORE,
//    MISCREG_CLEANWIN,
//    MISCREG_OTHERWIN,
//    MISCREG_WSTATE,
    MISCREG_GL,

    /** Hyper privileged registers */
    MISCREG_HPSTATE, /* 30 */
    MISCREG_HTSTATE,
    MISCREG_HINTP,
    MISCREG_HTBA,
    MISCREG_HVER,
    MISCREG_STRAND_STS_REG,
    MISCREG_HSTICK_CMPR,

    /** Floating Point Status Register */
    MISCREG_FSR,

    /** MMU Internal Registers */
    MISCREG_MMU_P_CONTEXT,
    MISCREG_MMU_S_CONTEXT, /* 40 */
    MISCREG_MMU_PART_ID,
    MISCREG_MMU_LSU_CTRL,

    /** Scratchpad regiscers **/
    MISCREG_SCRATCHPAD_R0, /* 60 */
    MISCREG_SCRATCHPAD_R1,
    MISCREG_SCRATCHPAD_R2,
    MISCREG_SCRATCHPAD_R3,
    MISCREG_SCRATCHPAD_R4,
    MISCREG_SCRATCHPAD_R5,
    MISCREG_SCRATCHPAD_R6,
    MISCREG_SCRATCHPAD_R7,

    /* CPU Queue Registers */
    MISCREG_QUEUE_CPU_MONDO_HEAD,
    MISCREG_QUEUE_CPU_MONDO_TAIL,
    MISCREG_QUEUE_DEV_MONDO_HEAD, /* 70 */
    MISCREG_QUEUE_DEV_MONDO_TAIL,
    MISCREG_QUEUE_RES_ERROR_HEAD,
    MISCREG_QUEUE_RES_ERROR_TAIL,
    MISCREG_QUEUE_NRES_ERROR_HEAD,
    MISCREG_QUEUE_NRES_ERROR_TAIL,

    /* All the data for the TLB packed up in one register. */
    MISCREG_TLB_DATA,
    MISCREG_NUMMISCREGS
};

BitUnion64(HPSTATE)
    Bitfield<0> tlz;
    Bitfield<2> hpriv;
    Bitfield<5> red;
    Bitfield<10> ibe;
    Bitfield<11> id;  // this impl. dependent (id) field m
EndBitUnion(HPSTATE)

BitUnion16(PSTATE)
    Bitfield<1> ie;
    Bitfield<2> priv;
    Bitfield<3> am;
    Bitfield<4> pef;
    Bitfield<6, 7> mm;
    Bitfield<8> tle;
    Bitfield<9> cle;
    Bitfield<10> pid0;
    Bitfield<11> pid1;
EndBitUnion(PSTATE)

struct STS
{
    const static int st_idle     = 0x00;
    const static int st_wait     = 0x01;
    const static int st_halt     = 0x02;
    const static int st_run      = 0x05;
    const static int st_spec_run = 0x07;
    const static int st_spec_rdy = 0x13;
    const static int st_ready    = 0x19;
    const static int active      = 0x01;
    const static int speculative = 0x04;
    const static int shft_id     = 8;
    const static int shft_fsm0   = 31;
    const static int shft_fsm1   = 26;
    const static int shft_fsm2   = 21;
    const static int shft_fsm3   = 16;
};

const int NumMiscRegs = MISCREG_NUMMISCREGS;

}

#endif
<commit_msg>sparc: Fixup bit ordering in the PSTATE bit union<commit_after>/*
 * Copyright (c) 2003-2005 The Regents of The University of Michigan
 * 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 copyright holders 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.
 *
 * Authors: Gabe Black
 *          Ali Saidi
 */

#ifndef __ARCH_SPARC_MISCREGS_HH__
#define __ARCH_SPARC_MISCREGS_HH__

#include "base/bitunion.hh"
#include "base/types.hh"

namespace SparcISA
{
enum MiscRegIndex
{
    /** Ancillary State Registers */
//    MISCREG_Y,
//    MISCREG_CCR,
    MISCREG_ASI,
    MISCREG_TICK,
    MISCREG_FPRS,
    MISCREG_PCR,
    MISCREG_PIC,
    MISCREG_GSR,
    MISCREG_SOFTINT_SET,
    MISCREG_SOFTINT_CLR,
    MISCREG_SOFTINT, /* 10 */
    MISCREG_TICK_CMPR,
    MISCREG_STICK,
    MISCREG_STICK_CMPR,

    /** Privilged Registers */
    MISCREG_TPC,
    MISCREG_TNPC,
    MISCREG_TSTATE,
    MISCREG_TT,
    MISCREG_PRIVTICK,
    MISCREG_TBA,
    MISCREG_PSTATE, /* 20 */
    MISCREG_TL,
    MISCREG_PIL,
    MISCREG_CWP,
//    MISCREG_CANSAVE,
//    MISCREG_CANRESTORE,
//    MISCREG_CLEANWIN,
//    MISCREG_OTHERWIN,
//    MISCREG_WSTATE,
    MISCREG_GL,

    /** Hyper privileged registers */
    MISCREG_HPSTATE, /* 30 */
    MISCREG_HTSTATE,
    MISCREG_HINTP,
    MISCREG_HTBA,
    MISCREG_HVER,
    MISCREG_STRAND_STS_REG,
    MISCREG_HSTICK_CMPR,

    /** Floating Point Status Register */
    MISCREG_FSR,

    /** MMU Internal Registers */
    MISCREG_MMU_P_CONTEXT,
    MISCREG_MMU_S_CONTEXT, /* 40 */
    MISCREG_MMU_PART_ID,
    MISCREG_MMU_LSU_CTRL,

    /** Scratchpad regiscers **/
    MISCREG_SCRATCHPAD_R0, /* 60 */
    MISCREG_SCRATCHPAD_R1,
    MISCREG_SCRATCHPAD_R2,
    MISCREG_SCRATCHPAD_R3,
    MISCREG_SCRATCHPAD_R4,
    MISCREG_SCRATCHPAD_R5,
    MISCREG_SCRATCHPAD_R6,
    MISCREG_SCRATCHPAD_R7,

    /* CPU Queue Registers */
    MISCREG_QUEUE_CPU_MONDO_HEAD,
    MISCREG_QUEUE_CPU_MONDO_TAIL,
    MISCREG_QUEUE_DEV_MONDO_HEAD, /* 70 */
    MISCREG_QUEUE_DEV_MONDO_TAIL,
    MISCREG_QUEUE_RES_ERROR_HEAD,
    MISCREG_QUEUE_RES_ERROR_TAIL,
    MISCREG_QUEUE_NRES_ERROR_HEAD,
    MISCREG_QUEUE_NRES_ERROR_TAIL,

    /* All the data for the TLB packed up in one register. */
    MISCREG_TLB_DATA,
    MISCREG_NUMMISCREGS
};

BitUnion64(HPSTATE)
    Bitfield<0> tlz;
    Bitfield<2> hpriv;
    Bitfield<5> red;
    Bitfield<10> ibe;
    Bitfield<11> id;  // this impl. dependent (id) field m
EndBitUnion(HPSTATE)

BitUnion16(PSTATE)
    Bitfield<1> ie;
    Bitfield<2> priv;
    Bitfield<3> am;
    Bitfield<4> pef;
    Bitfield<7, 6> mm;
    Bitfield<8> tle;
    Bitfield<9> cle;
    Bitfield<10> pid0;
    Bitfield<11> pid1;
EndBitUnion(PSTATE)

struct STS
{
    const static int st_idle     = 0x00;
    const static int st_wait     = 0x01;
    const static int st_halt     = 0x02;
    const static int st_run      = 0x05;
    const static int st_spec_run = 0x07;
    const static int st_spec_rdy = 0x13;
    const static int st_ready    = 0x19;
    const static int active      = 0x01;
    const static int speculative = 0x04;
    const static int shft_id     = 8;
    const static int shft_fsm0   = 31;
    const static int shft_fsm1   = 26;
    const static int shft_fsm2   = 21;
    const static int shft_fsm3   = 16;
};

const int NumMiscRegs = MISCREG_NUMMISCREGS;

}

#endif
<|endoftext|>


<commit_before>#pragma once

#include <depthai-shared/common/optional.hpp>
#include <nlohmann/json.hpp>

namespace dai {

/**
 * Specify StereoDepth options
 */
struct StereoDepthProperties {
    /**
     * Median filter config for disparity post-processing
     */
    enum class MedianFilter : int32_t { MEDIAN_OFF = 0, KERNEL_3x3 = 3, KERNEL_5x5 = 5, KERNEL_7x7 = 7 };

    /**
     * Calibration data byte array
     */
    std::vector<std::uint8_t> calibration;
    /**
     * Set kernel size for disparity/depth median filtering, or disable
     */
    MedianFilter median = MedianFilter::KERNEL_7x7;
    /**
     * Confidence threshold for disparity calculation, 0..255
     */
    std::int32_t confidenceThreshold = 200;
    /**
     * Computes and combines disparities in both L-R and R-L directions, and combine them.
     * For better occlusion handling
     */
    bool enableLeftRightCheck = false;
    /**
     * Computes disparity with sub-pixel interpolation (5 fractional bits), suitable for long range
     */
    bool enableSubpixel = false;
    /**
     * Disparity range increased from 96 to 192, combined from full resolution and downscaled images.
     * Suitable for short range objects
     */
    bool enableExtendedDisparity = false;
    /**
     * Mirror rectified frames: true to have disparity/depth normal (non-mirrored)
     */
    bool rectifyMirrorFrame = true;
    /**
     * Fill color for missing data at frame edges: grayscale 0..255, or -1 to replicate pixels
     */
    std::int32_t rectifyEdgeFillColor = -1;
    /**
     * Input frame width. Optional (taken from MonoCamera nodes if they exist)
     */
    tl::optional<std::int32_t> width;
    /**
     * Input frame height. Optional (taken from MonoCamera nodes if they exist)
     */
    tl::optional<std::int32_t> height;

    // TODO: rectification mesh option for fisheye camera use-cases
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(StereoDepthProperties,
                                   calibration,
                                   median,
                                   confidenceThreshold,
                                   enableLeftRightCheck,
                                   enableSubpixel,
                                   enableExtendedDisparity,
                                   rectifyMirrorFrame,
                                   rectifyEdgeFillColor,
                                   width,
                                   height);

}  // namespace dai
<commit_msg>StereoDepthProperties: add baselineOverrideCm, fovOverrideDegres<commit_after>#pragma once

#include <depthai-shared/common/optional.hpp>
#include <nlohmann/json.hpp>

namespace dai {

/**
 * Specify StereoDepth options
 */
struct StereoDepthProperties {
    /**
     * Median filter config for disparity post-processing
     */
    enum class MedianFilter : int32_t { MEDIAN_OFF = 0, KERNEL_3x3 = 3, KERNEL_5x5 = 5, KERNEL_7x7 = 7 };

    /**
     * Calibration data byte array
     */
    std::vector<std::uint8_t> calibration;
    /**
     * Set kernel size for disparity/depth median filtering, or disable
     */
    MedianFilter median = MedianFilter::KERNEL_7x7;
    /**
     * Confidence threshold for disparity calculation, 0..255
     */
    std::int32_t confidenceThreshold = 200;
    /**
     * Computes and combines disparities in both L-R and R-L directions, and combine them.
     * For better occlusion handling
     */
    bool enableLeftRightCheck = false;
    /**
     * Computes disparity with sub-pixel interpolation (5 fractional bits), suitable for long range
     */
    bool enableSubpixel = false;
    /**
     * Disparity range increased from 96 to 192, combined from full resolution and downscaled images.
     * Suitable for short range objects
     */
    bool enableExtendedDisparity = false;
    /**
     * Mirror rectified frames: true to have disparity/depth normal (non-mirrored)
     */
    bool rectifyMirrorFrame = true;
    /**
     * Fill color for missing data at frame edges: grayscale 0..255, or -1 to replicate pixels
     */
    std::int32_t rectifyEdgeFillColor = -1;
    /**
     * Input frame width. Optional (taken from MonoCamera nodes if they exist)
     */
    tl::optional<std::int32_t> width;
    /**
     * Input frame height. Optional (taken from MonoCamera nodes if they exist)
     */
    tl::optional<std::int32_t> height;
    /**
     * Overrides the baseline used for depth calculation. In centimeters
     */
    float baselineOverrideCm = 0;
    /**
     * Overrides the camera horizontal field of view used for depth calculation. In degrees
     */
    float fovOverrideDegrees = 0;

    // TODO: rectification mesh option for fisheye camera use-cases
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(StereoDepthProperties,
                                   calibration,
                                   median,
                                   confidenceThreshold,
                                   enableLeftRightCheck,
                                   enableSubpixel,
                                   enableExtendedDisparity,
                                   rectifyMirrorFrame,
                                   rectifyEdgeFillColor,
                                   width,
                                   height,
                                   baselineOverrideCm,
                                   fovOverrideDegrees);

}  // namespace dai
<|endoftext|>