BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
sphere.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/ba3d/model/geometry/sphere.cpp
6 //! @brief Implements utility functions in ba3d namespace
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
15 #include "Base/Utils/Assert.h"
17 #include <qmath.h>
18 
19 namespace RealSpace {
20 
21 // cut: 0..1 - how much is cut off from the bottom
22 // removedTop - how much fraction of the radius is removed from the top
23 Geometry::Mesh Geometry::meshSphere(float cut, float baseShift, float removedTop)
24 {
25  if (1 <= cut)
26  return Mesh();
27  cut = qMax(0.f, cut);
28  ASSERT(0 <= cut && cut < 1);
29 
30  // 'rings' are the # of horizontal cross-sections ranging from bottom to top of the sphere
31  // 'slices' are the # of vertices in a given ring
32  int rings, slices = SLICES;
33  float minPh, maxPh, phRge;
34 
35  if (cut > 0) // South pole absent
36  {
37  minPh = asinf(2 * cut - 1);
38  if (removedTop > 0) // North pole absent
39  maxPh = asinf(1 - 2 * removedTop);
40  else // North pole present
41  maxPh = float(M_PI_2) - float(M_PI) / RINGS;
42  } else // South pole present
43  {
44  minPh = -float(M_PI_2) + float(M_PI) / RINGS;
45  if (removedTop > 0) // North pole absent
46  maxPh = asinf(1 - removedTop);
47  else // North pole present
48  maxPh = float(M_PI_2) - float(M_PI) / RINGS;
49  }
50  phRge = maxPh - minPh;
51  rings = qMax(2, qCeil(qreal(RINGS * phRge) / M_PI)); // At least 2 rings (incl. lowest ring)
52 
53  ASSERT(qAbs(minPh) < float(M_PI_2));
54  ASSERT(2 <= rings && 2 <= slices);
55 
56  // meshes of vertices and normals, without poles, _[ring][slice]
57  QVector<Vertices> vs_(rings), ns_(rings);
58  for (auto& ring : vs_)
59  ring.resize(slices);
60  for (auto& ring : ns_)
61  ring.resize(slices);
62 
63  float const R = .5f;
64 
65  for (int r = 0; r < rings; ++r) {
66  float ph = minPh + phRge * r / (rings - 1);
67  float cp = cosf(ph), sp = sinf(ph);
68 
69  for (int s = 0; s < slices; ++s) {
70  float th = float(2 * M_PI * s / slices);
71  Vector3D v(R * cp * cosf(th), R * cp * sinf(th), R * sp);
72  v.z += baseShift; // baseShift is used for shifting the bottom of the spherical shape
73  // to z=0 plane
74  vs_[r][s] = v;
75  ns_[r][s] = v.normalized();
76  }
77  }
78 
79  // make into triangles
80  int const nv = 6 * (rings)*slices;
81  Vertices vs;
82  vs.reserve(nv);
83  Vertices ns;
84  ns.reserve(nv);
85 
86  for (int r = 0; r < rings; ++r) {
87  auto &vr = vs_.at(r), &nr = ns_.at(r);
88 
89  for (int s = 0; s < slices; ++s) {
90  int s0 = s, s1 = (s + 1) % slices;
91 
92  auto &v0 = vr.at(s0), &v1 = vr.at(s1);
93  auto &n0 = nr.at(s0), &n1 = nr.at(s1);
94 
95  if (r == 0) { // bottom most ring
96  Vector3D vp, n0, n1, np(-Vector3D::_z);
97  if (cut > 0) { // South pole absent
98  vp = Vector3D(0, 0, v0.z);
99  n0 = n1 = np;
100  } else { // South pole present
101  vp = Vector3D(0, 0, -R + baseShift);
102  n0 = nr.at(s0);
103  n1 = nr.at(s1);
104  }
105  vs.addTriangle(v0, vp, v1);
106  ns.addTriangle(n0, np, n1);
107  }
108 
109  if (r + 1 == rings) { // top most ring
110  Vector3D vp, n0, n1, np(Vector3D::_z);
111  if (removedTop > 0) { // North pole absent
112  vp = Vector3D(0, 0, v0.z);
113  n0 = n1 = np;
114  } else { // North pole present
115  vp = Vector3D(0, 0, +R + baseShift);
116  n0 = nr.at(s0);
117  n1 = nr.at(s1);
118  }
119  vs.addTriangle(v0, v1, vp);
120  ns.addTriangle(n0, n1, np);
121  } else { // in between poles
122  auto &vr1 = vs_.at(r + 1), &nr1 = ns_.at(r + 1);
123  auto &n2 = nr1.at(s1), &n3 = nr1.at(s0);
124  vs.addQuad(v0, v1, vr1.at(s1), vr1.at(s0));
125  ns.addQuad(n0, n1, n2, n3);
126  }
127  }
128  }
129 
130  return makeMesh(vs, ns);
131 }
132 
133 } // namespace RealSpace
Defines the macro ASSERT.
#define ASSERT(condition)
Definition: Assert.h:31
#define M_PI_2
Definition: Constants.h:45
#define M_PI
Definition: Constants.h:44
static Mesh meshSphere(float cut, float baseShift=0.0f, float removedTop=0.0f)
Definition: sphere.cpp:23
static int const SLICES
Definition: geometry.h:90
static Mesh makeMesh(const Vertices &vs, Vertices const *ns=nullptr)
Definition: geometry.cpp:111
QVector< Vert_Normal > Mesh
Definition: geometry.h:66
static int const RINGS
Definition: geometry.h:90
Defines Geometry class.
void addTriangle(const Vector3D &, const Vector3D &, const Vector3D &)
Definition: geometry.cpp:30
void addQuad(const Vector3D &, const Vector3D &, const Vector3D &, const Vector3D &)
Definition: geometry.cpp:37
static Vector3D const _z
Definition: def.h:49
Vector3D normalized() const
Definition: def.cpp:36