// ********** NOTE I'VE HALTED WORK ON THIS PLUGIN TOOL UNTIL I CAN ADD SQL SUPPORT
// ********** TO WHITEBOX. THIS IS REALLY THE WAY FORWARD HERE ********
/*
// * Copyright (C) 2011-2012 Dr. John Lindsay <jlindsay@uoguelph.ca>
// *
// * 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 plugins;
//
//import com.vividsolutions.jts.geom.GeometryFactory;
//import java.io.File;
//import java.text.DecimalFormat;
//import java.util.ArrayList;
//import java.util.SortedSet;
//import java.util.TreeSet;
//import whitebox.geospatialfiles.ShapeFile;
//import whitebox.geospatialfiles.shapefile.attributes.DBFField;
//import whitebox.geospatialfiles.shapefile.attributes.DBFReader;
//import whitebox.geospatialfiles.shapefile.attributes.DBFWriter;
//import whitebox.geospatialfiles.shapefile.ShapeFileRecord;
//import whitebox.geospatialfiles.shapefile.ShapeType;
//import whitebox.geospatialfiles.shapefile.attributes.AttributeTable;
//import whitebox.interfaces.WhiteboxPlugin;
//import whitebox.interfaces.WhiteboxPluginHost;
//
///**
// * WhiteboxPlugin is used to define a plugin tool for Whitebox GIS.
// *
// * @author Dr. John Lindsay <jlindsay@uoguelph.ca>
// */
//public class IsolateVectorFeaturesByAttribute implements WhiteboxPlugin {
//
// private WhiteboxPluginHost myHost = null;
// private String[] args;
//
// /**
// * Used to retrieve the plugin tool's name. This is a short, unique name
// * containing no spaces.
// *
// * @return String containing plugin name.
// */
// @Override
// public String getName() {
// return "IsolateVectorFeaturesByAttribute";
// }
//
// /**
// * Used to retrieve the plugin tool's descriptive name. This can be a longer
// * name (containing spaces) and is used in the interface to list the tool.
// *
// * @return String containing the plugin descriptive name.
// */
// @Override
// public String getDescriptiveName() {
// return "Isolate Vector Features By Attribute";
// }
//
// /**
// * Used to retrieve a short description of what the plugin tool does.
// *
// * @return String containing the plugin's description.
// */
// @Override
// public String getToolDescription() {
// return "Isolates vector features based on an attribute.";
// }
//
// /**
// * Used to identify which toolboxes this plugin tool should be listed in.
// *
// * @return Array of Strings.
// */
// @Override
// public String[] getToolbox() {
// String[] ret = { "VectorTools" };
// return ret;
// }
//
// /**
// * Sets the WhiteboxPluginHost to which the plugin tool is tied. This is the
// * class that the plugin will send all feedback messages, progress updates,
// * and return objects.
// *
// * @param host The WhiteboxPluginHost that called the plugin tool.
// */
// @Override
// public void setPluginHost(WhiteboxPluginHost host) {
// myHost = host;
// }
//
// /**
// * Used to communicate feedback pop-up messages between a plugin tool and
// * the main Whitebox user-interface.
// *
// * @param feedback String containing the text to display.
// */
// private void showFeedback(String message) {
// if (myHost != null) {
// myHost.showFeedback(message);
// } else {
// System.out.println(message);
// }
// }
//
// /**
// * Used to communicate a return object from a plugin tool to the main
// * Whitebox user-interface.
// *
// * @return Object, such as an output WhiteboxRaster.
// */
// private void returnData(Object ret) {
// if (myHost != null) {
// myHost.returnData(ret);
// }
// }
//
// private int previousProgress = 0;
// private String previousProgressLabel = "";
//
// /**
// * Used to communicate a progress update between a plugin tool and the main
// * Whitebox user interface.
// *
// * @param progressLabel A String to use for the progress label.
// * @param progress Float containing the progress value (between 0 and 100).
// */
// private void updateProgress(String progressLabel, int progress) {
// if (myHost != null && ((progress != previousProgress) ||
// (!progressLabel.equals(previousProgressLabel)))) {
// myHost.updateProgress(progressLabel, progress);
// }
// previousProgress = progress;
// previousProgressLabel = progressLabel;
// }
//
// /**
// * Used to communicate a progress update between a plugin tool and the main
// * Whitebox user interface.
// *
// * @param progress Float containing the progress value (between 0 and 100).
// */
// private void updateProgress(int progress) {
// if (myHost != null && progress != previousProgress) {
// myHost.updateProgress(progress);
// }
// previousProgress = progress;
// }
//
// /**
// * Sets the arguments (parameters) used by the plugin.
// *
// * @param args
// */
// @Override
// public void setArgs(String[] args) {
// this.args = args.clone();
// }
//
// private boolean cancelOp = false;
//
// /**
// * Used to communicate a cancel operation from the Whitebox GUI.
// *
// * @param cancel Set to true if the plugin should be canceled.
// */
// @Override
// public void setCancelOp(boolean cancel) {
// cancelOp = cancel;
// }
//
// private void cancelOperation() {
// showFeedback("Operation cancelled.");
// updateProgress("Progress: ", 0);
// }
//
// private boolean amIActive = false;
//
// /**
// * Used by the Whitebox GUI to tell if this plugin is still running.
// *
// * @return a boolean describing whether or not the plugin is actively being
// * used.
// */
// @Override
// public boolean isActive() {
// return amIActive;
// }
//
// @Override
// public void run() {
// amIActive = true;
//
// String shapefile = null;
// String inputFieldsString = null;
// String[] fieldNames = null;
// double z;
// int numFields;
// int progress = 0;
// int lastProgress = 0;
// int row;
// int a, i, j;
// double[] fieldAverages;
// double[] fieldTotals;
// String instructions;
//
//
// if (args.length <= 0) {
// showFeedback("Plugin parameters have not been set.");
// return;
// }
//
// // read the input parameters
//
// inputFieldsString = args[0]; // a shapefile and field pair, seperated by a semicolon
// instructions = args[1];
//
//
//
// try {
// // deal with the input fields
// String[] inputs = inputFieldsString.split(";");
// shapefile = inputs[0];
// numFields = inputs.length - 1;
// fieldNames = new String[numFields];
// System.arraycopy(inputs, 1, fieldNames, 0, numFields);
//
// // read the appropriate field from the dbf file into an array
// AttributeTable table = new AttributeTable(shapefile.replace(".shp", ".dbf"));
// int numRecs = table.getNumberOfRecords();
// DBFField[] fields = table.getAllFields();
// ArrayList<Integer> PCAFields = new ArrayList<Integer>();
// for (j = 0; j < fieldNames.length; j++) {
// for (i = 0; i < fields.length; i++) {
// if (fields[i].getName().equals(fieldNames[j]) &&
// (fields[i].getDataType() == DBFField.FIELD_TYPE_N ||
// fields[i].getDataType() == DBFField.FIELD_TYPE_F)) {
// PCAFields.add(i);
// }
// }
// }
//
// if (numFields != PCAFields.size()) {
// showFeedback("Not all of the specified database fields were found in the file or "
// + "a field of a non-numerical type was selected.");
// return;
// }
//
// double[][] fieldArray = new double[numRecs][numFields];
// Object[] rec;
// for (i = 0; i < numRecs; i++) {
// rec = table.getRecord(i);
// for (j = 0; j < numFields; j++) {
// fieldArray[i][j] = (Double)(rec[PCAFields.get(j)]);
// }
// if (cancelOp) {
// cancelOperation();
// return;
// }
// progress = (int) (100f * i / (numRecs - 1));
// if (progress != lastProgress) { updateProgress("Reading data:", progress);}
// lastProgress = progress;
// }
//
// fieldAverages = new double[numFields];
// fieldTotals = new double[numFields];
//
// // Calculate the means
// for (row = 0; row < numRecs; row++) {
// for (i = 0; i < numFields; i++) {
// fieldTotals[i] += fieldArray[row][i];
// }
// }
//
// for (i = 0; i < numFields; i++) {
// fieldAverages[i] = fieldTotals[i] / numRecs;
// }
//
// // Calculate the covariance matrix and total deviations
// double[] fieldTotalDeviation = new double[numFields];
// double[][] covariances = new double[numFields][numFields];
// double[][] correlationMatrix = new double[numFields][numFields];
//
// for (row = 0; row < numRecs; row++) {
// for (i = 0; i < numFields; i++) {
// fieldTotalDeviation[i] += (fieldArray[row][i] - fieldAverages[i])
// * (fieldArray[row][i] - fieldAverages[i]);
// for (a = 0; a < numFields; a++) {
// covariances[i][a] += (fieldArray[row][i] - fieldAverages[i])
// * (fieldArray[row][a] - fieldAverages[a]);
//
// }
// }
// if (cancelOp) {
// cancelOperation();
// return;
// }
// progress = (int) (100f * row / (numRecs - 1));
// if (progress != lastProgress) { updateProgress("Calculating covariances:", progress);}
// lastProgress = progress;
// }
//
// for (i = 0; i < numFields; i++) {
// for (a = 0; a < numFields; a++) {
// correlationMatrix[i][a] = covariances[i][a] / (Math.sqrt(fieldTotalDeviation[i] * fieldTotalDeviation[a]));
// }
// }
//
// for (i = 0; i < numFields; i++) {
// for (a = 0; a < numFields; a++) {
// covariances[i][a] = covariances[i][a] / (numRecs- 1);
// }
// }
//
// // Calculate the eigenvalues and eigenvectors
// Matrix cov = null;
// if (!standardizedPCA) {
// cov = new Matrix(covariances);
// } else {
// cov = new Matrix(correlationMatrix);
// }
// EigenvalueDecomposition eigen = cov.eig();
// double[] eigenvalues;
// Matrix eigenvectors;
// SortedSet<PrincipalComponent> principalComponents;
// eigenvalues = eigen.getRealEigenvalues();
// eigenvectors = eigen.getV();
//
// double[][] vecs = eigenvectors.getArray();
// int numComponents = eigenvectors.getColumnDimension(); // same as num rows.
// principalComponents = new TreeSet<PrincipalComponent>();
// for (i = 0; i < numComponents; i++) {
// double[] eigenvector = new double[numComponents];
// for (j = 0; j < numComponents; j++) {
// eigenvector[j] = vecs[j][i];
// }
// principalComponents.add(new PrincipalComponent(eigenvalues[i], eigenvector));
// }
//
// double totalEigenvalue = 0;
// for (i = 0; i < numComponents; i++) {
// totalEigenvalue += eigenvalues[i];
// }
//
// double[][] explainedVarianceArray = new double[numComponents][2]; // percent and cum. percent
// j = 0;
// for (PrincipalComponent pc: principalComponents) {
// explainedVarianceArray[j][0] = pc.eigenValue / totalEigenvalue * 100.0;
// if (j == 0) {
// explainedVarianceArray[j][1] = explainedVarianceArray[j][0];
// } else {
// explainedVarianceArray[j][1] = explainedVarianceArray[j][0] + explainedVarianceArray[j - 1][1];
// }
// j++;
// }
//
// DecimalFormat df1 = new DecimalFormat("0.00");
// DecimalFormat df2 = new DecimalFormat("0.0000");
// DecimalFormat df3 = new DecimalFormat("0.000000");
// DecimalFormat df4 = new DecimalFormat("0.000");
// String ret = "Principal Component Analysis Report:\n\n";
// ret += "Component\tExplained Var.\tCum. %\tEigenvalue\tEigenvector\n";
// j = 0;
// for (PrincipalComponent pc: principalComponents) {
//
// String explainedVariance = df1.format(explainedVarianceArray[j][0]);
// String explainedCumVariance = df1.format(explainedVarianceArray[j][1]);
// double[] eigenvector = pc.eigenVector.clone();
// ret += (j + 1) + "\t" + explainedVariance + "\t" + explainedCumVariance + "\t" + df2.format(pc.eigenValue) + "\t";
// String eigenvec = "[";
// for (i = 0; i < numComponents; i++) {
// if (i < numComponents - 1) {
// eigenvec += df3.format(eigenvector[i]) + ", ";
// } else {
// eigenvec += df3.format(eigenvector[i]);
// }
// }
// eigenvec += "]";
// ret += eigenvec + "\n";
//
// if (j < numberOfComponentsOutput) {
// DBFField field = new DBFField();
// field = new DBFField();
// field.setName("COMP" + (j + 1));
// field.setDataType(DBFField.FIELD_TYPE_N);
// field.setFieldLength(10);
// field.setDecimalCount(4);
// table.addField(field);
//
// for (row = 0; row < numRecs; row++) {
// z = 0;
// for (i = 0; i < numFields; i++) {
// z += fieldArray[row][i] * eigenvector[i];
// }
//
// Object[] recData = table.getRecord(row);
// recData[recData.length - 1] = new Double(z);
// table.updateRecord(row, recData);
//
// if (cancelOp) {
// cancelOperation();
// return;
// }
// progress = (int) (100f * row / (numRecs - 1));
// if (progress != lastProgress) { updateProgress("Outputing Component " + (j + 1) + ":", progress);}
// lastProgress = progress;
// }
// }
// j++;
// }
//
//
//
// } catch (Exception e) {
// showFeedback(e.getMessage());
// } finally {
// updateProgress("Progress: ", 0);
// // tells the main application that this process is completed.
// amIActive = false;
// myHost.pluginComplete();
// }
// }
//
//// // This method is only used during testing.
//// public static void main(String[] args) {
//// args = new String[2];
////// args[0] = "/Users/johnlindsay/Documents/Data/ShapeFiles/NTDB_roads_rmow.shp"
////// + ";/Users/johnlindsay/Documents/Data/ShapeFiles/Water_Line_rmow.shp"
////// + ";/Users/johnlindsay/Documents/Data/ShapeFiles/Water_Body_rmow.shp";
////// args[1] = "/Users/johnlindsay/Documents/Data/ShapeFiles/tmp1.shp";
////
////// args[0] = "/Users/johnlindsay/Documents/Data/ShapeFiles/someLakes.shp"
////// + ";/Users/johnlindsay/Documents/Data/ShapeFiles/tmp5.shp";
////// args[1] = "/Users/johnlindsay/Documents/Data/ShapeFiles/tmp1.shp";
////
////// args[0] = "/Users/johnlindsay/Documents/Data/ShapeFiles/rondeau lakes.shp"
////// + ";/Users/johnlindsay/Documents/Research/Conference Presentations and Guest Talks/2012 CGU/Data/rivers.shp";
////// args[1] = "/Users/johnlindsay/Documents/Data/ShapeFiles/tmp2.shp";
////
//// args[0] = "/Users/johnlindsay/Documents/Data/ShapeFiles/tmp1.shp"
//// + ";/Users/johnlindsay/Documents/Data/ShapeFiles/tmp2.shp";
//// args[1] = "/Users/johnlindsay/Documents/Data/ShapeFiles/tmp3.shp";
////
//// Union u = new Union();
//// u.setArgs(args);
//// u.run();
//// }
//}