Quark Physics  1.0
2D Rigid and Soft Body Physics Engine
qmesh.h
1 
2 /************************************************************************************
3  * MIT License
4  *
5  * Copyright (c) 2023 Eray Zesen
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  * https://github.com/erayzesen/QuarkPhysics
25  *
26 **************************************************************************************/
27 
28 #ifndef QMESH_H
29 #define QMESH_H
30 #include <vector>
31 #include "cmath"
32 #include "qspring.h"
33 #include "qparticle.h"
34 #include "qangleconstraint.h"
35 #include "json/json.hpp"
36 #include "fstream"
37 #include "qmath_utils.h"
38 
39 using json =nlohmann::json;
40 
41 using namespace std;
42 
43 class QBody;
48 struct QMesh
49 {
50 public:
51  enum CollisionBehaviors{
52  CIRCLES,
53  POLYGONS,
54  POLYLINE
55  };
56 protected:
57  vector<QParticle*> particles=vector<QParticle*>();
58 
59  //General Properties
60  QVector position=QVector::Zero();
61  QVector globalPosition=QVector::Zero();
62  float rotation=0.0f;
63  float globalRotation=0.0f;
64  vector<QSpring*> springs=vector<QSpring*>();
65  vector<QAngleConstraint*> angleConstraints=vector<QAngleConstraint*>();
66  vector <QParticle*> polygon=vector<QParticle*>();
67  vector<vector<QParticle*>> subConvexPolygons=vector<vector<QParticle*>>();
68  vector<QVector> polygonBisectors;
69  float circumference=0.0f;
70  QBody *ownerBody=nullptr;
71  CollisionBehaviors collisionBehavior=CollisionBehaviors::CIRCLES;
72  vector<vector<int>> UVMaps=vector<vector<int>>();
73  bool disablePolygonForCollisions=false;
74 
75 
76  bool collisionBehaviorNeedsUpdate=false;
77 
78  //Helper Methods
79  void UpdateCollisionBehavior();
80 
81 
82  //Polygon Properties
83  vector<float> lastPolygonCornerAngles;
84  float minAngleConstraintOfPolygon=M_PI*0.3;
85 
86  //Polygon Methods
87  void UpdateSubConvexPolygons(bool majorUpdate=true);
88  void UpdatePolygonBisectors();
89  static vector<QVector> GetBisectors(vector<QParticle*> polygonParticles);
90  void ApplyAngleConstraintsToPolygon();
91  bool CheckIsPolygonConcave(vector<QParticle*> polygonParticles);
92  static bool CheckIsReflex(QVector pA,QVector pB, QVector pC);
93  static bool CheckIsReflex(int indexA,int indexB, int indexC, vector<QParticle*> polygonParticles);
94  static void TriangulatePolygon(vector<QParticle*> &polygonParticles,vector<vector<int>> &triangles);
95  static void DecompositePolygon(vector<QParticle*> &polygonParticles,vector<vector<QParticle*>> &polygons);
96  static void DecompositePolygon2(vector<QParticle*> &polygonParticles,vector<vector<QParticle*>> &polygons);
97  bool subConvexPolygonsNeedsUpdate=false;
98  bool polygonBisectorsNeedsUpdate=true;
99  bool isPolygonSelfIntersected=false;
100 
101 public:
104  struct MeshData{
106  vector<QVector> particlePositions;
108  vector<float> particleRadValues;
112  vector<bool> particleEnabledValues;
114  vector<bool> particleLazyValues;
118  vector<pair<int,int>> springList;
123  vector<pair<int,int>> internalSpringList;
129  vector<int> polygon;
130 
131 
137  vector<vector<int>> UVMaps;
138 
140  QVector position=QVector::Zero();
141 
143  float rotation=0.0f;
144 
145  };
146 
147  friend class QWorld;
148  friend class QBody;
149  friend class QRigidBody;
150  friend class QSoftBody;
151  friend class QRaycast;
152  friend class QCollision;
153  friend class QParticle;
154 
156  QMesh();
157  ~QMesh();
158 
159 
160  //General Get Methods
163  return position;
164  }
167  return globalPosition;
168  }
170  float GetRotation(){
171  return rotation;
172  }
175  return globalRotation;
176  }
178  float GetInitialArea(){
179  float res=0.0f;
180  res+=GetPolygonArea(polygon,true);
181  for(auto particle:particles){
182  if(particle->GetRadius()>0.5f){
183  res+=particle->GetRadius()*particle->GetRadius();
184  }
185  }
186  return res;
187  }
190  float res=GetPolygonArea(polygon,true);
191  return res;
192  }
195  float GetArea(){
196  float res=0.0f;
197  res+=GetPolygonArea(polygon,false);
198  for(auto particle:particles){
199  if(particle->GetRadius()>0.5f){
200  res+=particle->GetRadius()*particle->GetRadius();
201  }
202  }
203  return res;
204  }
206  float GetPolygonArea(){
207  float res=GetPolygonArea(polygon,false);
208 
209  return res;
210  }
211 
214  float res=0.0f;
215  for(int i=0;i<polygon.size();i++){
216  QParticle *p=polygon[i];
217  QParticle *np=polygon[(i+1)%polygon.size()];
218  float length=(np->GetPosition()-p->GetPosition()).Length();
219  res+=length;
220  }
221 
222  return res;
223  }
228  return ownerBody;
229  }
233  CollisionBehaviors GetCollisionBehavior(){
234  if(collisionBehaviorNeedsUpdate){
235  UpdateCollisionBehavior();
236  collisionBehaviorNeedsUpdate=false;
237  }
238  return collisionBehavior;
239  }
247  return disablePolygonForCollisions;
248  }
249 
250 
251  //General Set Methods
257  position=value;
258  return this;
259  }
265  globalPosition=value;
266  return this;
267  }
272  QMesh *SetRotation(float value){
273  rotation=value;
274  return this;
275  }
276 
286  disablePolygonForCollisions=value;
287  collisionBehaviorNeedsUpdate=true;
288  return this;
289  }
290 
291 
292 
293 
294 
295  //Particle Operations
296 
301  QMesh * AddParticle(QParticle *particle);
302 
307  QMesh * RemoveParticleAt(int index);
312  QMesh * RemoveParticle(QParticle *particle);
315  int GetParticleCount();
319  QParticle *GetParticleAt(int index);
320 
325  int GetParticleIndex(QParticle *particle){
326  for(int i=0;i<particles.size();i++){
327  if(particles[i]==particle){
328  return i;
329  }
330  }
331  return -1;
332  }
333 
334 
335 
336 
337  //Polygon Operations
338 
343  QMesh * SetPolygon(vector<QParticle *> polygonParticles);
344 
351  QMesh * AddParticleToPolygon(QParticle * particle, int position=-1);
352 
359  QMesh *RemoveParticleFromPolygon(QParticle * particle);
360 
367  QMesh * RemoveParticleFromPolygonAt(int index);
368 
373  QMesh * RemovePolygon();
374 
377  int GetPolygonParticleCount();
378 
384  QParticle *GetParticleFromPolygon(int index);
385 
386 
392  return minAngleConstraintOfPolygon;
393  }
394 
401  minAngleConstraintOfPolygon=radian;
402  return this;
403  }
404 
405 
406 
410  if (subConvexPolygonsNeedsUpdate==true){
411  UpdateSubConvexPolygons();
412  subConvexPolygonsNeedsUpdate=false;
413  }
414  return subConvexPolygons.size();
415  }
419  vector<QParticle*> &GetSubConvexPolygonAt(int index){
420  if (subConvexPolygonsNeedsUpdate==true){
421  UpdateSubConvexPolygons();
422  subConvexPolygonsNeedsUpdate=false;
423  }
424  return subConvexPolygons[index];
425  }
426 
427  QVector GetPolygonBisectorVectorAt(int index){
428  return polygonBisectors[index];
429  }
430 
431 
432  //Spring Operations
433 
438  QMesh *AddSpring(QSpring *spring);
443  QMesh *RemoveSpring(QSpring *spring);
448  QMesh *RemoveSpringAt(int index);
453  QMesh *RemoveMatchingSprings(QParticle *particle);
457  return springs.size();
458  }
462  QSpring *GetSpringAt(int index){
463  return springs[index];
464  }
469  int GetSpringIndex(QSpring *spring){
470  for(int i=0;i<springs.size();i++)
471  if(springs[i]==spring)
472  return i;
473  return -1;
474  }
475 
476 
477 
478  //UV Operations
479 
483  return UVMaps.size();
484  };
485 
489  vector<int> GetUVMapAt(int index){
490  return UVMaps[index];
491  };
492 
497  QMesh * AddUVMap(vector<int> map);
498 
504  QMesh * RemoveUVMapAt(int index);
505 
510  QMesh * ClearUVMaps();
511 
512 
517  QMesh * RemoveMatchingUVMaps(int particleIndex);
518 
519 
520 
521 
522  //Angle Constraint Operations
523 
526  return angleConstraints.size();
527  }
533  return angleConstraints[index];
534  }
540  angleConstraints.push_back(angleConstraint);
541  return this;
542  }
543 
550  angleConstraints.erase(angleConstraints.begin()+index );
551  return this;
552  }
558  for(int i=0;i<angleConstraints.size();i++)
559  if(angleConstraints[i]==angleConstraint)
560  return i;
561  return -1;
562  }
563 
569  int index=GetAngleConstraintIndex(angleConstraint);
570  if(index!=-1){
571  RemoveAngleConstraintAt(index);
572  }
573  return this;
574  }
575 
582  int i=0;
583  while(i<angleConstraints.size()){
584  QAngleConstraint *constraint=angleConstraints[i];
585  if(constraint->GetParticleA()==particle || constraint->GetParticleB()==particle || constraint->GetParticleC()==particle){
586  RemoveAngleConstraintAt(i);
587  }else{
588  ++i;
589  }
590  }
591 
592  return this;
593  }
594 
595 
596 
597 
598 
599  //Static Methods
606  static QMesh * CreateWithCircle(float radius,QVector centerPosition=QVector::Zero());
618  static QMesh * CreateWithPolygon(float radius,int sideCount,QVector centerPosition=QVector::Zero(),int polarGrid=-1,bool enableSprings=true, bool enablePolygons=true,float particleRadius=0.5f);
619 
630  static QMesh * CreateWithRect(QVector size,QVector centerPosition=QVector::Zero(),QVector grid=QVector::Zero(),bool enableSprings=true, bool enablePolygons=true,float particleRadius=0.5f);
631 
638  static QMesh * CreateWithMeshData(QMesh::MeshData &data,bool enableSprings=true, bool enablePolygons=true);
639 
644  static vector<QMesh::MeshData> GetMeshDatasFromFile(string filePath);
645 
646 
651  static vector<QMesh::MeshData> GetMeshDatasFromJsonData(std::string &jsonBasedData);
652 
653 
654 
655 
656 
662  static float GetPolygonArea(vector<QParticle*> &polygonPoints,bool withLocalPositions=false);
663 
664 
672  static bool CheckCollisionBehaviors(QMesh *meshA,QMesh * meshB,CollisionBehaviors firstBehavior,CollisionBehaviors secondBehavior );
681  static MeshData GenerateRectangleMeshData(QVector size,QVector centerPosition=QVector::Zero(),QVector grid=QVector::Zero(),float particleRadius=0.5f);
691  static MeshData GeneratePolygonMeshData(float radius, int sideCount, QVector centerPosition=QVector::Zero(),int polarGrid=-1,float particleRadius=0.5f);
692 
697  static pair<QVector, float> GetAveragePositionAndRotation(vector<QParticle*> particleCollection);
698 
706  static vector<QVector> GetMatchingParticlePositions(vector<QParticle*> particleCollection,QVector targetPosition, float targetRotation);
707 
708 
712  bool manualDeletion=false;
713 
714  friend class QSoftBody;
715 
716 
717 
718 };
719 
720 #endif // QMESH_H
You can apply angle constraints between 3 particles using the QAngleConstraint. The physics engine us...
Definition: qangleconstraint.h:38
QParticle * GetParticleB()
Definition: qangleconstraint.h:84
QParticle * GetParticleC()
Definition: qangleconstraint.h:88
QParticle * GetParticleA()
Definition: qangleconstraint.h:80
QBody objects are the base class for all types of bodies. Any class derived from QBody shares these m...
Definition: qbody.h:43
The QCollision class performs all collision detection operations. The relevant methods return contact...
Definition: qcollision.h:44
QParticle objects form the network structures of QMesh objects defined for all body object types....
Definition: qparticle.h:40
bool manualDeletion
Definition: qparticle.h:270
QVector GetPosition()
Definition: qparticle.h:102
QRaycast objects send a ray into the world and return collision results with body objects....
Definition: qraycast.h:38
QRigidBody is a type of body that is simulated with the dynamics of Rigid body. A rigid body is a typ...
Definition: qrigidbody.h:40
QSoftBody is a body type that defines deformable, soft objects in the physics world....
Definition: qsoftbody.h:35
You can apply distance constraints between 2 particles using the QSpring. The physics engine uses QSp...
Definition: qspring.h:39
A QWorld object is required to create a physics simulation. The QWorld class manages the entire physi...
Definition: qworld.h:51
Definition: qmesh.h:104
vector< QVector > particlePositions
Definition: qmesh.h:106
vector< pair< int, int > > springList
Definition: qmesh.h:118
vector< bool > particleLazyValues
Definition: qmesh.h:114
vector< bool > particleInternalValues
Definition: qmesh.h:110
vector< int > polygon
Definition: qmesh.h:129
vector< vector< int > > UVMaps
Definition: qmesh.h:137
vector< float > particleRadValues
Definition: qmesh.h:108
vector< pair< int, int > > internalSpringList
Definition: qmesh.h:123
vector< bool > particleEnabledValues
Definition: qmesh.h:112
Every QBody object requires meshes. In other traditional physics engines, the term 'shape' is used in...
Definition: qmesh.h:49
vector< QParticle * > & GetSubConvexPolygonAt(int index)
Definition: qmesh.h:419
QVector GetGlobalPosition()
Definition: qmesh.h:166
QSpring * GetSpringAt(int index)
Definition: qmesh.h:462
int GetSpringIndex(QSpring *spring)
Definition: qmesh.h:469
float GetPolygonArea()
Definition: qmesh.h:206
QMesh * SetPolygonForCollisionsDisabled(bool value)
Definition: qmesh.h:285
bool GetPolygonForCollisionsDisabled()
Definition: qmesh.h:246
QVector GetPosition()
Definition: qmesh.h:162
QMesh * RemoveAngleConstraintAt(int index)
Definition: qmesh.h:549
float GetRotation()
Definition: qmesh.h:170
int GetAngleConstraintCount()
Definition: qmesh.h:525
QAngleConstraint * GetAngleConstraintAt(int index)
Definition: qmesh.h:532
QMesh * SetGlobalPosition(QVector value)
Definition: qmesh.h:264
QMesh * AddAngleConstraint(QAngleConstraint *angleConstraint)
Definition: qmesh.h:539
float GetGlobalRotation()
Definition: qmesh.h:174
int GetUVMapCount()
Definition: qmesh.h:482
float GetMinAngleConstraintOfPolygon()
Definition: qmesh.h:391
float GetArea()
Definition: qmesh.h:195
int GetParticleIndex(QParticle *particle)
Definition: qmesh.h:325
int GetAngleConstraintIndex(QAngleConstraint *angleConstraint)
Definition: qmesh.h:557
vector< int > GetUVMapAt(int index)
Definition: qmesh.h:489
QBody * GetOwnerBody()
Definition: qmesh.h:227
QMesh * SetRotation(float value)
Definition: qmesh.h:272
int GetSpringCount()
Definition: qmesh.h:456
int GetSubConvexPolygonCount()
Definition: qmesh.h:409
float GetInitialPolygonArea()
Definition: qmesh.h:189
QMesh * RemoveAngleConstraint(QAngleConstraint *angleConstraint)
Definition: qmesh.h:568
float GetCircumference()
Definition: qmesh.h:213
QMesh * RemoveMatchingAngleConstraints(QParticle *particle)
Definition: qmesh.h:581
float GetInitialArea()
Definition: qmesh.h:178
QMesh * SetPosition(QVector value)
Definition: qmesh.h:256
QMesh * SetMinAngleConstraintOfPolygon(float radian)
Definition: qmesh.h:400
CollisionBehaviors GetCollisionBehavior()
Definition: qmesh.h:233
Definition: qvector.h:44