Commit ee4551ba authored by Arnaud Blanchard's avatar Arnaud Blanchard
Browse files

Initial commit

parents
# Set the minimum version of cmake required to build this project
cmake_minimum_required(VERSION 2.6)
project(gnuplot)
subdirs(o_gnuplot)
subdirs(o_gnuplot_poi)
Gnuplot
=======
Links
-----
- [gnuplot](http://www.gnuplot.info) Official website
- [gnuplotting](http://www.gnuplotting.org) Nice blogs with lot of original exemples
- [Impossible gnuplot graphs](http://www.phyast.pitt.edu/~zov1/gnuplot/html/intro.html) see specifically [stats function](http://www.phyast.pitt.edu/~zov1/gnuplot/patch/stats.html) (syntax is deprecated but the principle is there)
- [not so Frequently Asked Questions](http://lowrank.net/gnuplot/index-e.html)
- [gnuplot surprising](http://gnuplot-surprising.blogspot.fr) A bit old (2012) but interesting
# Copyright ETIS — ENSEA, Université de Cergy-Pontoise, CNRS (2011 - 2016)
# Author: Arnaud Blanchard (November 2016)
# This software is governed by the CeCILL v2.1 license under French law and abiding by the rules of distribution of free software.
# You can use, modify and/ or redistribute the software under the terms of the CeCILL v2.1 license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info".
# As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license,
# users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the successive licensors have only limited liability.
# In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or developing or reproducing the software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also therefore means that it is reserved for developers and experienced professionals having in-depth computer knowledge.
# Users are therefore encouraged to load and test the software's suitability as regards their requirements in conditions enabling the security of their systems and/or data to be ensured  and, more generally, to use and operate it in the same conditions as regards security.
# The fact that you are presently reading this means that you have had knowledge of the CeCILL v2.1 license and that you accept its terms.
cd `dirname $0`
echo
echo "Checking `basename $PWD`"
echo "===================="
echo
echo "No check for now"
echo
# Set the minimum version of cmake required to build this project
cmake_minimum_required(VERSION 2.6)
project(o_gnuplot)
find_package(blc_channel REQUIRED)
find_package(blc_program REQUIRED)
add_definitions(${BL_DEFINITIONS})
include_directories(${BL_INCLUDE_DIRS})
add_executable(o_gnuplot src/o_gnuplot.cpp src/graph.cpp src/history_graph.cpp)
target_link_libraries(o_gnuplot ${BL_LIBRARIES})
insatall
========
Mac OSx
-------
You need install gnuplot with qt:
brew install gnuplot --with qt
# Copyright ETIS — ENSEA, Université de Cergy-Pontoise, CNRS (2011 - 2016)
# Author: Arnaud Blanchard (November 2016)
# This software is governed by the CeCILL v2.1 license under French law and abiding by the rules of distribution of free software.
# You can use, modify and/ or redistribute the software under the terms of the CeCILL v2.1 license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info".
# As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license,
# users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the successive licensors have only limited liability.
# In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or developing or reproducing the software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also therefore means that it is reserved for developers and experienced professionals having in-depth computer knowledge.
# Users are therefore encouraged to load and test the software's suitability as regards their requirements in conditions enabling the security of their systems and/or data to be ensured  and, more generally, to use and operate it in the same conditions as regards security.
# The fact that you are presently reading this means that you have had knowledge of the CeCILL v2.1 license and that you accept its terms.
cd `dirname $0`
echo
echo "Checking `basename $PWD`"
echo "===================="
echo
echo "No check for now"
echo
# Basic Libraries And Applications for Robotics (BLAAR)
# Copyright ETIS — ENSEA, University of Cergy-Pontoise, CNRS (2011 - 2017)
# Author: Arnaud Blanchard
#
# This software is governed by the CeCILL v2.1 license under French law and abiding by the rules of distribution of free software.
# You can use, modify and/ or redistribute the software under the terms of the CeCILL v2.1 license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info".
# As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license,
# users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the successive licensors have only limited liability.
# In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or developing or reproducing the software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also therefore means that it is reserved for developers and experienced professionals having in-depth computer knowledge.
# Users are therefore encouraged to load and test the software's suitability as regards their requirements in conditions enabling the security of their systems and/or data to be ensured  and, more generally, to use and operate it in the same conditions as regards security.
# The fact that you are presently reading this means that you have had knowledge of the CeCILL v2.1 license and that you accept its terms.
#We go in blaar dir
cd $(dirname $0)/..
brew install gnuplot --with-qt
git submodule add https://framagit.org/blaar/o_gnuplot.git
./install.sh o_gnuplot
#include "blc_program.h"
#include "graph.h"
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
typedef struct history:blc_array{
blc_array *array;
void init_timer();
void start_refresh_history_chars();
void start_refresh_history_floats();
int compute_next_k();
int sampling_period, iteration, length;
size_t element_size;
unsigned long initial_us;
}type_history;
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
int k;
void type_history::init_timer(){
struct timeval initial_timer;
gettimeofday(&initial_timer, NULL);
length=dims[dims_nb-1].length;
initial_us = initial_timer.tv_sec*1000000+initial_timer.tv_usec;
k=length-1;
}
/**This is in order to take into acount the absolute time. If an iteration is longer than it should, the next one will be shorter.*/
int type_history::compute_next_k(){
div_t samples_div;
struct timeval timer;
gettimeofday(&timer, NULL);
//sample_div.quot is the theoritical iteration.
samples_div=div(timer.tv_sec*1000000+timer.tv_usec-initial_us, sampling_period);
//We try to stay in the midle of the iteration
if ((int)(iteration-samples_div.quot) >= 0) usleep((iteration+1-samples_div.quot)*sampling_period+sampling_period/2-samples_div.rem);
iteration++;
return div(samples_div.quot, length).rem;
}
void type_history::start_refresh_history_chars(){
int i, next_k;
while(1){
next_k=compute_next_k();
pthread_mutex_lock(&mutex);
if(next_k==k+1){ //normal case
FOR(i, array->total_length) chars[i*length+next_k]=array->chars[i];
}
else if ((next_k-k)>1){
color_eprintf(BLC_BRIGHT_YELLOW, "Missing '%d' samples\n", next_k-k);
FOR(i, array->total_length) memset(chars+i*length+k, array->chars[i], next_k-k+1);
}
else if (next_k==k){
color_eprintf(BLC_BRIGHT_YELLOW, "Twice the same sample iteration %d\n", iteration);
}
else FOR(i, array->total_length){ //It accross the end of the buffer
memset(chars+i*length+k, array->chars[i], length-k);
memset(chars+i*length, array->chars[i], next_k+1);
}
k=next_k;
pthread_mutex_unlock(&mutex);
}
}
void type_history::start_refresh_history_floats(){
int i, j, next_k;
while(1){
next_k=compute_next_k();
pthread_mutex_lock(&mutex);
if(next_k==k+1){ //normal case
FOR(i, array->total_length) floats[i*length+next_k]=array->floats[i];
}
else if ((next_k-k)>1){
color_eprintf(BLC_BRIGHT_YELLOW, "Missing '%d' samples\n", next_k-k);
FOR(i, array->total_length) for(j=k; j!=next_k+1; j++) floats[i*length+j]=array->floats[i];
}
else if (next_k==k){
color_eprintf(BLC_BRIGHT_YELLOW, "Twice the same sample iteration %d\n", iteration);
}
else FOR(i, array->total_length){ //It accross the end of the buffer
for(j=k; j!=length; j++) floats[i*length+j]=array->floats[i];
for(j=0; j!=next_k+1; j++) floats[i*length+j]=array->floats[i];
}
k=next_k;
pthread_mutex_unlock(&mutex);
}
}
static void *refresh_history_cb(void *history_pt){
type_history *history=(type_history*)history_pt;
history->init_timer();
switch (history->type) {
case 'UIN8': case 'INT8':
history->start_refresh_history_chars();
break;
case 'FL32':
history->start_refresh_history_floats();
break;
default:
break;
}
return NULL;
}
static void init_term(FILE *pipef, char const *title, char const* verbatim){
fprintf(pipef, "set term qt 1 noraise\n"); //Keep focus on the calling terminal
fprintf(pipef, "set datafile nofpe_trap\n"); //Speend up acquisition but crash if there is a problem with the DATA
fprintf(pipef, "set title '%s'\n", title); //axis x en y only
fprintf(pipef, "set border 3\n"); //axis x en y only
fprintf(pipef, "set title font ',20'\n");
fprintf(pipef, "set label font ',10'\n");
fprintf(pipef, "set key font ',10'\n");
fprintf(pipef, "set terminal qt noenhanced\n");//avoid interpretation of '_'
fprintf(pipef, "set style %s\n", style_option);
fprintf(pipef, "set boxwidth 0.9 relative\n");
fprintf(pipef, "set grid\n");
if (verbatim) fprintf(pipef, "%s\n", verbatim);
}
void create_graph(blc_channel *input, char const *title, int refresh_period, float min, float max, float xmin, float xmax, float label_max, char const *verbatim){
char const *gnuplot_format=NULL;
char command[LINE_MAX];
char code;
int i, offset, columns_nb=0, rows_nb=0;
FILE *pipef;
size_t element_size;
char *buffer;
SYSTEM_ERROR_CHECK(pipef=popen("gnuplot", "w"), NULL, "Calling gnuplot");
switch (input->dims_nb){
case 0:
columns_nb=1;
rows_nb=1;
break;
case 1:
columns_nb=input->dims[0].length;
rows_nb=1;
break;
case 2:
columns_nb=input->dims[0].length;
rows_nb=input->dims[1].length;
break;
default:
EXIT_ON_ARRAY_ERROR(input, "Too many dims");
break;
}
switch (input->type){
case 'UIN8':
gnuplot_format="%uchar";
element_size=sizeof(uchar);
break;
case 'INT8':
gnuplot_format="%char";
element_size=sizeof(char);
break;
case 'FL32':
gnuplot_format="%float";
element_size=sizeof(float);
break;
default: EXIT_ON_ARRAY_ERROR(input, "The type is not managed");
}
init_term(pipef, title, verbatim);
// if (min!=max) fprintf(pipef, "set yrange [%f:%f]\n", min, max);
// if (xmin!=xmax) fprintf(pipef, "set xrange [%f:%f]\n", xmin, xmax);
if (input->dims_nb==2){
// fprintf(pipef, "set xrange [%f:%f]\n", 0, 10);
/*fprintf(pipef, "set yrange [%f:%f]\n", 0, 10);*/
// fprintf(pipef, "set zrange [%f:%f]\n", min, max);
fprintf(pipef, "set view 30,190\n");
offset=snprintf(command, LINE_MAX, "splot '-' binary format='%s' array=%dx%d title 'values' with pm3d ", gnuplot_format, columns_nb, rows_nb);
}
else{
offset=snprintf(command, LINE_MAX, "plot '-' binary format='%s' record=%d using ($0*%f):1 title '%d' with %s", gnuplot_format, columns_nb, label_max/(float)columns_nb, 0, with_option);
for(i=1; i!=rows_nb; i++){
if (i<10) code=48+i;
else code=97+i-10;
offset+=snprintf(command+offset, LINE_MAX-offset, ", '-' binary format='%s' record=%d title '%c' with %s", gnuplot_format, columns_nb, code, with_option);
}
}
buffer=MANY_ALLOCATIONS(input->size, char);
blc_loop_try_add_waiting_semaphore(input->sem_new_data);
BLC_COMMAND_LOOP(refresh_period){
memcpy(buffer, input->data, input->size);
if (input->sem_ack_data) SYSTEM_ERROR_CHECK(sem_post(input->sem_ack_data), -1, NULL);
fprintf(pipef, "\n%s\n", command);
SYSTEM_ERROR_CHECK(fwrite(buffer, element_size, columns_nb*rows_nb, pipef), -1, NULL);
SYSTEM_ERROR_CHECK(fflush(pipef), -1, NULL);
}
SYSTEM_ERROR_CHECK(fclose(pipef), -1, NULL);
FREE(buffer);
}
//
// history_graph.h
// f_gnuplot
//
// Created by Arnaud Blanchard on 13/12/2016.
//
//
#ifndef HISTORY_GRAPH_H
#define HISTORY_GRAPH_H
#include "blc_channel.h"
extern char const *with_option, *style_option;
void create_history_graph(blc_channel *input, char const *title, int history_length, int refresh_period, int sampling_period, float min, float max, char const *verbatim);
void create_graph(blc_channel *input, char const *title, int refresh_period, float min, float max, float xmin, float xmax, float label_max, char const *verbatim);
#endif /* history_graph_h */
//
// history_graph.h
// f_gnuplot
//
// Created by Arnaud Blanchard on 13/12/2016.
//
//
#ifndef HISTORY_GRAPH_H
#define HISTORY_GRAPH_H
#include "blc_channel.h"
extern char const *with_option, *style_option;
void create_history_graph(blc_channel *input, char const *title, int history_length, int refresh_period, int sampling_period, float min, float max, char const *verbatim);
void create_graph(blc_channel *input, char const *title, int refresh_period, float min, float max, float xmin, float xmax, float label_max, char const *verbatim);
#endif /* history_graph_h */
#include "blc_channel.h"
#include "blc_program.h"
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>
#include "graph.h"
#include "history_graph.h"
blc_channel input;
blc_array history_array;
char const *with_option, *style_option;
int sx, sy;
int sampling_period;
int interactive_mode=0;
int final_columns_nb, final_rows_nb;
int offset=0;
int bands=1;
int dims_nb, *lengths;
double min, max;
enum {RUN, PAUSE};
int status=RUN;
void refresh_period_cb(char const*argument, void*){
sampling_period=strtol(argument, NULL, 10)*1000;
}
int main(int argc, char *argv[]){
char const *refresh_string, *min_str, *max_str, *history_str, *channel_name, *sample_string, *verbatim;
char const *xmin_str, *xmax_str, *label_max_str;
float xmin, xmax, lmax;
int status=0;
blc_program_set_description("Display the content of the blc_channel depending on its type and format");
blc_program_add_option(&min_str, 'm', "min", "FL32", "minimal value", NULL);
blc_program_add_option(&max_str, 'M', "max", "FL32", "maximal value", NULL);
blc_program_add_option(&sample_string, 'p', "period", "UI32", "sampling period in ms or history", "10");
blc_program_add_option(&style_option, 's', "style", "string", "gnuplot option set option (style, boxwidth, ...)", "fill solid");
blc_program_add_option(&verbatim, 't', "text", "string", "text directly put on the gnuplot set commandline", NULL);
blc_program_add_option(&with_option, 'w', "with", "string", "gnuplot option with (lines, boxes, dots,...)", "lines");
blc_program_add_option(&xmin_str, 'x', "xmin", "FL32", "minimal abscissa value", NULL);
blc_program_add_option(&xmax_str, 'X', "xmax", "FL32", "maximal abscissa value", NULL);
blc_program_add_option(&label_max_str, 'L', "label-max", "FL32", "display the absisca scale in order to have the last value as label-max ", NULL);
blc_program_add_option(&history_str, 'H', "history", "UI32", "size of the history", NULL);
blc_program_add_option(&refresh_string, 'P', "period", "UI32", "graph refresh period in ms", "100");
blc_program_add_parameter(&channel_name, "blc_channel", 1, "channel you want to graph", NULL);
// blc_program_add_option(&size_str, 's', "size", "UI32[xUI32]", "size of the matrix", NULL);
blc_program_init(&argc, &argv, blc_quit);
/*
if (size_str){
dims_nb=blc_sscan_dims(&lengths, size_str);
switch(dims_nb){
case 1: final_columns_nb=lengths[0];
final_rows_nb=1;
break;
case 2:final_columns_nb=lengths[0];
final_rows_nb=lengths[1];
break;
default:EXIT_ON_ERROR("Size of dim %d is not yet managed in size '%s'.", dims_nb, size_str);
}
FREE(lengths);
}*/
input.open(channel_name, BLC_CHANNEL_READ);
if (min_str) min=strtof(min_str, NULL);
else switch (input.type){
case 'UIN8':case 'UI16':case 'UI32':case 'IN16':case 'IN32':case 'IN64':case 'FL32':case'FL64':min=0.0;break;
case 'INT8':min=INT8_MIN;break;
default: EXIT_ON_CHANNEL_ERROR(&input, "No default min value");
}
if (max_str) max=strtof(max_str, NULL);
else switch (input.type){
case 'UIN8':max=UINT8_MAX;break;
case 'INT8':max=INT8_MAX;break;
case 'FL32': case 'FL64':max=1.0;break;
default: EXIT_ON_CHANNEL_ERROR(&input, "No default max value");
}
if (xmin_str) SSCANF(1, xmin_str, "%f", &xmin);
else xmin=0;
if (xmax_str) SSCANF(1, xmax_str, "%f", &xmax);
else xmax=input.total_length;
if (label_max_str) {
SSCANF(1, label_max_str, "%f", &lmax);
if (xmax_str==NULL) xmax=lmax; //We still want to see all the graph
}
else lmax=input.total_length;
sampling_period=strtol(refresh_string, NULL, 10)*1000;
fprintf(stderr, "=== %s: ", blc_program_name);
if (history_str) fprintf(stderr, "sample period (%.3fms), history(%s), ", sampling_period/1000.f, history_str);
fprintf(stderr, "min(%.3lf), max(%.2lf) === \n", min, max);
blc_command_add("p", refresh_period_cb, "ms", "sampling period", NULL);
if (history_str) create_history_graph(&input, input.name+1, strtol(history_str, NULL, 10), sampling_period, strtol(sample_string, NULL, 10)*1000, min, max, verbatim);
else create_graph(&input, input.name+1, sampling_period, min, max, xmin, xmax, lmax, verbatim);
return (status);
}
# Set the minimum version of cmake required to build this project
cmake_minimum_required(VERSION 2.6)
project(o_gnuplot_poi)
find_package(blc_channel REQUIRED)
find_package(blc_program REQUIRED)
add_definitions(${BL_DEFINITIONS})
include_directories(${BL_INCLUDE_DIRS})
add_executable(o_gnuplot_poi o_gnuplot_poi.cpp graph.cpp)
target_link_libraries(o_gnuplot_poi ${BL_LIBRARIES})
#include "blc_program.h"
#include "graph.h"
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
static void init_term(FILE *pipef, char const *title, char const* verbatim){
fprintf(pipef, "set term qt 1 noraise\n"); //Keep focus on the calling terminal
fprintf(pipef, "set title '%s'\n", title); //axis x en y only
fprintf(pipef, "set border 3\n"); //axis x en y only
fprintf(pipef, "set title font ',20'\n");
fprintf(pipef, "set label font ',10'\n");
fprintf(pipef, "set key font ',10'\n");
fprintf(pipef, "set terminal qt noenhanced\n");//avoid interpretation of '_'
fprintf(pipef, "set boxwidth 0.9 relative\n");
fprintf(pipef, "set grid\n");
fprintf(pipef, "set yrange [* : *] reverse\n");
if (verbatim) fprintf(pipef, "%s\n", verbatim);
}
void create_poi_loop(unsigned char *image, int width, int height, uint16_t *coords, int points_nb){
char command[LINE_MAX];
FILE *pipef;
int text_offset=0;
SYSTEM_ERROR_CHECK(pipef=popen("gnuplot", "w"), NULL, "calling gnuplot");
init_term(pipef, "image", "");
fprintf(pipef, "set palette gray\n");
// fprintf(pipef, "set view 30,190\n");
text_offset=snprintf(command, LINE_MAX, "plot '-' binary format='%%uchar' array=%dx%d title 'image' with image ", width, height);
text_offset=snprintf(command+text_offset, LINE_MAX, ", '-' binary format='%%uint16%%uint16' record=%d using 1:2:($0) title 'points of interest' with linespoints palette ", points_nb);
BLC_COMMAND_LOOP(0){
fprintf(pipef, "%s\n", command);
SYSTEM_ERROR_CHECK(fwrite(image, sizeof(uchar), width*height, pipef), -1, NULL);
SYSTEM_ERROR_CHECK(fwrite(coords, sizeof(uint16_t), 2*points_nb, pipef), -1, NULL);
SYSTEM_ERROR_CHECK(fflush(pipef), -1, NULL);
}
SYSTEM_ERROR_CHECK(fclose(pipef), -1, NULL);
}
//
// history_graph.h
// f_gnuplot
//
// Created by Arnaud Blanchard on 13/12/2016.
//
//
#ifndef GRAPH_H
#define GRAPH_H
void create_poi_loop(unsigned char *image, int width, int height, uint16_t *coords, int points_nb);
#endif /* history_graph_h */
#include "blc_channel.h"
#include "blc_program.h"
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>
#include "graph.h"
char const *with_option, *style_option;
int sx, sy;
int sampling_period;
int interactive_mode=0;
int final_columns_nb, final_rows_nb;
int offset=0;
int bands=1;
int dims_nb, *lengths;
double min, max;
enum {RUN, PAUSE};
int status=RUN;
void refresh_period_cb(char const*argument, void*){
sampling_period=strtol(argument, NULL, 10)*1000;
}
int main(int argc, char *argv[]){
blc_channel input_image, poi;
char const *poi_name, *input_image_name;
<