/* * EpochPlot.cc * * Created on: 16 jan. 2015 * Author: AKKA */ #include "EpochPlot.hh" #include "ParamsNode.hh" #include "AxesNode.hh" #include "PlotOutput.hh" #include "TimeUtil.hh" #include "Parameter.hh" #include "ParamInfo.hh" #include "ParamMgr.hh" #include #include "EpochAxisDecorator.hh" #include "TickMarkDecorator.hh" #include "PlotLogger.hh" #include "ParamMgr.hh" #include "TimeUtil.hh" #include "AxisLegendManager.hh" #include using namespace AMDA::Parameters; using namespace AMDA::Info; namespace plot { EpochPlot::EpochPlot(AMDA::Parameters::ParameterManager& manager, boost::shared_ptr panel) : PanelPlotOutput(manager, panel), _centerTimeId(""){ _epochDecoratorPtr.reset(new EpochAxisDecorator()); } EpochPlot::~EpochPlot() { } EpochAxis* EpochPlot::getEpochAxis(){ std::string lAxisId = getXAxisId(); boost::shared_ptr xAxis = _panel->getAxis(lAxisId); if (xAxis.get() == nullptr) { std::stringstream lError; lError << "EpochPlot::apply" << ": epoch axis with id '" << lAxisId << "' not found."; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } return dynamic_cast(xAxis.get()); } void EpochPlot::preparePlotArea(double startTime, double stopTime, int intervalIndex) { // dump properties for test const char* lBuildType=getenv("BUILD_TYPE"); if(lBuildType && std::string(lBuildType) == "Debug") { std::ofstream out("epochPlot.txt"); dump(out); out.close(); } configureSeriesAxis(); configureAxisLegend(); configureParamsLegend(startTime, stopTime, intervalIndex); // configure X epoch axis _epochDecoratorPtr->configure(this, getEpochAxis(), getEpochAxis()->getRange().getMin(), getEpochAxis()->getRange().getMax(), _pParameterValues); getEpochAxis()->_used = true; PanelPlotOutput::preparePlotArea(startTime,stopTime,intervalIndex); } bool EpochPlot::draw(double startTime, double stopTime, int intervalIndex, bool isFirstInterval, bool isLastInterval) { return PanelPlotOutput::draw(startTime,stopTime,intervalIndex,isFirstInterval,isLastInterval); } void EpochPlot::calculatePlotArea(Bounds& bounds_) { PanelPlotOutput::calculatePlotArea(bounds_); // decorator is responsible of reserving extra space for what it manage (labels for instance). _epochDecoratorPtr->updatePlotArea(this, getEpochAxis(), bounds_); } void EpochPlot::configureSeriesAxis() { /* * Configure the epoch time axis */ EpochAxis* epochAxis = getEpochAxis(); if (epochAxis == NULL) { std::stringstream lError; lError << "EpochPlot::configureSeriesAxis: Cannot find epochAxis"; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } //get epoch axis range Range lEpochRange; if (!epochAxis->isNormalized()) { //axis not normalized TimeIntervalList::iterator crtTimeInterval = _timeIntervalListPtr->begin(); while (crtTimeInterval != _timeIntervalListPtr->end()) { //get center time data for this interval double leftDeltaTime = 0.; double rightDeltaTime = 0.; std::vector& crtCenterTimeData = _parameterManager.getInputIntervalDataList(crtTimeInterval->_index, _centerTimeId); if (crtCenterTimeData.empty()) { leftDeltaTime = (crtTimeInterval->_stopTime-crtTimeInterval->_startTime) / 2.; rightDeltaTime = leftDeltaTime; } else { //compute left and right delta times (relative to the center time) double crtCenterTime = AMDA::TimeUtil::readTimeInIso((char*)crtCenterTimeData[0].c_str()); leftDeltaTime = crtCenterTime-crtTimeInterval->_startTime; rightDeltaTime = crtTimeInterval->_stopTime-crtCenterTime; } if ((leftDeltaTime < 0) || (rightDeltaTime < 0)) { LOG4CXX_WARN(gLogger, "EpochPlot::configureSeriesAxis - centerTime not contained in the interval for the interval with index : " << crtTimeInterval->_index << " => skip this interval"); ++crtTimeInterval; continue; } //configure the range of the axis if (isnan(lEpochRange.getMin()) || (lEpochRange.getMin() > -leftDeltaTime)) lEpochRange.setMin(-leftDeltaTime); if (isnan(lEpochRange.getMax()) || (lEpochRange.getMax() < rightDeltaTime)) lEpochRange.setMax(rightDeltaTime); ++crtTimeInterval; } } else { //normalized epoch axis lEpochRange.setMin(-1); lEpochRange.setMax(1); } if (isnan(lEpochRange.getMin()) || isnan(lEpochRange.getMax())) { std::stringstream lError; lError << "EpochPlot::configureSeriesAxis: Cannot configure the range of the epochAxis"; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } fixRange(lEpochRange, epochAxis->_scale == Axis::Scale::LOGARITHMIC); epochAxis->setRange(lEpochRange); /* * configure y and z axis */ std::map lAxisRange; Range lColorAxeRange; SeriesProperties lSeriesProperties; boost::shared_ptr lZAxis = _panel->getColorAxis(); // Parse each parameter to define on which axis to draw series. for (auto param: _parameterAxesList) { // Get number of series to draw // For each index of parameter identify to which axis series must be drawn. for(auto lSeriesProperties: param.getYSeriePropertiesList()) { if(!lSeriesProperties.hasYAxis()){ continue; } boost::shared_ptr lYAxis = _panel->getAxis(lSeriesProperties.getYAxisId()); if (lYAxis.get() == nullptr) { std::stringstream lError; lError << "EpochPlot::configureSeriesAxis" << ": Y axis with id '" << lSeriesProperties.getYAxisId() << "' not found."; BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } lYAxis->_used = true; Range lRange(lYAxis->getRange()); // If range status for this axis is set by the user do not update range "automatically". if (isnan(lRange.getMin()) && isnan(lRange.getMax())) { Range lEstimatedRange(lAxisRange[lYAxis->_id]); for (auto index : lSeriesProperties.getIndexList(_pParameterValues)) { Range lParamIndexRange( (*_pParameterValues)[lSeriesProperties.getParamId()].getMin(index), (*_pParameterValues)[lSeriesProperties.getParamId()].getMax(index)); if (isnan(lEstimatedRange.getMin()) && isnan(lEstimatedRange.getMax())) { lEstimatedRange.setMin(lParamIndexRange.getMin()); lEstimatedRange.setMax(lParamIndexRange.getMax()); } else { lEstimatedRange.setMin(std::min(lEstimatedRange.getMin(), lParamIndexRange.getMin())); lEstimatedRange.setMax(std::max(lEstimatedRange.getMax(), lParamIndexRange.getMax())); } } fixRange(lEstimatedRange, lYAxis->_scale == Axis::Scale::LOGARITHMIC); lEstimatedRange._extend = lRange._extend; lAxisRange[lYAxis->_id] = lEstimatedRange; } // Set ZAxis range if a color param is defined for this serie if (lZAxis != nullptr) { if (!lSeriesProperties.getColorParamId().empty()) { lZAxis->_used = true; Range lRange(lZAxis->getRange()); ParameterAxes* colorSerieParameterAxes = getParameterAxesByColorSerieId(lSeriesProperties.getColorSerieId()); if (colorSerieParameterAxes == NULL) continue; ColorSeriesProperties& colorSerieProp = colorSerieParameterAxes->getColorSeriePropertiesById(lSeriesProperties.getColorSerieId()); // If range status for this axis is set by the user do not update range "automatically". if (isnan(lRange.getMin()) && isnan(lRange.getMax())) { Range lEstimatedRange(lColorAxeRange); Range lParamIndexRange( (*_pParameterValues)[lSeriesProperties.getColorParamId()].getMin( colorSerieProp.getIndex()), (*_pParameterValues)[lSeriesProperties.getColorParamId()].getMax( colorSerieProp.getIndex())); if (isnan(lEstimatedRange.getMin()) && isnan(lEstimatedRange.getMax())) { lEstimatedRange.setMin(lParamIndexRange.getMin()); lEstimatedRange.setMax(lParamIndexRange.getMax()); } else { lEstimatedRange.setMin(std::min(lEstimatedRange.getMin(), lParamIndexRange.getMin())); lEstimatedRange.setMax(std::max(lEstimatedRange.getMax(), lParamIndexRange.getMax())); } fixRange(lEstimatedRange, lZAxis->_scale == Axis::Scale::LOGARITHMIC); lEstimatedRange._extend = lRange._extend; lColorAxeRange = lEstimatedRange; } } } } } // Update range of axis. Done after because, axis range may be processed in several pass (one for each series) for (auto lAxis: lAxisRange) { _panel->getAxis(lAxis.first)->setRange(lAxis.second); } if (lZAxis != nullptr && lColorAxeRange.isSet()) lZAxis->setRange(lColorAxeRange); } void EpochPlot::configureAxisLegend() { // Y axis AxisLegendManager::configureYAxisLegendForSeries(this); // Z axis AxisLegendManager::configureColorAxisLegendForSeries(this); } void EpochPlot::drawXAxis(boost::shared_ptr pXAxis, PlWindow& pPlWindow, Bounds& pPlotAreaSize, TickConf& pTickConf){ LOG4CXX_DEBUG(gLogger, "Drawing X axis "); // draw main axis... PanelPlotOutput::drawXAxis(pXAxis,pPlWindow, pPlotAreaSize, pTickConf); // delegate to decorator any extra drawing stuff it needs to perform... _epochDecoratorPtr->draw(this,getEpochAxis(), _pls); } void EpochPlot::drawSeries(double startDate, double stopDate, int intervalIndex, std::string pParamId, SeriesProperties& pSeries, AMDA::Common::ParameterIndexComponent pParamIndex, ParameterAxes& param, bool moreThanOneSerieForAxis) { LOG4CXX_DEBUG(gLogger, "Drawing epoch serie for parameter "<& crtCenterTimeData = _parameterManager.getInputIntervalDataList(intervalIndex, _centerTimeId); double crtCenterTime = 0.; if (crtCenterTimeData.empty()) crtCenterTime = startDate + (stopDate - startDate) / 2.; else crtCenterTime = AMDA::TimeUtil::readTimeInIso((char*)crtCenterTimeData[0].c_str()); //set the current center time to the epoch axis epochAxis->setCrtCenterTime(crtCenterTime); //get computed values double *computedValues = NULL; double *timeValues = NULL; int nbValues; if (!getComputedValuesFromSerieAndInterval(startDate, stopDate, pSeries, pParamIndex, &computedValues, &timeValues, nbValues)) { LOG4CXX_DEBUG(gLogger, "EpochPlot::drawSeries - Cannot get computed values for serie"); return; } //compute epoch time value double *epochTimeValues = epochAxis->getComputedValues( timeValues, nbValues, startDate, stopDate); double *coloredComputedValues = NULL; double *coloredTimeValues = NULL; //get colored value if needed if (!pSeries.getColorParamId().empty() && (_panel->getColorAxis() != nullptr)) { int nbColoredValues; if (!getColoredComputedValuesFromSerieAndInterval(startDate, stopDate, pSeries, &coloredComputedValues, &coloredTimeValues, nbColoredValues)) { LOG4CXX_DEBUG(gLogger, "EpochPlot::drawSeries - Cannot get computed values for colored parameter"); return; } } PlWindow lPlWindow = PlWindow(getEpochAxis()->getRange().getMin(), getEpochAxis()->getRange().getMax(), _panel->getAxis(yAxisId)->getRange().getMin(), _panel->getAxis(yAxisId)->getRange().getMax()); _pls->wind(std::get<0>(lPlWindow), std::get<1>(lPlWindow), std::get<2>(lPlWindow), std::get<3>(lPlWindow)); //draw serie Color lineColor = getSerieLineColor(pSeries, moreThanOneSerieForAxis); Color symbolColor = getSerieSymbolColor(pSeries, lineColor); drawSymbols( pSeries.getSymbolProperties().getType(), pSeries.getSymbolProperties().getSize(), 1., symbolColor, nbValues, epochTimeValues, computedValues, coloredComputedValues); drawLines( pSeries.getLineProperties().getType(), pSeries.getLineProperties().getStyle(), pSeries.getLineProperties().getWidth(), lineColor, nbValues, epochTimeValues, computedValues, coloredComputedValues); addSerieToParamsLegend(pSeries,pParamIndex,param._originalParamId, lineColor,symbolColor,startDate,stopDate,intervalIndex); delete[] computedValues; delete[] epochTimeValues; if (coloredComputedValues != NULL) delete[] coloredComputedValues; } const std::string EpochPlot::getXAxisId() const { // epoch plot can manage only one x axis. // search for its id for (auto param : _parameterAxesList) { //search epoch axis in color serie if exist if (!param.getYSeriePropertiesList().empty()) return param.getYSeriePropertiesList().begin()->getXAxisId(); } return "epochAxis"; } void EpochPlot::setCenterTimeId(std::string centerTimeId) { _centerTimeId = centerTimeId; } } /* namespace plot */