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