Skip to content

Commit

Permalink
Add support for laps in fit format and calories from fit file.
Browse files Browse the repository at this point in the history
(instead of wrong calculations).
  • Loading branch information
Qball Cow authored and Qball Cow committed Oct 16, 2013
1 parent d881ccf commit b77603a
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 57 deletions.
49 changes: 45 additions & 4 deletions src/fit-parser.vala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace Gpx
private uint32 data_length = 0;

private enum FitTypes {
LAP = 19,
ACTIVITY_SUMMARY = 20
}
// Internal structs.
Expand Down Expand Up @@ -85,16 +86,18 @@ namespace Gpx
fs.set_byte_order(DataStreamByteOrder.LITTLE_ENDIAN);
}

track = new Gpx.Track();
//track = new Gpx.Track();
// Parse the header file.
this.parse_header(fs);
// Parse all the records.
while(this.parse_record(fs));


// Add the track
track.filter_points();
tracks.append(track);
if(track != null) {
track.filter_points();
tracks.append(track);
}
} catch ( GLib.IOError err ) {
throw new FileError.IO_ERROR(err.message);
} catch ( GLib.Error err ) {
Expand Down Expand Up @@ -208,8 +211,43 @@ namespace Gpx
}
return retv;
}
private void parse_data_record_lap(DataInputStream fs, FieldDefinition *def) throws FileError, GLib.IOError
{

foreach ( var field in def->fields ) {
switch(field.def_num) {
case 11:
// Calories of the track?
uint32 val = parse_field(field, fs);
track.hrmt.calories = val;
break;
/** Currently we do not store other fields, as we do not care about them. */
case 15:
// AVG BPM
uint32 val = parse_field(field, fs);
break;
case 16:
// MAX BPM
uint32 val = parse_field(field, fs);
break;
default:
uint32 val = parse_field(field, fs);
stdout.printf("%d %u\n", field.def_num,val);
break;
}
}
// Add the track
if(track != null) {
track.filter_points();
tracks.append(track);
track = null;
}
}
private void parse_data_record_activity_summary(DataInputStream fs, FieldDefinition *def) throws FileError, GLib.IOError
{
if(track == null) {
track = new Gpx.Track();
}
Gpx.Point p = new Gpx.Point();
foreach ( var field in def->fields ) {
switch(field.def_num) {
Expand Down Expand Up @@ -301,8 +339,11 @@ namespace Gpx
parse_data_record_activity_summary(fs, def);

break;

case FitTypes.LAP:
parse_data_record_lap(fs, def);
break;
default:
stdout.printf("Unknown record: %d\n", def.type);
foreach ( var field in def->fields ) {
fs.skip(field.size);
data_length-=field.size;
Expand Down
54 changes: 13 additions & 41 deletions src/gpx-parser.vala
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ namespace Gpx
public struct HeartRateMonitorPoint
{
public int heartrate;


}
public struct HeartRateMonitorTrack
{
public uint32 calories;
}

/**
* Represents a point in the track or a waypoint.
*/
Expand Down Expand Up @@ -121,6 +124,7 @@ namespace Gpx
*/
public class Track : GLib.Object
{
public HeartRateMonitorTrack hrmt = HeartRateMonitorTrack() { calories = 0 };
/* make a property */
public string name {get; set; default = null;}
/** Number of points that the #filter_points() function removed */
Expand Down Expand Up @@ -270,7 +274,7 @@ namespace Gpx
} else break;
}
point.smooth_elevation = elevation_value / weights;
log(LOG_DOMAIN, LogLevelFlags.LEVEL_DEBUG, "Used %d points in radius of %f m", i, radius * 1000.0);
//log(LOG_DOMAIN, LogLevelFlags.LEVEL_DEBUG, "Used %d points in radius of %f m", i, radius * 1000.0);
if(point.has_position()) {
last = iter;
}
Expand Down Expand Up @@ -558,46 +562,14 @@ namespace Gpx
return (total_time > 0)?(uint)(total/total_time):0;
}

public uint heartrate_calc_calories(
Point start, Point stop,
bool male,
double weight, double age)
public uint get_burned_calories()
{
double total = 0;
double total_time = 0.0;
Point *prev = null;
weak List<Point?> iter = this.points.find(start);
if(iter == null) return 0;
do {
var p = iter.data;
if(p.tpe.heartrate != 0) {
if(prev == null) {
prev = p;
}else{
double diff = (double)p.get_time()-(double)prev->get_time();
{
total+= ((prev->tpe.heartrate+p.tpe.heartrate)/2.0)*diff;
total_time+=diff;
}

prev = p;
}
}
iter = iter.next;
}while (iter != null && iter.prev.data != stop);
double cal=0;
if (male) {
cal = ((-55.0969 + (0.6309 * total/total_time) + (0.1988 * weight) + (0.2017 * age))/4.184) *
(total_time/60.0);
} else {
cal = ((-20.4022 + (0.4472 * total/total_time) - (0.1263 * weight) + (0.074 * age))/4.184) *
total_time/60.0;
}
return (uint)cal;
return this.hrmt.calories;
}
public void set_burned_calories(uint value)
{
this.hrmt.calories = value;
}



}


Expand Down
20 changes: 8 additions & 12 deletions src/gpx-viewer.c
Original file line number Diff line number Diff line change
Expand Up @@ -509,18 +509,11 @@ static void interface_update_heading(GtkBuilder * c_builder, GpxTrack * track, G
}
/* Average calories */
if(track != NULL ){
gboolean male = gpx_viewer_settings_get_boolean (priv->settings, "calories" , "male", TRUE);
double weight = gpx_viewer_settings_get_double (priv->settings, "calories" , "weight", 0.0);
double age = gpx_viewer_settings_get_double (priv->settings, "calories" , "age", 0.0);
if(weight > 0 && age > 0) {
double hr = gpx_track_heartrate_calc_calories(track,start,stop, male, weight, age);
gchar *string = g_strdup_printf("%.1f kcal", hr);
label = (GtkWidget *) gtk_builder_get_object(priv->builder, "calories_label");
gtk_label_set_text(GTK_LABEL(label), string);
g_free(string);
}else{
gtk_label_set_text(GTK_LABEL(label), _("Please configure first"));
}
uint32_t hr = gpx_track_get_burned_calories(track);
gchar *string = g_strdup_printf("%u kcal (full track)", hr);
label = (GtkWidget *) gtk_builder_get_object(priv->builder, "calories_label");
gtk_label_set_text(GTK_LABEL(label), string);
g_free(string);
}else {
label = (GtkWidget *) gtk_builder_get_object(priv->builder, "calories_label");
gtk_label_set_text(GTK_LABEL(label), _("n/a"));
Expand Down Expand Up @@ -1096,15 +1089,18 @@ static void interface_create_fake_master_track(GpxFileBase *file, GtkTreeIter *l

if (gpx_file_base_get_tracks(file))
{
uint32_t calories = 0;
for (iter = g_list_first(gpx_file_base_get_tracks(file)); iter; iter = g_list_next(iter))
{
GList *piter;
calories += gpx_track_get_burned_calories(GPX_TRACK(iter->data));
for(piter = g_list_first(GPX_TRACK(iter->data)->points); piter != NULL; piter = g_list_next(piter))
{
GpxPoint *p = piter->data;
gpx_track_add_point(route->track, gpx_point_copy(p));
}
}
gpx_track_set_burned_calories(GPX_TRACK(route->track), calories);
}
if(gpx_file_base_get_routes(file))
{
Expand Down

0 comments on commit b77603a

Please sign in to comment.