<commit_before>// *****************************************************************************
//
// Copyright (c) 2015, Southwest Research Institute® (SwRI®)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Southwest Research Institute® (SwRI®) nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// *****************************************************************************

#include <tile_map/tile_map_view.h>

#include <cmath>

#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>

#include <GL/gl.h>

#include <ros/ros.h>

#include <math_util/constants.h>
#include <math_util/trig_util.h>
#include <transform_util/earth_constants.h>

#include <tile_map/image_cache.h>

namespace tile_map
{
  TileMapView::TileMapView() :
    base_url_("localhost"),
    extension_(".jpg"),
    max_level_(19),
    level_(-1),
    width_(100),
    height_(100)
  {
    ImageCachePtr image_cache = boost::make_shared<ImageCache>("/tmp/tile_map");
    tile_cache_ = boost::make_shared<TextureCache>(image_cache);
  }

  void TileMapView::SetMaxLevel(int32_t level)
  {
    max_level_ = level;
  }

  void TileMapView::SetExtension(const std::string& extension)
  {
    extension_ = extension;
  }

  void TileMapView::SetBaseUrl(const std::string& url)
  {
    if (base_url_ != url)
    {
      base_url_ = url;
      level_ = -1;
    }
  }

  void TileMapView::SetTransform(const transform_util::Transform& transform)
  {
    transform_ = transform;

    // TODO: check if modified.

    for (size_t i = 0; i < tiles_.size(); i++)
    {
      tiles_[i].top_left_t = transform_ * tiles_[i].top_left;
      tiles_[i].top_right_t = transform_ * tiles_[i].top_right;
      tiles_[i].bottom_right_t = transform_ * tiles_[i].bottom_right;
      tiles_[i].bottom_left_t = transform_ * tiles_[i].bottom_left;
    }

    for (size_t i = 0; i < precache_above_.size(); i++)
    {
      precache_above_[i].top_left_t = transform_ * precache_above_[i].top_left;
      precache_above_[i].top_right_t = transform_ * precache_above_[i].top_right;
      precache_above_[i].bottom_right_t = transform_ * precache_above_[i].bottom_right;
      precache_above_[i].bottom_left_t = transform_ * precache_above_[i].bottom_left;
    }
  }

  void TileMapView::SetView(
    double latitude,
    double longitude,
    double scale,
    int32_t width,
    int32_t height)
  {
    latitude = std::max(-90.0, std::min(90.0, latitude));
    longitude = std::max(-180.0, std::min(180.0, longitude));

    double lat = math_util::ToRadians(latitude);

    // Calculate the current zoom level:
    //
    // According to http://wiki.openstreetmap.org/wiki/Zoom_levels:
    //   meters_per_pixel = earth_circumference * cos(lat) / 2^(level + 8)
    //
    // Therefore,
    //   level = log2(earth_circumference * cos(lat) / meters_per_pixel) - 8
    //
    double lat_circumference =
      transform_util::_earth_equator_circumference * std::cos(lat) / scale;
    int32_t level = std::min((double)max_level_, std::max(0.0, std::ceil(std::log(lat_circumference) / std::log(2) - 8)));

    int64_t max_size = std::pow(2, level);

    int64_t center_x = std::min((double)max_size - 1.0, std::floor(((longitude + 180.0) / 360.0) * std::pow(2.0, level)));
    int64_t center_y = std::min((long double)max_size - 1.0, std::floor((1.0 - std::log(std::tan(lat) + 1.0 / std::cos(lat)) / math_util::_pi) / 2.0 * std::pow(2.0, level)));

    width_ = width;
    height_ = height;

    double max_dimension = std::max(width, height);

    double meters_per_pixel = transform_util::_earth_equator_circumference * std::cos(lat) / std::pow(2, level + 8);
    double tile_size = 256.0 * (meters_per_pixel / scale);

    int64_t size = std::max(1.0, std::min((double)max_size, std::ceil(0.5 * max_dimension / tile_size) * 2 + 1));

    if (size > 50)
    {
      ROS_ERROR("Invalid map size: %ld", size);
      return;
    }

    if (size_ != size_ || level_ != level || center_x_ != center_x || center_y_ != center_y)
    {
      size_ = size;
      level_ = level;
      center_x_ = center_x;
      center_y_ = center_y;

      int64_t top = std::max(0L, center_y_ - size_ / 2);
      int64_t left = std::max(0L, center_x_ - size_ / 2);

      int64_t right = std::min(max_size, left + size_);
      int64_t bottom = std::min(max_size, top + size_);

      for (size_t i = 0; i < tiles_.size(); i++)
      {
        tile_cache_->AddTexture(tiles_[i].texture);
      }
      tiles_.clear();

      for (int64_t i = top; i < bottom; i++)
      {
        for (int64_t j = left; j < right; j++)
        {
          Tile tile;
          InitializeTile(level_, j, i, tile);
          tiles_.push_back(tile);
        }
      }

      for (size_t i = 0; i < precache_above_.size(); i++)
      {
        tile_cache_->AddTexture(precache_above_[i].texture);
      }
      precache_above_.clear();

      if (level_ > 0)
      {
        int64_t above_x = std::floor(((longitude + 180.0) / 360.0) * std::pow(2.0, level - 1));
        int64_t above_y = std::floor((1.0 - std::log(std::tan(lat) + 1.0 / std::cos(lat)) / math_util::_pi) / 2.0 * std::pow(2.0, level - 1));

        int64_t above_max_size = std::pow(2, level - 1);

        int64_t above_top = std::max(0L, above_y - (size_ - 1) / 2);
        int64_t above_left = std::max(0L, above_x - (size_ - 1) / 2);

        int64_t above_right = std::min(above_max_size, above_left + size_);
        int64_t above_bottom = std::min(above_max_size, above_top + size_);

        for (int64_t i = above_top; i < above_bottom; i++)
        {
          for (int64_t j = above_left; j < above_right; j++)
          {
            Tile tile;
            InitializeTile(level_ - 1, j, i, tile);
            precache_above_.push_back(tile);
          }
        }
      }
    }
  }

  void TileMapView::Draw()
  {
    glEnable(GL_TEXTURE_2D);

    for (size_t i = 0; i < precache_above_.size(); i++)
    {
      TexturePtr texture = precache_above_[i].texture;

      if (!texture)
      {
        bool failed;
        texture = tile_cache_->GetTexture(precache_above_[i].url_hash, precache_above_[i].url, failed);
        if (failed)
        {
          max_level_ = std::min(max_level_, precache_above_[i].level - 1);
          ROS_WARN("===== SETTING MAX LEVEL TO %d =====", max_level_);
        }
      }

      if (texture)
      {
        glBindTexture(GL_TEXTURE_2D, texture->id);

        glBegin(GL_TRIANGLES);

        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

        glTexCoord2f(0, 1); glVertex2d(precache_above_[i].top_left_t.x(), precache_above_[i].top_left_t.y());
        glTexCoord2f(1, 1); glVertex2d(precache_above_[i].top_right_t.x(), precache_above_[i].top_right_t.y());
        glTexCoord2f(1, 0); glVertex2d(precache_above_[i].bottom_right_t.x(), precache_above_[i].bottom_right_t.y());

        glTexCoord2f(0, 1); glVertex2d(precache_above_[i].top_left_t.x(), precache_above_[i].top_left_t.y());
        glTexCoord2f(1, 0); glVertex2d(precache_above_[i].bottom_right_t.x(), precache_above_[i].bottom_right_t.y());
        glTexCoord2f(0, 0); glVertex2d(precache_above_[i].bottom_left_t.x(), precache_above_[i].bottom_left_t.y());

        glEnd();

        glBindTexture(GL_TEXTURE_2D, 0);
      }
    }

    for (size_t i = 0; i < tiles_.size(); i++)
    {
      TexturePtr texture = tiles_[i].texture;

      if (!texture)
      {
        bool failed;
        texture = tile_cache_->GetTexture(tiles_[i].url_hash, tiles_[i].url, failed);
        if (failed)
        {
          max_level_ = std::min(max_level_, tiles_[i].level - 1);
          ROS_WARN("===== SETTING MAX LEVEL TO %d =====", max_level_);
        }
      }

      if (texture)
      {
        glBindTexture(GL_TEXTURE_2D, texture->id);

        glBegin(GL_TRIANGLES);

        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

        glTexCoord2f(0, 1); glVertex2d(tiles_[i].top_left_t.x(), tiles_[i].top_left_t.y());
        glTexCoord2f(1, 1); glVertex2d(tiles_[i].top_right_t.x(), tiles_[i].top_right_t.y());
        glTexCoord2f(1, 0); glVertex2d(tiles_[i].bottom_right_t.x(), tiles_[i].bottom_right_t.y());

        glTexCoord2f(0, 1); glVertex2d(tiles_[i].top_left_t.x(), tiles_[i].top_left_t.y());
        glTexCoord2f(1, 0); glVertex2d(tiles_[i].bottom_right_t.x(), tiles_[i].bottom_right_t.y());
        glTexCoord2f(0, 0); glVertex2d(tiles_[i].bottom_left_t.x(), tiles_[i].bottom_left_t.y());

        glEnd();

        glBindTexture(GL_TEXTURE_2D, 0);
      }
    }

    glDisable(GL_TEXTURE_2D);
  }

  void TileMapView::ToLatLon(int32_t level, int32_t x, int32_t y, double& latitude, double& longitude)
  {
    double n = std::pow(2, level);
    longitude = (double)x / n * 360.0 - 180.0;

    double r = math_util::_pi - math_util::_2pi * (double)y / n;
    latitude = math_util::_rad_2_deg * std::atan(0.5 * (std::exp(r) - std::exp(-r)));
  }

  void TileMapView::InitializeTile(int32_t level, int64_t x, int64_t y, Tile& tile)
  {
    tile.url = base_url_ +
      boost::lexical_cast<std::string>(level) + "/" +
      boost::lexical_cast<std::string>(x) + "/" +
      boost::lexical_cast<std::string>(y) + extension_;

    tile.url_hash = hash_function_(tile.url);

    tile.level = level;

    bool failed;
    tile.texture = tile_cache_->GetTexture(tile.url_hash, tile.url, failed);
    if (failed)
    {
      max_level_ = std::min(max_level_, level - 1);
      ROS_WARN("===== SETTING MAX LEVEL TO %d =====", max_level_);
    }

    double t_lat, t_lon;
    ToLatLon(level, x, y, t_lat, t_lon);
    tile.top_left = tf::Vector3(t_lon, t_lat, 0);
    tile.top_left_t = transform_ * tile.top_left;

    ToLatLon(level, x + 1, y, t_lat, t_lon);
    tile.top_right = tf::Vector3(t_lon, t_lat, 0);
    tile.top_right_t = transform_ * tile.top_right;

    ToLatLon(level, x + 1, y + 1, t_lat, t_lon);
    tile.bottom_right = tf::Vector3(t_lon, t_lat, 0);
    tile.bottom_right_t = transform_ * tile.bottom_right;

    ToLatLon(level, x, y + 1, t_lat, t_lon);
    tile.bottom_left = tf::Vector3(t_lon, t_lat, 0);
    tile.bottom_left_t = transform_ * tile.bottom_left;
  }
}
<commit_msg>only transform tile map when the transform changes<commit_after>// *****************************************************************************
//
// Copyright (c) 2015, Southwest Research Institute® (SwRI®)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Southwest Research Institute® (SwRI®) nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// *****************************************************************************

#include <tile_map/tile_map_view.h>

#include <cmath>

#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>

#include <GL/gl.h>

#include <ros/ros.h>

#include <math_util/constants.h>
#include <math_util/trig_util.h>
#include <transform_util/earth_constants.h>

#include <tile_map/image_cache.h>

namespace tile_map
{
  TileMapView::TileMapView() :
    base_url_("localhost"),
    extension_(".jpg"),
    max_level_(19),
    level_(-1),
    width_(100),
    height_(100)
  {
    ImageCachePtr image_cache = boost::make_shared<ImageCache>("/tmp/tile_map");
    tile_cache_ = boost::make_shared<TextureCache>(image_cache);
  }

  void TileMapView::SetMaxLevel(int32_t level)
  {
    max_level_ = level;
  }

  void TileMapView::SetExtension(const std::string& extension)
  {
    extension_ = extension;
  }

  void TileMapView::SetBaseUrl(const std::string& url)
  {
    if (base_url_ != url)
    {
      base_url_ = url;
      level_ = -1;
    }
  }

  void TileMapView::SetTransform(const transform_util::Transform& transform)
  {
    if (transform.GetOrigin() == transform_.GetOrigin() &&
        transform.GetOrientation() == transform_.GetOrientation())
    {
      return;
    }

    transform_ = transform;

    for (size_t i = 0; i < tiles_.size(); i++)
    {
      tiles_[i].top_left_t = transform_ * tiles_[i].top_left;
      tiles_[i].top_right_t = transform_ * tiles_[i].top_right;
      tiles_[i].bottom_right_t = transform_ * tiles_[i].bottom_right;
      tiles_[i].bottom_left_t = transform_ * tiles_[i].bottom_left;
    }

    for (size_t i = 0; i < precache_above_.size(); i++)
    {
      precache_above_[i].top_left_t = transform_ * precache_above_[i].top_left;
      precache_above_[i].top_right_t = transform_ * precache_above_[i].top_right;
      precache_above_[i].bottom_right_t = transform_ * precache_above_[i].bottom_right;
      precache_above_[i].bottom_left_t = transform_ * precache_above_[i].bottom_left;
    }
  }

  void TileMapView::SetView(
    double latitude,
    double longitude,
    double scale,
    int32_t width,
    int32_t height)
  {
    latitude = std::max(-90.0, std::min(90.0, latitude));
    longitude = std::max(-180.0, std::min(180.0, longitude));

    double lat = math_util::ToRadians(latitude);

    // Calculate the current zoom level:
    //
    // According to http://wiki.openstreetmap.org/wiki/Zoom_levels:
    //   meters_per_pixel = earth_circumference * cos(lat) / 2^(level + 8)
    //
    // Therefore,
    //   level = log2(earth_circumference * cos(lat) / meters_per_pixel) - 8
    //
    double lat_circumference =
      transform_util::_earth_equator_circumference * std::cos(lat) / scale;
    int32_t level = std::min((double)max_level_, std::max(0.0, std::ceil(std::log(lat_circumference) / std::log(2) - 8)));

    int64_t max_size = std::pow(2, level);

    int64_t center_x = std::min((double)max_size - 1.0, std::floor(((longitude + 180.0) / 360.0) * std::pow(2.0, level)));
    int64_t center_y = std::min((long double)max_size - 1.0, std::floor((1.0 - std::log(std::tan(lat) + 1.0 / std::cos(lat)) / math_util::_pi) / 2.0 * std::pow(2.0, level)));

    width_ = width;
    height_ = height;

    double max_dimension = std::max(width, height);

    double meters_per_pixel = transform_util::_earth_equator_circumference * std::cos(lat) / std::pow(2, level + 8);
    double tile_size = 256.0 * (meters_per_pixel / scale);

    int64_t size = std::max(1.0, std::min((double)max_size, std::ceil(0.5 * max_dimension / tile_size) * 2 + 1));

    if (size > 50)
    {
      ROS_ERROR("Invalid map size: %ld", size);
      return;
    }

    if (size_ != size_ || level_ != level || center_x_ != center_x || center_y_ != center_y)
    {
      size_ = size;
      level_ = level;
      center_x_ = center_x;
      center_y_ = center_y;

      int64_t top = std::max(0L, center_y_ - size_ / 2);
      int64_t left = std::max(0L, center_x_ - size_ / 2);

      int64_t right = std::min(max_size, left + size_);
      int64_t bottom = std::min(max_size, top + size_);

      for (size_t i = 0; i < tiles_.size(); i++)
      {
        tile_cache_->AddTexture(tiles_[i].texture);
      }
      tiles_.clear();

      for (int64_t i = top; i < bottom; i++)
      {
        for (int64_t j = left; j < right; j++)
        {
          Tile tile;
          InitializeTile(level_, j, i, tile);
          tiles_.push_back(tile);
        }
      }

      for (size_t i = 0; i < precache_above_.size(); i++)
      {
        tile_cache_->AddTexture(precache_above_[i].texture);
      }
      precache_above_.clear();

      if (level_ > 0)
      {
        int64_t above_x = std::floor(((longitude + 180.0) / 360.0) * std::pow(2.0, level - 1));
        int64_t above_y = std::floor((1.0 - std::log(std::tan(lat) + 1.0 / std::cos(lat)) / math_util::_pi) / 2.0 * std::pow(2.0, level - 1));

        int64_t above_max_size = std::pow(2, level - 1);

        int64_t above_top = std::max(0L, above_y - (size_ - 1) / 2);
        int64_t above_left = std::max(0L, above_x - (size_ - 1) / 2);

        int64_t above_right = std::min(above_max_size, above_left + size_);
        int64_t above_bottom = std::min(above_max_size, above_top + size_);

        for (int64_t i = above_top; i < above_bottom; i++)
        {
          for (int64_t j = above_left; j < above_right; j++)
          {
            Tile tile;
            InitializeTile(level_ - 1, j, i, tile);
            precache_above_.push_back(tile);
          }
        }
      }
    }
  }

  void TileMapView::Draw()
  {
    glEnable(GL_TEXTURE_2D);

    for (size_t i = 0; i < precache_above_.size(); i++)
    {
      TexturePtr texture = precache_above_[i].texture;

      if (!texture)
      {
        bool failed;
        texture = tile_cache_->GetTexture(precache_above_[i].url_hash, precache_above_[i].url, failed);
        if (failed)
        {
          max_level_ = std::min(max_level_, precache_above_[i].level - 1);
          ROS_WARN("===== SETTING MAX LEVEL TO %d =====", max_level_);
        }
      }

      if (texture)
      {
        glBindTexture(GL_TEXTURE_2D, texture->id);

        glBegin(GL_TRIANGLES);

        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

        glTexCoord2f(0, 1); glVertex2d(precache_above_[i].top_left_t.x(), precache_above_[i].top_left_t.y());
        glTexCoord2f(1, 1); glVertex2d(precache_above_[i].top_right_t.x(), precache_above_[i].top_right_t.y());
        glTexCoord2f(1, 0); glVertex2d(precache_above_[i].bottom_right_t.x(), precache_above_[i].bottom_right_t.y());

        glTexCoord2f(0, 1); glVertex2d(precache_above_[i].top_left_t.x(), precache_above_[i].top_left_t.y());
        glTexCoord2f(1, 0); glVertex2d(precache_above_[i].bottom_right_t.x(), precache_above_[i].bottom_right_t.y());
        glTexCoord2f(0, 0); glVertex2d(precache_above_[i].bottom_left_t.x(), precache_above_[i].bottom_left_t.y());

        glEnd();

        glBindTexture(GL_TEXTURE_2D, 0);
      }
    }

    for (size_t i = 0; i < tiles_.size(); i++)
    {
      TexturePtr texture = tiles_[i].texture;

      if (!texture)
      {
        bool failed;
        texture = tile_cache_->GetTexture(tiles_[i].url_hash, tiles_[i].url, failed);
        if (failed)
        {
          max_level_ = std::min(max_level_, tiles_[i].level - 1);
          ROS_WARN("===== SETTING MAX LEVEL TO %d =====", max_level_);
        }
      }

      if (texture)
      {
        glBindTexture(GL_TEXTURE_2D, texture->id);

        glBegin(GL_TRIANGLES);

        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

        glTexCoord2f(0, 1); glVertex2d(tiles_[i].top_left_t.x(), tiles_[i].top_left_t.y());
        glTexCoord2f(1, 1); glVertex2d(tiles_[i].top_right_t.x(), tiles_[i].top_right_t.y());
        glTexCoord2f(1, 0); glVertex2d(tiles_[i].bottom_right_t.x(), tiles_[i].bottom_right_t.y());

        glTexCoord2f(0, 1); glVertex2d(tiles_[i].top_left_t.x(), tiles_[i].top_left_t.y());
        glTexCoord2f(1, 0); glVertex2d(tiles_[i].bottom_right_t.x(), tiles_[i].bottom_right_t.y());
        glTexCoord2f(0, 0); glVertex2d(tiles_[i].bottom_left_t.x(), tiles_[i].bottom_left_t.y());

        glEnd();

        glBindTexture(GL_TEXTURE_2D, 0);
      }
    }

    glDisable(GL_TEXTURE_2D);
  }

  void TileMapView::ToLatLon(int32_t level, int32_t x, int32_t y, double& latitude, double& longitude)
  {
    double n = std::pow(2, level);
    longitude = (double)x / n * 360.0 - 180.0;

    double r = math_util::_pi - math_util::_2pi * (double)y / n;
    latitude = math_util::_rad_2_deg * std::atan(0.5 * (std::exp(r) - std::exp(-r)));
  }

  void TileMapView::InitializeTile(int32_t level, int64_t x, int64_t y, Tile& tile)
  {
    tile.url = base_url_ +
      boost::lexical_cast<std::string>(level) + "/" +
      boost::lexical_cast<std::string>(x) + "/" +
      boost::lexical_cast<std::string>(y) + extension_;

    tile.url_hash = hash_function_(tile.url);

    tile.level = level;

    bool failed;
    tile.texture = tile_cache_->GetTexture(tile.url_hash, tile.url, failed);
    if (failed)
    {
      max_level_ = std::min(max_level_, level - 1);
      ROS_WARN("===== SETTING MAX LEVEL TO %d =====", max_level_);
    }

    double t_lat, t_lon;
    ToLatLon(level, x, y, t_lat, t_lon);
    tile.top_left = tf::Vector3(t_lon, t_lat, 0);
    tile.top_left_t = transform_ * tile.top_left;

    ToLatLon(level, x + 1, y, t_lat, t_lon);
    tile.top_right = tf::Vector3(t_lon, t_lat, 0);
    tile.top_right_t = transform_ * tile.top_right;

    ToLatLon(level, x + 1, y + 1, t_lat, t_lon);
    tile.bottom_right = tf::Vector3(t_lon, t_lat, 0);
    tile.bottom_right_t = transform_ * tile.bottom_right;

    ToLatLon(level, x, y + 1, t_lat, t_lon);
    tile.bottom_left = tf::Vector3(t_lon, t_lat, 0);
    tile.bottom_left_t = transform_ * tile.bottom_left;
  }
}
<|endoftext|>


<commit_before>/*!
  \copyright (c) RDO-Team, 2011
  \file      main.cpp
  \authors     (rdo@rk9.bmstu.ru)
  \authors     (lord.tiran@gmail.com)
  \date      10.05.2009
  \brief
  \indent    4T
*/

// ---------------------------------------------------------------------------- PCH
// ----------------------------------------------------------------------- INCLUDES
#include <iostream>
#define BOOST_TEST_MODULE RDORuntime_Fuzzy_Test
#include <boost/test/included/unit_test.hpp>
// ----------------------------------------------------------------------- SYNOPSIS
#include "simulator/runtime/rdo_runtime.h"
#include "simulator/runtime/rdo_fuzzy.h"
// --------------------------------------------------------------------------------

OPEN_RDO_RUNTIME_NAMESPACE

BOOST_AUTO_TEST_SUITE(RDORuntime_Fuzzy_Test)

BOOST_AUTO_TEST_CASE(DefineAreaTest)
{
	LPRDORuntime pRuntime = rdo::Factory<RDORuntime>::create();
	BOOST_CHECK(pRuntime);

	LPDefineArea pDefineAreaEmpty = rdo::Factory<DefineArea>::create();
	BOOST_CHECK(pDefineAreaEmpty);

	LPDefineArea pDefineArea = rdo::Factory<DefineArea>::create(1.0, 5.0);
	BOOST_CHECK(pDefineArea);

	RDOValue testValueFalse = 100;
	RDOValue testValueTrue = 3.0;

	BOOST_CHECK(pDefineArea->inDomain(testValueFalse));
	BOOST_CHECK(pDefineArea->inDomain(testValueTrue));
}

BOOST_AUTO_TEST_SUITE_END() // RDORuntime_Fuzzy_Test

CLOSE_RDO_RUNTIME_NAMESPACE
<commit_msg> - исправления<commit_after>/*!
  \copyright (c) RDO-Team, 2011
  \file      main.cpp
  \authors     (rdo@rk9.bmstu.ru)
  \authors     (lord.tiran@gmail.com)
  \date      10.05.2009
  \brief
  \indent    4T
*/

// ---------------------------------------------------------------------------- PCH
// ----------------------------------------------------------------------- INCLUDES
#include <iostream>
#define BOOST_TEST_MODULE RDORuntime_Fuzzy_Test
#include <boost/test/included/unit_test.hpp>
// ----------------------------------------------------------------------- SYNOPSIS
#include "simulator/runtime/rdo_runtime.h"
#include "simulator/runtime/rdo_fuzzy.h"
// --------------------------------------------------------------------------------

OPEN_RDO_RUNTIME_NAMESPACE

BOOST_AUTO_TEST_SUITE(RDORuntime_Fuzzy_Test)

BOOST_AUTO_TEST_CASE(DefineAreaTest)
{
	LPRDORuntime pRuntime = rdo::Factory<RDORuntime>::create();
	BOOST_CHECK(pRuntime);

	LPDefineArea pDefineAreaEmpty = rdo::Factory<DefineArea>::create();
	BOOST_CHECK(pDefineAreaEmpty);

	LPDefineArea pDefineArea = rdo::Factory<DefineArea>::create(1.0, 5.0);
	BOOST_CHECK(pDefineArea);

	RDOValue testValueFalse = 100;
	RDOValue testValueTrue = 3.0;

	BOOST_CHECK_EQUAL(pDefineArea->inDomain(testValueFalse), false);
	BOOST_CHECK(pDefineArea->inDomain(testValueTrue));
}

BOOST_AUTO_TEST_SUITE_END() // RDORuntime_Fuzzy_Test

CLOSE_RDO_RUNTIME_NAMESPACE
<|endoftext|>


<commit_before>// Copyright (c) 2012 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/metrics/stats_counters.h"
#include "base/metrics/stats_table.h"
#include "base/shared_memory.h"
#include "base/stringprintf.h"
#include "base/string_piece.h"
#include "base/test/multiprocess_test.h"
#include "base/threading/platform_thread.h"
#include "base/threading/simple_thread.h"
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"

namespace base {

class StatsTableTest : public MultiProcessTest {
 public:
  void DeleteShmem(const std::string& name) {
    SharedMemory mem;
    mem.Delete(name);
  }
};

// Open a StatsTable and verify that we can write to each of the
// locations in the table.
TEST_F(StatsTableTest, VerifySlots) {
  const std::string kTableName = "VerifySlotsStatTable";
  const int kMaxThreads = 1;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);

  // Register a single thread.
  std::string thread_name = "mainThread";
  int slot_id = table.RegisterThread(thread_name);
  EXPECT_NE(slot_id, 0);

  // Fill up the table with counters.
  std::string counter_base_name = "counter";
  for (int index = 0; index < kMaxCounter; index++) {
    std::string counter_name = counter_base_name;
    base::StringAppendF(&counter_name, "counter.ctr%d", index);
    int counter_id = table.FindCounter(counter_name);
    EXPECT_GT(counter_id, 0);
  }

  // Try to allocate an additional thread.  Verify it fails.
  slot_id = table.RegisterThread("too many threads");
  EXPECT_EQ(slot_id, 0);

  // Try to allocate an additional counter.  Verify it fails.
  int counter_id = table.FindCounter(counter_base_name);
  EXPECT_EQ(counter_id, 0);

  DeleteShmem(kTableName);
}

// CounterZero will continually be set to 0.
const std::string kCounterZero = "CounterZero";
// Counter1313 will continually be set to 1313.
const std::string kCounter1313 = "Counter1313";
// CounterIncrement will be incremented each time.
const std::string kCounterIncrement = "CounterIncrement";
// CounterDecrement will be decremented each time.
const std::string kCounterDecrement = "CounterDecrement";
// CounterMixed will be incremented by odd numbered threads and
// decremented by even threads.
const std::string kCounterMixed = "CounterMixed";
// The number of thread loops that we will do.
const int kThreadLoops = 100;

class StatsTableThread : public SimpleThread {
 public:
  StatsTableThread(std::string name, int id)
      : SimpleThread(name),
        id_(id) {}

  virtual void Run() OVERRIDE;

 private:
  int id_;
};

void StatsTableThread::Run() {
  // Each thread will open the shared memory and set counters
  // concurrently in a loop.  We'll use some pauses to
  // mixup the thread scheduling.

  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);
  for (int index = 0; index < kThreadLoops; index++) {
    StatsCounter mixed_counter(kCounterMixed);  // create this one in the loop
    zero_counter.Set(0);
    lucky13_counter.Set(1313);
    increment_counter.Increment();
    decrement_counter.Decrement();
    if (id_ % 2)
      mixed_counter.Decrement();
    else
      mixed_counter.Increment();
    PlatformThread::Sleep(TimeDelta::FromMilliseconds(index % 10));
  }
}

// Create a few threads and have them poke on their counters.
// See http://crbug.com/10611 for more information.
#if defined(OS_MACOSX)
#define MAYBE_MultipleThreads DISABLED_MultipleThreads
#else
#define MAYBE_MultipleThreads MultipleThreads
#endif
TEST_F(StatsTableTest, MAYBE_MultipleThreads) {
  // Create a stats table.
  const std::string kTableName = "MultipleThreadStatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  EXPECT_EQ(0, table.CountThreadsRegistered());

  // Spin up a set of threads to go bang on the various counters.
  // After we join the threads, we'll make sure the counters
  // contain the values we expected.
  StatsTableThread* threads[kMaxThreads];

  // Spawn the threads.
  for (int index = 0; index < kMaxThreads; index++) {
    threads[index] = new StatsTableThread("MultipleThreadsTest", index);
    threads[index]->Start();
  }

  // Wait for the threads to finish.
  for (int index = 0; index < kMaxThreads; index++) {
    threads[index]->Join();
    delete threads[index];
  }

  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);
  StatsCounter mixed_counter(kCounterMixed);

  // Verify the various counters are correct.
  std::string name;
  name = "c:" + kCounterZero;
  EXPECT_EQ(0, table.GetCounterValue(name));
  name = "c:" + kCounter1313;
  EXPECT_EQ(1313 * kMaxThreads,
      table.GetCounterValue(name));
  name = "c:" + kCounterIncrement;
  EXPECT_EQ(kMaxThreads * kThreadLoops,
      table.GetCounterValue(name));
  name = "c:" + kCounterDecrement;
  EXPECT_EQ(-kMaxThreads * kThreadLoops,
      table.GetCounterValue(name));
  name = "c:" + kCounterMixed;
  EXPECT_EQ((kMaxThreads % 2) * kThreadLoops,
      table.GetCounterValue(name));
  EXPECT_EQ(0, table.CountThreadsRegistered());

  DeleteShmem(kTableName);
}

const std::string kMPTableName = "MultipleProcessStatTable";

MULTIPROCESS_TEST_MAIN(StatsTableMultipleProcessMain) {
  // Each process will open the shared memory and set counters
  // concurrently in a loop.  We'll use some pauses to
  // mixup the scheduling.

  StatsTable table(kMPTableName, 0, 0);
  StatsTable::set_current(&table);
  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);
  for (int index = 0; index < kThreadLoops; index++) {
    zero_counter.Set(0);
    lucky13_counter.Set(1313);
    increment_counter.Increment();
    decrement_counter.Decrement();
    PlatformThread::Sleep(TimeDelta::FromMilliseconds(index % 10));
  }
  return 0;
}

// Create a few processes and have them poke on their counters.
// This test is slow and flaky http://crbug.com/10611
TEST_F(StatsTableTest, DISABLED_MultipleProcesses) {
  // Create a stats table.
  const int kMaxProcs = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kMPTableName);
  StatsTable table(kMPTableName, kMaxProcs, kMaxCounter);
  StatsTable::set_current(&table);
  EXPECT_EQ(0, table.CountThreadsRegistered());

  // Spin up a set of processes to go bang on the various counters.
  // After we join the processes, we'll make sure the counters
  // contain the values we expected.
  ProcessHandle procs[kMaxProcs];

  // Spawn the processes.
  for (int16 index = 0; index < kMaxProcs; index++) {
    procs[index] = this->SpawnChild("StatsTableMultipleProcessMain", false);
    EXPECT_NE(kNullProcessHandle, procs[index]);
  }

  // Wait for the processes to finish.
  for (int index = 0; index < kMaxProcs; index++) {
    EXPECT_TRUE(WaitForSingleProcess(procs[index], 60 * 1000));
    CloseProcessHandle(procs[index]);
  }

  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);

  // Verify the various counters are correct.
  std::string name;
  name = "c:" + kCounterZero;
  EXPECT_EQ(0, table.GetCounterValue(name));
  name = "c:" + kCounter1313;
  EXPECT_EQ(1313 * kMaxProcs,
      table.GetCounterValue(name));
  name = "c:" + kCounterIncrement;
  EXPECT_EQ(kMaxProcs * kThreadLoops,
      table.GetCounterValue(name));
  name = "c:" + kCounterDecrement;
  EXPECT_EQ(-kMaxProcs * kThreadLoops,
      table.GetCounterValue(name));
  EXPECT_EQ(0, table.CountThreadsRegistered());

  DeleteShmem(kMPTableName);
}

class MockStatsCounter : public StatsCounter {
 public:
  explicit MockStatsCounter(const std::string& name)
      : StatsCounter(name) {}
  int* Pointer() { return GetPtr(); }
};

// Test some basic StatsCounter operations
TEST_F(StatsTableTest, StatsCounter) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  MockStatsCounter foo("foo");

  // Test initial state.
  EXPECT_TRUE(foo.Enabled());
  ASSERT_NE(foo.Pointer(), static_cast<int*>(0));
  EXPECT_EQ(0, *(foo.Pointer()));
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));

  // Test Increment.
  while (*(foo.Pointer()) < 123) foo.Increment();
  EXPECT_EQ(123, table.GetCounterValue("c:foo"));
  foo.Add(0);
  EXPECT_EQ(123, table.GetCounterValue("c:foo"));
  foo.Add(-1);
  EXPECT_EQ(122, table.GetCounterValue("c:foo"));

  // Test Set.
  foo.Set(0);
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));
  foo.Set(100);
  EXPECT_EQ(100, table.GetCounterValue("c:foo"));
  foo.Set(-1);
  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
  foo.Set(0);
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));

  // Test Decrement.
  foo.Subtract(1);
  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
  foo.Subtract(0);
  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
  foo.Subtract(-1);
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));

  DeleteShmem(kTableName);
}

class MockStatsCounterTimer : public StatsCounterTimer {
 public:
  explicit MockStatsCounterTimer(const std::string& name)
      : StatsCounterTimer(name) {}

  TimeTicks start_time() { return start_time_; }
  TimeTicks stop_time() { return stop_time_; }
};

// Test some basic StatsCounterTimer operations
TEST_F(StatsTableTest, StatsCounterTimer) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  MockStatsCounterTimer bar("bar");

  // Test initial state.
  EXPECT_FALSE(bar.Running());
  EXPECT_TRUE(bar.start_time().is_null());
  EXPECT_TRUE(bar.stop_time().is_null());

  const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);

  // Do some timing.
  bar.Start();
  PlatformThread::Sleep(kDuration);
  bar.Stop();
  EXPECT_GT(table.GetCounterValue("t:bar"), 0);
  EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:bar"));

  // Verify that timing again is additive.
  bar.Start();
  PlatformThread::Sleep(kDuration);
  bar.Stop();
  EXPECT_GT(table.GetCounterValue("t:bar"), 0);
  EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:bar"));
}

// Test some basic StatsRate operations
// Usually fails on all platforms when run alone. http://crbug.com/131024
TEST_F(StatsTableTest, DISABLED_StatsRate) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  StatsRate baz("baz");

  // Test initial state.
  EXPECT_FALSE(baz.Running());
  EXPECT_EQ(0, table.GetCounterValue("c:baz"));
  EXPECT_EQ(0, table.GetCounterValue("t:baz"));

  const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);

  // Do some timing.
  baz.Start();
  PlatformThread::Sleep(kDuration);
  baz.Stop();
  EXPECT_EQ(1, table.GetCounterValue("c:baz"));
  EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:baz"));

  // Verify that timing again is additive.
  baz.Start();
  PlatformThread::Sleep(kDuration);
  baz.Stop();
  EXPECT_EQ(2, table.GetCounterValue("c:baz"));
  EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:baz"));
}

// Test some basic StatsScope operations
TEST_F(StatsTableTest, StatsScope) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  StatsCounterTimer foo("foo");
  StatsRate bar("bar");

  // Test initial state.
  EXPECT_EQ(0, table.GetCounterValue("t:foo"));
  EXPECT_EQ(0, table.GetCounterValue("t:bar"));
  EXPECT_EQ(0, table.GetCounterValue("c:bar"));

  const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);

  // Try a scope.
  {
    StatsScope<StatsCounterTimer> timer(foo);
    StatsScope<StatsRate> timer2(bar);
    PlatformThread::Sleep(kDuration);
  }
  EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:foo"));
  EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:bar"));
  EXPECT_EQ(1, table.GetCounterValue("c:bar"));

  // Try a second scope.
  {
    StatsScope<StatsCounterTimer> timer(foo);
    StatsScope<StatsRate> timer2(bar);
    PlatformThread::Sleep(kDuration);
  }
  EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:foo"));
  EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:bar"));
  EXPECT_EQ(2, table.GetCounterValue("c:bar"));

  DeleteShmem(kTableName);
}

}  // namespace base
<commit_msg>Add shared memory cleanup before/after all tests<commit_after>// Copyright (c) 2012 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/metrics/stats_counters.h"
#include "base/metrics/stats_table.h"
#include "base/shared_memory.h"
#include "base/stringprintf.h"
#include "base/string_piece.h"
#include "base/test/multiprocess_test.h"
#include "base/threading/platform_thread.h"
#include "base/threading/simple_thread.h"
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"

namespace base {

class StatsTableTest : public MultiProcessTest {
 public:
  void DeleteShmem(const std::string& name) {
    SharedMemory mem;
    mem.Delete(name);
  }
};

// Open a StatsTable and verify that we can write to each of the
// locations in the table.
TEST_F(StatsTableTest, VerifySlots) {
  const std::string kTableName = "VerifySlotsStatTable";
  const int kMaxThreads = 1;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);

  // Register a single thread.
  std::string thread_name = "mainThread";
  int slot_id = table.RegisterThread(thread_name);
  EXPECT_NE(slot_id, 0);

  // Fill up the table with counters.
  std::string counter_base_name = "counter";
  for (int index = 0; index < kMaxCounter; index++) {
    std::string counter_name = counter_base_name;
    base::StringAppendF(&counter_name, "counter.ctr%d", index);
    int counter_id = table.FindCounter(counter_name);
    EXPECT_GT(counter_id, 0);
  }

  // Try to allocate an additional thread.  Verify it fails.
  slot_id = table.RegisterThread("too many threads");
  EXPECT_EQ(slot_id, 0);

  // Try to allocate an additional counter.  Verify it fails.
  int counter_id = table.FindCounter(counter_base_name);
  EXPECT_EQ(counter_id, 0);

  DeleteShmem(kTableName);
}

// CounterZero will continually be set to 0.
const std::string kCounterZero = "CounterZero";
// Counter1313 will continually be set to 1313.
const std::string kCounter1313 = "Counter1313";
// CounterIncrement will be incremented each time.
const std::string kCounterIncrement = "CounterIncrement";
// CounterDecrement will be decremented each time.
const std::string kCounterDecrement = "CounterDecrement";
// CounterMixed will be incremented by odd numbered threads and
// decremented by even threads.
const std::string kCounterMixed = "CounterMixed";
// The number of thread loops that we will do.
const int kThreadLoops = 100;

class StatsTableThread : public SimpleThread {
 public:
  StatsTableThread(std::string name, int id)
      : SimpleThread(name),
        id_(id) {}

  virtual void Run() OVERRIDE;

 private:
  int id_;
};

void StatsTableThread::Run() {
  // Each thread will open the shared memory and set counters
  // concurrently in a loop.  We'll use some pauses to
  // mixup the thread scheduling.

  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);
  for (int index = 0; index < kThreadLoops; index++) {
    StatsCounter mixed_counter(kCounterMixed);  // create this one in the loop
    zero_counter.Set(0);
    lucky13_counter.Set(1313);
    increment_counter.Increment();
    decrement_counter.Decrement();
    if (id_ % 2)
      mixed_counter.Decrement();
    else
      mixed_counter.Increment();
    PlatformThread::Sleep(TimeDelta::FromMilliseconds(index % 10));
  }
}

// Create a few threads and have them poke on their counters.
// See http://crbug.com/10611 for more information.
#if defined(OS_MACOSX)
#define MAYBE_MultipleThreads DISABLED_MultipleThreads
#else
#define MAYBE_MultipleThreads MultipleThreads
#endif
TEST_F(StatsTableTest, MAYBE_MultipleThreads) {
  // Create a stats table.
  const std::string kTableName = "MultipleThreadStatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  EXPECT_EQ(0, table.CountThreadsRegistered());

  // Spin up a set of threads to go bang on the various counters.
  // After we join the threads, we'll make sure the counters
  // contain the values we expected.
  StatsTableThread* threads[kMaxThreads];

  // Spawn the threads.
  for (int index = 0; index < kMaxThreads; index++) {
    threads[index] = new StatsTableThread("MultipleThreadsTest", index);
    threads[index]->Start();
  }

  // Wait for the threads to finish.
  for (int index = 0; index < kMaxThreads; index++) {
    threads[index]->Join();
    delete threads[index];
  }

  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);
  StatsCounter mixed_counter(kCounterMixed);

  // Verify the various counters are correct.
  std::string name;
  name = "c:" + kCounterZero;
  EXPECT_EQ(0, table.GetCounterValue(name));
  name = "c:" + kCounter1313;
  EXPECT_EQ(1313 * kMaxThreads,
      table.GetCounterValue(name));
  name = "c:" + kCounterIncrement;
  EXPECT_EQ(kMaxThreads * kThreadLoops,
      table.GetCounterValue(name));
  name = "c:" + kCounterDecrement;
  EXPECT_EQ(-kMaxThreads * kThreadLoops,
      table.GetCounterValue(name));
  name = "c:" + kCounterMixed;
  EXPECT_EQ((kMaxThreads % 2) * kThreadLoops,
      table.GetCounterValue(name));
  EXPECT_EQ(0, table.CountThreadsRegistered());

  DeleteShmem(kTableName);
}

const std::string kMPTableName = "MultipleProcessStatTable";

MULTIPROCESS_TEST_MAIN(StatsTableMultipleProcessMain) {
  // Each process will open the shared memory and set counters
  // concurrently in a loop.  We'll use some pauses to
  // mixup the scheduling.

  StatsTable table(kMPTableName, 0, 0);
  StatsTable::set_current(&table);
  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);
  for (int index = 0; index < kThreadLoops; index++) {
    zero_counter.Set(0);
    lucky13_counter.Set(1313);
    increment_counter.Increment();
    decrement_counter.Decrement();
    PlatformThread::Sleep(TimeDelta::FromMilliseconds(index % 10));
  }
  return 0;
}

// Create a few processes and have them poke on their counters.
// This test is slow and flaky http://crbug.com/10611
TEST_F(StatsTableTest, DISABLED_MultipleProcesses) {
  // Create a stats table.
  const int kMaxProcs = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kMPTableName);
  StatsTable table(kMPTableName, kMaxProcs, kMaxCounter);
  StatsTable::set_current(&table);
  EXPECT_EQ(0, table.CountThreadsRegistered());

  // Spin up a set of processes to go bang on the various counters.
  // After we join the processes, we'll make sure the counters
  // contain the values we expected.
  ProcessHandle procs[kMaxProcs];

  // Spawn the processes.
  for (int16 index = 0; index < kMaxProcs; index++) {
    procs[index] = this->SpawnChild("StatsTableMultipleProcessMain", false);
    EXPECT_NE(kNullProcessHandle, procs[index]);
  }

  // Wait for the processes to finish.
  for (int index = 0; index < kMaxProcs; index++) {
    EXPECT_TRUE(WaitForSingleProcess(procs[index], 60 * 1000));
    CloseProcessHandle(procs[index]);
  }

  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);

  // Verify the various counters are correct.
  std::string name;
  name = "c:" + kCounterZero;
  EXPECT_EQ(0, table.GetCounterValue(name));
  name = "c:" + kCounter1313;
  EXPECT_EQ(1313 * kMaxProcs,
      table.GetCounterValue(name));
  name = "c:" + kCounterIncrement;
  EXPECT_EQ(kMaxProcs * kThreadLoops,
      table.GetCounterValue(name));
  name = "c:" + kCounterDecrement;
  EXPECT_EQ(-kMaxProcs * kThreadLoops,
      table.GetCounterValue(name));
  EXPECT_EQ(0, table.CountThreadsRegistered());

  DeleteShmem(kMPTableName);
}

class MockStatsCounter : public StatsCounter {
 public:
  explicit MockStatsCounter(const std::string& name)
      : StatsCounter(name) {}
  int* Pointer() { return GetPtr(); }
};

// Test some basic StatsCounter operations
TEST_F(StatsTableTest, StatsCounter) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  MockStatsCounter foo("foo");

  // Test initial state.
  EXPECT_TRUE(foo.Enabled());
  ASSERT_NE(foo.Pointer(), static_cast<int*>(0));
  EXPECT_EQ(0, *(foo.Pointer()));
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));

  // Test Increment.
  while (*(foo.Pointer()) < 123) foo.Increment();
  EXPECT_EQ(123, table.GetCounterValue("c:foo"));
  foo.Add(0);
  EXPECT_EQ(123, table.GetCounterValue("c:foo"));
  foo.Add(-1);
  EXPECT_EQ(122, table.GetCounterValue("c:foo"));

  // Test Set.
  foo.Set(0);
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));
  foo.Set(100);
  EXPECT_EQ(100, table.GetCounterValue("c:foo"));
  foo.Set(-1);
  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
  foo.Set(0);
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));

  // Test Decrement.
  foo.Subtract(1);
  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
  foo.Subtract(0);
  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
  foo.Subtract(-1);
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));

  DeleteShmem(kTableName);
}

class MockStatsCounterTimer : public StatsCounterTimer {
 public:
  explicit MockStatsCounterTimer(const std::string& name)
      : StatsCounterTimer(name) {}

  TimeTicks start_time() { return start_time_; }
  TimeTicks stop_time() { return stop_time_; }
};

// Test some basic StatsCounterTimer operations
TEST_F(StatsTableTest, StatsCounterTimer) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  MockStatsCounterTimer bar("bar");

  // Test initial state.
  EXPECT_FALSE(bar.Running());
  EXPECT_TRUE(bar.start_time().is_null());
  EXPECT_TRUE(bar.stop_time().is_null());

  const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);

  // Do some timing.
  bar.Start();
  PlatformThread::Sleep(kDuration);
  bar.Stop();
  EXPECT_GT(table.GetCounterValue("t:bar"), 0);
  EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:bar"));

  // Verify that timing again is additive.
  bar.Start();
  PlatformThread::Sleep(kDuration);
  bar.Stop();
  EXPECT_GT(table.GetCounterValue("t:bar"), 0);
  EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:bar"));
  DeleteShmem(kTableName);
}

// Test some basic StatsRate operations
TEST_F(StatsTableTest, StatsRate) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  StatsRate baz("baz");

  // Test initial state.
  EXPECT_FALSE(baz.Running());
  EXPECT_EQ(0, table.GetCounterValue("c:baz"));
  EXPECT_EQ(0, table.GetCounterValue("t:baz"));

  const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);

  // Do some timing.
  baz.Start();
  PlatformThread::Sleep(kDuration);
  baz.Stop();
  EXPECT_EQ(1, table.GetCounterValue("c:baz"));
  EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:baz"));

  // Verify that timing again is additive.
  baz.Start();
  PlatformThread::Sleep(kDuration);
  baz.Stop();
  EXPECT_EQ(2, table.GetCounterValue("c:baz"));
  EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:baz"));
  DeleteShmem(kTableName);
}

// Test some basic StatsScope operations
TEST_F(StatsTableTest, StatsScope) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  StatsCounterTimer foo("foo");
  StatsRate bar("bar");

  // Test initial state.
  EXPECT_EQ(0, table.GetCounterValue("t:foo"));
  EXPECT_EQ(0, table.GetCounterValue("t:bar"));
  EXPECT_EQ(0, table.GetCounterValue("c:bar"));

  const TimeDelta kDuration = TimeDelta::FromMilliseconds(100);

  // Try a scope.
  {
    StatsScope<StatsCounterTimer> timer(foo);
    StatsScope<StatsRate> timer2(bar);
    PlatformThread::Sleep(kDuration);
  }
  EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:foo"));
  EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:bar"));
  EXPECT_EQ(1, table.GetCounterValue("c:bar"));

  // Try a second scope.
  {
    StatsScope<StatsCounterTimer> timer(foo);
    StatsScope<StatsRate> timer2(bar);
    PlatformThread::Sleep(kDuration);
  }
  EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:foo"));
  EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:bar"));
  EXPECT_EQ(2, table.GetCounterValue("c:bar"));

  DeleteShmem(kTableName);
}

}  // namespace base
<|endoftext|>


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

  This source file is part of the ChemData project.

  Copyright 2012 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

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

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

#include "mongodatabase.h"

#include "kmeansclusteringdialog.h"
#include "ui_kmeansclusteringdialog.h"

#include <QtGui>

#include <QVTKWidget.h>

#include <vtkNew.h>
#include <vtkTable.h>
#include <vtkChartXYZ.h>
#include <vtkIntArray.h>
#include <vtkFloatArray.h>
#include <vtkContextView.h>
#include <vtkLookupTable.h>
#include <vtkContextScene.h>
#include <vtkPlotPoints3D.h>
#include <vtkRenderWindow.h>
#include <vtkSmartPointer.h>
#include <vtkKMeansStatistics.h>

#include <chemkit/molecule.h>
#include <chemkit/moleculardescriptor.h>

// avoid shadow warnings from Qt's foreach by using Boost's
#undef foreach
#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH

class KMeansClusteringDialogPrivate
{
public:
  QVTKWidget *vtkWidget;
  int kValue;
  std::vector<MoleculeRef> molecules;
  vtkSmartPointer<vtkTable> table;
  vtkNew<vtkContextView> chartView;
  vtkNew<vtkChartXYZ> chart;
  vtkPlotPoints3D *plot;
  boost::array<std::string, 3> descriptors;
  vtkNew<vtkLookupTable> lut;
};

KMeansClusteringDialog::KMeansClusteringDialog(QWidget *parent_)
  : QDialog(parent_),
    d(new KMeansClusteringDialogPrivate),
    ui(new Ui::KMeansClusteringDialog)
{
  // setup ui
  ui->setupUi(this);

  // setup descriptors
  setupDescriptors();

  // setup vtk widget
  d->vtkWidget = new QVTKWidget(this);
  d->chartView->SetInteractor(d->vtkWidget->GetInteractor());
  d->vtkWidget->SetRenderWindow(d->chartView->GetRenderWindow());
  ui->viewFrameLayout->addWidget(d->vtkWidget);

  // setup chart xyz
  d->plot = 0;
  d->chart->SetFitToScene(true);
  d->chart->SetDecorateAxes(true);
  d->chart->SetGeometry(vtkRectf(0, 0, 600, 600));

  // setup chart view
  d->chartView->GetScene()->AddItem(d->chart.GetPointer());

  // setup k-means statistics
  d->kValue = 3;
  ui->kValueSpinBox->setValue(d->kValue);

  // render
  d->vtkWidget->update();

  // connect signals
  connect(ui->kValueSpinBox, SIGNAL(valueChanged(int)),
          this, SLOT(kValueSpinBoxChanged(int)));
  connect(ui->xDescriptorComboBox, SIGNAL(currentIndexChanged(QString)),
          this, SLOT(xDescriptorChanged(QString)));
  connect(ui->yDescriptorComboBox, SIGNAL(currentIndexChanged(QString)),
          this, SLOT(yDescriptorChanged(QString)));
  connect(ui->zDescriptorComboBox, SIGNAL(currentIndexChanged(QString)),
          this, SLOT(zDescriptorChanged(QString)));
  connect(d->vtkWidget, SIGNAL(mouseEvent(QMouseEvent*)),
          this, SLOT(viewMouseEvent(QMouseEvent*)));
}

KMeansClusteringDialog::~KMeansClusteringDialog()
{
  delete d;
  delete ui;
}

void KMeansClusteringDialog::setMolecules(const std::vector<MoleculeRef> &molecules_)
{
  // display progress dialog
  QProgressDialog progressDialog("Calculating Descriptors",
                                 "Cancel",
                                 0,
                                 molecules_.size(),
                                 this);

  // pop-up progress dialog immediately
  progressDialog.setMinimumDuration(0);

  // connect to the database
  MongoDatabase *db = MongoDatabase::instance();

  // set molecules
  d->molecules = molecules_;

  // remove old plot
  if (d->plot) {
    d->chart->ClearPlots();
    d->plot->Delete();
    d->plot = 0;
  }

  // create table for the descriptors
  d->table = vtkSmartPointer<vtkTable>::New();

  // setup descriptor arrays
  boost::array<vtkFloatArray *, 3> arrays;
  for (size_t i = 0; i < 3; i++) {
    vtkFloatArray *array = vtkFloatArray::New();
    array->SetName(d->descriptors[i].c_str());
    arrays[i] = array;
    d->table->AddColumn(array);
    array->Delete();
  }

  // setup color array
  vtkIntArray *colorArray = vtkIntArray::New();
  colorArray->SetName("color");
  colorArray->SetNumberOfComponents(1);
  d->table->AddColumn(colorArray);
  colorArray->Delete();

  // calculate descriptors
  foreach (const MoleculeRef &ref, molecules_) {
    // stop calculating if the user clicked cancel
    if(progressDialog.wasCanceled())
      break;

    // create molecule object
    boost::shared_ptr<const chemkit::Molecule> molecule = db->createMolecule(ref);

    // calculate descriptors for the molecule
    for (size_t i = 0; i < 3; i++)
      arrays[i]->InsertNextValue(molecule->descriptor(d->descriptors[i]).toFloat());

    // set cluster to 0 (will be set to its real value later by running k-means)
    colorArray->InsertNextValue(0);

    // update progress dialog
    progressDialog.setValue(progressDialog.value() + 1);
  }

  // run k-means statstics
  runKMeansStatistics();

  // setup plot
  d->plot = vtkPlotPoints3D::New();
  d->plot->SetInputData(d->table.GetPointer(),
                        d->descriptors[0],
                        d->descriptors[1],
                        d->descriptors[2],
                        "color");

  // setup chart
  d->chart->AddPlot(d->plot);

  // update bounds and display chart
  d->chart->RecalculateBounds();
  d->chart->RecalculateTransform();
  d->vtkWidget->update();
}

std::vector<MoleculeRef> KMeansClusteringDialog::molecules() const
{
  return d->molecules;
}

void KMeansClusteringDialog::setKValue(int k)
{
  // set k value
  d->kValue = k;

  // run k-means statistics
  runKMeansStatistics();

  // update plot with new colors (i wish this was easier)
  if (d->plot) {
    d->chart->ClearPlots();
    d->plot->Delete();
    d->plot = vtkPlotPoints3D::New();
    d->plot->SetInputData(d->table.GetPointer(),
                          d->descriptors[0],
                          d->descriptors[1],
                          d->descriptors[2],
                          "color");
    d->chart->AddPlot(d->plot);
    d->chart->RecalculateBounds();
    d->chart->RecalculateTransform();
    d->vtkWidget->update();
  }
}

int KMeansClusteringDialog::kValue() const
{
  return d->kValue;
}

void KMeansClusteringDialog::setDescriptor(int index, const QString &descriptor_)
{
  if (index < 0 || index > 2)
    return;

  // set descriptor name
  d->descriptors[index] = descriptor_.toStdString();

  // update
  setMolecules(d->molecules);
}

QString KMeansClusteringDialog::descriptor(int index)
{
  if (index >= 0 && index < 3)
    return QString::fromStdString(d->descriptors[index]);
  else
    return QString();
}

void KMeansClusteringDialog::kValueSpinBoxChanged(int value)
{
  setKValue(value);
}

void KMeansClusteringDialog::resetCamera()
{
  d->vtkWidget->update();
}

void KMeansClusteringDialog::xDescriptorChanged(const QString &descriptor_)
{
  setDescriptor(0, descriptor_);
}

void KMeansClusteringDialog::yDescriptorChanged(const QString &descriptor_)
{
  setDescriptor(1, descriptor_);
}

void KMeansClusteringDialog::zDescriptorChanged(const QString &descriptor_)
{
  setDescriptor(2, descriptor_);
}

void KMeansClusteringDialog::viewMouseEvent(QMouseEvent *event_)
{
  // not sure how to implement this with vtkChartXYZ
  (void) event_;

//  if (event_->button() == Qt::LeftButton &&
//      event_->type() == QMouseEvent::MouseButtonDblClick) {
//    vtkNew<vtkPointPicker> picker;
//    vtkRenderer *renderer = d->renderer.GetPointer();
//    vtkRenderWindowInteractor *interactor = d->vtkWidget->GetInteractor();

//    int *pos_ = interactor->GetEventPosition();

//    if (picker->Pick(pos_[0], pos_[1], 0, renderer)) {
//      vtkIdType id = picker->GetPointId();

//      if (id != -1)
//        emit moleculeDoubleClicked(id);
//    }
//  }
}

void KMeansClusteringDialog::setupDescriptors()
{
  // populate combo boxes
  std::vector<std::string> descriptors =
    chemkit::MolecularDescriptor::descriptors();

  // create map of descriptor dimensionality to list of descriptor names
  QMap<int, QStringList> descriptorsMap;

  foreach (const std::string &name, descriptors) {
    boost::scoped_ptr<chemkit::MolecularDescriptor>
      descriptor_(chemkit::MolecularDescriptor::create(name));

    int dimensionality = descriptor_->dimensionality();

    if (dimensionality == -1) {
      // descriptors with unknown dimensionality have a value of -1 so we
      // set it to INT_MAX in order to put them at the bottom of the list
      dimensionality = std::numeric_limits<int>::max();
    }

    descriptorsMap[dimensionality].append(name.c_str());
  }

  // list of the combo boxes for each of the x, y and z axes
  QList<QComboBox *> comboBoxes;
  comboBoxes.append(ui->xDescriptorComboBox);
  comboBoxes.append(ui->yDescriptorComboBox);
  comboBoxes.append(ui->zDescriptorComboBox);

  // insert each descriptor into each combo box grouped by dimensionality
  foreach (int key, descriptorsMap.keys()) {
    int dimensionality = key;
    const QStringList &names = descriptorsMap[key];

    foreach (QComboBox *comboBox, comboBoxes) {
      // insert title
      int titleIndex = comboBox->count();
      if (dimensionality != std::numeric_limits<int>::max())
        comboBox->addItem(tr("%1D Descriptors").arg(dimensionality));
      else
        comboBox->addItem(tr("Other Descriptors"));

      // set bold font for title and make it non-selectable
      QStandardItem *item =
        qobject_cast<QStandardItemModel *>(comboBox->model())->item(titleIndex);

      if (item) {
        QFont font_ = item->font();
        font_.setBold(true);
        item->setFont(font_);
        item->setFlags(Qt::ItemIsEnabled);
      }

      // add a separator
      comboBox->insertSeparator(comboBox->count());

      // insert name of each descriptor
      foreach (const QString &name, names)
        comboBox->addItem(name);
    }
  }

  // default to X = mass, Y = tpsa, and Z = vabc
  int massIndex = ui->xDescriptorComboBox->findText("mass");
  ui->xDescriptorComboBox->setCurrentIndex(massIndex);
  d->descriptors[0] = "mass";
  int tpsaIndex = ui->yDescriptorComboBox->findText("tpsa");
  ui->yDescriptorComboBox->setCurrentIndex(tpsaIndex);
  d->descriptors[1] = "tpsa";
  int vabcIndex = ui->zDescriptorComboBox->findText("vabc");
  ui->zDescriptorComboBox->setCurrentIndex(vabcIndex);
  d->descriptors[2] = "vabc";
}

void KMeansClusteringDialog::runKMeansStatistics()
{
  // run k-means statistics
  vtkNew<vtkKMeansStatistics> kMeansStatistics;
  kMeansStatistics->RequestSelectedColumns();
  kMeansStatistics->SetAssessOption(true);
  kMeansStatistics->SetDefaultNumberOfClusters(d->kValue);
  kMeansStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA,
                                 d->table.GetPointer());

  for (size_t i = 0; i < 3; i++)
    kMeansStatistics->SetColumnStatus(d->descriptors[i].c_str(), 1);

  kMeansStatistics->RequestSelectedColumns();
  kMeansStatistics->Update();

  // assign molecules to clusters
  vtkNew<vtkIntArray> clusterAssignments;
  clusterAssignments->SetNumberOfComponents(1);

  size_t clusterCount = kMeansStatistics->GetOutput()->GetNumberOfColumns();
  std::vector<size_t> clusterSizes(clusterCount);

  for (vtkIdType r = 0; r < kMeansStatistics->GetOutput()->GetNumberOfRows(); r++) {
    vtkVariant v = kMeansStatistics->GetOutput()->GetValue(r, clusterCount - 1);

    int cluster = v.ToInt();
    clusterAssignments->InsertNextValue(cluster);
    clusterSizes[cluster]++;
  }

  // update lookup table
  d->lut->SetNumberOfTableValues(d->kValue);
  d->lut->Build();

  // update color array
  vtkIntArray *colorArray =
    vtkIntArray::SafeDownCast(d->table->GetColumnByName("color"));
  for(vtkIdType i = 0; i < colorArray->GetNumberOfTuples(); i++){
    colorArray->SetValue(i, clusterAssignments->GetValue(i));
  }
  d->table->Modified();

  // update cluster table widget
  ui->clusterTableWidget->setRowCount(d->kValue);
  for (int row = 0; row < d->kValue; row++) {
    // column 0 - cluster color
    QTableWidgetItem *colorItem = new QTableWidgetItem;

    double color[4];
    d->lut->GetTableValue(row, color);
    colorItem->setBackgroundColor(QColor::fromRgbF(color[0],
                                  color[1],
                                  color[2],
                                  0.8f));
    ui->clusterTableWidget->setItem(row, 0, colorItem);

    // column 1 - cluster number
    QTableWidgetItem *numberItem =
      new QTableWidgetItem(QString::number(row + 1));
    numberItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    ui->clusterTableWidget->setItem(row, 1, numberItem);

    // column 2 - cluster size
    QTableWidgetItem *sizeItem =
      new QTableWidgetItem(QString::number(clusterSizes[row]));
    sizeItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    ui->clusterTableWidget->setItem(row, 2, sizeItem);
  }
  ui->clusterTableWidget->resizeColumnsToContents();
  ui->clusterTableWidget->horizontalHeader()->setStretchLastSection(true);
}
<commit_msg>Fix missing array include in kmeansclusteringdialog.cpp<commit_after>/******************************************************************************

  This source file is part of the ChemData project.

  Copyright 2012 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

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

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

#include "mongodatabase.h"

#include "kmeansclusteringdialog.h"
#include "ui_kmeansclusteringdialog.h"

#include <QtGui>

#include <QVTKWidget.h>

#include <vtkNew.h>
#include <vtkTable.h>
#include <vtkChartXYZ.h>
#include <vtkIntArray.h>
#include <vtkFloatArray.h>
#include <vtkContextView.h>
#include <vtkLookupTable.h>
#include <vtkContextScene.h>
#include <vtkPlotPoints3D.h>
#include <vtkRenderWindow.h>
#include <vtkSmartPointer.h>
#include <vtkKMeansStatistics.h>

#include <boost/array.hpp>

#include <chemkit/molecule.h>
#include <chemkit/moleculardescriptor.h>

// avoid shadow warnings from Qt's foreach by using Boost's
#undef foreach
#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH

class KMeansClusteringDialogPrivate
{
public:
  QVTKWidget *vtkWidget;
  int kValue;
  std::vector<MoleculeRef> molecules;
  vtkSmartPointer<vtkTable> table;
  vtkNew<vtkContextView> chartView;
  vtkNew<vtkChartXYZ> chart;
  vtkPlotPoints3D *plot;
  boost::array<std::string, 3> descriptors;
  vtkNew<vtkLookupTable> lut;
};

KMeansClusteringDialog::KMeansClusteringDialog(QWidget *parent_)
  : QDialog(parent_),
    d(new KMeansClusteringDialogPrivate),
    ui(new Ui::KMeansClusteringDialog)
{
  // setup ui
  ui->setupUi(this);

  // setup descriptors
  setupDescriptors();

  // setup vtk widget
  d->vtkWidget = new QVTKWidget(this);
  d->chartView->SetInteractor(d->vtkWidget->GetInteractor());
  d->vtkWidget->SetRenderWindow(d->chartView->GetRenderWindow());
  ui->viewFrameLayout->addWidget(d->vtkWidget);

  // setup chart xyz
  d->plot = 0;
  d->chart->SetFitToScene(true);
  d->chart->SetDecorateAxes(true);
  d->chart->SetGeometry(vtkRectf(0, 0, 600, 600));

  // setup chart view
  d->chartView->GetScene()->AddItem(d->chart.GetPointer());

  // setup k-means statistics
  d->kValue = 3;
  ui->kValueSpinBox->setValue(d->kValue);

  // render
  d->vtkWidget->update();

  // connect signals
  connect(ui->kValueSpinBox, SIGNAL(valueChanged(int)),
          this, SLOT(kValueSpinBoxChanged(int)));
  connect(ui->xDescriptorComboBox, SIGNAL(currentIndexChanged(QString)),
          this, SLOT(xDescriptorChanged(QString)));
  connect(ui->yDescriptorComboBox, SIGNAL(currentIndexChanged(QString)),
          this, SLOT(yDescriptorChanged(QString)));
  connect(ui->zDescriptorComboBox, SIGNAL(currentIndexChanged(QString)),
          this, SLOT(zDescriptorChanged(QString)));
  connect(d->vtkWidget, SIGNAL(mouseEvent(QMouseEvent*)),
          this, SLOT(viewMouseEvent(QMouseEvent*)));
}

KMeansClusteringDialog::~KMeansClusteringDialog()
{
  delete d;
  delete ui;
}

void KMeansClusteringDialog::setMolecules(const std::vector<MoleculeRef> &molecules_)
{
  // display progress dialog
  QProgressDialog progressDialog("Calculating Descriptors",
                                 "Cancel",
                                 0,
                                 molecules_.size(),
                                 this);

  // pop-up progress dialog immediately
  progressDialog.setMinimumDuration(0);

  // connect to the database
  MongoDatabase *db = MongoDatabase::instance();

  // set molecules
  d->molecules = molecules_;

  // remove old plot
  if (d->plot) {
    d->chart->ClearPlots();
    d->plot->Delete();
    d->plot = 0;
  }

  // create table for the descriptors
  d->table = vtkSmartPointer<vtkTable>::New();

  // setup descriptor arrays
  boost::array<vtkFloatArray *, 3> arrays;
  for (size_t i = 0; i < 3; i++) {
    vtkFloatArray *array = vtkFloatArray::New();
    array->SetName(d->descriptors[i].c_str());
    arrays[i] = array;
    d->table->AddColumn(array);
    array->Delete();
  }

  // setup color array
  vtkIntArray *colorArray = vtkIntArray::New();
  colorArray->SetName("color");
  colorArray->SetNumberOfComponents(1);
  d->table->AddColumn(colorArray);
  colorArray->Delete();

  // calculate descriptors
  foreach (const MoleculeRef &ref, molecules_) {
    // stop calculating if the user clicked cancel
    if(progressDialog.wasCanceled())
      break;

    // create molecule object
    boost::shared_ptr<const chemkit::Molecule> molecule = db->createMolecule(ref);

    // calculate descriptors for the molecule
    for (size_t i = 0; i < 3; i++)
      arrays[i]->InsertNextValue(molecule->descriptor(d->descriptors[i]).toFloat());

    // set cluster to 0 (will be set to its real value later by running k-means)
    colorArray->InsertNextValue(0);

    // update progress dialog
    progressDialog.setValue(progressDialog.value() + 1);
  }

  // run k-means statstics
  runKMeansStatistics();

  // setup plot
  d->plot = vtkPlotPoints3D::New();
  d->plot->SetInputData(d->table.GetPointer(),
                        d->descriptors[0],
                        d->descriptors[1],
                        d->descriptors[2],
                        "color");

  // setup chart
  d->chart->AddPlot(d->plot);

  // update bounds and display chart
  d->chart->RecalculateBounds();
  d->chart->RecalculateTransform();
  d->vtkWidget->update();
}

std::vector<MoleculeRef> KMeansClusteringDialog::molecules() const
{
  return d->molecules;
}

void KMeansClusteringDialog::setKValue(int k)
{
  // set k value
  d->kValue = k;

  // run k-means statistics
  runKMeansStatistics();

  // update plot with new colors (i wish this was easier)
  if (d->plot) {
    d->chart->ClearPlots();
    d->plot->Delete();
    d->plot = vtkPlotPoints3D::New();
    d->plot->SetInputData(d->table.GetPointer(),
                          d->descriptors[0],
                          d->descriptors[1],
                          d->descriptors[2],
                          "color");
    d->chart->AddPlot(d->plot);
    d->chart->RecalculateBounds();
    d->chart->RecalculateTransform();
    d->vtkWidget->update();
  }
}

int KMeansClusteringDialog::kValue() const
{
  return d->kValue;
}

void KMeansClusteringDialog::setDescriptor(int index, const QString &descriptor_)
{
  if (index < 0 || index > 2)
    return;

  // set descriptor name
  d->descriptors[index] = descriptor_.toStdString();

  // update
  setMolecules(d->molecules);
}

QString KMeansClusteringDialog::descriptor(int index)
{
  if (index >= 0 && index < 3)
    return QString::fromStdString(d->descriptors[index]);
  else
    return QString();
}

void KMeansClusteringDialog::kValueSpinBoxChanged(int value)
{
  setKValue(value);
}

void KMeansClusteringDialog::resetCamera()
{
  d->vtkWidget->update();
}

void KMeansClusteringDialog::xDescriptorChanged(const QString &descriptor_)
{
  setDescriptor(0, descriptor_);
}

void KMeansClusteringDialog::yDescriptorChanged(const QString &descriptor_)
{
  setDescriptor(1, descriptor_);
}

void KMeansClusteringDialog::zDescriptorChanged(const QString &descriptor_)
{
  setDescriptor(2, descriptor_);
}

void KMeansClusteringDialog::viewMouseEvent(QMouseEvent *event_)
{
  // not sure how to implement this with vtkChartXYZ
  (void) event_;

//  if (event_->button() == Qt::LeftButton &&
//      event_->type() == QMouseEvent::MouseButtonDblClick) {
//    vtkNew<vtkPointPicker> picker;
//    vtkRenderer *renderer = d->renderer.GetPointer();
//    vtkRenderWindowInteractor *interactor = d->vtkWidget->GetInteractor();

//    int *pos_ = interactor->GetEventPosition();

//    if (picker->Pick(pos_[0], pos_[1], 0, renderer)) {
//      vtkIdType id = picker->GetPointId();

//      if (id != -1)
//        emit moleculeDoubleClicked(id);
//    }
//  }
}

void KMeansClusteringDialog::setupDescriptors()
{
  // populate combo boxes
  std::vector<std::string> descriptors =
    chemkit::MolecularDescriptor::descriptors();

  // create map of descriptor dimensionality to list of descriptor names
  QMap<int, QStringList> descriptorsMap;

  foreach (const std::string &name, descriptors) {
    boost::scoped_ptr<chemkit::MolecularDescriptor>
      descriptor_(chemkit::MolecularDescriptor::create(name));

    int dimensionality = descriptor_->dimensionality();

    if (dimensionality == -1) {
      // descriptors with unknown dimensionality have a value of -1 so we
      // set it to INT_MAX in order to put them at the bottom of the list
      dimensionality = std::numeric_limits<int>::max();
    }

    descriptorsMap[dimensionality].append(name.c_str());
  }

  // list of the combo boxes for each of the x, y and z axes
  QList<QComboBox *> comboBoxes;
  comboBoxes.append(ui->xDescriptorComboBox);
  comboBoxes.append(ui->yDescriptorComboBox);
  comboBoxes.append(ui->zDescriptorComboBox);

  // insert each descriptor into each combo box grouped by dimensionality
  foreach (int key, descriptorsMap.keys()) {
    int dimensionality = key;
    const QStringList &names = descriptorsMap[key];

    foreach (QComboBox *comboBox, comboBoxes) {
      // insert title
      int titleIndex = comboBox->count();
      if (dimensionality != std::numeric_limits<int>::max())
        comboBox->addItem(tr("%1D Descriptors").arg(dimensionality));
      else
        comboBox->addItem(tr("Other Descriptors"));

      // set bold font for title and make it non-selectable
      QStandardItem *item =
        qobject_cast<QStandardItemModel *>(comboBox->model())->item(titleIndex);

      if (item) {
        QFont font_ = item->font();
        font_.setBold(true);
        item->setFont(font_);
        item->setFlags(Qt::ItemIsEnabled);
      }

      // add a separator
      comboBox->insertSeparator(comboBox->count());

      // insert name of each descriptor
      foreach (const QString &name, names)
        comboBox->addItem(name);
    }
  }

  // default to X = mass, Y = tpsa, and Z = vabc
  int massIndex = ui->xDescriptorComboBox->findText("mass");
  ui->xDescriptorComboBox->setCurrentIndex(massIndex);
  d->descriptors[0] = "mass";
  int tpsaIndex = ui->yDescriptorComboBox->findText("tpsa");
  ui->yDescriptorComboBox->setCurrentIndex(tpsaIndex);
  d->descriptors[1] = "tpsa";
  int vabcIndex = ui->zDescriptorComboBox->findText("vabc");
  ui->zDescriptorComboBox->setCurrentIndex(vabcIndex);
  d->descriptors[2] = "vabc";
}

void KMeansClusteringDialog::runKMeansStatistics()
{
  // run k-means statistics
  vtkNew<vtkKMeansStatistics> kMeansStatistics;
  kMeansStatistics->RequestSelectedColumns();
  kMeansStatistics->SetAssessOption(true);
  kMeansStatistics->SetDefaultNumberOfClusters(d->kValue);
  kMeansStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA,
                                 d->table.GetPointer());

  for (size_t i = 0; i < 3; i++)
    kMeansStatistics->SetColumnStatus(d->descriptors[i].c_str(), 1);

  kMeansStatistics->RequestSelectedColumns();
  kMeansStatistics->Update();

  // assign molecules to clusters
  vtkNew<vtkIntArray> clusterAssignments;
  clusterAssignments->SetNumberOfComponents(1);

  size_t clusterCount = kMeansStatistics->GetOutput()->GetNumberOfColumns();
  std::vector<size_t> clusterSizes(clusterCount);

  for (vtkIdType r = 0; r < kMeansStatistics->GetOutput()->GetNumberOfRows(); r++) {
    vtkVariant v = kMeansStatistics->GetOutput()->GetValue(r, clusterCount - 1);

    int cluster = v.ToInt();
    clusterAssignments->InsertNextValue(cluster);
    clusterSizes[cluster]++;
  }

  // update lookup table
  d->lut->SetNumberOfTableValues(d->kValue);
  d->lut->Build();

  // update color array
  vtkIntArray *colorArray =
    vtkIntArray::SafeDownCast(d->table->GetColumnByName("color"));
  for(vtkIdType i = 0; i < colorArray->GetNumberOfTuples(); i++){
    colorArray->SetValue(i, clusterAssignments->GetValue(i));
  }
  d->table->Modified();

  // update cluster table widget
  ui->clusterTableWidget->setRowCount(d->kValue);
  for (int row = 0; row < d->kValue; row++) {
    // column 0 - cluster color
    QTableWidgetItem *colorItem = new QTableWidgetItem;

    double color[4];
    d->lut->GetTableValue(row, color);
    colorItem->setBackgroundColor(QColor::fromRgbF(color[0],
                                  color[1],
                                  color[2],
                                  0.8f));
    ui->clusterTableWidget->setItem(row, 0, colorItem);

    // column 1 - cluster number
    QTableWidgetItem *numberItem =
      new QTableWidgetItem(QString::number(row + 1));
    numberItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    ui->clusterTableWidget->setItem(row, 1, numberItem);

    // column 2 - cluster size
    QTableWidgetItem *sizeItem =
      new QTableWidgetItem(QString::number(clusterSizes[row]));
    sizeItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    ui->clusterTableWidget->setItem(row, 2, sizeItem);
  }
  ui->clusterTableWidget->resizeColumnsToContents();
  ui->clusterTableWidget->horizontalHeader()->setStretchLastSection(true);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: jvmargs.hxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: hr $ $Date: 2004-11-09 13:54:04 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef __JVM_HXX
#define __JVM_HXX

#include <vector>
#include <rtl/ustring>

#include "jni.h"

extern "C" {
    typedef jint JNICALL JNI_InitArgs_Type(void *);
    typedef jint JNICALL JNI_CreateVM_Type(JavaVM **, JNIEnv **, void *);

}

namespace stoc_javavm {

    class JVM {
        ::std::vector<rtl::OUString> _props;

    public:
        JVM() throw();

        void pushProp(const ::rtl::OUString & uString);
        const ::std::vector< ::rtl::OUString> & getProperties() const;
    };
}

#endif
<commit_msg>INTEGRATION: CWS ooo19126 (1.10.38); FILE MERGED 2005/09/05 17:10:57 rt 1.10.38.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: jvmargs.hxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 08:00:16 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef __JVM_HXX
#define __JVM_HXX

#include <vector>
#include <rtl/ustring>

#include "jni.h"

extern "C" {
    typedef jint JNICALL JNI_InitArgs_Type(void *);
    typedef jint JNICALL JNI_CreateVM_Type(JavaVM **, JNIEnv **, void *);

}

namespace stoc_javavm {

    class JVM {
        ::std::vector<rtl::OUString> _props;

    public:
        JVM() throw();

        void pushProp(const ::rtl::OUString & uString);
        const ::std::vector< ::rtl::OUString> & getProperties() const;
    };
}

#endif
<|endoftext|>


<commit_before>/*

    OF-TangibleFramework . Framework for Taller de Sistemes Interactius I
    Universitat Pompeu Fabra

    Copyright (c) 2010 Carles F. Julià <carles.fernandez@upf.edu>

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/

#include "InputGestureTuio1.12D.hpp"

#include <cstring>

using namespace osc;

namespace tuio
{

void InputGestureTuio112D::ReceiveCall(const char * addr, ReceivedMessageArgumentStream & args)
{
    if(!valid)
        return;
    if( strcmp( addr, "/tuio/2Dcur" ) == 0 )
        tuio2Dcur(args);
    if( strcmp( addr, "/tuio/2Dobj" ) == 0 )
        tuio2Dobj(args);
    if( strcmp( addr, "/tuio/2Dblb" ) == 0 )
        tuio2Dobj(args);
}

void InputGestureTuio112D::tuio2Dcur(ReceivedMessageArgumentStream & args)
{
    const char* cmd;
    args >> cmd;

    if(strcmp(cmd,"set")== 0)
    {
        int32 s_id;
        float xpos, ypos, xspeed, yspeed, maccel;

        args >> s_id >> xpos >> ypos >> xspeed >> yspeed >> maccel >> EndMessage;
        if(squaredInterface)
        {
            xpos = (xpos -0.125f)*1.333333f;
        }
        if(c_s_ids.find(s_id) == c_s_ids.end())
        {
            SimpleCallEvent(CanTuio112D,addTuioCursor2D,(s_id, xpos,ypos,xspeed,yspeed,maccel ));
            c_s_ids.insert(s_id);
        }
        else
        {

            SimpleCallEvent(CanTuio112D,updateTuioCursor2D,(s_id, xpos,ypos,xspeed,yspeed,maccel ));
        }

    }
    else if( strcmp( cmd, "alive" ) == 0 )
    {
        int32 s_id;
        std::set<int32> t(c_s_ids);
        while(!args.Eos())
        {
            args >> s_id;
            t.erase(s_id);
        }
        args >> EndMessage;
        for (std::set<int32>::iterator it = t.begin(); it != t.end(); ++it)
        {
            s_id = *it;
            c_s_ids.erase(s_id);
            SimpleCallEvent(CanTuio112D,removeTuioCursor2D,(s_id));
        }
    }

}

void InputGestureTuio112D::tuio2Dobj(ReceivedMessageArgumentStream & args)
{
           const char* cmd;
        args >> cmd;

        if(strcmp(cmd,"set")== 0)
        {
            int32 s_id, f_id;
            float xpos, ypos, angle, xspeed, yspeed, rspeed, maccel, raccel;

            args >> s_id >> f_id >> xpos >> ypos >> angle >> xspeed >> yspeed >> rspeed >> maccel >> raccel >> EndMessage;

            if(squaredInterface)
            {
                xpos = (xpos -0.125f)*1.333333f;
            }

            if(o_s_ids.find(s_id) == o_s_ids.end())
            {
                o_s_ids.insert(s_id);
                SimpleCallEvent(CanTuio112D,addTuioObject2D,( s_id, f_id ,xpos, ypos, angle, xspeed,yspeed, rspeed, maccel,  raccel));
            }
            else
            {
                SimpleCallEvent(CanTuio112D,updateTuioObject2D,( s_id, f_id ,xpos, ypos, angle, xspeed,yspeed, rspeed, maccel,  raccel));
            }

        }
        else if( strcmp( cmd, "alive" ) == 0 )
        {

            int32 s_id;
            std::set<int32> t(o_s_ids);
            while(!args.Eos())
            {
                args >> s_id;
                t.erase(s_id);
            }
            args >> EndMessage;
            for (std::set<int32>::iterator it = t.begin(); it != t.end(); ++it)
            {
                s_id = *it;
                o_s_ids.erase(s_id);
                SimpleCallEvent(CanTuio112D,removeTuioObject2D,(s_id));
            }
        }

}

void InputGestureTuio112D::tuio2Dblb(ReceivedMessageArgumentStream & args)
{
           const char* cmd;
        args >> cmd;

        if(strcmp(cmd,"set")== 0)
        {
            int32 s_id;
            float xpos, ypos, angle, width, height, area, xspeed, yspeed, rspeed, maccel, raccel;
            args >> s_id >> xpos >> ypos >> angle >> width >> height >> area >> xspeed >> yspeed >> rspeed >> maccel >> raccel >> EndMessage;

            if(b_s_ids.find(s_id) == b_s_ids.end())
            {
                SimpleCallEvent(CanTuio112D,addTuioBlob2D,(s_id, xpos, ypos,  angle,  width,  height,  area,  xspeed, yspeed, rspeed, maccel,  raccel));
                b_s_ids.insert(s_id);
            }
            else
            {
                SimpleCallEvent(CanTuio112D,updateTuioBlob2D,(s_id, xpos, ypos,  angle,  width,  height,  area,  xspeed, yspeed, rspeed, maccel,  raccel));
            }

        }
        else if( strcmp( cmd, "alive" ) == 0 )
        {

            int32 s_id;
            std::set<int32> t(b_s_ids);
            while(!args.Eos())
            {
                args >> s_id;
                t.erase(s_id);
            }
            args >> EndMessage;
            for (std::set<int32>::iterator it = t.begin(); it != t.end(); ++it)
            {
                s_id = *it;
                b_s_ids.erase(s_id);
                SimpleCallEvent(CanTuio112D,removeTuioBlob2D,(s_id));
            }
        }

}

}
<commit_msg>Quick fix for rectangular interfaces (only 4:3 for now)<commit_after>/*

    OF-TangibleFramework . Framework for Taller de Sistemes Interactius I
    Universitat Pompeu Fabra

    Copyright (c) 2010 Carles F. Julià <carles.fernandez@upf.edu>

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/

#include "InputGestureTuio1.12D.hpp"

#include <cstring>

using namespace osc;

namespace tuio
{

void InputGestureTuio112D::ReceiveCall(const char * addr, ReceivedMessageArgumentStream & args)
{
    if(!valid)
        return;
    if( strcmp( addr, "/tuio/2Dcur" ) == 0 )
        tuio2Dcur(args);
    if( strcmp( addr, "/tuio/2Dobj" ) == 0 )
        tuio2Dobj(args);
    if( strcmp( addr, "/tuio/2Dblb" ) == 0 )
        tuio2Dobj(args);
}

void InputGestureTuio112D::tuio2Dcur(ReceivedMessageArgumentStream & args)
{
    const char* cmd;
    args >> cmd;

    if(strcmp(cmd,"set")== 0)
    {
        int32 s_id;
        float xpos, ypos, xspeed, yspeed, maccel;

        args >> s_id >> xpos >> ypos >> xspeed >> yspeed >> maccel >> EndMessage;

        ///This is a quick fix, it only works with 4:3 window ratios
        if(squaredInterface)
        {
            xpos = (xpos -0.125f)*1.333333f;
        }
        else
        {
            xpos = xpos *1.333333f;
        }
        if(c_s_ids.find(s_id) == c_s_ids.end())
        {
            SimpleCallEvent(CanTuio112D,addTuioCursor2D,(s_id, xpos,ypos,xspeed,yspeed,maccel ));
            c_s_ids.insert(s_id);
        }
        else
        {

            SimpleCallEvent(CanTuio112D,updateTuioCursor2D,(s_id, xpos,ypos,xspeed,yspeed,maccel ));
        }

    }
    else if( strcmp( cmd, "alive" ) == 0 )
    {
        int32 s_id;
        std::set<int32> t(c_s_ids);
        while(!args.Eos())
        {
            args >> s_id;
            t.erase(s_id);
        }
        args >> EndMessage;
        for (std::set<int32>::iterator it = t.begin(); it != t.end(); ++it)
        {
            s_id = *it;
            c_s_ids.erase(s_id);
            SimpleCallEvent(CanTuio112D,removeTuioCursor2D,(s_id));
        }
    }

}

void InputGestureTuio112D::tuio2Dobj(ReceivedMessageArgumentStream & args)
{
           const char* cmd;
        args >> cmd;

        if(strcmp(cmd,"set")== 0)
        {
            int32 s_id, f_id;
            float xpos, ypos, angle, xspeed, yspeed, rspeed, maccel, raccel;

            args >> s_id >> f_id >> xpos >> ypos >> angle >> xspeed >> yspeed >> rspeed >> maccel >> raccel >> EndMessage;

            ///This is a quick fix, it only works with 4:3 window ratios
            if(squaredInterface)
            {
                xpos = (xpos -0.125f)*1.333333f;
            }
            else
            {
                xpos = xpos *1.333333f;
            }

            if(o_s_ids.find(s_id) == o_s_ids.end())
            {
                o_s_ids.insert(s_id);
                SimpleCallEvent(CanTuio112D,addTuioObject2D,( s_id, f_id ,xpos, ypos, angle, xspeed,yspeed, rspeed, maccel,  raccel));
            }
            else
            {
                SimpleCallEvent(CanTuio112D,updateTuioObject2D,( s_id, f_id ,xpos, ypos, angle, xspeed,yspeed, rspeed, maccel,  raccel));
            }

        }
        else if( strcmp( cmd, "alive" ) == 0 )
        {

            int32 s_id;
            std::set<int32> t(o_s_ids);
            while(!args.Eos())
            {
                args >> s_id;
                t.erase(s_id);
            }
            args >> EndMessage;
            for (std::set<int32>::iterator it = t.begin(); it != t.end(); ++it)
            {
                s_id = *it;
                o_s_ids.erase(s_id);
                SimpleCallEvent(CanTuio112D,removeTuioObject2D,(s_id));
            }
        }

}

void InputGestureTuio112D::tuio2Dblb(ReceivedMessageArgumentStream & args)
{
           const char* cmd;
        args >> cmd;

        if(strcmp(cmd,"set")== 0)
        {
            int32 s_id;
            float xpos, ypos, angle, width, height, area, xspeed, yspeed, rspeed, maccel, raccel;
            args >> s_id >> xpos >> ypos >> angle >> width >> height >> area >> xspeed >> yspeed >> rspeed >> maccel >> raccel >> EndMessage;

            if(b_s_ids.find(s_id) == b_s_ids.end())
            {
                SimpleCallEvent(CanTuio112D,addTuioBlob2D,(s_id, xpos, ypos,  angle,  width,  height,  area,  xspeed, yspeed, rspeed, maccel,  raccel));
                b_s_ids.insert(s_id);
            }
            else
            {
                SimpleCallEvent(CanTuio112D,updateTuioBlob2D,(s_id, xpos, ypos,  angle,  width,  height,  area,  xspeed, yspeed, rspeed, maccel,  raccel));
            }

        }
        else if( strcmp( cmd, "alive" ) == 0 )
        {

            int32 s_id;
            std::set<int32> t(b_s_ids);
            while(!args.Eos())
            {
                args >> s_id;
                t.erase(s_id);
            }
            args >> EndMessage;
            for (std::set<int32>::iterator it = t.begin(); it != t.end(); ++it)
            {
                s_id = *it;
                b_s_ids.erase(s_id);
                SimpleCallEvent(CanTuio112D,removeTuioBlob2D,(s_id));
            }
        }

}

}
<|endoftext|>