<commit_before>/*
 * LiveImageViewPlugin.cpp
 *
 *  Created on: 6 Sept 2018
 *      Author: Adam Neaves - wbd45595
 */

#include "LiveViewPlugin.h"
#include "version.h"
#include <boost/algorithm/string.hpp>

namespace FrameProcessor
{
/* Default Config*/
const int32_t     LiveViewPlugin::DEFAULT_FRAME_FREQ = 1;
const int32_t     LiveViewPlugin::DEFAULT_PER_SECOND = 0;
const std::string LiveViewPlugin::DEFAULT_IMAGE_VIEW_SOCKET_ADDR = "tcp://127.0.0.1:5020";
const std::string LiveViewPlugin::DEFAULT_DATASET_NAME = "";
const std::string LiveViewPlugin::DEFAULT_TAGGED_FILTER = "";

/* Config Names*/
const std::string LiveViewPlugin::CONFIG_FRAME_FREQ =  "frame_frequency";
const std::string LiveViewPlugin::CONFIG_PER_SECOND =  "per_second";
const std::string LiveViewPlugin::CONFIG_SOCKET_ADDR = "live_view_socket_addr";
const std::string LiveViewPlugin::CONFIG_DATASET_NAME = "dataset_name";
const std::string LiveViewPlugin::CONFIG_TAGGED_FILTER_NAME = "filter_tagged";

/**
 * Constructor for this class. Sets up ZMQ pub socket and other default values for the config
 */
LiveViewPlugin::LiveViewPlugin() :
    publish_socket_(ZMQ_PUB)
{
  logger_ = Logger::getLogger("FW.LiveViewPlugin");
  logger_->setLevel(Level::getAll());
  LOG4CXX_INFO(logger_, "LiveViewPlugin version " << this->get_version_long() << " loaded");

  set_frame_freq_config(DEFAULT_FRAME_FREQ);
  set_per_second_config(DEFAULT_PER_SECOND);
  set_socket_addr_config(DEFAULT_IMAGE_VIEW_SOCKET_ADDR);
  set_dataset_name_config(DEFAULT_DATASET_NAME);
  set_tagged_filter_config(DEFAULT_TAGGED_FILTER);
}

/**
 * Class Destructor. Closes the Publish socket
 */
LiveViewPlugin::~LiveViewPlugin()
{
  LOG4CXX_TRACE(logger_, "LiveViewPlugin destructor.");
  publish_socket_.close();
}

/**
 * Process recieved frame. For the live view plugin, this means checking if certain conditions are true (time elapsed, frame number, dataset name)
 * and then, if the conditions mean sending the frame, creating a json header and copying the data to send to the publisher socket.
 *
 * \param[in] frame - pointer to a frame object.
 */
void LiveViewPlugin::process_frame(boost::shared_ptr<Frame> frame)
{
  /** Static Frame Count will increment each time this method is called, basically as a count of how many frames have been processed by the plugin*/
  static uint32_t frame_count_;
  LOG4CXX_TRACE(logger_, "LiveViewPlugin Process Frame.");

  std::string frame_dataset = frame->get_dataset_name();
  /* If datasets is empty, or contains the frame's dataset, then we can potentially send it*/
  if (datasets_.empty() || std::find(datasets_.begin(), datasets_.end(), frame_dataset) != datasets_.end())
  {
    /* If either filtering by tag is disabled, or the frame has the tagged param */
    bool tag_filter_active = !tags_.empty();
    bool is_tagged = false;
    if (tag_filter_active)
    {
      for (int i = 0; i < tags_.size(); i++)
      {
        if (frame->has_parameter(tags_[i]))
        {
          is_tagged = true;
          break;
        }
      }
    }
    if (!tag_filter_active || is_tagged)
    {
      boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
      int32_t elapsed_time = (now - time_last_frame_).total_milliseconds();

      if (per_second_ != 0 && elapsed_time > time_between_frames_) //time between frames too large, showing frame no matter what the frame number is
      {
        LOG4CXX_TRACE(logger_, "Elapsed time " << elapsed_time << " > " << time_between_frames_);
        pass_live_frame(frame);
      }
      else if (frame_freq_ != 0 && frame_count_ % frame_freq_ == 0)
      {
        LOG4CXX_TRACE(logger_, "LiveViewPlugin Frame " << frame->get_frame_number() << " to be displayed.");
        pass_live_frame(frame);
      }
    }
    else
    {
      LOG4CXX_TRACE(logger_, "LiveViewPlugin No Tag(s) found, frame skipped.");
    }
  }
  else
  {
    LOG4CXX_TRACE(logger_,"Frame dataset: " << frame_dataset << " not desired");
  }

  LOG4CXX_TRACE(logger_, "Pushing Data Frame" );
  //push frame down the pipeline no matter if frame was passed to live viewer or not
  frame_count_ ++;
  this->push(frame);
}

/**
 * Set configuration options for this Plugin.
 *
 * This sets up the Live View Plugin according to the configuration IpcMessage
 * objects that are received.
 *
 * \param[in] config - IpcMessage containing configuration data.
 * \param[out] reply - Response IpcMessage.
 */
void LiveViewPlugin::configure(OdinData::IpcMessage& config, OdinData::IpcMessage& reply)
{
  try{
    /* Check if we're setting the frequency of frames to show*/
    if (config.has_param(CONFIG_FRAME_FREQ))
    {
      set_frame_freq_config(config.get_param<int32_t>(CONFIG_FRAME_FREQ));
    }
    /* Check if we're setting the per_second config*/
    if (config.has_param(CONFIG_PER_SECOND))
    {
      set_per_second_config(config.get_param<int32_t>(CONFIG_PER_SECOND));
    }
    /* Check if we are setting the dataset name filter*/
    if (config.has_param(CONFIG_DATASET_NAME))
    {
      set_dataset_name_config(config.get_param<std::string>(CONFIG_DATASET_NAME));
    }
    if (config.has_param(CONFIG_TAGGED_FILTER_NAME))
    {
      set_tagged_filter_config(config.get_param<std::string>(CONFIG_TAGGED_FILTER_NAME));
    }
    /* Display warning if configuration sets the plugin to do nothing*/
    if (per_second_ == 0 && frame_freq_ == 0)
    {
      LOG4CXX_WARN(logger_, "CURRENT LIVE VIEW CONFIGURATION RESULTS IN IT DOING NOTHING");
    }
    /* Check if we're setting the address of the socket to send the live view frames to.*/
    if (config.has_param(CONFIG_SOCKET_ADDR))
    {
      set_socket_addr_config(config.get_param<std::string>(CONFIG_SOCKET_ADDR));
    }
  }
  catch (std::runtime_error& e)
  {
    std::stringstream ss;
    ss << "Bad ctrl msg: " << e.what();
    this->set_error(ss.str());
    throw;
  }
}

/**
 * Get the configuration values for this Plugin.
 *
 * \param[out] reply - Response IpcMessage.
 */
void LiveViewPlugin::requestConfiguration(OdinData::IpcMessage& reply)
{
  reply.set_param(get_name() + "/" + LiveViewPlugin::CONFIG_FRAME_FREQ, frame_freq_);
  reply.set_param(get_name() + "/" + LiveViewPlugin::CONFIG_SOCKET_ADDR, image_view_socket_addr_);
  reply.set_param(get_name() + "/" + LiveViewPlugin::CONFIG_PER_SECOND, per_second_);
}

/**
 * Constructs a header with information about the data frame, then sends that header and the data
 * to the ZMQ socket interface to be consumed by an external live viewer.
 * The Header contains the following:
 * - int32_t Frame number
 * - string   Acquisition ID
 * - string   Data Type
 * - size_t   Data Size
 * - string   compression type
 * - size_t[] dimensions
 * \param[in] frame - pointer to the data frame
 * \param[in] frame_num - the number of the frame
 *
 */
void LiveViewPlugin::pass_live_frame(boost::shared_ptr<Frame> frame)
{
  void* frame_data_copy = (void*)frame->get_data();

  uint32_t frame_num = frame->get_frame_number();
  std::string aqqID = frame->get_acquisition_id();
  dimensions_t dim = frame->get_dimensions();
  std::string type = get_type_from_enum((DataType)frame->get_data_type());
  std::size_t size = frame->get_data_size();
  std::string compress = get_compress_from_enum((CompressionType)frame->get_compression());
  std::string dataset = frame->get_dataset_name();

  rapidjson::Document document; /* Header info*/
  document.SetObject();
  LOG4CXX_TRACE(logger_, "LiveViewPlugin Building Frame Header");
  //building image header

  add_json_member(&document, "frame_num", frame_num);
  add_json_member(&document, "acquisition_id", aqqID);
  add_json_member(&document, "dtype", type);
  add_json_member(&document, "dsize", static_cast<uint64_t>(size));
  add_json_member(&document, "dataset", dataset);
  add_json_member(&document, "compression", compress);

  //getting tags manually because it is an array
  rapidjson::Value keyTags("tags", document.GetAllocator());
  rapidjson::Value valueTags(rapidjson::kArrayType);
  if (!tags_.empty())
  {
    for(int i = 0; i < tags_.size(); i++)
    {
      if (frame->has_parameter(tags_[i]))
      {
        rapidjson::Value tagStringVal(tags_[i].c_str(), document.GetAllocator());
        valueTags.PushBack(tagStringVal, document.GetAllocator());
      }
    }
    document.AddMember(keyTags, valueTags, document.GetAllocator());
  }

  //getting dimensions manually because its an array
  rapidjson::Value keyDims("shape", document.GetAllocator());
  rapidjson::Value valueDims(rapidjson::kArrayType);

  size_t dim_size = dim.size();
  for(size_t i=0; i < dim_size; i++)
  {
    std::string dimString = boost::to_string(dim[i]);
    rapidjson::Value dimStringVal(dimString.c_str(), document.GetAllocator());
    valueDims.PushBack(dimStringVal, document.GetAllocator());
  }

  document.AddMember(keyDims, valueDims, document.GetAllocator());

  //convert to a json like string so that it can be passed along the socket as the image header
  rapidjson::StringBuffer buffer;
  buffer.Clear();
  rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<> > writer(buffer);

  document.Accept(writer);

  LOG4CXX_TRACE(logger_, "LiveViewPlugin Header Built, sending down socket.");
  publish_socket_.send(buffer.GetString(), ZMQ_SNDMORE);
  LOG4CXX_TRACE(logger_, "LiveViewPlugin Sending frame raw data");
  publish_socket_.send(size, frame_data_copy, 0);

  time_last_frame_ = boost::posix_time::microsec_clock::local_time();
}

void LiveViewPlugin::add_json_member(rapidjson::Document* document, std::string key, std::string value)
{
  rapidjson::Value rkey(key.c_str(), document->GetAllocator());
  rapidjson::Value rvalue(value.c_str(), document->GetAllocator());
  document->AddMember(rkey, rvalue, document->GetAllocator());
}

void LiveViewPlugin::add_json_member(rapidjson::Document* document, std::string key, uint32_t value)
{
  rapidjson::Value rkey(key.c_str(), document->GetAllocator());
  rapidjson::Value rvalue(value);
  document->AddMember(rkey, rvalue, document->GetAllocator());
}
int LiveViewPlugin::get_version_major()
{
  return ODIN_DATA_VERSION_MAJOR;
}

int LiveViewPlugin::get_version_minor()
{
  return ODIN_DATA_VERSION_MINOR;
}

int LiveViewPlugin::get_version_patch()
{
  return ODIN_DATA_VERSION_PATCH;
}

std::string LiveViewPlugin::get_version_short()
{
  return ODIN_DATA_VERSION_STR_SHORT;
}

std::string LiveViewPlugin::get_version_long()
{
  return ODIN_DATA_VERSION_STR;
}

/**
 * Sets the config value "per_second" which tells the plugin the number of frames to show each second
 * Setting this value to 0 disables the "frames per second" checking
 * \param[in] value - the value to assign to per_second
 */
void LiveViewPlugin::set_per_second_config(int32_t value)
{
  per_second_ = value;

  if (per_second_ == 0)
  {
    LOG4CXX_INFO(logger_, "Disabling Frames Per Second Option");
  }
  else
  {
    LOG4CXX_INFO(logger_, "Displaying " << per_second_ << " frames per second");
    time_between_frames_ = 1000 / per_second_;
  }
}
/**
 * Sets the Frame Frequency config value. This value tells the plugin to show every Nth frame.
 * Setting this value to 0 disables this check
 * \param[in] value - the value to assign to frame_freq
 */
void LiveViewPlugin::set_frame_freq_config(int32_t value)
{
  frame_freq_ = value;
  if (frame_freq_ == 0)
  {
    LOG4CXX_INFO(logger_, "Disabling Frame Frequency");
  }
  else
  {
    LOG4CXX_INFO(logger_, "Showing every " << frame_freq_ << " frame(s)");
  }
}
/**
 * Sets the address of the publisher socket that live view data is sent to.
 * When setting this address, it also binds the socket to the address, unbinding it from any previous address given
 * \param[in] value - the address to bind the socket to.
 */
void LiveViewPlugin::set_socket_addr_config(std::string value)
{
  //we dont want to unbind and rebind the same address, as it can cause an error if it takes time to unbind, so we check first
  if (publish_socket_.has_bound_endpoint(value))
  {
    LOG4CXX_WARN(logger_, "Socket already bound to " << value << ". Doing nothing");
    return;
  }
  uint32_t linger = 0;
  publish_socket_.setsockopt(ZMQ_LINGER, &linger, sizeof(linger));
  publish_socket_.unbind(image_view_socket_addr_.c_str());

  image_view_socket_addr_ = value;
  LOG4CXX_INFO(logger_, "Setting Live View Socket Address to " << image_view_socket_addr_);
  publish_socket_.bind(image_view_socket_addr_);
}

/**
 * Sets the dataset filter configuration. The live view output can be filtered by the dataset variable on the frame based off a list
 * of desired datasets.
 * \param[in] value - A comma deliminated list of dataset names, or an empty string to ignore this filtering.
 */
void LiveViewPlugin::set_dataset_name_config(std::string value)
{
  std::string delim = ",";
  datasets_.clear();
  if (!value.empty())
  {
    //delim value string by comma
    boost::split(datasets_, value, boost::is_any_of(delim));
  }
  std::string dataset_string = "";
  for (int i = 0; i < datasets_.size(); i++)
  {
    boost::trim(datasets_[i]);
    dataset_string += datasets_[i] + ",";
  }
  LOG4CXX_INFO(logger_, "Setting the datasets allowed to: " << dataset_string);
}

void LiveViewPlugin::set_tagged_filter_config(std::string value)
{
  std::string delim = ",";
  tags_.clear();
  if (!value.empty())
  {
    boost::split(tags_, value, boost::is_any_of(delim));
  }
  std::string tags_string = "";
  for (int i = 0; i < tags_.size(); i++)
  {
    boost::trim(tags_[i]);
    tags_string += tags_[i] + ", ";
  }
  LOG4CXX_INFO(logger_, "Only Displaying images with the following tags: " << tags_string);
}

}/*namespace FrameProcessor*/

<commit_msg>Moved the frame count incrementation so it only counts frames that match the desired dataset<commit_after>/*
 * LiveImageViewPlugin.cpp
 *
 *  Created on: 6 Sept 2018
 *      Author: Adam Neaves - wbd45595
 */

#include "LiveViewPlugin.h"
#include "version.h"
#include <boost/algorithm/string.hpp>

namespace FrameProcessor
{
/* Default Config*/
const int32_t     LiveViewPlugin::DEFAULT_FRAME_FREQ = 1;
const int32_t     LiveViewPlugin::DEFAULT_PER_SECOND = 0;
const std::string LiveViewPlugin::DEFAULT_IMAGE_VIEW_SOCKET_ADDR = "tcp://127.0.0.1:5020";
const std::string LiveViewPlugin::DEFAULT_DATASET_NAME = "";
const std::string LiveViewPlugin::DEFAULT_TAGGED_FILTER = "";

/* Config Names*/
const std::string LiveViewPlugin::CONFIG_FRAME_FREQ =  "frame_frequency";
const std::string LiveViewPlugin::CONFIG_PER_SECOND =  "per_second";
const std::string LiveViewPlugin::CONFIG_SOCKET_ADDR = "live_view_socket_addr";
const std::string LiveViewPlugin::CONFIG_DATASET_NAME = "dataset_name";
const std::string LiveViewPlugin::CONFIG_TAGGED_FILTER_NAME = "filter_tagged";

/**
 * Constructor for this class. Sets up ZMQ pub socket and other default values for the config
 */
LiveViewPlugin::LiveViewPlugin() :
    publish_socket_(ZMQ_PUB)
{
  logger_ = Logger::getLogger("FW.LiveViewPlugin");
  logger_->setLevel(Level::getAll());
  LOG4CXX_INFO(logger_, "LiveViewPlugin version " << this->get_version_long() << " loaded");

  set_frame_freq_config(DEFAULT_FRAME_FREQ);
  set_per_second_config(DEFAULT_PER_SECOND);
  set_socket_addr_config(DEFAULT_IMAGE_VIEW_SOCKET_ADDR);
  set_dataset_name_config(DEFAULT_DATASET_NAME);
  set_tagged_filter_config(DEFAULT_TAGGED_FILTER);
}

/**
 * Class Destructor. Closes the Publish socket
 */
LiveViewPlugin::~LiveViewPlugin()
{
  LOG4CXX_TRACE(logger_, "LiveViewPlugin destructor.");
  publish_socket_.close();
}

/**
 * Process recieved frame. For the live view plugin, this means checking if certain conditions are true (time elapsed, frame number, dataset name)
 * and then, if the conditions mean sending the frame, creating a json header and copying the data to send to the publisher socket.
 *
 * \param[in] frame - pointer to a frame object.
 */
void LiveViewPlugin::process_frame(boost::shared_ptr<Frame> frame)
{
  /** Static Frame Count will increment each time this method is called, basically as a count of how many frames have been processed by the plugin*/
  static uint32_t frame_count_;
  LOG4CXX_TRACE(logger_, "LiveViewPlugin Process Frame.");

  std::string frame_dataset = frame->get_dataset_name();
  /* If datasets is empty, or contains the frame's dataset, then we can potentially send it*/
  if (datasets_.empty() || std::find(datasets_.begin(), datasets_.end(), frame_dataset) != datasets_.end())
  {
    /* If either filtering by tag is disabled, or the frame has the tagged param */
    bool tag_filter_active = !tags_.empty();
    bool is_tagged = false;
    if (tag_filter_active)
    {
      for (int i = 0; i < tags_.size(); i++)
      {
        if (frame->has_parameter(tags_[i]))
        {
          is_tagged = true;
          break;
        }
      }
    }
    if (!tag_filter_active || is_tagged)
    {
      boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
      int32_t elapsed_time = (now - time_last_frame_).total_milliseconds();

      if (per_second_ != 0 && elapsed_time > time_between_frames_) //time between frames too large, showing frame no matter what the frame number is
      {
        LOG4CXX_TRACE(logger_, "Elapsed time " << elapsed_time << " > " << time_between_frames_);
        pass_live_frame(frame);
      }
      else if (frame_freq_ != 0 && frame_count_ % frame_freq_ == 0)
      {
        LOG4CXX_TRACE(logger_, "LiveViewPlugin Frame " << frame->get_frame_number() << " to be displayed.");
        pass_live_frame(frame);
      }
    }
    else
    {
      LOG4CXX_TRACE(logger_, "LiveViewPlugin No Tag(s) found, frame skipped.");
    }
    //push frame down the pipeline no matter if frame was passed to live viewer or not
    frame_count_ ++;
  }
  else
  {
    LOG4CXX_TRACE(logger_,"Frame dataset: " << frame_dataset << " not desired");
  }

  LOG4CXX_TRACE(logger_, "Pushing Data Frame" );
  this->push(frame);
}

/**
 * Set configuration options for this Plugin.
 *
 * This sets up the Live View Plugin according to the configuration IpcMessage
 * objects that are received.
 *
 * \param[in] config - IpcMessage containing configuration data.
 * \param[out] reply - Response IpcMessage.
 */
void LiveViewPlugin::configure(OdinData::IpcMessage& config, OdinData::IpcMessage& reply)
{
  try{
    /* Check if we're setting the frequency of frames to show*/
    if (config.has_param(CONFIG_FRAME_FREQ))
    {
      set_frame_freq_config(config.get_param<int32_t>(CONFIG_FRAME_FREQ));
    }
    /* Check if we're setting the per_second config*/
    if (config.has_param(CONFIG_PER_SECOND))
    {
      set_per_second_config(config.get_param<int32_t>(CONFIG_PER_SECOND));
    }
    /* Check if we are setting the dataset name filter*/
    if (config.has_param(CONFIG_DATASET_NAME))
    {
      set_dataset_name_config(config.get_param<std::string>(CONFIG_DATASET_NAME));
    }
    if (config.has_param(CONFIG_TAGGED_FILTER_NAME))
    {
      set_tagged_filter_config(config.get_param<std::string>(CONFIG_TAGGED_FILTER_NAME));
    }
    /* Display warning if configuration sets the plugin to do nothing*/
    if (per_second_ == 0 && frame_freq_ == 0)
    {
      LOG4CXX_WARN(logger_, "CURRENT LIVE VIEW CONFIGURATION RESULTS IN IT DOING NOTHING");
    }
    /* Check if we're setting the address of the socket to send the live view frames to.*/
    if (config.has_param(CONFIG_SOCKET_ADDR))
    {
      set_socket_addr_config(config.get_param<std::string>(CONFIG_SOCKET_ADDR));
    }
  }
  catch (std::runtime_error& e)
  {
    std::stringstream ss;
    ss << "Bad ctrl msg: " << e.what();
    this->set_error(ss.str());
    throw;
  }
}

/**
 * Get the configuration values for this Plugin.
 *
 * \param[out] reply - Response IpcMessage.
 */
void LiveViewPlugin::requestConfiguration(OdinData::IpcMessage& reply)
{
  reply.set_param(get_name() + "/" + LiveViewPlugin::CONFIG_FRAME_FREQ, frame_freq_);
  reply.set_param(get_name() + "/" + LiveViewPlugin::CONFIG_SOCKET_ADDR, image_view_socket_addr_);
  reply.set_param(get_name() + "/" + LiveViewPlugin::CONFIG_PER_SECOND, per_second_);
}

/**
 * Constructs a header with information about the data frame, then sends that header and the data
 * to the ZMQ socket interface to be consumed by an external live viewer.
 * The Header contains the following:
 * - int32_t Frame number
 * - string   Acquisition ID
 * - string   Data Type
 * - size_t   Data Size
 * - string   compression type
 * - size_t[] dimensions
 * \param[in] frame - pointer to the data frame
 * \param[in] frame_num - the number of the frame
 *
 */
void LiveViewPlugin::pass_live_frame(boost::shared_ptr<Frame> frame)
{
  void* frame_data_copy = (void*)frame->get_data();

  uint32_t frame_num = frame->get_frame_number();
  std::string aqqID = frame->get_acquisition_id();
  dimensions_t dim = frame->get_dimensions();
  std::string type = get_type_from_enum((DataType)frame->get_data_type());
  std::size_t size = frame->get_data_size();
  std::string compress = get_compress_from_enum((CompressionType)frame->get_compression());
  std::string dataset = frame->get_dataset_name();

  rapidjson::Document document; /* Header info*/
  document.SetObject();
  LOG4CXX_TRACE(logger_, "LiveViewPlugin Building Frame Header");
  //building image header

  add_json_member(&document, "frame_num", frame_num);
  add_json_member(&document, "acquisition_id", aqqID);
  add_json_member(&document, "dtype", type);
  add_json_member(&document, "dsize", static_cast<uint64_t>(size));
  add_json_member(&document, "dataset", dataset);
  add_json_member(&document, "compression", compress);

  //getting tags manually because it is an array
  rapidjson::Value keyTags("tags", document.GetAllocator());
  rapidjson::Value valueTags(rapidjson::kArrayType);
  if (!tags_.empty())
  {
    for(int i = 0; i < tags_.size(); i++)
    {
      if (frame->has_parameter(tags_[i]))
      {
        rapidjson::Value tagStringVal(tags_[i].c_str(), document.GetAllocator());
        valueTags.PushBack(tagStringVal, document.GetAllocator());
      }
    }
    document.AddMember(keyTags, valueTags, document.GetAllocator());
  }

  //getting dimensions manually because its an array
  rapidjson::Value keyDims("shape", document.GetAllocator());
  rapidjson::Value valueDims(rapidjson::kArrayType);

  size_t dim_size = dim.size();
  for(size_t i=0; i < dim_size; i++)
  {
    std::string dimString = boost::to_string(dim[i]);
    rapidjson::Value dimStringVal(dimString.c_str(), document.GetAllocator());
    valueDims.PushBack(dimStringVal, document.GetAllocator());
  }

  document.AddMember(keyDims, valueDims, document.GetAllocator());

  //convert to a json like string so that it can be passed along the socket as the image header
  rapidjson::StringBuffer buffer;
  buffer.Clear();
  rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<> > writer(buffer);

  document.Accept(writer);

  LOG4CXX_TRACE(logger_, "LiveViewPlugin Header Built, sending down socket.");
  publish_socket_.send(buffer.GetString(), ZMQ_SNDMORE);
  LOG4CXX_TRACE(logger_, "LiveViewPlugin Sending frame raw data");
  publish_socket_.send(size, frame_data_copy, 0);

  time_last_frame_ = boost::posix_time::microsec_clock::local_time();
}

void LiveViewPlugin::add_json_member(rapidjson::Document* document, std::string key, std::string value)
{
  rapidjson::Value rkey(key.c_str(), document->GetAllocator());
  rapidjson::Value rvalue(value.c_str(), document->GetAllocator());
  document->AddMember(rkey, rvalue, document->GetAllocator());
}

void LiveViewPlugin::add_json_member(rapidjson::Document* document, std::string key, uint32_t value)
{
  rapidjson::Value rkey(key.c_str(), document->GetAllocator());
  rapidjson::Value rvalue(value);
  document->AddMember(rkey, rvalue, document->GetAllocator());
}
int LiveViewPlugin::get_version_major()
{
  return ODIN_DATA_VERSION_MAJOR;
}

int LiveViewPlugin::get_version_minor()
{
  return ODIN_DATA_VERSION_MINOR;
}

int LiveViewPlugin::get_version_patch()
{
  return ODIN_DATA_VERSION_PATCH;
}

std::string LiveViewPlugin::get_version_short()
{
  return ODIN_DATA_VERSION_STR_SHORT;
}

std::string LiveViewPlugin::get_version_long()
{
  return ODIN_DATA_VERSION_STR;
}

/**
 * Sets the config value "per_second" which tells the plugin the number of frames to show each second
 * Setting this value to 0 disables the "frames per second" checking
 * \param[in] value - the value to assign to per_second
 */
void LiveViewPlugin::set_per_second_config(int32_t value)
{
  per_second_ = value;

  if (per_second_ == 0)
  {
    LOG4CXX_INFO(logger_, "Disabling Frames Per Second Option");
  }
  else
  {
    LOG4CXX_INFO(logger_, "Displaying " << per_second_ << " frames per second");
    time_between_frames_ = 1000 / per_second_;
  }
}
/**
 * Sets the Frame Frequency config value. This value tells the plugin to show every Nth frame.
 * Setting this value to 0 disables this check
 * \param[in] value - the value to assign to frame_freq
 */
void LiveViewPlugin::set_frame_freq_config(int32_t value)
{
  frame_freq_ = value;
  if (frame_freq_ == 0)
  {
    LOG4CXX_INFO(logger_, "Disabling Frame Frequency");
  }
  else
  {
    LOG4CXX_INFO(logger_, "Showing every " << frame_freq_ << " frame(s)");
  }
}
/**
 * Sets the address of the publisher socket that live view data is sent to.
 * When setting this address, it also binds the socket to the address, unbinding it from any previous address given
 * \param[in] value - the address to bind the socket to.
 */
void LiveViewPlugin::set_socket_addr_config(std::string value)
{
  //we dont want to unbind and rebind the same address, as it can cause an error if it takes time to unbind, so we check first
  if (publish_socket_.has_bound_endpoint(value))
  {
    LOG4CXX_WARN(logger_, "Socket already bound to " << value << ". Doing nothing");
    return;
  }
  uint32_t linger = 0;
  publish_socket_.setsockopt(ZMQ_LINGER, &linger, sizeof(linger));
  publish_socket_.unbind(image_view_socket_addr_.c_str());

  image_view_socket_addr_ = value;
  LOG4CXX_INFO(logger_, "Setting Live View Socket Address to " << image_view_socket_addr_);
  publish_socket_.bind(image_view_socket_addr_);
}

/**
 * Sets the dataset filter configuration. The live view output can be filtered by the dataset variable on the frame based off a list
 * of desired datasets.
 * \param[in] value - A comma deliminated list of dataset names, or an empty string to ignore this filtering.
 */
void LiveViewPlugin::set_dataset_name_config(std::string value)
{
  std::string delim = ",";
  datasets_.clear();
  if (!value.empty())
  {
    //delim value string by comma
    boost::split(datasets_, value, boost::is_any_of(delim));
  }
  std::string dataset_string = "";
  for (int i = 0; i < datasets_.size(); i++)
  {
    boost::trim(datasets_[i]);
    dataset_string += datasets_[i] + ",";
  }
  LOG4CXX_INFO(logger_, "Setting the datasets allowed to: " << dataset_string);
}

void LiveViewPlugin::set_tagged_filter_config(std::string value)
{
  std::string delim = ",";
  tags_.clear();
  if (!value.empty())
  {
    boost::split(tags_, value, boost::is_any_of(delim));
  }
  std::string tags_string = "";
  for (int i = 0; i < tags_.size(); i++)
  {
    boost::trim(tags_[i]);
    tags_string += tags_[i] + ", ";
  }
  LOG4CXX_INFO(logger_, "Only Displaying images with the following tags: " << tags_string);
}

}/*namespace FrameProcessor*/

<|endoftext|>


<commit_before>/**
  *  @copyright Copyright (c) 2015, J-PET collaboration
  *  @file JPetOptions.cpp
  *  @author Wojciech Krzemien, wojciech.krzemien@if.uj.edu.pl
  */

#include "./JPetOptions.h"
#include "../../JPetLoggerInclude.h"

JPetOptions::Options JPetOptions::kDefaultOptions = {
  {"inputFile", ""},
  {"inputFileType", ""},
  {"outputFile", ""},
  {"outputFileType", ""},
  {"firstEvent", "-1"},
  {"lastEvent", "-1"},
  {"progressBar", "false"},
  {"runId", "-1"}
};

JPetOptions::JPetOptions()
{
  setStringToFileTypeConversion();
  fOptions = JPetOptions::kDefaultOptions;
}

JPetOptions::JPetOptions(const Options& opts):
  fOptions(opts)
{
  setStringToFileTypeConversion();
  if (areCorrect(opts)) {
    setOptions(opts);
  } else {
    ERROR("Options are not correct using default ones");
  }
}

void JPetOptions::setStringToFileTypeConversion()
{
  fStringToFileType = {
    {"", kNoType},
    {"root", kRoot},
    {"scope", kScope},
    {"raw", kRaw},
    {"hld", kHld},
    {"phys.eve", kPhysEve},
    {"phys.hit", kPhysHit},
    {"phys.sig", kPhysSig},
    {"raw.sig", kRawSig},
    {"reco.sig", kRecoSig},
    {"tslot.cal", kTslotCal},
    {"tslot.raw", kTslotRaw}
  };
}

bool JPetOptions::areCorrect(const Options& opts) const
{
  return true;
}
<commit_msg>Change default outputfile to test.root<commit_after>/**
  *  @copyright Copyright (c) 2015, J-PET collaboration
  *  @file JPetOptions.cpp
  *  @author Wojciech Krzemien, wojciech.krzemien@if.uj.edu.pl
  */

#include "./JPetOptions.h"
#include "../../JPetLoggerInclude.h"

JPetOptions::Options JPetOptions::kDefaultOptions = {
  {"inputFile", ""},
  {"inputFileType", ""},
  {"outputFile", "root"},
  {"outputFileType", "test.root"},
  {"firstEvent", "-1"},
  {"lastEvent", "-1"},
  {"progressBar", "false"},
  {"runId", "-1"}
};

JPetOptions::JPetOptions()
{
  setStringToFileTypeConversion();
  fOptions = JPetOptions::kDefaultOptions;
}

JPetOptions::JPetOptions(const Options& opts):
  fOptions(opts)
{
  setStringToFileTypeConversion();
  if (areCorrect(opts)) {
    setOptions(opts);
  } else {
    ERROR("Options are not correct using default ones");
  }
}

void JPetOptions::setStringToFileTypeConversion()
{
  fStringToFileType = {
    {"", kNoType},
    {"root", kRoot},
    {"scope", kScope},
    {"raw", kRaw},
    {"hld", kHld},
    {"phys.eve", kPhysEve},
    {"phys.hit", kPhysHit},
    {"phys.sig", kPhysSig},
    {"raw.sig", kRawSig},
    {"reco.sig", kRecoSig},
    {"tslot.cal", kTslotCal},
    {"tslot.raw", kTslotRaw}
  };
}

bool JPetOptions::areCorrect(const Options& opts) const
{
  return true;
}
<|endoftext|>


<commit_before>#include "TrackLayer.h"

#include "PathUtil.h"
#include "Projection.h"
#include "Types.h"
#include "ViewCtx.h"

#define PARTICLE_RADIUS 12.0
#define MEDIUM_LOD_RES 10.0
#define LO_LOD_RES 20.0

using namespace cinder;

const Color TrackLayer::RunColor = Color( 1, 0, 0 );
const Color TrackLayer::OtherColor = Color( 0.3, 0.3, 1 );
const Color TrackLayer::SelectedColor = Color( 1, 1, 0 );

QOpenGLShaderProgram* TrackLayer::_shader;
bool TrackLayer::_isSetup = false;
bool TrackLayer::_particlesDrawn = false;
bool TrackLayer::_selectedParticlesDrawn = false;
QList<Vec2d> TrackLayer::_particleDrawList;
QList<Vec2d> TrackLayer::_selectedParticleDrawList;
float TrackLayer::_particleRadius = PARTICLE_RADIUS;

void
TrackLayer::_setup()
{
    _shader = new QOpenGLShaderProgram();
    // shaders from http://www.geeks3d.com/20130705/shader-library-circle-disc-fake-sphere-in-glsl-opengl-glslhacker/3/
    _shader->addShaderFromSourceCode(QOpenGLShader::Vertex,
        "#version 120\n"
        "void main()\n"
        "{\n"
        "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
        "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
        "}\n");
    _shader->addShaderFromSourceCode(QOpenGLShader::Fragment,
        "#version 120\n"
        "uniform sampler2D tex0;\n"
        "uniform float border_size; // 0.01\n"
        "uniform float disc_radius; // 0.5\n"
        "uniform vec4 disc_color; // vec4(1.0, 1.0, 1.0, 1.0)\n"
        "uniform vec2 disc_center; // vec2(0.5, 0.5)\n"
        "void main (void)\n"
        "{\n"
        "    vec2 uv = gl_TexCoord[0].xy;\n\n"
        "    vec4 bkg_color = texture2D(tex0,uv * vec2(1.0, -1.0));\n"
        "    // Offset uv with the center of the circle.\n"
        "    uv -= disc_center;\n"
        "    float dist = sqrt(dot(uv, uv));\n"
        "    float t = smoothstep(disc_radius+border_size, disc_radius-border_size, dist);\n"
        "    gl_FragColor = mix(bkg_color, disc_color, t);\n"
        "}\n");
    _isSetup = true;
}

TrackLayer::TrackLayer(const Track *track) : Layer(),
_mediumLodRes(MEDIUM_LOD_RES),
_loLodRes(LO_LOD_RES),
_track(track),
_duration(0)
{
    if (!_isSetup)
        _setup();
    int numPts = track->points.size();
    if (numPts > 0)
        _startTime = QDateTime::fromTime_t(track->points[0].time);
    if (numPts > 1)
        _duration = track->points[numPts-1].time - track->points[0].time;
    _pathBuffer = (float*)malloc(sizeof(float)*4*numPts);
}

TrackLayer::~TrackLayer()
{
    free(_pathBuffer);
    _pathBuffer = NULL;
    delete _track;
}

QString
TrackLayer::name() const
{
    return _track->name;
}

QString
TrackLayer::sport() const
{
    return _track->sport;
}

QDateTime
TrackLayer::startTime() const
{
    return _startTime;
}

PassMap
TrackLayer::passes() const
{
    PassMap layers;
    layers.insert(Pass_UnselectedPath);
    layers.insert(Pass_SelectedPath);
    layers.insert(Pass_Particles);
    return layers;
}

/*
 * Linear interpolate between a and b by the fractional f.
 */
double lerp(double a, double b, double f)
{
    return a + f * (b - a);
}

MapPoint lerp(const MapPoint& a, const MapPoint& b, double f)
{
    return MapPoint(lerp(a.x, b.x, f), lerp(a.y, b.y, f));
}

unsigned int
TrackLayer::duration() const
{
    return _duration;
}

void
TrackLayer::project(const Projection &projection)
{
    // Project the track into the hi-res path and compute the bounding box
    int startTime = 0;
    for(size_t i=0; i < _track->points.size(); i++) {
        TrackPoint pt = _track->points[i];
        if (i == 0)
            startTime = pt.time;
        PathPoint newPt;
        newPt.pos = projection.toProjection(pt.pos);
        newPt.time = pt.time - startTime;
        _path_hi.push_back(newPt);
        _bounds += newPt.pos;
    }

    _particleRadius *= projection.getScaleMultiplier();
    _mediumLodRes *= projection.getScaleMultiplier();
    _loLodRes *= projection.getScaleMultiplier();

    qDebug("med: %f, lo: %f", _mediumLodRes, _loLodRes);
    qDebug("hi: %d points", _path_hi.count());

    // Make the medium res path
    _path_med = PathUtil::DouglasPeucker(_path_hi, _mediumLodRes);
    qDebug("med: %d points", _path_med.count());

    // Make the low res path
    _path_lo = PathUtil::DouglasPeucker(_path_med, _loLodRes);
    qDebug("lo: %d points", _path_lo.count());
}

void
TrackLayer::draw(uint pass, const ViewCtx &viewCtx, const TimeCtx &timeCtx)
{
    if (!visible() || !_bounds.overlaps(viewCtx.getBoundingBox()))
        return;
    bool selected = viewCtx.isSelected(id());
    switch (pass) {
        case Pass_UnselectedPath:
            if (!selected)
                _drawPath(viewCtx, timeCtx);
            _pushParticle(viewCtx);
            break;
        case Pass_SelectedPath:
            if (selected)
                _drawPath(viewCtx, timeCtx);
            break;
        case Pass_Particles:
            _drawParticles(viewCtx);
            break;
    };
}

void
TrackLayer::_drawPath(const ViewCtx &viewCtx, const TimeCtx &timeCtx)
{
    // Choose which path to display
    Path *currentPath = &_path_hi;
    double res = viewCtx.getResolution();
    if (res >= _mediumLodRes && res < _loLodRes)
        currentPath = &_path_med;
    else if (res >= _loLodRes)
        currentPath = &_path_lo;

    if (viewCtx.isSelected(id()))
        gl::color( SelectedColor );
    else if (_track->sport == "Running")
        gl::color( RunColor );
    else
        gl::color( OtherColor );

    MapPoint w2c = viewCtx.getWorldToCamera();
    PathPoint *lastPathPt;
    MapPoint *lastMapPt;
    int bufferIndex = 0;
    bool lastInbounds = false;
    for(int i=0; i < currentPath->count(); i++) {
        PathPoint *pt = &(*currentPath)[i];
        MapPoint *thisMapPt = &(pt->pos);
        bool inbounds = viewCtx.getBoundingBox().contains(*thisMapPt);
        if (i == 0 || pt->time < timeCtx.getMapSeconds()) {
            if (i > 0 && (inbounds || lastInbounds)) {
                _pathBuffer[bufferIndex++] = w2c.x + lastMapPt->x;
                _pathBuffer[bufferIndex++] = w2c.y + lastMapPt->y;
                _pathBuffer[bufferIndex++] = w2c.x + thisMapPt->x;
                _pathBuffer[bufferIndex++] = w2c.y + thisMapPt->y;
            }
            lastMapPt = thisMapPt;
            lastPathPt = pt;
            _particlePos = *lastMapPt;
        } else {
            double elapsed = timeCtx.getMapSeconds() -
                             double(lastPathPt->time);
            int trkElapsed = pt->time - lastPathPt->time;
            double f = (trkElapsed == 0) ? 0. : elapsed / double(trkElapsed);
            if (f > 0.0 && (inbounds || lastInbounds)) {
                MapPoint finalPt = lerp(*lastMapPt, *thisMapPt, f);
                _pathBuffer[bufferIndex++] = w2c.x + lastMapPt->x;
                _pathBuffer[bufferIndex++] = w2c.y + lastMapPt->y;
                _pathBuffer[bufferIndex++] = w2c.x + finalPt.x;
                _pathBuffer[bufferIndex++] = w2c.y + finalPt.y;
                _particlePos = finalPt;
            }
            break;
        }
        lastInbounds = inbounds;
    }
    glEnableClientState( GL_VERTEX_ARRAY );
    glVertexPointer( 2, GL_FLOAT, 0, _pathBuffer );
    glDrawArrays( GL_LINES, 0, bufferIndex/2 );
    glDisableClientState( GL_VERTEX_ARRAY );
}

void
TrackLayer::_pushParticle(const ViewCtx &viewCtx) const
{
    _particlesDrawn = false;
    // transform to camera space
    const Vec2d particlePosCamera = viewCtx.getWorldToCamera() + _particlePos;
    if (viewCtx.isSelected(id()))
        _selectedParticleDrawList.append(particlePosCamera);
    else
        _particleDrawList.append(particlePosCamera);
    /*
    gl::drawSolidCircle( particlePosCamera, radius);
    if (viewCtx.isSelected(id())) {
        gl::drawStrokedCircle(particlePosCamera, radius*1.5);
        gl::drawStrokedCircle(particlePosCamera, radius*2.0);
    }
    gl::color( Color( 0.3, 0.3, 0.3 ) );
    gl::drawStrokedCircle(particlePosCamera, radius);
    */
}

BoundingBox
TrackLayer::getBoundingBox() const
{
    return _bounds;
}

MapPoint
TrackLayer::position() const
{
    return _particlePos;
}

bool
TrackLayer::ephemeral() const
{
    return false;
}

void
TrackLayer::_drawParticles(const ViewCtx &viewCtx)
{
    _particlesDrawn = true;
    Vec2d particle;
    size_t numParticles = _particleDrawList.count();
    float *_particleBuffer = (float*)malloc(sizeof(float)*2*numParticles);
    size_t bufferIndex = 0;
    foreach(particle, _particleDrawList) {
        _particleBuffer[bufferIndex++] = particle.x;
        _particleBuffer[bufferIndex++] = particle.y;
    }
    float radius = _particleRadius;
    if (radius < viewCtx.getResolution()*2.)
        radius = viewCtx.getResolution()*2.;
    _shader->bind();
    glEnableClientState( GL_VERTEX_ARRAY );
    glVertexPointer( 2, GL_FLOAT, 0, _particleBuffer );
    glDrawArrays( GL_POINTS, 0, bufferIndex/2 );
    glDisableClientState( GL_VERTEX_ARRAY );
    _shader->release();
    free(_particleBuffer);
}

void
TrackLayer::_drawSelectedParticles(const ViewCtx &viewCtx)
{
    _selectedParticlesDrawn = true;
}
<commit_msg>And don’t forget to clear the particle drawlist after drawing the particles.<commit_after>#include "TrackLayer.h"

#include "PathUtil.h"
#include "Projection.h"
#include "Types.h"
#include "ViewCtx.h"

#define PARTICLE_RADIUS 12.0
#define MEDIUM_LOD_RES 10.0
#define LO_LOD_RES 20.0

using namespace cinder;

const Color TrackLayer::RunColor = Color( 1, 0, 0 );
const Color TrackLayer::OtherColor = Color( 0.3, 0.3, 1 );
const Color TrackLayer::SelectedColor = Color( 1, 1, 0 );

QOpenGLShaderProgram* TrackLayer::_shader;
bool TrackLayer::_isSetup = false;
bool TrackLayer::_particlesDrawn = false;
bool TrackLayer::_selectedParticlesDrawn = false;
QList<Vec2d> TrackLayer::_particleDrawList;
QList<Vec2d> TrackLayer::_selectedParticleDrawList;
float TrackLayer::_particleRadius = PARTICLE_RADIUS;

void
TrackLayer::_setup()
{
    _shader = new QOpenGLShaderProgram();
    // shaders from http://www.geeks3d.com/20130705/shader-library-circle-disc-fake-sphere-in-glsl-opengl-glslhacker/3/
    _shader->addShaderFromSourceCode(QOpenGLShader::Vertex,
        "#version 120\n"
        "void main()\n"
        "{\n"
        "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
        "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
        "}\n");
    _shader->addShaderFromSourceCode(QOpenGLShader::Fragment,
        "#version 120\n"
        "uniform sampler2D tex0;\n"
        "uniform float border_size; // 0.01\n"
        "uniform float disc_radius; // 0.5\n"
        "uniform vec4 disc_color; // vec4(1.0, 1.0, 1.0, 1.0)\n"
        "uniform vec2 disc_center; // vec2(0.5, 0.5)\n"
        "void main (void)\n"
        "{\n"
        "    vec2 uv = gl_TexCoord[0].xy;\n\n"
        "    vec4 bkg_color = texture2D(tex0,uv * vec2(1.0, -1.0));\n"
        "    // Offset uv with the center of the circle.\n"
        "    uv -= disc_center;\n"
        "    float dist = sqrt(dot(uv, uv));\n"
        "    float t = smoothstep(disc_radius+border_size, disc_radius-border_size, dist);\n"
        "    gl_FragColor = mix(bkg_color, disc_color, t);\n"
        "}\n");
    _isSetup = true;
}

TrackLayer::TrackLayer(const Track *track) : Layer(),
_mediumLodRes(MEDIUM_LOD_RES),
_loLodRes(LO_LOD_RES),
_track(track),
_duration(0)
{
    if (!_isSetup)
        _setup();
    int numPts = track->points.size();
    if (numPts > 0)
        _startTime = QDateTime::fromTime_t(track->points[0].time);
    if (numPts > 1)
        _duration = track->points[numPts-1].time - track->points[0].time;
    _pathBuffer = (float*)malloc(sizeof(float)*4*numPts);
}

TrackLayer::~TrackLayer()
{
    free(_pathBuffer);
    _pathBuffer = NULL;
    delete _track;
}

QString
TrackLayer::name() const
{
    return _track->name;
}

QString
TrackLayer::sport() const
{
    return _track->sport;
}

QDateTime
TrackLayer::startTime() const
{
    return _startTime;
}

PassMap
TrackLayer::passes() const
{
    PassMap layers;
    layers.insert(Pass_UnselectedPath);
    layers.insert(Pass_SelectedPath);
    layers.insert(Pass_Particles);
    return layers;
}

/*
 * Linear interpolate between a and b by the fractional f.
 */
double lerp(double a, double b, double f)
{
    return a + f * (b - a);
}

MapPoint lerp(const MapPoint& a, const MapPoint& b, double f)
{
    return MapPoint(lerp(a.x, b.x, f), lerp(a.y, b.y, f));
}

unsigned int
TrackLayer::duration() const
{
    return _duration;
}

void
TrackLayer::project(const Projection &projection)
{
    // Project the track into the hi-res path and compute the bounding box
    int startTime = 0;
    for(size_t i=0; i < _track->points.size(); i++) {
        TrackPoint pt = _track->points[i];
        if (i == 0)
            startTime = pt.time;
        PathPoint newPt;
        newPt.pos = projection.toProjection(pt.pos);
        newPt.time = pt.time - startTime;
        _path_hi.push_back(newPt);
        _bounds += newPt.pos;
    }

    _particleRadius *= projection.getScaleMultiplier();
    _mediumLodRes *= projection.getScaleMultiplier();
    _loLodRes *= projection.getScaleMultiplier();

    qDebug("med: %f, lo: %f", _mediumLodRes, _loLodRes);
    qDebug("hi: %d points", _path_hi.count());

    // Make the medium res path
    _path_med = PathUtil::DouglasPeucker(_path_hi, _mediumLodRes);
    qDebug("med: %d points", _path_med.count());

    // Make the low res path
    _path_lo = PathUtil::DouglasPeucker(_path_med, _loLodRes);
    qDebug("lo: %d points", _path_lo.count());
}

void
TrackLayer::draw(uint pass, const ViewCtx &viewCtx, const TimeCtx &timeCtx)
{
    if (!visible() || !_bounds.overlaps(viewCtx.getBoundingBox()))
        return;
    bool selected = viewCtx.isSelected(id());
    switch (pass) {
        case Pass_UnselectedPath:
            if (!selected)
                _drawPath(viewCtx, timeCtx);
            _pushParticle(viewCtx);
            break;
        case Pass_SelectedPath:
            if (selected)
                _drawPath(viewCtx, timeCtx);
            break;
        case Pass_Particles:
            _drawParticles(viewCtx);
            break;
    };
}

void
TrackLayer::_drawPath(const ViewCtx &viewCtx, const TimeCtx &timeCtx)
{
    // Choose which path to display
    Path *currentPath = &_path_hi;
    double res = viewCtx.getResolution();
    if (res >= _mediumLodRes && res < _loLodRes)
        currentPath = &_path_med;
    else if (res >= _loLodRes)
        currentPath = &_path_lo;

    if (viewCtx.isSelected(id()))
        gl::color( SelectedColor );
    else if (_track->sport == "Running")
        gl::color( RunColor );
    else
        gl::color( OtherColor );

    MapPoint w2c = viewCtx.getWorldToCamera();
    PathPoint *lastPathPt;
    MapPoint *lastMapPt;
    int bufferIndex = 0;
    bool lastInbounds = false;
    for(int i=0; i < currentPath->count(); i++) {
        PathPoint *pt = &(*currentPath)[i];
        MapPoint *thisMapPt = &(pt->pos);
        bool inbounds = viewCtx.getBoundingBox().contains(*thisMapPt);
        if (i == 0 || pt->time < timeCtx.getMapSeconds()) {
            if (i > 0 && (inbounds || lastInbounds)) {
                _pathBuffer[bufferIndex++] = w2c.x + lastMapPt->x;
                _pathBuffer[bufferIndex++] = w2c.y + lastMapPt->y;
                _pathBuffer[bufferIndex++] = w2c.x + thisMapPt->x;
                _pathBuffer[bufferIndex++] = w2c.y + thisMapPt->y;
            }
            lastMapPt = thisMapPt;
            lastPathPt = pt;
            _particlePos = *lastMapPt;
        } else {
            double elapsed = timeCtx.getMapSeconds() -
                             double(lastPathPt->time);
            int trkElapsed = pt->time - lastPathPt->time;
            double f = (trkElapsed == 0) ? 0. : elapsed / double(trkElapsed);
            if (f > 0.0 && (inbounds || lastInbounds)) {
                MapPoint finalPt = lerp(*lastMapPt, *thisMapPt, f);
                _pathBuffer[bufferIndex++] = w2c.x + lastMapPt->x;
                _pathBuffer[bufferIndex++] = w2c.y + lastMapPt->y;
                _pathBuffer[bufferIndex++] = w2c.x + finalPt.x;
                _pathBuffer[bufferIndex++] = w2c.y + finalPt.y;
                _particlePos = finalPt;
            }
            break;
        }
        lastInbounds = inbounds;
    }
    glEnableClientState( GL_VERTEX_ARRAY );
    glVertexPointer( 2, GL_FLOAT, 0, _pathBuffer );
    glDrawArrays( GL_LINES, 0, bufferIndex/2 );
    glDisableClientState( GL_VERTEX_ARRAY );
}

void
TrackLayer::_pushParticle(const ViewCtx &viewCtx) const
{
    _particlesDrawn = false;
    // transform to camera space
    const Vec2d particlePosCamera = viewCtx.getWorldToCamera() + _particlePos;
    if (viewCtx.isSelected(id()))
        _selectedParticleDrawList.append(particlePosCamera);
    else
        _particleDrawList.append(particlePosCamera);
    /*
    gl::drawSolidCircle( particlePosCamera, radius);
    if (viewCtx.isSelected(id())) {
        gl::drawStrokedCircle(particlePosCamera, radius*1.5);
        gl::drawStrokedCircle(particlePosCamera, radius*2.0);
    }
    gl::color( Color( 0.3, 0.3, 0.3 ) );
    gl::drawStrokedCircle(particlePosCamera, radius);
    */
}

BoundingBox
TrackLayer::getBoundingBox() const
{
    return _bounds;
}

MapPoint
TrackLayer::position() const
{
    return _particlePos;
}

bool
TrackLayer::ephemeral() const
{
    return false;
}

void
TrackLayer::_drawParticles(const ViewCtx &viewCtx)
{
    _particlesDrawn = true;
    Vec2d particle;
    size_t numParticles = _particleDrawList.count();
    float *_particleBuffer = (float*)malloc(sizeof(float)*2*numParticles);
    size_t bufferIndex = 0;
    foreach(particle, _particleDrawList) {
        _particleBuffer[bufferIndex++] = particle.x;
        _particleBuffer[bufferIndex++] = particle.y;
    }
    float radius = _particleRadius;
    if (radius < viewCtx.getResolution()*2.)
        radius = viewCtx.getResolution()*2.;
    _shader->bind();
    glEnableClientState( GL_VERTEX_ARRAY );
    glVertexPointer( 2, GL_FLOAT, 0, _particleBuffer );
    glDrawArrays( GL_POINTS, 0, bufferIndex/2 );
    glDisableClientState( GL_VERTEX_ARRAY );
    _shader->release();
    free(_particleBuffer);
    _particleDrawList.clear();
}

void
TrackLayer::_drawSelectedParticles(const ViewCtx &viewCtx)
{
    _selectedParticlesDrawn = true;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001 Russell L. Smith.            *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of the GNU Lesser General Public            *
 * License as published by the Free Software Foundation; either          *
 * version 2.1 of the License, or (at your option) any later version.    *
 *                                                                       *
 * This library is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
 * Lesser General Public License for more details.                       *
 *                                                                       *
 * You should have received a copy of the GNU Lesser General Public      *
 * License along with this library (see the file LICENSE.TXT); if not,   *
 * write to the Free Software Foundation, Inc., 59 Temple Place,         *
 * Suite 330, Boston, MA 02111-1307 USA.                                 *
 *                                                                       *
 *************************************************************************/

#include <stdio.h>
#include "ode/ode.h"
#include "drawstuff/drawstuff.h"

// select correct drawing functions

#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCappedCylinder dsDrawCappedCylinderD
#endif

// some constants

#define LENGTH 0.7	// chassis length
#define WIDTH 0.5	// chassis width
#define HEIGHT 0.2	// chassis height
#define RADIUS 0.18	// wheel radius
#define STARTZ 0.5	// starting height of chassis
#define CMASS 1		// chassis mass
#define WMASS 0.2	// wheel mass

// dynamics and collision objects (chassis, 3 wheels, environment)

static dWorldID world;
static dSpaceID space;
static dBodyID body[4];
static dJointID joint[3];	// joint[0] is the front wheel
static dJointID dmotor,smotor;	// front wheel drive & steering motors
static dJointGroupID contactgroup;
static dGeomID ground;
static dGeomID box[1];
static dGeomID sphere[3];
static dGeomID ground_box;

// things that the user controls

static dReal speed=0,steer=0;	// user commands

// this is called by dSpaceCollide when two objects in space are
// potentially colliding.

static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
  // only collide things with the ground
  int g1 = (o1 == ground || o1 == ground_box);
  int g2 = (o2 == ground || o2 == ground_box);
  if (!(g1 ^ g2)) return;

  dContact contact;
  contact.surface.mode = 0;
  contact.surface.mu = dInfinity;
  if (dCollide (o1,o2,0,&contact.geom,sizeof(dContactGeom))) {
    //    if (o1==ground_box) printf ("foo 1\n");
    //    if (o2==ground_box) printf ("foo 2\n");

    dJointID c = dJointCreateContact (world,contactgroup,&contact);
    dJointAttach (c,dGeomGetBody(o1),dGeomGetBody(o2));
  }
}

// start simulation - set viewpoint

static void start()
{
  static float xyz[3] = {0.8317,-0.9817,0.8000};
  static float hpr[3] = {121.0000,-27.5000,0.0000};
  dsSetViewpoint (xyz,hpr);
}

// called when a key pressed

static void command (int cmd)
{
  switch (cmd) {
  case 'a': case 'A':
    speed += 0.3;
    break;
  case 'z': case 'Z':
    speed -= 0.3;
    break;
  case ',':
    steer -= 0.2;
    break;
  case '.':
    steer += 0.2;
    break;
  case ' ':
    speed = 0;
    steer = 0;
    break;
  }
}

// simulation loop

static void simLoop (int pause)
{
  int i;
  if (!pause) {
    //dJointSetRMotorVel (dmotor,speed);
    //dJointSetRMotorTmax (dmotor,0.1);
    dJointSetHingeVel (joint[2],speed);
    dJointSetHingeTmax (joint[2],0.1);

    dJointSetRMotorVel (smotor,steer);
    dJointSetRMotorTmax (smotor,0.1);

    dSpaceCollide (space,0,&nearCallback);
    dWorldStep (world,0.05);

    // remove all contact joints
    dJointGroupEmpty (contactgroup);
  }

  dsSetColor (0,1,1);
  dsSetTexture (DS_WOOD);
  dReal sides[3] = {LENGTH,WIDTH,HEIGHT};
  dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides);
  dsSetColor (1,1,1);
  for (i=1; i<=3; i++) dsDrawCylinder (dBodyGetPosition(body[i]),
				       dBodyGetRotation(body[i]),0.02,RADIUS);

  /*
  dVector3 ss;
  dGeomBoxGetLengths (ground_box,ss);
  dsDrawBox (dGeomGetPosition(ground_box),dGeomGetRotation(ground_box),ss);
  */

  printf ("%.10f %.10f %.10f %.10f\n",
	  dJointGetHingeAngle (joint[1]),
	  dJointGetHingeAngle (joint[2]),
	  dJointGetHingeAngleRate (joint[1]),
	  dJointGetHingeAngleRate (joint[2]));
}

int main (int argc, char **argv)
{
  int i;
  dMass m;

  // setup pointers to drawstuff callback functions
  dsFunctions fn;
  fn.version = DS_VERSION;
  fn.start = &start;
  fn.step = &simLoop;
  fn.command = &command;
  fn.stop = 0;
  fn.path_to_textures = "../../drawstuff/textures";

  // create world

  world = dWorldCreate();
  space = dSpaceCreate();
  contactgroup = dJointGroupCreate (1000000);
  dWorldSetGravity (world,0,0,-0.5);
  ground = dCreatePlane (space,0,0,1,0);

  // chassis body
  body[0] = dBodyCreate (world);
  dBodySetPosition (body[0],0,0,STARTZ);
  dMassSetBox (&m,1,LENGTH,WIDTH,HEIGHT);
  dMassAdjust (&m,CMASS);
  dBodySetMass (body[0],&m);
  box[0] = dCreateBox (space,LENGTH,WIDTH,HEIGHT);
  dGeomSetBody (box[0],body[0]);

  // wheel bodies
  for (i=1; i<=3; i++) {
    body[i] = dBodyCreate (world);
    dQuaternion q;
    dQFromAxisAndAngle (q,1,0,0,M_PI*0.5);
    dBodySetQuaternion (body[i],q);
    dMassSetSphere (&m,1,RADIUS);
    dMassAdjust (&m,WMASS);
    dBodySetMass (body[i],&m);
    sphere[i-1] = dCreateSphere (space,RADIUS);
    dGeomSetBody (sphere[i-1],body[i]);
  }
  dBodySetPosition (body[1],0.5*LENGTH,0,STARTZ-HEIGHT*0.5);
  dBodySetPosition (body[2],-0.5*LENGTH, WIDTH*0.5,STARTZ-HEIGHT*0.5);
  dBodySetPosition (body[3],-0.5*LENGTH,-WIDTH*0.5,STARTZ-HEIGHT*0.5);

  // front wheel hinge
  joint[0] = dJointCreateHinge2 (world,0);
  dJointAttach (joint[0],body[0],body[1]);
  const dReal *a = dBodyGetPosition (body[1]);
  dJointSetHinge2Anchor (joint[0],a[0],a[1],a[2]);
  dJointSetHinge2Axis1 (joint[0],0,0,1);
  dJointSetHinge2Axis2 (joint[0],0,1,0);

  // back wheel hinges
  for (i=1; i<3; i++) {
    joint[i] = dJointCreateHinge (world,0);
    dJointAttach (joint[i],body[0],body[i+1]);
    const dReal *a = dBodyGetPosition (body[i+1]);
    dJointSetHingeAnchor (joint[i],a[0],a[1],a[2]);
    dJointSetHingeAxis (joint[i],0,1,0);
  }

  // front wheel motors
  //dmotor = dJointCreateRMotor (world,0);
  //dJointAttach (dmotor,body[1],body[0]);
  //dJointSetRMotorAxis (dmotor,0,1,0);		// motor axis rel to 1st body
  smotor = dJointCreateRMotor (world,0);
  dJointAttach (smotor,body[0],body[1]);
  dJointSetRMotorAxis (smotor,0,0,1);		// motor axis rel to 1st body

  // environment
  /*
  ground_box = dCreateBox (space,2,1.5,1);
  dMatrix3 R;
  dRFromAxisAndAngle (R,0,1,0,-0.15);
  dGeomSetPosition (ground_box,2,0,-0.34);
  dGeomSetRotation (ground_box,R);
  */

  // run simulation
  dsSimulationLoop (argc,argv,352,288,&fn);

  dJointGroupDestroy (contactgroup);
  dSpaceDestroy (space);
  dWorldDestroy (world);

  return 0;
}
<commit_msg>hmmmm.<commit_after>/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001 Russell L. Smith.            *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of the GNU Lesser General Public            *
 * License as published by the Free Software Foundation; either          *
 * version 2.1 of the License, or (at your option) any later version.    *
 *                                                                       *
 * This library is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
 * Lesser General Public License for more details.                       *
 *                                                                       *
 * You should have received a copy of the GNU Lesser General Public      *
 * License along with this library (see the file LICENSE.TXT); if not,   *
 * write to the Free Software Foundation, Inc., 59 Temple Place,         *
 * Suite 330, Boston, MA 02111-1307 USA.                                 *
 *                                                                       *
 *************************************************************************/

#include <stdio.h>
#include "ode/ode.h"
#include "drawstuff/drawstuff.h"

// select correct drawing functions

#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCappedCylinder dsDrawCappedCylinderD
#endif

// some constants

#define LENGTH 0.7	// chassis length
#define WIDTH 0.5	// chassis width
#define HEIGHT 0.2	// chassis height
#define RADIUS 0.18	// wheel radius
#define STARTZ 0.5	// starting height of chassis
#define CMASS 1		// chassis mass
#define WMASS 0.2	// wheel mass

// dynamics and collision objects (chassis, 3 wheels, environment)

static dWorldID world;
static dSpaceID space;
static dBodyID body[4];
static dJointID joint[3];	// joint[0] is the front wheel
static dJointGroupID contactgroup;
static dGeomID ground;
static dGeomID box[1];
static dGeomID sphere[3];
static dGeomID ground_box;

// things that the user controls

static dReal speed=0,steer=0;	// user commands

// this is called by dSpaceCollide when two objects in space are
// potentially colliding.

static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
  // only collide things with the ground
  int g1 = (o1 == ground || o1 == ground_box);
  int g2 = (o2 == ground || o2 == ground_box);
  if (!(g1 ^ g2)) return;

  dContact contact;
  contact.surface.mode = 0;
  contact.surface.mu = dInfinity;
  if (dCollide (o1,o2,0,&contact.geom,sizeof(dContactGeom))) {
    //    if (o1==ground_box) printf ("foo 1\n");
    //    if (o2==ground_box) printf ("foo 2\n");

    dJointID c = dJointCreateContact (world,contactgroup,&contact);
    dJointAttach (c,dGeomGetBody(o1),dGeomGetBody(o2));
  }
}

// start simulation - set viewpoint

static void start()
{
  static float xyz[3] = {0.8317,-0.9817,0.8000};
  static float hpr[3] = {121.0000,-27.5000,0.0000};
  dsSetViewpoint (xyz,hpr);
}

// called when a key pressed

static void command (int cmd)
{
  switch (cmd) {
  case 'a': case 'A':
    speed += 0.3;
    break;
  case 'z': case 'Z':
    speed -= 0.3;
    break;
  case ',':
    steer += 0.5;
    break;
  case '.':
    steer -= 0.5;
    break;
  case ' ':
    speed = 0;
    steer = 0;
    break;
  }
}

// simulation loop

static void simLoop (int pause)
{
  int i;
  if (!pause) {
    // motor
    dJointSetHingeParam (joint[2],dParamVel,speed);
    dJointSetHingeParam (joint[2],dParamFMax,0.1);

    // steering
    printf ("%.4f\n",dJointGetHinge2Angle1 (joint[0]));
    dReal v = steer - dJointGetHinge2Angle1 (joint[0]);
    if (v > 0.1) v = 0.1;
    if (v < -0.1) v = -0.1;
    v *= 10.0;
    dJointSetHinge2Param1 (joint[0],dParamVel,v);
    dJointSetHinge2Param1 (joint[0],dParamFMax,0.2);
    dJointSetHinge2Param1 (joint[0],dParamLoStop,-0.75);
    dJointSetHinge2Param1 (joint[0],dParamHiStop,0.75);
    dJointSetHinge2Param1 (joint[0],dParamFudgeFactor,0.1);

    dSpaceCollide (space,0,&nearCallback);
    dWorldStep (world,0.05);

    // remove all contact joints
    dJointGroupEmpty (contactgroup);
  }

  dsSetColor (0,1,1);
  dsSetTexture (DS_WOOD);
  dReal sides[3] = {LENGTH,WIDTH,HEIGHT};
  dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides);
  dsSetColor (1,1,1);
  for (i=1; i<=3; i++) dsDrawCylinder (dBodyGetPosition(body[i]),
				       dBodyGetRotation(body[i]),0.02,RADIUS);

  /*
  dVector3 ss;
  dGeomBoxGetLengths (ground_box,ss);
  dsDrawBox (dGeomGetPosition(ground_box),dGeomGetRotation(ground_box),ss);
  */

  /*
  printf ("%.10f %.10f %.10f %.10f\n",
	  dJointGetHingeAngle (joint[1]),
	  dJointGetHingeAngle (joint[2]),
	  dJointGetHingeAngleRate (joint[1]),
	  dJointGetHingeAngleRate (joint[2]));
  */
}

int main (int argc, char **argv)
{
  int i;
  dMass m;

  // setup pointers to drawstuff callback functions
  dsFunctions fn;
  fn.version = DS_VERSION;
  fn.start = &start;
  fn.step = &simLoop;
  fn.command = &command;
  fn.stop = 0;
  fn.path_to_textures = "../../drawstuff/textures";

  // create world

  world = dWorldCreate();
  space = dSpaceCreate();
  contactgroup = dJointGroupCreate (1000000);
  dWorldSetGravity (world,0,0,-0.5);
  ground = dCreatePlane (space,0,0,1,0);

  // chassis body
  body[0] = dBodyCreate (world);
  dBodySetPosition (body[0],0,0,STARTZ);
  dMassSetBox (&m,1,LENGTH,WIDTH,HEIGHT);
  dMassAdjust (&m,CMASS);
  dBodySetMass (body[0],&m);
  box[0] = dCreateBox (space,LENGTH,WIDTH,HEIGHT);
  dGeomSetBody (box[0],body[0]);

  // wheel bodies
  for (i=1; i<=3; i++) {
    body[i] = dBodyCreate (world);
    dQuaternion q;
    dQFromAxisAndAngle (q,1,0,0,M_PI*0.5);
    dBodySetQuaternion (body[i],q);
    dMassSetSphere (&m,1,RADIUS);
    dMassAdjust (&m,WMASS);
    dBodySetMass (body[i],&m);
    sphere[i-1] = dCreateSphere (space,RADIUS);
    dGeomSetBody (sphere[i-1],body[i]);
  }
  dBodySetPosition (body[1],0.5*LENGTH,0,STARTZ-HEIGHT*0.5);
  dBodySetPosition (body[2],-0.5*LENGTH, WIDTH*0.5,STARTZ-HEIGHT*0.5);
  dBodySetPosition (body[3],-0.5*LENGTH,-WIDTH*0.5,STARTZ-HEIGHT*0.5);

  // front wheel hinge
  joint[0] = dJointCreateHinge2 (world,0);
  dJointAttach (joint[0],body[0],body[1]);
  const dReal *a = dBodyGetPosition (body[1]);
  dJointSetHinge2Anchor (joint[0],a[0],a[1],a[2]);
  dJointSetHinge2Axis1 (joint[0],0,0,1);
  dJointSetHinge2Axis2 (joint[0],0,1,0);

  // back wheel hinges
  for (i=1; i<3; i++) {
    joint[i] = dJointCreateHinge (world,0);
    dJointAttach (joint[i],body[0],body[i+1]);
    const dReal *a = dBodyGetPosition (body[i+1]);
    dJointSetHingeAnchor (joint[i],a[0],a[1],a[2]);
    dJointSetHingeAxis (joint[i],0,1,0);
  }

  // environment
  /*
  ground_box = dCreateBox (space,2,1.5,1);
  dMatrix3 R;
  dRFromAxisAndAngle (R,0,1,0,-0.15);
  dGeomSetPosition (ground_box,2,0,-0.34);
  dGeomSetRotation (ground_box,R);
  */

  // run simulation
  dsSimulationLoop (argc,argv,352,288,&fn);

  dJointGroupDestroy (contactgroup);
  dSpaceDestroy (space);
  dWorldDestroy (world);

  return 0;
}
<|endoftext|>


<commit_before># include "particle-functions.h"
# include <application.h>

void WeatherData :: message(int data)     // defined outside class definition
{
 Serial.print("Timestamp: "); Serial.println(weatherTime);
 Serial.print("Temp (F): "); Serial.println(greenhouseTemp);
 Serial.print("Humidity (%): "); Serial.println(greenhouseHumidity);
}

void WeatherData :: weatherData(unsigned int weatherTime, int greenhouseTemp,int greenhouseHumidity,
                                int backupGreenhouseTemp, int backupGreenhouseHumidity,int outsideTemp,
                                int outsideHumidity, int high, int low)
 {
 _weatherTime = weatherTime;
 _greenhouseTemp = greenhouseTemp;
 _greenhouseHumidity = greenhouseHumidity;
 _backupGreenhouseTemp = backupGreenhouseTemp;
 _backupGreenhouseHumidity = backupGreenhouseHumidity;
 _outsideTemp = outsideTemp;
 _outsideHumidity = outsideHumidity;
 _high = high;
 _low = low;
 }

void WeatherData :: init()
{
 Spark.function("ghData",greenhouseData);
}

<commit_msg>Update particle-functions.cpp<commit_after># include "particle-functions2.h"
# include <application.h>

void WeatherData :: message(int data)     // defined outside class definition
{
 Serial.print("Timestamp: "); Serial.println(weatherTime);
 Serial.print("Temp (F): "); Serial.println(greenhouseTemp);
 Serial.print("Humidity (%): "); Serial.println(greenhouseHumidity);
}

void WeatherData :: weatherData(unsigned int weatherTime, int greenhouseTemp,int greenhouseHumidity,
                                int backupGreenhouseTemp, int backupGreenhouseHumidity,int outsideTemp,
                                int outsideHumidity, int high, int low)
 {
 _weatherTime = weatherTime;
 _greenhouseTemp = greenhouseTemp;
 _greenhouseHumidity = greenhouseHumidity;
 _backupGreenhouseTemp = backupGreenhouseTemp;
 _backupGreenhouseHumidity = backupGreenhouseHumidity;
 _outsideTemp = outsideTemp;
 _outsideHumidity = outsideHumidity;
 _high = high;
 _low = low;
 }

void WeatherData :: init()
{
 Spark.function("ghData",greenhouseData);
}

<|endoftext|>


<commit_before>#include "thermistor-library.h"

Thermistor::Thermistor(int pin, int resistor) {
	_pin = pin;
	_resistor = resistor;
}

void Thermistor::begin(void) {
	pinMode(_pin, INPUT);
}

int Thermistor::getTempRaw(bool smooth=false) {
	delay(1);

	if(smooth==true) {
		int total = 0;

		for(int i=0; i<100; i++) {
			total += analogRead(_pin);
			delay(1);
		}

		_temp_raw = total/100;
	} else
		_temp_raw = analogRead(_pin);

	return _temp_raw;
}

float Thermistor::getTempK(bool smooth=false) {
	_temp_raw = getTempRaw(smooth);

	_temp_k = log(((40960000/_temp_raw) - _resistor));
	_temp_k = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * _temp_k * _temp_k ))* _temp_k);

	return _temp_k;
}

float Thermistor::getTempC(bool smooth) {
	_temp_k = getTempK(smooth);

	_temp_c = _temp_k - 273.15;

	return _temp_c;
}

float Thermistor::getTempF(bool smooth) {
	_temp_c = getTempC(smooth);

	_temp_f = (_temp_c * 9.0)/ 5.0 + 32.0;

	return _temp_f;
}

float Thermistor::getTemp(bool smooth) {
	return getTempC(smooth);
}
<commit_msg>missed out some default param<commit_after>#include "thermistor-library.h"

Thermistor::Thermistor(int pin, int resistor) {
	_pin = pin;
	_resistor = resistor;
}

void Thermistor::begin(void) {
	pinMode(_pin, INPUT);
}

int Thermistor::getTempRaw(bool smooth) {
	delay(1);

	if(smooth==true) {
		int total = 0;

		for(int i=0; i<100; i++) {
			total += analogRead(_pin);
			delay(1);
		}

		_temp_raw = total/100;
	} else
		_temp_raw = analogRead(_pin);

	return _temp_raw;
}

float Thermistor::getTempK(bool smooth) {
	_temp_raw = getTempRaw(smooth);

	_temp_k = log(((40960000/_temp_raw) - _resistor));
	_temp_k = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * _temp_k * _temp_k ))* _temp_k);

	return _temp_k;
}

float Thermistor::getTempC(bool smooth) {
	_temp_k = getTempK(smooth);

	_temp_c = _temp_k - 273.15;

	return _temp_c;
}

float Thermistor::getTempF(bool smooth) {
	_temp_c = getTempC(smooth);

	_temp_f = (_temp_c * 9.0)/ 5.0 + 32.0;

	return _temp_f;
}

float Thermistor::getTemp(bool smooth) {
	return getTempC(smooth);
}
<|endoftext|>


<commit_before>#include "framework/serialization/serialize.h"
#include "dependencies/pugixml/src/pugixml.hpp"
#include "framework/filesystem.h"
#include "framework/logger.h"
#include "framework/serialization/providers/filedataprovider.h"
#include "framework/serialization/providers/providerwithchecksum.h"
#include "framework/serialization/providers/zipdataprovider.h"
#include "framework/trace.h"
#include "library/sp.h"
#include "library/strings.h"
#include "library/strings_format.h"
#include <deque>
#include <map>
#include <sstream>

namespace OpenApoc
{

SerializationNode *SerializationNode::getNodeReq(const char *name)
{
	auto node = this->getNodeOpt(name);
	if (!node)
	{
		throw SerializationException(format("Missing node \"%s\"", name), this);
	}
	return node;
}

SerializationNode *SerializationNode::getSectionReq(const char *name)
{
	auto node = this->getSectionOpt(name);
	if (!node)
	{
		throw SerializationException(format("Missing section \"%s\"", name), this);
	}
	return node;
}

SerializationNode *SerializationNode::getNextSiblingReq(const char *name)
{
	auto node = this->getNextSiblingOpt(name);
	if (!node)
	{
		throw SerializationException(format("Missing sibling of \"%s\"", name), this);
	}
	return node;
}

using namespace pugi;
class XMLSerializationArchive;

class XMLSerializationNode final : public SerializationNode
{
  private:
	SerializationDataProvider *dataProvider;
	XMLSerializationArchive *archive;
	xml_node node;
	XMLSerializationNode *parent;
	UString prefix;

  public:
	XMLSerializationNode(XMLSerializationArchive *archive, xml_node node,
	                     XMLSerializationNode *parent)
	    : archive(archive), node(node), parent(parent)
	{
	}

	XMLSerializationNode(XMLSerializationArchive *archive, xml_node node, const UString &prefix)
	    : archive(archive), node(node), parent(nullptr), prefix(prefix)
	{
	}

	SerializationNode *addNode(const char *name, const UString &value = "") override;
	SerializationNode *addSection(const char *name) override;

	SerializationNode *getNodeOpt(const char *name) override;
	SerializationNode *getNextSiblingOpt(const char *name) override;
	SerializationNode *getSectionOpt(const char *name) override;

	UString getName() override;
	void setName(const UString &str) override;
	UString getValue() override;
	void setValue(const UString &str) override;

	unsigned int getValueUInt() override;
	void setValueUInt(unsigned int i) override;

	unsigned char getValueUChar() override;
	void setValueUChar(unsigned char i) override;

	int getValueInt() override;
	void setValueInt(int i) override;

	unsigned long long getValueUInt64() override;
	void setValueUInt64(unsigned long long i) override;

	long long getValueInt64() override;
	void setValueInt64(long long i) override;

	float getValueFloat() override;
	void setValueFloat(float f) override;

	bool getValueBool() override;
	void setValueBool(bool b) override;

	std::vector<bool> getValueBoolVector() override;
	void setValueBoolVector(const std::vector<bool> &vec) override;

	UString getFullPath() override;
	const UString &getPrefix() const override
	{
		if (this->parent)
			return this->parent->getPrefix();
		else
			return this->prefix;
	}

	~XMLSerializationNode() override = default;
};

class XMLSerializationArchive final : public SerializationArchive
{
  private:
	up<SerializationDataProvider> dataProvider;
	std::map<UString, xml_document> docRoots;
	std::deque<XMLSerializationNode> nodes;
	friend class SerializationArchive;
	friend class XMLSerializationNode;

  public:
	SerializationNode *newRoot(const UString &prefix, const char *name) override;
	SerializationNode *getRoot(const UString &prefix, const char *name) override;
	bool write(const UString &path, bool pack, bool pretty) override;
	XMLSerializationArchive() : dataProvider(nullptr), docRoots(){};
	XMLSerializationArchive(up<SerializationDataProvider> dataProvider)
	    : dataProvider(std::move(dataProvider)){};
	~XMLSerializationArchive() override = default;
};

up<SerializationArchive> SerializationArchive::createArchive()
{
	return mkup<XMLSerializationArchive>();
}

up<SerializationDataProvider> getProvider(bool pack)
{
	if (!pack)
	{
		// directory loader
		return mkup<ProviderWithChecksum>(mkup<FileDataProvider>());
	}
	else
	{
		// zip loader
		return mkup<ProviderWithChecksum>(mkup<ZipDataProvider>());
	}
}

up<SerializationArchive> SerializationArchive::readArchive(const UString &path)
{
	up<SerializationDataProvider> dataProvider = getProvider(!fs::is_directory(path.str()));
	if (!dataProvider->openArchive(path, false))
	{
		LogWarning("Failed to open archive at \"%s\"", path);
		return nullptr;
	}
	LogInfo("Opened archive \"%s\"", path);

	return mkup<XMLSerializationArchive>(std::move(dataProvider));
}

SerializationNode *XMLSerializationArchive::newRoot(const UString &prefix, const char *name)
{
	auto path = prefix + name + ".xml";
	auto root = this->docRoots[path].root().append_child();
	auto decl = this->docRoots[path].prepend_child(pugi::node_declaration);
	decl.append_attribute("version") = "1.0";
	decl.append_attribute("encoding") = "UTF-8";
	root.set_name(name);
	return &this->nodes.emplace_back(this, root, prefix + name + "/");
}

SerializationNode *XMLSerializationArchive::getRoot(const UString &prefix, const char *name)
{
	auto path = prefix + name + ".xml";
	if (dataProvider == nullptr)
	{
		LogWarning("Reading from not opened archive: %s!", path);
		return nullptr;
	}

	auto it = this->docRoots.find(path);
	if (it == this->docRoots.end())
	{
		TraceObj trace("Reading archive", {{"path", path}});
		UString content;
		if (dataProvider->readDocument(path, content))
		{
			// FIXME: Make this actually read from the root and load the xinclude tags properly?
			auto &doc = this->docRoots[path];
			TraceObj traceParse("Parsing archive", {{"path", path}});
			auto parse_result = doc.load_string(content.cStr());
			if (!parse_result)
			{
				LogInfo("Failed to parse \"%s\" : \"%s\" at \"%llu\"", path,
				        parse_result.description(), (unsigned long long)parse_result.offset);
				return nullptr;
			}
			it = this->docRoots.find(path);
			LogInfo("Parsed \"%s\"", path);
		}
	}
	if (it == this->docRoots.end())
	{
		return nullptr;
	}

	auto root = it->second.child(name);
	if (!root)
	{
		LogWarning("Failed to find root with name \"%s\" in \"%s\"", name, path);
		return nullptr;
	}
	return &this->nodes.emplace_back(this, root, prefix + name + "/");
}

bool XMLSerializationArchive::write(const UString &path, bool pack, bool pretty)
{
	TraceObj trace("Writing archive", {{"path", path}});
	// warning! data provider must be freed when this method ends,
	// so code calling this method may override archive
	auto dataProvider = getProvider(pack);
	if (!dataProvider->openArchive(path, true))
	{
		LogWarning("Failed to open archive at \"%s\"", path);
		return false;
	}

	for (auto &root : this->docRoots)
	{
		TraceObj traceSave("Saving root", {{"root", root.first}});
		std::stringstream ss;
		unsigned int flags = pugi::format_default;
		if (pretty == false)
		{
			flags = pugi::format_raw;
		}
		root.second.save(ss, "", flags);
		TraceObj traceSaveData("Saving root data", {{"root", root.first}});
		if (!dataProvider->saveDocument(root.first, ss.str()))
		{
			return false;
		}
	}

	return dataProvider->finalizeSave();
}

SerializationNode *XMLSerializationNode::addNode(const char *name, const UString &value)
{
	auto newNode = this->node.append_child();
	newNode.set_name(name);
	newNode.text().set(value.cStr());
	return &this->archive->nodes.emplace_back(this->archive, newNode, this);
}

SerializationNode *XMLSerializationNode::getNodeOpt(const char *name)
{
	auto newNode = this->node.child(name);
	if (!newNode)
	{
		return nullptr;
	}
	return &this->archive->nodes.emplace_back(this->archive, newNode, this);
}

SerializationNode *XMLSerializationNode::getNextSiblingOpt(const char *name)
{
	auto newNode = this->node.next_sibling(name);
	if (!newNode)
	{
		return nullptr;
	}
	return &this->archive->nodes.emplace_back(this->archive, newNode, this);
}

SerializationNode *XMLSerializationNode::addSection(const char *name)
{
	auto includeNode = static_cast<XMLSerializationNode *>(this->addNode("xi:include"));
	auto path = UString(name) + ".xml";
	auto nsAttribute = includeNode->node.append_attribute("xmlns:xi");
	nsAttribute.set_value("http://www.w3.org/2001/XInclude");
	auto attribute = includeNode->node.append_attribute("href");
	attribute.set_value(path.cStr());
	return this->archive->newRoot(this->getPrefix(), name);
}

SerializationNode *XMLSerializationNode::getSectionOpt(const char *name)
{
	return archive->getRoot(this->getPrefix(), name);
}

UString XMLSerializationNode::getName() { return node.name(); }

void XMLSerializationNode::setName(const UString &str) { node.set_name(str.cStr()); }

UString XMLSerializationNode::getValue() { return node.text().get(); }

void XMLSerializationNode::setValue(const UString &str) { node.text().set(str.cStr()); }

unsigned int XMLSerializationNode::getValueUInt() { return node.text().as_uint(); }

void XMLSerializationNode::setValueUInt(unsigned int i) { node.text().set(i); }

unsigned char XMLSerializationNode::getValueUChar()
{
	auto uint = node.text().as_uint();
	if (uint > std::numeric_limits<unsigned char>::max())
	{
		throw SerializationException(format("Value %u is out of range of unsigned char type", uint),
		                             this);
	}
	return static_cast<unsigned char>(uint);
}

void XMLSerializationNode::setValueUChar(unsigned char c) { node.text().set((unsigned int)c); }

int XMLSerializationNode::getValueInt() { return node.text().as_int(); }

void XMLSerializationNode::setValueInt(int i) { node.text().set(i); }

unsigned long long XMLSerializationNode::getValueUInt64() { return node.text().as_ullong(); }

void XMLSerializationNode::setValueUInt64(unsigned long long i) { node.text().set(i); }

long long XMLSerializationNode::getValueInt64() { return node.text().as_llong(); }

void XMLSerializationNode::setValueInt64(long long i) { node.text().set(i); }

float XMLSerializationNode::getValueFloat() { return node.text().as_float(); }

void XMLSerializationNode::setValueFloat(float f) { node.text().set(f); }

bool XMLSerializationNode::getValueBool() { return node.text().as_bool(); }

void XMLSerializationNode::setValueBool(bool b) { node.text().set(b); }

std::vector<bool> XMLSerializationNode::getValueBoolVector()
{
	std::vector<bool> vec;
	auto string = this->getValue().str();

	vec.resize(string.length());
	for (size_t i = 0; i < string.length(); i++)
	{
		auto c = string[i];
		if (c == '1')
			vec[i] = true;
		else if (c == '0')
			vec[i] = false;
		else
			throw SerializationException(format("Unknown char '%c' in bool vector", c), this);
	}
	return vec;
}

void XMLSerializationNode::setValueBoolVector(const std::vector<bool> &vec)
{
	std::string str(vec.size(), ' ');

	for (size_t i = 0; i < vec.size(); i++)
	{
		auto b = vec[i];
		if (b)
			str[i] = '1';
		else
			str[i] = '0';
	}
	this->setValue(str);
}

UString XMLSerializationNode::getFullPath()
{
	UString str;
	if (this->parent)
	{
		str = this->parent->getFullPath();
	}
	else
	{
		str += node.name();
		str += ".xml:";
	}
	str += "/";
	str += node.name();
	return str;
}

} // namespace OpenApoc
<commit_msg>Remove unused 'dataProvider' member from XMLSerializationNode<commit_after>#include "framework/serialization/serialize.h"
#include "dependencies/pugixml/src/pugixml.hpp"
#include "framework/filesystem.h"
#include "framework/logger.h"
#include "framework/serialization/providers/filedataprovider.h"
#include "framework/serialization/providers/providerwithchecksum.h"
#include "framework/serialization/providers/zipdataprovider.h"
#include "framework/trace.h"
#include "library/sp.h"
#include "library/strings.h"
#include "library/strings_format.h"
#include <deque>
#include <map>
#include <sstream>

namespace OpenApoc
{

SerializationNode *SerializationNode::getNodeReq(const char *name)
{
	auto node = this->getNodeOpt(name);
	if (!node)
	{
		throw SerializationException(format("Missing node \"%s\"", name), this);
	}
	return node;
}

SerializationNode *SerializationNode::getSectionReq(const char *name)
{
	auto node = this->getSectionOpt(name);
	if (!node)
	{
		throw SerializationException(format("Missing section \"%s\"", name), this);
	}
	return node;
}

SerializationNode *SerializationNode::getNextSiblingReq(const char *name)
{
	auto node = this->getNextSiblingOpt(name);
	if (!node)
	{
		throw SerializationException(format("Missing sibling of \"%s\"", name), this);
	}
	return node;
}

using namespace pugi;
class XMLSerializationArchive;

class XMLSerializationNode final : public SerializationNode
{
  private:
	XMLSerializationArchive *archive;
	xml_node node;
	XMLSerializationNode *parent;
	UString prefix;

  public:
	XMLSerializationNode(XMLSerializationArchive *archive, xml_node node,
	                     XMLSerializationNode *parent)
	    : archive(archive), node(node), parent(parent)
	{
	}

	XMLSerializationNode(XMLSerializationArchive *archive, xml_node node, const UString &prefix)
	    : archive(archive), node(node), parent(nullptr), prefix(prefix)
	{
	}

	SerializationNode *addNode(const char *name, const UString &value = "") override;
	SerializationNode *addSection(const char *name) override;

	SerializationNode *getNodeOpt(const char *name) override;
	SerializationNode *getNextSiblingOpt(const char *name) override;
	SerializationNode *getSectionOpt(const char *name) override;

	UString getName() override;
	void setName(const UString &str) override;
	UString getValue() override;
	void setValue(const UString &str) override;

	unsigned int getValueUInt() override;
	void setValueUInt(unsigned int i) override;

	unsigned char getValueUChar() override;
	void setValueUChar(unsigned char i) override;

	int getValueInt() override;
	void setValueInt(int i) override;

	unsigned long long getValueUInt64() override;
	void setValueUInt64(unsigned long long i) override;

	long long getValueInt64() override;
	void setValueInt64(long long i) override;

	float getValueFloat() override;
	void setValueFloat(float f) override;

	bool getValueBool() override;
	void setValueBool(bool b) override;

	std::vector<bool> getValueBoolVector() override;
	void setValueBoolVector(const std::vector<bool> &vec) override;

	UString getFullPath() override;
	const UString &getPrefix() const override
	{
		if (this->parent)
			return this->parent->getPrefix();
		else
			return this->prefix;
	}

	~XMLSerializationNode() override = default;
};

class XMLSerializationArchive final : public SerializationArchive
{
  private:
	up<SerializationDataProvider> dataProvider;
	std::map<UString, xml_document> docRoots;
	std::deque<XMLSerializationNode> nodes;
	friend class SerializationArchive;
	friend class XMLSerializationNode;

  public:
	SerializationNode *newRoot(const UString &prefix, const char *name) override;
	SerializationNode *getRoot(const UString &prefix, const char *name) override;
	bool write(const UString &path, bool pack, bool pretty) override;
	XMLSerializationArchive() : dataProvider(nullptr), docRoots(){};
	XMLSerializationArchive(up<SerializationDataProvider> dataProvider)
	    : dataProvider(std::move(dataProvider)){};
	~XMLSerializationArchive() override = default;
};

up<SerializationArchive> SerializationArchive::createArchive()
{
	return mkup<XMLSerializationArchive>();
}

up<SerializationDataProvider> getProvider(bool pack)
{
	if (!pack)
	{
		// directory loader
		return mkup<ProviderWithChecksum>(mkup<FileDataProvider>());
	}
	else
	{
		// zip loader
		return mkup<ProviderWithChecksum>(mkup<ZipDataProvider>());
	}
}

up<SerializationArchive> SerializationArchive::readArchive(const UString &path)
{
	up<SerializationDataProvider> dataProvider = getProvider(!fs::is_directory(path.str()));
	if (!dataProvider->openArchive(path, false))
	{
		LogWarning("Failed to open archive at \"%s\"", path);
		return nullptr;
	}
	LogInfo("Opened archive \"%s\"", path);

	return mkup<XMLSerializationArchive>(std::move(dataProvider));
}

SerializationNode *XMLSerializationArchive::newRoot(const UString &prefix, const char *name)
{
	auto path = prefix + name + ".xml";
	auto root = this->docRoots[path].root().append_child();
	auto decl = this->docRoots[path].prepend_child(pugi::node_declaration);
	decl.append_attribute("version") = "1.0";
	decl.append_attribute("encoding") = "UTF-8";
	root.set_name(name);
	return &this->nodes.emplace_back(this, root, prefix + name + "/");
}

SerializationNode *XMLSerializationArchive::getRoot(const UString &prefix, const char *name)
{
	auto path = prefix + name + ".xml";
	if (dataProvider == nullptr)
	{
		LogWarning("Reading from not opened archive: %s!", path);
		return nullptr;
	}

	auto it = this->docRoots.find(path);
	if (it == this->docRoots.end())
	{
		TraceObj trace("Reading archive", {{"path", path}});
		UString content;
		if (dataProvider->readDocument(path, content))
		{
			// FIXME: Make this actually read from the root and load the xinclude tags properly?
			auto &doc = this->docRoots[path];
			TraceObj traceParse("Parsing archive", {{"path", path}});
			auto parse_result = doc.load_string(content.cStr());
			if (!parse_result)
			{
				LogInfo("Failed to parse \"%s\" : \"%s\" at \"%llu\"", path,
				        parse_result.description(), (unsigned long long)parse_result.offset);
				return nullptr;
			}
			it = this->docRoots.find(path);
			LogInfo("Parsed \"%s\"", path);
		}
	}
	if (it == this->docRoots.end())
	{
		return nullptr;
	}

	auto root = it->second.child(name);
	if (!root)
	{
		LogWarning("Failed to find root with name \"%s\" in \"%s\"", name, path);
		return nullptr;
	}
	return &this->nodes.emplace_back(this, root, prefix + name + "/");
}

bool XMLSerializationArchive::write(const UString &path, bool pack, bool pretty)
{
	TraceObj trace("Writing archive", {{"path", path}});
	// warning! data provider must be freed when this method ends,
	// so code calling this method may override archive
	auto dataProvider = getProvider(pack);
	if (!dataProvider->openArchive(path, true))
	{
		LogWarning("Failed to open archive at \"%s\"", path);
		return false;
	}

	for (auto &root : this->docRoots)
	{
		TraceObj traceSave("Saving root", {{"root", root.first}});
		std::stringstream ss;
		unsigned int flags = pugi::format_default;
		if (pretty == false)
		{
			flags = pugi::format_raw;
		}
		root.second.save(ss, "", flags);
		TraceObj traceSaveData("Saving root data", {{"root", root.first}});
		if (!dataProvider->saveDocument(root.first, ss.str()))
		{
			return false;
		}
	}

	return dataProvider->finalizeSave();
}

SerializationNode *XMLSerializationNode::addNode(const char *name, const UString &value)
{
	auto newNode = this->node.append_child();
	newNode.set_name(name);
	newNode.text().set(value.cStr());
	return &this->archive->nodes.emplace_back(this->archive, newNode, this);
}

SerializationNode *XMLSerializationNode::getNodeOpt(const char *name)
{
	auto newNode = this->node.child(name);
	if (!newNode)
	{
		return nullptr;
	}
	return &this->archive->nodes.emplace_back(this->archive, newNode, this);
}

SerializationNode *XMLSerializationNode::getNextSiblingOpt(const char *name)
{
	auto newNode = this->node.next_sibling(name);
	if (!newNode)
	{
		return nullptr;
	}
	return &this->archive->nodes.emplace_back(this->archive, newNode, this);
}

SerializationNode *XMLSerializationNode::addSection(const char *name)
{
	auto includeNode = static_cast<XMLSerializationNode *>(this->addNode("xi:include"));
	auto path = UString(name) + ".xml";
	auto nsAttribute = includeNode->node.append_attribute("xmlns:xi");
	nsAttribute.set_value("http://www.w3.org/2001/XInclude");
	auto attribute = includeNode->node.append_attribute("href");
	attribute.set_value(path.cStr());
	return this->archive->newRoot(this->getPrefix(), name);
}

SerializationNode *XMLSerializationNode::getSectionOpt(const char *name)
{
	return archive->getRoot(this->getPrefix(), name);
}

UString XMLSerializationNode::getName() { return node.name(); }

void XMLSerializationNode::setName(const UString &str) { node.set_name(str.cStr()); }

UString XMLSerializationNode::getValue() { return node.text().get(); }

void XMLSerializationNode::setValue(const UString &str) { node.text().set(str.cStr()); }

unsigned int XMLSerializationNode::getValueUInt() { return node.text().as_uint(); }

void XMLSerializationNode::setValueUInt(unsigned int i) { node.text().set(i); }

unsigned char XMLSerializationNode::getValueUChar()
{
	auto uint = node.text().as_uint();
	if (uint > std::numeric_limits<unsigned char>::max())
	{
		throw SerializationException(format("Value %u is out of range of unsigned char type", uint),
		                             this);
	}
	return static_cast<unsigned char>(uint);
}

void XMLSerializationNode::setValueUChar(unsigned char c) { node.text().set((unsigned int)c); }

int XMLSerializationNode::getValueInt() { return node.text().as_int(); }

void XMLSerializationNode::setValueInt(int i) { node.text().set(i); }

unsigned long long XMLSerializationNode::getValueUInt64() { return node.text().as_ullong(); }

void XMLSerializationNode::setValueUInt64(unsigned long long i) { node.text().set(i); }

long long XMLSerializationNode::getValueInt64() { return node.text().as_llong(); }

void XMLSerializationNode::setValueInt64(long long i) { node.text().set(i); }

float XMLSerializationNode::getValueFloat() { return node.text().as_float(); }

void XMLSerializationNode::setValueFloat(float f) { node.text().set(f); }

bool XMLSerializationNode::getValueBool() { return node.text().as_bool(); }

void XMLSerializationNode::setValueBool(bool b) { node.text().set(b); }

std::vector<bool> XMLSerializationNode::getValueBoolVector()
{
	std::vector<bool> vec;
	auto string = this->getValue().str();

	vec.resize(string.length());
	for (size_t i = 0; i < string.length(); i++)
	{
		auto c = string[i];
		if (c == '1')
			vec[i] = true;
		else if (c == '0')
			vec[i] = false;
		else
			throw SerializationException(format("Unknown char '%c' in bool vector", c), this);
	}
	return vec;
}

void XMLSerializationNode::setValueBoolVector(const std::vector<bool> &vec)
{
	std::string str(vec.size(), ' ');

	for (size_t i = 0; i < vec.size(); i++)
	{
		auto b = vec[i];
		if (b)
			str[i] = '1';
		else
			str[i] = '0';
	}
	this->setValue(str);
}

UString XMLSerializationNode::getFullPath()
{
	UString str;
	if (this->parent)
	{
		str = this->parent->getFullPath();
	}
	else
	{
		str += node.name();
		str += ".xml:";
	}
	str += "/";
	str += node.name();
	return str;
}

} // namespace OpenApoc
<|endoftext|>


<commit_before>/*
 *  Phusion Passenger - http://www.modrails.com/
 *  Copyright (C) 2008  Phusion
 *
 *  Phusion Passenger is a trademark of Hongli Lai & Ninh Bui.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include "Bucket.h"

using namespace Passenger;

static void bucket_destroy(void *data);
static apr_status_t bucket_read(apr_bucket *a, const char **str, apr_size_t *len, apr_read_type_e block);

static const apr_bucket_type_t apr_bucket_type_passenger_pipe = {
	"PASSENGER_PIPE",
	5,
	apr_bucket_type_t::APR_BUCKET_DATA,
	bucket_destroy,
	bucket_read,
	apr_bucket_setaside_notimpl,
	apr_bucket_split_notimpl,
	apr_bucket_copy_notimpl
};

struct BucketData {
	Application::SessionPtr session;
	apr_file_t *pipe;
};

static void
bucket_destroy(void *data) {
	BucketData *bucket_data = (BucketData *) data;
	if (data != NULL) {
		delete bucket_data;
	}
}

static apr_status_t
bucket_read(apr_bucket *bucket, const char **str, apr_size_t *len, apr_read_type_e block) {
	apr_file_t *pipe;
	char *buf;
	apr_status_t ret;

	BucketData *data = (BucketData *) bucket->data;
	pipe = data->pipe;

	*str = NULL;
	*len = APR_BUCKET_BUFF_SIZE;
	buf = (char *) apr_bucket_alloc(*len, bucket->list); // TODO: check for failure?

	do {
		ret = apr_file_read(pipe, buf, len);
	} while (APR_STATUS_IS_EAGAIN(ret));

	if (ret != APR_SUCCESS && ret != APR_EOF) {
		// ... we might want to set an error flag here ...
		delete data;
		bucket->data = NULL;
		apr_bucket_free(buf);
		return ret;
	}
	/*
	 * If there's more to read we have to keep the rest of the pipe
	 * for later.
	 */
	if (*len > 0) {
		apr_bucket_heap *h;

		*str = buf;
		bucket->data = NULL;

		/* Change the current bucket to refer to what we read */
		bucket = apr_bucket_heap_make(bucket, buf, *len, apr_bucket_free);
		h = (apr_bucket_heap *) bucket->data;
		h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */
		APR_BUCKET_INSERT_AFTER(bucket, passenger_bucket_create(
			data->session, pipe, bucket->list));

		delete data;
	} else {
		delete data;
		bucket->data = NULL;

		apr_bucket_free(buf);
		bucket = apr_bucket_immortal_make(bucket, "", 0);
		*str = (const char *) bucket->data;
		// if (rv != APR_EOF) {
		//     ... we might want to set an error flag here ...
		// }
	}
	return APR_SUCCESS;
}

static apr_bucket *
passenger_bucket_make(apr_bucket *bucket, Application::SessionPtr session, apr_file_t *pipe) {
	BucketData *data = new BucketData();
	data->session  = session;
	data->pipe     = pipe;

	bucket->type   = &apr_bucket_type_passenger_pipe;
	bucket->length = (apr_size_t)(-1);
	bucket->start  = -1;
	bucket->data   = data;
	return bucket;
}

apr_bucket *
passenger_bucket_create(Application::SessionPtr session, apr_file_t *pipe, apr_bucket_alloc_t *list) {
	apr_bucket *bucket;

	bucket = (apr_bucket *) apr_bucket_alloc(sizeof(*bucket), list);
	APR_BUCKET_INIT(bucket);
	bucket->free = apr_bucket_free;
	bucket->list = list;
	return passenger_bucket_make(bucket, session, pipe);
}

<commit_msg>Prevent Apache from buffering all data sent by the backend process before sending the data to the HTTP client. This allows backend processes to stream data.<commit_after>/*
 *  Phusion Passenger - http://www.modrails.com/
 *  Copyright (C) 2008  Phusion
 *
 *  Phusion Passenger is a trademark of Hongli Lai & Ninh Bui.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include "Bucket.h"

using namespace Passenger;

static void bucket_destroy(void *data);
static apr_status_t bucket_read(apr_bucket *a, const char **str, apr_size_t *len, apr_read_type_e block);

static const apr_bucket_type_t apr_bucket_type_passenger_pipe = {
	"PASSENGER_PIPE",
	5,
	apr_bucket_type_t::APR_BUCKET_DATA,
	bucket_destroy,
	bucket_read,
	apr_bucket_setaside_notimpl,
	apr_bucket_split_notimpl,
	apr_bucket_copy_notimpl
};

struct BucketData {
	Application::SessionPtr session;
	apr_file_t *pipe;
};

static void
bucket_destroy(void *data) {
	BucketData *bucket_data = (BucketData *) data;
	if (data != NULL) {
		delete bucket_data;
	}
}

static apr_status_t
bucket_read(apr_bucket *bucket, const char **str, apr_size_t *len, apr_read_type_e block) {
	apr_file_t *pipe;
	char *buf;
	apr_status_t ret;

	BucketData *data = (BucketData *) bucket->data;
	pipe = data->pipe;

	*str = NULL;
	*len = APR_BUCKET_BUFF_SIZE;

	if (block == APR_NONBLOCK_READ) {
		/*
		 * The bucket brigade that Hooks::handleRequest() passes using
		 * ap_pass_brigade() is always passed through ap_content_length_filter,
		 * which is a filter which attempts to read all data from the
		 * bucket brigade and computes the Content-Length header from
		 * that. We don't want this to happen; because suppose that the
		 * Rails application sends back 1 GB of data, then
		 * ap_content_length_filter will buffer this entire 1 GB of data
		 * in memory before passing it to the HTTP client.
		 *
		 * ap_content_length_filter aborts and passes the bucket brigade
		 * down the filter chain when it encounters an APR_EAGAIN, except
		 * for the first read. So by returning APR_EAGAIN on every
		 * non-blocking read request, we can prevent ap_content_length_filter
		 * from buffering all data.
		 */
		return APR_EAGAIN;
	}

	buf = (char *) apr_bucket_alloc(*len, bucket->list); // TODO: check for failure?

	do {
		ret = apr_file_read(pipe, buf, len);
	} while (APR_STATUS_IS_EAGAIN(ret));

	if (ret != APR_SUCCESS && ret != APR_EOF) {
		// ... we might want to set an error flag here ...
		delete data;
		bucket->data = NULL;
		apr_bucket_free(buf);
		return ret;
	}
	/*
	 * If there's more to read we have to keep the rest of the pipe
	 * for later.
	 */
	if (*len > 0) {
		apr_bucket_heap *h;

		*str = buf;
		bucket->data = NULL;

		/* Change the current bucket to refer to what we read */
		bucket = apr_bucket_heap_make(bucket, buf, *len, apr_bucket_free);
		h = (apr_bucket_heap *) bucket->data;
		h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */
		APR_BUCKET_INSERT_AFTER(bucket, passenger_bucket_create(
			data->session, pipe, bucket->list));
		delete data;
	} else {
		delete data;
		bucket->data = NULL;

		apr_bucket_free(buf);
		bucket = apr_bucket_immortal_make(bucket, "", 0);
		*str = (const char *) bucket->data;
		// if (rv != APR_EOF) {
		//     ... we might want to set an error flag here ...
		// }
	}
	return APR_SUCCESS;
}

static apr_bucket *
passenger_bucket_make(apr_bucket *bucket, Application::SessionPtr session, apr_file_t *pipe) {
	BucketData *data = new BucketData();
	data->session  = session;
	data->pipe     = pipe;

	bucket->type   = &apr_bucket_type_passenger_pipe;
	bucket->length = (apr_size_t)(-1);
	bucket->start  = -1;
	bucket->data   = data;
	return bucket;
}

apr_bucket *
passenger_bucket_create(Application::SessionPtr session, apr_file_t *pipe, apr_bucket_alloc_t *list) {
	apr_bucket *bucket;

	bucket = (apr_bucket *) apr_bucket_alloc(sizeof(*bucket), list);
	APR_BUCKET_INIT(bucket);
	bucket->free = apr_bucket_free;
	bucket->list = list;
	return passenger_bucket_make(bucket, session, pipe);
}

<|endoftext|>