package com.isti.traceview.transformations.ppm; import java.util.ArrayList; import java.util.List; import javax.swing.JFrame; import javax.swing.JOptionPane; import org.jfree.data.xy.XYDataset; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import com.isti.traceview.common.TimeInterval; import com.isti.traceview.data.PlotDataProvider; import com.isti.traceview.data.Segment; import com.isti.traceview.filters.IFilter; import com.isti.traceview.processing.FilterFacade; import com.isti.traceview.processing.IstiUtilsMath; import com.isti.traceview.transformations.ITransformation; import com.isti.xmax.XMAXException; import com.isti.xmax.gui.XMAXframe; /** * Particle motion transformation. Prepares data for presentation in * {@link ViewPPM} * */ public class TransPPM implements ITransformation { public static final String NAME = "Particle motion"; private int maxDataLength = 8192; @Override public void transform(List<PlotDataProvider> input, TimeInterval ti, IFilter filter, Object configuration, JFrame parentFrame) { if ((input == null) || (input.size() != 2)) { JOptionPane.showMessageDialog(parentFrame, "You should select two channels to view PPM", "Error", JOptionPane.ERROR_MESSAGE); } else { try { /* * Whenever we use channels with N and E as a third symbol * (like, BHN/NHE) N channel ALWAYS denotes the north and E * channel always denotes the East (regardless of the selection * order). Same for channels BH1 and BH2 : 1 is North; 2 is * East. For all other channel pairs, they go in the selection * order: first NS, second EW. */ List<PlotDataProvider> inputRepositioned = new ArrayList<PlotDataProvider>(); char type1 = input.get(0).getType(); char type2 = input.get(1).getType(); if (((type2 == 'N' || type2 == '1') && type1 != 'N' && type1 != '1') || ((type1 == 'E' || type1 == '2') && type2 != 'E' && type2 != '2')) { inputRepositioned.add(input.get(1)); inputRepositioned.add(input.get(0)); } else { inputRepositioned.add(input.get(0)); inputRepositioned.add(input.get(1)); } @SuppressWarnings("unused") ViewPPM vr = new ViewPPM(parentFrame, createDataset(inputRepositioned, filter, ti), ti, "N:" + inputRepositioned.get(0).getName() + " E:" + inputRepositioned.get(1).getName(), filter); } catch (XMAXException e) { JOptionPane.showMessageDialog(parentFrame, e.getMessage(), "Warning", JOptionPane.WARNING_MESSAGE); } } ((XMAXframe) parentFrame).getGraphPanel().forceRepaint(); } @Override public void setMaxDataLength(int dataLength) { this.maxDataLength = dataLength; } /** * @param input * List of traces to process * @param filter * Filter applied to traces before correlation * @param ti * Time interval to define processed range * @return jFreeChart dataset of trace data in polar coordinates * @throws XMAXException * if sample rates differ, gaps in the data, or no data for a * channel */ private XYDataset createDataset(List<PlotDataProvider> input, IFilter filter, TimeInterval ti) throws XMAXException { XYSeriesCollection dataset = new XYSeriesCollection(); PlotDataProvider channel1 = input.get(0); // N/S PlotDataProvider channel2 = input.get(1); // E/W if (channel1.getSampleRate() != channel2.getSampleRate()) throw new XMAXException("Channels have different sample rate"); XYSeries series = new XYSeries(channel1.getName() + " " + channel2.getName(), false); double sampleRate; List<Segment> segments1; if(channel1.getRotation() != null && channel1.isRotated()) { segments1 = channel1.getRawData(channel1.getRotation(), ti); } else segments1 = channel1.getRawData(ti); int[] intData1 = new int[0]; if (segments1.size() > 0) { long segment_end_time = 0; sampleRate = segments1.get(0).getSampleRate(); for (Segment segment : segments1) { if (segment.getSampleRate() != sampleRate) { throw new XMAXException( "You have data with different sample rate for channel " + channel1.getName()); } if (segment_end_time != 0 && Segment.isDataBreak(segment_end_time, segment.getStartTime().getTime(), sampleRate)) { throw new XMAXException("You have gap in the data for channel " + channel1.getName()); } segment_end_time = segment.getEndTime().getTime(); intData1 = IstiUtilsMath.padArray(intData1, segment.getData(ti).data); } } else { throw new XMAXException("You have no data for channel " + channel1.getName()); } List<Segment> segments2; if(channel2.getRotation() != null && channel2.isRotated()) segments2 = channel2.getRawData(channel2.getRotation(), ti); else segments2 = channel2.getRawData(ti); int[] intData2 = new int[0]; if (segments2.size() > 0) { long segment_end_time = 0; for (Segment segment : segments2) { if (segment.getSampleRate() != sampleRate) { throw new XMAXException("Channels " + channel1.getName() + " and " + channel2.getName() + " have different sample rates: " + sampleRate + " and " + segment.getSampleRate()); } if (segment_end_time != 0 && Segment.isDataBreak(segment_end_time, segment.getStartTime().getTime(), sampleRate)) { throw new XMAXException("You have gap in the data for channel " + channel2.getName()); } segment_end_time = segment.getEndTime().getTime(); intData2 = IstiUtilsMath.padArray(intData2, segment.getData(ti).data); } } else { throw new XMAXException("You have no data for channel " + channel1.getName()); } if (filter != null) { intData1 = new FilterFacade(filter, channel1).filter(intData1); intData2 = new FilterFacade(filter, channel2).filter(intData2); } int dataSize = Math.min(intData1.length, intData2.length); if (dataSize > maxDataLength) { throw new XMAXException("Too many datapoints are selected."); } ArrayValues values1 = new ArrayValues(intData1, dataSize); ArrayValues values2 = new ArrayValues(intData2, dataSize); for (int i = 0; i < dataSize; i++) { double x = intData1[i] - values1.getAverage(); double y = intData2[i] - values2.getAverage(); double radius = Math.sqrt(x * x + y * y); double theta = 180 * Math.atan2(y, x) / Math.PI; series.add(theta, radius); } dataset.addSeries(series); return dataset; } private class ArrayValues { int max = Integer.MIN_VALUE; int min = Integer.MAX_VALUE; int average = 0; public ArrayValues(int[] array, int size) { for (int i = 0; i < size; i++) { if (array[i] > max) max = array[i]; if (array[i] < min) min = array[i]; average = average + array[i]; } average = average / size; } @SuppressWarnings("unused") public int getMax() { return max; } @SuppressWarnings("unused") public int getMin() { return min; } public double getAverage() { return average; } } @Override public String getName() { return TransPPM.NAME; } }