libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

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. inline 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. }