BornAgain  1.19.79
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/mesh/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/Math/Constants.h"
16 #include "Base/Util/Assert.h"
18 #include <qmath.h>
19 
20 namespace GUI::RealSpace {
21 
22 // cut: 0..1 - how much is cut off from the bottom
23 // removedTop - how much fraction of the radius is removed from the top
24 Geometry::Mesh Geometry::meshSphere(float cut, float baseShift, float removedTop)
25 {
26  if (1 <= cut)
27  return Mesh();
28  cut = qMax(0.f, cut);
29  ASSERT(0 <= cut && cut < 1);
30 
31  // 'rings' are the # of horizontal cross-sections ranging from bottom to top of the sphere
32  // 'slices' are the # of vertices in a given ring
33  int rings;
34  int slices = SLICES;
35  float minPh, maxPh, phRge;
36 
37  if (cut > 0) // South pole absent
38  {
39  minPh = asinf(2 * cut - 1);
40  if (removedTop > 0) // North pole absent
41  maxPh = asinf(1 - 2 * removedTop);
42  else // North pole present
43  maxPh = float(M_PI_2) - float(M_PI) / RINGS;
44  } else // South pole present
45  {
46  minPh = -float(M_PI_2) + float(M_PI) / RINGS;
47  if (removedTop > 0) // North pole absent
48  maxPh = asinf(1 - removedTop);
49  else // North pole present
50  maxPh = float(M_PI_2) - float(M_PI) / RINGS;
51  }
52  phRge = maxPh - minPh;
53  rings = qMax(2, qCeil(qreal(RINGS * phRge) / M_PI)); // At least 2 rings (incl. lowest ring)
54 
55  ASSERT(qAbs(minPh) < float(M_PI_2));
56  ASSERT(2 <= rings && 2 <= slices);
57 
58  // meshes of vertices and normals, without poles, _[ring][slice]
59  QVector<Vertices> vs_(rings);
60  QVector<Vertices> ns_(rings);
61  for (auto& ring : vs_)
62  ring.resize(slices);
63  for (auto& ring : ns_)
64  ring.resize(slices);
65 
66  float const R = .5f;
67 
68  for (int r = 0; r < rings; ++r) {
69  float ph = minPh + phRge * r / (rings - 1);
70  float cp = cosf(ph), sp = sinf(ph);
71 
72  for (int s = 0; s < slices; ++s) {
73  auto th = float(M_TWOPI * s / slices);
74  Vector3D v(R * cp * cosf(th), R * cp * sinf(th), R * sp);
75  v.z += baseShift; // baseShift is used for shifting the bottom of the spherical shape
76  // to z=0 plane
77  vs_[r][s] = v;
78  ns_[r][s] = v.normalized();
79  }
80  }
81 
82  // make into triangles
83  int const nv = 6 * (rings)*slices;
84  Vertices vs;
85  vs.reserve(nv);
86  Vertices ns;
87  ns.reserve(nv);
88 
89  for (int r = 0; r < rings; ++r) {
90  auto &vr = vs_.at(r), &nr = ns_.at(r);
91 
92  for (int s = 0; s < slices; ++s) {
93  int s0 = s, s1 = (s + 1) % slices;
94 
95  auto &v0 = vr.at(s0), &v1 = vr.at(s1);
96  auto &n0 = nr.at(s0), &n1 = nr.at(s1);
97 
98  if (r == 0) { // bottom most ring
99  Vector3D vp, n0, n1, np(-Vector3D::_z);
100  if (cut > 0) { // South pole absent
101  vp = Vector3D(0, 0, v0.z);
102  n0 = n1 = np;
103  } else { // South pole present
104  vp = Vector3D(0, 0, -R + baseShift);
105  n0 = nr.at(s0);
106  n1 = nr.at(s1);
107  }
108  vs.addTriangle(v0, vp, v1);
109  ns.addTriangle(n0, np, n1);
110  }
111 
112  if (r + 1 == rings) { // top most ring
113  Vector3D vp, n0, n1, np(Vector3D::_z);
114  if (removedTop > 0) { // North pole absent
115  vp = Vector3D(0, 0, v0.z);
116  n0 = n1 = np;
117  } else { // North pole present
118  vp = Vector3D(0, 0, +R + baseShift);
119  n0 = nr.at(s0);
120  n1 = nr.at(s1);
121  }
122  vs.addTriangle(v0, v1, vp);
123  ns.addTriangle(n0, n1, np);
124  } else { // in between poles
125  auto &vr1 = vs_.at(r + 1), &nr1 = ns_.at(r + 1);
126  auto &n2 = nr1.at(s1), &n3 = nr1.at(s0);
127  vs.addQuad(v0, v1, vr1.at(s1), vr1.at(s0));
128  ns.addQuad(n0, n1, n2, n3);
129  }
130  }
131  }
132 
133  return makeMesh(vs, ns);
134 }
135 
136 } // namespace GUI::RealSpace
static Mesh makeMesh(const Vertices &vs, Vertices const *ns=nullptr)
Definition: geometry.cpp:117
static int const SLICES
Definition: geometry.h:90
QVector< Vert_Normal > Mesh
Definition: geometry.h:66
static int const RINGS
Definition: geometry.h:90
static Mesh meshSphere(float cut, float baseShift=0.0f, float removedTop=0.0f)
Definition: sphere.cpp:24
Defines Geometry class.
void addTriangle(const Vector3D &, const Vector3D &, const Vector3D &)
Definition: geometry.cpp:35
void addQuad(const Vector3D &, const Vector3D &, const Vector3D &, const Vector3D &)
Definition: geometry.cpp:42
static Vector3D const _z
Definition: def.h:46
Vector3D normalized() const
Definition: def.cpp:49