[Schmitzm-commits] r920 - in trunk: src/schmitzm/geotools/feature src/schmitzm/jfree/feature/style src_junit/schmitzm/geotools/feature src_junit/schmitzm/jfree/feature/style

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Thu Jul 1 17:45:24 CEST 2010


Author: mojays
Date: 2010-07-01 17:45:20 +0200 (Thu, 01 Jul 2010)
New Revision: 920

Added:
   trunk/src/schmitzm/geotools/feature/FeatureComparator.java
   trunk/src_junit/schmitzm/geotools/feature/FeatureComparatorTest.java
Modified:
   trunk/src/schmitzm/geotools/feature/FeatureUtil.java
   trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java
   trunk/src_junit/schmitzm/jfree/feature/style/FeatureChartStyleTest.java
Log:
new FeatureComparator to compare features by multiple attributes
new FeatureComparatorTest
FeatureUtil.sortFeatures(.): support of multiple ordering attributes
FeatureChartUtil: Sorting features also by series attribute (on grouping) during dataset creation with sorted domain axis

Added: trunk/src/schmitzm/geotools/feature/FeatureComparator.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/FeatureComparator.java	2010-07-01 13:34:07 UTC (rev 919)
+++ trunk/src/schmitzm/geotools/feature/FeatureComparator.java	2010-07-01 15:45:20 UTC (rev 920)
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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 Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+
+package schmitzm.geotools.feature;
+
+import java.util.Comparator;
+
+import org.geotools.feature.FeatureComparators;
+import org.opengis.feature.simple.SimpleFeature;
+
+/**
+ * This class is an extension of {@link FeatureComparators.Name}.
+ * In contrast to {@link FeatureComparators.Name}, respectively
+ * {@link FeatureComparators.Index}, this class allows to specify MULTIPLE
+ * attributes (names or indices) which are compared sequently.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class FeatureComparator implements Comparator<SimpleFeature> {
+
+  /** Holds the comparators for each attribute which is included in
+   *  the comparison. */
+  protected Comparator<SimpleFeature>[] attrComp = null;
+  
+  /**
+   * Creates a new comparator.
+   * @param attrName compare attributes in the order of comparison.
+   */
+  public FeatureComparator(String... attrName) {
+    if ( attrName == null || attrName.length < 1 )
+      throw new IllegalArgumentException("At least one attribute must be specified for FeatureComparator.");
+    // Create comparators for each attribute
+    this.attrComp = new Comparator[attrName.length];
+    for (int i=0; i<attrComp.length; i++) {
+      if ( attrName[i] == null )
+        throw new IllegalArgumentException("NULL not allowed as comparation attribute: "+i);
+      this.attrComp[i] = FeatureComparators.byAttributeName(attrName[i]);
+    }
+  }
+  
+  /**
+   * Creates a new comparator.
+   * @param attrIdx compare attributes (by index) in the order of comparison.
+   */
+  public FeatureComparator(int... attrIdx) {
+    if ( attrIdx == null || attrIdx.length < 1 )
+      throw new IllegalArgumentException("At least one attribute must be specified for FeatureComparator.");
+    // Create comparators for each attribute
+    this.attrComp = new Comparator[attrIdx.length];
+    for (int i=0; i<attrComp.length; i++) {
+      if ( attrIdx[i] < 0 )
+        throw new IllegalArgumentException("Negative indices are not allowed as comparation attribute: "+i+" ("+attrIdx[i]+")");
+      this.attrComp[i] = FeatureComparators.byAttributeIndex(attrIdx[i]);
+    }
+  }
+  
+  /**
+   * Compares all comparison attributes of two features.
+   * @return a negative value if {@code f1 < f2}, a positive value if {@code f1 > f2} or
+   *         zero if {@code f1} and {@code f2} equal in all comparison attributes.  
+   */
+  @Override
+  public int compare(SimpleFeature f1, SimpleFeature f2) {
+    for (int i=0; i<attrComp.length; i++) {
+      int comp = attrComp[i].compare(f1, f2);
+      if ( comp != 0 )
+        return comp;
+    }
+    // no difference in all attributes
+    // -> Features are equal
+    return 0;
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/feature/FeatureUtil.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/FeatureUtil.java	2010-07-01 13:34:07 UTC (rev 919)
+++ trunk/src/schmitzm/geotools/feature/FeatureUtil.java	2010-07-01 15:45:20 UTC (rev 920)
@@ -780,12 +780,12 @@
 	 * @param fi
 	 *            the features to order
 	 * @param attrName
-	 *            the attribute to order by
+	 *            the attribute(s) to order by
 	 * @return a list of ordered features
 	 */
 	public static Vector<SimpleFeature> sortFeatures(
 			FeatureCollection<SimpleFeatureType, SimpleFeature> fc,
-			String attrName) {
+			String... attrName) {
 		final FeatureCollection<SimpleFeatureType, SimpleFeature> source = fc;
 		FeatureIterator<SimpleFeature> iterator = source.features();
 		try {
@@ -806,35 +806,52 @@
 	 * @param fi
 	 *            an iterator for the features
 	 * @param attrName
-	 *            the attribute to order by
+	 *            the attribute(s) to order by
 	 * @return a list of ordered features
 	 */
 	protected static Vector<SimpleFeature> sortFeatures(
-			FeatureIterator<SimpleFeature> fi, String attrName) {
+			FeatureIterator<SimpleFeature> fi, String... attrName) {
+	  
+	    // Create a comparator for sorting in order to
+	    // the sort attributes
+	    FeatureComparator fComp = new FeatureComparator(attrName);
+	  
+	  
 		// First create a SortedMap with CollisionList
-		SortedMap<Comparable<?>, Vector<SimpleFeature>> sortedFeatureLists = new TreeMap<Comparable<?>, Vector<SimpleFeature>>();
+		SortedMap<SimpleFeature, Vector<SimpleFeature>> sortedFeatureLists = new TreeMap<SimpleFeature, Vector<SimpleFeature>>(fComp);
+		
 		for (; fi.hasNext();) {
 			SimpleFeature f = fi.next();
-			// Check whether attribute value is Comparable
-			Object attrValue = f.getAttribute(attrName);
-			if (attrValue != null && !(attrValue instanceof Comparable))
-				throw new UnsupportedOperationException(
-						"SimpleFeature sort only supported for Comparable attributes: "
-								+ LangUtil.getSimpleClassName(attrValue));
-			// Determine X value as sort attribute (NULL not permitted for
-			// XYDateset!)
-			Comparable<?> xValue = (Comparable<?>) attrValue;
-			if (xValue == null)
-				continue;
+//			// Check whether attribute value is Comparable
+//			Object attrValue = f.getAttribute(attrName);
+//			if (attrValue != null && !(attrValue instanceof Comparable))
+//				throw new UnsupportedOperationException(
+//						"SimpleFeature sort only supported for Comparable attributes: "
+//								+ LangUtil.getSimpleClassName(attrValue));
+//			// Determine X value as sort attribute (NULL not permitted for
+//			// XYDateset!)
+//			Comparable<?> xValue = (Comparable<?>) attrValue;
+//			if (xValue == null)
+//				continue;
+//
+//			// Check whether collision list exists
+//			Vector<SimpleFeature> collList = sortedFeatureLists.get(xValue);
+//			if (collList == null) {
+//				collList = new Vector<SimpleFeature>();
+//				sortedFeatureLists.put(xValue, collList);
+//			}
+//			// Add feature to collision list
+//			collList.add(f);
 
-			// Check whether collision list exists
-			Vector<SimpleFeature> collList = sortedFeatureLists.get(xValue);
-			if (collList == null) {
-				collList = new Vector<SimpleFeature>();
-				sortedFeatureLists.put(xValue, collList);
-			}
-			// Add feature to collision list
-			collList.add(f);
+            // Check whether collision list exists
+            Vector<SimpleFeature> collList = sortedFeatureLists.get(f);
+            if (collList == null) {
+                collList = new Vector<SimpleFeature>();
+                sortedFeatureLists.put(f, collList);
+            }
+            // Add feature to collision list
+            collList.add(f);
+		
 		}
 
 		// Put the (now ordered) features from the collision lists

Modified: trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java	2010-07-01 13:34:07 UTC (rev 919)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java	2010-07-01 15:45:20 UTC (rev 920)
@@ -253,8 +253,14 @@
     FeatureIterator<SimpleFeature> features = null;
     Iterator<SimpleFeature> fi = null;
     if (chartStyle.isSortDomainAxis()) {
-      Vector<SimpleFeature> sortedFeatures = FeatureUtil.sortFeatures(fc,
-                                                                      xAttrName);
+      // Sorting attribute(s) -> Category attribute
+      String[] sortAttr = new String[] {xAttrName};
+      // If grouping is used so create series, also sort by
+      // this attribute, so that the series are also sorted
+      // "inside" every category
+      if ( chartStyle.getSeriesAttributeName() != null )
+        sortAttr = LangUtil.extendArray(sortAttr, chartStyle.getSeriesAttributeName());
+      Vector<SimpleFeature> sortedFeatures = FeatureUtil.sortFeatures(fc,sortAttr);
       // Create an Iterator for the sorted Features
       fi = sortedFeatures.iterator();
     } else {
@@ -660,8 +666,14 @@
     FeatureIterator<SimpleFeature> features = null;
     Iterator<SimpleFeature> fi = null;
     if (chartStyle.isSortDomainAxis()) {
-      Vector<SimpleFeature> sortedFeatures = FeatureUtil.sortFeatures(fc,
-                                                                      xAttrName);
+      // Sorting attribute(s) -> Category attribute
+      String[] sortAttr = new String[] {xAttrName};
+      // If grouping is used so create series, also sort by
+      // this attribute, so that the series are also sorted
+      // "inside" every category
+      if ( chartStyle.getSeriesAttributeName() != null )
+        sortAttr = LangUtil.extendArray(sortAttr, chartStyle.getSeriesAttributeName());
+      Vector<SimpleFeature> sortedFeatures = FeatureUtil.sortFeatures(fc,sortAttr);
       // Create an Iterator for the sorted Features
       fi = sortedFeatures.iterator();
     } else {

Added: trunk/src_junit/schmitzm/geotools/feature/FeatureComparatorTest.java
===================================================================
--- trunk/src_junit/schmitzm/geotools/feature/FeatureComparatorTest.java	2010-07-01 13:34:07 UTC (rev 919)
+++ trunk/src_junit/schmitzm/geotools/feature/FeatureComparatorTest.java	2010-07-01 15:45:20 UTC (rev 920)
@@ -0,0 +1,109 @@
+package schmitzm.geotools.feature;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.GraphicsEnvironment;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.geotools.feature.FeatureCollection;
+import org.geotools.feature.FeatureIterator;
+import org.junit.Test;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+import org.opengis.feature.type.GeometryDescriptor;
+
+import schmitzm.geotools.feature.FeatureUtil.GeometryForm;
+import schmitzm.geotools.io.GeoImportUtil;
+import schmitzm.jfree.feature.style.FeatureChartStyleTest;
+
+import com.vividsolutions.jts.geom.Point;
+import com.vividsolutions.jts.geom.Polygon;
+
+
+public class FeatureComparatorTest {
+  /** If tests are run on a system with head, we may theoretically open dialgs, frames etc. **/
+
+  boolean INTERACTIVE = !GraphicsEnvironment.isHeadless();
+  
+  String resLocation = "/schmitzm/jfree/feature/style/testLineChartShape/testKreiseLineChart.shp";
+  
+	@Test
+	public void testFeatureComparator() throws Exception {
+      // Testdatenshape einlesen
+      URL resourceUrl = FeatureChartStyleTest.class.getResource(
+                      resLocation);
+      assertNotNull(resLocation+" wurde nicht gefunden!",
+              resourceUrl);
+      FeatureCollection<SimpleFeatureType, SimpleFeature> testFeatures = GeoImportUtil
+              .readFeaturesFromShapeURL(resourceUrl);
+      assertNotNull("Testfeatures konnten nicht aus " + resourceUrl
+              + " gelesen werden", testFeatures);
+
+      String[] sortAttr = new String[] {"dm_u3","jahr" };
+      
+      // Show features unsorted
+      System.out.println("**** FEATURES UNSORTED ****");
+      showFeatures(new PipedFeatureIterator(testFeatures.features()),false,sortAttr);
+      // Sort features
+      Vector<SimpleFeature> testFeaturesSorted = FeatureUtil.sortFeatures(testFeatures, sortAttr);
+      // Show features unsorted
+      System.out.println("**** FEATURES SORTED ****");
+      showFeatures(testFeaturesSorted.iterator(),true,sortAttr);
+      
+      
+	
+	}
+	
+	/**
+	 * Shows features.
+	 * @param fi an iterator for the features
+	 * @param checkSorting indicates whether the ordering is checked during showing
+	 * @param attrName the attributes which are shown (and checked for ordering)
+	 */
+	private void showFeatures(Iterator<SimpleFeature> fi, boolean checkSorting, String... attrName) {
+      // Show features unsorted
+      SimpleFeature  lastFeature = null;
+      for (;fi.hasNext();) {
+        SimpleFeature f = fi.next();
+        // Show ID and the specified attributes 
+        if ( INTERACTIVE ) {
+          System.out.print(f.getID() + "\t");
+          for (String name : attrName)
+            System.out.print( f.getAttribute(name) + "\t");
+          System.out.println();
+        }
+        // Check sorting if at least 2 Features are present (optional)
+        if ( checkSorting && lastFeature != null )
+          checkAscendingSort(lastFeature,f,attrName);
+
+        lastFeature = f;
+      }
+	}
+
+	/**
+	 * Checks whether f1 <= f2 by fundamental methods :-)
+	 * If not an assertion is thrown.
+	 * @param lastFeature a feature
+	 * @param f           another feature
+	 */
+	private void checkAscendingSort(SimpleFeature f1, SimpleFeature f2, String... attrName) {
+      for (String name : attrName) {
+        Object a1 = f1.getAttribute(name);
+        Object a2 = f2.getAttribute(name);
+        // Attribute values must be Comparable
+        assertTrue("a1 must be Comparable", a1 instanceof Comparable);
+        assertTrue("a2 must be Comparable", a2 instanceof Comparable);
+
+        // f1 must be <= f2
+        int comp = ((Comparable)a1).compareTo(a2);
+        assertTrue("a1."+name+" must be <= a2."+name+"("+a1+" <= "+a2+")", comp <= 0);
+        // if f1 < f2, the other attributes must be ignored
+        if ( comp < 0 )
+          break;
+	  }
+	}
+}

Modified: trunk/src_junit/schmitzm/jfree/feature/style/FeatureChartStyleTest.java
===================================================================
--- trunk/src_junit/schmitzm/jfree/feature/style/FeatureChartStyleTest.java	2010-07-01 13:34:07 UTC (rev 919)
+++ trunk/src_junit/schmitzm/jfree/feature/style/FeatureChartStyleTest.java	2010-07-01 15:45:20 UTC (rev 920)
@@ -106,6 +106,8 @@
 		barChartStyle.setTooltips(true);
 
 		barChartStyle.setSeriesAttributeName(groupAttribName);
+		
+		barChartStyle.setSortDomainAxis(true);
 
 		assertNull("Wenn nicht explizit gesetzt wird null geliefert",
 				barChartStyle.getRendererStyle(0));



More information about the Schmitzm-commits mailing list