]> git.mxchange.org Git - flightgear.git/blob - src/Environment/environment.cxx
eed66fa17cd28c5ece0da1d192b53254cc7e79c9
[flightgear.git] / src / Environment / environment.cxx
1 // environment.cxx -- routines to model the natural environment
2 //
3 // Written by David Megginson, started February 2002.
4 //
5 // Copyright (C) 2002  David Megginson - david@megginson.com
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <math.h>
29
30 #include <boost/tuple/tuple.hpp>
31
32 #include <plib/sg.h>
33
34 #include <simgear/constants.h>
35 #include <simgear/debug/logstream.hxx>
36 #include <simgear/math/interpolater.hxx>
37 #include <simgear/props/props.hxx>
38 #include <simgear/environment/visual_enviro.hxx>
39
40 #include <Main/fg_props.hxx>
41 #include <signal.h>
42
43 #include "environment.hxx"
44 #include "atmosphere.hxx"
45
46 \f
47 ////////////////////////////////////////////////////////////////////////
48 // Atmosphere model.
49 ////////////////////////////////////////////////////////////////////////
50
51 #ifdef USING_TABLES
52
53 // Calculated based on the ISA standard day, as found at e.g.
54 // http://www.av8n.com/physics/altimetry.htm
55
56 // Each line of data has 3 elements:
57 //   Elevation (ft), 
58 //   temperature factor (dimensionless ratio of absolute temp), 
59 //   pressure factor (dimensionless ratio)
60 static double atmosphere_data[][3] = {
61  {  -3000.00,   1.021,  1.1133 },
62  {      0.00,   1.000,  1.0000 },
63  {   2952.76,   0.980,  0.8978 },
64  {   5905.51,   0.959,  0.8042 },
65  {   8858.27,   0.939,  0.7187 },
66  {  11811.02,   0.919,  0.6407 },
67  {  14763.78,   0.898,  0.5697 },
68  {  17716.54,   0.878,  0.5052 },
69  {  20669.29,   0.858,  0.4468 },
70  {  23622.05,   0.838,  0.3940 },
71  {  26574.80,   0.817,  0.3463 },
72  {  29527.56,   0.797,  0.3034 },
73  {  32480.31,   0.777,  0.2649 },
74  {  35433.07,   0.756,  0.2305 },
75  {  38385.83,   0.752,  0.2000 },
76  {  41338.58,   0.752,  0.1736 },
77  {  44291.34,   0.752,  0.1506 },
78  {  47244.09,   0.752,  0.1307 },
79  {  50196.85,   0.752,  0.1134 },
80  {  53149.61,   0.752,  0.0984 },
81  {  56102.36,   0.752,  0.0854 },
82  {  59055.12,   0.752,  0.0741 },
83  {  62007.87,   0.752,  0.0643 },
84  {  65000.00,   0.752,  0.0557 },
85  {  68000.00,   0.754,  0.0482 },
86  {  71000.00,   0.758,  0.0418 },
87  {  74000.00,   0.761,  0.0362 },
88  {  77000.00,   0.764,  0.0314 },
89  {  80000.00,   0.767,  0.0273 },
90  {  83000.00,   0.770,  0.0237 },
91  {  86000.00,   0.773,  0.0206 },
92  {  89000.00,   0.777,  0.0179 },
93  {  92000.00,   0.780,  0.0156 },
94  {  95000.00,   0.783,  0.0135 },
95  {  98000.00,   0.786,  0.0118 },
96  { 101000.00,   0.789,  0.0103 },
97  { -1, -1, -1 }
98 };
99
100 static SGInterpTable * _temperature_degc_table = 0;
101 static SGInterpTable * _pressure_inhg_table = 0;
102
103 static void
104 _setup_tables ()
105 {
106   if (_temperature_degc_table != 0)
107       return;
108
109   _temperature_degc_table = new SGInterpTable;
110   _pressure_inhg_table = new SGInterpTable;
111
112   for (int i = 0; atmosphere_data[i][0] != -1; i++) {
113     _temperature_degc_table->addEntry(atmosphere_data[i][0],
114                                       atmosphere_data[i][1]);
115     _pressure_inhg_table->addEntry(atmosphere_data[i][0],
116                                    atmosphere_data[i][2]);
117   }
118 }
119 #endif
120
121 \f
122 ////////////////////////////////////////////////////////////////////////
123 // Implementation of FGEnvironment.
124 ////////////////////////////////////////////////////////////////////////
125
126 void FGEnvironment::_init()
127 {
128     elevation_ft = 0;
129     visibility_m = 32000;
130     temperature_sea_level_degc = 15;
131     temperature_degc = 15;
132     dewpoint_sea_level_degc = 5; // guess
133     dewpoint_degc = 5;
134     pressure_sea_level_inhg = 29.92;
135     pressure_inhg = 29.92;
136     turbulence_magnitude_norm = 0;
137     turbulence_rate_hz = 1;
138     wind_from_heading_deg = 0;
139     wind_speed_kt = 0;
140     wind_from_north_fps = 0;
141     wind_from_east_fps = 0;
142     wind_from_down_fps = 0;
143     altitude_half_to_sun_m = 1000;
144     altitude_tropo_top_m = 10000;
145 #ifdef USING_TABLES
146     _setup_tables();
147 #endif
148     _recalc_density();
149     _recalc_relative_humidity();
150     
151 }
152
153 FGEnvironment::FGEnvironment()
154 {
155     _init();
156 }
157
158 FGEnvironment::FGEnvironment (const FGEnvironment &env)
159 {
160     _init();
161     copy(env);
162 }
163
164 FGEnvironment::~FGEnvironment()
165 {
166 }
167
168 void
169 FGEnvironment::copy (const FGEnvironment &env)
170 {
171     elevation_ft = env.elevation_ft;
172     visibility_m = env.visibility_m;
173     temperature_sea_level_degc = env.temperature_sea_level_degc;
174     temperature_degc = env.temperature_degc;
175     dewpoint_sea_level_degc = env.dewpoint_sea_level_degc;
176     dewpoint_degc = env.dewpoint_degc;
177     pressure_sea_level_inhg = env.pressure_sea_level_inhg;
178     wind_from_heading_deg = env.wind_from_heading_deg;
179     wind_speed_kt = env.wind_speed_kt;
180     wind_from_north_fps = env.wind_from_north_fps;
181     wind_from_east_fps = env.wind_from_east_fps;
182     wind_from_down_fps = env.wind_from_down_fps;
183     turbulence_magnitude_norm = env.turbulence_magnitude_norm;
184     turbulence_rate_hz = env.turbulence_rate_hz;
185 }
186
187 static inline bool
188 maybe_copy_value (FGEnvironment * env, const SGPropertyNode * node,
189                   const char * name, void (FGEnvironment::*setter)(double))
190 {
191     const SGPropertyNode * child = node->getNode(name);
192                                 // fragile: depends on not being typed
193                                 // as a number
194     if (child != 0 && child->hasValue() &&
195         child->getStringValue()[0] != '\0') {
196         (env->*setter)(child->getDoubleValue());
197         return true;
198     } else {
199         return false;
200     }
201 }
202
203 void
204 FGEnvironment::read (const SGPropertyNode * node)
205 {
206     maybe_copy_value(this, node, "visibility-m",
207                      &FGEnvironment::set_visibility_m);
208
209     if (!maybe_copy_value(this, node, "temperature-sea-level-degc",
210                           &FGEnvironment::set_temperature_sea_level_degc))
211         maybe_copy_value(this, node, "temperature-degc",
212                          &FGEnvironment::set_temperature_degc);
213
214     if (!maybe_copy_value(this, node, "dewpoint-sea-level-degc",
215                           &FGEnvironment::set_dewpoint_sea_level_degc))
216         maybe_copy_value(this, node, "dewpoint-degc",
217                          &FGEnvironment::set_dewpoint_degc);
218
219     if (!maybe_copy_value(this, node, "pressure-sea-level-inhg",
220                           &FGEnvironment::set_pressure_sea_level_inhg))
221         maybe_copy_value(this, node, "pressure-inhg",
222                          &FGEnvironment::set_pressure_inhg);
223
224     maybe_copy_value(this, node, "wind-from-heading-deg",
225                      &FGEnvironment::set_wind_from_heading_deg);
226
227     maybe_copy_value(this, node, "wind-speed-kt",
228                      &FGEnvironment::set_wind_speed_kt);
229
230     maybe_copy_value(this, node, "elevation-ft",
231                      &FGEnvironment::set_elevation_ft);
232
233     maybe_copy_value(this, node, "turbulence/magnitude-norm",
234                      &FGEnvironment::set_turbulence_magnitude_norm);
235
236     maybe_copy_value(this, node, "turbulence/rate-hz",
237                      &FGEnvironment::set_turbulence_rate_hz);
238 }
239
240
241 double
242 FGEnvironment::get_visibility_m () const
243 {
244   return visibility_m;
245 }
246
247 double
248 FGEnvironment::get_temperature_sea_level_degc () const
249 {
250   return temperature_sea_level_degc;
251 }
252
253 double
254 FGEnvironment::get_temperature_degc () const
255 {
256   return temperature_degc;
257 }
258
259 double
260 FGEnvironment::get_temperature_degf () const
261 {
262   return (temperature_degc * 9.0 / 5.0) + 32.0;
263 }
264
265 double
266 FGEnvironment::get_dewpoint_sea_level_degc () const
267 {
268   return dewpoint_sea_level_degc;
269 }
270
271 double
272 FGEnvironment::get_dewpoint_degc () const
273 {
274   return dewpoint_degc;
275 }
276
277 double
278 FGEnvironment::get_pressure_sea_level_inhg () const
279 {
280   return pressure_sea_level_inhg;
281 }
282
283 double
284 FGEnvironment::get_pressure_inhg () const
285 {
286   return pressure_inhg;
287 }
288
289 double
290 FGEnvironment::get_density_slugft3 () const
291 {
292   return density_slugft3;
293 }
294
295 double
296 FGEnvironment::get_relative_humidity () const
297 {
298   return relative_humidity;
299 }
300
301 double
302 FGEnvironment::get_density_tropo_avg_kgm3 () const
303 {
304   return density_tropo_avg_kgm3;
305 }
306
307 double
308 FGEnvironment::get_altitude_half_to_sun_m () const
309 {
310   return altitude_half_to_sun_m;
311 }
312
313 double
314 FGEnvironment::get_altitude_tropo_top_m () const
315 {
316   return altitude_tropo_top_m;
317 }
318
319 double
320 FGEnvironment::get_wind_from_heading_deg () const
321 {
322   return wind_from_heading_deg;
323 }
324
325 double
326 FGEnvironment::get_wind_speed_kt () const
327 {
328   return wind_speed_kt;
329 }
330
331 double
332 FGEnvironment::get_wind_from_north_fps () const
333 {
334   return wind_from_north_fps;
335 }
336
337 double
338 FGEnvironment::get_wind_from_east_fps () const
339 {
340   return wind_from_east_fps;
341 }
342
343 double
344 FGEnvironment::get_wind_from_down_fps () const
345 {
346   return wind_from_down_fps;
347 }
348
349 double
350 FGEnvironment::get_turbulence_magnitude_norm () const
351 {
352   if( sgEnviro.get_turbulence_enable_state() )
353     if (fgGetBool("/environment/params/real-world-weather-fetch") == true)
354       return sgEnviro.get_cloud_turbulence();
355   return turbulence_magnitude_norm;
356 }
357
358 double
359 FGEnvironment::get_turbulence_rate_hz () const
360 {
361   return turbulence_rate_hz;
362 }
363
364 double
365 FGEnvironment::get_elevation_ft () const
366 {
367   return elevation_ft;
368 }
369
370 void
371 FGEnvironment::set_visibility_m (double v)
372 {
373   visibility_m = v;
374 }
375
376 void
377 FGEnvironment::set_temperature_sea_level_degc (double t)
378 {
379   temperature_sea_level_degc = t;
380   if (dewpoint_sea_level_degc > t)
381       dewpoint_sea_level_degc = t;
382   _recalc_alt_pt();
383   _recalc_density();
384 }
385
386 void
387 FGEnvironment::set_temperature_degc (double t)
388 {
389   temperature_degc = t;
390   _recalc_sl_temperature();
391   _recalc_sl_pressure();
392   _recalc_alt_pt();
393   _recalc_density();
394   _recalc_relative_humidity();
395 }
396
397 void
398 FGEnvironment::set_dewpoint_sea_level_degc (double t)
399 {
400   dewpoint_sea_level_degc = t;
401   if (temperature_sea_level_degc < t)
402       temperature_sea_level_degc = t;
403   _recalc_alt_dewpoint();
404   _recalc_density();
405 }
406
407 void
408 FGEnvironment::set_dewpoint_degc (double t)
409 {
410   dewpoint_degc = t;
411   _recalc_sl_dewpoint();
412   _recalc_density();
413   _recalc_relative_humidity();
414 }
415
416 void
417 FGEnvironment::set_pressure_sea_level_inhg (double p)
418 {
419   pressure_sea_level_inhg = p;
420   _recalc_alt_pt();
421   _recalc_density();
422 }
423
424 void
425 FGEnvironment::set_pressure_inhg (double p)
426 {
427   pressure_inhg = p;
428   _recalc_sl_pressure();
429   _recalc_density();
430 }
431
432 void
433 FGEnvironment::set_wind_from_heading_deg (double h)
434 {
435   wind_from_heading_deg = h;
436   _recalc_ne();
437 }
438
439 void
440 FGEnvironment::set_wind_speed_kt (double s)
441 {
442   wind_speed_kt = s;
443   _recalc_ne();
444 }
445
446 void
447 FGEnvironment::set_wind_from_north_fps (double n)
448 {
449   wind_from_north_fps = n;
450   _recalc_hdgspd();
451 }
452
453 void
454 FGEnvironment::set_wind_from_east_fps (double e)
455 {
456   wind_from_east_fps = e;
457   _recalc_hdgspd();
458 }
459
460 void
461 FGEnvironment::set_wind_from_down_fps (double d)
462 {
463   wind_from_down_fps = d;
464   _recalc_hdgspd();
465 }
466
467 void
468 FGEnvironment::set_turbulence_magnitude_norm (double t)
469 {
470   turbulence_magnitude_norm = t;
471 }
472
473 void
474 FGEnvironment::set_turbulence_rate_hz (double r)
475 {
476   turbulence_rate_hz = r;
477 }
478
479 void
480 FGEnvironment::set_elevation_ft (double e)
481 {
482   elevation_ft = e;
483   _recalc_alt_dewpoint();
484   _recalc_alt_pt();
485   _recalc_density();
486   _recalc_relative_humidity();
487 }
488
489 void
490 FGEnvironment::set_altitude_half_to_sun_m (double alt)
491 {
492  altitude_half_to_sun_m = alt;
493  _recalc_density_tropo_avg_kgm3();
494 }
495
496 void
497 FGEnvironment::set_altitude_tropo_top_m (double alt)
498 {
499  altitude_tropo_top_m = alt;
500  _recalc_density_tropo_avg_kgm3();
501 }
502
503
504 void
505 FGEnvironment::_recalc_hdgspd ()
506 {
507   double angle_rad;
508
509   if (wind_from_east_fps == 0) {
510     angle_rad = (wind_from_north_fps >= 0 ? SGD_PI_2 : -SGD_PI_2);
511   } else {
512     angle_rad = atan(wind_from_north_fps/wind_from_east_fps);
513   }
514   wind_from_heading_deg = angle_rad * SGD_RADIANS_TO_DEGREES;
515   if (wind_from_east_fps >= 0)
516     wind_from_heading_deg = 90 - wind_from_heading_deg;
517   else
518     wind_from_heading_deg = 270 - wind_from_heading_deg;
519
520 #if 0
521   // FIXME: Windspeed can become negative with these formulas.
522   //        which can cause problems for animations that rely
523   //        on the windspeed property.
524   if (angle_rad == 0)
525     wind_speed_kt = fabs(wind_from_east_fps
526                          * SG_METER_TO_NM * SG_FEET_TO_METER * 3600);
527   else
528     wind_speed_kt = (wind_from_north_fps / sin(angle_rad))
529       * SG_METER_TO_NM * SG_FEET_TO_METER * 3600;
530 #else
531   wind_speed_kt = sqrt(wind_from_north_fps * wind_from_north_fps +
532                        wind_from_east_fps * wind_from_east_fps) 
533                   * SG_METER_TO_NM * SG_FEET_TO_METER * 3600;
534 #endif
535 }
536
537 void
538 FGEnvironment::_recalc_ne ()
539 {
540   double speed_fps =
541     wind_speed_kt * SG_NM_TO_METER * SG_METER_TO_FEET * (1.0/3600);
542
543   wind_from_north_fps = speed_fps *
544     cos(wind_from_heading_deg * SGD_DEGREES_TO_RADIANS);
545   wind_from_east_fps = speed_fps *
546     sin(wind_from_heading_deg * SGD_DEGREES_TO_RADIANS);
547 }
548
549 // Intended to help with the interpretation of METAR data,
550 // not for random in-flight outside-air temperatures.
551 void
552 FGEnvironment::_recalc_sl_temperature ()
553 {
554
555 #if 0
556   {
557     SG_LOG(SG_GENERAL, SG_DEBUG, "recalc_sl_temperature: using "
558       << temperature_degc << " @ " << elevation_ft << " :: " << this);
559   }
560 #endif
561
562   if (elevation_ft >= ISA_def[1].height) {
563     SG_LOG(SG_GENERAL, SG_ALERT, "recalc_sl_temperature: "
564         << "valid only in troposphere, not " << elevation_ft);
565     return;
566   }
567
568 // Clamp: temperature of the stratosphere, in degrees C:
569   double t_strato = ISA_def[1].temp - atmodel::freezing;
570   if (temperature_degc < t_strato) temperature_sea_level_degc = t_strato;
571   else temperature_sea_level_degc = 
572       temperature_degc - elevation_ft * ISA_def[0].lapse;
573
574 // Alternative implemenation:
575 //  else temperature_sea_level_inhg = T_layer(0., elevation_ft * foot,
576 //      pressure_inhg * inHg, temperature_degc + freezing, ISA_def[0].lapse) - freezing;
577 }
578
579 void
580 FGEnvironment::_recalc_sl_dewpoint ()
581 {
582                                 // 0.2degC/1000ft
583                                 // FIXME: this will work only for low
584                                 // elevations
585   dewpoint_sea_level_degc = dewpoint_degc + (elevation_ft * .0002);
586   if (dewpoint_sea_level_degc > temperature_sea_level_degc)
587     dewpoint_sea_level_degc = temperature_sea_level_degc;
588 }
589
590 void
591 FGEnvironment::_recalc_alt_dewpoint ()
592 {
593                                 // 0.2degC/1000ft
594                                 // FIXME: this will work only for low
595                                 // elevations
596   dewpoint_degc = dewpoint_sea_level_degc + (elevation_ft * .0002);
597   if (dewpoint_degc > temperature_degc)
598     dewpoint_degc = temperature_degc;
599 }
600
601 void
602 FGEnvironment::_recalc_sl_pressure ()
603 {
604   using namespace atmodel;
605 #if 0
606   {
607     SG_LOG(SG_GENERAL, SG_ALERT, "recalc_sl_pressure: using "
608       << pressure_inhg << " and "
609       << temperature_degc << " @ " << elevation_ft << " :: " << this);
610   }
611 #endif
612   pressure_sea_level_inhg = P_layer(0., elevation_ft * foot,
613       pressure_inhg * inHg, temperature_degc + freezing, ISA_def[0].lapse) / inHg;
614 }
615
616 // This gets called at frame rate, to account for the aircraft's
617 // changing altitude. 
618 // Called by set_elevation_ft() which is called by FGEnvironmentMgr::update
619
620 void
621 FGEnvironment::_recalc_alt_pt ()
622 {
623   using namespace atmodel;
624 #if 0
625   {
626     static int count(0);
627     if (++count % 1000 == 0) {
628       SG_LOG(SG_GENERAL, SG_ALERT, 
629            "recalc_alt_pt for: " << elevation_ft
630         << "  using "  << pressure_sea_level_inhg 
631         << "  and "  << temperature_sea_level_degc
632         << " :: " << this
633         << "  # " << count);
634         ///////////////////////////////////raise(SIGUSR1);
635     }
636   }
637 #endif
638   double press, temp;
639   boost::tie(press, temp) = PT_vs_hpt(elevation_ft * foot, 
640         pressure_sea_level_inhg * inHg, temperature_sea_level_degc + freezing);
641   temperature_degc = temp - freezing;
642   pressure_inhg = press / inHg;
643 }
644
645 void
646 FGEnvironment::_recalc_density ()
647 {
648   double pressure_psf = pressure_inhg * 70.7487;
649   
650   // adjust for humidity
651   // calculations taken from USA Today (oops!) at
652   // http://www.usatoday.com/weather/basics/density-calculations.htm
653   double temperature_degk = temperature_degc + 273.15;
654   double pressure_mb = pressure_inhg * 33.86;
655   double vapor_pressure_mb =
656     6.11 * pow(10.0, 7.5 * dewpoint_degc / (237.7 + dewpoint_degc));
657   double virtual_temperature_degk = temperature_degk / (1 - (vapor_pressure_mb / pressure_mb) * (1.0 - 0.622));
658   double virtual_temperature_degr = virtual_temperature_degk * 1.8;
659
660   density_slugft3 = pressure_psf / (virtual_temperature_degr * 1718);
661   _recalc_density_tropo_avg_kgm3();
662 }
663
664 // This is used to calculate the average density on the path 
665 // of sunlight to the observer for calculating sun-color
666 void
667 FGEnvironment::_recalc_density_tropo_avg_kgm3 ()
668 {
669   double pressure_mb = pressure_inhg * 33.86;
670   double vaporpressure = 6.11 * pow(10.0, ((7.5 * dewpoint_degc) / (237.7 + dewpoint_degc)));
671
672   double virtual_temp = (temperature_degc + 273.15) / (1 - 0.379 * (vaporpressure/pressure_mb));
673
674   double density_half = (100 * pressure_mb * exp(-altitude_half_to_sun_m / 8000))
675       / (287.05 * virtual_temp);
676   double density_tropo = (100 * pressure_mb * exp((-1 * altitude_tropo_top_m) / 8000))
677       / ( 287.05 * virtual_temp);
678
679   density_tropo_avg_kgm3 = ((density_slugft3 * 515.379) + density_half + density_tropo) / 3;
680 }
681
682 void
683 FGEnvironment::_recalc_relative_humidity ()
684 {
685   double vaporpressure = 6.11 * pow(10.0, ((7.5 * dewpoint_degc) / ( 237.7 + dewpoint_degc)));
686   double sat_vaporpressure = 6.11 * pow(10.0, ((7.5 * temperature_degc)
687       / ( 237.7 + temperature_degc)) );
688   relative_humidity = 100 * vaporpressure / sat_vaporpressure ;
689 }
690
691
692
693 ////////////////////////////////////////////////////////////////////////
694 // Functions.
695 ////////////////////////////////////////////////////////////////////////
696
697 static inline double
698 do_interp (double a, double b, double fraction)
699 {
700     double retval = (a + ((b - a) * fraction));
701     return retval;
702 }
703
704 static inline double
705 do_interp_deg (double a, double b, double fraction)
706 {
707     a = fmod(a, 360);
708     b = fmod(b, 360);
709     if (fabs(b-a) > 180) {
710         if (a < b)
711             a += 360;
712         else
713             b += 360;
714     }
715     return fmod(do_interp(a, b, fraction), 360);
716 }
717
718 void
719 interpolate (const FGEnvironment * env1, const FGEnvironment * env2,
720              double fraction, FGEnvironment * result)
721 {
722     result->set_visibility_m
723         (do_interp(env1->get_visibility_m(),
724                    env2->get_visibility_m(),
725                    fraction));
726
727     result->set_temperature_sea_level_degc
728         (do_interp(env1->get_temperature_sea_level_degc(),
729                    env2->get_temperature_sea_level_degc(),
730                    fraction));
731
732     result->set_dewpoint_degc
733         (do_interp(env1->get_dewpoint_sea_level_degc(),
734                    env2->get_dewpoint_sea_level_degc(),
735                    fraction));
736
737     result->set_pressure_sea_level_inhg
738         (do_interp(env1->get_pressure_sea_level_inhg(),
739                    env2->get_pressure_sea_level_inhg(),
740                    fraction));
741
742     result->set_wind_from_heading_deg
743         (do_interp_deg(env1->get_wind_from_heading_deg(),
744                        env2->get_wind_from_heading_deg(),
745                        fraction));
746
747     result->set_wind_speed_kt
748         (do_interp(env1->get_wind_speed_kt(),
749                    env2->get_wind_speed_kt(),
750                    fraction));
751
752     result->set_elevation_ft
753         (do_interp(env1->get_elevation_ft(),
754                    env2->get_elevation_ft(),
755                    fraction));
756
757     result->set_turbulence_magnitude_norm
758         (do_interp(env1->get_turbulence_magnitude_norm(),
759                    env2->get_turbulence_magnitude_norm(),
760                    fraction));
761
762     result->set_turbulence_rate_hz
763         (do_interp(env1->get_turbulence_rate_hz(),
764                    env2->get_turbulence_rate_hz(),
765                    fraction));
766 }
767
768 // end of environment.cxx