SineFitInteractor.java

// @formatter:off
 /*******************************************************************************
 *
 * This file is part of JMad.
 * 
 * Copyright (c) 2008-2011, CERN. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 ******************************************************************************/
// @formatter:on

package cern.accsoft.steering.util.gui.dv.ds;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;

import cern.accsoft.steering.util.fit.DataViewerFit;
import cern.accsoft.steering.util.fit.SineFit;
import cern.accsoft.steering.util.gui.icons.Icon;
import cern.jdve.data.DataSet;
import cern.jdve.interactor.EditInteractor;
import cern.jdve.utils.DataRange;
import cern.jdve.utils.DisplayPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * this class provides methods to create a fit on a dataset of a dataviewer, using selected points
 * 
 * @author Kajetan Fuchsberger (kajetan.fuchsberger at cern.ch)
 */
public abstract class SineFitInteractor extends EditInteractor {
    private final static Logger logger = LoggerFactory.getLogger(SineFitInteractor.class);

    /** the minimum of points that must be selected */
    private final static int MIN_POINTS_SELECTED = 1;

    /** the number of points that shall be calculated by the fit */
    private final static int DEFAULT_CALC_POINTS = 400;

    /** the action to create a sine-fit */
    private Action sineFitAction = new SineFitAction();

    /** the action to remove the fit */
    private Action clearFitAction = new ClearFitAction();

    /** the buttons for the toolbar */
    private JButton[] toolBarButtons;

    /** the button to invoke the sine fit */
    private JButton btnSineFit;

    /**
     * the constructor. Prepares the Toolbar-buttons
     */
    public SineFitInteractor() {
        super();
        createToolBarButtons();
    }

    /**
     * creates a sineFit with the selected DataPoints.
     */
    private void createSineFit() {
        List<DisplayPoint> selectedPoints = getSelectedDataPoints();
        if (selectedPoints.size() < MIN_POINTS_SELECTED) {
            logger.warn("Not enough datapoints selected (min " + MIN_POINTS_SELECTED + "), aborting fit.");
            return;
        }

        SineFit fit = new SineFit(selectedPoints);
        fit.doFit();
        setFitToChart(fit);
    }

    /**
     * searches for the selected points for this
     * 
     * @return
     */
    private List<DisplayPoint> getSelectedDataPoints() {
        DisplayPoint[] displayPoints = getSelectedDisplayPoints();
        List<DisplayPoint> list = new ArrayList<DisplayPoint>();
        for (int i = 0; i < displayPoints.length; i++) {
            list.add(displayPoints[i]);
        }
        return list;
    }

    /**
     * adds the given Fit to the chart.
     * 
     * @param fit the fit to add.
     */
    private void setFitToChart(DataViewerFit fit) {
        DataRange range = getChart().getDataWindow().getXRange();
        setFitDataSet(fit.getResultDataSet(range, DEFAULT_CALC_POINTS));
    }

    /**
     * to be overridden by subclass: must display the given data
     * 
     * @param dataSet the dataSet which contains the fitted data
     */
    protected abstract void setFitDataSet(DataSet dataSet);

    /**
     * to be overriden by subclass: must clear the data of the fit.
     */
    protected abstract void clearFit();

    /**
     * creates the Buttons for display in the toolbar
     */
    private void createToolBarButtons() {
        btnSineFit = new JButton(sineFitAction);
        btnSineFit.setText(null);
        this.toolBarButtons = new JButton[] { btnSineFit };
    }

    @Override
    public Component[] getToolBarComponents() {
        return this.toolBarButtons;
    }

    @Override
    public Action[] getPopupActions() {
        return new Action[] { sineFitAction, clearFitAction };
    }

    @Override
    public void setActive(boolean active) {
        super.setActive(active);

        if (toolBarButtons != null && !active) {
            toolBarButtons[0].setEnabled(active);
        }
    }

    /**
     * The action to create a sine fit
     * 
     * @author Kajetan Fuchsberger (kajetan.fuchsberger at cern.ch)
     */
    public class SineFitAction extends AbstractAction {
        private static final long serialVersionUID = -645526133743397868L;

        public SineFitAction() {
            super("Sine fit", Icon.SINE_FIT.getImageIcon());
            super.putValue(Action.SHORT_DESCRIPTION, "<html><center><b>Sine fit</b></center>Usage:<br/>"
                    + "To create a sine fit - select points to use as fit - input select <br/>"
                    + "them using left mouse button and click this button.</html>");
        }

        @Override
        public void actionPerformed(ActionEvent evt) {
            createSineFit();
        }
    }

    /**
     * action to remove the fit from the dataViewer
     * 
     * @author Kajetan Fuchsberger (kajetan.fuchsberger at cern.ch)
     */
    public class ClearFitAction extends AbstractAction {
        private static final long serialVersionUID = -6375357705542370646L;

        public ClearFitAction() {
            super("clear fit");
            super.putValue(Action.SHORT_DESCRIPTION, "<html><center><b>clear fit</b></center>Usage:<br/>"
                    + "use this button to remove the fit line from the dataviewer. </html>");
        }

        @Override
        public void actionPerformed(ActionEvent evt) {
            clearFit();
        }

    }

}