diff --git a/src/control.c b/src/control.c index d80ca6b..0f915ac 100644 --- a/src/control.c +++ b/src/control.c @@ -168,6 +168,33 @@ void control_key_event(traj_info_t* traj_info, int key, int mods) traj_info->time_frozen -= 1000000; if (key == GLFW_KEY_UP) traj_info->time_frozen += 1000000; + if( key==GLFW_KEY_PAGE_UP) + { + SEL.joint_cycle_list_index = (SEL.joint_cycle_list_index + 1) % SEL.joint_cycle_list_size; + if(SEL.node_type == NODE_JOINTID) + REVISUALIZE; + } + else if( key==GLFW_KEY_PAGE_DOWN) + { + SEL.joint_cycle_list_index = (SEL.joint_cycle_list_index - 1 + SEL.joint_cycle_list_size) % SEL.joint_cycle_list_size; + if(SEL.node_type == NODE_JOINTID) + REVISUALIZE; + } + } + else if (!(*traj_info->paused) && !(mods & GLFW_MOD_CONTROL)) + { + if( key==GLFW_KEY_PAGE_UP) + { + SEL.joint_cycle_list_index = (SEL.joint_cycle_list_index + 1) % SEL.joint_cycle_list_size; + if(SEL.node_type == NODE_JOINTID) + REVISUALIZE; + } + else if( key==GLFW_KEY_PAGE_DOWN) + { + SEL.joint_cycle_list_index = (SEL.joint_cycle_list_index - 1 + SEL.joint_cycle_list_size) % SEL.joint_cycle_list_size; + if(SEL.node_type == NODE_JOINTID) + REVISUALIZE; + } } else if (mods & GLFW_MOD_CONTROL) { @@ -202,21 +229,6 @@ void control_key_event(traj_info_t* traj_info, int key, int mods) traj_info->time_start -= traj_info->time_start*(.2) - traj_time_in_micros()*(.2); } } - else - { - if( key==GLFW_KEY_PAGE_UP) - { - SEL.joint_cycle_list_index = (SEL.joint_cycle_list_index + 1) % SEL.joint_cycle_list_size; - if(SEL.node_type == NODE_JOINTID) - REVISUALIZE; - } - else if( key==GLFW_KEY_PAGE_DOWN) - { - SEL.joint_cycle_list_index = (SEL.joint_cycle_list_index - 1 + SEL.joint_cycle_list_size) % SEL.joint_cycle_list_size; - if(SEL.node_type == NODE_JOINTID) - REVISUALIZE; - } - } if(key== GLFW_KEY_C) { diff --git a/src/main.h b/src/main.h index 4fcd0d5..9ab1acc 100644 --- a/src/main.h +++ b/src/main.h @@ -11,9 +11,11 @@ #define XMLNODECOUNT 50 #define NODECOUNT (traj_info->selection.nodecount) #define FILENAME_STEP_DATA "stepdata.bin" //used in simulate.c : reset_traj_info() -#define DECOR_BUF_SIZE 400 +#define LOOP_TRAJECTORY 2 #define IK_STEP_CUTOFF 1500 +#define DECOR_BUF_SIZE 400 + struct _qpos_t_ { double q[CASSIE_QPOS_SIZE]; @@ -28,7 +30,11 @@ enum node_type_e NODE_JOINTMOVE }; +#if (LOOP_TRAJECTORY == 1) #define NODE_TYPE_E_COUNT 3 +#else +#define NODE_TYPE_E_COUNT 1 +#endif enum scale_type_e { @@ -40,7 +46,8 @@ enum scale_type_e struct _timeline_t_ { - int numposes; + int numframes; + int numnoloopframes; double duration; qpos_t* qposes; enum node_type_e node_type; diff --git a/src/node.c b/src/node.c index 196bdbd..ec95c4c 100644 --- a/src/node.c +++ b/src/node.c @@ -127,6 +127,37 @@ void node_calculate_arbitrary_target_using_scale_type( traj_info->d->pstack = stack_mark; } +void node_gimme_target_friendly_rf_init_body_xpos( + traj_info_t* traj_info, + timeline_t* timeline, + v3_t fixed_body_init_xpos_at_rootframe, + v3_t global_body_init_xpos_at_rootframe, + int rootframe, + int frame_offset, + cassie_body_id_t body_id) +{ + double pelvis_start[3]; + double pelvis_end[3]; + double pelvis_delta[3]; + int numdeltas; + + numdeltas = mju_round((frame_offset + 0.0) / (timeline->numnoloopframes + 0.0)); + mju_copy3(pelvis_start, node_get_body_xpos_by_frame( + traj_info, + timeline, + 0, + node_get_cassie_id_from_index(1))); + mju_copy3(pelvis_end, node_get_body_xpos_by_frame( + traj_info, + timeline, + timeline->numnoloopframes-1, + node_get_cassie_id_from_index(1))); + mju_sub3(pelvis_delta, pelvis_end, pelvis_start); + mju_addScl3(fixed_body_init_xpos_at_rootframe, + global_body_init_xpos_at_rootframe, + pelvis_delta, + numdeltas); +} void node_calclate_global_target_using_transformation_type( traj_info_t* traj_info, @@ -140,23 +171,55 @@ void node_calclate_global_target_using_transformation_type( { double filter; v3_t body_init_xpos; + int i; + double temp; + double fixed_body_init_xpos_at_rootframe[3]; + + // printf("fo: %d \n", frame_offset); filter = node_calculate_filter_from_frame_offset( frame_offset, SEL.nodesigma, SEL.nodeheight); + + for(i = 0; i * traj_info->timeline->numnoloopframes < traj_info->timeline->numframes; i++) + { + temp = node_calculate_filter_from_frame_offset( + frame_offset + i * traj_info->timeline->numnoloopframes, + SEL.nodesigma, + SEL.nodeheight); + filter = mju_max(temp,filter); + temp = node_calculate_filter_from_frame_offset( + frame_offset - i * traj_info->timeline->numnoloopframes, + SEL.nodesigma, + SEL.nodeheight); + filter = mju_max(temp,filter); + } + + frame_offset = timeline_make_frame_safe( rootframe + frame_offset, + timeline->numframes) - rootframe; + + node_gimme_target_friendly_rf_init_body_xpos( + traj_info, + timeline, + fixed_body_init_xpos_at_rootframe, + global_body_init_xpos_at_rootframe, + rootframe, + frame_offset, + body_id); + body_init_xpos = node_get_body_xpos_by_frame( traj_info, timeline, rootframe + frame_offset, - body_id); + body_id); node_calculate_arbitrary_target_using_scale_type( traj_info, global_body_target_xpos, rootframe_transform_vector, body_init_xpos, - global_body_init_xpos_at_rootframe, + fixed_body_init_xpos_at_rootframe, 3, filter); } @@ -169,11 +232,11 @@ int node_get_frame_from_node_body_id(traj_info_t* traj_info, int frame; offset = SEL.frame_offset; while(offset < 0) - offset += timeline->numposes; - offset = SEL.frame_offset % timeline->numposes; - frame = (timeline->numposes / NODECOUNT) * (node_id.id - 26); // or maybe 28 + offset += timeline->numframes; + offset = SEL.frame_offset % timeline->numframes; + frame = (timeline->numframes / NODECOUNT) * (node_id.id - 26); // or maybe 28 frame += offset; - frame %= timeline->numposes; + frame %= timeline->numframes; return frame; } @@ -229,7 +292,7 @@ void node_refine_pert( timeline_new = timeline_duplicate(timeline_old); init_time = traj_calculate_runtime_micros(traj_info); - rootframe = timeline_make_frame_safe(rootframe, timeline_old->numposes); + rootframe = timeline_make_frame_safe(rootframe, timeline_old->numframes); for(i = 0; i < traj_info->target_list_size; i++) { frame = rootframe + traj_info->target_list[i].frame_offset; @@ -269,7 +332,7 @@ void node_calc_frame_lowhigh( int* low_frame, int* high_frame, int rootframe, - int numposes, + int numframes, traj_info_t* traj_info) { int i; @@ -288,7 +351,7 @@ void node_calc_frame_lowhigh( if(!SEL.loop_enabled) { *low_frame = mju_max(0, rootframe - i); - *high_frame = mju_min(numposes-1, rootframe + i); + *high_frame = mju_min(numframes-1, rootframe + i); } else { @@ -318,27 +381,28 @@ void node_perform_pert( int loopcount; timeline_t* timeline_old; timeline_t* timeline_new; + timeline_t* timeline_final; bool failed; failed = 0; timeline_old = traj_info->timeline; - timeline_new = timeline_duplicate(timeline_old); - rootframe = timeline_make_frame_safe(rootframe, timeline_old->numposes); + timeline_new = timeline_noloop(timeline_old); + rootframe = timeline_make_frame_safe(rootframe, timeline_new->numframes); node_calc_frame_lowhigh( &low_frame, &high_frame, rootframe, - timeline_old->numposes, + timeline_new->numframes, traj_info); init_time = traj_calculate_runtime_micros(traj_info); mju_copy3( global_body_init_xpos_at_rootframe, - node_get_body_xpos_curr(traj_info, body_id)); + node_get_body_xpos_by_frame(traj_info, timeline_new, rootframe, body_id)); node_calclate_global_target_using_transformation_type( traj_info, - timeline_old, + timeline_new, global_body_init_xpos_at_rootframe, global_body_target_xpos, rootframe_transform_vector, @@ -387,7 +451,7 @@ void node_perform_pert( { node_calclate_global_target_using_transformation_type( traj_info, - timeline_old, + timeline_new, global_body_init_xpos_at_rootframe, global_body_target_xpos, rootframe_transform_vector, @@ -416,7 +480,7 @@ void node_perform_pert( node_calclate_global_target_using_transformation_type( traj_info, - timeline_old, + timeline_new, global_body_init_xpos_at_rootframe, global_body_target_xpos, rootframe_transform_vector, @@ -443,7 +507,7 @@ void node_perform_pert( &ik_iter_total); } - if(frame_offset > 1 && ik_iter_total > (.95 * IK_STEP_CUTOFF * (2*frame_offset + 1))) + if(frame_offset > 1 && ik_iter_total > (.6 * IK_STEP_CUTOFF * (2*frame_offset + 1))) { printf("TOO HARD. ABORTING. \n"); failed = 1; @@ -460,6 +524,11 @@ void node_perform_pert( (iktimedelta/1000000.0), 1000.0*params->ik_accuracy_cutoff); + timeline_final = timeline_loop( + timeline_new, + mju_round(timeline_old->numframes/timeline_old->numnoloopframes)); + timeline_free(timeline_new); + timeline_new = timeline_final; timeline_safe_link(timeline_new, timeline_old); traj_info->timeline = timeline_new; timeline_new->node_type = NODE_POSITIONAL; @@ -486,8 +555,12 @@ void node_dropped_jointmove( double rootframe_init; double filter; double jointdiff; + double temp; + int i; + int frame_offset; timeline_t* timeline_old; timeline_t* timeline_new; + timeline_t* timeline_final; timeline_old = traj_info->timeline; timeline_new = timeline_duplicate(timeline_old); @@ -495,7 +568,7 @@ void node_dropped_jointmove( rootframe = node_get_frame_from_node_body_id(traj_info, timeline_new, node_id); - + rootframe = timeline_make_frame_safe(rootframe, timeline_new->numnoloopframes); timeline_set_qposes_to_pose_frame( traj_info, timeline_old, @@ -507,13 +580,28 @@ void node_dropped_jointmove( jointdiff = node_caluclate_jointdiff(traj_info, node_get_body_xpos_curr(traj_info, body_id)); - for (frame = 0; frame < timeline_new->numposes; frame++) + for (frame = 0; frame < timeline_new->numnoloopframes; frame++) { + frame_offset = frame - rootframe; filter = node_calculate_filter_from_frame_offset( - frame - rootframe, + frame_offset, SEL.nodesigma, SEL.nodeheight); + for(i = 0; SEL.loop_enabled && i * traj_info->timeline->numnoloopframes <= traj_info->timeline->numframes; i++) + { + temp = node_calculate_filter_from_frame_offset( + frame_offset + i * traj_info->timeline->numnoloopframes, + SEL.nodesigma, + SEL.nodeheight); + filter = mju_max(temp,filter); + temp = node_calculate_filter_from_frame_offset( + frame_offset - i * traj_info->timeline->numnoloopframes, + SEL.nodesigma, + SEL.nodeheight); + filter = mju_max(temp,filter); + } + node_calculate_arbitrary_target_using_scale_type( traj_info, timeline_new->qposes[frame].q + GETJOINTNUM, @@ -524,8 +612,14 @@ void node_dropped_jointmove( filter); } - timeline_safe_link(timeline_new, timeline_old); + // timeline_final = timeline_loop( + // timeline_new, + // mju_round(timeline_old->numframes/timeline_old->numnoloopframes)); + // timeline_free(timeline_new); + // timeline_new = timeline_final; + timeline_safe_link(timeline_new, timeline_old); traj_info->timeline = timeline_new; + timeline_new->node_type = NODE_JOINTMOVE; node_position_initial_using_cassie_body(traj_info, body_id); } @@ -708,23 +802,23 @@ void node_compare_looped_filters( if(SEL.loop_enabled && filter < node_calculate_filter_from_frame_offset( - oldcurrframe - rootframe - traj_info->timeline->numposes, + oldcurrframe - rootframe - traj_info->timeline->numframes, SEL.nodesigma, SEL.nodeheight)) { - *currframe = oldcurrframe - traj_info->timeline->numposes; + *currframe = oldcurrframe - traj_info->timeline->numframes; filter = node_calculate_filter_from_frame_offset( - oldcurrframe - rootframe - traj_info->timeline->numposes, + oldcurrframe - rootframe - traj_info->timeline->numframes, SEL.nodesigma, SEL.nodeheight); } if(SEL.loop_enabled && filter < node_calculate_filter_from_frame_offset( - oldcurrframe - rootframe + traj_info->timeline->numposes, + oldcurrframe - rootframe + traj_info->timeline->numframes, SEL.nodesigma, SEL.nodeheight)) { - *currframe = oldcurrframe + traj_info->timeline->numposes; + *currframe = oldcurrframe + traj_info->timeline->numframes; } *frame_offset = *currframe - rootframe; diff --git a/src/overlay.c b/src/overlay.c index f4748d0..87a9a38 100644 --- a/src/overlay.c +++ b/src/overlay.c @@ -198,10 +198,10 @@ void overlay_set_time_and_frame(traj_info_t* traj_info, int frame) { float result; - frame = timeline_make_frame_safe(frame, traj_info->timeline->numposes); + frame = timeline_make_frame_safe(frame, traj_info->timeline->numframes); result = frame; - result /= traj_info->timeline->numposes; + result /= traj_info->timeline->numframes; result *= traj_info->timeline->duration; OV.sec = result; diff --git a/src/timeline.c b/src/timeline.c index d22e6a3..b0bdbfe 100644 --- a/src/timeline.c +++ b/src/timeline.c @@ -37,11 +37,11 @@ uint32_t timeline_fill_full_traj_state_array(traj_info_t* traj_info, uint8_t** b return readsofar; } -int timeline_make_frame_safe(int frame, int numposes) +int timeline_make_frame_safe(int frame, int numframes) { while(frame < 0) - frame += numposes; - frame %= numposes; + frame += numframes; + frame %= numframes; return frame; } @@ -54,7 +54,7 @@ void timeiline_init_from_input_file(traj_info_t* traj_info) int start; int loopcount; - loopcount = 1; + loopcount = LOOP_TRAJECTORY; bytecount = timeline_fill_full_traj_state_array(traj_info, (uint8_t**) &fulls); bytecount /= sizeof(full_traj_state_t); @@ -90,7 +90,8 @@ void timeiline_init_from_input_file(traj_info_t* traj_info) free(fulls); - traj_info->timeline->numposes = bytecount * loopcount; + traj_info->timeline->numnoloopframes = bytecount; + traj_info->timeline->numframes = bytecount * loopcount; traj_info->timeline->next = NULL; traj_info->timeline->prev = NULL; traj_info->timeline->node_type = NODE_NONE; @@ -123,7 +124,7 @@ void filename_replace_dots(char* filename) } } -void timeline_export_to_file(traj_info_t* traj_info, full_traj_state_t* fulls, int numposes) +void timeline_export_to_file(traj_info_t* traj_info, full_traj_state_t* fulls, int numframes) { char filename[256]; char infilename[256]; @@ -145,7 +146,7 @@ void timeline_export_to_file(traj_info_t* traj_info, full_traj_state_t* fulls, i } // printf("bytes: %d, doubles: %f\n", sizeof(full_traj_state_t), (sizeof(full_traj_state_t)+0.0)/sizeof(double)); - fwrite(fulls, sizeof(full_traj_state_t), numposes, outfile); + fwrite(fulls, sizeof(full_traj_state_t), numframes, outfile); fflush(outfile); fclose(outfile); } @@ -158,14 +159,14 @@ void timeline_export(traj_info_t* traj_info, timeline_t* timeline) full_traj_state_t* membuf; savestackptr = traj_info->d->pstack; - numDubsNeeded = timeline->numposes * sizeof(full_traj_state_t); + numDubsNeeded = timeline->numframes * sizeof(full_traj_state_t); numDubsNeeded /= sizeof(double); membuf = (full_traj_state_t*) mj_stackAlloc(traj_info->d, mju_ceil(numDubsNeeded)); - for(i = 0; i < timeline->numposes; i++) + for(i = 0; i < timeline->numframes; i++) { - membuf[i].time = (timeline->duration / (timeline->numposes-1)) * i; + membuf[i].time = (timeline->duration / (timeline->numframes-1)) * i; mju_copy(membuf[i].qpos, timeline->qposes[i].q, 35); mju_zero(membuf[i].qvel, 32); mju_zero(membuf[i].torque, 10); @@ -173,7 +174,7 @@ void timeline_export(traj_info_t* traj_info, timeline_t* timeline) mju_zero(membuf[i].mvel, 10); } - timeline_export_to_file(traj_info, membuf, timeline->numposes); + timeline_export_to_file(traj_info, membuf, timeline->numframes); traj_info->d->pstack = savestackptr; } @@ -185,9 +186,9 @@ timeline_t* timeline_init_with_single_pose(qpos_t* qpos, timeline_t* xcopy) int i; dest = malloc(sizeof(timeline_t)); - dest->qposes = malloc(sizeof(qpos_t) * xcopy->numposes); + dest->qposes = malloc(sizeof(qpos_t) * xcopy->numframes); - for(i = 0; i < xcopy->numposes; i++) + for(i = 0; i < xcopy->numframes; i++) { mju_copy(dest->qposes[i].q, qpos->q, CASSIE_QPOS_SIZE); mju_copy(dest->qposes[i].q, xcopy->qposes[i].q, 1); @@ -195,19 +196,61 @@ timeline_t* timeline_init_with_single_pose(qpos_t* qpos, timeline_t* xcopy) dest->next = NULL; dest->prev = NULL; - dest->numposes = xcopy->numposes; + dest->numframes = xcopy->numframes; dest->node_type = NODE_NONE; + dest->numnoloopframes = xcopy->numnoloopframes; + return dest; +} + +timeline_t* timeline_loop(timeline_t* ref, int loopcount) +{ + timeline_t* dest; + int qposbytecount; + int i; + int big; + int start; + + qposbytecount = sizeof(qpos_t) * ref->numnoloopframes * loopcount; + + dest = malloc(sizeof(timeline_t)); + dest->qposes = malloc(qposbytecount); + + for(i = 0; i < ref->numnoloopframes * loopcount; i++) + { + mju_copy(dest->qposes[i].q, + ref->qposes[i % ref->numnoloopframes].q, + CASSIE_QPOS_SIZE); + } + + for(big = 1; big <= loopcount-1; big++) + { + start = ref->numnoloopframes * big; + for(i = start; i < start + ref->numnoloopframes; i++) + { + mju_add(dest->qposes[i].q, + dest->qposes[i].q, + dest->qposes[start-1].q, + 1); + } + } + + dest->next = NULL; + dest->prev = NULL; + dest->numframes = ref->numframes * loopcount; + dest->numnoloopframes = ref->numnoloopframes; + dest->duration = ref->duration; + dest->node_type = NODE_NONE; return dest; } -timeline_t* timeline_duplicate(timeline_t* ref) +timeline_t* timeline_noloop(timeline_t* ref) { timeline_t* dest; int qposbytecount; - qposbytecount = sizeof(qpos_t) * ref->numposes; + qposbytecount = sizeof(qpos_t) * ref->numnoloopframes; dest = malloc(sizeof(timeline_t)); dest->qposes = malloc(qposbytecount); @@ -215,10 +258,31 @@ timeline_t* timeline_duplicate(timeline_t* ref) memcpy(dest->qposes, ref->qposes, qposbytecount); dest->next = NULL; dest->prev = NULL; - dest->numposes = ref->numposes; + dest->numframes = ref->numnoloopframes; + dest->numnoloopframes = ref->numnoloopframes; dest->duration = ref->duration; dest->node_type = NODE_NONE; + return dest; +} + +timeline_t* timeline_duplicate(timeline_t* ref) +{ + timeline_t* dest; + int qposbytecount; + + qposbytecount = sizeof(qpos_t) * ref->numframes; + + dest = malloc(sizeof(timeline_t)); + dest->qposes = malloc(qposbytecount); + + memcpy(dest->qposes, ref->qposes, qposbytecount); + dest->next = NULL; + dest->prev = NULL; + dest->numframes = ref->numframes; + dest->numnoloopframes = ref->numnoloopframes; + dest->duration = ref->duration; + dest->node_type = NODE_NONE; return dest; } @@ -240,7 +304,7 @@ void timeline_free(timeline_t* ref) qpos_t* timeline_get_qposes_from_frame(timeline_t* timeline, int frame) { - frame = timeline_make_frame_safe(frame, timeline->numposes); + frame = timeline_make_frame_safe(frame, timeline->numframes); return timeline->qposes + frame ; } @@ -250,18 +314,10 @@ void timeline_set_mj_qpose(traj_info_t* traj_info, qpos_t* desired) mju_copy(traj_info->d->qpos, desired->q, CASSIE_QPOS_SIZE); } -void panic() -{ - fprintf(stderr, "PANIC!\n"); - exit(1); -} void timeline_set_qposes_to_pose_frame(traj_info_t* traj_info, timeline_t* timeline, int frame) { - if(!timeline) - panic(); - - frame = timeline_make_frame_safe(frame, timeline->numposes); + frame = timeline_make_frame_safe(frame, timeline->numframes); timeline_set_mj_qpose(traj_info, timeline->qposes + frame); } @@ -269,9 +325,6 @@ void timeline_set_qposes_to_pose_frame(traj_info_t* traj_info, timeline_t* timel void timeline_overwrite_frame_using_curr_pose(traj_info_t* traj_info, timeline_t* timeline, int frame) { qpos_t* qposes; - - if(!timeline) - panic(); qposes = timeline_get_qposes_from_frame(timeline, frame); diff --git a/src/timeline.h b/src/timeline.h index 45880a9..f25862f 100644 --- a/src/timeline.h +++ b/src/timeline.h @@ -21,18 +21,23 @@ typedef struct _full_traj_state_t_ full_traj_state_t; #include "timeline.h" - -timeline_t* timeline_init_with_single_pose(qpos_t* qpos, timeline_t* xcopy); +void timeiline_init_from_input_file(traj_info_t* traj_info); timeline_t* timeline_duplicate(timeline_t* ref); -void timeline_safe_link(timeline_t* next, timeline_t* prev); +void timeline_export_to_file(traj_info_t* traj_info, full_traj_state_t* fulls, int numframes); +void timeline_export(traj_info_t* traj_info, timeline_t* timeline); +uint32_t timeline_fill_full_traj_state_array(traj_info_t* traj_info, uint8_t** buf); void timeline_free(timeline_t* ref); +int timeline_get_frame_from_time(traj_info_t* traj_info); qpos_t* timeline_get_qposes_from_frame(timeline_t* timeline, int frame); -void timeline_set_qposes_to_pose_frame(traj_info_t* traj_info, timeline_t* timeline, int frame); +timeline_t* timeline_init_with_single_pose(qpos_t* qpos, timeline_t* xcopy); +timeline_t* timeline_loop(timeline_t* ref, int loopcount); +int timeline_make_frame_safe(int frame, int numframes); +timeline_t* timeline_noloop(timeline_t* ref); void timeline_overwrite_frame_using_curr_pose(traj_info_t* traj_info, timeline_t* timeline, int frame); -int timeline_make_frame_safe(int frame, int numposes); -int timeline_get_frame_from_time(traj_info_t* traj_info); +void timeline_safe_link(timeline_t* next, timeline_t* prev); +void timeline_set_mj_qpose(traj_info_t* traj_info, qpos_t* desired); +void timeline_set_qposes_to_pose_frame(traj_info_t* traj_info, timeline_t* timeline, int frame); void timeline_update_mj_poses_from_realtime(traj_info_t* traj_info); -void timeline_export(traj_info_t* traj_info, timeline_t* timeline); #endif