Skip to content

Commit

Permalink
Merge pull request #383 from AAVSO/period-analysis-messages
Browse files Browse the repository at this point in the history
Period analysis dialog issues with messages
  • Loading branch information
dbenn authored Dec 14, 2023
2 parents 98a0486 + 6ff82cb commit 02f9803
Show file tree
Hide file tree
Showing 12 changed files with 430 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.BorderFactory;
Expand Down Expand Up @@ -177,21 +178,34 @@ protected void addDismissButton(JPanel buttonPane) {
* The data in which to search; assumed to be frequencies.
* @return A list of harmonic objects.
*/
protected List<Harmonic> findHarmonics(double freq, List<Double> data) {
protected List<Harmonic> findHarmonics(double freq, List<Double> data, double tolerance) {
List<Harmonic> harmonics = new ArrayList<Harmonic>();
harmonics.add(new Harmonic(freq, Harmonic.FUNDAMENTAL));
int n = Harmonic.FUNDAMENTAL + 1;

//Do not assume that the fundamental frequency exists in the data.
//harmonics.add(new Harmonic(freq, Harmonic.FUNDAMENTAL));
//int n = Harmonic.FUNDAMENTAL + 1;

double minData = Collections.min(data);
double maxData = Collections.max(data);

assert(freq > 0 || minData > 0);

int n = Harmonic.FUNDAMENTAL;

for (int i = 0; i < data.size(); i++) {

double potentialHarmonic = data.get(i) / n;

// Check if the data is a harmonic of the frequency within
// a relative tolerance range
if(Tolerance.areClose(potentialHarmonic, freq, 1e-3, false)){
harmonics.add(new Harmonic(freq * n, n));
n++;
}
// Do not assume that data are sorted.
while (freq * n <= maxData) {
for (int i = 0; i < data.size(); i++) {
double potentialHarmonic = data.get(i) / n;
// Check if the data is a harmonic of the frequency within
// a relative tolerance range
if (Tolerance.areClose(potentialHarmonic, freq, tolerance, false)) {
if (freq * n >= minData || freq * n <= maxData) {
harmonics.add(new Harmonic(freq * n, n));
break;
}
}
}
n++;
}

return harmonics;
Expand Down
181 changes: 142 additions & 39 deletions src/org/aavso/tools/vstar/ui/dialog/model/HarmonicInfoDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,17 @@
*/
package org.aavso.tools.vstar.ui.dialog.model;

import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;

Expand All @@ -32,16 +39,23 @@
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.aavso.tools.vstar.ui.dialog.period.PeriodAnalysis2DChartPane;
import org.aavso.tools.vstar.ui.dialog.period.PeriodAnalysisDataTablePane;
import org.aavso.tools.vstar.ui.mediator.DocumentManager;
import org.aavso.tools.vstar.ui.mediator.Mediator;
import org.aavso.tools.vstar.ui.mediator.message.HarmonicSearchResultMessage;
import org.aavso.tools.vstar.ui.model.list.PeriodAnalysisDataTableModel;
import org.aavso.tools.vstar.util.Tolerance;
import org.aavso.tools.vstar.util.model.Harmonic;
import org.aavso.tools.vstar.util.period.PeriodAnalysisCoordinateType;
import org.aavso.tools.vstar.util.period.dcdft.PeriodAnalysisDataPoint;
import org.aavso.tools.vstar.util.prefs.NumericPrecisionPrefs;
import org.jfree.chart.plot.XYPlot;

/**
* This dialog shows harmonics found from a search for harmonics of some
Expand All @@ -53,38 +67,49 @@ public class HarmonicInfoDialog extends JDialog implements
ListSelectionListener {

private HarmonicSearchResultMessage msg;
private PeriodAnalysis2DChartPane plotPane;
//private PeriodAnalysis2DChartPane plotPane;
private Component interfaceComponent;

private double startX, startY;

private ArrayList<Integer> startIndices;

private JList harmonicList;
private DefaultListModel harmonicListModel;

private Map<String, Harmonic> harmonicMap;

private JButton dismissButton;

/**
* Constructor.
*
* @param msg
* The harmonic search result message.
* @param plotPane
* The corresponding plot pane to set the cross-hair on.
* @param interfaceComponent
* plot pane or data table.
*/
public HarmonicInfoDialog(HarmonicSearchResultMessage msg,
PeriodAnalysis2DChartPane plotPane) {
Component interfaceComponent) {
super(DocumentManager.findActiveWindow());

this.setTitle("Harmonics");
this.setModal(true);

this.msg = msg;
this.plotPane = plotPane;

startX = plotPane.getChart().getXYPlot().getDomainCrosshairValue();
startY = plotPane.getChart().getXYPlot().getRangeCrosshairValue();


this.interfaceComponent = interfaceComponent;
if (interfaceComponent instanceof PeriodAnalysis2DChartPane) {
XYPlot plot = ((PeriodAnalysis2DChartPane)interfaceComponent).getChart().getXYPlot();
startX = plot.getDomainCrosshairValue();
startY = plot.getRangeCrosshairValue();
} else if (interfaceComponent instanceof PeriodAnalysisDataTablePane) {
JTable table = ((PeriodAnalysisDataTablePane)interfaceComponent).getTable();
int[] indices = table.getSelectedRows();
startIndices = new ArrayList<Integer>();
for (int row : indices) {
startIndices.add(row);
}
}

this.harmonicMap = new TreeMap<String, Harmonic>();

JPanel topPane = new JPanel();
Expand All @@ -96,6 +121,13 @@ public HarmonicInfoDialog(HarmonicSearchResultMessage msg,

getContentPane().add(topPane);
pack();

this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
dismiss();
}
});

setLocationRelativeTo(Mediator.getUI().getContentPane());
setVisible(true);
}
Expand Down Expand Up @@ -128,11 +160,16 @@ private JPanel createListPane() {
private JPanel createButtonPane() {
JPanel panel = new JPanel(new FlowLayout());

dismissButton = new JButton("Dismiss");
JButton dismissButton = new JButton("Dismiss");
dismissButton.addActionListener(createDismissButtonListener());
dismissButton.setEnabled(true);
panel.add(dismissButton);

JButton copyButton = new JButton("Copy");
copyButton.addActionListener(createCopyButtonListener());
copyButton.setEnabled(true);
panel.add(copyButton);

this.getRootPane().setDefaultButton(dismissButton);

return panel;
Expand All @@ -147,46 +184,112 @@ public void valueChanged(ListSelectionEvent e) {
String desc = (String) harmonicListModel
.get(selectedModelIndex);
Harmonic harmonic = harmonicMap.get(desc);
plotPane
.setCrossHair(harmonic.getFrequency(),
findNthRangeValueFromFrequency(harmonic
.getFrequency()));
double x;

if (interfaceComponent instanceof PeriodAnalysis2DChartPane) {
PeriodAnalysis2DChartPane plotPane = (PeriodAnalysis2DChartPane)interfaceComponent;
if (plotPane.getModel().getDomainType() == PeriodAnalysisCoordinateType.FREQUENCY) {
x = harmonic.getFrequency();
} else if (plotPane.getModel().getDomainType() == PeriodAnalysisCoordinateType.PERIOD) {
x = harmonic.getPeriod();
} else {
return;
}
plotPane.setCrossHair(x, 0);
} else if (interfaceComponent instanceof PeriodAnalysisDataTablePane) {
selectHarmonic(((PeriodAnalysisDataTablePane)interfaceComponent).getTable(), harmonic, msg.getTolerance());
}
}
}
}

// Return the range value corresponding to the specified frequency.
private Double findNthRangeValueFromFrequency(double frequency) {
Double value = null;

List<Double> freqVals = plotPane.getModel().getDomainValues();
List<Double> rangeVals = plotPane.getModel().getRangeValues();

int i = 0;
while (i < freqVals.size()) {
if (freqVals.get(i) == frequency) {
value = rangeVals.get(i);
break;

private void selectHarmonic(JTable table, Harmonic harmonic, double tolerance) {
if (table.getModel() instanceof PeriodAnalysisDataTableModel) {
PeriodAnalysisDataTableModel model = (PeriodAnalysisDataTableModel)(table.getModel());
Integer closestRow = null;
Double minDiff = null;
int n = harmonic.getHarmonicNumber();
//System.out.println("\nselectHarmonic");
for (int row = 0; row < model.getRowCount(); row++) {
PeriodAnalysisDataPoint dataPoint = model.getDataPointFromRow(row);
double f = dataPoint.getFrequency();
// use tolerance but also look for the closest point inside the tolerance!
if (Tolerance.areClose(f / n, harmonic.getFrequency() / n, tolerance, false)) {
double dif = Math.abs(f - harmonic.getFrequency());
if (minDiff == null || dif < minDiff) {
minDiff = dif;
closestRow = row;
//System.out.println("minDif = " + minDiff);
}
}
}
if (closestRow != null) {
closestRow = table.convertRowIndexToView(closestRow);
ensureVisible(table, closestRow);
boolean state = ((PeriodAnalysisDataTablePane)interfaceComponent).disableValueChangeEvent();
try {
table.setRowSelectionInterval(closestRow, closestRow);
} finally {
((PeriodAnalysisDataTablePane)interfaceComponent).setValueChangedDisabledState(state);
}
} else {
throw new IllegalArgumentException("Harmonic not found");
}
i++;
}
}

if (value == null) {
throw new IllegalArgumentException("Unknown frequency");
private void dismiss() {
setVisible(false);
dispose();
// Restore the plot's cross hair or table's selection(s).
if (interfaceComponent instanceof PeriodAnalysis2DChartPane) {
((PeriodAnalysis2DChartPane)interfaceComponent).setCrossHair(startX, startY);
} else if (interfaceComponent instanceof PeriodAnalysisDataTablePane) {
JTable table = ((PeriodAnalysisDataTablePane)interfaceComponent).getTable();
if (startIndices != null) {
if (startIndices.size() > 0) {
ensureVisible(table, startIndices.get(0));
}
boolean state = ((PeriodAnalysisDataTablePane)interfaceComponent).disableValueChangeEvent();
try {
table.clearSelection();
for (int row : startIndices) {
table.addRowSelectionInterval(row, row);
}
} finally {
((PeriodAnalysisDataTablePane)interfaceComponent).setValueChangedDisabledState(state);
}
}
}

return value;
}

private void ensureVisible(JTable table, int row) {
int colWidth = (int) table.getCellRect(row, 0, true).getWidth();
int rowHeight = table.getRowHeight(row);
table.scrollRectToVisible(new Rectangle(colWidth, rowHeight * row, colWidth, rowHeight));
}

// Return a listener for the "Dismiss" button.
private ActionListener createDismissButtonListener() {
return new ActionListener() {
public void actionPerformed(ActionEvent e) {
setVisible(false);
dispose();
// Restore the plot's cross hair.
plotPane.setCrossHair(startX, startY);
dismiss();
}
};
}

// Return a listener for the "Dismiss" button.
private ActionListener createCopyButtonListener() {
return new ActionListener() {
public void actionPerformed(ActionEvent e) {
String s = "";
for (int i = 0; i < harmonicListModel.size(); i++) {
s += harmonicListModel.get(i).toString() + "\n";
}
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(s) , null);
}
};
}

}
Loading

0 comments on commit 02f9803

Please sign in to comment.