libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

cmGnuPlot.c 29KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  1. //| Copyright: (C) 2009-2020 Kevin Larke <contact AT larke DOT org>
  2. //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
  3. #include "cmPrefix.h"
  4. #include "cmGlobal.h"
  5. #include "cmRpt.h"
  6. #include "cmMem.h"
  7. #include "cmMallocDebug.h"
  8. #include "cmGnuPlot.h"
  9. #include <errno.h>
  10. #include <signal.h>
  11. #include <sys/wait.h>
  12. #include <unistd.h> // read/write/close
  13. enum
  14. {
  15. kX_PdFl = 0x01, // the data set contains explicit x coordinates
  16. kY_PdFl = 0x02, // the data set contains explicit y coordinates
  17. kZ_PdFl = 0x04, // the data set contains explicit z coordinates
  18. kImpulse_PdFl = 0x08, // plot using the gnuplot impulse style
  19. kInvalidLineId = -2,
  20. kSolidLineId = -1,
  21. kDashedLineId = 0
  22. };
  23. typedef struct
  24. {
  25. unsigned flags; // see kXXX_PdFl
  26. char* legendStrH; // plot legend label for this data set
  27. char* colorStrH; // string containing a gnuplot color spec
  28. double* xyzMtxPtr; // data to be plotted contained in a column major mtx with 1,2, or 3 columns
  29. unsigned rn; //
  30. unsigned cn; //
  31. int lineId; // gnuplot line style id
  32. int pointId; // gnuplot point style id
  33. } cmPlotData;
  34. //----------------------------------------------------------------------------------------------------------
  35. enum
  36. {
  37. kTitleIdx = 0,
  38. kXLabelIdx,
  39. kYLabelIdx,
  40. kZLabelIdx,
  41. kPlotStrCnt
  42. };
  43. enum
  44. {
  45. kXMinRangeIdx,
  46. kXMaxRangeIdx,
  47. kYMinRangeIdx,
  48. kYMaxRangeIdx,
  49. kZMinRangeIdx,
  50. kZMaxRangeIdx,
  51. kRangeCnt
  52. };
  53. // There is one cmPlot per sub-plot. These records are held in cmPlotPage.plotPtrArray
  54. typedef struct
  55. {
  56. cmChar_t* strArray[ kPlotStrCnt ]; // an array of various labels and titles
  57. double range[ kRangeCnt ]; // a set of range limits for each dimension (used to automatically fill in coord values when they are not explicitely given)
  58. unsigned rowIdx; // the plot page row index of this sub-plot
  59. unsigned colIdx; // the plot page col index of this sub-plot
  60. cmPlotData** dataPtrArray; // pointer to data sets containing data for this sub-plot
  61. unsigned dataCnt;
  62. } cmPlot;
  63. //----------------------------------------------------------------------------------------------------------
  64. // The plotter contains a single cmPlotPage (pointed to by _cmpp).
  65. typedef struct
  66. {
  67. unsigned rowCnt; // number of rows of sub-plots
  68. unsigned colCnt; // number of columns of sub-plots
  69. cmChar_t* titleStrH; // page title
  70. int pipeFd[2]; // communication pipe with gnuplot process
  71. int pid; // process id of the gnuplot process
  72. cmPlot** plotPtrArray; // vector of sub-plots
  73. unsigned plotCnt; //
  74. unsigned curPlotIdx; // the sub-plot currently receiving plotting commands and data
  75. } cmPlotPage;
  76. cmPlotPage _cmPlotPage = { 0,0,NULL,{-1,-1},-1,NULL,0,cmInvalidIdx};
  77. cmPlotPage* _cmpp = NULL;
  78. void _cmPrintf( int fd, const char* fmt, ... )
  79. {
  80. const int bufCnt = 255;
  81. char buf[bufCnt+1];
  82. buf[bufCnt]='\0';
  83. va_list vl;
  84. va_start(vl,fmt);
  85. int n = vsnprintf(buf,bufCnt,fmt,vl);
  86. assert( n < 255 );
  87. write(fd,buf,n);
  88. va_end(vl);
  89. }
  90. // unexpected event signal handler
  91. void cmPlotSignalHandler( int sig )
  92. {
  93. switch( sig )
  94. {
  95. case SIGCHLD:
  96. if( _cmpp != NULL )
  97. _cmpp->pid = -1;
  98. break;
  99. case SIGBUS:
  100. case SIGSEGV:
  101. case SIGTERM:
  102. cmPlotFinalize();
  103. break;
  104. }
  105. }
  106. unsigned _cmPlotError( cmPlotPage* p, unsigned rc, bool sysErrFl, const char* fmt, ... )
  107. {
  108. va_list vl;
  109. va_start(vl,fmt);
  110. fprintf(stderr,"cmPlot Error:");
  111. vfprintf(stderr,fmt,vl);
  112. if( sysErrFl )
  113. fprintf(stderr," System Msg:%s\n",strerror(errno));
  114. va_end(vl);
  115. return rc;
  116. }
  117. //----------------------------------------------------------------------------------------------------------
  118. void _cmPlotDataInit( cmPlotData* p )
  119. {
  120. p->flags = 0;
  121. p->legendStrH = NULL;
  122. p->colorStrH = NULL;
  123. p->xyzMtxPtr = NULL;
  124. p->rn = 0;
  125. p->cn = 0;
  126. p->lineId = kInvalidLineId;
  127. p->pointId = kInvalidPlotPtId;
  128. }
  129. void _cmPlotDataCons( cmPlotData* p, unsigned flags, const char* legendStr, const char* colorStr, double* mtxPtr, unsigned rn, unsigned cn, unsigned styleFlags )
  130. {
  131. p->flags = flags + (cmIsFlag(styleFlags,kImpulsePlotFl) ? kImpulse_PdFl : 0);
  132. p->legendStrH = cmMemAllocStr(legendStr);
  133. p->colorStrH = cmMemAllocStr(colorStr);
  134. p->xyzMtxPtr = mtxPtr;
  135. p->rn = rn;
  136. p->cn = cn;
  137. p->lineId = ((styleFlags & kPlotLineMask) >> kPlotLineShift) - 2; // convert from the interface style flags to gnuplot id's
  138. p->pointId = styleFlags & kPlotPtMask;
  139. }
  140. void _cmPlotDataFree( cmPlotData* p )
  141. {
  142. cmMemPtrFree(&p->legendStrH);
  143. cmMemPtrFree(&p->colorStrH);
  144. //cmDM_Free(&p->xyzMtxPtr);
  145. cmMemPtrFree(&p->xyzMtxPtr);
  146. }
  147. /*
  148. bool _cmPlotDataFreeFE( unsigned i, cmPlotData* p, void *vp )
  149. {
  150. _cmPlotDataFree(p);
  151. return true;
  152. }
  153. */
  154. //----------------------------------------------------------------------------------------------------------
  155. void _cmPlotInit( cmPlot* p )
  156. {
  157. unsigned i;
  158. for(i=0; i<kPlotStrCnt; ++i)
  159. p->strArray[i] = NULL;
  160. for(i=0; i<kRangeCnt; ++i)
  161. p->range[i] = 0;
  162. p->rowIdx = cmInvalidIdx;
  163. p->colIdx = cmInvalidIdx;
  164. p->dataPtrArray = NULL;
  165. p->dataCnt = 0;
  166. }
  167. void _cmPlotCons( cmPlot* p, unsigned ri, unsigned ci )
  168. {
  169. p->rowIdx = ri;
  170. p->colIdx = ci;
  171. assert( p->dataPtrArray == NULL );
  172. //p->dataPtrArray = cmPlotDataVect_AllocEmpty();
  173. }
  174. void _cmPlotInsertData( cmPlot* p, cmPlotData* rp)
  175. {
  176. cmPlotData* nrp = cmMemAlloc(cmPlotData,1);
  177. *nrp = *rp;
  178. p->dataPtrArray = cmMemResizeP( cmPlotData*, p->dataPtrArray, p->dataCnt + 1 );
  179. p->dataPtrArray[ p->dataCnt ] = nrp;
  180. ++p->dataCnt;
  181. }
  182. void _cmPlotClearData( cmPlot* p )
  183. {
  184. unsigned i;
  185. // release the strings
  186. for(i=0; i<kPlotStrCnt; ++i)
  187. cmMemPtrFree(&p->strArray[i]);
  188. // release the plot data
  189. for(i=0; i<p->dataCnt; ++i)
  190. {
  191. _cmPlotDataFree( p->dataPtrArray[i] );
  192. cmMemPtrFree( &p->dataPtrArray[i] );
  193. }
  194. // set the data cnt to 0
  195. p->dataCnt = 0;
  196. }
  197. void _cmPlotFree( cmPlot* p )
  198. {
  199. _cmPlotClearData(p);
  200. cmMemPtrFree(&p->dataPtrArray);
  201. }
  202. //----------------------------------------------------------------------------------------------------------
  203. void _cmPlotPageInit( cmPlotPage* rp )
  204. {
  205. rp->rowCnt = 0;
  206. rp->colCnt = 0;
  207. rp->titleStrH = NULL;
  208. rp->pipeFd[0] = -1;
  209. rp->pipeFd[1] = -1;
  210. rp->pid = -1;
  211. rp->plotPtrArray = NULL;
  212. rp->curPlotIdx = cmInvalidIdx;
  213. }
  214. cmRC_t _cmPlotPageCons( cmPlotPage* rp, int pid, int inFd, int outFd, const char* terminalStr )
  215. {
  216. cmRC_t rc = kOkPlRC;
  217. rp->pid = pid;
  218. rp->pipeFd[0] = inFd;
  219. rp->pipeFd[1] = outFd;
  220. rp->plotPtrArray = NULL; //cmPlotVect_AllocEmpty();
  221. if(terminalStr != NULL )
  222. _cmPrintf( outFd, "set terminal %s\n",terminalStr );
  223. return rc;
  224. }
  225. void _cmPlotPageSetup( cmPlotPage* rp, const char* title, unsigned rowCnt, unsigned colCnt )
  226. {
  227. unsigned i,ri, ci;
  228. rp->titleStrH = cmMemResizeStr(rp->titleStrH,title); // acStringAssign(&rp->titleStrH,title);
  229. rp->rowCnt = rowCnt;
  230. rp->colCnt = colCnt;
  231. rp->curPlotIdx = rowCnt*colCnt > 0 ? 0 : cmInvalidIdx;
  232. // free any resources held by each plot and empty the plot array
  233. for(i=0; i<rp->plotCnt; ++i)
  234. {
  235. _cmPlotFree(rp->plotPtrArray[i]);
  236. cmMemPtrFree( &rp->plotPtrArray[i] );
  237. }
  238. rp->plotCnt = 0;
  239. // insert rowCnt*colCnt blank plot records
  240. // allocate the plotVect[]
  241. rp->plotPtrArray = cmMemResizeZ( cmPlot*, rp->plotPtrArray, rowCnt*colCnt );
  242. rp->plotCnt = rowCnt * colCnt;
  243. // initialize each cmPlot record
  244. for(ri=0,i=0; ri<rowCnt; ++ri)
  245. for(ci=0; ci<colCnt; ++ci,++i)
  246. {
  247. rp->plotPtrArray[i] = cmMemAllocZ(cmPlot,1);
  248. _cmPlotInit( rp->plotPtrArray[i]);
  249. _cmPlotCons( rp->plotPtrArray[i], ri, ci);
  250. }
  251. }
  252. cmRC_t _cmPlotPageFree( cmPlotPage* rp )
  253. {
  254. unsigned i;
  255. cmRC_t rc = kOkPlRC;
  256. cmMemPtrFree(&rp->titleStrH);
  257. //acStringDelete( &rp->titleStrH );
  258. // if the plot process was successfully started - stop it here
  259. if( rp->pid > 0)
  260. {
  261. int rc;
  262. kill(rp->pid,SIGKILL);
  263. wait(&rc);
  264. rp->pid = -1;
  265. }
  266. // close the pipe input to the plot process
  267. for(i=0; i<2; ++i)
  268. {
  269. if( rp->pipeFd[i] != -1 )
  270. if( close(rp->pipeFd[i]) == -1 )
  271. rc = _cmPlotError(rp,kPipeCloseFailedPlRC,true,"Pipe %i close() failed.",i);
  272. rp->pipeFd[i] = -1;
  273. }
  274. // deallocate the plot array
  275. if( rp->plotPtrArray != NULL )
  276. {
  277. for(i=0; i<rp->plotCnt; ++i)
  278. {
  279. _cmPlotFree(rp->plotPtrArray[i] );
  280. cmMemPtrFree(&rp->plotPtrArray[i]);
  281. }
  282. cmMemPtrFree(&rp->plotPtrArray);
  283. rp->plotCnt = 0;
  284. }
  285. return rc;
  286. }
  287. //----------------------------------------------------------------------------------------------------------
  288. cmRC_t cmPlotInitialize( const char* terminalStr )
  289. {
  290. cmRC_t rc = kOkPlRC;
  291. // if this is the first call to this function
  292. if( _cmpp == NULL )
  293. {
  294. struct sigaction sa;
  295. _cmpp = &_cmPlotPage;
  296. _cmPlotPageInit(_cmpp);
  297. sa.sa_handler = cmPlotSignalHandler;
  298. sigemptyset(&sa.sa_mask);
  299. if (sigaction(SIGBUS, &sa, NULL) == -1)
  300. {
  301. rc = _cmPlotError(_cmpp,kSignalFailedPlRC,true,"sigaction(SIGBUS) failed.");
  302. goto errLabel;
  303. }
  304. sa.sa_handler = cmPlotSignalHandler;
  305. sigemptyset(&sa.sa_mask);
  306. if (sigaction(SIGSEGV, &sa, NULL) == -1)
  307. {
  308. rc = _cmPlotError(_cmpp,kSignalFailedPlRC,true,"sigaction(SIGSEGV) failed.");
  309. goto errLabel;
  310. }
  311. sa.sa_handler = cmPlotSignalHandler;
  312. sigemptyset(&sa.sa_mask);
  313. if (sigaction(SIGTERM, &sa, NULL) == -1)
  314. {
  315. rc = _cmPlotError(_cmpp,kSignalFailedPlRC,true,"sigaction(SIGTERM) failed.");
  316. goto errLabel;
  317. }
  318. sa.sa_handler = cmPlotSignalHandler;
  319. sigemptyset(&sa.sa_mask);
  320. if (sigaction(SIGCHLD, &sa, NULL) == -1)
  321. {
  322. rc = _cmPlotError(_cmpp,kSignalFailedPlRC,true,"sigaction(SIGCHLD) failed.");
  323. goto errLabel;
  324. }
  325. }
  326. else // if this is the second or greater call to this function
  327. {
  328. if((rc = cmPlotFinalize()) != kOkPlRC )
  329. return rc;
  330. }
  331. int pipeFD[2];
  332. // create the pipe
  333. if( pipe(pipeFD) == -1 )
  334. {
  335. rc = _cmPlotError(_cmpp,kPipeFailedPlRC,true,"pipe() failed.");
  336. goto errLabel;
  337. }
  338. int pid;
  339. // create the child proces
  340. switch( pid = fork() )
  341. {
  342. case -1:
  343. printf("Error\n");
  344. rc = _cmPlotError(_cmpp,kForkFailedPlRC,true,"fork() failed.");
  345. goto errLabel;
  346. break;
  347. case 0:
  348. close(fileno(stdin)); // close stdin
  349. dup(pipeFD[0]); // replace stdin with the pipe input
  350. execlp("gnuplot","gnuplot",NULL); // start gnuplot
  351. // under normal conditions execlp() should never return
  352. rc = _cmPlotError(_cmpp,kExecFailedPlRC,true,"exec() failed.");
  353. goto errLabel;
  354. break;
  355. default:
  356. // normal return for parent process
  357. rc = _cmPlotPageCons(_cmpp,pid,pipeFD[0],pipeFD[1], terminalStr );
  358. break;
  359. }
  360. return rc;
  361. errLabel:
  362. cmPlotFinalize();
  363. return rc;
  364. }
  365. cmRC_t cmPlotFinalize()
  366. {
  367. cmRC_t rc = kOkPlRC, rc0;
  368. struct sigaction sa;
  369. if( _cmpp == NULL )
  370. return kOkPlRC;
  371. // install some unexpected event signal handlers to clean up if the application
  372. // process crashes prior to calling cmPlotFinalize(). This will prevent unconnected gnuplot
  373. // processes from being left in the process list.
  374. sa.sa_handler = SIG_DFL;
  375. sigemptyset(&sa.sa_mask);
  376. if( sigaction( SIGCHLD,&sa,NULL) == -1 )
  377. rc =_cmPlotError(_cmpp,kSignalFailedPlRC,true,"sigaction(SIGCHLD) restore failed.");
  378. if( sigaction( SIGTERM,&sa,NULL) == -1 )
  379. rc =_cmPlotError(_cmpp,kSignalFailedPlRC,true,"sigaction(SIGTERM) restore failed.");
  380. if( sigaction( SIGSEGV,&sa,NULL) == -1 )
  381. rc =_cmPlotError(_cmpp,kSignalFailedPlRC,true,"sigaction(SIGSEGV) restore failed.");
  382. if( sigaction( SIGBUS,&sa,NULL) == -1 )
  383. rc =_cmPlotError(_cmpp,kSignalFailedPlRC,true,"sigaction(SIGBUS) restore failed.");
  384. // restore the child termination signal handler
  385. signal(SIGCHLD,SIG_DFL);
  386. rc0 = _cmPlotPageFree(_cmpp);
  387. return rc==kOkPlRC ? rc0 : rc;
  388. }
  389. cmRC_t cmPlotInitialize2( const char* terminalStr, const char* title, unsigned rowCnt, unsigned colCnt )
  390. {
  391. cmRC_t rc;
  392. if((rc = cmPlotInitialize(terminalStr)) != cmOkRC )
  393. return rc;
  394. return cmPlotSetup(title,rowCnt,colCnt);
  395. }
  396. cmRC_t cmPlotSetup( const char* title, unsigned rowCnt, unsigned colCnt )
  397. {
  398. _cmPlotPageSetup( _cmpp,title,rowCnt,colCnt);
  399. return kOkPlRC;
  400. }
  401. // called to locate a cmPlot given plot row/col indexes
  402. unsigned _cmRowColToPlotIndex( cmPlotPage* p, unsigned ri, unsigned ci )
  403. {
  404. unsigned i;
  405. for(i=0; i<_cmpp->plotCnt; ++i)
  406. if( _cmpp->plotPtrArray[i]->rowIdx==ri && _cmpp->plotPtrArray[i]->colIdx==ci )
  407. return i;
  408. _cmPlotError(_cmpp,kPlotNotFoundPlRC,false,"No plot exists at row:%i and col:%i\n",ri,ci);
  409. return cmInvalidIdx;
  410. }
  411. cmRC_t cmPlotSelectSubPlot( unsigned ri, unsigned ci )
  412. {
  413. unsigned i;
  414. if((i= _cmRowColToPlotIndex( _cmpp, ri, ci ) ) != cmInvalidIdx )
  415. _cmpp->curPlotIdx = i;
  416. return kOkPlRC;
  417. }
  418. cmPlot* _cmPlotGetCurPlotPtr()
  419. {
  420. if( _cmpp->curPlotIdx == cmInvalidIdx )
  421. {
  422. _cmPlotError(_cmpp,kNoCurPlotPlRC,false,"No plot exists for the current page.");
  423. assert(0);
  424. return NULL;
  425. };
  426. assert( _cmpp->curPlotIdx < _cmpp->plotCnt );
  427. cmPlot* p = _cmpp->plotPtrArray[_cmpp->curPlotIdx];
  428. assert( p != NULL );
  429. return p;
  430. }
  431. cmRC_t cmPlotSetLabels( const char* titleStr, const char* xLabelStr, const char* yLabelStr, const char* zLabelStr )
  432. {
  433. cmPlot* p = _cmPlotGetCurPlotPtr();
  434. p->strArray[kTitleIdx] = cmMemAllocStr( titleStr ); // acStringAssign( &p->strArray[ kTitleIdx ], titleStr );
  435. p->strArray[kXLabelIdx] = cmMemAllocStr( xLabelStr ); // acStringAssign( &p->strArray[ kXLabelIdx ], xLabelStr );
  436. p->strArray[kYLabelIdx] = cmMemAllocStr( yLabelStr ); // acStringAssign( &p->strArray[ kYLabelIdx ], yLabelStr );
  437. p->strArray[kZLabelIdx] = cmMemAllocStr( zLabelStr ); //acStringAssign( &p->strArray[ kZLabelIdx ], zLabelStr );
  438. return kOkPlRC;
  439. }
  440. cmRC_t cmPlotSetRange( double xMin, double xMax, double yMin, double yMax, double zMin, double zMax )
  441. {
  442. cmPlot* p = _cmPlotGetCurPlotPtr();
  443. if( xMin != 0 || xMax != 0 )
  444. {
  445. p->range[ kXMinRangeIdx ] = xMin;
  446. p->range[ kXMaxRangeIdx ] = xMax;
  447. }
  448. if( yMin != 0 || yMax != 0 )
  449. {
  450. p->range[ kYMinRangeIdx ] = yMin;
  451. p->range[ kYMaxRangeIdx ] = yMax;
  452. }
  453. if( zMin != 0 || zMax != 0 )
  454. {
  455. p->range[ kZMinRangeIdx ] = zMin;
  456. p->range[ kZMaxRangeIdx ] = zMax;
  457. }
  458. return kOkPlRC;
  459. }
  460. void cmPlot2DLine( const float* x, const float* y, unsigned n, const char* color, int lineType, int lineWidth, int pointType )
  461. {
  462. //char cmd[] = "reset\nset size 1,1\nset origin 0,0\nset multiplot layout 1,1\nplot '-' binary array=16 format='%float' origin=(16,0) dx=10 using 1 with lines\n";
  463. char cmd[] = "reset\nset size 1,1\nset origin 0,0\nset multiplot layout 1,1\nplot '-' binary record=16 format='%float' using 1:2 with lines\n";
  464. char cmd2[] = "unset multiplot\n";
  465. unsigned i;
  466. int rc = write(_cmpp->pipeFd[1],cmd,strlen(cmd));
  467. //int rc = fprintf(fp,"%s",cmd);
  468. for( i=0; i<n; ++i)
  469. {
  470. write(_cmpp->pipeFd[1],x+i,sizeof(float));
  471. write(_cmpp->pipeFd[1],y+i,sizeof(float));
  472. }
  473. write(_cmpp->pipeFd[1],cmd2,strlen(cmd2));
  474. printf("%i %s",rc,cmd);
  475. }
  476. void cmPlot2DLine1( const float* x, const float* y, unsigned n, const char* color, int lineType, int lineWidth, int pointType )
  477. {
  478. //char cmd[] = "reset\nset size 1,1\nset origin 0,0\nset multiplot layout 1,1\nplot '/home/kevin/src/gnuplot/data1.bin' binary record=16x2\n";
  479. char cmd[] = "reset\nset size 1,1\nset origin 0,0\nset multiplot layout 1,1\nplot '-' binary record=16 format='%float' using 1:2 with lines\n";
  480. char cmd2[] = "unset multiplot\n";
  481. unsigned i;
  482. int rc = write(_cmpp->pipeFd[1],cmd,strlen(cmd));
  483. //int rc = fprintf(fp,"%s",cmd);
  484. for( i=0; i<n; ++i)
  485. {
  486. write(_cmpp->pipeFd[1],x+i,sizeof(float));
  487. write(_cmpp->pipeFd[1],y+i,sizeof(float));
  488. }
  489. write(_cmpp->pipeFd[1],cmd2,strlen(cmd2));
  490. printf("%i %s",rc,cmd);
  491. }
  492. /// Clear the current current subplot
  493. cmRC_t cmPlotClear()
  494. {
  495. cmPlot* p = _cmPlotGetCurPlotPtr();
  496. _cmPlotClearData(p);
  497. return kOkPlRC;
  498. }
  499. void _cmPlotInsertDataRecd( cmPlot* p, unsigned flags, const char* legendStr, const char* colorStr, unsigned styleFlags, double* mtxPtr, unsigned rn, unsigned cn )
  500. {
  501. cmPlotData r;
  502. _cmPlotDataInit(&r);
  503. _cmPlotDataCons(&r,flags,legendStr,colorStr,mtxPtr,rn,cn,styleFlags);
  504. _cmPlotInsertData(p,&r);
  505. }
  506. cmRC_t cmPlotLineF( const char* legendStr, const float* x, const float* y, const float* z, unsigned n, const char* colorStr, unsigned styleFlags )
  507. {
  508. cmPlot* p = _cmPlotGetCurPlotPtr();
  509. unsigned flags = 0;
  510. unsigned rn = 0;
  511. unsigned ri = 0;
  512. const float* array[3] = {x,y,z};
  513. unsigned i;
  514. // determine which data vectors were provided
  515. for(i=0; i<3; ++i)
  516. if( array[i] != NULL )
  517. {
  518. ++rn;
  519. switch(i)
  520. {
  521. case 0: flags = cmSetFlag(flags,kX_PdFl); break;
  522. case 1: flags = cmSetFlag(flags,kY_PdFl); break;
  523. case 2: flags = cmSetFlag(flags,kZ_PdFl); break;
  524. default:
  525. {assert(0);}
  526. }
  527. }
  528. // create the matrix to hold the data
  529. double* mtxPtr = cmMemAlloc(double,rn*n);
  530. // copy the data into the matrix
  531. for(i=0; i<3; ++i)
  532. if( array[i] != NULL )
  533. {
  534. unsigned ci;
  535. for(ci=0; ci<n; ++ci)
  536. mtxPtr[ ci*rn + ri ] = array[i][ci];
  537. ++ri;
  538. }
  539. // store the a record to represent this line
  540. _cmPlotInsertDataRecd(p, flags, legendStr, colorStr, styleFlags, mtxPtr, rn, n );
  541. return kOkPlRC;
  542. }
  543. cmRC_t cmPlotLineD( const char* legendStr, const double* x, const double* y, const double* z, unsigned n, const char* colorStr, unsigned styleFlags )
  544. {
  545. cmPlot* p = _cmPlotGetCurPlotPtr();
  546. unsigned flags = 0;
  547. unsigned rn = 0;
  548. unsigned ri = 0;
  549. const double* array[3] = { x,y,z};
  550. unsigned i;
  551. // determine wihc data vectors were provided
  552. for(i=0; i<3; ++i)
  553. if( array[i] != NULL )
  554. {
  555. ++rn;
  556. switch(i)
  557. {
  558. case 0: flags = cmSetFlag(flags,kX_PdFl); break;
  559. case 1: flags = cmSetFlag(flags,kY_PdFl); break;
  560. case 2: flags = cmSetFlag(flags,kZ_PdFl); break;
  561. default:
  562. {assert(0);}
  563. }
  564. }
  565. // create the matrix to hold the data
  566. double* mtxPtr = cmMemAlloc(double,rn*n);
  567. // copy the data into the matrix
  568. for(i=0; i<3; ++i)
  569. if( array[i] != NULL )
  570. {
  571. unsigned ci;
  572. for(ci=0; ci<n; ++ci)
  573. mtxPtr[ ci*rn + ri ] = array[i][ci];
  574. ++ri;
  575. }
  576. // store the a record to represent this line
  577. _cmPlotInsertDataRecd(p, flags, legendStr, colorStr, styleFlags, mtxPtr, rn, n );
  578. return kOkPlRC;
  579. }
  580. cmRC_t cmPlotLineMD( const double* x, const double* y, const double* z, unsigned rn, unsigned cn, unsigned styleFlags )
  581. {
  582. cmRC_t rc;
  583. unsigned i;
  584. for(i=0; i<cn; ++i)
  585. if((rc = cmPlotLineD( NULL, x==NULL ? NULL : x+(i*rn), y==NULL ? NULL : y+(i*rn), z==NULL ? NULL : z+(i*rn), rn, NULL, styleFlags )) != cmOkRC )
  586. return rc;
  587. return cmOkRC;
  588. }
  589. const double* _cmPrintData( int fd, unsigned i, const double* p, double minV, double fact )
  590. {
  591. if( p != NULL )
  592. _cmPrintf(fd,"%f ",*p++);
  593. else
  594. if( fact != 0 )
  595. {
  596. double v = minV + (fact * i );
  597. _cmPrintf(fd,"%f ",v);
  598. }
  599. return p;
  600. }
  601. cmRC_t _cmPlotDraw(int fd, bool printDataFl )
  602. {
  603. unsigned ri,ci,di;
  604. _cmPrintf(fd,"reset\n");
  605. _cmPrintf(fd,"set size 1,1\n");
  606. _cmPrintf(fd,"set origin 0,0\n");
  607. _cmPrintf(fd,"set multiplot layout %i,%i\n",_cmpp->rowCnt,_cmpp->colCnt);
  608. for(ri=0; ri<_cmpp->rowCnt; ++ri)
  609. for(ci=0; ci<_cmpp->colCnt; ++ci)
  610. {
  611. // get the plot at ri,ci
  612. unsigned plotIdx = _cmRowColToPlotIndex(_cmpp,ri,ci);
  613. assert( plotIdx != cmInvalidIdx );
  614. cmPlot* p = _cmpp->plotPtrArray[plotIdx];
  615. // get the count of data sets assigned to this plot
  616. unsigned dataCnt = p->dataCnt;
  617. if( dataCnt > 0 )
  618. {
  619. bool printPlotKeywordFl = false;
  620. // note which ranges are valid
  621. bool isXRangeFl = p->range[ kXMinRangeIdx ] != 0 || p->range[ kXMaxRangeIdx != 0 ];
  622. bool isYRangeFl = p->range[ kYMinRangeIdx ] != 0 || p->range[ kYMaxRangeIdx != 0 ];
  623. bool isZRangeFl = p->range[ kZMinRangeIdx ] != 0 || p->range[ kZMaxRangeIdx != 0 ];
  624. // set the plot title
  625. if( p->strArray[kTitleIdx] != NULL )
  626. _cmPrintf(fd,"set title '%s'\n",(p->strArray[kTitleIdx]));
  627. else
  628. {
  629. // if this is a one plot page use the page title as the plot title
  630. if( _cmpp->titleStrH != NULL && _cmpp->rowCnt==1 && _cmpp->colCnt == 1 )
  631. _cmPrintf(fd,"set title '%s'\n", _cmpp->titleStrH );
  632. }
  633. // set the plot x label
  634. if( p->strArray[kXLabelIdx] != NULL )
  635. _cmPrintf(fd,"set xlabel '%s'\n",(p->strArray[kXLabelIdx]));
  636. // set the plot y label
  637. if( p->strArray[kYLabelIdx] != NULL )
  638. _cmPrintf(fd,"set ylabel '%s'\n",(p->strArray[kYLabelIdx]));
  639. for(di=0; di<dataCnt; ++di)
  640. {
  641. cmPlotData* dp = p->dataPtrArray[di];
  642. unsigned eleCnt = dp->cn; //acDM_Cols(dp->xyzMtxPtr);
  643. unsigned dimCnt = dp->rn; //acDM_Rows(dp->xyzMtxPtr);
  644. if( eleCnt == 0 || dimCnt==0 )
  645. continue;
  646. // must defer printing the 'plot' command until we are sure there is a non-empty matrix to print
  647. if( printPlotKeywordFl == false )
  648. {
  649. _cmPrintf(fd,"plot ");
  650. printPlotKeywordFl = true;
  651. }
  652. bool useXRangeFl = (cmIsFlag(dp->flags,kX_PdFl)==false) && isXRangeFl;
  653. bool useYRangeFl = (cmIsFlag(dp->flags,kY_PdFl)==false) && isYRangeFl;
  654. bool useZRangeFl = (cmIsFlag(dp->flags,kZ_PdFl)==false) && isZRangeFl;
  655. bool useRangeFl = useXRangeFl | useYRangeFl | useZRangeFl;
  656. _cmPrintf(fd," '-' binary %s=%i format='%%double' ", (dimCnt==1) && useRangeFl ? "array":"record",eleCnt);
  657. if( (dimCnt == 1) && (useXRangeFl || useYRangeFl) )
  658. {
  659. _cmPrintf(fd," origin=(%f,%f) ", useXRangeFl ? p->range[ kXMinRangeIdx ] : 0, useYRangeFl ? p->range[ kYMinRangeIdx ] : 0);
  660. if( useXRangeFl )
  661. _cmPrintf(fd, " dx=%f ", (p->range[ kXMaxRangeIdx ] - p->range[ kXMinRangeIdx ]) / eleCnt );
  662. if( useYRangeFl )
  663. _cmPrintf(fd, " dy=%f ", (p->range[ kYMaxRangeIdx ] - p->range[ kYMinRangeIdx ]) / eleCnt );
  664. _cmPrintf(fd," using %i ", 1 );
  665. }
  666. else
  667. _cmPrintf(fd," using %i:%i ", dimCnt==1 ? 0 : 1, dimCnt==1 ? 1 : 2 );
  668. if( dp->legendStrH != NULL )
  669. _cmPrintf(fd," title '%s' ", dp->legendStrH);
  670. else
  671. _cmPrintf(fd, " notitle ");
  672. bool impulseFl = cmIsFlag(dp->flags,kImpulse_PdFl );
  673. if( impulseFl || (dp->lineId != kInvalidLineId) || (dp->pointId != kInvalidPlotPtId) )
  674. {
  675. _cmPrintf(fd," with ");
  676. if( impulseFl )
  677. _cmPrintf(fd,"impulses");
  678. else
  679. {
  680. if( dp->lineId != kInvalidLineId )
  681. _cmPrintf(fd,"lines");
  682. if( dp->pointId != kInvalidPlotPtId )
  683. _cmPrintf(fd,"points pt %i ", dp->pointId);
  684. }
  685. if( dp->colorStrH != NULL )
  686. _cmPrintf(fd," lt rgb '%s' ", dp->colorStrH );
  687. }
  688. if( di+1 < dataCnt )
  689. _cmPrintf(fd,",");
  690. else
  691. {
  692. _cmPrintf(fd,"\n");
  693. // for each data set contained in this plot
  694. for(di=0; di<dataCnt; ++di)
  695. {
  696. cmPlotData* dp = p->dataPtrArray[di];
  697. //acDM* mp = dp->xyzMtxPtr;
  698. unsigned eleCnt = dp->cn; //acDM_Cols(mp);
  699. const double* ddp = dp->xyzMtxPtr; //acDM_ConstPtr(mp);
  700. // if we are printing the output to the console instead of sending it too gnuplot
  701. if( fd == fileno(stdout) )
  702. {
  703. if( printDataFl )
  704. {
  705. unsigned i = 0;
  706. for(i=0; i<eleCnt; ++i )
  707. ddp=_cmPrintData( fd, i,ddp, 0, 0 );
  708. }
  709. }
  710. else
  711. {
  712. // Note: each row contains a of the matrix contains the data for a given dimension
  713. // (e.g. x coords are in row 0, y coords are in row 1, etc). If the matrix contains
  714. // multiple rows then writing the matrix memory buffer out linearly will result
  715. // in interleaving the coordinates as: x0 y0 x1 y1 x2 y2 ....
  716. write(fd,ddp,dp->rn*eleCnt*sizeof(double));
  717. }
  718. }
  719. }
  720. } // if dataCnt > 0
  721. } // for ci
  722. } // for ri
  723. /*
  724. _cmPrintf(fd,"\n");
  725. for(ri=0; ri<_cmpp->rowCnt; ++ri)
  726. for(ci=0; ci<_cmpp->colCnt; ++ci)
  727. {
  728. // get the plot at ri,ci
  729. cmPlot* p = cmPlotVect_Ptr(_cmpp->plotPtrArray,_acRowColToPlotIndex(_cmpp,ri,ci));
  730. // get the count of data sets assigned to this plot
  731. unsigned dataCnt = cmPlotDataVect_Count(p->dataPtrArray);
  732. // for each data set contained in this plot
  733. for(di=0; di<dataCnt; ++di)
  734. {
  735. cmPlotData* dp = cmPlotDataVect_Ptr(p->dataPtrArray,di);
  736. acDM* mp = dp->xyzMtxPtr;
  737. unsigned eleCnt = acDM_Cols(mp);
  738. const double* ddp = acDM_ConstPtr(mp);
  739. // if we are printing the output to the console instead of sending it too gnuplot
  740. if( fd == fileno(stdout) )
  741. {
  742. if( printDataFl )
  743. {
  744. unsigned i = 0;
  745. for(i=0; i<eleCnt; ++i )
  746. ddp=_acPrintData( fd, i,ddp, 0, 0 );
  747. }
  748. }
  749. else
  750. {
  751. // Note: each row contains a of the matrix contains the data for a given dimension
  752. // (e.g. x coords are in row 0, y coords are in row 1, etc). If the matrix contains
  753. // multiple rows then writing the matrix memory buffer out linearly will result
  754. // in interleaving the coordinates as: x0 y0 x1 y1 x2 y2 ....
  755. write(fd,ddp,acDM_Rows(mp)*eleCnt*sizeof(double));
  756. }
  757. }
  758. }
  759. */
  760. _cmPrintf(fd,"\nunset multiplot\n");
  761. return kOkPlRC;
  762. }
  763. cmRC_t cmPlotDraw()
  764. {
  765. return _cmPlotDraw(_cmpp->pipeFd[1],false);
  766. }
  767. cmRC_t cmPlotPrint( bool printDataFl )
  768. {
  769. return _cmPlotDraw(fileno(stdout),printDataFl);
  770. }
  771. cmRC_t cmPlotDrawAndPrint( bool printDataFl )
  772. {
  773. cmPlotDraw();
  774. return _cmPlotDraw(fileno(stdout),printDataFl);
  775. }
  776. // ncl - min column value
  777. // nch - max column value
  778. // nrl - min row value
  779. // nrh - max row value
  780. int fwrite_matrix(FILE* fout, float**m, int nrl, int nrh, int ncl, int nch, float* row_title, float* column_title)
  781. {
  782. int j;
  783. float length;
  784. int col_length;
  785. int status;
  786. // calc the number of columns
  787. length = (float)(col_length = nch-ncl+1);
  788. printf("cols:%i %f\n",col_length,length);
  789. // write the number of columns
  790. if((status = fwrite((char*)&length,sizeof(float),1,fout))!=1)
  791. {
  792. fprintf(stderr,"fwrite 1 returned %d\n",status);
  793. return(0);
  794. }
  795. // write the column titles
  796. fwrite((char*)column_title,sizeof(float),col_length,fout);
  797. // write the row_title followed by the data on each line
  798. for(j=nrl; j<=nrh; j++)
  799. {
  800. fwrite( (char*)&row_title[j], sizeof(float), 1, fout);
  801. fwrite( (char*)(m[j]+ncl), sizeof(float), col_length,fout);
  802. printf("%i %li\n",j,ftell(fout));
  803. }
  804. return(1);
  805. }
  806. // Generate a 'matrix-binary' data file for use with: plot "data0.bin" binary
  807. void cmPlotWriteBinaryMatrix()
  808. {
  809. const char fn[] = "/home/kevin/src/gnuplot/data0.bin";
  810. unsigned rn = 2; // row cnt
  811. unsigned cn = 16; // col cnt
  812. float srate = 16;
  813. float d[rn*cn];
  814. //float* m[rn];
  815. float c[cn];
  816. //float r[rn];
  817. unsigned i;
  818. for(i=0; i<cn; ++i)
  819. {
  820. d[i] = (float)sin(2*M_PI*i/srate);
  821. d[cn + i] = (float)cos(2*M_PI*i/srate);
  822. c[i] = i;
  823. }
  824. //m[0] = d;
  825. //r[0] = 0;
  826. FILE* fp = fopen(fn,"wb");
  827. float fcn = cn;
  828. fwrite((char*)&fcn,sizeof(fcn),1,fp); // write the count of columns
  829. fwrite((char*)c,sizeof(float),cn,fp); // write the column labels
  830. for(i=0; i<rn; ++i)
  831. {
  832. fwrite((char*)&i,sizeof(float),1,fp); // write the row label
  833. fwrite((char*)(d +(i*cn)),sizeof(float),cn,fp); // write a data row
  834. }
  835. fclose(fp);
  836. }
  837. // Generate a 'matrix-binary' data file for use with: plot "data1.bin" binary record=16x2 using 1:2
  838. void cmPlotWriteBinaryGeneralExample()
  839. {
  840. const char fn[] = "/home/kevin/src/gnuplot/data1.bin";
  841. unsigned rn = 16; // row cnt
  842. unsigned cn = 2; // col cnt
  843. float srate = 16;
  844. float d[rn*cn];
  845. unsigned i;
  846. for(i=0; i<rn; ++i)
  847. {
  848. d[(i*cn)+0] = (float)cos(2*M_PI*i/srate);
  849. d[(i*cn)+1] = (float)sin(2*M_PI*i/srate);
  850. }
  851. FILE* fp = fopen(fn,"wb");
  852. fwrite((char*)d,sizeof(float),rn*cn,fp);
  853. fclose(fp);
  854. }