|
|
@ -1,3 +1,5 @@ |
|
|
|
#include <concurrent_vector.h> |
|
|
|
|
|
|
|
#include <algorithm/glue_algorithm.hpp> |
|
|
|
|
|
|
|
#include "internal_primitive_desc.hpp" |
|
|
@ -7,6 +9,7 @@ static inline auto manually_projection(const raw_vector3d_t & |
|
|
|
const Eigen::Ref<const Eigen::Vector3d> &y_dir, |
|
|
|
const Eigen::Ref<const Eigen::Vector2d> &offset) |
|
|
|
{ |
|
|
|
Eigen::aligned_allocator<Eigen::Vector2d> allocator; |
|
|
|
Eigen::Vector3d p; |
|
|
|
vec3d_conversion(point, p); |
|
|
|
return Eigen::Vector2d{p.dot(x_dir), p.dot(y_dir)} + offset; |
|
|
@ -26,13 +29,13 @@ namespace internal |
|
|
|
{ |
|
|
|
void polyline::build_as_axis(const polyline_descriptor_t &desc, |
|
|
|
const raw_vector3d_t &profile_ref_normal, |
|
|
|
Eigen::Transform<double, 3, Eigen::AffineCompact> &axis_to_world, |
|
|
|
Eigen::Transform<double, 3, Eigen::AffineCompact, Eigen::DontAlign> &axis_to_world, |
|
|
|
aabb_t<> &aabb) |
|
|
|
{ |
|
|
|
auto &matrix_handle = axis_to_world.matrix(); |
|
|
|
vec3d_conversion(profile_ref_normal, matrix_handle.col(1)); |
|
|
|
vec3d_conversion(desc.reference_normal, matrix_handle.col(1)); |
|
|
|
matrix_handle.col(1).normalize(); |
|
|
|
vec3d_conversion(desc.reference_normal, matrix_handle.col(2)); |
|
|
|
vec3d_conversion(profile_ref_normal, matrix_handle.col(2)); |
|
|
|
matrix_handle.col(2).normalize(); |
|
|
|
matrix_handle.col(0) = matrix_handle.col(1).cross(matrix_handle.col(2)); |
|
|
|
vec3d_conversion(desc.points[0], matrix_handle.col(3)); |
|
|
@ -50,13 +53,13 @@ void polyline::build_as_axis(const polyline_descriptor_t & |
|
|
|
|
|
|
|
void polyline::build_as_axis(polyline_descriptor_t &&desc, |
|
|
|
const raw_vector3d_t &profile_ref_normal, |
|
|
|
Eigen::Transform<double, 3, Eigen::AffineCompact> &axis_to_world, |
|
|
|
Eigen::Transform<double, 3, Eigen::AffineCompact, Eigen::DontAlign> &axis_to_world, |
|
|
|
aabb_t<> &aabb) |
|
|
|
{ |
|
|
|
auto &matrix_handle = axis_to_world.matrix(); |
|
|
|
vec3d_conversion(profile_ref_normal, matrix_handle.col(1)); |
|
|
|
vec3d_conversion(std::move(desc.reference_normal), matrix_handle.col(1)); |
|
|
|
matrix_handle.col(1).normalize(); |
|
|
|
vec3d_conversion(std::move(desc.reference_normal), matrix_handle.col(2)); |
|
|
|
vec3d_conversion(profile_ref_normal, matrix_handle.col(2)); |
|
|
|
matrix_handle.col(2).normalize(); |
|
|
|
matrix_handle.col(0) = matrix_handle.col(1).cross(matrix_handle.col(2)); |
|
|
|
vec3d_conversion(desc.points[0], matrix_handle.col(3)); |
|
|
@ -84,69 +87,54 @@ void polyline::build_as_profile(const polyline_descriptor_t &desc, |
|
|
|
// collect indices info
|
|
|
|
this->thetas.resize(desc.bulge_number); |
|
|
|
this->start_indices.resize(desc.bulge_number + 1, uint8_t{0}); |
|
|
|
stl_vector<uint8_t> line_start_indices(desc.bulge_number + 1), circle_start_indices(desc.bulge_number + 1); |
|
|
|
if (this->start_indices.size() > 16) { |
|
|
|
std::atomic_size_t line_start_indices_offset{0}; |
|
|
|
std::atomic_size_t circle_start_indices_offset{0}; |
|
|
|
Concurrency::concurrent_vector<uint8_t, tbb::tbb_allocator<uint8_t>> circle_start_indices{}; |
|
|
|
circle_start_indices.reserve(desc.bulge_number + 1); |
|
|
|
std::transform_inclusive_scan(std::execution::par_unseq, |
|
|
|
counting_iterator<size_t>{}, |
|
|
|
counting_iterator<size_t>{this->start_indices.size()}, |
|
|
|
this->start_indices.begin() + 1, |
|
|
|
std::plus<uint8_t>{}, |
|
|
|
[&](size_t index) { |
|
|
|
auto &theta = this->thetas[index]; |
|
|
|
theta = std::atan(fabs(desc.bulges[index])) * 4; |
|
|
|
if (theta <= EPSILON) { |
|
|
|
const auto offset = line_start_indices_offset.fetch_add(1); |
|
|
|
line_start_indices[offset] = index; |
|
|
|
return uint8_t{1}; |
|
|
|
} else { |
|
|
|
const auto offset = circle_start_indices_offset.fetch_add(1); |
|
|
|
return uint8_t{3}; |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
size_t line_start_indices_offset{0}; |
|
|
|
size_t circle_start_indices_offset{0}; |
|
|
|
std::transform_inclusive_scan(counting_iterator<size_t>{}, |
|
|
|
counting_iterator<size_t>{this->start_indices.size()}, |
|
|
|
counting_iterator<size_t>{desc.bulge_number}, |
|
|
|
this->start_indices.begin() + 1, |
|
|
|
std::plus<uint8_t>{}, |
|
|
|
[&](size_t index) { |
|
|
|
auto &theta = this->thetas[index]; |
|
|
|
theta = std::atan(fabs(desc.bulges[index])) * 4; |
|
|
|
if (theta <= EPSILON) { |
|
|
|
line_start_indices[line_start_indices_offset++] = index; |
|
|
|
return uint8_t{1}; |
|
|
|
} else { |
|
|
|
circle_start_indices[circle_start_indices_offset++] = index; |
|
|
|
circle_start_indices.push_back(static_cast<uint8_t>(index)); |
|
|
|
return uint8_t{3}; |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
// i.e. iff close curve, deduce loop to simple segements by copying the first vertex to the end
|
|
|
|
this->vertices.resize(this->start_indices.back() + static_cast<size_t>(desc.is_close)); |
|
|
|
this->vertices.resize(this->start_indices.back() + 1); |
|
|
|
this->start_indices.pop_back(); |
|
|
|
circle_start_indices.shrink_to_fit(); |
|
|
|
|
|
|
|
const Eigen::Vector2d offset = {-proj_x_dir.dot(proj_origin), -proj_y_dir.dot(proj_origin)}; |
|
|
|
|
|
|
|
// first loop: process all line segment vertices
|
|
|
|
algorithm::for_loop(size_t{}, line_start_indices.size(), [&](size_t i) { |
|
|
|
const auto &index = line_start_indices[i]; |
|
|
|
const auto &start_index = this->start_indices[index]; |
|
|
|
auto &v = this->vertices[start_index]; |
|
|
|
v = manually_projection(desc.points[index], proj_x_dir, proj_y_dir, offset); |
|
|
|
// first loop: process all start vertices
|
|
|
|
algorithm::for_loop(size_t{}, this->start_indices.size(), [&](size_t i) { |
|
|
|
const auto &index = this->start_indices[i]; |
|
|
|
auto &v = this->vertices[index]; |
|
|
|
v = manually_projection(desc.points[i], proj_x_dir, proj_y_dir, offset); |
|
|
|
aabb.extend(v); |
|
|
|
}); |
|
|
|
if (desc.is_close) this->vertices.back() = this->vertices.front(); |
|
|
|
// ways to handle the last vertex:
|
|
|
|
// iff close curve, deduce loop to simple segements by copying the first vertex to the end
|
|
|
|
// if not, then process the last vertex
|
|
|
|
if (desc.is_close) |
|
|
|
this->vertices.back() = this->vertices.front(); |
|
|
|
else { |
|
|
|
auto &v = this->vertices.back(); |
|
|
|
v = manually_projection(desc.points[desc.point_number - 1], proj_x_dir, proj_y_dir, offset); |
|
|
|
aabb.extend(v); |
|
|
|
} |
|
|
|
|
|
|
|
// second loop: process all circle vertices
|
|
|
|
algorithm::for_loop(size_t{}, circle_start_indices.size(), [&](size_t i) { |
|
|
|
const auto &index = line_start_indices[i]; |
|
|
|
const auto &index = circle_start_indices[i]; |
|
|
|
const auto &start_index = this->start_indices[index]; |
|
|
|
const auto &bulge = desc.bulges[index]; |
|
|
|
const auto &theta = this->thetas[index]; |
|
|
|
this->vertices[start_index] = manually_projection(desc.points[index], proj_x_dir, proj_y_dir, offset); |
|
|
|
|
|
|
|
const auto &a = this->vertices[start_index]; |
|
|
|
const auto &b = this->vertices[start_index + 3]; |
|
|
@ -168,7 +156,6 @@ void polyline::build_as_profile(const polyline_descriptor_t &desc, |
|
|
|
else |
|
|
|
d = c + Eigen::Vector2d{-vec_ca[1], vec_ca[0]}; |
|
|
|
|
|
|
|
aabb.extend(a); |
|
|
|
aabb.extend(c); |
|
|
|
aabb.extend(d); |
|
|
|
}); |
|
|
@ -186,69 +173,54 @@ void polyline::build_as_profile(polyline_descriptor_t &&desc, |
|
|
|
// collect indices info
|
|
|
|
this->thetas.resize(desc.bulge_number); |
|
|
|
this->start_indices.resize(desc.bulge_number + 1, uint8_t{0}); |
|
|
|
stl_vector<uint8_t> line_start_indices(desc.bulge_number + 1), circle_start_indices(desc.bulge_number + 1); |
|
|
|
if (this->start_indices.size() > 16) { |
|
|
|
std::atomic_size_t line_start_indices_offset{0}; |
|
|
|
std::atomic_size_t circle_start_indices_offset{0}; |
|
|
|
Concurrency::concurrent_vector<uint8_t, tbb::tbb_allocator<uint8_t>> circle_start_indices{}; |
|
|
|
circle_start_indices.reserve(desc.bulge_number + 1); |
|
|
|
std::transform_inclusive_scan(std::execution::par_unseq, |
|
|
|
counting_iterator<size_t>{}, |
|
|
|
counting_iterator<size_t>{this->start_indices.size()}, |
|
|
|
counting_iterator<size_t>{desc.bulge_number}, |
|
|
|
this->start_indices.begin() + 1, |
|
|
|
std::plus<uint8_t>{}, |
|
|
|
[&](size_t index) { |
|
|
|
auto &theta = this->thetas[index]; |
|
|
|
theta = std::atan(fabs(desc.bulges[index])) * 4; |
|
|
|
if (theta <= EPSILON) { |
|
|
|
const auto offset = line_start_indices_offset.fetch_add(1); |
|
|
|
line_start_indices[offset] = index; |
|
|
|
return uint8_t{1}; |
|
|
|
} else { |
|
|
|
const auto offset = circle_start_indices_offset.fetch_add(1); |
|
|
|
circle_start_indices.push_back(static_cast<uint8_t>(index)); |
|
|
|
return uint8_t{3}; |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
size_t line_start_indices_offset{0}; |
|
|
|
size_t circle_start_indices_offset{0}; |
|
|
|
std::transform_inclusive_scan(counting_iterator<size_t>{}, |
|
|
|
counting_iterator<size_t>{this->start_indices.size()}, |
|
|
|
this->start_indices.begin() + 1, |
|
|
|
std::plus<uint8_t>{}, |
|
|
|
[&](size_t index) { |
|
|
|
auto &theta = this->thetas[index]; |
|
|
|
theta = std::atan(fabs(desc.bulges[index])) * 4; |
|
|
|
if (theta <= EPSILON) { |
|
|
|
line_start_indices[line_start_indices_offset++] = index; |
|
|
|
return uint8_t{1}; |
|
|
|
} else { |
|
|
|
circle_start_indices[circle_start_indices_offset++] = index; |
|
|
|
return uint8_t{3}; |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
// i.e. iff close curve, deduce loop to simple segements by copying the first vertex to the end
|
|
|
|
this->vertices.resize(this->start_indices.back() + static_cast<size_t>(desc.is_close)); |
|
|
|
this->vertices.resize(this->start_indices.back() + 1); |
|
|
|
this->start_indices.pop_back(); |
|
|
|
circle_start_indices.shrink_to_fit(); |
|
|
|
|
|
|
|
const Eigen::Vector2d offset = {-proj_x_dir.dot(proj_origin), -proj_y_dir.dot(proj_origin)}; |
|
|
|
|
|
|
|
// first loop: process all line segment vertices
|
|
|
|
algorithm::for_loop(size_t{}, line_start_indices.size(), [&](size_t i) { |
|
|
|
const auto &index = line_start_indices[i]; |
|
|
|
const auto &start_index = this->start_indices[index]; |
|
|
|
auto &v = this->vertices[start_index]; |
|
|
|
v = manually_projection(std::move(desc.points[index]), proj_x_dir, proj_y_dir, offset); |
|
|
|
// first loop: process all start vertices
|
|
|
|
algorithm::for_loop(size_t{}, this->start_indices.size(), [&](size_t i) { |
|
|
|
const auto &index = this->start_indices[i]; |
|
|
|
auto &v = this->vertices[index]; |
|
|
|
v = manually_projection(std::move(desc.points[i]), proj_x_dir, proj_y_dir, offset); |
|
|
|
aabb.extend(v); |
|
|
|
}); |
|
|
|
if (desc.is_close) this->vertices.back() = this->vertices.front(); |
|
|
|
// ways to handle the last vertex:
|
|
|
|
// iff close curve, deduce loop to simple segements by copying the first vertex to the end
|
|
|
|
// if not, then process the last vertex
|
|
|
|
if (desc.is_close) |
|
|
|
this->vertices.back() = this->vertices.front(); |
|
|
|
else { |
|
|
|
auto &v = this->vertices.back(); |
|
|
|
v = manually_projection(std::move(desc.points[desc.point_number - 1]), proj_x_dir, proj_y_dir, offset); |
|
|
|
aabb.extend(v); |
|
|
|
} |
|
|
|
|
|
|
|
// second loop: process all circle vertices
|
|
|
|
algorithm::for_loop(size_t{}, circle_start_indices.size(), [&](size_t i) { |
|
|
|
const auto &index = line_start_indices[i]; |
|
|
|
const auto &index = circle_start_indices[i]; |
|
|
|
const auto &start_index = this->start_indices[index]; |
|
|
|
const auto &bulge = desc.bulges[index]; |
|
|
|
const auto &theta = this->thetas[index]; |
|
|
|
this->vertices[start_index] = manually_projection(std::move(desc.points[index]), proj_x_dir, proj_y_dir, offset); |
|
|
|
|
|
|
|
const auto &a = this->vertices[start_index]; |
|
|
|
const auto &b = this->vertices[start_index + 3]; |
|
|
@ -270,7 +242,6 @@ void polyline::build_as_profile(polyline_descriptor_t &&desc, |
|
|
|
else |
|
|
|
d = c + Eigen::Vector2d{-vec_ca[1], vec_ca[0]}; |
|
|
|
|
|
|
|
aabb.extend(a); |
|
|
|
aabb.extend(c); |
|
|
|
aabb.extend(d); |
|
|
|
}); |
|
|
@ -405,7 +376,8 @@ void polyline::build_as_profile(polyline_descriptor_t &&desc, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[[nodiscard]] bool polyline::pmc(const Eigen::Ref<const Eigen::Vector2d>&p, const line_closest_param_t& closest_param) const { |
|
|
|
[[nodiscard]] bool polyline::pmc(const Eigen::Ref<const Eigen::Vector2d> &p, const line_closest_param_t &closest_param) const |
|
|
|
{ |
|
|
|
if (closest_param.is_peak_value) { |
|
|
|
return (p - closest_param.point.topRows<2>()).dot(this->calculate_normal(closest_param.t)) < 0; |
|
|
|
} |
|
|
@ -414,7 +386,5 @@ void polyline::build_as_profile(polyline_descriptor_t &&desc, |
|
|
|
return (p - closest_param.point.topRows<2>()).dot(this->calculate_normal(closest_param.t)) < 0; |
|
|
|
} |
|
|
|
|
|
|
|
[[nodiscard]] bool polyline::isEnd(const double t) const { |
|
|
|
return t >= thetas.size() - EPSILON || t < EPSILON; |
|
|
|
} |
|
|
|
[[nodiscard]] bool polyline::isEnd(const double t) const { return t >= thetas.size() - EPSILON || t < EPSILON; } |
|
|
|
} // namespace internal
|