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  }
335  QVector GetAveragePosition();
336 
339  float GetAverageRotation();
340 
341 
342 
343 
344  //Polygon Operations
345 
350  QMesh * SetPolygon(vector<QParticle *> polygonParticles);
351 
358  QMesh * AddParticleToPolygon(QParticle * particle, int position=-1);
359 
366  QMesh *RemoveParticleFromPolygon(QParticle * particle);
367 
374  QMesh * RemoveParticleFromPolygonAt(int index);
375 
380  QMesh * RemovePolygon();
381 
384  int GetPolygonParticleCount();
385 
391  QParticle *GetParticleFromPolygon(int index);
392 
393 
399  return minAngleConstraintOfPolygon;
400  }
401 
408  minAngleConstraintOfPolygon=radian;
409  return this;
410  }
411 
412 
413 
417  if (subConvexPolygonsNeedsUpdate==true){
418  UpdateSubConvexPolygons();
419  subConvexPolygonsNeedsUpdate=false;
420  }
421  return subConvexPolygons.size();
422  }
426  vector<QParticle*> &GetSubConvexPolygonAt(int index){
427  if (subConvexPolygonsNeedsUpdate==true){
428  UpdateSubConvexPolygons();
429  subConvexPolygonsNeedsUpdate=false;
430  }
431  return subConvexPolygons[index];
432  }
433 
434  QVector GetPolygonBisectorVectorAt(int index){
435  return polygonBisectors[index];
436  }
437 
438 
439  //Spring Operations
440 
445  QMesh *AddSpring(QSpring *spring);
450  QMesh *RemoveSpring(QSpring *spring);
455  QMesh *RemoveSpringAt(int index);
460  QMesh *RemoveMatchingSprings(QParticle *particle);
464  return springs.size();
465  }
469  QSpring *GetSpringAt(int index){
470  return springs[index];
471  }
476  int GetSpringIndex(QSpring *spring){
477  for(int i=0;i<springs.size();i++)
478  if(springs[i]==spring)
479  return i;
480  return -1;
481  }
482 
483 
484 
485  //UV Operations
486 
490  return UVMaps.size();
491  };
492 
496  vector<int> GetUVMapAt(int index){
497  return UVMaps[index];
498  };
499 
504  QMesh * AddUVMap(vector<int> map);
505 
511  QMesh * RemoveUVMapAt(int index);
512 
517  QMesh * ClearUVMaps();
518 
519 
524  QMesh * RemoveMatchingUVMaps(int particleIndex);
525 
526 
527 
528 
529  //Angle Constraint Operations
530 
533  return angleConstraints.size();
534  }
540  return angleConstraints[index];
541  }
547  angleConstraints.push_back(angleConstraint);
548  return this;
549  }
550 
557  angleConstraints.erase(angleConstraints.begin()+index );
558  return this;
559  }
565  for(int i=0;i<angleConstraints.size();i++)
566  if(angleConstraints[i]==angleConstraint)
567  return i;
568  return -1;
569  }
570 
576  int index=GetAngleConstraintIndex(angleConstraint);
577  if(index!=-1){
578  RemoveAngleConstraintAt(index);
579  }
580  return this;
581  }
582 
589  int i=0;
590  while(i<angleConstraints.size()){
591  QAngleConstraint *constraint=angleConstraints[i];
592  if(constraint->GetParticleA()==particle || constraint->GetParticleB()==particle || constraint->GetParticleC()==particle){
593  RemoveAngleConstraintAt(i);
594  }else{
595  ++i;
596  }
597  }
598 
599  return this;
600  }
601 
602 
603 
604 
605 
606  //Static Methods
613  static QMesh * CreateWithCircle(float radius,QVector centerPosition=QVector::Zero());
625  static QMesh * CreateWithPolygon(float radius,int sideCount,QVector centerPosition=QVector::Zero(),int polarGrid=-1,bool enableSprings=true, bool enablePolygons=true,float particleRadius=0.5f);
626 
637  static QMesh * CreateWithRect(QVector size,QVector centerPosition=QVector::Zero(),QVector grid=QVector::Zero(),bool enableSprings=true, bool enablePolygons=true,float particleRadius=0.5f);
638 
645  static QMesh * CreateWithMeshData(QMesh::MeshData &data,bool enableSprings=true, bool enablePolygons=true);
646 
651  static vector<QMesh::MeshData> GetMeshDatasFromFile(string filePath);
652 
653 
658  static vector<QMesh::MeshData> GetMeshDatasFromJsonData(std::string &jsonBasedData);
659 
660 
661 
662 
663 
669  static float GetPolygonArea(vector<QParticle*> &polygonPoints,bool withLocalPositions=false);
670 
671 
679  static bool CheckCollisionBehaviors(QMesh *meshA,QMesh * meshB,CollisionBehaviors firstBehavior,CollisionBehaviors secondBehavior );
688  static MeshData GenerateRectangleMeshData(QVector size,QVector centerPosition=QVector::Zero(),QVector grid=QVector::Zero(),float particleRadius=0.5f);
698  static MeshData GeneratePolygonMeshData(float radius, int sideCount, QVector centerPosition=QVector::Zero(),int polarGrid=-1,float particleRadius=0.5f);
699 
704  static pair<QVector, float> GetAveragePositionAndRotation(vector<QParticle*> particleCollection);
705 
713  static vector<QVector> GetMatchingParticlePositions(vector<QParticle*> particleCollection,QVector targetPosition, float targetRotation);
714 
715 
719  bool manualDeletion=false;
720 
721  friend class QSoftBody;
722 
723 
724 
725 };
726 
727 #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:426
QVector GetGlobalPosition()
Definition: qmesh.h:166
QSpring * GetSpringAt(int index)
Definition: qmesh.h:469
int GetSpringIndex(QSpring *spring)
Definition: qmesh.h:476
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:556
float GetRotation()
Definition: qmesh.h:170
int GetAngleConstraintCount()
Definition: qmesh.h:532
QAngleConstraint * GetAngleConstraintAt(int index)
Definition: qmesh.h:539
QMesh * SetGlobalPosition(QVector value)
Definition: qmesh.h:264
QMesh * AddAngleConstraint(QAngleConstraint *angleConstraint)
Definition: qmesh.h:546
float GetGlobalRotation()
Definition: qmesh.h:174
int GetUVMapCount()
Definition: qmesh.h:489
float GetMinAngleConstraintOfPolygon()
Definition: qmesh.h:398
float GetArea()
Definition: qmesh.h:195
int GetParticleIndex(QParticle *particle)
Definition: qmesh.h:325
int GetAngleConstraintIndex(QAngleConstraint *angleConstraint)
Definition: qmesh.h:564
vector< int > GetUVMapAt(int index)
Definition: qmesh.h:496
QBody * GetOwnerBody()
Definition: qmesh.h:227
QMesh * SetRotation(float value)
Definition: qmesh.h:272
int GetSpringCount()
Definition: qmesh.h:463
int GetSubConvexPolygonCount()
Definition: qmesh.h:416
float GetInitialPolygonArea()
Definition: qmesh.h:189
QMesh * RemoveAngleConstraint(QAngleConstraint *angleConstraint)
Definition: qmesh.h:575
float GetCircumference()
Definition: qmesh.h:213
QMesh * RemoveMatchingAngleConstraints(QParticle *particle)
Definition: qmesh.h:588
float GetInitialArea()
Definition: qmesh.h:178
QMesh * SetPosition(QVector value)
Definition: qmesh.h:256
QMesh * SetMinAngleConstraintOfPolygon(float radian)
Definition: qmesh.h:407
CollisionBehaviors GetCollisionBehavior()
Definition: qmesh.h:233
Definition: qvector.h:44