<commit_before>#include <geometry_msgs/Quaternion.h>
#include <ros/ros.h>
#include <serial/serial.h>
#include <sensor_msgs/Imu.h>
#include <std_msgs/String.h>
#include <std_srvs/Empty.h>
#include <string>
#include <tf/transform_broadcaster.h>
#include <tf/transform_datatypes.h>

bool zero_orientation_set = false;

bool set_zero_orientation(std_srvs::Empty::Request&,
                          std_srvs::Empty::Response&)
{
  ROS_INFO("Zero Orientation Set.");
  zero_orientation_set = false;
  return true;
}

int main(int argc, char** argv)
{
  serial::Serial ser;
  std::string port;
  std::string tf_parent_frame_id;
  std::string tf_frame_id;
  std::string frame_id;
  double time_offset_in_seconds;
  bool broadcast_tf;
  double linear_acceleration_stddev;
  double angular_velocity_stddev;
  double orientation_stddev;
  uint8_t last_received_message_number;
  bool received_message = false;
  int data_packet_start;

  tf::Quaternion orientation;
  tf::Quaternion zero_orientation;

  ros::init(argc, argv, "mpu6050_serial_to_imu_node");

  ros::NodeHandle private_node_handle("~");
  private_node_handle.param<std::string>("port", port, "/dev/ttyACM0");
  private_node_handle.param<std::string>("tf_parent_frame_id", tf_parent_frame_id, "imu_base");
  private_node_handle.param<std::string>("tf_frame_id", tf_frame_id, "imu_link");
  private_node_handle.param<std::string>("frame_id", frame_id, "imu_link");
  private_node_handle.param<double>("time_offset_in_seconds", time_offset_in_seconds, 0.0);
  private_node_handle.param<bool>("broadcast_tf", broadcast_tf, true);
  private_node_handle.param<double>("linear_acceleration_stddev", linear_acceleration_stddev, 0.0);
  private_node_handle.param<double>("angular_velocity_stddev", angular_velocity_stddev, 0.0);
  private_node_handle.param<double>("orientation_stddev", orientation_stddev, 0.0);

  ros::NodeHandle nh("imu");
  ros::Publisher imu_pub = nh.advertise<sensor_msgs::Imu>("data", 50);
  ros::ServiceServer service = nh.advertiseService("set_zero_orientation", set_zero_orientation);

  ros::Rate r(1000); // 1000 hz

  sensor_msgs::Imu imu;

  imu.linear_acceleration_covariance[0] = linear_acceleration_stddev;
  imu.linear_acceleration_covariance[4] = linear_acceleration_stddev;
  imu.linear_acceleration_covariance[8] = linear_acceleration_stddev;

  imu.angular_velocity_covariance[0] = angular_velocity_stddev;
  imu.angular_velocity_covariance[4] = angular_velocity_stddev;
  imu.angular_velocity_covariance[8] = angular_velocity_stddev;

  imu.orientation_covariance[0] = orientation_stddev;
  imu.orientation_covariance[4] = orientation_stddev;
  imu.orientation_covariance[8] = orientation_stddev;

  std::string input;
  std::string read;

  while(ros::ok())
  {
    try
    {
      if (ser.isOpen())
      {
        // read string from serial device
        if(ser.available())
        {
          read = ser.read(ser.available());
          ROS_DEBUG("read %i new characters from serial port, adding to %i characters of old input.", (int)read.size(), (int)input.size());
          input += read;
          while (input.length() >= 26) // while there might be a complete package in input
          {
            //parse for data packets
            data_packet_start = input.find("$\x03");
            if (data_packet_start != std::string::npos)
            {
              ROS_DEBUG("found possible start of data packet at position %d", data_packet_start);
              if ((input.length() >= data_packet_start + 26) && (input.compare(data_packet_start + 24, 2, "\n\r")))  //check if positions 24,25 exist, then test values
              {
                ROS_DEBUG("seems to be a real data package: long enough and found end characters");
                // get quaternion values
                int16_t w = (((0xff &(char)input[data_packet_start + 2]) << 8) | 0xff &(char)input[data_packet_start + 3]);
                int16_t x = (((0xff &(char)input[data_packet_start + 4]) << 8) | 0xff &(char)input[data_packet_start + 5]);
                int16_t y = (((0xff &(char)input[data_packet_start + 6]) << 8) | 0xff &(char)input[data_packet_start + 7]);
                int16_t z = (((0xff &(char)input[data_packet_start + 8]) << 8) | 0xff &(char)input[data_packet_start + 9]);

                double wf = w/16384.0;
                double xf = x/16384.0;
                double yf = y/16384.0;
                double zf = z/16384.0;

                tf::Quaternion orientation(xf, yf, zf, wf);

                if (!zero_orientation_set)
                {
                  zero_orientation = orientation;
                  zero_orientation_set = true;
                }

                //http://answers.ros.org/question/10124/relative-rotation-between-two-quaternions/
                tf::Quaternion differential_rotation;
                differential_rotation = zero_orientation.inverse() * orientation;

                // get gyro values
                int16_t gx = (((0xff &(char)input[data_packet_start + 10]) << 8) | 0xff &(char)input[data_packet_start + 11]);
                int16_t gy = (((0xff &(char)input[data_packet_start + 12]) << 8) | 0xff &(char)input[data_packet_start + 13]);
                int16_t gz = (((0xff &(char)input[data_packet_start + 14]) << 8) | 0xff &(char)input[data_packet_start + 15]);
                // calculate rotational velocities in rad/s
                // without the last factor the velocities were too small
                // http://www.i2cdevlib.com/forums/topic/106-get-angular-velocity-from-mpu-6050/
                // FIFO frequency 100 Hz -> factor 10
                //TODO: check / test if rotational velocities are correct
                double gxf = gx * (4000.0/65536.0) * (M_PI/180.0) * 10.0;
                double gyf = gy * (4000.0/65536.0) * (M_PI/180.0) * 10.0;
                double gzf = gz * (4000.0/65536.0) * (M_PI/180.0) * 10.0;

                // get acelerometer values
                int16_t ax = (((0xff &(char)input[data_packet_start + 16]) << 8) | 0xff &(char)input[data_packet_start + 17]);
                int16_t ay = (((0xff &(char)input[data_packet_start + 18]) << 8) | 0xff &(char)input[data_packet_start + 19]);
                int16_t az = (((0xff &(char)input[data_packet_start + 20]) << 8) | 0xff &(char)input[data_packet_start + 21]);
                // calculate accelerations in m/s²
                double axf = ax * (8.0 / 65536.0) * 9.81;
                double ayf = ay * (8.0 / 65536.0) * 9.81;
                double azf = az * (8.0 / 65536.0) * 9.81;

                uint8_t received_message_number = input[data_packet_start + 23];
                ROS_DEBUG("received message number: %i", received_message_number);

                if (received_message) // can only check for continuous numbers if already received at least one packet
                {
                  uint8_t message_distance = received_message_number - last_received_message_number;
                  if ( message_distance > 1 )
                  {
                    ROS_WARN_STREAM("Missed " << message_distance - 1 << " MPU6050 data packets from arduino.");
                  }
                }
                else
                {
                  received_message = true;
                }
                last_received_message_number = received_message_number;

                // calculate measurement time
                ros::Time measurement_time = ros::Time::now() + ros::Duration(time_offset_in_seconds);

                // publish imu message
                imu.header.stamp = measurement_time;
                imu.header.frame_id = frame_id;

                quaternionTFToMsg(differential_rotation, imu.orientation);

                imu.angular_velocity.x = gxf;
                imu.angular_velocity.y = gyf;
                imu.angular_velocity.z = gzf;

                imu.linear_acceleration.x = axf;
                imu.linear_acceleration.y = ayf;
                imu.linear_acceleration.z = azf;

                imu_pub.publish(imu);

                // publish tf transform
                if (broadcast_tf)
                {
                  static tf::TransformBroadcaster br;
                  tf::Transform transform;
                  transform.setRotation(differential_rotation);
                  br.sendTransform(tf::StampedTransform(transform, measurement_time, tf_parent_frame_id, tf_frame_id));
                }
                input.erase(0, data_packet_start + 26); // delete everything up to and including the processed packet
              }
              else
              {
                if (input.length() >= data_packet_start + 26)
                {
                  input.erase(0, data_packet_start + 1); // delete up to false data_packet_start character so it is not found again
                }
                else
                {
                  // do not delete start character, maybe complete package has not arrived yet
                  input.erase(0, data_packet_start);
                }
              }
            }
            else
            {
              // no start character found in input, so delete everything
              input.clear();
            }
          }
        }
      }
      else
      {
        // try and open the serial port
        try
        {
          ser.setPort(port);
          ser.setBaudrate(115200);
          serial::Timeout to = serial::Timeout::simpleTimeout(1000);
          ser.setTimeout(to);
          ser.open();
        }
        catch (serial::IOException& e)
        {
          ROS_ERROR_STREAM("Unable to open serial port " << ser.getPort() << ". Trying again in 5 seconds.");
          ros::Duration(5).sleep();
        }

        if(ser.isOpen())
        {
          ROS_DEBUG_STREAM("Serial port " << ser.getPort() << " initialized and opened.");
        }
      }
    }
    catch (serial::IOException& e)
    {
      ROS_ERROR_STREAM("Error reading from the serial port " << ser.getPort() << ". Closing connection.");
      ser.close();
    }
    ros::spinOnce();
    r.sleep();
  }
}
<commit_msg>lowered rosnode frequency<commit_after>#include <geometry_msgs/Quaternion.h>
#include <ros/ros.h>
#include <serial/serial.h>
#include <sensor_msgs/Imu.h>
#include <std_msgs/String.h>
#include <std_srvs/Empty.h>
#include <string>
#include <tf/transform_broadcaster.h>
#include <tf/transform_datatypes.h>

bool zero_orientation_set = false;

bool set_zero_orientation(std_srvs::Empty::Request&,
                          std_srvs::Empty::Response&)
{
  ROS_INFO("Zero Orientation Set.");
  zero_orientation_set = false;
  return true;
}

int main(int argc, char** argv)
{
  serial::Serial ser;
  std::string port;
  std::string tf_parent_frame_id;
  std::string tf_frame_id;
  std::string frame_id;
  double time_offset_in_seconds;
  bool broadcast_tf;
  double linear_acceleration_stddev;
  double angular_velocity_stddev;
  double orientation_stddev;
  uint8_t last_received_message_number;
  bool received_message = false;
  int data_packet_start;

  tf::Quaternion orientation;
  tf::Quaternion zero_orientation;

  ros::init(argc, argv, "mpu6050_serial_to_imu_node");

  ros::NodeHandle private_node_handle("~");
  private_node_handle.param<std::string>("port", port, "/dev/ttyACM0");
  private_node_handle.param<std::string>("tf_parent_frame_id", tf_parent_frame_id, "imu_base");
  private_node_handle.param<std::string>("tf_frame_id", tf_frame_id, "imu_link");
  private_node_handle.param<std::string>("frame_id", frame_id, "imu_link");
  private_node_handle.param<double>("time_offset_in_seconds", time_offset_in_seconds, 0.0);
  private_node_handle.param<bool>("broadcast_tf", broadcast_tf, true);
  private_node_handle.param<double>("linear_acceleration_stddev", linear_acceleration_stddev, 0.0);
  private_node_handle.param<double>("angular_velocity_stddev", angular_velocity_stddev, 0.0);
  private_node_handle.param<double>("orientation_stddev", orientation_stddev, 0.0);

  ros::NodeHandle nh("imu");
  ros::Publisher imu_pub = nh.advertise<sensor_msgs::Imu>("data", 50);
  ros::ServiceServer service = nh.advertiseService("set_zero_orientation", set_zero_orientation);

  ros::Rate r(200); // 200 hz

  sensor_msgs::Imu imu;

  imu.linear_acceleration_covariance[0] = linear_acceleration_stddev;
  imu.linear_acceleration_covariance[4] = linear_acceleration_stddev;
  imu.linear_acceleration_covariance[8] = linear_acceleration_stddev;

  imu.angular_velocity_covariance[0] = angular_velocity_stddev;
  imu.angular_velocity_covariance[4] = angular_velocity_stddev;
  imu.angular_velocity_covariance[8] = angular_velocity_stddev;

  imu.orientation_covariance[0] = orientation_stddev;
  imu.orientation_covariance[4] = orientation_stddev;
  imu.orientation_covariance[8] = orientation_stddev;

  std::string input;
  std::string read;

  while(ros::ok())
  {
    try
    {
      if (ser.isOpen())
      {
        // read string from serial device
        if(ser.available())
        {
          read = ser.read(ser.available());
          ROS_DEBUG("read %i new characters from serial port, adding to %i characters of old input.", (int)read.size(), (int)input.size());
          input += read;
          while (input.length() >= 26) // while there might be a complete package in input
          {
            //parse for data packets
            data_packet_start = input.find("$\x03");
            if (data_packet_start != std::string::npos)
            {
              ROS_DEBUG("found possible start of data packet at position %d", data_packet_start);
              if ((input.length() >= data_packet_start + 26) && (input.compare(data_packet_start + 24, 2, "\n\r")))  //check if positions 24,25 exist, then test values
              {
                ROS_DEBUG("seems to be a real data package: long enough and found end characters");
                // get quaternion values
                int16_t w = (((0xff &(char)input[data_packet_start + 2]) << 8) | 0xff &(char)input[data_packet_start + 3]);
                int16_t x = (((0xff &(char)input[data_packet_start + 4]) << 8) | 0xff &(char)input[data_packet_start + 5]);
                int16_t y = (((0xff &(char)input[data_packet_start + 6]) << 8) | 0xff &(char)input[data_packet_start + 7]);
                int16_t z = (((0xff &(char)input[data_packet_start + 8]) << 8) | 0xff &(char)input[data_packet_start + 9]);

                double wf = w/16384.0;
                double xf = x/16384.0;
                double yf = y/16384.0;
                double zf = z/16384.0;

                tf::Quaternion orientation(xf, yf, zf, wf);

                if (!zero_orientation_set)
                {
                  zero_orientation = orientation;
                  zero_orientation_set = true;
                }

                //http://answers.ros.org/question/10124/relative-rotation-between-two-quaternions/
                tf::Quaternion differential_rotation;
                differential_rotation = zero_orientation.inverse() * orientation;

                // get gyro values
                int16_t gx = (((0xff &(char)input[data_packet_start + 10]) << 8) | 0xff &(char)input[data_packet_start + 11]);
                int16_t gy = (((0xff &(char)input[data_packet_start + 12]) << 8) | 0xff &(char)input[data_packet_start + 13]);
                int16_t gz = (((0xff &(char)input[data_packet_start + 14]) << 8) | 0xff &(char)input[data_packet_start + 15]);
                // calculate rotational velocities in rad/s
                // without the last factor the velocities were too small
                // http://www.i2cdevlib.com/forums/topic/106-get-angular-velocity-from-mpu-6050/
                // FIFO frequency 100 Hz -> factor 10
                //TODO: check / test if rotational velocities are correct
                double gxf = gx * (4000.0/65536.0) * (M_PI/180.0) * 10.0;
                double gyf = gy * (4000.0/65536.0) * (M_PI/180.0) * 10.0;
                double gzf = gz * (4000.0/65536.0) * (M_PI/180.0) * 10.0;

                // get acelerometer values
                int16_t ax = (((0xff &(char)input[data_packet_start + 16]) << 8) | 0xff &(char)input[data_packet_start + 17]);
                int16_t ay = (((0xff &(char)input[data_packet_start + 18]) << 8) | 0xff &(char)input[data_packet_start + 19]);
                int16_t az = (((0xff &(char)input[data_packet_start + 20]) << 8) | 0xff &(char)input[data_packet_start + 21]);
                // calculate accelerations in m/s²
                double axf = ax * (8.0 / 65536.0) * 9.81;
                double ayf = ay * (8.0 / 65536.0) * 9.81;
                double azf = az * (8.0 / 65536.0) * 9.81;

                uint8_t received_message_number = input[data_packet_start + 23];
                ROS_DEBUG("received message number: %i", received_message_number);

                if (received_message) // can only check for continuous numbers if already received at least one packet
                {
                  uint8_t message_distance = received_message_number - last_received_message_number;
                  if ( message_distance > 1 )
                  {
                    ROS_WARN_STREAM("Missed " << message_distance - 1 << " MPU6050 data packets from arduino.");
                  }
                }
                else
                {
                  received_message = true;
                }
                last_received_message_number = received_message_number;

                // calculate measurement time
                ros::Time measurement_time = ros::Time::now() + ros::Duration(time_offset_in_seconds);

                // publish imu message
                imu.header.stamp = measurement_time;
                imu.header.frame_id = frame_id;

                quaternionTFToMsg(differential_rotation, imu.orientation);

                imu.angular_velocity.x = gxf;
                imu.angular_velocity.y = gyf;
                imu.angular_velocity.z = gzf;

                imu.linear_acceleration.x = axf;
                imu.linear_acceleration.y = ayf;
                imu.linear_acceleration.z = azf;

                imu_pub.publish(imu);

                // publish tf transform
                if (broadcast_tf)
                {
                  static tf::TransformBroadcaster br;
                  tf::Transform transform;
                  transform.setRotation(differential_rotation);
                  br.sendTransform(tf::StampedTransform(transform, measurement_time, tf_parent_frame_id, tf_frame_id));
                }
                input.erase(0, data_packet_start + 26); // delete everything up to and including the processed packet
              }
              else
              {
                if (input.length() >= data_packet_start + 26)
                {
                  input.erase(0, data_packet_start + 1); // delete up to false data_packet_start character so it is not found again
                }
                else
                {
                  // do not delete start character, maybe complete package has not arrived yet
                  input.erase(0, data_packet_start);
                }
              }
            }
            else
            {
              // no start character found in input, so delete everything
              input.clear();
            }
          }
        }
      }
      else
      {
        // try and open the serial port
        try
        {
          ser.setPort(port);
          ser.setBaudrate(115200);
          serial::Timeout to = serial::Timeout::simpleTimeout(1000);
          ser.setTimeout(to);
          ser.open();
        }
        catch (serial::IOException& e)
        {
          ROS_ERROR_STREAM("Unable to open serial port " << ser.getPort() << ". Trying again in 5 seconds.");
          ros::Duration(5).sleep();
        }

        if(ser.isOpen())
        {
          ROS_DEBUG_STREAM("Serial port " << ser.getPort() << " initialized and opened.");
        }
      }
    }
    catch (serial::IOException& e)
    {
      ROS_ERROR_STREAM("Error reading from the serial port " << ser.getPort() << ". Closing connection.");
      ser.close();
    }
    ros::spinOnce();
    r.sleep();
  }
}
<|endoftext|>


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

#include "config.h"

#include <stdio.h>

#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include "sqlite3.h"

#include "auto_mem.hh"
#include "vtab_module.hh"
#include "sqlite-extension-func.hh"

using namespace std;

static string sql_gethostbyname(const char *name_in)
{
    char             buffer[INET6_ADDRSTRLEN];
    auto_mem<struct addrinfo> ai(freeaddrinfo);
    struct addrinfo hints = { 0 };
    void *           addr_ptr = NULL;
    int rc;

    hints.ai_flags = AI_DEFAULT;
    while ((rc = getaddrinfo(name_in, NULL, &hints, ai.out())) == EAI_AGAIN) {
        sqlite3_sleep(10);
    }
    if (rc != 0) {
        return name_in;
    }

    switch (ai.in()->ai_family) {
    case AF_INET:
        addr_ptr = &((struct sockaddr_in *)ai.in()->ai_addr)->sin_addr;
        break;

    case AF_INET6:
        addr_ptr = &((struct sockaddr_in6 *)ai.in()->ai_addr)->sin6_addr;
        break;

    default:
        return name_in;
    }

    inet_ntop(ai.in()->ai_family, addr_ptr, buffer, sizeof(buffer));

    return buffer;
}

static string sql_gethostbyaddr(const char *addr_str)
{
    union {
        struct sockaddr_in  sin;
        struct sockaddr_in6 sin6;
    }           sa;
    char        buffer[NI_MAXHOST];
    int         family, socklen;
    char *      addr_raw;
    int         rc;

    memset(&sa, 0, sizeof(sa));
    if (strchr(addr_str, ':')) {
        family              = AF_INET6;
        socklen             = sizeof(struct sockaddr_in6);
        sa.sin6.sin6_family = family;
        addr_raw            = (char *)&sa.sin6.sin6_addr;
    }
    else {
        family            = AF_INET;
        socklen           = sizeof(struct sockaddr_in);
        sa.sin.sin_family = family;
        addr_raw          = (char *)&sa.sin.sin_addr;
    }

    if (inet_pton(family, addr_str, addr_raw) != 1) {
        return addr_str;
    }

    while ((rc = getnameinfo((struct sockaddr *)&sa, socklen,
                             buffer, sizeof(buffer), NULL, 0,
                             0)) == EAI_AGAIN) {
        sqlite3_sleep(10);
    }

    if (rc != 0) {
        return addr_str;
    }

    return buffer;
}

int network_extension_functions(struct FuncDef **basic_funcs,
                                struct FuncDefAgg **agg_funcs)
{
    static struct FuncDef network_funcs[] = {
        sqlite_func_adapter<decltype(&sql_gethostbyname), sql_gethostbyname>::builder(
            help_text("gethostbyname",
                      "Get the IP address for the given hostname")
                .sql_function()
                .with_parameter({"hostname", "The DNS hostname to lookup."})
                .with_example({"SELECT gethostbyname('localhost')"})
        ),

        sqlite_func_adapter<decltype(&sql_gethostbyaddr), sql_gethostbyaddr>::builder(
            help_text("gethostbyaddr",
                      "Get the IP address for the given hostname")
                .sql_function()
                .with_parameter({"hostname", "The DNS hostname to lookup."})
                .with_example({"SELECT gethostbyaddr('127.0.0.1')"})
        ),

        { NULL }
    };

    *basic_funcs = network_funcs;

    return SQLITE_OK;
}
<commit_msg>[build] don't pass hints to getaddrinfo<commit_after>/**
 * Copyright (c) 2013, Timothy Stack
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @file nextwork-extension-functions.cc
 */

#include "config.h"

#include <stdio.h>

#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include "sqlite3.h"

#include "auto_mem.hh"
#include "vtab_module.hh"
#include "sqlite-extension-func.hh"

using namespace std;

static string sql_gethostbyname(const char *name_in)
{
    char             buffer[INET6_ADDRSTRLEN];
    auto_mem<struct addrinfo> ai(freeaddrinfo);
    void *           addr_ptr = NULL;
    int rc;

    while ((rc = getaddrinfo(name_in, NULL, NULL, ai.out())) == EAI_AGAIN) {
        sqlite3_sleep(10);
    }
    if (rc != 0) {
        return name_in;
    }

    switch (ai.in()->ai_family) {
    case AF_INET:
        addr_ptr = &((struct sockaddr_in *)ai.in()->ai_addr)->sin_addr;
        break;

    case AF_INET6:
        addr_ptr = &((struct sockaddr_in6 *)ai.in()->ai_addr)->sin6_addr;
        break;

    default:
        return name_in;
    }

    inet_ntop(ai.in()->ai_family, addr_ptr, buffer, sizeof(buffer));

    return buffer;
}

static string sql_gethostbyaddr(const char *addr_str)
{
    union {
        struct sockaddr_in  sin;
        struct sockaddr_in6 sin6;
    }           sa;
    char        buffer[NI_MAXHOST];
    int         family, socklen;
    char *      addr_raw;
    int         rc;

    memset(&sa, 0, sizeof(sa));
    if (strchr(addr_str, ':')) {
        family              = AF_INET6;
        socklen             = sizeof(struct sockaddr_in6);
        sa.sin6.sin6_family = family;
        addr_raw            = (char *)&sa.sin6.sin6_addr;
    }
    else {
        family            = AF_INET;
        socklen           = sizeof(struct sockaddr_in);
        sa.sin.sin_family = family;
        addr_raw          = (char *)&sa.sin.sin_addr;
    }

    if (inet_pton(family, addr_str, addr_raw) != 1) {
        return addr_str;
    }

    while ((rc = getnameinfo((struct sockaddr *)&sa, socklen,
                             buffer, sizeof(buffer), NULL, 0,
                             0)) == EAI_AGAIN) {
        sqlite3_sleep(10);
    }

    if (rc != 0) {
        return addr_str;
    }

    return buffer;
}

int network_extension_functions(struct FuncDef **basic_funcs,
                                struct FuncDefAgg **agg_funcs)
{
    static struct FuncDef network_funcs[] = {
        sqlite_func_adapter<decltype(&sql_gethostbyname), sql_gethostbyname>::builder(
            help_text("gethostbyname",
                      "Get the IP address for the given hostname")
                .sql_function()
                .with_parameter({"hostname", "The DNS hostname to lookup."})
                .with_example({"SELECT gethostbyname('localhost')"})
        ),

        sqlite_func_adapter<decltype(&sql_gethostbyaddr), sql_gethostbyaddr>::builder(
            help_text("gethostbyaddr",
                      "Get the IP address for the given hostname")
                .sql_function()
                .with_parameter({"hostname", "The DNS hostname to lookup."})
                .with_example({"SELECT gethostbyaddr('127.0.0.1')"})
        ),

        { NULL }
    };

    *basic_funcs = network_funcs;

    return SQLITE_OK;
}
<|endoftext|>


<commit_before>#ifndef TEE_BUF_HPP
#define TEE_BUF_HPP

#include <string>
#include <ostream>
#include <streambuf>
#include <functional>

#define CreateOstreamTeeBuf(s, n, f) OstreamTeeBuf<decltype(s)> n(s, f)
#define BindStdStringAppend(s) std::bind<decltype(s)&(decltype(s)::*)(decltype(s)::const_pointer, decltype(s)::size_type)>(&decltype(s)::append, &s, std::placeholders::_1, std::placeholders::_2)

template <class OstrT>
class OstreamTeeBuf: private std::basic_streambuf<typename OstrT::char_type> {
	typedef std::function<void(const typename OstrT::char_type* s, std::streamsize n)> TeeCallbackType;
private:
	OstrT &ostr;
	std::basic_streambuf<typename OstrT::char_type> *orig_buf;
	TeeCallbackType tee_callback;
	bool no_err;

	//Hacky hacky hacky...
	//Class tries to redirect all the output to original ostream/wcostream buffer
	//This is not intended behaviour of basic_streambuf descendant
	//We are expected to provide our own buffer and handle overflow and sync functions like a good descendant wood do
	//And only while behaving like proper basic_streambuf we are allowed to do whatever we want with data passed (like forwarding it to original buffer via public functions)
	//There is a perfect reason for this - we don't know how basic_streambuf will be used and by who
	//By conforming to the standard we are ensuring that whoever use it, if he also conforms to standard, will get expected results
	//But no... we will cut off some corners and just redirect protected members to it's equivalents of original buffer via hacky means
	//Actually it works and if we redirect all of the protected members we are pretty safe
	//Observations on behaviour of GCC's ostream implementaion show that it's enough to redirect only protected functions listed below (at least for this particular implementation)
	//(BTW, ostream calls these protected functions directly because they are friends with basic_streambuf)

	std::streamsize xsputn(const typename OstrT::char_type* s, std::streamsize n) {
		if (tee_callback) tee_callback(s, n);
		std::streamsize res=((OstreamTeeBuf<OstrT>*)orig_buf)->xsputn(s, n);
		return no_err?n:res;
	};

	typename std::char_traits<typename OstrT::char_type>::int_type overflow(typename std::char_traits<typename OstrT::char_type>::int_type c) {
		if (tee_callback) {
			typename OstrT::char_type cc=std::char_traits<typename OstrT::char_type>::to_char_type(c);
			tee_callback(&cc, 1);
		}
		typename std::char_traits<typename OstrT::char_type>::int_type res=((OstreamTeeBuf<OstrT>*)orig_buf)->overflow(c);
		return no_err?(c==std::char_traits<typename OstrT::char_type>::eof()?std::char_traits<typename OstrT::char_type>::not_eof(c):c):res;
	};

	int sync() {
		int res=((OstreamTeeBuf<OstrT>*)orig_buf)->sync();
		return no_err?0:res;
	};
public:
	OstreamTeeBuf(OstrT &ostr, TeeCallbackType tee_callback): ostr(ostr), orig_buf(ostr.rdbuf(this)), tee_callback(tee_callback), no_err(false) {};

	void Deactivate() {
		if (orig_buf) {
			ostr.rdbuf(orig_buf);
			orig_buf=NULL;
		}
	};

	void IgnoreOutputErrors(bool value) {
		no_err=value;
	};

	~OstreamTeeBuf() {
		Deactivate();
	};
};

#endif //TEE_BUF_HPP
<commit_msg>Grammar<commit_after>#ifndef TEE_BUF_HPP
#define TEE_BUF_HPP

#include <string>
#include <ostream>
#include <streambuf>
#include <functional>

#define CreateOstreamTeeBuf(s, n, f) OstreamTeeBuf<decltype(s)> n(s, f)
#define BindStdStringAppend(s) std::bind<decltype(s)&(decltype(s)::*)(decltype(s)::const_pointer, decltype(s)::size_type)>(&decltype(s)::append, &s, std::placeholders::_1, std::placeholders::_2)

template <class OstrT>
class OstreamTeeBuf: private std::basic_streambuf<typename OstrT::char_type> {
	typedef std::function<void(const typename OstrT::char_type* s, std::streamsize n)> TeeCallbackType;
private:
	OstrT &ostr;
	std::basic_streambuf<typename OstrT::char_type> *orig_buf;
	TeeCallbackType tee_callback;
	bool no_err;

	//Hacky hacky hacky...
	//Class tries to redirect all the output to original ostream/wcostream buffer
	//This is not intended behaviour of basic_streambuf descendant
	//We are expected to provide our own buffer and handle overflow and sync functions like a good descendant would do
	//And only while behaving like proper basic_streambuf we are allowed to do whatever we want with data passed (like forwarding it to original buffer via public functions)
	//There is a perfect reason for this - we don't know how basic_streambuf will be used and by who
	//By conforming to the standard we are ensuring that whoever use it, if he also conforms to standard, will get expected results
	//But no... we will cut off some corners and just redirect protected members to it's equivalents of original buffer via hacky means
	//Actually it works and if we redirect all of the protected members we are pretty safe
	//Observations on behaviour of GCC's ostream implementaion show that it's enough to redirect only protected functions listed below (at least for this particular implementation)
	//(BTW, ostream calls these protected functions directly because they are friends with basic_streambuf)

	std::streamsize xsputn(const typename OstrT::char_type* s, std::streamsize n) {
		if (tee_callback) tee_callback(s, n);
		std::streamsize res=((OstreamTeeBuf<OstrT>*)orig_buf)->xsputn(s, n);
		return no_err?n:res;
	};

	typename std::char_traits<typename OstrT::char_type>::int_type overflow(typename std::char_traits<typename OstrT::char_type>::int_type c) {
		if (tee_callback) {
			typename OstrT::char_type cc=std::char_traits<typename OstrT::char_type>::to_char_type(c);
			tee_callback(&cc, 1);
		}
		typename std::char_traits<typename OstrT::char_type>::int_type res=((OstreamTeeBuf<OstrT>*)orig_buf)->overflow(c);
		return no_err?(c==std::char_traits<typename OstrT::char_type>::eof()?std::char_traits<typename OstrT::char_type>::not_eof(c):c):res;
	};

	int sync() {
		int res=((OstreamTeeBuf<OstrT>*)orig_buf)->sync();
		return no_err?0:res;
	};
public:
	OstreamTeeBuf(OstrT &ostr, TeeCallbackType tee_callback): ostr(ostr), orig_buf(ostr.rdbuf(this)), tee_callback(tee_callback), no_err(false) {};

	void Deactivate() {
		if (orig_buf) {
			ostr.rdbuf(orig_buf);
			orig_buf=NULL;
		}
	};

	void IgnoreOutputErrors(bool value) {
		no_err=value;
	};

	~OstreamTeeBuf() {
		Deactivate();
	};
};

#endif //TEE_BUF_HPP
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * 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; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_VERTEX_CONVERTERS_HPP
#define MAPNIK_VERTEX_CONVERTERS_HPP

// boost
#include <boost/type_traits/is_same.hpp>
// mpl
#include <boost/mpl/vector.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/distance.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/int.hpp>
// fusion
#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/include/at_c.hpp>
#include <boost/fusion/include/make_vector.hpp>
//#include <boost/fusion/adapted/mpl.hpp>

#include <boost/foreach.hpp>
#include <boost/utility.hpp>
#include <boost/array.hpp>

// mapnik
#include <mapnik/agg_helpers.hpp>
#include <mapnik/offset_converter.hpp>
// agg
#include "agg_conv_clip_polygon.h"
#include "agg_conv_clip_polyline.h"
#include "agg_conv_smooth_poly1.h"
#include "agg_conv_stroke.h"
#include "agg_conv_dash.h"
#include "agg_conv_transform.h"

namespace mapnik {

struct transform_tag {};
struct clip_line_tag {};
struct clip_poly_tag {};
struct smooth_tag {};
struct stroke_tag {};
struct dash_tag {};
struct affine_transform_tag {};
struct offset_transform_tag {};

namespace  detail {

template <typename T0, typename T1>
struct converter_traits
{
    typedef T0 geometry_type;
    typedef geometry_type conv_type;
    template <typename Args>
    static void setup(geometry_type & geom, Args & args)
    {
        throw "BOOM!";
    }
};

template <typename T>
struct converter_traits<T,mapnik::smooth_tag>
{
    typedef T geometry_type;
    typedef typename agg::conv_smooth_poly1_curve<geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args & args)
    {
        geom.smooth_value(boost::fusion::at_c<2>(args).smooth());
    }
};

template <typename T>
struct converter_traits<T, mapnik::clip_line_tag>
{
    typedef T geometry_type;
    typedef typename agg::conv_clip_polyline<geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args & args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<0> >::type const& box = boost::fusion::at_c<0>(args);
        geom.clip_box(box.minx(),box.miny(),box.maxx(),box.maxy());
    }
};

template <typename T>
struct converter_traits<T, mapnik::dash_tag>
{
    typedef T geometry_type;
    typedef typename agg::conv_dash<geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args & args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<2> >::type const& sym = boost::fusion::at_c<2>(args);
        double scale_factor = boost::fusion::at_c<5>(args);
        stroke const& stroke_ = sym.get_stroke();
        dash_array const& d = stroke_.get_dash_array();
        dash_array::const_iterator itr = d.begin();
        dash_array::const_iterator end = d.end();
        for (;itr != end;++itr)
        {
            geom.add_dash(itr->first * scale_factor,
                          itr->second * scale_factor);
        }

    }
};

template <typename T>
struct converter_traits<T, mapnik::stroke_tag>
{
    typedef T geometry_type;
    typedef typename agg::conv_stroke<geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args & args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<2> >::type const& sym = boost::fusion::at_c<2>(args);
        stroke const& stroke_ = sym.get_stroke();
        set_join_caps(stroke_,geom);
        geom.generator().miter_limit(stroke_.get_miterlimit());
        double scale_factor = boost::fusion::at_c<5>(args);
        geom.generator().width(stroke_.get_width() * scale_factor);
    }
};

template <typename T>
struct converter_traits<T,mapnik::clip_poly_tag>
{
    typedef T geometry_type;
    typedef typename agg::conv_clip_polygon<geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args & args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<0> >::type const& box = boost::fusion::at_c<0>(args);
        geom.clip_box(box.minx(),box.miny(),box.maxx(),box.maxy());
    }
};

template <typename T>
struct converter_traits<T,mapnik::transform_tag>
{
    typedef T geometry_type;
    typedef coord_transform2<CoordTransform, geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args & args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<3> >::type const& tr = boost::fusion::at_c<3>(args);
        typename boost::mpl::at<Args,boost::mpl::int_<4> >::type const& prj_trans = boost::fusion::at_c<4>(args);
        geom.set_proj_trans(prj_trans);
        geom.set_trans(tr);
    }
};

template <typename T>
struct converter_traits<T,mapnik::affine_transform_tag>
{
    typedef T geometry_type;

    struct conv_type : public agg::conv_transform<geometry_type>
    {
        agg::trans_affine trans_;

        conv_type(geometry_type& geom)
            : agg::conv_transform<geometry_type>(geom, trans_) {}
    };

    template <typename Args>
    static void setup(geometry_type & geom, Args & args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<2> >::type const& sym = boost::fusion::at_c<2>(args);
        boost::array<double,6> const& m = sym.get_transform();
        geom.trans_.load_from(&m[0]);
    }
};

template <typename T>
struct converter_traits<T,mapnik::offset_transform_tag>
{
    typedef T geometry_type;
    typedef offset_converter<geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args & args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<2> >::type const& sym = boost::fusion::at_c<2>(args);
        geom.set_offset(sym.offset());
    }
};

template <bool>
struct converter_fwd
{
    template <typename Base, typename T0,typename T1,typename T2, typename Iter,typename End>
    static void forward(Base& base, T0 & geom,T1 & args)
    {
        typedef T0 geometry_type;
        typedef T2 conv_tag;
        typedef typename detail::converter_traits<geometry_type,conv_tag>::conv_type conv_type;
        conv_type conv(geom);
        detail::converter_traits<conv_type,conv_tag>::setup(conv,args);
        base.template dispatch<Iter,End>(conv, typename boost::is_same<Iter,End>::type());
    }
};

template <>
struct converter_fwd<true>
{
    template <typename Base, typename T0,typename T1,typename T2, typename Iter,typename End>
    static void forward(Base& base, T0 & geom,T1 & args)
    {
        base.template dispatch<Iter,End>(geom, typename boost::is_same<Iter,End>::type());
    }
};

template <typename A, typename C>
struct dispatcher
{
    typedef dispatcher this_type;
    typedef A args_type;
    typedef C conv_types;

    dispatcher(args_type args)
        : args_(args)
    {
        std::memset(&vec_[0], 0,  sizeof(unsigned)*vec_.size());
    }

    template <typename Iter, typename End, typename Geometry>
    void dispatch(Geometry & geom, boost::mpl::true_)
    {
        boost::fusion::at_c<1>(args_).add_path(geom);
    }

    template <typename Iter, typename End, typename Geometry>
    void dispatch(Geometry & geom, boost::mpl::false_)
    {
        typedef typename boost::mpl::deref<Iter>::type conv_tag;
        typedef typename detail::converter_traits<Geometry,conv_tag>::conv_type conv_type;
        typedef typename boost::mpl::next<Iter>::type Next;

        std::size_t index = boost::mpl::distance<Iter,End>::value - 1;
        if (vec_[index] == 1)
        {
            converter_fwd<boost::is_same<Geometry,conv_type>::value>::
                template forward<this_type,Geometry,args_type,conv_tag,Next,End>(*this,geom,args_);
        }
        else
        {
            converter_fwd<boost::mpl::true_::value>::
                template forward<this_type,Geometry,args_type,conv_tag,Next,End>(*this,geom,args_);
        }

    }

    template <typename Geometry>
    void apply(Geometry & geom)
    {
        typedef typename boost::mpl::begin<conv_types>::type begin;
        typedef typename boost::mpl::end  <conv_types>::type end;
        dispatch<begin,end,Geometry>(geom, boost::false_type());
    }

    boost::array<unsigned, boost::mpl::size<conv_types>::value> vec_;
    args_type  args_;
};
}

template <typename B, typename R, typename S, typename P, typename T, typename C >
struct vertex_converter : private boost::noncopyable
{
    typedef C conv_types;
    typedef B bbox_type;
    typedef R rasterizer_type;
    typedef S symbolizer_type;
    typedef P proj_trans_type;
    typedef T trans_type;
    typedef typename boost::fusion::vector
    <
    bbox_type const&,
    rasterizer_type&,
    symbolizer_type const&,
    trans_type const&,
    proj_trans_type const&,
    double //scale-factor
    > args_type;

    vertex_converter(bbox_type const& b, rasterizer_type & ras,
                     symbolizer_type const& sym, trans_type & tr,
                     proj_trans_type const& prj_trans,
                     double scale_factor)
        : disp_(args_type(boost::cref(b),boost::ref(ras),
                          boost::cref(sym),boost::cref(tr),
                          boost::cref(prj_trans),scale_factor)) {}

    template <typename Geometry>
    void apply(Geometry & geom)
    {
        typedef Geometry geometry_type;
        disp_.template apply<geometry_type>(geom);
    }

    template <typename Conv>
    void set()
    {
        typedef typename boost::mpl::find<conv_types,Conv>::type iter;
        typedef typename boost::mpl::end<conv_types>::type end;
        std::size_t index = boost::mpl::distance<iter,end>::value - 1;
        if (index < disp_.vec_.size())
            disp_.vec_[index]=1;
    }

    detail::dispatcher<args_type,conv_types> disp_;
};

}

#endif // MAPNIK_VERTEX_CONVERTERS_HPP
<commit_msg>+ pass Args by const-ref<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * 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; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_VERTEX_CONVERTERS_HPP
#define MAPNIK_VERTEX_CONVERTERS_HPP

// boost
#include <boost/type_traits/is_same.hpp>
// mpl
#include <boost/mpl/vector.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/distance.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/int.hpp>
// fusion
#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/include/at_c.hpp>
#include <boost/fusion/include/make_vector.hpp>
//#include <boost/fusion/adapted/mpl.hpp>

#include <boost/foreach.hpp>
#include <boost/utility.hpp>
#include <boost/array.hpp>

// mapnik
#include <mapnik/agg_helpers.hpp>
#include <mapnik/offset_converter.hpp>
// agg
#include "agg_conv_clip_polygon.h"
#include "agg_conv_clip_polyline.h"
#include "agg_conv_smooth_poly1.h"
#include "agg_conv_stroke.h"
#include "agg_conv_dash.h"
#include "agg_conv_transform.h"

namespace mapnik {

struct transform_tag {};
struct clip_line_tag {};
struct clip_poly_tag {};
struct smooth_tag {};
struct stroke_tag {};
struct dash_tag {};
struct affine_transform_tag {};
struct offset_transform_tag {};

namespace  detail {

template <typename T0, typename T1>
struct converter_traits
{
    typedef T0 geometry_type;
    typedef geometry_type conv_type;
    template <typename Args>
    static void setup(geometry_type & geom, Args const& args)
    {
        throw "BOOM!";
    }
};

template <typename T>
struct converter_traits<T,mapnik::smooth_tag>
{
    typedef T geometry_type;
    typedef typename agg::conv_smooth_poly1_curve<geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args const& args)
    {
        geom.smooth_value(boost::fusion::at_c<2>(args).smooth());
    }
};

template <typename T>
struct converter_traits<T, mapnik::clip_line_tag>
{
    typedef T geometry_type;
    typedef typename agg::conv_clip_polyline<geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args const& args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<0> >::type const& box = boost::fusion::at_c<0>(args);
        geom.clip_box(box.minx(),box.miny(),box.maxx(),box.maxy());
    }
};

template <typename T>
struct converter_traits<T, mapnik::dash_tag>
{
    typedef T geometry_type;
    typedef typename agg::conv_dash<geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args const& args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<2> >::type const& sym = boost::fusion::at_c<2>(args);
        double scale_factor = boost::fusion::at_c<5>(args);
        stroke const& stroke_ = sym.get_stroke();
        dash_array const& d = stroke_.get_dash_array();
        dash_array::const_iterator itr = d.begin();
        dash_array::const_iterator end = d.end();
        for (;itr != end;++itr)
        {
            geom.add_dash(itr->first * scale_factor,
                          itr->second * scale_factor);
        }

    }
};

template <typename T>
struct converter_traits<T, mapnik::stroke_tag>
{
    typedef T geometry_type;
    typedef typename agg::conv_stroke<geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args const& args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<2> >::type const& sym = boost::fusion::at_c<2>(args);
        stroke const& stroke_ = sym.get_stroke();
        set_join_caps(stroke_,geom);
        geom.generator().miter_limit(stroke_.get_miterlimit());
        double scale_factor = boost::fusion::at_c<5>(args);
        geom.generator().width(stroke_.get_width() * scale_factor);
    }
};

template <typename T>
struct converter_traits<T,mapnik::clip_poly_tag>
{
    typedef T geometry_type;
    typedef typename agg::conv_clip_polygon<geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args const& args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<0> >::type const& box = boost::fusion::at_c<0>(args);
        geom.clip_box(box.minx(),box.miny(),box.maxx(),box.maxy());
    }
};

template <typename T>
struct converter_traits<T,mapnik::transform_tag>
{
    typedef T geometry_type;
    typedef coord_transform2<CoordTransform, geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args const& args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<3> >::type const& tr = boost::fusion::at_c<3>(args);
        typename boost::mpl::at<Args,boost::mpl::int_<4> >::type const& prj_trans = boost::fusion::at_c<4>(args);
        geom.set_proj_trans(prj_trans);
        geom.set_trans(tr);
    }
};

template <typename T>
struct converter_traits<T,mapnik::affine_transform_tag>
{
    typedef T geometry_type;

    struct conv_type : public agg::conv_transform<geometry_type>
    {
        agg::trans_affine trans_;

        conv_type(geometry_type& geom)
            : agg::conv_transform<geometry_type>(geom, trans_) {}
    };

    template <typename Args>
    static void setup(geometry_type & geom, Args & args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<2> >::type const& sym = boost::fusion::at_c<2>(args);
        boost::array<double,6> const& m = sym.get_transform();
        geom.trans_.load_from(&m[0]);
    }
};

template <typename T>
struct converter_traits<T,mapnik::offset_transform_tag>
{
    typedef T geometry_type;
    typedef offset_converter<geometry_type> conv_type;

    template <typename Args>
    static void setup(geometry_type & geom, Args const& args)
    {
        typename boost::mpl::at<Args,boost::mpl::int_<2> >::type const& sym = boost::fusion::at_c<2>(args);
        geom.set_offset(sym.offset());
    }
};

template <bool>
struct converter_fwd
{
    template <typename Base, typename T0,typename T1,typename T2, typename Iter,typename End>
    static void forward(Base& base, T0 & geom,T1 const& args)
    {
        typedef T0 geometry_type;
        typedef T2 conv_tag;
        typedef typename detail::converter_traits<geometry_type,conv_tag>::conv_type conv_type;
        conv_type conv(geom);
        detail::converter_traits<conv_type,conv_tag>::setup(conv,args);
        base.template dispatch<Iter,End>(conv, typename boost::is_same<Iter,End>::type());
    }
};

template <>
struct converter_fwd<true>
{
    template <typename Base, typename T0,typename T1,typename T2, typename Iter,typename End>
    static void forward(Base& base, T0 & geom,T1 const& args)
    {
        base.template dispatch<Iter,End>(geom, typename boost::is_same<Iter,End>::type());
    }
};

template <typename A, typename C>
struct dispatcher
{
    typedef dispatcher this_type;
    typedef A args_type;
    typedef C conv_types;

    dispatcher(args_type const& args)
        : args_(args)
    {
        std::memset(&vec_[0], 0,  sizeof(unsigned)*vec_.size());
    }

    template <typename Iter, typename End, typename Geometry>
    void dispatch(Geometry & geom, boost::mpl::true_)
    {
        boost::fusion::at_c<1>(args_).add_path(geom);
    }

    template <typename Iter, typename End, typename Geometry>
    void dispatch(Geometry & geom, boost::mpl::false_)
    {
        typedef typename boost::mpl::deref<Iter>::type conv_tag;
        typedef typename detail::converter_traits<Geometry,conv_tag>::conv_type conv_type;
        typedef typename boost::mpl::next<Iter>::type Next;

        std::size_t index = boost::mpl::distance<Iter,End>::value - 1;
        if (vec_[index] == 1)
        {
            converter_fwd<boost::is_same<Geometry,conv_type>::value>::
                template forward<this_type,Geometry,args_type,conv_tag,Next,End>(*this,geom,args_);
        }
        else
        {
            converter_fwd<boost::mpl::true_::value>::
                template forward<this_type,Geometry,args_type,conv_tag,Next,End>(*this,geom,args_);
        }

    }

    template <typename Geometry>
    void apply(Geometry & geom)
    {
        typedef typename boost::mpl::begin<conv_types>::type begin;
        typedef typename boost::mpl::end  <conv_types>::type end;
        dispatch<begin,end,Geometry>(geom, boost::false_type());
    }

    boost::array<unsigned, boost::mpl::size<conv_types>::value> vec_;
    args_type args_;
};
}

template <typename B, typename R, typename S, typename P, typename T, typename C >
struct vertex_converter : private boost::noncopyable
{
    typedef C conv_types;
    typedef B bbox_type;
    typedef R rasterizer_type;
    typedef S symbolizer_type;
    typedef P proj_trans_type;
    typedef T trans_type;
    typedef typename boost::fusion::vector
    <
    bbox_type const&,
    rasterizer_type&,
    symbolizer_type const&,
    trans_type const&,
    proj_trans_type const&,
    double //scale-factor
    > args_type;

    vertex_converter(bbox_type const& b, rasterizer_type & ras,
                     symbolizer_type const& sym, trans_type & tr,
                     proj_trans_type const& prj_trans,
                     double scale_factor)
        : disp_(args_type(boost::cref(b),boost::ref(ras),
                          boost::cref(sym),boost::cref(tr),
                          boost::cref(prj_trans),scale_factor)) {}

    template <typename Geometry>
    void apply(Geometry & geom)
    {
        typedef Geometry geometry_type;
        disp_.template apply<geometry_type>(geom);
    }

    template <typename Conv>
    void set()
    {
        typedef typename boost::mpl::find<conv_types,Conv>::type iter;
        typedef typename boost::mpl::end<conv_types>::type end;
        std::size_t index = boost::mpl::distance<iter,end>::value - 1;
        if (index < disp_.vec_.size())
            disp_.vec_[index]=1;
    }

    detail::dispatcher<args_type,conv_types> disp_;
};

}

#endif // MAPNIK_VERTEX_CONVERTERS_HPP
<|endoftext|>


<commit_before>#ifndef INC_METTLE_DETAIL_MOVE_IF_HPP
#define INC_METTLE_DETAIL_MOVE_IF_HPP

#include <type_traits>

namespace mettle {

namespace detail {
  template<typename Container, typename Element>
  inline decltype(auto) forward_if(Element &&value) {
    using Value = typename std::remove_reference<Element>::type;
    using ReturnType = typename std::conditional<
      std::is_lvalue_reference<Container>::value, Value &, Value &&
    >::type;
    return static_cast<ReturnType>(value);
  }
}

} // namespace mettle

#endif
<commit_msg>Work around MSVC's broken decltype(auto) support<commit_after>#ifndef INC_METTLE_DETAIL_MOVE_IF_HPP
#define INC_METTLE_DETAIL_MOVE_IF_HPP

#include <type_traits>

namespace mettle {

namespace detail {
  template<typename Container, typename Element>
  struct ref_if {
    using type = typename std::conditional<
      std::is_lvalue_reference<Container>::value,
      typename std::remove_reference<Element>::type &,
      typename std::remove_reference<Element>::type &&
     >::type;
  };

  // XXX: We could use decltype(auto) for this function, but MSVC's
  // implementation is currently broken.
  template<typename Container, typename Element>
  inline typename ref_if<Container, Element>::type
  forward_if(Element &&value) {
    return static_cast<typename ref_if<Container, Element>::type>(value);
  }
}

} // namespace mettle

#endif
<|endoftext|>


<commit_before>#pragma once

#include "../../indexer/feature.hpp"
#include "../../indexer/osm2type.hpp"
#include "../../indexer/xml_element.hpp"
#include "../../indexer/osm_decl.hpp"
#include "../../indexer/feature_visibility.hpp"

#include "../../base/string_utils.hpp"
#include "../../base/logging.hpp"
#include "../../base/stl_add.hpp"

#include "../../std/unordered_map.hpp"
#include "../../std/list.hpp"
#include "../../std/set.hpp"
#include "../../std/vector.hpp"

#include "../../base/start_mem_debug.hpp"

/// @param  TEmitter  Feature accumulating policy
/// @param  THolder   Nodes, ways, relations holder
template <class TEmitter, class THolder>
class SecondPassParserBase : public BaseOSMParser
{
protected:
  TEmitter & m_emitter;
  THolder & m_holder;

  /// max possible number of types per feature
  static const size_t max_number_of_types = 16;

  SecondPassParserBase(TEmitter & emitter, THolder & holder)
    : m_emitter(emitter), m_holder(holder)
  {
    static char const * tags[] = { "osm", "node", "way", "relation" };
    SetTags(tags);
  }

  static bool IsValidAreaPath(vector<m2::PointD> const & pts)
  {
    return (pts.size() > 2 && pts.front() == pts.back());
  }

  bool GetPoint(uint64_t id, m2::PointD & pt)
  {
    return m_holder.GetNode(id, pt.y, pt.x);
  }

  template <class ToDo> class process_points
  {
    SecondPassParserBase * m_pMain;
    ToDo & m_toDo;

  public:
    process_points(SecondPassParserBase * pMain, ToDo & toDo)
      : m_pMain(pMain), m_toDo(toDo)
    {
    }
    void operator () (uint64_t id)
    {
      m2::PointD pt;
      if (m_pMain->GetPoint(id, pt))
        m_toDo(pt);
    }
  };

  template <class ToDo>
  void ForEachWayPoint(uint64_t id, ToDo toDo)
  {
    WayElement e;
    if (m_holder.GetWay(id, e))
    {
      process_points<ToDo> process(this, toDo);
      e.ForEachPoint(process);
    }
  }

  class holes_accumulator
  {
    SecondPassParserBase * m_pMain;

  public:
    /// @param[out] list of holes
    list<vector<m2::PointD> > m_holes;

    holes_accumulator(SecondPassParserBase * pMain) : m_pMain(pMain) {}

    void operator() (uint64_t id)
    {
      m_holes.push_back(vector<m2::PointD>());

      m_pMain->ForEachWayPoint(id, MakeBackInsertFunctor(m_holes.back()));

      if (!m_pMain->IsValidAreaPath(m_holes.back()))
        m_holes.pop_back();
    }
  };

  /// Find holes for way with 'id' in first relation.
  class multipolygon_holes_processor
  {
    uint64_t m_id;      ///< id of way to find it's holes
    holes_accumulator m_holes;

  public:
    multipolygon_holes_processor(uint64_t id, SecondPassParserBase * pMain)
      : m_id(id), m_holes(pMain)
    {
    }

    /// 1. relations process function
    bool operator() (uint64_t /*id*/, RelationElement const & e)
    {
      if (e.GetType() == "multipolygon")
      {
        string role;
        if (e.FindWay(m_id, role) && (role == "outer"))
        {
          e.ForEachWay(*this);
          // stop processing (??? assume that "outer way" exists in one relation only ???)
          return true;
        }
      }
      return false;
    }

    /// 2. "ways in relation" process function
    void operator() (uint64_t id, string const & role)
    {
      if (id != m_id && role == "inner")
        m_holes(id);
    }

    list<vector<m2::PointD> > & GetHoles() { return m_holes.m_holes; }
  };

  /// Feature description struct.
  struct value_t
  {
    typedef vector<uint32_t> types_t;
    types_t types;    ///< 1-n types, not empty
    string name;      ///< 1-1 name, @todo 1-n names
    int32_t layer;    ///< layer

    value_t()
    {
      types.reserve(max_number_of_types);
    }
    bool IsValid() const { return !types.empty(); }
    void Add(value_t const & v)
    {
      types.insert(types.end(), v.types.begin(), v.types.end());
    }
  };

  /// Feature types processor.
  class type_processor
  {
    void make_xml_element(RelationElement const & rel, XMLElement & out)
    {
      for (map<string, string>::const_iterator i = rel.tags.begin(); i != rel.tags.end(); ++i)
      {
        if (i->first == "type") continue;

        out.childs.push_back(XMLElement());
        XMLElement & e = out.childs.back();
        e.name = "tag";
        e.attrs["k"] = i->first;
        e.attrs["v"] = i->second;
      }
    }

    /// @param[in]  ID of processing feature.
    uint64_t m_featureID;

    /// @param[out] Feature value as result.
    value_t * m_val;

    /// Cache: relation id -> feature value (for fast feature parsing)
    unordered_map<uint64_t, value_t> m_typeCache;

  public:
    /// Start process new feature.
    void Reset(uint64_t fID, value_t * val)
    {
      m_featureID = fID;
      m_val = val;
    }

    /// 1. "initial relation" process
    int operator() (uint64_t id)
    {
      typename unordered_map<uint64_t, value_t>::const_iterator i = m_typeCache.find(id);
      if (i != m_typeCache.end())
      {
        m_val->Add(i->second);
        return -1;  // continue process relations
      }
      return 0;     // read relation from file (see next operator)
    }

    /// 2. "relation from file" process
    bool operator() (uint64_t id, RelationElement const & rel)
    {
      // make XMLElement struct from relation's tags for GetNameAndType function.
      XMLElement e;
      make_xml_element(rel, e);

      if (rel.GetType() == "multipolygon")
      {
        // we will process multipolygons later
      }
      else
      {
        // process types of relation and add them to m_val
        value_t val;
        if (ftype::GetNameAndType(&e, val.types, val.name, val.layer))
        {
          m_typeCache[id] = val;
          m_val->Add(val);
        }
        else
          m_typeCache[id] = value_t();
      }

      // continue process relations
      return false;
    }
  } m_typeProcessor;

  typedef FeatureBuilder1 feature_builder_t;

  void FinishAreaFeature(uint64_t id, feature_builder_t & ft)
  {
    ASSERT ( ft.IsGeometryClosed(), () );

    multipolygon_holes_processor processor(id, this);
    m_holder.ForEachRelationByWay(id, processor);
    ft.SetAreaAddHoles(processor.GetHoles());
  }

  bool ParseType(XMLElement * p, uint64_t & id, value_t & fValue)
  {
    VERIFY ( utils::to_uint64(p->attrs["id"], id),
      ("Unknown element with invalid id : ", p->attrs["id"]) );

    // try to get type from element tags
    ftype::GetNameAndType(p, fValue.types, fValue.name, fValue.layer);

    // try to get type from relations tags
    m_typeProcessor.Reset(id, &fValue);

    if (p->name == "node")
      m_holder.ForEachRelationByNodeCached(id, m_typeProcessor);
    else if (p->name == "way")
      m_holder.ForEachRelationByWayCached(id, m_typeProcessor);

    // remove duplicating types
    sort(fValue.types.begin(), fValue.types.end());
    fValue.types.erase(unique(fValue.types.begin(), fValue.types.end()), fValue.types.end());

    // unrecognized feature by classificator
    return fValue.IsValid();
  }
};

/*
template <class TEmitter, class THolder>
class SecondPassParserJoin : public SecondPassParserBase<TEmitter, THolder>
{
  typedef SecondPassParserBase<TEmitter, THolder> base_type;

  set<uint64_t> m_usedDirect;

  bool TryEmitUnited(uint64_t featureID, typename base_type::feature_builder_t & ft)
  {
    // check, if feature already processed early
    if (m_usedDirect.count(featureID) > 0)
      return true;

    set<uint64_t> path;
    path.insert(featureID);

    WayElement e;

    // process geometry of initial way itself
    base_type::m_holder.GetWay(featureID, e);
    if (e.nodes.empty())
      return false;

    for (size_t i = 0; i < e.nodes.size(); ++i)
    {
      m2::PointD pt;
      if (base_type::GetPoint(e.nodes[i], pt))
        ft.AddPoint(pt);
      else
        return false;
    }

    // process connected ways in cycle while ...
    uint64_t fID = featureID;
    while (!ft.IsGeometryClosed())
    {
      uint64_t const nodeID = e.nodes.back();
      if (!base_type::m_holder.GetNextWay(fID, nodeID, e))
        break;

      if (!path.insert(fID).second)
      {
        LOG_SHORT(LWARNING, ("JOIN_DBG! Cycle found during way joining, duplicate id = ", fID));
        break;
      }

      // skip first point, because it's equal with previous
      size_t i;
      int inc;
      if (e.nodes.front() == nodeID)
      {
        i = 1;
        inc = 1;
      }
      else
      {
        ASSERT ( e.nodes.back() == nodeID, () );

        i = e.nodes.size() - 2;
        inc = -1;
      }

      size_t count = 1;
      while (count++ < e.nodes.size())
      {
        m2::PointD pt;
        if (base_type::GetPoint(e.nodes[i], pt))
          ft.AddPoint(pt);
        else
          return false;

        i += inc;
      }
    }

    if (ft.IsGeometryClosed())
    {
      m_usedDirect.insert(path.begin(), path.end());

      base_type::FinishAreaFeature(featureID, ft);

      base_type::m_emitter(ft);
      return true;
    }
    else
    {
      LOG_SHORT(LWARNING, ("JOIN_DBG! Ways not connected for root way = ", featureID));
      return false;
    }
  }

protected:
  virtual void EmitElement(XMLElement * p)
  {
    uint64_t id;
    typename base_type::value_t fValue;
    if (!ParseType(p, id, fValue))
      return;

    // check, if we can make united feature
    for (typename base_type::value_t::types_t::iterator i = fValue.types.begin(); i != fValue.types.end(); ++i)
      if (feature::NeedUnite(*i))
      {
        typename base_type::feature_builder_t ft;
        ft.AddName(fValue.name);
        ft.AddTypes(fValue.types.begin(), fValue.types.end());
        ft.AddLayer(fValue.layer);

        TryEmitUnited(id, ft);
        break;
      }
  }

public:
  SecondPassParserJoin(TEmitter & emitter, THolder & holder)
    : base_type(emitter, holder)
  {
  }
};
*/

template <class TEmitter, class THolder>
class SecondPassParserUsual : public SecondPassParserBase<TEmitter, THolder>
{
  typedef SecondPassParserBase<TEmitter, THolder> base_type;

protected:
  virtual void EmitElement(XMLElement * p)
  {
    uint64_t id;
    typename base_type::value_t fValue;
    if (!ParseType(p, id, fValue))
      return;

    typename base_type::feature_builder_t ft;
    ft.AddName(fValue.name);
    ft.AddTypes(fValue.types.begin(), fValue.types.end());
    ft.AddLayer(fValue.layer);

    if (p->name == "node")
    {
      if (!feature::IsDrawableLike(fValue.types, feature::fpoint))
        return;

      m2::PointD pt;
      if (p->childs.empty() || !base_type::GetPoint(id, pt))
        return;

      ft.SetCenter(pt);
    }
    else if (p->name == "way")
    {
      bool const isLine = feature::IsDrawableLike(fValue.types, feature::fline);
      bool const isArea = feature::IsDrawableLike(fValue.types, feature::farea);

      if (!isLine && !isArea)
        return;

      // geometry of feature
      for (size_t i = 0; i < p->childs.size(); ++i)
      {
        if (p->childs[i].name == "nd")
        {
          uint64_t nodeID;
          VERIFY ( utils::to_uint64(p->childs[i].attrs["ref"], nodeID),
                   ("Bad node ref in way : ", p->childs[i].attrs["ref"]) );

          m2::PointD pt;
          if (!base_type::GetPoint(nodeID, pt))
            return;

          ft.AddPoint(pt);
        }
      }

      size_t const count = ft.GetPointsCount();
      if (count < 2)
        return;

      if (isLine)
        ft.SetLinear();

      // Get the tesselation for an area object (only if it has area drawing rules,
      // otherwise it will stay a linear object).
      if (isArea && count > 2 && ft.IsGeometryClosed())
        base_type::FinishAreaFeature(id, ft);
    }
    else if (p->name == "relation")
    {
      if (!feature::IsDrawableLike(fValue.types, feature::farea))
        return;

      // check, if this is our processable relation
      bool isProcess = false;
      for (size_t i = 0; i < p->childs.size(); ++i)
      {
        if (p->childs[i].name == "tag" &&
            p->childs[i].attrs["k"] == "type" &&
            p->childs[i].attrs["v"] == "multipolygon")
        {
          isProcess = true;
        }
      }
      if (!isProcess)
        return;

      holes_accumulator holes(this);

      // iterate ways to get 'outer' and 'inner' geometries
      for (size_t i = 0; i < p->childs.size(); ++i)
      {
        if (p->childs[i].name == "member" &&
            p->childs[i].attrs["type"] == "way")
        {
          string const & role = p->childs[i].attrs["role"];
          uint64_t wayID;
          VERIFY ( utils::to_uint64(p->childs[i].attrs["ref"], wayID),
            ("Bad way ref in relation : ", p->childs[i].attrs["ref"]) );

          if (role == "outer")
          {
            ForEachWayPoint(wayID, bind(&base_type::feature_builder_t::AddPoint, ref(ft), _1));
          }
          else if (role == "inner")
          {
            holes(wayID);
          }
        }
      }

      if (ft.IsGeometryClosed())
        ft.SetAreaAddHoles(holes.m_holes);
    }

    if (ft.PreSerialize())
      base_type::m_emitter(ft);
  }

public:
  SecondPassParserUsual(TEmitter & emitter, THolder & holder)
    : base_type(emitter, holder)
  {
  }
};

#include "../../base/stop_mem_debug.hpp"
<commit_msg>Fix nodes-type definition (process relations for nodes only if it hasn't native types).<commit_after>#pragma once

#include "../../indexer/feature.hpp"
#include "../../indexer/osm2type.hpp"
#include "../../indexer/xml_element.hpp"
#include "../../indexer/osm_decl.hpp"
#include "../../indexer/feature_visibility.hpp"

#include "../../base/string_utils.hpp"
#include "../../base/logging.hpp"
#include "../../base/stl_add.hpp"

#include "../../std/unordered_map.hpp"
#include "../../std/list.hpp"
#include "../../std/set.hpp"
#include "../../std/vector.hpp"

#include "../../base/start_mem_debug.hpp"

/// @param  TEmitter  Feature accumulating policy
/// @param  THolder   Nodes, ways, relations holder
template <class TEmitter, class THolder>
class SecondPassParserBase : public BaseOSMParser
{
protected:
  TEmitter & m_emitter;
  THolder & m_holder;

  /// max possible number of types per feature
  static const size_t max_number_of_types = 16;

  SecondPassParserBase(TEmitter & emitter, THolder & holder)
    : m_emitter(emitter), m_holder(holder)
  {
    static char const * tags[] = { "osm", "node", "way", "relation" };
    SetTags(tags);
  }

  static bool IsValidAreaPath(vector<m2::PointD> const & pts)
  {
    return (pts.size() > 2 && pts.front() == pts.back());
  }

  bool GetPoint(uint64_t id, m2::PointD & pt)
  {
    return m_holder.GetNode(id, pt.y, pt.x);
  }

  template <class ToDo> class process_points
  {
    SecondPassParserBase * m_pMain;
    ToDo & m_toDo;

  public:
    process_points(SecondPassParserBase * pMain, ToDo & toDo)
      : m_pMain(pMain), m_toDo(toDo)
    {
    }
    void operator () (uint64_t id)
    {
      m2::PointD pt;
      if (m_pMain->GetPoint(id, pt))
        m_toDo(pt);
    }
  };

  template <class ToDo>
  void ForEachWayPoint(uint64_t id, ToDo toDo)
  {
    WayElement e;
    if (m_holder.GetWay(id, e))
    {
      process_points<ToDo> process(this, toDo);
      e.ForEachPoint(process);
    }
  }

  class holes_accumulator
  {
    SecondPassParserBase * m_pMain;

  public:
    /// @param[out] list of holes
    list<vector<m2::PointD> > m_holes;

    holes_accumulator(SecondPassParserBase * pMain) : m_pMain(pMain) {}

    void operator() (uint64_t id)
    {
      m_holes.push_back(vector<m2::PointD>());

      m_pMain->ForEachWayPoint(id, MakeBackInsertFunctor(m_holes.back()));

      if (!m_pMain->IsValidAreaPath(m_holes.back()))
        m_holes.pop_back();
    }
  };

  /// Find holes for way with 'id' in first relation.
  class multipolygon_holes_processor
  {
    uint64_t m_id;      ///< id of way to find it's holes
    holes_accumulator m_holes;

  public:
    multipolygon_holes_processor(uint64_t id, SecondPassParserBase * pMain)
      : m_id(id), m_holes(pMain)
    {
    }

    /// 1. relations process function
    bool operator() (uint64_t /*id*/, RelationElement const & e)
    {
      if (e.GetType() == "multipolygon")
      {
        string role;
        if (e.FindWay(m_id, role) && (role == "outer"))
        {
          e.ForEachWay(*this);
          // stop processing (??? assume that "outer way" exists in one relation only ???)
          return true;
        }
      }
      return false;
    }

    /// 2. "ways in relation" process function
    void operator() (uint64_t id, string const & role)
    {
      if (id != m_id && role == "inner")
        m_holes(id);
    }

    list<vector<m2::PointD> > & GetHoles() { return m_holes.m_holes; }
  };

  /// Feature description struct.
  struct value_t
  {
    typedef vector<uint32_t> types_t;
    types_t types;    ///< 1-n types, not empty
    string name;      ///< 1-1 name, @todo 1-n names
    int32_t layer;    ///< layer

    value_t()
    {
      types.reserve(max_number_of_types);
    }
    bool IsValid() const { return !types.empty(); }
    void Add(value_t const & v)
    {
      types.insert(types.end(), v.types.begin(), v.types.end());
    }
  };

  /// Feature types processor.
  class type_processor
  {
    void make_xml_element(RelationElement const & rel, XMLElement & out)
    {
      for (map<string, string>::const_iterator i = rel.tags.begin(); i != rel.tags.end(); ++i)
      {
        if (i->first == "type") continue;

        out.childs.push_back(XMLElement());
        XMLElement & e = out.childs.back();
        e.name = "tag";
        e.attrs["k"] = i->first;
        e.attrs["v"] = i->second;
      }
    }

    /// @param[in]  ID of processing feature.
    uint64_t m_featureID;

    /// @param[out] Feature value as result.
    value_t * m_val;

    /// Cache: relation id -> feature value (for fast feature parsing)
    unordered_map<uint64_t, value_t> m_typeCache;

  public:
    /// Start process new feature.
    void Reset(uint64_t fID, value_t * val)
    {
      m_featureID = fID;
      m_val = val;
    }

    /// 1. "initial relation" process
    int operator() (uint64_t id)
    {
      typename unordered_map<uint64_t, value_t>::const_iterator i = m_typeCache.find(id);
      if (i != m_typeCache.end())
      {
        m_val->Add(i->second);
        return -1;  // continue process relations
      }
      return 0;     // read relation from file (see next operator)
    }

    /// 2. "relation from file" process
    bool operator() (uint64_t id, RelationElement const & rel)
    {
      // make XMLElement struct from relation's tags for GetNameAndType function.
      XMLElement e;
      make_xml_element(rel, e);

      if (rel.GetType() == "multipolygon")
      {
        // we will process multipolygons later
      }
      else
      {
        // process types of relation and add them to m_val
        value_t val;
        if (ftype::GetNameAndType(&e, val.types, val.name, val.layer))
        {
          m_typeCache[id] = val;
          m_val->Add(val);
        }
        else
          m_typeCache[id] = value_t();
      }

      // continue process relations
      return false;
    }
  } m_typeProcessor;

  typedef FeatureBuilder1 feature_builder_t;

  void FinishAreaFeature(uint64_t id, feature_builder_t & ft)
  {
    ASSERT ( ft.IsGeometryClosed(), () );

    multipolygon_holes_processor processor(id, this);
    m_holder.ForEachRelationByWay(id, processor);
    ft.SetAreaAddHoles(processor.GetHoles());
  }

  bool ParseType(XMLElement * p, uint64_t & id, value_t & fValue)
  {
    VERIFY ( utils::to_uint64(p->attrs["id"], id),
      ("Unknown element with invalid id : ", p->attrs["id"]) );

    // try to get type from element tags
    ftype::GetNameAndType(p, fValue.types, fValue.name, fValue.layer);

    // try to get type from relations tags
    m_typeProcessor.Reset(id, &fValue);

    if (p->name == "node" && !fValue.IsValid())
    {
      // additional process of nodes ONLY if there is no native types
      m_holder.ForEachRelationByNodeCached(id, m_typeProcessor);
    }
    else if (p->name == "way")
    {
      // always make additional process of ways
      m_holder.ForEachRelationByWayCached(id, m_typeProcessor);
    }

    // remove duplicating types
    sort(fValue.types.begin(), fValue.types.end());
    fValue.types.erase(unique(fValue.types.begin(), fValue.types.end()), fValue.types.end());

    // unrecognized feature by classificator
    return fValue.IsValid();
  }
};

/*
template <class TEmitter, class THolder>
class SecondPassParserJoin : public SecondPassParserBase<TEmitter, THolder>
{
  typedef SecondPassParserBase<TEmitter, THolder> base_type;

  set<uint64_t> m_usedDirect;

  bool TryEmitUnited(uint64_t featureID, typename base_type::feature_builder_t & ft)
  {
    // check, if feature already processed early
    if (m_usedDirect.count(featureID) > 0)
      return true;

    set<uint64_t> path;
    path.insert(featureID);

    WayElement e;

    // process geometry of initial way itself
    base_type::m_holder.GetWay(featureID, e);
    if (e.nodes.empty())
      return false;

    for (size_t i = 0; i < e.nodes.size(); ++i)
    {
      m2::PointD pt;
      if (base_type::GetPoint(e.nodes[i], pt))
        ft.AddPoint(pt);
      else
        return false;
    }

    // process connected ways in cycle while ...
    uint64_t fID = featureID;
    while (!ft.IsGeometryClosed())
    {
      uint64_t const nodeID = e.nodes.back();
      if (!base_type::m_holder.GetNextWay(fID, nodeID, e))
        break;

      if (!path.insert(fID).second)
      {
        LOG_SHORT(LWARNING, ("JOIN_DBG! Cycle found during way joining, duplicate id = ", fID));
        break;
      }

      // skip first point, because it's equal with previous
      size_t i;
      int inc;
      if (e.nodes.front() == nodeID)
      {
        i = 1;
        inc = 1;
      }
      else
      {
        ASSERT ( e.nodes.back() == nodeID, () );

        i = e.nodes.size() - 2;
        inc = -1;
      }

      size_t count = 1;
      while (count++ < e.nodes.size())
      {
        m2::PointD pt;
        if (base_type::GetPoint(e.nodes[i], pt))
          ft.AddPoint(pt);
        else
          return false;

        i += inc;
      }
    }

    if (ft.IsGeometryClosed())
    {
      m_usedDirect.insert(path.begin(), path.end());

      base_type::FinishAreaFeature(featureID, ft);

      base_type::m_emitter(ft);
      return true;
    }
    else
    {
      LOG_SHORT(LWARNING, ("JOIN_DBG! Ways not connected for root way = ", featureID));
      return false;
    }
  }

protected:
  virtual void EmitElement(XMLElement * p)
  {
    uint64_t id;
    typename base_type::value_t fValue;
    if (!ParseType(p, id, fValue))
      return;

    // check, if we can make united feature
    for (typename base_type::value_t::types_t::iterator i = fValue.types.begin(); i != fValue.types.end(); ++i)
      if (feature::NeedUnite(*i))
      {
        typename base_type::feature_builder_t ft;
        ft.AddName(fValue.name);
        ft.AddTypes(fValue.types.begin(), fValue.types.end());
        ft.AddLayer(fValue.layer);

        TryEmitUnited(id, ft);
        break;
      }
  }

public:
  SecondPassParserJoin(TEmitter & emitter, THolder & holder)
    : base_type(emitter, holder)
  {
  }
};
*/

template <class TEmitter, class THolder>
class SecondPassParserUsual : public SecondPassParserBase<TEmitter, THolder>
{
  typedef SecondPassParserBase<TEmitter, THolder> base_type;

protected:
  virtual void EmitElement(XMLElement * p)
  {
    uint64_t id;
    typename base_type::value_t fValue;
    if (!ParseType(p, id, fValue))
      return;

    typename base_type::feature_builder_t ft;
    ft.AddName(fValue.name);
    ft.AddTypes(fValue.types.begin(), fValue.types.end());
    ft.AddLayer(fValue.layer);

    if (p->name == "node")
    {
      if (!feature::IsDrawableLike(fValue.types, feature::fpoint))
        return;

      m2::PointD pt;
      if (p->childs.empty() || !base_type::GetPoint(id, pt))
        return;

      ft.SetCenter(pt);
    }
    else if (p->name == "way")
    {
      bool const isLine = feature::IsDrawableLike(fValue.types, feature::fline);
      bool const isArea = feature::IsDrawableLike(fValue.types, feature::farea);

      if (!isLine && !isArea)
        return;

      // geometry of feature
      for (size_t i = 0; i < p->childs.size(); ++i)
      {
        if (p->childs[i].name == "nd")
        {
          uint64_t nodeID;
          VERIFY ( utils::to_uint64(p->childs[i].attrs["ref"], nodeID),
                   ("Bad node ref in way : ", p->childs[i].attrs["ref"]) );

          m2::PointD pt;
          if (!base_type::GetPoint(nodeID, pt))
            return;

          ft.AddPoint(pt);
        }
      }

      size_t const count = ft.GetPointsCount();
      if (count < 2)
        return;

      if (isLine)
        ft.SetLinear();

      // Get the tesselation for an area object (only if it has area drawing rules,
      // otherwise it will stay a linear object).
      if (isArea && count > 2 && ft.IsGeometryClosed())
        base_type::FinishAreaFeature(id, ft);
    }
    else if (p->name == "relation")
    {
      if (!feature::IsDrawableLike(fValue.types, feature::farea))
        return;

      // check, if this is our processable relation
      bool isProcess = false;
      for (size_t i = 0; i < p->childs.size(); ++i)
      {
        if (p->childs[i].name == "tag" &&
            p->childs[i].attrs["k"] == "type" &&
            p->childs[i].attrs["v"] == "multipolygon")
        {
          isProcess = true;
        }
      }
      if (!isProcess)
        return;

      holes_accumulator holes(this);

      // iterate ways to get 'outer' and 'inner' geometries
      for (size_t i = 0; i < p->childs.size(); ++i)
      {
        if (p->childs[i].name == "member" &&
            p->childs[i].attrs["type"] == "way")
        {
          string const & role = p->childs[i].attrs["role"];
          uint64_t wayID;
          VERIFY ( utils::to_uint64(p->childs[i].attrs["ref"], wayID),
            ("Bad way ref in relation : ", p->childs[i].attrs["ref"]) );

          if (role == "outer")
          {
            ForEachWayPoint(wayID, bind(&base_type::feature_builder_t::AddPoint, ref(ft), _1));
          }
          else if (role == "inner")
          {
            holes(wayID);
          }
        }
      }

      if (ft.IsGeometryClosed())
        ft.SetAreaAddHoles(holes.m_holes);
    }

    if (ft.PreSerialize())
      base_type::m_emitter(ft);
  }

public:
  SecondPassParserUsual(TEmitter & emitter, THolder & holder)
    : base_type(emitter, holder)
  {
  }
};

#include "../../base/stop_mem_debug.hpp"
<|endoftext|>


<commit_before>
// Copyright **********************************************************
//
// IBM Confidential
// OCO Source Materials
// 9400 Licensed Internal Code
// (C) COPYRIGHT IBM CORP. 2003
//
// The source code for this program is not published or otherwise
// divested of its trade secrets, irrespective of what has been
// deposited with the U.S. Copyright Office.
//
// End Copyright ******************************************************
/* $Header$ */

//--------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------
#include <string.h>
#include <stdio.h>
#include <ctype.h>

// Include the Swig Perl headers for Croak
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include <ecmdClientCapi.H>
#include <ecmdReturnCodes.H>
#include <ecmdUtils.H>
#include <ecmdClientPerlapi.H>
#include <ecmdClientPerlapiFunc.H>
#include <ecmdSharedUtils.H>

static int myErrorCode = ECMD_SUCCESS;
static bool safeMode = true;

int ECMDPERLAPI::ecmdPerlInterfaceErrorCheck (int errorCode) {

  if (errorCode == -1) {
    errorCode = myErrorCode;
    myErrorCode = ECMD_SUCCESS;

    if (errorCode != ECMD_SUCCESS) {
      ::ecmdOutputError( (::ecmdGetErrorMsg(errorCode) + "\n").c_str());
    }

    return errorCode;
  }
  else if (errorCode != ECMD_SUCCESS) {
    myErrorCode = errorCode;
  }

  return ECMD_SUCCESS;
}

bool ECMDPERLAPI::ecmdQuerySafeMode() {
  return safeMode;
}

void ECMDPERLAPI::ecmdDisablePerlSafeMode() { safeMode = false; }

void ECMDPERLAPI::ecmdEnablePerlSafeMode() { safeMode = true; }

void ECMDPERLAPI::ecmdUnloadDll()  {
  ::ecmdUnloadDll();
}

int ECMDPERLAPI::ecmdLoadDll (const char * i_dllName, const char * i_clientVersion) {

  int rc = ECMD_SUCCESS;
  std::string dllName = "";
  if (i_dllName != NULL) {
    dllName = i_dllName;
  }

  rc = ::ecmdLoadDll(dllName);
  ecmdPerlInterfaceErrorCheck(rc);

  /* Check our Perl Major Version */
  char perlVersion[10];
  strcpy(perlVersion,ECMD_PERLAPI_VERSION);
  int majorlength = (int)(strchr(perlVersion, '.') - perlVersion);
  /* Strip off the minor version */
  perlVersion[majorlength] = '\0';

  if (!strstr(i_clientVersion,perlVersion)) {
    fprintf(stderr,"**** FATAL : eCMD Perl Module and your client major version numbers don't match, they are not compatible\n");
    fprintf(stderr,"**** FATAL : Client Version(s) : %s   : Perl Module Version : %s\n",i_clientVersion, ECMD_PERLAPI_VERSION);

    croak("(ecmdClientPerlapi::initDll) :: Perl Module version mismatch - execution halted\n");
  }

  return rc;

}

int ECMDPERLAPI::ecmdCommandArgs(char** i_argv){

  int rc =0;
  int looper =0;

  while(i_argv[looper] != NULL) looper++;

  rc = ::ecmdCommandArgs(&looper, &i_argv);

  ecmdPerlInterfaceErrorCheck(rc);
  return rc;
}

/* This is overwritten because the retval is a number not a return code */
uint32_t ECMDPERLAPI::simFusionRand32(uint32_t i_min , uint32_t i_max , const char* i_fusionRandObject ) {
  return ::simFusionRand32(i_min, i_max, i_fusionRandObject);
}

/* This is overwritten because the retval is a number not a return code */
uint64_t ECMDPERLAPI::simFusionRand64(uint64_t i_min , uint64_t i_max , const char* i_fusionRandObject ) {
  return ::simFusionRand64(i_min, i_max, i_fusionRandObject);
}

/* This is overwritten to handle passing in NULL for ringName */
uint32_t ECMDPERLAPI::getLatch(ecmdChipTarget & i_target, const char* i_ringName, const char * i_latchName, std::list<ecmdLatchEntry> & o_data, ecmdLatchMode_t i_mode) {
  uint32_t rc = ECMD_SUCCESS;
  if (strlen(i_ringName) == 0)
    rc = ::getLatch(i_target, NULL, i_latchName, o_data, i_mode);
  else
    rc = ::getLatch(i_target, i_ringName, i_latchName, o_data, i_mode);
  ECMDPERLAPI::ecmdPerlInterfaceErrorCheck(rc);
  return rc;
}

/* This is overwritten to handle passing in NULL for ringName */
uint32_t ECMDPERLAPI::putLatch(ecmdChipTarget & i_target, const char* i_ringName, const char * i_latchName, ecmdDataBuffer & i_data, uint32_t i_startBit, uint32_t i_numBits, uint32_t & o_matchs, ecmdLatchMode_t i_mode) {
  uint32_t rc = ECMD_SUCCESS;
  if (strlen(i_ringName) == 0)
    rc = ::putLatch(i_target, NULL, i_latchName, i_data, i_startBit, i_numBits, o_matchs, i_mode);
  else
    rc = ::putLatch(i_target, i_ringName, i_latchName, i_data, i_startBit, i_numBits, o_matchs, i_mode);
  ECMDPERLAPI::ecmdPerlInterfaceErrorCheck(rc);
  return rc;
}

<commit_msg>Removed fusion64 function<commit_after>
// Copyright **********************************************************
//
// IBM Confidential
// OCO Source Materials
// 9400 Licensed Internal Code
// (C) COPYRIGHT IBM CORP. 2003
//
// The source code for this program is not published or otherwise
// divested of its trade secrets, irrespective of what has been
// deposited with the U.S. Copyright Office.
//
// End Copyright ******************************************************
/* $Header$ */

//--------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------
#include <string.h>
#include <stdio.h>
#include <ctype.h>

// Include the Swig Perl headers for Croak
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include <ecmdClientCapi.H>
#include <ecmdReturnCodes.H>
#include <ecmdUtils.H>
#include <ecmdClientPerlapi.H>
#include <ecmdClientPerlapiFunc.H>
#include <ecmdSharedUtils.H>

static int myErrorCode = ECMD_SUCCESS;
static bool safeMode = true;

int ECMDPERLAPI::ecmdPerlInterfaceErrorCheck (int errorCode) {

  if (errorCode == -1) {
    errorCode = myErrorCode;
    myErrorCode = ECMD_SUCCESS;

    if (errorCode != ECMD_SUCCESS) {
      ::ecmdOutputError( (::ecmdGetErrorMsg(errorCode) + "\n").c_str());
    }

    return errorCode;
  }
  else if (errorCode != ECMD_SUCCESS) {
    myErrorCode = errorCode;
  }

  return ECMD_SUCCESS;
}

bool ECMDPERLAPI::ecmdQuerySafeMode() {
  return safeMode;
}

void ECMDPERLAPI::ecmdDisablePerlSafeMode() { safeMode = false; }

void ECMDPERLAPI::ecmdEnablePerlSafeMode() { safeMode = true; }

void ECMDPERLAPI::ecmdUnloadDll()  {
  ::ecmdUnloadDll();
}

int ECMDPERLAPI::ecmdLoadDll (const char * i_dllName, const char * i_clientVersion) {

  int rc = ECMD_SUCCESS;
  std::string dllName = "";
  if (i_dllName != NULL) {
    dllName = i_dllName;
  }

  rc = ::ecmdLoadDll(dllName);
  ecmdPerlInterfaceErrorCheck(rc);

  /* Check our Perl Major Version */
  char perlVersion[10];
  strcpy(perlVersion,ECMD_PERLAPI_VERSION);
  int majorlength = (int)(strchr(perlVersion, '.') - perlVersion);
  /* Strip off the minor version */
  perlVersion[majorlength] = '\0';

  if (!strstr(i_clientVersion,perlVersion)) {
    fprintf(stderr,"**** FATAL : eCMD Perl Module and your client major version numbers don't match, they are not compatible\n");
    fprintf(stderr,"**** FATAL : Client Version(s) : %s   : Perl Module Version : %s\n",i_clientVersion, ECMD_PERLAPI_VERSION);

    croak("(ecmdClientPerlapi::initDll) :: Perl Module version mismatch - execution halted\n");
  }

  return rc;

}

int ECMDPERLAPI::ecmdCommandArgs(char** i_argv){

  int rc =0;
  int looper =0;

  while(i_argv[looper] != NULL) looper++;

  rc = ::ecmdCommandArgs(&looper, &i_argv);

  ecmdPerlInterfaceErrorCheck(rc);
  return rc;
}

/* This is overwritten because the retval is a number not a return code */
uint32_t ECMDPERLAPI::simFusionRand32(uint32_t i_min , uint32_t i_max , const char* i_fusionRandObject ) {
  return ::simFusionRand32(i_min, i_max, i_fusionRandObject);
}

/* This is overwritten to handle passing in NULL for ringName */
uint32_t ECMDPERLAPI::getLatch(ecmdChipTarget & i_target, const char* i_ringName, const char * i_latchName, std::list<ecmdLatchEntry> & o_data, ecmdLatchMode_t i_mode) {
  uint32_t rc = ECMD_SUCCESS;
  if (strlen(i_ringName) == 0)
    rc = ::getLatch(i_target, NULL, i_latchName, o_data, i_mode);
  else
    rc = ::getLatch(i_target, i_ringName, i_latchName, o_data, i_mode);
  ECMDPERLAPI::ecmdPerlInterfaceErrorCheck(rc);
  return rc;
}

/* This is overwritten to handle passing in NULL for ringName */
uint32_t ECMDPERLAPI::putLatch(ecmdChipTarget & i_target, const char* i_ringName, const char * i_latchName, ecmdDataBuffer & i_data, uint32_t i_startBit, uint32_t i_numBits, uint32_t & o_matchs, ecmdLatchMode_t i_mode) {
  uint32_t rc = ECMD_SUCCESS;
  if (strlen(i_ringName) == 0)
    rc = ::putLatch(i_target, NULL, i_latchName, i_data, i_startBit, i_numBits, o_matchs, i_mode);
  else
    rc = ::putLatch(i_target, i_ringName, i_latchName, i_data, i_startBit, i_numBits, o_matchs, i_mode);
  ECMDPERLAPI::ecmdPerlInterfaceErrorCheck(rc);
  return rc;
}

<|endoftext|>