libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmGnuPlot.c 29KB

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