|
|
@ -43,8 +43,10 @@ void polyline::build_as_axis(const polyline_descriptor_t |
|
|
|
// vec3d_conversion(desc.points[0], matrix_handle.col(3));
|
|
|
|
vec3d_conversion(anchor_point, matrix_handle.col(3)); |
|
|
|
|
|
|
|
aabb_t<2> profile_aabb; |
|
|
|
build_as_profile(desc, matrix_handle.col(0), matrix_handle.col(1), matrix_handle.col(3), profile_aabb); |
|
|
|
aabb_t<2> profile_aabb; |
|
|
|
Eigen::Vector3d proj_origin; |
|
|
|
vec3d_conversion(desc.points[0], proj_origin); |
|
|
|
build_as_profile(std::move(desc), matrix_handle.col(0), matrix_handle.col(1), proj_origin, profile_aabb); |
|
|
|
const auto &profile_aabb_min = profile_aabb.min(); |
|
|
|
const auto &profile_aabb_max = profile_aabb.max(); |
|
|
|
aabb = { |
|
|
@ -69,8 +71,10 @@ void polyline::build_as_axis(polyline_descriptor_t |
|
|
|
// vec3d_conversion(desc.points[0], matrix_handle.col(3));
|
|
|
|
vec3d_conversion(anchor_point, matrix_handle.col(3)); |
|
|
|
|
|
|
|
aabb_t<2> profile_aabb; |
|
|
|
build_as_profile(std::move(desc), matrix_handle.col(0), matrix_handle.col(1), matrix_handle.col(3), profile_aabb); |
|
|
|
aabb_t<2> profile_aabb; |
|
|
|
Eigen::Vector3d proj_origin; |
|
|
|
vec3d_conversion(desc.points[0], proj_origin); |
|
|
|
build_as_profile(std::move(desc), matrix_handle.col(0), matrix_handle.col(1), proj_origin, profile_aabb); |
|
|
|
const auto &profile_aabb_min = profile_aabb.min(); |
|
|
|
const auto &profile_aabb_max = profile_aabb.max(); |
|
|
|
aabb = { |
|
|
@ -101,12 +105,12 @@ void polyline::build_as_profile(const polyline_descriptor_t &desc, |
|
|
|
std::plus<uint8_t>{}, |
|
|
|
[&](size_t index) { |
|
|
|
auto &theta = this->thetas[index]; |
|
|
|
theta = std::atan(fabs(desc.bulges[index])) * 4; |
|
|
|
theta = std::atan(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}; |
|
|
|
return uint8_t{2}; |
|
|
|
} |
|
|
|
}); |
|
|
|
// i.e. iff close curve, deduce loop to simple segements by copying the first vertex to the end
|
|
|
@ -148,9 +152,7 @@ void polyline::build_as_profile(const polyline_descriptor_t &desc, |
|
|
|
const auto &a = this->vertices[start_index]; |
|
|
|
const auto &b = this->vertices[start_index + 3]; |
|
|
|
auto &c = this->vertices[start_index + 1]; |
|
|
|
auto &d = this->vertices[start_index + 2]; |
|
|
|
const auto center_vec_ab = 0.5 * (a + b); |
|
|
|
const auto half_vec_ab = b - center_vec_ab; |
|
|
|
Eigen::Matrix<double, 2, 1> temp = center_vec_ab; // for debug
|
|
|
|
if (theta == PI) { |
|
|
|
c = std::move(center_vec_ab); |
|
|
@ -159,15 +161,11 @@ void polyline::build_as_profile(const polyline_descriptor_t &desc, |
|
|
|
// and no more operations are needed for identifying the circle center
|
|
|
|
// since all direction info is already included in the sign & magnitude of bulge
|
|
|
|
const auto inv_tan_half_theta = (1 - bulge * bulge) / (2 * bulge); |
|
|
|
c = center_vec_ab + inv_tan_half_theta * Eigen::Vector2d{half_vec_ab[1], -half_vec_ab[0]}; |
|
|
|
const auto half_vec_ab = center_vec_ab - a; |
|
|
|
c = center_vec_ab + inv_tan_half_theta * Eigen::Vector2d{-half_vec_ab[1], half_vec_ab[0]}; |
|
|
|
} |
|
|
|
const auto vec_ca = a - c; |
|
|
|
if (bulge > 0) |
|
|
|
d = c + Eigen::Vector2d{vec_ca[1], -vec_ca[0]}; |
|
|
|
else |
|
|
|
d = c + Eigen::Vector2d{-vec_ca[1], vec_ca[0]}; |
|
|
|
|
|
|
|
aabb.extend(c); |
|
|
|
aabb.extend(d); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
@ -192,12 +190,12 @@ void polyline::build_as_profile(polyline_descriptor_t &&desc, |
|
|
|
std::plus<uint8_t>{}, |
|
|
|
[&](size_t index) { |
|
|
|
auto &theta = this->thetas[index]; |
|
|
|
theta = std::atan(fabs(desc.bulges[index])) * 4; |
|
|
|
if (theta <= EPSILON) { |
|
|
|
theta = std::atan(desc.bulges[index]) * 4; |
|
|
|
if (-EPSILON <= theta && theta <= EPSILON) { |
|
|
|
return uint8_t{1}; |
|
|
|
} else { |
|
|
|
circle_start_indices.push_back(static_cast<uint8_t>(index)); |
|
|
|
return uint8_t{3}; |
|
|
|
return uint8_t{2}; |
|
|
|
} |
|
|
|
}); |
|
|
|
// i.e. iff close curve, deduce loop to simple segements by copying the first vertex to the end
|
|
|
@ -235,9 +233,7 @@ void polyline::build_as_profile(polyline_descriptor_t &&desc, |
|
|
|
const auto &a = this->vertices[start_index]; |
|
|
|
const auto &b = this->vertices[start_index + 3]; |
|
|
|
auto &c = this->vertices[start_index + 1]; |
|
|
|
auto &d = this->vertices[start_index + 2]; |
|
|
|
const auto center_vec_ab = 0.5 * (a + b); |
|
|
|
const auto half_vec_ab = b - center_vec_ab; |
|
|
|
Eigen::Matrix<double, 2, 1> temp = center_vec_ab; // for debug
|
|
|
|
if (theta == PI) { |
|
|
|
c = std::move(center_vec_ab); |
|
|
@ -246,16 +242,11 @@ void polyline::build_as_profile(polyline_descriptor_t &&desc, |
|
|
|
// and no more operations are needed for identifying the circle center
|
|
|
|
// since all direction info is already included in the sign & magnitude of bulge
|
|
|
|
const auto inv_tan_half_theta = (1 - bulge * bulge) / (2 * bulge); |
|
|
|
c = center_vec_ab + inv_tan_half_theta * Eigen::Vector2d{half_vec_ab[1], -half_vec_ab[0]}; |
|
|
|
const auto half_vec_ab = center_vec_ab - a; |
|
|
|
c = center_vec_ab + inv_tan_half_theta * Eigen::Vector2d{-half_vec_ab[1], half_vec_ab[0]}; |
|
|
|
} |
|
|
|
const auto vec_ca = a - c; |
|
|
|
if (bulge > 0) |
|
|
|
d = c + Eigen::Vector2d{vec_ca[1], -vec_ca[0]}; |
|
|
|
else |
|
|
|
d = c + Eigen::Vector2d{-vec_ca[1], vec_ca[0]}; |
|
|
|
|
|
|
|
aabb.extend(c); |
|
|
|
aabb.extend(d); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
@ -263,15 +254,22 @@ void polyline::build_as_profile(polyline_descriptor_t &&desc, |
|
|
|
{ |
|
|
|
assert(t >= 0 && t <= this->start_indices.size()); |
|
|
|
|
|
|
|
double frac; |
|
|
|
const auto n = static_cast<uint32_t>(std::modf(t, &frac)); |
|
|
|
const auto iter = this->vertices.begin() + this->start_indices[n]; |
|
|
|
if (this->thetas[n] <= EPSILON) { |
|
|
|
return (*(iter + 1) - *iter).normalized(); |
|
|
|
double frac; |
|
|
|
const auto n = static_cast<uint32_t>(std::modf(t, &frac)); |
|
|
|
const auto iter = this->vertices.begin() + this->start_indices[n]; |
|
|
|
const auto &theta = this->thetas[n]; |
|
|
|
|
|
|
|
const auto line_vec = (*(iter + 1) - *iter).normalized(); // i.e. vec{AB} (line) or vec{AC} (circle)
|
|
|
|
if (-EPSILON <= theta && theta <= EPSILON) { |
|
|
|
return line_vec; |
|
|
|
} else { |
|
|
|
const auto alpha_deriv = -std::sin(t * this->thetas[n]); |
|
|
|
const auto beta_deriv = std::cos(t * this->thetas[n]); |
|
|
|
return (alpha_deriv * *iter + beta_deriv * *(iter + 2) - (alpha_deriv + beta_deriv) * *(iter + 1)).normalized(); |
|
|
|
// NOTE: it can be proved that P = M_R * A + (1 - M_R) * C,
|
|
|
|
// where M_R is the rotation matrix corresponding to delta theta
|
|
|
|
// so it's tangent can be simply calculated as M_R' * vec{CA}
|
|
|
|
// and M_R' can be simply obtained by adding a PI/2 rotation to the rotation matrix
|
|
|
|
// CAUTION: we do not need normalize here anymore
|
|
|
|
Eigen::Rotation2Dd rotation_matrix_deriv{t * this->thetas[n] + PI2}; |
|
|
|
return rotation_matrix_deriv.toRotationMatrix() * -line_vec; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -280,17 +278,21 @@ void polyline::build_as_profile(polyline_descriptor_t &&desc, |
|
|
|
{ |
|
|
|
assert(t >= 0 && t <= this->start_indices.size()); |
|
|
|
|
|
|
|
double frac; |
|
|
|
const auto n = static_cast<uint32_t>(std::modf(t, &frac)); |
|
|
|
const auto iter = this->vertices.begin() + this->start_indices[n]; |
|
|
|
if (this->thetas[n] <= EPSILON) { |
|
|
|
double frac; |
|
|
|
const auto n = static_cast<uint32_t>(std::modf(t, &frac)); |
|
|
|
const auto iter = this->vertices.begin() + this->start_indices[n]; |
|
|
|
const auto &theta = this->thetas[n]; |
|
|
|
|
|
|
|
const auto line_vec = (*(iter + 1) - *iter).normalized(); |
|
|
|
if (-EPSILON <= theta && theta <= EPSILON) { |
|
|
|
// HINT: assume the plane normal (ref_normal) to be {0, 0, 1}, then the normal should be this
|
|
|
|
const auto temp = (*(iter + 1) - *iter).normalized(); |
|
|
|
return Eigen::Vector2d{-temp.y(), temp.x()}.normalized(); |
|
|
|
return {-line_vec[1], line_vec[0]}; |
|
|
|
} else { |
|
|
|
const auto alpha = std::cos(t * this->thetas[n]); |
|
|
|
const auto beta = std::sin(t * this->thetas[n]); |
|
|
|
return ((alpha + beta) * *(iter + 1) - alpha * *iter - beta * *(iter + 2)).normalized(); |
|
|
|
// as mentioned above, the matrix M_R'' can be obtained by adding a PI rotation to the rotation matrix
|
|
|
|
// caution: raw direction always points to the inside of the circle
|
|
|
|
// but we want it to point the inside of the polyline, so we need to reverse the direction when theta < 0
|
|
|
|
Eigen::Rotation2Dd rotation_matrix_deriv{t * this->thetas[n] + PI}; |
|
|
|
return sign(theta) * rotation_matrix_deriv.toRotationMatrix() * -line_vec; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -329,14 +331,14 @@ void polyline::build_as_profile(polyline_descriptor_t &&desc, |
|
|
|
const auto iter = this->vertices.begin() + this->start_indices[index]; |
|
|
|
const auto theta = this->thetas[index]; |
|
|
|
const auto base_vec1 = *iter - *(iter + 1); |
|
|
|
const auto base_vec2 = *(iter + 2) - *(iter + 1); |
|
|
|
const auto base_vec2 = Eigen::Vector2d{-base_vec1[1], base_vec1[0]}; |
|
|
|
const auto p_vec = p.topRows<2>() - *(iter + 1); |
|
|
|
|
|
|
|
const auto local_x = base_vec1.dot(p_vec); |
|
|
|
const auto local_y = base_vec2.dot(p_vec); |
|
|
|
const auto phi = std::atan2(local_y, local_x); |
|
|
|
// illegal solve, return null
|
|
|
|
if (phi < 0 || phi > theta) return {}; |
|
|
|
if (!((0 <= phi && phi <= theta) || (theta <= phi && phi <= 0))) return {}; |
|
|
|
|
|
|
|
const auto p_vec_norm = p_vec.norm(); |
|
|
|
const auto r = base_vec1.norm(); |
|
|
@ -356,7 +358,8 @@ void polyline::build_as_profile(polyline_descriptor_t &&desc, |
|
|
|
counting_iterator<size_t>(this->thetas.size()), |
|
|
|
closest_params.begin(), |
|
|
|
[&](size_t index) { |
|
|
|
if (this->thetas[index] <= EPSILON) |
|
|
|
const auto &theta = this->thetas[index]; |
|
|
|
if (-EPSILON <= theta && theta <= EPSILON) |
|
|
|
return line_cpm(index); |
|
|
|
else |
|
|
|
return circle_cpm(index); |
|
|
|