Browse Source

refactor: signed pattern SDF and extrude cap improvements

- Change pattern eval_sdf to return double (signed distance) instead of pair
- Add reversed parameter to get_local_cap_mat for correct cap orientation
- Add has_end_caps flag to extrude, handle closed axis caps properly
- Add is_closed field to polyline_axis_descriptor
- Use desc.is_closed instead of computing from point/bulge counts
- Fix total_theta calculation in helixline (multiply by two_pi)
- Fix scale vector initialization (zero-fill w component)
V2-integral
Zhicheng Wang 1 day ago
parent
commit
d420ac4d14
  1. 5
      frontend/src/io_axis.cpp
  2. 4
      frontend/src/io_primitive.cpp
  3. 2
      primitive_process/interface/primitive/axis/extrude_axis.hpp
  4. 2
      primitive_process/interface/primitive/axis/helixline_extrude_axis.hpp
  5. 2
      primitive_process/interface/primitive/axis/polyline_extrude_axis.hpp
  6. 16
      primitive_process/interface/primitive/extrude/extrude.hpp
  7. 2
      primitive_process/interface/primitive/pattern/pattern.hpp
  8. 2
      primitive_process/interface/primitive/pattern/polyline_pattern.hpp
  9. 9
      primitive_process/interface/primitive/simple/box.hpp
  10. 1
      primitive_process/interface/primitive_descriptor.h
  11. 3
      primitive_process/src/base/primitive.cpp
  12. 117
      primitive_process/src/primitive/axis/helixline_extrude_axis.cpp
  13. 72
      primitive_process/src/primitive/axis/polyline_extrude_axis.cpp
  14. 193
      primitive_process/src/primitive/pattern/polyline_pattern.cpp
  15. 10
      primitive_process/src/subface/extrude/extrude_side_face.cpp

5
frontend/src/io_axis.cpp

@ -4,7 +4,6 @@
auto construct_polyline_extrude_axis(const polyline_axis_descriptor_t& desc) auto construct_polyline_extrude_axis(const polyline_axis_descriptor_t& desc)
{ {
bool is_closed = desc.point_number == desc.bulge_number + 1;
bool is_ccw{}; bool is_ccw{};
const Eigen::Vector3d vert0 = convert_vec3d(desc.points[0]); const Eigen::Vector3d vert0 = convert_vec3d(desc.points[0]);
@ -58,7 +57,7 @@ auto construct_polyline_extrude_axis(const polyline_axis_descriptor_t& desc)
axis_to_world.matrix().col(2) = vec_z; axis_to_world.matrix().col(2) = vec_z;
axis_to_world.matrix().col(3) = vert0; axis_to_world.matrix().col(3) = vert0;
return std::make_tuple(obj, is_closed, axis_to_world); return std::make_tuple(obj, desc.is_closed, axis_to_world);
} }
auto construct_helixline_extrude_axis(const helixline_axis_descriptor_t& desc) auto construct_helixline_extrude_axis(const helixline_axis_descriptor_t& desc)
@ -67,7 +66,7 @@ auto construct_helixline_extrude_axis(const helixline_axis_descriptor_t& desc)
Eigen::Vector3d vec_z = convert_vec3d(desc.axis_end) - origin; Eigen::Vector3d vec_z = convert_vec3d(desc.axis_end) - origin;
auto height = vec_z.norm(); auto height = vec_z.norm();
vec_z /= height; vec_z /= height;
auto total_theta = height / desc.advance_per_round; auto total_theta = height / desc.advance_per_round * two_pi;
internal::helixline_extrude_axis obj{}; internal::helixline_extrude_axis obj{};
obj.scale_coeff_x = desc.radius; obj.scale_coeff_x = desc.radius;

4
frontend/src/io_primitive.cpp

@ -28,7 +28,7 @@ API primitive* create_param_primitive(const extend_axis_object_t* axis,
return internal::new_param_primitive(axis->object, return internal::new_param_primitive(axis->object,
axis->is_closed, axis->is_closed,
convert_mat3x4d(axis->axis_to_world), convert_mat3x4d(axis->axis_to_world),
pattern, *pattern,
type, type,
static_cast<primitive_data_center_t*>(data_center)); static_cast<primitive_data_center_t*>(data_center));
} }
@ -44,7 +44,7 @@ API void destroy_primitive(primitive* primitive_ptr)
API void primitive_apply_scale(primitive* primitive_ptr, vector3d scale) API void primitive_apply_scale(primitive* primitive_ptr, vector3d scale)
{ {
if (primitive_ptr == nullptr) return; if (primitive_ptr == nullptr) return;
Eigen::Vector4d scale_eigen; Eigen::Vector4d scale_eigen{0, 0, 0, 1};
std::move(&scale.x, &scale.x + 3, scale_eigen.data()); std::move(&scale.x, &scale.x + 3, scale_eigen.data());
primitive_ptr->apply_transform(internal::transform_type::scale, scale_eigen); primitive_ptr->apply_transform(internal::transform_type::scale, scale_eigen);
} }

2
primitive_process/interface/primitive/axis/extrude_axis.hpp

@ -12,7 +12,7 @@ struct PE_API extrude_axis {
virtual double get_closest_param(Eigen::Vector3d p) const = 0; virtual double get_closest_param(Eigen::Vector3d p) const = 0;
// 输入的p需要在axis局部坐标系下,且输出的局部坐标需要由轴坐标系到子面坐标系 // 输入的p需要在axis局部坐标系下,且输出的局部坐标需要由轴坐标系到子面坐标系
virtual std::pair<Eigen::Vector2d, Eigen::Projective2d> to_pattern_local(double t, Eigen::Vector3d p) const = 0; virtual std::pair<Eigen::Vector2d, Eigen::Projective2d> to_pattern_local(double t, Eigen::Vector3d p) const = 0;
virtual Eigen::AffineCompact3d get_local_cap_mat(double t) const = 0; virtual Eigen::AffineCompact3d get_local_cap_mat(double t, bool reversed) const = 0;
virtual aabb_t get_local_aabb() const = 0; virtual aabb_t get_local_aabb() const = 0;
}; };

2
primitive_process/interface/primitive/axis/helixline_extrude_axis.hpp

@ -10,7 +10,7 @@ struct PE_API helixline_extrude_axis final : public extrude_axis {
double get_closest_param(Eigen::Vector3d p) const override; double get_closest_param(Eigen::Vector3d p) const override;
std::pair<Eigen::Vector2d, Eigen::Projective2d> to_pattern_local(double t, Eigen::Vector3d p) const override; std::pair<Eigen::Vector2d, Eigen::Projective2d> to_pattern_local(double t, Eigen::Vector3d p) const override;
Eigen::AffineCompact3d get_local_cap_mat(double t) const override; Eigen::AffineCompact3d get_local_cap_mat(double t, bool reversed) const override;
aabb_t get_local_aabb() const override { return k_aabb_up_unit; } aabb_t get_local_aabb() const override { return k_aabb_up_unit; }

2
primitive_process/interface/primitive/axis/polyline_extrude_axis.hpp

@ -11,7 +11,7 @@ struct PE_API polyline_extrude_axis final : public extrude_axis {
double get_closest_param(Eigen::Vector3d p) const override; double get_closest_param(Eigen::Vector3d p) const override;
std::pair<Eigen::Vector2d, Eigen::Projective2d> to_pattern_local(double t, Eigen::Vector3d p) const override; std::pair<Eigen::Vector2d, Eigen::Projective2d> to_pattern_local(double t, Eigen::Vector3d p) const override;
Eigen::AffineCompact3d get_local_cap_mat(double t) const override; Eigen::AffineCompact3d get_local_cap_mat(double t, bool reversed) const override;
aabb_t get_local_aabb() const override aabb_t get_local_aabb() const override
{ {

16
primitive_process/interface/primitive/extrude/extrude.hpp

@ -25,21 +25,24 @@ struct extrude_t final : public primitive {
aabb.min().array() -= pattern_max_length; aabb.min().array() -= pattern_max_length;
aabb.max().array() += pattern_max_length; aabb.max().array() += pattern_max_length;
if (closed_axis) if (closed_axis) {
has_end_caps = false;
initialize( initialize(
{ {
make_pointer_wrapper(axis_transform) make_pointer_wrapper(axis_transform)
}, },
{{(void*)axis, (void*)pattern}}, {{(void*)axis, (void*)pattern}},
aabb); aabb);
else { } else {
paired_model_matrix bottom_cap_transform{}; paired_model_matrix bottom_cap_transform{};
bottom_cap_transform.local_to_world = axis_to_world * axis->get_local_cap_mat(0); bottom_cap_transform.local_to_world = axis_to_world * axis->get_local_cap_mat(0, true);
bottom_cap_transform.world_to_local = bottom_cap_transform.local_to_world.inverse(); bottom_cap_transform.world_to_local = bottom_cap_transform.local_to_world.inverse();
paired_model_matrix top_cap_transform{}; paired_model_matrix top_cap_transform{};
top_cap_transform.local_to_world = axis_to_world * axis->get_local_cap_mat(1); top_cap_transform.local_to_world = axis_to_world * axis->get_local_cap_mat(1, false);
top_cap_transform.world_to_local = top_cap_transform.local_to_world.inverse(); top_cap_transform.world_to_local = top_cap_transform.local_to_world.inverse();
has_end_caps = true;
initialize( initialize(
{ {
make_pointer_wrapper(axis_transform), make_pointer_wrapper(axis_transform),
@ -55,17 +58,18 @@ struct extrude_t final : public primitive {
span<marked_subface_ptr_t<subface>> get_subfaces() const override span<marked_subface_ptr_t<subface>> get_subfaces() const override
{ {
return {const_cast<marked_subface_ptr_t<subface>*>(subfaces.data()), subfaces[1] == nullptr ? 1u : 3u}; return {const_cast<marked_subface_ptr_t<subface>*>(subfaces.data()), has_end_caps ? 3u : 1u};
} }
std::vector<surface_type> get_subface_types() const override std::vector<surface_type> get_subface_types() const override
{ {
if (subfaces[1] == nullptr) if (!has_end_caps)
return {surface_type::extrude_side}; return {surface_type::extrude_side};
else else
return {surface_type::extrude_side, surface_type::plane, surface_type::plane}; return {surface_type::extrude_side, surface_type::plane, surface_type::plane};
} }
std::array<marked_subface_ptr_t<subface>, 3> subfaces{nullptr, nullptr, nullptr}; std::array<marked_subface_ptr_t<subface>, 3> subfaces{nullptr, nullptr, nullptr};
bool has_end_caps{};
}; };
} // namespace internal } // namespace internal

2
primitive_process/interface/primitive/pattern/pattern.hpp

@ -8,7 +8,7 @@ namespace internal
struct PE_API pattern { struct PE_API pattern {
virtual ~pattern() = default; virtual ~pattern() = default;
virtual std::pair<bool, Eigen::Vector2d> eval_sdf(Eigen::Vector2d p) const = 0; virtual double eval_sdf(Eigen::Vector2d p) const = 0;
// virtual double eval_sdf_grad(Eigen::Vector2d p) const = 0; // virtual double eval_sdf_grad(Eigen::Vector2d p) const = 0;
virtual double get_max_bounding_length() const = 0; virtual double get_max_bounding_length() const = 0;

2
primitive_process/interface/primitive/pattern/polyline_pattern.hpp

@ -11,7 +11,7 @@ namespace internal
struct PE_API polyline_pattern final : public pattern { struct PE_API polyline_pattern final : public pattern {
~polyline_pattern() override = default; ~polyline_pattern() override = default;
std::pair<bool, Eigen::Vector2d> eval_sdf(Eigen::Vector2d p) const override; double eval_sdf(Eigen::Vector2d p) const override;
double get_max_bounding_length() const override double get_max_bounding_length() const override
{ {

9
primitive_process/interface/primitive/simple/box.hpp

@ -16,6 +16,15 @@ struct box_t final : public primitive {
trans_by_target_axis_matrices_ptr<model_matrix::axis::z, false, 1>}, trans_by_target_axis_matrices_ptr<model_matrix::axis::z, false, 1>},
{{}, {}, {}, {}, {}, {}}, {{}, {}, {}, {}, {}, {}},
k_aabb_unit); k_aabb_unit);
for(auto s : get_subfaces())
{
std::cout << (s->world_to_local * Eigen::Vector4d{0, 0, 0, 1}).transpose() << std::endl;
// std::cout << s->local_to_world.matrix() << std::endl;
// std::cout << (s->local_to_world * Eigen::Vector4d{0, 0, 0, 1}).transpose() << std::endl;
// std::cout << s.get_mark() << std::endl;
s.set_mark(~s.get_mark());
}
} }
primitive_type get_type() const override { return PRIMITIVE_TYPE_BOX; }; primitive_type get_type() const override { return PRIMITIVE_TYPE_BOX; };

1
primitive_process/interface/primitive_descriptor.h

@ -30,6 +30,7 @@ typedef struct {
uint32_t bulge_number; // The bulge number of the polyline uint32_t bulge_number; // The bulge number of the polyline
double* bulges; // The bulge of each edge double* bulges; // The bulge of each edge
vector3d reference_normal; // The reference normal of the polyline vector3d reference_normal; // The reference normal of the polyline
bool is_closed;
} polyline_axis_descriptor_t; } polyline_axis_descriptor_t;
typedef struct { typedef struct {

3
primitive_process/src/base/primitive.cpp

@ -42,6 +42,7 @@ void primitive::initialize(const std::vector<internal::paired_model_matrix_ptr_t
auto subface_types = get_subface_types(); auto subface_types = get_subface_types();
for (size_t i = 0; i < subfaces.size(); ++i) { for (size_t i = 0; i < subfaces.size(); ++i) {
// subfaces[i].set_mark(static_cast<size_t>(reversed_flags[i])); // subfaces[i].set_mark(static_cast<size_t>(reversed_flags[i]));
// std::cout << matrices[i]->local_to_world.matrix() << "\n\n";
data_center->require_surface(subface_types[i], matrices[i], additional_structures[i], subfaces[i]); data_center->require_surface(subface_types[i], matrices[i], additional_structures[i], subfaces[i]);
} }
@ -70,7 +71,7 @@ void primitive::apply_transform(internal::transform_type type, Eigen::Vector4d p
switch (type) { switch (type) {
case internal::transform_type::scale: { case internal::transform_type::scale: {
auto scale = Eigen::Isometry3d(Eigen::Scaling(param)); auto scale = Eigen::Affine3d(Eigen::Scaling(param));
for (auto &model_matrix : new_model_matrices) { for (auto &model_matrix : new_model_matrices) {
model_matrix.local_to_world = scale * model_matrix.local_to_world; model_matrix.local_to_world = scale * model_matrix.local_to_world;
model_matrix.world_to_local = model_matrix.world_to_local * scale.inverse(); model_matrix.world_to_local = model_matrix.world_to_local * scale.inverse();

117
primitive_process/src/primitive/axis/helixline_extrude_axis.cpp

@ -1,6 +1,7 @@
#include <numeric> #include <numeric>
#include <primitive/axis/helixline_extrude_axis.hpp> #include <primitive/axis/helixline_extrude_axis.hpp>
#include <data/simple_matrix.hpp>
namespace internal namespace internal
{ {
@ -17,44 +18,68 @@ double helixline_extrude_axis::get_closest_param(Eigen::Vector3d p) const
const auto theta = std::abs(this->total_theta); const auto theta = std::abs(this->total_theta);
// 等价转化为椭圆型Kepler方程,计算相关常量 // 等价转化为椭圆型Kepler方程,计算相关常量
const auto e = r_p * theta * theta; const auto e = r_p * theta * theta;
const auto M = pi + theta * h_p - theta_p; auto k = std::ceil((theta * h_p - theta_p) * inv_two_pi);
const auto k_range = theta * inv_two_pi; auto M = pi + theta * h_p - theta_p - 2 * pi * k;
// 每一周期内的计算函数 auto sign = 1.;
auto halley_solve = [&](auto k) { if (M < 0) {
const auto M_k = M - k * two_pi; M = -M;
sign = -1.;
auto E = (M_k + e * pi) / (1 + e); }
// 经实验验证,我们只需要一步Halley迭代就能产生足够的精度
const auto K = E - e * std::sin(E); auto markley_solve = [&] {
const auto Kp = 1 - e * std::cos(E); M = std::fmod(M, two_pi);
const auto Kpp = e * std::sin(E); if (M > pi) M = two_pi - pi;
const auto delta_E = 2 * (K - M_k) * Kp / (2 * Kp * Kp - (K - M) * Kpp); if (M < 1e-15) return .0;
E -= delta_E;
auto alpha = (3 * pi * pi + 1.6 * pi * (pi - M) / (e + 1)) / (pi * pi - 6);
const auto t = (E + theta_p + k * two_pi - pi) / theta; auto d = 3 * (1 - e) + alpha * e;
auto q = 2 * alpha * d * (1 - e) - M * M;
if (t >= 0 && t <= 1) auto r = 3 * alpha * d * (d - 1 + e) * M + M * M * M;
return std::array{t, distance(t, theta, r_p, theta_p, h_p)};
else auto w = std::pow(std::abs(r) + std::sqrt(q * q * q + r * r), 2 / 3);
return std::array{.0, std::numeric_limits<double>::max()}; auto E1 = (2 * r * w / (w * w + w * q + q * q) + M) / d;
auto sinE = std::sin(E1), cosE = std::cos(E1);
auto f = E1 - e * sinE - M;
auto f1 = 1 - e * cosE;
auto f2 = e * sinE;
auto f3 = e * cosE;
auto f4 = -e * sinE;
auto denom3 = f1 - .5 * f * f2 / f1;
auto d3 = -f / denom3;
auto denom4 = f1 + .5 * d3 * f2 + (d3 * d3) * f3 / 6;
auto d4 = -f / denom4;
auto denom5 = f1 + .5 * d4 * f2 + (d4 * d4) * f3 / 6 + (d4 * d4 * d4) * f4 / 24;
auto d5 = -f / denom5;
return E1 + d5;
}; };
std::vector<size_t> k_indices(k_range); auto halley_solve = [&] {
std::iota(k_indices.begin(), k_indices.end(), 0); auto E = (M + e * pi) / (e + 1);
auto res = std::transform_reduce( auto delta = std::numeric_limits<double>::max();
k_indices.begin(), size_t step{};
k_indices.end(), while (delta >= epsilon && step < 8) {
std::array{.0, std::numeric_limits<double>::max()}, auto sinE = std::sin(E), cosE = std::cos(E);
[](auto&& lhs, auto&& rhs) { return lhs[1] < rhs[1] ? lhs : rhs; }, auto K = E - e * sinE - M;
[&](auto k) { return halley_solve(k); }); auto Kp = 1 - e * cosE;
auto Kpp = e * sinE;
// 额外比较与区间端点处的值 auto denom = 2 * Kp * Kp - K * Kpp;
if (auto dist0 = distance(.0, theta, r_p, theta_p, h_p); dist0 < res[1]) res = {.0, dist0}; auto dE = denom * 1e6 > epsilon ? (2 * K * Kp) / denom : K / Kp;
if (auto dist1 = distance(1., theta, r_p, theta_p, h_p); dist1 < res[1]) res = {1., dist1};
E -= dE;
delta = std::abs(dE);
}
return E;
};
return res[0]; auto E = e <= 1 ? markley_solve() : halley_solve();
E *= sign;
return (theta_p + (2 * k - 1) * pi + E) / theta;
} }
std::pair<Eigen::Vector2d, Eigen::Projective2d> helixline_extrude_axis::to_pattern_local(double t, Eigen::Vector3d p) const std::pair<Eigen::Vector2d, Eigen::Projective2d> helixline_extrude_axis::to_pattern_local(double t, Eigen::Vector3d p) const
@ -81,16 +106,20 @@ std::pair<Eigen::Vector2d, Eigen::Projective2d> helixline_extrude_axis::to_patte
}; };
} }
Eigen::AffineCompact3d helixline_extrude_axis::get_local_cap_mat(double t) const Eigen::AffineCompact3d helixline_extrude_axis::get_local_cap_mat(double t, bool reversed) const
{ {
const Eigen::Vector3d o = {std::cos(this->total_theta * t), std::sin(this->total_theta * t), t}; auto sine = std::sin(this->total_theta * t);
Eigen::Vector3d tangent = {-std::sin(this->total_theta * t), std::cos(this->total_theta * t), 1}; auto cosine = std::cos(this->total_theta * t);
tangent /= sqrt_2; const Eigen::Vector3d o = {cosine, sine, t};
Eigen::Vector3d tangent = {this->total_theta * -sine, this->total_theta * cosine, 1};
Eigen::AffineCompact3d res{}; tangent.normalize();
auto rot = Eigen::Quaterniond::FromTwoVectors(Eigen::Vector3d{1, 0, 0}, tangent);
res.linear() = rot.toRotationMatrix(); Eigen::AffineCompact3d res =
res.translation() = o; reversed ? internal::trans_by_target_axis_matrices_ptr<model_matrix::axis::z, true>->local_to_world
: internal::trans_by_target_axis_matrices_ptr<model_matrix::axis::z, false>->local_to_world;
// auto rot = Eigen::Quaterniond::FromTwoVectors(Eigen::Vector3d{1, 0, 0}, reversed ? -tangent : tangent);
// res.linear() = rot.toRotationMatrix();
res.translation() = o;
return res; return res;
} }

72
primitive_process/src/primitive/axis/polyline_extrude_axis.cpp

@ -41,9 +41,9 @@ double polyline_extrude_axis::get_closest_param(Eigen::Vector3d p) const
const auto r = ca.norm(); // 圆弧半径 const auto r = ca.norm(); // 圆弧半径
if (cp_norm < epsilon) return std::array{r, .0, static_cast<double>(index)}; if (cp_norm < epsilon) return std::array{r, .0, static_cast<double>(index)};
pa.normalize(); ca /= r;
cp /= cp_norm; cp /= cp_norm;
const auto delta_theta = pi - std::acos(pa.dot(cp)); const auto delta_theta = std::acos(ca.dot(cp));
const auto theta = std::atan(bulge) * 2; const auto theta = std::atan(bulge) * 2;
const auto t = std::clamp(delta_theta / theta, .0, 1.); const auto t = std::clamp(delta_theta / theta, .0, 1.);
@ -69,16 +69,17 @@ double polyline_extrude_axis::get_closest_param(Eigen::Vector3d p) const
}, },
[&](size_t i) { return (std::abs(this->bulges[i]) <= epsilon) ? line_cpm(i) : circle_cpm(i); }); [&](size_t i) { return (std::abs(this->bulges[i]) <= epsilon) ? line_cpm(i) : circle_cpm(i); });
return n + t; return static_cast<double>(n + t) / bulges.size();
} }
std::pair<Eigen::Vector2d, Eigen::Projective2d> polyline_extrude_axis::to_pattern_local(double t, Eigen::Vector3d p) const std::pair<Eigen::Vector2d, Eigen::Projective2d> polyline_extrude_axis::to_pattern_local(double t, Eigen::Vector3d p) const
{ {
const Eigen::Vector2d local_p = p.head<2>(); const Eigen::Vector2d local_p = p.head<2>();
size_t n = static_cast<size_t>(t); auto t_ = t * bulges.size();
double frac = t - n; size_t n = static_cast<size_t>(t_);
if (n == vertices.size()) { // 重定位到合法区间的终点 double frac = t_ - n;
if (n == bulges.size()) { // 重定位到合法区间的终点
n -= 1; n -= 1;
frac = 1.; frac = 1.;
} }
@ -90,14 +91,17 @@ std::pair<Eigen::Vector2d, Eigen::Projective2d> polyline_extrude_axis::to_patter
const auto line = verts[1] - verts[0]; const auto line = verts[1] - verts[0];
const auto tangent = line.normalized(); const auto tangent = line.normalized();
normal = {tangent.y(), -tangent.x()}; normal = {tangent.y(), -tangent.x()};
o = verts[0] + t * line; o = verts[0] + frac * line;
} else { // 圆弧段 } else { // 圆弧段
const Eigen::Vector2d a = verts[0]; const auto a = verts[0];
const Eigen::Vector2d center = verts[1]; const auto b = verts[1];
const auto ca = a - center; const auto half_ab = 0.5 * (a + b);
const auto theta = std::atan(bulge) * 2; const auto bisec_vec = 0.5 * Eigen::Vector2d{a.y() - b.y(), b.x() - a.x()};
const auto center = half_ab + bisec_vec / bulge;
Eigen::Rotation2Dd rot{t * theta}; const auto ca = a - center;
const auto theta = std::atan(bulge) * 2;
Eigen::Rotation2Dd rot{frac * theta};
const auto cp = rot * ca; const auto cp = rot * ca;
normal = theta < .0 ? cp.normalized() : -cp.normalized(); normal = theta < .0 ? cp.normalized() : -cp.normalized();
@ -109,8 +113,8 @@ std::pair<Eigen::Vector2d, Eigen::Projective2d> polyline_extrude_axis::to_patter
const auto proj_x = -p.z(); // 因为bitangent永远为(0, 0, -1) const auto proj_x = -p.z(); // 因为bitangent永远为(0, 0, -1)
Eigen::Projective2d pattern_to_axis{}; Eigen::Projective2d pattern_to_axis{};
pattern_to_axis.linear()(2, 0) = -1; pattern_to_axis.matrix()(2, 0) = -1;
pattern_to_axis.linear().col(1).head<2>() = normal; pattern_to_axis.matrix().col(1).head<2>() = normal;
pattern_to_axis.translation().head<2>() = o; pattern_to_axis.translation().head<2>() = o;
return { return {
@ -119,11 +123,12 @@ std::pair<Eigen::Vector2d, Eigen::Projective2d> polyline_extrude_axis::to_patter
}; };
} }
Eigen::AffineCompact3d polyline_extrude_axis::get_local_cap_mat(double t) const Eigen::AffineCompact3d polyline_extrude_axis::get_local_cap_mat(double t, bool reversed) const
{ {
size_t n = static_cast<size_t>(t); auto t_ = t * bulges.size();
double frac = t - n; size_t n = static_cast<size_t>(t_);
if (n == vertices.size()) { // 重定位到合法区间的终点 double frac = t_ - n;
if (n == bulges.size()) { // 重定位到合法区间的终点
n -= 1; n -= 1;
frac = 1.; frac = 1.;
} }
@ -132,26 +137,31 @@ Eigen::AffineCompact3d polyline_extrude_axis::get_local_cap_mat(double t) const
const auto bulge = bulges[n]; const auto bulge = bulges[n];
Eigen::Vector2d tangent{}, o{}; // 法线永远指向外侧 Eigen::Vector2d tangent{}, o{}; // 法线永远指向外侧
if (std::abs(bulge) <= epsilon) { // 直线 if (std::abs(bulge) <= epsilon) { // 直线
const auto line = verts[1] - verts[0]; const auto line = verts[1] - verts[0];
const auto tangent = line.normalized(); tangent = line.normalized();
o = verts[0] + t * line; o = verts[0] + t * line;
} else { // 圆弧段 } else { // 圆弧段
const Eigen::Vector2d a = verts[0]; const auto a = verts[0];
const Eigen::Vector2d center = verts[1]; const auto b = verts[1];
const auto ca = a - center; const auto half_ab = 0.5 * (a + b);
const auto theta = std::atan(bulge) * 2; const auto bisec_vec = 0.5 * Eigen::Vector2d{a.y() - b.y(), b.x() - a.x()};
const auto center = half_ab + bisec_vec / bulge;
Eigen::Rotation2Dd rot{t * theta}; const auto ca = a - center;
const auto theta = std::atan(bulge) * 2;
Eigen::Rotation2Dd rot{frac * theta};
auto cp = rot * ca; auto cp = rot * ca;
o = cp + center; o = cp + center;
cp.normalize(); cp.normalize();
tangent = theta < 0 ? Eigen::Vector2d{ca.y(), -ca.x()} : Eigen::Vector2d{-ca.y(), ca.x()}; tangent = theta < 0 ? Eigen::Vector2d{cp.y(), -cp.x()} : Eigen::Vector2d{-cp.y(), cp.x()};
} }
Eigen::AffineCompact3d res{}; Eigen::AffineCompact3d res{};
auto rot = Eigen::Quaterniond::FromTwoVectors(Eigen::Vector3d{1, 0, 0}, Eigen::Vector3d{tangent[0], tangent[1], 0}); auto rot = Eigen::Quaterniond::FromTwoVectors(
res.linear() = rot.toRotationMatrix(); Eigen::Vector3d{1, 0, 0},
reversed ? Eigen::Vector3d{-tangent[0], -tangent[1], 0} : Eigen::Vector3d{tangent[0], tangent[1], 0});
res.linear() = rot.toRotationMatrix();
res.translation() = Eigen::Vector3d{o[0], o[1], 0}; res.translation() = Eigen::Vector3d{o[0], o[1], 0};
return res; return res;
} }

193
primitive_process/src/primitive/pattern/polyline_pattern.cpp

@ -2,7 +2,7 @@
namespace internal namespace internal
{ {
std::pair<bool, Eigen::Vector2d> polyline_pattern::eval_sdf(Eigen::Vector2d p) const double polyline_pattern::eval_sdf(Eigen::Vector2d p) const
{ {
auto line_cpm = [&](auto index) { auto line_cpm = [&](auto index) {
const auto a = this->vertices[index]; const auto a = this->vertices[index];
@ -22,72 +22,163 @@ std::pair<bool, Eigen::Vector2d> polyline_pattern::eval_sdf(Eigen::Vector2d p) c
const auto cross = ap.x() * bp.y() - ap.y() * bp.x(); const auto cross = ap.x() * bp.y() - ap.y() * bp.x();
const auto d_theta = std::atan2(cross, dot); const auto d_theta = std::atan2(cross, dot);
return std::array{dist, d_theta, proj.x(), proj.y()}; return std::array{dist, d_theta};
}; };
auto circle_cpm = [&](auto index) { auto circle_cpm = [&](auto index) {
const auto bulge = this->bulges[index]; const auto bulge = this->bulges[index];
const auto a = this->vertices[index]; const auto a = this->vertices[index];
const auto b = this->vertices[index + 1]; const auto b = this->vertices[index + 1];
const auto half_ab = 0.5 * (a + b); const Eigen::Vector2d half_ab = 0.5 * (a + b);
const auto bisec_vec = 0.5 * Eigen::Vector2d{a.y() - b.y(), b.x() - a.x()}; const Eigen::Vector2d bisec_vec = 0.5 * Eigen::Vector2d{a.y() - b.y(), b.x() - a.x()};
const auto center = half_ab + bisec_vec / bulge; const Eigen::Vector2d center = half_ab + bisec_vec / bulge;
Eigen::Vector2d ca = a - center; Eigen::Vector2d ca = a - center;
Eigen::Vector2d cb = b - center; Eigen::Vector2d cb = b - center;
Eigen::Vector2d cp = p - center; Eigen::Vector2d cp = p - center;
Eigen::Vector2d pa = a - p; Eigen::Vector2d pa = a - p;
Eigen::Vector2d pb = b - p; Eigen::Vector2d pb = b - p;
const auto D = cp.norm(); // 查询点到圆心的距离 const auto D = cp.norm(); // 查询点到圆心的距离
const auto r = ca.norm(); // 圆弧半径 const auto r = ca.norm(); // 圆弧半径
if (D < epsilon) return std::array{r, std::atan(bulge) * 2, a.x(), a.y()}; const auto half_theta = std::atan(bulge);
if (D <= epsilon) return std::array{r, half_theta * 2};
// 计算GWN // 计算GWN
const auto term1 = std::atan(bulge); const auto gwn_main = half_theta;
auto dot = ca.dot(cp); const auto r_mul_D = r * D, r_plus_D = r + D, abs_r_sub_D = std::abs(r - D);
const auto cross1 = cp.x() * ca.y() - ca.x() * cp.y(); auto gwn = gwn_main;
const auto term2 = ((r - D) * cross1) / ((r + D) * (r * D + dot)); if (abs_r_sub_D > epsilon) {
dot = cb.dot(cp); auto dot = ca.dot(cp);
const auto cross2 = cp.x() * cb.y() - cb.x() * cp.y(); auto cross = cp.x() * ca.y() - ca.x() * cp.y();
const auto term3 = ((r - D) * cross2) / ((r + D) * (r * D + dot)); auto Y = r_plus_D * cross, X = abs_r_sub_D * (r_mul_D + dot);
const auto gwn = term1 + term3 - term2; auto Ga = std::atan2(Y, X);
if (std::abs(X) <= epsilon && std::abs(Y) <= epsilon) Ga = std::copysign(pi_div_2, -half_theta);
cp /= D; dot = cb.dot(cp);
ca /= r; cross = cp.x() * cb.y() - cb.x() * cp.y();
cb /= r; Y = r_plus_D * cross;
X = abs_r_sub_D * (r_mul_D + dot);
// 原理:根据叉乘符号判断方向,不论何种情况cp都应该在ca和cb之间 auto Gb = std::atan2(Y, X);
if (cross1 * cross2 > 0) { if (std::abs(X) <= epsilon && std::abs(Y) <= epsilon) Gb = std::copysign(pi_div_2, -half_theta);
// 在圆弧范围内 auto gwn_fix = Gb - Ga;
return std::array{D - r, gwn, center.x() + cp.x(), center.y() + cp.y()}; if (gwn_fix * half_theta < 0) gwn_fix += std::copysign(pi, half_theta);
} else { gwn += (r > D) ? gwn_fix : -gwn_fix;
// 最近点为圆弧端点
if (auto pa_norm = pa.norm(), pb_norm = pb.norm(); pa_norm < pb_norm)
return std::array{pa_norm, gwn, a.x(), a.y()};
else
return std::array{pa_norm, gwn, b.x(), b.y()};
} }
return std::array{std::min({abs_r_sub_D, pa.norm(), pb.norm()}), gwn};
}; };
// 单次遍历 // 单次遍历
std::vector<size_t> indices(this->bulges.size()); std::vector<size_t> indices(this->bulges.size());
std::iota(indices.begin(), indices.end(), 0); std::iota(indices.begin(), indices.end(), 0);
auto [min_dist, gwn, x, y] = std::transform_reduce( auto [min_dist, gwn] = std::transform_reduce(
indices.begin(), indices.begin(),
indices.end(), indices.end(),
std::array{std::numeric_limits<double>::max(), .0, .0, .0}, std::array{std::numeric_limits<double>::max(), .0},
[](auto&& lhs, auto&& rhs) { [](auto&& lhs, auto&& rhs) {
const auto gwn = lhs[1] + rhs[1]; const auto gwn = lhs[1] + rhs[1];
if (lhs[0] < rhs[0]) const auto dist = std::min(lhs[0], rhs[0]);
return std::array{lhs[0], gwn, lhs[2], lhs[3]}; return std::array{dist, gwn};
else
return std::array{rhs[0], gwn, rhs[2], rhs[3]};
}, },
[&](size_t i) { return (std::abs(this->bulges[i]) <= epsilon) ? line_cpm(i) : circle_cpm(i); }); [&](size_t i) { return (std::abs(this->bulges[i]) <= epsilon) ? line_cpm(i) : circle_cpm(i); });
return { // if (p.norm() > 1 && std::abs(gwn) / two_pi != .0) abort();
std::abs(gwn) < two_pi * epsilon, return std::abs(gwn) / two_pi < 1. ? min_dist : -min_dist;
Eigen::Vector2d{x, y}
};
} }
// double polyline_pattern::eval_sdf(Eigen::Vector2d p) const
// {
// auto line_cpm = [&](auto index) {
// const auto a = this->vertices[index];
// const auto b = this->vertices[index + 1];
// const Eigen::Vector2d line_vec = b - a;
// const Eigen::Vector2d ap = p - a;
// const Eigen::Vector2d bp = p - b;
// // 计算投影参数
// const auto t = std::clamp(line_vec.dot(ap) / line_vec.squaredNorm(), .0, 1.);
// const Eigen::Vector2d proj = a + t * line_vec;
// const auto dist = (p - proj).norm();
// // 计算GWN
// const auto dot = ap.dot(bp);
// const auto cross = ap.x() * bp.y() - ap.y() * bp.x();
// const auto d_theta = std::atan2(cross, dot);
// return std::array{dist, d_theta, proj.x(), proj.y()};
// };
// auto circle_cpm = [&](auto index) {
// const auto bulge = this->bulges[index];
// const auto a = this->vertices[index];
// const auto b = this->vertices[index + 1];
// const Eigen::Vector2d half_ab = 0.5 * (a + b);
// const Eigen::Vector2d bisec_vec = 0.5 * Eigen::Vector2d{a.y() - b.y(), b.x() - a.x()};
// const Eigen::Vector2d center = half_ab + bisec_vec / bulge;
// Eigen::Vector2d ca = a - center;
// Eigen::Vector2d cb = b - center;
// Eigen::Vector2d cp = p - center;
// Eigen::Vector2d pa = a - p;
// Eigen::Vector2d pb = b - p;
// const auto D = cp.norm(); // 查询点到圆心的距离
// const auto r = ca.norm(); // 圆弧半径
// const auto half_theta = std::atan(bulge);
// if (D < epsilon) return std::array{r, half_theta * 2, a.x(), a.y()};
// // 计算GWN
// const auto gwn_main = half_theta;
// const auto r_mul_D = r * D, r_plus_D = r + D, abs_r_sub_D = std::abs(r - D);
// const auto cross1 = cp.x() * ca.y() - ca.x() * cp.y();
// const auto cross2 = cp.x() * cb.y() - cb.x() * cp.y();
// auto gwn = gwn_main;
// if (abs_r_sub_D > epsilon) {
// auto dot = ca.dot(cp);
// const auto Ga = std::atan2(r_plus_D * cross1, abs_r_sub_D * (r_mul_D + dot));
// dot = cb.dot(cp);
// const auto Gb = std::atan2(r_plus_D * cross2, abs_r_sub_D * (r_mul_D + dot));
// auto gwn_fix = Gb - Ga;
// if (gwn_fix * half_theta < 0) gwn_fix += std::copysign(pi, half_theta);
// gwn += (r > D) ? gwn_fix : -gwn_fix;
// }
// cp /= D;
// ca /= r;
// cb /= r;
// // 原理:根据叉乘符号判断方向,不论何种情况cp都应该在ca和cb之间
// if (cross1 * cross2 > 0) {
// // 在圆弧范围内
// return std::array{D - r, gwn, center.x() + cp.x(), center.y() + cp.y()};
// } else {
// // 最近点为圆弧端点
// if (auto pa_norm = pa.norm(), pb_norm = pb.norm(); pa_norm < pb_norm)
// return std::array{pa_norm, gwn, a.x(), a.y()};
// else
// return std::array{pa_norm, gwn, b.x(), b.y()};
// }
// };
// // 单次遍历
// std::vector<size_t> indices(this->bulges.size());
// std::iota(indices.begin(), indices.end(), 0);
// auto [min_dist, gwn, x, y] = std::transform_reduce(
// indices.begin(),
// indices.end(),
// std::array{std::numeric_limits<double>::max(), .0, .0, .0},
// [](auto&& lhs, auto&& rhs) {
// const auto gwn = lhs[1] + rhs[1];
// if (lhs[0] < rhs[0])
// return std::array{lhs[0], gwn, lhs[2], lhs[3]};
// else
// return std::array{rhs[0], gwn, rhs[2], rhs[3]};
// },
// [&](size_t i) { return (std::abs(this->bulges[i]) <= epsilon) ? line_cpm(i) : circle_cpm(i); });
// return {
// // std::abs(gwn) < two_pi * epsilon,
// std::abs(gwn) == 0.,
// Eigen::Vector2d{x, y}
// };
// }
} // namespace internal } // namespace internal

10
primitive_process/src/subface/extrude/extrude_side_face.cpp

@ -11,14 +11,10 @@ double extrude_side_function_impl::eval_sdf(pointer_wrapper<subface> object, Eig
const auto v = axis_->get_closest_param(local_p.head<3>()); const auto v = axis_->get_closest_param(local_p.head<3>());
auto [pattern_p, local_TBN] = axis_->to_pattern_local(v, local_p.head<3>()); auto [pattern_p, local_TBN] = axis_->to_pattern_local(v, local_p.head<3>());
pattern* pattern_ = reinterpret_cast<pattern*>(object->additional_structure[1]); pattern* pattern_ = reinterpret_cast<pattern*>(object->additional_structure[1]);
const auto [outside, closest_point] = pattern_->eval_sdf(pattern_p); const auto sdf = pattern_->eval_sdf(pattern_p);
auto local_q = local_TBN * Eigen::Vector3d{closest_point.x(), closest_point.y(), 0}; return sdf;
auto vec_pq = local_p.head<3>() - local_q;
auto sdf = object->local_to_world_scale().cwiseProduct(vec_pq).norm();
return outside ? sdf : -sdf;
} }
Eigen::Vector3d extrude_side_function_impl::eval_sdf_grad(pointer_wrapper<subface> object, Eigen::Vector3d p) Eigen::Vector3d extrude_side_function_impl::eval_sdf_grad(pointer_wrapper<subface> object, Eigen::Vector3d p)

Loading…
Cancel
Save