int point_in(VngoPointF &pt) {return point_in(int(pt.x),int(pt.y));}
void LaserProjection::transformLaserScanToPointCloud_ (const std::string &target_frame, const sensor_msgs::LaserScan &scan_in, sensor_msgs::PointCloud2 &cloud_out, tf::Transformer &tf, double range_cutoff, int channel_options) { //check if the user has requested the index field bool requested_index = false; if ((channel_options & channel_option::Index)) requested_index = true; //we'll enforce that we get index values for the laser scan so that we //ensure that we use the correct timestamps channel_options |= channel_option::Index; projectLaser_(scan_in, cloud_out, -1.0, channel_options); //we'll assume no associated viewpoint by default bool has_viewpoint = false; uint32_t vp_x_offset = 0; //we need to find the offset of the intensity field in the point cloud //we also know that the index field is guaranteed to exist since we //set the channel option above. To be really safe, it might be worth //putting in a check at some point, but I'm just going to put in an //assert for now uint32_t index_offset = 0; for(unsigned int i = 0; i < cloud_out.fields.size(); ++i) { if(cloud_out.fields[i].name == "index") { index_offset = cloud_out.fields[i].offset; } //we want to check if the cloud has a viewpoint associated with it //checking vp_x should be sufficient since vp_x, vp_y, and vp_z all //get put in together if(cloud_out.fields[i].name == "vp_x") { has_viewpoint = true; vp_x_offset = cloud_out.fields[i].offset; } } ROS_ASSERT(index_offset > 0); cloud_out.header.frame_id = target_frame; // Extract transforms for the beginning and end of the laser scan ros::Time start_time = scan_in.header.stamp; ros::Time end_time = scan_in.header.stamp + ros::Duration ().fromSec (scan_in.ranges.size () * scan_in.time_increment); tf::StampedTransform start_transform, end_transform, cur_transform ; tf.lookupTransform (target_frame, scan_in.header.frame_id, start_time, start_transform); tf.lookupTransform (target_frame, scan_in.header.frame_id, end_time, end_transform); double ranges_norm = 1 / ((double) scan_in.ranges.size () - 1.0); //we want to loop through all the points in the cloud for(size_t i = 0; i < cloud_out.width; ++i) { // Apply the transform to the current point float *pstep = (float*)&cloud_out.data[i * cloud_out.point_step + 0]; //find the index of the point uint32_t pt_index; memcpy(&pt_index, &cloud_out.data[i * cloud_out.point_step + index_offset], sizeof(uint32_t)); // Assume constant motion during the laser-scan, and use slerp to compute intermediate transforms tfScalar ratio = pt_index * ranges_norm; //! \todo Make a function that performs both the slerp and linear interpolation needed to interpolate a Full Transform (Quaternion + Vector) // Interpolate translation tf::Vector3 v (0, 0, 0); v.setInterpolate3 (start_transform.getOrigin (), end_transform.getOrigin (), ratio); cur_transform.setOrigin (v); // Interpolate rotation tf::Quaternion q1, q2; start_transform.getBasis ().getRotation (q1); end_transform.getBasis ().getRotation (q2); // Compute the slerp-ed rotation cur_transform.setRotation (slerp (q1, q2 , ratio)); tf::Vector3 point_in (pstep[0], pstep[1], pstep[2]); tf::Vector3 point_out = cur_transform * point_in; // Copy transformed point into cloud pstep[0] = point_out.x (); pstep[1] = point_out.y (); pstep[2] = point_out.z (); // Convert the viewpoint as well if(has_viewpoint) { float *vpstep = (float*)&cloud_out.data[i * cloud_out.point_step + vp_x_offset]; point_in = tf::Vector3 (vpstep[0], vpstep[1], vpstep[2]); point_out = cur_transform * point_in; // Copy transformed point into cloud vpstep[0] = point_out.x (); vpstep[1] = point_out.y (); vpstep[2] = point_out.z (); } } //if the user didn't request the index field, then we need to copy the PointCloud and drop it if(!requested_index) { sensor_msgs::PointCloud2 cloud_without_index; //copy basic meta data cloud_without_index.header = cloud_out.header; cloud_without_index.width = cloud_out.width; cloud_without_index.height = cloud_out.height; cloud_without_index.is_bigendian = cloud_out.is_bigendian; cloud_without_index.is_dense = cloud_out.is_dense; //copy the fields cloud_without_index.fields.resize(cloud_out.fields.size()); unsigned int field_count = 0; unsigned int offset_shift = 0; for(unsigned int i = 0; i < cloud_out.fields.size(); ++i) { if(cloud_out.fields[i].name != "index") { cloud_without_index.fields[field_count] = cloud_out.fields[i]; cloud_without_index.fields[field_count].offset -= offset_shift; ++field_count; } else { //once we hit the index, we'll set the shift offset_shift = 4; } } //resize the fields cloud_without_index.fields.resize(field_count); //compute the size of the new data cloud_without_index.point_step = cloud_out.point_step - offset_shift; cloud_without_index.row_step = cloud_without_index.point_step * cloud_without_index.width; cloud_without_index.data.resize (cloud_without_index.row_step * cloud_without_index.height); uint32_t i = 0; uint32_t j = 0; //copy over the data from one cloud to the other while (i < cloud_out.data.size()) { if((i % cloud_out.point_step) < index_offset || (i % cloud_out.point_step) >= (index_offset + 4)) { cloud_without_index.data[j++] = cloud_out.data[i]; } i++; } //make sure to actually set the output cloud_out = cloud_without_index; } }
int point_in(VngoPoint &pt) {return point_in(pt.x,pt.y);}