42 pcl::PointCloud<PointT>::ConstPtr cloud_,
43 pcl::PointCloud<PointN>::ConstPtr normals_,
44 pcl::PointCloud<PointL>::ConstPtr labels_,
const double grid_size) ->
void {
46 using RTCVertex =
struct RTCVertex {
50 using RTCNormal =
struct RTCNormal {
54 using RTCData =
struct RTCData {
60 assert(cloud_->size() == labels_->size() &&
61 "Point cloud and label cloud must have the same size");
62 assert(cloud_->size() == normals_->size() &&
63 "Point cloud and normal cloud must have the same size");
65 const double radius_ = grid_size * M_SQRT2;
68 "Using ray tracing for {} points with grid size {:.3} and radius {:.3}",
69 cloud_->size(), grid_size, radius_);
72 "c:room_probabilities")
76 std::vector<unsigned int> labels;
77 labels.reserve(labels_->points.size());
79 for (
const auto &p : labels_->points)
80 if (p.label !=
static_cast<unsigned int>(-1))
81 labels.push_back(p.label);
83 std::sort(labels.begin(), labels.end());
84 labels.erase(std::unique(labels.begin(), labels.end()), labels.end());
88 c_rp[*cit] = std::vector<double>(labels.size() + 1, 0.0);
92 unsigned int old_mxcsr = _mm_getcsr();
93 _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
94 _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
97 RTCDevice device_ = rtcNewDevice(
"verbose=0");
98 RTCScene scene_ = rtcNewScene(device_);
99 rtcSetSceneFlags(scene_, RTC_SCENE_FLAG_ROBUST);
100 rtcSetSceneBuildQuality(scene_, RTC_BUILD_QUALITY_HIGH);
101 assert(device_ !=
nullptr &&
"Error creating Embree device");
102 assert(scene_ !=
nullptr &&
"Error creating Embree scene");
103 rtcSetDeviceErrorFunction(
105 [](
void *, RTCError err,
const char *str) {
110 case RTC_ERROR_UNKNOWN:
111 throw std::runtime_error(
"Embree: An unknown error has occurred.");
113 case RTC_ERROR_INVALID_ARGUMENT:
114 throw std::runtime_error(
115 "Embree: An invalid argument was specified.");
117 case RTC_ERROR_INVALID_OPERATION:
118 throw std::runtime_error(
119 "Embree: The operation is not allowed for the specified object.");
121 case RTC_ERROR_OUT_OF_MEMORY:
122 throw std::runtime_error(
"Embree: There is not enough memory left to "
123 "complete the operation.");
125 case RTC_ERROR_UNSUPPORTED_CPU:
126 throw std::runtime_error(
127 "Embree: The CPU is not supported as it does not support SSE2.");
129 case RTC_ERROR_CANCELLED:
130 throw std::runtime_error(
131 "Embree: The operation got cancelled by an Memory Monitor "
132 "Callback or Progress Monitor Callback function.");
135 throw std::runtime_error(
"Embree: An invalid error has occurred.");
144 pcl::UniformSampling<PointT> us;
145 us.setInputCloud(cloud_);
146 us.setRadiusSearch(grid_size);
148 using RTCDataPtr = std::shared_ptr<RTCData>;
149 std::vector<RTCDataPtr> rtc_data_vec{};
150 for (
size_t i = 0; i < labels.size(); ++i) {
152 pcl::IndicesPtr indices(
new pcl::Indices);
153 for (
size_t j = 0; j < cloud_->size(); ++j)
154 if (labels_->points[j].label == labels[i])
155 indices->push_back(
static_cast<int>(j));
160 us.setIndices(indices);
166 RTCGeometry geometry_ =
167 rtcNewGeometry(device_, RTC_GEOMETRY_TYPE_ORIENTED_DISC_POINT);
169 RTCVertex *vb = (RTCVertex *)rtcSetNewGeometryBuffer(
170 geometry_, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT4,
171 sizeof(RTCVertex), indices->size());
173 RTCNormal *nb = (RTCNormal *)rtcSetNewGeometryBuffer(
174 geometry_, RTC_BUFFER_TYPE_NORMAL, 0, RTC_FORMAT_FLOAT3,
175 sizeof(RTCNormal), indices->size());
177 for (
size_t i = 0; i < indices->size(); ++i) {
178 const auto &p = cloud_->points[indices->at(i)];
179 const auto &n = normals_->points[indices->at(i)];
181 vb[i].x =
static_cast<float>(p.x);
182 vb[i].y =
static_cast<float>(p.y);
183 vb[i].z =
static_cast<float>(p.z);
184 vb[i].r =
static_cast<float>(radius_) * 1.05f;
186 nb[i].x =
static_cast<float>(n.normal_x);
187 nb[i].y =
static_cast<float>(n.normal_y);
188 nb[i].z =
static_cast<float>(n.normal_z);
191 rtc_data_vec.emplace_back(
new RTCData{i});
192 rtcSetGeometryUserData(geometry_, rtc_data_vec.back().get());
194 rtcCommitGeometry(geometry_);
195 rtcAttachGeometry(scene_, geometry_);
196 rtcReleaseGeometry(geometry_);
200 rtcCommitScene(scene_);
206 "Computing room probabilities", this->
num_cells());
208#pragma omp parallel for schedule(dynamic)
209 for (
size_t cell_idx = 0; cell_idx < this->
num_cells(); ++cell_idx) {
211 std::advance(cit, cell_idx);
216 std::vector<double> local_accum(c_rp[*cit].size(), 0.0);
217 double *accum_ptr = local_accum.data();
218 const int N =
static_cast<int>(c_rp[*cit].size());
220#pragma omp parallel for reduction(+ : accum_ptr[ : N])
221 for (
size_t i = 0; i < dirs.size(); ++i) {
222 const auto dir = dirs[i];
223 auto c = (*this)[*cit].pos;
226 rayhit.ray.org_x =
static_cast<float>(c.x());
227 rayhit.ray.org_y =
static_cast<float>(c.y());
228 rayhit.ray.org_z =
static_cast<float>(c.z());
229 rayhit.ray.dir_x =
static_cast<float>(dir.x());
230 rayhit.ray.dir_y =
static_cast<float>(dir.y());
231 rayhit.ray.dir_z =
static_cast<float>(dir.z());
233 rayhit.ray.tnear = 0.001f;
234 rayhit.ray.tfar = std::numeric_limits<float>::infinity();
235 rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
237 rayhit.ray.mask = -1;
238 rayhit.ray.flags = 0;
239 rayhit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
241 rtcIntersect1(scene_, &rayhit);
243 if (rayhit.hit.geomID == RTC_INVALID_GEOMETRY_ID) {
252 Eigen::Vector3f(rayhit.hit.Ng_x, rayhit.hit.Ng_y, rayhit.hit.Ng_z)
254 const Eigen::Vector3f dir_vec(dir.x(), dir.y(), dir.z());
255 if (normal.dot(dir_vec) > 0) {
264 auto geometry = rtcGetGeometry(scene_, rayhit.hit.geomID);
266 RTCData *data = (RTCData *)rtcGetGeometryUserData(
geometry);
273 accum_ptr[data->label_index + 1] += 1;
285 for (
auto &p : local_accum)
287 c_rp[*cit] = std::move(local_accum);
292 rtcReleaseScene(scene_);
293 rtcReleaseDevice(device_);
295 _mm_setcsr(old_mxcsr);
298 auto sum_results = std::vector<double>(labels.size() + 1, 0.0);
300 for (
size_t i = 0; i < c_rp[*cit].size(); ++i)
301 sum_results[i] += c_rp[*cit][i];
303 fmt::join(sum_results,
", "));