/* * DigitalAxis.cc * * Created on: 3 déc. 2013 * Author: CS */ #include "DigitalAxis.hh" #include "PlotLogger.hh" #include "PanelPlotOutputException.hh" #include #include #include #include "plplot/plplotP.h" namespace plot { const int DigitalAxis::MAX_DIGIT_NUMBER = 3; const int DigitalAxis::STANDARD_FORMAT_PRECISION = 1; const int DigitalAxis::LOG_CONSTANT = 1000000; std::string DigitalAxis::getPlotOpt() { std::string options = Axis::getPlotOpt(); // Remove m or n plplot option if tickmark not visible // This will prevent plplot to draw any tickmark if (_showTickMark == false) { size_t pos; if ((pos = options.find("m")) != std::string::npos) { options.replace(pos, 1, ""); } if ((pos = options.find("n")) != std::string::npos) { options.replace(pos, 1, ""); } } if (_scale == Scale::LOGARITHMIC) { options += "l"; } else if (getFormat() == Format::SCIENTIFIC) { // Check format to use for label options += "of"; } else { options += "f"; } return options; } Range DigitalAxis::getRange() { Range lRange = Axis::getRange(); try { if (_scale == Scale::LOGARITHMIC) { double min; if (lRange.getMin() <= 0) { min = log10(lRange.getMax() / LOG_CONSTANT); } else { min = log10(lRange.getMin()); } double max; if (lRange.getMax() <= 0) { max = log10(lRange.getMin() / LOG_CONSTANT); } else { max = log10(lRange.getMax()); } lRange.setMin(min); lRange.setMax(max); if (lRange._extend) { return extendRange(lRange); } else { return lRange; } } else { if (lRange._extend) { return extendRange(lRange); } else { return lRange; } } } catch (std::exception& e) { // negative value for log ... stop process std::stringstream lError; lError << "DigitalAxis::getRange : range min and max have to be positive value (" << e.what() << ")"; BOOST_THROW_EXCEPTION( PanelPlotOutputException() << AMDA::ex_msg(lError.str())); } } DigitalAxis::Format DigitalAxis::getFormat() { double lMin = pow(10, -MAX_DIGIT_NUMBER); double lMax = pow(10, MAX_DIGIT_NUMBER); double lDesiredMin = std::abs(getRange().getMin()); double lDesiredMax = std::abs(getRange().getMax()); // If maximum range doesn't include desired range, // label need to be formatted. if ( (lDesiredMin != 0 && (lDesiredMin <= lMin || lDesiredMin >= lMax)) || (lDesiredMax != 0 && (lDesiredMax <= lMin || lDesiredMax >= lMax)) ) { return DigitalAxis::Format::SCIENTIFIC; } else { return DigitalAxis::Format::STANDARD; } } std::pair DigitalAxis::getTickMarkSize() { // If tickmarks are not visible return a null size if (_showTickMark == false) { return std::pair (0,0); } std::pair tickMarkSize(0, getTickMarkLines()); // If TickMark width is fixed, return it ! if (_fixedTickMarkWidth != -1) { tickMarkSize.first = _fixedTickMarkWidth; return tickMarkSize; } Range lRange(getRange()); if (_scale == Scale::LOGARITHMIC) { tickMarkSize.first = 3; } else if (getFormat() == Format::SCIENTIFIC){ // (i.e. 1.3e⁴) _scientific_format_precision = computeScientificFormatPrecision(lRange.getMin(), lRange.getMax()); tickMarkSize.first = _scientific_format_precision + 4 + (lRange.getMin() < 0 ? 1 : 0); } else { double dMinFloor = floor(fabs(lRange.getMin())); double dMaxFloor = floor(fabs(lRange.getMax())); // Check that min and max for is not null to avoid log10(0) ! if ((dMinFloor == 0) && (dMaxFloor == 0)) { char buf1 [64], buf2 [64]; sprintf (buf1,"%.3f", lRange.getMin()); sprintf (buf2,"%.3f", lRange.getMax()); tickMarkSize.first = std::max(strlen (buf1), strlen (buf2)); } else { int iMinFloor = log10 (dMinFloor) + 1; int iMaxFloor = log10 (dMaxFloor) + 1; double rangeSize = lRange.getMin() - lRange.getMax(); int precision = abs(floor(log10(fabs(rangeSize)))); tickMarkSize.first = precision + std::max(iMinFloor, iMaxFloor) + 1; if (lRange.getMin() < 0 || lRange.getMax() < 0) { tickMarkSize.first += 1; } } } return tickMarkSize; } /** * @overrides Axis::getComputedValues */ double* DigitalAxis::getComputedValues(double* originalValues_, int size_, double min, double max) { double *computedValues = new double [size_]; // Duplicates data memcpy (computedValues, originalValues_, size_ * sizeof (double)); // Need to filter min max values ? if ((std::isnan(min) == false) || (std::isnan(max) == false)) { for (int i = 0; i < size_; ++i) { if ((originalValues_[i] < min) || (originalValues_[i] > max)) { computedValues [i] = nan(""); } } } // if scale is logarithmic, just calculate log for each value if ((_scale == Scale::LOGARITHMIC) && !_isZAxis) { for (int i = 0; i < size_; ++i) { if (computedValues[i] <= 0) { computedValues [i] = log10(std::max(min, max) / DigitalAxis::LOG_CONSTANT); LOG4CXX_WARN(gLogger, "Negative value found, no log calculated"); } else { computedValues [i] = log10(computedValues[i]); } } } return computedValues; } void generateDigitalLabel(PLINT /*axis*/, PLFLT value, char *label, PLINT length, PLPointer data) { DigitalAxis *pAxis = (DigitalAxis *)data; getDigitalLabel(value, pAxis->getScientificFormatPrecision(), label, length); } void generateNoDigitalLabel(PLINT /*axis*/, PLFLT /*value*/, char *label, PLINT /*length*/, PLPointer /*data*/) { // Builds an empty Time label label [0] = 0; } int computeScientificFormatPrecision(double min, double max) { int precision = 1; int lMinExp = floor(log10(fabs(min))); int lMaxExp = floor(log10(fabs(max))); if (lMaxExp != lMinExp) { return precision; } PLFLT tick = 0; PLINT nsubt = 0; pldtik( min, max, &tick, &nsubt, false); double v = tick / pow(10, lMinExp); precision = ceil(fabs(log10(v))); return precision; } void getDigitalLabel(double value, int precision, char* label, int length) { if (value != 0) { int lExp = floor(log10(fabs(value))); double lValue = value / pow(10, lExp); if (lExp == 0) snprintf( label, length, "%.*f", precision, lValue); else snprintf( label, length, "%.*fe#u%i#d", precision, lValue, lExp); } else { std::stringstream lStrValue; lStrValue << value; snprintf( label, length, "%s", lStrValue.str().c_str()); } } } /* namespace plot */