/*
* Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see http://www.gnu.org/licenses/
*/
package org.esa.snap.rcp.colormanip;
import com.bc.ceres.core.ProgressMonitor;
import org.esa.snap.core.datamodel.ColorPaletteDef;
import org.esa.snap.core.datamodel.ImageInfo;
import org.esa.snap.core.datamodel.ProductNodeEvent;
import org.esa.snap.core.datamodel.RasterDataNode;
import org.esa.snap.core.datamodel.Scaling;
import org.esa.snap.core.datamodel.Stx;
import org.esa.snap.core.datamodel.StxFactory;
import org.esa.snap.ui.ImageInfoEditorModel;
import javax.swing.AbstractButton;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Component;
class Continuous1BandGraphicalForm implements ColorManipulationChildForm {
public static final Scaling POW10_SCALING = new Pow10Scaling();
private final ColorManipulationForm parentForm;
private final ImageInfoEditor2 imageInfoEditor;
private final ImageInfoEditorSupport imageInfoEditorSupport;
private final JPanel contentPanel;
private final AbstractButton logDisplayButton;
private final AbstractButton evenDistButton;
private final MoreOptionsForm moreOptionsForm;
private final DiscreteCheckBox discreteCheckBox;
Continuous1BandGraphicalForm(final ColorManipulationForm parentForm) {
this.parentForm = parentForm;
imageInfoEditor = new ImageInfoEditor2(parentForm);
imageInfoEditorSupport = new ImageInfoEditorSupport(imageInfoEditor);
contentPanel = new JPanel(new BorderLayout(2, 2));
contentPanel.add(imageInfoEditor, BorderLayout.CENTER);
moreOptionsForm = new MoreOptionsForm(this, parentForm.getFormModel().canUseHistogramMatching());
discreteCheckBox = new DiscreteCheckBox(parentForm);
moreOptionsForm.addRow(discreteCheckBox);
parentForm.getFormModel().modifyMoreOptionsForm(moreOptionsForm);
logDisplayButton = LogDisplay.createButton();
logDisplayButton.addActionListener(e -> {
final boolean shouldLog10Display = logDisplayButton.isSelected();
if (shouldLog10Display) {
final ImageInfo imageInfo = parentForm.getFormModel().getModifiedImageInfo();
final ColorPaletteDef cpd = imageInfo.getColorPaletteDef();
if (LogDisplay.checkApplicability(cpd)) {
setLogarithmicDisplay(parentForm.getFormModel().getRaster(), true);
parentForm.applyChanges();
} else {
LogDisplay.showNotApplicableInfo(parentForm.getContentPanel());
logDisplayButton.setSelected(false);
}
} else {
setLogarithmicDisplay(parentForm.getFormModel().getRaster(), false);
parentForm.applyChanges();
}
});
evenDistButton = ImageInfoEditorSupport.createButton("org/esa/snap/rcp/icons/EvenDistribution24.gif");
evenDistButton.setName("evenDistButton");
evenDistButton.setToolTipText("Distribute sliders evenly between first and last slider");
evenDistButton.addActionListener(parentForm.wrapWithAutoApplyActionListener(e -> distributeSlidersEvenly()));
}
@Override
public Component getContentPanel() {
return contentPanel;
}
@Override
public ColorManipulationForm getParentForm() {
return parentForm;
}
@Override
public void handleFormShown(FormModel formModel) {
updateFormModel(formModel);
}
@Override
public void handleFormHidden(FormModel formModel) {
if (imageInfoEditor.getModel() != null) {
imageInfoEditor.setModel(null);
}
}
@Override
public void updateFormModel(FormModel formModel) {
final ImageInfoEditorModel oldModel = imageInfoEditor.getModel();
final ImageInfo imageInfo = parentForm.getFormModel().getModifiedImageInfo();
final ImageInfoEditorModel newModel = new ImageInfoEditorModel1B(imageInfo);
imageInfoEditor.setModel(newModel);
final RasterDataNode raster = formModel.getRaster();
setLogarithmicDisplay(raster, newModel.getImageInfo().isLogScaled());
if (oldModel != null) {
newModel.setHistogramViewGain(oldModel.getHistogramViewGain());
newModel.setMinHistogramViewSample(oldModel.getMinHistogramViewSample());
newModel.setMaxHistogramViewSample(oldModel.getMaxHistogramViewSample());
}
if (newModel.getSliderSample(0) < newModel.getMinHistogramViewSample() ||
newModel.getSliderSample(newModel.getSliderCount() - 1) > newModel.getMaxHistogramViewSample()) {
imageInfoEditor.computeZoomInToSliderLimits();
}
discreteCheckBox.setDiscreteColorsMode(imageInfo.getColorPaletteDef().isDiscrete());
logDisplayButton.setSelected(newModel.getImageInfo().isLogScaled());
parentForm.revalidateToolViewPaneControl();
}
@Override
public void resetFormModel(FormModel formModel) {
updateFormModel(formModel);
imageInfoEditor.computeZoomOutToFullHistogramm();
parentForm.revalidateToolViewPaneControl();
}
@Override
public void handleRasterPropertyChange(ProductNodeEvent event, RasterDataNode raster) {
final ImageInfoEditorModel model = imageInfoEditor.getModel();
if (model != null) {
if (event.getPropertyName().equals(RasterDataNode.PROPERTY_NAME_STX)) {
updateFormModel(parentForm.getFormModel());
} else {
setLogarithmicDisplay(raster, model.getImageInfo().isLogScaled());
}
}
}
@Override
public RasterDataNode[] getRasters() {
return parentForm.getFormModel().getRasters();
}
@Override
public MoreOptionsForm getMoreOptionsForm() {
return moreOptionsForm;
}
private void setLogarithmicDisplay(final RasterDataNode raster, final boolean logarithmicDisplay) {
final ImageInfoEditorModel model = imageInfoEditor.getModel();
if (logarithmicDisplay) {
final StxFactory stxFactory = new StxFactory();
final Stx stx = stxFactory
.withHistogramBinCount(raster.getStx().getHistogramBinCount())
.withLogHistogram(logarithmicDisplay)
.withResolutionLevel(raster.getSourceImage().getModel().getLevelCount() - 1)
.create(raster, ProgressMonitor.NULL);
model.setDisplayProperties(raster.getName(), raster.getUnit(), stx, POW10_SCALING);
} else {
model.setDisplayProperties(raster.getName(), raster.getUnit(), raster.getStx(), Scaling.IDENTITY);
}
model.getImageInfo().setLogScaled(logarithmicDisplay);
}
private void distributeSlidersEvenly() {
imageInfoEditor.distributeSlidersEvenly();
}
@Override
public AbstractButton[] getToolButtons() {
return new AbstractButton[]{
imageInfoEditorSupport.autoStretch95Button,
imageInfoEditorSupport.autoStretch100Button,
imageInfoEditorSupport.zoomInVButton,
imageInfoEditorSupport.zoomOutVButton,
imageInfoEditorSupport.zoomInHButton,
imageInfoEditorSupport.zoomOutHButton,
logDisplayButton,
evenDistButton,
imageInfoEditorSupport.showExtraInfoButton,
};
}
static void setDisplayProperties(ImageInfoEditorModel model, RasterDataNode raster) {
model.setDisplayProperties(raster.getName(), raster.getUnit(), raster.getStx(),
raster.isLog10Scaled() ? POW10_SCALING : Scaling.IDENTITY);
}
private static class Log10Scaling implements Scaling {
@Override
public final double scale(double value) {
return value > 1.0E-9 ? Math.log10(value) : -9.0;
}
@Override
public final double scaleInverse(double value) {
return value < -9.0 ? 1.0E-9 : Math.pow(10.0, value);
}
}
private static class Pow10Scaling implements Scaling {
private final Scaling log10Scaling = new Log10Scaling();
@Override
public double scale(double value) {
return log10Scaling.scaleInverse(value);
}
@Override
public double scaleInverse(double value) {
return log10Scaling.scale(value);
}
}
}