DigitalAxis.cc 5.61 KB
/*
 * DigitalAxis.cc
 *
 *  Created on: 3 déc. 2013
 *      Author: CS
 */

#include "DigitalAxis.hh"
#include "PlotLogger.hh"
#include "PanelPlotOutputException.hh"

#include <sstream>
#include <iomanip>
#include <iostream>

namespace plot {

const int DigitalAxis::MAX_DIGIT_NUMBER = 3;
const int DigitalAxis::SCIENTIFIC_FORMAT_PRECISION = 1;
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<int, int> DigitalAxis::getTickMarkSize() {
	// If tickmarks are not visible return a null size
	if (_showTickMark == false) {
		return std::pair<int , int> (0,0);
	}

	std::pair<int, int> tickMarkSize(0, getTickMarkLines());

	// If TickMark width is fixed, return it !
	if (_fixedTickMarkWidth != -1) {
		tickMarkSize.first = _fixedTickMarkWidth;
		return tickMarkSize;
	}

	if (_scale == Scale::LOGARITHMIC) {
		tickMarkSize.first = 3;
	} else if (getFormat() == Format::SCIENTIFIC){
		// (i.e. 1.3e⁴)
		tickMarkSize.first = SCIENTIFIC_FORMAT_PRECISION + 4;
	} else {
		Range lRange(getRange());

		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 ((isnan(min) == false) || (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) {
		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*/) {
	if (value != 0) {
		// Determination exposant et mantisse
		int lExp = floor(log10(fabs(value)));
		double lValue = value / pow(10, lExp);
		if (lExp == 0)
			snprintf( label, length, "%.*f", plot::DigitalAxis::SCIENTIFIC_FORMAT_PRECISION, lValue);
		else
			snprintf( label, length, "%.*fe#u%i#d", plot::DigitalAxis::SCIENTIFIC_FORMAT_PRECISION, lValue, lExp);
	} else {
		std::stringstream lStrValue;
		lStrValue << value;
		snprintf( label, length, "%s", lStrValue.str().c_str());
	}
}

void generateNoDigitalLabel(PLINT /*axis*/, PLFLT /*value*/, char *label, PLINT /*length*/, PLPointer /*data*/) {
	// Builds an empty Time label
	label [0] = 0;
}

} /* namespace plot */