2017-05-25 10:57:06 +00:00
// SPDX-License-Identifier: GPL-2.0
2024-03-07 10:09:40 +00:00
/* plannernotes.cpp
2017-05-25 10:57:06 +00:00
*
2024-03-08 09:44:20 +00:00
* format notes describing a dive plan
2017-05-25 10:57:06 +00:00
*
* ( c ) Dirk Hohndel 2013
*/
# include <assert.h>
# include <unistd.h>
# include <ctype.h>
# include <string.h>
2023-12-03 21:59:21 +00:00
# include <stdlib.h>
2017-05-25 10:57:06 +00:00
# include "deco.h"
2024-06-18 20:23:57 +00:00
# include "dive.h"
# include "divelist.h"
# include "divelog.h"
2024-05-25 06:16:57 +00:00
# include "event.h"
2019-05-15 16:39:29 +00:00
# include "units.h"
2017-05-25 10:57:06 +00:00
# include "planner.h"
2024-05-28 19:31:11 +00:00
# include "range.h"
2017-05-25 10:57:06 +00:00
# include "gettext.h"
# include "libdivecomputer/parser.h"
2018-02-24 22:28:13 +00:00
# include "qthelper.h"
2018-03-14 19:37:19 +00:00
# include "format.h"
2024-03-08 09:44:20 +00:00
# include "subsurface-string.h"
2017-05-25 10:57:06 +00:00
# include "version.h"
2018-03-13 20:39:20 +00:00
static int diveplan_duration ( struct diveplan * diveplan )
2017-05-25 10:57:06 +00:00
{
struct divedatapoint * dp = diveplan - > dp ;
int duration = 0 ;
2019-03-20 15:29:27 +00:00
int lastdepth = 0 ;
2017-05-25 10:57:06 +00:00
while ( dp ) {
2019-03-20 15:29:27 +00:00
if ( dp - > time > duration & & ( dp - > depth . mm > SURFACE_THRESHOLD | | lastdepth > SURFACE_THRESHOLD ) ) {
2017-05-25 10:57:06 +00:00
duration = dp - > time ;
2019-03-20 15:29:27 +00:00
lastdepth = dp - > depth . mm ;
}
2017-05-25 10:57:06 +00:00
dp = dp - > next ;
}
2017-11-28 13:59:36 +00:00
return ( duration + 30 ) / 60 ;
2017-05-25 10:57:06 +00:00
}
2018-01-15 07:43:57 +00:00
/* Add the icd results of one trimix gas change to the dive plan html buffer. Two rows are added to the table, one
* indicating fractions of gas , the other indication partial pressures of gas . This function makes use of the
* icd_data structure that was filled with information by the function isobaric_counterdiffusion ( ) .
* Parameters : 1 ) Pointer to the output buffer position at which writing should start .
* 2 ) The size of the part of the unused output buffer that remains unused .
* 3 ) The data structure containing icd calculation results : icdvalues .
2018-01-28 15:44:54 +00:00
* 4 ) A boolean value indicating whether a table header should be written before the data . Only during 1 st call .
* 5 ) Pointers to gas mixes in the gas change : gas - from and gas - to .
2018-01-15 07:43:57 +00:00
* Returns : The size of the output buffer that has been used after the new results have been added .
*/
2024-03-08 09:44:20 +00:00
static std : : string icd_entry ( struct icd_data * icdvalues , bool printheader , int time_seconds , int ambientpressure_mbar , struct gasmix gas_from , struct gasmix gas_to )
2018-01-15 07:43:57 +00:00
{
2024-03-08 09:44:20 +00:00
std : : string b ;
2018-01-28 15:44:54 +00:00
if ( printheader ) { // Create a table description and a table header if no icd data have been written yet.
2024-03-08 09:44:20 +00:00
b + = format_string_std ( " <div>%s: " , translate ( " gettextFromC " , " Isobaric counterdiffusion information " ) ) ;
b + = format_string_std ( " <table><tr><td align='left'><b>%s</b></td> " , translate ( " gettextFromC " , " runtime " ) ) ;
b + = format_string_std ( " <td align='center'><b>%s</b></td> " , translate ( " gettextFromC " , " gaschange " ) ) ;
b + = format_string_std ( " <td style='padding-left: 15px;'><b>%s</b></td> " , translate ( " gettextFromC " , " ΔHe " ) ) ;
b + = format_string_std ( " <td style='padding-left: 20px;'><b>%s</b></td> " , translate ( " gettextFromC " , " ΔN₂ " ) ) ;
b + = format_string_std ( " <td style='padding-left: 10px;'><b>%s</b></td></tr> " , translate ( " gettextFromC " , " max ΔN₂ " ) ) ;
2018-01-28 15:44:54 +00:00
} // Add one entry to the icd table:
2024-03-08 09:44:20 +00:00
b + = casprintf_loc (
2018-01-20 10:56:04 +00:00
" <tr><td rowspan='2' style= 'vertical-align:top;'>%3d%s</td> "
" <td rowspan=2 style= 'vertical-align:top;'>%s➙ " ,
( time_seconds + 30 ) / 60 , translate ( " gettextFromC " , " min " ) , gasname ( gas_from ) ) ;
2024-03-08 09:44:20 +00:00
b + = casprintf_loc (
2018-01-24 19:50:35 +00:00
" %s</td><td style='padding-left: 10px;'>%+5.1f%%</td> "
" <td style= 'padding-left: 15px; color:%s;'>%+5.1f%%</td> "
" <td style='padding-left: 15px;'>%+5.1f%%</td></tr> "
2018-01-20 10:56:04 +00:00
" <tr><td style='padding-left: 10px;'>%+5.2f%s</td> "
" <td style='padding-left: 15px; color:%s;'>%+5.2f%s</td> "
" <td style='padding-left: 15px;'>%+5.2f%s</td></tr> " ,
2018-02-24 13:46:04 +00:00
gasname ( gas_to ) , icdvalues - > dHe / 10.0 ,
( ( 5 * icdvalues - > dN2 ) > - icdvalues - > dHe ) ? " red " : " #383838 " , icdvalues - > dN2 / 10.0 , 0.2 * ( - icdvalues - > dHe / 10.0 ) ,
2018-01-24 19:50:35 +00:00
ambientpressure_mbar * icdvalues - > dHe / 1e6 f , translate ( " gettextFromC " , " bar " ) , ( ( 5 * icdvalues - > dN2 ) > - icdvalues - > dHe ) ? " red " : " #383838 " ,
2018-02-24 13:46:04 +00:00
ambientpressure_mbar * icdvalues - > dN2 / 1e6 f , translate ( " gettextFromC " , " bar " ) ,
2018-01-24 19:50:35 +00:00
ambientpressure_mbar * - icdvalues - > dHe / 5e6 f , translate ( " gettextFromC " , " bar " ) ) ;
2024-03-08 09:44:20 +00:00
return b ;
2018-01-15 07:43:57 +00:00
}
2017-05-25 10:57:06 +00:00
2024-05-04 16:45:55 +00:00
const char * get_planner_disclaimer ( )
2019-09-01 15:52:25 +00:00
{
return translate ( " gettextFromC " , " DISCLAIMER / WARNING: THIS IMPLEMENTATION OF THE %s "
" ALGORITHM AND A DIVE PLANNER IMPLEMENTATION BASED ON THAT HAS "
" RECEIVED ONLY A LIMITED AMOUNT OF TESTING. WE STRONGLY RECOMMEND NOT TO "
" PLAN DIVES SIMPLY BASED ON THE RESULTS GIVEN HERE. " ) ;
}
2019-09-10 13:29:03 +00:00
/* Returns newly allocated buffer. Must be freed by caller */
2024-03-08 09:44:20 +00:00
extern std : : string get_planner_disclaimer_formatted ( )
2019-09-10 13:29:03 +00:00
{
2021-02-12 17:19:24 +00:00
const char * deco = decoMode ( true ) = = VPMB ? translate ( " gettextFromC " , " VPM-B " )
: translate ( " gettextFromC " , " BUHLMANN " ) ;
2024-03-08 09:44:20 +00:00
return format_string_std ( get_planner_disclaimer ( ) , deco ) ;
2019-09-10 13:29:03 +00:00
}
2024-05-04 16:45:55 +00:00
void add_plan_to_notes ( struct diveplan * diveplan , struct dive * dive , bool show_disclaimer , bool error )
2017-05-25 10:57:06 +00:00
{
2024-03-08 09:44:20 +00:00
std : : string buf ;
std : : string icdbuf ;
2019-09-10 13:29:03 +00:00
const char * segmentsymbol ;
2018-03-14 06:50:04 +00:00
int lastdepth = 0 , lasttime = 0 , lastsetpoint = - 1 , newdepth = 0 , lastprintdepth = 0 , lastprintsetpoint = - 1 ;
2018-09-10 18:40:25 +00:00
struct gasmix lastprintgasmix = gasmix_invalid ;
2017-05-25 10:57:06 +00:00
struct divedatapoint * dp = diveplan - > dp ;
bool plan_verbatim = prefs . verbatim_plan ;
bool plan_display_runtime = prefs . display_runtime ;
bool plan_display_duration = prefs . display_duration ;
bool plan_display_transitions = prefs . display_transitions ;
bool gaschange_after = ! plan_verbatim ;
bool gaschange_before ;
2018-06-17 21:20:59 +00:00
bool rebreatherchange_after = ! plan_verbatim ;
bool rebreatherchange_before ;
enum divemode_t lastdivemode = UNDEF_COMP_TYPE ;
2017-05-25 10:57:06 +00:00
bool lastentered = true ;
2018-01-28 15:44:54 +00:00
bool icdwarning = false , icdtableheader = true ;
2017-05-25 10:57:06 +00:00
struct divedatapoint * nextdp = NULL ;
struct divedatapoint * lastbottomdp = NULL ;
2018-01-15 07:43:57 +00:00
struct icd_data icdvalues ;
2017-05-25 10:57:06 +00:00
2018-01-15 07:43:57 +00:00
if ( ! dp )
2018-03-14 06:50:04 +00:00
return ;
2017-05-25 10:57:06 +00:00
if ( error ) {
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " <span style='color: red;'>%s </span> %s<br/> " ,
2018-03-14 06:50:04 +00:00
translate ( " gettextFromC " , " Warning: " ) ,
translate ( " gettextFromC " , " Decompression calculation aborted due to excessive time " ) ) ;
2024-03-08 09:44:20 +00:00
// TODO: avoid copy
2024-05-29 18:40:18 +00:00
dive - > notes = buf ;
2024-03-08 09:44:20 +00:00
return ;
2017-05-25 10:57:06 +00:00
}
2018-03-14 06:50:04 +00:00
if ( show_disclaimer ) {
2024-03-08 09:44:20 +00:00
buf + = " <div><b> " ;
buf + = get_planner_disclaimer_formatted ( ) ;
buf + = " </b><br/> \n </div> \n " ;
2018-03-14 06:50:04 +00:00
}
2017-05-25 10:57:06 +00:00
2024-03-08 09:44:20 +00:00
buf + = " <div> \n <b> " ;
2017-10-02 09:17:10 +00:00
if ( diveplan - > surface_interval < 0 ) {
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " %s (%s) %s " ,
2018-01-11 13:11:45 +00:00
translate ( " gettextFromC " , " Subsurface " ) ,
subsurface_canonical_version ( ) ,
translate ( " gettextFromC " , " dive plan</b> (overlapping dives detected) " ) ) ;
2024-03-08 09:44:20 +00:00
// TODO: avoid copy
2024-05-29 18:40:18 +00:00
dive - > notes = buf ;
2024-03-08 09:44:20 +00:00
return ;
2017-10-02 09:17:10 +00:00
} else if ( diveplan - > surface_interval > = 48 * 60 * 60 ) {
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " %s (%s) %s %s " ,
2018-01-11 13:11:45 +00:00
translate ( " gettextFromC " , " Subsurface " ) ,
subsurface_canonical_version ( ) ,
translate ( " gettextFromC " , " dive plan</b> created on " ) ,
2024-03-08 09:44:20 +00:00
get_current_date ( ) . c_str ( ) ) ;
2017-10-02 09:17:10 +00:00
} else {
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( " %s (%s) %s %d:%02d) %s %s " ,
2018-01-11 13:11:45 +00:00
translate ( " gettextFromC " , " Subsurface " ) ,
subsurface_canonical_version ( ) ,
translate ( " gettextFromC " , " dive plan</b> (surface interval " ) ,
2024-05-01 09:01:06 +00:00
FRACTION_TUPLE ( diveplan - > surface_interval / 60 , 60 ) ,
2018-01-11 13:11:45 +00:00
translate ( " gettextFromC " , " created on " ) ,
2024-03-08 09:44:20 +00:00
get_current_date ( ) . c_str ( ) ) ;
2017-05-25 10:57:06 +00:00
}
2024-03-08 09:44:20 +00:00
buf + = " <br/> \n " ;
2017-05-25 10:57:06 +00:00
2021-02-12 17:19:24 +00:00
if ( prefs . display_variations & & decoMode ( true ) ! = RECREATIONAL )
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( translate ( " gettextFromC " , " Runtime: %dmin%s " ) ,
2019-08-28 08:37:33 +00:00
diveplan_duration ( diveplan ) , " VARIATIONS " ) ;
2017-09-18 14:10:47 +00:00
else
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( translate ( " gettextFromC " , " Runtime: %dmin%s " ) ,
2019-08-28 08:37:33 +00:00
diveplan_duration ( diveplan ) , " " ) ;
2024-03-08 09:44:20 +00:00
buf + = " <br/> \n </div> \n " ;
2017-09-18 14:10:47 +00:00
2017-05-25 10:57:06 +00:00
if ( ! plan_verbatim ) {
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " <table> \n <thead> \n <tr><th></th><th>%s</th> " , translate ( " gettextFromC " , " depth " ) ) ;
2017-05-25 10:57:06 +00:00
if ( plan_display_duration )
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " <th style='padding-left: 10px;'>%s</th> " , translate ( " gettextFromC " , " duration " ) ) ;
2017-05-25 10:57:06 +00:00
if ( plan_display_runtime )
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " <th style='padding-left: 10px;'>%s</th> " , translate ( " gettextFromC " , " runtime " ) ) ;
buf + = format_string_std ( " <th style='padding-left: 10px; float: left;'>%s</th></tr> \n </thead> \n <tbody style='float: left;'> \n " ,
2017-05-25 10:57:06 +00:00
translate ( " gettextFromC " , " gas " ) ) ;
}
2018-01-15 07:43:57 +00:00
2017-05-25 10:57:06 +00:00
do {
struct gasmix gasmix , newgasmix = { } ;
const char * depth_unit ;
double depthvalue ;
int decimals ;
bool isascent = ( dp - > depth . mm < lastdepth ) ;
nextdp = dp - > next ;
if ( dp - > time = = 0 )
continue ;
2024-06-25 05:43:32 +00:00
gasmix = dive - > get_cylinder ( dp - > cylinderid ) - > gasmix ;
2017-05-25 10:57:06 +00:00
depthvalue = get_depth_units ( dp - > depth . mm , & decimals , & depth_unit ) ;
/* analyze the dive points ahead */
while ( nextdp & & nextdp - > time = = 0 )
nextdp = nextdp - > next ;
if ( nextdp )
2024-06-25 05:43:32 +00:00
newgasmix = dive - > get_cylinder ( nextdp - > cylinderid ) - > gasmix ;
2018-08-16 17:10:10 +00:00
gaschange_after = ( nextdp & & ( gasmix_distance ( gasmix , newgasmix ) ) ) ;
gaschange_before = ( gasmix_distance ( lastprintgasmix , gasmix ) ) ;
2018-06-17 21:20:59 +00:00
rebreatherchange_after = ( nextdp & & ( dp - > setpoint ! = nextdp - > setpoint | | dp - > divemode ! = nextdp - > divemode ) ) ;
rebreatherchange_before = lastprintsetpoint ! = dp - > setpoint | | lastdivemode ! = dp - > divemode ;
2017-05-25 10:57:06 +00:00
/* do we want to skip this leg as it is devoid of anything useful? */
if ( ! dp - > entered & &
nextdp & &
dp - > depth . mm ! = lastdepth & &
nextdp - > depth . mm ! = dp - > depth . mm & &
! gaschange_before & &
2018-06-17 21:20:59 +00:00
! gaschange_after & &
! rebreatherchange_before & &
! rebreatherchange_after )
2017-05-25 10:57:06 +00:00
continue ;
2019-03-20 15:29:27 +00:00
// Ignore final surface segment for notes
if ( lastdepth = = 0 & & dp - > depth . mm = = 0 & & ! dp - > next )
continue ;
2017-12-29 00:50:20 +00:00
if ( ( dp - > time - lasttime < 10 & & lastdepth = = dp - > depth . mm ) & & ! ( gaschange_after & & dp - > next & & dp - > depth . mm ! = dp - > next - > depth . mm ) )
2017-05-25 10:57:06 +00:00
continue ;
/* Store pointer to last entered datapoint for minimum gas calculation */
if ( dp - > entered & & ! nextdp - > entered )
lastbottomdp = dp ;
if ( plan_verbatim ) {
/* When displaying a verbatim plan, we output a waypoint for every gas change.
* Therefore , we do not need to test for difficult cases that mean we need to
* print a segment just so we don ' t miss a gas change . This makes the logic
* to determine whether or not to print a segment much simpler than with the
* non - verbatim plan .
*/
if ( dp - > depth . mm ! = lastprintdepth ) {
if ( plan_display_transitions | | dp - > entered | | ! dp - > next | | ( gaschange_after & & dp - > next & & dp - > depth . mm ! = nextdp - > depth . mm ) ) {
2018-01-11 13:11:45 +00:00
if ( dp - > setpoint ) {
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( translate ( " gettextFromC " , " %s to %.*f %s in %d:%02d min - runtime %d:%02u on %s (SP = %.1fbar) " ) ,
2018-02-24 13:46:04 +00:00
dp - > depth . mm < lastprintdepth ? translate ( " gettextFromC " , " Ascend " ) : translate ( " gettextFromC " , " Descend " ) ,
decimals , depthvalue , depth_unit ,
2024-05-01 09:01:06 +00:00
FRACTION_TUPLE ( dp - > time - lasttime , 60 ) ,
FRACTION_TUPLE ( dp - > time , 60 ) ,
2018-08-16 17:10:10 +00:00
gasname ( gasmix ) ,
2018-02-24 13:46:04 +00:00
( double ) dp - > setpoint / 1000.0 ) ;
2018-01-11 13:11:45 +00:00
} else {
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( translate ( " gettextFromC " , " %s to %.*f %s in %d:%02d min - runtime %d:%02u on %s " ) ,
2018-02-24 13:46:04 +00:00
dp - > depth . mm < lastprintdepth ? translate ( " gettextFromC " , " Ascend " ) : translate ( " gettextFromC " , " Descend " ) ,
decimals , depthvalue , depth_unit ,
2024-05-01 09:01:06 +00:00
FRACTION_TUPLE ( dp - > time - lasttime , 60 ) ,
FRACTION_TUPLE ( dp - > time , 60 ) ,
2018-08-16 17:10:10 +00:00
gasname ( gasmix ) ) ;
2018-01-11 13:11:45 +00:00
}
2018-03-14 06:50:04 +00:00
2024-03-08 09:44:20 +00:00
buf + = " <br/> \n " ;
2017-05-25 10:57:06 +00:00
}
newdepth = dp - > depth . mm ;
lasttime = dp - > time ;
} else {
if ( ( nextdp & & dp - > depth . mm ! = nextdp - > depth . mm ) | | gaschange_after ) {
2018-01-11 13:11:45 +00:00
if ( dp - > setpoint ) {
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( translate ( " gettextFromC " , " Stay at %.*f %s for %d:%02d min - runtime %d:%02u on %s (SP = %.1fbar CCR) " ) ,
2018-02-24 13:46:04 +00:00
decimals , depthvalue , depth_unit ,
2024-05-01 09:01:06 +00:00
FRACTION_TUPLE ( dp - > time - lasttime , 60 ) ,
FRACTION_TUPLE ( dp - > time , 60 ) ,
2018-08-16 17:10:10 +00:00
gasname ( gasmix ) ,
2018-02-24 13:46:04 +00:00
( double ) dp - > setpoint / 1000.0 ) ;
2018-01-11 13:11:45 +00:00
} else {
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( translate ( " gettextFromC " , " Stay at %.*f %s for %d:%02d min - runtime %d:%02u on %s %s " ) ,
2018-02-24 13:46:04 +00:00
decimals , depthvalue , depth_unit ,
2024-05-01 09:01:06 +00:00
FRACTION_TUPLE ( dp - > time - lasttime , 60 ) ,
FRACTION_TUPLE ( dp - > time , 60 ) ,
2018-08-16 17:10:10 +00:00
gasname ( gasmix ) ,
2018-07-13 15:27:06 +00:00
translate ( " gettextFromC " , divemode_text_ui [ dp - > divemode ] ) ) ;
2018-01-11 13:11:45 +00:00
}
2024-03-08 09:44:20 +00:00
buf + = " <br/> \n " ;
2017-05-25 10:57:06 +00:00
newdepth = dp - > depth . mm ;
lasttime = dp - > time ;
}
}
} else {
/* When not displaying the verbatim dive plan, we typically ignore ascents between deco stops,
* unless the display transitions option has been selected . We output a segment if any of the
* following conditions are met .
* 1 ) Display transitions is selected
* 2 ) The segment was manually entered
* 3 ) It is the last segment of the dive
* 4 ) The segment is not an ascent , there was a gas change at the start of the segment and the next segment
* is a change in depth ( typical deco stop )
* 5 ) There is a gas change at the end of the segment and the last segment was entered ( first calculated
* segment if it ends in a gas change )
* 6 ) There is a gaschange after but no ascent . This should only occur when backgas breaks option is selected
* 7 ) It is an ascent ending with a gas change , but is not followed by a stop . As case 5 already matches
* the first calculated ascent if it ends with a gas change , this should only occur if a travel gas is
* used for a calculated ascent , there is a subsequent gas change before the first deco stop , and zero
* time has been allowed for a gas switch .
*/
if ( plan_display_transitions | | dp - > entered | | ! dp - > next | |
( nextdp & & dp - > depth . mm ! = nextdp - > depth . mm ) | |
2018-06-17 21:20:59 +00:00
( ! isascent & & ( gaschange_before | | rebreatherchange_before ) & & nextdp & & dp - > depth . mm ! = nextdp - > depth . mm ) | |
( ( gaschange_after | | rebreatherchange_after ) & & lastentered ) | | ( ( gaschange_after | | rebreatherchange_after ) & & ! isascent ) | |
( isascent & & ( gaschange_after | | rebreatherchange_after ) & & nextdp & & dp - > depth . mm ! = nextdp - > depth . mm ) | |
2019-09-08 14:55:00 +00:00
( lastentered & & ! dp - > entered & & dp - > next - > depth . mm = = dp - > depth . mm ) ) {
2017-05-25 10:57:06 +00:00
// Print a symbol to indicate whether segment is an ascent, descent, constant depth (user entered) or deco stop
if ( isascent )
segmentsymbol = " ➚ " ; // up-right arrow for ascent
else if ( dp - > depth . mm > lastdepth )
segmentsymbol = " ➘ " ; // down-right arrow for descent
else if ( dp - > entered )
segmentsymbol = " ➙ " ; // right arrow for entered entered segment at constant depth
else
segmentsymbol = " - " ; // minus sign (a.k.a. horizontal line) for deco stop
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " <tr><td style='padding-left: 10px; float: right;'>%s</td> " , segmentsymbol ) ;
2017-05-25 10:57:06 +00:00
2024-03-08 09:44:20 +00:00
std : : string temp = casprintf_loc ( translate ( " gettextFromC " , " %3.0f%s " ) , depthvalue , depth_unit ) ;
buf + = format_string_std ( " <td style='padding-left: 10px; float: right;'>%s</td> " , temp . c_str ( ) ) ;
2017-05-25 10:57:06 +00:00
if ( plan_display_duration ) {
2024-03-08 09:44:20 +00:00
temp = casprintf_loc ( translate ( " gettextFromC " , " %3dmin " ) , ( dp - > time - lasttime + 30 ) / 60 ) ;
buf + = format_string_std ( " <td style='padding-left: 10px; float: right;'>%s</td> " , temp . c_str ( ) ) ;
2017-05-25 10:57:06 +00:00
}
if ( plan_display_runtime ) {
2024-03-08 09:44:20 +00:00
temp = casprintf_loc ( translate ( " gettextFromC " , " %3dmin " ) , ( dp - > time + 30 ) / 60 ) ;
buf + = format_string_std ( " <td style='padding-left: 10px; float: right;'>%s</td> " , temp . c_str ( ) ) ;
2017-05-25 10:57:06 +00:00
}
/* Normally a gas change is displayed on the stopping segment, so only display a gas change at the end of
* an ascent segment if it is not followed by a stop
*/
2023-02-17 12:45:37 +00:00
if ( isascent & & gaschange_after & & dp - > next & & nextdp & & nextdp - > entered ) {
if ( nextdp - > setpoint ) {
2024-03-08 09:44:20 +00:00
temp = casprintf_loc ( translate ( " gettextFromC " , " (SP = %.1fbar CCR) " ) , nextdp - > setpoint / 1000.0 ) ;
buf + = format_string_std ( " <td style='padding-left: 10px; color: red; float: left;'><b>%s %s</b></td> " ,
gasname ( newgasmix ) , temp . c_str ( ) ) ;
2017-05-25 10:57:06 +00:00
} else {
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " <td style='padding-left: 10px; color: red; float: left;'><b>%s %s</b></td> " ,
2023-02-17 12:45:37 +00:00
gasname ( newgasmix ) , dp - > divemode = = UNDEF_COMP_TYPE | | dp - > divemode = = nextdp - > divemode ? " " : translate ( " gettextFromC " , divemode_text_ui [ nextdp - > divemode ] ) ) ;
2018-08-16 17:10:10 +00:00
if ( isascent & & ( get_he ( lastprintgasmix ) > 0 ) ) { // For a trimix gas change on ascent, save ICD info if previous cylinder had helium
if ( isobaric_counterdiffusion ( lastprintgasmix , newgasmix , & icdvalues ) ) // Do icd calulations
2018-01-15 07:43:57 +00:00
icdwarning = true ;
2018-01-28 15:44:54 +00:00
if ( icdvalues . dN2 > 0 ) { // If the gas change involved helium as well as an increase in nitrogen..
2024-06-20 20:09:47 +00:00
icdbuf + = icd_entry ( & icdvalues , icdtableheader , dp - > time , dive - > depth_to_mbar ( dp - > depth . mm ) , lastprintgasmix , newgasmix ) ; // .. then print calculations to buffer.
2018-01-28 15:44:54 +00:00
icdtableheader = false ;
}
2018-01-15 07:43:57 +00:00
}
2017-05-25 10:57:06 +00:00
}
2023-02-17 12:45:37 +00:00
lastprintsetpoint = nextdp - > setpoint ;
2017-05-25 10:57:06 +00:00
lastprintgasmix = newgasmix ;
2023-02-17 12:45:37 +00:00
lastdivemode = nextdp - > divemode ;
2017-05-25 10:57:06 +00:00
gaschange_after = false ;
2018-06-17 21:20:59 +00:00
} else if ( gaschange_before | | rebreatherchange_before ) {
2018-01-11 13:11:45 +00:00
// If a new gas has been used for this segment, now is the time to show it
2017-05-25 10:57:06 +00:00
if ( dp - > setpoint ) {
2024-03-08 09:44:20 +00:00
temp = casprintf_loc ( translate ( " gettextFromC " , " (SP = %.1fbar CCR) " ) , ( double ) dp - > setpoint / 1000.0 ) ;
buf + = format_string_std ( " <td style='padding-left: 10px; color: red; float: left;'><b>%s %s</b></td> " , gasname ( gasmix ) , temp . c_str ( ) ) ;
2017-05-25 10:57:06 +00:00
} else {
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " <td style='padding-left: 10px; color: red; float: left;'><b>%s %s</b></td> " , gasname ( gasmix ) ,
2018-07-13 15:42:03 +00:00
lastdivemode = = UNDEF_COMP_TYPE | | lastdivemode = = dp - > divemode ? " " : translate ( " gettextFromC " , divemode_text_ui [ dp - > divemode ] ) ) ;
2018-08-16 17:10:10 +00:00
if ( get_he ( lastprintgasmix ) > 0 ) { // For a trimix gas change, save ICD info if previous cylinder had helium
if ( isobaric_counterdiffusion ( lastprintgasmix , gasmix , & icdvalues ) ) // Do icd calculations
2018-01-15 07:43:57 +00:00
icdwarning = true ;
2018-01-28 15:44:54 +00:00
if ( icdvalues . dN2 > 0 ) { // If the gas change involved helium as well as an increase in nitrogen..
2024-06-20 20:09:47 +00:00
icdbuf + = icd_entry ( & icdvalues , icdtableheader , lasttime , dive - > depth_to_mbar ( dp - > depth . mm ) , lastprintgasmix , gasmix ) ; // .. then print data to buffer.
2018-01-28 15:44:54 +00:00
icdtableheader = false ;
}
2018-02-24 13:46:04 +00:00
}
2017-05-25 10:57:06 +00:00
}
// Set variables so subsequent iterations can test against the last gas printed
lastprintsetpoint = dp - > setpoint ;
lastprintgasmix = gasmix ;
2018-06-17 21:20:59 +00:00
lastdivemode = dp - > divemode ;
2017-05-25 10:57:06 +00:00
gaschange_after = false ;
} else {
2024-03-08 09:44:20 +00:00
buf + = " <td> </td> " ;
2017-05-25 10:57:06 +00:00
}
2024-03-08 09:44:20 +00:00
buf + = " </tr> \n " ;
2017-05-25 10:57:06 +00:00
newdepth = dp - > depth . mm ;
2019-10-30 14:01:54 +00:00
// Only add the time we actually displayed so rounding errors dont accumulate
lasttime + = ( ( dp - > time - lasttime + 30 ) / 60 ) * 60 ;
2017-05-25 10:57:06 +00:00
}
}
2019-08-28 08:37:33 +00:00
if ( gaschange_after | | gaschange_before ) {
2018-01-15 07:43:57 +00:00
// gas switch at this waypoint for verbatim
2017-05-25 10:57:06 +00:00
if ( plan_verbatim ) {
if ( lastsetpoint > = 0 ) {
2018-01-15 07:43:57 +00:00
if ( nextdp & & nextdp - > setpoint ) {
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( translate ( " gettextFromC " , " Switch gas to %s (SP = %.1fbar) " ) , gasname ( newgasmix ) , ( double ) nextdp - > setpoint / 1000.0 ) ;
2018-01-15 07:43:57 +00:00
} else {
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( translate ( " gettextFromC " , " Switch gas to %s " ) , gasname ( newgasmix ) ) ;
2018-08-16 17:10:10 +00:00
if ( ( isascent ) & & ( get_he ( lastprintgasmix ) > 0 ) ) { // For a trimix gas change on ascent:
if ( isobaric_counterdiffusion ( lastprintgasmix , newgasmix , & icdvalues ) ) // Do icd calculations
2018-01-15 07:43:57 +00:00
icdwarning = true ;
2018-01-28 15:44:54 +00:00
if ( icdvalues . dN2 > 0 ) { // If the gas change involved helium as well as an increase in nitrogen..
2024-06-20 20:09:47 +00:00
icdbuf + = icd_entry ( & icdvalues , icdtableheader , dp - > time , dive - > depth_to_mbar ( dp - > depth . mm ) , lastprintgasmix , newgasmix ) ; // ... then print data to buffer.
2018-01-28 15:44:54 +00:00
icdtableheader = false ;
}
2018-01-15 07:43:57 +00:00
}
}
2024-03-08 09:44:20 +00:00
buf + = " <br/> \n " ;
2017-05-25 10:57:06 +00:00
}
2018-01-15 07:43:57 +00:00
lastprintgasmix = newgasmix ;
2017-05-25 10:57:06 +00:00
gaschange_after = false ;
2018-01-11 13:11:45 +00:00
gasmix = newgasmix ;
2017-05-25 10:57:06 +00:00
}
}
lastprintdepth = newdepth ;
lastdepth = dp - > depth . mm ;
lastsetpoint = dp - > setpoint ;
lastentered = dp - > entered ;
} while ( ( dp = nextdp ) ! = NULL ) ;
if ( ! plan_verbatim )
2024-03-08 09:44:20 +00:00
buf + = " </tbody> \n </table> \n <br/> \n " ;
2017-05-25 10:57:06 +00:00
/* Print the CNS and OTU next.*/
dive - > cns = 0 ;
dive - > maxcns = 0 ;
2024-06-23 12:20:59 +00:00
divelog . dives . update_cylinder_related_info ( * dive ) ;
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( " <div> \n %s: %i%% " , translate ( " gettextFromC " , " CNS " ) , dive - > cns ) ;
buf + = casprintf_loc ( " <br/> \n %s: %i<br/> \n </div> \n " , translate ( " gettextFromC " , " OTU " ) , dive - > otu ) ;
2017-05-25 10:57:06 +00:00
/* Print the settings for the diveplan next. */
2024-03-08 09:44:20 +00:00
buf + = " <div> \n " ;
2021-02-12 17:19:24 +00:00
if ( decoMode ( true ) = = BUEHLMANN ) {
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( translate ( " gettextFromC " , " Deco model: Bühlmann ZHL-16C with GFLow = %d%% and GFHigh = %d%% " ) , diveplan - > gflow , diveplan - > gfhigh ) ;
2021-02-12 17:19:24 +00:00
} else if ( decoMode ( true ) = = VPMB ) {
2017-05-25 10:57:06 +00:00
if ( diveplan - > vpmb_conservatism = = 0 )
2024-03-08 09:44:20 +00:00
buf + = translate ( " gettextFromC " , " Deco model: VPM-B at nominal conservatism " ) ;
2017-05-25 10:57:06 +00:00
else
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( translate ( " gettextFromC " , " Deco model: VPM-B at +%d conservatism " ) , diveplan - > vpmb_conservatism ) ;
2017-05-25 10:57:06 +00:00
if ( diveplan - > eff_gflow )
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( translate ( " gettextFromC " , " , effective GF=%d/%d " ) , diveplan - > eff_gflow , diveplan - > eff_gfhigh ) ;
2021-02-12 17:19:24 +00:00
} else if ( decoMode ( true ) = = RECREATIONAL ) {
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( translate ( " gettextFromC " , " Deco model: Recreational mode based on Bühlmann ZHL-16B with GFLow = %d%% and GFHigh = %d%% " ) ,
2018-02-24 13:46:04 +00:00
diveplan - > gflow , diveplan - > gfhigh ) ;
2017-05-25 10:57:06 +00:00
}
2024-03-08 09:44:20 +00:00
buf + = " <br/> \n " ;
2017-05-25 10:57:06 +00:00
2024-03-07 10:09:40 +00:00
{
const char * depth_unit ;
int altitude = ( int ) get_depth_units ( ( int ) ( pressure_to_altitude ( diveplan - > surface_pressure ) ) , NULL , & depth_unit ) ;
2017-05-25 10:57:06 +00:00
2024-03-08 09:44:20 +00:00
buf + = casprintf_loc ( translate ( " gettextFromC " , " ATM pressure: %dmbar (%d%s)<br/> \n </div> \n " ) , diveplan - > surface_pressure , altitude , depth_unit ) ;
2024-03-07 10:09:40 +00:00
}
2017-05-25 10:57:06 +00:00
/* Get SAC values and units for printing it in gas consumption */
2024-03-07 10:09:40 +00:00
{
double bottomsacvalue , decosacvalue ;
int sacdecimals ;
const char * sacunit ;
2017-05-25 10:57:06 +00:00
2024-03-07 10:09:40 +00:00
bottomsacvalue = get_volume_units ( prefs . bottomsac , & sacdecimals , & sacunit ) ;
decosacvalue = get_volume_units ( prefs . decosac , NULL , NULL ) ;
2017-05-25 10:57:06 +00:00
2024-03-07 10:09:40 +00:00
/* Reduce number of decimals from 1 to 0 for bar/min, keep 2 for cuft/min */
if ( sacdecimals = = 1 ) sacdecimals - - ;
2017-05-25 10:57:06 +00:00
2024-03-07 10:09:40 +00:00
/* Print the gas consumption next.*/
2024-03-08 09:44:20 +00:00
std : : string temp ;
2024-05-27 15:09:48 +00:00
if ( dive - > dcs [ 0 ] . divemode = = CCR )
2024-03-08 09:44:20 +00:00
temp = translate ( " gettextFromC " , " Gas consumption (CCR legs excluded): " ) ;
2024-03-07 10:09:40 +00:00
else
2024-03-08 09:44:20 +00:00
temp = casprintf_loc ( " %s %.*f|%.*f%s/min): " , translate ( " gettextFromC " , " Gas consumption (based on SAC " ) ,
2024-03-07 10:09:40 +00:00
sacdecimals , bottomsacvalue , sacdecimals , decosacvalue , sacunit ) ;
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " <div> \n %s<br/> \n " , temp . c_str ( ) ) ;
2024-03-07 10:09:40 +00:00
}
2017-05-25 10:57:06 +00:00
/* Print gas consumption: This loop covers all cylinders */
2024-05-28 19:31:11 +00:00
for ( auto [ gasidx , cyl ] : enumerated_range ( dive - > cylinders ) ) {
2017-10-03 11:17:46 +00:00
double volume , pressure , deco_volume , deco_pressure , mingas_volume , mingas_pressure , mingas_d_pressure , mingas_depth ;
2017-05-25 10:57:06 +00:00
const char * unit , * pressure_unit , * depth_unit ;
2024-03-08 09:44:20 +00:00
std : : string temp ;
std : : string warning ;
std : : string mingas ;
2024-05-28 19:31:11 +00:00
if ( cyl . cylinder_use = = NOT_USED )
2019-04-15 11:29:25 +00:00
continue ;
2017-05-25 10:57:06 +00:00
2024-05-28 19:31:11 +00:00
volume = get_volume_units ( cyl . gas_used . mliter , NULL , & unit ) ;
deco_volume = get_volume_units ( cyl . deco_gas_used . mliter , NULL , & unit ) ;
if ( cyl . type . size . mliter ) {
int remaining_gas = lrint ( ( double ) cyl . end . mbar * cyl . type . size . mliter / 1000.0 / gas_compressibility_factor ( cyl . gasmix , cyl . end . mbar / 1000.0 ) ) ;
double deco_pressure_mbar = isothermal_pressure ( cyl . gasmix , 1.0 , remaining_gas + cyl . deco_gas_used . mliter ,
cyl . type . size . mliter ) * 1000 - cyl . end . mbar ;
2017-10-03 11:17:46 +00:00
deco_pressure = get_pressure_units ( lrint ( deco_pressure_mbar ) , & pressure_unit ) ;
2024-05-28 19:31:11 +00:00
pressure = get_pressure_units ( cyl . start . mbar - cyl . end . mbar , & pressure_unit ) ;
2017-05-25 10:57:06 +00:00
/* Warn if the plan uses more gas than is available in a cylinder
* This only works if we have working pressure for the cylinder
* 10 bar is a made up number - but it seemed silly to pretend you could breathe cylinder down to 0 */
2024-05-28 19:31:11 +00:00
if ( cyl . end . mbar < 10000 )
2024-03-08 09:44:20 +00:00
warning = format_string_std ( " <br/> \n — <span style='color: red;'>%s </span> %s " ,
2017-05-25 10:57:06 +00:00
translate ( " gettextFromC " , " Warning: " ) ,
translate ( " gettextFromC " , " this is more gas than available in the specified cylinder! " ) ) ;
else
2024-05-28 19:31:11 +00:00
if ( cyl . end . mbar / 1000.0 * cyl . type . size . mliter / gas_compressibility_factor ( cyl . gasmix , cyl . end . mbar / 1000.0 )
< cyl . deco_gas_used . mliter )
2024-03-08 09:44:20 +00:00
warning = format_string_std ( " <br/> \n — <span style='color: red;'>%s </span> %s " ,
2017-05-25 10:57:06 +00:00
translate ( " gettextFromC " , " Warning: " ) ,
translate ( " gettextFromC " , " not enough reserve for gas sharing on ascent! " ) ) ;
/* Do and print minimum gas calculation for last bottom gas, but only for OC mode, */
/* not for recreational mode and if no other warning was set before. */
else
if ( lastbottomdp & & gasidx = = lastbottomdp - > cylinderid
2024-05-27 15:09:48 +00:00
& & dive - > dcs [ 0 ] . divemode = = OC & & decoMode ( true ) ! = RECREATIONAL ) {
2017-05-25 10:57:06 +00:00
/* Calculate minimum gas volume. */
volume_t mingasv ;
mingasv . mliter = lrint ( prefs . sacfactor / 100.0 * prefs . problemsolvingtime * prefs . bottomsac
2024-06-20 20:09:47 +00:00
* dive - > depth_to_bar ( lastbottomdp - > depth . mm )
2024-05-28 19:31:11 +00:00
+ prefs . sacfactor / 100.0 * cyl . deco_gas_used . mliter ) ;
2017-05-25 10:57:06 +00:00
/* Calculate minimum gas pressure for cyclinder. */
2024-05-28 19:31:11 +00:00
lastbottomdp - > minimum_gas . mbar = lrint ( isothermal_pressure ( cyl . gasmix , 1.0 ,
mingasv . mliter , cyl . type . size . mliter ) * 1000 ) ;
2017-05-25 10:57:06 +00:00
/* Translate all results into correct units */
mingas_volume = get_volume_units ( mingasv . mliter , NULL , & unit ) ;
mingas_pressure = get_pressure_units ( lastbottomdp - > minimum_gas . mbar , & pressure_unit ) ;
2024-05-28 19:31:11 +00:00
mingas_d_pressure = get_pressure_units ( lrint ( ( double ) cyl . end . mbar + deco_pressure_mbar - lastbottomdp - > minimum_gas . mbar ) , & pressure_unit ) ;
2017-05-25 10:57:06 +00:00
mingas_depth = get_depth_units ( lastbottomdp - > depth . mm , NULL , & depth_unit ) ;
/* Print it to results */
2024-05-28 19:31:11 +00:00
if ( cyl . start . mbar > lastbottomdp - > minimum_gas . mbar ) {
2024-03-08 09:44:20 +00:00
mingas = casprintf_loc ( " <br/> \n — <span style='color: %s;'>%s</span> (%s %.1fx%s/+%d%s@%.0f%s): "
2018-02-24 13:46:04 +00:00
" %.0f%s/%.0f%s<span style='color: %s;'>/Δ:%+.0f%s</span> " ,
mingas_d_pressure > 0 ? " green " : " red " ,
translate ( " gettextFromC " , " Minimum gas " ) ,
translate ( " gettextFromC " , " based on " ) ,
prefs . sacfactor / 100.0 ,
translate ( " gettextFromC " , " SAC " ) ,
prefs . problemsolvingtime ,
translate ( " gettextFromC " , " min " ) ,
mingas_depth , depth_unit ,
mingas_volume , unit ,
mingas_pressure , pressure_unit ,
mingas_d_pressure > 0 ? " grey " : " indianred " ,
mingas_d_pressure , pressure_unit ) ;
2017-10-18 13:58:36 +00:00
} else {
2024-03-08 09:44:20 +00:00
warning = format_string_std ( " <br/> \n — <span style='color: red;'>%s </span> %s " ,
2017-10-18 13:58:36 +00:00
translate ( " gettextFromC " , " Warning: " ) ,
translate ( " gettextFromC " , " required minimum gas for ascent already exceeding start pressure of cylinder! " ) ) ;
}
2017-05-25 10:57:06 +00:00
}
/* Print the gas consumption for every cylinder here to temp buffer. */
2018-01-11 13:11:45 +00:00
if ( lrint ( volume ) > 0 ) {
2024-03-08 09:44:20 +00:00
temp = casprintf_loc ( translate ( " gettextFromC " , " %.0f%s/%.0f%s of <span style='color: red;'><b>%s</b></span> (%.0f%s/%.0f%s in planned ascent) " ) ,
2024-05-28 19:31:11 +00:00
volume , unit , pressure , pressure_unit , gasname ( cyl . gasmix ) , deco_volume , unit , deco_pressure , pressure_unit ) ;
2018-01-11 13:11:45 +00:00
} else {
2024-03-08 09:44:20 +00:00
temp = casprintf_loc ( translate ( " gettextFromC " , " %.0f%s/%.0f%s of <span style='color: red;'><b>%s</b></span> " ) ,
2024-05-28 19:31:11 +00:00
volume , unit , pressure , pressure_unit , gasname ( cyl . gasmix ) ) ;
2018-01-11 13:11:45 +00:00
}
2017-05-25 10:57:06 +00:00
} else {
2018-01-15 07:43:57 +00:00
if ( lrint ( volume ) > 0 ) {
2024-03-08 09:44:20 +00:00
temp = casprintf_loc ( translate ( " gettextFromC " , " %.0f%s of <span style='color: red;'><b>%s</b></span> (%.0f%s during planned ascent) " ) ,
2024-05-28 19:31:11 +00:00
volume , unit , gasname ( cyl . gasmix ) , deco_volume , unit ) ;
2018-01-15 07:43:57 +00:00
} else {
2024-03-08 09:44:20 +00:00
temp = casprintf_loc ( translate ( " gettextFromC " , " %.0f%s of <span style='color: red;'><b>%s</b></span> " ) ,
2024-05-28 19:31:11 +00:00
volume , unit , gasname ( cyl . gasmix ) ) ;
2018-01-15 07:43:57 +00:00
}
2017-05-25 10:57:06 +00:00
}
/* Gas consumption: Now finally print all strings to output */
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " %s%s%s<br/> \n " , temp . c_str ( ) , warning . c_str ( ) , mingas . c_str ( ) ) ;
2017-05-25 10:57:06 +00:00
}
2024-03-08 09:44:20 +00:00
buf + = " </div> \n " ;
2017-05-25 10:57:06 +00:00
2018-01-28 15:44:54 +00:00
/* For trimix OC dives, if an icd table header and icd data were printed to buffer, then add the ICD table here */
2018-02-24 19:07:11 +00:00
if ( ! icdtableheader & & prefs . show_icd ) {
2024-03-08 09:44:20 +00:00
icdbuf + = " </tbody></table> \n " ; // End the ICD table
buf + = icdbuf ;
2018-01-28 15:44:54 +00:00
if ( icdwarning ) { // If necessary, add warning
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " <span style='color: red;'>%s</span> %s " ,
2018-01-15 07:43:57 +00:00
translate ( " gettextFromC " , " Warning: " ) ,
translate ( " gettextFromC " , " Isobaric counterdiffusion conditions exceeded " ) ) ;
}
2024-03-08 09:44:20 +00:00
buf + = " <br/></div> \n " ;
2018-01-15 07:43:57 +00:00
}
2024-03-07 10:09:40 +00:00
/* Print warnings for pO2 (move into separate function?) */
{
dp = diveplan - > dp ;
bool o2warning_exist = false ;
double amb ;
2024-05-27 15:09:48 +00:00
divemode_loop loop ( dive - > dcs [ 0 ] ) ;
if ( dive - > dcs [ 0 ] . divemode ! = CCR ) {
2024-03-07 10:09:40 +00:00
while ( dp ) {
if ( dp - > time ! = 0 ) {
2024-03-08 09:44:20 +00:00
std : : string temp ;
2024-06-25 05:43:32 +00:00
struct gasmix gasmix = dive - > get_cylinder ( dp - > cylinderid ) - > gasmix ;
2024-03-07 10:09:40 +00:00
2024-05-25 06:16:57 +00:00
divemode_t current_divemode = loop . next ( dp - > time ) ;
2024-06-20 20:09:47 +00:00
amb = dive - > depth_to_atm ( dp - > depth . mm ) ;
2024-05-05 04:54:30 +00:00
gas_pressures pressures = fill_pressures ( amb , gasmix , ( current_divemode = = OC ) ? 0.0 : amb * gasmix . o2 . permille / 1000.0 , current_divemode ) ;
2024-03-07 10:09:40 +00:00
if ( pressures . o2 > ( dp - > entered ? prefs . bottompo2 : prefs . decopo2 ) / 1000.0 ) {
const char * depth_unit ;
int decimals ;
double depth_value = get_depth_units ( dp - > depth . mm , & decimals , & depth_unit ) ;
if ( ! o2warning_exist )
2024-03-08 09:44:20 +00:00
buf + = " <div> \n " ;
2024-03-07 10:09:40 +00:00
o2warning_exist = true ;
2024-03-08 09:44:20 +00:00
temp = casprintf_loc ( translate ( " gettextFromC " , " high pO₂ value %.2f at %d:%02u with gas %s at depth %.*f %s " ) ,
2024-05-01 09:01:06 +00:00
pressures . o2 , FRACTION_TUPLE ( dp - > time , 60 ) , gasname ( gasmix ) , decimals , depth_value , depth_unit ) ;
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " <span style='color: red;'>%s </span> %s<br/> \n " , translate ( " gettextFromC " , " Warning: " ) , temp . c_str ( ) ) ;
2024-03-07 10:09:40 +00:00
} else if ( pressures . o2 < 0.16 ) {
const char * depth_unit ;
int decimals ;
double depth_value = get_depth_units ( dp - > depth . mm , & decimals , & depth_unit ) ;
if ( ! o2warning_exist )
2024-03-08 09:44:20 +00:00
buf + = " <div> " ;
2024-03-07 10:09:40 +00:00
o2warning_exist = true ;
2024-03-08 09:44:20 +00:00
temp = casprintf_loc ( translate ( " gettextFromC " , " low pO₂ value %.2f at %d:%02u with gas %s at depth %.*f %s " ) ,
2024-05-01 09:01:06 +00:00
pressures . o2 , FRACTION_TUPLE ( dp - > time , 60 ) , gasname ( gasmix ) , decimals , depth_value , depth_unit ) ;
2024-03-08 09:44:20 +00:00
buf + = format_string_std ( " <span style='color: red;'>%s </span> %s<br/> \n " , translate ( " gettextFromC " , " Warning: " ) , temp . c_str ( ) ) ;
2024-03-07 10:09:40 +00:00
}
2017-05-25 10:57:06 +00:00
}
2024-03-07 10:09:40 +00:00
dp = dp - > next ;
2017-05-25 10:57:06 +00:00
}
}
2024-03-07 10:09:40 +00:00
if ( o2warning_exist )
2024-03-08 09:44:20 +00:00
buf + = " </div> \n " ;
2017-05-25 10:57:06 +00:00
}
2024-03-08 09:44:20 +00:00
// TODO: avoid copy
2024-05-29 18:40:18 +00:00
dive - > notes = buf ;
2019-08-28 08:13:10 +00:00
# ifdef DEBUG_PLANNER_NOTES
printf ( " <!DOCTYPE html> \n <html> \n \t <head><title>plannernotes</title><meta http-equiv= \" Content-Type \" content= \" text/html; charset=utf-8 \" /></head> \n \t <body> \n %s \t </body> \n </html> \n " , dive - > notes ) ;
# endif
2018-01-15 07:43:57 +00:00
}