MercuryDPM  Alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
TriangulatedWall.cc
Go to the documentation of this file.
1 //Copyright (c) 2013-2014, The MercuryDPM Developers Team. All rights reserved.
2 //For the list of developers, see <http://www.MercuryDPM.org/Team>.
3 //
4 //Redistribution and use in source and binary forms, with or without
5 //modification, are permitted provided that the following conditions are met:
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above copyright
9 // notice, this list of conditions and the following disclaimer in the
10 // documentation and/or other materials provided with the distribution.
11 // * Neither the name MercuryDPM nor the
12 // names of its contributors may be used to endorse or promote products
13 // derived from this software without specific prior written permission.
14 //
15 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 //ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 //WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 //DISCLAIMED. IN NO EVENT SHALL THE MERCURYDPM DEVELOPERS TEAM BE LIABLE FOR ANY
19 //DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 //(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 //ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 //(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 #include "TriangulatedWall.h"
27 #include "InteractionHandler.h"
28 #include "Particles/BaseParticle.h"
29 #include <fstream>
30 #include <stdio.h>
31 #include <stdlib.h>
32 
34 {
35  logger(DEBUG, "TriangulatedWall() constructed.");
36 }
37 
42  : BaseWall(other)
43 {
44  face_ = other.face_;
45  vertex_ = other.vertex_;
46  //now reset the pointers
47  for (unsigned f = 0; f<face_.size(); f++)
48  {
49  for (unsigned i = 0; i<3; i++)
50  {
51  if (other.face_[f].neighbor[i]) {
52  face_[f].neighbor[i] = &face_[other.face_[f].neighbor[i] - &other.face_[0]];
53  } //else nullptr
54  face_[f].vertex[i] = &vertex_[other.face_[f].vertex[i] - &other.vertex_[0]];
55  }
56  }
57  logger(DEBUG, "TriangulatedWall(TriangulatedWall&) constructed.");
58 }
59 
60 TriangulatedWall::TriangulatedWall(std::string filename, const ParticleSpecies *species)
61 {
62  setSpecies(species);
63  readVTK(filename);
64 }
65 
69 void TriangulatedWall::readVTK(std::string filename)
70 {
71  std::fstream file;
72  file.open(filename.c_str(), std::ios::in);
73  logger.assert_always(file.is_open(), "File opening failed: %",filename);
74 
75  std::string dummy;
76  getline(file, dummy);
77  getline(file, dummy);
78  getline(file, dummy);
79  getline(file, dummy);
80  //read points
81  unsigned num;
82  file >> dummy >> num >> dummy;
83  vertex_.reserve(num);
84  Vec3D v;
85  for (unsigned i = 0; i < num; i++)
86  {
87  file >> v.X >> v.Y >> v.Z;
88  vertex_.push_back(v);
89  }
90  //read faces
91  file >> dummy >> num >> dummy;
92  face_.reserve(num);
93  Face f;
94  unsigned id0, id1, id2;
95  for (unsigned i = 0; i < num; i++)
96  {
97  file >> dummy >> id0 >> id1 >> id2;
98  f.vertex[0] = &vertex_[id0];
99  f.vertex[1] = &vertex_[id1];
100  f.vertex[2] = &vertex_[id2];
101  face_.push_back(f);
102  }
103  file >> dummy;
104  //set normals and positions
105  for (auto& face: face_)
106  {
107  face.normal = Vec3D::getUnitVector(Vec3D::cross(*face.vertex[1]-*face.vertex[0],*face.vertex[2]-*face.vertex[0]));
108  }
109  //set neighbours
110  for (auto face0=face_.begin(); face0+1!=face_.end(); face0++)
111  {
112  for (auto face1=face0+1; face1!=face_.end(); face1++)
113  {
114  if (face0->vertex[0]==face1->vertex[0]) {
115  if (face0->vertex[1]==face1->vertex[2]) { //edge 0=2
116  face0->neighbor[0]=&*face1;
117  face1->neighbor[2]=&*face0;
118  } else if (face0->vertex[2]==face1->vertex[1]) { //edge 2=0
119  face0->neighbor[2]=&*face1;
120  face1->neighbor[0]=&*face0;
121  }
122  } else if (face0->vertex[0]==face1->vertex[1]) {
123  if (face0->vertex[1]==face1->vertex[0]) { //edge 0=0
124  face0->neighbor[0]=&*face1;
125  face1->neighbor[0]=&*face0;
126  } else if (face0->vertex[2]==face1->vertex[2]) { //edge 2=1
127  face0->neighbor[2]=&*face1;
128  face1->neighbor[1]=&*face0;
129  }
130  } else if (face0->vertex[0]==face1->vertex[2]) {
131  if (face0->vertex[1]==face1->vertex[1]) { //edge 0=1
132  face0->neighbor[0]=&*face1;
133  face1->neighbor[1]=&*face0;
134  } else if (face0->vertex[2]==face1->vertex[0]) { //edge 2=2
135  face0->neighbor[2]=&*face1;
136  face1->neighbor[2]=&*face0;
137  }
138  } else if (face0->vertex[1]==face1->vertex[0]) {
139  if (face0->vertex[2]==face1->vertex[2]) { //edge 1=2
140  face0->neighbor[1]=&*face1;
141  face1->neighbor[2]=&*face0;
142  }
143  } else if (face0->vertex[1]==face1->vertex[1]) {
144  if (face0->vertex[2]==face1->vertex[0]) { //edge 1=0
145  face0->neighbor[1]=&*face1;
146  face1->neighbor[0]=&*face0;
147  }
148  } else if (face0->vertex[1]==face1->vertex[2]) {
149  if (face0->vertex[2]==face1->vertex[1]) { //edge 1=1
150  face0->neighbor[1]=&*face1;
151  face1->neighbor[1]=&*face0;
152  }
153  }
154 
155  }
156  }
157  //set edge normals (inwards facing)
158  for (auto& face: face_)
159  {
160  face.edgeNormal[0] = Vec3D::getUnitVector(Vec3D::cross(face.normal,*face.vertex[1]-*face.vertex[0]));
161  face.edgeNormal[1] = Vec3D::getUnitVector(Vec3D::cross(face.normal,*face.vertex[2]-*face.vertex[1]));
162  face.edgeNormal[2] = Vec3D::getUnitVector(Vec3D::cross(face.normal,*face.vertex[0]-*face.vertex[2]));
163  }
164  file.close();
165 }
166 
168 {
169  logger(DEBUG, "~TriangulatedWall() has been called.");
170 }
171 
176 {
177  logger(DEBUG, "TriangulatedWall::operator= called.");
178  if (this == &other)
179  {
180  return *this;
181  }
182  return *(other.copy());
183 }
184 
189 {
190  return new TriangulatedWall(*this);
191 }
192 
209 bool TriangulatedWall::getDistanceAndNormal(const BaseParticle &p, Mdouble &distance, Vec3D &normal_return) const
210 {
211  //it's important to use a reference here, as the faces use pointers
212  for (const auto& face : face_)
213  {
214  if (face.getDistanceAndNormal(p, distance, normal_return))
215  return true;
216  }
217  return false;
218 }
219 
231 void TriangulatedWall::move(const Vec3D &move)
232 {
234  for (auto& v : vertex_)
235  {
236  v += move;
237  }
238 }
239 
243 void TriangulatedWall::read(std::istream &is)
244 {
246 }
247 
252 void TriangulatedWall::write(std::ostream &os) const
253 {
254  os << "Vertices " << vertex_.size();
255  for (const auto& vertex: vertex_)
256  os << " " << vertex;
257  os << std::endl;
258  //os << "Faces " << face_.size() << std::endl;
259  unsigned counter = 0;
260  for (const auto& face: face_)
261  {
262  os << "Face " << counter++
263  << " vertex " << face.vertex[0] - &vertex_[0]
264  << " " << face.vertex[1] - &vertex_[0]
265  << " " << face.vertex[2] - &vertex_[0]
266  << " neighbor " << (face.neighbor[0]?(face.neighbor[0] - &face_[0]):-1)
267  << " " << (face.neighbor[1]?(face.neighbor[1] - &face_[0]):-1)
268  << " " << (face.neighbor[2]?(face.neighbor[2] - &face_[0]):-1)
269  << " normal " << face.normal
270  << " edgeNormal " << face.edgeNormal[0]
271  << " " << face.edgeNormal[1]
272  << " " << face.edgeNormal[2]
273  << std::endl;
274  }
275 }
276 
280 std::string TriangulatedWall::getName() const
281 {
282  return "TriangulatedWall";
283 }
284 
292 std::vector<BaseInteraction*> TriangulatedWall::getInteractionWith(BaseParticle *p, Mdouble timeStamp,
293  InteractionHandler *interactionHandler)
294 {
295  Mdouble distance;
296  Vec3D normal;
297  Face* neighbor;
298  //write(std::cout);
299  std::vector<BaseInteraction*> interactions;
300  for (const auto& face : face_)
301  {
302  if (face.getDistanceAndNormal(*p, distance, normal))
303  {
304  normal = -normal;
305  //logger(INFO,"t=% n=% f=%(%) c=%", timeStamp,normal,&face,&face-&face_[0],p->getPosition() - distance * normal);
306  BaseInteraction* const c = interactionHandler->getInteraction(p, this, timeStamp, normal);
307  //logger.assert(c,"BaseInteraction not set");
308  c->setNormal(normal);
309  c->setDistance(distance);
310  c->setOverlap(p->getRadius() - distance);
311  c->setContactPoint(p->getPosition() - distance * normal);
312  interactions.push_back(c);
313  }
314  }
315  return interactions;
316 }
317 
319 {
320  return Vec3D::dot(*vertex[0] - otherPosition, normal);
321 }
322 
327 bool TriangulatedWall::Face::getDistanceAndNormal(const BaseParticle &p, Mdouble &distance, Vec3D &normal_return) const
328 {
329  //check if particle overlaps
330  distance = getDistance(p.getPosition());
331  //return if distance is large, or particle has too much overlap
332  Mdouble interactionRadius = p.getWallInteractionRadius();
333  if (fabs(distance) >= interactionRadius)
334  return false;
335 
336  //Contact radius squared
337  Mdouble allowedDistanceSquared = interactionRadius*interactionRadius-distance*distance;
338  int touchingEdge = -1;
339  Vec3D* touchingVertex = nullptr;
340  //loop through edges to find out if there is a contact with face, edge, vertex, or neither.
341  for (unsigned i=0; i<3; i++)
342  {
343  //distance from the edge
344  Mdouble edgeDistance = Vec3D::dot(edgeNormal[i], *vertex[i] - p.getPosition());
345  if (edgeDistance<=0) //if in contact with the face
346  continue;
347  if (edgeDistance * edgeDistance >= allowedDistanceSquared) //if not in contact with anything
348  return false;
349  //this point is only reached if in contact, but not with the face
350  //if edge is convex, treat as face, not edge contact
351  bool convex = (neighbor[i] && ((neighbor[i]->getDistance(p.getPosition())<0)?(Vec3D::dot(neighbor[i]->normal,edgeNormal[i])>1e-12):(Vec3D::dot(neighbor[i]->normal,edgeNormal[i])<-1e-12)));
352  if (touchingEdge==-1) {
353  //edge or vertex contact (depending if more edges are found)
354  touchingEdge = i;
355  } else {
356  //vertex contact
357  touchingVertex = vertex[(i==2 && touchingEdge==0)?0:i];
358  }
359  //if (!convex) continue;
360  //do not compute if neighbor exists and has lower index or face contact.
361  if (neighbor[i] > this){ //if neighbor has higher index
362  if (neighbor[i]->neighbor[0]==this) {
363  edgeDistance = Vec3D::dot(neighbor[i]->edgeNormal[0], *vertex[i] - p.getPosition());
364  } else if (neighbor[i]->neighbor[1]==this) {
365  edgeDistance = Vec3D::dot(neighbor[i]->edgeNormal[1], *vertex[i] - p.getPosition());
366  } else { //if (neighbor[i]->neighbor[2]==this)
367  edgeDistance = Vec3D::dot(neighbor[i]->edgeNormal[2], *vertex[i] - p.getPosition());
368  }
369  if (edgeDistance<=0 && !convex) //if neighbor has face contact, ignore the edge contact
370  return false;
371  } else if (neighbor[i] && !convex) {
372  return false;
373  }
374  }
375 
376 
377  //check if convex neighbours are overlapping as well
378  if (touchingVertex) { //vertex contact
379  normal_return = *touchingVertex -p.getPosition();
380  distance = Vec3D::getLength(normal_return);
381  normal_return /= distance;
382  //return false;
383  //logger(INFO,"vertex contact");
384  } else if (touchingEdge==-1) { //face contact
385  if (distance>=0) { // front face contact
386  normal_return = normal;
387  } else { // back face contact
388  normal_return = -normal;
389  distance = -distance;
390  }
391  //return false;
392  //logger(INFO,"face contact");
393  } else { //edge contact
394  Vec3D VP = *vertex[touchingEdge] - p.getPosition();
395  Vec3D VW = *vertex[touchingEdge] - *vertex[(touchingEdge==2)?0:(touchingEdge+1)];
396  normal_return = VP - Vec3D::dot(VP, VW)/Vec3D::getLengthSquared(VW)*VW;
397  distance = Vec3D::getLength(normal_return);
398  normal_return /= distance;
399  //return false;
400  //logger(INFO,"edge contact at c=% p=% d=% n=%",p.getPosition() + distance * normal_return,p.getPosition(), distance, normal_return);
401  }
402  return true;
403 }
404 
406 {
407  const int s = vtk.points.size();
408  vtk.points.reserve(s+vertex_.size());
409  for (auto v : vertex_) {
410  vtk.points.push_back(v);
411  }
412  for (auto f : face_) {
413  std::vector<double> cell;
414  cell.reserve(3);
415  cell.push_back(s+f.vertex[0]- &vertex_[0]);
416  cell.push_back(s+f.vertex[1]- &vertex_[0]);
417  cell.push_back(s+f.vertex[2]- &vertex_[0]);
418  vtk.triangleStrips.push_back(cell);
419  }
420 }
void setNormal(Vec3D normal)
Sets the normal vector between the two interacting objects.
Mdouble X
the vector components
Definition: Vector.h:52
TriangulatedWall()
Default constructor.
static Vec3D getUnitVector(const Vec3D &a)
Returns a unit Vec3D based on a.
Definition: Vector.cc:428
Logger< MERCURY_LOGLEVEL > logger("MercuryKernel")
void setOverlap(Mdouble overlap)
Set the overlap between the two interacting object.
bool getDistanceAndNormal(const BaseParticle &p, Mdouble &distance, Vec3D &normal_return) const
Returns true if contact with the face exists, false if not. If contact exists, then the distance and ...
A TriangulatedWall is a triangulation created from a set of vertices and a n-by-3 connectivity matrix...
BaseInteraction * getInteraction(BaseInteractable *P, BaseInteractable *I, Mdouble timeStamp)
Returns the Interaction between the BaseInteractable's P and I.
bool getDistanceAndNormal(const BaseParticle &p, Mdouble &distance, Vec3D &normal_return) const override
Compute the distance from the wall for a given BaseParticle and return if there is a collision...
double Mdouble
void setContactPoint(Vec3D contactPoint)
Set the location of the contact point between the two interacting objects.
void write(std::ostream &os) const override
Writes an TriangulatedWall to an output stream, for example a restart file.
static Mdouble dot(const Vec3D &a, const Vec3D &b)
Calculates the dot product of two Vec3D: .
Definition: Vector.cc:167
void setDistance(Mdouble distance)
Sets the interaction distance between the two interacting objects.
Mdouble getLengthSquared() const
Calculates the squared length of this Vec3D: .
Definition: Vector.cc:300
const Vec3D & getPosition() const
Returns the position of this BaseInteractable.
Stores information about interactions between two interactable objects; often particles but could be ...
std::vector< Vec3D > vertex_
Mdouble getWallInteractionRadius() const
Returns the interaction radius for interaction with walls. See also BaseParticle::getInteractionRadiu...
Struct used to store the properties of a face needed for contact detection.
void read(std::istream &is) override
Reads an TriangulatedWall from an input stream, for example a restart file.
TriangulatedWall & operator=(const TriangulatedWall &other)
void readVTK(std::string filename)
std::vector< BaseInteraction * > getInteractionWith(BaseParticle *p, Mdouble timeStamp, InteractionHandler *interactionHandler) override
Get the interaction between this TriangulatedWall and given BaseParticle at a given time...
std::array< Vec3D *, 3 > vertex
defines the three vertices (anticlockwise direction around the normal)
std::vector< std::vector< double > > triangleStrips
Definition: BaseWall.h:36
Container to store Interaction objects.
std::string getName() const override
Returns the name of the object, here the string "TriangulatedWall".
Vec3D normal
face normal (vertices are ordered anticlockwise direction around the normal)
static Vec3D cross(const Vec3D &a, const Vec3D &b)
Calculates the cross product of two Vec3D: .
Definition: Vector.cc:255
Mdouble getRadius() const
Returns the particle's radius_.
void writeVTK(VTKContainer &vtk) const override
Basic class for walls.
Definition: BaseWall.h:44
Mdouble Y
Definition: Vector.h:52
void move(const Vec3D &move) override
Move the TriangulatedWall to a new position, which is a Vec3D from the old position.
std::vector< Vec3D > points
Definition: BaseWall.h:35
Mdouble getLength() const
Calculates the length of this Vec3D: .
Definition: Vector.cc:403
std::vector< Face > face_
virtual ~TriangulatedWall()
Destructor.
TriangulatedWall * copy() const override
Wall copy method. It calls the copy constructor of this Wall, useful for polymorphism.
Mdouble getDistance(const Vec3D &otherPosition) const
computes the signed distance to the face in normal direction
Implementation of a 3D vector (by Vitaliy).
Definition: Vector.h:45
virtual void move(const Vec3D &move)
Moves this BaseInteractable by adding an amount to the position.
Mdouble Z
Definition: Vector.h:52
void setSpecies(const ParticleSpecies *species)
Define the species of this wall.
Definition: BaseWall.cc:113