Skip to content

Commit d1c0eb3

Browse files
committed
CPatchSolver: fix edge case where clipper is a segment
1 parent b470ca8 commit d1c0eb3

File tree

2 files changed

+71
-37
lines changed

2 files changed

+71
-37
lines changed

include/hpp/fcl/contact_patch/contact_patch_solver.hxx

+71-32
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ void ContactPatchSolver::computePatch(const ShapeType1& s1,
111111
// expects points to be ranked counter-clockwise.
112112
this->reset(s1, tf1, s2, tf2, contact_patch);
113113
assert(this->num_samples_curved_shapes > 3);
114-
SupportSet& current = const_cast<SupportSet&>(this->current());
114+
SupportSet& current_set = const_cast<SupportSet&>(this->current());
115115
this->supportFuncShape1(
116-
&s1, current, this->support_guess[0], this->supports_data[0],
116+
&s1, current_set, this->support_guess[0], this->supports_data[0],
117117
this->num_samples_curved_shapes, this->patch_tolerance);
118118
SupportSet& clipper = const_cast<SupportSet&>(this->clipper());
119119
this->supportFuncShape2(
@@ -122,46 +122,85 @@ void ContactPatchSolver::computePatch(const ShapeType1& s1,
122122

123123
// We can immediatly return if one of the support set has only
124124
// one point.
125-
if (current.size() <= 1 || clipper.size() <= 1) {
125+
if (current_set.size() <= 1 || clipper.size() <= 1) {
126126
contact_patch.addPoint(contact.pos);
127127
return;
128128
}
129129

130-
//
131-
// Step 3 - Main loop of the algorithm: use the "clipper"
132-
// to clip the current contact patch. The resulting intersection is the
133-
// contact patch of the contact between s1 and s2.
134-
// Currently, to clip one patch with the other, we use the Sutherland-Hodgman
135-
// algorithm:
136-
// https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm
137-
//
138-
this->m_id_current = 0;
139-
const size_t clipper_size = this->clipper().points().size();
140-
for (size_t i = 0; i < clipper_size; ++i) {
141-
const Vec2f a = this->clipper().point(i);
142-
const Vec2f b = this->clipper().point((i + 1) % clipper_size);
130+
if (clipper.size() == 2) {
131+
if (current_set.size() == 2) {
132+
// Segment - Segment case
133+
const Vec2f a = this->clipper().point(0);
134+
const Vec2f b = this->clipper().point(1);
135+
136+
ContactPatch& current = const_cast<ContactPatch&>(this->current());
137+
const Vec2f c = current.point(0);
138+
const Vec2f d = current.point(1);
143139

144-
this->m_id_current = 1 - this->m_id_current;
145-
ContactPatch& current = const_cast<ContactPatch&>(this->current());
146-
current.points().clear();
147-
const size_t previous_size = this->previous().size();
148-
for (size_t j = 0; j < previous_size; ++j) {
149-
const Vec2f vcurrent = this->previous().point(j);
150-
const Vec2f vnext = this->previous().point((j + 1) % previous_size);
151-
if (pointIsInsideClippingRegion(vcurrent, a, b)) {
152-
current.points().emplace_back(vcurrent);
153-
if (!pointIsInsideClippingRegion(vnext, a, b)) {
140+
const Vec2f p = computeLineSegmentIntersection(a, b, c, d);
141+
current.points().clear();
142+
current.points().emplace_back(p);
143+
} else {
144+
// Segment - Polygon case
145+
const Vec2f a = this->clipper().point(0);
146+
const Vec2f b = this->clipper().point(1);
147+
148+
this->m_id_current = 1 - this->m_id_current;
149+
ContactPatch& current = const_cast<ContactPatch&>(this->current());
150+
current.points().clear();
151+
const size_t previous_size = this->previous().size();
152+
for (size_t j = 0; j < previous_size; ++j) {
153+
const Vec2f vcurrent = this->previous().point(j);
154+
const Vec2f vnext = this->previous().point((j + 1) % previous_size);
155+
if (pointIsInsideClippingRegion(vcurrent, a, b)) {
156+
if (!pointIsInsideClippingRegion(vnext, a, b)) {
157+
const Vec2f p =
158+
computeLineSegmentIntersection(a, b, vcurrent, vnext);
159+
current.points().emplace_back(p);
160+
}
161+
} else if (pointIsInsideClippingRegion(vnext, a, b)) {
154162
const Vec2f p = computeLineSegmentIntersection(a, b, vcurrent, vnext);
155163
current.points().emplace_back(p);
156164
}
157-
} else if (pointIsInsideClippingRegion(vnext, a, b)) {
158-
const Vec2f p = computeLineSegmentIntersection(a, b, vcurrent, vnext);
159-
current.points().emplace_back(p);
160165
}
161166
}
162-
if (this->current().size() == 0) {
163-
// No intersection found, the algo can early stop.
164-
break;
167+
} else {
168+
//
169+
// Step 3 - Main loop of the algorithm: use the "clipper"
170+
// to clip the current contact patch. The resulting intersection is the
171+
// contact patch of the contact between s1 and s2.
172+
// Currently, to clip one patch with the other, we use the
173+
// Sutherland-Hodgman algorithm:
174+
// https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm
175+
//
176+
const size_t clipper_size = this->clipper().points().size();
177+
for (size_t i = 0; i < clipper_size; ++i) {
178+
const Vec2f a = this->clipper().point(i);
179+
const Vec2f b = this->clipper().point((i + 1) % clipper_size);
180+
181+
this->m_id_current = 1 - this->m_id_current;
182+
ContactPatch& current = const_cast<ContactPatch&>(this->current());
183+
current.points().clear();
184+
const size_t previous_size = this->previous().size();
185+
for (size_t j = 0; j < previous_size; ++j) {
186+
const Vec2f vcurrent = this->previous().point(j);
187+
const Vec2f vnext = this->previous().point((j + 1) % previous_size);
188+
if (pointIsInsideClippingRegion(vcurrent, a, b)) {
189+
current.points().emplace_back(vcurrent);
190+
if (!pointIsInsideClippingRegion(vnext, a, b)) {
191+
const Vec2f p =
192+
computeLineSegmentIntersection(a, b, vcurrent, vnext);
193+
current.points().emplace_back(p);
194+
}
195+
} else if (pointIsInsideClippingRegion(vnext, a, b)) {
196+
const Vec2f p = computeLineSegmentIntersection(a, b, vcurrent, vnext);
197+
current.points().emplace_back(p);
198+
}
199+
}
200+
if (this->current().size() == 0) {
201+
// No intersection found, the algo can early stop.
202+
break;
203+
}
165204
}
166205
}
167206

src/narrowphase/support_functions.cpp

-5
Original file line numberDiff line numberDiff line change
@@ -928,11 +928,6 @@ HPP_FCL_DLLAPI void computeSupportSetConvexHull(
928928
cvx_hull.clear();
929929

930930
if (cloud.size() <= 2) {
931-
if (cloud.size() == 2) {
932-
if (cloud[0](0) < cloud[1](0)) {
933-
std::swap(cloud[0], cloud[1]);
934-
}
935-
}
936931
// Point or segment, nothing to do.
937932
for (const Vec2f& point : cloud) {
938933
cvx_hull.emplace_back(point);

0 commit comments

Comments
 (0)