File indexing completed on 2024-04-21 03:51:21

0001 /*
0002     SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 /** \file collisionsolver.h
0008  *  \brief CollisionSolver interface
0009  */
0010 
0011 #ifndef STEPCORE_COLLISIONSOLVER_H
0012 #define STEPCORE_COLLISIONSOLVER_H
0013 
0014 #include "object.h"
0015 #include "world.h"
0016 #include "vector.h"
0017 #include "solver.h"
0018 
0019 #define EIGEN_USE_NEW_STDVECTOR
0020 #include <Eigen/StdVector>
0021 
0022 namespace StepCore
0023 {
0024 
0025 class BasePolygon;
0026 class Body;
0027 
0028 /** \ingroup contacts
0029  *  \brief Description of contact between two bodies
0030  */
0031 struct Contact {
0032     EIGEN_MAKE_ALIGNED_OPERATOR_NEW
0033 
0034     enum {
0035         Unknown = 0,    /**< Contact state was not (can not) be determined
0036                              (if state == Unknown all other fields are not used) */
0037         Separated,      /**< Bodies are far away */
0038         Separating,     /**< Bodies are contacted but moving apart */
0039         Contacted,      /**< Bodies are contacted but resting */
0040         Colliding,      /**< Bodies are colliding */
0041         Intersected     /**< Bodies are interpenetrating */
0042     };
0043     enum {
0044         UnknownType,
0045         PolygonPolygonType,
0046         PolygonDiskType,
0047         PolygonParticleType,
0048         DiskDiskType,
0049         DiskParticleType
0050     };
0051     int      type;          /**< Contact type (used internally) */
0052     Body*    body0;         /**< Body0 */
0053     Body*    body1;         /**< Body1 */
0054     int      state;         /**< Contact state (maximum of pointsState if pointsCount > 0) */
0055     double   distance;      /**< Distance between bodies */
0056     Vector2d normal;        /**< Contact normal (pointing from body0 to body1) */
0057     Vector2d normalDerivative; /**< Time derivative of contact normal (only if state == Contacted) */
0058     int      pointsCount;   /**< Count of contact points (either one or two) */
0059     int      pointsState[2];/**< Contact point states */
0060     Vector2d points[2];     /**< Contact point coordinated */
0061     double   vrel[2];       /**< Relative velocities at contact points */
0062 
0063     // Cached values from previous run
0064     // TODO: move it to GJK-specific derived struct
0065     int _w1[2];
0066 };
0067 
0068 /** \ingroup contacts
0069  *  \brief Collision solver interface
0070  *
0071  *  Provides generic interface for collision solvers.
0072  */
0073 class CollisionSolver : public Object
0074 {
0075     STEPCORE_OBJECT(CollisionSolver)
0076 
0077 public:
0078     CollisionSolver(): _toleranceAbs(0.001), _localError(0) {}
0079     virtual ~CollisionSolver() {}
0080 
0081     /** Get absolute allowed tolerance */
0082     double toleranceAbs() const { return _toleranceAbs; }
0083     /** Set absolute allowed tolerance */
0084     virtual void setToleranceAbs(double toleranceAbs) { _toleranceAbs = toleranceAbs; }
0085     /** Get error estimation from last step */
0086     double localError() const { return _localError; }
0087 
0088     /** <!--Check (and update) state of the contact
0089      *  \param contact contact to check (only body0 and body1 fields must be set)
0090      *  \return state of the contact (equals to contact->state)-->
0091      */
0092     //virtual int checkContact(Contact* contact) = 0;
0093 
0094     /** Check and count contacts between several bodies
0095      *  \param bodies list of bodies to check
0096      *  \param collisions defines whether body collisions are taken into account
0097      *  \param count number of contacts
0098      *  \return maximum contact state (i.e. maximum value of Contact::state)
0099      */
0100     virtual int checkContacts(BodyList& bodies, bool collisions = false, int* count = nullptr) = 0;
0101     
0102     /** Fill the constraint info structure with the contacts computed by checkContacts()
0103      *  \param info ConstraintsInfo structure to fill
0104      *  \param collisions defines whether body collisions are taken into account
0105      */
0106     virtual void getContactsInfo(ConstraintsInfo& info, bool collisions = false) = 0;
0107 
0108     // TODO: add errors
0109     /** Solve the collisions between bodies
0110      */
0111     virtual int solveCollisions(BodyList& bodies) = 0;
0112 
0113     /** Reset internal caches of collision information
0114      *  @todo do it automatically by checking the cache
0115      */
0116     virtual void resetCaches() {}
0117 
0118     virtual void bodyAdded(BodyList&, Body*) {}
0119     virtual void bodyRemoved(BodyList&, Body*) {}
0120 
0121 public:
0122     enum {
0123         InternalError = Solver::CollisionError
0124     };
0125 
0126 protected:
0127     double _toleranceAbs;
0128     //double _toleranceRel;
0129     double _localError;
0130 };
0131 
0132 typedef std::vector<Contact, Eigen::aligned_allocator<Contact> >
0133             ContactValueList;
0134 
0135 /** \ingroup contacts
0136  *  \brief Discrete collision solver using Gilbert-Johnson-Keerthi distance algorithm
0137  *
0138  *  Objects are treated as colliding if distance between them is greater than zero
0139  *  but smaller than certain small value. If distance is less than zero objects are
0140  *  always treated as interpenetrating - this signals World::doEvolve to invalidate
0141  *  current time step and try with smaller stepSize until objects are colliding but
0142  *  not interpenetrating.
0143  */
0144 class GJKCollisionSolver : public CollisionSolver
0145 {
0146     STEPCORE_OBJECT(GJKCollisionSolver)
0147 
0148 public:
0149     GJKCollisionSolver() : _contactsIsValid(false) {}
0150 
0151     // TODO: proper copying of the cache !
0152     GJKCollisionSolver(const GJKCollisionSolver& solver)
0153         : CollisionSolver(solver), _contactsIsValid(false) {}
0154     GJKCollisionSolver& operator=(const GJKCollisionSolver&) {
0155         _contactsIsValid = false; return *this; }
0156 
0157     /*
0158     enum {
0159         OK = 0,
0160         CollisionDetected = 4096,
0161         PenetrationDetected = 4097
0162     };*/
0163 
0164     /**
0165      * \param bodies list of bodies to check
0166      * \param collisions defines whether body collisions are taken into account
0167      * \param count number of contacts
0168      */
0169     int checkContacts(BodyList& bodies, bool collisions = false, int* count = nullptr) override;
0170     /**
0171      * \param info ConstraintsInfo structure to fill
0172      * \param collisions defines whether body collisions are taken into account
0173      */
0174     void getContactsInfo(ConstraintsInfo& info, bool collisions = false) override;
0175     //int findClosestPoints(const BasePolygon* polygon1, const BasePolygon* polygon2);
0176 
0177     int solveCollisions(BodyList& bodies) override;
0178     //int solveConstraints(BodyList& bodies);
0179 
0180     void resetCaches() override;
0181     void bodyAdded(BodyList& bodies, Body* body) override;
0182     void bodyRemoved(BodyList& bodies, Body* body) override;
0183 
0184 protected:
0185     int checkContact(Contact* contact);
0186 
0187     int checkPolygonPolygon(Contact* contact);
0188     int solvePolygonPolygon(Contact* contact);
0189 
0190     int checkPolygonParticle(Contact* contact);
0191     int solvePolygonParticle(Contact* contact);
0192 
0193     int checkPolygonDisk(Contact* contact);
0194     int solvePolygonDisk(Contact* contact);
0195 
0196     int checkDiskDisk(Contact* contact);
0197     int solveDiskDisk(Contact* contact);
0198 
0199     int checkDiskParticle(Contact* contact);
0200     int solveDiskParticle(Contact* contact);
0201 
0202     void addContact(Body* body0, Body* body1);
0203     void checkCache(BodyList& bodies);
0204 
0205 protected:
0206     ContactValueList _contacts;
0207     bool             _contactsIsValid;
0208 };
0209 
0210 } // namespace StepCore
0211 
0212 #endif
0213