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
28using namespace webrtc;
29
30#ifdef MATLAB
31MatlabEngine eng;
32
33MatlabLine::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
58MatlabLine::~MatlabLine()
59{
60    if (_xArray != NULL)
61    {
62        mxDestroyArray(_xArray);
63    }
64    if (_yArray != NULL)
65    {
66        mxDestroyArray(_yArray);
67    }
68}
69
70void 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
84void 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
100void 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
129void MatlabLine::SetAttribute(char *plotAttrib)
130{
131    _plotAttribute = plotAttrib;
132}
133
134void MatlabLine::SetName(char *name)
135{
136    _name = name;
137}
138
139void 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
190std::string MatlabLine::GetXName()
191{
192    std::ostringstream xString;
193    xString << "x_" << _name;
194    return xString.str();
195}
196
197std::string MatlabLine::GetYName()
198{
199    std::ostringstream yString;
200    yString << "y_" << _name;
201    return yString.str();
202}
203
204std::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
226std::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
241std::string MatlabLine::GetLegendString()
242{
243    return ("'" + _name + "'");
244}
245
246bool MatlabLine::hasLegend()
247{
248    return (!_name.empty());
249}
250
251
252// remove data points, but keep attributes
253void MatlabLine::Reset()
254{
255    _xData.clear();
256    _yData.clear();
257}
258
259
260void 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
270double 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
281double 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
292double 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
303double 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
316MatlabTimeLine::MatlabTimeLine(int horizonSeconds /*= -1*/, const char *plotAttrib /*= NULL*/,
317                               const char *name /*= NULL*/,
318                               int64_t refTimeMs /* = -1*/)
319                               :
320_timeHorizon(horizonSeconds),
321MatlabLine(-1, plotAttrib, name) // infinite number of elements
322{
323    if (refTimeMs < 0)
324        _refTimeMs = TickTime::MillisecondTimestamp();
325    else
326        _refTimeMs = refTimeMs;
327}
328
329void MatlabTimeLine::Append(double y)
330{
331    MatlabLine::Append(static_cast<double>(TickTime::MillisecondTimestamp() - _refTimeMs) / 1000.0, y);
332
333    PurgeOldData();
334}
335
336
337void 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
372int64_t MatlabTimeLine::GetRefTime()
373{
374    return(_refTimeMs);
375}
376
377
378
379
380MatlabPlot::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
407MatlabPlot::~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
423int 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
438int 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
455int 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
489void 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
509void 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
529int 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
552int 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
575int 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
596void 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
614void 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
647bool 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
674void 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
731void 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
746void 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
778bool 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
793void 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
805void 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
818void MatlabPlot::SetFigHandle(int handle)
819{
820    CriticalSectionScoped cs(_critSect);
821
822    if (handle > 0)
823        _figHandle = handle;
824}
825
826bool
827MatlabPlot::TimeToPlot()
828{
829    CriticalSectionScoped cs(_critSect);
830    return _enabled && _timeToPlot;
831}
832
833void
834MatlabPlot::Plotting()
835{
836    CriticalSectionScoped cs(_critSect);
837    _plotting = true;
838}
839
840void
841MatlabPlot::DonePlotting()
842{
843    CriticalSectionScoped cs(_critSect);
844    _timeToPlot = false;
845    _plotting = false;
846    _donePlottingEvent->Set();
847}
848
849void
850MatlabPlot::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
862int 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
890MatlabEngine::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
915MatlabEngine::~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
945MatlabPlot * 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
962void 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
991bool 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