/* * PanelPlotOutput.cc * * Created on: 29 oct. 2013 * Author: CS */ #include "PanelPlotOutput.hh" #include "Catalog.hh" #include "ColorAxis.hh" #include "ColormapManager.hh" #include "DecoratorPlot.hh" #include "Page.hh" #include "ParamMgr.hh" #include "ParameterManager.hh" #include "PlPlotUtil.hh" #include "PlotLogger.hh" #include "ShadesTools.hh" #include "TimeTableCatalogFactory.hh" #include "TimeUtil.hh" #include #include using namespace AMDA::Parameters; using namespace AMDA::Info; namespace plot { /** * Width character proportion is approximatively 0.83 times smaller than height. */ const float PanelPlotOutput::CHAR_RATIO = 5. / 6.; const float PanelPlotOutput::DEFAULT_TICK_LENGTH_FACTOR = 0.75; // Vertical is for Y axis. const float PanelPlotOutput::VERTICAL_TICK_LENGTH_LIMIT = 0.5; // Horizontal is for X axis. const float PanelPlotOutput::HORIZONTAL_TICK_LENGTH_LIMIT = 0.75; // margin in case of constante curve const float YAXISMARGIN = 0.05; PanelPlotOutput::PanelPlotOutput(AMDA::Parameters::ParameterManager &manager, boost::shared_ptr panel, bool isStandalone) : _panel(panel), _parameterManager(manager), _pParameterValues(NULL), _timeIntervalListPtr(NULL), _panelPlotXYRatio(1), _leftAxisTickMarkWidth(0), _automaticSerieColorCursor(0), _isStandalone(isStandalone) { } PanelPlotOutput::~PanelPlotOutput() { } double getVerticalTickLength(Axis *pAxis, double charHeight) { float horizontalTickLengthLimit = PanelPlotOutput::HORIZONTAL_TICK_LENGTH_LIMIT; float defaultTickLengthFactor = PanelPlotOutput::DEFAULT_TICK_LENGTH_FACTOR; double tickLengthFactor = pAxis->_tick._lengthFactor; if ((!isnan(tickLengthFactor)) && (tickLengthFactor > horizontalTickLengthLimit)) { // 1 character size is equal to 0.75 tick length. return charHeight + (((tickLengthFactor - horizontalTickLengthLimit) * charHeight) / (defaultTickLengthFactor)); } else if ((isnan(tickLengthFactor)) && (defaultTickLengthFactor > horizontalTickLengthLimit)) { // 1 character size is equal to 0.75 tick length. return charHeight + (((defaultTickLengthFactor - horizontalTickLengthLimit) * charHeight) / (defaultTickLengthFactor)); } else { return charHeight; } } double getHorizontalTickLength(Axis *pAxis, double charHeight) { float verticalTickLengthLimit = PanelPlotOutput::VERTICAL_TICK_LENGTH_LIMIT; float defaultTickLengthFactor = PanelPlotOutput::DEFAULT_TICK_LENGTH_FACTOR; double tickLengthFactor = pAxis->_tick._lengthFactor; if ((!isnan(tickLengthFactor)) && (tickLengthFactor > verticalTickLengthLimit)) { // 1 character size is equal to 0.75 tick length. return charHeight + (((tickLengthFactor - verticalTickLengthLimit) * charHeight * PanelPlotOutput::CHAR_RATIO) / (defaultTickLengthFactor)); } else if ((isnan(tickLengthFactor)) && (defaultTickLengthFactor > verticalTickLengthLimit)) { // 1 character size is equal to 0.75 tick length. return charHeight + (((defaultTickLengthFactor - verticalTickLengthLimit) * charHeight * PanelPlotOutput::CHAR_RATIO) / (defaultTickLengthFactor)); } else { return charHeight; } } void PanelPlotOutput::calculatePlotArea(const Bounds & /*panelBounds_*/, Bounds &bounds_) { double topSpace = 0; double bottomSpace = 0; double leftSpace = 0; double rightSpace = 0; // Init _plotAreaSideSet[PlotCommon::Position::POS_TOP] = false; _plotAreaSideSet[PlotCommon::Position::POS_BOTTOM] = false; _plotAreaSideSet[PlotCommon::Position::POS_RIGHT] = false; _plotAreaSideSet[PlotCommon::Position::POS_LEFT] = false; _plotAreaSideSet[PlotCommon::Position::POS_CENTER] = false; // Reserve space for title double titleHeight = 0; _panel->reserveSpaceForTitle(topSpace, bottomSpace, titleHeight); // Reserve space for axes // std::map nbAxesBySide; nbAxesBySide[PlotCommon::Position::POS_TOP] = 0; nbAxesBySide[PlotCommon::Position::POS_BOTTOM] = 0; nbAxesBySide[PlotCommon::Position::POS_RIGHT] = 0; nbAxesBySide[PlotCommon::Position::POS_LEFT] = 0; for (Axes::iterator it = _panel->_axes.begin(); it != _panel->_axes.end(); ++it) { boost::shared_ptr lAxis = it->second; if ((lAxis == nullptr) || (lAxis->_isZAxis) || (!lAxis->_used) || (!lAxis->_visible) || (lAxis->_position == PlotCommon::Position::POS_CENTER)) continue; ++nbAxesBySide[lAxis->_position]; } // ZAxis must be drawn at last! for (Axes::iterator it = _panel->_axes.begin(); it != _panel->_axes.end(); ++it) { // Add X and Y axis boost::shared_ptr lAxis = it->second; if ((lAxis == nullptr) || (lAxis->_isZAxis)) continue; reserveSpaceForAxis(lAxis, titleHeight, nbAxesBySide, topSpace, bottomSpace, leftSpace, rightSpace); } for (Axes::iterator it = _panel->_axes.begin(); it != _panel->_axes.end(); ++it) { // Add Z axis boost::shared_ptr lAxis = it->second; if ((lAxis == nullptr) || (!lAxis->_isZAxis)) continue; reserveSpaceForAxis(lAxis, titleHeight, nbAxesBySide, topSpace, bottomSpace, leftSpace, rightSpace); } // Get character size for panel. PlPlotUtil::setPlFont(_panel->getFont()); CharSize lCharSizePanel = PlPlotUtil::getCharacterSizeInPlPage(_panel->_page); double panelCharWidth = lCharSizePanel.first; double panelCharHeight = lCharSizePanel.second; // add params legend right space when outside if (!_panel->_paramsLegendProperties.getLegendLines().empty() && _panel->_paramsLegendProperties.isVisible() && (_panel->_paramsLegendProperties.getPosition() == ParamsLegendPosition::POS_OUTSIDE)) { PlPlotUtil::setPlFont(_panel->_paramsLegendProperties.getFont()); CharSize lCharSizeLegend = PlPlotUtil::getCharacterSizeInPlPage(_panel->_page); double legendCharWidth = lCharSizeLegend.first; // set offset _panel->_paramsLegendProperties.setLeftOffset(rightSpace); // reserve place for legend rightSpace += _panel->_paramsLegendProperties.getEstimateWidth(legendCharWidth); } // Reserve space for text legend ( maximum 1 text legend by position /*bool leftTextLegendFound = false; bool rightTextLegendFound = false; bool topTextLegendFound = false; bool bottomTextLegendFound = false; */ for (auto textLegendProp : _panel->_textLegendPropertiesList) { bool toDraw = true; /* switch (textLegendProp->getPosition()) { case TextLegendPosition::POS_LEFT : if (leftTextLegendFound) toDraw = false; leftTextLegendFound = true; break; case TextLegendPosition::POS_RIGHT : if (rightTextLegendFound) toDraw = false; rightTextLegendFound = true; break; case TextLegendPosition::POS_TOP : if (topTextLegendFound) toDraw = false; topTextLegendFound = true; break; case TextLegendPosition::POS_BOTTOM : if (bottomTextLegendFound) toDraw = false; bottomTextLegendFound = true; break; }*/ if (toDraw) reserveSpaceForTextLegend(textLegendProp, titleHeight, topSpace, bottomSpace, leftSpace, rightSpace); } // Set specified left, right, top and bottom margins and display a warning // message if computed margins are bigger than specified ones if (_panel->_leftMargin != -1) { if ((_panel->_leftMargin * panelCharWidth) < leftSpace) LOG4CXX_WARN(gLogger, "Left margin for the panel was forced beyond computed size"); leftSpace = _panel->_leftMargin * panelCharWidth; } if (_panel->_rightMargin != -1) { if ((_panel->_rightMargin * panelCharWidth) < rightSpace) LOG4CXX_WARN(gLogger, "Right margin for the panel was forced beyond computed size"); rightSpace = _panel->_rightMargin * panelCharWidth; } if (_panel->_topMargin != -1) { if ((_panel->_topMargin * panelCharHeight) < topSpace) LOG4CXX_WARN(gLogger, "Top margin for the panel was forced beyond computed size"); topSpace = _panel->_topMargin * panelCharHeight; } if (_panel->_bottomMargin != -1) { if ((_panel->_bottomMargin * panelCharHeight) < bottomSpace) LOG4CXX_WARN(gLogger, "Bottom margin for the panel was forced beyond computed size"); bottomSpace = _panel->_bottomMargin * panelCharHeight; } // Update plot area bounds bounds_._x += leftSpace; bounds_._y += bottomSpace; bounds_._width -= (leftSpace + rightSpace); bounds_._height -= (bottomSpace + topSpace); } void PanelPlotOutput::reserveSpaceForAxis(boost::shared_ptr &pAxis, double titleHeight, std::map nbAxesBySide, double &topSpace, double &bottomSpace, double &leftSpace, double &rightSpace) { if (pAxis == nullptr || !pAxis->_used || !pAxis->_visible) return; // Get number of line to draw for legend. int nbLegendRows = pAxis->_legend.getNbLines(); if ((nbLegendRows == 0) && pAxis->_showLegend) nbLegendRows = 1; // Compute legend character size Font legendFont(pAxis->getLegendFont(this->_panel.get())); PlPlotUtil::setPlFont(legendFont); CharSize legendCharSizePanel = PlPlotUtil::getCharacterSizeInPlPage(_panel->_page); std::tuple pageSize = _panel->_page->getSizeInMm(); // Reserve place in relation with the axis position switch (pAxis->_position) { case PlotCommon::Position::POS_BOTTOM: if (pAxis->isZAxis()) LOG4CXX_WARN(gLogger, "PanelPlotOutput::calculatePlotArea: Unrecognized position for z axis '" << pAxis->_position << "'"); // This attribute is used later (in function PanelPlotOutput::drawSeries). if (!pAxis->isZAxis()) _plotAreaSideSet[pAxis->_position] = true; // Reserve space for ticks if (pAxis->_tick._position == Tick::TickPosition::OUTWARDS) { double tickSize = getVerticalTickLength(pAxis.get(), legendCharSizePanel.second); bottomSpace += tickSize; if (nbAxesBySide[PlotCommon::Position::POS_TOP] == 0) // add space for oposite axis topSpace += tickSize; } // Reserve space for ticks labels if (pAxis->_showTickMark == true) bottomSpace += legendCharSizePanel.second * (1 + 0.25); // Reserve space for legend if ((pAxis->_showLegend == true) && (nbLegendRows != 0)) { bottomSpace += PlPlotUtil::LINE_SPACE_TITLE * legendCharSizePanel.second; double legendOffset = bottomSpace + 0.5 * legendCharSizePanel.second; if (!_panel->getTitle()->_text.empty() && (_panel->_titlePosition == PlotCommon::Position::POS_BOTTOM)) legendOffset -= titleHeight; pAxis->setLegendOffset(legendOffset); bottomSpace += (nbLegendRows + PlPlotUtil::LINE_SPACE_TITLE * (nbLegendRows + 1)) * legendCharSizePanel.second; } break; case PlotCommon::Position::POS_TOP: if (pAxis->isZAxis()) LOG4CXX_WARN(gLogger, "PanelPlotOutput::calculatePlotArea: Unrecognized position for z axis '" << pAxis->_position << "'"); // This attribute is used later (in function PanelPlotOutput::drawSeries). if (!pAxis->isZAxis()) _plotAreaSideSet[pAxis->_position] = true; // Reserve space for ticks if (pAxis->_tick._position == Tick::TickPosition::OUTWARDS) { double tickSize = getVerticalTickLength(pAxis.get(), legendCharSizePanel.second); topSpace += tickSize; if (nbAxesBySide[PlotCommon::Position::POS_BOTTOM] == 0) // add space for oposite axis bottomSpace += tickSize; } // Reserve space for ticks labels if (pAxis->_showTickMark == true) topSpace += legendCharSizePanel.second * (1 + 0.25); // Reserve space for legend if ((pAxis->_showLegend == true) && (nbLegendRows != 0)) { topSpace += PlPlotUtil::LINE_SPACE_TITLE * legendCharSizePanel.second; double legendOffset = topSpace - 0.5 * legendCharSizePanel.second; if (!_panel->getTitle()->_text.empty() && (_panel->_titlePosition == PlotCommon::Position::POS_TOP)) legendOffset += titleHeight; pAxis->setLegendOffset(legendOffset); topSpace += (nbLegendRows + PlPlotUtil::LINE_SPACE_TITLE * (nbLegendRows + 1)) * legendCharSizePanel.second; } break; case PlotCommon::Position::POS_LEFT: // Record axis offset used for multi-axes pAxis->setAxisOffset(leftSpace); if (pAxis->isZAxis()) { leftSpace += estimateZAxisWidth(pAxis); break; } // This attribute is used later (in function PanelPlotOutput::drawSeries). _plotAreaSideSet[pAxis->_position] = true; // Reserve space for ticks labels if (pAxis->_showTickMark == true) leftSpace += legendCharSizePanel.first * (pAxis->getTickMarkSize().first + 2 * PlPlotUtil::LINE_SPACE_TITLE + 0.25); // Reserve space for ticks if (pAxis->_tick._position == Tick::TickPosition::OUTWARDS) { double tickSize = getHorizontalTickLength(pAxis.get(), legendCharSizePanel.second); leftSpace += tickSize; if (nbAxesBySide[PlotCommon::Position::POS_RIGHT] == 0) // add space for oposite axis rightSpace += tickSize; } // Reserve space for legend if ((pAxis->_showLegend == true) && (nbLegendRows != 0)) { leftSpace += PlPlotUtil::LINE_SPACE_TITLE * legendCharSizePanel.second * std::get<1>(pageSize) / std::get<0>(pageSize); pAxis->setLegendOffset(leftSpace + 0.5 * legendCharSizePanel.second * std::get<1>(pageSize) / std::get<0>(pageSize)); leftSpace += (nbLegendRows + PlPlotUtil::LINE_SPACE_TITLE * (nbLegendRows + 1)) * legendCharSizePanel.second * std::get<1>(pageSize) / std::get<0>(pageSize); } break; case PlotCommon::Position::POS_RIGHT: // Record axis offset used for multi-axes pAxis->setAxisOffset(rightSpace); if (pAxis->isZAxis()) { rightSpace += estimateZAxisWidth(pAxis); break; } // This attribute is used later (in function PanelPlotOutput::drawSeries). _plotAreaSideSet[pAxis->_position] = true; // Reserve space for ticks labels if (pAxis->_showTickMark == true) rightSpace += legendCharSizePanel.first * (pAxis->getTickMarkSize().first + 2 * PlPlotUtil::LINE_SPACE_TITLE + 0.25); // Reserve space for ticks if (pAxis->_tick._position == Tick::TickPosition::OUTWARDS) { double tickSize = getHorizontalTickLength(pAxis.get(), legendCharSizePanel.second); rightSpace += tickSize; if (nbAxesBySide[PlotCommon::Position::POS_LEFT] == 0) // add space for oposite axis leftSpace += tickSize; } // Reserve space for legend if ((pAxis->_showLegend == true) && (nbLegendRows != 0)) { rightSpace += PlPlotUtil::LINE_SPACE_TITLE * legendCharSizePanel.second * std::get<1>(pageSize) / std::get<0>(pageSize); pAxis->setLegendOffset(rightSpace + 0.5 * legendCharSizePanel.second * std::get<1>(pageSize) / std::get<0>(pageSize)); rightSpace += (nbLegendRows + PlPlotUtil::LINE_SPACE_TITLE * (nbLegendRows + 1)) * legendCharSizePanel.second * std::get<1>(pageSize) / std::get<0>(pageSize); } break; case PlotCommon::Position::POS_CENTER: default: LOG4CXX_WARN(gLogger, "PanelPlotOutput::drawPlotArea: Unrecognized position for axis '" << pAxis->_position << "'"); } } void PanelPlotOutput::reserveSpaceForTextLegend(boost::shared_ptr &pTextLegendProp, double titleHeight, double &topSpace, double &bottomSpace, double &leftSpace, double &rightSpace) { int textLegendLinesNb = pTextLegendProp->getTextLinesNb(); if (textLegendLinesNb == 0) return; PlPlotUtil::setPlFont(pTextLegendProp->getFont()); CharSize lCharSizeLegend = PlPlotUtil::getCharacterSizeInPlPage(_panel->_page); std::tuple pageSize = _panel->_page->getSizeInMm(); switch (pTextLegendProp->getPosition()) { case TextLegendPosition::POS_LEFT: pTextLegendProp->setOffset(leftSpace); leftSpace += (textLegendLinesNb + PlPlotUtil::LINE_SPACE_TITLE * (textLegendLinesNb + 1)) * lCharSizeLegend.second * std::get<1>(pageSize) / std::get<0>(pageSize); break; case TextLegendPosition::POS_RIGHT: pTextLegendProp->setOffset(rightSpace); rightSpace += (textLegendLinesNb + PlPlotUtil::LINE_SPACE_TITLE * (textLegendLinesNb + 1)) * lCharSizeLegend.second * std::get<1>(pageSize) / std::get<0>(pageSize); break; case TextLegendPosition::POS_TOP: if (_panel->_titlePosition == PlotCommon::Position::POS_TOP) pTextLegendProp->setOffset(topSpace - titleHeight); else pTextLegendProp->setOffset(topSpace); topSpace += (textLegendLinesNb + PlPlotUtil::LINE_SPACE_TITLE * (textLegendLinesNb + 1)) * lCharSizeLegend.second; break; case TextLegendPosition::POS_BOTTOM: if (_panel->_titlePosition == PlotCommon::Position::POS_BOTTOM) pTextLegendProp->setOffset(bottomSpace - titleHeight); else pTextLegendProp->setOffset(bottomSpace); bottomSpace += (textLegendLinesNb + PlPlotUtil::LINE_SPACE_TITLE * (textLegendLinesNb + 1)) * lCharSizeLegend.second; break; } } /** * @brief Compute panel XY ratio used for angular conversions */ void PanelPlotOutput::computePanelPlotXYRatio(void) { // panel plot XY ratio = page ratio * plot area bound size ratio _panelPlotXYRatio = (std::get<0>(_panel->_page->getSize()) / std::get<1>(_panel->_page->getSize())) * (_plotAreaBounds._width / _plotAreaBounds._height); } /** * @brief Draw legend for each axis. */ void PanelPlotOutput::drawLegends(boost::shared_ptr &pAxis, PlWindow &pPlWindow, Bounds &pPlotAreaSize) { LOG4CXX_DEBUG(gLogger, "Drawing legend for axis " << pAxis->_id << " : " << pAxis->_legend.getText()); // Set legend font Font legendFont(pAxis->getLegendFont(this->_panel.get())); PlPlotUtil::setPlFont(legendFont); // Get legend row info std::list> lines = pAxis->_legend.getLines(); // Check if there is something to draw ! if ((pAxis->_visible == true) && (pAxis->_showLegend == true) && (lines.size() != 0)) { Color lInitialColor; // If legend has not it's own color set axis color. if ((pAxis->_legend.getColor()._colorIndex == -1) && ((pAxis->_legend.getColor()._red == -1) && (pAxis->_legend.getColor()._green == -1) && (pAxis->_legend.getColor()._blue == -1))) { lInitialColor = changeColor(_pls, pAxis->_color, _panel->_page->_mode); } else { Color legendColor = pAxis->_legend.getColor(); lInitialColor = changeColor(_pls, legendColor, _panel->_page->_mode); } // Init position double lPosition = PlPlotUtil::LINE_SPACE_TITLE; unsigned int lineIndex = 0; // Depending on the way to draw legend, for BOTTOM position we have to draw from first legend line to last. switch (pAxis->_position) { case PlotCommon::Position::POS_BOTTOM: _pls->vpor(pPlotAreaSize._x, pPlotAreaSize._x + pPlotAreaSize._width, pPlotAreaSize._y - pAxis->getLegendOffset(), pPlotAreaSize._y - pAxis->getLegendOffset() + pPlotAreaSize._height); _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); // Draw lines, beginning by the first one for (auto line : lines) { std::string lineToDraw = line.first; if (lineIndex == lines.size() - 1) { // add unit if defined if (!pAxis->getAxisUnits().empty()) { lineToDraw += " ("; lineToDraw += pAxis->getAxisUnits(); lineToDraw += ")"; } } Color lSavedColor; if (line.second.isSet()) { lSavedColor = changeColor(_pls, line.second, _panel->_page->_mode); } _pls->mtex(getPlSide(pAxis->_position).c_str(), lPosition, 0.5, 0.5, lineToDraw.c_str()); lPosition += (1 + PlPlotUtil::LINE_SPACE_TITLE); if (line.second.isSet()) { restoreColor(_pls, lSavedColor, _panel->_page->_mode); } ++lineIndex; } break; case PlotCommon::Position::POS_TOP: _pls->vpor(pPlotAreaSize._x, pPlotAreaSize._x + pPlotAreaSize._width, pPlotAreaSize._y + pAxis->getLegendOffset(), pPlotAreaSize._y + pAxis->getLegendOffset() + pPlotAreaSize._height); _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); // Draw lines, beginning by the last one for (auto line : boost::adaptors::reverse(lines)) { std::string lineToDraw = line.first; if (lineIndex == lines.size() - 1) { // add unit if defined if (!pAxis->getAxisUnits().empty()) { lineToDraw += " ("; lineToDraw += pAxis->getAxisUnits(); lineToDraw += ")"; } } Color lSavedColor; if (line.second.isSet()) { lSavedColor = changeColor(_pls, line.second, _panel->_page->_mode); } _pls->mtex(getPlSide(pAxis->_position).c_str(), lPosition, 0.5, 0.5, lineToDraw.c_str()); lPosition += (1 + PlPlotUtil::LINE_SPACE_TITLE); if (line.second.isSet()) { restoreColor(_pls, lSavedColor, _panel->_page->_mode); } ++lineIndex; } break; case PlotCommon::Position::POS_RIGHT: _pls->vpor(pPlotAreaSize._x, pPlotAreaSize._x + pAxis->getLegendOffset() + pPlotAreaSize._width, pPlotAreaSize._y, pPlotAreaSize._y + pPlotAreaSize._height); _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); // Draw lines, beginning by the first one for (auto line : lines) { std::string lineToDraw = line.first; if (lineIndex == lines.size() - 1) { // add unit if defined if (!pAxis->getAxisUnits().empty()) { lineToDraw += " ("; lineToDraw += pAxis->getAxisUnits(); lineToDraw += ")"; } } Color lSavedColor; if (line.second.isSet()) { lSavedColor = changeColor(_pls, line.second, _panel->_page->_mode); } _pls->mtex(getPlSide(pAxis->_position).c_str(), lPosition, 0.5, 0.5, lineToDraw.c_str()); lPosition += (1 + PlPlotUtil::LINE_SPACE_TITLE); if (line.second.isSet()) { restoreColor(_pls, lSavedColor, _panel->_page->_mode); } ++lineIndex; } break; case PlotCommon::Position::POS_LEFT: _pls->vpor(pPlotAreaSize._x - pAxis->getLegendOffset(), pPlotAreaSize._x + pPlotAreaSize._width, pPlotAreaSize._y, pPlotAreaSize._y + pPlotAreaSize._height); _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); // Draw lines, beginning by the last one for (auto line : boost::adaptors::reverse(lines)) { std::string lineToDraw = line.first; if (lineIndex == lines.size() - 1) { // add unit if defined if (!pAxis->getAxisUnits().empty()) { lineToDraw += " ("; lineToDraw += pAxis->getAxisUnits(); lineToDraw += ")"; } } Color lSavedColor; if (line.second.isSet()) { lSavedColor = changeColor(_pls, line.second, _panel->_page->_mode); } _pls->mtex(getPlSide(pAxis->_position).c_str(), lPosition, 0.5, 0.5, lineToDraw.c_str()); lPosition += (1 + PlPlotUtil::LINE_SPACE_TITLE); if (line.second.isSet()) { restoreColor(_pls, lSavedColor, _panel->_page->_mode); } ++lineIndex; } break; case PlotCommon::Position::POS_CENTER: default: LOG4CXX_WARN(gLogger, "PanelPlotOutput::drawPlotArea: Unrecognized position for axis '" << pAxis->_position << "'"); } _pls->vpor(pPlotAreaSize._x, pPlotAreaSize._x + pPlotAreaSize._width, pPlotAreaSize._y, pPlotAreaSize._y + pPlotAreaSize._height); _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); // Restore initial color. restoreColor(_pls, lInitialColor, _panel->_page->_mode); } } void PanelPlotOutput::drawAxis(boost::shared_ptr pAxis, TickConf &pTickConf, std::string pXAxisOptions, std::string pYAxisOptions) { Color lInitialColor = changeColor(_pls, pAxis->_color, _panel->_page->_mode); // Set axis thickness. _pls->width(pAxis->_thickness); // Set tick (major and minor) length factor PLFLT lTickLenFact = DEFAULT_TICK_LENGTH_FACTOR; if (!isnan(pAxis->_tick._lengthFactor)) { lTickLenFact = pAxis->_tick._lengthFactor; } else { // Nothing to do. } // 0 => keep tick height in millimeters. _pls->smaj(0, lTickLenFact); _pls->smin(0, lTickLenFact); // if options contains "o" character we need to set label function if ((pXAxisOptions.find("o") != std::string::npos) || (pYAxisOptions.find("o") != std::string::npos)) { _pls->slabelfunc(pAxis->_labelGenerator->_function, pAxis->_labelGenerator->_data); } // Set line style (force to be plain) _pls->lsty(static_cast(getPlLineStyle(LineStyle::PLAIN))); // Set font to draw axes. Font axisFont(pAxis->getLegendFont(this->_panel.get())); axisFont.setStyle(Font::Style::NORMAL); axisFont.setWeight(Font::Weight::NORMAL); PlPlotUtil::setPlFont(axisFont); size_t lPos; double xMajorTickSpace = std::get<0>(pTickConf); double xMinorTickNumber = std::get<1>(pTickConf); double yMajorTickSpace = std::get<2>(pTickConf); double yMinorTickNumber = std::get<3>(pTickConf); // if options contains "a" character we need to draw origin separately. if ((lPos = pXAxisOptions.find("a")) != std::string::npos) { pXAxisOptions.replace(lPos, 1, ""); _pls->box("a", xMajorTickSpace, xMinorTickNumber, "", yMajorTickSpace, yMinorTickNumber); } else if ((lPos = pYAxisOptions.find("a")) != std::string::npos) { pYAxisOptions.replace(lPos, 1, ""); _pls->box("", xMajorTickSpace, xMinorTickNumber, "a", yMajorTickSpace, yMinorTickNumber); } else { // Nothing to do. } // Draw axis. _pls->box(pXAxisOptions.c_str(), xMajorTickSpace, xMinorTickNumber, pYAxisOptions.c_str(), yMajorTickSpace, yMinorTickNumber); // Restore initial color. restoreColor(_pls, lInitialColor, _panel->_page->_mode); // Set axis as drawn. pAxis->_drawn = true; } void PanelPlotOutput::drawXAxis(boost::shared_ptr pXAxis, PlWindow &pPlWindow, Bounds &pPlotAreaSize, TickConf &pTickConf) { // Set option to draw origin. std::string lAxisOption = pXAxis->getPlotOpt(); std::string lTmpAxisOption = "xi"; // plplot doesn't provide solution to set space between tick and tick mark. // To do that we need to play with viewport position and size. // So axis will be drawn in two times: // - first draw tick marks // - second draw tick and edge // Custom space between tick marks and tick is only done when tick length is greater than 0.75. // Get extra tick mark space (only if they are outwards) if (pXAxis->_tick._position == Tick::TickPosition::OUTWARDS) { float lTickLengthFactor = 0; if ((!isnan(pXAxis->_tick._lengthFactor)) && (pXAxis->_tick._lengthFactor > HORIZONTAL_TICK_LENGTH_LIMIT)) { lTickLengthFactor = pXAxis->_tick._lengthFactor; } else if ((isnan(pXAxis->_tick._lengthFactor)) && (DEFAULT_TICK_LENGTH_FACTOR > HORIZONTAL_TICK_LENGTH_LIMIT)) { lTickLengthFactor = DEFAULT_TICK_LENGTH_FACTOR; } if (lTickLengthFactor != 0) { // 1 character size is equal to 0.75 tick length. PlPlotUtil::setPlFont(_panel->getFont()); float lTickMarkSpace = (lTickLengthFactor - HORIZONTAL_TICK_LENGTH_LIMIT) * (PlPlotUtil::getCharacterSizeInPlPage(_panel->_page).second) / (DEFAULT_TICK_LENGTH_FACTOR); size_t lPos; if ((lPos = lAxisOption.find("m")) != std::string::npos) { lTmpAxisOption += "m"; lAxisOption.replace(lPos, 1, ""); } if ((lPos = lAxisOption.find("n")) != std::string::npos) { lTmpAxisOption += "n"; lAxisOption.replace(lPos, 1, ""); } if ((lPos = lAxisOption.find("o")) != std::string::npos) { lTmpAxisOption += "o"; lAxisOption.replace(lPos, 1, ""); } if ((lPos = lAxisOption.find("d")) != std::string::npos) { lTmpAxisOption += "d"; lAxisOption.replace(lPos, 1, ""); } if ((lPos = lAxisOption.find("f")) != std::string::npos) { lTmpAxisOption += "f"; lAxisOption.replace(lPos, 1, ""); } if (pXAxis->_position == PlotCommon::Position::POS_BOTTOM) { _pls->vpor(pPlotAreaSize._x, pPlotAreaSize._x + pPlotAreaSize._width, pPlotAreaSize._y - lTickMarkSpace, pPlotAreaSize._y + pPlotAreaSize._height); } else { _pls->vpor(pPlotAreaSize._x, pPlotAreaSize._x + pPlotAreaSize._width, pPlotAreaSize._y, pPlotAreaSize._y + pPlotAreaSize._height + lTickMarkSpace); } _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); // Draw tick mark. drawAxis(pXAxis, pTickConf, lTmpAxisOption, ""); } } // Restore default plot area _pls->vpor(pPlotAreaSize._x, pPlotAreaSize._x + pPlotAreaSize._width, pPlotAreaSize._y, pPlotAreaSize._y + pPlotAreaSize._height); // Set window. _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); // Check if origin must be drawn. if (std::get<0>(pPlWindow) != 0 && std::get<1>(pPlWindow) && pXAxis->_origin == 0) { lAxisOption += "a"; } // Check if opposite plot area side need to be drawn lAxisOption += drawOppositeSide(pXAxis); // Draw rest of axis. drawAxis(pXAxis, pTickConf, lAxisOption, ""); } void PanelPlotOutput::drawYAxis(boost::shared_ptr pYAxis, PlWindow &pPlWindow, Bounds &pPlotAreaSize, TickConf &pTickConf) { // Get axis offset in case of multi-axes double axisOffset = pYAxis->getAxisOffset(); // Set option to draw origin ("v" is set to have numeric labels parallel to X axis). std::string lAxisOption = pYAxis->getPlotOpt(); std::string lTmpAxisOption = "xiv"; // plplot doesn't provide solution to set space between tick and tick mark. // To do that we need to play with viewport position and size. // So axis will be drawn in two times: // - first draw tick marks // - second draw tick and edge // Custom space between tick marks and tick is only done when tick length is greater than 0.5. // Get extra tick mark space (only if they are outwards) pPlotAreaSize._width = pPlotAreaSize._width; if (pYAxis->_tick._position == Tick::TickPosition::OUTWARDS) { float lTickLengthFactor = 0; if ((!isnan(pYAxis->_tick._lengthFactor)) && (pYAxis->_tick._lengthFactor > VERTICAL_TICK_LENGTH_LIMIT)) { lTickLengthFactor = pYAxis->_tick._lengthFactor; } else if ((isnan(pYAxis->_tick._lengthFactor)) && (DEFAULT_TICK_LENGTH_FACTOR > VERTICAL_TICK_LENGTH_LIMIT)) { lTickLengthFactor = DEFAULT_TICK_LENGTH_FACTOR; } if (lTickLengthFactor != 0) { // 1 character size is equal to 0.75 tick length. PlPlotUtil::setPlFont(_panel->getFont()); double lTickMarkSpace = (lTickLengthFactor - VERTICAL_TICK_LENGTH_LIMIT) * (PlPlotUtil::getCharacterSizeInPlPage(_panel->_page).second) / (DEFAULT_TICK_LENGTH_FACTOR); size_t lPos; if ((lPos = lAxisOption.find("m")) != std::string::npos) { lTmpAxisOption += "m"; lAxisOption.replace(lPos, 1, ""); } if ((lPos = lAxisOption.find("n")) != std::string::npos) { lTmpAxisOption += "n"; lAxisOption.replace(lPos, 1, ""); } if ((lPos = lAxisOption.find("o")) != std::string::npos) { lTmpAxisOption += "o"; lAxisOption.replace(lPos, 1, ""); } if ((lPos = lAxisOption.find("f")) != std::string::npos) { lTmpAxisOption += "f"; lAxisOption.replace(lPos, 1, ""); } if (lAxisOption.find("l") != std::string::npos) { // Do not remove on original axis option // because option is needed to draw logarithmic tick. lTmpAxisOption += "l"; } // Set plot area used to draw tick mark if (pYAxis->_position == PlotCommon::Position::POS_LEFT) { _pls->vpor(pPlotAreaSize._x - lTickMarkSpace - axisOffset, pPlotAreaSize._x + pPlotAreaSize._width, pPlotAreaSize._y, pPlotAreaSize._y + pPlotAreaSize._height); } else { _pls->vpor(pPlotAreaSize._x, pPlotAreaSize._x + pPlotAreaSize._width + lTickMarkSpace + axisOffset, pPlotAreaSize._y, pPlotAreaSize._y + pPlotAreaSize._height); } _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); // Draw tick mark. drawAxis(pYAxis, pTickConf, "", lTmpAxisOption); } } // Set plot area used to draw tick if (pYAxis->_position == PlotCommon::Position::POS_LEFT) { _pls->vpor(pPlotAreaSize._x - axisOffset, pPlotAreaSize._x + pPlotAreaSize._width, pPlotAreaSize._y, pPlotAreaSize._y + pPlotAreaSize._height); } else { _pls->vpor(pPlotAreaSize._x, pPlotAreaSize._x + pPlotAreaSize._width + axisOffset, pPlotAreaSize._y, pPlotAreaSize._y + pPlotAreaSize._height); } // Set window. _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); // Check if origin must be drawn. if (std::get<0>(pPlWindow) != 0 && std::get<1>(pPlWindow) && pYAxis->_origin == 0) { lAxisOption += "a"; } // Check if opposite plot area side need to be drawn lAxisOption += drawOppositeSide(pYAxis); // Draw rest of axis. drawAxis(pYAxis, pTickConf, "", lAxisOption); // Restore default plot area _pls->vpor(pPlotAreaSize._x, pPlotAreaSize._x + pPlotAreaSize._width, pPlotAreaSize._y, pPlotAreaSize._y + pPlotAreaSize._height); // Set window. _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); } #define COLORBAR_X_OFFSET 0.01 #define COLORBAR_BODY_WIDTH 0.0375 double PanelPlotOutput::estimateZAxisWidth(boost::shared_ptr pZAxis) { double axisWidth = (COLORBAR_X_OFFSET + COLORBAR_BODY_WIDTH) * _panel->_bounds._width; PlPlotUtil::setPlFont(_panel->getFont()); CharSize lCharSize = PlPlotUtil::getCharacterSizeInPlPage(_panel->_page); int nbLineLegend = pZAxis->_legend.getNbLines(); if ((pZAxis->_showLegend == true) && (nbLineLegend != 0)) { if (_panel->_page->_orientation == PlotCommon::Orientation::LANDSCAPE) axisWidth += lCharSize.second * (2 * nbLineLegend + 1); else axisWidth += lCharSize.first * (2 * nbLineLegend + 1); } return axisWidth; } void PanelPlotOutput::drawZAxis(boost::shared_ptr pZAxis, PlWindow &pPlWindow, Bounds &pPlotAreaSize, TickConf & /*pTickConf*/) { Color lInitialColor; _pls->gcol0(0, lInitialColor._red, lInitialColor._green, lInitialColor._blue); // Set axis thickness. _pls->width(pZAxis->_thickness); // Set line style (force to be plain) _pls->lsty(static_cast(getPlLineStyle(LineStyle::PLAIN))); // Set font to draw axes. PlPlotUtil::setPlFont(_panel->getFont()); std::string lAxisOption = pZAxis->getPlotOpt(); std::string lAxisLegend = ""; std::list> lines = pZAxis->_legend.getLines(); for (auto line : lines) { if (line.first.empty()) { continue; } if (!lAxisLegend.empty()) { lAxisLegend += "\n"; } lAxisLegend += line.first; } PLFLT colorbar_width, colorbar_height; const int cont_color = 0; const PLFLT cont_width = 0.0; // set legend const PLINT n_labels = (lAxisLegend.empty()) ? 0 : 1; std::string label = lAxisLegend; const char *labels[n_labels]; if (!lAxisLegend.empty()) labels[0] = label.c_str(); // set axis options const PLINT n_axis_opts = 1; const char *axis_opts[n_axis_opts] = { lAxisOption.c_str(), }; PLFLT axis_ticks[n_axis_opts] = { 0}; PLINT axis_subticks[n_axis_opts] = { 0}; // if options contains "o" character we need to set label function if (lAxisOption.find("o") != std::string::npos) { _pls->slabelfunc(pZAxis->_labelGenerator->_function, pZAxis->_labelGenerator->_data); } // set nb og colors const int nbCol = 20; PLINT num_values[1] = { nbCol + 1}; Range r = pZAxis->getRange(); PLFLT *shedge = new PLFLT[nbCol + 1]; ShadesTools::computeEdgesLevels(r, nbCol + 1, shedge); PLFLT *values[1]; values[0] = shedge; // set color map _pls->spal1( ColormapManager::getInstance().getColorAxis(pZAxis->_color._colorMapIndex).c_str(), true); // set color bar and legend position PLINT position = PL_POSITION_OUTSIDE | PL_POSITION_VIEWPORT; PLINT label_opts[1]; switch (pZAxis->_position) { case PlotCommon::Position::POS_LEFT: position |= PL_POSITION_LEFT; label_opts[0] = PL_COLORBAR_LABEL_LEFT; _pls->vpor(pPlotAreaSize._x - pZAxis->getAxisOffset(), pPlotAreaSize._x + pPlotAreaSize._width, pPlotAreaSize._y, pPlotAreaSize._y + pPlotAreaSize._height); break; case PlotCommon::Position::POS_RIGHT: position |= PL_POSITION_RIGHT; label_opts[0] = PL_COLORBAR_LABEL_RIGHT; _pls->vpor(pPlotAreaSize._x, pPlotAreaSize._x + pPlotAreaSize._width + pZAxis->getAxisOffset(), pPlotAreaSize._y, pPlotAreaSize._y + pPlotAreaSize._height); break; default: { std::stringstream lError; lError << "PanelPlotOutput::drawZAxis : Bad Z axis position"; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } } _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); _pls->colorbar( &colorbar_width, &colorbar_height, PL_COLORBAR_GRADIENT, // PL_COLORBAR_SHADE, position, 0.0, // COLORBAR_X_OFFSET, 0.0, COLORBAR_BODY_WIDTH, 0.875, 0, /*bg_color*/ 1, 1, 0.0, 0.0, cont_color, cont_width, n_labels, label_opts, labels, n_axis_opts, axis_opts, axis_ticks, axis_subticks, num_values, (const PLFLT *const *)values); // reset color map _pls->spal1( ColormapManager::getInstance().get(_panel->_page->_mode, ColormapManager::DEFAULT_COLORMAP_1) .c_str(), true); _pls->scol0(0, lInitialColor._red, lInitialColor._green, lInitialColor._blue); delete[] shedge; // Restore initial color. restoreColor(_pls, lInitialColor, _panel->_page->_mode); // Restore default plot area _pls->vpor(pPlotAreaSize._x, pPlotAreaSize._x + pPlotAreaSize._width, pPlotAreaSize._y, pPlotAreaSize._y + pPlotAreaSize._height); _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); // Set axis as drawn. pZAxis->_drawn = true; } Range PanelPlotOutput::getXAxisRange(SeriesProperties &pSeries, boost::shared_ptr pAxis) { if (pSeries.hasXAxis() && pAxis.get() == nullptr) { std::stringstream lError; lError << "PanelPlotOutput::drawSeries" << ": X axis with id '" << pSeries.getXAxisId() << "' not found."; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } else if (pSeries.hasXAxis()) { // fill X range (plplot window). return (pAxis->getRange()); } return Range(); } Range PanelPlotOutput::getYAxisRange(SeriesProperties &pSeries, boost::shared_ptr pAxis) { if (pSeries.hasYAxis() && pAxis.get() == nullptr) { std::stringstream lError; lError << "PanelPlotOutput::drawSeries" << ": Y axis with id '" << pSeries.getYAxisId() << "' not found."; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } else if (pSeries.hasYAxis()) { // fill Y range (plplot window). return (pAxis->getRange()); } return Range(); } Range PanelPlotOutput::getZAxisRange(SeriesProperties &pSeries, boost::shared_ptr pAxis) { if (pSeries.hasZAxis() && pAxis.get() == nullptr) { std::stringstream lError; lError << "PanelPlotOutput::drawSeries" << ": Z axis with id '" << pSeries.getYAxisId() << "' not found."; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } else if (pSeries.hasZAxis()) { // fill Z range (plplot window). return (pAxis->getRange()); } return Range(); } /** * Convert an X axis string value to a double X value */ double PanelPlotOutput::convertXAxisValue(const std::string &value) { return std::stod(value); } /** * Convert an Y axis string value to a double Y value */ double PanelPlotOutput::convertYAxisValue(const std::string &value) { return std::stod(value); } /** * Get colored value associated to a data value. Return false if the value is filtered. */ bool PanelPlotOutput::getColoredValue(double value, double filterMin, double filterMax, bool useLog0AsMin, PLFLT &col) { boost::shared_ptr lZAxis = _panel->getColorAxis(); if (lZAxis == nullptr) return false; bool filterMinMax = (isNAN(filterMin) == false) || (isNAN(filterMax) == false); Range r = lZAxis->getRange(); if (isnan(value)) return false; if ((filterMinMax == true) && ((value < filterMin) || (value > filterMax))) return false; double correctedValue = value; if (lZAxis->_scale == Axis::Scale::LOGARITHMIC) { if (correctedValue <= 0) { if (useLog0AsMin) { col = 0; return true; } return false; } correctedValue = log10(correctedValue); } if (!lZAxis->_reverse) col = (correctedValue - r.getMin()) / (r.getMax() - r.getMin()); else col = (correctedValue - r.getMax()) / (r.getMin() - r.getMax()); return true; } /** * Draw list of symbols */ void PanelPlotOutput::drawSymbols(SymbolType pType, int pSize, double pFactor, Color pColor, int pNbData, double *pXData, double *pYData, double *pZData, double filterZMin, double filterZMax) { if (pType == SymbolType::NO) return; Color lInitialColor; // Set color. lInitialColor = changeColor(_pls, pColor, _panel->_page->_mode); PlPlotUtil::setPlFont(_panel->_page->getFont()); // Set size. _pls->ssym(pSize, pFactor); // Get colored axis boost::shared_ptr lZAxis = _panel->getColorAxis(); // draw symbols if ((pZData == NULL) || (lZAxis == nullptr)) _pls->poin(pNbData, pXData, pYData, static_cast(pType)); else { // set color map _pls->spal1( ColormapManager::getInstance().getColorAxis(lZAxis->_color._colorMapIndex).c_str(), true); // get specific colors for min / max values Color minValColor = lZAxis->getMinValColor(); Color maxValColor = lZAxis->getMaxValColor(); PLFLT col; for (int i = 0; i < pNbData; ++i) { if (!getColoredValue(pZData[i], filterZMin, filterZMax, false, col)) continue; if (col <= 0.) { if (minValColor.isSet()) { restoreColor(_pls, minValColor, _panel->_page->_mode); _pls->poin(1, &pXData[i], &pYData[i], static_cast(pType)); _pls->spal1(ColormapManager::getInstance().getColorAxis(lZAxis->_color._colorMapIndex).c_str(), true); } else { _pls->col1(0); _pls->poin(1, &pXData[i], &pYData[i], static_cast(pType)); } } else if (col >= 1.) { if (maxValColor.isSet()) { restoreColor(_pls, maxValColor, _panel->_page->_mode); _pls->poin(1, &pXData[i], &pYData[i], static_cast(pType)); _pls->spal1(ColormapManager::getInstance().getColorAxis(lZAxis->_color._colorMapIndex).c_str(), true); } else { _pls->col1(1); _pls->poin(1, &pXData[i], &pYData[i], static_cast(pType)); } } else { _pls->col1(col); _pls->poin(1, &pXData[i], &pYData[i], static_cast(pType)); } } } // Restore color. restoreColor(_pls, lInitialColor, _panel->_page->_mode); } /** * Draw list of lines */ void PanelPlotOutput::drawLines(LineType pType, LineStyle pStyle, int pWidth, Color &pColor, int pNbData, double *pXData, double *pYData, double *pZData, double filterZMin, double filterZMax) { if (pType == LineType::EMPTY) return; if (pType != LineType::LINE) { BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg("HISTO line type can't be used in time plot. Use LINE or EMPTY type")); } Color lInitialColor; // Set color. lInitialColor = changeColor(_pls, pColor, _panel->_page->_mode); // Set line type. _pls->lsty(static_cast(getPlLineStyle(pStyle))); // Set line thickness. _pls->width(pWidth); // Get colored axis boost::shared_ptr lZAxis = _panel->getColorAxis(); // draw lines. if ((pZData == NULL) || (lZAxis == nullptr)) { _pls->line(pNbData, pXData, pYData); } else { // set color map _pls->spal1( ColormapManager::getInstance().getColorAxis(lZAxis->_color._colorMapIndex).c_str(), true); // get specific colors for min / max values Color minValColor = lZAxis->getMinValColor(); Color maxValColor = lZAxis->getMaxValColor(); PLFLT col; for (int i = 0; i < pNbData - 1; ++i) { if (!getColoredValue(pZData[i], filterZMin, filterZMax, false, col)) continue; if (col <= 0.) { if (minValColor.isSet()) { restoreColor(_pls, minValColor, _panel->_page->_mode); _pls->line(2, &pXData[i], &pYData[i]); _pls->spal1(ColormapManager::getInstance().getColorAxis(lZAxis->_color._colorMapIndex).c_str(), true); } else { _pls->col1(0); _pls->line(2, &pXData[i], &pYData[i]); } } else if (col >= 1.) { if (maxValColor.isSet()) { restoreColor(_pls, maxValColor, _panel->_page->_mode); _pls->line(2, &pXData[i], &pYData[i]); _pls->spal1(ColormapManager::getInstance().getColorAxis(lZAxis->_color._colorMapIndex).c_str(), true); } else { _pls->col1(1); _pls->line(2, &pXData[i], &pYData[i]); } } else { _pls->col1(col); _pls->line(2, &pXData[i], &pYData[i]); } } } // Restore color. restoreColor(_pls, lInitialColor, _panel->_page->_mode); } /** * Draw a rectangle */ void PanelPlotOutput::drawRectangle(double xmin, double xmax, double ymin, double ymax, Color &color, double alpha) { if (!color.isSet()) { return; } Color lInitialColor; // Set color. lInitialColor = changeColor(_pls, color, _panel->_page->_mode); // Draw rectangle PLFLT x[4], y[4]; x[0] = xmin; x[1] = xmin; x[2] = xmax; x[3] = xmax; y[0] = ymin; y[1] = ymax; y[2] = ymax; y[3] = ymin; // Fill rectangle PLINT icol = 0; PLINT r, g, b = 0; PLFLT a = 0; _pls->gcol0a(icol, r, g, b, a); a = alpha; _pls->scol0a(icol, r, g, b, a); _pls->col0(icol); _pls->fill(4, x, y); // Restore color. restoreColor(_pls, lInitialColor, _panel->_page->_mode); } /* * @brief Draw a matrix */ void PanelPlotOutput::drawMatrix(MatrixGrid &matrixGrid, double minDataVal, double maxDataVal, Color minValColor, Color maxValColor, int colorMapIndex, bool useLog0AsMin) { // set color map _pls->spal1( ColormapManager::getInstance().getColorAxis(colorMapIndex).c_str(), true); Color lInitialColor; _pls->gcol0(0, lInitialColor._red, lInitialColor._green, lInitialColor._blue); // plot matrix PLFLT x[4], y[4]; PLFLT col; for (auto part : matrixGrid) { x[0] = part.x[0]; x[1] = part.x[1]; x[2] = x[1]; x[3] = x[0]; y[0] = part.y[0]; y[1] = y[0]; y[2] = part.y[1]; y[3] = y[2]; if (isNAN(part.value)) continue; if (!part.isColorIndex) { if (!getColoredValue(part.value, minDataVal, maxDataVal, useLog0AsMin, col)) continue; } else { Color dataValueColor(colorMapIndex, (int)part.value); restoreColor(_pls, dataValueColor, _panel->_page->_mode); _pls->fill(4, x, y); _pls->spal1(ColormapManager::getInstance().getColorAxis(colorMapIndex).c_str(), true); continue; } if (col <= 0.) { if (minValColor.isSet()) { restoreColor(_pls, minValColor, _panel->_page->_mode); _pls->fill(4, x, y); _pls->spal1(ColormapManager::getInstance().getColorAxis(colorMapIndex).c_str(), true); } else { _pls->col1(0); _pls->fill(4, x, y); } } else if (col >= 1.) { if (maxValColor.isSet()) { restoreColor(_pls, maxValColor, _panel->_page->_mode); _pls->fill(4, x, y); _pls->spal1(ColormapManager::getInstance().getColorAxis(colorMapIndex).c_str(), true); } else { _pls->col1(1); _pls->fill(4, x, y); } } else { _pls->col1(col); _pls->fill(4, x, y); } } // restore to initial color context _pls->spal1( ColormapManager::getInstance().get(_panel->_page->_mode, ColormapManager::DEFAULT_COLORMAP_1) .c_str(), true); _pls->scol0(0, lInitialColor._red, lInitialColor._green, lInitialColor._blue); // Restore color. restoreColor(_pls, lInitialColor, _panel->_page->_mode); } /** * Draw errors segments */ void PanelPlotOutput::drawYErrors( LineType pType, LineStyle pStyle, int pWidth, Color &pColor, int pNbData, double *pXData, double *pYMinData, double *pYMaxData) { if (pType == LineType::EMPTY) return; if (pType != LineType::LINE) { BOOST_THROW_EXCEPTION(PanelPlotOutputException() << AMDA::ex_msg("HISTO line type can't be used in time plot. Use LINE or EMPTY type")); } Color lInitialColor; // Set color. lInitialColor = changeColor(_pls, pColor, _panel->_page->_mode); // Set line type. _pls->lsty(static_cast(getPlLineStyle(pStyle))); // Set line thickness. _pls->width(pWidth); // Set the default tich with _pls->smin(0, 0.5); // Draw error bars _pls->erry(pNbData, pXData, pYMinData, pYMaxData); // Restore color. restoreColor(_pls, lInitialColor, _panel->_page->_mode); } /** * Draws X constant lines linked to axis */ void PanelPlotOutput::drawXConstantLines(boost::shared_ptr pAxis, PlWindow &pPlWindow) { double x[2], y[2]; _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); for (auto constantLine : pAxis->_constantLines) { if (constantLine->isDrawn()) continue; x[0] = convertXAxisValue(constantLine->getValue()); x[1] = convertXAxisValue(constantLine->getValue()); y[0] = std::get<2>(pPlWindow); y[1] = std::get<3>(pPlWindow); if (pAxis->_scale == Axis::Scale::LOGARITHMIC) { x[0] = log10(x[0]); x[1] = log10(x[1]); } drawLines( LineType::LINE, constantLine->getStyle(), constantLine->getWidth(), constantLine->getColor(), 2, x, y); constantLine->setDrawn(true); } } /** * Draws Y constant lines linked to axis */ void PanelPlotOutput::drawYConstantLines(boost::shared_ptr pAxis, PlWindow &pPlWindow) { double x[2], y[2]; _pls->wind(std::get<0>(pPlWindow), std::get<1>(pPlWindow), std::get<2>(pPlWindow), std::get<3>(pPlWindow)); for (auto constantLine : pAxis->_constantLines) { if (constantLine->isDrawn()) continue; x[0] = std::get<0>(pPlWindow); x[1] = std::get<1>(pPlWindow); y[0] = convertYAxisValue(constantLine->getValue()); y[1] = convertYAxisValue(constantLine->getValue()); if (pAxis->_scale == Axis::Scale::LOGARITHMIC) { y[0] = log10(y[0]); y[1] = log10(y[1]); } drawLines( LineType::LINE, constantLine->getStyle(), constantLine->getWidth(), constantLine->getColor(), 2, x, y); constantLine->setDrawn(true); } } /** * Draws TextPlots */ void PanelPlotOutput::drawTextPlots(boost::shared_ptr pXAxis, boost::shared_ptr pYAxis, PlWindow &pPlWindow, const TextPlots &textPlots) { double x, y; double x1, x2, y1, y2; x1 = std::get<0>(pPlWindow); x2 = std::get<1>(pPlWindow); y1 = std::get<2>(pPlWindow); y2 = std::get<3>(pPlWindow); _pls->wind(x1, x2, y1, y2); for (auto textPlot : textPlots) { if (textPlot->isDrawn()) continue; if (!textPlot->_xAxisId.empty() && (textPlot->_xAxisId.compare(pXAxis->_id) != 0)) continue; if (!textPlot->_yAxisId.empty() && (textPlot->_yAxisId.compare(pYAxis->_id) != 0)) continue; // Compute x y position for the text if (textPlot->_x.find("%") != std::string::npos) { // Remove % before conversion int pos = textPlot->_x.find("%"); std::string xPos = textPlot->_x; xPos.erase(pos); // Compute x value as a percent of the x value x = x1 + (x2 - x1) * std::stod(xPos) / 100.0; } else { x = convertXAxisValue(textPlot->_x); } if (textPlot->_y.find("%") != std::string::npos) { // Remove % before conversion int pos = textPlot->_y.find("%"); std::string yPos = textPlot->_y; yPos.erase(pos); // Compute x value as a percent of the x value y = y1 + (y2 - y1) * std::stod(yPos) / 100.0; } else { y = convertYAxisValue(textPlot->_y); } // Select font family, size, style and weight PlPlotUtil::setPlFont(textPlot->getFont()); // Set color Color lInitialColor = changeColor(_pls, textPlot->_color, _panel->_page->_mode); // Compute dx & dy orientation double dx = cos(textPlot->_angle * M_PI / 180) * (x2 - x1) / 10.0; double dy = sin(textPlot->_angle * M_PI / 180) * (y2 - y1) / 10.0 * _panelPlotXYRatio; // Draw text _pls->ptex(x, y, dx, dy, textPlot->_align, textPlot->_text.c_str()); // Restore initial color. restoreColor(_pls, lInitialColor, _panel->_page->_mode); textPlot->setDrawn(true); } } /* * @brief Draw interval */ void PanelPlotOutput::drawSerieInterval(SeriesProperties &pSeries, double *xValues, double *yValues, double *timeValues, int nbValues, int intervalIndex) { LOG4CXX_DEBUG(gLogger, "PanelPlotOutput::drawSerieInterval"); IntervalTickProperties itProps = pSeries.getIntervalTickProperties(); // Draw Interval ticks if required ! if (itProps.getMode() == IntervalTickMode::NONE) return; // Get X and Y axis. boost::shared_ptr lXAxis(_panel->getAxis(pSeries.getXAxisId())); boost::shared_ptr lYAxis(_panel->getAxis(pSeries.getYAxisId())); Range lXRange = getXAxisRange(pSeries, lXAxis); Range lYRange = getYAxisRange(pSeries, lYAxis); PlWindow lPlWindow = PlWindow(lXRange.getMin(), lXRange.getMax(), lYRange.getMin(), lYRange.getMax()); // prepare data for plot double xData[2] = {NAN, NAN}; double yData[2] = {NAN, NAN}; double timeData[2] = {NAN, NAN}; // skip NAN values for (int i = 0; i < nbValues; ++i) if (!isNAN(xValues[i]) && !isNAN(yValues[i])) { xData[0] = xValues[i]; yData[0] = yValues[i]; timeData[0] = timeValues[i]; break; } for (int i = nbValues - 1; i >= 0; --i) if (!isNAN(xValues[i]) && !isNAN(yValues[i])) { xData[1] = xValues[i]; yData[1] = yValues[i]; timeData[1] = timeValues[i]; break; } // draw symbols drawSymbols( itProps.getSymbol().getType(), itProps.getSymbol().getSize(), 1., itProps.getSymbol().getColor(), 2, (double *)&xData, (double *)&yData, NULL); if (itProps.getMode() == IntervalTickMode::SYMBOL_ONLY) return; // Add start interval info to a list of TextPlot TextPlots textPlots; TextPlot baseTextPlot; baseTextPlot._color = itProps.getColor(); baseTextPlot.setFont(itProps.getFont()); boost::shared_ptr startTextPlot(new TextPlot(baseTextPlot)); double xPos = (xData[0] - lXRange.getMin()) / (lXRange.getMax() - lXRange.getMin()) * 100; startTextPlot->_x = boost::lexical_cast(xPos); startTextPlot->_x += "%"; double yPos = (yData[0] - lYRange.getMin()) / (lYRange.getMax() - lYRange.getMin()) * 100 + 1.5; startTextPlot->_y = boost::lexical_cast(yPos); startTextPlot->_y += "%"; if (itProps.getMode() == IntervalTickMode::INTERVAL_INDEX) { startTextPlot->_text = "I"; startTextPlot->_text += std::to_string(intervalIndex); } else startTextPlot->_text = AMDA::TimeUtil::formatTimeDateInIso(timeData[0]); textPlots.push_back(startTextPlot); if (itProps.getMode() != IntervalTickMode::START_TIME) { boost::shared_ptr stopTextPlot(new TextPlot(baseTextPlot)); xPos = (xData[1] - lXRange.getMin()) / (lXRange.getMax() - lXRange.getMin()) * 100; stopTextPlot->_x = boost::lexical_cast(xPos); stopTextPlot->_x += "%"; yPos = (yData[1] - lYRange.getMin()) / (lYRange.getMax() - lYRange.getMin()) * 100 + 1.5; stopTextPlot->_y = boost::lexical_cast(yPos); stopTextPlot->_y += "%"; if (itProps.getMode() == IntervalTickMode::INTERVAL_INDEX) stopTextPlot->_text = startTextPlot->_text; else stopTextPlot->_text = AMDA::TimeUtil::formatTimeDateInIso(timeData[1]); textPlots.push_back(stopTextPlot); } drawTextPlots(lXAxis, lYAxis, lPlWindow, textPlots); } /** * @brief Draw parameters legend. */ void PanelPlotOutput::drawParamsLegend(void) { ParamsLegendProperties &legendProp = _panel->_paramsLegendProperties; if (!legendProp.isVisible() || legendProp.isDrawn()) return; std::list lines = legendProp.getLegendLines(); if (lines.empty()) return; // init arguments to call pllegend function PLINT nbLines = lines.size(); PLINT opt_array[nbLines]; PLINT text_colors[nbLines]; PLINT line_colors[nbLines]; PLINT line_styles[nbLines]; PLFLT line_widths[nbLines]; PLINT symbol_numbers[nbLines]; PLINT symbol_colors[nbLines]; PLFLT symbol_scales[nbLines]; const char *symbols[nbLines]; const char *texts[nbLines]; int index = 0; std::string symbol_str[nbLines]; for (auto line : lines) { opt_array[index] = 0; // set line options if (!legendProp.isOnlyText() && line.isLineVisible()) { opt_array[index] |= PL_LEGEND_LINE; line_colors[index] = legendProp.getColorIndex(_pls.get(), line.getLineProperties().getColor()); line_styles[index] = static_cast(getPlLineStyle(line.getLineProperties().getStyle())); line_widths[index] = line.getLineProperties().getWidth(); } // set symbols options if (!legendProp.isOnlyText() && line.isSymbolsVisible()) { opt_array[index] |= PL_LEGEND_SYMBOL; symbol_numbers[index] = LEGEND_NB_SYMBOLS_TO_DRAW; symbol_colors[index] = legendProp.getColorIndex(_pls.get(), line.getSymbolProperties().getColor()); symbol_scales[index] = (double)line.getSymbolProperties().getSize() / PlPlotUtil::DEFAULT_CHARACTER_SIZE; std::stringstream workingstr; workingstr << "#(" << fontTypeToSymSymbol[line.getSymbolProperties().getType()] << ")"; symbol_str[index] = workingstr.str(); symbols[index] = symbol_str[index].c_str(); } text_colors[index] = legendProp.getColorIndex(_pls.get(), line.getTextColor(legendProp.isOnlyText())); texts[index] = line.getText(); ++index; } PLFLT legend_width, legend_height; PLINT opt = PL_LEGEND_BACKGROUND; // show or hide bounding box if (legendProp.isBorderVisible()) opt |= PL_LEGEND_BOUNDING_BOX; PLINT position = PL_POSITION_VIEWPORT; switch (legendProp.getPosition()) { case ParamsLegendPosition::POS_INSIDE: position |= PL_POSITION_INSIDE | PL_POSITION_TOP | PL_POSITION_RIGHT; break; case ParamsLegendPosition::POS_OUTSIDE: position |= PL_POSITION_OUTSIDE | PL_POSITION_RIGHT; break; default: LOG4CXX_WARN(gLogger, "Legend position not implemented => set to POS_INSIDE"); position |= PL_POSITION_INSIDE | PL_POSITION_TOP | PL_POSITION_RIGHT; } // define offset PLFLT x_offset = 0.0; PLFLT y_offset = 0.0; switch (legendProp.getPosition()) { case ParamsLegendPosition::POS_INSIDE: x_offset = LEGEND_INSIDE_OFFSET; y_offset = LEGEND_INSIDE_OFFSET * _panelPlotXYRatio; break; case ParamsLegendPosition::POS_OUTSIDE: x_offset = LEGEND_OUTSIDE_OFFSET; y_offset = 0.0; break; default: x_offset = LEGEND_INSIDE_OFFSET; y_offset = LEGEND_INSIDE_OFFSET * _panelPlotXYRatio; } // show or hide line and symbols PLFLT plot_width = 0; if (!legendProp.isOnlyText()) plot_width = LEGEND_LINE_SYM_WIDTH; // background color = panel color PLINT bg_color = legendProp.getColorIndex(_pls.get(), _panel->_backgroundColor); // bounding box PLINT bb_color = legendProp.getColorIndex(_pls.get(), legendProp.getBorderColor()); PLINT bb_style = 1; // text option PLFLT text_offset = 0.0; if (!legendProp.isOnlyText()) text_offset = LEGEND_TEXT_OFFSET; PLFLT text_scale = PlPlotUtil::getPlFontScaleFactor(legendProp.getFont()); PLFLT text_spacing = LEGEND_TEXT_SPACING; PLFLT text_justification = LEGEND_TEXT_JUSTIFICATION; // colored boxes not used PLINT *box_colors = NULL; PLINT *box_patterns = NULL; PLFLT *box_scales = NULL; PLFLT *box_line_widths = NULL; // save color Color fakeColor; Color initialColor = changeColor(_pls, fakeColor, _panel->_page->_mode); // set viewport _pls->vpor(_plotAreaBounds._x, _plotAreaBounds._x + _plotAreaBounds._width + legendProp.getLeftOffset(), _plotAreaBounds._y, _plotAreaBounds._y + _plotAreaBounds._height); // set font PlPlotUtil::setPlFont(legendProp.getFont()); // init cmap0 to draw legend std::vector colors = legendProp.getColorsMap(); _pls->scmap0n(colors.size()); index = 0; for (auto color : colors) { _pls->scol0(index, color._red, color._green, color._blue); ++index; } // draw tthe legend _pls->legend( &legend_width, &legend_height, opt, position, x_offset, y_offset, plot_width, bg_color, bb_color, bb_style, 0, /* nrow */ 0, /* ncolumn */ nbLines, opt_array, text_offset, text_scale, text_spacing, text_justification, text_colors, (const char **)texts, box_colors, box_patterns, box_scales, box_line_widths, line_colors, line_styles, line_widths, symbol_colors, symbol_scales, symbol_numbers, (const char **)symbols); // Restore initial color. restoreColor(_pls, initialColor, _panel->_page->_mode); legendProp.setDrawn(true); } /** * @brief Draw text legends. */ void PanelPlotOutput::drawTextLegends(void) { double xmin = _plotAreaBounds._x; double xmax = _plotAreaBounds._x + _plotAreaBounds._width; double ymin = _plotAreaBounds._y; double ymax = _plotAreaBounds._y + _plotAreaBounds._height; /*bool leftTextLegendFound = false; bool rightTextLegendFound = false; bool topTextLegendFound = false; bool bottomTextLegendFound = false;*/ for (auto textLegend : _panel->_textLegendPropertiesList) { if (textLegend->isDrawn()) continue; // Set color Color initialColor = changeColor(_pls, textLegend->getColor(), _panel->_page->_mode); // set font PlPlotUtil::setPlFont(textLegend->getFont()); // If legend at a given position not already drawn : //- Set viewport depending on legend position // - Retrieve text lines from text legend and draw them // - See calculatePlotArea to know how text legend position are calculated std::vector textLines = textLegend->getTextLines(); double disp = 1; switch (textLegend->getPosition()) { case TextLegendPosition::POS_LEFT: // if (leftTextLegendFound == false) { _pls->vpor(xmin - textLegend->getOffset(), xmax, ymin, ymax); for (int i = 0; i < (int)textLines.size(); i++) { _pls->mtex("l", disp, 0.5, 0.5, textLines.at(textLines.size() - 1 - i).c_str()); disp += 1.5; } // leftTextLegendFound = true; // } break; case TextLegendPosition::POS_RIGHT: // if (rightTextLegendFound == false) { _pls->vpor(xmin, xmax + textLegend->getOffset(), ymin, ymax); for (int i = 0; i < (int)textLines.size(); i++) { _pls->mtex("r", disp, 0.5, 0.5, textLines.at(i).c_str()); disp += 1.5; } // rightTextLegendFound = true; // } break; case TextLegendPosition::POS_TOP: // if (topTextLegendFound == false) { _pls->vpor(xmin, xmax, ymin, ymax + textLegend->getOffset()); for (int i = 0; i < (int)textLines.size(); i++) { _pls->mtex("t", disp, 0.5, 0.5, textLines.at(textLines.size() - 1 - i).c_str()); disp += 1.5; } // topTextLegendFound = true; // } break; case TextLegendPosition::POS_BOTTOM: // if (bottomTextLegendFound == false) { _pls->vpor(xmin, xmax, ymin - textLegend->getOffset(), ymax); for (int i = 0; i < (int)textLines.size(); i++) { _pls->mtex("b", disp, 0.5, 0.5, textLines.at(i).c_str()); disp += 1.5; } // bottomTextLegendFound = true; // } break; default: break; } restoreColor(_pls, initialColor, _panel->_page->_mode); textLegend->setDrawn(true); } } /** * Draws Curve */ void PanelPlotOutput::drawCurvePlot(CurvePlot & /*curvePlot*/) { // Nothing to do - Deleguate to subclasses } /** * @brief Write plot context */ void PanelPlotOutput::writeContext(ContextFileWriter &writer, AMDA::Parameters::TimeIntervalList::iterator currentTimeInterval) { if (!isStandalone()) return; writer.startElement("panel"); _panel->writeContext(_pls, writer); writer.startElement("parameters"); for (ParameterAxesList::iterator it = _parameterAxesList.begin(); it != _parameterAxesList.end(); ++it) { AMDA::Parameters::ParameterSPtr originalParam = _parameterManager.getParameter(it->_originalParamId); double resol = originalParam->getDataWriterTemplate()->getMinSampling(); std::string resolstr = std::to_string(resol); writer.startElement("parameter"); writer.addAttribute("id", originalParam->getId().c_str()); writer.addAttribute("MinSampling", resolstr.c_str()); writer.endElement(); } writer.endElement(); if (!_parameterAxesList.empty()) { bool hasSpectro = false; bool hasSauvaud = false; for (auto parameter : _parameterAxesList) { if (parameter.getSpectroProperties() != nullptr) { hasSpectro = true; break; } if (parameter.getSauvaudProperties() != nullptr) { hasSauvaud = true; break; } if (parameter.getIntervalsProperties() != nullptr) { ParameterSPtr p = _parameterManager.getParameter(parameter._originalParamId); AMDA::Info::ParamInfoSPtr paramInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(p->getInfoId()); std::map inputAdditionals = paramInfo->getAdditionInfo(); std::string ttOrCatPath = inputAdditionals["TTCatToParamPath"]; // Load TT or Catalog std::string lReaderType = TimeTableCatalog::TimeTableCatalogFactory::getInstance().getReaderType(ttOrCatPath); if (!lReaderType.empty()) { TimeTableCatalog::Catalog inputTTOrCat; inputTTOrCat.read(ttOrCatPath, lReaderType); for (std::vector::const_iterator it = inputTTOrCat.getIntervals().begin(); it != inputTTOrCat.getIntervals().end(); ++it) { double acceptedRatio = 0.005; // if the interval is too small, no more info given double timeRatio = (currentTimeInterval->_stopTime - currentTimeInterval->_startTime) / _plotAreaBounds._width; std::map> data; bool needTTWriter = false; bool needCatWriter = false; double startTime = it->_startTime; double stopTime = it->_stopTime; if (it->_startTime >= currentTimeInterval->_startTime && it->_stopTime <= currentTimeInterval->_stopTime) // inside the interval { if (timeRatio * acceptedRatio < (stopTime - startTime) / _plotAreaBounds._width) { needTTWriter = true; data = it->getAllParameterData(); if (data.size() > 0) needCatWriter = true; } } else if (it->_startTime <= currentTimeInterval->_startTime && it->_stopTime <= currentTimeInterval->_stopTime && it->_stopTime >= currentTimeInterval->_startTime) // begins before, ends inside { startTime = currentTimeInterval->_startTime; if (timeRatio * acceptedRatio < (stopTime - startTime) / _plotAreaBounds._width) { needTTWriter = true; data = it->getAllParameterData(); if (data.size() > 0) needCatWriter = true; } } else if (it->_startTime >= currentTimeInterval->_startTime && it->_startTime <= currentTimeInterval->_stopTime && it->_stopTime >= currentTimeInterval->_stopTime) // begins inside, ends after { stopTime = currentTimeInterval->_stopTime; if (timeRatio * acceptedRatio < (stopTime - startTime) / _plotAreaBounds._width) { needTTWriter = true; data = it->getAllParameterData(); if (data.size() > 0) needCatWriter = true; } } if (needTTWriter) { writer.startElement("intervals"); writer.addAttribute("name", inputTTOrCat._name.c_str()); writer.addAttribute("id", std::to_string(it->_index).c_str()); writer.addAttribute("startTime", std::to_string(startTime).c_str()); writer.addAttribute("stopTime", std::to_string(stopTime).c_str()); if (needCatWriter) { std::string allParams; for (auto i : data) { allParams += i.second[0] + "|"; } writer.addAttribute("params", allParams.c_str()); } writer.endElement(); } } } } } writer.startElement("plotArea"); if (_panel->_page->_orientation == PlotCommon::Orientation::PORTRAIT) { writer.addAttribute("x", std::to_string(_plotAreaBounds._y * std::get<0>(_panel->_page->getSize())).c_str()); writer.addAttribute("y", std::to_string(_plotAreaBounds._x * std::get<1>(_panel->_page->getSize())).c_str()); writer.addAttribute("width", std::to_string(_plotAreaBounds._height * std::get<0>(_panel->_page->getSize())).c_str()); writer.addAttribute("height", std::to_string(_plotAreaBounds._width * std::get<1>(_panel->_page->getSize())).c_str()); } else { writer.addAttribute("x", std::to_string(_plotAreaBounds._x * std::get<0>(_panel->_page->getSize())).c_str()); writer.addAttribute("y", std::to_string(_plotAreaBounds._y * std::get<1>(_panel->_page->getSize())).c_str()); writer.addAttribute("width", std::to_string(_plotAreaBounds._width * std::get<0>(_panel->_page->getSize())).c_str()); writer.addAttribute("height", std::to_string(_plotAreaBounds._height * std::get<1>(_panel->_page->getSize())).c_str()); } writer.addAttribute("hasSpectro", hasSpectro ? "true" : "false"); writer.addAttribute("hasSauvaud", hasSauvaud ? "true" : "false"); for (Axes::iterator it = _panel->_axes.begin(); it != _panel->_axes.end(); ++it) { boost::shared_ptr lAxis = it->second; if (lAxis == nullptr) continue; if (lAxis->_visible && lAxis->_used) lAxis->writeContext(writer); } writer.endElement(); } writer.endElement(); } /** * @brief Compute the initial plot area for the panel */ void PanelPlotOutput::preparePlotArea(double /*startTime*/, double /*stopTime*/, int /*intervalIndex*/) { Bounds panelBounds = _panel->getBoundsInPlPage(); _plotAreaBounds = panelBounds; calculatePlotArea(panelBounds, _plotAreaBounds); _panel->_paramsLegendProperties.resetPlot(); } void PanelPlotOutput::fillBackground(std::shared_ptr &pls) { if (_panel->_plotAreaBackgroundColor._red != -1 && _panel->_plotAreaBackgroundColor._green != -1 && _panel->_plotAreaBackgroundColor._blue != -1) { Color plotAreaBackgroundColor = _panel->_plotAreaBackgroundColor; PLINT lInitialRed = -1, lInitialGreen = -1, lInitialBlue = -1; // Store initial color in first index. pls->gcol0(0, lInitialRed, lInitialGreen, lInitialBlue); pls->scol0(0, plotAreaBackgroundColor._red, plotAreaBackgroundColor._green, plotAreaBackgroundColor._blue); pls->col0(0); // Compute panel coordinate in the page Bounds lBounds = _plotAreaBounds; // Specify viewport for the panel pls->vpor(_plotAreaBounds._x, _plotAreaBounds._x + _plotAreaBounds._width, _plotAreaBounds._y, _plotAreaBounds._y + _plotAreaBounds._height); // Set window size. pls->wind(0, 1, 0, 1); // Fill background. PLFLT px[] = {0, 0, 1, 1}; PLFLT py[] = {0, 1, 1, 0}; pls->fill(4, px, py); pls->col0(0); if (lInitialRed != -1 && lInitialGreen != -1 && lInitialBlue != -1) { pls->scol0(0, lInitialRed, lInitialGreen, lInitialBlue); } } } /** * @brief Retrieve plot area bounds for the panel */ void PanelPlotOutput::getPlotAreaBounds(Bounds &plotAreaBounds) { plotAreaBounds = _plotAreaBounds; } /** * @brief Force the plot area horizontal position and width */ void PanelPlotOutput::forcePlotAreaPosAndWidth(double plotAreaX, double plotAreaWidth) { _plotAreaBounds._x = plotAreaX; _plotAreaBounds._width = plotAreaWidth; } /** * @brief Retrieve left axis tickMark width */ int PanelPlotOutput::getLeftAxisTickMarkWidth(void) { return _leftAxisTickMarkWidth; } /** * @brief Force left axis tickmark width for the panel */ void PanelPlotOutput::forceLeftAxisTickMarkWidth(int leftAxisTickMarkWidth) { for (Axes::iterator it = _panel->_axes.begin(); it != _panel->_axes.end(); ++it) { boost::shared_ptr lAxis = it->second; if (lAxis == nullptr) continue; // Look for a visible fleft Axis with legend and if ((lAxis->_visible) && (lAxis->_position == PlotCommon::Position::POS_LEFT)) { lAxis->setFixedTickMarkWidth(leftAxisTickMarkWidth); } } } /** * @brief Get nb series to draw by y axis */ std::map &PanelPlotOutput::getNbSeriesByYAxis() { if (!_nbSeriesByYAxisMap.empty()) { return _nbSeriesByYAxisMap; } SeriesProperties lSeries; for (auto parameter : _parameterAxesList) { for (auto lSeries : parameter.getYSeriePropertiesList()) { if (!lSeries.hasYAxis()) continue; std::string yAxisId = lSeries.getYAxisId(); if (_nbSeriesByYAxisMap.find(yAxisId) == _nbSeriesByYAxisMap.end()) _nbSeriesByYAxisMap[yAxisId] = 0; _nbSeriesByYAxisMap[yAxisId] += lSeries.getIndexList(_pParameterValues).size(); } } return _nbSeriesByYAxisMap; } /** * @brief draw the plot for the current time interval */ bool PanelPlotOutput::draw(double startTime, double stopTime, int intervalIndex, bool isFirstInterval, bool isLastInterval) { // Sets panel plplot viewport, draw background & title for the panel _panel->draw(_pls); fillBackground(_pls); bool noData = true; if (_parameterAxesList.empty()) { noData = false; // Do not draw No Data if the panel is empty _panel->drawEmptyPanel(_pls); } if (isFirstInterval) _panel->_paramsLegendProperties.resetPlot(); // Set pointer to ParameterData list if (_pParameterValues == NULL) { std::stringstream lError; lError << "PanelPlotOutput::draw - Pointer to parameterValues is not set"; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } LOG4CXX_DEBUG(gLogger, "Panel bounds = " << _panel->_bounds.toString()); LOG4CXX_DEBUG(gLogger, "Plot area = " << _plotAreaBounds.toString()); // Draw spectro for (auto parameter : _parameterAxesList) { if (parameter.getSpectroProperties() != nullptr) { // draw spectro LOG4CXX_DEBUG(gLogger, "Draw a spectro for parameter " << parameter._originalParamId); // Draw (configure) window for this series. drawSpectro(startTime, stopTime, parameter._originalParamId, *(parameter.getSpectroProperties())); ParameterData &data = (*_pParameterValues)[parameter.getSpectroProperties()->getParamId()]; if (parameter.getSpectroProperties()->getIndexes().empty()) { noData = data.noData(); } else { for (auto index : parameter.getSpectroProperties()->getIndexes()) { if (noData) noData = data.noData(index); } } } if (parameter.getSauvaudProperties() != nullptr) { // draw sauvaud LOG4CXX_DEBUG(gLogger, "Draw a sauvaud for parameter " << parameter._originalParamId); // Draw (configure) window for this series. drawSauvaud(startTime, stopTime, parameter._originalParamId, *(parameter.getSauvaudProperties()), 0, 1, ""); ParameterData &data = (*_pParameterValues)[parameter.getSauvaudProperties()->getParamId()]; if (parameter.getSauvaudProperties()->getIndexes().empty()) { noData = data.noData(); } else { for (auto index : parameter.getSauvaudProperties()->getIndexes()) { if (noData) noData = data.noData(index); } } } } // Draw intervals for (auto parameter : _parameterAxesList) { if (parameter.getIntervalsProperties() != nullptr) { // draw intervals LOG4CXX_DEBUG(gLogger, "Draw intervals for parameter " << parameter._originalParamId); // Draw (configure) window for this series. drawIntervals(startTime, stopTime, parameter._originalParamId, *(parameter.getIntervalsProperties())); ParameterData &data = (*_pParameterValues)[parameter.getIntervalsProperties()->getParamId()]; if (parameter.getIntervalsProperties()->getIndexes().empty()) { noData = data.noData(); } else { for (auto index : parameter.getIntervalsProperties()->getIndexes()) { if (noData) noData = data.noData(index); } } } } // Compute panel XY ratio used for angular conversions computePanelPlotXYRatio(); // Draw fill area between parameter and constant or between parameters drawFills(startTime, stopTime); // Compute nb series to draw by y axis std::map nbSeriesByYAxisMap = getNbSeriesByYAxis(); SeriesProperties lSeries; // Draw series for parameters. for (auto parameter : _parameterAxesList) { // Get series index to draw for parameter // Draw each index of parameter for (auto lSeries : parameter.getYSeriePropertiesList()) { for (auto lIndex : lSeries.getIndexList(_pParameterValues)) { bool moreThanOneSerieForYAxis = false; if (lSeries.hasYAxis()) moreThanOneSerieForYAxis = (nbSeriesByYAxisMap[lSeries.getYAxisId()] > 1); // Draw (configure) window for this series. drawSeries(startTime, stopTime, intervalIndex, parameter._originalParamId, lSeries, lIndex, parameter, moreThanOneSerieForYAxis); ParameterData &data = (*_pParameterValues)[lSeries.getParamId()]; if (noData) { noData = data.noData(lIndex); } } } } // Draw additional objects drawAdditionalObjects(); // Draw parameter legend if (isLastInterval || !_panel->_page->_superposeMode) drawParamsLegend(); // Draw text legends drawTextLegends(); return !noData; } void PanelPlotOutput::drawSauvaud(double /*startDate*/, double /*stopDate*/, std::string /*pParamId*/, SauvaudProperties &pSauvaud, int subIndex = 0, int subsNumber = 1, std::string opositeLegend = "") { // Get X, Y and Z axis. boost::shared_ptr lXAxis(_panel->getAxis(pSauvaud.getXAxisId())); boost::shared_ptr lYAxis(_panel->getAxis(pSauvaud.getYAxisId())); boost::shared_ptr lZAxis(_panel->getAxis(pSauvaud.getZAxisId())); Range lXRange, lYRange, lZRange; if (pSauvaud.hasXAxis() && lXAxis.get() == nullptr) { std::stringstream lError; lError << "PanelPlotOutput::drawSauvaud" << ": X axis with id '" << pSauvaud.getXAxisId() << "' not found."; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } else if (pSauvaud.hasXAxis()) { // fill X range (plplot window). lXRange = lXAxis->getRange(); } if (pSauvaud.hasYAxis() && lYAxis.get() == nullptr) { std::stringstream lError; lError << "PanelPlotOutput::drawSauvaud" << ": Y axis with id '" << pSauvaud.getYAxisId() << "' not found."; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); lYRange = Range(); } else if (pSauvaud.hasYAxis()) { // fill Y range (plplot window). lYRange = lYAxis->getRange(); fixRange(lYRange, lYAxis->_scale == Axis::Scale::LOGARITHMIC); } if (pSauvaud.hasZAxis() && lZAxis.get() == nullptr) { std::stringstream lError; lError << "PanelPlotOutput::drawSauvaud" << ": Z axis with id '" << pSauvaud.getZAxisId() << "' not found."; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); lZRange = Range(); } else if (pSauvaud.hasZAxis()) { // fill Z range (plplot window). lZRange = lZAxis->getRange(); } PlWindow lPlWindow; lPlWindow = PlWindow(lXRange.getMin(), lXRange.getMax(), lYRange.getMin(), lYRange.getMax()); // Calculate X and Y tick TickConf lTickConf; double lXMajorTickSpace = nan(""); int lXMinorTickNumber = 0; double lYMajorTickSpace = nan(""); int lYMinorTickNumber = 0; if (pSauvaud.hasXAxis() && (subIndex == 0)) { // Calculate X tick lXMajorTickSpace = getMajorTickSpace(lXAxis.get(), std::get<0>(lPlWindow), std::get<1>(lPlWindow)); lXMinorTickNumber = getMinorTickNumber(lXAxis.get(), std::get<0>(lPlWindow), std::get<1>(lPlWindow), lXMajorTickSpace); } if (pSauvaud.hasYAxis() && (subIndex == subsNumber - 1)) { // Calculate Y tick lYMajorTickSpace = getMajorTickSpace(lYAxis.get(), std::get<2>(lPlWindow), std::get<3>(lPlWindow)); lYMinorTickNumber = getMinorTickNumber(lYAxis.get(), std::get<2>(lPlWindow), std::get<3>(lPlWindow), lYMajorTickSpace); } lTickConf = TickConf(lXMajorTickSpace, lXMinorTickNumber, lYMajorTickSpace, lYMinorTickNumber); Bounds areaBounds(_plotAreaBounds); double width = _plotAreaBounds._height / (subsNumber + 1); if (subsNumber > 0) { areaBounds._y = _plotAreaBounds._y + subIndex * (width + width / 10); areaBounds._height = width; } // Draw Y axis and legend if (pSauvaud.hasYAxis()) { Label label(lYAxis->_legend.getFont(), lYAxis->_legend.getColor()); Font font_(label.getFont()); int size_ = font_.getSize(); if (font_.getSize() == 0) { size_ = std::round(314.5 * width - 2.7); size_ = std::max(size_, 2); size_ = std::min(size_, 8); font_.setSize(size_); label.setFont(font_); lYAxis->_legend.setLabel(label); } bool changed = false; // Draw legend for the last spectro. if (subIndex == subsNumber - 1) { lYAxis->setShowTickMark(true); PlotCommon::Position pos_ = lYAxis->_position; Label label(lYAxis->_legend.getFont(), lYAxis->_legend.getColor()); Font font_(label.getFont()); std::string text_ = lYAxis->_legend.getText(); if (!opositeLegend.empty()) { label._text = opositeLegend; changed = true; } if (lYAxis->_scale == Axis::Scale::LOGARITHMIC && font_.getSize() > 3) { font_.setSize(3); changed = true; } lYAxis->_legend.clearLabels(); lYAxis->_legend.setLabel(label); switch (pos_) { case PlotCommon::Position::POS_LEFT: lYAxis->_position = PlotCommon::Position::POS_RIGHT; break; case PlotCommon::Position::POS_RIGHT: lYAxis->_position = PlotCommon::Position::POS_LEFT; break; default: break; } drawYAxis(lYAxis, lPlWindow, areaBounds, lTickConf); if (!opositeLegend.empty()) drawLegends(lYAxis, lPlWindow, areaBounds); lYAxis->_position = pos_; if (changed) { font_.setSize(size_); label.setFont(font_); label._text = text_; lYAxis->_legend.clearLabels(); lYAxis->_legend.setLabel(label); changed = false; } drawLegends(lYAxis, lPlWindow, areaBounds); } else { lYAxis->setShowTickMark(false); if (subIndex < subsNumber) drawYAxis(lYAxis, lPlWindow, areaBounds, lTickConf); drawLegends(lYAxis, lPlWindow, areaBounds); } } // Draw Z axis and legend if (pSauvaud.hasZAxis() && (lZAxis != nullptr) && !lZAxis->_drawn) { drawZAxis(lZAxis, lPlWindow, _plotAreaBounds, lTickConf); } // Draw X axis and legend if (pSauvaud.hasXAxis() && subIndex < subsNumber) { drawXAxis(lXAxis, lPlWindow, areaBounds, lTickConf); // Draw legend. if (subIndex == 0) drawLegends(lXAxis, lPlWindow, areaBounds); } } void PanelPlotOutput::drawSpectro(double /*startDate*/, double /*stopDate*/, std::string /*pParamId*/, SpectroProperties &pSpectro) { // Get X, Y and Z axis. boost::shared_ptr lXAxis(_panel->getAxis(pSpectro.getXAxisId())); boost::shared_ptr lYAxis(_panel->getAxis(pSpectro.getYAxisId())); boost::shared_ptr lZAxis(_panel->getAxis(pSpectro.getZAxisId())); PlWindow lPlWindow; Range lXRange, lYRange, lZRange; if (pSpectro.hasXAxis() && lXAxis.get() == nullptr) { std::stringstream lError; lError << "PanelPlotOutput::drawSpectro" << ": X axis with id '" << pSpectro.getXAxisId() << "' not found."; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } else if (pSpectro.hasXAxis()) { // fill X range (plplot window). lXRange = lXAxis->getRange(); } if (pSpectro.hasYAxis() && lYAxis.get() == nullptr) { std::stringstream lError; lError << "PanelPlotOutput::drawSpectro" << ": Y axis with id '" << pSpectro.getYAxisId() << "' not found."; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); lYRange = Range(); } else if (pSpectro.hasYAxis()) { // fill Y range (plplot window). lYRange = lYAxis->getRange(); fixRange(lYRange, lYAxis->_scale == Axis::Scale::LOGARITHMIC); } if (pSpectro.hasZAxis() && lZAxis.get() == nullptr) { std::stringstream lError; lError << "PanelPlotOutput::drawSpectro" << ": Z axis with id '" << pSpectro.getZAxisId() << "' not found."; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); lZRange = Range(); } else if (pSpectro.hasZAxis()) { // fill Z range (plplot window). lZRange = lZAxis->getRange(); } lPlWindow = PlWindow(lXRange.getMin(), lXRange.getMax(), lYRange.getMin(), lYRange.getMax()); // Calculate X and Y tick TickConf lTickConf; double lXMajorTickSpace = nan(""); int lXMinorTickNumber = 0; double lYMajorTickSpace = nan(""); int lYMinorTickNumber = 0; if (pSpectro.hasXAxis()) { // Calculate X tick lXMajorTickSpace = getMajorTickSpace(lXAxis.get(), std::get<0>(lPlWindow), std::get<1>(lPlWindow)); lXMinorTickNumber = getMinorTickNumber(lXAxis.get(), std::get<0>(lPlWindow), std::get<1>(lPlWindow), lXMajorTickSpace); } if (pSpectro.hasYAxis()) { // Calculate Y tick lYMajorTickSpace = getMajorTickSpace(lYAxis.get(), std::get<2>(lPlWindow), std::get<3>(lPlWindow)); lYMinorTickNumber = getMinorTickNumber(lYAxis.get(), std::get<2>(lPlWindow), std::get<3>(lPlWindow), lYMajorTickSpace); } lTickConf = TickConf(lXMajorTickSpace, lXMinorTickNumber, lYMajorTickSpace, lYMinorTickNumber); // Draw Y axis and legend if (pSpectro.hasYAxis() && !lYAxis->_drawn) { drawYAxis(lYAxis, lPlWindow, _plotAreaBounds, lTickConf); // Draw legend. drawLegends(lYAxis, lPlWindow, _plotAreaBounds); } // Draw X axis and legend if (pSpectro.hasXAxis() && !lXAxis->_drawn) { drawXAxis(lXAxis, lPlWindow, _plotAreaBounds, lTickConf); // Draw legend. drawLegends(lXAxis, lPlWindow, _plotAreaBounds); } // Draw Z axis and legend if (pSpectro.hasZAxis() && (lZAxis != nullptr) && !lZAxis->_drawn) { drawZAxis(lZAxis, lPlWindow, _plotAreaBounds, lTickConf); } } void PanelPlotOutput::drawIntervals(double /*startDate*/, double /*stopDate*/, std::string /*pParamId*/, IntervalsProperties &pIntervals) { boost::shared_ptr lXAxis(_panel->getAxis(pIntervals.getXAxisId())); PlWindow lPlWindow; Range lXRange, lYRange; if (lXAxis.get() == nullptr) { std::stringstream lError; lError << "PanelPlotOutput::drawIntervals" << ": X axis with id '" << pIntervals.getXAxisId() << "' not found."; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } lXRange = lXAxis->getRange(); lYRange = Range(0, 1); lPlWindow = PlWindow(lXRange.getMin(), lXRange.getMax(), lYRange.getMin(), lYRange.getMax()); // Calculate X and Y tick TickConf lTickConf; double lXMajorTickSpace = nan(""); int lXMinorTickNumber = 0; double lYMajorTickSpace = nan(""); int lYMinorTickNumber = 0; lXMajorTickSpace = getMajorTickSpace(lXAxis.get(), std::get<0>(lPlWindow), std::get<1>(lPlWindow)); lXMinorTickNumber = getMinorTickNumber(lXAxis.get(), std::get<0>(lPlWindow), std::get<1>(lPlWindow), lXMajorTickSpace); lTickConf = TickConf(lXMajorTickSpace, lXMinorTickNumber, lYMajorTickSpace, lYMinorTickNumber); // Draw X axis and legend if (!lXAxis->_drawn) { drawXAxis(lXAxis, lPlWindow, _plotAreaBounds, lTickConf); // Draw legend. drawLegends(lXAxis, lPlWindow, _plotAreaBounds); } _pls->vpor(_plotAreaBounds._x, _plotAreaBounds._x + _plotAreaBounds._width, _plotAreaBounds._y, _plotAreaBounds._y + _plotAreaBounds._height); } void PanelPlotOutput::drawFills(double /*startDate*/, double /*stopDate*/) { // Nothing done here except setting the viewport, see subclasses for specific implementation _pls->vpor(_plotAreaBounds._x, _plotAreaBounds._x + _plotAreaBounds._width, _plotAreaBounds._y, _plotAreaBounds._y + _plotAreaBounds._height); } void PanelPlotOutput::drawSeries(double /*startDate*/, double /*stopDate*/, int /*intervalIndex*/, std::string /*pParamId*/, SeriesProperties &pSeries, AMDA::Common::ParameterIndexComponent /*pParamIndex*/, ParameterAxes & /*param*/, bool /*moreThanOneSerieForAxis*/) { // Get X, Y and Z axis. boost::shared_ptr lXAxis(_panel->getAxis(pSeries.getXAxisId())); boost::shared_ptr lYAxis(_panel->getAxis(pSeries.getYAxisId())); boost::shared_ptr lZAxis(_panel->getAxis(pSeries.getZAxisId())); Range lXRange = getXAxisRange(pSeries, lXAxis); Range lYRange = getYAxisRange(pSeries, lYAxis); // Range lZRange = getZAxisRange (pSeries, lZAxis); PlWindow lPlWindow = PlWindow(lXRange.getMin(), lXRange.getMax(), lYRange.getMin(), lYRange.getMax()); // Calculate X and Y tick TickConf lTickConf; double lXMajorTickSpace = nan(""); int lXMinorTickNumber = 0; double lYMajorTickSpace = nan(""); int lYMinorTickNumber = 0; if (pSeries.hasXAxis()) { // Calculate X tick lXMajorTickSpace = getMajorTickSpace(lXAxis.get(), std::get<0>(lPlWindow), std::get<1>(lPlWindow)); lXMinorTickNumber = getMinorTickNumber(lXAxis.get(), std::get<0>(lPlWindow), std::get<1>(lPlWindow), lXMajorTickSpace); } if (pSeries.hasYAxis()) { // Calculate Y tick lYMajorTickSpace = getMajorTickSpace(lYAxis.get(), std::get<2>(lPlWindow), std::get<3>(lPlWindow)); lYMinorTickNumber = getMinorTickNumber(lYAxis.get(), std::get<2>(lPlWindow), std::get<3>(lPlWindow), lYMajorTickSpace); } lTickConf = TickConf(lXMajorTickSpace, lXMinorTickNumber, lYMajorTickSpace, lYMinorTickNumber); // Draw Y axis and legend if (pSeries.hasYAxis() && !lYAxis->_drawn) { drawYAxis(lYAxis, lPlWindow, _plotAreaBounds, lTickConf); // Draw legend. drawLegends(lYAxis, lPlWindow, _plotAreaBounds); } // Draw X axis and legend if (pSeries.hasXAxis() && !lXAxis->_drawn) { drawXAxis(lXAxis, lPlWindow, _plotAreaBounds, lTickConf); // Draw legend. drawLegends(lXAxis, lPlWindow, _plotAreaBounds); } // Draw Z axis and legend if (pSeries.hasZAxis() && (lZAxis != nullptr) && !lZAxis->_drawn) { drawZAxis(lZAxis, lPlWindow, _plotAreaBounds, lTickConf); } } void PanelPlotOutput::drawAdditionalObjects() { for (auto parameter : _parameterAxesList) { if (parameter.getSpectroProperties() != nullptr) { boost::shared_ptr lXAxis(_panel->getAxis(parameter.getSpectroProperties()->getXAxisId())); boost::shared_ptr lYAxis(_panel->getAxis(parameter.getSpectroProperties()->getYAxisId())); if ((lXAxis == nullptr) || (lYAxis == nullptr)) continue; Range lXRange = lXAxis->getRange(); Range lYRange = lYAxis->getRange(); PlWindow lPlWindow = PlWindow(lXRange.getMin(), lXRange.getMax(), lYRange.getMin(), lYRange.getMax()); if (!lXAxis->_additionalObjDrawn) drawXConstantLines(lXAxis, lPlWindow); if (!lYAxis->_additionalObjDrawn) drawYConstantLines(lYAxis, lPlWindow); if (!lXAxis->_additionalObjDrawn || !lYAxis->_additionalObjDrawn) drawTextPlots(lXAxis, lYAxis, lPlWindow, _panel->_textPlots); lXAxis->_additionalObjDrawn = true; lYAxis->_additionalObjDrawn = true; } if (parameter.getSauvaudProperties() != nullptr) { boost::shared_ptr lXAxis(_panel->getAxis(parameter.getSauvaudProperties()->getXAxisId())); boost::shared_ptr lYAxis(_panel->getAxis(parameter.getSauvaudProperties()->getYAxisId())); if ((lXAxis == nullptr) || (lYAxis == nullptr)) continue; Range lXRange = lXAxis->getRange(); Range lYRange = lYAxis->getRange(); PlWindow lPlWindow = PlWindow(lXRange.getMin(), lXRange.getMax(), lYRange.getMin(), lYRange.getMax()); if (!lXAxis->_additionalObjDrawn) drawXConstantLines(lXAxis, lPlWindow); if (!lYAxis->_additionalObjDrawn) drawYConstantLines(lYAxis, lPlWindow); if (!lXAxis->_additionalObjDrawn || !lYAxis->_additionalObjDrawn) drawTextPlots(lXAxis, lYAxis, lPlWindow, _panel->_textPlots); lXAxis->_additionalObjDrawn = true; lYAxis->_additionalObjDrawn = true; } } SeriesProperties lSeries; for (auto parameter : _parameterAxesList) { for (auto lSeries : parameter.getYSeriePropertiesList()) { boost::shared_ptr lXAxis(_panel->getAxis(lSeries.getXAxisId())); boost::shared_ptr lYAxis(_panel->getAxis(lSeries.getYAxisId())); if ((lXAxis == nullptr) || (lYAxis == nullptr)) continue; Range lXRange = lXAxis->getRange(); Range lYRange = lYAxis->getRange(); PlWindow lPlWindow = PlWindow(lXRange.getMin(), lXRange.getMax(), lYRange.getMin(), lYRange.getMax()); if (!lXAxis->_additionalObjDrawn) drawXConstantLines(lXAxis, lPlWindow); if (!lYAxis->_additionalObjDrawn) drawYConstantLines(lYAxis, lPlWindow); if (!lXAxis->_additionalObjDrawn || !lYAxis->_additionalObjDrawn) drawTextPlots(lXAxis, lYAxis, lPlWindow, _panel->_textPlots); lXAxis->_additionalObjDrawn = true; lYAxis->_additionalObjDrawn = true; } } // Draw curvePlots for (auto curvePlot : _panel->_curvePlots) drawCurvePlot(*curvePlot); } void PanelPlotOutput::setPlStream(std::shared_ptr &pls) { _pls = pls; } std::string PanelPlotOutput::drawOppositeSide(boost::shared_ptr pAxis) { boost::shared_ptr lNewAxis; std::string lOppositeSide; switch (pAxis->_position) { case PlotCommon::Position::POS_BOTTOM: if (pAxis->_visible && !_plotAreaSideSet[PlotCommon::Position::POS_TOP]) { lOppositeSide = "c"; } break; case PlotCommon::Position::POS_TOP: if (pAxis->_visible && !_plotAreaSideSet[PlotCommon::Position::POS_BOTTOM]) { lOppositeSide = "b"; } break; case PlotCommon::Position::POS_LEFT: if (pAxis->_visible && !_plotAreaSideSet[PlotCommon::Position::POS_RIGHT]) { lOppositeSide = "c"; } break; case PlotCommon::Position::POS_RIGHT: if (pAxis->_visible && !_plotAreaSideSet[PlotCommon::Position::POS_LEFT]) { lOppositeSide = "b"; } break; case PlotCommon::Position::POS_CENTER: default: lOppositeSide = ""; } return lOppositeSide; } /* * Create a sampled parameter from an original parameter and a sampling value */ AMDA::Parameters::ParameterSPtr PanelPlotOutput::createSampledParameter(AMDA::Parameters::ParameterSPtr &originalParam, float samplingValue) { AMDA::Parameters::ParameterSPtr sampledParam = _parameterManager.getSampledParameter( originalParam->getId(), "classic", samplingValue, originalParam->getGapThreshold(), true); if (sampledParam == NULL) { LOG4CXX_ERROR(gLogger, "ParamOutput::createSampledParameter : cannot create sampled parameter"); BOOST_THROW_EXCEPTION( AMDA::Parameters::ParamOutput_exception()); } LOG4CXX_INFO(gLogger, "ParamOutput::createSampledParameter : sampled parameter : " << sampledParam->getId() << " created"); return sampledParam; } /* * Create a sampled parameter from an original parameter and a reference parameter for time definition */ AMDA::Parameters::ParameterSPtr PanelPlotOutput::createSampledParameterUnderReferenceParameter(AMDA::Parameters::ParameterSPtr &originalParam, AMDA::Parameters::ParameterSPtr &refParam) { /*if (originalParam == refParam) { return originalParam; }*/ AMDA::Parameters::ParameterSPtr sampledParam = _parameterManager.getSampledParameterUnderRefParam( originalParam->getId(), refParam->getId(), true); if (sampledParam == NULL) { LOG4CXX_ERROR(gLogger, "ParamOutput::createSampledParameterUnderReferenceParameter : cannot create sampled parameter"); BOOST_THROW_EXCEPTION( AMDA::Parameters::ParamOutput_exception()); } LOG4CXX_INFO(gLogger, "ParamOutput::createSampledParameterUnderReferenceParameter : sampled parameter : " << sampledParam->getId() << " created"); return sampledParam; } ParameterAxes *PanelPlotOutput::getParameterAxesByColorSerieId(int colorSerieId) { if (colorSerieId < 0) return NULL; for (ParameterAxesList::iterator it = _parameterAxesList.begin(); it != _parameterAxesList.end(); ++it) { for (auto serieProp : it->getColorSeriePropertiesList()) { if (serieProp.getId() == colorSerieId) return &(*it); } } LOG4CXX_ERROR(gLogger, "ParamOutput::getColorSeriePropertiesById : Not founded : " << colorSerieId); return NULL; } ParameterAxes *PanelPlotOutput::getParameterAxesByXSerieId(int xSerieId) { for (ParameterAxesList::iterator it = _parameterAxesList.begin(); it != _parameterAxesList.end(); ++it) { for (auto serieProp : it->getXSeriePropertiesList()) { if (serieProp.getId() == xSerieId) return &(*it); } } LOG4CXX_ERROR(gLogger, "ParamOutput::getXSeriePropertiesById : Not founded : " << xSerieId); return NULL; } /** * Create parameters needed for this plot. * By default, the creation method create parameters for a time serie. * Override it for other plot type */ void PanelPlotOutput::createParameters(std::list &usedParametersId_) { // -- for each y serie on each parameter, calculate // y serie sampling according to max resolution for (ParameterAxesList::iterator it = _parameterAxesList.begin(); it != _parameterAxesList.end(); ++it) { AMDA::Parameters::ParameterSPtr originalParam = _parameterManager.getParameter(it->_originalParamId); // original parameter sampling double samplingValue = getSamplingInTreeParameter(originalParam); // For each series std::vector::iterator ity; for (ity = it->getYSeriePropertiesList().begin(); ity != it->getYSeriePropertiesList().end(); ++ity) { ParameterAxes *colorSerieParameterAxes = getParameterAxesByColorSerieId(ity->getColorSerieId()); AMDA::Parameters::ParameterSPtr originalColorParam; if (colorSerieParameterAxes != NULL) originalColorParam = _parameterManager.getParameter(colorSerieParameterAxes->_originalParamId); // get corrected sampling value in relation with max resolution double correctedSamplingValue = getCorrectedSamplingValue(ity->getMaxResolution(), samplingValue); AMDA::Parameters::ParameterSPtr usedParam; // create parameter and link to the serie switch (ity->getResamplingProperties().getType()) { case ResamplingType::MANUAL: { // create resampling parameters for param usedParam = createSampledParameter(originalParam, ity->getResamplingProperties().getValue()); break; } case ResamplingType::AUTO: case ResamplingType::YPARAM: case ResamplingType::XPARAM: if (abs(samplingValue - correctedSamplingValue) > 1.) { // more than one second between samplingValue and correctedSamplingValue //=> use resampling parameter usedParam = createSampledParameter(originalParam, correctedSamplingValue); } else { // use original parameter usedParam = originalParam; } break; } // Add used parameter to parameters list if (std::find(usedParametersId_.begin(), usedParametersId_.end(), usedParam->getId()) == usedParametersId_.end()) usedParametersId_.push_back(usedParam->getId()); // link this paramter to the serie ity->setParamId(usedParam->getId()); ErrorBarProperties &errorBarProp = ity->getErrorBarProperties(); // Compute min / max re-sampled parameters if min/max error bar are defined for the serie if (errorBarProp.getErrorMinMax() != nullptr) { std::stringstream usedParamIndex; if (ity->getIndex().getDim1Index() != -1) { usedParamIndex << "[" << std::to_string(ity->getIndex().getDim1Index()); if (ity->getIndex().getDim2Index() != -1) usedParamIndex << "," << std::to_string(ity->getIndex().getDim2Index()); usedParamIndex << "]"; } std::stringstream minParamIndex; if (errorBarProp.getErrorMinMax()->getIndexMin().getDim1Index() != -1) { minParamIndex << "[" << std::to_string(errorBarProp.getErrorMinMax()->getIndexMin().getDim1Index()); if (errorBarProp.getErrorMinMax()->getIndexMin().getDim2Index() != -1) minParamIndex << "," << std::to_string(errorBarProp.getErrorMinMax()->getIndexMin().getDim2Index()); minParamIndex << "]"; } std::stringstream maxParamIndex; if (errorBarProp.getErrorMinMax()->getIndexMax().getDim1Index() != -1) { maxParamIndex << "[" << std::to_string(errorBarProp.getErrorMinMax()->getIndexMax().getDim1Index()); if (errorBarProp.getErrorMinMax()->getIndexMax().getDim2Index() != -1) maxParamIndex << "," << std::to_string(errorBarProp.getErrorMinMax()->getIndexMax().getDim2Index()); maxParamIndex << "]"; } // Build expression for computed parameter = usedParam - minParam AMDA::Parameters::ParameterSPtr originalMinParam = _parameterManager.getParameter(errorBarProp.getErrorMinMax()->getOriginalParamMin()); AMDA::Parameters::ParameterSPtr minParam = createSampledParameterUnderReferenceParameter(originalMinParam, usedParam); std::stringstream minExpr; minExpr << "$" << usedParam->getId() << usedParamIndex.str() << "-$" + minParam->getId() << minParamIndex.str(); // create parameter from expression AMDA::Parameters::ParameterSPtr usedMinParam = _parameterManager.getParameterFromExpression(minExpr.str(), originalParam->getGapThreshold(), true); if (usedMinParam == nullptr) { LOG4CXX_ERROR(gLogger, "PanelPlotOutput::createParameters - Cannot create parameter from expression " << minExpr.str()); continue; } if (std::find(usedParametersId_.begin(), usedParametersId_.end(), usedMinParam->getId()) == usedParametersId_.end()) usedParametersId_.push_back(usedMinParam->getId()); errorBarProp.getErrorMinMax()->setUsedParamMin(usedMinParam->getId()); // Build expression for computed parameter = usedParam + maxParam AMDA::Parameters::ParameterSPtr originalMaxParam = _parameterManager.getParameter(errorBarProp.getErrorMinMax()->getOriginalParamMax()); AMDA::Parameters::ParameterSPtr maxParam = createSampledParameterUnderReferenceParameter(originalMaxParam, usedParam); std::stringstream maxExpr; maxExpr << "$" << usedParam->getId() << usedParamIndex.str() << "+$" + maxParam->getId() << maxParamIndex.str(); // create parameter from expression AMDA::Parameters::ParameterSPtr usedMaxParam = _parameterManager.getParameterFromExpression(maxExpr.str(), originalParam->getGapThreshold(), true); if (usedMaxParam == nullptr) { LOG4CXX_ERROR(gLogger, "PanelPlotOutput::createParameters - Cannot create parameter from expression " << maxExpr.str()); continue; } if (std::find(usedParametersId_.begin(), usedParametersId_.end(), usedMaxParam->getId()) == usedParametersId_.end()) usedParametersId_.push_back(usedMaxParam->getId()); errorBarProp.getErrorMinMax()->setUsedParamMax(usedMaxParam->getId()); } if (originalColorParam != nullptr) { AMDA::Parameters::ParameterSPtr usedColorParam = createSampledParameterUnderReferenceParameter(originalColorParam, usedParam); // Add used color parameter to parameters list if (std::find(usedParametersId_.begin(), usedParametersId_.end(), usedColorParam->getId()) == usedParametersId_.end()) usedParametersId_.push_back(usedColorParam->getId()); // link this color parameter to the y serie ity->setColorParamId(usedColorParam->getId()); // link the used parameter to the color serie colorSerieParameterAxes->getColorSeriePropertiesById(ity->getColorSerieId()).addParamId(usedParam->getId(), usedColorParam->getId()); // activate the Z Axis ity->setZAxis(true); } } // For spectro if defined std::shared_ptr pSpecProp = it->getSpectroProperties(); if (pSpecProp != nullptr) { AMDA::Info::ParamInfoSPtr paramInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(originalParam->getInfoId()); boost::shared_ptr tableSPtr; if (paramInfo != nullptr) tableSPtr = paramInfo->getTable(pSpecProp->getRelatedDim()); // get corrected sampling value in relation with max resolution double correctedSamplingValue = getCorrectedSamplingValue(pSpecProp->getMaxResolution(), samplingValue); AMDA::Parameters::ParameterSPtr usedParam; if (abs(samplingValue - correctedSamplingValue) > 1.) { // more than one second between samplingValue and correctedSamplingValue //=> use resampling parameter usedParam = createSampledParameter(originalParam, correctedSamplingValue); if ((tableSPtr != nullptr) && tableSPtr->isVariable(&_parameterManager)) { for (std::map::iterator it = tableSPtr->getTableParams(&_parameterManager).begin(); it != tableSPtr->getTableParams(&_parameterManager).end(); ++it) { std::string tableParamKey = it->first; std::string tableParamName = it->second; AMDA::Parameters::ParameterSPtr originalTableParam = _parameterManager.getParameter(tableParamName); AMDA::Parameters::ParameterSPtr usedTableParam = createSampledParameter(originalTableParam, correctedSamplingValue); pSpecProp->addTableParam(tableParamKey, usedTableParam->getId()); } } } else { // use original parameter usedParam = originalParam; if ((tableSPtr != nullptr) && tableSPtr->isVariable(&_parameterManager)) { for (std::map::iterator it = tableSPtr->getTableParams(&_parameterManager).begin(); it != tableSPtr->getTableParams(&_parameterManager).end(); ++it) { std::string tableParamKey = it->first; std::string tableParamName = it->second; AMDA::Parameters::ParameterSPtr originalTableParam = _parameterManager.getParameter(tableParamName); pSpecProp->addTableParam(tableParamKey, originalTableParam->getId()); } } } // Add used parameter to parameters list if (std::find(usedParametersId_.begin(), usedParametersId_.end(), usedParam->getId()) == usedParametersId_.end()) usedParametersId_.push_back(usedParam->getId()); pSpecProp->setParamId(usedParam->getId()); // Add table parameters to parameters list for (std::map::iterator it = pSpecProp->getTableParams().begin(); it != pSpecProp->getTableParams().end(); ++it) { std::string tableParamId = it->second; if (std::find(usedParametersId_.begin(), usedParametersId_.end(), tableParamId) == usedParametersId_.end()) usedParametersId_.push_back(tableParamId); } } // For sauvaud if defined std::shared_ptr pSauvaudProp = it->getSauvaudProperties(); if (pSauvaudProp != nullptr) { AMDA::Info::ParamInfoSPtr paramInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(originalParam->getInfoId()); boost::shared_ptr tableSPtr; if (paramInfo != nullptr) tableSPtr = paramInfo->getTable(pSauvaudProp->getRelatedDim()); // get corrected sampling value in relation with max resolution double correctedSamplingValue = getCorrectedSamplingValue(pSauvaudProp->getMaxResolution(), samplingValue); AMDA::Parameters::ParameterSPtr usedParam; if (abs(samplingValue - correctedSamplingValue) > 1.) { // more than one second between samplingValue and correctedSamplingValue //=> use resampling parameter usedParam = createSampledParameter(originalParam, correctedSamplingValue); if ((tableSPtr != nullptr) && tableSPtr->isVariable(&_parameterManager)) { for (std::map::iterator it = tableSPtr->getTableParams(&_parameterManager).begin(); it != tableSPtr->getTableParams(&_parameterManager).end(); ++it) { std::string tableParamKey = it->first; std::string tableParamName = it->second; AMDA::Parameters::ParameterSPtr originalTableParam = _parameterManager.getParameter(tableParamName); AMDA::Parameters::ParameterSPtr usedTableParam = createSampledParameter(originalTableParam, correctedSamplingValue); pSauvaudProp->addTableParam(tableParamKey, usedTableParam->getId()); } } } else { // use original parameter usedParam = originalParam; if ((tableSPtr != nullptr) && tableSPtr->isVariable(&_parameterManager)) { for (std::map::iterator it = tableSPtr->getTableParams(&_parameterManager).begin(); it != tableSPtr->getTableParams(&_parameterManager).end(); ++it) { std::string tableParamKey = it->first; std::string tableParamName = it->second; AMDA::Parameters::ParameterSPtr originalTableParam = _parameterManager.getParameter(tableParamName); pSauvaudProp->addTableParam(tableParamKey, originalTableParam->getId()); } } } // Add used parameter to parameters list if (std::find(usedParametersId_.begin(), usedParametersId_.end(), usedParam->getId()) == usedParametersId_.end()) usedParametersId_.push_back(usedParam->getId()); pSauvaudProp->setParamId(usedParam->getId()); // Add table parameters to parameters list for (std::map::iterator it = pSauvaudProp->getTableParams().begin(); it != pSauvaudProp->getTableParams().end(); ++it) { std::string tableParamId = it->second; if (std::find(usedParametersId_.begin(), usedParametersId_.end(), tableParamId) == usedParametersId_.end()) usedParametersId_.push_back(tableParamId); } } // For intervals if defined std::shared_ptr pIntProp = it->getIntervalsProperties(); if (pIntProp != nullptr) { // get corrected sampling value in relation with max resolution double correctedSamplingValue = getCorrectedSamplingValue(pIntProp->getMaxResolution(), samplingValue); AMDA::Parameters::ParameterSPtr usedParam; if (abs(samplingValue - correctedSamplingValue) > 1.) { // more than one second between samplingValue and correctedSamplingValue //=> use resampling parameter usedParam = createSampledParameter(originalParam, correctedSamplingValue); } else { // use original parameter usedParam = originalParam; } // Add used parameter to parameters list if (std::find(usedParametersId_.begin(), usedParametersId_.end(), usedParam->getId()) == usedParametersId_.end()) usedParametersId_.push_back(usedParam->getId()); pIntProp->setParamId(usedParam->getId()); } } } /** * Gets sampling value from resolution (point-per-plot) according to * the plot time interval and the base parameter sampling value. */ double PanelPlotOutput::getCorrectedSamplingValue(int maxResolution, double samplingValue) { double timeInt = 0.; if (_panel->_page->_superposeMode) { // merge all intervals size TimeIntervalList::iterator crtTimeInterval = _parameterManager.getInputIntervals()->begin(); while (crtTimeInterval != _parameterManager.getInputIntervals()->end()) { timeInt += (crtTimeInterval->_stopTime - crtTimeInterval->_startTime); ++crtTimeInterval; } } else { // find the biggest intervals size TimeIntervalList::iterator crtTimeInterval = _parameterManager.getInputIntervals()->begin(); while (crtTimeInterval != _parameterManager.getInputIntervals()->end()) { if ((crtTimeInterval->_stopTime - crtTimeInterval->_startTime) > timeInt) timeInt = crtTimeInterval->_stopTime - crtTimeInterval->_startTime; ++crtTimeInterval; } } if ((timeInt == 0) || (maxResolution == -1) || (timeInt / samplingValue < maxResolution)) { return samplingValue; } // get the exact sampling double correctedSampling = timeInt / maxResolution; // rounded it to the next int sampling double roundedSampling = (int)correctedSampling; if (roundedSampling < correctedSampling) { roundedSampling += 1; } return roundedSampling; } /** * @brief Get the list of indexes used for a parameter */ std::vector PanelPlotOutput::getParamUsedIndexes(std::string paramId, int dim1Size, int dim2Size) { std::vector indexes; for (ParameterAxesList::iterator paramAxeIt = _parameterAxesList.begin(); paramAxeIt != _parameterAxesList.end(); ++paramAxeIt) { // get indexes for spectro std::shared_ptr pSpecProp = paramAxeIt->getSpectroProperties(); if (pSpecProp != nullptr) { if (pSpecProp->getParamId() == paramId) { if (pSpecProp->getIndexes().empty()) { // get used indexes by the spectro thanks to the index definition in the request AMDA::Common::ParameterIndexComponentList indexList; AMDA::Common::ParameterIndexesTool::parse(pSpecProp->getIndexDef(), dim1Size, dim2Size, indexList); pSpecProp->setIndexes(indexList); } for (auto index : pSpecProp->getIndexes()) { if (std::find(indexes.begin(), indexes.end(), index) != indexes.end()) continue; indexes.push_back(index); } } } // get indexes for spectro std::shared_ptr pSauvaudProp = paramAxeIt->getSauvaudProperties(); if (pSauvaudProp != nullptr) { if (pSauvaudProp->getParamId() == paramId) { if (pSauvaudProp->getIndexes().empty()) { // get used indexes by the spectro thanks to the index definition in the request AMDA::Common::ParameterIndexComponentList indexList; AMDA::Common::ParameterIndexesTool::parse(pSauvaudProp->getIndexDef(), dim1Size, dim2Size, indexList); pSauvaudProp->setIndexes(indexList); } for (auto index : pSauvaudProp->getIndexes()) { if (std::find(indexes.begin(), indexes.end(), index) != indexes.end()) continue; indexes.push_back(index); } } } // get indexes for intervals std::shared_ptr pIntProp = paramAxeIt->getIntervalsProperties(); if (pIntProp != nullptr) { if (pIntProp->getParamId() == paramId) { if (pIntProp->getIndexes().empty()) { // get used indexes by the intervals thanks to the index definition in the request AMDA::Common::ParameterIndexComponentList indexList; AMDA::Common::ParameterIndexesTool::parse(pIntProp->getIndexDef(), dim1Size, dim2Size, indexList); pIntProp->setIndexes(indexList); } for (auto index : pIntProp->getIndexes()) { if (std::find(indexes.begin(), indexes.end(), index) != indexes.end()) continue; indexes.push_back(index); } } } // get indexes for series of this ParameterAxe std::vector seriesIndexes = paramAxeIt->getParamUsedIndexes(paramId); for (AMDA::Common::ParameterIndexComponent index : seriesIndexes) { if ((index.getDim1Index() == -1) && (index.getDim2Index() == -1)) { //-1 => all indexes indexes.clear(); indexes.push_back(AMDA::Common::ParameterIndexComponent(-1, -1)); return indexes; } if (std::find(indexes.begin(), indexes.end(), index) != indexes.end()) continue; indexes.push_back(index); } } if (indexes.empty()) indexes.push_back(AMDA::Common::ParameterIndexComponent(-1, -1)); return indexes; } /* * @brief Set pointer to params values */ void PanelPlotOutput::setParameterValues(std::map *pParameterValues) { _pParameterValues = pParameterValues; } /* * @brief Set a pointer to the time intervals list */ void PanelPlotOutput::setTimeIntervalListPtr(AMDA::Parameters::TimeIntervalList *timeIntervalListPtr) { _timeIntervalListPtr = timeIntervalListPtr; } /* * @brief Get computed values (in relation with the y axis definition) for a y serie and a time interval * Do not forget to delete computedValues !! * Don't delete timeValues !! */ bool PanelPlotOutput::getComputedValuesFromSerieAndInterval(double startDate, double stopDate, SeriesProperties &rSeriesProperties, AMDA::Common::ParameterIndexComponent index, double **computedValues, double **timeValues, int &nbValues) { LOG4CXX_DEBUG(gLogger, "PanelPlotOutput::getComputedValuesFromSerieAndInterval"); // get parameter data for this serie ParameterData &data = (*_pParameterValues)[rSeriesProperties.getParamId()]; // get original data for interval [startDate, stopDate] int startIndex; data.getIntervalBounds(startDate, stopDate, startIndex, nbValues); if (nbValues == 0) { LOG4CXX_DEBUG(gLogger, "PanelPlotOutput::getComputedValuesFromSerieAndInterval - Cannot find data for serie with id " << rSeriesProperties.getId()); return false; } double *valuesInterval = data.getValues(index, startIndex); // get computed data for interval [startDate, stopDate] in relation with the serie y axis (*computedValues) = _panel->getAxis(rSeriesProperties.getYAxisId())->getComputedValues(valuesInterval, nbValues, rSeriesProperties.getMin(), rSeriesProperties.getMax()); // get time values (*timeValues) = &data.getTimes()[startIndex]; return true; } /* * @brief Get computed values (in relation with the color axis definition) for a color serie and a time interval * Do not forget to delete computedValues !! * Don't delete timeValues !! */ bool PanelPlotOutput::getColoredComputedValuesFromSerieAndInterval(double startDate, double stopDate, SeriesProperties &rSeriesProperties, double **computedValues, double **timeValues, int &nbValues) { LOG4CXX_DEBUG(gLogger, "PanelPlotOutput::getColoredComputedValuesFromSerieAndInterval"); // get parameter data for this color serie ParameterData &data = (*_pParameterValues)[rSeriesProperties.getColorParamId()]; ParameterAxes *colorSerieParameterAxes = getParameterAxesByColorSerieId(rSeriesProperties.getColorSerieId()); if (colorSerieParameterAxes == NULL) { LOG4CXX_DEBUG(gLogger, "PanelPlotOutput::getColoredComputedValuesFromSerieAndInterval - Cannot retrieve parameter axe"); return false; } ColorSeriesProperties &colorSerieProp = colorSerieParameterAxes->getColorSeriePropertiesById(rSeriesProperties.getColorSerieId()); // get original data for interval [startDate, stopDate] int startIndex; data.getIntervalBounds(startDate, stopDate, startIndex, nbValues); if (nbValues == 0) { LOG4CXX_DEBUG(gLogger, "PanelPlotOutput::getColoredComputedValuesFromSerieAndInterval - Cannot find data for color serie with id " << colorSerieProp.getId()); return false; } double *valuesInterval = data.getValues(colorSerieProp.getIndex(), startIndex); // get computed data for interval [startDate, stopDate] in relation with the color axis (*computedValues) = _panel->getColorAxis()->getComputedValues( valuesInterval, nbValues, colorSerieProp.getMin(), colorSerieProp.getMax()); // get time values (*timeValues) = &data.getTimes()[startIndex]; return true; } /* * @brief Get computed values (in relation with the y axis definition) for a y serie and a time interval * Do not forget to delete computedValues !! * Don't delete timeValues !! */ bool PanelPlotOutput::getErrorComputedValuesFromSerieAndInterval(double startDate, double stopDate, SeriesProperties &rSeriesProperties, double **minComputedValues, double **minTimeValues, int &nbMinValues, double **maxComputedValues, double **maxTimeValues, int &nbMaxValues) { LOG4CXX_DEBUG(gLogger, "PanelPlotOutput::getErrorComputedValuesFromSrieAndInterval"); ErrorBarProperties &errorBarProp = rSeriesProperties.getErrorBarProperties(); if (errorBarProp.getErrorMinMax() == nullptr) return false; // get parameter dataMin for this color bar ParameterData &dataMin = (*_pParameterValues)[errorBarProp.getErrorMinMax()->getUsedParamMin()]; // get original min data for interval [startDate, stopDate] int minStartIndex; dataMin.getIntervalBounds(startDate, stopDate, minStartIndex, nbMinValues); if (nbMinValues == 0) { LOG4CXX_DEBUG(gLogger, "PanelPlotOutput::getErrorComputedValuesFromSerieAndInterval - Cannot get min data for error bar"); return false; } double *minValuesInterval = dataMin.getValues(errorBarProp.getErrorMinMax()->getIndexMin(), minStartIndex); // get computed min data for interval [startDate, stopDate] in relation with the serie y axis (*minComputedValues) = _panel->getAxis(rSeriesProperties.getYAxisId())->getComputedValues(minValuesInterval, nbMinValues, rSeriesProperties.getMin(), rSeriesProperties.getMax()); // get time values (*minTimeValues) = &dataMin.getTimes()[minStartIndex]; // get parameter dataMax for this color bar ParameterData &dataMax = (*_pParameterValues)[errorBarProp.getErrorMinMax()->getUsedParamMax()]; // get original max data for interval [startDate, stopDate] int maxStartIndex; dataMax.getIntervalBounds(startDate, stopDate, maxStartIndex, nbMaxValues); if (nbMaxValues == 0) { LOG4CXX_DEBUG(gLogger, "PanelPlotOutput::getErrorComputedValuesFromSerieAndInterval - Cannot get min data for error bar"); delete[](*minComputedValues); return false; } double *maxValuesInterval = dataMax.getValues(errorBarProp.getErrorMinMax()->getIndexMax(), maxStartIndex); // get computed max data for interval [startDate, stopDate] in relation with the serie y axis (*maxComputedValues) = _panel->getAxis(rSeriesProperties.getYAxisId())->getComputedValues(maxValuesInterval, nbMaxValues, rSeriesProperties.getMin(), rSeriesProperties.getMax()); // get time values (*maxTimeValues) = &dataMax.getTimes()[maxStartIndex]; return true; } /* * @brief Return the color to draw the line of a serie */ Color PanelPlotOutput::getSerieLineColor(SeriesProperties &rSeriesProperties, bool moreThanOneSerieForAxis) { Color lLineColor = rSeriesProperties.getLineProperties().getColor(); if ((lLineColor._colorIndex == -1) && (lLineColor._red == -1) && (lLineColor._green == -1) && (lLineColor._blue == -1)) { // if line color not defined, try to use the serie color lLineColor = rSeriesProperties.getColor(); if ((lLineColor._colorIndex == -1) && (lLineColor._red == -1) && (lLineColor._green == -1) && (lLineColor._blue == -1)) { // if color not defined if (!_panel->_page->_superposeMode && !moreThanOneSerieForAxis) { lLineColor = _panel->getAxis(rSeriesProperties.getYAxisId())->_color; } else { // get a default color getDefaultColor(_panel->_page->_mode, _automaticSerieColorCursor, lLineColor); } } } return lLineColor; } /* * @brief Return the color to draw the symbols of a serie */ Color PanelPlotOutput::getSerieSymbolColor(SeriesProperties &rSeriesProperties, Color &pLineColor) { Color lSymbolColor = rSeriesProperties.getSymbolProperties().getColor(); if ((lSymbolColor._colorIndex == -1) && (lSymbolColor._red == -1) && (lSymbolColor._green == -1) && (lSymbolColor._blue == -1)) { // if not defined, use the line color lSymbolColor = pLineColor; } return lSymbolColor; } /** * @brief Configure params legend. */ void PanelPlotOutput::configureParamsLegend(double startTime, double stopTime, int intervalIndex) { _panel->_paramsLegendProperties.resetPlot(); for (auto parameter : _parameterAxesList) { for (auto lSeries : parameter.getYSeriePropertiesList()) { for (auto lIndex : lSeries.getIndexList(_pParameterValues)) { // for the legend configuration, we don't need to know the line and symbol colors Color fakeColor(0, 0, 0); addSerieToParamsLegend(lSeries, lIndex, parameter._originalParamId, fakeColor, fakeColor, startTime, stopTime, intervalIndex); } } } } /** * @brief Add a serie to the param legend */ void PanelPlotOutput::addSerieToParamsLegend(SeriesProperties &lSeriesProperties, AMDA::Common::ParameterIndexComponent &index, std::string originalParamId, Color &lineColor, Color &symbolColor, double startTime, double stopTime, int intervalIndex) { if (!_panel->_paramsLegendProperties.isVisible()) return; LOG4CXX_DEBUG(gLogger, "PanelPlotOutput::addSerieToParamsLegend"); std::stringstream fullLegendText; if (_panel->_paramsLegendProperties.isParamInfoVisible()) { // add params info fullLegendText << getSerieParamsLegendString(lSeriesProperties, index, originalParamId); } if (_panel->_paramsLegendProperties.isIntervalInfoVisible()) { // add interval info if (!fullLegendText.str().empty()) fullLegendText << "; "; switch (_panel->_paramsLegendProperties.getIntervalInfoType()) { case ParamsLegendProperties::IntervalInfoType::INDEX: fullLegendText << "I"; fullLegendText << intervalIndex; break; case ParamsLegendProperties::IntervalInfoType::STARTSTOP: fullLegendText << "["; fullLegendText << AMDA::TimeUtil::formatTimeDateInIso(startTime); fullLegendText << ", "; fullLegendText << AMDA::TimeUtil::formatTimeDateInIso(stopTime); fullLegendText << "]"; } } // push this legend to the params legend properties _panel->_paramsLegendProperties.addSerie(lSeriesProperties, fullLegendText.str().c_str(), lineColor, symbolColor); } /* * @brief Return the associated params legend to a serie */ std::string PanelPlotOutput::getSerieParamsLegendString(SeriesProperties &rSeriesProperties, AMDA::Common::ParameterIndexComponent &index, std::string originalParamId) { // Retrieve ParamInfo Manager ParamMgr *piMgr = ParamMgr::getInstance(); // Try to retrieve informations from paramInfo ParameterSPtr p = _parameterManager.getParameter(rSeriesProperties.getParamId()); ParamInfoSPtr paramInfo = piMgr->getParamInfoFromId(p->getInfoId()); // Build parameter text legend depending on the availability of paramInfo std::stringstream paramLegendText; if (paramInfo) { if ((index.getDim1Index() == -1) && (index.getDim2Index() == -1)) { // parameter legend text = short_name paramLegendText << paramInfo->getShortName(); } else { if (paramInfo->getComponents(index).empty() == false) // parameter legend text = components at index lIndex] paramLegendText << paramInfo->getComponents(index); else { // parameter legend text = short_name [lIndex] paramLegendText << paramInfo->getShortName() << "[" << index.getDim1Index(); if (index.getDim2Index() != -1) paramLegendText << "," << index.getDim2Index(); paramLegendText << "]"; } } } else { if ((index.getDim1Index() == -1) && (index.getDim2Index() == -1)) // parameter legend text = _originalParamId paramLegendText << originalParamId; else { // parameter legend text = _originalParamId [lIndex] paramLegendText << originalParamId << "[" << index.getDim1Index(); if (index.getDim2Index() != -1) paramLegendText << "," << index.getDim2Index(); paramLegendText << "]"; } } return paramLegendText.str(); } /* * Dumps properties for test. */ void PanelPlotOutput::dump(std::ostream &out) { out << *(_panel->_page) << std::endl; out << *_panel << std::endl; std::string prefix = "parameter."; for (auto parameter : _parameterAxesList) { parameter.dump(out, prefix); } } } /* namespace plot */