Skip to content
This repository was archived by the owner on Oct 22, 2025. It is now read-only.

Commit 512fda2

Browse files
committed
deal with codim vert/edge in 2D
1 parent d128e2c commit 512fda2

File tree

5 files changed

+164
-111
lines changed

5 files changed

+164
-111
lines changed

src/ipc/collision_mesh.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,17 @@ void CollisionMesh::construct_edges_to_faces()
145145

146146
void CollisionMesh::init_codim_vertices()
147147
{
148-
std::vector<bool> is_codim_vertex(num_vertices(), true);
148+
m_is_codim_vertex.assign(num_vertices(), true);
149149
for (int i : m_edges.reshaped()) {
150-
is_codim_vertex[i] = false;
150+
m_is_codim_vertex[i] = false;
151151
}
152152

153153
m_codim_vertices.resize(
154-
std::count(is_codim_vertex.begin(), is_codim_vertex.end(), true));
154+
std::count(m_is_codim_vertex.begin(), m_is_codim_vertex.end(), true));
155155

156156
int j = 0;
157157
for (int i = 0; i < num_vertices(); i++) {
158-
if (is_codim_vertex[i]) {
158+
if (m_is_codim_vertex[i]) {
159159
assert(j < m_codim_vertices.size());
160160
m_codim_vertices[j++] = i;
161161
}
@@ -165,17 +165,17 @@ void CollisionMesh::init_codim_vertices()
165165

166166
void CollisionMesh::init_codim_edges()
167167
{
168-
std::vector<bool> is_codim_edge(num_edges(), true);
168+
m_is_codim_edge.assign(num_edges(), true);
169169
for (int i : m_faces_to_edges.reshaped()) {
170-
is_codim_edge[i] = false;
170+
m_is_codim_edge[i] = false;
171171
}
172172

173173
m_codim_edges.resize(
174-
std::count(is_codim_edge.begin(), is_codim_edge.end(), true));
174+
std::count(m_is_codim_edge.begin(), m_is_codim_edge.end(), true));
175175

176176
int j = 0;
177177
for (int i = 0; i < num_edges(); i++) {
178-
if (is_codim_edge[i]) {
178+
if (m_is_codim_edge[i]) {
179179
assert(j < m_codim_edges.size());
180180
m_codim_edges[j++] = i;
181181
}

src/ipc/collision_mesh.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,13 @@ class CollisionMesh {
9999
/// @brief Get the indices of codimensional vertices of the collision mesh (#CV x 1).
100100
const Eigen::VectorXi& codim_vertices() const { return m_codim_vertices; }
101101

102+
bool is_codim_vertex(const long& v) const { return m_is_codim_vertex[v]; }
103+
102104
/// @brief Get the indices of codimensional edges of the collision mesh (#CE x 1).
103105
const Eigen::VectorXi& codim_edges() const { return m_codim_edges; }
104106

107+
bool is_codim_edge(const long& e) const { return m_is_codim_edge[e]; }
108+
105109
/// @brief Get the edges of the collision mesh (#E × 2).
106110
const Eigen::MatrixXi& edges() const { return m_edges; }
107111

@@ -317,8 +321,12 @@ class CollisionMesh {
317321
Eigen::MatrixXd m_full_rest_positions;
318322
/// @brief The vertex positions at rest (#V × dim).
319323
Eigen::MatrixXd m_rest_positions;
324+
/// @brief The mask of codimensional vertices (#V).
325+
std::vector<bool> m_is_codim_vertex;
320326
/// @brief The indices of codimensional vertices (#CV x 1).
321327
Eigen::VectorXi m_codim_vertices;
328+
/// @brief The mask of codimensional edges (#E).
329+
std::vector<bool> m_is_codim_edge;
322330
/// @brief The indices of codimensional edges (#CE x 1).
323331
Eigen::VectorXi m_codim_edges;
324332
/// @brief Edges as rows of indicies into vertices (#E × 2).

src/ipc/smooth_contact/primitives/edge2.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,20 @@ Edge2::Edge2(
1010
: Primitive(id, param)
1111
{
1212
_vert_ids = { { mesh.edges()(id, 0), mesh.edges()(id, 1) } };
13-
Vector2d edge = vertices.row(_vert_ids[1]) - vertices.row(_vert_ids[0]);
14-
is_active_ = Math<double>::cross2(d, edge) > 0;
13+
14+
is_active_ = mesh.is_codim_edge(id) || Math<double>::cross2(d, vertices.row(_vert_ids[1]) - vertices.row(_vert_ids[0])) > 0;
15+
}
16+
17+
int Edge2::n_vertices() const
18+
{
19+
return n_edge_neighbors_2d;
1520
}
16-
int Edge2::n_vertices() const { return n_edge_neighbors_2d; }
21+
1722
double Edge2::potential(const Vector2d& d, const Vector4d& x) const
1823
{
1924
return (x.tail<2>() - x.head<2>()).norm();
2025
}
26+
2127
Vector6d Edge2::grad(const Vector2d& d, const Vector4d& x) const
2228
{
2329
const Vector2d t = x.tail<2>() - x.head<2>();
@@ -28,6 +34,7 @@ Vector6d Edge2::grad(const Vector2d& d, const Vector4d& x) const
2834
g.segment<2>(4) = t / len;
2935
return g;
3036
}
37+
3138
Matrix6d Edge2::hessian(const Vector2d& d, const Vector4d& x) const
3239
{
3340
Matrix6d h;

src/ipc/smooth_contact/primitives/point2.cpp

Lines changed: 134 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -2,98 +2,164 @@
22

33
namespace ipc {
44

5+
namespace {
6+
bool smooth_point2_term_type(
7+
const Eigen::Ref<const Vector2d>& v,
8+
const Eigen::Ref<const Vector2d>& direc,
9+
const Eigen::Ref<const Vector2d>& e0,
10+
const Eigen::Ref<const Vector2d>& e1,
11+
const ParameterType& param,
12+
const bool orientable)
13+
{
14+
const Vector2d dn = -direc.normalized();
15+
const Vector2d t0 = (e0 - v).normalized(), t1 = (e1 - v).normalized();
16+
17+
if (dn.dot(t0) <= -param.alpha_t || dn.dot(t1) <= -param.alpha_t)
18+
return false;
19+
20+
if (orientable)
21+
{
22+
const double tmp = Math<double>::smooth_heaviside(-Math<double>::cross2(dn, t0), param.alpha_n, param.beta_n) +
23+
Math<double>::smooth_heaviside(Math<double>::cross2(dn, t1), param.alpha_n, param.beta_n);
24+
if (tmp <= 1. - param.alpha_n)
25+
return false;
26+
}
27+
28+
return true;
29+
}
30+
31+
template <class scalar>
32+
scalar smooth_point2_term(
33+
const Eigen::Ref<const Vector2<scalar>>& v,
34+
const Eigen::Ref<const Vector2<scalar>>& direc,
35+
const Eigen::Ref<const Vector2<scalar>>& e0,
36+
const Eigen::Ref<const Vector2<scalar>>& e1,
37+
const ParameterType& param,
38+
const bool orientable)
39+
{
40+
const Vector2<scalar> dn = -direc.normalized();
41+
const Vector2<scalar> t0 = (e0 - v).normalized(), t1 = (v - e1).normalized();
42+
43+
scalar val = Math<scalar>::smooth_heaviside(dn.dot(t0), param.alpha_t, param.beta_t) *
44+
Math<scalar>::smooth_heaviside(-dn.dot(t1), param.alpha_t, param.beta_t);
45+
46+
if (orientable)
47+
{
48+
const scalar tmp = Math<scalar>::smooth_heaviside(-Math<scalar>::cross2(dn, t0), param.alpha_n, param.beta_n) +
49+
Math<scalar>::smooth_heaviside(-Math<scalar>::cross2(dn, t1), param.alpha_n, param.beta_n);
50+
val = val * Math<scalar>::smooth_heaviside(tmp - 1., param.alpha_n, 0);
51+
}
52+
53+
return val * ((e0 - v).norm() + (e1 - v).norm()) / 2.;
54+
}
55+
56+
template <class scalar>
57+
scalar smooth_point2_term_one_side(
58+
const Eigen::Ref<const Vector2<scalar>>& v,
59+
const Eigen::Ref<const Vector2<scalar>>& direc,
60+
const Eigen::Ref<const Vector2<scalar>>& e0,
61+
const ParameterType& param)
62+
{
63+
const Vector2<scalar> dn = -direc.normalized();
64+
const Vector2<scalar> t0 = e0 - v;
65+
66+
const scalar tangent_term = Math<scalar>::smooth_heaviside(dn.dot(t0) / t0.norm(), param.alpha_t, param.beta_t);
67+
68+
return tangent_term * t0.norm();
69+
}
70+
}
71+
572
Point2::Point2(const long &id,
673
const CollisionMesh& mesh,
774
const Eigen::MatrixXd& vertices,
875
const VectorMax3d& d,
976
const ParameterType& param)
1077
: Primitive(id, param)
1178
{
12-
_vert_ids = {{-1, -1, -1}};
13-
_vert_ids[0] = id;
79+
orientable = !mesh.is_codim_vertex(id);
80+
auto neighbor_verts = mesh.find_vertex_adjacent_vertices(id);
81+
has_neighbor_1 = neighbor_verts[0] >= 0;
82+
has_neighbor_2 = neighbor_verts[1] >= 0;
1483

15-
if (mesh.vertex_edge_adjacencies()[id].size() != 2)
16-
logger().error("Invalid number of vertex neighbor in 2D! {} should be 2.", mesh.vertex_edge_adjacencies()[id].size());
17-
for (long i : mesh.vertex_edge_adjacencies()[id])
84+
if (has_neighbor_1 && has_neighbor_2)
1885
{
19-
if (mesh.edges()(i, 0) == id)
20-
_vert_ids[1] = mesh.edges()(i, 1);
21-
else if (mesh.edges()(i, 1) == id)
22-
_vert_ids[2] = mesh.edges()(i, 0);
23-
else
24-
logger().error("Wrong edge-vertex adjacency!");
86+
_vert_ids = {{id, neighbor_verts[0], neighbor_verts[1]}};
87+
is_active_ = smooth_point2_term_type(vertices.row(id), d, vertices.row(_vert_ids[1]), vertices.row(_vert_ids[2]), _param, orientable);
2588
}
89+
else if (has_neighbor_1 || has_neighbor_2)
90+
{
91+
_vert_ids = {{id, has_neighbor_1 ? neighbor_verts[0] : neighbor_verts[1]}};
2692

27-
is_active_ = smooth_point2_term_type(vertices.row(id), d, vertices.row(_vert_ids[1]), vertices.row(_vert_ids[2]), _param);
93+
const Vector2d dn = -d.normalized();
94+
const Vector2d t0 = (vertices.row(_vert_ids[1]) - vertices.row(_vert_ids[0])).normalized();
95+
96+
is_active_ = dn.dot(t0) > -param.alpha_t;
97+
}
98+
else
99+
{
100+
_vert_ids = {{id}};
101+
is_active_ = true;
102+
}
28103
}
29104

30105
int Point2::n_vertices() const
31106
{
32-
return 3;
107+
return _vert_ids.size();
33108
}
34109

35110
double Point2::potential(const Vector<double, dim> &d, const Vector<double, -1, max_size> &x) const
36111
{
37-
return smooth_point2_term<double>(x.segment<dim>(0), d, x.segment<dim>(dim), x.segment<dim>(2 * dim), _param);
112+
if (has_neighbor_1 && has_neighbor_2)
113+
return smooth_point2_term<double>(x.segment<dim>(0), d, x.segment<dim>(dim), x.segment<dim>(2 * dim), _param, orientable);
114+
else if (has_neighbor_1 || has_neighbor_2)
115+
return smooth_point2_term_one_side<double>(x.segment<dim>(0), d, x.segment<dim>(dim), _param);
116+
else
117+
return 1.;
38118
}
39119
Vector<double, -1, Point2::max_size+Point2::dim> Point2::grad(const Vector<double, dim> &d, const Vector<double, -1, max_size> &x) const
40120
{
41-
DiffScalarBase::setVariableCount(4*dim);
42-
using T = ADGrad<4*dim>;
43-
Vector<double, 4*dim> tmp;
44-
tmp << d, x;
45-
Eigen::Matrix<T, 4, dim> X = slice_positions<T, 4, dim>(tmp);
46-
return smooth_point2_term<T>(X.row(1), X.row(0), X.row(2), X.row(3), _param).getGradient();
121+
if (has_neighbor_1 && has_neighbor_2)
122+
{
123+
DiffScalarBase::setVariableCount(4*dim);
124+
using T = ADGrad<4*dim>;
125+
Vector<double, 4*dim> tmp;
126+
tmp << d, x;
127+
Eigen::Matrix<T, 4, dim> X = slice_positions<T, 4, dim>(tmp);
128+
return smooth_point2_term<T>(X.row(1), X.row(0), X.row(2), X.row(3), _param, orientable).getGradient();
129+
}
130+
else if (has_neighbor_1 || has_neighbor_2)
131+
{
132+
DiffScalarBase::setVariableCount(3*dim);
133+
using T = ADGrad<3*dim>;
134+
Vector<double, 3*dim> tmp;
135+
tmp << d, x;
136+
Eigen::Matrix<T, 3, dim> X = slice_positions<T, 3, dim>(tmp);
137+
return smooth_point2_term_one_side<T>(X.row(1), X.row(0), X.row(2), _param).getGradient();
138+
}
139+
else
140+
return Vector<double, -1, Point2::max_size+Point2::dim>::Zero(x.size() + d.size());
47141
}
48142
MatrixMax<double, Point2::max_size+Point2::dim, Point2::max_size+Point2::dim> Point2::hessian(const Vector<double, dim> &d, const Vector<double, -1, max_size> &x) const
49143
{
50-
DiffScalarBase::setVariableCount(4*dim);
51-
using T = ADHessian<4*dim>;
52-
Vector<double, 4*dim> tmp;
53-
tmp << d, x;
54-
Eigen::Matrix<T, 4, dim> X = slice_positions<T, 4, dim>(tmp);
55-
return smooth_point2_term<T>(X.row(1), X.row(0), X.row(2), X.row(3), _param).getHessian();
56-
}
57-
58-
template <class scalar>
59-
scalar smooth_point2_term(
60-
const Eigen::Ref<const Vector2<scalar>>& v,
61-
const Eigen::Ref<const Vector2<scalar>>& direc,
62-
const Eigen::Ref<const Vector2<scalar>>& e0,
63-
const Eigen::Ref<const Vector2<scalar>>& e1,
64-
const ParameterType& param)
65-
{
66-
const Vector2<scalar> dn = -direc.normalized();
67-
const Vector2<scalar> t0 = (e0 - v).normalized(), t1 = (v - e1).normalized();
68-
69-
const scalar tangent_term = Math<scalar>::smooth_heaviside(dn.dot(t0), param.alpha_t, param.beta_t) *
70-
Math<scalar>::smooth_heaviside(-dn.dot(t1), param.alpha_t, param.beta_t);
71-
72-
const scalar tmp = Math<scalar>::smooth_heaviside(-Math<scalar>::cross2(dn, t0), param.alpha_n, param.beta_n) +
73-
Math<scalar>::smooth_heaviside(-Math<scalar>::cross2(dn, t1), param.alpha_n, param.beta_n);
74-
const scalar normal_term = Math<scalar>::smooth_heaviside(tmp - 1., param.alpha_n, 0);
75-
76-
return tangent_term * normal_term * ((e0 - v).norm() + (e1 - v).norm()) / 2.;
77-
}
78-
79-
bool smooth_point2_term_type(
80-
const Eigen::Ref<const Vector2d>& v,
81-
const Eigen::Ref<const Vector2d>& direc,
82-
const Eigen::Ref<const Vector2d>& e0,
83-
const Eigen::Ref<const Vector2d>& e1,
84-
const ParameterType& param)
85-
{
86-
const Vector2d dn = -direc.normalized();
87-
const Vector2d t0 = (e0 - v).normalized(), t1 = (v - e1).normalized();
88-
89-
if (dn.dot(t0) <= -param.alpha_t || -dn.dot(t1) <= -param.alpha_t)
90-
return false;
91-
92-
const double tmp = Math<double>::smooth_heaviside(-Math<double>::cross2(dn, t0), param.alpha_n, param.beta_n) +
93-
Math<double>::smooth_heaviside(-Math<double>::cross2(dn, t1), param.alpha_n, param.beta_n);
94-
if (tmp <= 1. - param.alpha_n)
95-
return false;
96-
97-
return true;
144+
if (has_neighbor_1 && has_neighbor_2)
145+
{
146+
DiffScalarBase::setVariableCount(4*dim);
147+
using T = ADHessian<4*dim>;
148+
Vector<double, 4*dim> tmp;
149+
tmp << d, x;
150+
Eigen::Matrix<T, 4, dim> X = slice_positions<T, 4, dim>(tmp);
151+
return smooth_point2_term<T>(X.row(1), X.row(0), X.row(2), X.row(3), _param, orientable).getHessian();
152+
}
153+
else if (has_neighbor_1 || has_neighbor_2)
154+
{
155+
DiffScalarBase::setVariableCount(3*dim);
156+
using T = ADHessian<3*dim>;
157+
Vector<double, 3*dim> tmp;
158+
tmp << d, x;
159+
Eigen::Matrix<T, 3, dim> X = slice_positions<T, 3, dim>(tmp);
160+
return smooth_point2_term_one_side<T>(X.row(1), X.row(0), X.row(2), _param).getHessian();
161+
}
162+
else
163+
return MatrixMax<double, -1, Point2::max_size+Point2::dim>::Zero(x.size() + d.size(), x.size() + d.size());
98164
}
99165
}

src/ipc/smooth_contact/primitives/point2.hpp

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -36,37 +36,9 @@ class Point2 : public Primitive {
3636
MatrixMax<double, max_size + dim, max_size + dim> hessian(
3737
const Vector<double, dim>& d,
3838
const Vector<double, -1, max_size>& x) const;
39-
};
40-
41-
/// @brief
42-
/// @param v
43-
/// @param direc points from v
44-
/// @param e0
45-
/// @param e1
46-
/// @param alpha
47-
/// @param beta
48-
/// @return
49-
template <class scalar>
50-
scalar smooth_point2_term(
51-
const Eigen::Ref<const Vector2<scalar>>& v,
52-
const Eigen::Ref<const Vector2<scalar>>& direc,
53-
const Eigen::Ref<const Vector2<scalar>>& e0,
54-
const Eigen::Ref<const Vector2<scalar>>& e1,
55-
const ParameterType& param);
56-
57-
/// @brief
58-
/// @param v
59-
/// @param direc points from v
60-
/// @param e0
61-
/// @param e1
62-
/// @param alpha
63-
/// @param beta
64-
/// @return
65-
bool smooth_point2_term_type(
66-
const Eigen::Ref<const Vector2<double>>& v,
67-
const Eigen::Ref<const Vector2<double>>& direc,
68-
const Eigen::Ref<const Vector2<double>>& e0,
69-
const Eigen::Ref<const Vector2<double>>& e1,
70-
const ParameterType& param);
7139

40+
private:
41+
bool has_neighbor_1, has_neighbor_2;
42+
bool orientable;
43+
};
7244
} // namespace ipc

0 commit comments

Comments
 (0)