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  float circumference=0.0f;
69  QBody *ownerBody=nullptr;
70  CollisionBehaviors collisionBehavior=CollisionBehaviors::CIRCLES;
71  vector<vector<int>> UVMaps=vector<vector<int>>();
72  bool disablePolygonForCollisions=false;
73 
74  bool collisionBehaviorNeedsUpdate=false;
75 
76  //Helper Methods
77  void UpdateCollisionBehavior();
78 
79  //Polygon Properties
80  vector<float> lastPolygonCornerAngles;
81  float minAngleConstraintOfPolygon=M_PI*0.3;
82 
83  //Polygon Methods
84  void UpdateSubConvexPolygons(bool majorUpdate=true);
85  void ApplyAngleConstraintsToPolygon();
86  bool CheckIsPolygonConcave(vector<QParticle*> polygonParticles);
87  static bool CheckIsReflex(QVector pA,QVector pB, QVector pC);
88  static bool CheckIsReflex(int indexA,int indexB, int indexC, vector<QParticle*> polygonParticles);
89  static void TriangulatePolygon(vector<QParticle*> &polygonParticles,vector<vector<int>> &triangles);
90  static void DecompositePolygon(vector<QParticle*> &polygonParticles,vector<vector<QParticle*>> &polygons);
91  static void DecompositePolygon2(vector<QParticle*> &polygonParticles,vector<vector<QParticle*>> &polygons);
92  bool subConvexPolygonsNeedsUpdate=false;
93 
94 public:
97  struct MeshData{
99  vector<QVector> particlePositions;
101  vector<float> particleRadValues;
105  vector<bool> particleEnabledValues;
107  vector<bool> particleLazyValues;
111  vector<pair<int,int>> springList;
116  vector<pair<int,int>> internalSpringList;
122  vector<int> polygon;
123 
124 
130  vector<vector<int>> UVMaps;
131 
133  QVector position=QVector::Zero();
134 
136  float rotation=0.0f;
137 
138  };
139 
140  friend class QWorld;
141  friend class QBody;
142  friend class QRigidBody;
143  friend class QSoftBody;
144  friend class QRaycast;
145  friend class QCollision;
146  friend class QParticle;
147 
149  QMesh();
150  ~QMesh();
151 
152 
153  //General Get Methods
156  return position;
157  }
160  return globalPosition;
161  }
163  float GetRotation(){
164  return rotation;
165  }
168  return globalRotation;
169  }
171  float GetInitialArea(){
172  float res=0.0f;
173  for(size_t n=0;n<GetSubConvexPolygonCount();n++){
174 
175  res+=GetPolygonArea(GetSubConvexPolygonAt(n),true);
176  }
177  for(auto particle:particles){
178  if(particle->GetRadius()>0.5f){
179  res+=particle->GetRadius()*particle->GetRadius();
180  }
181  }
182  return res;
183  }
186  float res=0.0f;
187  for(size_t n=0;n<GetSubConvexPolygonCount();n++){
188  res+=GetPolygonArea(GetSubConvexPolygonAt(n),true);
189  }
190  return res;
191  }
194  float GetArea(){
195  float res=0.0f;
196  for(size_t n=0;n<GetSubConvexPolygonCount();n++){
197  res+=GetPolygonArea(GetSubConvexPolygonAt(n));
198  }
199  for(auto particle:particles){
200  if(particle->GetRadius()>0.5f){
201  res+=particle->GetRadius()*particle->GetRadius();
202  }
203  }
204  return res;
205  }
208  float res=0.0f;
209  for(size_t n=0;n<GetSubConvexPolygonCount();n++){
210  res+=GetPolygonArea(GetSubConvexPolygonAt(n));
211  }
212 
213  return res;
214  }
215 
218  float res=0.0f;
219  for(size_t n=0;n<GetSubConvexPolygonCount();n++){
220  auto polygon=GetSubConvexPolygonAt(n);
221  for(int i=0;i<polygon.size();i++){
222  QParticle *p=polygon[i];
223  QParticle *np=polygon[(i+1)%polygon.size()];
224  float length=(np->GetPosition()-p->GetPosition()).Length();
225  res+=length;
226  }
227  }
228 // for(auto spring:springs){
229 // res+=(spring.GetParticleA()->GetGlobalPosition()-spring.GetParticleB()->GetGlobalPosition()).Length();
230 // }
231  return res;
232  }
237  return ownerBody;
238  }
242  CollisionBehaviors GetCollisionBehavior(){
243  if(collisionBehaviorNeedsUpdate){
244  UpdateCollisionBehavior();
245  collisionBehaviorNeedsUpdate=false;
246  }
247  return collisionBehavior;
248  }
256  return disablePolygonForCollisions;
257  }
258 
259 
260  //General Set Methods
266  position=value;
267  return this;
268  }
274  globalPosition=value;
275  return this;
276  }
281  QMesh *SetRotation(float value){
282  rotation=value;
283  return this;
284  }
285 
295  disablePolygonForCollisions=value;
296  collisionBehaviorNeedsUpdate=true;
297  return this;
298  }
299 
300 
301 
302 
303 
304  //Particle Operations
305 
310  QMesh * AddParticle(QParticle *particle);
311 
316  QMesh * RemoveParticleAt(int index);
321  QMesh * RemoveParticle(QParticle *particle);
324  int GetParticleCount();
328  QParticle *GetParticleAt(int index);
329 
334  int GetParticleIndex(QParticle *particle){
335  for(int i=0;i<particles.size();i++){
336  if(particles[i]==particle){
337  return i;
338  }
339  }
340  return -1;
341  }
342 
343 
344 
345 
346  //Polygon Operations
347 
352  QMesh * SetPolygon(vector<QParticle *> polygonParticles);
353 
360  QMesh * AddParticleToPolygon(QParticle * particle, int position=-1);
361 
368  QMesh *RemoveParticleFromPolygon(QParticle * particle);
369 
376  QMesh * RemoveParticleFromPolygonAt(int index);
377 
382  QMesh * RemovePolygon();
383 
386  int GetPolygonParticleCount();
387 
393  QParticle *GetParticleFromPolygon(int index);
394 
395 
401  return minAngleConstraintOfPolygon;
402  }
403 
410  minAngleConstraintOfPolygon=radian;
411  return this;
412  }
413 
414 
415 
419  if (subConvexPolygonsNeedsUpdate==true){
420  UpdateSubConvexPolygons();
421  subConvexPolygonsNeedsUpdate=false;
422  }
423  return subConvexPolygons.size();
424  }
428  vector<QParticle*> &GetSubConvexPolygonAt(int index){
429  if (subConvexPolygonsNeedsUpdate==true){
430  UpdateSubConvexPolygons();
431  subConvexPolygonsNeedsUpdate=false;
432  }
433  return subConvexPolygons[index];
434  }
435 
436 
437  //Spring Operations
438 
443  QMesh *AddSpring(QSpring *spring);
448  QMesh *RemoveSpring(QSpring *spring);
453  QMesh *RemoveSpringAt(int index);
458  QMesh *RemoveMatchingSprings(QParticle *particle);
462  return springs.size();
463  }
467  QSpring *GetSpringAt(int index){
468  return springs[index];
469  }
474  int GetSpringIndex(QSpring *spring){
475  for(int i=0;i<springs.size();i++)
476  if(springs[i]==spring)
477  return i;
478  return -1;
479  }
480 
481 
482 
483  //UV Operations
484 
488  return UVMaps.size();
489  };
490 
494  vector<int> GetUVMapAt(int index){
495  return UVMaps[index];
496  };
497 
502  QMesh * AddUVMap(vector<int> map);
503 
509  QMesh * RemoveUVMapAt(int index);
510 
515  QMesh * ClearUVMaps();
516 
517 
522  QMesh * RemoveMatchingUVMaps(int particleIndex);
523 
524 
525 
526 
527  //Angle Constraint Operations
528 
531  return angleConstraints.size();
532  }
538  return angleConstraints[index];
539  }
545  angleConstraints.push_back(angleConstraint);
546  return this;
547  }
548 
555  angleConstraints.erase(angleConstraints.begin()+index );
556  return this;
557  }
563  for(int i=0;i<angleConstraints.size();i++)
564  if(angleConstraints[i]==angleConstraint)
565  return i;
566  return -1;
567  }
568 
574  int index=GetAngleConstraintIndex(angleConstraint);
575  if(index!=-1){
576  RemoveAngleConstraintAt(index);
577  }
578  return this;
579  }
580 
587  int i=0;
588  while(i<angleConstraints.size()){
589  QAngleConstraint *constraint=angleConstraints[i];
590  if(constraint->GetParticleA()==particle || constraint->GetParticleB()==particle || constraint->GetParticleC()==particle){
591  RemoveAngleConstraintAt(i);
592  }else{
593  ++i;
594  }
595  }
596 
597  return this;
598  }
599 
600 
601 
602 
603 
604  //Static Methods
611  static QMesh * CreateWithCircle(float radius,QVector centerPosition=QVector::Zero());
623  static QMesh * CreateWithPolygon(float radius,int sideCount,QVector centerPosition=QVector::Zero(),int polarGrid=-1,bool enableSprings=true, bool enablePolygons=true,float particleRadius=0.5f);
624 
635  static QMesh * CreateWithRect(QVector size,QVector centerPosition=QVector::Zero(),QVector grid=QVector::Zero(),bool enableSprings=true, bool enablePolygons=true,float particleRadius=0.5f);
636 
643  static QMesh * CreateWithMeshData(QMesh::MeshData &data,bool enableSprings=true, bool enablePolygons=true);
644 
649  static vector<QMesh::MeshData> GetMeshDatasFromFile(string filePath);
650 
651 
656  static vector<QMesh::MeshData> GetMeshDatasFromJsonData(std::string &jsonBasedData);
657 
658 
659 
660 
661 
667  static float GetPolygonArea(vector<QParticle*> &polygonPoints,bool withLocalPositions=false);
668 
669 
677  static bool CheckCollisionBehaviors(QMesh *meshA,QMesh * meshB,CollisionBehaviors firstBehavior,CollisionBehaviors secondBehavior );
686  static MeshData GenerateRectangleMeshData(QVector size,QVector centerPosition=QVector::Zero(),QVector grid=QVector::Zero(),float particleRadius=0.5f);
696  static MeshData GeneratePolygonMeshData(float radius, int sideCount, QVector centerPosition=QVector::Zero(),int polarGrid=-1,float particleRadius=0.5f);
697 
702  static pair<QVector, float> GetAveragePositionAndRotation(vector<QParticle*> particleCollection);
703 
711  static vector<QVector> GetMatchingParticlePositions(vector<QParticle*> particleCollection,QVector targetPosition, float targetRotation);
712 
713 
717  bool manualDeletion=false;
718 
719  friend class QSoftBody;
720 
721 
722 
723 };
724 
725 #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:97
vector< QVector > particlePositions
Definition: qmesh.h:99
vector< pair< int, int > > springList
Definition: qmesh.h:111
vector< bool > particleLazyValues
Definition: qmesh.h:107
vector< bool > particleInternalValues
Definition: qmesh.h:103
vector< int > polygon
Definition: qmesh.h:122
vector< vector< int > > UVMaps
Definition: qmesh.h:130
vector< float > particleRadValues
Definition: qmesh.h:101
vector< pair< int, int > > internalSpringList
Definition: qmesh.h:116
vector< bool > particleEnabledValues
Definition: qmesh.h:105
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:428
QVector GetGlobalPosition()
Definition: qmesh.h:159
QSpring * GetSpringAt(int index)
Definition: qmesh.h:467
int GetSpringIndex(QSpring *spring)
Definition: qmesh.h:474
QMesh * SetPolygonForCollisionsDisabled(bool value)
Definition: qmesh.h:294
bool GetPolygonForCollisionsDisabled()
Definition: qmesh.h:255
QVector GetPosition()
Definition: qmesh.h:155
QMesh * RemoveAngleConstraintAt(int index)
Definition: qmesh.h:554
float GetRotation()
Definition: qmesh.h:163
int GetAngleConstraintCount()
Definition: qmesh.h:530
QAngleConstraint * GetAngleConstraintAt(int index)
Definition: qmesh.h:537
QMesh * SetGlobalPosition(QVector value)
Definition: qmesh.h:273
QMesh * AddAngleConstraint(QAngleConstraint *angleConstraint)
Definition: qmesh.h:544
float GetGlobalRotation()
Definition: qmesh.h:167
int GetUVMapCount()
Definition: qmesh.h:487
float GetMinAngleConstraintOfPolygon()
Definition: qmesh.h:400
float GetArea()
Definition: qmesh.h:194
int GetParticleIndex(QParticle *particle)
Definition: qmesh.h:334
int GetAngleConstraintIndex(QAngleConstraint *angleConstraint)
Definition: qmesh.h:562
vector< int > GetUVMapAt(int index)
Definition: qmesh.h:494
QBody * GetOwnerBody()
Definition: qmesh.h:236
float GetInitialPolygonsArea()
Definition: qmesh.h:185
QMesh * SetRotation(float value)
Definition: qmesh.h:281
int GetSpringCount()
Definition: qmesh.h:461
int GetSubConvexPolygonCount()
Definition: qmesh.h:418
QMesh * RemoveAngleConstraint(QAngleConstraint *angleConstraint)
Definition: qmesh.h:573
float GetCircumference()
Definition: qmesh.h:217
QMesh * RemoveMatchingAngleConstraints(QParticle *particle)
Definition: qmesh.h:586
float GetInitialArea()
Definition: qmesh.h:171
QMesh * SetPosition(QVector value)
Definition: qmesh.h:265
float GetPolygonsArea()
Definition: qmesh.h:207
QMesh * SetMinAngleConstraintOfPolygon(float radian)
Definition: qmesh.h:409
CollisionBehaviors GetCollisionBehavior()
Definition: qmesh.h:242
Definition: qvector.h:44