<commit_before>// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/ui/views/global_menu_bar_x11.h"

#include <X11/Xlib.h>

// This conflicts with mate::Converter,
#undef True
#undef False
// and V8,
#undef None
// and url_request_status.h,
#undef Status

#include <dlfcn.h>
#include <glib-object.h>

#include "atom/browser/native_window_views.h"
#include "atom/browser/ui/atom_menu_model.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
#include "ui/events/keycodes/keyboard_code_conversion_x.h"

// libdbusmenu-glib types
typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_func)();
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_with_id_func)(int id);

typedef int (*dbusmenu_menuitem_get_id_func)(DbusmenuMenuitem* item);
typedef GList* (*dbusmenu_menuitem_get_children_func)(DbusmenuMenuitem* item);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_child_append_func)(
    DbusmenuMenuitem* parent,
    DbusmenuMenuitem* child);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_func)(
    DbusmenuMenuitem* item,
    const char* property,
    const char* value);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_variant_func)(
    DbusmenuMenuitem* item,
    const char* property,
    GVariant* value);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_bool_func)(
    DbusmenuMenuitem* item,
    const char* property,
    bool value);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_int_func)(
    DbusmenuMenuitem* item,
    const char* property,
    int value);

typedef struct _DbusmenuServer      DbusmenuServer;
typedef DbusmenuServer* (*dbusmenu_server_new_func)(const char* object);
typedef void (*dbusmenu_server_set_root_func)(DbusmenuServer* self,
                                              DbusmenuMenuitem* root);

namespace atom {

namespace {

// Retrieved functions from libdbusmenu-glib.

// DbusmenuMenuItem methods:
dbusmenu_menuitem_new_func menuitem_new = NULL;
dbusmenu_menuitem_new_with_id_func menuitem_new_with_id = NULL;
dbusmenu_menuitem_get_id_func menuitem_get_id = NULL;
dbusmenu_menuitem_get_children_func menuitem_get_children = NULL;
dbusmenu_menuitem_get_children_func menuitem_take_children = NULL;
dbusmenu_menuitem_child_append_func menuitem_child_append = NULL;
dbusmenu_menuitem_property_set_func menuitem_property_set = NULL;
dbusmenu_menuitem_property_set_variant_func menuitem_property_set_variant =
    NULL;
dbusmenu_menuitem_property_set_bool_func menuitem_property_set_bool = NULL;
dbusmenu_menuitem_property_set_int_func menuitem_property_set_int = NULL;

// DbusmenuServer methods:
dbusmenu_server_new_func server_new = NULL;
dbusmenu_server_set_root_func server_set_root = NULL;

// Properties that we set on menu items:
const char kPropertyEnabled[] = "enabled";
const char kPropertyLabel[] = "label";
const char kPropertyShortcut[] = "shortcut";
const char kPropertyType[] = "type";
const char kPropertyToggleType[] = "toggle-type";
const char kPropertyToggleState[] = "toggle-state";
const char kPropertyVisible[] = "visible";
const char kPropertyChildrenDisplay[] = "children-display";

const char kToggleCheck[] = "checkmark";
const char kToggleRadio[] = "radio";
const char kTypeSeparator[] = "separator";
const char kDisplaySubmenu[] = "submenu";

void EnsureMethodsLoaded() {
  static bool attempted_load = false;
  if (attempted_load)
    return;
  attempted_load = true;

  void* dbusmenu_lib = dlopen("libdbusmenu-glib.so", RTLD_LAZY);
  if (!dbusmenu_lib)
    dbusmenu_lib = dlopen("libdbusmenu-glib.so.4", RTLD_LAZY);
  if (!dbusmenu_lib)
    return;

  // DbusmenuMenuItem methods.
  menuitem_new = reinterpret_cast<dbusmenu_menuitem_new_func>(
      dlsym(dbusmenu_lib, "dbusmenu_menuitem_new"));
  menuitem_new_with_id = reinterpret_cast<dbusmenu_menuitem_new_with_id_func>(
      dlsym(dbusmenu_lib, "dbusmenu_menuitem_new_with_id"));
  menuitem_get_id = reinterpret_cast<dbusmenu_menuitem_get_id_func>(
      dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_id"));
  menuitem_get_children = reinterpret_cast<dbusmenu_menuitem_get_children_func>(
      dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_children"));
  menuitem_take_children =
      reinterpret_cast<dbusmenu_menuitem_get_children_func>(
          dlsym(dbusmenu_lib, "dbusmenu_menuitem_take_children"));
  menuitem_child_append = reinterpret_cast<dbusmenu_menuitem_child_append_func>(
      dlsym(dbusmenu_lib, "dbusmenu_menuitem_child_append"));
  menuitem_property_set = reinterpret_cast<dbusmenu_menuitem_property_set_func>(
      dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set"));
  menuitem_property_set_variant =
      reinterpret_cast<dbusmenu_menuitem_property_set_variant_func>(
          dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_variant"));
  menuitem_property_set_bool =
      reinterpret_cast<dbusmenu_menuitem_property_set_bool_func>(
          dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_bool"));
  menuitem_property_set_int =
      reinterpret_cast<dbusmenu_menuitem_property_set_int_func>(
          dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_int"));

  // DbusmenuServer methods.
  server_new = reinterpret_cast<dbusmenu_server_new_func>(
      dlsym(dbusmenu_lib, "dbusmenu_server_new"));
  server_set_root = reinterpret_cast<dbusmenu_server_set_root_func>(
      dlsym(dbusmenu_lib, "dbusmenu_server_set_root"));
}

AtomMenuModel* ModelForMenuItem(DbusmenuMenuitem* item) {
  return reinterpret_cast<AtomMenuModel*>(
      g_object_get_data(G_OBJECT(item), "model"));
}

bool GetMenuItemID(DbusmenuMenuitem* item, int *id) {
  gpointer id_ptr = g_object_get_data(G_OBJECT(item), "menu-id");
  if (id_ptr != NULL) {
    *id = GPOINTER_TO_INT(id_ptr) - 1;
    return true;
  }

  return false;
}

void SetMenuItemID(DbusmenuMenuitem* item, int id) {
  DCHECK_GE(id, 0);

  // Add 1 to the menu_id to avoid setting zero (null) to "menu-id".
  g_object_set_data(G_OBJECT(item), "menu-id", GINT_TO_POINTER(id + 1));
}

std::string GetMenuModelStatus(AtomMenuModel* model) {
  std::string ret;
  for (int i = 0; i < model->GetItemCount(); ++i) {
    int status = model->GetTypeAt(i) | (model->IsVisibleAt(i) << 30)
                                     | (model->IsEnabledAt(i) << 29)
                                     | (model->IsItemCheckedAt(i) << 28);
    ret += base::StringPrintf(
        "%s-%d\n", base::UTF16ToUTF8(model->GetLabelAt(i)).c_str(), status);
  }
  return ret;
}

}  // namespace

GlobalMenuBarX11::GlobalMenuBarX11(NativeWindowViews* window)
    : window_(window),
      xid_(window_->GetNativeWindow()->GetHost()->GetAcceleratedWidget()),
      server_(NULL) {
  EnsureMethodsLoaded();
  if (server_new)
    InitServer(xid_);

  GlobalMenuBarRegistrarX11::GetInstance()->OnWindowMapped(xid_);
}

GlobalMenuBarX11::~GlobalMenuBarX11() {
  if (IsServerStarted())
    g_object_unref(server_);

  GlobalMenuBarRegistrarX11::GetInstance()->OnWindowUnmapped(xid_);
}

// static
std::string GlobalMenuBarX11::GetPathForWindow(gfx::AcceleratedWidget xid) {
  return base::StringPrintf("/com/canonical/menu/%lX", xid);
}

void GlobalMenuBarX11::SetMenu(AtomMenuModel* menu_model) {
  if (!IsServerStarted())
    return;

  DbusmenuMenuitem* root_item = menuitem_new();
  menuitem_property_set(root_item, kPropertyLabel, "Root");
  menuitem_property_set_bool(root_item, kPropertyVisible, true);
  BuildMenuFromModel(menu_model, root_item);

  server_set_root(server_, root_item);
  g_object_unref(root_item);
}

bool GlobalMenuBarX11::IsServerStarted() const {
  return server_;
}

void GlobalMenuBarX11::InitServer(gfx::AcceleratedWidget xid) {
  std::string path = GetPathForWindow(xid);
  server_ = server_new(path.c_str());
}

void GlobalMenuBarX11::OnWindowMapped() {
  GlobalMenuBarRegistrarX11::GetInstance()->OnWindowMapped(xid_);
}

void GlobalMenuBarX11::OnWindowUnmapped() {
  GlobalMenuBarRegistrarX11::GetInstance()->OnWindowUnmapped(xid_);
}

void GlobalMenuBarX11::BuildMenuFromModel(AtomMenuModel* model,
                                          DbusmenuMenuitem* parent) {
  for (int i = 0; i < model->GetItemCount(); ++i) {
    DbusmenuMenuitem* item = menuitem_new();
    menuitem_property_set_bool(item, kPropertyVisible, model->IsVisibleAt(i));

    AtomMenuModel::ItemType type = model->GetTypeAt(i);
    if (type == AtomMenuModel::TYPE_SEPARATOR) {
      menuitem_property_set(item, kPropertyType, kTypeSeparator);
    } else {
      std::string label = ui::ConvertAcceleratorsFromWindowsStyle(
          base::UTF16ToUTF8(model->GetLabelAt(i)));
      menuitem_property_set(item, kPropertyLabel, label.c_str());
      menuitem_property_set_bool(item, kPropertyEnabled, model->IsEnabledAt(i));

      g_object_set_data(G_OBJECT(item), "model", model);
      SetMenuItemID(item, i);

      if (type == AtomMenuModel::TYPE_SUBMENU) {
        menuitem_property_set(item, kPropertyChildrenDisplay, kDisplaySubmenu);
        g_signal_connect(item, "about-to-show",
                         G_CALLBACK(OnSubMenuShowThunk), this);
      } else {
        ui::Accelerator accelerator;
        if (model->GetAcceleratorAtWithParams(i, true, &accelerator))
          RegisterAccelerator(item, accelerator);

        g_signal_connect(item, "item-activated",
                         G_CALLBACK(OnItemActivatedThunk), this);

        if (type == AtomMenuModel::TYPE_CHECK ||
            type == AtomMenuModel::TYPE_RADIO) {
          menuitem_property_set(item, kPropertyToggleType,
              type == AtomMenuModel::TYPE_CHECK ? kToggleCheck : kToggleRadio);
          menuitem_property_set_int(item, kPropertyToggleState,
              model->IsItemCheckedAt(i));
        }
      }
    }

    menuitem_child_append(parent, item);
    g_object_unref(item);
  }
}

void GlobalMenuBarX11::RegisterAccelerator(DbusmenuMenuitem* item,
                                           const ui::Accelerator& accelerator) {
  // A translation of libdbusmenu-gtk's menuitem_property_set_shortcut()
  // translated from GDK types to ui::Accelerator types.
  GVariantBuilder builder;
  g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);

  if (accelerator.IsCtrlDown())
    g_variant_builder_add(&builder, "s", "Control");
  if (accelerator.IsAltDown())
    g_variant_builder_add(&builder, "s", "Alt");
  if (accelerator.IsShiftDown())
    g_variant_builder_add(&builder, "s", "Shift");

  char* name = XKeysymToString(XKeysymForWindowsKeyCode(
      accelerator.key_code(), false));
  if (!name) {
    NOTIMPLEMENTED();
    return;
  }
  g_variant_builder_add(&builder, "s", name);

  GVariant* inside_array = g_variant_builder_end(&builder);
  g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
  g_variant_builder_add_value(&builder, inside_array);
  GVariant* outside_array = g_variant_builder_end(&builder);

  menuitem_property_set_variant(item, kPropertyShortcut, outside_array);
}

void GlobalMenuBarX11::OnItemActivated(DbusmenuMenuitem* item,
                                       unsigned int timestamp) {
  int id;
  AtomMenuModel* model = ModelForMenuItem(item);
  if (model && GetMenuItemID(item, &id))
    model->ActivatedAt(id, 0);
}

void GlobalMenuBarX11::OnSubMenuShow(DbusmenuMenuitem* item) {
  int id;
  AtomMenuModel* model = ModelForMenuItem(item);
  if (!model || !GetMenuItemID(item, &id))
    return;

  // Do not update menu if the submenu has not been changed.
  std::string status = GetMenuModelStatus(model);
  char* old = static_cast<char*>(g_object_get_data(G_OBJECT(item), "status"));
  if (old && status == old)
    return;

  // Save the new status.
  g_object_set_data_full(G_OBJECT(item), "status", g_strdup(status.c_str()),
                         g_free);

  // Clear children.
  GList *children = menuitem_take_children(item);
  g_list_foreach(children, reinterpret_cast<GFunc>(g_object_unref), NULL);
  g_list_free(children);

  // Build children.
  BuildMenuFromModel(model->GetSubmenuModelAt(id), item);
}

}  // namespace atom
<commit_msg>Make the status string shorter<commit_after>// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/ui/views/global_menu_bar_x11.h"

#include <X11/Xlib.h>

// This conflicts with mate::Converter,
#undef True
#undef False
// and V8,
#undef None
// and url_request_status.h,
#undef Status

#include <dlfcn.h>
#include <glib-object.h>

#include "atom/browser/native_window_views.h"
#include "atom/browser/ui/atom_menu_model.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
#include "ui/events/keycodes/keyboard_code_conversion_x.h"

// libdbusmenu-glib types
typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_func)();
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_with_id_func)(int id);

typedef int (*dbusmenu_menuitem_get_id_func)(DbusmenuMenuitem* item);
typedef GList* (*dbusmenu_menuitem_get_children_func)(DbusmenuMenuitem* item);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_child_append_func)(
    DbusmenuMenuitem* parent,
    DbusmenuMenuitem* child);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_func)(
    DbusmenuMenuitem* item,
    const char* property,
    const char* value);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_variant_func)(
    DbusmenuMenuitem* item,
    const char* property,
    GVariant* value);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_bool_func)(
    DbusmenuMenuitem* item,
    const char* property,
    bool value);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_int_func)(
    DbusmenuMenuitem* item,
    const char* property,
    int value);

typedef struct _DbusmenuServer      DbusmenuServer;
typedef DbusmenuServer* (*dbusmenu_server_new_func)(const char* object);
typedef void (*dbusmenu_server_set_root_func)(DbusmenuServer* self,
                                              DbusmenuMenuitem* root);

namespace atom {

namespace {

// Retrieved functions from libdbusmenu-glib.

// DbusmenuMenuItem methods:
dbusmenu_menuitem_new_func menuitem_new = NULL;
dbusmenu_menuitem_new_with_id_func menuitem_new_with_id = NULL;
dbusmenu_menuitem_get_id_func menuitem_get_id = NULL;
dbusmenu_menuitem_get_children_func menuitem_get_children = NULL;
dbusmenu_menuitem_get_children_func menuitem_take_children = NULL;
dbusmenu_menuitem_child_append_func menuitem_child_append = NULL;
dbusmenu_menuitem_property_set_func menuitem_property_set = NULL;
dbusmenu_menuitem_property_set_variant_func menuitem_property_set_variant =
    NULL;
dbusmenu_menuitem_property_set_bool_func menuitem_property_set_bool = NULL;
dbusmenu_menuitem_property_set_int_func menuitem_property_set_int = NULL;

// DbusmenuServer methods:
dbusmenu_server_new_func server_new = NULL;
dbusmenu_server_set_root_func server_set_root = NULL;

// Properties that we set on menu items:
const char kPropertyEnabled[] = "enabled";
const char kPropertyLabel[] = "label";
const char kPropertyShortcut[] = "shortcut";
const char kPropertyType[] = "type";
const char kPropertyToggleType[] = "toggle-type";
const char kPropertyToggleState[] = "toggle-state";
const char kPropertyVisible[] = "visible";
const char kPropertyChildrenDisplay[] = "children-display";

const char kToggleCheck[] = "checkmark";
const char kToggleRadio[] = "radio";
const char kTypeSeparator[] = "separator";
const char kDisplaySubmenu[] = "submenu";

void EnsureMethodsLoaded() {
  static bool attempted_load = false;
  if (attempted_load)
    return;
  attempted_load = true;

  void* dbusmenu_lib = dlopen("libdbusmenu-glib.so", RTLD_LAZY);
  if (!dbusmenu_lib)
    dbusmenu_lib = dlopen("libdbusmenu-glib.so.4", RTLD_LAZY);
  if (!dbusmenu_lib)
    return;

  // DbusmenuMenuItem methods.
  menuitem_new = reinterpret_cast<dbusmenu_menuitem_new_func>(
      dlsym(dbusmenu_lib, "dbusmenu_menuitem_new"));
  menuitem_new_with_id = reinterpret_cast<dbusmenu_menuitem_new_with_id_func>(
      dlsym(dbusmenu_lib, "dbusmenu_menuitem_new_with_id"));
  menuitem_get_id = reinterpret_cast<dbusmenu_menuitem_get_id_func>(
      dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_id"));
  menuitem_get_children = reinterpret_cast<dbusmenu_menuitem_get_children_func>(
      dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_children"));
  menuitem_take_children =
      reinterpret_cast<dbusmenu_menuitem_get_children_func>(
          dlsym(dbusmenu_lib, "dbusmenu_menuitem_take_children"));
  menuitem_child_append = reinterpret_cast<dbusmenu_menuitem_child_append_func>(
      dlsym(dbusmenu_lib, "dbusmenu_menuitem_child_append"));
  menuitem_property_set = reinterpret_cast<dbusmenu_menuitem_property_set_func>(
      dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set"));
  menuitem_property_set_variant =
      reinterpret_cast<dbusmenu_menuitem_property_set_variant_func>(
          dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_variant"));
  menuitem_property_set_bool =
      reinterpret_cast<dbusmenu_menuitem_property_set_bool_func>(
          dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_bool"));
  menuitem_property_set_int =
      reinterpret_cast<dbusmenu_menuitem_property_set_int_func>(
          dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_int"));

  // DbusmenuServer methods.
  server_new = reinterpret_cast<dbusmenu_server_new_func>(
      dlsym(dbusmenu_lib, "dbusmenu_server_new"));
  server_set_root = reinterpret_cast<dbusmenu_server_set_root_func>(
      dlsym(dbusmenu_lib, "dbusmenu_server_set_root"));
}

AtomMenuModel* ModelForMenuItem(DbusmenuMenuitem* item) {
  return reinterpret_cast<AtomMenuModel*>(
      g_object_get_data(G_OBJECT(item), "model"));
}

bool GetMenuItemID(DbusmenuMenuitem* item, int *id) {
  gpointer id_ptr = g_object_get_data(G_OBJECT(item), "menu-id");
  if (id_ptr != NULL) {
    *id = GPOINTER_TO_INT(id_ptr) - 1;
    return true;
  }

  return false;
}

void SetMenuItemID(DbusmenuMenuitem* item, int id) {
  DCHECK_GE(id, 0);

  // Add 1 to the menu_id to avoid setting zero (null) to "menu-id".
  g_object_set_data(G_OBJECT(item), "menu-id", GINT_TO_POINTER(id + 1));
}

std::string GetMenuModelStatus(AtomMenuModel* model) {
  std::string ret;
  for (int i = 0; i < model->GetItemCount(); ++i) {
    int status = model->GetTypeAt(i) | (model->IsVisibleAt(i) << 3)
                                     | (model->IsEnabledAt(i) << 4)
                                     | (model->IsItemCheckedAt(i) << 5);
    ret += base::StringPrintf(
        "%s-%X\n", base::UTF16ToUTF8(model->GetLabelAt(i)).c_str(), status);
  }
  return ret;
}

}  // namespace

GlobalMenuBarX11::GlobalMenuBarX11(NativeWindowViews* window)
    : window_(window),
      xid_(window_->GetNativeWindow()->GetHost()->GetAcceleratedWidget()),
      server_(NULL) {
  EnsureMethodsLoaded();
  if (server_new)
    InitServer(xid_);

  GlobalMenuBarRegistrarX11::GetInstance()->OnWindowMapped(xid_);
}

GlobalMenuBarX11::~GlobalMenuBarX11() {
  if (IsServerStarted())
    g_object_unref(server_);

  GlobalMenuBarRegistrarX11::GetInstance()->OnWindowUnmapped(xid_);
}

// static
std::string GlobalMenuBarX11::GetPathForWindow(gfx::AcceleratedWidget xid) {
  return base::StringPrintf("/com/canonical/menu/%lX", xid);
}

void GlobalMenuBarX11::SetMenu(AtomMenuModel* menu_model) {
  if (!IsServerStarted())
    return;

  DbusmenuMenuitem* root_item = menuitem_new();
  menuitem_property_set(root_item, kPropertyLabel, "Root");
  menuitem_property_set_bool(root_item, kPropertyVisible, true);
  BuildMenuFromModel(menu_model, root_item);

  server_set_root(server_, root_item);
  g_object_unref(root_item);
}

bool GlobalMenuBarX11::IsServerStarted() const {
  return server_;
}

void GlobalMenuBarX11::InitServer(gfx::AcceleratedWidget xid) {
  std::string path = GetPathForWindow(xid);
  server_ = server_new(path.c_str());
}

void GlobalMenuBarX11::OnWindowMapped() {
  GlobalMenuBarRegistrarX11::GetInstance()->OnWindowMapped(xid_);
}

void GlobalMenuBarX11::OnWindowUnmapped() {
  GlobalMenuBarRegistrarX11::GetInstance()->OnWindowUnmapped(xid_);
}

void GlobalMenuBarX11::BuildMenuFromModel(AtomMenuModel* model,
                                          DbusmenuMenuitem* parent) {
  for (int i = 0; i < model->GetItemCount(); ++i) {
    DbusmenuMenuitem* item = menuitem_new();
    menuitem_property_set_bool(item, kPropertyVisible, model->IsVisibleAt(i));

    AtomMenuModel::ItemType type = model->GetTypeAt(i);
    if (type == AtomMenuModel::TYPE_SEPARATOR) {
      menuitem_property_set(item, kPropertyType, kTypeSeparator);
    } else {
      std::string label = ui::ConvertAcceleratorsFromWindowsStyle(
          base::UTF16ToUTF8(model->GetLabelAt(i)));
      menuitem_property_set(item, kPropertyLabel, label.c_str());
      menuitem_property_set_bool(item, kPropertyEnabled, model->IsEnabledAt(i));

      g_object_set_data(G_OBJECT(item), "model", model);
      SetMenuItemID(item, i);

      if (type == AtomMenuModel::TYPE_SUBMENU) {
        menuitem_property_set(item, kPropertyChildrenDisplay, kDisplaySubmenu);
        g_signal_connect(item, "about-to-show",
                         G_CALLBACK(OnSubMenuShowThunk), this);
      } else {
        ui::Accelerator accelerator;
        if (model->GetAcceleratorAtWithParams(i, true, &accelerator))
          RegisterAccelerator(item, accelerator);

        g_signal_connect(item, "item-activated",
                         G_CALLBACK(OnItemActivatedThunk), this);

        if (type == AtomMenuModel::TYPE_CHECK ||
            type == AtomMenuModel::TYPE_RADIO) {
          menuitem_property_set(item, kPropertyToggleType,
              type == AtomMenuModel::TYPE_CHECK ? kToggleCheck : kToggleRadio);
          menuitem_property_set_int(item, kPropertyToggleState,
              model->IsItemCheckedAt(i));
        }
      }
    }

    menuitem_child_append(parent, item);
    g_object_unref(item);
  }
}

void GlobalMenuBarX11::RegisterAccelerator(DbusmenuMenuitem* item,
                                           const ui::Accelerator& accelerator) {
  // A translation of libdbusmenu-gtk's menuitem_property_set_shortcut()
  // translated from GDK types to ui::Accelerator types.
  GVariantBuilder builder;
  g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);

  if (accelerator.IsCtrlDown())
    g_variant_builder_add(&builder, "s", "Control");
  if (accelerator.IsAltDown())
    g_variant_builder_add(&builder, "s", "Alt");
  if (accelerator.IsShiftDown())
    g_variant_builder_add(&builder, "s", "Shift");

  char* name = XKeysymToString(XKeysymForWindowsKeyCode(
      accelerator.key_code(), false));
  if (!name) {
    NOTIMPLEMENTED();
    return;
  }
  g_variant_builder_add(&builder, "s", name);

  GVariant* inside_array = g_variant_builder_end(&builder);
  g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
  g_variant_builder_add_value(&builder, inside_array);
  GVariant* outside_array = g_variant_builder_end(&builder);

  menuitem_property_set_variant(item, kPropertyShortcut, outside_array);
}

void GlobalMenuBarX11::OnItemActivated(DbusmenuMenuitem* item,
                                       unsigned int timestamp) {
  int id;
  AtomMenuModel* model = ModelForMenuItem(item);
  if (model && GetMenuItemID(item, &id))
    model->ActivatedAt(id, 0);
}

void GlobalMenuBarX11::OnSubMenuShow(DbusmenuMenuitem* item) {
  int id;
  AtomMenuModel* model = ModelForMenuItem(item);
  if (!model || !GetMenuItemID(item, &id))
    return;

  // Do not update menu if the submenu has not been changed.
  std::string status = GetMenuModelStatus(model);
  char* old = static_cast<char*>(g_object_get_data(G_OBJECT(item), "status"));
  if (old && status == old)
    return;

  // Save the new status.
  g_object_set_data_full(G_OBJECT(item), "status", g_strdup(status.c_str()),
                         g_free);

  // Clear children.
  GList *children = menuitem_take_children(item);
  g_list_foreach(children, reinterpret_cast<GFunc>(g_object_unref), NULL);
  g_list_free(children);

  // Build children.
  BuildMenuFromModel(model->GetSubmenuModelAt(id), item);
}

}  // namespace atom
<|endoftext|>


<commit_before>#include "FAST/Testing.hpp"
#include "FAST/Streamers/ImageFileStreamer.hpp"
#include "KalmanFilter.hpp"
#include "FAST/Visualization/MeshRenderer/MeshRenderer.hpp"
#include "FAST/Visualization/SliceRenderer/SliceRenderer.hpp"
#include "FAST/Visualization/ImageRenderer/ImageRenderer.hpp"
#include "FAST/Visualization/SimpleWindow.hpp"
#include "FAST/Algorithms/ImageSlicer/ImageSlicer.hpp"
#include "AppearanceModels/StepEdge/StepEdgeModel.hpp"
#include "ShapeModels/MeanValueCoordinates/MeanValueCoordinatesModel.hpp"
#include "ShapeModels/Ellipse/EllipseModel.hpp"
#include "ShapeModels/CardinalSpline/CardinalSplineModel.hpp"

using namespace fast;

TEST_CASE("Model based segmentation with mean value coordinates on 3D cardiac US data", "[fast][ModelBasedSegmentation][cardiac][3d][visual]") {
	ImageFileStreamer::pointer streamer = ImageFileStreamer::New();
	streamer->setFilenameFormat("/home/smistad/CETUS/Patient1/Patient1_frame#.mhd");
	streamer->setZeroFilling(2);
	streamer->setStartNumber(1);
	streamer->enableLooping();
	streamer->setStreamingMode(STREAMING_MODE_PROCESS_ALL_FRAMES);
	//streamer->setSleepTime(2000);

	MeanValueCoordinatesModel::pointer shapeModel = MeanValueCoordinatesModel::New();
	shapeModel->loadMeshes("/home/smistad/Dropbox/Programmering/Mean value coordinates/cetus_model_mesh_small.vtk",
			"/home/smistad/Dropbox/Programmering/Mean value coordinates/cetus_control_mesh.vtk");
	shapeModel->initializeShapeToImageCenter();
	KalmanFilter::pointer segmentation = KalmanFilter::New();
	StepEdgeModel::pointer appearanceModel = StepEdgeModel::New();
	appearanceModel->setLineLength(0.025);
	appearanceModel->setLineSampleSpacing(0.025/32.0);
	segmentation->setAppearanceModel(appearanceModel);
	segmentation->setShapeModel(shapeModel);
	segmentation->setInputConnection(streamer->getOutputPort());

	MeshRenderer::pointer meshRenderer = MeshRenderer::New();
	meshRenderer->setInputConnection(segmentation->getOutputPort());

	SliceRenderer::pointer sliceRenderer = SliceRenderer::New();
	sliceRenderer->setInputConnection(streamer->getOutputPort());
	sliceRenderer->setSlicePlane(PLANE_Y);

	SimpleWindow::pointer window = SimpleWindow::New();
	window->addRenderer(meshRenderer);
	window->addRenderer(sliceRenderer);
	window->start();
}

TEST_CASE("Model based segmentation with spline model on 2D pediatric cardiac US data", "[fast][ModelBasedSegmentation][2d][cardiac][pediatric][visual]") {
	ImageFileStreamer::pointer streamer = ImageFileStreamer::New();
	streamer->setFilenameFormat("/home/smistad/Cardiac_2D/labelImage#.mhd");
	streamer->setZeroFilling(2);
	streamer->enableLooping();
	streamer->setStreamingMode(STREAMING_MODE_PROCESS_ALL_FRAMES);
	streamer->update(); // TODO this should not be needed
	streamer->setSleepTime(200);

	// Control points for spline model
	std::vector<Vector2f> controlPoints = {
	        Vector2f(20.0, 45.1),
	        Vector2f(30.7, 55.2),
	        Vector2f(45.6, 55.9),
	        Vector2f(46.4, 40.8),
	        Vector2f(38.7, 20.8),
	        Vector2f(22.5, 22.5),
	};

	CardinalSplineModel::pointer shapeModel = CardinalSplineModel::New();
	shapeModel->setControlPoints(controlPoints);
	shapeModel->setGlobalProcessError(0.000001f);
	shapeModel->setLocalProcessError(0.0000001f);
	shapeModel->setResolution(12);
	KalmanFilter::pointer segmentation = KalmanFilter::New();
	StepEdgeModel::pointer appearanceModel = StepEdgeModel::New();
	appearanceModel->setLineLength(8);
	appearanceModel->setLineSampleSpacing(8/32.0);
	appearanceModel->setIntensityDifferenceThreshold(20);
	appearanceModel->setMinimumDepth(15);
	segmentation->setStartIterations(10);
	segmentation->setIterations(10);
	segmentation->setAppearanceModel(appearanceModel);
	segmentation->setShapeModel(shapeModel);
	segmentation->setInputConnection(streamer->getOutputPort());

	MeshRenderer::pointer meshRenderer = MeshRenderer::New();
	meshRenderer->addInputConnection(segmentation->getOutputPort());
	meshRenderer->addInputConnection(segmentation->getDisplacementsOutputPort(), Color::Red(), 1.0);

	ImageRenderer::pointer imageRenderer = ImageRenderer::New();
	imageRenderer->addInputConnection(streamer->getOutputPort());

	SimpleWindow::pointer window = SimpleWindow::New();
	window->addRenderer(imageRenderer);
	window->addRenderer(meshRenderer);
	window->set2DMode();
	window->start();
}

TEST_CASE("Model based segmentation with spline model on 2D cardiac US data", "[fast][ModelBasedSegmentation][2d][cardiac][visual]") {
	ImageFileStreamer::pointer streamer = ImageFileStreamer::New();
	streamer->setFilenameFormat("/home/smistad/CETUS/Patient1/Patient1_frame#.mhd");
	streamer->setZeroFilling(2);
	streamer->setStartNumber(1);
	streamer->enableLooping();
	streamer->setStreamingMode(STREAMING_MODE_PROCESS_ALL_FRAMES);
	streamer->update(); // TODO this should not be needed
	streamer->setSleepTime(50);

	ImageSlicer::pointer slicer = ImageSlicer::New();
	slicer->setInputConnection(streamer->getOutputPort());
	slicer->setOrthogonalSlicePlane(PLANE_Y);

	// Control points for spline model
	std::vector<Vector2f> controlPoints = {
	        Vector2f(0, 3), // Apex
	        Vector2f(0.8, 2),
	        Vector2f(1.15, 1),
	        Vector2f(0.8, 0),
	        Vector2f(-0.8, 0),
	        Vector2f(-1.15, 1),
	        Vector2f(-0.8, 2)
	};

	CardinalSplineModel::pointer shapeModel = CardinalSplineModel::New();
	shapeModel->setControlPoints(controlPoints);
	shapeModel->setInitialScaling(0.02, 0.03);
	shapeModel->setInitialRotation(M_PI);
	shapeModel->setGlobalProcessError(0.01f);
	shapeModel->setLocalProcessError(0.001f);
	shapeModel->initializeShapeToImageCenter();
	KalmanFilter::pointer segmentation = KalmanFilter::New();
	StepEdgeModel::pointer appearanceModel = StepEdgeModel::New();
	appearanceModel->setLineLength(0.025);
	appearanceModel->setLineSampleSpacing(0.025/32.0);
	segmentation->setAppearanceModel(appearanceModel);
	segmentation->setShapeModel(shapeModel);
	segmentation->setInputConnection(slicer->getOutputPort());

	MeshRenderer::pointer meshRenderer = MeshRenderer::New();
	meshRenderer->setInputConnection(segmentation->getOutputPort());

	ImageRenderer::pointer imageRenderer = ImageRenderer::New();
	imageRenderer->addInputConnection(slicer->getOutputPort());

	SimpleWindow::pointer window = SimpleWindow::New();
	window->addRenderer(imageRenderer);
	window->addRenderer(meshRenderer);
	window->set2DMode();
	window->start();
}

TEST_CASE("Model based segmentation with ellipse model on 2D femoral nerve block US data", "[fast][ModelBasedSegmentation][visual]") {
	ImageFileStreamer::pointer streamer = ImageFileStreamer::New();
	streamer->setFilenameFormat("/home/smistad/AssistantTestData/FL/US-Acq_01_20150608T102019/Acquisition/US-Acq_01_20150608T102019_Image_Transducer_#.mhd");
	streamer->setStartNumber(26);
	streamer->enableLooping();
	streamer->setStreamingMode(STREAMING_MODE_PROCESS_ALL_FRAMES);
	streamer->setSleepTime(100);

	EllipseModel::pointer shapeModel = EllipseModel::New();
	shapeModel->setInitialState(Vector2f(27, 10), 5, 4.5);
	KalmanFilter::pointer segmentation = KalmanFilter::New();
	StepEdgeModel::pointer appearanceModel = StepEdgeModel::New();
	appearanceModel->setLineLength(4);
	appearanceModel->setLineSampleSpacing(4.0/16.0);
	segmentation->setAppearanceModel(appearanceModel);
	segmentation->setShapeModel(shapeModel);
	segmentation->setInputConnection(streamer->getOutputPort());

	MeshRenderer::pointer meshRenderer = MeshRenderer::New();
	meshRenderer->setInputConnection(segmentation->getOutputPort());

	ImageRenderer::pointer imageRenderer = ImageRenderer::New();
	imageRenderer->setInputConnection(streamer->getOutputPort());

	SimpleWindow::pointer window = SimpleWindow::New();
	window->addRenderer(imageRenderer);
	window->addRenderer(meshRenderer);
	window->set2DMode();
	window->start();
}
<commit_msg>added a test<commit_after>#include "FAST/Testing.hpp"
#include "FAST/Streamers/ImageFileStreamer.hpp"
#include "KalmanFilter.hpp"
#include "FAST/Visualization/MeshRenderer/MeshRenderer.hpp"
#include "FAST/Visualization/SliceRenderer/SliceRenderer.hpp"
#include "FAST/Visualization/ImageRenderer/ImageRenderer.hpp"
#include "FAST/Visualization/SimpleWindow.hpp"
#include "FAST/Algorithms/ImageSlicer/ImageSlicer.hpp"
#include "AppearanceModels/StepEdge/StepEdgeModel.hpp"
#include "ShapeModels/MeanValueCoordinates/MeanValueCoordinatesModel.hpp"
#include "ShapeModels/Ellipse/EllipseModel.hpp"
#include "ShapeModels/CardinalSpline/CardinalSplineModel.hpp"

using namespace fast;

TEST_CASE("Model based segmentation with mean value coordinates on 3D cardiac US data", "[fast][ModelBasedSegmentation][cardiac][3d][visual]") {
	ImageFileStreamer::pointer streamer = ImageFileStreamer::New();
	streamer->setFilenameFormat("/home/smistad/CETUS/Patient1/Patient1_frame#.mhd");
	streamer->setZeroFilling(2);
	streamer->setStartNumber(1);
	streamer->enableLooping();
	streamer->setStreamingMode(STREAMING_MODE_PROCESS_ALL_FRAMES);
	//streamer->setSleepTime(2000);

	MeanValueCoordinatesModel::pointer shapeModel = MeanValueCoordinatesModel::New();
	shapeModel->loadMeshes("/home/smistad/Dropbox/Programmering/Mean value coordinates/cetus_model_mesh_small.vtk",
			"/home/smistad/Dropbox/Programmering/Mean value coordinates/cetus_control_mesh.vtk");
	shapeModel->initializeShapeToImageCenter();
	KalmanFilter::pointer segmentation = KalmanFilter::New();
	StepEdgeModel::pointer appearanceModel = StepEdgeModel::New();
	appearanceModel->setLineLength(0.025);
	appearanceModel->setLineSampleSpacing(0.025/32.0);
	segmentation->setAppearanceModel(appearanceModel);
	segmentation->setShapeModel(shapeModel);
	segmentation->setInputConnection(streamer->getOutputPort());

	MeshRenderer::pointer meshRenderer = MeshRenderer::New();
	meshRenderer->setInputConnection(segmentation->getOutputPort());

	SliceRenderer::pointer sliceRenderer = SliceRenderer::New();
	sliceRenderer->setInputConnection(streamer->getOutputPort());
	sliceRenderer->setSlicePlane(PLANE_Y);

	SimpleWindow::pointer window = SimpleWindow::New();
	window->addRenderer(meshRenderer);
	window->addRenderer(sliceRenderer);
	window->start();
}

TEST_CASE("Model based segmentation with spline model on 2D pediatric cardiac US data", "[fast][ModelBasedSegmentation][2d][cardiac][pediatric][visual]") {
	ImageFileStreamer::pointer streamer = ImageFileStreamer::New();
	streamer->setFilenameFormat("/home/smistad/Cardiac_2D/labelImage#.mhd");
	streamer->setZeroFilling(2);
	streamer->enableLooping();
	streamer->setStreamingMode(STREAMING_MODE_PROCESS_ALL_FRAMES);
	streamer->update(); // TODO this should not be needed
	streamer->setSleepTime(200);

	// Control points for spline model
	std::vector<Vector2f> controlPoints = {
	        Vector2f(20.0, 45.1),
	        Vector2f(30.7, 55.2),
	        Vector2f(45.6, 55.9),
	        Vector2f(46.4, 40.8),
	        Vector2f(38.7, 20.8),
	        Vector2f(22.5, 22.5),
	};

	CardinalSplineModel::pointer shapeModel = CardinalSplineModel::New();
	shapeModel->setControlPoints(controlPoints);
	shapeModel->setGlobalProcessError(0.000001f);
	shapeModel->setLocalProcessError(0.0000001f);
	shapeModel->setResolution(12);
	KalmanFilter::pointer segmentation = KalmanFilter::New();
	StepEdgeModel::pointer appearanceModel = StepEdgeModel::New();
	appearanceModel->setLineLength(8);
	appearanceModel->setLineSampleSpacing(8/32.0);
	appearanceModel->setIntensityDifferenceThreshold(20);
	appearanceModel->setMinimumDepth(15);
	segmentation->setStartIterations(10);
	segmentation->setIterations(10);
	segmentation->setAppearanceModel(appearanceModel);
	segmentation->setShapeModel(shapeModel);
	segmentation->setInputConnection(streamer->getOutputPort());

	MeshRenderer::pointer meshRenderer = MeshRenderer::New();
	meshRenderer->addInputConnection(segmentation->getOutputPort());
	meshRenderer->addInputConnection(segmentation->getDisplacementsOutputPort(), Color::Red(), 1.0);

	ImageRenderer::pointer imageRenderer = ImageRenderer::New();
	imageRenderer->addInputConnection(streamer->getOutputPort());

	SimpleWindow::pointer window = SimpleWindow::New();
	window->addRenderer(imageRenderer);
	window->addRenderer(meshRenderer);
	window->set2DMode();
	window->start();
}

TEST_CASE("Model based segmentation with spline model on 2D pediatric aorta US data", "[fast][ModelBasedSegmentation][2d][aorta][pediatric][visual]") {
	ImageFileStreamer::pointer streamer = ImageFileStreamer::New();
	streamer->setFilenameFormat("/home/smistad/Data/aorta_us/labelImage#.mhd");
	streamer->setZeroFilling(2);
	streamer->enableLooping();
	streamer->setStreamingMode(STREAMING_MODE_PROCESS_ALL_FRAMES);
	streamer->update(); // TODO this should not be needed
	streamer->setSleepTime(1000);

	// Control points for spline model
	std::vector<Vector2f> controlPoints = {
	        Vector2f(35.0, 45.1),
	        Vector2f(35.0, 55.1),
	        Vector2f(50.0, 55.1),
	        Vector2f(50.0, 45.1),
	};

	CardinalSplineModel::pointer shapeModel = CardinalSplineModel::New();
	shapeModel->setControlPoints(controlPoints);
	shapeModel->setGlobalProcessError(0.0001f);
	shapeModel->setLocalProcessError(0.00001f);
	shapeModel->setResolution(12);
	KalmanFilter::pointer segmentation = KalmanFilter::New();
	StepEdgeModel::pointer appearanceModel = StepEdgeModel::New();
	appearanceModel->setLineLength(8);
	appearanceModel->setLineSampleSpacing(8/32.0);
	appearanceModel->setIntensityDifferenceThreshold(10);
	appearanceModel->setMinimumDepth(15);
	segmentation->setStartIterations(10);
	segmentation->setIterations(10);
	segmentation->setAppearanceModel(appearanceModel);
	segmentation->setShapeModel(shapeModel);
	segmentation->setInputConnection(streamer->getOutputPort());

	MeshRenderer::pointer meshRenderer = MeshRenderer::New();
	meshRenderer->addInputConnection(segmentation->getOutputPort());
	meshRenderer->addInputConnection(segmentation->getDisplacementsOutputPort(), Color::Red(), 1.0);

	ImageRenderer::pointer imageRenderer = ImageRenderer::New();
	imageRenderer->addInputConnection(streamer->getOutputPort());

	SimpleWindow::pointer window = SimpleWindow::New();
	window->addRenderer(imageRenderer);
	window->addRenderer(meshRenderer);
	window->set2DMode();
	window->start();
}

TEST_CASE("Model based segmentation with spline model on 2D cardiac US data", "[fast][ModelBasedSegmentation][2d][cardiac][visual]") {
	ImageFileStreamer::pointer streamer = ImageFileStreamer::New();
	streamer->setFilenameFormat("/home/smistad/CETUS/Patient1/Patient1_frame#.mhd");
	streamer->setZeroFilling(2);
	streamer->setStartNumber(1);
	streamer->enableLooping();
	streamer->setStreamingMode(STREAMING_MODE_PROCESS_ALL_FRAMES);
	streamer->update(); // TODO this should not be needed
	streamer->setSleepTime(50);

	ImageSlicer::pointer slicer = ImageSlicer::New();
	slicer->setInputConnection(streamer->getOutputPort());
	slicer->setOrthogonalSlicePlane(PLANE_Y);

	// Control points for spline model
	std::vector<Vector2f> controlPoints = {
	        Vector2f(0, 3), // Apex
	        Vector2f(0.8, 2),
	        Vector2f(1.15, 1),
	        Vector2f(0.8, 0),
	        Vector2f(-0.8, 0),
	        Vector2f(-1.15, 1),
	        Vector2f(-0.8, 2)
	};

	CardinalSplineModel::pointer shapeModel = CardinalSplineModel::New();
	shapeModel->setControlPoints(controlPoints);
	shapeModel->setInitialScaling(0.02, 0.03);
	shapeModel->setInitialRotation(M_PI);
	shapeModel->setGlobalProcessError(0.01f);
	shapeModel->setLocalProcessError(0.001f);
	shapeModel->initializeShapeToImageCenter();
	KalmanFilter::pointer segmentation = KalmanFilter::New();
	StepEdgeModel::pointer appearanceModel = StepEdgeModel::New();
	appearanceModel->setLineLength(0.025);
	appearanceModel->setLineSampleSpacing(0.025/32.0);
	segmentation->setAppearanceModel(appearanceModel);
	segmentation->setShapeModel(shapeModel);
	segmentation->setInputConnection(slicer->getOutputPort());

	MeshRenderer::pointer meshRenderer = MeshRenderer::New();
	meshRenderer->setInputConnection(segmentation->getOutputPort());

	ImageRenderer::pointer imageRenderer = ImageRenderer::New();
	imageRenderer->addInputConnection(slicer->getOutputPort());

	SimpleWindow::pointer window = SimpleWindow::New();
	window->addRenderer(imageRenderer);
	window->addRenderer(meshRenderer);
	window->set2DMode();
	window->start();
}

TEST_CASE("Model based segmentation with ellipse model on 2D femoral nerve block US data", "[fast][ModelBasedSegmentation][visual]") {
	ImageFileStreamer::pointer streamer = ImageFileStreamer::New();
	streamer->setFilenameFormat("/home/smistad/AssistantTestData/FL/US-Acq_01_20150608T102019/Acquisition/US-Acq_01_20150608T102019_Image_Transducer_#.mhd");
	streamer->setStartNumber(26);
	streamer->enableLooping();
	streamer->setStreamingMode(STREAMING_MODE_PROCESS_ALL_FRAMES);
	streamer->setSleepTime(100);

	EllipseModel::pointer shapeModel = EllipseModel::New();
	shapeModel->setInitialState(Vector2f(27, 10), 5, 4.5);
	KalmanFilter::pointer segmentation = KalmanFilter::New();
	StepEdgeModel::pointer appearanceModel = StepEdgeModel::New();
	appearanceModel->setLineLength(4);
	appearanceModel->setLineSampleSpacing(4.0/16.0);
	segmentation->setAppearanceModel(appearanceModel);
	segmentation->setShapeModel(shapeModel);
	segmentation->setInputConnection(streamer->getOutputPort());

	MeshRenderer::pointer meshRenderer = MeshRenderer::New();
	meshRenderer->setInputConnection(segmentation->getOutputPort());

	ImageRenderer::pointer imageRenderer = ImageRenderer::New();
	imageRenderer->setInputConnection(streamer->getOutputPort());

	SimpleWindow::pointer window = SimpleWindow::New();
	window->addRenderer(imageRenderer);
	window->addRenderer(meshRenderer);
	window->set2DMode();
	window->start();
}
<|endoftext|>


<commit_before>//**************************************************************************************************
//
//     OSSIM Open Source Geospatial Data Processing Library
//     See top level LICENSE.txt file for license information
//
//**************************************************************************************************

#include "ossimDescriptorSource.h"
#include "../AtpOpenCV.h"
#include <ossim/imaging/ossimImageDataFactory.h>
#include <ossim/base/ossimSortedVector.h>

#include <opencv2/xfeatures2d.hpp>

namespace ATP
{
static const int DEFAULT_CMP_PATCH_SIZING_FACTOR = 2;
static const double DEFAULT_NOMINAL_POSITION_ERROR = 50; // meters

ossimDescriptorSource::ossimDescriptorSource()
{
}

ossimDescriptorSource::ossimDescriptorSource(ossimConnectableObject::ConnectableObjectList& inputSources)
: AtpTileSource(inputSources)
{
   initialize();
}

ossimDescriptorSource::ossimDescriptorSource(AtpGeneratorBase* generator)
: AtpTileSource(generator)
{
}

ossimDescriptorSource::~ossimDescriptorSource()
{
}

void ossimDescriptorSource::initialize()
{
   // Base class initializes ref and cmp chain datat members and associated IVTs. Subsequent call
   // to base class setViewGeom() will initialize the associated IVTs:
   AtpTileSource::initialize();

   m_nominalCmpPatchSize = 0.0;
   unsigned int refPatchSize = AtpConfig::instance().getParameter("corrWindowSize").asUint(); // min distance between points
   m_nominalCmpPatchSize = DEFAULT_CMP_PATCH_SIZING_FACTOR*refPatchSize;

   if (m_refIVT && m_cmpIVT)
   {
      ossimDpt gsd = m_refIVT->getOutputMetersPerPixel();
      double nominalGsd = (gsd.x + gsd.y)/2.0;

      // Fetch the CE90 of both images to determine cmp image search patch size:
      ossimSensorModel* ref_sm = dynamic_cast<ossimSensorModel*>(
              m_refIVT->getImageGeometry()->getProjection());
      ossimSensorModel* cmp_sm = dynamic_cast<ossimSensorModel*>(
              m_cmpIVT->getImageGeometry()->getProjection());
      if (ref_sm && cmp_sm)
      {
         double ref_ce = ref_sm->getNominalPosError();
         double cmp_ce = cmp_sm->getNominalPosError();
         double total_error = ref_ce + cmp_ce; // meters -- being conservative here and not doing rss
         ossimDpt gsd = m_refIVT->getOutputMetersPerPixel();
         double nominalGsd = (gsd.x + gsd.y)/2.0;
         double searchSizePixels = 2.0*total_error/nominalGsd;
         m_nominalCmpPatchSize = refPatchSize + searchSizePixels;
      }
      else
      {
         double searchSizePixels = 2.0*DEFAULT_NOMINAL_POSITION_ERROR/nominalGsd;
         m_nominalCmpPatchSize = refPatchSize + searchSizePixels;
      }
   }
}

ossimRefPtr<ossimImageData> ossimDescriptorSource::getTile(const ossimIrect& tileRect,
                                                            ossim_uint32 resLevel)
{
   static const char* MODULE = "ossimDescriptorSource::getTile()  ";
   AtpConfig& config = AtpConfig::instance();

   if (config.diagnosticLevel(2))
      ossimNotify(ossimNotifyLevel_INFO)<<"\n\n"<< MODULE << " -- tileRect: "<<tileRect<<endl;
   m_tiePoints.clear();

   if(!m_tile.get())
   {
      // try to initialize
      initialize();
      if(!m_tile.get()){
         ossimNotify(ossimNotifyLevel_INFO) << MODULE << " ERROR: could not initialize tile\n";
         return m_tile;
      }
   }

   // Make sure there are at least two images as input.
   if(getNumberOfInputs() < 2)
   {
      ossimNotify(ossimNotifyLevel_INFO) << MODULE << " ERROR: wrong number of inputs " << getNumberOfInputs() << " when expecting at least 2 \n";
      return 0;
   }

   // The tileRect passed in is in a common map-projected view space. Need to transform the rect
   // into image space for both ref and cmp images:
   ossimIrect refRect (m_refIVT->getViewToImageBounds(tileRect));
   ossimIrect cmpRect (m_cmpIVT->getViewToImageBounds(tileRect));
   cmpRect.expand(ossimIpt(m_nominalCmpPatchSize, m_nominalCmpPatchSize));

   // Retrieve both the ref and cmp image data
   ossimRefPtr<ossimImageData> ref_tile = m_refChain->getTile(refRect, resLevel);
   if (ref_tile->getDataObjectStatus() == OSSIM_EMPTY)
   {
      ossimNotify(ossimNotifyLevel_WARN) << MODULE << " ERROR: could not get REF tile with rect " << refRect << "\n";
      return m_tile;
   }
   if (config.diagnosticLevel(5))
      ref_tile->write("REF_TILE.RAS");

   ossimRefPtr<ossimImageData> cmp_tile = m_cmpChain->getTile(cmpRect, resLevel);
   if (cmp_tile->getDataObjectStatus() == OSSIM_EMPTY)
   {
      ossimNotify(ossimNotifyLevel_WARN) << MODULE << " ERROR: could not get CMP tile with rect " << cmpRect << "\n";
      return m_tile;
   }
   if (config.diagnosticLevel(5))
      cmp_tile->write("CMP_TILE.RAS");

   m_tile = ref_tile;

   // Convert both into OpenCV Mat objects using the Ipl image.
   IplImage* refImage = convertToIpl32(ref_tile.get());
   IplImage* cmpImage = convertToIpl32(cmp_tile.get());
   cv::Mat queryImg = cv::cvarrToMat(refImage);
   cv::Mat trainImg = cv::cvarrToMat(cmpImage);

   // Get the KeyPoints using appropriate descriptor.
   ossimSortedVector<cv::KeyPoint> kpA;
   ossimSortedVector<cv::KeyPoint> kpB;
   cv::Mat desA;
   cv::Mat desB;

   ossimString descriptorType (config.getParameter("descriptor").asString());
   descriptorType.upcase();

#if 1
   // Search for features and compute descriptors for all:
   cv::Ptr<cv::Feature2D> detector;
   if(descriptorType == "AKAZE")
   {
      detector = cv::AKAZE::create();
   }
   else if(descriptorType == "KAZE")
   {
      detector = cv::KAZE::create();
   }
   else if(descriptorType == "ORB")
   {
      // For some reason orb wants multiple channel mats so fake it.
      //if (queryImg.channels() == 1)
      //{
      //   std::vector<cv::Mat> channels;
      //   channels.push_back(queryImg);
      //   channels.push_back(queryImg);
      //   channels.push_back(queryImg);
      //   cv::merge(channels, queryImg);
      //}
      //
      //if (trainImg.channels() == 1)
      //{
      //   std::vector<cv::Mat> channels;
      //   channels.push_back(trainImg);
      //   channels.push_back(trainImg);
      //   channels.push_back(trainImg);
      //   cv::merge(channels, trainImg);
      //}

      detector = cv::ORB::create();
   }
   else if(descriptorType == "SURF")
   {
      detector = cv::xfeatures2d::SURF::create();
   }
   else if(descriptorType == "SIFT")
   {
      detector = cv::xfeatures2d::SIFT::create();
   }
   else
   {
      ossimNotify(ossimNotifyLevel_WARN) << MODULE << " WARNING: No such descriptor as " << descriptorType << "\n";
      return m_tile;
   }

   detector->detectAndCompute(queryImg, cv::noArray(), kpA, desA);
   detector->detectAndCompute(trainImg, cv::noArray(), kpB, desB);

#else
   // Separate detect and compute to limit the number of features for which descriptors are
   // computed... Instantiate feature detector and descriptor algo:
   cv::Ptr<cv::Feature2D> detector;
   if(descriptorType == "AKAZE")
      detector = cv::AKAZE::create();
   else if(descriptorType == "KAZE")
      detector = cv::KAZE::create();
   else if(descriptorType == "ORB")
   {
      //// For some reason orb wants multiple channel mats so fake it.
      //if (queryImg.channels() == 1)
      //{
      //   std::vector<cv::Mat> channels;
      //   channels.push_back(queryImg);
      //   channels.push_back(queryImg);
      //   channels.push_back(queryImg);
      //   cv::merge(channels, queryImg);
      //}
      //
      //if (trainImg.channels() == 1)
      //{
      //   std::vector<cv::Mat> channels;
      //   channels.push_back(trainImg);
      //   channels.push_back(trainImg);
      //   channels.push_back(trainImg);
      //   cv::merge(channels, trainImg);
      //}

      detector = cv::ORB::create();
   }
   else if(descriptorType == "SURF")
      detector = cv::xfeatures2d::SURF::create();
   else if(descriptorType == "SIFT")
      detector = cv::xfeatures2d::SIFT::create();
   else
   {
      ossimNotify(ossimNotifyLevel_WARN) << MODULE << " WARNING: No such descriptor as " << descriptorType << "\n";
      return m_tile;
   }

   // Perform detection:
   detector->detect(queryImg, kpA);
   detector->detect(trainImg, kpB);

   cout << "\nDETECT:\n  kpA.size = "<<kpA.size() << endl;
   cout << "  kpb.size = "<<kpA.size() << endl;

   // Limit strongest detections to max number of features per tile on query image:
   unsigned int maxNumFeatures = config.getParameter("numFeaturesPerTile").asUint();
   cout << "\n numFeatures= "<<maxNumFeatures << endl;
   if (kpA.size() > maxNumFeatures)
   {
      sort(kpA.begin(), kpA.end(), sortFunc);
      kpA.resize(maxNumFeatures);
   }

   //if (kpB.size() > maxNumFeatures)
   //{
   //   sort(kpB.begin(), kpB.end(), sortFunc);
   //   kpB.resize(maxNumFeatures);
   //}
   //cout << "\nTRIM:\n  kpA.size = "<<kpA.size() << endl;
   //cout << "  kpb.size = "<<kpA.size() << endl;

   // Now perform descriptor computations on remaining features:
   detector->compute(queryImg, kpA, desA);
   detector->compute(trainImg, kpB, desB);
   cout << "\nCOMPUTE:\n  desA.size = "<<desA.size() << endl;
   cout << "  desB.size = "<<desB.size() << endl;

#endif

   if (config.diagnosticLevel(4))
   {
      ossimNotify(ossimNotifyLevel_INFO) << "\nDETECT:\n  kpA.size = " << kpA.size() << endl;
      ossimNotify(ossimNotifyLevel_INFO) << "  kpb.size = " << kpA.size() << endl;
      ossimNotify(ossimNotifyLevel_INFO) << "\nCOMPUTE:\n  desA.size = " << desA.size() << endl;
      ossimNotify(ossimNotifyLevel_INFO) << "  desB.size = " << desB.size() << endl;
   }

   // Get the DPoints using the appropriate matcher.
   std::vector< std::vector<cv::DMatch> > matches;
   if(!(desA.empty() || desB.empty()))
   {
      std::string matcherType = config.getParameter("matcher").asString();
      uint k = config.getParameter("maxNumMatchesPerFeature").asUint();
      if (config.paramExists("k")) // support legacy keywords
         k = config.getParameter("k").asUint();
      if (kpA.size() < k)
         k = kpA.size();
      transform(matcherType.begin(), matcherType.end(), matcherType.begin(),::toupper);

      if(matcherType == "FLANN")
      {
         if(desA.type()!=CV_32F)
            desA.convertTo(desA, CV_32F);
         if(desB.type()!=CV_32F)
            desB.convertTo(desB, CV_32F);
         cv::FlannBasedMatcher matcher;
         matcher.knnMatch(desA, desB, matches, k);
      }
      else if(matcherType == "BF")
      {
         ossimNotify(ossimNotifyLevel_WARN) << MODULE << " BF NOT YET IMPLEMENTED\n";
         return m_tile;
      }
      else
      {
         ossimNotify(ossimNotifyLevel_WARN) << MODULE << " WARNING: No such matcher as " << matcherType << "\n";
         return m_tile;
      }
   }

   int leastDistance = INT_MAX;
   int maxDistance = 0;

   // Find the highest distance to compute the relative confidence of each match
   for (size_t i = 0; i < matches.size(); ++i)
   {
      for (size_t j = 0; j < matches[i].size(); ++j)
      {
         if (leastDistance > matches[i][j].distance)
            leastDistance = matches[i][j].distance;
         if (maxDistance < matches[i][j].distance)
            maxDistance = matches[i][j].distance;
      }
   }

   // Sort the matches in order of strength (i.e., confidence) using stl map:
   map<double, shared_ptr<AutoTiePoint> > tpMap;

   // Convert the openCV match points to something Atp could understand.
   string sid(""); // Leave blank to have it auto-assigned by CorrelationTiePoint constructor
   for (size_t i = 0; i < matches.size(); ++i)
   {
      shared_ptr<AutoTiePoint> atp (new AutoTiePoint(this, sid));
      cv::KeyPoint cv_A = kpA[(matches[i][0]).queryIdx];
      cv::KeyPoint cv_B;

      ossimDpt refImgPt (refRect.ul().x + cv_A.pt.x, refRect.ul().y + cv_A.pt.y);
      atp->setRefImagePt(refImgPt);

      // Create the match points
      double strength = 0;
      for (size_t j = 0; j < matches[i].size(); ++j)
      {
         cv_B = kpB[(matches[i][j]).trainIdx];
         ossimDpt cmpImgPt (cmpRect.ul().x + cv_B.pt.x, cmpRect.ul().y + cv_B.pt.y);
         double strength_j = 1.0 - (matches[i][j].distance-leastDistance)/maxDistance;
         if (strength_j > strength)
            strength = strength_j;
         atp->addImageMatch(cmpImgPt, strength_j);
      }

      // Insert into sorted map using one's complement as key since in ascending order:
      tpMap.insert(pair<double, shared_ptr<AutoTiePoint> >(1.0-strength, atp));

      sid.clear();
   }

   if (config.diagnosticLevel(2))
      ossimNotify(ossimNotifyLevel_INFO)<<MODULE<<"Before filtering, num matches in tile = "<<matches.size()<<endl;

   // Now skim off the best matches and copy them to the list being returned:
   unsigned int N = config.getParameter("numFeaturesPerTile").asUint();
   unsigned int n = 0;
   map<double, shared_ptr<AutoTiePoint> >::iterator tp_iter = tpMap.begin();
   while ((tp_iter != tpMap.end()) && (n < N))
   {
      m_tiePoints.push_back(tp_iter->second);
      tp_iter++;
      n++;
   }

   if (config.diagnosticLevel(2))
      ossimNotify(ossimNotifyLevel_INFO)<<MODULE<<"After capping to max num features ("<<N<<"), num TPs in tile = "<<n<<endl;

   return m_tile;
}

}
<commit_msg>Fixed typo<commit_after>//**************************************************************************************************
//
//     OSSIM Open Source Geospatial Data Processing Library
//     See top level LICENSE.txt file for license information
//
//**************************************************************************************************

#include "ossimDescriptorSource.h"
#include "../AtpOpenCV.h"
#include <ossim/imaging/ossimImageDataFactory.h>

#include <opencv2/xfeatures2d.hpp>

namespace ATP
{
static const int DEFAULT_CMP_PATCH_SIZING_FACTOR = 2;
static const double DEFAULT_NOMINAL_POSITION_ERROR = 50; // meters

ossimDescriptorSource::ossimDescriptorSource()
{
}

ossimDescriptorSource::ossimDescriptorSource(ossimConnectableObject::ConnectableObjectList& inputSources)
: AtpTileSource(inputSources)
{
   initialize();
}

ossimDescriptorSource::ossimDescriptorSource(AtpGeneratorBase* generator)
: AtpTileSource(generator)
{
}

ossimDescriptorSource::~ossimDescriptorSource()
{
}

void ossimDescriptorSource::initialize()
{
   // Base class initializes ref and cmp chain datat members and associated IVTs. Subsequent call
   // to base class setViewGeom() will initialize the associated IVTs:
   AtpTileSource::initialize();

   m_nominalCmpPatchSize = 0.0;
   unsigned int refPatchSize = AtpConfig::instance().getParameter("corrWindowSize").asUint(); // min distance between points
   m_nominalCmpPatchSize = DEFAULT_CMP_PATCH_SIZING_FACTOR*refPatchSize;

   if (m_refIVT && m_cmpIVT)
   {
      ossimDpt gsd = m_refIVT->getOutputMetersPerPixel();
      double nominalGsd = (gsd.x + gsd.y)/2.0;

      // Fetch the CE90 of both images to determine cmp image search patch size:
      ossimSensorModel* ref_sm = dynamic_cast<ossimSensorModel*>(
              m_refIVT->getImageGeometry()->getProjection());
      ossimSensorModel* cmp_sm = dynamic_cast<ossimSensorModel*>(
              m_cmpIVT->getImageGeometry()->getProjection());
      if (ref_sm && cmp_sm)
      {
         double ref_ce = ref_sm->getNominalPosError();
         double cmp_ce = cmp_sm->getNominalPosError();
         double total_error = ref_ce + cmp_ce; // meters -- being conservative here and not doing rss
         ossimDpt gsd = m_refIVT->getOutputMetersPerPixel();
         double nominalGsd = (gsd.x + gsd.y)/2.0;
         double searchSizePixels = 2.0*total_error/nominalGsd;
         m_nominalCmpPatchSize = refPatchSize + searchSizePixels;
      }
      else
      {
         double searchSizePixels = 2.0*DEFAULT_NOMINAL_POSITION_ERROR/nominalGsd;
         m_nominalCmpPatchSize = refPatchSize + searchSizePixels;
      }
   }
}

ossimRefPtr<ossimImageData> ossimDescriptorSource::getTile(const ossimIrect& tileRect,
                                                            ossim_uint32 resLevel)
{
   static const char* MODULE = "ossimDescriptorSource::getTile()  ";
   AtpConfig& config = AtpConfig::instance();

   if (config.diagnosticLevel(2))
      ossimNotify(ossimNotifyLevel_INFO)<<"\n\n"<< MODULE << " -- tileRect: "<<tileRect<<endl;
   m_tiePoints.clear();

   if(!m_tile.get())
   {
      // try to initialize
      initialize();
      if(!m_tile.get()){
         ossimNotify(ossimNotifyLevel_INFO) << MODULE << " ERROR: could not initialize tile\n";
         return m_tile;
      }
   }

   // Make sure there are at least two images as input.
   if(getNumberOfInputs() < 2)
   {
      ossimNotify(ossimNotifyLevel_INFO) << MODULE << " ERROR: wrong number of inputs " << getNumberOfInputs() << " when expecting at least 2 \n";
      return 0;
   }

   // The tileRect passed in is in a common map-projected view space. Need to transform the rect
   // into image space for both ref and cmp images:
   ossimIrect refRect (m_refIVT->getViewToImageBounds(tileRect));
   ossimIrect cmpRect (m_cmpIVT->getViewToImageBounds(tileRect));
   cmpRect.expand(ossimIpt(m_nominalCmpPatchSize, m_nominalCmpPatchSize));

   // Retrieve both the ref and cmp image data
   ossimRefPtr<ossimImageData> ref_tile = m_refChain->getTile(refRect, resLevel);
   if (ref_tile->getDataObjectStatus() == OSSIM_EMPTY)
   {
      ossimNotify(ossimNotifyLevel_WARN) << MODULE << " ERROR: could not get REF tile with rect " << refRect << "\n";
      return m_tile;
   }
   if (config.diagnosticLevel(5))
      ref_tile->write("REF_TILE.RAS");

   ossimRefPtr<ossimImageData> cmp_tile = m_cmpChain->getTile(cmpRect, resLevel);
   if (cmp_tile->getDataObjectStatus() == OSSIM_EMPTY)
   {
      ossimNotify(ossimNotifyLevel_WARN) << MODULE << " ERROR: could not get CMP tile with rect " << cmpRect << "\n";
      return m_tile;
   }
   if (config.diagnosticLevel(5))
      cmp_tile->write("CMP_TILE.RAS");

   m_tile = ref_tile;

   // Convert both into OpenCV Mat objects using the Ipl image.
   IplImage* refImage = convertToIpl32(ref_tile.get());
   IplImage* cmpImage = convertToIpl32(cmp_tile.get());
   cv::Mat queryImg = cv::cvarrToMat(refImage);
   cv::Mat trainImg = cv::cvarrToMat(cmpImage);

   // Get the KeyPoints using appropriate descriptor.
   vector<cv::KeyPoint> kpA;
   vector<cv::KeyPoint> kpB;
   cv::Mat desA;
   cv::Mat desB;

   ossimString descriptorType (config.getParameter("descriptor").asString());
   descriptorType.upcase();

#if 1
   // Search for features and compute descriptors for all:
   cv::Ptr<cv::Feature2D> detector;
   if(descriptorType == "AKAZE")
   {
      detector = cv::AKAZE::create();
   }
   else if(descriptorType == "KAZE")
   {
      detector = cv::KAZE::create();
   }
   else if(descriptorType == "ORB")
   {
      // For some reason orb wants multiple channel mats so fake it.
      //if (queryImg.channels() == 1)
      //{
      //   std::vector<cv::Mat> channels;
      //   channels.push_back(queryImg);
      //   channels.push_back(queryImg);
      //   channels.push_back(queryImg);
      //   cv::merge(channels, queryImg);
      //}
      //
      //if (trainImg.channels() == 1)
      //{
      //   std::vector<cv::Mat> channels;
      //   channels.push_back(trainImg);
      //   channels.push_back(trainImg);
      //   channels.push_back(trainImg);
      //   cv::merge(channels, trainImg);
      //}

      detector = cv::ORB::create();
   }
   else if(descriptorType == "SURF")
   {
      detector = cv::xfeatures2d::SURF::create();
   }
   else if(descriptorType == "SIFT")
   {
      detector = cv::xfeatures2d::SIFT::create();
   }
   else
   {
      ossimNotify(ossimNotifyLevel_WARN) << MODULE << " WARNING: No such descriptor as " << descriptorType << "\n";
      return m_tile;
   }

   detector->detectAndCompute(queryImg, cv::noArray(), kpA, desA);
   detector->detectAndCompute(trainImg, cv::noArray(), kpB, desB);

#else
   // Separate detect and compute to limit the number of features for which descriptors are
   // computed... Instantiate feature detector and descriptor algo:
   cv::Ptr<cv::Feature2D> detector;
   if(descriptorType == "AKAZE")
      detector = cv::AKAZE::create();
   else if(descriptorType == "KAZE")
      detector = cv::KAZE::create();
   else if(descriptorType == "ORB")
   {
      //// For some reason orb wants multiple channel mats so fake it.
      //if (queryImg.channels() == 1)
      //{
      //   std::vector<cv::Mat> channels;
      //   channels.push_back(queryImg);
      //   channels.push_back(queryImg);
      //   channels.push_back(queryImg);
      //   cv::merge(channels, queryImg);
      //}
      //
      //if (trainImg.channels() == 1)
      //{
      //   std::vector<cv::Mat> channels;
      //   channels.push_back(trainImg);
      //   channels.push_back(trainImg);
      //   channels.push_back(trainImg);
      //   cv::merge(channels, trainImg);
      //}

      detector = cv::ORB::create();
   }
   else if(descriptorType == "SURF")
      detector = cv::xfeatures2d::SURF::create();
   else if(descriptorType == "SIFT")
      detector = cv::xfeatures2d::SIFT::create();
   else
   {
      ossimNotify(ossimNotifyLevel_WARN) << MODULE << " WARNING: No such descriptor as " << descriptorType << "\n";
      return m_tile;
   }

   // Perform detection:
   detector->detect(queryImg, kpA);
   detector->detect(trainImg, kpB);

   cout << "\nDETECT:\n  kpA.size = "<<kpA.size() << endl;
   cout << "  kpb.size = "<<kpA.size() << endl;

   // Limit strongest detections to max number of features per tile on query image:
   unsigned int maxNumFeatures = config.getParameter("numFeaturesPerTile").asUint();
   cout << "\n numFeatures= "<<maxNumFeatures << endl;
   if (kpA.size() > maxNumFeatures)
   {
      sort(kpA.begin(), kpA.end(), sortFunc);
      kpA.resize(maxNumFeatures);
   }

   //if (kpB.size() > maxNumFeatures)
   //{
   //   sort(kpB.begin(), kpB.end(), sortFunc);
   //   kpB.resize(maxNumFeatures);
   //}
   //cout << "\nTRIM:\n  kpA.size = "<<kpA.size() << endl;
   //cout << "  kpb.size = "<<kpA.size() << endl;

   // Now perform descriptor computations on remaining features:
   detector->compute(queryImg, kpA, desA);
   detector->compute(trainImg, kpB, desB);
   cout << "\nCOMPUTE:\n  desA.size = "<<desA.size() << endl;
   cout << "  desB.size = "<<desB.size() << endl;

#endif

   if (config.diagnosticLevel(4))
   {
      ossimNotify(ossimNotifyLevel_INFO) << "\nDETECT:\n  kpA.size = " << kpA.size() << endl;
      ossimNotify(ossimNotifyLevel_INFO) << "  kpb.size = " << kpA.size() << endl;
      ossimNotify(ossimNotifyLevel_INFO) << "\nCOMPUTE:\n  desA.size = " << desA.size() << endl;
      ossimNotify(ossimNotifyLevel_INFO) << "  desB.size = " << desB.size() << endl;
   }

   // Get the DPoints using the appropriate matcher.
   std::vector< std::vector<cv::DMatch> > matches;
   if(!(desA.empty() || desB.empty()))
   {
      std::string matcherType = config.getParameter("matcher").asString();
      uint k = config.getParameter("maxNumMatchesPerFeature").asUint();
      if (config.paramExists("k")) // support legacy keywords
         k = config.getParameter("k").asUint();
      if (kpA.size() < k)
         k = kpA.size();
      transform(matcherType.begin(), matcherType.end(), matcherType.begin(),::toupper);

      if(matcherType == "FLANN")
      {
         if(desA.type()!=CV_32F)
            desA.convertTo(desA, CV_32F);
         if(desB.type()!=CV_32F)
            desB.convertTo(desB, CV_32F);
         cv::FlannBasedMatcher matcher;
         matcher.knnMatch(desA, desB, matches, k);
      }
      else if(matcherType == "BF")
      {
         ossimNotify(ossimNotifyLevel_WARN) << MODULE << " BF NOT YET IMPLEMENTED\n";
         return m_tile;
      }
      else
      {
         ossimNotify(ossimNotifyLevel_WARN) << MODULE << " WARNING: No such matcher as " << matcherType << "\n";
         return m_tile;
      }
   }

   int leastDistance = INT_MAX;
   int maxDistance = 0;

   // Find the highest distance to compute the relative confidence of each match
   for (size_t i = 0; i < matches.size(); ++i)
   {
      for (size_t j = 0; j < matches[i].size(); ++j)
      {
         if (leastDistance > matches[i][j].distance)
            leastDistance = matches[i][j].distance;
         if (maxDistance < matches[i][j].distance)
            maxDistance = matches[i][j].distance;
      }
   }

   // Sort the matches in order of strength (i.e., confidence) using stl map:
   map<double, shared_ptr<AutoTiePoint> > tpMap;

   // Convert the openCV match points to something Atp could understand.
   string sid(""); // Leave blank to have it auto-assigned by CorrelationTiePoint constructor
   for (size_t i = 0; i < matches.size(); ++i)
   {
      shared_ptr<AutoTiePoint> atp (new AutoTiePoint(this, sid));
      cv::KeyPoint cv_A = kpA[(matches[i][0]).queryIdx];
      cv::KeyPoint cv_B;

      ossimDpt refImgPt (refRect.ul().x + cv_A.pt.x, refRect.ul().y + cv_A.pt.y);
      atp->setRefImagePt(refImgPt);

      // Create the match points
      double strength = 0;
      for (size_t j = 0; j < matches[i].size(); ++j)
      {
         cv_B = kpB[(matches[i][j]).trainIdx];
         ossimDpt cmpImgPt (cmpRect.ul().x + cv_B.pt.x, cmpRect.ul().y + cv_B.pt.y);
         double strength_j = 1.0 - (matches[i][j].distance-leastDistance)/maxDistance;
         if (strength_j > strength)
            strength = strength_j;
         atp->addImageMatch(cmpImgPt, strength_j);
      }

      // Insert into sorted map using one's complement as key since in ascending order:
      tpMap.insert(pair<double, shared_ptr<AutoTiePoint> >(1.0-strength, atp));

      sid.clear();
   }

   if (config.diagnosticLevel(2))
      ossimNotify(ossimNotifyLevel_INFO)<<MODULE<<"Before filtering, num matches in tile = "<<matches.size()<<endl;

   // Now skim off the best matches and copy them to the list being returned:
   unsigned int N = config.getParameter("numFeaturesPerTile").asUint();
   unsigned int n = 0;
   map<double, shared_ptr<AutoTiePoint> >::iterator tp_iter = tpMap.begin();
   while ((tp_iter != tpMap.end()) && (n < N))
   {
      m_tiePoints.push_back(tp_iter->second);
      tp_iter++;
      n++;
   }

   if (config.diagnosticLevel(2))
      ossimNotify(ossimNotifyLevel_INFO)<<MODULE<<"After capping to max num features ("<<N<<"), num TPs in tile = "<<n<<endl;

   return m_tile;
}

}
<|endoftext|>


<commit_before>#include "UnitTests.h"

#include "../NULLC/nullc.h"
#include "../NULLC/nullc_debug.h"
#include "../NULLC/nullc_internal.h"

// Check that remote debug module compiles correctly
#if defined(_MSC_VER)
	#include "../NULLC/nullc_remote.h"
#endif

#include "../NULLC/includes/file.h"
#include "../NULLC/includes/math.h"
#include "../NULLC/includes/vector.h"
#include "../NULLC/includes/random.h"
#include "../NULLC/includes/dynamic.h"
#include "../NULLC/includes/gc.h"
#include "../NULLC/includes/time.h"
#include "../NULLC/includes/string.h"

#include "../NULLC/includes/canvas.h"
#include "../NULLC/includes/window.h"
#include "../NULLC/includes/io.h"

#include "../NULLC/includes/pugi.h"

#include "TestBase.h"
#include "TestSpeed.h"
#include "TestCompileFail.h"
#include "TestParseFail.h"
#include "TestInterface.h"

#if defined(_MSC_VER)
#pragma warning(disable: 4127 4996)
#endif

//#define ALLOC_TOP_DOWN
//#define NO_CUSTOM_ALLOCATOR

unsigned testTotalMemoryAlloc = 0;
unsigned testTotalMemoryFree = 0;
unsigned testTotalMemoryRequested = 0;
unsigned testTotalMemoryUsed = 0;

struct MallocAllocatorRef : Allocator
{
	MallocAllocatorRef()
	{
	}

	~MallocAllocatorRef()
	{
	}

	virtual void* alloc(int size)
	{
		return malloc(size);
	}

	virtual void dealloc(void* ptr)
	{
		free(ptr);
	}

	virtual unsigned requested()
	{
		return 0;
	}
};

struct PointerHasher
{
	unsigned operator()(void *key)
	{
		char data[sizeof(void*)];
		memcpy(data, &key, sizeof(void*));

		unsigned int hash = 5381;
		for(unsigned i = 0; i < sizeof(void*); i++)
			hash = ((hash << 5) + hash) + data[i];
		return hash;
	}
};

MallocAllocatorRef setAllocator;
SmallDenseMap<void*, bool, PointerHasher, 1024> activePoiners(&setAllocator);

void* testAlloc(int size)
{
#ifdef ALLOC_TOP_DOWN
	return VirtualAlloc(NULL, size + 128, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE);
#else
	testTotalMemoryAlloc++;
	testTotalMemoryRequested += size;
	testTotalMemoryUsed += size;

	char *ptr = new char[size + 128];
	memset(ptr, 0xee, 128);
	*(unsigned*)ptr = size;

	activePoiners.insert(ptr, 1);

	return ptr + 128;
#endif
}
void testDealloc(void* ptr)
{
	if(!ptr)
		return;
#ifdef ALLOC_TOP_DOWN
	VirtualFree((char*)ptr - 128, 0, MEM_RELEASE);
#else
	ptr = (char*)ptr - 128;

	bool* active = activePoiners.find(ptr);

	if(!active || !*active)
	{
		printf("pointer was not allocated");
		abort();
	}

	activePoiners.insert(ptr, 0);

	testTotalMemoryFree++;
	testTotalMemoryUsed -= *(unsigned*)ptr;

	for(unsigned i = sizeof(unsigned); i < 128; i++)
		assert(((unsigned char*)ptr)[i] == 0xee);
	delete[] (char*)ptr;
#endif
}

nullres CompileFile(const char* fileName)
{
	static char content[64 * 1024];

	FILE *euler = fopen(fileName, "rb");
	fseek(euler, 0, SEEK_END);
	unsigned int textSize = ftell(euler);
	assert(textSize < 64 * 1024);
	fseek(euler, 0, SEEK_SET);
	fread(content, 1, textSize, euler);
	content[textSize] = 0;
	fclose(euler);

	return nullcCompile(content);
}

int RunTests(bool verbose, const char* (*fileLoadFunc)(const char*, unsigned*), void (*fileFreeFunc)(const char*), bool runSpeedTests, bool testOutput, bool testTranslationSave, bool testTranslation)
{
	Tests::messageVerbose = verbose;
	Tests::fileLoadFunc = fileLoadFunc;
	Tests::fileFreeFunc = fileFreeFunc;

	// Extra tests

	// Safe sprintf test
	{
		testsCount[TEST_TYPE_EXTRA]++;

		char buf[8];
		char *pos = buf + NULLC::SafeSprintf(buf, 8, "this ");
		pos += NULLC::SafeSprintf(pos, 8 - int(pos - buf), "string is too long");
		if(memcmp(buf, "this st", 8) != 0)
			printf("Safe sprintf test failed: string is incorrect\n");
		else if(pos != buf + 8)
			printf("Safe sprintf test failed: iterator is incorrect\n");
		else
			testsPassed[TEST_TYPE_EXTRA]++;
	}

	{
		testsCount[TEST_TYPE_EXTRA]++;

		char buf[8];
		char *pos = buf + NULLC::SafeSprintf(buf, 8, "this string");
		pos += NULLC::SafeSprintf(pos, 8 - int(pos - buf), " is too long");
		if(memcmp(buf, "this st", 8) != 0)
			printf("Safe sprintf test failed: string is incorrect\n");
		else if(pos != buf + 8)
			printf("Safe sprintf test failed: iterator is incorrect\n");
		else
			testsPassed[TEST_TYPE_EXTRA]++;
	}

/*
	unsigned int tStart = clock();
	for(unsigned int i = 0; i < 10000; i++)
	{
		nullcInit("Modules/");
		nullcTerminate();
	}
	printf("Finished in %d\r\n", clock() - tStart);
*/

	Tests::enableLogFiles = testOutput;
	Tests::doSaveTranslation = testTranslationSave;
	Tests::doTranslation = testTranslation;

	if(testTranslation)
	{
		Tests::messageVerbose = true;
		Tests::openStreamFunc = 0;
		Tests::writeStreamFunc = 0;
		Tests::closeStreamFunc = 0;
	}

	// To test translation to C with build and execution
	/*
	Tests::messageVerbose = true;
	Tests::doSaveTranslation = true;
	Tests::doTranslation = true;
	Tests::openStreamFunc = 0;
	Tests::writeStreamFunc = 0;
	Tests::closeStreamFunc = 0;
	*/

	// To enable real log files during tests
	/*
	Tests::enableLogFiles = true;
	Tests::messageVerbose = true;
	Tests::openStreamFunc = 0;
	Tests::writeStreamFunc = 0;
	Tests::closeStreamFunc = 0;
	*/

	// Init NULLC for interface tests
#ifdef NO_CUSTOM_ALLOCATOR
	nullcInit();
	nullcAddImportPath(MODULE_PATH_A);
	nullcAddImportPath(MODULE_PATH_B);
#else
	nullcInitCustomAlloc(testAlloc, testDealloc);
	nullcAddImportPath(MODULE_PATH_A);
	nullcAddImportPath(MODULE_PATH_B);
#endif
	nullcSetFileReadHandler(Tests::fileLoadFunc, Tests::fileFreeFunc);
	nullcSetEnableLogFiles(Tests::enableLogFiles, Tests::openStreamFunc, Tests::writeStreamFunc, Tests::closeStreamFunc);

	nullcInitTypeinfoModule();
	nullcInitDynamicModule();
	RunInterfaceTests();

	// Init NULLC for test set
#ifdef NO_CUSTOM_ALLOCATOR
	nullcInit();
	nullcAddImportPath(MODULE_PATH_A);
	nullcAddImportPath(MODULE_PATH_B);
#else
	nullcInitCustomAlloc(testAlloc, testDealloc);
	nullcAddImportPath(MODULE_PATH_A);
	nullcAddImportPath(MODULE_PATH_B);
#endif
	nullcSetFileReadHandler(Tests::fileLoadFunc, Tests::fileFreeFunc);
	nullcSetEnableLogFiles(Tests::enableLogFiles, Tests::openStreamFunc, Tests::writeStreamFunc, Tests::closeStreamFunc);

	nullcInitTypeinfoModule();
	nullcInitFileModule();
	nullcInitMathModule();
	nullcInitVectorModule();
	nullcInitRandomModule();
	nullcInitDynamicModule();
	nullcInitGCModule();
	nullcInitStringModule();

	nullcInitIOModule();
	nullcInitCanvasModule();

#if defined(_MSC_VER)
	nullcInitWindowModule();
#endif

	/*
	//SpeedTestFile("test_document.nc");
	//SpeedTestFile("shapes.nc");
	//SpeedTestFile("raytrace.nc");
	//SpeedTestFile("blob.nc");
	return 0;*/

	RunParseFailTests();
	RunCompileFailTests();

	TestQueue queue;
	queue.RunTests();

	// Conclusion
	printf("VM passed %d of %d tests\n", testsPassed[TEST_TYPE_VM], testsCount[TEST_TYPE_VM]);

	printf("Expr Evaluated %d of %d tests\n", testsPassed[TEST_TYPE_EXPR_EVALUATION], testsCount[TEST_TYPE_EXPR_EVALUATION]);
	printf("Inst Evaluated %d of %d tests\n", testsPassed[TEST_TYPE_INST_EVALUATION], testsCount[TEST_TYPE_INST_EVALUATION]);

#ifdef NULLC_BUILD_X86_JIT
	printf("X86 passed %d of %d tests\n", testsPassed[TEST_TYPE_X86], testsCount[TEST_TYPE_X86]);
#else
	testsPassed[TEST_TYPE_X86] = 0;
	testsCount[TEST_TYPE_X86] = 0;
#endif

#ifdef NULLC_LLVM_SUPPORT
	printf("LLVM passed %d of %d tests\n", testsPassed[TEST_TYPE_LLVM], testsCount[TEST_TYPE_LLVM]);
#else
	testsPassed[TEST_TYPE_LLVM] = 0;
	testsCount[TEST_TYPE_LLVM] = 0;
#endif

	printf("RegVM passed %d of %d tests\n", testsPassed[TEST_TYPE_REGVM], testsCount[TEST_TYPE_REGVM]);

	printf("Failure tests: passed %d of %d tests\n", testsPassed[TEST_TYPE_FAILURE], testsCount[TEST_TYPE_FAILURE]);
	printf("Extra tests: passed %d of %d tests\n", testsPassed[TEST_TYPE_EXTRA], testsCount[TEST_TYPE_EXTRA]);
	printf("Translation tests: passed %d of %d tests\n", testsPassed[TEST_TYPE_TRANSLATION], testsCount[TEST_TYPE_TRANSLATION]);

	unsigned allTests = 0;
	unsigned allPassed = 0;
	for(unsigned i = 0; i < TEST_TYPE_COUNT; i++)
	{
		allTests += testsCount[i];
		allPassed += testsPassed[i];
	}

	printf("Compilation time: %f\n", Tests::timeCompile);
	printf("Get bytecode time: %f\n", Tests::timeGetBytecode);
	printf("Tree visit time: %f\n", Tests::timeVisit);
	printf("Expression evaluation time: %f\n", Tests::timeExprEvaluate);
	printf("Instruction evaluation time: %f\n", Tests::timeInstEvaluate);
	printf("Translation time: %f\n", Tests::timeTranslate);
	printf("Clean time: %f\n", Tests::timeClean);
	printf("Link time: %f\n", Tests::timeLinkCode);
	printf("Run time: %f\n", Tests::timeRun);

	printf("Total time: %f\n", Tests::timeCompile + Tests::timeGetBytecode + Tests::timeVisit + Tests::timeExprEvaluate + Tests::timeInstEvaluate + Tests::timeTranslate + Tests::timeClean + Tests::timeLinkCode + Tests::timeRun);

	printf("Total log output: %lld\n", Tests::totalOutput);
	printf("Total nodes: %d syntax, %d expression\n", Tests::totalSyntaxNodes, Tests::totalExpressionNodes);

	printf("Total global allocs: %d (%.3fMB requested)\n", testTotalMemoryAlloc, testTotalMemoryRequested / 1024 / 1024.0);

	printf("Passed %d of %d tests\n", allPassed, allTests);

	if(runSpeedTests)
		RunSpeedTests();

	// Terminate NULLC
	nullcTerminate();

	return allPassed == allTests ? 0 : 1;
}
<commit_msg>Top-down allocation test fix<commit_after>#include "UnitTests.h"

#include "../NULLC/nullc.h"
#include "../NULLC/nullc_debug.h"
#include "../NULLC/nullc_internal.h"

// Check that remote debug module compiles correctly
#if defined(_MSC_VER)
	#include "../NULLC/nullc_remote.h"
#endif

#include "../NULLC/includes/file.h"
#include "../NULLC/includes/math.h"
#include "../NULLC/includes/vector.h"
#include "../NULLC/includes/random.h"
#include "../NULLC/includes/dynamic.h"
#include "../NULLC/includes/gc.h"
#include "../NULLC/includes/time.h"
#include "../NULLC/includes/string.h"

#include "../NULLC/includes/canvas.h"
#include "../NULLC/includes/window.h"
#include "../NULLC/includes/io.h"

#include "../NULLC/includes/pugi.h"

#include "TestBase.h"
#include "TestSpeed.h"
#include "TestCompileFail.h"
#include "TestParseFail.h"
#include "TestInterface.h"

#if defined(_MSC_VER)
#pragma warning(disable: 4127 4996)
#endif

//#define ALLOC_TOP_DOWN
//#define NO_CUSTOM_ALLOCATOR

unsigned testTotalMemoryAlloc = 0;
unsigned testTotalMemoryFree = 0;
unsigned testTotalMemoryRequested = 0;
unsigned testTotalMemoryUsed = 0;

struct MallocAllocatorRef : Allocator
{
	MallocAllocatorRef()
	{
	}

	~MallocAllocatorRef()
	{
	}

	virtual void* alloc(int size)
	{
		return malloc(size);
	}

	virtual void dealloc(void* ptr)
	{
		free(ptr);
	}

	virtual unsigned requested()
	{
		return 0;
	}
};

struct PointerHasher
{
	unsigned operator()(void *key)
	{
		char data[sizeof(void*)];
		memcpy(data, &key, sizeof(void*));

		unsigned int hash = 5381;
		for(unsigned i = 0; i < sizeof(void*); i++)
			hash = ((hash << 5) + hash) + data[i];
		return hash;
	}
};

MallocAllocatorRef setAllocator;
SmallDenseMap<void*, bool, PointerHasher, 1024> activePoiners(&setAllocator);

void* testAlloc(int size)
{
	testTotalMemoryAlloc++;
	testTotalMemoryRequested += size;
	testTotalMemoryUsed += size;

#ifdef ALLOC_TOP_DOWN
	char *ptr = (char*)VirtualAlloc(NULL, size + 128, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE);
#else
	char *ptr = new char[size + 128];
#endif

	if(size < 0 || !ptr)
	{
		assert(!"out of memory");
		return 0;
	}

	memset(ptr, 0xee, 128);
	*(unsigned*)ptr = size;

	activePoiners.insert(ptr, 1);

	return ptr + 128;
}

void testDealloc(void* ptr)
{
	if(!ptr)
		return;

	ptr = (char*)ptr - 128;

	bool* active = activePoiners.find(ptr);

	if(!active || !*active)
	{
		printf("pointer was not allocated");
		abort();
	}

	activePoiners.insert(ptr, 0);

	testTotalMemoryFree++;
	testTotalMemoryUsed -= *(unsigned*)ptr;

	for(unsigned i = sizeof(unsigned); i < 128; i++)
		assert(((unsigned char*)ptr)[i] == 0xee);

#ifdef ALLOC_TOP_DOWN
	VirtualFree((char*)ptr, 0, MEM_RELEASE);
#else
	delete[] (char*)ptr;
#endif
}

nullres CompileFile(const char* fileName)
{
	static char content[64 * 1024];

	FILE *euler = fopen(fileName, "rb");
	fseek(euler, 0, SEEK_END);
	unsigned int textSize = ftell(euler);
	assert(textSize < 64 * 1024);
	fseek(euler, 0, SEEK_SET);
	fread(content, 1, textSize, euler);
	content[textSize] = 0;
	fclose(euler);

	return nullcCompile(content);
}

int RunTests(bool verbose, const char* (*fileLoadFunc)(const char*, unsigned*), void (*fileFreeFunc)(const char*), bool runSpeedTests, bool testOutput, bool testTranslationSave, bool testTranslation)
{
	Tests::messageVerbose = verbose;
	Tests::fileLoadFunc = fileLoadFunc;
	Tests::fileFreeFunc = fileFreeFunc;

	// Extra tests

	// Safe sprintf test
	{
		testsCount[TEST_TYPE_EXTRA]++;

		char buf[8];
		char *pos = buf + NULLC::SafeSprintf(buf, 8, "this ");
		pos += NULLC::SafeSprintf(pos, 8 - int(pos - buf), "string is too long");
		if(memcmp(buf, "this st", 8) != 0)
			printf("Safe sprintf test failed: string is incorrect\n");
		else if(pos != buf + 8)
			printf("Safe sprintf test failed: iterator is incorrect\n");
		else
			testsPassed[TEST_TYPE_EXTRA]++;
	}

	{
		testsCount[TEST_TYPE_EXTRA]++;

		char buf[8];
		char *pos = buf + NULLC::SafeSprintf(buf, 8, "this string");
		pos += NULLC::SafeSprintf(pos, 8 - int(pos - buf), " is too long");
		if(memcmp(buf, "this st", 8) != 0)
			printf("Safe sprintf test failed: string is incorrect\n");
		else if(pos != buf + 8)
			printf("Safe sprintf test failed: iterator is incorrect\n");
		else
			testsPassed[TEST_TYPE_EXTRA]++;
	}

/*
	unsigned int tStart = clock();
	for(unsigned int i = 0; i < 10000; i++)
	{
		nullcInit("Modules/");
		nullcTerminate();
	}
	printf("Finished in %d\r\n", clock() - tStart);
*/

	Tests::enableLogFiles = testOutput;
	Tests::doSaveTranslation = testTranslationSave;
	Tests::doTranslation = testTranslation;

	if(testTranslation)
	{
		Tests::messageVerbose = true;
		Tests::openStreamFunc = 0;
		Tests::writeStreamFunc = 0;
		Tests::closeStreamFunc = 0;
	}

	// To test translation to C with build and execution
	/*
	Tests::messageVerbose = true;
	Tests::doSaveTranslation = true;
	Tests::doTranslation = true;
	Tests::openStreamFunc = 0;
	Tests::writeStreamFunc = 0;
	Tests::closeStreamFunc = 0;
	*/

	// To enable real log files during tests
	/*
	Tests::enableLogFiles = true;
	Tests::messageVerbose = true;
	Tests::openStreamFunc = 0;
	Tests::writeStreamFunc = 0;
	Tests::closeStreamFunc = 0;
	*/

	// Init NULLC for interface tests
#ifdef NO_CUSTOM_ALLOCATOR
	nullcInit();
	nullcAddImportPath(MODULE_PATH_A);
	nullcAddImportPath(MODULE_PATH_B);
#else
	nullcInitCustomAlloc(testAlloc, testDealloc);
	nullcAddImportPath(MODULE_PATH_A);
	nullcAddImportPath(MODULE_PATH_B);
#endif
	nullcSetFileReadHandler(Tests::fileLoadFunc, Tests::fileFreeFunc);
	nullcSetEnableLogFiles(Tests::enableLogFiles, Tests::openStreamFunc, Tests::writeStreamFunc, Tests::closeStreamFunc);

	nullcInitTypeinfoModule();
	nullcInitDynamicModule();
	RunInterfaceTests();

	// Init NULLC for test set
#ifdef NO_CUSTOM_ALLOCATOR
	nullcInit();
	nullcAddImportPath(MODULE_PATH_A);
	nullcAddImportPath(MODULE_PATH_B);
#else
	nullcInitCustomAlloc(testAlloc, testDealloc);
	nullcAddImportPath(MODULE_PATH_A);
	nullcAddImportPath(MODULE_PATH_B);
#endif
	nullcSetFileReadHandler(Tests::fileLoadFunc, Tests::fileFreeFunc);
	nullcSetEnableLogFiles(Tests::enableLogFiles, Tests::openStreamFunc, Tests::writeStreamFunc, Tests::closeStreamFunc);

	nullcInitTypeinfoModule();
	nullcInitFileModule();
	nullcInitMathModule();
	nullcInitVectorModule();
	nullcInitRandomModule();
	nullcInitDynamicModule();
	nullcInitGCModule();
	nullcInitStringModule();

	nullcInitIOModule();
	nullcInitCanvasModule();

#if defined(_MSC_VER)
	nullcInitWindowModule();
#endif

	/*
	//SpeedTestFile("test_document.nc");
	//SpeedTestFile("shapes.nc");
	//SpeedTestFile("raytrace.nc");
	//SpeedTestFile("blob.nc");
	return 0;*/

	RunParseFailTests();
	RunCompileFailTests();

	TestQueue queue;
	queue.RunTests();

	// Conclusion
	printf("VM passed %d of %d tests\n", testsPassed[TEST_TYPE_VM], testsCount[TEST_TYPE_VM]);

	printf("Expr Evaluated %d of %d tests\n", testsPassed[TEST_TYPE_EXPR_EVALUATION], testsCount[TEST_TYPE_EXPR_EVALUATION]);
	printf("Inst Evaluated %d of %d tests\n", testsPassed[TEST_TYPE_INST_EVALUATION], testsCount[TEST_TYPE_INST_EVALUATION]);

#ifdef NULLC_BUILD_X86_JIT
	printf("X86 passed %d of %d tests\n", testsPassed[TEST_TYPE_X86], testsCount[TEST_TYPE_X86]);
#else
	testsPassed[TEST_TYPE_X86] = 0;
	testsCount[TEST_TYPE_X86] = 0;
#endif

#ifdef NULLC_LLVM_SUPPORT
	printf("LLVM passed %d of %d tests\n", testsPassed[TEST_TYPE_LLVM], testsCount[TEST_TYPE_LLVM]);
#else
	testsPassed[TEST_TYPE_LLVM] = 0;
	testsCount[TEST_TYPE_LLVM] = 0;
#endif

	printf("RegVM passed %d of %d tests\n", testsPassed[TEST_TYPE_REGVM], testsCount[TEST_TYPE_REGVM]);

	printf("Failure tests: passed %d of %d tests\n", testsPassed[TEST_TYPE_FAILURE], testsCount[TEST_TYPE_FAILURE]);
	printf("Extra tests: passed %d of %d tests\n", testsPassed[TEST_TYPE_EXTRA], testsCount[TEST_TYPE_EXTRA]);
	printf("Translation tests: passed %d of %d tests\n", testsPassed[TEST_TYPE_TRANSLATION], testsCount[TEST_TYPE_TRANSLATION]);

	unsigned allTests = 0;
	unsigned allPassed = 0;
	for(unsigned i = 0; i < TEST_TYPE_COUNT; i++)
	{
		allTests += testsCount[i];
		allPassed += testsPassed[i];
	}

	printf("Compilation time: %f\n", Tests::timeCompile);
	printf("Get bytecode time: %f\n", Tests::timeGetBytecode);
	printf("Tree visit time: %f\n", Tests::timeVisit);
	printf("Expression evaluation time: %f\n", Tests::timeExprEvaluate);
	printf("Instruction evaluation time: %f\n", Tests::timeInstEvaluate);
	printf("Translation time: %f\n", Tests::timeTranslate);
	printf("Clean time: %f\n", Tests::timeClean);
	printf("Link time: %f\n", Tests::timeLinkCode);
	printf("Run time: %f\n", Tests::timeRun);

	printf("Total time: %f\n", Tests::timeCompile + Tests::timeGetBytecode + Tests::timeVisit + Tests::timeExprEvaluate + Tests::timeInstEvaluate + Tests::timeTranslate + Tests::timeClean + Tests::timeLinkCode + Tests::timeRun);

	printf("Total log output: %lld\n", Tests::totalOutput);
	printf("Total nodes: %d syntax, %d expression\n", Tests::totalSyntaxNodes, Tests::totalExpressionNodes);

	printf("Total global allocs: %d (%.3fMB requested)\n", testTotalMemoryAlloc, testTotalMemoryRequested / 1024 / 1024.0);

	printf("Passed %d of %d tests\n", allPassed, allTests);

	if(runSpeedTests)
		RunSpeedTests();

	// Terminate NULLC
	nullcTerminate();

	return allPassed == allTests ? 0 : 1;
}
<|endoftext|>