MercuryDPM  Alpha
 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  for (auto& wall : wallObjects_)
43  {
44  if (getHandler() != nullptr)
45  wall.setHandler(getHandler());
46  }
47  A_ = other.A_;
48  AB_ = other.AB_;
49  C_ = other.C_;
50  logger(DEBUG, "IntersectionOfWalls(IntersectionOfWalls&) constructed.");
51 }
52 
53 IntersectionOfWalls::IntersectionOfWalls(std::vector<IntersectionOfWalls::normalAndPosition> walls, const ParticleSpecies* species)
54 {
55  setSpecies(species);
56  for (auto wall : walls)
57  {
58  addObject(wall.normal,wall.position);
59  }
60 }
61 
62 
64 {
65  logger(DEBUG, "~IntersectionOfWalls() has been called.");
66 }
67 
69 {
70  BaseWall::setSpecies(species);
71  for (auto wall : wallObjects_)
72  {
73  wall.setSpecies(species);
74  }
75 }
76 
81 {
82  logger(DEBUG, "IntersectionOfWalls::operator= called.");
83  if (this == &other)
84  {
85  return *this;
86  }
87  return *(other.copy());
88 }
89 
94 {
95  return new IntersectionOfWalls(*this);
96 }
97 
99 {
100  wallObjects_.clear();
101  A_.clear();
102  AB_.clear();
103  C_.clear();
104 }
105 
107 {
108  BaseWall::setHandler(wallHandler);
109  for (InfiniteWall w : wallObjects_)
110  {
111  BaseWall::setHandler(wallHandler);
112  }
113 }
114 
124 {
125  normal.normalize();
126 
127  //n is the index of the new wall
128  std::size_t n = wallObjects_.size();
129  InfiniteWall w;
130  if (getSpecies()) w.setSpecies(getSpecies());
131  w.set(normal, point);
132  wallObjects_.push_back(w);
133 
134  // AB[n*(n-1)/2+m] is the direction of the intersecting line between walls m and n, m<n
135  // A[n*(n-1)/2+m] is a point on the intersecting line between walls m and n, m<n
136  // See http://www.netcomuk.co.uk/~jenolive/vect18d.html for finding the line where two planes meet
137  AB_.resize(n * (n + 1) / 2); //0 + 1 + 2 + ... + indexNew, total number of walls you need
138  A_.resize(n * (n + 1) / 2);
139  for (std::size_t m = 0; m < n; m++)
140  {
141  std::size_t id = (n - 1) * n / 2 + m;
142  //first we cross the wall normals and normalize to obtain AB
143  AB_[id] = Vec3D::cross(wallObjects_[m].getNormal(), wallObjects_[n].getNormal());
144  AB_[id] /= sqrt(AB_[id].getLengthSquared());
145  //then we find a point A (using AB*x=0 as a third plane)
146  Mdouble invdet = 1.0 / (+wallObjects_[n].getNormal().X * (wallObjects_[m].getNormal().Y * AB_[id].Z - AB_[id].Y * wallObjects_[m].getNormal().Z)
147  - wallObjects_[n].getNormal().Y * (wallObjects_[m].getNormal().X * AB_[id].Z - wallObjects_[m].getNormal().Z * AB_[id].X)
148  + wallObjects_[n].getNormal().Z * (wallObjects_[m].getNormal().X * AB_[id].Y - wallObjects_[m].getNormal().Y * AB_[id].X));
149 
150  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())
151  -(wallObjects_[n].getNormal().Y * AB_[id].Z - wallObjects_[n].getNormal().Z * AB_[id].Y) * Vec3D::dot(wallObjects_[m].getPosition(),wallObjects_[m].getNormal())
152  +(wallObjects_[n].getNormal().Y * wallObjects_[m].getNormal().Z - wallObjects_[n].getNormal().Z * wallObjects_[m].getNormal().Y) * 0.0,
153  -(wallObjects_[m].getNormal().X * AB_[id].Z - wallObjects_[m].getNormal().Z * AB_[id].X) * Vec3D::dot(wallObjects_[n].getPosition(),wallObjects_[n].getNormal())
154  +(wallObjects_[n].getNormal().X * AB_[id].Z - wallObjects_[n].getNormal().Z * AB_[id].X) * Vec3D::dot(wallObjects_[m].getPosition(),wallObjects_[m].getNormal())
155  -(wallObjects_[n].getNormal().X * wallObjects_[m].getNormal().Z - wallObjects_[m].getNormal().X * wallObjects_[n].getNormal().Z) * 0.0,
156  +(wallObjects_[m].getNormal().X * AB_[id].Y - AB_[id].X * wallObjects_[m].getNormal().Y) * Vec3D::dot(wallObjects_[n].getPosition(),wallObjects_[n].getNormal())
157  -(wallObjects_[n].getNormal().X * AB_[id].Y - AB_[id].X * wallObjects_[n].getNormal().Y) * Vec3D::dot(wallObjects_[m].getPosition(),wallObjects_[m].getNormal())
158  +(wallObjects_[n].getNormal().X * wallObjects_[m].getNormal().Y - wallObjects_[m].getNormal().X * wallObjects_[n].getNormal().Y) * 0.0) * invdet;
159  }
160 
161  // C[(n-2)*(n-1)*n/6+(m-1)*m/2+l] is a point intersecting walls l, m and n, l<m<n
162  C_.resize((n - 1) * n * (n + 1) / 6);
163  for (std::size_t m = 0; m < n; m++)
164  {
165  for (std::size_t l = 0; l < m; l++)
166  {
167  std::size_t id = (n - 2) * (n - 1) * n / 6 + (m - 1) * m / 2 + l;
168  Mdouble invdet = 1.0 / (+wallObjects_[n].getNormal().X * (wallObjects_[m].getNormal().Y * wallObjects_[l].getNormal().Z - wallObjects_[l].getNormal().Y * wallObjects_[m].getNormal().Z)
169  - wallObjects_[n].getNormal().Y * (wallObjects_[m].getNormal().X * wallObjects_[l].getNormal().Z - wallObjects_[m].getNormal().Z * wallObjects_[l].getNormal().X)
170  + wallObjects_[n].getNormal().Z * (wallObjects_[m].getNormal().X * wallObjects_[l].getNormal().Y - wallObjects_[m].getNormal().Y * wallObjects_[l].getNormal().X));
171  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())
172  - (wallObjects_[n].getNormal().Y * wallObjects_[l].getNormal().Z - wallObjects_[n].getNormal().Z * wallObjects_[l].getNormal().Y) * Vec3D::dot(wallObjects_[m].getPosition(),wallObjects_[m].getNormal())
173  + (wallObjects_[n].getNormal().Y * wallObjects_[m].getNormal().Z - wallObjects_[n].getNormal().Z * wallObjects_[m].getNormal().Y) * Vec3D::dot(wallObjects_[l].getPosition(),wallObjects_[l].getNormal()),
174  -(wallObjects_[m].getNormal().X * wallObjects_[l].getNormal().Z - wallObjects_[m].getNormal().Z * wallObjects_[l].getNormal().X) * Vec3D::dot(wallObjects_[n].getPosition(),wallObjects_[n].getNormal())
175  + (wallObjects_[n].getNormal().X * wallObjects_[l].getNormal().Z - wallObjects_[n].getNormal().Z * wallObjects_[l].getNormal().X) * Vec3D::dot(wallObjects_[m].getPosition(),wallObjects_[m].getNormal())
176  - (wallObjects_[n].getNormal().X * wallObjects_[m].getNormal().Z - wallObjects_[m].getNormal().X * wallObjects_[n].getNormal().Z) * Vec3D::dot(wallObjects_[l].getPosition(),wallObjects_[l].getNormal()),
177  +(wallObjects_[m].getNormal().X * wallObjects_[l].getNormal().Y - wallObjects_[l].getNormal().X * wallObjects_[m].getNormal().Y) * Vec3D::dot(wallObjects_[n].getPosition(),wallObjects_[n].getNormal())
178  - (wallObjects_[n].getNormal().X * wallObjects_[l].getNormal().Y - wallObjects_[l].getNormal().X * wallObjects_[n].getNormal().Y) * Vec3D::dot(wallObjects_[m].getPosition(),wallObjects_[m].getNormal())
179  + (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;
180  }
181  }
182 
183  logger(VERBOSE, "%", *this);
184  for (InfiniteWall w : wallObjects_)
185  logger(VERBOSE, "wallObject %, %", w.getNormal(), w.getPosition());
186  for (Vec3D v : A_)
187  logger(VERBOSE, "A %", v);
188  for (Vec3D v : AB_)
189  logger(VERBOSE, "AB %", v);
190  for (Vec3D v : C_)
191  logger(VERBOSE, "C %", v);
192 }
193 
199 {
200  logger(WARN, "This function is deprecated, use IntersectionOfWalls::addObject(Vec3D, Vec3D) instead.");
201  addObject(normal, position*normal);
202 }
203 
212 void IntersectionOfWalls::createOpenPrism(std::vector<Vec3D> points, Vec3D prismAxis)
213 {
214  clear();
215  //note: use i+1 < points.size() instead of i < points.size()-1, otherwise it creates havoc if point has zero entries.
216  for (unsigned int i = 0; i+1 < points.size(); i++)
217  addObject(Vec3D::cross(points[i] - points[i + 1], prismAxis), points[i]);
218 }
219 
227 void IntersectionOfWalls::createPrism(std::vector<Vec3D> points, Vec3D prismAxis)
228 {
229  createOpenPrism(points, prismAxis);
230  addObject(Vec3D::cross(points.back() - points.front(), prismAxis), points.front());
231 }
232 
240 void IntersectionOfWalls::createOpenPrism(std::vector<Vec3D> points)
241 {
242  Vec3D prismAxis = Vec3D::cross(
243  Vec3D::getUnitVector(points[1] - points[0]),
244  Vec3D::getUnitVector(points[2] - points[0]));
245  createOpenPrism(points, prismAxis);
246 }
247 
255 void IntersectionOfWalls::createPrism(std::vector<Vec3D> points)
256 {
257  Vec3D prismAxis = Vec3D::cross(
258  Vec3D::getUnitVector(points[1] - points[0]),
259  Vec3D::getUnitVector(points[2] - points[0]));
260  createPrism(points, prismAxis);
261 }
262 
277 bool IntersectionOfWalls::getDistanceAndNormal(const BaseParticle& p, Mdouble& distance, Vec3D& normal_return) const
278 {
279  return getDistanceAndNormal(p.getPosition(), p.getInteractionRadius(), distance, normal_return);
280 }
281 
304 bool IntersectionOfWalls::getDistanceAndNormal(const Vec3D& position, Mdouble wallInteractionRadius, Mdouble &distance, Vec3D &normal_return) const
305 {
306  if (wallObjects_.size()==0)
307  {
308  logger(DEBUG,"Empty IntersectionOfWalls");
309  return false;
310  }
311 
312  distance = -1e20;
313  Mdouble distance2 = -1e20;
314  Mdouble distance3 = -1e20;
315  Mdouble distanceCurrent;
316  unsigned int id=0;
317  unsigned int id2=0;
318  unsigned int id3=0;
319 
320  //The object has to touch each wall each wall (distanceCurrent) and keep the minimum distance (distance) and wall index (id)
321  for (unsigned int i = 0; i < wallObjects_.size(); i++)
322  {
323  // Calculate distance to each wall (distanceCurrent);
324  distanceCurrent = wallObjects_[i].getDistance(position);
325  // The object has to touch each wall (distanceCurrent >= wallInteractionRadius), otherwise return false (i.e. no contact)
326  // This means that for each InfiniteWall in wallObjects_, the particle is either "inside"
327  // the wall or touching it. If not, there is no interaction.
328  if (distanceCurrent >= wallInteractionRadius)
329  return false;
330  // Find out which of the InfiniteWalls is interacting with the particle.
331  // Keep the minimum distance (distance) and wall index (id)
332  // and store up to two walls (id2, id3) and their distances (distance2, distance3),
333  // if the possible contact point is near the intersection between id and id2 (and id3)
334  if (distanceCurrent > distance)
335  {
336  if (distance > -wallInteractionRadius)
337  {
338  if (distance2 > -wallInteractionRadius)
339  {
340  distance3 = distance;
341  id3 = id;
342  }
343  else
344  {
345  distance2 = distance;
346  id2 = id;
347  }
348  }
349  distance = distanceCurrent;
350  id = i;
351  }
352  else if (distanceCurrent > -wallInteractionRadius)
353  {
354  if (distance2 > -wallInteractionRadius)
355  {
356  distance3 = distanceCurrent;
357  id3 = i;
358  }
359  else
360  {
361  distance2 = distanceCurrent;
362  id2 = i;
363  }
364  }
365  }
366 
367  //If we are here, the closest wall is id;
368  //if distance2>-P.Radius (and distance3>-P.Radius), the possible contact point
369  // is near the intersection between id and id2 (and id3)
370  if (distance2 > -wallInteractionRadius)
371  {
372  //D is the point on wall id closest to P
373  Vec3D D = position + wallObjects_[id].getNormal() * distance;
374  //If the distance of D to id2 is positive, the contact is with the intersection
375  bool intersection_with_id2 = (wallObjects_[id2].getDistance(D) > 0.0);
376 
377  if (distance3 > -wallInteractionRadius && (wallObjects_[id3].getDistance(D) > 0.0))
378  {
379  if (intersection_with_id2)
380  {
381  //possible contact is with intersection of id,id2,id3
382  //we know id2<id3
383  unsigned int index =
384  (id < id2) ? ((id3 - 2) * (id3 - 1) * id3 / 6 + (id2 - 1) * id2 / 2 + id) :
385  (id < id3) ? ((id3 - 2) * (id3 - 1) * id3 / 6 + (id - 1) * id / 2 + id2) :
386  ((id - 2) * (id - 1) * id / 6 + (id3 - 1) * id3 / 2 + id2);
387  normal_return = position - C_[index];
388  distance = sqrt(normal_return.getLengthSquared());
389  if (distance >= wallInteractionRadius)
390  return false; //no contact
391  normal_return /= -distance;
392  return true; //contact with id,id2,id3
393  }
394  else
395  {
396  intersection_with_id2 = true;
397  distance2 = distance3;
398  id2 = id3;
399  }
400  }
401 
402  if (intersection_with_id2)
403  { //possible contact is with intersection of id,id2
404  unsigned int index = (id > id2) ? ((id - 1) * id / 2 + id2) : ((id2 - 1) * id2 / 2 + id);
405  Vec3D AC = position - A_[index];
406  normal_return = AC - AB_[index] * Vec3D::dot(AC, AB_[index]);
407  distance = sqrt(normal_return.getLengthSquared());
408  if (distance >= wallInteractionRadius)
409  return false; //no contact
410  normal_return /= -distance;
411  return true; //contact with two walls
412  }
413  }
414  //contact is with id
415  normal_return = wallObjects_[id].getNormal();
416  return true;
417 }
418 
431 {
433  for(Vec3D& a : A_)
434  {
435  a += move;
436  }
437  for(Vec3D& c : C_)
438  {
439  c += move;
440  }
441  for(InfiniteWall& o : wallObjects_)
442  {
443  o.move(move);
444  }
445 }
446 
450 void IntersectionOfWalls::read(std::istream& is)
451 {
452  BaseWall::read(is);
453  std::string dummy;
454  int n;
455  is >> dummy >> n;
456 
457  Vec3D normal;
458  Vec3D position;
459  for (int i = 0; i < n; i++)
460  {
461  is >> dummy >> normal >> dummy >> position;
462  addObject(normal, position);
463  }
464 }
465 
470 void IntersectionOfWalls::write(std::ostream& os) const
471 {
472  BaseWall::write(os);
473  os << " numIntersectionOfWalls " << wallObjects_.size();
474  for (std::vector<InfiniteWall>::const_iterator it = wallObjects_.begin(); it != wallObjects_.end(); ++it)
475  {
476  os << " normal " << it->getNormal() << " position " << it->getPosition();
477  }
478 }
479 
483 std::string IntersectionOfWalls::getName() const
484 {
485  return "IntersectionOfWalls";
486 }
487 
489 {
490  for (auto wall=wallObjects_.begin(); wall!=wallObjects_.end(); wall++)
491  {
492  std::vector<Vec3D> points;
493  wall->createVTK (points);
494  for (auto other=wallObjects_.begin(); other!=wallObjects_.end(); other++)
495  {
496  if (other!=wall)
497  {
498  intersectVTK(points, -other->getNormal(), other->getPosition());
499  }
500  }
501  wall->addToVTK (points, vtk);
502  }
503 }
static Mdouble getLengthSquared(const Vec3D &a)
Calculates the squared length of a Vec3D: .
Definition: Vector.cc:291
static Vec3D getUnitVector(const Vec3D &a)
Returns a unit Vec3D based on a.
Definition: Vector.cc:428
A IntersectionOfWalls is convex polygon defined as an intersection of InfiniteWall's.
void writeVTK(VTKContainer &vtk) const override
Logger< MERCURY_LOGLEVEL > logger("MercuryKernel")
void normalize()
Makes this Vec3D unit length.
Definition: Vector.cc:214
const ParticleSpecies * getSpecies() const
Returns a pointer to the species of this BaseInteractable.
void read(std::istream &is) override
Reads an IntersectionOfWalls from an input stream, for example a restart file.
virtual void setHandler(WallHandler *handler)
A function which sets the WallHandler for this BaseWall.
Definition: BaseWall.cc:76
double Mdouble
Vec3D getNormal() const
Access function for normal.
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".
void intersectVTK(std::vector< Vec3D > &points, const Vec3D normal, const Vec3D position) const
Definition: BaseWall.cc:163
static Mdouble dot(const Vec3D &a, const Vec3D &b)
Calculates the dot product of two Vec3D: .
Definition: Vector.cc:167
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.
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 setSpecies(const ParticleSpecies *species)
sets species of subwalls as well
WallHandler * getHandler() const
A function which returns the WallHandler that handles this BaseWall.
Definition: BaseWall.cc:85
IntersectionOfWalls()
Default constructor.
MERCURY_DEPRECATED void clear() override
Removes all parts of the walls.
std::vector< Vec3D > C_
A vector that stores the intersection point of three different InfiniteWall.
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:255
Basic class for walls.
Definition: BaseWall.h:44
void move(const Vec3D &move) override
Move the IntersectionOfWalls to a new position, which is a Vec3D from the old position.
IntersectionOfWalls * copy() const override
Wall copy method. It calls the copy constructor of this Wall, useful for polymorphism.
Container to store all BaseWall.
Definition: WallHandler.h:42
std::vector< Vec3D > AB_
A vector that stores the direction of the intersecting lines between two different InfiniteWall...
void set(Vec3D normal, Vec3D point)
Defines a standard wall, given an outward normal vector s.t. normal*x=normal*point for all x of the w...
Definition: InfiniteWall.cc:79
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:47
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 setHandler(WallHandler *wallHandler) override
A function which sets the WallHandler for this BaseWall.
void write(std::ostream &os) const override
Writes an IntersectionOfWalls to an output stream, for example a restart file.
void read(std::istream &is)
Function that reads a BaseWall from an input stream, usually a restart file.
Definition: BaseWall.cc:60
void setSpecies(const ParticleSpecies *species)
Define the species of this wall.
Definition: BaseWall.cc:113