Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [udig-devel] How can we find intersection of two geometries?

Hello,

not sure if anyone got back to you...

The general solution is quite hard but a working solution can be
obtained using the underlying geometry library (JTS). Essentially you

  create your geometric elements (JTS) for cutting
  get a list of features, and for each:
    get the geometry
    use JTS operations to cut it with your elements
  re-combine the new geometries with your original or with new features
  repackage the whole thing

attached is a file that implements a uDig operation and buffers points
in this way. Hooking up the operation into uDig requires some eclipse
magic around the file---look at the uDig tootip example on the web to
understand the uDig IOp extension point.

hope this helps,
adrian


On Wed, 2007-04-04 at 20:02 +0300, Sergiy Doroshenko wrote:
> Hi all!
> 
> How can we create new feature from given one by intersecting its
> geometry by another geometry? For example, split given feature by
> rectangular grid and create new feature for every peace - in this case
> we need to find intersection of multipolygon and rectangles.
> 
> Is there some udig's or geotools' instrument, or this geometrical
> operation can be done only with some 3d party libraries?
> _______________________________________________
> User-friendly Desktop Internet GIS (uDig)
> http://udig.refractions.net
> http://lists.refractions.net/mailman/listinfo/udig-devel
/*
 * This is a naive buffer operation for uDig, which operates on Point layers. 
 * 
 * The uDig operation extention point provides an approach to interact with the 
 * RichClientPlatform. The operation extention point can be implemented by 
 * creating four files:
 *   1) A plugin activator
 *   2) A java file which implements IOp by providing a single method op(...).
 *   3) A plugin.xml, which declares the use of the extention point.
 *   4) A Manifest
 * This file uses the extention point to target uDig 'Layers'. 
 * 
 * TODO: CRS: for production use, 'naive buffer' should work in projected space. 
 * 		 For now, the buffer is done in the euclidean space of the included 
 * 		 features.
 * TODO: Validate: add lots of checks on incoming data type.
 * TODO: Use a Logger: change all the System.out/err calls to call the log
 * TODO: Sort out how to create the layer (discouraged access vs. deprecation)
 * 
 * (c) 2006 Adrian Custer, the uDig project, and others.
 * 
 * @version: 0.0.3
 * 
 * Targets uDig 1.1M7pre nightly builds of March 2006.
 */

package an.oread.operationsPlugin;


import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import net.refractions.udig.catalog.CatalogPlugin;
import net.refractions.udig.catalog.IGeoResource;
import net.refractions.udig.catalog.memory.internal.AnotherMemoryDataStore;
import net.refractions.udig.catalog.memory.internal.MemoryServiceImpl;
import net.refractions.udig.project.ILayer;
import net.refractions.udig.project.IMap;
import net.refractions.udig.project.internal.Layer;
import net.refractions.udig.project.internal.Project;
import net.refractions.udig.project.internal.impl.LayerFactoryImpl;
import net.refractions.udig.project.ui.ApplicationGIS;
import net.refractions.udig.ui.operations.IOp;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.geotools.data.FeatureReader;
import org.geotools.data.FeatureSource;
import org.geotools.data.FeatureStore;
import org.geotools.feature.AttributeType;
import org.geotools.feature.AttributeTypeFactory;
import org.geotools.feature.Feature;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureType;
import org.geotools.feature.FeatureTypeBuilder;
import org.geotools.feature.GeometryAttributeType;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.osgi.framework.Bundle;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;





public class BufferPtLayerOp implements IOp {

	// This structure is defined in an inner class below. It is placed at the 
	// class level to ensure access is possible throughout the operation code.
	final DialogData theDD = new DialogData();
	
	// This variable defines the units in which we will have to buffer. If the 
	// user unit (theDD.unit) differs, then we have to convert the user distance
	// into values for this unit. 
	// TODO: change from String to use org.jscience units.
	String buffering_unit = null;
	
	// These references to GUI widgets allow us to pass focus from one widget to
	// the next when the <Tab> key is pressed. The {verify,modify}Listener 
	// methods will call .setFocus() on the 'next' Control.
	Control unitCtrl, doitCtrl = null;
	
	
	/**
	 * This is the implementation of the op(...) method which does the work 
	 * when the menu entry is clicked. This method is the requirement of the IOp 
	 * interface. The menu entry may be invoked from a main menu or from a 
	 * context menu.
	 * 
	 * @see net.refractions.udig.ui.operations.IOp#op(
	 *                               org.eclipse.swt.widgets.Display,
     *                               java.lang.Object, 
     *                               org.eclipse.core.runtime.IProgressMonitor)
	 */
	public void op(final Display display, Object target, IProgressMonitor monitor) 
			throws Exception {
		
		// To show that we are running our code, even when all else breaks.
		// TODO:Cleanup - remove.
		System.out.println("\nReached BufferPtLayerOp code...");
		System.out.println("Start of operation: Buffer a point layer.");
		
		//reset (for multiple runs)
		theDD.distance = 0.0;
		theDD.unit = "undefined";
		
		// Get the cannonical references to 
		// In our plugin.xml, we defined our target to be an ILayer 
		// so we cast our target from Object to that.
		// TODO Check instanceOf; Check it's a point layer; Check there's only 1
		// TODO Figure out how to handle a collection of point layers
		final ILayer myLayer = (ILayer) target;
		

		// Get the cannonical references to Elements of the running app
		final String myLayerName = myLayer.getName();
		final IMap myIMap = myLayer.getMap();
		
		
		final Project myProject = (Project) ApplicationGIS.getActiveProject();
		
//		CoordinateReferenceSystem theCoordRefSys = null;
		CoordinateReferenceSystem sourceCoordRefSys; // get from target layer
		CoordinateReferenceSystem targetCoordRefSys = myLayer.getMap().getViewportModel().getCRS();
		
//////	 STEP 0: Get a buffer distance from the user
		
		// TODO UNIT! Get the units from the renderer and set in the dialog.
		//              This will need to be set in a global variable 
		//              buffering_unit so the dialog can grab thevalue and set 
		//              it for presentation as the default unit.
		// N.B. If we want to buffer on the original layer, this code will have
		// to move lower down and be changed to get the unit from the layer.
		
		
		display.syncExec(new Runnable(){
			public void run() {
				
				open(display);
			}
		});
		
		System.out.println("The DD is: " + 
				            theDD.distance + 
				            " in units: " + 
				            theDD.unit);
		
		
		// TODO:Cleanup - remove.
        System.out.println("Got the user to provide a buffer distance.");
		
        
        	
        	
////// STEP 1: Get access to the target's features
		// TODO Convert to use expressions? This code accesses the feature 
		// contents directly which works as of uDig 1.1M4 and Geotools 2.2.pre0
		// but is not guaranteed to work forever.
        final IGeoResource myIGR = myLayer.getGeoResource(FeatureSource.class);
        FeatureSource myFS = null;
        	if (myIGR.canResolve(FeatureSource.class)) {
        	   	try {
        	   			
        	   		myFS = myIGR.resolve(FeatureSource.class, monitor);
        	   			
        	   	} catch (Exception e) {
        	   		System.out.println(
        	   			 "Resolving the IGeoResource failed with exception "+e);
        	   		// TODO: re-emit the exception, bail from the operation.
        	   	}
        	}
        	FeatureCollection myFC = myFS.getFeatures();
        // TODO:Cleanup - remove.
        System.out.println("Got to access the target's features.");
        
        
        
        
        
////// STEP 2: Validate       TODO
    	//  1) all features share a common CRS 
    	//  2) not too many 
        // For now, because they are from a shapefile, they will share a CRS
        // and we can assume the shapefile is reasonable)

         
        
        
////// STEP 3: Get access to the geometries and buffer them into a new geom.
        // TODO: CRITICAL the distance is defined in terms of the geom CRS.
        // TODO: Handle the buffering of zero distance.-->It's a union
        // TODO: Handle the case of unprojected coordinates.
        // TODO: Add tolerance to the zero distance check.
        Iterator myFCIter = null; 		//Always close it after use!
		Geometry z = null;
		MathTransform trans = null;
       	try {
    		myFCIter = myFC.iterator();
    		Feature f = (Feature) myFCIter.next();
    		sourceCoordRefSys = 
  			  f.getFeatureType().getDefaultGeometry().getCoordinateSystem();
//    		System.out.println(sourceCoordRefSys);
//    		System.out.println(targetCoordRefSys);
    		
    		//This may throw a factoryException
    		trans = CRS.transform(sourceCoordRefSys, targetCoordRefSys, true);
    		
    		Geometry oldg = f.getDefaultGeometry();
    		Geometry g = JTS.transform(oldg, trans);
    		if (0.0 == theDD.distance){
    			z = g;
    		} else {
    			z = g.buffer(theDD.distance);
    		}
//    		System.out.println(oldg);
//    		System.out.println(g);
//    		System.out.println(z);
//    		System.out.println(z.getGeometryType());
    		
    		
        	while (  myFCIter.hasNext()){ 
    			f = (Feature) myFCIter.next();
    			oldg = f.getDefaultGeometry();
    			g = JTS.transform(oldg, trans);
    			//TODO: assert that the geometries have the same CRS as z.
    			if(0.0 == theDD.distance){
        			z = z.union(g);
        		} else {
        			z = z.union(g.buffer(theDD.distance));
        		}
    		}
//    	} catch (FactoryException fe){ //from the transform
//    		System.out.println("Grrr.l 232 exception on transform---factoryEx.");
    	}
    	finally {
    		myFC.close( myFCIter );
    	}
    	// TODO:Cleanup - remove.
    	System.out.println("Got to access the geometries and made the buffer.");
        
        
        	
        	
////// STEP 4: Make a feature from the geometries
        	
//////// 4.1: Make the FeatureType using a factory
////////// 4.1.1: Make the GeometryAttributeType
    	GeometryAttributeType myGT = null;
    	AttributeType myGeomAT = null;
    	
    	// TODO: ASK how do we make this more robust to changes in geometry?
    	Class c = Class.forName("com.vividsolutions.jts.geom."+ z.getGeometryType());
    	try {
    		myGeomAT = AttributeTypeFactory.newAttributeType("the_geom", 
					c, true, 1, null,targetCoordRefSys);
    	} catch (Exception e){
    		System.out.println("The exception is: "+ e.getMessage());
    	}
    	// A less elegant approach, robust to change of package but doesn't 
    	// pick up new types of geometry. Which is better?
//    	try {
//    		if ("Point" == z.getGeometryType()){
//        		myGeomAT = AttributeTypeFactory.newAttributeType("the_geom", 
//    					Point.class, true, 1, null,targetCoordRefSys);
//    		} else if ("MultiPoint" == z.getGeometryType()){
//        		myGeomAT = AttributeTypeFactory.newAttributeType("the_geom", 
//    					MultiPoint.class, true, 1, null,targetCoordRefSys);
//    		} else if ("LineString" == z.getGeometryType()){
//        		myGeomAT = AttributeTypeFactory.newAttributeType("the_geom", 
//    					LineString.class, true, 1, null,targetCoordRefSys);
//    		}  else if ("MultiLineString" == z.getGeometryType()){
//        		myGeomAT = AttributeTypeFactory.newAttributeType("the_geom", 
//        				MultiLineString.class, true, 1, null,targetCoordRefSys);
//    		} else if ("Polygon" == z.getGeometryType()){
//        		myGeomAT = AttributeTypeFactory.newAttributeType("the_geom", 
//        				Polygon.class, true, 1, null,targetCoordRefSys);
//    		} else if ("MultiPolygon" == z.getGeometryType()){
//        		myGeomAT = AttributeTypeFactory.newAttributeType("the_geom", 
//        				MultiPolygon.class, true, 1, null,targetCoordRefSys);
//    		} 
//    	} catch (Exception e){
//    		System.out.println("The exception is: "+ e.getMessage());
//    	}
    	
    	if (myGeomAT instanceof GeometryAttributeType){
    		myGT = (GeometryAttributeType) myGeomAT;
    	}
    	
    	FeatureTypeBuilder myFTBuilder = FeatureTypeBuilder.newInstance(
    												"orgOreadMultiPolyBUILDER");
    	// TODO: Add a better check to ensure the name is unique.
    	// The name must be unique for repeated buffering. Name clashes probably
    	// fail in the memoryDataStore creation routine.
    	myFTBuilder.setName(myLayerName 
    						+ ":Buffered-" 
    						+ System.currentTimeMillis() 
    						+ "ms");
    	myFTBuilder.setDefaultGeometry(myGT);
    	FeatureType myBufferFT = myFTBuilder.getFeatureType();
        
//////// 4.2: Now make the Feature
    	Feature myBufferF = null;	
        myBufferF = myBufferFT.create(new Object[] {z}, 
        									"orgOreadbufferedPointsFEATURE");
        // TODO:Cleanup - remove.
        System.out.println("Got to make the buffer Feature.");	
        
        
        
        
        
////// STEP 5: Turn the Geotools Feature into a uDig Layer
                
        List<IGeoResource> geoResourceList2 = null, myGRList = null;
        
	   // Use the CatalogPlugin convenience method:
	   //   1) get an IGeoResource through the convenience method
	   //   2) resolve the IGeoResource to get a FeatureStore of some kind.
	   //   3) get an iterator on a List of features to add
	   //   4) use the deprecated!? addFeatures with a FeatureReader
	   //   5) create the Layer

        System.out.println("...using the modern approach.");
        
        IGeoResource newIGR = CatalogPlugin.getDefault().getLocalCatalog().
                                      createTemporaryResource( myBufferFT );
   		
        FeatureStore newFS = null;
    	if (newIGR.canResolve(FeatureStore.class)) {
    	   	try {
    	   			
    	   		newFS = newIGR.resolve(FeatureStore.class, monitor);;
    	   			
    	   	} catch (Exception e) {
    	   		System.err.println(
    	   		   "Resolving the IGeoResource failed with exception " + e);
    	   		// TODO: re-emit the exception, bail from the operation.
    	   	}
		}
    	
    	final Iterator<Feature> iter = Arrays.asList(myBufferF).iterator();

    	newFS.addFeatures( (FeatureReader) new FeatureReader(){
    	  public boolean hasNext(){  return iter.hasNext(); }
    	  public Feature next() { return iter.next(); }
    	  // TODO: what should this be?
    	  public void close() { ; }
    	  public void remove() {throw new UnsupportedOperationException();}
    	  public FeatureType getFeatureType(){return this.getFeatureType();}
    	  }
    	);
	        
    	// WHY? Creating the Layer is what adds it to the catalog!?
        LayerFactoryImpl myLF = LayerFactoryImpl.create();
        myLF.createLayer(newIGR);
        
        //Make a List <IGeoResource>
        myGRList = new ArrayList<IGeoResource> ();
        myGRList.add(newIGR);
        
        
        // TODO:Cleanup - remove.
        System.out.println("Got to create the layer.");
        
        
        
        
        
////// STEP 6: Add the layer to a Map
        
//////// Step 6a: Add the layer to the current map.
        ApplicationGIS.addLayersToMap(
        		       myLayer.getMap(),myGRList,myLayer.getZorder(),myProject);

	    // TODO:Cleanup - remove.
	    System.out.println("Got to add the layer to the map.");
      
        
      
      
      
      
      
///// STEP 7: Confirm we are done
        
      // TODO:Cleanup - remove.
      System.out.println("Got to end of the operation.\n");
        
	}

	
	/**
	 * This is the method which shows the dialog and stores the modifed data in
	 * the final global variable theDD, an instance of DialogData.
	 * The method also uses an inner class defining the verification code for 
	 * the freeform text box to ensure we get a postiive or zero number.
	 * 
	 * @param display The Display passed in from the Op method.
	 */
	public void open(Display display){
		
//		final DialogData opDD = new DialogData();
		
		// Using SWT directly
		final Shell s = new Shell(display,SWT.DIALOG_TRIM | SWT.RESIZE);
		s.setSize(340,500);
		s.setText("uDig-SpAn: Buffer a point layer");
		
		//Place in center of parent
		Rectangle rect = display.getActiveShell().getBounds();
		Point dialogSize = s.getSize();
		s.setLocation(
				rect.x + (rect.width - dialogSize.x) / 2,
				rect.y + (rect.height - dialogSize.y) /2
		);
		
	    // Create the shell's form layout
	    s.setLayout(new FormLayout());
	    
		// Make the 'perform' button, the base Composites, and add to the layout
	    FormData reusableFrmDat;

	    Button butPerform = new Button(s,SWT.PUSH);
	    doitCtrl = butPerform;
	    butPerform.setText("Perform Operation");
		reusableFrmDat = new FormData();
		reusableFrmDat.right = new FormAttachment(100,-10);
		reusableFrmDat.bottom = new FormAttachment(100,-10);
		butPerform.setLayoutData(reusableFrmDat);
		butPerform.addSelectionListener(new SelectionAdapter(){
		    public void widgetSelected(SelectionEvent se){
//		 	   theDD.setDistance(opDD.distance);
//		 	   theDD.setUnit(opDD.unit);
		 	   ((Button) se.widget).getShell().close();
		    }
	    });

		Composite titleComp = new Composite(s,SWT.NONE);
//		Composite titleComp = new Composite(s,SWT.BORDER);
		reusableFrmDat = new FormData();
		reusableFrmDat.top = new FormAttachment(0,5);
		reusableFrmDat.left = new FormAttachment(0,5);
		reusableFrmDat.right = new FormAttachment(100,-5);
		titleComp.setLayoutData(reusableFrmDat);
		
		Composite simpleSettingsComp = new Composite(s,SWT.BORDER);
		reusableFrmDat = new FormData();
		reusableFrmDat.top = new FormAttachment(titleComp,5);
		reusableFrmDat.left = new FormAttachment(0,5);
		reusableFrmDat.right = new FormAttachment(100,-5);
		simpleSettingsComp.setLayoutData(reusableFrmDat);
		
		Composite complexOptionsComp = new Composite(s,SWT.BORDER);
		reusableFrmDat = new FormData();
		reusableFrmDat.top = new FormAttachment(simpleSettingsComp,5);
		reusableFrmDat.left = new FormAttachment(0,5);
		reusableFrmDat.right = new FormAttachment(100,-5);
		complexOptionsComp.setLayoutData(reusableFrmDat);
		
		// HACK-A-RAMMA!
		Composite fillComp = new Composite(s,SWT.NONE);
		reusableFrmDat = new FormData();
		reusableFrmDat.top = new FormAttachment(complexOptionsComp,5);
		reusableFrmDat.left = new FormAttachment(0,5);
		reusableFrmDat.right = new FormAttachment(100,-5);
		reusableFrmDat.bottom = new FormAttachment(butPerform,-10);
		fillComp.setLayoutData(reusableFrmDat);
		
		////////////////////////////////////////////////////////////////////////
		// START OF SPECIFIC BLOCK
		// TODO: make the code below call into the generic code above and below
		//
		
			////////////////// TITLE CONTENTS  /////////////////////////////////
			titleComp.setLayout(new FormLayout());
			
			Label titleLab = new Label(titleComp,SWT.CENTER);
			titleLab.setText("Point Buffer Operation");
			Font titleFnt = new Font(null,"Arial", 18, SWT.BOLD);     //dispose!
			titleLab.setFont(titleFnt);
			reusableFrmDat = new FormData();
			reusableFrmDat.top = new FormAttachment(0,5);
			reusableFrmDat.left = new FormAttachment(0,5);
			reusableFrmDat.right = new FormAttachment(100,-5);
			titleLab.setLayoutData(reusableFrmDat);
			
			Label pictogramLab = new Label(titleComp,SWT.CENTER);
			Bundle bundle = Platform.getBundle("an.oread.operationsPlugin");
	        IPath path = new Path("icons/uDigSpAn-Buffer.png");
	        URL url = Platform.find(bundle, path);
			ImageDescriptor desc = ImageDescriptor.createFromURL(url);
			Image titleImg = desc.createImage();                      //dispose!
//			ImageRegistry registry = new ImageRegistry();
//			registry.put("uDigSpAn-Buffer", desc); 
//			Image titleImg = registry.get("uDigSpAn-Buffer");
			pictogramLab.setImage(titleImg);
			reusableFrmDat = new FormData();
			reusableFrmDat.top = new FormAttachment(titleLab,10);
			reusableFrmDat.left = new FormAttachment(0,5);
			reusableFrmDat.right = new FormAttachment(100,-5);
			pictogramLab.setLayoutData(reusableFrmDat);
			
			Label explanationLab = new Label(titleComp,SWT.WRAP);
			explanationLab.setText(
					"The Point Buffer Operation takes a layer containing " +
					"Features with point geometries and outputs a " +
					"multipolygon whose extent includes all the area " +
					"around the points up to the distance set below.");
			reusableFrmDat = new FormData();
			reusableFrmDat.top = new FormAttachment(pictogramLab,10);
			reusableFrmDat.left = new FormAttachment(0,10);
			reusableFrmDat.right = new FormAttachment(100,-10);
			reusableFrmDat.bottom = new FormAttachment(100,-10);
			explanationLab.setLayoutData(reusableFrmDat);
			
			////////////////// SIMPLE SETTINGS CONTENTS  ///////////////////////
			simpleSettingsComp.setLayout(new FormLayout());
			
				//Create a group for the distance input number and unit.
				///////////////////////////////////////////////// START OF GROUP
				Group g = new Group(simpleSettingsComp, SWT.BORDER);
				g.setText("Buffer Distance");
				reusableFrmDat = new FormData();
				reusableFrmDat.top = new FormAttachment(0,5);
				reusableFrmDat.left = new FormAttachment(0,5);
				reusableFrmDat.right = new FormAttachment(100,-5);
				reusableFrmDat.bottom = new FormAttachment(100,-5);
				reusableFrmDat.height = 50; //Otherwise it's too tall.
				g.setLayoutData(reusableFrmDat);
				g.setLayout(new FormLayout());
			    
				
				Label lab2 = new Label(g,SWT.CENTER);
			    lab2.setText("Distance: ");
				reusableFrmDat = new FormData();
				reusableFrmDat.top = new FormAttachment(0,10);
				reusableFrmDat.left = new FormAttachment(0,5);
				lab2.setLayoutData(reusableFrmDat);
		   
			    
			   	Text t = new Text(g, SWT.SINGLE | SWT.BORDER | SWT.FILL);
			   	// The listeners are defined in inner classes below; both ensure
			   	// that we obtain a non-negative number while handling keyboard
			   	// navigation.
				// Note the setText(...) call triggers the listeners.
			   	t.addVerifyListener(new DistanceVerifyListener());
			   	t.addModifyListener(new DistanceModifyListener());
			   	// TODO: FIXME make resizing work, now we set an absurd number.
//			   	t.setText("0.0");
//			   	t.setSize(1000,2000);
//			   	t.setBounds(10,10,100,20);
			   	t.setText("0000000.0");
			   	t.selectAll();
//			   	t.setSelection(0,7);
				reusableFrmDat = new FormData();
				reusableFrmDat.top = new FormAttachment(0,10);
				reusableFrmDat.left = new FormAttachment(lab2,5);
				t.setLayoutData(reusableFrmDat);
			   	
			   	
			   	Combo c = new Combo(g, SWT.DROP_DOWN |SWT.SINGLE | SWT.READ_ONLY );
			   	c.setItems( new String [] {"undefined","meter", "degree", "inch"});
			   	// The listener sets the unit in the DialogData struture opDD.
			   	c.addModifyListener(new ModifyListener(){
			   		public void modifyText(ModifyEvent me){
		       			theDD.setUnit(( (Combo) me.widget ).getText());
			   		};
			   	});
			   	c.select(0);
				reusableFrmDat = new FormData();
				reusableFrmDat.top = new FormAttachment(0,10);
				reusableFrmDat.left = new FormAttachment(t,5);
				c.setLayoutData(reusableFrmDat);
			    //TODO: Create the logic to handle units
				//TODO: Remove this setEnabled(false).
			    c.setEnabled(false);
				
				
				Composite fillCmpHoriz = new Composite(g,SWT.NONE);
				reusableFrmDat = new FormData();
				reusableFrmDat.top = new FormAttachment(0,10);
				reusableFrmDat.left = new FormAttachment(c,5);
				reusableFrmDat.right = new FormAttachment(100,-5);
				reusableFrmDat.height = 10;
				fillCmpHoriz.setLayoutData(reusableFrmDat);
			   	/////////////////////////////////////////////////// END OF GROUP

			////////////////// COMPLEX OPTIONS CONTENTS  ///////////////////////
			complexOptionsComp.setLayout(new FormLayout());
			
			//The DETAILS button
			Button bMod = new Button(complexOptionsComp,SWT.PUSH);
		    bMod.setText("Modify default settings ...");
			reusableFrmDat = new FormData();
			reusableFrmDat.top = new FormAttachment(0,5);
			reusableFrmDat.left = new FormAttachment(0,5);
			reusableFrmDat.bottom = new FormAttachment(100,-5);
			bMod.setLayoutData(reusableFrmDat);
			
		    //TODO: Create the other dialog groups: CRS, Ouput (to file)...
			//TODO: Remove this setEnabled(false).
			//TODO: Create listeners that change the dialog and reopen it.
		    bMod.setEnabled(false);
		    
		    t.setFocus();
		    
		    
	    
	    
		// END OF SPECIFIC BLOCK
		////////////////////////////////////////////////////////////////////////
		
	    s.open();
	    
	    while (!s.isDisposed() ){
    		   if (!display.readAndDispatch() )
    			   display.sleep();
    	}
	    
	    titleFnt.dispose();
	    titleImg.dispose();
	}
	

	/**
	 * This class is designed to ensure that the Distance text field remains 
	 * numeric and positive. This is a quick initial attempt which does not 
	 * address localization and other refined issues. 
	 * 
	 * @author acuster
	 *
	 */
	//TODO: Handle the 'return' value.
	private class DistanceVerifyListener implements VerifyListener{

 	   public void verifyText(VerifyEvent ve){
 		   
 		   Text theText = (Text) ve.widget;
 		   

 		   //Handle blanking the field
 		   if (0 == ve.text.length()){
 			   return;
 		   }
 		   
 		   // Handle the programatic setting of the value through a call with
 		   // many characters at once.
 		   if (1 < ve.text.length()){

 	 		   // Check the result appears to be a number. Note that this 
 	 		   // approach actually allows the programatic creation of java 
 			   // doubles like 23.4d which we don't want to accept.
 	 		   try{
 	 			   Double.parseDouble(ve.text);
 	 		   } catch (NumberFormatException nfEx){
 	 			   ve.doit = false;
 	 		   }
 	 		   return;
 		   }
 		   
 		   // TODO:Refactor to use a 'switch' statement.
 		   // TODO:Localization for number formats 24,000.00 vs. 24.000,00 
 		   // TODO:Robustness - handle scientific notation: 1.2232E34
 		   // Handle the common case, where a user types in a single character
 		   // at a time into the Text field.
 		   char c = ve.text.charAt(0);
// 		   System.out.println("verifyEvent c is: "+c);
 		   
 		   //Handle <Enter>
 		   if (SWT.CR == c){
 			  ve.doit = false;
 			  return;
 		   }
 		   
 		   //Handle <Tab>
 		   //TODO UNITS change the focus to the unit.
 		   if (SWT.TAB == c){
  			  ve.doit = false;
  			  doitCtrl.setFocus();
 			  return;
 		   }
 		   
 		   //Handle a leading "."
 		   if (('.' == c) && (0 == theText.getText().length())){
 			   ve.text = new String ("0.");
 			   return;
 		   }
 		   
 		   String newString = 
 			  theText.getText().substring(0,ve.start) +
 			  ve.text +
 			  theText.getText().substring( ve.end, theText.getText().length() );
 		   
 		   // Check the input text is acceptable.
 		   //TODO: deal with locale commas, etc.
 		   String validChars = "0123456789.";
 		   if (-1 == validChars.indexOf(c)){
 			   ve.doit = false;
 			   return;
 		   }
 		   
 		   // Check the result appears to be a number. Note that this approach
 		   // allows the java numbers 23.4d and 2443.0f which we don't want to
 		   // accept.
 		   try{
 			   Double.parseDouble(newString);
 		   } catch (NumberFormatException nfEx){
 			   ve.doit = false;
 		   }
 	   
   		}
	}//end of class DistanceVerificationListener
	
	/**
	 * This handles the modifications. We dropped opDD from here, from the 
	 * "Perform Operation" button, and from its declaration at the begining of 
	 * the operation.
	 */
	private class DistanceModifyListener implements ModifyListener{
		
   		public void modifyText(ModifyEvent me){

   			String newDistStr = ((Text) me.widget ).getText();
   			
   			// Allow blanking
	  		if (0 == newDistStr.length()){
	  			return;
	  		}
   			
   			double d = -1.0;
   			// Need to check because the value may be set programtically 
   			// eventhough when this is triggered by UI we have just checked the
   			// number is parsable.
  		   try{
  			   d = Double.parseDouble(newDistStr);
 		   } catch (NumberFormatException nfEx){
 			   System.out.println("We win a NumberFormatException!");
 		   }
  			   
  		   theDD.setDistance(d);
   		}
	}
	
	
	/**
	 * This class holds the data we wish to obtain from the user through the 
	 * dialog.
	 * 
	 * @author acuster
	 *
	 */
	private class DialogData {
		double distance;
		String unit = null;
		
		//Should not be needed since we should not access these before they are 
		// set. Check by commenting out.
//		DialogData(){
//			this.distance = 0.0;
//			this.unit = "meter";
//		}
		
		void setDistance(double d){
			this.distance = d;
		}
		double getDistance(){;
			return distance;
		}
		void setUnit(String u){
			this.unit = u;
		}
		String getUnit(){
			return unit;
		}
	}//end of class DialogData
	
		
	
}

Back to the top