<commit_before>#include <gflags/gflags.h>
#include <libusb-1.0/libusb.h>
#include <stdarg.h>
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <vector>

DEFINE_int32(verbose, 0, "increase verbosity");
DEFINE_bool(test, false, "test adaptor hardware");
DEFINE_string(hex, "", "sata to send in hex. e.g. \"de,ad,be,ef\"");

static const int USBI2C_VENDOR_ID = 0xF055;
static const int USBI2C_PRODUCT_ID = 0xD316;
static const size_t MAX_BULK_LEN = 0x5000;

struct libusb_context* g_usbctx;

std::vector<uint8_t> parseHex(const std::string& str) {
  std::vector<uint8_t> parsed;
  uint8_t b;
  bool halfbyte_pending = false;

  for (char c : str) {
    uint8_t hb;
    if ('0' <= c && c <= '9')
      hb = c - '0';
    else if ('a' <= c && c <= 'f')
      hb = c - 'a' + 0xa;
    else if ('A' <= c && c <= 'F')
      hb = c - 'A' + 0xa;
    else
      continue;

    if (!halfbyte_pending) {
      b = hb << 4;
      halfbyte_pending = true;
    } else {
      parsed.push_back(b | hb);
      halfbyte_pending = false;
    }
  }

  return parsed;
}

std::string stringPrintF(const char* fmt, ...) {
  va_list arg;
  char tmp[512]; // FIXME

  va_start(arg, fmt);
  vsprintf(tmp, fmt, arg);
  va_end(arg);

  return std::string(tmp);
}

std::string formatHex(const std::vector<uint8_t>& data) {
  // FIXME: not very efficient

  std::string ret;

  for (uint8_t b : data)
    ret += stringPrintF("%02x ", b);

  return std::move(ret);
}

std::vector<uint8_t> prepareTxData() {
  std::vector<uint8_t> txdata;

  if (FLAGS_hex != "") {
    txdata = parseHex(FLAGS_hex);
  }
  if (txdata.size() > MAX_BULK_LEN) {
    throw std::runtime_error("txdata too large!");
  }

  return txdata;
}

class LibUSBError : public std::runtime_error {
 public:
  LibUSBError(const char* context, int err)
      : std::runtime_error(stringPrintF("%s failed: %s", context, libusb_strerror(static_cast<libusb_error>(err)))) {}
};

class noncopyable {
 public:
  noncopyable() {}
  noncopyable(noncopyable&&) = default;
  noncopyable& operator=(noncopyable&&) = default;

 private:
  noncopyable(const noncopyable&) = delete;
  noncopyable& operator=(const noncopyable&) = delete;
};

class USBDeviceHandle : noncopyable {
 public:
  USBDeviceHandle(libusb_device* device) : device_(device) {
    int err = libusb_open(device, &devhandle_);
    if (err != 0) throw LibUSBError("libusb_open", err);
  }

  USBDeviceHandle(USBDeviceHandle&&) = default;

  ~USBDeviceHandle() {
    if (devhandle_) {
      if (claimed_)
        libusb_release_interface(devhandle_, 0);

      // FIXME: this crashes.
      // libusb_close(devhandle_);
    }
  }

  libusb_device_handle* get() { return devhandle_; }

  std::string getStringDescriptor(uint8_t index) {
    unsigned char tmp[32];
    int err =
        libusb_get_string_descriptor_ascii(devhandle_, index, tmp, sizeof(tmp));
    if (err < 0) throw LibUSBError("libusb_get_string_descriptor_ascii", err);

    return std::string(reinterpret_cast<char*>(tmp));
  }

  const libusb_device_descriptor& getDescriptor() {
    if (!fetched_descriptor_) {
      int err = libusb_get_device_descriptor(device_, &descriptor_);
      if (err < 0) throw LibUSBError("libusb_get_device_descriptor", err);
      fetched_descriptor_ = true;
    }

    return descriptor_;
  }

  void claim() {
    int err;
#if 0
    err = libusb_set_configuration(devhandle_, 0);
    if (err != 0) throw LibUSBError("libusb_set_configuration", err);

    err = libusb_set_auto_detach_kernel_driver(devhandle_, 1);
    if (err != 0) throw LibUSBError("libusb_set_auto_detach_kernel_driver", err);
#endif

    err = libusb_claim_interface(devhandle_, 0);
    if (err != 0) throw LibUSBError("libusb_claim_interface", err);

    claimed_ = true;
  }

  std::string getProductStringDescriptor() {
    return getStringDescriptor(getDescriptor().iProduct);
  }

  void sendBulk(const std::vector<uint8_t>& txdata) {
    sendBulk(txdata.data(), txdata.size());
  }
  void sendBulk(const uint8_t* data, size_t len);

  std::vector<uint8_t> recvBulk(size_t len);
  // std::vector<uint8_t> recvFeatureReportInterrupt(size_t len);

 private:
  libusb_device* device_ = nullptr;
  libusb_device_handle* devhandle_ = nullptr;
  bool claimed_ = false;
  bool fetched_descriptor_ = false;
  libusb_device_descriptor descriptor_;
  int timeout_ = 100;
};

void USBDeviceHandle::sendBulk(const uint8_t* data, size_t len) {
  if (len > MAX_BULK_LEN)
    throw std::runtime_error("txdata too long for a feature report");

  if (FLAGS_verbose) {
    printf("to: %d\n", timeout_);
    printf("Tx bulk: %s ... ",
           formatHex(std::vector<uint8_t>(data, data + len)).c_str());
    fflush(stdout);
  }

  int txlen = 0;
  int success = libusb_bulk_transfer(
      devhandle_, 0x01,
      const_cast<uint8_t*>(data), static_cast<uint16_t>(len), &txlen, timeout_);
  if (success < 0) throw LibUSBError("libusb_control_transfer Tx", txlen);
  if (txlen < len) throw std::runtime_error("sent data shorter than expected");
  if (FLAGS_verbose) printf("success!\n");
}

std::vector<uint8_t> USBDeviceHandle::recvBulk(size_t len) {
  std::vector<uint8_t> rxdata(len);

  if (FLAGS_verbose) {
    printf("Rx feature report... ");
    fflush(stdout);
  }
  int rxlen = 0;
  int success = libusb_bulk_transfer(
      devhandle_, 0x82,
      rxdata.data(), static_cast<uint16_t>(len),
      &rxlen, timeout_);
  if (success < 0) throw LibUSBError("libusb_control_transfer Rx", rxlen);
  if (rxlen < len)
    throw std::runtime_error("received data shorter than expected");
  if (FLAGS_verbose) printf("Success! Rx: %s\n", formatHex(rxdata).c_str());

  return std::move(rxdata);
}

#if 0
std::vector<uint8_t> USBDeviceHandle::recvFeatureReportInterrupt(size_t len) {
  std::vector<uint8_t> rxdata(len);

  static const int INTERRUPT_IN_ENDPOINT = 1;

  int ntx = 0;
  int err = libusb_interrupt_transfer(devhandle_, INTERRUPT_IN_ENDPOINT,
                                      rxdata.data(), static_cast<uint16_t>(len),
                                      &ntx, timeout_);
  if (err < 0) throw LibUSBError("libusb_interrupt_transfer Rx", err);

  return std::move(rxdata);
}
#endif

class USBDeviceList : noncopyable {
 public:
  USBDeviceList() {
    ndevices_ = libusb_get_device_list(g_usbctx, &list_);
    if (ndevices_ < 0) throw LibUSBError("libusb_get_device_list", ndevices_);
  }

  ~USBDeviceList() { ::libusb_free_device_list(list_, 1); }

  libusb_device** begin() { return list_; }
  libusb_device** end() { return list_ + ndevices_; }

 private:
  libusb_device** list_ = nullptr;
  ssize_t ndevices_;
};

USBDeviceHandle findDevice() {
  USBDeviceList list;
  for (libusb_device* device : list) {
    USBDeviceHandle devhandle(device);

    if (devhandle.getDescriptor().idVendor != USBI2C_VENDOR_ID) continue;
    if (devhandle.getDescriptor().idProduct != USBI2C_PRODUCT_ID) continue;
    // if (devhandle.getProductStringDescriptor() != "usbi2c") continue;
    printf("found device: %s\n", devhandle.getProductStringDescriptor().c_str());

    return std::move(devhandle);
  }

  throw std::runtime_error("device not found");
}

std::vector<uint8_t> doTest(USBDeviceHandle* devhandle,
                           std::vector<uint8_t> txdata) {
  if (FLAGS_verbose)
    printf("Sending test data: %s\n", formatHex(txdata).c_str());

  if (txdata.size() == 0)
    throw std::runtime_error("test txdata not specified.");

  if (txdata.size() > MAX_BULK_LEN)
    throw std::runtime_error("test txdata too long.");

  devhandle->sendBulk(txdata);
  std::vector<uint8_t> rxdata = devhandle->recvBulk(MAX_BULK_LEN);
  return std::move(rxdata);
}

int main(int argc, char* argv[]) {
  google::SetUsageMessage(
      std::string("dmixlpc test client.\n Usage: ") + argv[0]);
  google::ParseCommandLineFlags(&argc, &argv, true);

  try {
    if (libusb_init(&g_usbctx) != 0)
      throw std::runtime_error("libusb init failed");

    printf("ihoge!\n");
    USBDeviceHandle devhandle = findDevice();
    printf("try claim!\n");
    devhandle.claim();
    printf("claimed!\n");

    auto txdata = parseHex(FLAGS_hex);
    doTest(&devhandle, txdata);
  } catch (std::exception& e) {
    fprintf(stderr, "Error: %s\n", e.what());
    return 1;
  }

  libusb_exit(nullptr);
  return 0;
}
<commit_msg>bulk tx working<commit_after>#include <gflags/gflags.h>
#include <libusb-1.0/libusb.h>
#include <stdarg.h>
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <vector>

DEFINE_int32(verbose, 0, "increase verbosity");
DEFINE_bool(test, false, "test adaptor hardware");
DEFINE_string(hex, "", "sata to send in hex. e.g. \"de,ad,be,ef\"");

static const int USBI2C_VENDOR_ID = 0xF055;
static const int USBI2C_PRODUCT_ID = 0xD316;
static const size_t MAX_BULK_LEN = 0x5000;

struct libusb_context* g_usbctx;

std::vector<uint8_t> parseHex(const std::string& str) {
  std::vector<uint8_t> parsed;
  uint8_t b;
  bool halfbyte_pending = false;

  for (char c : str) {
    uint8_t hb;
    if ('0' <= c && c <= '9')
      hb = c - '0';
    else if ('a' <= c && c <= 'f')
      hb = c - 'a' + 0xa;
    else if ('A' <= c && c <= 'F')
      hb = c - 'A' + 0xa;
    else
      continue;

    if (!halfbyte_pending) {
      b = hb << 4;
      halfbyte_pending = true;
    } else {
      parsed.push_back(b | hb);
      halfbyte_pending = false;
    }
  }

  return parsed;
}

std::string stringPrintF(const char* fmt, ...) {
  va_list arg;
  char tmp[512]; // FIXME

  va_start(arg, fmt);
  vsprintf(tmp, fmt, arg);
  va_end(arg);

  return std::string(tmp);
}

std::string formatHex(const std::vector<uint8_t>& data) {
  // FIXME: not very efficient

  std::string ret;

  for (uint8_t b : data)
    ret += stringPrintF("%02x ", b);

  return std::move(ret);
}

std::vector<uint8_t> prepareTxData() {
  std::vector<uint8_t> txdata;

  if (FLAGS_hex != "") {
    txdata = parseHex(FLAGS_hex);
  }
  if (txdata.size() > MAX_BULK_LEN) {
    throw std::runtime_error("txdata too large!");
  }

  return txdata;
}

class LibUSBError : public std::runtime_error {
 public:
  LibUSBError(const char* context, int err)
      : std::runtime_error(stringPrintF("%s failed: %s", context, libusb_strerror(static_cast<libusb_error>(err)))) {}
};

class noncopyable {
 public:
  noncopyable() {}
  noncopyable(noncopyable&&) = default;
  noncopyable& operator=(noncopyable&&) = default;

 private:
  noncopyable(const noncopyable&) = delete;
  noncopyable& operator=(const noncopyable&) = delete;
};

class USBDeviceHandle : noncopyable {
 public:
  USBDeviceHandle(libusb_device* device) : device_(device) {
    int err = libusb_open(device, &devhandle_);
    if (err != 0) throw LibUSBError("libusb_open", err);
  }

  USBDeviceHandle(USBDeviceHandle&&) = default;

  ~USBDeviceHandle() {
    if (devhandle_) {
      if (claimed_)
        libusb_release_interface(devhandle_, 0);

      // FIXME: this crashes.
      // libusb_close(devhandle_);
    }
  }

  libusb_device_handle* get() { return devhandle_; }

  std::string getStringDescriptor(uint8_t index) {
    unsigned char tmp[32];
    int err =
        libusb_get_string_descriptor_ascii(devhandle_, index, tmp, sizeof(tmp));
    if (err < 0) throw LibUSBError("libusb_get_string_descriptor_ascii", err);

    return std::string(reinterpret_cast<char*>(tmp));
  }

  const libusb_device_descriptor& getDescriptor() {
    if (!fetched_descriptor_) {
      int err = libusb_get_device_descriptor(device_, &descriptor_);
      if (err < 0) throw LibUSBError("libusb_get_device_descriptor", err);
      fetched_descriptor_ = true;
    }

    return descriptor_;
  }

  void claim() {
    int err;
#if 0
    err = libusb_set_configuration(devhandle_, 0);
    if (err != 0) throw LibUSBError("libusb_set_configuration", err);

    err = libusb_set_auto_detach_kernel_driver(devhandle_, 1);
    if (err != 0) throw LibUSBError("libusb_set_auto_detach_kernel_driver", err);
#endif

    err = libusb_claim_interface(devhandle_, 0);
    if (err != 0) throw LibUSBError("libusb_claim_interface", err);

    claimed_ = true;
  }

  std::string getProductStringDescriptor() {
    return getStringDescriptor(getDescriptor().iProduct);
  }

  void sendBulk(const std::vector<uint8_t>& txdata) {
    sendBulk(txdata.data(), txdata.size());
  }
  void sendBulk(const uint8_t* data, size_t len);

  std::vector<uint8_t> recvBulk(size_t len);
  // std::vector<uint8_t> recvFeatureReportInterrupt(size_t len);

 private:
  libusb_device* device_ = nullptr;
  libusb_device_handle* devhandle_ = nullptr;
  bool claimed_ = false;
  bool fetched_descriptor_ = false;
  libusb_device_descriptor descriptor_;
  int timeout_ = 100;
};

void USBDeviceHandle::sendBulk(const uint8_t* data, size_t len) {
  if (len > MAX_BULK_LEN)
    throw std::runtime_error("txdata too long for a bulk tx");

  if (FLAGS_verbose) {
    printf("Tx bulk: %s ... ",
           formatHex(std::vector<uint8_t>(data, data + len)).c_str());
    fflush(stdout);
  }

  int txlen = 0;
  int success = libusb_bulk_transfer(
      devhandle_, 0x01,
      const_cast<uint8_t*>(data), static_cast<uint16_t>(len), &txlen, timeout_);
  if (success < 0) throw LibUSBError("libusb_bulk_transfer Tx", success);
  if (txlen < len) throw std::runtime_error("sent data shorter than expected");
  if (FLAGS_verbose) printf("success!\n");
}

std::vector<uint8_t> USBDeviceHandle::recvBulk(size_t len) {
  std::vector<uint8_t> rxdata(len);

  if (FLAGS_verbose) {
    printf("Rx bulk... ");
    fflush(stdout);
  }
  int rxlen = 0;
  int success = libusb_bulk_transfer(
      devhandle_, 0x81,
      rxdata.data(), static_cast<uint16_t>(len),
      &rxlen, timeout_);
  if (success < 0) throw LibUSBError("libusb_bulk_transfer Rx", success);
  rxdata.resize(rxlen);
  if (FLAGS_verbose) printf("Success! Rx: %s\n", formatHex(rxdata).c_str());

  return std::move(rxdata);
}

#if 0
std::vector<uint8_t> USBDeviceHandle::recvFeatureReportInterrupt(size_t len) {
  std::vector<uint8_t> rxdata(len);

  static const int INTERRUPT_IN_ENDPOINT = 1;

  int ntx = 0;
  int err = libusb_interrupt_transfer(devhandle_, INTERRUPT_IN_ENDPOINT,
                                      rxdata.data(), static_cast<uint16_t>(len),
                                      &ntx, timeout_);
  if (err < 0) throw LibUSBError("libusb_interrupt_transfer Rx", err);

  return std::move(rxdata);
}
#endif

class USBDeviceList : noncopyable {
 public:
  USBDeviceList() {
    ndevices_ = libusb_get_device_list(g_usbctx, &list_);
    if (ndevices_ < 0) throw LibUSBError("libusb_get_device_list", ndevices_);
  }

  ~USBDeviceList() { ::libusb_free_device_list(list_, 1); }

  libusb_device** begin() { return list_; }
  libusb_device** end() { return list_ + ndevices_; }

 private:
  libusb_device** list_ = nullptr;
  ssize_t ndevices_;
};

USBDeviceHandle findDevice() {
  USBDeviceList list;
  for (libusb_device* device : list) {
    USBDeviceHandle devhandle(device);

    if (devhandle.getDescriptor().idVendor != USBI2C_VENDOR_ID) continue;
    if (devhandle.getDescriptor().idProduct != USBI2C_PRODUCT_ID) continue;
    if (devhandle.getProductStringDescriptor() != "dmix_lpc") continue;

    return std::move(devhandle);
  }

  throw std::runtime_error("device not found");
}

std::vector<uint8_t> doTest(USBDeviceHandle* devhandle,
                           std::vector<uint8_t> txdata) {
  if (FLAGS_verbose)
    printf("Sending test data: %s\n", formatHex(txdata).c_str());

  if (txdata.size() == 0)
    throw std::runtime_error("test txdata not specified.");

  if (txdata.size() > MAX_BULK_LEN)
    throw std::runtime_error("test txdata too long.");

  devhandle->sendBulk(txdata);
  sleep(1);
  std::vector<uint8_t> rxdata = devhandle->recvBulk(4096);
  return std::move(rxdata);
}

int main(int argc, char* argv[]) {
  google::SetUsageMessage(
      std::string("dmixlpc test client.\n Usage: ") + argv[0]);
  google::ParseCommandLineFlags(&argc, &argv, true);

  try {
    if (libusb_init(&g_usbctx) != 0)
      throw std::runtime_error("libusb init failed");

    printf("ihoge!\n");
    USBDeviceHandle devhandle = findDevice();
    printf("try claim!\n");
    devhandle.claim();
    printf("claimed!\n");

    auto txdata = parseHex(FLAGS_hex);
    doTest(&devhandle, txdata);
  } catch (std::exception& e) {
    fprintf(stderr, "Error: %s\n", e.what());
    return 1;
  }

  libusb_exit(nullptr);
  return 0;
}
<|endoftext|>


<commit_before>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2012, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "LPanel.h"
#include "LSession.h"
#include "panel-plugins/systemtray/LSysTray.h"

LPanel::LPanel(QSettings *file, int scr, int num, QWidget *parent) : QWidget(){
  //Take care of inputs
  qDebug() << " - Creating Panel:" << scr << num;
  bgWindow = parent; //save for later
  //Setup the widget overlay for the entire panel to provide transparency effects
  panelArea = new QWidget(this);
  QBoxLayout *tmp = new QBoxLayout(QBoxLayout::LeftToRight);
	tmp->setContentsMargins(0,0,0,0);
	this->setLayout(tmp);
	tmp->addWidget(panelArea);
  settings = file;
  screennum = scr;
  screen = LSession::desktop();
  PPREFIX = "panel"+QString::number(screennum)+"."+QString::number(num)+"/";
  defaultpanel = (screen->screenGeometry(screennum).x()==0 && num==0);
  //if(settings->value("defaultpanel",QString::number(screen->primaryScreen())+".0").toString()==QString::number(screennum)+"."+QString::number(num) ){ defaultpanel=true;}
  //else{defaultpanel=false; }
  horizontal=true; //use this by default initially
  hidden = false; //use this by default
  //Setup the panel
  qDebug() << " -- Setup Panel";
  this->setContentsMargins(0,0,0,0);
  this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  //panels cannot get keyboard focus otherwise it upsets the task manager window detection
  this->setAttribute(Qt::WA_X11DoNotAcceptFocus);
  this->setAttribute(Qt::WA_X11NetWmWindowTypeDock);
  this->setAttribute(Qt::WA_AlwaysShowToolTips);
  this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);

  this->setWindowTitle("LuminaPanel");
  this->setObjectName("LuminaPanelBackgroundWidget");
  this->setStyleSheet("QToolButton::menu-indicator{ image: none; }");
  panelArea->setObjectName("LuminaPanelColor");
  layout = new QBoxLayout(QBoxLayout::LeftToRight);
    layout->setContentsMargins(0,0,0,0);
    layout->setSpacing(1);
    //layout->setSizeConstraint(QLayout::SetFixedSize);
  panelArea->setLayout(layout);
  //Set special window flags on the panel for proper usage
  this->show();
  //this->setFocusPolicy(Qt::NoFocus);
  //LSession::handle()->XCB->SetAsSticky(this->winId());
  //LSession::handle()->XCB->SetAsPanel(this->winId());  //make sure this happens after Qt creates the window first
  LX11::SetAsPanel(this->winId());

  QTimer::singleShot(1,this, SLOT(UpdatePanel()) ); //start this in a new thread
  connect(screen, SIGNAL(resized(int)), this, SLOT(UpdatePanel()) ); //in case the screen resolution changes
}

LPanel::~LPanel(){

}

//===========
// PUBLIC SLOTS
//===========
void LPanel::UpdatePanel(){
  //Create/Update the panel as designated in the Settings file
  settings->sync(); //make sure to catch external settings changes
  //First set the geometry of the panel and send the EWMH message to reserve that space
  qDebug() << "Update Panel";
  hidden = settings->value(PPREFIX+"hidepanel",false).toBool(); //default to true for the moment
  QString loc = settings->value(PPREFIX+"location","").toString();
  if(loc.isEmpty() && defaultpanel){ loc="top"; }
  if(loc=="top" || loc=="bottom"){
    horizontal=true;
    layout->setAlignment(Qt::AlignLeft);
    layout->setDirection(QBoxLayout::LeftToRight);
  }else{
    horizontal=false;
    layout->setAlignment(Qt::AlignTop);
    layout->setDirection(QBoxLayout::TopToBottom);
  }
  int ht = settings->value(PPREFIX+"height", 30).toInt(); //this is technically the distance into the screen from the edge
  //qDebug() << " - set Geometry";
  int xwid = screen->screenGeometry(screennum).width();
  int xhi = screen->screenGeometry(screennum).height();
  int xloc = screen->screenGeometry(screennum).x();
  //xloc=xoffset;
  if(loc=="top"){ //top of screen
    QSize sz = QSize(xwid, ht);
    this->setMinimumSize(sz);
    this->setMaximumSize(sz);
    this->setGeometry(xloc,0,xwid, ht );
    if(!hidden){ LX11::ReservePanelLocation(this->winId(), xloc, 0, this->width(), ht, "top"); }
    else{
      LX11::ReservePanelLocation(this->winId(), xloc, 0, this->width(), 2, "top");
      hidepoint = QPoint(xloc, 2-ht);
      showpoint = QPoint(xloc, 0);
      this->move(hidepoint); //Could bleed over onto the screen above
    }
  }else if(loc=="bottom"){ //bottom of screen
    QSize sz = QSize(xwid, ht);
    this->setMinimumSize(sz);
    this->setMaximumSize(sz);
    this->setGeometry(xloc,xhi-ht,xwid, ht );
    if(!hidden){ LX11::ReservePanelLocation(this->winId(), xloc, xhi-ht, this->width(), ht, "bottom"); }
    else{
      LX11::ReservePanelLocation(this->winId(), xloc, xhi-2, this->width(), 2, "bottom");
      hidepoint = QPoint(xloc, xhi-2);
      showpoint = QPoint(xloc, xhi-ht);
      this->move(hidepoint); //Could bleed over onto the screen below
    }
  }else if(loc=="left"){ //left side of screen
    QSize sz = QSize(ht, xhi);
    this->setMinimumSize(sz);
    this->setMaximumSize(sz);
    this->setGeometry(xloc,0, ht, xhi);
    if(!hidden){ LX11::ReservePanelLocation(this->winId(), xloc, 0, ht, xhi, "left"); }
    else{
      LX11::ReservePanelLocation(this->winId(), xloc, 0, 2, xhi, "left");
      hidepoint = QPoint(xloc-ht+2, 0);
      showpoint = QPoint(xloc, 0);
      this->move(hidepoint); //Could bleed over onto the screen left
    }
  }else{ //right side of screen
    QSize sz = QSize(ht, xhi);
    this->setMinimumSize(sz);
    this->setMaximumSize(sz);
    this->setGeometry(xloc+xwid-ht,0,ht, xhi);
    if(!hidden){ LX11::ReservePanelLocation(this->winId(), xloc+xwid-ht, 0, ht, xhi, "right"); }
    else{
      LX11::ReservePanelLocation(this->winId(), xloc+xwid-2, 0, 2, xhi, "right");
      hidepoint = QPoint(xloc+xwid-2, 0);
      showpoint = QPoint(xloc+xwid-ht, 0);
      this->move(hidepoint); //Could bleed over onto the screen right
    }
  }
  //With QT5, we need to make sure to reset window properties on occasion
  //LSession::handle()->XCB->SetAsSticky(this->winId());
  //LX11::SetAsPanel(this->winId());
  //First test/update all the window attributes as necessary
  //if(!this->testAttribute(Qt::WA_X11DoNotAcceptFocus)){ this->setAttribute(Qt::WA_X11DoNotAcceptFocus); }
  //if(!this->testAttribute(Qt::WA_X11NetWmWindowTypeDock)){ this->setAttribute(Qt::WA_X11NetWmWindowTypeDock); }
  //if(!this->testAttribute(Qt::WA_AlwaysShowToolTips)){ this->setAttribute(Qt::WA_AlwaysShowToolTips); }

  //Now update the appearance of the toolbar
  if(settings->value(PPREFIX+"customcolor", false).toBool()){
    QString color = settings->value(PPREFIX+"color", "rgba(255,255,255,160)").toString();
    QString style = "QWidget#LuminaPanelColor{ background: %1; border-radius: 3px; border: 1px solid %1; }";
    style = style.arg(color);
    panelArea->setStyleSheet(style);
  }else{
    panelArea->setStyleSheet(""); //clear it and use the one from the theme
  }

  //Then go through the plugins and create them as necessary
  QStringList plugins = settings->value(PPREFIX+"pluginlist", QStringList()).toStringList();
  if(defaultpanel && plugins.isEmpty()){
    plugins << "userbutton" << "taskmanager" << "spacer" << "systemtray" << "clock" << "systemdashboard";
  }
  qDebug() << " - Initialize Plugins: " << plugins;
  for(int i=0; i<plugins.length(); i++){
    //Ensure this plugin has a unique ID (NOTE: this numbering does not persist between sessions)
    if(!plugins[i].contains("---")){
      int num=1;
      while( plugins.contains(plugins[i]+"---"+QString::number(screennum)+"."+QString::number(this->number())+"."+QString::number(num)) ){
        num++;
      }

      plugins[i] = plugins[i]+"---"+QString::number(screennum)+"."+QString::number(this->number())+"."+QString::number(num);
      //qDebug() << "Adjust Plugin ID:" << plugins[i];
    }
    //See if this plugin is already there or in a different spot
    bool found = false;
    for(int p=0; p<PLUGINS.length(); p++){
      if(PLUGINS[p]->type()==plugins[i]){
        found = true; //already exists
	//Make sure the plugin layout has the correct orientation
	if(horizontal){PLUGINS[p]->layout()->setDirection(QBoxLayout::LeftToRight); }
	else{ PLUGINS[p]->layout()->setDirection(QBoxLayout::TopToBottom); }
	QTimer::singleShot(0,PLUGINS[p], SLOT( OrientationChange() ) );
	//Now check the location of the plugin in the panel
	if(p!=i){ //wrong place in the panel
	  layout->takeAt(p); //remove the item from the current location
	  layout->insertWidget(i, PLUGINS[p]); //add the item into the correct location
	  PLUGINS.move(p,i); //move the identifier in the list to match
	}
	break;
      }
    }
    if(!found){
      //New Plugin
      qDebug() << " -- New Plugin:" << plugins[i] << i;
      LPPlugin *plug = NewPP::createPlugin(plugins[i], panelArea, horizontal);
      if(plug != 0){
        PLUGINS.insert(i, plug);
        layout->insertWidget(i, PLUGINS[i]);
      }else{
        //invalid plugin type
	plugins.removeAt(i); //remove this invalid plugin from the list
	i--; //make sure we don't miss the next item with the re-order
      }
    }
    LSession::processEvents();
  }
  //Now remove any extra plugins from the end
  //qDebug() << "plugins:" << plugins;
  //qDebug() << "PLUGINS length:" << PLUGINS.length();
  for(int i=0; i<PLUGINS.length(); i++){
    if(plugins.contains(PLUGINS[i]->type())){ continue; } //good plugin - skip it
    qDebug() << " -- Remove Plugin: " << PLUGINS[i]->type();
    //If this is the system tray - stop it first
    if( PLUGINS[i]->type().startsWith("systemtray---") ){
      static_cast<LSysTray*>(PLUGINS[i])->stop();
    }
    layout->takeAt(i); //remove from the layout
    delete PLUGINS.takeAt(i); //delete the actual widget
    LSession::processEvents();
    i--; //need to back up one space to not miss another plugin
  }
  this->update();
  this->show(); //make sure the panel is visible now
  if(hidden){ this->move(hidepoint); }
  //Now go through and send the orientation update signal to each plugin
  for(int i=0; i<PLUGINS.length(); i++){
    QTimer::singleShot(0,PLUGINS[i], SLOT(OrientationChange()));
  }
  LSession::processEvents();
}

void LPanel::UpdateLocale(){
  //The panel itself has no text to translate, just forward the signal to all the plugins
  for(int i=0; i<PLUGINS.length(); i++){
    QTimer::singleShot(1,PLUGINS[i], SLOT(LocaleChange()));
  }
}

void LPanel::UpdateTheme(){
  //The panel itself has no theme-based icons, just forward the signal to all the plugins
  for(int i=0; i<PLUGINS.length(); i++){
    QTimer::singleShot(1,PLUGINS[i], SLOT(ThemeChange()));
  }
}

//===========
// PROTECTED
//===========
void LPanel::paintEvent(QPaintEvent *event){
  QPainter *painter = new QPainter(this);
  //Make sure the base background of the event rectangle is the associated rectangle from the BGWindow
  QRect rec(event->rect().x(), event->rect().y(), event->rect().width(), event->rect().height()); //already in global coords? (translating to bgWindow coords crashes Lumina)
  //Need to translate that rectangle to the background image coordinates
  //qDebug() << "Rec:" << rec.x() << rec.y();
  //Need to change to global coords for the main window
  if(hidden && (this->pos()==hidepoint) ){ rec.moveTo( this->mapToGlobal(rec.topLeft()-hidepoint+showpoint) ); }
  else{ rec.moveTo( this->mapToGlobal(rec.topLeft()) ); }
  //qDebug() << "Global Rec:" << rec.x() << rec.y() << screennum;
  rec.moveTo( rec.x()-screen->screenGeometry(screennum).x(), rec.y() );
  //qDebug() << "Adjusted Global Rec:" << rec.x() << rec.y();
  painter->drawPixmap(event->rect(), bgWindow->grab(rec) );
  QWidget::paintEvent(event); //now pass the event along to the normal painting event
}

void LPanel::enterEvent(QEvent *event){
  //qDebug() << "Panel Enter Event:";
  if(hidden){
    //Move the panel out so it is fully available
    this->move(showpoint);
  }
  event->accept(); //just to quiet the compile warning
}

void LPanel::leaveEvent(QEvent *event){
  /*qDebug() << "Panel Leave Event:";
  qDebug() << "Panel Geom:" << this->geometry().x() << this->geometry().y() << this->geometry().width() << this->geometry().height() ;
  QPoint pt = QCursor::pos();
  qDebug() << "Mouse Point (global):" << pt.x() << pt.y();
  //pt = this->mapFromGlobal(pt);
  //qDebug() << "Mouse Point (local):" << pt.x() << pt.y();
  qDebug() << "Contained:" << this->geometry().contains(pt);*/
  if(hidden && !this->geometry().contains(QCursor::pos()) ){
    //Move the panel back to it's "hiding" spot
    this->move(hidepoint);
  }
  event->accept(); //just to quiet the compile warning
}

<commit_msg>Make sure that the panel has the "sticky" flag set. This ensures that it is consistant across all workspaces.<commit_after>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2012, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "LPanel.h"
#include "LSession.h"
#include "panel-plugins/systemtray/LSysTray.h"

LPanel::LPanel(QSettings *file, int scr, int num, QWidget *parent) : QWidget(){
  //Take care of inputs
  qDebug() << " - Creating Panel:" << scr << num;
  bgWindow = parent; //save for later
  //Setup the widget overlay for the entire panel to provide transparency effects
  panelArea = new QWidget(this);
  QBoxLayout *tmp = new QBoxLayout(QBoxLayout::LeftToRight);
	tmp->setContentsMargins(0,0,0,0);
	this->setLayout(tmp);
	tmp->addWidget(panelArea);
  settings = file;
  screennum = scr;
  screen = LSession::desktop();
  PPREFIX = "panel"+QString::number(screennum)+"."+QString::number(num)+"/";
  defaultpanel = (screen->screenGeometry(screennum).x()==0 && num==0);
  //if(settings->value("defaultpanel",QString::number(screen->primaryScreen())+".0").toString()==QString::number(screennum)+"."+QString::number(num) ){ defaultpanel=true;}
  //else{defaultpanel=false; }
  horizontal=true; //use this by default initially
  hidden = false; //use this by default
  //Setup the panel
  qDebug() << " -- Setup Panel";
  this->setContentsMargins(0,0,0,0);
  this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  //panels cannot get keyboard focus otherwise it upsets the task manager window detection
  this->setAttribute(Qt::WA_X11DoNotAcceptFocus);
  this->setAttribute(Qt::WA_X11NetWmWindowTypeDock);
  this->setAttribute(Qt::WA_AlwaysShowToolTips);
  this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);

  this->setWindowTitle("LuminaPanel");
  this->setObjectName("LuminaPanelBackgroundWidget");
  this->setStyleSheet("QToolButton::menu-indicator{ image: none; }");
  panelArea->setObjectName("LuminaPanelColor");
  layout = new QBoxLayout(QBoxLayout::LeftToRight);
    layout->setContentsMargins(0,0,0,0);
    layout->setSpacing(1);
    //layout->setSizeConstraint(QLayout::SetFixedSize);
  panelArea->setLayout(layout);
  //Set special window flags on the panel for proper usage
  this->show();
  //this->setFocusPolicy(Qt::NoFocus);
  LSession::handle()->XCB->SetAsSticky(this->winId());
  //LSession::handle()->XCB->SetAsPanel(this->winId());
  LX11::SetAsPanel(this->winId());

  QTimer::singleShot(1,this, SLOT(UpdatePanel()) ); //start this in a new thread
  connect(screen, SIGNAL(resized(int)), this, SLOT(UpdatePanel()) ); //in case the screen resolution changes
}

LPanel::~LPanel(){

}

//===========
// PUBLIC SLOTS
//===========
void LPanel::UpdatePanel(){
  //Create/Update the panel as designated in the Settings file
  settings->sync(); //make sure to catch external settings changes
  //First set the geometry of the panel and send the EWMH message to reserve that space
  qDebug() << "Update Panel";
  hidden = settings->value(PPREFIX+"hidepanel",false).toBool(); //default to true for the moment
  QString loc = settings->value(PPREFIX+"location","").toString();
  if(loc.isEmpty() && defaultpanel){ loc="top"; }
  if(loc=="top" || loc=="bottom"){
    horizontal=true;
    layout->setAlignment(Qt::AlignLeft);
    layout->setDirection(QBoxLayout::LeftToRight);
  }else{
    horizontal=false;
    layout->setAlignment(Qt::AlignTop);
    layout->setDirection(QBoxLayout::TopToBottom);
  }
  int ht = settings->value(PPREFIX+"height", 30).toInt(); //this is technically the distance into the screen from the edge
  //qDebug() << " - set Geometry";
  int xwid = screen->screenGeometry(screennum).width();
  int xhi = screen->screenGeometry(screennum).height();
  int xloc = screen->screenGeometry(screennum).x();
  //xloc=xoffset;
  if(loc=="top"){ //top of screen
    QSize sz = QSize(xwid, ht);
    this->setMinimumSize(sz);
    this->setMaximumSize(sz);
    this->setGeometry(xloc,0,xwid, ht );
    if(!hidden){ LX11::ReservePanelLocation(this->winId(), xloc, 0, this->width(), ht, "top"); }
    else{
      LX11::ReservePanelLocation(this->winId(), xloc, 0, this->width(), 2, "top");
      hidepoint = QPoint(xloc, 2-ht);
      showpoint = QPoint(xloc, 0);
      this->move(hidepoint); //Could bleed over onto the screen above
    }
  }else if(loc=="bottom"){ //bottom of screen
    QSize sz = QSize(xwid, ht);
    this->setMinimumSize(sz);
    this->setMaximumSize(sz);
    this->setGeometry(xloc,xhi-ht,xwid, ht );
    if(!hidden){ LX11::ReservePanelLocation(this->winId(), xloc, xhi-ht, this->width(), ht, "bottom"); }
    else{
      LX11::ReservePanelLocation(this->winId(), xloc, xhi-2, this->width(), 2, "bottom");
      hidepoint = QPoint(xloc, xhi-2);
      showpoint = QPoint(xloc, xhi-ht);
      this->move(hidepoint); //Could bleed over onto the screen below
    }
  }else if(loc=="left"){ //left side of screen
    QSize sz = QSize(ht, xhi);
    this->setMinimumSize(sz);
    this->setMaximumSize(sz);
    this->setGeometry(xloc,0, ht, xhi);
    if(!hidden){ LX11::ReservePanelLocation(this->winId(), xloc, 0, ht, xhi, "left"); }
    else{
      LX11::ReservePanelLocation(this->winId(), xloc, 0, 2, xhi, "left");
      hidepoint = QPoint(xloc-ht+2, 0);
      showpoint = QPoint(xloc, 0);
      this->move(hidepoint); //Could bleed over onto the screen left
    }
  }else{ //right side of screen
    QSize sz = QSize(ht, xhi);
    this->setMinimumSize(sz);
    this->setMaximumSize(sz);
    this->setGeometry(xloc+xwid-ht,0,ht, xhi);
    if(!hidden){ LX11::ReservePanelLocation(this->winId(), xloc+xwid-ht, 0, ht, xhi, "right"); }
    else{
      LX11::ReservePanelLocation(this->winId(), xloc+xwid-2, 0, 2, xhi, "right");
      hidepoint = QPoint(xloc+xwid-2, 0);
      showpoint = QPoint(xloc+xwid-ht, 0);
      this->move(hidepoint); //Could bleed over onto the screen right
    }
  }
  //With QT5, we need to make sure to reset window properties on occasion
  //LSession::handle()->XCB->SetAsSticky(this->winId());
  //LX11::SetAsPanel(this->winId());
  //First test/update all the window attributes as necessary
  //if(!this->testAttribute(Qt::WA_X11DoNotAcceptFocus)){ this->setAttribute(Qt::WA_X11DoNotAcceptFocus); }
  //if(!this->testAttribute(Qt::WA_X11NetWmWindowTypeDock)){ this->setAttribute(Qt::WA_X11NetWmWindowTypeDock); }
  //if(!this->testAttribute(Qt::WA_AlwaysShowToolTips)){ this->setAttribute(Qt::WA_AlwaysShowToolTips); }

  //Now update the appearance of the toolbar
  if(settings->value(PPREFIX+"customcolor", false).toBool()){
    QString color = settings->value(PPREFIX+"color", "rgba(255,255,255,160)").toString();
    QString style = "QWidget#LuminaPanelColor{ background: %1; border-radius: 3px; border: 1px solid %1; }";
    style = style.arg(color);
    panelArea->setStyleSheet(style);
  }else{
    panelArea->setStyleSheet(""); //clear it and use the one from the theme
  }

  //Then go through the plugins and create them as necessary
  QStringList plugins = settings->value(PPREFIX+"pluginlist", QStringList()).toStringList();
  if(defaultpanel && plugins.isEmpty()){
    plugins << "userbutton" << "taskmanager" << "spacer" << "systemtray" << "clock" << "systemdashboard";
  }
  qDebug() << " - Initialize Plugins: " << plugins;
  for(int i=0; i<plugins.length(); i++){
    //Ensure this plugin has a unique ID (NOTE: this numbering does not persist between sessions)
    if(!plugins[i].contains("---")){
      int num=1;
      while( plugins.contains(plugins[i]+"---"+QString::number(screennum)+"."+QString::number(this->number())+"."+QString::number(num)) ){
        num++;
      }

      plugins[i] = plugins[i]+"---"+QString::number(screennum)+"."+QString::number(this->number())+"."+QString::number(num);
      //qDebug() << "Adjust Plugin ID:" << plugins[i];
    }
    //See if this plugin is already there or in a different spot
    bool found = false;
    for(int p=0; p<PLUGINS.length(); p++){
      if(PLUGINS[p]->type()==plugins[i]){
        found = true; //already exists
	//Make sure the plugin layout has the correct orientation
	if(horizontal){PLUGINS[p]->layout()->setDirection(QBoxLayout::LeftToRight); }
	else{ PLUGINS[p]->layout()->setDirection(QBoxLayout::TopToBottom); }
	QTimer::singleShot(0,PLUGINS[p], SLOT( OrientationChange() ) );
	//Now check the location of the plugin in the panel
	if(p!=i){ //wrong place in the panel
	  layout->takeAt(p); //remove the item from the current location
	  layout->insertWidget(i, PLUGINS[p]); //add the item into the correct location
	  PLUGINS.move(p,i); //move the identifier in the list to match
	}
	break;
      }
    }
    if(!found){
      //New Plugin
      qDebug() << " -- New Plugin:" << plugins[i] << i;
      LPPlugin *plug = NewPP::createPlugin(plugins[i], panelArea, horizontal);
      if(plug != 0){
        PLUGINS.insert(i, plug);
        layout->insertWidget(i, PLUGINS[i]);
      }else{
        //invalid plugin type
	plugins.removeAt(i); //remove this invalid plugin from the list
	i--; //make sure we don't miss the next item with the re-order
      }
    }
    LSession::processEvents();
  }
  //Now remove any extra plugins from the end
  //qDebug() << "plugins:" << plugins;
  //qDebug() << "PLUGINS length:" << PLUGINS.length();
  for(int i=0; i<PLUGINS.length(); i++){
    if(plugins.contains(PLUGINS[i]->type())){ continue; } //good plugin - skip it
    qDebug() << " -- Remove Plugin: " << PLUGINS[i]->type();
    //If this is the system tray - stop it first
    if( PLUGINS[i]->type().startsWith("systemtray---") ){
      static_cast<LSysTray*>(PLUGINS[i])->stop();
    }
    layout->takeAt(i); //remove from the layout
    delete PLUGINS.takeAt(i); //delete the actual widget
    LSession::processEvents();
    i--; //need to back up one space to not miss another plugin
  }
  this->update();
  this->show(); //make sure the panel is visible now
  if(hidden){ this->move(hidepoint); }
  //Now go through and send the orientation update signal to each plugin
  for(int i=0; i<PLUGINS.length(); i++){
    QTimer::singleShot(0,PLUGINS[i], SLOT(OrientationChange()));
  }
  LSession::processEvents();
}

void LPanel::UpdateLocale(){
  //The panel itself has no text to translate, just forward the signal to all the plugins
  for(int i=0; i<PLUGINS.length(); i++){
    QTimer::singleShot(1,PLUGINS[i], SLOT(LocaleChange()));
  }
}

void LPanel::UpdateTheme(){
  //The panel itself has no theme-based icons, just forward the signal to all the plugins
  for(int i=0; i<PLUGINS.length(); i++){
    QTimer::singleShot(1,PLUGINS[i], SLOT(ThemeChange()));
  }
}

//===========
// PROTECTED
//===========
void LPanel::paintEvent(QPaintEvent *event){
  QPainter *painter = new QPainter(this);
  //Make sure the base background of the event rectangle is the associated rectangle from the BGWindow
  QRect rec(event->rect().x(), event->rect().y(), event->rect().width(), event->rect().height()); //already in global coords? (translating to bgWindow coords crashes Lumina)
  //Need to translate that rectangle to the background image coordinates
  //qDebug() << "Rec:" << rec.x() << rec.y();
  //Need to change to global coords for the main window
  if(hidden && (this->pos()==hidepoint) ){ rec.moveTo( this->mapToGlobal(rec.topLeft()-hidepoint+showpoint) ); }
  else{ rec.moveTo( this->mapToGlobal(rec.topLeft()) ); }
  //qDebug() << "Global Rec:" << rec.x() << rec.y() << screennum;
  rec.moveTo( rec.x()-screen->screenGeometry(screennum).x(), rec.y() );
  //qDebug() << "Adjusted Global Rec:" << rec.x() << rec.y();
  painter->drawPixmap(event->rect(), bgWindow->grab(rec) );
  QWidget::paintEvent(event); //now pass the event along to the normal painting event
}

void LPanel::enterEvent(QEvent *event){
  //qDebug() << "Panel Enter Event:";
  if(hidden){
    //Move the panel out so it is fully available
    this->move(showpoint);
  }
  event->accept(); //just to quiet the compile warning
}

void LPanel::leaveEvent(QEvent *event){
  /*qDebug() << "Panel Leave Event:";
  qDebug() << "Panel Geom:" << this->geometry().x() << this->geometry().y() << this->geometry().width() << this->geometry().height() ;
  QPoint pt = QCursor::pos();
  qDebug() << "Mouse Point (global):" << pt.x() << pt.y();
  //pt = this->mapFromGlobal(pt);
  //qDebug() << "Mouse Point (local):" << pt.x() << pt.y();
  qDebug() << "Contained:" << this->geometry().contains(pt);*/
  if(hidden && !this->geometry().contains(QCursor::pos()) ){
    //Move the panel back to it's "hiding" spot
    this->move(hidepoint);
  }
  event->accept(); //just to quiet the compile warning
}

<|endoftext|>


<commit_before>/***
 * @file nca_test.cc
 * @author Ryan Curtin
 *
 * Unit tests for Neighborhood Components Analysis and related code (including
 * the softmax error function).
 */
#include <fastlib/fastlib.h>
#include <mlpack/core/kernels/lmetric.h>
#include "nca.h"

#define BOOST_TEST_MODULE Neighborhood Components Analysis Test
#include <boost/test/unit_test.hpp>

using namespace mlpack;
using namespace mlpack::kernel;
using namespace mlpack::nca;

/***
 * The Softmax error function should return the identity matrix as its initial
 * point.
 */
BOOST_AUTO_TEST_CASE(softmax_initial_point) {
  // Cheap fake dataset.
  arma::mat data;
  data.randu(5, 5);
  arma::uvec labels;
  labels.zeros(5);

  SoftmaxErrorFunction<SquaredEuclideanDistance> sef(data, labels);

  // Verify the initial point is the identity matrix.
  arma::mat initial_point = sef.GetInitialPoint();
  for (int row = 0; row < 5; row++) {
    for (int col = 0; col < 5; col++) {
      if (row == col)
        BOOST_REQUIRE_CLOSE(initial_point(row, col), 1.0, 1e-5);
      else
        BOOST_REQUIRE(initial_point(row, col) == 0.0);
    }
  }
}

/***
 * On a simple fake dataset, ensure that the initial function evaluation is
 * correct.
 */
BOOST_AUTO_TEST_CASE(softmax_initial_evaluation) {
  // Useful but simple dataset with six points and two classes.
  arma::mat data    = "-0.1 -0.1 -0.1  0.1  0.1  0.1;"
                      " 1.0  0.0 -1.0  1.0  0.0 -1.0 ";
  arma::uvec labels = " 0    0    0    1    1    1   ";

  std::cout << data << std::endl;

  SoftmaxErrorFunction<SquaredEuclideanDistance> sef(data, labels);

  double objective = sef.Evaluate(arma::eye<arma::mat>(2, 2));

  // Result painstakingly calculated by hand by rcurtin (recorded forever in his
  // notebook).  As a result of lack of precision of the by-hand result, the
  // tolerance is fairly high.
  BOOST_REQUIRE_CLOSE(objective, -1.5115, 0.01);
}

/***
 * On a simple fake dataset, ensure that the initial gradient evaluation is
 * correct.
 */
BOOST_AUTO_TEST_CASE(softmax_initial_gradient) {
  // Useful but simple dataset with six points and two classes.
  arma::mat data    = "-0.1 -0.1 -0.1  0.1  0.1  0.1;"
                      " 1.0  0.0 -1.0  1.0  0.0 -1.0 ";
  arma::uvec labels = " 0    0    0    1    1    1   ";

  SoftmaxErrorFunction<SquaredEuclideanDistance> sef(data, labels);

  arma::mat gradient;
  sef.Gradient(arma::eye<arma::mat>(2, 2), gradient);

  // Results painstakingly calculated by hand by rcurtin (recorded forever in
  // his notebook).  As a result of lack of precision of the by-hand result, the
  // tolerance is fairly high.
  BOOST_REQUIRE_CLOSE(gradient(0, 0), -0.089766, 0.05);
  BOOST_REQUIRE(gradient(1, 0) == 0.0);
  BOOST_REQUIRE(gradient(0, 1) == 0.0);
  BOOST_REQUIRE_CLOSE(gradient(1, 1), 1.63823, 0.01);
}
<commit_msg>Add tests for the evaluation of the objective and gradient of already optimal datasets.<commit_after>/***
 * @file nca_test.cc
 * @author Ryan Curtin
 *
 * Unit tests for Neighborhood Components Analysis and related code (including
 * the softmax error function).
 */
#include <fastlib/fastlib.h>
#include <mlpack/core/kernels/lmetric.h>
#include "nca.h"

#define BOOST_TEST_MODULE Neighborhood Components Analysis Test
#include <boost/test/unit_test.hpp>

using namespace mlpack;
using namespace mlpack::kernel;
using namespace mlpack::nca;

/***
 * The Softmax error function should return the identity matrix as its initial
 * point.
 */
BOOST_AUTO_TEST_CASE(softmax_initial_point) {
  // Cheap fake dataset.
  arma::mat data;
  data.randu(5, 5);
  arma::uvec labels;
  labels.zeros(5);

  SoftmaxErrorFunction<SquaredEuclideanDistance> sef(data, labels);

  // Verify the initial point is the identity matrix.
  arma::mat initial_point = sef.GetInitialPoint();
  for (int row = 0; row < 5; row++) {
    for (int col = 0; col < 5; col++) {
      if (row == col)
        BOOST_REQUIRE_CLOSE(initial_point(row, col), 1.0, 1e-5);
      else
        BOOST_REQUIRE(initial_point(row, col) == 0.0);
    }
  }
}

/***
 * On a simple fake dataset, ensure that the initial function evaluation is
 * correct.
 */
BOOST_AUTO_TEST_CASE(softmax_initial_evaluation) {
  // Useful but simple dataset with six points and two classes.
  arma::mat data    = "-0.1 -0.1 -0.1  0.1  0.1  0.1;"
                      " 1.0  0.0 -1.0  1.0  0.0 -1.0 ";
  arma::uvec labels = " 0    0    0    1    1    1   ";

  std::cout << data << std::endl;

  SoftmaxErrorFunction<SquaredEuclideanDistance> sef(data, labels);

  double objective = sef.Evaluate(arma::eye<arma::mat>(2, 2));

  // Result painstakingly calculated by hand by rcurtin (recorded forever in his
  // notebook).  As a result of lack of precision of the by-hand result, the
  // tolerance is fairly high.
  BOOST_REQUIRE_CLOSE(objective, -1.5115, 0.01);
}

/***
 * On a simple fake dataset, ensure that the initial gradient evaluation is
 * correct.
 */
BOOST_AUTO_TEST_CASE(softmax_initial_gradient) {
  // Useful but simple dataset with six points and two classes.
  arma::mat data    = "-0.1 -0.1 -0.1  0.1  0.1  0.1;"
                      " 1.0  0.0 -1.0  1.0  0.0 -1.0 ";
  arma::uvec labels = " 0    0    0    1    1    1   ";

  SoftmaxErrorFunction<SquaredEuclideanDistance> sef(data, labels);

  arma::mat gradient;
  sef.Gradient(arma::eye<arma::mat>(2, 2), gradient);

  // Results painstakingly calculated by hand by rcurtin (recorded forever in
  // his notebook).  As a result of lack of precision of the by-hand result, the
  // tolerance is fairly high.
  BOOST_REQUIRE_CLOSE(gradient(0, 0), -0.089766, 0.05);
  BOOST_REQUIRE(gradient(1, 0) == 0.0);
  BOOST_REQUIRE(gradient(0, 1) == 0.0);
  BOOST_REQUIRE_CLOSE(gradient(1, 1), 1.63823, 0.01);
}

/***
 * On optimally separated datasets, ensure that the objective function is
 * optimal (equal to the negative number of points).
 */
BOOST_AUTO_TEST_CASE(softmax_optimal_evaluation) {
  // Simple optimal dataset.
  arma::mat data    = " 500  500 -500 -500;"
                      "   1    0    1    0 ";
  arma::uvec labels = "   0    0    1    1 ";

  SoftmaxErrorFunction<SquaredEuclideanDistance> sef(data, labels);

  double objective = sef.Evaluate(arma::eye<arma::mat>(2, 2));

  // Use a very close tolerance for optimality; we need to be sure this function
  // gives optimal results correctly.
  BOOST_REQUIRE_CLOSE(objective, -4.0, 1e-10);
}

/***
 * On optimally separated datasets, ensure that the gradient is zero.
 */
BOOST_AUTO_TEST_CASE(softmax_optimal_gradient) {
  // Simple optimal dataset.
  arma::mat data    = " 500  500 -500 -500;"
                      "   1    0    1    0 ";
  arma::uvec labels = "   0    0    1    1 ";

  SoftmaxErrorFunction<SquaredEuclideanDistance> sef(data, labels);

  arma::mat gradient;
  sef.Gradient(arma::eye<arma::mat>(2, 2), gradient);

  BOOST_REQUIRE(gradient(0, 0) == 0.0);
  BOOST_REQUIRE(gradient(0, 1) == 0.0);
  BOOST_REQUIRE(gradient(1, 0) == 0.0);
  BOOST_REQUIRE(gradient(1, 1) == 0.0);
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/message_pump_glib_x.h"

#include <gdk/gdkx.h>
#if defined(HAVE_XINPUT2)
#include <X11/extensions/XInput2.h>
#else
#include <X11/Xlib.h>
#endif

#include "base/message_pump_glib_x_dispatch.h"

namespace {

gboolean PlaceholderDispatch(GSource* source,
                             GSourceFunc cb,
                             gpointer data) {
  return TRUE;
}

#if defined(HAVE_XINPUT2)

// Setup XInput2 select for the GtkWidget.
gboolean GtkWidgetRealizeCallback(GSignalInvocationHint* hint, guint nparams,
                                  const GValue* pvalues, gpointer data) {
  GtkWidget* widget = GTK_WIDGET(g_value_get_object(pvalues));
  GdkWindow* window = widget->window;
  base::MessagePumpGlibX* msgpump = static_cast<base::MessagePumpGlibX*>(data);

  DCHECK(window);  // TODO(sad): Remove once determined if necessary.

  if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_TOPLEVEL &&
      GDK_WINDOW_TYPE(window) != GDK_WINDOW_CHILD &&
      GDK_WINDOW_TYPE(window) != GDK_WINDOW_DIALOG)
    return true;

  // TODO(sad): Do we need to set a flag on |window| to make sure we don't
  // select for the same GdkWindow multiple times? Does it matter?
  msgpump->SetupXInput2ForXWindow(GDK_WINDOW_XID(window));

  return true;
}

// We need to capture all the GDK windows that get created, and start
// listening for XInput2 events. So we setup a callback to the 'realize'
// signal for GTK+ widgets, so that whenever the signal triggers for any
// GtkWidget, which means the GtkWidget should now have a GdkWindow, we can
// setup XInput2 events for the GdkWindow.
void SetupGtkWidgetRealizeNotifier(base::MessagePumpGlibX* msgpump) {
  guint signal_id;
  gpointer klass = g_type_class_ref(GTK_TYPE_WIDGET);

  g_signal_parse_name("realize", GTK_TYPE_WIDGET, &signal_id, NULL, FALSE);
  g_signal_add_emission_hook(signal_id, 0, GtkWidgetRealizeCallback,
      static_cast<gpointer>(msgpump), NULL);

  g_type_class_unref(klass);
}

#endif  // HAVE_XINPUT2

}  // namespace

namespace base {

MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(),
#if defined(HAVE_XINPUT2)
    xiopcode_(-1),
    masters_(),
    slaves_(),
#endif
    gdksource_(NULL),
    dispatching_event_(false),
    capture_x_events_(0),
    capture_gdk_events_(0) {
  gdk_event_handler_set(&EventDispatcherX, this, NULL);

#if defined(HAVE_XINPUT2)
  InitializeXInput2();
#endif
  InitializeEventsToCapture();
}

MessagePumpGlibX::~MessagePumpGlibX() {
}

#if defined(HAVE_XINPUT2)
void MessagePumpGlibX::SetupXInput2ForXWindow(Window xwindow) {
  Display* xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());

  // Setup mask for mouse events.
  unsigned char mask[(XI_LASTEVENT + 7)/8];
  memset(mask, 0, sizeof(mask));

  XISetMask(mask, XI_ButtonPress);
  XISetMask(mask, XI_ButtonRelease);
  XISetMask(mask, XI_Motion);

  // It is necessary to select only for the master devices. XInput2 provides
  // enough information to the event callback to decide which slave device
  // triggered the event, thus decide whether the 'pointer event' is a 'mouse
  // event' or a 'touch event'. So it is not necessary to select for the slave
  // devices here.
  XIEventMask evmasks[masters_.size()];
  int count = 0;
  for (std::set<int>::const_iterator iter = masters_.begin();
       iter != masters_.end();
       ++iter, ++count) {
    evmasks[count].deviceid = *iter;
    evmasks[count].mask_len = sizeof(mask);
    evmasks[count].mask = mask;
  }

  XISelectEvents(xdisplay, xwindow, evmasks, masters_.size());

  // TODO(sad): Setup masks for keyboard events.

  XFlush(xdisplay);
}
#endif  // HAVE_XINPUT2

bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
  GdkDisplay* gdisp = gdk_display_get_default();
  if (!gdisp)
    return MessagePumpForUI::RunOnce(context, block);

  Display* display = GDK_DISPLAY_XDISPLAY(gdisp);
  bool should_quit = false;

  if (XPending(display)) {
    XEvent xev;
    XPeekEvent(display, &xev);
    if (capture_x_events_[xev.type]
#if defined(HAVE_XINPUT2)
        && (xev.type != GenericEvent || xev.xcookie.extension == xiopcode_)
#endif
        ) {
      XNextEvent(display, &xev);

#if defined(HAVE_XINPUT2)
      bool have_cookie = false;
      if (xev.type == GenericEvent &&
          XGetEventData(xev.xgeneric.display, &xev.xcookie)) {
        have_cookie = true;
      }
#endif

      MessagePumpGlibXDispatcher::DispatchStatus status =
          static_cast<MessagePumpGlibXDispatcher*>
          (GetDispatcher())->DispatchX(&xev);

      if (status == MessagePumpGlibXDispatcher::EVENT_QUIT) {
        should_quit = true;
        Quit();
      } else if (status == MessagePumpGlibXDispatcher::EVENT_IGNORED) {
        DLOG(WARNING) << "Event (" << xev.type << ") not handled.";

        // TODO(sad): It is necessary to put back the event so that the default
        // GDK events handler can take care of it. Without this, it is
        // impossible to use the omnibox at the moment. However, this will
        // eventually be removed once the omnibox code is updated for touchui.
        XPutBackEvent(display, &xev);
        if (gdksource_)
          gdksource_->source_funcs->dispatch = gdkdispatcher_;
        g_main_context_iteration(context, FALSE);
      }

#if defined(HAVE_XINPUT2)
      if (have_cookie) {
        XFreeEventData(xev.xgeneric.display, &xev.xcookie);
      }
#endif
    } else {
      // TODO(sad): A couple of extra events can still sneak in during this.
      // Those should be sent back to the X queue from the dispatcher
      // EventDispatcherX.
      if (gdksource_)
        gdksource_->source_funcs->dispatch = gdkdispatcher_;
      g_main_context_iteration(context, FALSE);
    }
  }

  if (should_quit)
    return true;

  bool retvalue;
  if (gdksource_) {
    // Replace the dispatch callback of the GDK event source temporarily so that
    // it doesn't read events from X.
    gboolean (*cb)(GSource*, GSourceFunc, void*) =
        gdksource_->source_funcs->dispatch;
    gdksource_->source_funcs->dispatch = PlaceholderDispatch;

    dispatching_event_ = true;
    retvalue = g_main_context_iteration(context, block);
    dispatching_event_ = false;

    gdksource_->source_funcs->dispatch = cb;
  } else {
    retvalue = g_main_context_iteration(context, block);
  }

  return retvalue;
}

void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) {
  MessagePumpGlibX* pump_x = reinterpret_cast<MessagePumpGlibX*>(data);

  if (!pump_x->gdksource_) {
    pump_x->gdksource_ = g_main_current_source();
    pump_x->gdkdispatcher_ = pump_x->gdksource_->source_funcs->dispatch;
  } else if (!pump_x->IsDispatchingEvent()) {
    if (event->type != GDK_NOTHING &&
        pump_x->capture_gdk_events_[event->type]) {
      // TODO(sad): An X event is caught by the GDK handler. Put it back in the
      // X queue so that we catch it in the next iteration. When done, the
      // following DLOG statement will be removed.
      DLOG(WARNING) << "GDK received an event it shouldn't have";
    }
  }

  pump_x->DispatchEvents(event);
}

void MessagePumpGlibX::InitializeEventsToCapture(void) {
  // TODO(sad): Decide which events we want to capture and update the tables
  // accordingly.
  capture_x_events_[KeyPress] = true;
  capture_gdk_events_[GDK_KEY_PRESS] = true;

  capture_x_events_[KeyRelease] = true;
  capture_gdk_events_[GDK_KEY_RELEASE] = true;

  capture_x_events_[ButtonPress] = true;
  capture_gdk_events_[GDK_BUTTON_PRESS] = true;

  capture_x_events_[ButtonRelease] = true;
  capture_gdk_events_[GDK_BUTTON_RELEASE] = true;

  capture_x_events_[MotionNotify] = true;
  capture_gdk_events_[GDK_MOTION_NOTIFY] = true;

#if defined(HAVE_XINPUT2)
  capture_x_events_[GenericEvent] = true;
#endif
}

#if defined(HAVE_XINPUT2)
void MessagePumpGlibX::InitializeXInput2(void) {
  GdkDisplay* display = gdk_display_get_default();
  if (!display)
    return;

  Display* xdisplay = GDK_DISPLAY_XDISPLAY(display);
  int event, err;

  if (!XQueryExtension(xdisplay, "XInputExtension", &xiopcode_, &event, &err)) {
    DLOG(WARNING) << "X Input extension not available.";
    xiopcode_ = -1;
    return;
  }

  int major = 2, minor = 0;
  if (XIQueryVersion(xdisplay, &major, &minor) == BadRequest) {
    DLOG(WARNING) << "XInput2 not supported in the server.";
    xiopcode_ = -1;
    return;
  }

  // TODO(sad): Here, we only setup so that the X windows created by GTK+ are
  // setup for XInput2 events. We need a way to listen for XInput2 events for X
  // windows created by other means (e.g. for context menus).
  SetupGtkWidgetRealizeNotifier(this);

  // Instead of asking X for the list of devices all the time, let's maintain a
  // list of slave (physical) and master (virtual) pointer devices.
  int count = 0;
  XIDeviceInfo* devices = XIQueryDevice(xdisplay, XIAllDevices, &count);
  for (int i = 0; i < count; i++) {
    XIDeviceInfo* devinfo = devices + i;
    if (devinfo->use == XISlavePointer) {
      slaves_.insert(devinfo->deviceid);
    } else if (devinfo->use == XIMasterPointer) {
      masters_.insert(devinfo->deviceid);
    }
    // We do not need to care about XIFloatingSlave, because the callback for
    // XI_HierarchyChanged event will take care of it.
  }
  XIFreeDeviceInfo(devices);

  // TODO(sad): Select on root for XI_HierarchyChanged so that slaves_ and
  // masters_ can be kept up-to-date. This is a relatively rare event, so we can
  // put it off for a later time.
  // Note: It is not necessary to listen for XI_DeviceChanged events.
}
#endif  // HAVE_XINPUT2

}  // namespace base
<commit_msg>touch: more fixes in the message pump.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/message_pump_glib_x.h"

#include <gdk/gdkx.h>
#if defined(HAVE_XINPUT2)
#include <X11/extensions/XInput2.h>
#else
#include <X11/Xlib.h>
#endif

#include "base/message_pump_glib_x_dispatch.h"

namespace {

gboolean PlaceholderDispatch(GSource* source,
                             GSourceFunc cb,
                             gpointer data) {
  return TRUE;
}

#if defined(HAVE_XINPUT2)

// Setup XInput2 select for the GtkWidget.
gboolean GtkWidgetRealizeCallback(GSignalInvocationHint* hint, guint nparams,
                                  const GValue* pvalues, gpointer data) {
  GtkWidget* widget = GTK_WIDGET(g_value_get_object(pvalues));
  GdkWindow* window = widget->window;
  base::MessagePumpGlibX* msgpump = static_cast<base::MessagePumpGlibX*>(data);

  DCHECK(window);  // TODO(sad): Remove once determined if necessary.

  if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_TOPLEVEL &&
      GDK_WINDOW_TYPE(window) != GDK_WINDOW_CHILD &&
      GDK_WINDOW_TYPE(window) != GDK_WINDOW_DIALOG)
    return true;

  // TODO(sad): Do we need to set a flag on |window| to make sure we don't
  // select for the same GdkWindow multiple times? Does it matter?
  msgpump->SetupXInput2ForXWindow(GDK_WINDOW_XID(window));

  return true;
}

// We need to capture all the GDK windows that get created, and start
// listening for XInput2 events. So we setup a callback to the 'realize'
// signal for GTK+ widgets, so that whenever the signal triggers for any
// GtkWidget, which means the GtkWidget should now have a GdkWindow, we can
// setup XInput2 events for the GdkWindow.
static guint realize_signal_id = 0;
static guint realize_hook_id = 0;

void SetupGtkWidgetRealizeNotifier(base::MessagePumpGlibX* msgpump) {
  gpointer klass = g_type_class_ref(GTK_TYPE_WIDGET);

  g_signal_parse_name("realize", GTK_TYPE_WIDGET,
                      &realize_signal_id, NULL, FALSE);
  realize_hook_id = g_signal_add_emission_hook(realize_signal_id, 0,
      GtkWidgetRealizeCallback, static_cast<gpointer>(msgpump), NULL);

  g_type_class_unref(klass);
}

void RemoveGtkWidgetRealizeNotifier() {
  if (realize_signal_id != 0)
    g_signal_remove_emission_hook(realize_signal_id, realize_hook_id);
  realize_signal_id = 0;
  realize_hook_id = 0;
}

#endif  // HAVE_XINPUT2

}  // namespace

namespace base {

MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(),
#if defined(HAVE_XINPUT2)
    xiopcode_(-1),
    masters_(),
    slaves_(),
#endif
    gdksource_(NULL),
    dispatching_event_(false),
    capture_x_events_(0),
    capture_gdk_events_(0) {
  gdk_event_handler_set(&EventDispatcherX, this, NULL);

#if defined(HAVE_XINPUT2)
  InitializeXInput2();
#endif
  InitializeEventsToCapture();
}

MessagePumpGlibX::~MessagePumpGlibX() {
#if defined(HAVE_XINPUT2)
  RemoveGtkWidgetRealizeNotifier();
#endif
}

#if defined(HAVE_XINPUT2)
void MessagePumpGlibX::SetupXInput2ForXWindow(Window xwindow) {
  Display* xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());

  // Setup mask for mouse events.
  unsigned char mask[(XI_LASTEVENT + 7)/8];
  memset(mask, 0, sizeof(mask));

  XISetMask(mask, XI_ButtonPress);
  XISetMask(mask, XI_ButtonRelease);
  XISetMask(mask, XI_Motion);

  // It is necessary to select only for the master devices. XInput2 provides
  // enough information to the event callback to decide which slave device
  // triggered the event, thus decide whether the 'pointer event' is a 'mouse
  // event' or a 'touch event'. So it is not necessary to select for the slave
  // devices here.
  XIEventMask evmasks[masters_.size()];
  int count = 0;
  for (std::set<int>::const_iterator iter = masters_.begin();
       iter != masters_.end();
       ++iter, ++count) {
    evmasks[count].deviceid = *iter;
    evmasks[count].mask_len = sizeof(mask);
    evmasks[count].mask = mask;
  }

  XISelectEvents(xdisplay, xwindow, evmasks, masters_.size());

  // TODO(sad): Setup masks for keyboard events.

  XFlush(xdisplay);
}
#endif  // HAVE_XINPUT2

bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
  GdkDisplay* gdisp = gdk_display_get_default();
  if (!gdisp || !GetDispatcher())
    return MessagePumpForUI::RunOnce(context, block);

  Display* display = GDK_DISPLAY_XDISPLAY(gdisp);
  bool should_quit = false;

  if (XPending(display)) {
    XEvent xev;
    XPeekEvent(display, &xev);
    if (capture_x_events_[xev.type]
#if defined(HAVE_XINPUT2)
        && (xev.type != GenericEvent || xev.xcookie.extension == xiopcode_)
#endif
        ) {
      XNextEvent(display, &xev);

#if defined(HAVE_XINPUT2)
      bool have_cookie = false;
      if (xev.type == GenericEvent &&
          XGetEventData(xev.xgeneric.display, &xev.xcookie)) {
        have_cookie = true;
      }
#endif

      MessagePumpGlibXDispatcher::DispatchStatus status =
          static_cast<MessagePumpGlibXDispatcher*>
          (GetDispatcher())->DispatchX(&xev);

      if (status == MessagePumpGlibXDispatcher::EVENT_QUIT) {
        should_quit = true;
        Quit();
      } else if (status == MessagePumpGlibXDispatcher::EVENT_IGNORED) {
        DLOG(WARNING) << "Event (" << xev.type << ") not handled.";

        // TODO(sad): It is necessary to put back the event so that the default
        // GDK events handler can take care of it. Without this, it is
        // impossible to use the omnibox at the moment. However, this will
        // eventually be removed once the omnibox code is updated for touchui.
        XPutBackEvent(display, &xev);
        if (gdksource_)
          gdksource_->source_funcs->dispatch = gdkdispatcher_;
        g_main_context_iteration(context, FALSE);
      }

#if defined(HAVE_XINPUT2)
      if (have_cookie) {
        XFreeEventData(xev.xgeneric.display, &xev.xcookie);
      }
#endif
    } else {
      // TODO(sad): A couple of extra events can still sneak in during this.
      // Those should be sent back to the X queue from the dispatcher
      // EventDispatcherX.
      if (gdksource_)
        gdksource_->source_funcs->dispatch = gdkdispatcher_;
      g_main_context_iteration(context, FALSE);
    }
  }

  if (should_quit)
    return true;

  bool retvalue;
  if (gdksource_) {
    // Replace the dispatch callback of the GDK event source temporarily so that
    // it doesn't read events from X.
    gboolean (*cb)(GSource*, GSourceFunc, void*) =
        gdksource_->source_funcs->dispatch;
    gdksource_->source_funcs->dispatch = PlaceholderDispatch;

    dispatching_event_ = true;
    retvalue = g_main_context_iteration(context, block);
    dispatching_event_ = false;

    gdksource_->source_funcs->dispatch = cb;
  } else {
    retvalue = g_main_context_iteration(context, block);
  }

  return retvalue;
}

void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) {
  MessagePumpGlibX* pump_x = reinterpret_cast<MessagePumpGlibX*>(data);

  if (!pump_x->gdksource_) {
    pump_x->gdksource_ = g_main_current_source();
    pump_x->gdkdispatcher_ = pump_x->gdksource_->source_funcs->dispatch;
  } else if (!pump_x->IsDispatchingEvent()) {
    if (event->type != GDK_NOTHING &&
        pump_x->capture_gdk_events_[event->type]) {
      // TODO(sad): An X event is caught by the GDK handler. Put it back in the
      // X queue so that we catch it in the next iteration. When done, the
      // following DLOG statement will be removed.
      DLOG(WARNING) << "GDK received an event it shouldn't have";
    }
  }

  pump_x->DispatchEvents(event);
}

void MessagePumpGlibX::InitializeEventsToCapture(void) {
  // TODO(sad): Decide which events we want to capture and update the tables
  // accordingly.
  capture_x_events_[KeyPress] = true;
  capture_gdk_events_[GDK_KEY_PRESS] = true;

  capture_x_events_[KeyRelease] = true;
  capture_gdk_events_[GDK_KEY_RELEASE] = true;

  capture_x_events_[ButtonPress] = true;
  capture_gdk_events_[GDK_BUTTON_PRESS] = true;

  capture_x_events_[ButtonRelease] = true;
  capture_gdk_events_[GDK_BUTTON_RELEASE] = true;

  capture_x_events_[MotionNotify] = true;
  capture_gdk_events_[GDK_MOTION_NOTIFY] = true;

#if defined(HAVE_XINPUT2)
  capture_x_events_[GenericEvent] = true;
#endif
}

#if defined(HAVE_XINPUT2)
void MessagePumpGlibX::InitializeXInput2(void) {
  GdkDisplay* display = gdk_display_get_default();
  if (!display)
    return;

  Display* xdisplay = GDK_DISPLAY_XDISPLAY(display);
  int event, err;

  if (!XQueryExtension(xdisplay, "XInputExtension", &xiopcode_, &event, &err)) {
    DLOG(WARNING) << "X Input extension not available.";
    xiopcode_ = -1;
    return;
  }

  int major = 2, minor = 0;
  if (XIQueryVersion(xdisplay, &major, &minor) == BadRequest) {
    DLOG(WARNING) << "XInput2 not supported in the server.";
    xiopcode_ = -1;
    return;
  }

  // TODO(sad): Here, we only setup so that the X windows created by GTK+ are
  // setup for XInput2 events. We need a way to listen for XInput2 events for X
  // windows created by other means (e.g. for context menus).
  SetupGtkWidgetRealizeNotifier(this);

  // Instead of asking X for the list of devices all the time, let's maintain a
  // list of slave (physical) and master (virtual) pointer devices.
  int count = 0;
  XIDeviceInfo* devices = XIQueryDevice(xdisplay, XIAllDevices, &count);
  for (int i = 0; i < count; i++) {
    XIDeviceInfo* devinfo = devices + i;
    if (devinfo->use == XISlavePointer) {
      slaves_.insert(devinfo->deviceid);
    } else if (devinfo->use == XIMasterPointer) {
      masters_.insert(devinfo->deviceid);
    }
    // We do not need to care about XIFloatingSlave, because the callback for
    // XI_HierarchyChanged event will take care of it.
  }
  XIFreeDeviceInfo(devices);

  // TODO(sad): Select on root for XI_HierarchyChanged so that slaves_ and
  // masters_ can be kept up-to-date. This is a relatively rare event, so we can
  // put it off for a later time.
  // Note: It is not necessary to listen for XI_DeviceChanged events.
}
#endif  // HAVE_XINPUT2

}  // namespace base
<|endoftext|>


<commit_before>// Produce deprecation warnings (needs to come before arrayobject.h inclusion).
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION

#include <boost/python.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <memory>

#include "conversion.h"

#include "kyheader.h"
#include "Objectness.h"
#include "ValStructVec.h"

using namespace boost::python;

class Bing {

public:

    void load(std::string model_name) {
        DataSetVOC dummy;
        model_.reset(new Objectness(&dummy, 2, 8, 2));
        model_->loadTrainedModel(model_name);
    }

    PyObject* get_windows(PyObject *img_obj, int num_per_size = 130) {

        if (!model_) {
            throw std::runtime_error("model not loaded!");
        }

        NDArrayConverter cvt;
        cv::Mat img;
        img = cvt.toMat(img_obj);
        ValStructVec<float, cv::Vec4i> boxes;
        model_->getObjBndBoxes(img, boxes, num_per_size);
        cv::Mat b_mat = cv::Mat::zeros(boxes.size(), 4, CV_32F);

        for (int i = 0; i < boxes.size(); i++) {
            b_mat.at<float>(i, 0) = boxes[i][0]; // x1
            b_mat.at<float>(i, 1) = boxes[i][1]; // y1
            b_mat.at<float>(i, 2) = boxes[i][2]; // x2
            b_mat.at<float>(i, 3) = boxes[i][3]; // y2
        }

        return cvt.toNDArray(b_mat);
    }

private:
    std::shared_ptr<Objectness> model_;
};

BOOST_PYTHON_MODULE(bing)
{
    class_<Bing>("Bing")
        .def("load", &Bing::load)
        .def("get_windows", &Bing::get_windows)
    ;
}
<commit_msg>Make the default argument work and add doc string<commit_after>// Produce deprecation warnings (needs to come before arrayobject.h inclusion).
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION

#include <boost/python.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <memory>

#include "conversion.h"

#include "kyheader.h"
#include "Objectness.h"
#include "ValStructVec.h"

using namespace boost::python;

class Bing {

public:

    void load(std::string model_name) {
        DataSetVOC dummy;
        model_.reset(new Objectness(&dummy, 2, 8, 2));
        model_->loadTrainedModel(model_name);
    }

    PyObject* get_windows(PyObject *img_obj, int num_per_size = 130) {

        if (!model_) {
            throw std::runtime_error("model not loaded!");
        }

        NDArrayConverter cvt;
        cv::Mat img;
        img = cvt.toMat(img_obj);
        ValStructVec<float, cv::Vec4i> boxes;
        model_->getObjBndBoxes(img, boxes, num_per_size);
        cv::Mat b_mat = cv::Mat::zeros(boxes.size(), 4, CV_32F);

        for (int i = 0; i < boxes.size(); i++) {
            b_mat.at<float>(i, 0) = boxes[i][0]; // x1
            b_mat.at<float>(i, 1) = boxes[i][1]; // y1
            b_mat.at<float>(i, 2) = boxes[i][2]; // x2
            b_mat.at<float>(i, 3) = boxes[i][3]; // y2
        }

        return cvt.toNDArray(b_mat);
    }

private:
    std::shared_ptr<Objectness> model_;
};

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(get_windows_overloads, get_windows, 1, 2)

BOOST_PYTHON_MODULE(bing)
{
    class_<Bing>("Bing", "Python Wrapper for Bing Objectness")
        .def("load", &Bing::load)
        .def("get_windows", &Bing::get_windows,
                get_windows_overloads(
                    args("img", "num_per_size"),
                    "Get the region proposals of an image"
                    )
                )
    ;
}
<|endoftext|>


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

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

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

//  Software Guide : BeginCommandLineArgs
//    INPUTS: {suburb2.jpeg}
//    OUTPUTS: {suburb2_an_1.jpeg}, {suburb2_an_2.jpeg},  {suburb2_an_3.jpeg}, {suburb2_an_4.jpeg}
//    OUTPUTS: {suburb2_sf_1.jpeg}, {suburb2_sf_2.jpeg}, {suburb2_sf_3.jpeg}, {suburb2_sf_4.jpeg}
//    OUTPUTS: {suburb2_if_1.jpeg}, {suburb2_if_2.jpeg}, {suburb2_if_3.jpeg}, {suburb2_if_4.jpeg}
//    OUTPUTS: {suburb2_id_1.jpeg}, {suburb2_id_2.jpeg}, {suburb2_id_3.jpeg}, {suburb2_id_4.jpeg}
//    OUTPUTS: {suburb2_sd_1.jpeg}, {suburb2_sd_2.jpeg}, {suburb2_sd_3.jpeg}, {suburb2_sd_4.jpeg}
//    4 2
//  Software Guide : EndCommandLineArgs

// Software Guide : BeginLatex
//
// This example illustrates the use of the \doxygen{otb}{MorphologicalPyramidAnalyseFilter}.
//
// The first step required to use this filter is to include its header file.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "otbMorphologicalPyramidAnalysisFilter.h"
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// The mathematical morphology filters to be used have also to be
// included here.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "otbOpeningClosingMorphologicalFilter.h"
#include "itkBinaryBallStructuringElement.h"
// Software Guide : EndCodeSnippet

#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
#include "otbImage.h"
#include "itkExceptionObject.h"

int main(int argc, char * argv[])
{

  if (argc != 24)
    {
    std::cerr << "Usage: " << argv[0] << " inputImageFile ";
    std::cerr << " outputImagePrefix iterations decimationRatio" << std::endl;
    return EXIT_FAILURE;
    }

  const char *       inputFilename = argv[1];
  const unsigned int numberOfLevels = atoi(argv[22]);
  const float        decimationRatio = atof(argv[23]);

// Software Guide : BeginLatex
//
// As usual, we start by defining the types needed for the pixels, the
// images, the image reader and the image writer.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  const unsigned int Dimension = 2;
  typedef unsigned char InputPixelType;
  typedef unsigned char OutputPixelType;

  typedef otb::Image<InputPixelType, Dimension>  InputImageType;
  typedef otb::Image<OutputPixelType, Dimension> OutputImageType;

  typedef otb::ImageFileReader<InputImageType>  ReaderType;
  typedef otb::ImageFileWriter<OutputImageType> WriterType;
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// Now, we define the types needed for the morphological filters which
// will be used to build the morphological pyramid. The first thing to
// do is define the structuring element, which in our case, will be a
// \doxygen{itk}{BinaryBallStructuringElement} which is templated over
// the pixel type and the dimension of the image.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  typedef itk::BinaryBallStructuringElement<InputPixelType,
      Dimension> StructuringElementType;
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// We can now define the type of the filter to be used by the
// morphological pyramid. In this case, we choose to use an
// \doxygen{otb}{OpeningClosingMorphologicalFilter} which is just the
// concatenation of an opening and a closing. This filter is theplated
// over the input and output image types and the structurung element
// type that we just define above.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  typedef otb::OpeningClosingMorphologicalFilter<InputImageType,
      InputImageType,
      StructuringElementType>
  OpeningClosingFilterType;
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// We can finally define the type of the morpholoical pyramid
// filter. The filter is templated over the input and output mage
// types and the {\em lowpas} morphological filter to be used.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  typedef otb::MorphologicalPyramidAnalysisFilter<InputImageType,
      OutputImageType,
      OpeningClosingFilterType>
  PyramidFilterType;
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// Since the \doxygen{otb}{MorphologicalPyramidAnalyseFilter}
// generates a list of images as output, it is useful to have an
// iterator to access the images. This is done as follows :
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  typedef PyramidFilterType::OutputImageListType::Iterator
  ImageListIterator;
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// We can now instantiate the reader in order to access the input
// image which has to be analysed.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName(inputFilename);
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// We instantiate the morphological pyramid analysis filter and set
// its parameters which are:
//\begin{itemize}
//    \item the number of iterations or levels of the pyramid;
//    \item the subsample scale or decimation factor between two
// successive pyramid levels.
//\end{itemize}
// After that, we plug the pipeline and run it by calling the
// \code{Update()} method.
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  PyramidFilterType::Pointer pyramid = PyramidFilterType::New();
  pyramid->SetNumberOfLevels(numberOfLevels);
  pyramid->SetDecimationRatio(decimationRatio);
  pyramid->SetInput(reader->GetOutput());
  pyramid->Update();
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
//  The morphological pyramid has 5
// types of output:
// \begin{itemize}
// \item the analysed image at each level of the pyramid through the
// \code{GetOutput()} method;
// \item the brighter details extracted from the filtering operation  through the
// \code{GetSupFilter()} method;
// \item the darker details extracted from the filtering operation through the
// \code{GetInfFilter()} method;
// \item the brighter details extracted from the resampling operation  through the
// \code{GetSupDeci()} method;
// \item the darker details extracted from the resampling operation  through the
// \code{GetInfDeci()} method;
// to decimation
// \end{itemize}
// Each one of these methods provides a list of images (one for each
// level of analysis), so we can iterate through the image lists by
// using iterators.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  ImageListIterator itAnalyse = pyramid->GetOutput()->Begin();
  ImageListIterator itSupFilter = pyramid->GetSupFilter()->Begin();
  ImageListIterator itInfFilter = pyramid->GetInfFilter()->Begin();
  ImageListIterator itInfDeci = pyramid->GetSupDeci()->Begin();
  ImageListIterator itSupDeci =  pyramid->GetInfDeci()->Begin();
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
//  We can now instantiate a writer and use it to write all the images
//  to files.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  WriterType::Pointer writer =  WriterType::New();

  int i = 1;

  // Writing the results images
  std::cout << (itAnalyse != (pyramid->GetOutput()->End())) << std::endl;
  while (itAnalyse != pyramid->GetOutput()->End())
    {
    writer->SetInput(itAnalyse.Get());
    writer->SetFileName(argv[0 * 4 + i + 1]);
    writer->Update();

    writer->SetInput(itSupFilter.Get());
    writer->SetFileName(argv[1 * 4 + i + 1]);
    writer->Update();

    writer->SetInput(itInfFilter.Get());
    writer->SetFileName(argv[2 * 4 + i + 1]);
    writer->Update();

    writer->SetInput(itInfDeci.Get());
    writer->SetFileName(argv[3 * 4 + i + 1]);
    writer->Update();

    writer->SetInput(itSupDeci.Get());
    writer->SetFileName(argv[4 * 4 + i + 1]);
    writer->Update();

    ++itAnalyse;
    ++itSupFilter;
    ++itInfFilter;
    ++itInfDeci;
    ++itSupDeci;
    ++i;
    }
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// Figure \ref{fig:PYR_IM} shows the test image to be processed by the
// morphological pyramid.
// \begin{figure}
// \center
// \includegraphics[width=0.5\textwidth]{suburb2.eps}
// \itkcaption[Morphological pyramid analysis]{Test image for the
// morphological pyramid.}
// \label{fig:PYR_IM}
// \end{figure}
//
// Figure \ref{fig:PYR_AN} shows the 4 levels of analysis of the image.
// \begin{figure}
// \center
// \includegraphics[width=0.20\textwidth]{suburb2_an_1.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_an_2.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_an_3.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_an_4.eps}
// \itkcaption[Morphological pyramid analysis]{Result of the
// analysis for 4 levels of the pyramid.}
// \label{fig:PYR_AN}
// \end{figure}
//
// Figure \ref{fig:PYR_SF} shows the 4 levels of bright details.
// \begin{figure}
// \center
// \includegraphics[width=0.20\textwidth]{suburb2_sf_1.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_sf_2.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_sf_3.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_sf_4.eps}
// \itkcaption[Morphological pyramid analysis]{Bright details for 4 levels of the pyramid.}
// \label{fig:PYR_SF}
// \end{figure}
//
// Figure \ref{fig:PYR_IF} shows the 4 levels of dark details.
// \begin{figure}
// \center
// \includegraphics[width=0.20\textwidth]{suburb2_if_1.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_if_2.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_if_3.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_if_4.eps}
// \itkcaption[Morphological pyramid analysis]{Dark details for 4 levels of the pyramid.}
// \label{fig:PYR_IF}
// \end{figure}
//
// Figure \ref{fig:PYR_ID} shows the 4 levels of bright decimation details.
// \begin{figure}
// \center
// \includegraphics[width=0.20\textwidth]{suburb2_id_1.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_id_2.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_id_3.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_id_4.eps}
// \itkcaption[Morphological pyramid analysis]{Bright decimation details for 4 levels of the pyramid.}
// \label{fig:PYR_ID}
// \end{figure}
//
// Figure \ref{fig:PYR_SD} shows the 4 levels of dark decimation details.
// \begin{figure}
// \center
// \includegraphics[width=0.20\textwidth]{suburb2_sd_1.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_sd_2.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_sd_3.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_sd_4.eps}
// \itkcaption[Morphological pyramid analysis]{Dark decimation details for 4 levels of the pyramid.}
// \label{fig:PYR_SD}
// \end{figure}
//
// Software Guide : EndLatex

  return EXIT_SUCCESS;
}
<commit_msg>DOC: Fixing typos<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

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

//  Software Guide : BeginCommandLineArgs
//    INPUTS: {suburb2.jpeg}
//    OUTPUTS: {suburb2_an_1.jpeg}, {suburb2_an_2.jpeg},  {suburb2_an_3.jpeg}, {suburb2_an_4.jpeg}
//    OUTPUTS: {suburb2_sf_1.jpeg}, {suburb2_sf_2.jpeg}, {suburb2_sf_3.jpeg}, {suburb2_sf_4.jpeg}
//    OUTPUTS: {suburb2_if_1.jpeg}, {suburb2_if_2.jpeg}, {suburb2_if_3.jpeg}, {suburb2_if_4.jpeg}
//    OUTPUTS: {suburb2_id_1.jpeg}, {suburb2_id_2.jpeg}, {suburb2_id_3.jpeg}, {suburb2_id_4.jpeg}
//    OUTPUTS: {suburb2_sd_1.jpeg}, {suburb2_sd_2.jpeg}, {suburb2_sd_3.jpeg}, {suburb2_sd_4.jpeg}
//    4 2
//  Software Guide : EndCommandLineArgs

// Software Guide : BeginLatex
//
// This example illustrates the use of the \doxygen{otb}{MorphologicalPyramidAnalyseFilter}.
//
// The first step required to use this filter is to include its header file.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "otbMorphologicalPyramidAnalysisFilter.h"
// Software Guide : EndCodeSnippet
// Software Guide : BeginLatex
//
// The mathematical morphology filters to be used have also to be
// included here.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "otbOpeningClosingMorphologicalFilter.h"
#include "itkBinaryBallStructuringElement.h"
// Software Guide : EndCodeSnippet

#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
#include "otbImage.h"
#include "itkExceptionObject.h"

int main(int argc, char * argv[])
{

  if (argc != 24)
    {
    std::cerr << "Usage: " << argv[0] << " inputImageFile ";
    std::cerr << " outputImagePrefix iterations decimationRatio" << std::endl;
    return EXIT_FAILURE;
    }

  const char *       inputFilename = argv[1];
  const unsigned int numberOfLevels = atoi(argv[22]);
  const float        decimationRatio = atof(argv[23]);

// Software Guide : BeginLatex
//
// As usual, we start by defining the types needed for the pixels, the
// images, the image reader and the image writer.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  const unsigned int Dimension = 2;
  typedef unsigned char InputPixelType;
  typedef unsigned char OutputPixelType;

  typedef otb::Image<InputPixelType, Dimension>  InputImageType;
  typedef otb::Image<OutputPixelType, Dimension> OutputImageType;

  typedef otb::ImageFileReader<InputImageType>  ReaderType;
  typedef otb::ImageFileWriter<OutputImageType> WriterType;
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// Now, we define the types needed for the morphological filters which
// will be used to build the morphological pyramid. The first thing to
// do is define the structuring element, which in our case, will be a
// \doxygen{itk}{BinaryBallStructuringElement} which is templated over
// the pixel type and the dimension of the image.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  typedef itk::BinaryBallStructuringElement<InputPixelType,
      Dimension> StructuringElementType;
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// We can now define the type of the filter to be used by the
// morphological pyramid. In this case, we choose to use an
// \doxygen{otb}{OpeningClosingMorphologicalFilter} which is just the
// concatenation of an opening and a closing. This filter is templated
// over the input and output image types and the structuring element
// type that we just define above.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  typedef otb::OpeningClosingMorphologicalFilter<InputImageType,
      InputImageType,
      StructuringElementType>
  OpeningClosingFilterType;
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// We can finally define the type of the morpholoical pyramid
// filter. The filter is templated over the input and output image
// types and the {\em lowpas} morphological filter to be used.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  typedef otb::MorphologicalPyramidAnalysisFilter<InputImageType,
      OutputImageType,
      OpeningClosingFilterType>
  PyramidFilterType;
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// Since the \doxygen{otb}{MorphologicalPyramidAnalyseFilter}
// generates a list of images as output, it is useful to have an
// iterator to access the images. This is done as follows :
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  typedef PyramidFilterType::OutputImageListType::Iterator
  ImageListIterator;
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// We can now instantiate the reader in order to access the input
// image which has to be analysed.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName(inputFilename);
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// We instantiate the morphological pyramid analysis filter and set
// its parameters which are:
//\begin{itemize}
//    \item the number of iterations or levels of the pyramid;
//    \item the subsample scale or decimation factor between two
// successive pyramid levels.
//\end{itemize}
// After that, we plug the pipeline and run it by calling the
// \code{Update()} method.
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  PyramidFilterType::Pointer pyramid = PyramidFilterType::New();
  pyramid->SetNumberOfLevels(numberOfLevels);
  pyramid->SetDecimationRatio(decimationRatio);
  pyramid->SetInput(reader->GetOutput());
  pyramid->Update();
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
//  The morphological pyramid has 5
// types of output:
// \begin{itemize}
// \item the analysed image at each level of the pyramid through the
// \code{GetOutput()} method;
// \item the brighter details extracted from the filtering operation  through the
// \code{GetSupFilter()} method;
// \item the darker details extracted from the filtering operation through the
// \code{GetInfFilter()} method;
// \item the brighter details extracted from the resampling operation  through the
// \code{GetSupDeci()} method;
// \item the darker details extracted from the resampling operation  through the
// \code{GetInfDeci()} method;
// to decimation
// \end{itemize}
// Each one of these methods provides a list of images (one for each
// level of analysis), so we can iterate through the image lists by
// using iterators.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  ImageListIterator itAnalyse = pyramid->GetOutput()->Begin();
  ImageListIterator itSupFilter = pyramid->GetSupFilter()->Begin();
  ImageListIterator itInfFilter = pyramid->GetInfFilter()->Begin();
  ImageListIterator itInfDeci = pyramid->GetSupDeci()->Begin();
  ImageListIterator itSupDeci =  pyramid->GetInfDeci()->Begin();
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
//  We can now instantiate a writer and use it to write all the images
//  to files.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  WriterType::Pointer writer =  WriterType::New();

  int i = 1;

  // Writing the results images
  std::cout << (itAnalyse != (pyramid->GetOutput()->End())) << std::endl;
  while (itAnalyse != pyramid->GetOutput()->End())
    {
    writer->SetInput(itAnalyse.Get());
    writer->SetFileName(argv[0 * 4 + i + 1]);
    writer->Update();

    writer->SetInput(itSupFilter.Get());
    writer->SetFileName(argv[1 * 4 + i + 1]);
    writer->Update();

    writer->SetInput(itInfFilter.Get());
    writer->SetFileName(argv[2 * 4 + i + 1]);
    writer->Update();

    writer->SetInput(itInfDeci.Get());
    writer->SetFileName(argv[3 * 4 + i + 1]);
    writer->Update();

    writer->SetInput(itSupDeci.Get());
    writer->SetFileName(argv[4 * 4 + i + 1]);
    writer->Update();

    ++itAnalyse;
    ++itSupFilter;
    ++itInfFilter;
    ++itInfDeci;
    ++itSupDeci;
    ++i;
    }
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// Figure \ref{fig:PYR_IM} shows the test image to be processed by the
// morphological pyramid.
// \begin{figure}
// \center
// \includegraphics[width=0.5\textwidth]{suburb2.eps}
// \itkcaption[Morphological pyramid analysis]{Test image for the
// morphological pyramid.}
// \label{fig:PYR_IM}
// \end{figure}
//
// Figure \ref{fig:PYR_AN} shows the 4 levels of analysis of the image.
// \begin{figure}
// \center
// \includegraphics[width=0.20\textwidth]{suburb2_an_1.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_an_2.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_an_3.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_an_4.eps}
// \itkcaption[Morphological pyramid analysis]{Result of the
// analysis for 4 levels of the pyramid.}
// \label{fig:PYR_AN}
// \end{figure}
//
// Figure \ref{fig:PYR_SF} shows the 4 levels of bright details.
// \begin{figure}
// \center
// \includegraphics[width=0.20\textwidth]{suburb2_sf_1.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_sf_2.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_sf_3.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_sf_4.eps}
// \itkcaption[Morphological pyramid analysis]{Bright details for 4 levels of the pyramid.}
// \label{fig:PYR_SF}
// \end{figure}
//
// Figure \ref{fig:PYR_IF} shows the 4 levels of dark details.
// \begin{figure}
// \center
// \includegraphics[width=0.20\textwidth]{suburb2_if_1.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_if_2.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_if_3.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_if_4.eps}
// \itkcaption[Morphological pyramid analysis]{Dark details for 4 levels of the pyramid.}
// \label{fig:PYR_IF}
// \end{figure}
//
// Figure \ref{fig:PYR_ID} shows the 4 levels of bright decimation details.
// \begin{figure}
// \center
// \includegraphics[width=0.20\textwidth]{suburb2_id_1.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_id_2.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_id_3.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_id_4.eps}
// \itkcaption[Morphological pyramid analysis]{Bright decimation details for 4 levels of the pyramid.}
// \label{fig:PYR_ID}
// \end{figure}
//
// Figure \ref{fig:PYR_SD} shows the 4 levels of dark decimation details.
// \begin{figure}
// \center
// \includegraphics[width=0.20\textwidth]{suburb2_sd_1.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_sd_2.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_sd_3.eps}
// \includegraphics[width=0.20\textwidth]{suburb2_sd_4.eps}
// \itkcaption[Morphological pyramid analysis]{Dark decimation details for 4 levels of the pyramid.}
// \label{fig:PYR_SD}
// \end{figure}
//
// Software Guide : EndLatex

  return EXIT_SUCCESS;
}
<|endoftext|>