Program Listing for File gjk.h
↰ Return to documentation for file (include/coal/narrowphase/gjk.h
)
/*
* Software License Agreement (BSD License)
*
* Copyright (c) 2011-2014, Willow Garage, Inc.
* Copyright (c) 2014-2015, Open Source Robotics Foundation
* Copyright (c) 2021-2024, INRIA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Open Source Robotics Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef COAL_GJK_H
#define COAL_GJK_H
#include <vector>
#include "coal/narrowphase/minkowski_difference.h"
namespace coal {
namespace details {
struct COAL_DLLAPI GJK {
struct COAL_DLLAPI SimplexV {
Vec3s w0, w1;
Vec3s w;
};
typedef unsigned char vertex_id_t;
struct COAL_DLLAPI Simplex {
SimplexV* vertex[4];
vertex_id_t rank;
Simplex() {}
void reset() {
rank = 0;
for (size_t i = 0; i < 4; ++i) vertex[i] = nullptr;
}
};
enum Status {
DidNotRun,
Failed,
NoCollisionEarlyStopped,
NoCollision,
CollisionWithPenetrationInformation,
Collision
};
public:
CoalScalar distance_upper_bound;
Status status;
GJKVariant gjk_variant;
GJKConvergenceCriterion convergence_criterion;
GJKConvergenceCriterionType convergence_criterion_type;
MinkowskiDiff const* shape;
Vec3s ray;
support_func_guess_t support_hint;
CoalScalar distance;
Simplex* simplex; // Pointer to the result of the last run of GJK.
private:
// max_iteration and tolerance are made private
// because they are meant to be set by the `reset` function.
size_t max_iterations;
CoalScalar tolerance;
SimplexV store_v[4];
SimplexV* free_v[4];
vertex_id_t nfree;
vertex_id_t current;
Simplex simplices[2];
size_t iterations;
size_t iterations_momentum_stop;
public:
GJK(size_t max_iterations_, CoalScalar tolerance_)
: max_iterations(max_iterations_), tolerance(tolerance_) {
COAL_ASSERT(tolerance_ > 0, "Tolerance must be positive.",
std::invalid_argument);
initialize();
}
void reset(size_t max_iterations_, CoalScalar tolerance_);
Status evaluate(
const MinkowskiDiff& shape, const Vec3s& guess,
const support_func_guess_t& supportHint = support_func_guess_t::Zero());
inline void getSupport(const Vec3s& d, SimplexV& sv,
support_func_guess_t& hint) const {
shape->support(d, sv.w0, sv.w1, hint);
sv.w = sv.w0 - sv.w1;
}
bool encloseOrigin();
inline Simplex* getSimplex() const { return simplex; }
bool hasClosestPoints() const { return distance < distance_upper_bound; }
void getWitnessPointsAndNormal(const MinkowskiDiff& shape, Vec3s& w0,
Vec3s& w1, Vec3s& normal) const;
Vec3s getGuessFromSimplex() const;
void setDistanceEarlyBreak(const CoalScalar& dup) {
distance_upper_bound = dup;
}
bool checkConvergence(const Vec3s& w, const CoalScalar& rl, CoalScalar& alpha,
const CoalScalar& omega) const;
size_t getNumMaxIterations() const { return max_iterations; }
CoalScalar getTolerance() const { return tolerance; }
size_t getNumIterations() const { return iterations; }
size_t getNumIterationsMomentumStopped() const {
return iterations_momentum_stop;
}
private:
void initialize();
inline void removeVertex(Simplex& simplex);
inline void appendVertex(Simplex& simplex, const Vec3s& v,
support_func_guess_t& hint);
bool projectLineOrigin(const Simplex& current, Simplex& next);
bool projectTriangleOrigin(const Simplex& current, Simplex& next);
bool projectTetrahedraOrigin(const Simplex& current, Simplex& next);
};
struct COAL_DLLAPI EPA {
typedef GJK::SimplexV SimplexVertex;
struct COAL_DLLAPI SimplexFace {
Vec3s n;
CoalScalar d;
bool ignore; // If the origin does not project inside the face, we
// ignore this face.
size_t vertex_id[3]; // Index of vertex in sv_store.
SimplexFace* adjacent_faces[3]; // A face has three adjacent faces.
SimplexFace* prev_face; // The previous face in the list.
SimplexFace* next_face; // The next face in the list.
size_t adjacent_edge[3]; // Each face has 3 edges: `0`, `1` and `2`.
// The i-th adjacent face is bound (to this face)
// along its `adjacent_edge[i]`-th edge
// (with 0 <= i <= 2).
size_t pass;
SimplexFace() : n(Vec3s::Zero()), ignore(false) {};
};
struct COAL_DLLAPI SimplexFaceList {
SimplexFace* root;
size_t count;
SimplexFaceList() : root(nullptr), count(0) {}
void reset() {
root = nullptr;
count = 0;
}
void append(SimplexFace* face) {
face->prev_face = nullptr;
face->next_face = root;
if (root != nullptr) root->prev_face = face;
root = face;
++count;
}
void remove(SimplexFace* face) {
if (face->next_face != nullptr)
face->next_face->prev_face = face->prev_face;
if (face->prev_face != nullptr)
face->prev_face->next_face = face->next_face;
if (face == root) root = face->next_face;
--count;
}
};
static inline void bind(SimplexFace* fa, size_t ea, SimplexFace* fb,
size_t eb) {
assert(ea == 0 || ea == 1 || ea == 2);
assert(eb == 0 || eb == 1 || eb == 2);
fa->adjacent_edge[ea] = eb;
fa->adjacent_faces[ea] = fb;
fb->adjacent_edge[eb] = ea;
fb->adjacent_faces[eb] = fa;
}
struct COAL_DLLAPI SimplexHorizon {
SimplexFace* current_face; // current face in the horizon
SimplexFace* first_face; // first face in the horizon
size_t num_faces; // number of faces in the horizon
SimplexHorizon()
: current_face(nullptr), first_face(nullptr), num_faces(0) {}
};
enum Status {
DidNotRun = -1,
Failed = 0,
Valid = 1,
AccuracyReached = 1 << 1 | Valid,
Degenerated = 1 << 1 | Failed,
NonConvex = 2 << 1 | Failed,
InvalidHull = 3 << 1 | Failed,
OutOfFaces = 4 << 1 | Failed,
OutOfVertices = 5 << 1 | Failed,
FallBack = 6 << 1 | Failed
};
public:
Status status;
GJK::Simplex result;
Vec3s normal;
support_func_guess_t support_hint;
CoalScalar depth;
SimplexFace* closest_face;
private:
// max_iteration and tolerance are made private
// because they are meant to be set by the `reset` function.
size_t max_iterations;
CoalScalar tolerance;
std::vector<SimplexVertex> sv_store;
std::vector<SimplexFace> fc_store;
SimplexFaceList hull, stock;
size_t num_vertices; // number of vertices in polytpoe constructed by EPA
size_t iterations;
public:
EPA(size_t max_iterations_, CoalScalar tolerance_)
: max_iterations(max_iterations_), tolerance(tolerance_) {
initialize();
}
EPA(const EPA& other)
: max_iterations(other.max_iterations),
tolerance(other.tolerance),
sv_store(other.sv_store),
fc_store(other.fc_store) {
initialize();
}
size_t getNumMaxIterations() const { return max_iterations; }
size_t getNumMaxVertices() const { return sv_store.size(); }
size_t getNumMaxFaces() const { return fc_store.size(); }
CoalScalar getTolerance() const { return tolerance; }
size_t getNumIterations() const { return iterations; }
size_t getNumVertices() const { return num_vertices; }
size_t getNumFaces() const { return hull.count; }
void reset(size_t max_iterations, CoalScalar tolerance);
Status evaluate(GJK& gjk, const Vec3s& guess);
void getWitnessPointsAndNormal(const MinkowskiDiff& shape, Vec3s& w0,
Vec3s& w1, Vec3s& normal) const;
private:
void initialize();
bool getEdgeDist(SimplexFace* face, const SimplexVertex& a,
const SimplexVertex& b, CoalScalar& dist);
SimplexFace* newFace(size_t id_a, size_t id_b, size_t id_vertex,
bool force = false);
SimplexFace* findClosestFace();
bool expand(size_t pass, const SimplexVertex& w, SimplexFace* f, size_t e,
SimplexHorizon& horizon);
// @brief Use this function to debug expand if needed.
// void PrintExpandLooping(const SimplexFace* f, const SimplexVertex& w);
};
} // namespace details
} // namespace coal
#endif