SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SLLens.cpp
Go to the documentation of this file.
1 /**
2  * \file SLLens.cpp
3  * \date October 2014
4  * \authors Marcus Hudritsch, Philipp Jueni
5  * \copyright http://opensource.org/licenses/GPL-3.0
6 */
7 
8 #include <SLLens.h>
9 #include <SLMaterial.h>
10 #include <iostream>
11 
12 using std::cout;
13 using std::endl;
14 
15 //-----------------------------------------------------------------------------
16 /*!
17 SLLens::SLLens ctor for lens revolution object around the y-axis. <br>
18 Create the lens with the eye prescription card.
19 @image html images/EyePrescriptionCard.png
20 The first values in the prescription card is called Sphere. It is also the
21 diopter of the front side of the lens. <br>
22 The second value from the prescription card is called Cylinder. The sum from
23 the sphere and the cylinder is the diopter of the back side of the lens. <br>
24 The diopter is the inverse of the focal distance (f) of the lens. <br>
25 To correct myopic, negative diopters are used. <br>
26 To correct presbyopic, positive diopters are used.<br>
27 @image html images/Lens.png
28 
29 @param assetMgr Pointer to the asset manager
30 @param sphere SLfloat taken from the eyeglass passport.
31 @param cylinder SLfloat taken from the eyeglass passport.
32 @param diameter SLfloat The diameter (h) of the lens
33 @param thickness SLfloat The space between the primary planes of lens sides (d)
34 @param stacks SLint
35 @param slices SLint
36 @param name SLstring of the SLRevolver Mesh
37 @param mat SLMaterial* The Material of the lens
38 
39 The diopter of the front side is equal to the sphere. <br>
40 The diopter of the backside is the sum of the spehere and the cylinder. <br>
41 From the diopter, the radius (R1, R2) can be calculated: <br>
42 radiusFront = (LensMaterial - OutsideMaterial) / FrontDiopter) * diameter;<br>
43 radiusBack = (OutsideMaterial - LensMaterial) / BackDiopter) * diameter;<br>
44 */
46  double sphere,
47  double cylinder,
48  SLfloat diameter,
49  SLfloat thickness,
50  SLuint stacks,
51  SLuint slices,
52  SLstring name,
53  SLMaterial* mat) : SLRevolver(assetMgr, name)
54 {
55  assert(slices >= 3 && "Error: Not enough slices.");
56  assert(slices > 0 && "Error: Not enough stacks.");
57 
58  SLfloat diopterBot = (SLfloat)sphere; // D1 = sphere
59  SLfloat diopterTop = (SLfloat)(sphere + cylinder); // D2 = sphere + cylinder
60 
61  initLens(diopterBot, diopterTop, diameter, thickness, stacks, slices, mat);
62 }
63 //-----------------------------------------------------------------------------
64 /*!
65 SLLens::SLLens ctor for lens revolution object around the y-axis. <br>
66 Create the lens with radius.<br>
67 To correct presbyopic (far-sightedness) a converging lens is needed.
68 To correct myopic (short-sightedness) a diverging lens is needed.
69 @image html images/Lens.png
70 
71 @param assetMgr Pointer to the asset manager
72 @param radiusBot The radius of the front side of the lens
73 @param radiusTop The radius of the back side of the lens
74 @param diameter The diameter (h) of the lens
75 @param thickness The space between the primary planes of lens sides (d)
76 @param stacks No. of stacks of the lens
77 @param slices No. of slices in the lens
78 @param name Name of the SLRevolver Mesh
79 @param mat Pointer to the Material of the lens
80 
81 Positive radius creates a convex lens side. <br>
82 Negative radius creates a concave lens side. <br>
83 Setting the radius to 0 creates a plane. <br>
84 Combine the two radius to get the required lens.
85 */
87  SLfloat radiusBot,
88  SLfloat radiusTop,
89  SLfloat diameter,
90  SLfloat thickness,
91  SLuint stacks,
92  SLuint slices,
93  SLstring name,
94  SLMaterial* mat) : SLRevolver(assetMgr, std::move(name))
95 {
96  SLfloat nOut = 1.00; // kn material outside lens
97  SLfloat nLens = mat->kn(); // kn material of the lens
98  SLfloat diopterBot = (SLfloat)((nLens - nOut) * diameter / radiusBot);
99  SLfloat diopterTop = (SLfloat)((nOut - nLens) * diameter / radiusTop);
100 
101  initLens(diopterBot, diopterTop, diameter, thickness, stacks, slices, mat);
102 }
103 //-----------------------------------------------------------------------------
104 /*!
105 @brief Initialize the lens
106 @param diopterBot SLfloat The diopter of the bot (front) part of the lens
107 @param diopterTop SLfloat The diopter of the top (back) part of the lens
108 @param diameter SLfloat The diameter of the lens
109 @param thickness SLfloat d The space between the primary planes of lens sides
110 @param stacks SLint
111 @param slices SLint
112 @param mat SLMaterial* The Material of the lens
113 */
114 void SLLens::initLens(SLfloat diopterBot,
115  SLfloat diopterTop,
116  SLfloat diameter,
117  SLfloat thickness,
118  SLuint stacks,
119  SLuint slices,
120  SLMaterial* mat)
121 {
122  assert(slices >= 3 && "Error: Not enough slices.");
123  assert(slices > 0 && "Error: Not enough stacks.");
124 
125  _diameter = diameter;
126  _thickness = thickness;
127  _stacks = stacks;
128  _slices = slices;
129  _pointOutput = false; // cout the coordinates of each point of the lens
130 
131  // Gullstrand-Formel
132  // D = D1 + D2 - delta * D1 * D2
133 
134  // calc radius
135  SLfloat nOut = 1.00; // kn material outside lens
136  SLfloat nLens = mat->kn(); // kn material of the lens
137 
138  // calc radius
139  _radiusBot = (SLfloat)((nLens - nOut) / diopterBot) * _diameter;
140  _radiusTop = (SLfloat)((nOut - nLens) / diopterTop) * _diameter;
141 
142  if (_pointOutput)
143  cout << " radiusBot: " << _radiusBot << " radiusTop: " << _radiusTop << endl;
144 
145  // generate lens
147 }
148 //-----------------------------------------------------------------------------
149 /*!
150 @brief Generate the lens with given front and back radius
151 @param radiusBot radius of the lens front side
152 @param radiusTop radius of the lens back side
153 @param mat the material pointer that is passed to SLRevolver
154 */
156  SLfloat radiusTop,
157  SLMaterial* mat)
158 {
159  _smoothFirst = true;
160  _smoothLast = true;
161  _revAxis.set(0, 1, 0);
162 
163  if (_diameter > 0)
164  {
165  SLfloat x = generateLensTop(radiusTop);
166  if (x < 0.0001f)
167  buildMesh(mat);
168  else
169  cout << "error in lens calculation: (x = " << x << ")" << endl;
170  }
171  else
172  cout << "invalid lens diameter: " << _diameter << endl;
173 }
174 //-----------------------------------------------------------------------------
175 /*!
176 @brief Generate the bottom (front) part of the lens
177 @param radius of the lens
178 @return x the x coordinate of the last point of the bulge
179 */
181 {
182  // Point
183  SLVec3f p;
184  SLfloat y;
185  SLfloat x = 0;
186 
187  SLfloat sagitta = calcSagitta(radius);
188  SLint halfStacks = _stacks / 2;
189 
190  // check if lens has a deep
191  if ((sagitta >= 0))
192  {
193  SLfloat alphaAsin = _diameter / (2.0f * radius);
194  alphaAsin = Utils::clamp(alphaAsin, -1.0f, 1.0f);
195  SLfloat alphaRAD = 2.0f * (SLfloat)asin(alphaAsin);
196  SLfloat dAlphaRAD = (alphaRAD * 0.5f) / halfStacks;
197  SLfloat yStart1 = -sagitta;
198  SLfloat currentAlphaRAD = -Utils::HALFPI;
199  SLfloat currentAlphaDEG = currentAlphaRAD * Utils::RAD2DEG;
200  SLfloat radiusAmount1 = radius;
201  SLfloat yTranslate1 = radius - sagitta;
202 
203  // settings for negative radius
204  if (radius < 0)
205  {
206  yStart1 = 0;
207  currentAlphaRAD = Utils::HALFPI;
208  radiusAmount1 = -radius;
209  yTranslate1 = radius;
210  }
211 
212  y = yStart1;
213  // set start point
214  p.x = (SLfloat)x;
215  p.y = (SLfloat)y;
216  p.z = 0;
217  _revPoints.push_back(p);
218  if (_pointOutput) cout << currentAlphaDEG << " x: " << x << " y: " << y << endl;
219 
220  // draw bottom part of the lens
221  for (int i = 0; i < halfStacks; i++)
222  {
223  // change angle
224  currentAlphaRAD += dAlphaRAD;
225  currentAlphaDEG = currentAlphaRAD * Utils::RAD2DEG;
226 
227  // calc x
228  x = cos(currentAlphaRAD) * radiusAmount1;
229 
230  // calc y
231  if ((i + 1 == halfStacks) && (radius >= 0))
232  y = 0;
233  else
234  y = ((sin(currentAlphaRAD)) * radiusAmount1 + yTranslate1);
235 
236  if (_pointOutput) cout << currentAlphaDEG << " x: " << x << " y: " << y << endl;
237 
238  // set point
239  p.x = x;
240  p.y = y;
241  p.z = 0;
242  _revPoints.push_back(p);
243  }
244  }
245  else
246  {
247  SLfloat cutX = (_diameter / 2) / halfStacks;
248 
249  // Draw plane
250  for (int i = 0; i <= halfStacks - 1; i++)
251  {
252  x = cutX * i;
253  y = 0;
254 
255  // set point
256  p.x = x;
257  p.y = y;
258  p.z = 0;
259  _revPoints.push_back(p);
260  if (_pointOutput) cout << "0"
261  << " x: " << x << " y: " << y << " _B" << endl;
262  }
263  }
264  return x;
265 }
266 //-----------------------------------------------------------------------------
267 /*!
268 @brief Generate the top (back) part of the lens
269 @param radius of the lens
270 @return x the x coordinate of the last point of the bulge
271 */
273 {
274  // Point
275  SLVec3f p;
276  SLfloat x = _diameter / 2;
277  SLfloat y; // = yStart2;
278 
279  SLfloat sagitta = calcSagitta(radius);
280  SLint halfStacks = _stacks / 2;
281 
282  // check if the lens has a deep
283  if ((sagitta >= 0))
284  {
285  SLfloat yStart2 = _thickness;
286  SLfloat radiusAmount2 = radius;
287  SLfloat yTranslate2 = -radius + sagitta;
288 
289  SLfloat betaAsin = _diameter / (2.0f * radius);
290  betaAsin = (betaAsin > 1) ? 1 : betaAsin; // correct rounding errors
291  betaAsin = (betaAsin < -1) ? -1 : betaAsin; // correct rounding errors
292  SLfloat betaRAD = 2.0f * (SLfloat)asin(betaAsin);
293  SLfloat currentBetaRAD = Utils::HALFPI - (betaRAD * 0.5f);
294 
295  // settings for negative radius
296  if (radius < 0)
297  {
298  currentBetaRAD = -Utils::HALFPI - (betaRAD * 0.5f);
299  yStart2 = sagitta + _thickness;
300  radiusAmount2 = -radius;
301  yTranslate2 = -radius;
302  }
303 
304  SLfloat currentBetaDEG = currentBetaRAD * Utils::RAD2DEG;
305  SLfloat dBetaRAD = (betaRAD * 0.5f) / halfStacks;
306 
307  // set start point
308  y = yStart2;
309  p.x = (SLfloat)x;
310  p.y = (SLfloat)y;
311  p.z = 0;
312  _revPoints.push_back(p);
313  if (_pointOutput) cout << currentBetaDEG << " x: " << x << " y: " << y << endl;
314 
315  // draw top part of the lens
316  for (int i = 0; i < halfStacks; i++)
317  {
318  // change angle
319  currentBetaRAD += dBetaRAD;
320  currentBetaDEG = currentBetaRAD * Utils::RAD2DEG;
321 
322  // calc y
323  y = (((sin(currentBetaRAD)) * (radiusAmount2)) + yTranslate2 + _thickness);
324 
325  // calc x
326  if ((i + 1 == halfStacks))
327  {
328  x = 0;
329  if (radius < 0)
330  y = _thickness;
331  }
332  else
333  x = cos(currentBetaRAD) * radiusAmount2;
334 
335  if (_pointOutput) cout << currentBetaDEG << " x: " << x << " y: " << y << endl;
336 
337  // set point
338  p.x = x;
339  p.y = y;
340  p.z = 0;
341  _revPoints.push_back(p);
342  }
343  }
344  else
345  {
346  SLfloat cutX = x / halfStacks;
347 
348  // Draw plane
349  for (int i = halfStacks - 1; i >= 0; i--)
350  {
351  x = cutX * i;
352  y = _thickness;
353 
354  // set point
355  p.x = x;
356  p.y = y;
357  p.z = 0;
358  _revPoints.push_back(p);
359  if (_pointOutput) cout << "0"
360  << " x: " << x << " y: " << y << " _T" << endl;
361  }
362  }
363  return x;
364 }
365 //-----------------------------------------------------------------------------
366 /*!
367  @brief Calculate the sagitta (s) for a given radius (r) and diameter (l+l)
368  where l is half of the lens diameter
369  See also: http://en.wikipedia.org/wiki/Sagitta_%28geometry%29
370  @param radius r of the lens
371  @return sagitta s of the lens
372  @image html images/sagitta.png
373 */
375 {
376  // take the amount of the radius
377  SLfloat radiusAmount = (radius < 0) ? -radius : radius;
378  SLfloat l = _diameter * 0.5f;
379 
380  // sagitta = radius - sqrt( radius*radius - l*l )
381  // calc this part to sort out negative numbers in square root
382  SLfloat part = radiusAmount * radiusAmount - l * l;
383 
384  // set sagitta negative if no bulge is given -> plane
385  SLfloat sagitta = (part >= 0) ? (radiusAmount - sqrt(part)) : -1;
386  return sagitta;
387 }
388 //-----------------------------------------------------------------------------
float SLfloat
Definition: SL.h:173
unsigned int SLuint
Definition: SL.h:171
string SLstring
Definition: SL.h:158
int SLint
Definition: SL.h:170
Toplevel holder of the assets meshes, materials, textures and shaders.
void initLens(SLfloat diopterBot, SLfloat diopterTop, SLfloat diameter, SLfloat thickness, SLuint stacks, SLuint slices, SLMaterial *mat)
Initialize the lens.
Definition: SLLens.cpp:114
SLfloat _radiusTop
The radius of the top (back) side of the lens.
Definition: SLLens.h:74
SLfloat calcSagitta(SLfloat radius)
Calculate the sagitta (s) for a given radius (r) and diameter (l+l) where l is half of the lens diame...
Definition: SLLens.cpp:374
SLLens(SLAssetManager *assetMgr, double sphere, double cylinder, SLfloat diameter, SLfloat thickness, SLuint stacks=32, SLuint slices=32, SLstring name="lens mesh", SLMaterial *mat=nullptr)
Create a lens with given sphere, cylinder, diameter and thickness.
Definition: SLLens.cpp:45
SLfloat generateLensTop(SLfloat radius)
Generate the top (back) part of the lens.
Definition: SLLens.cpp:272
void generateLens(SLfloat radiusBot, SLfloat radiusTop, SLMaterial *mat)
Generate the lens with given front and back radius.
Definition: SLLens.cpp:155
SLbool _pointOutput
debug helper
Definition: SLLens.h:75
SLfloat _thickness
The space between the primary planes of lens sides.
Definition: SLLens.h:72
SLfloat _diameter
The diameter of the lens.
Definition: SLLens.h:71
SLfloat generateLensBot(SLfloat radius)
Generate the bottom (front) part of the lens.
Definition: SLLens.cpp:180
SLfloat _radiusBot
The radius of the bot (front) side of the lens.
Definition: SLLens.h:73
Defines a standard CG material with textures and a shader program.
Definition: SLMaterial.h:56
void kn(SLfloat kn)
Definition: SLMaterial.h:199
SLMaterial * mat() const
Definition: SLMesh.h:177
SLRevolver is an SLMesh object built out of revolving points.
Definition: SLRevolver.h:38
SLbool _smoothLast
flag if the normal of the last point is eqaual to revAxis
Definition: SLRevolver.h:67
SLVec3f _revAxis
axis of revolution
Definition: SLRevolver.h:59
SLuint stacks()
Definition: SLRevolver.h:54
SLuint slices()
Definition: SLRevolver.h:55
SLbool _smoothFirst
flag if the normal of the first point is eqaual to -revAxis
Definition: SLRevolver.h:64
SLuint _slices
NO. of slices.
Definition: SLRevolver.h:61
void buildMesh(SLMaterial *mat=nullptr)
Definition: SLRevolver.cpp:43
SLVVec3f _revPoints
Array revolving points.
Definition: SLRevolver.h:58
SLuint _stacks
No. of stacks (mostly used)
Definition: SLRevolver.h:60
T y
Definition: SLVec3.h:43
T x
Definition: SLVec3.h:43
void set(const T X, const T Y, const T Z)
Definition: SLVec3.h:59
T z
Definition: SLVec3.h:43
static const float HALFPI
Definition: Utils.h:242
T clamp(T a, T min, T max)
Definition: Utils.h:253
static const float RAD2DEG
Definition: Utils.h:238