Example Plugin For Buffering Features in a Layer

From OpenJUMP Wiki
Jump to navigation Jump to search

this example plugin shows:

  • how to retrieve data from a layer
  • how to provide input paramter for a spatial analysis
  • how to create a new layer that contains your results

package ch.unizh.geo.degen.jumpplugins;

import java.util.Collection;
import java.util.Iterator;

import javax.swing.JComboBox;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jump.feature.Feature;
import com.vividsolutions.jump.feature.FeatureCollection;
import com.vividsolutions.jump.feature.FeatureDataset;
import com.vividsolutions.jump.feature.FeatureSchema;
import com.vividsolutions.jump.task.TaskMonitor;
import com.vividsolutions.jump.workbench.WorkbenchContext;
import com.vividsolutions.jump.workbench.model.Layer;
import com.vividsolutions.jump.workbench.model.StandardCategoryNames;
import com.vividsolutions.jump.workbench.plugin.AbstractPlugIn;
import com.vividsolutions.jump.workbench.plugin.EnableCheckFactory;
import com.vividsolutions.jump.workbench.plugin.MultiEnableCheck;
import com.vividsolutions.jump.workbench.plugin.PlugInContext;
import com.vividsolutions.jump.workbench.plugin.ThreadedPlugIn;
import com.vividsolutions.jump.workbench.ui.GUIUtil;
import com.vividsolutions.jump.workbench.ui.MultiInputDialog;
import com.vividsolutions.jump.workbench.ui.plugin.FeatureInstaller;

/**
 * @description:
 *	Example plugin which creates buffers from the input
 *  features. The Plugin ask for the layer with the features
 *  and the radius for the buffer. The output will be 
 *  the buffered features containing the attributes from the
 *  source features.
 *     
 * @author sstein
 *
 **/
public class BufferFeaturesFromLayerPlugIn extends AbstractPlugIn implements ThreadedPlugIn{

    private String T1 ="buffers all features in a layer";
    private String T2 ="buffer radius";
    private String CLAYER = "select layer";    
    private Layer itemlayer = null;
    private double radius = 0; 

    /**
     * this method is called on the startup by JUMP/OpenJUMP.
     * We set here the menu entry for calling the function.
     */
    public void initialize(PlugInContext context) throws Exception {
    				
	    FeatureInstaller featureInstaller = new FeatureInstaller(context.getWorkbenchContext());
	    featureInstaller.addMainMenuItem(
	    	        this,				//exe
	                new String[] {"SSTools"}, 	//menu path
	                this.getName(), //name methode .getName recieved by AbstractPlugIn 
	                false,			//checkbox
	                null,			//icon
	                createEnableCheck(context.getWorkbenchContext())); //enable check
    }
    
    /**
     * This method is used to define when the menu entry is activated or
     * disabled. In this example we allow the menu entry to be usable only
     * if one layer exists.
     * @param workbenchContext
     * @return
     */
    public static MultiEnableCheck createEnableCheck(WorkbenchContext workbenchContext) {
        EnableCheckFactory checkFactory = new EnableCheckFactory(workbenchContext);

        return new MultiEnableCheck()
                        .add(checkFactory.createAtLeastNLayersMustExistCheck(1))
                        .add(checkFactory.createTaskWindowMustBeActiveCheck());
    }
    
    /**
     * this function is called by JUMP/OpenJUMP if one clicks on the menu entry.
     * It is called before the "run" method and useful to do all the GUI /user-input things
     * In this example we call two additional methods {@link #setDialogValues(MultiInputDialog, PlugInContext)}
     * and {@link #getDialogValues(MultiInputDialog)} to obtain the Layer and the buffer radius by the user. 
     */
	public boolean execute(PlugInContext context) throws Exception{
	    this.reportNothingToUndoYet(context);
	    MultiInputDialog dialog = new MultiInputDialog(
	            context.getWorkbenchFrame(), getName(), true);
	        this.setDialogValues(dialog, context);
	        GUIUtil.centreOnWindow(dialog);
	        dialog.setVisible(true);
	        if (! dialog.wasOKPressed()) { return false; }
	        this.getDialogValues(dialog);
	        return true;
	}
	
    private void setDialogValues(MultiInputDialog dialog, PlugInContext context){
	    dialog.setSideBarDescription(T1);
    	JComboBox addLayerComboBoxBuild = dialog.addLayerComboBox(this.CLAYER, context.getCandidateLayer(0), null, context.getLayerManager());
        dialog.addDoubleField(T2, this.radius, 6);
	  }

    private void getDialogValues(MultiInputDialog dialog){
    	this.itemlayer = dialog.getLayer(this.CLAYER);
        this.radius = dialog.getDouble(T2);
	  }
	
    /**
     * This method is called by JUMP/OpenJUMP after {@link #execute(PlugInContext)},
     * It is usefull to do some longterm calculations.  
     */
    public void run(TaskMonitor monitor, PlugInContext context) throws Exception{
            //-- allow cancel
            monitor.allowCancellationRequests();
    	    this.bufferItems(context, monitor, this.radius);
    	    System.gc();    		
    	}

     /**
     * This is a method which calculates buffers from the items in a layer. 
     * @param context
     * @param monitor 
     * @param radius used for the buffer
     * @return
     * @throws Exception
     */
     private boolean bufferItems(PlugInContext context, TaskMonitor monitor, double radius) throws Exception{
	System.gc(); //flush garbage collector
	// --------------------------	    
	//-- get items
        final Collection features = this.itemlayer.getFeatureCollectionWrapper().getFeatures();
        //-- create the FeatureCollection which will contain the buffers
	    FeatureCollection myCollA = null;
        // get the first feature to determine the FeatureSchema of the collection
        Feature firstF = (Feature)features.iterator().next();
        // get FeatureSchema
        FeatureSchema fs = firstF.getSchema();
        // create the new FeatureCollection (containing the output of the buffer operation)
        myCollA = new FeatureDataset(fs);
        // get every feature(clone it!) - get the geometry - calculate the buffer
        // and set as new Geometry the buffer geometry
        // so the buffers have the same attributes as the original features
        int numFeatures = features.size();
        int count=0;
	    for (Iterator iter = features.iterator(); iter.hasNext();) {
            Feature f = (Feature) iter.next();
            //-- clone the feature - so we can add it to a new FC
            Feature newF = f.clone(false); 
            Geometry geom = f.getGeometry();
            //-- calculate the buffer
            Geometry buffer = geom.buffer(radius);
            //-- set as new geometry the buffer geometry
            newF.setGeometry(buffer);
            //-- add the new (cloned) feature to the collection 
            myCollA.add(newF);
            count++;
            //-- give the user some info : how far the calculation is
            monitor.report("processed: "+count+" of " + numFeatures + " items");
            //-- stop here if the user whishes
            //   we will not display the buffers calculated so far
            if (monitor.isCancelRequested()){
                return false;
            }
        }
        //-- display the resulting buffer features
		context.addLayer(StandardCategoryNames.WORKING, "buffers", myCollA);	    	
		return true;        
	}	  	
}