1 /* 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/modules/rtp_rtcp/test/BWEStandAlone/MatlabPlot.h" 12 13 #include <math.h> 14 #include <stdio.h> 15 16 #include <algorithm> 17 #include <sstream> 18 19 #ifdef MATLAB 20 #include "engine.h" 21 #endif 22 23 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" 24 #include "webrtc/system_wrappers/interface/event_wrapper.h" 25 #include "webrtc/system_wrappers/interface/thread_wrapper.h" 26 #include "webrtc/system_wrappers/interface/tick_util.h" 27 28 using namespace webrtc; 29 30 #ifdef MATLAB 31 MatlabEngine eng; 32 33 MatlabLine::MatlabLine(int maxLen /*= -1*/, const char *plotAttrib /*= NULL*/, const char *name /*= NULL*/) 34 : 35 _xArray(NULL), 36 _yArray(NULL), 37 _maxLen(maxLen), 38 _plotAttribute(), 39 _name() 40 { 41 if (_maxLen > 0) 42 { 43 _xArray = mxCreateDoubleMatrix(1, _maxLen, mxREAL); 44 _yArray = mxCreateDoubleMatrix(1, _maxLen, mxREAL); 45 } 46 47 if (plotAttrib) 48 { 49 _plotAttribute = plotAttrib; 50 } 51 52 if (name) 53 { 54 _name = name; 55 } 56 } 57 58 MatlabLine::~MatlabLine() 59 { 60 if (_xArray != NULL) 61 { 62 mxDestroyArray(_xArray); 63 } 64 if (_yArray != NULL) 65 { 66 mxDestroyArray(_yArray); 67 } 68 } 69 70 void MatlabLine::Append(double x, double y) 71 { 72 if (_maxLen > 0 && _xData.size() > static_cast<uint32_t>(_maxLen)) 73 { 74 _xData.resize(_maxLen); 75 _yData.resize(_maxLen); 76 } 77 78 _xData.push_front(x); 79 _yData.push_front(y); 80 } 81 82 83 // append y-data with running integer index as x-data 84 void MatlabLine::Append(double y) 85 { 86 if (_xData.empty()) 87 { 88 // first element is index 0 89 Append(0, y); 90 } 91 else 92 { 93 // take last x-value and increment 94 double temp = _xData.back(); // last x-value 95 Append(temp + 1, y); 96 } 97 } 98 99 100 void MatlabLine::SetMaxLen(int maxLen) 101 { 102 if (maxLen <= 0) 103 { 104 // means no maxLen 105 _maxLen = -1; 106 } 107 else 108 { 109 _maxLen = maxLen; 110 111 if (_xArray != NULL) 112 { 113 mxDestroyArray(_xArray); 114 mxDestroyArray(_yArray); 115 } 116 _xArray = mxCreateDoubleMatrix(1, _maxLen, mxREAL); 117 _yArray = mxCreateDoubleMatrix(1, _maxLen, mxREAL); 118 119 maxLen = ((unsigned int)maxLen <= _xData.size()) ? maxLen : (int)_xData.size(); 120 _xData.resize(maxLen); 121 _yData.resize(maxLen); 122 123 //// reserve the right amount of memory 124 //_xData.reserve(_maxLen); 125 //_yData.reserve(_maxLen); 126 } 127 } 128 129 void MatlabLine::SetAttribute(char *plotAttrib) 130 { 131 _plotAttribute = plotAttrib; 132 } 133 134 void MatlabLine::SetName(char *name) 135 { 136 _name = name; 137 } 138 139 void MatlabLine::GetPlotData(mxArray** xData, mxArray** yData) 140 { 141 // Make sure we have enough Matlab allocated memory. 142 // Assuming both arrays (x and y) are of the same size. 143 if (_xData.empty()) 144 { 145 return; // No data 146 } 147 unsigned int size = 0; 148 if (_xArray != NULL) 149 { 150 size = (unsigned int)mxGetNumberOfElements(_xArray); 151 } 152 if (size < _xData.size()) 153 { 154 if (_xArray != NULL) 155 { 156 mxDestroyArray(_xArray); 157 mxDestroyArray(_yArray); 158 } 159 _xArray = mxCreateDoubleMatrix(1, _xData.size(), mxREAL); 160 _yArray = mxCreateDoubleMatrix(1, _yData.size(), mxREAL); 161 } 162 163 if (!_xData.empty()) 164 { 165 double* x = mxGetPr(_xArray); 166 167 std::list<double>::iterator it = _xData.begin(); 168 169 for (int i = 0; it != _xData.end(); it++, i++) 170 { 171 x[i] = *it; 172 } 173 } 174 175 if (!_yData.empty()) 176 { 177 double* y = mxGetPr(_yArray); 178 179 std::list<double>::iterator it = _yData.begin(); 180 181 for (int i = 0; it != _yData.end(); it++, i++) 182 { 183 y[i] = *it; 184 } 185 } 186 *xData = _xArray; 187 *yData = _yArray; 188 } 189 190 std::string MatlabLine::GetXName() 191 { 192 std::ostringstream xString; 193 xString << "x_" << _name; 194 return xString.str(); 195 } 196 197 std::string MatlabLine::GetYName() 198 { 199 std::ostringstream yString; 200 yString << "y_" << _name; 201 return yString.str(); 202 } 203 204 std::string MatlabLine::GetPlotString() 205 { 206 207 std::ostringstream s; 208 209 if (_xData.size() == 0) 210 { 211 s << "[0 1], [0 1]"; // To get an empty plot 212 } 213 else 214 { 215 s << GetXName() << "(1:" << _xData.size() << "),"; 216 s << GetYName() << "(1:" << _yData.size() << ")"; 217 } 218 219 s << ", '"; 220 s << _plotAttribute; 221 s << "'"; 222 223 return s.str(); 224 } 225 226 std::string MatlabLine::GetRefreshString() 227 { 228 std::ostringstream s; 229 230 if (_xData.size() > 0) 231 { 232 s << "set(h,'xdata',"<< GetXName() <<"(1:" << _xData.size() << "),'ydata',"<< GetYName() << "(1:" << _yData.size() << "));"; 233 } 234 else 235 { 236 s << "set(h,'xdata',[NaN],'ydata',[NaN]);"; 237 } 238 return s.str(); 239 } 240 241 std::string MatlabLine::GetLegendString() 242 { 243 return ("'" + _name + "'"); 244 } 245 246 bool MatlabLine::hasLegend() 247 { 248 return (!_name.empty()); 249 } 250 251 252 // remove data points, but keep attributes 253 void MatlabLine::Reset() 254 { 255 _xData.clear(); 256 _yData.clear(); 257 } 258 259 260 void MatlabLine::UpdateTrendLine(MatlabLine * sourceData, double slope, double offset) 261 { 262 Reset(); // reset data, not attributes and name 263 264 double thexMin = sourceData->xMin(); 265 double thexMax = sourceData->xMax(); 266 Append(thexMin, thexMin * slope + offset); 267 Append(thexMax, thexMax * slope + offset); 268 } 269 270 double MatlabLine::xMin() 271 { 272 if (!_xData.empty()) 273 { 274 std::list<double>::iterator theStart = _xData.begin(); 275 std::list<double>::iterator theEnd = _xData.end(); 276 return(*min_element(theStart, theEnd)); 277 } 278 return (0.0); 279 } 280 281 double MatlabLine::xMax() 282 { 283 if (!_xData.empty()) 284 { 285 std::list<double>::iterator theStart = _xData.begin(); 286 std::list<double>::iterator theEnd = _xData.end(); 287 return(*max_element(theStart, theEnd)); 288 } 289 return (0.0); 290 } 291 292 double MatlabLine::yMin() 293 { 294 if (!_yData.empty()) 295 { 296 std::list<double>::iterator theStart = _yData.begin(); 297 std::list<double>::iterator theEnd = _yData.end(); 298 return(*min_element(theStart, theEnd)); 299 } 300 return (0.0); 301 } 302 303 double MatlabLine::yMax() 304 { 305 if (!_yData.empty()) 306 { 307 std::list<double>::iterator theStart = _yData.begin(); 308 std::list<double>::iterator theEnd = _yData.end(); 309 return(*max_element(theStart, theEnd)); 310 } 311 return (0.0); 312 } 313 314 315 316 MatlabTimeLine::MatlabTimeLine(int horizonSeconds /*= -1*/, const char *plotAttrib /*= NULL*/, 317 const char *name /*= NULL*/, 318 int64_t refTimeMs /* = -1*/) 319 : 320 _timeHorizon(horizonSeconds), 321 MatlabLine(-1, plotAttrib, name) // infinite number of elements 322 { 323 if (refTimeMs < 0) 324 _refTimeMs = TickTime::MillisecondTimestamp(); 325 else 326 _refTimeMs = refTimeMs; 327 } 328 329 void MatlabTimeLine::Append(double y) 330 { 331 MatlabLine::Append(static_cast<double>(TickTime::MillisecondTimestamp() - _refTimeMs) / 1000.0, y); 332 333 PurgeOldData(); 334 } 335 336 337 void MatlabTimeLine::PurgeOldData() 338 { 339 if (_timeHorizon > 0) 340 { 341 // remove old data 342 double historyLimit = static_cast<double>(TickTime::MillisecondTimestamp() - _refTimeMs) / 1000.0 343 - _timeHorizon; // remove data points older than this 344 345 std::list<double>::reverse_iterator ritx = _xData.rbegin(); 346 uint32_t removeCount = 0; 347 while (ritx != _xData.rend()) 348 { 349 if (*ritx >= historyLimit) 350 { 351 break; 352 } 353 ritx++; 354 removeCount++; 355 } 356 if (removeCount == 0) 357 { 358 return; 359 } 360 361 // remove the range [begin, it). 362 //if (removeCount > 10) 363 //{ 364 // printf("Removing %lu elements\n", removeCount); 365 //} 366 _xData.resize(_xData.size() - removeCount); 367 _yData.resize(_yData.size() - removeCount); 368 } 369 } 370 371 372 int64_t MatlabTimeLine::GetRefTime() 373 { 374 return(_refTimeMs); 375 } 376 377 378 379 380 MatlabPlot::MatlabPlot() 381 : 382 _figHandle(-1), 383 _smartAxis(false), 384 _critSect(CriticalSectionWrapper::CreateCriticalSection()), 385 _timeToPlot(false), 386 _plotting(false), 387 _enabled(true), 388 _firstPlot(true), 389 _legendEnabled(true), 390 _donePlottingEvent(EventWrapper::Create()) 391 { 392 CriticalSectionScoped cs(_critSect); 393 394 _xlim[0] = 0; 395 _xlim[1] = 0; 396 _ylim[0] = 0; 397 _ylim[1] = 0; 398 399 #ifdef PLOT_TESTING 400 _plotStartTime = -1; 401 _plotDelay = 0; 402 #endif 403 404 } 405 406 407 MatlabPlot::~MatlabPlot() 408 { 409 _critSect->Enter(); 410 411 // delete all line objects 412 while (!_line.empty()) 413 { 414 delete *(_line.end() - 1); 415 _line.pop_back(); 416 } 417 418 delete _critSect; 419 delete _donePlottingEvent; 420 } 421 422 423 int MatlabPlot::AddLine(int maxLen /*= -1*/, const char *plotAttrib /*= NULL*/, const char *name /*= NULL*/) 424 { 425 CriticalSectionScoped cs(_critSect); 426 if (!_enabled) 427 { 428 return -1; 429 } 430 431 MatlabLine *newLine = new MatlabLine(maxLen, plotAttrib, name); 432 _line.push_back(newLine); 433 434 return (static_cast<int>(_line.size() - 1)); // index of newly inserted line 435 } 436 437 438 int MatlabPlot::AddTimeLine(int maxLen /*= -1*/, const char *plotAttrib /*= NULL*/, const char *name /*= NULL*/, 439 int64_t refTimeMs /*= -1*/) 440 { 441 CriticalSectionScoped cs(_critSect); 442 443 if (!_enabled) 444 { 445 return -1; 446 } 447 448 MatlabTimeLine *newLine = new MatlabTimeLine(maxLen, plotAttrib, name, refTimeMs); 449 _line.push_back(newLine); 450 451 return (static_cast<int>(_line.size() - 1)); // index of newly inserted line 452 } 453 454 455 int MatlabPlot::GetLineIx(const char *name) 456 { 457 CriticalSectionScoped cs(_critSect); 458 459 if (!_enabled) 460 { 461 return -1; 462 } 463 464 // search the list for a matching line name 465 std::vector<MatlabLine*>::iterator it = _line.begin(); 466 bool matchFound = false; 467 int lineIx = 0; 468 469 for (; it != _line.end(); it++, lineIx++) 470 { 471 if ((*it)->_name == name) 472 { 473 matchFound = true; 474 break; 475 } 476 } 477 478 if (matchFound) 479 { 480 return (lineIx); 481 } 482 else 483 { 484 return (-1); 485 } 486 } 487 488 489 void MatlabPlot::Append(int lineIndex, double x, double y) 490 { 491 CriticalSectionScoped cs(_critSect); 492 493 if (!_enabled) 494 { 495 return; 496 } 497 498 // sanity for index 499 if (lineIndex < 0 || lineIndex >= static_cast<int>(_line.size())) 500 { 501 throw "Line index out of range"; 502 exit(1); 503 } 504 505 return (_line[lineIndex]->Append(x, y)); 506 } 507 508 509 void MatlabPlot::Append(int lineIndex, double y) 510 { 511 CriticalSectionScoped cs(_critSect); 512 513 if (!_enabled) 514 { 515 return; 516 } 517 518 // sanity for index 519 if (lineIndex < 0 || lineIndex >= static_cast<int>(_line.size())) 520 { 521 throw "Line index out of range"; 522 exit(1); 523 } 524 525 return (_line[lineIndex]->Append(y)); 526 } 527 528 529 int MatlabPlot::Append(const char *name, double x, double y) 530 { 531 CriticalSectionScoped cs(_critSect); 532 533 if (!_enabled) 534 { 535 return -1; 536 } 537 538 // search the list for a matching line name 539 int lineIx = GetLineIx(name); 540 541 if (lineIx < 0) //(!matchFound) 542 { 543 // no match; append new line 544 lineIx = AddLine(-1, NULL, name); 545 } 546 547 // append data to line 548 Append(lineIx, x, y); 549 return (lineIx); 550 } 551 552 int MatlabPlot::Append(const char *name, double y) 553 { 554 CriticalSectionScoped cs(_critSect); 555 556 if (!_enabled) 557 { 558 return -1; 559 } 560 561 // search the list for a matching line name 562 int lineIx = GetLineIx(name); 563 564 if (lineIx < 0) //(!matchFound) 565 { 566 // no match; append new line 567 lineIx = AddLine(-1, NULL, name); 568 } 569 570 // append data to line 571 Append(lineIx, y); 572 return (lineIx); 573 } 574 575 int MatlabPlot::Length(char *name) 576 { 577 CriticalSectionScoped cs(_critSect); 578 579 if (!_enabled) 580 { 581 return -1; 582 } 583 584 int ix = GetLineIx(name); 585 if (ix >= 0) 586 { 587 return (static_cast<int>(_line[ix]->_xData.size())); 588 } 589 else 590 { 591 return (-1); 592 } 593 } 594 595 596 void MatlabPlot::SetPlotAttribute(char *name, char *plotAttrib) 597 { 598 CriticalSectionScoped cs(_critSect); 599 600 if (!_enabled) 601 { 602 return; 603 } 604 605 int lineIx = GetLineIx(name); 606 607 if (lineIx >= 0) 608 { 609 _line[lineIx]->SetAttribute(plotAttrib); 610 } 611 } 612 613 // Must be called under critical section _critSect 614 void MatlabPlot::UpdateData(Engine* ep) 615 { 616 if (!_enabled) 617 { 618 return; 619 } 620 621 for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.end(); it++) 622 { 623 mxArray* xData = NULL; 624 mxArray* yData = NULL; 625 (*it)->GetPlotData(&xData, &yData); 626 if (xData != NULL) 627 { 628 std::string xName = (*it)->GetXName(); 629 std::string yName = (*it)->GetYName(); 630 _critSect->Leave(); 631 #ifdef MATLAB6 632 mxSetName(xData, xName.c_str()); 633 mxSetName(yData, yName.c_str()); 634 engPutArray(ep, xData); 635 engPutArray(ep, yData); 636 #else 637 int ret = engPutVariable(ep, xName.c_str(), xData); 638 assert(ret == 0); 639 ret = engPutVariable(ep, yName.c_str(), yData); 640 assert(ret == 0); 641 #endif 642 _critSect->Enter(); 643 } 644 } 645 } 646 647 bool MatlabPlot::GetPlotCmd(std::ostringstream & cmd, Engine* ep) 648 { 649 _critSect->Enter(); 650 651 if (!DataAvailable()) 652 { 653 return false; 654 } 655 656 if (_firstPlot) 657 { 658 GetPlotCmd(cmd); 659 _firstPlot = false; 660 } 661 else 662 { 663 GetRefreshCmd(cmd); 664 } 665 666 UpdateData(ep); 667 668 _critSect->Leave(); 669 670 return true; 671 } 672 673 // Call inside critsect 674 void MatlabPlot::GetPlotCmd(std::ostringstream & cmd) 675 { 676 // we have something to plot 677 // empty the stream 678 cmd.str(""); // (this seems to be the only way) 679 680 cmd << "figure; h" << _figHandle << "= plot("; 681 682 // first line 683 std::vector<MatlabLine*>::iterator it = _line.begin(); 684 cmd << (*it)->GetPlotString(); 685 686 it++; 687 688 // remaining lines 689 for (; it != _line.end(); it++) 690 { 691 cmd << ", "; 692 cmd << (*it)->GetPlotString(); 693 } 694 695 cmd << "); "; 696 697 if (_legendEnabled) 698 { 699 GetLegendCmd(cmd); 700 } 701 702 if (_smartAxis) 703 { 704 double xMin = _xlim[0]; 705 double xMax = _xlim[1]; 706 double yMax = _ylim[1]; 707 for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.end(); it++) 708 { 709 xMax = std::max(xMax, (*it)->xMax()); 710 xMin = std::min(xMin, (*it)->xMin()); 711 712 yMax = std::max(yMax, (*it)->yMax()); 713 yMax = std::max(yMax, fabs((*it)->yMin())); 714 } 715 _xlim[0] = xMin; 716 _xlim[1] = xMax; 717 _ylim[0] = -yMax; 718 _ylim[1] = yMax; 719 720 cmd << "axis([" << _xlim[0] << ", " << _xlim[1] << ", " << _ylim[0] << ", " << _ylim[1] << "]);"; 721 } 722 723 int i=1; 724 for (it = _line.begin(); it != _line.end(); i++, it++) 725 { 726 cmd << "set(h" << _figHandle << "(" << i << "), 'Tag', " << (*it)->GetLegendString() << ");"; 727 } 728 } 729 730 // Call inside critsect 731 void MatlabPlot::GetRefreshCmd(std::ostringstream & cmd) 732 { 733 cmd.str(""); // (this seems to be the only way) 734 std::vector<MatlabLine*>::iterator it = _line.begin(); 735 for (it = _line.begin(); it != _line.end(); it++) 736 { 737 cmd << "h = findobj(0, 'Tag', " << (*it)->GetLegendString() << ");"; 738 cmd << (*it)->GetRefreshString(); 739 } 740 //if (_legendEnabled) 741 //{ 742 // GetLegendCmd(cmd); 743 //} 744 } 745 746 void MatlabPlot::GetLegendCmd(std::ostringstream & cmd) 747 { 748 std::vector<MatlabLine*>::iterator it = _line.begin(); 749 bool anyLegend = false; 750 for (; it != _line.end(); it++) 751 { 752 anyLegend = anyLegend || (*it)->hasLegend(); 753 } 754 if (anyLegend) 755 { 756 // create the legend 757 758 cmd << "legend(h" << _figHandle << ",{"; 759 760 761 // iterate lines 762 int i = 0; 763 for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.end(); it++) 764 { 765 if (i > 0) 766 { 767 cmd << ", "; 768 } 769 cmd << (*it)->GetLegendString(); 770 i++; 771 } 772 773 cmd << "}, 2); "; // place legend in upper-left corner 774 } 775 } 776 777 // Call inside critsect 778 bool MatlabPlot::DataAvailable() 779 { 780 if (!_enabled) 781 { 782 return false; 783 } 784 785 for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.end(); it++) 786 { 787 (*it)->PurgeOldData(); 788 } 789 790 return true; 791 } 792 793 void MatlabPlot::Plot() 794 { 795 CriticalSectionScoped cs(_critSect); 796 797 _timeToPlot = true; 798 799 #ifdef PLOT_TESTING 800 _plotStartTime = TickTime::MillisecondTimestamp(); 801 #endif 802 } 803 804 805 void MatlabPlot::Reset() 806 { 807 CriticalSectionScoped cs(_critSect); 808 809 _enabled = true; 810 811 for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.end(); it++) 812 { 813 (*it)->Reset(); 814 } 815 816 } 817 818 void MatlabPlot::SetFigHandle(int handle) 819 { 820 CriticalSectionScoped cs(_critSect); 821 822 if (handle > 0) 823 _figHandle = handle; 824 } 825 826 bool 827 MatlabPlot::TimeToPlot() 828 { 829 CriticalSectionScoped cs(_critSect); 830 return _enabled && _timeToPlot; 831 } 832 833 void 834 MatlabPlot::Plotting() 835 { 836 CriticalSectionScoped cs(_critSect); 837 _plotting = true; 838 } 839 840 void 841 MatlabPlot::DonePlotting() 842 { 843 CriticalSectionScoped cs(_critSect); 844 _timeToPlot = false; 845 _plotting = false; 846 _donePlottingEvent->Set(); 847 } 848 849 void 850 MatlabPlot::DisablePlot() 851 { 852 _critSect->Enter(); 853 while (_plotting) 854 { 855 _critSect->Leave(); 856 _donePlottingEvent->Wait(WEBRTC_EVENT_INFINITE); 857 _critSect->Enter(); 858 } 859 _enabled = false; 860 } 861 862 int MatlabPlot::MakeTrend(const char *sourceName, const char *trendName, double slope, double offset, const char *plotAttrib) 863 { 864 CriticalSectionScoped cs(_critSect); 865 866 int sourceIx; 867 int trendIx; 868 869 sourceIx = GetLineIx(sourceName); 870 if (sourceIx < 0) 871 { 872 // could not find source 873 return (-1); 874 } 875 876 trendIx = GetLineIx(trendName); 877 if (trendIx < 0) 878 { 879 // no trend found; add new line 880 trendIx = AddLine(2 /*maxLen*/, plotAttrib, trendName); 881 } 882 883 _line[trendIx]->UpdateTrendLine(_line[sourceIx], slope, offset); 884 885 return (trendIx); 886 887 } 888 889 890 MatlabEngine::MatlabEngine() 891 : 892 _critSect(CriticalSectionWrapper::CreateCriticalSection()), 893 _eventPtr(NULL), 894 _plotThread(NULL), 895 _running(false), 896 _numPlots(0) 897 { 898 _eventPtr = EventWrapper::Create(); 899 900 _plotThread = ThreadWrapper::CreateThread(MatlabEngine::PlotThread, this, kLowPriority, "MatlabPlot"); 901 902 if (_plotThread == NULL) 903 { 904 throw "Unable to start MatlabEngine thread"; 905 exit(1); 906 } 907 908 _running = true; 909 910 unsigned int tid; 911 _plotThread->Start(tid); 912 913 } 914 915 MatlabEngine::~MatlabEngine() 916 { 917 _critSect->Enter(); 918 919 if (_plotThread) 920 { 921 _plotThread->SetNotAlive(); 922 _running = false; 923 _eventPtr->Set(); 924 925 while (!_plotThread->Stop()) 926 { 927 ; 928 } 929 930 delete _plotThread; 931 } 932 933 _plots.clear(); 934 935 _plotThread = NULL; 936 937 delete _eventPtr; 938 _eventPtr = NULL; 939 940 _critSect->Leave(); 941 delete _critSect; 942 943 } 944 945 MatlabPlot * MatlabEngine::NewPlot(MatlabPlot *newPlot) 946 { 947 CriticalSectionScoped cs(_critSect); 948 949 //MatlabPlot *newPlot = new MatlabPlot(); 950 951 if (newPlot) 952 { 953 newPlot->SetFigHandle(++_numPlots); // first plot is number 1 954 _plots.push_back(newPlot); 955 } 956 957 return (newPlot); 958 959 } 960 961 962 void MatlabEngine::DeletePlot(MatlabPlot *plot) 963 { 964 CriticalSectionScoped cs(_critSect); 965 966 if (plot == NULL) 967 { 968 return; 969 } 970 971 std::vector<MatlabPlot *>::iterator it; 972 for (it = _plots.begin(); it < _plots.end(); it++) 973 { 974 if (plot == *it) 975 { 976 break; 977 } 978 } 979 980 assert (plot == *it); 981 982 (*it)->DisablePlot(); 983 984 _plots.erase(it); 985 --_numPlots; 986 987 delete plot; 988 } 989 990 991 bool MatlabEngine::PlotThread(void *obj) 992 { 993 if (!obj) 994 { 995 return (false); 996 } 997 998 MatlabEngine *eng = (MatlabEngine *) obj; 999 1000 Engine *ep = engOpen(NULL); 1001 if (!ep) 1002 { 1003 throw "Cannot open Matlab engine"; 1004 return (false); 1005 } 1006 1007 engSetVisible(ep, true); 1008 engEvalString(ep, "close all;"); 1009 1010 while (eng->_running) 1011 { 1012 eng->_critSect->Enter(); 1013 1014 // iterate through all plots 1015 for (unsigned int ix = 0; ix < eng->_plots.size(); ix++) 1016 { 1017 MatlabPlot *plot = eng->_plots[ix]; 1018 if (plot->TimeToPlot()) 1019 { 1020 plot->Plotting(); 1021 eng->_critSect->Leave(); 1022 std::ostringstream cmd; 1023 1024 if (engEvalString(ep, cmd.str().c_str())) 1025 { 1026 // engine dead 1027 return (false); 1028 } 1029 1030 // empty the stream 1031 cmd.str(""); // (this seems to be the only way) 1032 if (plot->GetPlotCmd(cmd, ep)) 1033 { 1034 // things to plot, we have already accessed what we need in the plot 1035 plot->DonePlotting(); 1036 1037 int64_t start = TickTime::MillisecondTimestamp(); 1038 // plot it 1039 int ret = engEvalString(ep, cmd.str().c_str()); 1040 printf("time=%I64i\n", TickTime::MillisecondTimestamp() - start); 1041 if (ret) 1042 { 1043 // engine dead 1044 return (false); 1045 } 1046 1047 #ifdef PLOT_TESTING 1048 if(plot->_plotStartTime >= 0) 1049 { 1050 plot->_plotDelay = TickTime::MillisecondTimestamp() - plot->_plotStartTime; 1051 plot->_plotStartTime = -1; 1052 } 1053 #endif 1054 } 1055 eng->_critSect->Enter(); 1056 } 1057 } 1058 1059 eng->_critSect->Leave(); 1060 // wait a while 1061 eng->_eventPtr->Wait(66); // 33 ms 1062 } 1063 1064 if (ep) 1065 { 1066 engClose(ep); 1067 ep = NULL; 1068 } 1069 1070 return (true); 1071 1072 } 1073 1074 #endif // MATLAB 1075