MercuryDPM  Beta
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
IntersectionOfWalls.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 "IntersectionOfWalls.h"
27 #include "InteractionHandler.h"
28 #include "Particles/BaseParticle.h"
29 
31 {
32  logger(DEBUG, "IntersectionOfWalls() constructed.");
33 }
34 
39  : BaseWall(other)
40 {
41  wallObjects_ = other.wallObjects_;
42  A_ = other.A_;
43  AB_ = other.AB_;
44  C_ = other.C_;
45  logger(DEBUG, "IntersectionOfWalls(IntersectionOfWalls&) constructed.");
46 }
47 
49 {
50  logger(DEBUG, "~IntersectionOfWalls() has been called.");
51 }
52 
57 {
58  logger(DEBUG, "IntersectionOfWalls::operator= called.");
59  if (this == &other)
60  {
61  return *this;
62  }
63  return *(other.copy());
64 }
65 
70 {
71  return new IntersectionOfWalls(*this);
72 }
73 
75 {
76  wallObjects_.clear();
77  A_.clear();
78  AB_.clear();
79  C_.clear();
80 }
81 
91 {
92  normal.normalize();
93 
94  //n is the index of the new wall
95  std::size_t n = wallObjects_.size();
96  wallObjects_.resize(n + 1);
97  wallObjects_[n].set(normal, point);
98 
99  // AB[n*(n-1)/2+m] is the direction of the intersecting line between walls m and n, m<n
100  // A[n*(n-1)/2+m] is a point on the intersecting line between walls m and n, m<n
101  // See http://www.netcomuk.co.uk/~jenolive/vect18d.html for finding the line where two planes meet
102  AB_.resize(n * (n + 1) / 2); //0 + 1 + 2 + ... + indexNew, total number of walls you need
103  A_.resize(n * (n + 1) / 2);
104  for (std::size_t m = 0; m < n; m++)
105  {
106  std::size_t id = (n - 1) * n / 2 + m;
107  //first we cross the wall normals and normalize to obtain AB
108  AB_[id] = Vec3D::cross(wallObjects_[m].getNormal(), wallObjects_[n].getNormal());
109  AB_[id] /= sqrt(AB_[id].getLengthSquared());
110  //then we find a point A (using AB*x=0 as a third plane)
111  Mdouble invdet = 1.0 / (+wallObjects_[n].getNormal().X * (wallObjects_[m].getNormal().Y * AB_[id].Z - AB_[id].Y * wallObjects_[m].getNormal().Z)
112  - wallObjects_[n].getNormal().Y * (wallObjects_[m].getNormal().X * AB_[id].Z - wallObjects_[m].getNormal().Z * AB_[id].X)
113  + wallObjects_[n].getNormal().Z * (wallObjects_[m].getNormal().X * AB_[id].Y - wallObjects_[m].getNormal().Y * AB_[id].X));
114 
115  A_[id] = Vec3D( +(wallObjects_[m].getNormal().Y * AB_[id].Z - AB_[id].Y * wallObjects_[m].getNormal().Z) * Vec3D::dot(wallObjects_[n].getPosition(),wallObjects_[n].getNormal())
116  -(wallObjects_[n].getNormal().Y * AB_[id].Z - wallObjects_[n].getNormal().Z * AB_[id].Y) * Vec3D::dot(wallObjects_[m].getPosition(),wallObjects_[m].getNormal())
117  +(wallObjects_[n].getNormal().Y * wallObjects_[m].getNormal().Z - wallObjects_[n].getNormal().Z * wallObjects_[m].getNormal().Y) * 0.0,
118  -(wallObjects_[m].getNormal().X * AB_[id].Z - wallObjects_[m].getNormal().Z * AB_[id].X) * Vec3D::dot(wallObjects_[n].getPosition(),wallObjects_[n].getNormal())
119  +(wallObjects_[n].getNormal().X * AB_[id].Z - wallObjects_[n].getNormal().Z * AB_[id].X) * Vec3D::dot(wallObjects_[m].getPosition(),wallObjects_[m].getNormal())
120  -(wallObjects_[n].getNormal().X * wallObjects_[m].getNormal().Z - wallObjects_[m].getNormal().X * wallObjects_[n].getNormal().Z) * 0.0,
121  +(wallObjects_[m].getNormal().X * AB_[id].Y - AB_[id].X * wallObjects_[m].getNormal().Y) * Vec3D::dot(wallObjects_[n].getPosition(),wallObjects_[n].getNormal())
122  -(wallObjects_[n].getNormal().X * AB_[id].Y - AB_[id].X * wallObjects_[n].getNormal().Y) * Vec3D::dot(wallObjects_[m].getPosition(),wallObjects_[m].getNormal())
123  +(wallObjects_[n].getNormal().X * wallObjects_[m].getNormal().Y - wallObjects_[m].getNormal().X * wallObjects_[n].getNormal().Y) * 0.0) * invdet;
124  }
125 
126  // C[(n-2)*(n-1)*n/6+(m-1)*m/2+l] is a point intersecting walls l, m and n, l<m<n
127  C_.resize((n - 1) * n * (n + 1) / 6);
128  for (std::size_t m = 0; m < n; m++)
129  {
130  for (std::size_t l = 0; l < m; l++)
131  {
132  std::size_t id = (n - 2) * (n - 1) * n / 6 + (m - 1) * m / 2 + l;
133  Mdouble invdet = 1.0 / (+wallObjects_[n].getNormal().X * (wallObjects_[m].getNormal().Y * wallObjects_[l].getNormal().Z - wallObjects_[l].getNormal().Y * wallObjects_[m].getNormal().Z)
134  - wallObjects_[n].getNormal().Y * (wallObjects_[m].getNormal().X * wallObjects_[l].getNormal().Z - wallObjects_[m].getNormal().Z * wallObjects_[l].getNormal().X)
135  + wallObjects_[n].getNormal().Z * (wallObjects_[m].getNormal().X * wallObjects_[l].getNormal().Y - wallObjects_[m].getNormal().Y * wallObjects_[l].getNormal().X));
136  C_[id] = Vec3D(+(wallObjects_[m].getNormal().Y * wallObjects_[l].getNormal().Z - wallObjects_[l].getNormal().Y * wallObjects_[m].getNormal().Z) * Vec3D::dot(wallObjects_[n].getPosition(),wallObjects_[n].getNormal())
137  - (wallObjects_[n].getNormal().Y * wallObjects_[l].getNormal().Z - wallObjects_[n].getNormal().Z * wallObjects_[l].getNormal().Y) * Vec3D::dot(wallObjects_[m].getPosition(),wallObjects_[m].getNormal())
138  + (wallObjects_[n].getNormal().Y * wallObjects_[m].getNormal().Z - wallObjects_[n].getNormal().Z * wallObjects_[m].getNormal().Y) * Vec3D::dot(wallObjects_[l].getPosition(),wallObjects_[l].getNormal()),
139  -(wallObjects_[m].getNormal().X * wallObjects_[l].getNormal().Z - wallObjects_[m].getNormal().Z * wallObjects_[l].getNormal().X) * Vec3D::dot(wallObjects_[n].getPosition(),wallObjects_[n].getNormal())
140  + (wallObjects_[n].getNormal().X * wallObjects_[l].getNormal().Z - wallObjects_[n].getNormal().Z * wallObjects_[l].getNormal().X) * Vec3D::dot(wallObjects_[m].getPosition(),wallObjects_[m].getNormal())
141  - (wallObjects_[n].getNormal().X * wallObjects_[m].getNormal().Z - wallObjects_[m].getNormal().X * wallObjects_[n].getNormal().Z) * Vec3D::dot(wallObjects_[l].getPosition(),wallObjects_[l].getNormal()),
142  +(wallObjects_[m].getNormal().X * wallObjects_[l].getNormal().Y - wallObjects_[l].getNormal().X * wallObjects_[m].getNormal().Y) * Vec3D::dot(wallObjects_[n].getPosition(),wallObjects_[n].getNormal())
143  - (wallObjects_[n].getNormal().X * wallObjects_[l].getNormal().Y - wallObjects_[l].getNormal().X * wallObjects_[n].getNormal().Y) * Vec3D::dot(wallObjects_[m].getPosition(),wallObjects_[m].getNormal())
144  + (wallObjects_[n].getNormal().X * wallObjects_[m].getNormal().Y - wallObjects_[m].getNormal().X * wallObjects_[n].getNormal().Y) * Vec3D::dot(wallObjects_[l].getPosition(),wallObjects_[l].getNormal())) * invdet;
145  }
146  }
147 
148  logger(VERBOSE, "%", *this);
149  for (InfiniteWall w : wallObjects_)
150  logger(VERBOSE, "wallObject %, %", w.getNormal(), w.getPosition());
151  for (Vec3D v : A_)
152  logger(VERBOSE, "A %", v);
153  for (Vec3D v : AB_)
154  logger(VERBOSE, "AB %", v);
155  for (Vec3D v : C_)
156  logger(VERBOSE, "C %", v);
157 }
158 
164 {
165  logger(WARN, "This function is deprecated, use IntersectionOfWalls::addObject(Vec3D, Vec3D) instead.");
166  addObject(normal, position*normal);
167 }
168 
177 void IntersectionOfWalls::createOpenPrism(std::vector<Vec3D> points, Vec3D prismAxis)
178 {
179  clear();
180  //note: use i+1 < points.size() instead of i < points.size()-1, otherwise it creates havoc if point has zero entries.
181  for (unsigned int i = 0; i+1 < points.size(); i++)
182  addObject(Vec3D::cross(points[i] - points[i + 1], prismAxis), points[i]);
183 }
184 
192 void IntersectionOfWalls::createPrism(std::vector<Vec3D> points, Vec3D prismAxis)
193 {
194  createOpenPrism(points, prismAxis);
195  addObject(Vec3D::cross(points.back() - points.front(), prismAxis), points.front());
196 }
197 
205 void IntersectionOfWalls::createOpenPrism(std::vector<Vec3D> points)
206 {
207  Vec3D prismAxis = Vec3D::cross(
208  Vec3D::getUnitVector(points[2] - points[0]),
209  Vec3D::getUnitVector(points[1] - points[0]));
210  createOpenPrism(points, prismAxis);
211 }
212 
220 void IntersectionOfWalls::createPrism(std::vector<Vec3D> points)
221 {
222  Vec3D prismAxis = Vec3D::cross(
223  Vec3D::getUnitVector(points[2] - points[0]),
224  Vec3D::getUnitVector(points[1] - points[0]));
225  createPrism(points, prismAxis);
226 }
227 
242 bool IntersectionOfWalls::getDistanceAndNormal(const BaseParticle& p, Mdouble& distance, Vec3D& normal_return) const
243 {
244  return getDistanceAndNormal(p.getPosition(), p.getInteractionRadius(), distance, normal_return);
245 }
246 
269 bool IntersectionOfWalls::getDistanceAndNormal(const Vec3D& position, Mdouble wallInteractionRadius, Mdouble &distance, Vec3D &normal_return) const
270 {
271  distance = -1e20;
272  Mdouble distance2 = -1e20;
273  Mdouble distance3 = -1e20;
274  Mdouble distanceCurrent;
275  unsigned int id=0;
276  unsigned int id2=0;
277  unsigned int id3=0;
278 
279  //The object has to touch each wall each wall (distanceCurrent) and keep the minimum distance (distance) and wall index (id)
280  for (unsigned int i = 0; i < wallObjects_.size(); i++)
281  {
282  // Calculate distance to each wall (distanceCurrent);
283  distanceCurrent = wallObjects_[i].getDistance(position);
284  // The object has to touch each wall (distanceCurrent >= wallInteractionRadius), otherwise return false (i.e. no contact)
285  // This means that for each InfiniteWall in wallObjects_, the particle is either "inside"
286  // the wall or touching it. If not, there is no interaction.
287  if (distanceCurrent >= wallInteractionRadius)
288  return false;
289  // Find out which of the InfiniteWalls is interacting with the particle.
290  // Keep the minimum distance (distance) and wall index (id)
291  // and store up to two walls (id2, id3) and their distances (distance2, distance3),
292  // if the possible contact point is near the intersection between id and id2 (and id3)
293  if (distanceCurrent > distance)
294  {
295  if (distance > -wallInteractionRadius)
296  {
297  if (distance2 > -wallInteractionRadius)
298  {
299  distance3 = distance;
300  id3 = id;
301  }
302  else
303  {
304  distance2 = distance;
305  id2 = id;
306  }
307  }
308  distance = distanceCurrent;
309  id = i;
310  }
311  else if (distanceCurrent > -wallInteractionRadius)
312  {
313  if (distance2 > -wallInteractionRadius)
314  {
315  distance3 = distanceCurrent;
316  id3 = i;
317  }
318  else
319  {
320  distance2 = distanceCurrent;
321  id2 = i;
322  }
323  }
324  }
325 
326  //If we are here, the closest wall is id;
327  //if distance2>-P.Radius (and distance3>-P.Radius), the possible contact point
328  // is near the intersection between id and id2 (and id3)
329  if (distance2 > -wallInteractionRadius)
330  {
331  //D is the point on wall id closest to P
332  Vec3D D = position + wallObjects_[id].getNormal() * distance;
333  //If the distance of D to id2 is positive, the contact is with the intersection
334  bool intersection_with_id2 = (wallObjects_[id2].getDistance(D) > 0.0);
335 
336  if (distance3 > -wallInteractionRadius && (wallObjects_[id3].getDistance(D) > 0.0))
337  {
338  if (intersection_with_id2)
339  {
340  //possible contact is with intersection of id,id2,id3
341  //we know id2<id3
342  unsigned int index =
343  (id < id2) ? ((id3 - 2) * (id3 - 1) * id3 / 6 + (id2 - 1) * id2 / 2 + id) :
344  (id < id3) ? ((id3 - 2) * (id3 - 1) * id3 / 6 + (id - 1) * id / 2 + id2) :
345  ((id - 2) * (id - 1) * id / 6 + (id3 - 1) * id3 / 2 + id2);
346  normal_return = position - C_[index];
347  distance = sqrt(normal_return.getLengthSquared());
348  if (distance >= wallInteractionRadius)
349  return false; //no contact
350  normal_return /= -distance;
351  return true; //contact with id,id2,id3
352  }
353  else
354  {
355  intersection_with_id2 = true;
356  distance2 = distance3;
357  id2 = id3;
358  }
359  }
360 
361  if (intersection_with_id2)
362  { //possible contact is with intersection of id,id2
363  unsigned int index = (id > id2) ? ((id - 1) * id / 2 + id2) : ((id2 - 1) * id2 / 2 + id);
364  Vec3D AC = position - A_[index];
365  normal_return = AC - AB_[index] * Vec3D::dot(AC, AB_[index]);
366  distance = sqrt(normal_return.getLengthSquared());
367  if (distance >= wallInteractionRadius)
368  return false; //no contact
369  normal_return /= -distance;
370  return true; //contact with two walls
371  }
372  }
373  //contact is with id
374  normal_return = wallObjects_[id].getNormal();
375  return true;
376 }
377 
390 {
392  for(Vec3D& a : A_)
393  {
394  a += move;
395  }
396  for(Vec3D& c : C_)
397  {
398  c += move;
399  }
400  for(InfiniteWall& o : wallObjects_)
401  {
402  o.move(move);
403  }
404 }
405 
409 void IntersectionOfWalls::read(std::istream& is)
410 {
411  BaseWall::read(is);
412  std::string dummy;
413  int n;
414  is >> dummy >> n;
415 
416  Vec3D normal;
417  Vec3D position;
418  for (int i = 0; i < n; i++)
419  {
420  is >> dummy >> normal >> dummy >> position;
421  addObject(normal, position);
422  }
423 }
424 
429 void IntersectionOfWalls::write(std::ostream& os) const
430 {
431  BaseWall::write(os);
432  os << " numIntersectionOfWalls " << wallObjects_.size();
433  for (std::vector<InfiniteWall>::const_iterator it = wallObjects_.begin(); it != wallObjects_.end(); ++it)
434  {
435  os << " normal " << it->getNormal() << " position " << it->getPosition();
436  }
437 }
438 
442 std::string IntersectionOfWalls::getName() const
443 {
444  return "IntersectionOfWalls";
445 }
446 
455 {
456  Mdouble distance;
457  Vec3D normal;
458 
459  if (getDistanceAndNormal(*p, distance, normal))
460  {
461  BaseInteraction* c = interactionHandler->getInteraction(p, this, timeStamp);
462  c->setNormal(-normal);
463  c->setDistance(distance);
464  c->setOverlap(p->getRadius() - distance);
466  c->setContactPoint(p->getPosition() - (p->getRadius() - 0.5 * c->getOverlap()) * c->getNormal());
467  return c;
468  }
469  else
470  {
471  return nullptr;
472  }
473 }
static Mdouble getLengthSquared(const Vec3D &a)
Calculates the squared length of a Vec3D: .
Definition: Vector.cc:304
void setNormal(Vec3D normal)
Sets the normal vector between the two interacting objects.
static Vec3D getUnitVector(const Vec3D &a)
Returns a unit Vec3D based on a.
Definition: Vector.cc:441
A IntersectionOfWalls is convex polygon defined as an intersection of InfiniteWall's.
Logger< MERCURY_LOGLEVEL > logger("MercuryKernel")
void setOverlap(Mdouble overlap)
Set the overlap between the two interacting object.
void normalize()
Makes this Vec3D unit length.
Definition: Vector.cc:234
BaseInteraction * getInteraction(BaseInteractable *P, BaseInteractable *I, Mdouble timeStamp)
Returns the Interaction between the BaseInteractable's P and I.
double Mdouble
BaseInteraction * getInteractionWith(BaseParticle *p, Mdouble timeStamp, InteractionHandler *interactionHandler)
Get the interaction between this IntersectionOfWalls and given BaseParticle at a given time...
void setContactPoint(Vec3D contactPoint)
Set the location of the contact point between the two interacting objects.
void move(const Vec3D &move)
Move the IntersectionOfWalls to a new position, which is a Vec3D from the old position.
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...
std::string getName() const override
Returns the name of the object, here the string "IntersectionOfWalls".
static Mdouble dot(const Vec3D &a, const Vec3D &b)
Calculates the dot product of two Vec3D: .
Definition: Vector.cc:187
void setDistance(Mdouble distance)
Sets the interaction distance between the two interacting objects.
void addObject(Vec3D normal, Vec3D point)
Adds a wall to the set of infinite walls, given an outward normal vector s.t. normal*x=normal*point.
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< InfiniteWall > wallObjects_
The wall "segments"/directions that together make up the finite wall.
void createOpenPrism(std::vector< Vec3D > points, Vec3D prismAxis)
Creates an open prism which is a polygon between the points, except the first and last point...
void read(std::istream &is)
Reads an IntersectionOfWalls from an input stream, for example a restart file.
IntersectionOfWalls()
Default constructor.
std::vector< Vec3D > C_
A vector that stores the intersection point of three different InfiniteWall.
Container to store Interaction objects.
const Vec3D & getNormal() const
Gets the normal vector between the two interacting objects.
std::vector< Vec3D > A_
A vector that stores a point for each intersecting line between two different InfiniteWall.
static Vec3D cross(const Vec3D &a, const Vec3D &b)
Calculates the cross product of two Vec3D: .
Definition: Vector.cc:268
Mdouble getRadius() const
Returns the particle's radius_.
Basic class for walls.
Definition: BaseWall.h:39
Mdouble getOverlap() const
Returns a Mdouble with the current overlap between the two interacting objects.
IntersectionOfWalls * copy() const override
Wall copy method. It calls the copy constructor of this Wall, useful for polymorphism.
MERCURY_DEPRECATED void clear()
Removes all parts of the walls.
std::vector< Vec3D > AB_
A vector that stores the direction of the intersecting lines between two different InfiniteWall...
void createPrism(std::vector< Vec3D > points, Vec3D prismAxis)
Creates an open prism which is a polygon between the points and extends infinitely in the PrismAxis d...
This is a class defining walls.
Definition: InfiniteWall.h:43
void write(std::ostream &os) const
Writes an IntersectionOfWalls to an output stream, for example a restart file.
virtual ~IntersectionOfWalls()
Destructor.
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.
IntersectionOfWalls & operator=(const IntersectionOfWalls &other)
void write(std::ostream &os) const
Function that writes a BaseWall to an output stream, usually a restart file.
Definition: BaseWall.cc:68
Mdouble getInteractionRadius() const
Returns the particle's interaction radius, which might be different from radius_ (e.g., when dealing with wet particles)
void read(std::istream &is)
Function that reads a BaseWall from an input stream, usually a restart file.
Definition: BaseWall.cc:60