Browse Source

fix up constructor of polyline;

add support of hand direction to helixline
gjj
Zhicheng Wang 6 months ago
parent
commit
cbcf2e8319
  1. 34
      primitive_process/interface/internal_primitive_desc.hpp
  2. 2
      primitive_process/interface/primitive_descriptor.h
  3. 29
      primitive_process/src/helixline.cpp
  4. 232
      primitive_process/src/polyline.cpp

34
primitive_process/interface/internal_primitive_desc.hpp

@ -1,5 +1,6 @@
#pragma once
#include <cassert>
#include <vector>
#include <variant>
@ -7,8 +8,6 @@
#include <utils/eigen_alias.hpp>
#include <macros.h>
#include <cassert>
#include "primitive_descriptor.h"
// =========================================================================================================================
@ -169,7 +168,7 @@ struct PE_API mesh {
};
// CAUTION: in polyline local space, the X/Y axis should be according to local N/B directions
struct polyline {
struct PE_API polyline {
std::vector<Eigen::Vector2d> vertices{}; //
// for a straight line, it consists of two vertices; for a circle arc, it consists
// of three vertices: start point, circle center, and a point on the circle to
@ -179,11 +178,11 @@ struct polyline {
void build_as_axis(const polyline_descriptor_t&,
const raw_vector3d_t&,
Eigen::Transform<double, 3, Eigen::AffineCompact>&,
Eigen::Transform<double, 3, Eigen::AffineCompact, Eigen::DontAlign>&,
aabb_t<>&);
void build_as_axis(polyline_descriptor_t&&,
const raw_vector3d_t&,
Eigen::Transform<double, 3, Eigen::AffineCompact>&,
Eigen::Transform<double, 3, Eigen::AffineCompact, Eigen::DontAlign>&,
aabb_t<>&);
void build_as_profile(const polyline_descriptor_t&,
const Eigen::Ref<const Eigen::Vector3d>&,
@ -203,40 +202,39 @@ struct polyline {
[[nodiscard]] std::pair<line_closest_param_t, double> calculate_closest_param(
const Eigen::Ref<const Eigen::Vector3d>&) const;
// return type: true for outside
[[nodiscard]] bool pmc(const Eigen::Ref<const Eigen::Vector2d>&, const line_closest_param_t&) const;
[[nodiscard]] bool isEnd(const double t) const;
// return type: true for outside
[[nodiscard]] bool pmc(const Eigen::Ref<const Eigen::Vector2d>&, const line_closest_param_t&) const;
[[nodiscard]] bool isEnd(const double t) const;
};
struct helixline {
double radius{};
double total_theta{};
double height{};
bool is_clockwise{};
// CAUTION: here returned aabb is in helixline's local space
helixline(const helixline_descriptor_t&, Eigen::Transform<double, 3, Eigen::AffineCompact>&, aabb_t<>&);
helixline(helixline_descriptor_t&&, Eigen::Transform<double, 3, Eigen::AffineCompact>&, aabb_t<>&);
helixline(const helixline_descriptor_t&, Eigen::Transform<double, 3, Eigen::AffineCompact, Eigen::DontAlign>&, aabb_t<>&);
helixline(helixline_descriptor_t&&, Eigen::Transform<double, 3, Eigen::AffineCompact, Eigen::DontAlign>&, aabb_t<>&);
[[nodiscard]] Eigen::Vector3d calculate_tangent(double) const;
[[nodiscard]] Eigen::Vector3d calculate_normal(double) const;
// CAUTION: make sure the input point is in the local space of the helixline
[[nodiscard]] line_closest_param_t calculate_closest_param(const Eigen::Ref<const Eigen::Vector3d>&) const;
[[nodiscard]] bool isEnd(const double t) const;
[[nodiscard]] bool isEnd(const double t) const;
};
struct PE_API extrude_polyline {
Eigen::Transform<double, 3, Eigen::AffineCompact> axis_to_world{};
polyline axis;
polyline profile;
Eigen::Transform<double, 3, Eigen::AffineCompact, Eigen::DontAlign> axis_to_world{};
polyline axis;
polyline profile;
DEF_PRIMITIVE_COMMON_METHODS(extrude_polyline, extrude_polyline_descriptor_t)
};
struct PE_API extrude_helixline {
Eigen::Transform<double, 3, Eigen::AffineCompact> axis_to_world{};
helixline axis;
polyline profile;
Eigen::Transform<double, 3, Eigen::AffineCompact, Eigen::DontAlign> axis_to_world{};
helixline axis;
polyline profile;
DEF_PRIMITIVE_COMMON_METHODS(extrude_helixline, extrude_helixline_descriptor_t)
};

2
primitive_process/interface/primitive_descriptor.h

@ -87,7 +87,7 @@ typedef struct {
double radius; // The radius of the helix line
double advance_per_round; // he advance per round of the helix line
raw_vector3d_t start_direction; // The direction from axisStart to start of the helix line
bool is_clockwise;
bool is_righthanded; // {axis_start -> axis_end} as upward direction
} helixline_descriptor_t;
// Note : In profiles, The first polyline is outer boundary, and the ohters is internal holes

29
primitive_process/src/helixline.cpp

@ -4,9 +4,9 @@
namespace internal
{
helixline::helixline(const helixline_descriptor_t &desc,
Eigen::Transform<double, 3, Eigen::AffineCompact> &axis_to_world,
aabb_t<> &aabb)
helixline::helixline(const helixline_descriptor_t &desc,
Eigen::Transform<double, 3, Eigen::AffineCompact, Eigen::DontAlign> &axis_to_world,
aabb_t<> &aabb)
{
Eigen::Vector3d origin, topper;
vec3d_conversion(desc.axis_start, origin);
@ -14,14 +14,16 @@ helixline::helixline(const helixline_descriptor_t &desc,
this->radius = desc.radius;
this->height = (topper - origin).norm();
this->total_theta = this->height / desc.advance_per_round * TWO_PI;
this->is_clockwise = desc.is_clockwise;
auto &matrix_handle = axis_to_world.matrix();
vec3d_conversion(desc.start_direction, matrix_handle.col(0));
matrix_handle.col(0).normalize();
matrix_handle.col(2) = (topper - origin) / this->height;
matrix_handle.col(3) = origin;
matrix_handle.col(1) = matrix_handle.col(2).cross(matrix_handle.col(0));
if (desc.is_righthanded)
matrix_handle.col(1) = matrix_handle.col(2).cross(matrix_handle.col(0));
else
matrix_handle.col(1) = matrix_handle.col(0).cross(matrix_handle.col(2));
aabb = {
Eigen::Vector3d{-this->radius, -this->radius, 0 },
@ -29,9 +31,9 @@ helixline::helixline(const helixline_descriptor_t &desc,
};
}
helixline::helixline(helixline_descriptor_t &&desc,
Eigen::Transform<double, 3, Eigen::AffineCompact> &axis_to_world,
aabb_t<> &aabb)
helixline::helixline(helixline_descriptor_t &&desc,
Eigen::Transform<double, 3, Eigen::AffineCompact, Eigen::DontAlign> &axis_to_world,
aabb_t<> &aabb)
{
Eigen::Vector3d origin, topper;
vec3d_conversion(std::move(desc.axis_start), origin);
@ -39,14 +41,16 @@ helixline::helixline(helixline_descriptor_t &&desc,
this->radius = std::move(desc.radius);
this->height = (topper - origin).norm();
this->total_theta = this->height / std::move(desc.advance_per_round) * TWO_PI;
this->is_clockwise = std::move(desc.is_clockwise);
auto &matrix_handle = axis_to_world.matrix();
vec3d_conversion(std::move(desc.start_direction), matrix_handle.col(0));
matrix_handle.col(0).normalize();
matrix_handle.col(2) = (topper - origin) / this->height;
matrix_handle.col(3) = origin;
matrix_handle.col(1) = matrix_handle.col(2).cross(matrix_handle.col(0));
if (desc.is_righthanded)
matrix_handle.col(1) = matrix_handle.col(2).cross(matrix_handle.col(0));
else
matrix_handle.col(1) = matrix_handle.col(0).cross(matrix_handle.col(2));
aabb = {
Eigen::Vector3d{-this->radius, -this->radius, 0 },
@ -183,8 +187,5 @@ helixline::helixline(helixline_descriptor_t &&desc,
};
}
[[nodiscard]] bool helixline::isEnd(const double t) const
{
return t >= 1 - EPSILON || t < EPSILON;
}
[[nodiscard]] bool helixline::isEnd(const double t) const { return t >= 1 - EPSILON || t < EPSILON; }
} // namespace internal

232
primitive_process/src/polyline.cpp

@ -1,3 +1,5 @@
#include <concurrent_vector.h>
#include <algorithm/glue_algorithm.hpp>
#include "internal_primitive_desc.hpp"
@ -7,7 +9,8 @@ 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::Vector3d p;
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;
}
@ -24,15 +27,15 @@ static inline auto manually_projection(raw_vector3d_t &&
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,
aabb_t<> &aabb)
void polyline::build_as_axis(const polyline_descriptor_t &desc,
const raw_vector3d_t &profile_ref_normal,
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));
@ -48,15 +51,15 @@ void polyline::build_as_axis(const polyline_descriptor_t &
aabb.transform(axis_to_world);
}
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,
aabb_t<> &aabb)
void polyline::build_as_axis(polyline_descriptor_t &&desc,
const raw_vector3d_t &profile_ref_normal,
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};
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()},
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};
}
});
}
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>{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) {
return uint8_t{1};
} else {
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 &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 &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];
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};
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()},
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};
}
});
}
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>{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) {
return uint8_t{1};
} else {
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(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 &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 &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];
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,16 +376,15 @@ 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 {
if (closest_param.is_peak_value) {
return (p - closest_param.point.topRows<2>()).dot(this->calculate_normal(closest_param.t)) < 0;
}
// the closest point is the vertex of the line
// todo: may not be robust for rare cases
return (p - closest_param.point.topRows<2>()).dot(this->calculate_normal(closest_param.t)) < 0;
[[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;
}
// the closest point is the vertex of the line
// todo: may not be robust for rare cases
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
Loading…
Cancel
Save