<commit_before>#include <ros/console.h>
#include <string>

#include <tr_hub_parser/RangeArray.h>
#include <tr_hub_parser/tr_evo_hub_parser.h>

namespace tr_hub_parser {

Tr_hub_parser::Tr_hub_parser() {
  // Get parameters
  ros::NodeHandle private_node_handle_("~");
  private_node_handle_.param("portname", portname_,
                             std::string("/dev/ttyACM0"));
  //Initialize local parameters and measurement array
  field_of_view = 0.0593;
  max_range = 14.0;
  min_range = 0.2;
  number_of_sensor = 8;
  frame_id = "base_range_";

  for (size_t i=0; i < number_of_sensor; i++) {
   sensor_msgs::Range range;
   range.field_of_view = field_of_view;
   range.max_range = max_range;
   range.min_range = min_range;
   range.radiation_type = sensor_msgs::Range::INFRARED;
   range.range = 0.0;
   range.header.frame_id =
       ros::names::append(ns_, frame_id + boost::lexical_cast<std::string>(i));

   measure.ranges.push_back(range);
  }

  // Publishers
  range_publisher_ = nh_.advertise<tr_hub_parser::RangeArray>("tr_hub_parser", 8);

  // Create serial port
  serial_port_ = new SerialPort();

  // Set callback function for the serial ports
  serial_data_callback_function_ =
      boost::bind(&Tr_hub_parser::serialDataCallback, this, _1);
  serial_port_->setSerialCallbackFunction(&serial_data_callback_function_);

  // Connect serial port
  if (!serial_port_->connect(portname_)) {
    ROS_ERROR("Could not open : %s ", portname_.c_str());
    ros::shutdown();
    return;
  }
  else {
    // This line is needed to start measurements on the hub
    const char enable[5] = {(char)0x00, (char)0x52, (char)0x02, (char)0x01, (char)0xDF}; //00520201DF
    const char tower_mode[4] = {(char)0x00, (char)0x31, (char)0x03, (char)0xE5};
    serial_port_->sendChar(enable, 5);
    serial_port_->sendChar(tower_mode, 4);
  }

  // Output loaded parameters to console for double checking
  ROS_INFO("[%s] is up and running with the following parameters:",
           ros::this_node::getName().c_str());
  ROS_INFO("[%s] portname: %s", ros::this_node::getName().c_str(),
           portname_.c_str());

  ns_ = ros::this_node::getNamespace();
  ns_ = ros::names::clean(ns_);
  std::string str = ns_.c_str();
  ROS_INFO("node namespace: [%s]", ns_.c_str());

  // Set operation Mode
  setMode(BINARY_MODE);

  // Force using 8 sensors
  // setMode(FORCE_8_SENSORS);

  // Dynamic reconfigure
  dyn_param_server_callback_function_ =
      boost::bind(&Tr_hub_parser::dynParamCallback, this, _1, _2);
  dyn_param_server_.setCallback(dyn_param_server_callback_function_);
}

Tr_hub_parser::~Tr_hub_parser() {}

uint8_t crc8(uint8_t *p, uint8_t len) {
  uint16_t i;
  uint16_t crc = 0x0;

  while (len--) {
    i = (crc ^ *p++) & 0xFF;
    crc = (crc_table[i] ^ (crc << 8)) & 0xFF;
  }
  return crc & 0xFF;
}

float two_chars_to_float(uint8_t c1, uint8_t c2){
  int16_t current_range = c1 << 8;
  current_range |= c2;

  float res = (float)current_range;
  return res;
}

void Tr_hub_parser::serialDataCallback(uint8_t single_character) {
  static uint8_t input_buffer[BUFFER_SIZE];
  static int buffer_ctr = 0;
  static int seq_ctr = 0;

  int frame_length = 31;
  int crc_length = 19;

  if (single_character != 'T' && buffer_ctr < frame_length) {
    // not the beginning of serial feed so add char to buffer
    input_buffer[buffer_ctr++] = single_character;
    return;
  }
  else if (single_character == 'T') {
    //ROS_INFO("%s\n", reinterpret_cast<const char*>(single_character));

    if (buffer_ctr == (frame_length-1)) {
      // end of feed, calculate
      int16_t crc = crc8(input_buffer, crc_length);

      if (crc == input_buffer[crc_length]) {
        ROS_DEBUG("Frame: %s ", input_buffer);
        // ROS_INFO("Bitmask: %d", (int)input_buffer[18]);

        for (size_t i=0; i < measure.ranges.size(); i++) {
          measure.ranges.at(i).header.stamp = ros::Time::now();
          measure.ranges.at(i).header.seq = seq_ctr++;

          // Doesn't go out of range because of fixed buffer size as long as the number of sensor is not above 8
          float float_range = two_chars_to_float(input_buffer[2 * (i + 1)],input_buffer[2 * (i + 1) + 1]);

          if ((float_range * 0.001 < min_range) && (float_range > 0)) { //check for hardware cut-off
            float_range = min_range;
          } else if ((float_range * 0.001 > max_range) || (float_range < 0)) { //software cut-off should be adapted to sensor
            float_range = -1.0;
          } else {
            float_range = float_range * 0.001;
          }
          measure.ranges.at(i).range = float_range;
        }
        range_publisher_.publish(measure);

      } else {
        ROS_DEBUG("[%s] crc missmatch", ros::this_node::getName().c_str());
      }
    } else {
      ROS_DEBUG("[%s] received T but did not expect it, reset buffer without "
                "evaluating data",
                ros::this_node::getName().c_str());
    }
  } else {
    ROS_DEBUG("[%s] buffer_overflowed without receiving T, reset input_buffer",
              ros::this_node::getName().c_str());
  }

  // reset
  buffer_ctr = 0;

  // clear struct
  bzero(&input_buffer, BUFFER_SIZE);

  // store T
  input_buffer[buffer_ctr++] = 'T';
}

void Tr_hub_parser::setMode(const char *c) { serial_port_->sendChar(c); }

void Tr_hub_parser::dynParamCallback(
    const tr_hub_parser::Tr_hub_parserConfig &config, uint32_t level) {
  if (config.Mode == tr_hub_parser::Tr_hub_parser_Fast) {
    setMode(FAST_MODE);
  }

  if (config.Mode == tr_hub_parser::Tr_hub_parser_Precise) {
    setMode(PRECISE_MODE);
  }

  if (config.Mode == tr_hub_parser::Tr_hub_parser_Outdoor) {
    setMode(OUTDOOR_MODE);
  }
}
}

int main(int argc, char **argv) {
  ros::init(argc, argv, "tr_hub_parser_node");
  tr_hub_parser::Tr_hub_parser tr_hub_parser_node;
  ros::spin();

  return 0;
}
<commit_msg>Disable old hub command<commit_after>#include <ros/console.h>
#include <string>

#include <tr_hub_parser/RangeArray.h>
#include <tr_hub_parser/tr_evo_hub_parser.h>

namespace tr_hub_parser {

Tr_hub_parser::Tr_hub_parser() {
  // Get parameters
  ros::NodeHandle private_node_handle_("~");
  private_node_handle_.param("portname", portname_,
                             std::string("/dev/ttyACM0"));
  //Initialize local parameters and measurement array
  field_of_view = 0.0593;
  max_range = 14.0;
  min_range = 0.2;
  number_of_sensor = 8;
  frame_id = "base_range_";

  for (size_t i=0; i < number_of_sensor; i++) {
   sensor_msgs::Range range;
   range.field_of_view = field_of_view;
   range.max_range = max_range;
   range.min_range = min_range;
   range.radiation_type = sensor_msgs::Range::INFRARED;
   range.range = 0.0;
   range.header.frame_id =
       ros::names::append(ns_, frame_id + boost::lexical_cast<std::string>(i));

   measure.ranges.push_back(range);
  }

  // Publishers
  range_publisher_ = nh_.advertise<tr_hub_parser::RangeArray>("tr_hub_parser", 8);

  // Create serial port
  serial_port_ = new SerialPort();

  // Set callback function for the serial ports
  serial_data_callback_function_ =
      boost::bind(&Tr_hub_parser::serialDataCallback, this, _1);
  serial_port_->setSerialCallbackFunction(&serial_data_callback_function_);

  // Connect serial port
  if (!serial_port_->connect(portname_)) {
    ROS_ERROR("Could not open : %s ", portname_.c_str());
    ros::shutdown();
    return;
  }
  else {
    // This line is needed to start measurements on the hub
    const char enable[5] = {(char)0x00, (char)0x52, (char)0x02, (char)0x01, (char)0xDF}; //00520201DF
    const char tower_mode[4] = {(char)0x00, (char)0x31, (char)0x03, (char)0xE5};
    serial_port_->sendChar(enable, 5);
    serial_port_->sendChar(tower_mode, 4);
  }

  // Output loaded parameters to console for double checking
  ROS_INFO("[%s] is up and running with the following parameters:",
           ros::this_node::getName().c_str());
  ROS_INFO("[%s] portname: %s", ros::this_node::getName().c_str(),
           portname_.c_str());

  ns_ = ros::this_node::getNamespace();
  ns_ = ros::names::clean(ns_);
  std::string str = ns_.c_str();
  ROS_INFO("node namespace: [%s]", ns_.c_str());

  // Set operation Mode
  setMode(BINARY_MODE);

  // Force using 8 sensors
  // setMode(FORCE_8_SENSORS);

  // Dynamic reconfigure
  dyn_param_server_callback_function_ =
      boost::bind(&Tr_hub_parser::dynParamCallback, this, _1, _2);
  dyn_param_server_.setCallback(dyn_param_server_callback_function_);
}

Tr_hub_parser::~Tr_hub_parser() {}

uint8_t crc8(uint8_t *p, uint8_t len) {
  uint16_t i;
  uint16_t crc = 0x0;

  while (len--) {
    i = (crc ^ *p++) & 0xFF;
    crc = (crc_table[i] ^ (crc << 8)) & 0xFF;
  }
  return crc & 0xFF;
}

float two_chars_to_float(uint8_t c1, uint8_t c2){
  int16_t current_range = c1 << 8;
  current_range |= c2;

  float res = (float)current_range;
  return res;
}

void Tr_hub_parser::serialDataCallback(uint8_t single_character) {
  static uint8_t input_buffer[BUFFER_SIZE];
  static int buffer_ctr = 0;
  static int seq_ctr = 0;

  int frame_length = 31;
  int crc_length = 19;

  if (single_character != 'T' && buffer_ctr < frame_length) {
    // not the beginning of serial feed so add char to buffer
    input_buffer[buffer_ctr++] = single_character;
    return;
  }
  else if (single_character == 'T') {
    //ROS_INFO("%s\n", reinterpret_cast<const char*>(single_character));

    if (buffer_ctr == (frame_length-1)) {
      // end of feed, calculate
      int16_t crc = crc8(input_buffer, crc_length);

      if (crc == input_buffer[crc_length]) {
        ROS_DEBUG("Frame: %s ", input_buffer);
        // ROS_INFO("Bitmask: %d", (int)input_buffer[18]);

        for (size_t i=0; i < measure.ranges.size(); i++) {
          measure.ranges.at(i).header.stamp = ros::Time::now();
          measure.ranges.at(i).header.seq = seq_ctr++;

          // Doesn't go out of range because of fixed buffer size as long as the number of sensor is not above 8
          float float_range = two_chars_to_float(input_buffer[2 * (i + 1)],input_buffer[2 * (i + 1) + 1]);

          if ((float_range * 0.001 < min_range) && (float_range > 0)) { //check for hardware cut-off
            float_range = min_range;
          } else if ((float_range * 0.001 > max_range) || (float_range < 0)) { //software cut-off should be adapted to sensor
            float_range = -1.0;
          } else {
            float_range = float_range * 0.001;
          }
          measure.ranges.at(i).range = float_range;
        }
        range_publisher_.publish(measure);

      } else {
        ROS_DEBUG("[%s] crc missmatch", ros::this_node::getName().c_str());
      }
    } else {
      ROS_DEBUG("[%s] received T but did not expect it, reset buffer without "
                "evaluating data",
                ros::this_node::getName().c_str());
    }
  } else {
    ROS_DEBUG("[%s] buffer_overflowed without receiving T, reset input_buffer",
              ros::this_node::getName().c_str());
  }

  // reset
  buffer_ctr = 0;

  // clear struct
  bzero(&input_buffer, BUFFER_SIZE);

  // store T
  input_buffer[buffer_ctr++] = 'T';
}

void Tr_hub_parser::setMode(const char *c) { serial_port_->sendChar(c); }

void Tr_hub_parser::dynParamCallback(
    const tr_hub_parser::Tr_hub_parserConfig &config, uint32_t level) {
  if (config.Mode == tr_hub_parser::Tr_hub_parser_Fast) {
    // setMode(FAST_MODE);
  }

  if (config.Mode == tr_hub_parser::Tr_hub_parser_Precise) {
    // setMode(PRECISE_MODE);
  }

  if (config.Mode == tr_hub_parser::Tr_hub_parser_Outdoor) {
    // setMode(OUTDOOR_MODE);
  }
}
}

int main(int argc, char **argv) {
  ros::init(argc, argv, "tr_hub_parser_node");
  tr_hub_parser::Tr_hub_parser tr_hub_parser_node;
  ros::spin();

  return 0;
}
<|endoftext|>


<commit_before>/******************************************************************************
 *
 * Project:  integrating laszip into liblas - http://liblas.org -
 * Purpose:
 * Author:   Martin Isenburg
 *           isenburg at cs.unc.edu
 *
 ******************************************************************************
 * Copyright (c) 2010, Martin Isenburg
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Licence as published
 * by the Free Software Foundation.
 *
 * See the COPYING file for more information.
 *
 ****************************************************************************/

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

  FILE:  laszippertest.cpp

  CONTENTS:

    This tool reads and writes point data in the LAS 1.X format compressed
    or uncompressed to test the laszipper and lasunzipper interfaces.

  PROGRAMMERS:

    martin isenburg@cs.unc.edu

  COPYRIGHT:

    copyright (C) 2010 martin isenburg@cs.unc.edu

    This software 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.

  CHANGE HISTORY:

    13 December 2010 -- created to test the remodularized laszip compressor

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

#include "laszipper.hpp"
#include "lasunzipper.hpp"

#if _MSC_VER < 1300
#include <istream.h>
#include <ostream.h>
#include <fstream.h>
#else
#include <fstream>
#endif

using namespace std;

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  unsigned char c;
  unsigned int i, j;
  unsigned int num_points = 100000;
  unsigned int num_errors = 0;
  filebuf ofb1;
  filebuf ofb2;
  ostream* ostream1 = 0;
  ostream* ostream2 = 0;
  FILE* ofile1 = 0;
  FILE* ofile2 = 0;
  filebuf ifb1;
  filebuf ifb2;
  istream* istream1 = 0;
  istream* istream2 = 0;
  FILE* ifile1 = 0;
  FILE* ifile2 = 0;

  bool range = false;
  bool use_iostream = true;

  // describe the point structure

  unsigned int num_items = 4;
  LASitem items[4];

  items[0].type = LASitem::POINT10;
  items[0].size = 20;
  items[0].version = 0;

  items[1].type = LASitem::GPSTIME;
  items[1].size = 8;
  items[1].version = 0;

  items[2].type = LASitem::RGB;
  items[2].size = 6;
  items[2].version = 0;

  items[3].type = LASitem::BYTE;
  items[3].size = 7;
  items[3].version = 0;

  // compute the point size
  unsigned int point_size = 0;
  for (i = 0; i < num_items; i++) point_size += items[i].size;

  // create the point data
  unsigned int point_offset = 0;
  unsigned char** point = new unsigned char*[num_items];
  unsigned char* point_data = new unsigned char[point_size];
  for (i = 0; i < num_items; i++)
  {
    point[i] = &(point_data[point_offset]);
    point_offset += items[i].size;
  }

  LASzipper* laszipper1 = new LASzipper(); // without compression
  LASzipper* laszipper2 = new LASzipper(); // with arithmetic compression

  if (use_iostream)
  {
    ofb1.open("test1.lax", ios::out);
    ostream1 = new ostream(&ofb1);
    if (!laszipper1->open(ostream1, num_items, items, LASZIP_COMPRESSION_NONE))
    {
      fprintf(stderr, "ERROR: could not open laszipper1\n");
      exit(1);
    }

    ofb2.open("test2.lax", ios::out);
    ostream2 = new ostream(&ofb2);
    if (!laszipper2->open(ostream2, num_items, items, LASZIP_COMPRESSION_ARITHMETIC))
    {
      fprintf(stderr, "ERROR: could not open laszipper2\n");
      exit(1);
    }
  }
  else
  {
    ofile1 = fopen("test1.lax", "wb");
    if (!laszipper1->open(ofile1, num_items, items, LASZIP_COMPRESSION_NONE))
    {
      fprintf(stderr, "ERROR: could not open laszipper1\n");
      exit(1);
    }

    ofile2 = fopen("test2.lax", "wb");
    if (!laszipper2->open(ofile2, num_items, items, LASZIP_COMPRESSION_ARITHMETIC))
    {
      fprintf(stderr, "ERROR: could not open laszipper2\n");
      exit(1);
    }
  }

  // compress 1000 points with "random" data

  c = 0;
  for (i = 0; i < num_points; i++)
  {
    for (j = 0; j < point_size; j++)
    {
      point_data[j] = c;
      c++;
    }
    laszipper1->write(point);
    laszipper2->write(point);
  }

  laszipper1->close();
  laszipper2->close();

  delete laszipper1;
  delete laszipper2;

  if (use_iostream)
  {
    ostream1.flush();
    ostream2.flush();
    delete ostream1;
    delete ostream2;
    ofb1.close();
    ofb2.close();
  }
  else
  {
    fclose(ofile1);
    fclose(ofile2);
  }

  LASunzipper* lasunzipper1 = new LASunzipper(); // without compression
  LASunzipper* lasunzipper2 = new LASunzipper(); // with arithmetic compression

  if (use_iostream)
  {
    ifb1.open("test1.lax", ios::in);
    istream1 = new istream(&ifb1);
    if (!lasunzipper1->open(istream1, num_items, items, LASZIP_COMPRESSION_NONE))
    {
      fprintf(stderr, "ERROR: could not open lasunzipper1\n");
      exit(1);
    }
    ifb2.open("test2.lax", ios::in);
    istream2 = new istream(&ifb2);
    if (!lasunzipper2->open(istream2, num_items, items, LASZIP_COMPRESSION_ARITHMETIC))
    {
      fprintf(stderr, "ERROR: could not open lasunzipper2\n");
      exit(1);
    }
  }
  else
  {
    ifile1 = fopen("test1.lax", "rb");
    if (!lasunzipper1->open(ifile1, num_items, items, LASZIP_COMPRESSION_NONE))
    {
      fprintf(stderr, "ERROR: could not open lasunzipper1\n");
      exit(1);
    }
    ifile2 = fopen("test2.lax", "rb");
    if (!lasunzipper2->open(ifile2, num_items, items, LASZIP_COMPRESSION_ARITHMETIC))
    {
      fprintf(stderr, "ERROR: could not open lasunzipper2\n");
      exit(1);
    }
  }

  // read 1000 points with "random" data

  num_errors = 0;
  c = 0;
  for (i = 0; i < num_points; i++)
  {
    lasunzipper1->read(point);
    for (j = 0; j < point_size; j++)
    {
      if (point_data[j] != c) num_errors++;
      c++;
    }
  }
  if (num_errors) fprintf(stderr, "ERROR: with lasunzipper1 %d\n", num_errors);
  else fprintf(stderr, "SUCCESS: lasunzipper1 read %d points correclty\n", num_points);

  // decompress 1000 points with "random" data

  num_errors = 0;
  c = 0;
  for (i = 0; i < num_points; i++)
  {
    lasunzipper2->read(point);
    for (j = 0; j < point_size; j++)
    {
      if (point_data[j] != c)
      {
        fprintf(stderr, "%d %d %d != %d\n", i, j, point_data[j], c);
        num_errors++;
        if (num_errors > 20) return -1;
      }
      c++;
    }
  }
  if (num_errors) fprintf(stderr, "ERROR: with lasunzipper2 %d\n", num_errors);
  else fprintf(stderr, "SUCCESS: lasunzipper2 read %d points correclty\n", num_points);

  lasunzipper1->close();
  lasunzipper2->close();

  delete lasunzipper1;
  delete lasunzipper2;

  if (use_iostream)
  {
    delete istream1;
    delete istream2;
    ifb1.close();
    ifb2.close();
  }
  else
  {
    fclose(ifile1);
    fclose(ifile2);
  }

  return 0;
}
<commit_msg>added check for input & output bytes<commit_after>/******************************************************************************
 *
 * Project:  integrating laszip into liblas - http://liblas.org -
 * Purpose:
 * Author:   Martin Isenburg
 *           isenburg at cs.unc.edu
 *
 ******************************************************************************
 * Copyright (c) 2010, Martin Isenburg
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Licence as published
 * by the Free Software Foundation.
 *
 * See the COPYING file for more information.
 *
 ****************************************************************************/

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

  FILE:  laszippertest.cpp

  CONTENTS:

    This tool reads and writes point data in the LAS 1.X format compressed
    or uncompressed to test the laszipper and lasunzipper interfaces.

  PROGRAMMERS:

    martin isenburg@cs.unc.edu

  COPYRIGHT:

    copyright (C) 2010 martin isenburg@cs.unc.edu

    This software 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.

  CHANGE HISTORY:

    13 December 2010 -- created to test the remodularized laszip compressor

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

#include "laszipper.hpp"
#include "lasunzipper.hpp"

#if _MSC_VER < 1300
#include <fstream.h>
#else
#include <fstream>
using namespace std;
#endif

#include <stdio.h>

int main(int argc, char *argv[])
{
  unsigned char c;
  unsigned int i, j;
  unsigned int num_points = 5;
  unsigned int num_errors = 0;
  filebuf ofb1;
  filebuf ofb2;
  ostream* ostream1 = 0;
  ostream* ostream2 = 0;
  FILE* ofile1 = 0;
  FILE* ofile2 = 0;
  filebuf ifb1;
  filebuf ifb2;
  istream* istream1 = 0;
  istream* istream2 = 0;
  FILE* ifile1 = 0;
  FILE* ifile2 = 0;

  bool range = false;
  bool use_iostream = true;

  // describe the point structure

  unsigned int num_items = 4;
  LASitem items[4];

  items[0].type = LASitem::POINT10;
  items[0].size = 20;
  items[0].version = 0;

  items[1].type = LASitem::GPSTIME;
  items[1].size = 8;
  items[1].version = 0;

  items[2].type = LASitem::RGB;
  items[2].size = 6;
  items[2].version = 0;

  items[3].type = LASitem::BYTE;
  items[3].size = 7;
  items[3].version = 0;

  // compute the point size
  unsigned int point_size = 0;
  for (i = 0; i < num_items; i++) point_size += items[i].size;

  // create the point data
  unsigned int point_offset = 0;
  unsigned char** point = new unsigned char*[num_items];
  unsigned char* point_data = new unsigned char[point_size];
  for (i = 0; i < num_items; i++)
  {
    point[i] = &(point_data[point_offset]);
    point_offset += items[i].size;
  }

  LASzipper* laszipper1 = new LASzipper(); // without compression
  LASzipper* laszipper2 = new LASzipper(); // with arithmetic compression

  if (use_iostream)
  {
    ofb1.open("test1.lax", ios::out);
    ofb1.setmode(filebuf::binary);
    ostream1 = new ostream(&ofb1);
    if (!laszipper1->open(ostream1, num_items, items, LASZIP_COMPRESSION_NONE))
    {
      fprintf(stderr, "ERROR: could not open laszipper1\n");
      return 0;
    }

    ofb2.open("test2.lax", ios::out);
    ofb2.setmode(filebuf::binary);
    ostream2 = new ostream(&ofb2);
    if (!laszipper2->open(ostream2, num_items, items, LASZIP_COMPRESSION_ARITHMETIC))
    {
      fprintf(stderr, "ERROR: could not open laszipper2\n");
      return 0;
    }
  }
  else
  {
    ofile1 = fopen("test1.lax", "wb");
    if (!laszipper1->open(ofile1, num_items, items, LASZIP_COMPRESSION_NONE))
    {
      fprintf(stderr, "ERROR: could not open laszipper1\n");
      return 0;
    }

    ofile2 = fopen("test2.lax", "wb");
    if (!laszipper2->open(ofile2, num_items, items, LASZIP_COMPRESSION_ARITHMETIC))
    {
      fprintf(stderr, "ERROR: could not open laszipper2\n");
      return 0;
    }
  }

  // write / compress num_points with "random" data

  c = 0;
  for (i = 0; i < num_points; i++)
  {
    for (j = 0; j < point_size; j++)
    {
      point_data[j] = c;
      c++;
    }
    laszipper1->write(point);
    laszipper2->write(point);
  }

  fprintf(stderr, "laszipper1 wrote %d bytes\n", laszipper1->close());
  fprintf(stderr, "laszipper2 wrote %d bytes\n", laszipper2->close());

  delete laszipper1;
  delete laszipper2;

  if (use_iostream)
  {
    ostream1->flush();
    ostream2->flush();
    delete ostream1;
    delete ostream2;
    ofb1.close();
    ofb2.close();
  }
  else
  {
    fclose(ofile1);
    fclose(ofile2);
  }

  LASunzipper* lasunzipper1 = new LASunzipper(); // without compression
  LASunzipper* lasunzipper2 = new LASunzipper(); // with arithmetic compression

  if (use_iostream)
  {
    ifb1.open("test1.lax", ios::in);
    ifb1.setmode(filebuf::binary);
    istream1 = new istream(&ifb1);
    if (!lasunzipper1->open(istream1, num_items, items, LASZIP_COMPRESSION_NONE))
    {
      fprintf(stderr, "ERROR: could not open lasunzipper1\n");
      return 0;
    }
    ifb2.open("test2.lax", ios::in);
    ifb2.setmode(filebuf::binary);
    istream2 = new istream(&ifb2);
    if (!lasunzipper2->open(istream2, num_items, items, LASZIP_COMPRESSION_ARITHMETIC))
    {
      fprintf(stderr, "ERROR: could not open lasunzipper2\n");
      return 0;
    }
  }
  else
  {
    ifile1 = fopen("test1.lax", "rb");
    if (!lasunzipper1->open(ifile1, num_items, items, LASZIP_COMPRESSION_NONE))
    {
      fprintf(stderr, "ERROR: could not open lasunzipper1\n");
      return 0;
    }
    ifile2 = fopen("test2.lax", "rb");
    if (!lasunzipper2->open(ifile2, num_items, items, LASZIP_COMPRESSION_ARITHMETIC))
    {
      fprintf(stderr, "ERROR: could not open lasunzipper2\n");
      return 0;
    }
  }

  // read num_points with "random" data

  num_errors = 0;
  c = 0;
  for (i = 0; i < num_points; i++)
  {
    lasunzipper1->read(point);
    for (j = 0; j < point_size; j++)
    {
      if (point_data[j] != c) num_errors++;
      c++;
    }
  }
  if (num_errors) fprintf(stderr, "ERROR: with lasunzipper1 %d\n", num_errors);
  else fprintf(stderr, "SUCCESS: lasunzipper1 read %d points correclty\n", num_points);

  // decompress num_points with "random" data

  num_errors = 0;
  c = 0;
  for (i = 0; i < num_points; i++)
  {
    lasunzipper2->read(point);
    for (j = 0; j < point_size; j++)
    {
      if (point_data[j] != c)
      {
        fprintf(stderr, "%d %d %d != %d\n", i, j, point_data[j], c);
        num_errors++;
        if (num_errors > 20) return -1;
      }
      c++;
    }
  }
  if (num_errors) fprintf(stderr, "ERROR: with lasunzipper2 %d\n", num_errors);
  else fprintf(stderr, "SUCCESS: lasunzipper2 read %d points correclty\n", num_points);

  fprintf(stderr, "lasunzipper1 read %d bytes\n", lasunzipper1->close());
  fprintf(stderr, "lasunzipper2 read %d bytes\n", lasunzipper2->close());

  delete lasunzipper1;
  delete lasunzipper2;

  if (use_iostream)
  {
    ifb1.close();
    ifb2.close();
    delete istream1;
    delete istream2;
  }
  else
  {
    fclose(ifile1);
    fclose(ifile2);
  }

  return 0;
}
<|endoftext|>


<commit_before>#include "QtViewerMapping.h"

#include <gloperate/painter/Camera.h>
#include <gloperate/painter/AbstractCameraCapability.h>
#include <gloperate/painter/AbstractProjectionCapability.h>
#include <gloperate/painter/AbstractViewportCapability.h>
#include <gloperate/painter/AbstractTypedRenderTargetCapability.h>
#include <gloperate/painter/Painter.h>
#include <gloperate/input/AbstractEvent.h>
#include <gloperate/input/KeyboardEvent.h>
#include <gloperate/input/MouseEvent.h>
#include <gloperate/input/WheelEvent.h>
#include <gloperate/navigation/WorldInHandNavigation.h>
#include <gloperate/tools/CoordinateProvider.h>

#include "util.hpp"

using namespace gloperate;
using namespace gloperate_qt;

QtViewerMapping::QtViewerMapping(QtOpenGLWindow * window)
:   AbstractQtMapping{window}
{
}

QtViewerMapping::~QtViewerMapping() = default;

void QtViewerMapping::initializeTools()
{
    if (m_painter &&
        m_painter->supports<AbstractCameraCapability>() &&
        m_painter->supports<AbstractViewportCapability>() &&
        m_painter->supports<AbstractTypedRenderTargetCapability>() &&
        m_painter->supports<AbstractProjectionCapability>())
    {
        auto cameraCapability = m_painter->getCapability<AbstractCameraCapability>();
        auto projectionCapability = m_painter->getCapability<AbstractProjectionCapability>();
        auto renderTargetCapability = m_painter->getCapability<AbstractTypedRenderTargetCapability>();
        auto viewportCapability = m_painter->getCapability<AbstractViewportCapability>();

        m_coordProvider = make_unique<CoordinateProvider>(
            cameraCapability,
            projectionCapability,
            viewportCapability,
            renderTargetCapability);

        m_navigation = make_unique<WorldInHandNavigation>(
            *cameraCapability,
            *viewportCapability,
            *m_coordProvider);
    }
}

void QtViewerMapping::mapEvent(AbstractEvent * event)
{
    switch (event->sourceType())
    {
        case SourceType::Keyboard:
            mapKeyboardEvent(event);
            break;
        case SourceType::Mouse:
            mapMouseEvent(event);
            break;
        case SourceType::Wheel:
            mapWheelEvent(event);
            break;
        default:
            break;
    }
}

void QtViewerMapping::mapKeyboardEvent(gloperate::AbstractEvent * event)
{
    const auto keyEvent = dynamic_cast<KeyboardEvent * >(event);

    if (!keyEvent)
        return;

    if (keyEvent->type() != KeyboardEvent::Type::Press)
        return;

    switch (keyEvent->key())
    {
            // WASD move camera
        case KeyW:
            m_navigation->pan(glm::vec3(0, 0, 1));
            break;
        case KeyA:
            m_navigation->pan(glm::vec3(1, 0, 0));
            break;
        case KeyS:
            m_navigation->pan(glm::vec3(0, 0, -1));
            break;
        case KeyD:
            m_navigation->pan(glm::vec3(-1, 0, 0));
            break;
            // Reset camera position
        case KeyR:
            m_navigation->reset();
            break;
            // Arrows rotate camera
        case KeyUp:
            m_navigation->rotate(0.0f, glm::radians(-10.0f));
            break;
        case KeyLeft:
            m_navigation->rotate(glm::radians(10.0f), 0.0f);
            break;
        case KeyDown:
            m_navigation->rotate(0.0f, glm::radians(10.0f));
            break;
        case KeyRight:
            m_navigation->rotate(glm::radians(-10.0f), 0.0f);
            break;
        default:
            break;
    }
}

void QtViewerMapping::mapMouseEvent(gloperate::AbstractEvent * event)
{
    const auto mouseEvent = dynamic_cast<MouseEvent*>(event);

    if (!mouseEvent)
        return;

    if (mouseEvent->type() == MouseEvent::Type::Press)
    {
        switch (mouseEvent->button())
        {
            case MouseButtonMiddle:
                m_navigation->reset();
                break;
            case MouseButtonLeft:
                m_navigation->panBegin(mouseEvent->pos());
                break;
            case MouseButtonRight:
                m_navigation->rotateBegin(mouseEvent->pos());
                break;
            default:
                break;
        }
    }
    else if (mouseEvent->type() == MouseEvent::Type::Move)
    {
        switch (m_navigation->mode())
        {
            case WorldInHandNavigation::InteractionMode::PanInteraction:
                m_navigation->panProcess(mouseEvent->pos());
                break;
            case WorldInHandNavigation::InteractionMode::RotateInteraction:
                m_navigation->rotateProcess(mouseEvent->pos());
                break;
            default:
                break;
        }
    }
    else if (mouseEvent->type() == MouseEvent::Type::Release)
    {
        switch (mouseEvent->button())
        {
            case MouseButtonLeft:
                m_navigation->panEnd();
                break;
            case MouseButtonRight:
                m_navigation->rotateEnd();
                break;
            default:
                break;
        }
    }
}

void QtViewerMapping::mapWheelEvent(gloperate::AbstractEvent * event)
{
    auto wheelEvent = dynamic_cast<WheelEvent*>(event);

    if (!wheelEvent)
        return;

    auto scale = wheelEvent->angleDelta().y;
    scale /= WheelEvent::defaultMouseAngleDelta();
    scale *= 0.1f; // smoother (slower) scaling
    m_navigation->scaleAtMouse(wheelEvent->pos(), scale);
}

<commit_msg>Fix high-res window coordinates<commit_after>#include "QtViewerMapping.h"

#include <gloperate/painter/Camera.h>
#include <gloperate/painter/AbstractCameraCapability.h>
#include <gloperate/painter/AbstractProjectionCapability.h>
#include <gloperate/painter/AbstractViewportCapability.h>
#include <gloperate/painter/AbstractTypedRenderTargetCapability.h>
#include <gloperate/painter/Painter.h>
#include <gloperate/input/AbstractEvent.h>
#include <gloperate/input/KeyboardEvent.h>
#include <gloperate/input/MouseEvent.h>
#include <gloperate/input/WheelEvent.h>
#include <gloperate/navigation/WorldInHandNavigation.h>
#include <gloperate/tools/CoordinateProvider.h>
#include <gloperate-qt/QtOpenGLWindow.h>

#include "util.hpp"

using namespace gloperate;
using namespace gloperate_qt;

QtViewerMapping::QtViewerMapping(QtOpenGLWindow * window)
:   AbstractQtMapping{window}
{
}

QtViewerMapping::~QtViewerMapping() = default;

void QtViewerMapping::initializeTools()
{
    if (m_painter &&
        m_painter->supports<AbstractCameraCapability>() &&
        m_painter->supports<AbstractViewportCapability>() &&
        m_painter->supports<AbstractTypedRenderTargetCapability>() &&
        m_painter->supports<AbstractProjectionCapability>())
    {
        auto cameraCapability = m_painter->getCapability<AbstractCameraCapability>();
        auto projectionCapability = m_painter->getCapability<AbstractProjectionCapability>();
        auto renderTargetCapability = m_painter->getCapability<AbstractTypedRenderTargetCapability>();
        auto viewportCapability = m_painter->getCapability<AbstractViewportCapability>();

        m_coordProvider = make_unique<CoordinateProvider>(
            cameraCapability,
            projectionCapability,
            viewportCapability,
            renderTargetCapability);

        m_navigation = make_unique<WorldInHandNavigation>(
            *cameraCapability,
            *viewportCapability,
            *m_coordProvider);
    }
}

void QtViewerMapping::mapEvent(AbstractEvent * event)
{
    switch (event->sourceType())
    {
        case SourceType::Keyboard:
            mapKeyboardEvent(event);
            break;
        case SourceType::Mouse:
            mapMouseEvent(event);
            break;
        case SourceType::Wheel:
            mapWheelEvent(event);
            break;
        default:
            break;
    }
}

void QtViewerMapping::mapKeyboardEvent(gloperate::AbstractEvent * event)
{
    const auto keyEvent = dynamic_cast<KeyboardEvent * >(event);

    if (!keyEvent)
        return;

    if (keyEvent->type() != KeyboardEvent::Type::Press)
        return;

    switch (keyEvent->key())
    {
            // WASD move camera
        case KeyW:
            m_navigation->pan(glm::vec3(0, 0, 1));
            break;
        case KeyA:
            m_navigation->pan(glm::vec3(1, 0, 0));
            break;
        case KeyS:
            m_navigation->pan(glm::vec3(0, 0, -1));
            break;
        case KeyD:
            m_navigation->pan(glm::vec3(-1, 0, 0));
            break;
            // Reset camera position
        case KeyR:
            m_navigation->reset();
            break;
            // Arrows rotate camera
        case KeyUp:
            m_navigation->rotate(0.0f, glm::radians(-10.0f));
            break;
        case KeyLeft:
            m_navigation->rotate(glm::radians(10.0f), 0.0f);
            break;
        case KeyDown:
            m_navigation->rotate(0.0f, glm::radians(10.0f));
            break;
        case KeyRight:
            m_navigation->rotate(glm::radians(-10.0f), 0.0f);
            break;
        default:
            break;
    }
}

void QtViewerMapping::mapMouseEvent(gloperate::AbstractEvent * event)
{
    const auto mouseEvent = dynamic_cast<MouseEvent *>(event);

    if (!mouseEvent)
        return;

    const auto mousePos = mouseEvent->pos() * static_cast<int>(m_window->devicePixelRatio());

    if (mouseEvent->type() == MouseEvent::Type::Press)
    {
        switch (mouseEvent->button())
        {
            case MouseButtonMiddle:
                m_navigation->reset();
                break;
            case MouseButtonLeft:
                m_navigation->panBegin(mousePos);
                break;
            case MouseButtonRight:
                m_navigation->rotateBegin(mousePos);
                break;
            default:
                break;
        }
    }
    else if (mouseEvent->type() == MouseEvent::Type::Move)
    {
        switch (m_navigation->mode())
        {
            case WorldInHandNavigation::InteractionMode::PanInteraction:
                m_navigation->panProcess(mousePos);
                break;
            case WorldInHandNavigation::InteractionMode::RotateInteraction:
                m_navigation->rotateProcess(mousePos);
                break;
            default:
                break;
        }
    }
    else if (mouseEvent->type() == MouseEvent::Type::Release)
    {
        switch (mouseEvent->button())
        {
            case MouseButtonLeft:
                m_navigation->panEnd();
                break;
            case MouseButtonRight:
                m_navigation->rotateEnd();
                break;
            default:
                break;
        }
    }
}

void QtViewerMapping::mapWheelEvent(gloperate::AbstractEvent * event)
{
    auto wheelEvent = dynamic_cast<WheelEvent *>(event);

    if (!wheelEvent)
        return;

    const auto mousePos = wheelEvent->pos() * static_cast<int>(m_window->devicePixelRatio());

    auto scale = wheelEvent->angleDelta().y;
    scale /= WheelEvent::defaultMouseAngleDelta();
    scale *= 0.1f; // smoother (slower) scaling
    m_navigation->scaleAtMouse(mousePos, scale);
}

<|endoftext|>


<commit_before>/* -*- Mode:C++; c-file-style:"gnu" -*- */
/*
 * Copyright 2014 Waseda University, Sato Laboratory
 *   Author: Jairo Eduardo Lopez <jairo@ruri.waseda.jp>
 *
 *  nnn-nnst-test.cc is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  nnn-nnst-test.cc 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 Affero Public License for more details.
 *
 *  You should have received a copy of the GNU Affero Public License
 *  along with nnn-nnst-test.cc.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

// Extensions
#include "nnnSIM/nnnSIM-module.h"
#include "nnnSIM/model/nnst/nnn-nnst.h"
#include "nnnSIM/model/nnst/nnn-nnst-entry.h"

using namespace ns3;
using namespace std;
using namespace nnn;

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

	NNNAddress nn_test1 ("be.54.32");
	NNNAddress nn_test2 ("af.67.31");
	NNNAddress nn_test3 ("ae.34.26");

	Simulator::Stop (Seconds (70));
	Simulator::Run ();
	Simulator::Destroy ();

}
<commit_msg>NNST test program<commit_after>/* -*- Mode:C++; c-file-style:"gnu" -*- */
/*
 * Copyright 2014 Waseda University, Sato Laboratory
 *   Author: Jairo Eduardo Lopez <jairo@ruri.waseda.jp>
 *
 *  nnn-nnst-test.cc is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  nnn-nnst-test.cc 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 Affero Public License for more details.
 *
 *  You should have received a copy of the GNU Affero Public License
 *  along with nnn-nnst-test.cc.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

// Extensions
#include "nnnSIM/nnnSIM-module.h"
#include "nnnSIM/model/nnst/nnn-nnst.h"
#include "nnnSIM/model/nnst/nnn-nnst-entry.h"

using namespace ns3;
using namespace std;
using namespace nnn;

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

	NNNAddress nn_test1 ("be.54.32");
	NNNAddress nn_test2 ("af.67.31");
	NNNAddress nn_test3 ("ae.34.26");

	Simulator::Stop (Seconds (70));
	Simulator::Run ();
	Simulator::Destroy ();

}
<|endoftext|>


<commit_before>#include <maya/MArgDatabase.h>
#include <maya/MArgList.h>
#include <maya/MSelectionList.h>
#include <maya/MStatus.h>

#include "Asset.h"
#include "AssetNode.h"
#include "AssetCommand.h"
#include "AssetSubCommand.h"
#include "AssetSubCommandLoadAsset.h"
#include "AssetSubCommandSync.h"
#include "util.h"

#define kListAssetsFlag "-ls"
#define kListAssetsFlagLong "-listAssets"
#define kLoadAssetFlag "-la"
#define kLoadAssetFlagLong "-loadAsset"
#define kSyncFlag "-syn"
#define kSyncFlagLong "-sync"
#define kSaveHIPFlag "-sh"
#define kSaveHIPFlagLong "-saveHIP"
#define kResetSimulationFlag "-rs"
#define kResetSimulationFlagLong "-resetSimulation"
#define kReloadAssetFlag "-rl"
#define kReloadAssetFlagLong "-reloadAsset"
#define kSyncAttributesFlag "-sa"
#define kSyncAttributesFlagLong "-syncAttributes"
#define kSyncOutputsFlag "-so"
#define kSyncOutputsFlagLong "-syncOutputs"
#define kSyncHiddenFlag "-shi"
#define kSyncHiddenFlagLong "-syncHidden"
#define kSyncTemplatedGeosFlag "-stm"
#define kSyncTemplatedGeosFlagLong "-syncTemplatedGeos"

class AssetSubCommandResetSimulation : public AssetSubCommandAsset
{
    public:
        AssetSubCommandResetSimulation(const MObject &assetNodeObj) :
            AssetSubCommandAsset(assetNodeObj)
        {
        }

        virtual MStatus doIt()
        {
            getAsset()->resetSimulation();

            return MStatus::kSuccess;
        }
};

class AssetSubCommandListAssets : public AssetSubCommand
{
    public:
        AssetSubCommandListAssets(const MString &otlFilePath) :
            myOTLFilePath(otlFilePath)
        {
        }

        virtual MStatus doIt()
        {
            int libraryId;
            HAPI_LoadAssetLibraryFromFile(myOTLFilePath.asChar(), &libraryId);

            int assetCount;
            HAPI_GetAvailableAssetCount(libraryId, &assetCount);

            std::vector<HAPI_StringHandle> assetNamesSH(assetCount);
            HAPI_GetAvailableAssets(libraryId,
                    &assetNamesSH.front(),
                    assetNamesSH.size());

            for(unsigned int i = 0; i < assetNamesSH.size(); i++)
            {
                MPxCommand::appendToResult(Util::getString(assetNamesSH[i]));
            }

            return MStatus::kSuccess;
        }

    protected:
        MString myOTLFilePath;
};

void* AssetCommand::creator()
{
    return new AssetCommand();
}

MSyntax
AssetCommand::newSyntax()
{
    MSyntax syntax;

    // -listAssets list assets in an OTL file
    CHECK_MSTATUS(syntax.addFlag(kListAssetsFlag, kListAssetsFlagLong,
                MSyntax::kString));

    // -loadAsset load an otl file
    // expected arguments: otl_file_name - the name of the otl file to load
    CHECK_MSTATUS(syntax.addFlag(kLoadAssetFlag, kLoadAssetFlagLong,
                MSyntax::kString,
                MSyntax::kString));

    // -sync synchronize the Maya nodes with the asset's state
    // expected arguments:
    //        asset node
    CHECK_MSTATUS(syntax.addFlag(kSyncFlag, kSyncFlagLong,
                MSyntax::kSelectionItem));

    // -saveHIP saves the contents of the current Houdini scene as a hip file
    // expected arguments: hip_file_name - the name of the hip file to save
    CHECK_MSTATUS(syntax.addFlag(kSaveHIPFlag, kSaveHIPFlagLong, MSyntax::kString));

    // -resetSimulation resets the simulation state for an asset.  This will clear
    // the DOPs cache for the asset.
    CHECK_MSTATUS(syntax.addFlag(kResetSimulationFlag,
                                 kResetSimulationFlagLong,
                                 MSyntax::kSelectionItem));

    // -reloadAsset will unload and immediate reload the asset.  If an otl file
    // has changed due to an edit in Houdini, this should pick up the change
        // Note that this won't refresh the AE, you need to that separately after
        // running this, with refreshEditorTemplates
    CHECK_MSTATUS(syntax.addFlag(kReloadAssetFlag,
                                 kReloadAssetFlagLong,
                                 MSyntax::kString));

    CHECK_MSTATUS(syntax.addFlag(kSyncAttributesFlag, kSyncAttributesFlagLong));
    CHECK_MSTATUS(syntax.addFlag(kSyncOutputsFlag, kSyncOutputsFlagLong));

    // -syncHidden will cause hidden objects to be sync'ed
    CHECK_MSTATUS(syntax.addFlag(kSyncHiddenFlag,
                                 kSyncHiddenFlagLong,
                                 MSyntax::kNoArg));

    // -syncTemplatedGeos will cause templated geos to be sync'ed
    CHECK_MSTATUS(syntax.addFlag(kSyncTemplatedGeosFlag,
                                 kSyncTemplatedGeosFlagLong,
                                 MSyntax::kNoArg));

    return syntax;
}

AssetCommand::AssetCommand() :
    myOperationType(kOperationInvalid),
    myAssetSubCommand(NULL)
{
}

AssetCommand::~AssetCommand()
{
    if(myOperationType == kOperationSubCommand)
    {
        delete myAssetSubCommand;
    }
}

MStatus
AssetCommand::parseArgs(const MArgList &args)
{
    MStatus status;
    MArgDatabase argData(syntax(), args, &status);
    if(!status)
    {
        return status;
    }

    if(!(argData.isFlagSet(kListAssetsFlag)
                ^ argData.isFlagSet(kLoadAssetFlag)
                ^ argData.isFlagSet(kSyncFlag)
                ^ argData.isFlagSet(kSaveHIPFlag)
                ^ argData.isFlagSet(kResetSimulationFlag)
                ^ argData.isFlagSet(kReloadAssetFlag)))
    {
        displayError("Exactly one of these flags must be specified:\n"
                kLoadAssetFlagLong "\n"
                kSyncFlagLong "\n"
                kSaveHIPFlagLong "\n"
                kResetSimulationFlagLong "\n"
                kReloadAssetFlagLong "\n");
        return MStatus::kInvalidParameter;
    }

    if(argData.isFlagSet(kListAssetsFlag))
    {
        myOperationType = kOperationSubCommand;

        MString otlFilePath;
        {
            status = argData.getFlagArgument(kListAssetsFlag, 0, otlFilePath);
            if(!status)
            {
                displayError("Invalid argument for \"" kListAssetsFlagLong "\".");
                return status;
            }
        }

        myAssetSubCommand = new AssetSubCommandListAssets(
                otlFilePath
                );
    }

    if(argData.isFlagSet(kLoadAssetFlag))
    {
        myOperationType = kOperationSubCommand;

        MString otlFilePath;
        {
            status = argData.getFlagArgument(kLoadAssetFlag, 0, otlFilePath);
            if(!status)
            {
                displayError("Invalid argument for \"" kLoadAssetFlagLong "\".");
                return status;
            }
        }

        MString assetName;
        {
            status = argData.getFlagArgument(kLoadAssetFlag, 1, assetName);
            if(!status)
            {
                displayError("Invalid argument for \"" kLoadAssetFlagLong "\".");
                return status;
            }
        }

        myAssetSubCommand = new AssetSubCommandLoadAsset(
                otlFilePath,
                assetName
                );
    }

    if(argData.isFlagSet(kReloadAssetFlag))
    {
        myOperationType = kOperationSubCommand;

        MString assetPath;
        {
            status = argData.getFlagArgument(kReloadAssetFlag, 0, assetPath);
            if(!status)
            {
                displayError("Invalid argument for \"" kReloadAssetFlagLong "\".");
                return status;
            }
        }

        MSelectionList selList;
        MObject assetNodeObj;

        selList.add(assetPath);
        selList.getDependNode(0, assetNodeObj);
        CHECK_MSTATUS_AND_RETURN_IT(status);

        MFnDependencyNode assetNodeFn(assetNodeObj);
        AssetNode* assetNode = dynamic_cast<AssetNode*>(assetNodeFn.userNode());
        assetNode->rebuildAsset();

        myAssetSubCommand = new AssetSubCommandSync(assetNodeObj);
    }

    if(argData.isFlagSet(kSyncFlag))
    {
        myOperationType = kOperationSubCommand;

        MObject assetNodeObj;
        {
            MSelectionList selection;

            status = argData.getFlagArgument(kSyncFlag, 0, selection);
            if(!status)
            {
                displayError("Invalid first argument for \"" kSyncFlagLong "\".");
                return status;
            }

            selection.getDependNode(0, assetNodeObj);
            CHECK_MSTATUS_AND_RETURN_IT(status);
        }

        AssetSubCommandSync* subCommand = new AssetSubCommandSync(
                assetNodeObj
                );

        if(argData.isFlagSet(kSyncAttributesFlag))
        {
            subCommand->setSyncAttributes();
        }

        if(argData.isFlagSet(kSyncOutputsFlag))
        {
            subCommand->setSyncOutputs();
        }

        if(argData.isFlagSet(kSyncHiddenFlag))
        {
            subCommand->setSyncOutputHidden();
        }

        if(argData.isFlagSet(kSyncTemplatedGeosFlag))
        {
            subCommand->setSyncOutputTemplatedGeos();
        }

        myAssetSubCommand = subCommand;
    }

    if(argData.isFlagSet(kSaveHIPFlag))
    {
        myOperationType = kOperationSaveHip;

        status = argData.getFlagArgument(kSaveHIPFlag, 0, myHIPFilePath);
        if(!status)
        {
            displayError("Invalid argument for \"" kSaveHIPFlagLong "\".");
            return status;
        }
    }

    if(argData.isFlagSet(kResetSimulationFlag))
    {
        myOperationType = kOperationSubCommand;

        MObject assetNodeObj;
        {
            MSelectionList selection;

            status = argData.getFlagArgument(kResetSimulationFlag, 0, selection);
            if(!status)
            {
                displayError("Invalid first argument for \"" kResetSimulationFlagLong "\".");
                return status;
            }

            selection.getDependNode(0, assetNodeObj);
            CHECK_MSTATUS_AND_RETURN_IT(status);
        }

        myAssetSubCommand = new AssetSubCommandResetSimulation(assetNodeObj);
    }

    return MStatus::kSuccess;
}

MStatus AssetCommand::doIt(const MArgList& args)
{
    MStatus status;

    status = parseArgs(args);
    if(!status)
    {
        return status;
    }

    if(myOperationType == kOperationSubCommand)
    {
        return myAssetSubCommand->doIt();
    }

    return redoIt();
}

MStatus AssetCommand::redoIt()
{
    if(myOperationType == kOperationSubCommand)
    {
        return myAssetSubCommand->redoIt();
    }

    if(myOperationType == kOperationSaveHip)
    {
        HAPI_SaveHIPFile(myHIPFilePath.asChar());
        return MS::kSuccess;
    }

    return MS::kFailure;
}

MStatus AssetCommand::undoIt()
{
    if(myOperationType == kOperationSubCommand)
    {
        return myAssetSubCommand->undoIt();
    }

    return MS::kSuccess;
}

bool AssetCommand::isUndoable() const
{
    if(myOperationType == kOperationSubCommand)
    {
        return myAssetSubCommand->isUndoable();
    }

    return false;
}
<commit_msg>Check for errors when using "-listAssets"<commit_after>#include <maya/MArgDatabase.h>
#include <maya/MArgList.h>
#include <maya/MSelectionList.h>
#include <maya/MStatus.h>

#include "Asset.h"
#include "AssetNode.h"
#include "AssetCommand.h"
#include "AssetSubCommand.h"
#include "AssetSubCommandLoadAsset.h"
#include "AssetSubCommandSync.h"
#include "util.h"

#define kListAssetsFlag "-ls"
#define kListAssetsFlagLong "-listAssets"
#define kLoadAssetFlag "-la"
#define kLoadAssetFlagLong "-loadAsset"
#define kSyncFlag "-syn"
#define kSyncFlagLong "-sync"
#define kSaveHIPFlag "-sh"
#define kSaveHIPFlagLong "-saveHIP"
#define kResetSimulationFlag "-rs"
#define kResetSimulationFlagLong "-resetSimulation"
#define kReloadAssetFlag "-rl"
#define kReloadAssetFlagLong "-reloadAsset"
#define kSyncAttributesFlag "-sa"
#define kSyncAttributesFlagLong "-syncAttributes"
#define kSyncOutputsFlag "-so"
#define kSyncOutputsFlagLong "-syncOutputs"
#define kSyncHiddenFlag "-shi"
#define kSyncHiddenFlagLong "-syncHidden"
#define kSyncTemplatedGeosFlag "-stm"
#define kSyncTemplatedGeosFlagLong "-syncTemplatedGeos"

class AssetSubCommandResetSimulation : public AssetSubCommandAsset
{
    public:
        AssetSubCommandResetSimulation(const MObject &assetNodeObj) :
            AssetSubCommandAsset(assetNodeObj)
        {
        }

        virtual MStatus doIt()
        {
            getAsset()->resetSimulation();

            return MStatus::kSuccess;
        }
};

class AssetSubCommandListAssets : public AssetSubCommand
{
    public:
        AssetSubCommandListAssets(const MString &otlFilePath) :
            myOTLFilePath(otlFilePath)
        {
        }

        virtual MStatus doIt()
        {
            HAPI_Result hapiResult;

            int libraryId = -1;
            hapiResult = HAPI_LoadAssetLibraryFromFile(myOTLFilePath.asChar(), &libraryId);
            if(HAPI_FAIL(hapiResult))
            {
                DISPLAY_ERROR("Could not load OTL file: ^1s", myOTLFilePath);
                DISPLAY_ERROR_HAPI_STATUS();

                return MStatus::kFailure;
            }

            int assetCount = 0;
            hapiResult = HAPI_GetAvailableAssetCount(libraryId, &assetCount);
            CHECK_HAPI_AND_RETURN(hapiResult, MStatus::kFailure);

            std::vector<HAPI_StringHandle> assetNamesSH(assetCount);
            hapiResult = HAPI_GetAvailableAssets(libraryId,
                    &assetNamesSH.front(),
                    assetNamesSH.size());
            CHECK_HAPI_AND_RETURN(hapiResult, MStatus::kFailure);

            for(unsigned int i = 0; i < assetNamesSH.size(); i++)
            {
                MPxCommand::appendToResult(Util::getString(assetNamesSH[i]));
            }

            return MStatus::kSuccess;
        }

    protected:
        MString myOTLFilePath;
};

void* AssetCommand::creator()
{
    return new AssetCommand();
}

MSyntax
AssetCommand::newSyntax()
{
    MSyntax syntax;

    // -listAssets list assets in an OTL file
    CHECK_MSTATUS(syntax.addFlag(kListAssetsFlag, kListAssetsFlagLong,
                MSyntax::kString));

    // -loadAsset load an otl file
    // expected arguments: otl_file_name - the name of the otl file to load
    CHECK_MSTATUS(syntax.addFlag(kLoadAssetFlag, kLoadAssetFlagLong,
                MSyntax::kString,
                MSyntax::kString));

    // -sync synchronize the Maya nodes with the asset's state
    // expected arguments:
    //        asset node
    CHECK_MSTATUS(syntax.addFlag(kSyncFlag, kSyncFlagLong,
                MSyntax::kSelectionItem));

    // -saveHIP saves the contents of the current Houdini scene as a hip file
    // expected arguments: hip_file_name - the name of the hip file to save
    CHECK_MSTATUS(syntax.addFlag(kSaveHIPFlag, kSaveHIPFlagLong, MSyntax::kString));

    // -resetSimulation resets the simulation state for an asset.  This will clear
    // the DOPs cache for the asset.
    CHECK_MSTATUS(syntax.addFlag(kResetSimulationFlag,
                                 kResetSimulationFlagLong,
                                 MSyntax::kSelectionItem));

    // -reloadAsset will unload and immediate reload the asset.  If an otl file
    // has changed due to an edit in Houdini, this should pick up the change
        // Note that this won't refresh the AE, you need to that separately after
        // running this, with refreshEditorTemplates
    CHECK_MSTATUS(syntax.addFlag(kReloadAssetFlag,
                                 kReloadAssetFlagLong,
                                 MSyntax::kString));

    CHECK_MSTATUS(syntax.addFlag(kSyncAttributesFlag, kSyncAttributesFlagLong));
    CHECK_MSTATUS(syntax.addFlag(kSyncOutputsFlag, kSyncOutputsFlagLong));

    // -syncHidden will cause hidden objects to be sync'ed
    CHECK_MSTATUS(syntax.addFlag(kSyncHiddenFlag,
                                 kSyncHiddenFlagLong,
                                 MSyntax::kNoArg));

    // -syncTemplatedGeos will cause templated geos to be sync'ed
    CHECK_MSTATUS(syntax.addFlag(kSyncTemplatedGeosFlag,
                                 kSyncTemplatedGeosFlagLong,
                                 MSyntax::kNoArg));

    return syntax;
}

AssetCommand::AssetCommand() :
    myOperationType(kOperationInvalid),
    myAssetSubCommand(NULL)
{
}

AssetCommand::~AssetCommand()
{
    if(myOperationType == kOperationSubCommand)
    {
        delete myAssetSubCommand;
    }
}

MStatus
AssetCommand::parseArgs(const MArgList &args)
{
    MStatus status;
    MArgDatabase argData(syntax(), args, &status);
    if(!status)
    {
        return status;
    }

    if(!(argData.isFlagSet(kListAssetsFlag)
                ^ argData.isFlagSet(kLoadAssetFlag)
                ^ argData.isFlagSet(kSyncFlag)
                ^ argData.isFlagSet(kSaveHIPFlag)
                ^ argData.isFlagSet(kResetSimulationFlag)
                ^ argData.isFlagSet(kReloadAssetFlag)))
    {
        displayError("Exactly one of these flags must be specified:\n"
                kLoadAssetFlagLong "\n"
                kSyncFlagLong "\n"
                kSaveHIPFlagLong "\n"
                kResetSimulationFlagLong "\n"
                kReloadAssetFlagLong "\n");
        return MStatus::kInvalidParameter;
    }

    if(argData.isFlagSet(kListAssetsFlag))
    {
        myOperationType = kOperationSubCommand;

        MString otlFilePath;
        {
            status = argData.getFlagArgument(kListAssetsFlag, 0, otlFilePath);
            if(!status)
            {
                displayError("Invalid argument for \"" kListAssetsFlagLong "\".");
                return status;
            }
        }

        myAssetSubCommand = new AssetSubCommandListAssets(
                otlFilePath
                );
    }

    if(argData.isFlagSet(kLoadAssetFlag))
    {
        myOperationType = kOperationSubCommand;

        MString otlFilePath;
        {
            status = argData.getFlagArgument(kLoadAssetFlag, 0, otlFilePath);
            if(!status)
            {
                displayError("Invalid argument for \"" kLoadAssetFlagLong "\".");
                return status;
            }
        }

        MString assetName;
        {
            status = argData.getFlagArgument(kLoadAssetFlag, 1, assetName);
            if(!status)
            {
                displayError("Invalid argument for \"" kLoadAssetFlagLong "\".");
                return status;
            }
        }

        myAssetSubCommand = new AssetSubCommandLoadAsset(
                otlFilePath,
                assetName
                );
    }

    if(argData.isFlagSet(kReloadAssetFlag))
    {
        myOperationType = kOperationSubCommand;

        MString assetPath;
        {
            status = argData.getFlagArgument(kReloadAssetFlag, 0, assetPath);
            if(!status)
            {
                displayError("Invalid argument for \"" kReloadAssetFlagLong "\".");
                return status;
            }
        }

        MSelectionList selList;
        MObject assetNodeObj;

        selList.add(assetPath);
        selList.getDependNode(0, assetNodeObj);
        CHECK_MSTATUS_AND_RETURN_IT(status);

        MFnDependencyNode assetNodeFn(assetNodeObj);
        AssetNode* assetNode = dynamic_cast<AssetNode*>(assetNodeFn.userNode());
        assetNode->rebuildAsset();

        myAssetSubCommand = new AssetSubCommandSync(assetNodeObj);
    }

    if(argData.isFlagSet(kSyncFlag))
    {
        myOperationType = kOperationSubCommand;

        MObject assetNodeObj;
        {
            MSelectionList selection;

            status = argData.getFlagArgument(kSyncFlag, 0, selection);
            if(!status)
            {
                displayError("Invalid first argument for \"" kSyncFlagLong "\".");
                return status;
            }

            selection.getDependNode(0, assetNodeObj);
            CHECK_MSTATUS_AND_RETURN_IT(status);
        }

        AssetSubCommandSync* subCommand = new AssetSubCommandSync(
                assetNodeObj
                );

        if(argData.isFlagSet(kSyncAttributesFlag))
        {
            subCommand->setSyncAttributes();
        }

        if(argData.isFlagSet(kSyncOutputsFlag))
        {
            subCommand->setSyncOutputs();
        }

        if(argData.isFlagSet(kSyncHiddenFlag))
        {
            subCommand->setSyncOutputHidden();
        }

        if(argData.isFlagSet(kSyncTemplatedGeosFlag))
        {
            subCommand->setSyncOutputTemplatedGeos();
        }

        myAssetSubCommand = subCommand;
    }

    if(argData.isFlagSet(kSaveHIPFlag))
    {
        myOperationType = kOperationSaveHip;

        status = argData.getFlagArgument(kSaveHIPFlag, 0, myHIPFilePath);
        if(!status)
        {
            displayError("Invalid argument for \"" kSaveHIPFlagLong "\".");
            return status;
        }
    }

    if(argData.isFlagSet(kResetSimulationFlag))
    {
        myOperationType = kOperationSubCommand;

        MObject assetNodeObj;
        {
            MSelectionList selection;

            status = argData.getFlagArgument(kResetSimulationFlag, 0, selection);
            if(!status)
            {
                displayError("Invalid first argument for \"" kResetSimulationFlagLong "\".");
                return status;
            }

            selection.getDependNode(0, assetNodeObj);
            CHECK_MSTATUS_AND_RETURN_IT(status);
        }

        myAssetSubCommand = new AssetSubCommandResetSimulation(assetNodeObj);
    }

    return MStatus::kSuccess;
}

MStatus AssetCommand::doIt(const MArgList& args)
{
    MStatus status;

    status = parseArgs(args);
    if(!status)
    {
        return status;
    }

    if(myOperationType == kOperationSubCommand)
    {
        return myAssetSubCommand->doIt();
    }

    return redoIt();
}

MStatus AssetCommand::redoIt()
{
    if(myOperationType == kOperationSubCommand)
    {
        return myAssetSubCommand->redoIt();
    }

    if(myOperationType == kOperationSaveHip)
    {
        HAPI_SaveHIPFile(myHIPFilePath.asChar());
        return MS::kSuccess;
    }

    return MS::kFailure;
}

MStatus AssetCommand::undoIt()
{
    if(myOperationType == kOperationSubCommand)
    {
        return myAssetSubCommand->undoIt();
    }

    return MS::kSuccess;
}

bool AssetCommand::isUndoable() const
{
    if(myOperationType == kOperationSubCommand)
    {
        return myAssetSubCommand->isUndoable();
    }

    return false;
}
<|endoftext|>


<commit_before>#include "GeoCoordinate.hpp"
#include "builders/MeshContext.hpp"
#include "entities/Node.hpp"
#include "entities/Way.hpp"
#include "entities/Area.hpp"
#include "entities/Relation.hpp"
#include "builders/buildings/BuildingBuilder.hpp"
#include "builders/buildings/facades/CylinderFacadeBuilder.hpp"
#include "builders/buildings/facades/FlatFacadeBuilder.hpp"
#include "builders/buildings/facades/SphereFacadeBuilder.hpp"
#include "builders/buildings/roofs/DomeRoofBuilder.hpp"
#include "builders/buildings/roofs/FlatRoofBuilder.hpp"
#include "builders/buildings/roofs/PyramidalRoofBuilder.hpp"
#include "builders/buildings/roofs/MansardRoofBuilder.hpp"
#include "builders/buildings/roofs/SkillionRoofBuilder.hpp"
#include "builders/buildings/roofs/RoundRoofBuilder.hpp"

using namespace utymap;
using namespace utymap::builders;
using namespace utymap::entities;
using namespace utymap::heightmap;
using namespace utymap::mapcss;
using namespace utymap::math;
using namespace utymap::index;
using namespace utymap::utils;

namespace {
const std::string MeshNamePrefix = "building:";

const std::string RoofPrefix = "roof-";
const std::string RoofTypeKey = RoofPrefix + StyleConsts::TypeKey();
const std::string RoofHeightKey = RoofPrefix + StyleConsts::HeightKey();
const std::string RoofGradientKey = RoofPrefix + StyleConsts::GradientKey();
const std::string RoofTextureIndexKey = RoofPrefix + StyleConsts::TextureIndexKey();
const std::string RoofTextureTypeKey = RoofPrefix + StyleConsts::TextureTypeKey();
const std::string RoofTextureScaleKey = RoofPrefix + StyleConsts::TextureScaleKey();
const std::string RoofDirectionKey = RoofPrefix + StyleConsts::DirectionKey();

const std::string FacadePrefix = "facade-";
const std::string FacadeTypeKey = FacadePrefix + StyleConsts::TypeKey();
const std::string FacadeGradientKey = FacadePrefix + StyleConsts::GradientKey();
const std::string FacadeTextureIndexKey = FacadePrefix + StyleConsts::TextureIndexKey();
const std::string FacadeTextureTypeKey = FacadePrefix + StyleConsts::TextureTypeKey();
const std::string FacadeTextureScaleKey = FacadePrefix + StyleConsts::TextureScaleKey();

/// Defines roof builder which does nothing.
class EmptyRoofBuilder : public RoofBuilder {
 public:
  EmptyRoofBuilder(const BuilderContext &bc, MeshContext &mc)
      : RoofBuilder(bc, mc) {}
  void build(Polygon &) override {}
};

typedef std::function<std::unique_ptr<RoofBuilder>(const BuilderContext &, MeshContext &)> RoofBuilderFactory;
std::unordered_map<std::string, RoofBuilderFactory> RoofBuilderFactoryMap =
    {
        {
            "none",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<EmptyRoofBuilder>(builderContext, meshContext);
            }
        },
        {
            "flat",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<FlatRoofBuilder>(builderContext, meshContext);
            }
        },
        {
            "dome",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<DomeRoofBuilder>(builderContext, meshContext);
            }
        },
        {
            "pyramidal",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<PyramidalRoofBuilder>(builderContext, meshContext);
            }
        },
        {
            "mansard",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<MansardRoofBuilder>(builderContext, meshContext);
            }
        },
        {
            "skillion",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<SkillionRoofBuilder>(builderContext, meshContext);
            }
        },
        {
            "round",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<RoundRoofBuilder>(builderContext, meshContext);
            }
        }
    };

typedef std::function<std::unique_ptr<FacadeBuilder>(const BuilderContext &, MeshContext &)> FacadeBuilderFactory;
std::unordered_map<std::string, FacadeBuilderFactory> FacadeBuilderFactoryMap =
    {
        {
            "flat",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<FlatFacadeBuilder>(builderContext, meshContext);
            }
        },
        {
            "cylinder",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<CylinderFacadeBuilder>(builderContext, meshContext);
            }
        },
        {
            "sphere",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<SphereFacadeBuilder>(builderContext, meshContext);
            }
        }
    };

/// Creates points for polygon
std::vector<Vector2> toPoints(const std::vector<GeoCoordinate> &coordinates) {
  std::vector<Vector2> points;
  points.reserve(coordinates.size());
  for (const auto &coordinate : coordinates) {
    points.push_back(Vector2(coordinate.longitude, coordinate.latitude));
  }

  return std::move(points);
}

/// NOTE this method exists due to special processing of all buildings parts of the
/// one relation. In general, we want to have ability to render complex building
/// as one game object. If area/relation is already part of relation then we
/// should avoid processing it as independent element. We cannot just delete
/// element from store as it might be a part of other relation.
inline bool shouldBeIgnored(const Element &element) {
  return hasIgnore(element.tags);
}

/// Responsible for processing multipolygon relation.
class MultiPolygonVisitor final : public ElementVisitor {
 public:

  explicit MultiPolygonVisitor(Polygon &polygon) :
      polygon_(polygon) {
  }

  void visitNode(const Node &node) override { fail(node); }

  void visitWay(const Way &way) override { fail(way); }

  virtual void visitRelation(const Relation &relation) override {
    for (const auto &element : relation.elements)
      element->accept(*this);
  }

  void visitArea(const Area &area) override {
    if (!utymap::utils::isClockwise(area.coordinates))
      polygon_.addContour(toPoints(area.coordinates));
    else
      polygon_.addHole(toPoints(area.coordinates));
  }

 private:
  static void fail(const utymap::entities::Element &element) {
    throw std::domain_error("Unexpected element in multipolygon: " + utymap::utils::toString(element.id));
  }
  Polygon &polygon_;
};
}

namespace utymap {
namespace builders {

class BuildingBuilder::BuildingBuilderImpl : public ElementBuilder {
 public:
  explicit BuildingBuilderImpl(const utymap::builders::BuilderContext &context) :
      ElementBuilder(context),
      id_(0) {
  }

  void visitNode(const Node &) override {}

  void visitWay(const Way &) override {}

  void visitArea(const Area &area) override {
    Style style = context_.styleProvider.forElement(area, context_.quadKey.levelOfDetail);

    // NOTE this might happen if relation contains not a building
    if (!isBuilding(style))
      return;

    bool justCreated = ensureContext(area);
    polygon_->addContour(toPoints(area.coordinates));
    build(area, style);

    completeIfNecessary(justCreated);
  }

  void visitRelation(const Relation &relation) override {
    if (relation.elements.empty())
      return;

    bool justCreated = ensureContext(relation);

    Style style = context_.styleProvider.forElement(relation, context_.quadKey.levelOfDetail);

    if (isMultipolygon(style) && isBuilding(style)) {
      MultiPolygonVisitor visitor(*polygon_);

      for (const auto &element : relation.elements)
        element->accept(visitor);

      build(relation, style);
    } else {
      for (const auto &element : relation.elements)
        element->accept(*this);
    }

    completeIfNecessary(justCreated);
  }

 private:

  bool ensureContext(const Element &element) {
    if (polygon_==nullptr)
      polygon_ = utymap::utils::make_unique<Polygon>(1, 0);

    if (mesh_==nullptr) {
      mesh_ = utymap::utils::make_unique<Mesh>(utymap::utils::getMeshName(MeshNamePrefix, element));
      id_ = element.id;
      return true;
    }

    return false;
  }

  void completeIfNecessary(bool justCreated) {
    if (justCreated) {
      context_.meshCallback(*mesh_);
      mesh_.reset();
    }
  }

  static bool isBuilding(const Style &style) {
    return style.getString("building")=="true";
  }

  static bool isMultipolygon(const Style &style) {
    return style.getString("multipolygon")=="true";
  }

  void build(const Element &element, const Style &style) {
    auto geoCoordinate = GeoCoordinate(polygon_->points[1], polygon_->points[0]);

    double height = style.getValue(StyleConsts::HeightKey());
    // NOTE do not allow height to be zero. This might happen due to the issues in input osm data.
    if (height==0)
      height = 10;

    double minHeight = style.getValue(StyleConsts::MinHeightKey());

    double elevation = context_.eleProvider.getElevation(context_.quadKey, geoCoordinate) + minHeight;

    height -= minHeight;

    attachRoof(*mesh_, style, elevation, height);

    // NOTE so far, attach floors only for buildings with minHeight
    if (minHeight > 0)
      attachFloors(*mesh_, style, elevation, height);

    attachFacade(*mesh_, style, elevation, height);

    polygon_.reset();
  }

  void attachRoof(Mesh &mesh, const Style &style, double elevation, double height) const {
    MeshContext roofMeshContext = MeshContext::create(mesh,
                                                      style,
                                                      context_.styleProvider,
                                                      RoofGradientKey,
                                                      RoofTextureIndexKey,
                                                      RoofTextureTypeKey,
                                                      RoofTextureScaleKey,
                                                      id_);

    auto roofType = roofMeshContext.style.getString(RoofTypeKey);
    double roofHeight = roofMeshContext.style.getValue(RoofHeightKey);
    auto direction = roofMeshContext.style.getString(RoofDirectionKey);

    auto roofBuilder = RoofBuilderFactoryMap.find(roofType)->second(context_, roofMeshContext);
    roofBuilder->setHeight(roofHeight);
    roofBuilder->setMinHeight(elevation + height);
    roofBuilder->setColorNoiseFreq(0);
    roofBuilder->setDirection(direction);
    roofBuilder->build(*polygon_);

    context_.meshBuilder.writeTextureMappingInfo(mesh, roofMeshContext.appearanceOptions);
  }

  void attachFloors(Mesh &mesh, const Style &style, double elevation, double height) const {
    MeshContext floorMeshContext = MeshContext::create(mesh,
                                                       style,
                                                       context_.styleProvider,
                                                       RoofGradientKey,
                                                       RoofTextureIndexKey,
                                                       RoofTextureTypeKey,
                                                       RoofTextureScaleKey,
                                                       id_);

    FlatRoofBuilder floorBuilder(context_, floorMeshContext);
    floorBuilder.setMinHeight(elevation);
    floorBuilder.setColorNoiseFreq(0);
    floorBuilder.flipSide();
    floorBuilder.build(*polygon_);

    context_.meshBuilder.writeTextureMappingInfo(mesh, floorMeshContext.appearanceOptions);
  }

  void attachFacade(Mesh &mesh, const Style &style, double elevation, double height) const {
    MeshContext facadeMeshContext = MeshContext::create(mesh,
                                                        style,
                                                        context_.styleProvider,
                                                        FacadeGradientKey,
                                                        FacadeTextureIndexKey,
                                                        FacadeTextureTypeKey,
                                                        FacadeTextureScaleKey,
                                                        id_);

    auto facadeType = facadeMeshContext.style.getString(FacadeTypeKey);
    auto facadeBuilder = FacadeBuilderFactoryMap.find(facadeType)->second(context_, facadeMeshContext);

    facadeBuilder->setHeight(height);
    facadeBuilder->setMinHeight(elevation);
    facadeBuilder->setColorNoiseFreq(0);
    facadeBuilder->build(*polygon_);

    context_.meshBuilder.writeTextureMappingInfo(mesh, facadeMeshContext.appearanceOptions);
  }

  std::unique_ptr<Polygon> polygon_;
  std::unique_ptr<Mesh> mesh_;
  std::uint64_t id_;
};

BuildingBuilder::BuildingBuilder(const BuilderContext &context)
    : ElementBuilder(context), pimpl_(utymap::utils::make_unique<BuildingBuilderImpl>(context)) {
}

BuildingBuilder::~BuildingBuilder() {}

void BuildingBuilder::visitArea(const Area &area) {
  if (!shouldBeIgnored(area))
    area.accept(*pimpl_);
}

void BuildingBuilder::visitRelation(const Relation &relation) {
  if (!shouldBeIgnored(relation))
    relation.accept(*pimpl_);
}

}
}
<commit_msg>core: use mesh bool in building builder<commit_after>#include "GeoCoordinate.hpp"
#include "builders/MeshContext.hpp"
#include "entities/Node.hpp"
#include "entities/Way.hpp"
#include "entities/Area.hpp"
#include "entities/Relation.hpp"
#include "builders/buildings/BuildingBuilder.hpp"
#include "builders/buildings/facades/CylinderFacadeBuilder.hpp"
#include "builders/buildings/facades/FlatFacadeBuilder.hpp"
#include "builders/buildings/facades/SphereFacadeBuilder.hpp"
#include "builders/buildings/roofs/DomeRoofBuilder.hpp"
#include "builders/buildings/roofs/FlatRoofBuilder.hpp"
#include "builders/buildings/roofs/PyramidalRoofBuilder.hpp"
#include "builders/buildings/roofs/MansardRoofBuilder.hpp"
#include "builders/buildings/roofs/SkillionRoofBuilder.hpp"
#include "builders/buildings/roofs/RoundRoofBuilder.hpp"

using namespace utymap;
using namespace utymap::builders;
using namespace utymap::entities;
using namespace utymap::heightmap;
using namespace utymap::mapcss;
using namespace utymap::math;
using namespace utymap::index;
using namespace utymap::utils;

namespace {
const std::string MeshNamePrefix = "building:";

const std::string RoofPrefix = "roof-";
const std::string RoofTypeKey = RoofPrefix + StyleConsts::TypeKey();
const std::string RoofHeightKey = RoofPrefix + StyleConsts::HeightKey();
const std::string RoofGradientKey = RoofPrefix + StyleConsts::GradientKey();
const std::string RoofTextureIndexKey = RoofPrefix + StyleConsts::TextureIndexKey();
const std::string RoofTextureTypeKey = RoofPrefix + StyleConsts::TextureTypeKey();
const std::string RoofTextureScaleKey = RoofPrefix + StyleConsts::TextureScaleKey();
const std::string RoofDirectionKey = RoofPrefix + StyleConsts::DirectionKey();

const std::string FacadePrefix = "facade-";
const std::string FacadeTypeKey = FacadePrefix + StyleConsts::TypeKey();
const std::string FacadeGradientKey = FacadePrefix + StyleConsts::GradientKey();
const std::string FacadeTextureIndexKey = FacadePrefix + StyleConsts::TextureIndexKey();
const std::string FacadeTextureTypeKey = FacadePrefix + StyleConsts::TextureTypeKey();
const std::string FacadeTextureScaleKey = FacadePrefix + StyleConsts::TextureScaleKey();

/// Defines roof builder which does nothing.
class EmptyRoofBuilder : public RoofBuilder {
 public:
  EmptyRoofBuilder(const BuilderContext &bc, MeshContext &mc)
      : RoofBuilder(bc, mc) {}
  void build(Polygon &) override {}
};

typedef std::function<std::unique_ptr<RoofBuilder>(const BuilderContext &, MeshContext &)> RoofBuilderFactory;
std::unordered_map<std::string, RoofBuilderFactory> RoofBuilderFactoryMap =
    {
        {
            "none",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<EmptyRoofBuilder>(builderContext, meshContext);
            }
        },
        {
            "flat",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<FlatRoofBuilder>(builderContext, meshContext);
            }
        },
        {
            "dome",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<DomeRoofBuilder>(builderContext, meshContext);
            }
        },
        {
            "pyramidal",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<PyramidalRoofBuilder>(builderContext, meshContext);
            }
        },
        {
            "mansard",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<MansardRoofBuilder>(builderContext, meshContext);
            }
        },
        {
            "skillion",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<SkillionRoofBuilder>(builderContext, meshContext);
            }
        },
        {
            "round",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<RoundRoofBuilder>(builderContext, meshContext);
            }
        }
    };

typedef std::function<std::unique_ptr<FacadeBuilder>(const BuilderContext &, MeshContext &)> FacadeBuilderFactory;
std::unordered_map<std::string, FacadeBuilderFactory> FacadeBuilderFactoryMap =
    {
        {
            "flat",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<FlatFacadeBuilder>(builderContext, meshContext);
            }
        },
        {
            "cylinder",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<CylinderFacadeBuilder>(builderContext, meshContext);
            }
        },
        {
            "sphere",
            [](const BuilderContext &builderContext, MeshContext &meshContext) {
              return utymap::utils::make_unique<SphereFacadeBuilder>(builderContext, meshContext);
            }
        }
    };

/// Creates points for polygon
std::vector<Vector2> toPoints(const std::vector<GeoCoordinate> &coordinates) {
  std::vector<Vector2> points;
  points.reserve(coordinates.size());
  for (const auto &coordinate : coordinates) {
    points.push_back(Vector2(coordinate.longitude, coordinate.latitude));
  }

  return std::move(points);
}

/// NOTE this method exists due to special processing of all buildings parts of the
/// one relation. In general, we want to have ability to render complex building
/// as one game object. If area/relation is already part of relation then we
/// should avoid processing it as independent element. We cannot just delete
/// element from store as it might be a part of other relation.
inline bool shouldBeIgnored(const Element &element) {
  return hasIgnore(element.tags);
}

/// Responsible for processing multipolygon relation.
class MultiPolygonVisitor final : public ElementVisitor {
 public:

  explicit MultiPolygonVisitor(Polygon &polygon) :
      polygon_(polygon) {
  }

  void visitNode(const Node &node) override { fail(node); }

  void visitWay(const Way &way) override { fail(way); }

  virtual void visitRelation(const Relation &relation) override {
    for (const auto &element : relation.elements)
      element->accept(*this);
  }

  void visitArea(const Area &area) override {
    if (!utymap::utils::isClockwise(area.coordinates))
      polygon_.addContour(toPoints(area.coordinates));
    else
      polygon_.addHole(toPoints(area.coordinates));
  }

 private:
  static void fail(const utymap::entities::Element &element) {
    throw std::domain_error("Unexpected element in multipolygon: " + utymap::utils::toString(element.id));
  }
  Polygon &polygon_;
};
}

namespace utymap {
namespace builders {

class BuildingBuilder::BuildingBuilderImpl : public ElementBuilder {
 public:
  explicit BuildingBuilderImpl(const utymap::builders::BuilderContext &context) :
      ElementBuilder(context),
      id_(0) {
  }

  void visitNode(const Node &) override {}

  void visitWay(const Way &) override {}

  void visitArea(const Area &area) override {
    Style style = context_.styleProvider.forElement(area, context_.quadKey.levelOfDetail);

    // NOTE this might happen if relation contains not a building
    if (!isBuilding(style))
      return;

    bool justCreated = ensureContext(area);
    polygon_->addContour(toPoints(area.coordinates));
    build(area, style);

    completeIfNecessary(justCreated);
  }

  void visitRelation(const Relation &relation) override {
    if (relation.elements.empty())
      return;

    bool justCreated = ensureContext(relation);

    Style style = context_.styleProvider.forElement(relation, context_.quadKey.levelOfDetail);

    if (isMultipolygon(style) && isBuilding(style)) {
      MultiPolygonVisitor visitor(*polygon_);

      for (const auto &element : relation.elements)
        element->accept(visitor);

      build(relation, style);
    } else {
      for (const auto &element : relation.elements)
        element->accept(*this);
    }

    completeIfNecessary(justCreated);
  }

 private:

  bool ensureContext(const Element &element) {
    if (polygon_==nullptr)
      polygon_ = utymap::utils::make_unique<Polygon>(1, 0);

    if (mesh_==nullptr) {
      auto mesh = context_.meshPool.getSmall(utymap::utils::getMeshName(MeshNamePrefix, element));
      mesh_ = std::unique_ptr<Mesh>(new Mesh(std::move(mesh)));
      id_ = element.id;
      return true;
    }

    return false;
  }

  void completeIfNecessary(bool justCreated) {
    if (justCreated) {
      context_.meshCallback(*mesh_);
      context_.meshPool.release(std::move(*mesh_));
      mesh_.reset();
    }
  }

  static bool isBuilding(const Style &style) {
    return style.getString("building")=="true";
  }

  static bool isMultipolygon(const Style &style) {
    return style.getString("multipolygon")=="true";
  }

  void build(const Element &element, const Style &style) {
    auto geoCoordinate = GeoCoordinate(polygon_->points[1], polygon_->points[0]);

    double height = style.getValue(StyleConsts::HeightKey());
    // NOTE do not allow height to be zero. This might happen due to the issues in input osm data.
    if (height==0)
      height = 10;

    double minHeight = style.getValue(StyleConsts::MinHeightKey());

    double elevation = context_.eleProvider.getElevation(context_.quadKey, geoCoordinate) + minHeight;

    height -= minHeight;

    attachRoof(*mesh_, style, elevation, height);

    // NOTE so far, attach floors only for buildings with minHeight
    if (minHeight > 0)
      attachFloors(*mesh_, style, elevation, height);

    attachFacade(*mesh_, style, elevation, height);

    polygon_.reset();
  }

  void attachRoof(Mesh &mesh, const Style &style, double elevation, double height) const {
    MeshContext roofMeshContext = MeshContext::create(mesh,
                                                      style,
                                                      context_.styleProvider,
                                                      RoofGradientKey,
                                                      RoofTextureIndexKey,
                                                      RoofTextureTypeKey,
                                                      RoofTextureScaleKey,
                                                      id_);

    auto roofType = roofMeshContext.style.getString(RoofTypeKey);
    double roofHeight = roofMeshContext.style.getValue(RoofHeightKey);
    auto direction = roofMeshContext.style.getString(RoofDirectionKey);

    auto roofBuilder = RoofBuilderFactoryMap.find(roofType)->second(context_, roofMeshContext);
    roofBuilder->setHeight(roofHeight);
    roofBuilder->setMinHeight(elevation + height);
    roofBuilder->setColorNoiseFreq(0);
    roofBuilder->setDirection(direction);
    roofBuilder->build(*polygon_);

    context_.meshBuilder.writeTextureMappingInfo(mesh, roofMeshContext.appearanceOptions);
  }

  void attachFloors(Mesh &mesh, const Style &style, double elevation, double height) const {
    MeshContext floorMeshContext = MeshContext::create(mesh,
                                                       style,
                                                       context_.styleProvider,
                                                       RoofGradientKey,
                                                       RoofTextureIndexKey,
                                                       RoofTextureTypeKey,
                                                       RoofTextureScaleKey,
                                                       id_);

    FlatRoofBuilder floorBuilder(context_, floorMeshContext);
    floorBuilder.setMinHeight(elevation);
    floorBuilder.setColorNoiseFreq(0);
    floorBuilder.flipSide();
    floorBuilder.build(*polygon_);

    context_.meshBuilder.writeTextureMappingInfo(mesh, floorMeshContext.appearanceOptions);
  }

  void attachFacade(Mesh &mesh, const Style &style, double elevation, double height) const {
    MeshContext facadeMeshContext = MeshContext::create(mesh,
                                                        style,
                                                        context_.styleProvider,
                                                        FacadeGradientKey,
                                                        FacadeTextureIndexKey,
                                                        FacadeTextureTypeKey,
                                                        FacadeTextureScaleKey,
                                                        id_);

    auto facadeType = facadeMeshContext.style.getString(FacadeTypeKey);
    auto facadeBuilder = FacadeBuilderFactoryMap.find(facadeType)->second(context_, facadeMeshContext);

    facadeBuilder->setHeight(height);
    facadeBuilder->setMinHeight(elevation);
    facadeBuilder->setColorNoiseFreq(0);
    facadeBuilder->build(*polygon_);

    context_.meshBuilder.writeTextureMappingInfo(mesh, facadeMeshContext.appearanceOptions);
  }

  std::unique_ptr<Polygon> polygon_;
  std::unique_ptr<Mesh> mesh_;
  std::uint64_t id_;
};

BuildingBuilder::BuildingBuilder(const BuilderContext &context)
    : ElementBuilder(context), pimpl_(utymap::utils::make_unique<BuildingBuilderImpl>(context)) {
}

BuildingBuilder::~BuildingBuilder() {}

void BuildingBuilder::visitArea(const Area &area) {
  if (!shouldBeIgnored(area))
    area.accept(*pimpl_);
}

void BuildingBuilder::visitRelation(const Relation &relation) {
  if (!shouldBeIgnored(relation))
    relation.accept(*pimpl_);
}

}
}
<|endoftext|>