polyhedron_volume.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2019 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17 
19 
20 using namespace buoyancy;
22 
25  : normal(0., 0., 1.), offset(0.)
26 {
27 }
28 
30 Polyhedron::Face::Face(int _i1, int _i2, int _i3)
31  : i1(_i1), i2(_i2), i3(_i3)
32 {
33 }
34 
37  : volume(0.0), centroid(ignition::math::Vector3d({0, 0, 0}))
38 {
39 }
40 
43 {
44  this->volume += rhs.volume;
45  this->centroid += rhs.centroid;
46  return *this;
47 }
48 
50 Polyhedron Polyhedron::makeCube(double x, double y, double z)
51 {
52  Polyhedron cube;
53  // generate vertices
54  for (int i = 0; i < 2; ++i)
55  {
56  for (int j = 0; j < 2; ++j)
57  {
58  for (int k = 0; k < 2; ++k)
59  {
60  cube.vertices.emplace_back(
61  ignition::math::Vector3d(i * x - x / 2.0,
62  j * y - y / 2.0, k * z - z / 2.0));
63  }
64  }
65  }
66  // generate faces
67  cube.faces.emplace_back(Face(0, 6, 4));
68  cube.faces.emplace_back(Face(0, 2, 6));
69  cube.faces.emplace_back(Face(0, 3, 2));
70  cube.faces.emplace_back(Face(0, 1, 3));
71  cube.faces.emplace_back(Face(2, 7, 6));
72  cube.faces.emplace_back(Face(2, 3, 7));
73  cube.faces.emplace_back(Face(4, 6, 7));
74  cube.faces.emplace_back(Face(4, 7, 5));
75  cube.faces.emplace_back(Face(0, 4, 5));
76  cube.faces.emplace_back(Face(0, 5, 1));
77  cube.faces.emplace_back(Face(1, 5, 7));
78  cube.faces.emplace_back(Face(1, 7, 3));
79 
80  return cube;
81 }
82 
84 Polyhedron Polyhedron::makeCylinder(double r, double l, int n)
85 {
86  assert(n > 4);
87 
88  buoyancy::Polyhedron cylinder;
89 
90  // generate all vertices
91  double angle_step = 2.0 * M_PI / n;
92  double l_2 = l / 2.0;
93  cylinder.vertices.resize(2*n+2);
94  cylinder.vertices[0] = ignition::math::Vector3d{0, 0, -l_2};
95  for (int i = 1; i <= n; ++i)
96  {
97  double x = r * ::sin(angle_step * (i-1));
98  double y = r * ::cos(angle_step * (i-1));
99  // bottom plate
100  cylinder.vertices[i] = ignition::math::Vector3d{x, y, -l_2};
101  // top plate
102  cylinder.vertices[i+n] = ignition::math::Vector3d{x, y, l_2};
103  }
104  cylinder.vertices[2*n+1] = ignition::math::Vector3d{0, 0, l_2};
105 
106  // generate all faces
107  for (int i = 1; i <= n; ++i)
108  { // bottom plate
109  cylinder.faces.emplace_back(Face(0, i, (i%n)+1));
110  }
111  for (int i = 1; i <= n; ++i)
112  { // walls
113  cylinder.faces.emplace_back(Face(i+1, i, n+i));
114  cylinder.faces.emplace_back(Face((i%n)+n, (i%n)+n+1, (i%n)+1));
115  }
116  for (int i = 1; i <= n; ++i)
117  { // top plate
118  cylinder.faces.emplace_back(Face(i+n, 2*n+1, (i%n)+n+1));
119  }
120 
121  assert(cylinder.vertices.size() == 2 * n + 2);
122  assert(cylinder.faces.size() == 4 * n);
123 
124  return cylinder;
125 }
126 
128 Volume Polyhedron::tetrahedronVolume(const ignition::math::Vector3d &v1,
129  const ignition::math::Vector3d &v2, const ignition::math::Vector3d &v3,
130  const ignition::math::Vector3d &p)
131 {
132  ignition::math::Vector3d a = v2 - v1;
133  ignition::math::Vector3d b = v3 - v1;
134  ignition::math::Vector3d r = p - v1;
135 
136  Volume output;
137  output.volume = (1/6.) * (b.Cross(a)).Dot(r);
138  output.centroid = 0.25 * output.volume * (v1 + v2 + v3 + p);
139  return output;
140 }
141 
144 {
145  Volume output;
146  // Compute the contribution of each triangle face
147  for (const auto& face : faces)
148  {
149  ignition::math::Vector3d v1 = vertices[face.i1];
150  ignition::math::Vector3d v2 = vertices[face.i2];
151  ignition::math::Vector3d v3 = vertices[face.i3];
152  output += tetrahedronVolume(v1, v2, v3);
153  }
154  return output;
155 }
156 
158 Volume Polyhedron::clipTriangle(const ignition::math::Vector3d &v1,
159  const ignition::math::Vector3d &v2,
160  const ignition::math::Vector3d &v3, double d1, double d2, double d3,
161  const ignition::math::Vector3d &p)
162 {
163  assert(d1 * d2 < 0);
164  Volume output;
165 
166  // calculate the intersection point from a to b
167  ignition::math::Vector3d ab = v1 + (d1/(d1 - d2))*(v2 - v1);
168  if (d1 < 0)
169  {
170  // b to c crosses the clipping plane
171  if (d3 < 0)
172  {
173  // Case B - a quadrilateral or two triangles
174  // Calculate intersection point from b to c.
175  ignition::math::Vector3d bc = v2 + (d2/(d2 - d3))*(v3 - v2);
176  output += tetrahedronVolume(ab, bc, v1, p);
177  output += tetrahedronVolume(bc, v3, v1, p);
178  }
179  else
180  {
181  // Case A - a single triangle.
182  ignition::math::Vector3d ac = v1 + (d1/(d1 - d3))*(v3 - v1);
183  output += tetrahedronVolume(ab, ac, v1, p);
184  }
185  }
186  else
187  {
188  if (d3 < 0)
189  {
190  // Case B
191  ignition::math::Vector3d ac = v1 + (d1/(d1 - d3))*(v3 - v1);
192  output += tetrahedronVolume(ab, v2, v3, p);
193  output += tetrahedronVolume(ab, v3, ac, p);
194  }
195  else
196  {
197  // Case A
198  ignition::math::Vector3d bc = v2 + (d2/(d2 - d3))*(v3 - v2);
199  output += tetrahedronVolume(ab, v2, bc, p);
200  }
201  }
202  return output;
203 }
204 
206 Volume Polyhedron::SubmergedVolume(const ignition::math::Vector3d &x,
207  const ignition::math::Quaterniond &q, Plane &plane)
208 {
209  // transform the plane into the polyhedron frame
210  auto qt = q.Inverse();
211  auto normal = qt.RotateVector(plane.normal);
212  double offset = plane.offset - plane.normal.Dot(x);
213 
214  // compute vertex heights relative to surface
215  std::vector<double> ds(vertices.size());
216  int numSubmerged = 0;
217  int sampleVert = 0;
218  for (size_t i = 0; i < vertices.size(); ++i)
219  {
220  ds[i] = normal.Dot(vertices[i]) - offset;
221  if (ds[i] < -EPSILON)
222  {
223  ++numSubmerged;
224  sampleVert = i;
225  }
226  }
227 
228  // if no submerged vertices return
229  if (numSubmerged == 0)
230  {
231  return Volume{};
232  }
233 
234  // Find a point on the water surface. Project a submerged point to
235  // get improved accuracy. This point serves as the point of origin for
236  // computing all the tetrahedron volumes. Since this point is on the
237  // surface, all of the surface faces get zero volume tetrahedrons.
238  // This way the surface polygon does not need to be considered.
239  ignition::math::Vector3d p = vertices[sampleVert] - ds[sampleVert] * normal;
240 
241  // compute the contribution of each triangle
242  Volume output;
243  for (const auto& face : faces)
244  {
245  ignition::math::Vector3d v1 = vertices[face.i1];
246  ignition::math::Vector3d v2 = vertices[face.i2];
247  ignition::math::Vector3d v3 = vertices[face.i3];
248  double d1 = ds[face.i1];
249  double d2 = ds[face.i2];
250  double d3 = ds[face.i3];
251 
252  if (d1 * d2 < 0)
253  { // v1-v2 crosses the plane
254  output += clipTriangle(v1, v2, v3, d1, d2, d3, p);
255  }
256  else if (d1 * d3 < 0)
257  { // v1-v3 crosses the plane
258  output += clipTriangle(v3, v1, v2, d3, d1, d2, p);
259  }
260  else if (d2 * d3 < 0)
261  { // v2-v3 crosses the plane
262  output += clipTriangle(v2, v3, v1, d2, d3, d1, p);
263  }
264  else if (d1 < 0 || d2 < 0 || d3 < 0)
265  { // fully submerged
266  output += tetrahedronVolume(v1, v2, v3, p);
267  }
268  }
269 
270  // small submerged slivers may have rounding error leading to
271  // a zero or negative volume. If so, then return a result of zero.
272  if (output.volume <= EPSILON)
273  {
274  return Volume{};
275  }
276 
277  // normalize the centroid by the total volume
278  output.centroid *= 1.0 / output.volume;
279  // transform the centroid into world coordinates
280  output.centroid = x + q.RotateVector(output.centroid);
281  // if centroid is very small make it zero
282  output.centroid.X() = ::fabs(output.centroid[0]) < EPSILON ?
283  0 : output.centroid.X();
284  output.centroid.Y() = ::fabs(output.centroid[1]) < EPSILON ?
285  0 : output.centroid.Y();
286  output.centroid.Z() = ::fabs(output.centroid[2]) < EPSILON ?
287  0 : output.centroid.Z();
288  return output;
289 }
ignition::math::Vector3d normal
Vector3 normal to plane.
Volume & operator+=(const Volume &rhs)
Overloads += for volume object.
float offset
Offset w.r.t. normal.
Volume ComputeFullVolume()
Compute full volume and center of buoyancy of the polyhedron.
std::vector< Face > faces
Object faces.
Polyhedron::Face Face
TFSIMD_FORCE_INLINE const tfScalar & y() const
Plane()
Initializes plane at z=0.
Submerged volume calculation using polyhedron based on: Exact Buoyancy for Polyhedra by Eric Catto...
static Polyhedron makeCube(double x, double y, double z)
Generate a cube polyhedron centered at origin.
static Polyhedron makeCylinder(double r, double l, int n)
Generate a cylinder polyhedron centered at origin.
TFSIMD_FORCE_INLINE const tfScalar & x() const
Store vertex index for a triangular face.
ignition::math::Vector3d centroid
Vector3 representing volume centroid.
static Volume clipTriangle(const ignition::math::Vector3d &v1, const ignition::math::Vector3d &v2, const ignition::math::Vector3d &v3, double d1, double d2, double d3, const ignition::math::Vector3d &p=ignition::math::Vector3d({0., 0., 0.}))
Clips a partially submerged triangle.
std::vector< ignition::math::Vector3d > vertices
Object vertices.
static Volume tetrahedronVolume(const ignition::math::Vector3d &v1, const ignition::math::Vector3d &v2, const ignition::math::Vector3d &v3, const ignition::math::Vector3d &p=ignition::math::Vector3d({0., 0., 0.}))
Computes volume and centroid of tetrahedron tetrahedron formed by triangle + arbitrary point...
Represents output volume with centroid.
Represents a plane as a normal and offset.
double volume
Submerged volume of shape.
Volume SubmergedVolume(const ignition::math::Vector3d &x, const ignition::math::Quaterniond &q, Plane &plane)
Compute submerge volume and center of buoyancy of a polyhedron.


usv_gazebo_plugins
Author(s): Brian Bingham , Carlos Aguero
autogenerated on Thu May 7 2020 03:54:47