All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mds.wave.Signal Maven / Gradle / Ivy

There is a newer version: 7.139.60
Show newest version
package mds.wave;

import java.awt.Color;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;

/**
 * The DataSignal class encapsulates a description of a
 *
 * are : name, marker, point step of marker, color index from an external color
 * pallet, measure point error, offset and gain values. DataSignal is defined in
 * a rectangular region.
 *
 * @see Waveform
 * @see MultiWaveform
 */
public class Signal implements WaveDataListener
{
	static class RegionDescriptor
	{
		double lowerBound, upperBound;
		double resolution;

		RegionDescriptor(double lowerBound, double upperBound, double resolution)
		{
			this.lowerBound = lowerBound;
			this.upperBound = upperBound;
			this.resolution = resolution; // Number of points for this region / (upperBound - lowerBound)
		}
	}

	class ResolutionManager
	{
		Vector lowResRegions = new Vector<>();

		ResolutionManager()
		{}

		ResolutionManager(ResolutionManager rm)
		{
			for (int i = 0; i < rm.lowResRegions.size(); i++)
				lowResRegions.addElement(rm.lowResRegions.elementAt(i));
		}

		void addRegion(RegionDescriptor newReg)
		{
			// New regions can only have increased resolution in case they intersect
			// previous regions
			// Skip disjoint regions with lower bounds
			if (newReg.upperBound < newReg.lowerBound)
			{
				System.err.println("INTERNAL ERROR: LOWER BOUND > UPPER BOUND!!!!!");
			}
			int idx;
			RegionDescriptor currRegion;
			for (idx = 0; idx < lowResRegions.size(); idx++)
			{
				currRegion = lowResRegions.elementAt(idx);
				if (currRegion.upperBound > newReg.lowerBound)
					break;
			}
			if (idx == lowResRegions.size()) // All regions with lower bounds
			{
				if (debug)
					System.out.println("Added region (" + newReg.lowerBound + "," + newReg.upperBound + ","
							+ newReg.resolution + ") at bottom");
				lowResRegions.addElement(newReg);
				return;
			}
			// Check if the first region which is not all before this region has any
			// intersection
			currRegion = lowResRegions.elementAt(idx);
			if (currRegion.lowerBound < newReg.lowerBound)
			{
				if (currRegion.upperBound <= newReg.upperBound)
				{
					currRegion.upperBound = newReg.lowerBound;
					if (debug)
						System.out.println(
								"updated region (" + currRegion.lowerBound + "," + currRegion.upperBound + ") ");
					idx++;
				}
				else // The new region is completely contained in currRegion
				{
					final double prevUpper = currRegion.upperBound;
					currRegion.upperBound = newReg.lowerBound;
					if (debug)
						System.out.println(
								"Updated region (" + currRegion.lowerBound + "," + currRegion.upperBound + ") ");
					idx++;
					lowResRegions.insertElementAt(newReg, idx);
					if (debug)
						System.out.println("Added region (" + newReg.lowerBound + "," + newReg.upperBound + ","
								+ newReg.resolution + ")");
					idx++;
					lowResRegions.insertElementAt(
							new RegionDescriptor(newReg.upperBound, prevUpper, currRegion.resolution), idx);
					if (debug)
						System.out.println("Added region (" + newReg.upperBound + "," + prevUpper + ","
								+ currRegion.resolution + ")");
					return; // done in this case
				}
			}
			// Remove regions completely contained in the new one
			while (idx < lowResRegions.size() && lowResRegions.elementAt(idx).upperBound <= newReg.upperBound)
			{
				if (debug)
					System.out.println("Removed region (" + lowResRegions.elementAt(idx).lowerBound + ","
							+ lowResRegions.elementAt(idx).upperBound + ")");
				lowResRegions.removeElementAt(idx);
			}
			// In case there is a overlapped region, adjust its lower bound
			if (idx < lowResRegions.size() && lowResRegions.elementAt(idx).lowerBound < newReg.upperBound)
			{
				lowResRegions.elementAt(idx).lowerBound = newReg.upperBound;
				if (debug)
					System.out.println("Updated region (" + lowResRegions.elementAt(idx).lowerBound + ","
							+ lowResRegions.elementAt(idx).upperBound + ")");
			}
			lowResRegions.insertElementAt(newReg, idx);
			if (debug)
				System.out.println(
						"Added region (" + newReg.lowerBound + "," + newReg.upperBound + "," + newReg.resolution + ")");
//Merge adjacent regions with same resolution (may happens due to the inteval enlargements which occur in zooms)
			idx = 1;
			while (idx < lowResRegions.size())
			{
				final RegionDescriptor currReg = lowResRegions.elementAt(idx);
				final RegionDescriptor prevReg = lowResRegions.elementAt(idx - 1);
				if (prevReg.upperBound == currReg.lowerBound && prevReg.resolution == currReg.resolution)
				{
					if (debug)
						System.out.println("Regions at (" + prevReg.lowerBound + "," + prevReg.upperBound + ")  ("
								+ currReg.lowerBound + "," + currReg.upperBound + ") merged");
					prevReg.upperBound = currReg.upperBound;
					lowResRegions.removeElementAt(idx);
				}
				else
					idx++;
			}
		}

		void appendRegion(RegionDescriptor newReg)
		{
			if (newReg.upperBound < newReg.lowerBound)
			{
				System.err.println("INTERNAL ERROR IN APPEND: LOWER BOUND > UPPER BOUND!!!!!");
			}
			if (lowResRegions.size() == 0)
			{
				lowResRegions.addElement(newReg);
				return;
			}
			final RegionDescriptor lastReg = lowResRegions.elementAt(lowResRegions.size() - 1);
			if (lastReg.resolution == newReg.resolution)
				lastReg.upperBound = newReg.upperBound;
			else
			{
				if (lastReg.upperBound > newReg.lowerBound)
				{
					// System.err.println("Warning: INTERNAL ERROR IN APPEND: NEW.LOWERBOUND <
					// LAST.UPPERBOUND");
					newReg.lowerBound = lastReg.upperBound;
				}
				lowResRegions.addElement(newReg);
			}
		}

		// Check if the passed interval intersects any low resolution region
		Vector getLowerResRegions(double lowerInt, double upperInt, double resolution)
		{
			final Vector retRegions = new Vector<>();
			for (int i = 0; i < lowResRegions.size(); i++)
			{
				// 3 cases to be handled
				final RegionDescriptor currReg = lowResRegions.elementAt(i);
				// 1) Lower bound is within interval
				if (currReg.lowerBound < upperInt && currReg.lowerBound > lowerInt)
				{
					if (debug)
						System.out.println("CASE 1: Lower bound is within interval for region " + i
								+ "  its resolution: " + currReg.resolution + " in resolution: " + resolution);
					if (currReg.resolution < resolution)
					{
						// Adjust upper bound
						double currUpper = currReg.upperBound;
						if (currUpper > upperInt)
							currUpper = upperInt;
						if (debug)
							System.out.println("Added Region lower: " + currReg.lowerBound + "  upper: " + currUpper
									+ " resoluton: " + resolution);
						retRegions.addElement(new RegionDescriptor(currReg.lowerBound, currUpper, resolution));
					}
				}
				// 2) Upper bound is within interval
				else if (currReg.upperBound < upperInt && currReg.upperBound > lowerInt)
				{
					if (debug)
						System.out.println("CASE 2: Upper bound is within interval for region " + i);
					if (currReg.resolution < resolution)
					{
						// Adjust lower bound
						double currLower = currReg.lowerBound;
						if (currLower < lowerInt)
							currLower = lowerInt;
						retRegions.addElement(new RegionDescriptor(currLower, currReg.upperBound, resolution));
					}
				}
				// 3) The interval is fully within the current region
				else if (currReg.lowerBound < lowerInt && currReg.upperBound > upperInt)
				{
					if (debug)
						System.out.println("CASE 3: UThe interval is fully within the current region for region " + i);
					if (currReg.resolution < resolution)
					{
						retRegions.addElement(new RegionDescriptor(lowerInt, upperInt, resolution));
					}
				}
			}
			return retRegions;
		}

		double[] getMinMaxX()
		{
			final double limits[] = new double[2];
			limits[0] = lowResRegions.elementAt(0).lowerBound;
			limits[1] = lowResRegions.elementAt(lowResRegions.size() - 1).upperBound;
			return limits;
		}

		boolean isEmpty()
		{ return lowResRegions.size() == 0; }

		void resetRegions()
		{
			lowResRegions.clear();
		}
	} // End inner class ResolutionManager

	public static final int TYPE_1D = 0;
	public static final int TYPE_2D = 1;
	public static final int MODE_XZ = 0;
	public static final int MODE_YZ = 1;
	public static final int MODE_CONTOUR = 2;
	public static final int MODE_IMAGE = 3;
	public static final int MODE_ONDINE = 4;
	public static final int MODE_PROFILE = 5;
	public static final int MODE_LINE = 0;
	public static final int MODE_NOLINE = 2;
	public static final int MODE_STEP = 3;
	public static final int DEFAULT_CONTOUR_LEVEL = 20;
	public static final int FUSO = 0;
	/**
	 * String vector of markers name.
	 */
	public static final String[] markerList = new String[]
	{ "None", "Square", "Circle", "Cross", "Triangle", "Point" };
	/**
	 * Integer vector of predefined marker step.
	 */
	static final int[] markerStepList = new int[]
	{ 1, 5, 10, 20, 50, 100 };
	/**
	 * No marker
	 */
	public static final int NONE = 0;
	/**
	 * Square marker
	 */
	public static final int SQUARE = 1;
	/**
	 * Circle marker
	 */
	public static final int CIRCLE = 2;
	/**
	 * Cross marker
	 */
	public static final int CROSS = 3;
	/**
	 * Triangle marker
	 */
	public static final int TRIANGLE = 4;
	/**
	 * Point marker
	 */
	public static final int POINT = 5;
	static final int NUM_POINTS = 2000;
	public final static int SIMPLE = 0;
	public final static int AT_CREATION = 1;
	public final static int FIXED_LIMIT = 2;
	public final static int DO_NOT_UPDATE = 4;
	private static final int DEFAULT_INC_SIZE = 10000;

	static String toStringTime(long time)
	{
		final DateFormat df = new SimpleDateFormat("HH:mm:sss");
		return df.format(new Date(time));
	}

	boolean debug = false;
	/**
	 * data object
	 */
	private WaveData data;
	/**
	 * X data object
	 */
	private WaveData x_data;
	/**
	 * up error object
	 */
	private WaveData up_errorData;
	/**
	 * low error object
	 */
	private WaveData low_errorData;
	private boolean xLimitsInitialized = false;
	/**
	 * x min signal region
	 */
	private double xmin;
	/**
	 * x max signal region
	 */
	private double xmax;
	/**
	 * y min signal region
	 */
	private double ymin;
	/**
	 * y max signal region
	 */
	private double ymax;
	/**
	 * x min region value saved at signal creation
	 */
	private double saved_xmin = -Double.MAX_VALUE;
	/**
	 * x max region value saved at signal creation
	 */
	private double saved_xmax = Double.MAX_VALUE;
	/**
	 * y min region value saved at signal creation
	 */
	private double saved_ymin = -Double.MAX_VALUE;
	/**
	 * y max region value saved at signal creation
	 */
	private double saved_ymax = Double.MAX_VALUE;
	/**
	 * true if symmetrical error defines
	 */
	private boolean error;
	/**
	 * true if asymmetrical error defines
	 */
	private boolean asym_error;
	/**
	 * index of NaN in x,y vector
	 */
	private int nans[];
	/**
	 * number of NaN in signal x, y vector
	 */
	private int n_nans = 0;
	private int prev_idx = 0;
	/**
	 * Translate x max signal region
	 */
	private double t_xmax;
	/**
	 * Translate x min signal region
	 */
	private double t_xmin;
	/**
	 * Translate y max signal region
	 */
	private double t_ymax;
	/**
	 * Translate y min signal region
	 */
	private double t_ymin;
	/**
	 * true if x vector point are increasing
	 */
	private boolean increasing_x = true;
	/**
	 * Signal name
	 */
	protected String name;
	/**
	 * Signal marker
	 */
	protected int marker = NONE;
	/**
	 * Signal marker step
	 */
	protected int marker_step = 1;
	/**
	 * Color index
	 */
	protected int color_idx = 0;
	/**
	 * Color index
	 */
	protected Color color = null;
	/**
	 * Interpolate flag
	 */
	protected boolean interpolate = true;
	/**
	 * Gain value
	 */
	protected float gain = 1.0F;
	/**
	 * Offset value
	 */
	protected float offset = 0.0F;
	protected int type = TYPE_1D;
	protected int mode2D;
	protected int mode1D;
	protected double curr_x_yz_plot = Double.NaN;
	protected float curr_y_xz_plot = Float.NaN;
	private int curr_y_xz_idx = -1;
	private int curr_x_yz_idx = -1;
	/*
	 * X and Y arrays when mode is MODE_XZ or MODE_YZ
	 */
	private double[] sliceX;
	private float[] sliceY;
	protected double z2D_max;
	protected double z2D_min;
	protected double y2D_max;
	protected double y2D_min;
	protected double x2D_max;
	protected double x2D_min;
	protected double curr_xmax;
	protected double curr_xmin;
	protected String xlabel;
	protected String ylabel;
	protected String zlabel;
	protected String title;
	// Legend associated with this signal
	private String legend = null;
	// True if signal is resampled on server side to
	// reduce net load
	private boolean full_load = false;
	private boolean longXLimits = false;
	private long xMinLong, xMaxLong;
	ContourSignal cs;
	private double contourLevels[];
	Vector>> contourSignals = new Vector<>();
	Vector contourLevelValues = new Vector<>();
	final int NOT_FREEZED = 0, FREEZED_BLOCK = 1, FREEZED_SCROLL = 2;
	int freezeMode = NOT_FREEZED;
	double freezedXMin, freezedXMax;
	Vector pendingUpdatesV = new Vector<>();
	Vector signalListeners = new Vector<>();
	/**
	 * Private caches of the signal (only for 1D Signals)
	 *
	 */
	// 2D management
	double x2D[];
	long x2DLong[];
	float y2D[];
	float z[];
	double xY2D[];
	float yY2D[];
	float zY2D[];
	// 1D management
	double x[] = null;
	float y[] = null;
	long xLong[] = null;
	float upError[];
	float lowError[];
	boolean upToDate = false;
	ResolutionManager resolutionManager = new ResolutionManager();
	private double z_value = Double.NaN;
	private boolean find_NaN = false;
	/**
	 * Return index of nearest signal point to argument (curr_x, curr_y) point.
	 *
	 * @param curr_x value
	 * @param curr_y value
	 * @return index of signal point
	 */
	private int img_xprev = 0;
	private int img_yprev = 0;
	boolean fix_xmin = false;
	boolean fix_xmax = false;
	boolean fix_ymin = false;
	boolean fix_ymax = false;
	private int updSignalSizeInc;
	public int startIndexToUpdate = 0;
	public boolean needFullUpdate = true;
	private int x2D_points = 0;
	private int y2D_points = 0;
	private int z2D_points = 0;
        
        double prevSetXMin, prevSetXMax;

	/**
	 * Constructs a zero Signal with 100 points.
	 */
	public Signal()
	{
		error = asym_error = false;
		final double x[] = new double[]
		{ 0., 1. };
		final float y[] = new float[]
		{ 0, 0 };
		data = new XYWaveData(x, y);
		setAxis();
		saved_xmin = curr_xmin = xmin;
		saved_xmax = curr_xmax = xmax;
		saved_ymin = ymin = 0;
		saved_ymax = ymax = 0;
		increasing_x = true;
	}

	public Signal(double _x[], float _y[])
	{
		error = asym_error = false;
		data = new XYWaveData(_x, _y, (_x.length < _y.length) ? _x.length : _y.length);
		setAxis();
		saved_xmin = curr_xmin = xmin;
		saved_xmax = curr_xmax = xmax;
		saved_ymin = ymin;
		saved_ymax = ymax;
		checkIncreasingX();
	}

	public Signal(double _x[], float _y[], int _n_points) throws IOException
	{
		error = asym_error = false;
		data = new XYWaveData(_x, _y, _n_points);
		setAxis();
		saved_xmin = curr_xmin = xmin;
		saved_xmax = curr_xmax = xmax;
		saved_ymin = ymin;
		saved_ymax = ymax;
		checkIncreasingX();
	}

	/**
	 * Constructs and initialize a Signal with x and y array.
	 *
	 * @param _x an array of x coordinates
	 * @param _y an array of y coordinates
	 */
	public Signal(float _x[], float _y[])
	{
		error = asym_error = false;
		data = new XYWaveData(_x, _y, (_x.length < _y.length) ? _x.length : _y.length);
		setAxis();
		saved_xmin = curr_xmin = xmin;
		saved_xmax = curr_xmax = xmax;
		saved_ymin = ymin;
		saved_ymax = ymax;
		checkIncreasingX();
	}

	public Signal(float _x[], float _y[], int _n_points) throws IOException
	{
		error = asym_error = false;
		data = new XYWaveData(_x, _y, _n_points);
		setAxis();
		xLimitsInitialized = true;
		saved_xmin = curr_xmin = xmin;
		saved_xmax = curr_xmax = xmax;
		saved_ymin = ymin;
		saved_ymax = ymax;
		checkIncreasingX();
	}

	/**
	 * Constructs a Signal with x and y array, with n_points in a defined
	 * two-dimensional region.
	 *
	 * @param _x        an array of x coordinates
	 * @param _y        an array of y coordinates
	 * @param _n_points number of Signal points
	 * @param _xmin     x minimum of region space
	 * @param _xmax     x maximum of region space
	 * @param _ymin     y minimum of region space
	 * @param _ymax     y maximum of region space
	 */
	public Signal(float _x[], float _y[], int _n_points, double _xmin, double _xmax, double _ymin, double _ymax)
	{
		error = asym_error = false;
		data = new XYWaveData(_x, _y, _n_points);
		xLimitsInitialized = true;
		xmin = _xmin;
		xmax = _xmax;
		if (xmax - xmin < _x[1] - _x[0])
			xmax = xmin + _x[1] - _x[0];
//        saved_xmin = curr_xmax = xmin;
//        saved_xmax = curr_xmin = xmax;
		saved_xmin = curr_xmin = xmin;
		saved_xmax = curr_xmax = xmax;
		if (xmax <= xmin)
			saved_xmax = xmax = xmin + (float) 1E-6;
		if (_ymin > _ymax)
			_ymin = _ymax;
		saved_ymin = ymin = _ymin;
		saved_ymax = ymax = _ymax;
		curr_xmax = xmax;
		curr_xmin = xmin;
		setAxis();
		// Here xmin and xmax have been passed, so override values computed by setAxis()
		ymin = saved_ymin;
		ymax = saved_ymax;
		saved_xmin = curr_xmin = xmin;
		saved_xmax = curr_xmax = xmax;
		// saved_ymin = ymin;
		// saved_ymax = ymax;
		checkIncreasingX();
	}

	/**
	 * Constructs a Signal with x and y array and name.
	 *
	 * @param _x   an array of x coordinates
	 * @param _y   an array of y coordinates
	 * @param name signal name
	 */
	public Signal(float _x[], float _y[], String name)
	{
		this(_x, _y);
		setName(new String(name));
	}

	public Signal(long _x[], float _y[], int _n_points)
	{
		error = asym_error = false;
		data = new XYWaveData(_x, _y);
		setAxis();
		saved_xmin = curr_xmin = xmin;
		saved_xmax = curr_xmax = xmax;
		saved_ymin = ymin;
		saved_ymax = ymax;
		checkIncreasingX();
	}

	/**
	 * Constructs a Signal equal to argument Signal
	 *
	 * @param s a Signal
	 */
	public Signal(Signal s)
	{
		error = s.error;
		if (error)
		{
			upError = s.upError;
		}
		asym_error = s.asym_error;
		if (asym_error)
		{
			lowError = s.lowError;
		}
		nans = s.nans;
		n_nans = s.n_nans;
		gain = s.gain;
		offset = s.offset;
		cs = s.cs;
		contourLevels = s.contourLevels;
		contourSignals = s.contourSignals;
		contourLevelValues = s.contourLevelValues;
		data = s.data; // WaveData is stateless!!
		data.addWaveDataListener(this);
		resolutionManager = new ResolutionManager(s.resolutionManager);
		xLimitsInitialized = s.xLimitsInitialized;
		saved_ymax = s.saved_ymax;
		ymax = s.ymax;
		saved_ymin = s.saved_ymin;
		ymin = s.ymin;
		saved_xmin = s.saved_xmin;
		curr_xmin = s.curr_xmin;
		xmin = s.xmin;
		saved_xmax = s.saved_xmax;
		curr_xmax = s.curr_xmax;
		xmax = s.xmax;
		fix_xmin = s.fix_xmin;
		fix_xmax = s.fix_xmax;
		fix_ymin = s.fix_ymin;
		fix_ymax = s.fix_ymax;
		x2D_max = s.x2D_max;
		x2D_min = s.x2D_min;
		y2D_max = s.y2D_max;
		y2D_min = s.y2D_min;
		z2D_max = s.z2D_max;
		z2D_min = s.z2D_min;
		if (xmax <= xmin)
			saved_xmax = xmax = xmin + 1E-6;
		increasing_x = s.increasing_x;
		marker = s.marker;
		marker_step = s.marker_step;
		color_idx = s.color_idx;
		color = s.color;
		interpolate = s.interpolate;
		name = s.name;
		type = s.type;
		mode1D = s.mode1D;
		mode2D = s.mode2D;
		xlabel = s.xlabel;
		ylabel = s.ylabel;
		zlabel = s.zlabel;
		title = s.title;
		// Deep copy buffered signals
		if (s.x != null)
		{
			x = new double[s.x.length];
			System.arraycopy(s.x, 0, x, 0, x.length);
		}
		if (s.y != null)
		{
			y = new float[s.y.length];
			System.arraycopy(s.y, 0, y, 0, y.length);
		}
		if (s.xLong != null)
		{
			xLong = new long[s.xLong.length];
			System.arraycopy(s.xLong, 0, xLong, 0, xLong.length);
		}
		x_data = s.x_data;
		if (s.x2D != null)
		{
			x2D = new double[s.x2D.length];
			System.arraycopy(s.x2D, 0, x2D, 0, x2D.length);
		}
		if (s.x2DLong != null)
		{
			x2DLong = new long[s.x2DLong.length];
			System.arraycopy(s.x2DLong, 0, x2DLong, 0, x2DLong.length);
		}
		if (s.y2D != null)
		{
			y2D = new float[s.y2D.length];
			System.arraycopy(s.y2D, 0, y2D, 0, y2D.length);
		}
		if (s.z != null)
		{
			z = new float[s.z.length];
			System.arraycopy(s.z, 0, z, 0, z.length);
		}
		if (s.xY2D != null)
		{
			xY2D = new double[s.xY2D.length];
			System.arraycopy(s.xY2D, 0, xY2D, 0, xY2D.length);
		}
		if (s.yY2D != null)
		{
			yY2D = new float[s.yY2D.length];
			System.arraycopy(s.yY2D, 0, yY2D, 0, yY2D.length);
		}
		if (s.zY2D != null)
		{
			zY2D = new float[s.zY2D.length];
			System.arraycopy(s.zY2D, 0, zY2D, 0, zY2D.length);
		}
		startIndexToUpdate = s.startIndexToUpdate;
		// signalListeners = s.signalListeners;
		freezeMode = s.freezeMode;
		longXLimits = s.longXLimits;
		xMinLong = s.xMinLong;
		xMaxLong = s.xMaxLong;
	}

	/**
	 * Constructs a Signal equal to argument Signal within a defined two-dimensional
	 * region
	 *
	 * @param s       Signal
	 * @param start_x x start point
	 * @param end_x   x end point
	 * @param start_y y start point
	 * @param end_y   y end point
	 */
	public Signal(Signal s, double start_x, double end_x, double start_y, double end_y)
	{
		xLimitsInitialized = true;
		this.data = s.data;
		nans = s.nans;
		n_nans = s.n_nans;
		error = s.error;
		if (error)
		{
			upError = s.upError;
		}
		asym_error = s.asym_error;
		if (asym_error)
		{
			lowError = s.lowError;
		}
		increasing_x = s.increasing_x;
		saved_ymax = s.saved_ymax;
		ymax = end_y;
		saved_ymin = s.saved_ymin;
		ymin = start_y;
		saved_xmin = curr_xmin = s.saved_xmin;
		xmin = start_x;
		saved_xmax = curr_xmax = s.saved_xmax;
		xmax = end_x;
		if (xmax <= xmin)
			saved_xmax = curr_xmax = xmax = xmin + 1E-6;
		marker = s.marker;
		marker_step = s.marker_step;
		color_idx = s.color_idx;
		color = s.color;
		interpolate = s.interpolate;
		name = s.name;
	}

	/**
	 * Constructs a zero Signal with name.
	 */
	public Signal(String name)
	{
		this();
		this.name = name;
	}

	public Signal(WaveData data, double xmin, double xmax) throws IOException
	{
		this(data, null, xmin, xmax);
	}

	/**
	 * Constructs and initializes a Signal from the specified parameters.
	 *
	 * @param _x        an array of x coordinates
	 * @param _y        an array of x coordinates
	 * @param _n_points the total number of points in the Signal
	 */
	public Signal(WaveData data, WaveData x_data, double xminVal, double xmaxVal) throws IOException
	{
		this(data, x_data, xminVal, xmaxVal, null, null);
	}

	public Signal(WaveData data, WaveData x_data, double xminVal, double xmaxVal, WaveData lowErrData,
			WaveData upErrData) throws IOException
	{
		error = (lowErrData != null || upErrData != null);
		asym_error = (lowErrData != null && upErrData != null);
		up_errorData = upErrData;
		low_errorData = lowErrData;
		if (xminVal != -Double.MAX_VALUE)
		{
			xLimitsInitialized = true;
			saved_xmin = this.xmin = curr_xmin = xminVal;
		}
		if (xmaxVal != Double.MAX_VALUE)
		{
			saved_xmax = this.xmax = curr_xmax = xmaxVal;
		}
		this.data = data;
		this.x_data = x_data;
		data.addWaveDataListener(this);
		checkData(saved_xmin, saved_xmax);
		if (saved_xmin == -Double.MAX_VALUE)
			saved_xmin = this.xmin;
		if (saved_xmax == Double.MAX_VALUE)
			saved_xmax = this.xmax;
	}

	public Signal(WaveData data, WaveData x_data, long xminVal, long xmaxVal) throws IOException
	{
		this(data, x_data, xminVal, xmaxVal, null, null);
	}

	public Signal(WaveData data, WaveData x_data, long xminVal, long xmaxVal, WaveData lowErrData, WaveData upErrData)
			throws IOException
	{
		xMinLong = xminVal;
		xMaxLong = xmaxVal;
		longXLimits = true;
		error = (lowErrData != null || upErrData != null);
		asym_error = (lowErrData != null && upErrData != null);
		up_errorData = upErrData;
		low_errorData = lowErrData;
		if (xminVal != -Double.MAX_VALUE)
		{
			xLimitsInitialized = true;
			saved_xmin = this.xmin = curr_xmin = xminVal;
		}
		if (xmaxVal != Double.MAX_VALUE)
		{
			saved_xmax = this.xmax = curr_xmax = xmaxVal;
		}
		this.data = data;
		this.x_data = x_data;
		try
		{
			checkData(saved_xmin, saved_xmax);
			if (saved_xmin == -Double.MAX_VALUE)
				saved_xmin = this.xmin;
			if (saved_xmax == Double.MAX_VALUE)
				saved_xmax = this.xmax;
		}
		catch (final Exception exc)
		{
			System.out.println("Signal exception: " + exc);
		}
		data.addWaveDataListener(this);
	}

	/**
	 * Add a asymmetric error bar.
	 *
	 * @param _up_error  an array of y up measure error
	 * @param _low_error an array of y low measure error
	 */
	public void AddAsymError(WaveData up_error, WaveData low_error)
	{
		error = asym_error = true;
		up_errorData = up_error;
		low_errorData = low_error;
	}

	public Vector> addContourLevel(double level)
	{
		if (cs == null)
		{
			cs = new ContourSignal(this);
		}
		final Vector> v = cs.contour(level);
		if (v.size() != 0)
		{
			contourSignals.addElement(v);
			contourLevelValues.addElement(new Double(level));
		}
		return v;
	}

	/**
	 * Add a symmetric error bar.
	 *
	 * @param _error an array of y measure error
	 */
	public void AddError(WaveData in_error)
	{
		error = true;
		up_errorData = low_errorData = in_error;
	}

	void adjustArraySizes()
	{
		if (x.length < y.length)
		{
			final float[] newY = new float[x.length];
			System.arraycopy(y, 0, newY, 0, x.length);
			y = newY;
		}
		if (y.length < x.length)
		{
			final double[] newX = new double[y.length];
			System.arraycopy(x, 0, newX, 0, y.length);
			x = newX;
		}
	}

	private double[] appendArray(double arr1[], int sizeUsed, double arr2[], int incSize)
	{
		/*
		 * float arr[] = new float[arr1.length]; for(int i = 0; i < arr1.length; i++)
		 * arr[i] = (float)arr1[i]; return appendArray(arr, sizeUsed, arr2, incSize);
		 */
		if (arr1 == null)
			return arr2.clone();
		if (arr2 == null)
			return arr1.clone();
		double val[];
		if (arr1.length < sizeUsed + arr2.length)
		{
			val = new double[arr1.length + arr2.length + incSize];
			System.arraycopy(arr1, 0, val, 0, sizeUsed);
		}
		else
			val = arr1;
		System.arraycopy(arr2, 0, val, sizeUsed, arr2.length);
		return val;
	}

	private float[] appendArray(float arr1[], int sizeUsed, float arr2[], int incSize)
	{
		if (arr1 == null)
			return arr2.clone();
		if (arr2 == null)
			return arr1.clone();
		float val[];
		if (arr1.length < sizeUsed + arr2.length)
		{
			val = new float[arr1.length + arr2.length + incSize];
			System.arraycopy(arr1, 0, val, 0, sizeUsed);
		}
		else
			val = arr1;
		System.arraycopy(arr2, 0, val, sizeUsed, arr2.length);
		return val;
	}

	public void appendValues(double x[], float y[], int numPoints[], float time[])
	{
		if (type != TYPE_2D || x.length != y.length || time == null || numPoints == null)
			return;
		int numProfile = 0;
		int xIdx, zIdx, yIdx;
		double x2D[] = data.getX2D();
		float y2D[] = data.getY2D();
		float z2D[] = data.getZ();
		xIdx = (x2D == null) ? 0 : x2D_points;
		yIdx = (y2D == null) ? 0 : y2D_points;
		zIdx = (z2D == null) ? 0 : z2D_points;
		if (numPoints.length == time.length)
		{
			numProfile = time.length * 2;
		}
		else if (numPoints.length > time.length)
		{
			numProfile = numPoints.length * 2;
		}
		else if (numPoints.length < time.length)
		{
			numProfile = time.length * 2;
		}
		final float t[] = new float[numProfile];
		for (int i = 0, j = 0; i < numProfile; i += 2)
		{
			t[i] = (time.length == 1) ? time[0] : time[j];
			t[i + 1] = (numPoints.length == 1) ? numPoints[0] : numPoints[j];
			j++;
		}
		x2D = appendArray(x2D, x2D_points, x, updSignalSizeInc);
		x2D_points += x.length;
		y2D = appendArray(y2D, y2D_points, y, updSignalSizeInc);
		y2D_points += y.length;
		z2D = appendArray(z2D, z2D_points, t, updSignalSizeInc);
		z2D_points += t.length;
		data = new XYWaveData(x2D, y2D, z2D);
		setAxis(x2D, z2D, y2D, xIdx, zIdx, yIdx);
		if (xmin > x2D_min)
			xmin = x2D_min;
		if (ymin > y2D_min)
			ymin = y2D_min;
		if (xmax < x2D_max)
			xmax = x2D_max;
		if (ymax < y2D_max)
			ymax = y2D_max;
		curr_x_yz_plot = t[t.length - 2];
	}

	// NOTE trhis is called only by CompositeWaveDisplay and not by jScope
	public void appendValues(float inX[], float inY[])
	{
		if (x == null || y == null)
			return;
		if (type == TYPE_1D)
		{
			final int len = (inX.length < inY.length) ? inX.length : inY.length;
			final double newX[] = new double[x.length + len];
			final float newY[] = new float[x.length + len];
			for (int i = 0; i < x.length; i++)
			{
				newX[i] = x[i];
				newY[i] = y[i];
			}
			for (int i = 0; i < len; i++)
			{
				newX[x.length + i] = inX[i];
				newY[x.length + i] = inY[i];
			}
			data = new XYWaveData(newX, newY);
			try
			{
				final XYData xyData = data.getData(NUM_POINTS);
				x = xyData.x;
				y = xyData.y;
				adjustArraySizes();
				xmax = x[x.length - 1];
			}
			catch (final Exception exc)
			{}
		}
	}

	/**
	 * Autoscale Signal.
	 */
	public void Autoscale()
	{
		freezeMode = NOT_FREEZED;
		setAxis();
		AutoscaleX();
		AutoscaleY();
	}

	/**
	 * Autoscale x coordinates.
	 */
	public void AutoscaleX()
	{
		if (type == TYPE_2D && (mode2D == Signal.MODE_IMAGE || mode2D == Signal.MODE_CONTOUR))
		{
			xmax = this.x2D_max;
			xmin = this.x2D_min;
			return;
		}
		double currX[];
		if (type == TYPE_2D && (mode2D == MODE_XZ || mode2D == MODE_YZ))
			currX = sliceX;
		else
			currX = x;
		if (x == null || x.length == 0)
			return;
		xmin = xmax = currX[0];
		for (final double element : currX)
		{
			if (element < xmin)
				xmin = element;
			if (element > xmax)
				xmax = element;
		}
		if (xmin == xmax)
			xmax = xmin + (float) 1E-10;
	}

	/**
	 * Autoscale y coordinates.
	 */
	public void AutoscaleY()
	{
		if (type == TYPE_2D)
		{
			if (mode2D == Signal.MODE_IMAGE || mode2D == Signal.MODE_CONTOUR)
			{
				ymax = this.y2D_max;
				ymin = this.y2D_min;
				return;
			}
			else
			{
				ymax = ymin = sliceY[0];
				for (final float element : sliceY)
				{
					if (element < ymin)
						ymin = element;
					if (element > ymax)
						ymax = element;
				}
				if (ymin == ymax)
					ymax = ymin + ymin / 4;
			}
			return;
		}
		if (y == null || y.length == 0)
			return;
		float currY[];
		if (type == TYPE_2D && (mode2D == MODE_XZ || mode2D == MODE_YZ))
			currY = sliceY;
		else
			currY = y;
		int startIdx;
		// Check for initial NaN Y values
		if (currY == null || y == null)
			return; // To avoid nullpointer exceptions in any condition
		for (startIdx = 0; startIdx < currY.length && Float.isNaN(y[startIdx]); startIdx++);
		ymin = ymax = y[startIdx];
		for (int i = startIdx; i < currY.length; i++)
		{
			if (Float.isNaN(y[startIdx]))
				continue;
			if (currY[i] < ymin)
				ymin = currY[i];
			if (currY[i] > ymax)
				ymax = currY[i];
		}
		if (ymin == ymax)
			ymax = ymin + ymin / 4;
	}

	/**
	 * Autoscale y coordinates between min and max x coordinates.
	 *
	 * @param min x minimum coordinates
	 * @param max x maximum coordinates
	 */
	public void AutoscaleY(double min, double max)
	{
		if (type == TYPE_2D && (mode2D == Signal.MODE_IMAGE || mode2D == Signal.MODE_CONTOUR))
		{
			ymin = this.y2D_min;
			ymax = this.y2D_max;
			return;
		}
		float currY[];
		double currX[];
		if (type == TYPE_2D && (mode2D == MODE_XZ || mode2D == MODE_YZ))
		{
			currY = sliceY;
			currX = sliceX;
		}
		else
		{
			currY = y;
			currX = x;
		}
		if (currX == null || currY == null)
			return;
		final int len = (currX.length < currY.length) ? currX.length : currY.length;
		for (int i = 0; i < len; i++)
		{
			if (currX[i] >= min && currX[i] <= xmax)
			{
				ymin = ymax = currY[i];
				break;
			}
		}
		for (int i = 0; i < len; i++)
		{
			if (currX[i] >= min && currX[i] <= max)
			{
				if (currY[i] < ymin)
					ymin = currY[i];
				if (currY[i] > ymax)
					ymax = currY[i];
			}
		}
		/******************************************************************
		 * int len = (x.length < y.length)?x.length:y.length; for(int i = 0; i < len;
		 * i++) { if(x[i] >= min && x[i] <= xmax) { ymin = ymax = y[i]; break; } }
		 * for(int i = 0; i < len; i++) { if(x[i] >= min && x[i] <= max) { if(y[i] <
		 * ymin) ymin = y[i]; if(y[i] > ymax) ymax = y[i]; } }
		 ********************************************************************/
	}

	void checkData(double xMin, double xMax) throws IOException
	{
		int numDimensions;
		try
		{
			numDimensions = data.getNumDimension();
		}
		catch (final Exception exc)
		{
			numDimensions = 1;
		}
		if (numDimensions == 1)
		{
			type = TYPE_1D;
			if (x == null)// Only if data not present
			{
				XYData xyData;
				if (!error)
				{
					if (longXLimits)
						xyData = data.getData(xMinLong, xMaxLong, NUM_POINTS);
					else
						xyData = data.getData(xMin, xMax, NUM_POINTS);
				}
				else
				{
					if (longXLimits)
						xyData = data.getData(xMinLong, xMaxLong, Integer.MAX_VALUE);
					else
						xyData = data.getData(xMin, xMax, Integer.MAX_VALUE);
				}
				if (xyData == null)
					return; // empty signal
				x = xyData.x;
				y = xyData.y;
				adjustArraySizes();
				increasing_x = xyData.increasingX;
				if (longXLimits)
				{
					if (xMin == 0)
						this.xmin = curr_xmin = xyData.xMin;
					else
						this.xmin = curr_xmin = xMin;
					if (xMax == 0)
						this.xmax = curr_xmax = xyData.xMax;
					else
						this.xmax = curr_xmax = xMax;
				}
				else
				{
					if (xMin == -Double.MAX_VALUE)
						this.xmin = curr_xmin = xyData.xMin;
					else
						this.xmin = curr_xmin = xMin;
					if (xMax == Double.MAX_VALUE)
						this.xmax = curr_xmax = xyData.xMax;
					else
						this.xmax = curr_xmax = xMax;
				}
//Autoscale Y, ymin and ymax are possibly changed afterwards
				if (y.length > 0)
				{
					this.ymin = this.ymax = y[0];
					for (final float element : y)
					{
						if (element < this.ymin)
							this.ymin = element;
						if (element > this.ymax)
							this.ymax = element;
					}
					if (data.isXLong())
					{
						xLong = xyData.xLong;
					}
					resolutionManager.addRegion(new RegionDescriptor(xMin, xMax, xyData.resolution));
				}
			}
			if (up_errorData != null && upError == null)
			{
				// XYData xyData = up_errorData.getData(xMin, xMax, NUM_POINTS);
				final XYData xyData = up_errorData.getData(xMin, xMax, Integer.MAX_VALUE);
				upError = xyData.y;
			}
			if (low_errorData != null && lowError == null)
			{
				// XYData xyData = low_errorData.getData(xMin, xMax, NUM_POINTS);
				final XYData xyData = low_errorData.getData(xMin, xMax, Integer.MAX_VALUE);
				lowError = xyData.y;
			}
			if (saved_ymin == -Double.MAX_VALUE)
				saved_ymin = ymin;
			if (saved_ymax == Double.MAX_VALUE)
				saved_ymax = ymax;
		}
		else if (numDimensions == 2)
		{
			type = TYPE_2D;
			x2D = data.getX2D();
			if (x2D == null && data.isXLong())
			{
				x2DLong = data.getX2DLong();
				x2D = new double[x2DLong.length];
				for (int i = 0; i < x2DLong.length; i++)
					x2D[i] = x2DLong[i];
			}
			y2D = data.getY2D();
			z = data.getZ();
			if (x_data != null) // This holds ONLY for bidimensional X axis, used to draw x-Y images over time
			{
				xY2D = x_data.getX2D();
				yY2D = x_data.getY2D();
				zY2D = x_data.getZ();
				if ((xY2D == null || yY2D == null || zY2D == null) || (xY2D != null && yY2D != null && zY2D != null
						&& ((x2D != null && x2D.length != xY2D.length)
								|| (x2DLong != null && x2DLong.length != xY2D.length) && y2D.length != yY2D.length
										&& z.length != zY2D.length)))
				{
					xY2D = null;
					yY2D = null;
					zY2D = null;
					x_data = null;
				}
			}
			double x2DVal[];
			x2DVal = x2D;
			x2D_min = x2D_max = x2DVal[0];
			for (int i = 0; i < x2D.length; i++)
			{
				if (x2DVal[i] < x2D_min)
					x2D_min = x2DVal[i];
				if (x2DVal[i] > x2D_max)
					x2D_max = x2DVal[i];
			}
			if (y2D != null && y2D.length > 0)
			{
				y2D_min = y2D_max = y2D[0];
				for (final float element : y2D)
				{
					if (element < y2D_min)
						y2D_min = element;
					if (element > y2D_max)
						y2D_max = element;
				}
			}
			else
			{
				y2D_min = y2D_max = 0;
			}
			if (z != null && z.length > 0)
			{
				z2D_min = z2D_max = z[0];
				for (final float element : z)
				{
					if (element < z2D_min)
						z2D_min = element;
					if (element > z2D_max)
						z2D_max = element;
				}
			}
			else
			{
				z2D_min = z2D_max = 0;
			}
			if (xMin == -Double.MAX_VALUE)
				this.xmin = curr_xmin = x2D_min;
			else
				this.xmin = curr_xmin = xMin;
			if (xMax == Double.MAX_VALUE)
				this.xmax = curr_xmax = x2D_max;
			else
				this.xmax = curr_xmax = xMax;
		}
		else
		{
			System.out.println("ERROR: UP TO 2 Dimensions supported");
		}
                //Update X and Y labels if not defined
                if(xlabel == null || xlabel.trim().length() == 0)
                    xlabel = data.GetXLabel();
                if(ylabel == null || ylabel.trim().length() == 0)
                    ylabel = data.GetYLabel();
        }

	/**
	 * Check if x array coordinates are increasing.
	 */
	void checkIncreasingX()
	{
		if (type == TYPE_2D)
		{
			checkIncreasingX2D();
			return;
		}
		increasing_x = true;
		for (int i = 1; i < x.length; i++)
		{
			if (x[i] < x[i - 1])
			{
				increasing_x = false;
				return;
			}
		}
	}

	void checkIncreasingX2D()
	{
		increasing_x = true;
		final double x[] = x2D;
		for (int i = 1; i < x.length; i++)
		{
			if (x[i] < x[i - 1])
			{
				increasing_x = false;
				return;
			}
		}
	}

	@Override
	public void dataRegionUpdated(double[] regX, float[] regY, double resolution)
	{
		if (regX == null || regX.length == 0)
			return;
		if (debug)
			System.out.println("dataRegionUpdated " + resolutionManager.lowResRegions.size() + " new data len:"
					+ regX.length + " XMIN:" + regX[0] + "  XMAX: " + regX[regX.length - 1]);
		if (freezeMode != NOT_FREEZED) // If zooming in ANY part of the signal
		{
			pendingUpdatesV.addElement(new XYData(regX, regY, resolution, true, regX[0], regX[regX.length - 1]));
			return;
		}
		int samplesBefore, samplesAfter;
		// if(regX.length == 0) return;
		if (x == null)
			x = new double[0];
		if (y == null)
			y = new float[0];
		for (samplesBefore = 0; samplesBefore < x.length && x[samplesBefore] < regX[0]; samplesBefore++);
		if (samplesBefore > 0 && samplesBefore < x.length && x[samplesBefore] > regX[0])
			samplesBefore--;
		for (samplesAfter = 0; samplesAfter < x.length - 1
				&& x[x.length - samplesAfter - 1] > regX[regX.length - 1]; samplesAfter++);
		final double[] newX = new double[samplesBefore + regX.length + samplesAfter];
		final float[] newY = new float[samplesBefore + regX.length + samplesAfter];
		for (int i = 0; i < samplesBefore; i++)
		{
			newX[i] = x[i];
			newY[i] = y[i];
		}
		for (int i = 0; i < regX.length; i++)
		{
			newX[samplesBefore + i] = regX[i];
			newY[samplesBefore + i] = regY[i];
		}
		for (int i = 0; i < samplesAfter; i++)
		{
			newX[newX.length - i - 1] = x[x.length - i - 1];
			newY[newX.length - i - 1] = y[x.length - i - 1];
		}
		if (x.length == 0 || regX[0] >= x[x.length - 1]) // Data are being appended
		{
			resolutionManager.appendRegion(new RegionDescriptor(regX[0], regX[regX.length - 1], resolution));
			if (xmax < newX[newX.length - 1])
				xmax = newX[newX.length - 1];
			x = newX;
			y = newY;
			fireSignalUpdated(true);
		}
		else
		{
			resolutionManager.addRegion(new RegionDescriptor(regX[0], regX[regX.length - 1], resolution));
			x = newX;
			y = newY;
			fireSignalUpdated(false);
		}
	}

	@Override
	public void dataRegionUpdated(long[] regX, float[] regY, double resolution)
	{
		if (regX == null || regX.length == 0)
			return;
		if (debug)
			System.out.println("dataRegionUpdated " + resolutionManager.lowResRegions.size());
		if (freezeMode == FREEZED_BLOCK) // If zooming in some inner part of the signal
		{
			pendingUpdatesV.addElement(new XYData(regX, regY, resolution, true));
			return;
		}
		/*
		 * if(freezeMode == FREEZED_SCROLL) //If zooming the end of the signal do the
		 * update keeing the width of the zoomed region { double delta =
		 * regX[regX.length - 1] - regX[0]; xmin += delta; xmax += delta; }
		 */
		if (freezeMode == FREEZED_SCROLL) // If zooming the end of the signal do the update keeing the width of the
											// zoomed region
		{
			final double delta = xmax - xmin;
			xmax = regX[regX.length - 1];
			xmin = xmax - delta;
		}
		if (xLong == null) // First data chunk
		{
			resolutionManager.appendRegion(new RegionDescriptor(regX[0], regX[regX.length - 1], resolution));
			xmin = regX[0];
			xmax = regX[regX.length - 1];
			xLong = regX;
			x = new double[regX.length];
			for (int i = 0; i < regX.length; i++)
				x[i] = regX[i];
			y = regY;
			fireSignalUpdated(true);
		}
		else // Data Appended
		{
			int samplesBefore, samplesAfter;
			for (samplesBefore = 0; samplesBefore < xLong.length && xLong[samplesBefore] < regX[0]; samplesBefore++);
//            for(samplesBefore = 0; samplesBefore < xLong.length - 1 && xLong[samplesBefore] < regX[0]; samplesBefore++);
			if (samplesBefore > 0 && samplesBefore < xLong.length && xLong[samplesBefore] > regX[0])
				samplesBefore--;
			for (samplesAfter = 0; samplesAfter < xLong.length - 1
					&& xLong[xLong.length - samplesAfter - 1] > regX[regX.length - 1]; samplesAfter++);
			if (samplesAfter > 0 && xLong.length - samplesAfter - 1 >= 0
					&& xLong[xLong.length - samplesAfter - 1] < regX[regX.length - 1])
				samplesAfter--;
			if (samplesBefore > x.length)
				samplesBefore = x.length;
			if (samplesBefore > y.length)
				samplesBefore = y.length;
			final double[] newX = new double[samplesBefore + regX.length + samplesAfter];
			final long[] newXLong = new long[samplesBefore + regX.length + samplesAfter];
			final float[] newY = new float[samplesBefore + regX.length + samplesAfter];
			for (int i = 0; i < samplesBefore; i++)
			{
				newX[i] = x[i];
				newXLong[i] = xLong[i];
				newY[i] = y[i];
			}
			for (int i = 0; i < regX.length; i++)
			{
				newX[samplesBefore + i] = regX[i];
				newXLong[samplesBefore + i] = regX[i];
				newY[samplesBefore + i] = regY[i];
			}
			for (int i = 0; i < samplesAfter; i++)
			{
				newXLong[newX.length - i - 1] = xLong[x.length - i - 1];
				newX[newX.length - i - 1] = x[x.length - i - 1];
				newY[newX.length - i - 1] = y[x.length - i - 1];
			}
			if (regX[0] >= xLong[xLong.length - 1]) // Data are being appended
			{
				final double delta = newX[newX.length - 1] - xmax;
				resolutionManager.appendRegion(new RegionDescriptor(regX[0], regX[regX.length - 1], resolution));
				if (freezeMode == FREEZED_SCROLL)
				{
					xmax += delta;
					xmin += delta;
				}
				else if (freezeMode == NOT_FREEZED)
					xmax = newX[newX.length - 1];
				x = newX;
				xLong = newXLong;
				y = newY;
				fireSignalUpdated(true);
			}
			else
			{
				resolutionManager.addRegion(new RegionDescriptor(regX[0], regX[regX.length - 1], resolution));
				x = newX;
				xLong = newXLong;
				y = newY;
				fireSignalUpdated(false);
			}
		}
	}

	public void decShow()
	{
		if (type == TYPE_2D)
		{
			switch (mode2D)
			{
			case Signal.MODE_XZ:
				decShowXZ();
				break;
			case Signal.MODE_YZ:
				decShowYZ();
				break;
			case Signal.MODE_PROFILE:
				// decShowProfile();
				break;
			}
		}
	}

	public void decShowXZ()
	{
		if (type == TYPE_2D && mode2D == Signal.MODE_XZ)
		{
			int idx = curr_y_xz_idx - 1;
			if (idx < 0)
				idx = y2D.length - 1;
			showXZ(idx);
		}
	}

	public void decShowYZ()
	{
		if (type == TYPE_2D && mode2D == Signal.MODE_YZ)
		{
			int idx = curr_x_yz_idx - 1;
			if (idx < 0)
				idx = x2D.length - 1;
			showYZ(idx);
		}
	}

	void dispose()
	{
		if (data != null)
			data.removeWaveDataListener(this);
	}

	public int FindClosestIdx(double curr_x, double curr_y)
	{
		double min_dist, curr_dist;
		int min_idx;
		int i = 0;
		if (this.type == Signal.TYPE_2D && (mode2D == Signal.MODE_IMAGE || mode2D == Signal.MODE_CONTOUR))
		{
			img_xprev = FindIndex(x2D, curr_x, img_xprev);
			img_yprev = FindIndex(y2D, curr_y, img_yprev);
			if (img_xprev > y2D.length)
				return img_xprev - 6;
			return img_xprev;
		}
		double currX[];
		if (type == Signal.TYPE_1D)
			currX = x;
		else
		{
			if (mode2D == MODE_XZ || mode2D == MODE_YZ)
				currX = sliceX;
			else
			{
				final double xf[] = x2D;
				currX = new double[xf.length];
				for (int idx = 0; idx < xf.length; idx++)
					currX[idx] = xf[idx];
			}
		}
		if (increasing_x || type == Signal.TYPE_2D)
		{
			if (currX == null || currX.length == 0)
				return -1;
			if (prev_idx >= currX.length)
				prev_idx = currX.length - 1;
			if (curr_x > currX[prev_idx])
			{
				for (i = prev_idx; i < currX.length && currX[i] < curr_x; i++);
				if (i > 0)
					i--;
				prev_idx = i;
				return i;
			}
			if (curr_x < currX[prev_idx])
			{
				for (i = prev_idx; i > 0 && currX[i] > curr_x; i--);
				prev_idx = i;
				return i;
			}
			return prev_idx;
		}
		// Handle below x values not in ascending order
		if (curr_x > curr_xmax)
		{
			for (min_idx = 0; min_idx < currX.length && currX[min_idx] != curr_xmax; min_idx++);
			if (min_idx == currX.length)
				min_idx--;
			return min_idx;
		}
		if (curr_x < curr_xmin)
		{
			for (min_idx = 0; min_idx < currX.length && currX[min_idx] != curr_xmin; min_idx++);
			if (min_idx == currX.length)
				min_idx--;
			return min_idx;
		}
		min_idx = 0;
		min_dist = Double.MAX_VALUE;
		find_NaN = false;
		for (i = 0; i < x.length - 1; i++)
		{
			if (Float.isNaN(y[i]))
			{
				find_NaN = true;
				continue;
			}
			if (curr_x > currX[i] && curr_x < currX[i + 1] || curr_x < currX[i] && curr_x > currX[i + 1]
					|| currX[i] == currX[i + 1])
			{
				curr_dist = (curr_x - currX[i]) * (curr_x - currX[i]) + (curr_y - y[i]) * (curr_y - y[i]);
				// Patch to elaborate strange RFX signal (roprand bar error signal)
				if (currX[i] != currX[i + 1] && !Float.isNaN(y[i + 1]))
					curr_dist += (curr_x - currX[i + 1]) * (curr_x - currX[i + 1])
							+ (curr_y - y[i + 1]) * (curr_y - y[i + 1]);
				if (curr_dist < min_dist)
				{
					min_dist = curr_dist;
					min_idx = i;
				}
			}
		}
		return min_idx;
	}

	private int findIndex(double d[], double v, int pIdx)
	{
		int i;
		if (v > d[pIdx])
		{
			for (i = pIdx; i < d.length && d[i] < v; i++)
			{}
			if (i > 0)
			{
				i--;
			}
			return i;
		}
		if (v < d[pIdx])
		{
			for (i = pIdx; i > 0 && d[i] > v; i--)
			{}
			return i;
		}
		return pIdx;
	}

	private int findIndex(float d[], double v, int pIdx)
	{
		final double[] o = new double[d.length];
		for (int i = 0; i < d.length; i++)
		{
			o[i] = d[i];
		}
		return findIndex(o, v, pIdx);
	}

	private int FindIndex(double d[], double v, int pIdx)
	{
		int i;
		if (v > d[pIdx])
		{
			for (i = pIdx; i < d.length && d[i] < v; i++);
			if (i > 0)
				i--;
			return i;
		}
		if (v < d[pIdx])
		{
			for (i = pIdx; i > 0 && d[i] > v; i--);
			return i;
		}
		return pIdx;
	}

	private int FindIndex(float d[], double v, int pIdx)
	{
		final double[] o = new double[d.length];
		for (int i = 0; i < d.length; i++)
		{
			o[i] = d[i];
		}
		return FindIndex(o, v, pIdx);
	}

	public boolean findNaN()
	{
		return find_NaN;
	}

	void fireSignalUpdated(boolean changeLimits)
	{
		if (debug)
			System.out.println("FIRE SIGNAL UPDATE " + signalListeners.size());
		for (int i = 0; i < signalListeners.size(); i++)
			signalListeners.elementAt(i).signalUpdated(changeLimits);
	}

	void freeze()
	{
		if (isLongX() && xmax > xLong[xLong.length - 1])
			freezeMode = FREEZED_SCROLL;
		else
			freezeMode = FREEZED_BLOCK;
		freezedXMin = xmin;
		freezedXMax = xmax;
	}

	public boolean fullPaint()
	{
		return true;
	}

	private int getArrayIndex(double arr[], double d)
	{
		int i = -1;
		if (i == -1)
		{
			for (i = 0; i < arr.length - 1; i++)
			{
				if ((d > arr[i] && d < arr[i + 1]) || d == arr[i])
					break;
			}
		}
		return i;
	}

	private int getArrayIndex(float arr[], double d)
	{
		int i = -1;
		if (i == -1)
		{
			for (i = 0; i < arr.length - 1; i++)
			{
				if ((d > arr[i] && d < arr[i + 1]) || d == arr[i])
					break;
			}
		}
		return i;
	}

	public float getClosestX(double x)
	{
		if (this.type == Signal.TYPE_2D && (mode2D == Signal.MODE_IMAGE || mode2D == Signal.MODE_CONTOUR))
		{
			img_xprev = FindIndex(x2D, x, img_xprev);
			return (float) x2D[img_xprev];
		}
		return 0;
	}

	public float getClosestY(double y)
	{
		if (this.type == Signal.TYPE_2D && (mode2D == Signal.MODE_IMAGE || mode2D == Signal.MODE_CONTOUR))
		{
			img_yprev = FindIndex(y2D, y, img_yprev);
			return y2D[img_yprev];
		}
		return 0;
	}

	/**
	 * Get color.
	 *
	 * @return Color the color
	 */
	public Color getColor()
	{ return color; }

	/**
	 * Get color index.
	 *
	 * @return Color index
	 */
	public int getColorIdx()
	{ return color_idx; }

	Vector getContourLevelValues()
	{ return contourLevelValues; }

	Vector>> getContourSignals()
	{ return contourSignals; }

	public double getCurrentXmax()
	{ return curr_xmax; }

	public double getCurrentXmin()
	{ return curr_xmin; }

	int getFreezeMode()
	{ return freezeMode; }

	/**
	 * Get gain parameter.
	 */
	public float getGain()
	{ return gain; }

	/**
	 * Get interpolate flag
	 *
	 * @return Interpolate flag
	 */
	public boolean getInterpolate()
	{ return interpolate; }

	public String getLegend()
	{ return legend; }

	public float[] getLowError()
	{ return lowError; }

	/**
	 * Get marker type.
	 *
	 * @return marker type
	 */
	public int getMarker()
	{ return marker; }

	/**
	 * Get marker step.
	 *
	 * @return marker step
	 */
	public int getMarkerStep()
	{
		if (marker == POINT)
			return 1;
		return marker_step;
	}

	public int getMode1D()
	{ return mode1D; }

	public int getMode2D()
	{ return mode2D; }

	/**
	 * Get signal name.
	 *
	 * @return Signal name
	 */
	public String getName()
	{ return name; }

	public int[] getNaNs()
	{ return nans; }

	public int getNumNaNs()
	{ return n_nans; }

	public int getNumPoints()
	{
		if (this.type == Signal.TYPE_2D && (mode2D == Signal.MODE_YZ || mode2D == Signal.MODE_XZ) && sliceX != null)
			return sliceX.length;
		if (data != null)
		{
			try
			{
				return (x.length < y.length) ? x.length : y.length;
			}
			catch (final Exception exc)
			{}
		}
		return 0;
	}

	/**
	 * Get offset parameter
	 */
	public float getOffset()
	{ return offset; }

	public double getOriginalYmax()
	{ return saved_ymax; }

	public double getOriginalYmin()
	{ return saved_ymin; }

	public String getStringOfXinYZplot()
	{
		if (this.isLongX())
			return toStringTime((long) curr_x_yz_plot);
		else
			return "" + curr_x_yz_plot;
	}

	public String getTitlelabel()
	{ return title; }

	public int getType()
	{ return type; }

	public int getUpdSignalSizeInc()
	{ return updSignalSizeInc; }

	public float[] getUpError()
	{ return upError; }

	public double[] getX() throws IOException
	{
		if (type == TYPE_2D && (mode2D == MODE_XZ || mode2D == MODE_YZ))
			return sliceX;
		return x;
	}

	public double getX(int idx)
	{
		try
		{
			if (this.type == Signal.TYPE_2D && (mode2D == Signal.MODE_YZ || mode2D == Signal.MODE_XZ))
				return sliceX[idx];
			return x[idx];
		}
		catch (final Exception exc)
		{
			return 0;
		}
	}

	public double[] getX2D()
	{
		if (x2D == null)
			x2D = data.getX2D();
		return x2D;
	}

	public double getX2Dmax()
	{ return x2D_max; }

	public double getX2Dmin()
	{ return x2D_min; }

	public double getXinYZplot()
	{ return curr_x_yz_plot; }

	public String getXlabel()
	{ return xlabel; }

	public double getXmax()
	{
		// if(!xLimitsInitialized)
		// return -Double.MAX_VALUE;
		return xmax;
	}

	public double getXmin()
	{
		// if(!xLimitsInitialized)
		// return Double.MAX_VALUE;
		return xmin;
	}

	public float[] getY() throws IOException
	{
		if (type == TYPE_2D && (mode2D == MODE_XZ || mode2D == MODE_YZ))
			return sliceY;
		return y;
	}

	public float getY(int idx)
	{
		try
		{
			if (this.type == Signal.TYPE_2D && (mode2D == Signal.MODE_YZ || mode2D == Signal.MODE_XZ))
				return sliceY[idx];
			return y[idx];
		}
		catch (final Exception exc)
		{
			return 0;
		}
	}

	public float[] getY2D()
	{
		if (y2D == null)
			y2D = data.getY2D();
		return y2D;
	}

	public double getY2Dmax()
	{ return y2D_max; }

	public double getY2Dmin()
	{ return y2D_min; }

	public float getYinXZplot()
	{ return curr_y_xz_plot; }

	public String getYlabel()
	{ return ylabel; }

	public double getYmax()
	{ return ymax; }

	public double getYmin()
	{ return ymin; }

	public float[] getZ()
	{
		if (z == null)
			z = data.getZ();
		return z;
	}

	public float getZ(int idx)
	{
		if (z == null)
			z = data.getZ();
		return z[idx];
	}

	public float[][] getZ2D()
	{
		final float zOut[][] = new float[x2D.length][y2D.length];
		int k;
		for (int i = 0; i < x2D.length; i++)
		{
			for (int j = 0; j < y2D.length; j++)
			{
				k = j * x2D.length + i;
				if (k < z.length)
					zOut[i][j] = z[k];
			}
		}
		return zOut;
	}

	public double getZ2Dmax()
	{ return z2D_max; }

	public double getZ2Dmin()
	{ return z2D_min; }

	public String getZlabel()
	{ return zlabel; }

	public double getZValue()
	{
		if (this.type == Signal.TYPE_2D)
		{
			switch (mode2D)
			{
			case Signal.MODE_IMAGE:
				final float y[] = y2D;
				final int idx = img_xprev * y.length + img_yprev;
				if (z != null && idx < z.length)
				{
					return z[idx];
				}
			case Signal.MODE_CONTOUR:
				return z_value;
			}
		}
		return Float.NaN;
	}

	boolean hasAsymError()
	{
		return asym_error;
	}

	boolean hasError()
	{
		return error;
	}

	public final boolean hasX()
	{
		return true;
		// return data.hasX();
	}

	public void incShow()
	{
		if (type == TYPE_2D)
		{
			switch (mode2D)
			{
			case Signal.MODE_XZ:
				incShowXZ();
				break;
			case Signal.MODE_YZ:
				incShowYZ();
				break;
			case Signal.MODE_PROFILE:
				// incShowProfile();
				break;
			}
		}
	}

	public void incShowXZ()
	{
		if (type == TYPE_2D && mode2D == Signal.MODE_XZ)
			showXZ((curr_y_xz_idx + 1) % y2D.length);
	}

	public void incShowYZ()
	{
		if (type == TYPE_2D && mode2D == Signal.MODE_YZ)
			showYZ((curr_x_yz_idx + 1) % x2D.length);
	}

	public void initContour()
	{
		saved_ymin = ymin = y2D_min;
		saved_ymax = ymax = y2D_max;
		saved_xmin = xmin = x2D_min;
		saved_xmax = xmax = x2D_max;
		// x = x2D;
		// y = y2D;
		cs = new ContourSignal(this);
		if (contourLevels == null || contourLevels.length == 0)
		{
			contourLevels = new double[DEFAULT_CONTOUR_LEVEL];
			final double dz = (z2D_max - z2D_min) / (DEFAULT_CONTOUR_LEVEL + 1);
			for (int i = 0; i < contourLevels.length; i++)
			{
				contourLevels[i] = z2D_min + dz * (i + 1);
			}
		}
		for (final double contourLevel : contourLevels)
		{
			addContourLevel(contourLevel);
		}
	}

	public boolean isFullLoad()
	{ return full_load; }

	final public boolean isIncreasingX()
	{ return increasing_x; }

	public boolean isLongX()
	{
		if (type == TYPE_1D || type == TYPE_2D && (mode2D == Signal.MODE_XZ || mode2D == Signal.MODE_IMAGE))
		{
			// return data.isXLong(); //Gabriele Dec 2015
			return xLong != null;
		}
		else
			return false;
	}

	public boolean isLongXForLabel()
	{
		if (type == TYPE_1D || type == TYPE_2D
				&& (mode2D == Signal.MODE_XZ || mode2D == Signal.MODE_YZ || mode2D == Signal.MODE_IMAGE))
			return data.isXLong();
		else
			return false;
	}

	@Override
	public void legendUpdated(String name)
	{
		setLegend(name);
	}

	// reset all region info building a single region with
	// resolution=NUM_POINTS/(xmax - xmin)
	public void mergeRegions()
	{
		if (x == null || x.length < 1)
			return;
		final double currXMin = x[0];
		final double currXMax = x[x.length - 1];
		final double currResolution = 3 * NUM_POINTS / (currXMax - currXMin);
		final double currDelta = (currXMax - currXMin) / (3 * NUM_POINTS);
		int newPoints = 0;
		double currX = currXMin - currDelta / 2;
		int currIdx = 0;
		int currOutIdx = 0;
		float currYMin = Float.MAX_VALUE;
		float currYMax = -Float.MAX_VALUE;
		while (currX <= currXMax + currDelta / 2)
		{
			while (currOutIdx < x.length && x[currOutIdx] < currX)
			{
				if (y[currOutIdx] < currYMin)
					currYMin = y[currOutIdx];
				if (y[currOutIdx] > currYMax)
					currYMax = y[currOutIdx];
				currOutIdx++;
			}
			if (currOutIdx == x.length)
				break;
			if (currYMin == currYMax)
			{
				newPoints++;
			}
			else if (currYMin != Float.MAX_VALUE)
			{
				newPoints += 2;
			}
			currIdx++;
			currX = currXMin - currDelta / 2 + currIdx * currDelta;
			currYMin = Float.MAX_VALUE;
			currYMax = -Float.MAX_VALUE;
		}
		final double[] newX = new double[newPoints];
		final float[] newY = new float[newPoints];
		currX = currXMin - currDelta / 2;
		currIdx = currOutIdx = newPoints = 0;
		currYMin = Float.MAX_VALUE;
		currYMax = -Float.MAX_VALUE;
		while (currX <= currXMax + currDelta / 2)
		{
			while (currOutIdx < x.length && x[currOutIdx] < currX)
			{
				if (y[currOutIdx] < currYMin)
					currYMin = y[currOutIdx];
				if (y[currOutIdx] > currYMax)
					currYMax = y[currOutIdx];
				currOutIdx++;
			}
			if (currOutIdx == x.length)
				break;
			if (currYMin == currYMax)
			{
				newX[newPoints] = x[(currOutIdx == 0) ? currOutIdx : currOutIdx - 1];
				newY[newPoints] = currYMin;
				newPoints++;
			}
			else if (currYMin != Float.MAX_VALUE)
			{
				newX[newPoints] = x[(currOutIdx == 0) ? currOutIdx : currOutIdx - 1];
				newY[newPoints] = currYMin;
				newPoints++;
				newX[newPoints] = x[(currOutIdx == 0) ? currOutIdx : currOutIdx - 1];
				newY[newPoints] = currYMax;
				newPoints++;
			}
			currIdx++;
			currX = currXMin - currDelta / 2 + currIdx * currDelta;
			currYMin = Float.MAX_VALUE;
			currYMax = -Float.MAX_VALUE;
		}
		x = newX;
		y = newY;
		resolutionManager.resetRegions();
		resolutionManager.appendRegion(new RegionDescriptor(currXMin, currXMax, currResolution));
	}

	void registerSignalListener(SignalListener listener)
	{
		signalListeners.addElement(listener);
	}

	/**
	 * Reset scale, return to the initial two dimensional region
	 */
	public void ResetScales()
	{
		xmax = freezedXMax = curr_xmax = saved_xmax;
		xmin = freezedXMin = curr_xmin = saved_xmin;
		ymax = saved_ymax;
		ymin = saved_ymin;
		unfreeze();
	}

	public void resetSignalData()
	{
		x2D_points = 0;
		y2D_points = 0;
		z2D_points = 0;
		final double x[] = new double[]
		{ 0., 1. };
		final float y[] = new float[]
		{ 0, 0 };
		data = new XYWaveData(x, y);
		this.low_errorData = null;
		this.up_errorData = null;
		startIndexToUpdate = 0;
	}

	/**
	 * Reset x scale, return to original x range two dimensional region
	 */
	public void ResetXScale()
	{
		xmax = freezedXMax = curr_xmax = saved_xmax;
		xmin = freezedXMin = curr_xmin = saved_xmin;
	}

	/**
	 * Reset x scale, return to the initial y range two dimensional region
	 */
	public void ResetYScale()
	{
		ymax = saved_ymax;
		ymin = saved_ymin;
	}

	public void setAttributes(Signal s)
	{
		this.color = s.getColor();
		this.color_idx = s.getColorIdx();
		this.gain = s.getGain();
		this.interpolate = s.getInterpolate();
		this.marker = s.getMarker();
		this.marker_step = s.getMarkerStep();
		this.offset = s.getOffset();
		this.name = s.getName();
	}

	/**
	 * Sets all signal attributes.
	 *
	 * @param name        signal name
	 * @param color_idx   color index from an external color table
	 * @param marker      marker type
	 * @param marker_step marker step
	 * @param interpolate interpolate flag
	 */
	public void setAttributes(String name, int color_idx, int marker, int marker_step, boolean interpolate)
	{
		this.marker = marker;
		this.marker_step = marker_step;
		this.interpolate = interpolate;
		this.color_idx = color_idx;
		this.name = new String(name);
	}

	void setAxis()
	{
		int i;
		// If the signal dimension is 2 or the x axis are not increasing, the signal is
		// assumed to be completely in memory
		// and no further readout from data is performed
		if (type != TYPE_1D || !increasing_x)
			return;
		// Check if the signal is fully available (i.e. has already been read without X
		// limits)
		if (!resolutionManager.isEmpty())
		{
			final double minMax[] = resolutionManager.getMinMaxX();
			if (minMax[0] == -Double.MAX_VALUE && minMax[1] == Double.MAX_VALUE)
			{
				xLimitsInitialized = true;
				xmin = x[0];
				xmax = x[x.length - 1];
				return;
			}
		}
		// resolutionManager.resetRegions();
		try
		{
			final XYData xyData = data.getData(NUM_POINTS);
			if (xyData == null)
				return;
			x = xyData.x;
			y = xyData.y;
			if (x == null || x.length == 0)
				return;
			adjustArraySizes();
			increasing_x = xyData.increasingX;
			if (increasing_x)
			{
				resolutionManager.addRegion(new RegionDescriptor(-Double.MAX_VALUE, Double.MAX_VALUE,
						NUM_POINTS / (x[x.length - 1] - x[0])));
			}
			if (data.isXLong())
				xLong = xyData.xLong;
			xmax = xyData.xMax;
			xmin = xyData.xMin;
			ymax = ymin = y[0];
			for (i = 0; i < x.length; i++)
			{
				if (Float.isNaN(y[i]) && n_nans < 100)
					nans[n_nans++] = i;
				if (y[i] > ymax)
					ymax = y[i];
				if (ymin > y[i])
					ymin = y[i];
			}
			curr_xmin = xmin;
			curr_xmax = xmax;
		}
		catch (final Exception exc)
		{
			System.out.println("Set Axis Exception: " + exc);
		}
	}

	void setAxis(double x2D[], float z2D[], float y2D[])
	{
		x2D_max = x2D_min = x2D[0];
		z2D_max = z2D_min = z2D[0];
		y2D_max = y2D_min = y2D[0];
		setAxis(x2D, z2D, y2D, 0, 0, 0);
	}

	void setAxis(double x2D[], float z2D[], float y2D[], int xIdx, int zIdx, int yIdx)
	{
		int i;
		for (i = xIdx; i < x2D.length; i++)
		{
			if (x2D[i] > x2D_max)
				x2D_max = x2D[i];
			if (x2D_min > x2D[i])
				x2D_min = x2D[i];
		}
		for (i = zIdx; i < z2D.length; i++)
		{
			if (z2D[i] > z2D_max)
				z2D_max = z2D[i];
			if (z2D_min > z2D[i])
				z2D_min = z2D[i];
		}
		for (i = yIdx; i < y2D.length; i++)
		{
			if (y2D[i] > y2D_max)
				y2D_max = y2D[i];
			if (y2D_min > y2D[i])
				y2D_min = y2D[i];
		}
	}

	public void setCalibrate(float gain, float offset)
	{
		this.gain = gain;
		this.offset = offset;
		setAxis();
	}

	/**
	 * Set color value
	 *
	 * @param color color value
	 */
	public void setColor(Color color)
	{ this.color = color; }

	/**
	 * Set color index. Index color is a reference to an external color palette
	 *
	 * @param color_idx index of the color
	 */
	public void setColorIdx(int color_idx)
	{
		color = null;
		this.color_idx = color_idx;
	}

	void setFreezeMode(int freezeMode)
	{ this.freezeMode = freezeMode; }

	public void setFullLoad(boolean full_load)
	{ this.full_load = full_load; }

	/**
	 * Set interpolate flag.
	 *
	 * @param interpolate define if is a point or line signal
	 */
	public void setInterpolate(boolean interpolate)
	{ this.interpolate = interpolate; }

	public void setLabels(String title, String xlabel, String ylabel, String zlabel)
	{
		this.title = title;
		this.xlabel = xlabel;
		this.ylabel = ylabel;
		this.zlabel = zlabel;
	}

	public void setLegend(String legend)
	{ this.legend = legend; }

	/**
	 * Set market type.
	 *
	 * @param marker marker type
	 */
	public void setMarker(int marker)
	{ this.marker = marker; }

	/**
	 * Set market type by name.
	 *
	 * @param marker marker type name
	 */
	public void setMarker(String name)
	{
		if (name == null)
			return;
		for (int i = 0; i < markerList.length; i++)
			if (name.toLowerCase().equals(markerList[i].toLowerCase()))
			{
				setMarker(i);
				return;
			}
		setMarker(0);
	}

	/**
	 * Set marker step.
	 *
	 * @param marker_step number of signal points between two marker
	 */
	public void setMarkerStep(int marker_step)
	{ this.marker_step = marker_step; }

	public void setMode1D(int mode)
	{
		this.mode1D = mode;
		switch (mode)
		{
		case MODE_LINE:
			this.interpolate = true;
			break;
		case MODE_NOLINE:
			this.interpolate = false;
			break;
		case MODE_STEP:
			this.interpolate = true;
			break;
		}
	}

	public void setMode2D(int mode)
	{
		if (this.type == Signal.TYPE_1D)
			return;
		switch (mode)
		{
		case MODE_IMAGE:
			setMode2D(mode, 0);
			break;
		case MODE_XZ:
			if (y2D != null && y2D.length > 0)
				setMode2D(mode, y2D[0]);
			break;
		case MODE_YZ:
			double v = x2D[0];
			if (!Double.isNaN(curr_x_yz_plot))
				v = curr_x_yz_plot;
			setMode2D(mode, v);
			break;
		case MODE_CONTOUR:
			setMode2D(mode, 0);
			break;
		case MODE_PROFILE:
			/*
			 * if(z2D != null && z2D.length > 0) { float v1 = z2D[0]; if
			 * (!Float.isNaN(curr_x_yz_plot)) v1 = curr_x_yz_plot; setMode2D(mode, v1); }
			 */
			break;
		}
	}

	public void setMode2D(int mode, double value)
	{
		if (this.type == Signal.TYPE_1D)
			return;
		curr_x_yz_plot = Float.NaN;
		curr_y_xz_plot = Float.NaN;
		curr_x_yz_idx = -1;
		curr_y_xz_idx = -1;
		switch (mode)
		{
		case MODE_IMAGE:
			/*
			 * saved_ymin = ymin = y2D_min; saved_ymax = ymax = y2D_max; saved_xmin = xmin =
			 * x2D_min; saved_xmax = xmax = x2D_max;
			 */
			if (saved_ymin == -Double.MAX_VALUE)
				saved_ymin = ymin = y2D_min;
			else
				ymin = saved_ymin;
			if (saved_ymax == Double.MAX_VALUE)
				saved_ymax = ymax = y2D_max;
			else
				ymax = saved_ymax;
			if (saved_xmin == -Double.MAX_VALUE)
				saved_xmin = xmin = x2D_min;
			else
				xmin = saved_xmin;
			if (saved_xmax == Double.MAX_VALUE)
				saved_xmax = xmax = x2D_max;
			else
				xmax = saved_xmax;
			break;
		case MODE_XZ:
			showXZ((float) value);
			break;
		case MODE_YZ:
			prev_idx = 0;
			showYZ((float) value);
			break;
		case MODE_CONTOUR:
			initContour();
			break;
		case MODE_PROFILE:
			/*
			 * prev_idx = 0; showProfile(mode, value);
			 */
			break;
		}
		this.mode2D = mode;
	}

	/**
	 * Set Signal name.
	 *
	 * @param name signal name
	 */
	public void setName(String name)
	{
		if (name != null && name.length() != 0)
			this.name = new String(name);
	}

	public void setStartIndexToUpdate()
	{
		if (x != null)
			startIndexToUpdate = x.length;
	}

	public void setType(int type)
	{ this.type = type; }

	public void setUpdSignalSizeInc(int updSignalSizeInc)
	{
		if (updSignalSizeInc <= 0)
			updSignalSizeInc = DEFAULT_INC_SIZE;
		this.updSignalSizeInc = updSignalSizeInc;
	}

	public void setXinYZplot(float curr_x_yz_plot)
	{ this.curr_x_yz_plot = curr_x_yz_plot; }

	public void setXLimits(double xmin, double xmax, int mode)
	{
 		if(xLimitsInitialized && prevSetXMin == xmin && prevSetXMax == xmax)
                {
                    return;
                }
                xLimitsInitialized = true;
                prevSetXMin = xmin;
                prevSetXMax = xmax;
                
		if (xmin != -Double.MAX_VALUE)
		{
			this.xmin = xmin;
			if ((mode & AT_CREATION) != 0)
			{
				saved_xmin = xmin;
			}
			if ((mode & FIXED_LIMIT) != 0)
				fix_xmin = true;
		}
		if (xmax != Double.MAX_VALUE)
		{
			this.xmax = xmax;
			if ((mode & AT_CREATION) != 0)
				this.saved_xmax = xmax;
			if ((mode & FIXED_LIMIT) != 0)
				fix_xmax = true;
		}
		double actXMin = xmin;
		if (actXMin == -Double.MAX_VALUE)
			actXMin = this.xmin;
		double actXMax = xmax;
		if (actXMax == Double.MAX_VALUE)
			actXMax = this.xmax;
		/* Enlarge by 1/20 */
//        double enlargeFactor = 40;
		final double enlargeFactor = 3;
		actXMax += (actXMax - actXMin) / enlargeFactor;
		actXMin -= (actXMax - actXMin) / enlargeFactor;
		final double actResolution = NUM_POINTS / (actXMax - actXMin);
		if (!increasing_x)
			return; // Dynamic resampling only for "classical" signas
		if (up_errorData != null || low_errorData != null)
			return; // Dynamic resampling only without error bars
		final Vector lowResRegions = resolutionManager.getLowerResRegions(actXMin, actXMax,
				actResolution);
		for (int i = 0; i < lowResRegions.size(); i++)
		{
			final RegionDescriptor currReg = lowResRegions.elementAt(i);
			final double currLower = currReg.lowerBound;
			double currUpper = currReg.upperBound;
			// Try to merge adjacent regions
			while (i < lowResRegions.size() - 1 && lowResRegions.elementAt(i + 1).lowerBound <= currUpper)
			{
				currUpper = lowResRegions.elementAt(i + 1).upperBound;
				i++;
			}
			if (((mode & DO_NOT_UPDATE) == 0)
					&& (currLower != saved_xmin || currUpper != saved_xmax || (mode & AT_CREATION) == 0))
                        {
				data.getDataAsync(currLower, currUpper, NUM_POINTS);
                        }
		}
		// fireSignalUpdated();
	}

	public void setYinXZplot(float curr_y_xz_plot)
	{ this.curr_y_xz_plot = curr_y_xz_plot; }

	/**
	 * Set y minimum and maximum of two-dimensional region.
	 *
	 * @param ymin y minimum
	 * @param ymax y maximum
	 */
	public void setYlimits(double ymin, double ymax)
	{
		if (ymax != Double.MAX_VALUE)
		{
			this.ymax = ymax;
			// this.ymax = saved_ymax = ymax;
			this.fix_ymax = true;
		}
		else
			this.fix_ymax = false;
		if (ymin != -Double.MAX_VALUE)
		{
//            this.ymin = saved_ymin = ymin;
			this.ymin = ymin;
			this.fix_ymin = true;
		}
		else
			this.fix_ymin = false;
	}

	public void setYmax(double ymax, int mode)
	{
		if (ymax == Double.MAX_VALUE)
			return;
		this.ymax = ymax;
		if ((mode & AT_CREATION) != 0)
			this.saved_ymax = ymax;
		if ((mode & FIXED_LIMIT) != 0)
			fix_ymax = true;
	}

	public void setYmin(double ymin, int mode)
	{
		if (ymin == -Double.MAX_VALUE)
			return;
		this.ymin = ymin;
		if ((mode & AT_CREATION) != 0)
			this.saved_ymin = ymin;
		if ((mode & FIXED_LIMIT) != 0)
			fix_ymin = true;
	}

	public void showXZ(double xd)
	{
		if (curr_y_xz_plot == xd)
			return;
		final int i = getArrayIndex(y2D, xd);
		showXZ(i);
	}

	public void showXZ(int idx)
	{
		final float[] y2d = y2D;
		double[] x2d = x2D;
		// if ( (idx >= x2d.length || idx == curr_y_xz_idx) &&
		if ((idx >= y2d.length || idx == curr_y_xz_idx) && mode2D == MODE_XZ)
			return;
		prev_idx = 0;
		curr_y_xz_plot = y2d[idx];
		curr_y_xz_idx = idx;
		curr_x_yz_plot = Float.NaN;
		curr_x_yz_idx = -1;
		if (zY2D != null)
		{
			x2d = new double[x2D.length];
			curr_xmin = curr_xmax = zY2D[x2D.length * idx];
			for (int j = 0; j < x2D.length; j++)
			{
				x2d[j] = zY2D[x2D.length * idx + j];
				if (x2d[j] > curr_xmax)
					curr_xmax = x2d[j];
				else if (x2d[j] < curr_xmin)
					curr_xmin = x2d[j];
			}
		}
		sliceX = new double[x2d.length];
		sliceY = new float[x2d.length];
		final int zLen = z.length;
		float sliceMin, sliceMax;
		// sliceMin = sliceMax = z[ y2d.length * idx];
                if(x2d.length * (idx + 1) >= z.length)
                    return; //Wrong dimensions, would cause ArrayOutOfBound Exception
		sliceMin = sliceMax = z[x2d.length * idx];
		for (int j = 0; j < x2d.length; j++)
		{
			sliceX[j] = x2d[j];
			// int k = y2d.length * idx + j;
			final int k = x2d.length * idx + j;
			if (k >= zLen)
				break;
			sliceY[j] = z[k];
			if (sliceMin > z[k])
				sliceMin = z[k];
			if (sliceMax < z[k])
				sliceMax = z[k];
		}
		error = asym_error = false;
		mode2D = Signal.MODE_XZ;
		if (!fix_xmin)
			saved_xmin = curr_xmin = xmin = x2D_min;
		// saved_xmin = curr_xmin;
		if (!fix_xmax)
			saved_xmax = curr_xmax = xmax = x2D_max;
		// saved_xmax = curr_xmax;
		if (!fix_ymin)
			saved_ymin = ymin = sliceMin;
		if (!fix_ymax)
			saved_ymax = ymax = sliceMax;
		// Assumed that for 2D data, dimensions are increasing
		increasing_x = true;
	}

	public void showYZ(double t)
	{
		if (curr_x_yz_plot == t && mode2D == MODE_YZ)
			return;
		final int i = getArrayIndex(x2D, t);
		showYZ(i);
	}

	public void showYZ(int idx)
	{
		final float[] y2d = y2D;
		final double[] x2d = x2D;
		if ((idx >= x2d.length || idx == curr_x_yz_idx) && mode2D == MODE_YZ)
			return;
		prev_idx = 0;
		curr_x_yz_plot = x2d[idx];
		curr_x_yz_idx = idx;
		curr_y_xz_plot = Float.NaN;
		curr_y_xz_idx = -1;
		if (zY2D != null && idx < zY2D.length)
		{
			ymin = ymax = zY2D[idx];
			for (int j = 0; j < y2d.length; j++)
			{
				final int k = x2d.length * j + idx;
				y2d[j] = zY2D[k];
				if (ymin > y2d[j])
					ymin = y2d[j];
				if (ymax < y2d[j])
					ymax = y2d[j];
			}
		}
		sliceX = new double[y2d.length];
		sliceY = new float[y2d.length];
		final int zLen = z.length;
		if (idx >= zLen)
			return;
		float sliceMin, sliceMax;
		sliceMin = sliceMax = z[idx];
		for (int j = 0; j < y2d.length; j++)
		{
			final int k = x2d.length * j + idx;
			sliceX[j] = y2d[j];
			if (k >= zLen)
				break;
			sliceY[j] = z[k];
			if (sliceMin > z[k])
				sliceMin = z[k];
			if (sliceMax < z[k])
				sliceMax = z[k];
		}
		error = asym_error = false;
		mode2D = Signal.MODE_YZ;
		if (!fix_xmin)
			saved_xmin = curr_xmin = xmin = y2D_min;
		// saved_xmin = curr_xmin = ymin;
		if (!fix_xmax)
			saved_xmax = curr_xmax = xmax = y2D_max;
		// saved_xmax = curr_xmax = ymax;
		if (!fix_ymin)
			saved_ymin = ymin = sliceMin;
		if (!fix_ymax)
			saved_ymax = ymax = sliceMax;
		// Assumed that for 2D data, dimensions are increasing
		increasing_x = true;
	}

	/**
	 * Metod to call before execute a Traslate method.
	 */
	public void StartTraslate()
	{
		t_xmax = xmax;
		t_xmin = xmin;
		t_ymax = ymax;
		t_ymin = ymin;
	}

	public boolean supportsStreaming()
	{
		return data.supportsStreaming();
	}

	public double surfaceValue(double x0, double y0)
	{
		double zOut = 0;
		final float z2D[] = z;
		try
		{
			if (this.type == Signal.TYPE_2D && (mode2D == Signal.MODE_IMAGE || mode2D == Signal.MODE_CONTOUR))
			{
				img_yprev = findIndex(y2D, y0, img_yprev);
				img_xprev = findIndex(x2D, x0, img_xprev);
				double xn, yn;
				double x1 = 0, y1 = 0, z1 = 0;
				double x2 = 0, y2 = 0, z2 = 0;
				double x3 = 0, y3 = 0, z3 = 0;
				double x4 = 0, y4 = 0, z4 = 0;
				xn = x2D[img_xprev];
				yn = y2D[img_yprev];
				if (x0 > xn && y0 > yn)
				{
					x1 = xn;
					y1 = yn;
					z1 = z2D[img_xprev * y2D.length + img_yprev];
					x2 = x2D[img_xprev + 1];
					y2 = y2D[img_yprev];
					z2 = z2D[(img_xprev + 1) * y2D.length + img_yprev];
					x3 = x2D[img_xprev];
					y3 = y2D[img_yprev + 1];
					z3 = z2D[img_xprev * y2D.length + img_yprev + 1];
					x4 = x2D[img_xprev + 1];
					y4 = y2D[img_yprev + 1];
					z4 = z2D[(img_xprev + 1) * y2D.length + img_yprev + 1];
				}
				else
				{
					if (x0 > xn && y0 < yn)
					{
						x1 = x2D[img_xprev - 1];
						y1 = y2D[img_yprev];
						z1 = z2D[(img_xprev - 1) * y2D.length + img_yprev];
						x2 = xn;
						y2 = yn;
						z2 = z2D[img_xprev * y2D.length + img_yprev];
						x3 = x2D[img_xprev - 1];
						y3 = y2D[img_yprev + 1];
						z3 = z2D[(img_xprev - 1) * y2D.length + img_yprev + 1];
						x4 = x2D[img_xprev];
						y4 = y2D[img_yprev + 1];
						z4 = z2D[img_xprev * y2D.length + img_yprev + 1];
					}
					else
					{
						if (x0 < xn && y0 > yn)
						{
							x1 = x2D[img_xprev];
							y1 = y2D[img_yprev - 1];
							z3 = z2D[img_xprev * y2D.length + img_yprev - 1];
							x2 = x2D[img_xprev - 1];
							y2 = y2D[img_yprev - 1];
							z2 = z2D[(img_xprev - 1) * y2D.length + img_yprev - 1];
							x3 = xn;
							y3 = yn;
							z3 = z2D[img_xprev * y2D.length + img_yprev];
							x4 = x2D[img_xprev + 1];
							y4 = y2D[img_yprev];
							z4 = z2D[(img_xprev + 1) * y2D.length + img_yprev];
						}
						else
						{
							if (x0 < xn && y0 < yn)
							{
								x1 = x2D[img_xprev - 1];
								y1 = y2D[img_yprev - 1];
								z1 = z2D[(img_xprev - 1) * y2D.length + img_yprev - 1];
								x2 = x2D[img_xprev];
								y2 = y2D[img_yprev - 1];
								z2 = z2D[img_xprev * y2D.length + img_yprev - 1];
								x3 = x2D[img_xprev - 1];
								y3 = y2D[img_yprev];
								z3 = z2D[(img_xprev - 1) * y2D.length + img_yprev];
								x4 = xn;
								y4 = yn;
								z4 = z2D[img_xprev * y2D.length + img_yprev];
							}
						}
					}
				}
				final double yc = ((float) x0 - x1) * (y4 - y1) / (x4 - x1) + y1;
				if (yc > y0)
				{
					zOut = ((float) y0 - y1) * ((x2 - x1) * (z4 - z1) - (z2 - z1) * (x4 - x1))
							/ ((x2 - x1) * (y4 - y1) - (y2 - y1) * (x4 - x1))
							- ((float) x0 - x1) * ((y2 - y1) * (z4 - z1) - (z2 - z1) * (y4 - y1))
									/ ((x2 - x1) * (y4 - y1) - (y2 - y1) * (x4 - x1))
							+ z1;
				}
				else
				{
					zOut = ((float) y0 - y1) * ((x3 - x1) * (z4 - z1) - (z3 - z1) * (x4 - x1))
							/ ((x3 - x1) * (y4 - y1) - (y3 - y1) * (x4 - x1))
							- ((float) x0 - x1) * ((y3 - y1) * (z4 - z1) - (z3 - z1) * (y4 - y1))
									/ ((x3 - x1) * (y4 - y1) - (y3 - y1) * (x4 - x1))
							+ z1;
				}
			}
		}
		catch (final Exception exc)
		{
			zOut = z2D[img_xprev * x2D.length + img_yprev];
		}
		z_value = zOut;
		return zOut;
	}

	/**
	 * Traslate signal of delta_x and delta_y
	 *
	 * @param delta_x x traslation factor
	 * @param delta_y y traslation factor
	 * @param x_log   logaritm scale flag, if is logaritm scale true
	 * @param y_log   logaritm scale flag, if is logaritm scale true
	 */
	public void Traslate(double delta_x, double delta_y, boolean x_log, boolean y_log)
	{
		if (x_log)
		{
			xmax = t_xmax * delta_x;
			xmin = t_xmin * delta_x;
		}
		else
		{
			xmax = t_xmax + delta_x;
			xmin = t_xmin + delta_x;
		}
		if (y_log)
		{
			ymax = t_ymax * delta_y;
			ymin = t_ymin * delta_y;
		}
		else
		{
			ymax = t_ymax + delta_y;
			ymin = t_ymin + delta_y;
		}
	}

	void unblock()
	{
		freezeMode = NOT_FREEZED;
	}

	void unfreeze()
	{
		freezeMode = NOT_FREEZED;
		xmin = freezedXMin;
		xmax = freezedXMax;
		for (int i = 0; i < pendingUpdatesV.size(); i++)
		{
			if (pendingUpdatesV.elementAt(i).xLong != null)
			{
				dataRegionUpdated(pendingUpdatesV.elementAt(i).xLong, pendingUpdatesV.elementAt(i).y,
						pendingUpdatesV.elementAt(i).resolution);
			}
			else
			{
				dataRegionUpdated(pendingUpdatesV.elementAt(i).x, pendingUpdatesV.elementAt(i).y,
						pendingUpdatesV.elementAt(i).resolution);
			}
		}
		pendingUpdatesV.clear();
	}

	// Gabriele Sept 2019: more efficient update on event for growing signals
	public boolean updateSignal()
	{
		if (longXLimits)
			return false; // For the moment use only relative times
		double currXMax;
		if (x != null && x.length > 0)
			currXMax = x[x.length - 1];
		else
			currXMax = xmin;
		data.getDataAsync(currXMax, Double.MAX_VALUE, NUM_POINTS);
		return true;
	}

	public boolean xLimitsInitialized()
	{
		return xLimitsInitialized;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy