/* * Copyright 2006, United States Government as represented by the Administrator * for the National Aeronautics and Space Administration. No copyright is * claimed in the United States under Title 17, U.S. Code. All Other Rights * Reserved. * * Created on Feb 23, 2004 */ package gov.nasa.ial.mde.solver; import gov.nasa.ial.mde.math.Bounds; import gov.nasa.ial.mde.math.MultiPointXY; import gov.nasa.ial.mde.solver.symbolic.AnalyzedData; import gov.nasa.ial.mde.solver.symbolic.AnalyzedEquation; import gov.nasa.ial.mde.solver.symbolic.AnalyzedItem; import java.util.EventListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; /** * Solution is a container class for a MDE graph solution. A Solution object * contains an AnalyzedItem, a show graph boolean value, a sonify graph boolean * value, and a list of registered showFlagsChangeEvent listeners. * * Solution provides convenience methods for accessing elements of the Solution * and its AnalyzedItem object. * * @author Dan Dexter * @version 1.0 * @since 1.0 */ public class Solution { /** An solved item, that is, a AnalyzedEquation or AnalyzedData object. */ protected AnalyzedItem analyzedItem; /** Show graph flag. */ protected boolean showGraph; /** Sonify graph flag. */ protected boolean sonifyGraph; /** Components registered to listen for showGraph or sonifyGraph change events. */ protected EventListenerList listenerList = new EventListenerList(); @SuppressWarnings("unused") private Solution() { throw new RuntimeException("Default constructor not allowed."); } /** * Construct a new Solution object with with given AnalyzedItem object. * showGraph and sonifyGraph flags default to true. * * @param analyzedItem the solution for the analyzed item. */ public Solution(AnalyzedItem analyzedItem) { if (analyzedItem == null) { throw new NullPointerException("Null analyzed-item."); } this.analyzedItem = analyzedItem; this.showGraph = true; this.sonifyGraph = true; } /** * Return this Solution object's AnalyzedItem object. * * @return this Solution object's AnalyzedItem object. */ public AnalyzedItem getAnalyzedItem() { return this.analyzedItem; } /** * Return the equation associated with this Solution, if the * AnalyzedItem object represents an equation. Return null otherwise. * * @return the equation associated with this Solution. */ public String getInputEquation() { return (analyzedItem instanceof AnalyzedEquation) ? ((AnalyzedEquation)analyzedItem).printEquation() : null; } /** * Determine whether this Solution represents a Polar equation solution. * * @return true if this Solution represents a Polar equation solution. */ public boolean isPolar() { return ((analyzedItem instanceof AnalyzedEquation) && ((AnalyzedEquation)analyzedItem).isPolar()); } /** * Determine whether this solution represents a bad equation. * * @return true if this solution represents a bad equation. */ public boolean isBadEquation() { return (analyzedItem == null) || ((analyzedItem instanceof AnalyzedEquation) && (((AnalyzedEquation)analyzedItem).isBad()||((AnalyzedEquation)analyzedItem).hasMoreThanTwoVariables())); } // end isBadEquation /** * Determine whether this Solution is describable. * * @return true if this Solution is describable. */ public boolean isDescribable() { return (getFeatures() != null); } // end isDescribable /** * Determine whether this Solution is graphable. * * @return true if this Solution is graphable. */ public boolean isGraphable() { return (getGraphTrails() != null); } // end isGraphable /** * Determine whether this Solution is sonifiable. * * @return true if this Solution is sonifiable. */ public boolean isSonifiable() { return (getPoints() != null); } // end isSonifiable /** * Get the SolvedGraph associated with this Solution. The graph's * describable features can be accessed from the SolvedGraph object. * * @return the SolvedGraph associated with this Solution. */ public SolvedGraph getFeatures() { return (analyzedItem != null) ? analyzedItem.getFeatures() : null; } /** * Get this Solution's sonification data point at the specified array index. * * @param index the index to the point. * @return this Solution's sonification data point at the specified array index. * @see gov.nasa.ial.mde.solver.symbolic.AnalyzedData#getPoint(int) */ public MultiPointXY getPoint(int index) { return analyzedItem.getPoint(index); } /** * Get this Solution's sonification data point near the specified array index. * * @param x the x value. * @return this Solution's sonification data point near the specified array index. * @see gov.nasa.ial.mde.solver.symbolic.AnalyzedData#getPoint(int) */ public MultiPointXY getPointNear(double x) { if (analyzedItem == null) { return null; } if (analyzedItem instanceof AnalyzedData) { // For real data, we need to use the method that finds the index // to the point that is as close to the given x as possible. AnalyzedData analyzedData = (AnalyzedData)analyzedItem; return analyzedData.getPoint(analyzedData.getPointIndexNear(x)); } // Otherwise calculate a relative position given the bounds and the // specified x-value. Bounds b = analyzedItem.getPreferredBounds(); double left = b.left; double right = b.right; if ((x < left) || (x > right)) { return null; } double position = (x - left)/(right - left); return analyzedItem.getPoint(position); } /** * Return the sonification points for this Solution. * * @return the sonification points for this Solution. */ public MultiPointXY[] getPoints() { return (analyzedItem != null) ? analyzedItem.getPoints() : null; } // end getPoints /** * Return the set of graph plotting points for this Solution. * * @return the set of graph plotting points for this Solution. * @see gov.nasa.ial.mde.solver.symbolic.AnalyzedItem#getGraphTrails */ public GraphTrail[] getGraphTrails() { return (analyzedItem != null) ? analyzedItem.getGraphTrails() : null; } // end getGraphTrails /** * Dispose of this Solution object (free up associated memory). * This Solution object should not be used after this method is called because * the reference to the AnalyzedItem is immutable and we set it to null in * this method. All change listeners are removed as well. * * @see gov.nasa.ial.mde.solver.symbolic.AnalyzedItem#dispose() */ public void dispose() { if (analyzedItem != null) { this.analyzedItem.dispose(); this.analyzedItem = null; } this.showGraph = false; this.sonifyGraph = false; removeAllChangeListeners(); this.listenerList = null; } /** * The graph for each analyzed-item can either be displayed or not. * * @param visible true - enable the drawing and sonification of the graph. * false - disable display and sonification of the graph. */ public void setShowGraph(boolean visible) { boolean showChanged = (visible != showGraph); boolean sonifyChanged = (!visible && sonifyGraph); // Disable sonification if we disable showing the graph. if (!visible) { sonifyGraph = false; } showGraph = visible; if (showChanged || sonifyChanged) { fireStateChanged(new SolutionFlagsStateChange(showChanged,sonifyChanged)); } } /** * Determine whether this Solution's graph is currently visible or hidden. * * @return true if this Solution's graph is currently visible. */ public boolean isShowGraph() { return showGraph; } /** * Sonification for the Solution can either be enabled or disabled. * * @param sonify true to enable sonification of the graph, false to disable it. * @exception IllegalArgumentException is thrown if the graph will not be shown * and you try to enabled sonification. */ public void setSonifyGraph(boolean sonify) { if (sonify && !showGraph) { throw new IllegalArgumentException("Graph can not be sonified if it is not shown."); } if (sonify != sonifyGraph) { sonifyGraph = sonify; fireStateChanged(new SolutionFlagsStateChange(false,true)); } } /** * Determine whether this graph's sonification is enabled or disabled. * * @return true if the graph is to be sonified, false to disable sonification. */ public boolean isSonifyGraph() { return sonifyGraph; } /** * Determine whether the input object and this Solution object are identical * objects. * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof Solution) { Solution s = (Solution)obj; return this.getAnalyzedItem().equals(s.getAnalyzedItem()); } return false; } /** * Output Solution name and show flag values. * @see java.lang.Object#toString() */ public String toString() { StringBuffer strBuff = new StringBuffer(64); strBuff.append(getClass().getName()).append("(") .append(analyzedItem.getClass().getName()).append(", ") .append("showGraph=").append(showGraph).append(", ") .append("sonifyGraph=").append(sonifyGraph).append(")"); return strBuff.toString(); } /** * Register a component to listen for show flag change events. * * @param l the change listener. */ public void addChangeListener(ChangeListener l) { listenerList.add(ChangeListener.class, l); } // end addChangeListener /** * Unregister a show flag listener component. * * @param l the change listener. */ public void removeChangeListener(ChangeListener l) { listenerList.remove(ChangeListener.class, l); } // end removeChangeListener /** * Clear all the show flag change listeners for this Solution object. */ public void removeAllChangeListeners() { EventListener[] listeners = listenerList.getListeners(ChangeListener.class); ChangeListener cl; for (int i = 0; i < listeners.length; i++) { // added a typecast to get past Xlint ROS 2/3/05 cl = (ChangeListener)listeners[i]; listenerList.remove(ChangeListener.class, cl); } } // end removeAllChangeListeners /** * Notify all registered listeners that a show flag change event has occurred. * * @param showSonifyStateChange true to show sonify state change. */ protected void fireStateChanged(SolutionFlagsStateChange showSonifyStateChange) { Object[] l = listenerList.getListenerList(); ChangeEvent changeEvent = (l.length > 0) ? new ChangeEvent(showSonifyStateChange) : null; for (int i = l.length - 2; i >= 0; i -= 2) { if (l[i] == ChangeListener.class) { ((ChangeListener)l[i + 1]).stateChanged(changeEvent); } } } // end fireStateChanged /** * A class representing a change in either the show graph or sonify graph * flags for the solution. * * @author Dan Dexter * @version 1.0 * @since 1.0 */ public class SolutionFlagsStateChange { /** A reference to the solution. */ public Solution solution; /** Flag indicating that the show-graph state changed. */ public boolean showGraphChanged; /** Flag indicating that the sonify-graph state changed. */ public boolean sonifyGraphChanged; /** * Creates an instance of <code>SolutionFlagsStateChange</code> using the * specified <code>showGraphChanged</code> and <code>sonifyGraphChanged</code> * flag values. A reference to the solution is automatically set. * * @param showGraphChanged true to indicate the show graph state changed. * @param sonifyGraphChanged true to indicate the sonify graph state changed. */ public SolutionFlagsStateChange(boolean showGraphChanged, boolean sonifyGraphChanged) { this.solution = Solution.this; this.showGraphChanged = showGraphChanged; this.sonifyGraphChanged = sonifyGraphChanged; } } }