/* SignalFFTSettings.java created 2007-12-17 * */ package org.signalml.plugin.fftsignaltool; import java.awt.Dimension; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintStream; import java.io.Serializable; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.log4j.Logger; import org.signalml.math.fft.WindowType; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * Settings how the power spectrum of the signal should be displayed. * For more information read them description of the parameters below. * * @author Michal Dobaczewski © 2007-2008 CC Otwarte Systemy Komputerowe * Sp. z o.o., Marcin Szumski */ public class SignalFFTSettings implements FFTWindowTypeSettings, Serializable { protected static final Logger logger = Logger.getLogger(SignalFFTSettings.class); /** * the serialization constant */ private static final long serialVersionUID = 1L; /** * boolean which tells if the channel for which the power spectrum is * calculated should be changed, when the mouse goes up or down */ private boolean channelSwitching; /** * the size of the {@link SignalFFTPlot FFT plot} */ private Dimension plotSize; /** * the size of the FFT window (number of samples) */ private int windowWidth; /** * the {@link WindowType type} of the window function */ private WindowType windowType; /** * the parameter of the window function */ private double windowParameter; /** * boolean which tells if the axis with logarithmic scale should be used * ({@code true}) or the normal scale should be used */ private boolean logarithmic; /** * boolean which tells if the chart should be antialiased */ private boolean antialias; /** * boolean which tells if the points should be connected using splines * ({@code true}) or lines ({@code false}) */ private boolean spline; /** * boolean which tells if the title of the plot should be displayed */ private boolean titleVisible; /** * boolean which tells if the labels with frequencies should be displayed */ private boolean frequencyAxisLabelsVisible; /** * boolean which tells if the labels with power values should be displayed */ private boolean powerAxisLabelsVisible; /** * the start of the frequencies range that is displayed */ private int visibleRangeStart = Integer.MIN_VALUE; /** * the end of the frequencies range that is displayed */ private int visibleRangeEnd = Integer.MAX_VALUE; /** * the maximum number of labels on the X (frequencies) axis */ private int xAxisLabelCount = Integer.MAX_VALUE; private boolean autoScaleYAxis = true; private double minPowerAxis = 0.0; private double maxPowerAxis = 200.00; public boolean isAutoScaleYAxis() { return autoScaleYAxis; } public void setAutoScaleYAxis(boolean autoScaleYAxis) { this.autoScaleYAxis = autoScaleYAxis; } public double getMinPowerAxis() { return minPowerAxis; } public void setMinPowerAxis(double minPowerAxis) { this.minPowerAxis = minPowerAxis; } public double getMaxPowerAxis() { return maxPowerAxis; } public void setMaxPowerAxis(double maxPowerAxis) { this.maxPowerAxis = maxPowerAxis; } /** * Constructor. Sets the default values of the parameters. */ public SignalFFTSettings() { channelSwitching = false; plotSize = new Dimension(600, 200); windowWidth = 256; windowType = WindowType.HAMMING; windowParameter = 0; logarithmic = false; spline = false; antialias = true; frequencyAxisLabelsVisible = true; xAxisLabelCount = 16; } /** * Returns the size of the {@link SignalFFTPlot FFT plot}. * @return the size of the {@link SignalFFTPlot FFT plot} */ public Dimension getPlotSize() { return plotSize; } /** * Sets the size of the {@link SignalFFTPlot FFT plot} * @param size the size of the {@link SignalFFTPlot FFT plot} */ public void setPlotSize(Dimension size) { if (size == null) { throw new NullPointerException("No size"); } plotSize = size; } /** * Returns if the channel for which the power spectrum is * calculated should be changed, when the mouse goes up or down . * @return if the channel for which the power spectrum is * calculated should be changed, when the mouse goes up or down */ public boolean isChannelSwitching() { return channelSwitching; } /** * Sets if the channel for which the power spectrum is * calculated should be changed, when the mouse goes up or down * @param channelSwitching {@code true} if the channel for which the power * spectrum is calculated should be changed, when the mouse goes up or down */ public void setChannelSwitching(boolean channelSwitching) { this.channelSwitching = channelSwitching; } /** * Returns the size of the FFT window (number of samples). * @return the size of the FFT window (number of samples) */ public int getWindowWidth() { return windowWidth; } /** * Sets the size of the FFT window (number of samples). * @param width the size of the FFT window (number of samples) */ public void setWindowWidth(int width) { this.windowWidth = width; } @Override public WindowType getWindowType() { return windowType; } @Override public void setWindowType(WindowType windowType) { if (windowType == null) { throw new NullPointerException("No window type"); } this.windowType = windowType; } @Override public double getWindowParameter() { return windowParameter; } @Override public void setWindowParameter(double windowParameter) { this.windowParameter = windowParameter; } /** * Returns if the axis with logarithmic scale should be used * ({@code true}) or the normal scale should be used. * @return if the axis with logarithmic scale should be used */ public boolean isLogarithmic() { return logarithmic; } /** * Sets if the axis with logarithmic scale should be used * ({@code true}) or the normal scale should be used. * @param logarithmic ({@code true}) if the axis with logarithmic scale * should be used or {@code false} if the normal scale should be used */ public void setLogarithmic(boolean logarithmic) { this.logarithmic = logarithmic; } /** * Returns if the points should be connected using splines * ({@code true}) or lines ({@code false}). * @return if the points should be connected using splines * ({@code true}) or lines ({@code false}) */ public boolean isSpline() { return spline; } /** * Sets if the points should be connected using splines * ({@code true}) or lines ({@code false}). * @param spline if the points should be connected using splines * ({@code true}) or lines ({@code false}) */ public void setSpline(boolean spline) { this.spline = spline; } /** * Returns if the chart should be antialiased * @return {@code true} if the chart should be antialiased, * {@code false} otherwise */ public boolean isAntialias() { return antialias; } /** * Sets if the chart should be antialiased. * @param antialias {@code true} if the chart should be antialiased, * {@code false} otherwise */ public void setAntialias(boolean antialias) { this.antialias = antialias; } /** * Returns if the title of the plot should be displayed. * @return {@code true} if the title of the plot should be displayed, * {@code false} otherwise */ public boolean isTitleVisible() { return titleVisible; } /** * Sets if the title of the plot should be displayed. * @param titleVisible {@code true} if the title of the plot should be * displayed, {@code false} otherwise */ public void setTitleVisible(boolean titleVisible) { this.titleVisible = titleVisible; } /** * Returns if the labels with frequencies should be displayed. * @return {@code true} if the labels with frequencies should be displayed, * {@code false} otherwise */ public boolean isFrequencyAxisLabelsVisible() { return frequencyAxisLabelsVisible; } /** * Sets if the labels with frequencies should be displayed. * @param frequencyAxisLabelsVisible {@code true} if the labels with * frequencies should be displayed, {@code false} otherwise */ public void setFrequencyAxisLabelsVisible(boolean frequencyAxisLabelsVisible) { this.frequencyAxisLabelsVisible = frequencyAxisLabelsVisible; } /** * Returns if the labels with power values should be displayed. * @return {@code true} if the labels with power values should be * displayed, {@code false} otherwise */ public boolean isPowerAxisLabelsVisible() { return powerAxisLabelsVisible; } /** * Sets if the labels with power values should be displayed. * @param powerAxisLabelsVisible {@code true} if the labels with power * values should be displayed, {@code false} otherwise */ public void setPowerAxisLabelsVisible(boolean powerAxisLabelsVisible) { this.powerAxisLabelsVisible = powerAxisLabelsVisible; } /** * Returns the start of the frequencies range that is displayed. * @return the start of the frequencies range that is displayed */ public int getVisibleRangeStart() { return visibleRangeStart; } /** * Sets the start of the frequencies range that is displayed. * @param visibleRangeStart the start of the frequencies range that is * displayed */ public void setVisibleRangeStart(int visibleRangeStart) { this.visibleRangeStart = visibleRangeStart; } /** * Returns the end of the frequencies range that is displayed. * @return the end of the frequencies range that is displayed */ public int getVisibleRangeEnd() { return visibleRangeEnd; } /** * Sets the end of the frequencies range that is displayed. * @param visibleRangeEnd the end of the frequencies range that is displayed */ public void setVisibleRangeEnd(int visibleRangeEnd) { this.visibleRangeEnd = visibleRangeEnd; } /** * Returns the maximum number of labels on the X (frequencies) axis. * @return the maximum number of labels on the X (frequencies) axis */ public int getXAxisLabelCount() { return xAxisLabelCount; } /** * Sets the maximum number of labels on the X (frequencies) axis. * @param maxLabelCount the maximum number of labels on the X (frequencies) * axis */ public void setXAxisLabelCount(int maxLabelCount) { this.xAxisLabelCount = maxLabelCount; } /** * Opens an XML file and returns the document element. * @param file the file in which XML tree is stored * @return the document element * @throws ParserConfigurationException if an error occurs while * creating a document builder * @throws SAXException if parsing XML failed * @throws IOException if I/O error occurs */ private Element openXMLDocument(File file) throws ParserConfigurationException, SAXException, IOException { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder; documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document document = documentBuilder.parse(file); Element element = document.getDocumentElement(); element.normalize(); return element; } /** * Writes the provided data to XML file of a given name. * @param path the path to the file * @param data the XML document to be saved * @throws FileNotFoundException If the given path does not denote * an existing, writable regular file and a new regular file * of that name cannot be created * @throws TransformerException if transformation from * DOMSource to StreamResult is not possible */ private void saveToXMLFile(File path, Document data) throws FileNotFoundException, TransformerException { PrintStream ps = new PrintStream(path); StreamResult result = new StreamResult(ps); TransformerFactory transfac = TransformerFactory.newInstance(); Transformer trans = transfac.newTransformer(); trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); trans.setOutputProperty(OutputKeys.INDENT, "yes"); DOMSource source = new DOMSource(data); trans.transform(source, result); ps.close(); } /** * Creates a document used to save data in XML form * @return created document * @throws ParserConfigurationException if a DocumentBuilder cannot be created */ private Document createXMLDocumentToSave() throws ParserConfigurationException { DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); Document doc = docBuilder.newDocument(); return doc; } /** * Adds an XML node with the boolean value as the child of the {@code root} * node in the document {@code doc} and sets its {@code value}. * @param doc the document in which the nodes are located * @param root the node to which the child will be added * @param name the name of the child node * @param value the value of the child node */ private void addBooleanNode(Document doc, Element root, String name, boolean value) { Element node = doc.createElement(name); node.appendChild(doc.createTextNode(Boolean.toString(value))); root.appendChild(node); } /** * Adds an XML node with the integer value as the child of the {@code root} * node in the document {@code doc} and sets its {@code value}. * @param doc the document in which the nodes are located * @param root the node to which the child will be added * @param name the name of the child node * @param value the value of the child node */ private void addIntNode(Document doc, Element root, String name, int value) { Element node = doc.createElement(name); node.appendChild(doc.createTextNode(Integer.toString(value))); root.appendChild(node); } /** * Adds an XML node with the double value as the child of the {@code root} * node in the document {@code doc} and sets its {@code value}. * @param doc the document in which the nodes are located * @param root the node to which the child will be added * @param name the name of the child node * @param value the value of the child node */ private void addDoubleNode(Document doc, Element root, String name, Double value) { Element node = doc.createElement(name); node.appendChild(doc.createTextNode(value.toString())); root.appendChild(node); } /** * Adds an XML node with the Dimension value as the child of the {@code root} * node in the document {@code doc} and sets its {@code value}. * @param doc the document in which the nodes are located * @param root the node to which the child will be added * @param name the name of the child node * @param value the value of the child node */ private void addDimensionNode(Document doc, Element root, String name, Dimension value) { Element node = doc.createElement(name); addIntNode(doc, node, "height", value.height); addIntNode(doc, node, "width", value.width); root.appendChild(node); } /** * Adds an XML node with the {@link WindowType} value as the child of the * {@code root} node in the document {@code doc} and sets its {@code value}. * @param doc the document in which the nodes are located * @param root the node to which the child will be added * @param name the name of the child node * @param value the value of the child node */ private void addWindowTypeNode(Document doc, Element root, String name, WindowType value) { Element node = doc.createElement(name); node.appendChild(doc.createTextNode(value.name())); root.appendChild(node); } /** * Reads the boolean value from the given XML node. * @param node the node * @return the read value */ private boolean readBooleanNode(Node node) { return Boolean.parseBoolean(node.getFirstChild().getNodeValue()); } /** * Reads the integer value from the given XML node. * @param node the node * @return the read value */ private int readIntNode(Node node) { return Integer.parseInt(node.getFirstChild().getNodeValue()); } /** * Reads the double value from the given XML node. * @param node the node * @return the read value */ private double readDoubleNode(Node node) { return Double.parseDouble(node.getFirstChild().getNodeValue()); } /** * Reads the Dimension value from the given XML node. * @param node the node * @return the read value */ private Dimension readDimensionNode(Node node) { NodeList nodeList = node.getChildNodes(); int width=0, height=0; for (int i = 0; i < nodeList.getLength(); ++i) { Node nodeTmp = nodeList.item(i); if (nodeTmp.getNodeName().equals("width")) width = readIntNode(nodeTmp); if (nodeTmp.getNodeName().equals("height")) height = readIntNode(nodeTmp); } return new Dimension(width, height); } /** * Reads the {@link WindowType} value from the given XML node. * @param node the node * @return the read value */ private WindowType readWindowTypeNode(Node node) { return WindowType.valueOf(node.getFirstChild().getNodeValue()); } /** * Updates the fields of this object with the data read from the given * XML file. * @param xmlFile the XML file */ public void readFromXMLFile(File xmlFile) { if (!xmlFile.exists()) return; Element element; try { element = openXMLDocument(xmlFile); NodeList nodeList = element.getChildNodes(); for (int i = 0; i < nodeList.getLength(); ++i) { Node nodeTmp = nodeList.item(i); if (nodeTmp.getNodeName().equals("antialias")) setAntialias(readBooleanNode(nodeTmp)); if (nodeTmp.getNodeName().equals("channelSwitching")) setChannelSwitching(readBooleanNode(nodeTmp)); if (nodeTmp.getNodeName().equals("frequencyAxisLabelsVisible")) setFrequencyAxisLabelsVisible(readBooleanNode(nodeTmp)); if (nodeTmp.getNodeName().equals("logarithmic")) setLogarithmic(readBooleanNode(nodeTmp)); if (nodeTmp.getNodeName().equals("powerAxisLabelsVisible")) setPowerAxisLabelsVisible(readBooleanNode(nodeTmp)); if (nodeTmp.getNodeName().equals("spline")) setSpline(readBooleanNode(nodeTmp)); if (nodeTmp.getNodeName().equals("titleVisible")) setTitleVisible(readBooleanNode(nodeTmp)); if (nodeTmp.getNodeName().equals("maxLabelCount")) setXAxisLabelCount(readIntNode(nodeTmp)); if (nodeTmp.getNodeName().equals("visibleRangeEnd")) setVisibleRangeEnd(readIntNode(nodeTmp)); if (nodeTmp.getNodeName().equals("visibleRangeStart")) setVisibleRangeStart(readIntNode(nodeTmp)); if (nodeTmp.getNodeName().equals("windowWidth")) setWindowWidth(readIntNode(nodeTmp)); if (nodeTmp.getNodeName().equals("windowParameter")) setWindowParameter(readDoubleNode(nodeTmp)); if (nodeTmp.getNodeName().equals("plotSize")) setPlotSize(readDimensionNode(nodeTmp)); if (nodeTmp.getNodeName().equals("windowType")) setWindowType(readWindowTypeNode(nodeTmp)); if (nodeTmp.getNodeName().equals("minYAxis")) setMinPowerAxis(readDoubleNode(nodeTmp)); if (nodeTmp.getNodeName().equals("maxYAxis")) setMaxPowerAxis(readDoubleNode(nodeTmp)); if (nodeTmp.getNodeName().equals("autoScaleY")) setAutoScaleYAxis(readBooleanNode(nodeTmp)); } } catch (ParserConfigurationException e) { logger.error("", e); } catch (SAXException e) { logger.error("", e); } catch (IOException e) { logger.error("", e); } } /** * Stores this object in the given XML file. * @param xmlFile the XML file */ public void storeInXMLFile(File xmlFile) { try { Document doc = createXMLDocumentToSave(); Element root = doc.createElement("signalFFTSettings"); doc.appendChild(root); addBooleanNode(doc, root, "antialias", isAntialias()); addBooleanNode(doc, root, "channelSwitching", isChannelSwitching()); addBooleanNode(doc, root, "frequencyAxisLabelsVisible", isFrequencyAxisLabelsVisible()); addBooleanNode(doc, root, "logarithmic", isLogarithmic()); addBooleanNode(doc, root, "powerAxisLabelsVisible", isPowerAxisLabelsVisible()); addBooleanNode(doc, root, "spline", isSpline()); addBooleanNode(doc, root, "titleVisible", isTitleVisible()); addBooleanNode(doc, root, "autoScaleY", isAutoScaleYAxis()); addIntNode(doc, root, "maxLabelCount", getXAxisLabelCount()); addIntNode(doc, root, "visibleRangeEnd", getVisibleRangeEnd()); addIntNode(doc, root, "visibleRangeStart", getVisibleRangeStart()); addIntNode(doc, root, "windowWidth", getWindowWidth()); addDoubleNode(doc, root, "windowParameter", getWindowParameter()); addDoubleNode(doc, root, "minYAxis", getMinPowerAxis()); addDoubleNode(doc, root, "maxYAxis", getMaxPowerAxis()); addDimensionNode(doc, root, "plotSize", getPlotSize()); addWindowTypeNode(doc, root, "windowType", getWindowType()); saveToXMLFile(xmlFile, doc); } catch (FileNotFoundException e) { logger.error("", e); } catch (TransformerException e) { logger.error("", e); } catch (ParserConfigurationException e) { logger.error("", e); } } }