/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2006-2008, Open Source Geospatial Foundation (OSGeo) * * This library 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; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package tigerOtherPoly; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.geotools.data.DataStore; import org.geotools.data.DefaultQuery; import org.geotools.data.DefaultTransaction; import org.geotools.data.FeatureReader; import org.geotools.data.FeatureSource; import org.geotools.data.FeatureStore; import org.geotools.data.FeatureWriter; import org.geotools.data.Query; import org.geotools.data.SchemaNotFoundException; import org.geotools.data.memory.MemoryDataStore; import org.geotools.data.postgis.PostgisDataStore; import org.geotools.data.postgis.PostgisDataStoreFactory; import org.geotools.feature.Feature; import org.geotools.feature.FeatureType; import org.geotools.filter.AttributeExpression; import org.geotools.filter.AttributeExpressionImpl; import org.geotools.filter.AttributeExpressionImpl2; import org.geotools.filter.CompareFilter; import org.geotools.filter.Filter; import org.geotools.filter.FilterFactory; import org.geotools.filter.FilterType; import org.geotools.filter.IllegalFilterException; import org.geotools.filter.LikeFilter; import org.geotools.filter.LogicFilter; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.MultiPolygon; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.index.strtree.SIRtree; import com.vividsolutions.jts.index.strtree.STRtree; import com.vividsolutions.jts.operation.linemerge.LineMerger; import com.vividsolutions.jts.operation.polygonize.Polygonizer; import com.vividsolutions.jts.simplify.TopologyPreservingSimplifier; /** * CREATE TABLE county_boundary AS SELECT * FROM completechain WHERE statel isnull or stater isnull or countyl isnull or countyr isnull or ( (statel||'-'||countyl) != (stater||'-'||countyr) ); alter table county_boundary add primary key (module,tlid); insert into geometry_columns values ('','','county_boundary','wkb_geometry',2,1,'GEOMETRY'); create index county_boundary_indx1 on county_boundary (statel,countyl); create index county_boundary_indx2 on county_boundary (stater,countyr); vacuum analyse county_boundary; * @author david blasby */ public class County { String MODULE = ""; String state = ""; String county =""; double tolerance1 = 0.00005; // 50% reduction double tolerance2 = 0.00025; // 75% reduction double tolerance3 = 0.00080; //87% reduction ArrayList lines = new ArrayList(); DataStore ds = null; Collection resultPolygon =null; /** * reads the completechain dataset * @throws Exception */ public void getrows() throws Exception { //SELECT ... FROM ... WHERE // (statel=state and countyl=county) OR (stater=state and countyr=county ) FilterFactory ff = FilterFactory.createFilterFactory(); CompareFilter cf1 = ff.createCompareFilter(FilterType.COMPARE_EQUALS); cf1.addLeftValue( ff.createAttributeExpression( null, "statel") ); cf1.addRightValue( ff.createLiteralExpression(state)); CompareFilter cf2 = ff.createCompareFilter(FilterType.COMPARE_EQUALS); cf2.addLeftValue( ff.createAttributeExpression( null, "countyl") ); cf2.addRightValue( ff.createLiteralExpression(county)); LogicFilter and1 = ff.createLogicFilter(cf1,cf2,Filter.LOGIC_AND); CompareFilter cf3 = ff.createCompareFilter(FilterType.COMPARE_EQUALS); cf3.addLeftValue( ff.createAttributeExpression( null, "stater") ); cf3.addRightValue( ff.createLiteralExpression(state)); CompareFilter cf4 = ff.createCompareFilter(FilterType.COMPARE_EQUALS); cf4.addLeftValue( ff.createAttributeExpression( null, "countyr") ); cf4.addRightValue( ff.createLiteralExpression(county)); LogicFilter and2 = ff.createLogicFilter(cf3,cf4,Filter.LOGIC_AND); LogicFilter or = ff.createLogicFilter(and1,and2,Filter.LOGIC_OR); String[] ps = new String []{"wkb_geometry","statel","countyl","stater","countyr"}; Query q = new DefaultQuery("county_boundary",or,ps); FeatureReader fr = ds.getFeatureReader(q, new DefaultTransaction() ); while (fr.hasNext()) { Feature f= fr.next(); if (!alreadyThere(f.getDefaultGeometry())) lines.add(f.getDefaultGeometry()); } fr.close(); } private void parseModule() throws Exception { Pattern p = Pattern.compile("TGR([0123456789][0123456789])([0123456789][0123456789][0123456789])"); // \\z --> $ (end of line) Matcher m = p.matcher(MODULE); if ( m.matches()) { state = m.group(1); county = m.group(2); } else throw new Exception("cannot parse module:"+MODULE); } /** * dbname=tiger2005fe user=postgres host=localhost * * parses the PG connect string into geotools postgis datastore params * * pg_Connect("host=myHost port=myPort dbname=myDB user=myUser password=myPassword "); * @param connectstring * @return * @throws Exception */ public static Map parsePG(String connectstring) throws Exception { Map param = new HashMap(); Pattern p = Pattern.compile(".*host=([^ ]+).*"); Matcher m = p.matcher(connectstring); if (m.matches()) { param.put("host",m.group(1)); } else { param.put("host","localhost"); } p = Pattern.compile(".*user=([^ ]+).*"); m = p.matcher(connectstring); if (m.matches()) { param.put("user",m.group(1)); } else { throw new Exception("PG CONNECT string does not contain a user name. connect string should look like: 'host=myHost port=myPort dbname=myDB user=myUser password=myPassword'"); } p = Pattern.compile(".*dbname=([^ ]+).*"); m = p.matcher(connectstring); if (m.matches()) { param.put("database",m.group(1)); } else { throw new Exception("PG CONNECT string does not contain a dbname. connect string should look like: 'host=myHost port=myPort dbname=myDB user=myUser password=myPassword'"); } p = Pattern.compile(".*port=([^ ]+).*"); m = p.matcher(connectstring); if (m.matches()) { param.put("port",m.group(1)); } else { param.put("port","5432"); } p = Pattern.compile(".*password=([^ ]+).*"); m = p.matcher(connectstring); if (m.matches()) { param.put("passwd",m.group(1)); } else { //do nothing } return param; } public static void main(String[] args) { if ( (args.length !=2) && (args.length !=3) ) { System.out.println("usage: \"host=myHost port=myPort dbname=myDB user=myUser password=myPassword\" <module name> "); System.out.println("dont forget to:"); System.out.println("1. put quotes around the postgresql connection string"); System.out.println("2. pre-create the output database table:"); return; } County THIS = new County(); PostgisDataStoreFactory pgdsf = new PostgisDataStoreFactory(); try{ Map param = parsePG(args[0]); param.put("wkb enabled","true"); param.put("loose bbox","true"); param.put("dbtype","postgis"); THIS.ds = pgdsf.createDataStore(param); THIS.MODULE = args[1]; THIS.parseModule(); System.out.println("start state = "+THIS.state+" county="+THIS.county); System.out.println("loading rows..."); THIS.getrows(); System.out.println("loaded rows"); System.out.println("Processing..."); THIS.process(); System.out.println("Saving..."); THIS.save(); System.out.println("Done!"); } catch (SchemaNotFoundException ee) { System.out.println("you need to have major_roads in your database:"); System.out.println(" create table poly_county ("); System.out.println(" module text, "); System.out.println(" gen_full geometry,"); System.out.println(" gen_1 geometry,"); System.out.println(" gen_2 geometry,"); System.out.println(" gen_3 geometry) with oids;"); System.out.println("insert into geometry_columns values ('','','poly_county','gen_full',2,1,'GEOMETRY');"); System.out.println("insert into geometry_columns values ('','','poly_county','gen_1',2,1,'GEOMETRY');"); System.out.println("insert into geometry_columns values ('','','poly_county','gen_2',2,1,'GEOMETRY');"); System.out.println("insert into geometry_columns values ('','','poly_county','gen_3',2,1,'GEOMETRY');"); } catch (Exception e) { e.printStackTrace(); } } private Geometry generalize(Geometry g, double tolerance) { return TopologyPreservingSimplifier.simplify(g,tolerance); } /** * */ private void save() throws Exception { FeatureStore fs = (FeatureStore) ds.getFeatureSource("poly_county"); FeatureType ft = fs.getSchema(); MemoryDataStore memorystore =new MemoryDataStore(); ArrayList polys = new ArrayList(resultPolygon); Geometry gfinal = null; if (polys.size() == 1) { gfinal = (Polygon) polys.get(0); //POLYGON } else { GeometryFactory gf = ((Polygon) polys.get(0)).getFactory(); gfinal = new MultiPolygon((Polygon[]) polys.toArray( new Polygon[polys.size()]), gf ); } gfinal = gfinal.buffer(0); // for topologic problems. Object[] values = new Object[5]; values[ft.find("module")] = MODULE; values[ft.find("gen_full")] = gfinal; values[ft.find("gen_1")] = generalize(gfinal,tolerance1);; values[ft.find("gen_2")] = generalize(gfinal,tolerance1);; values[ft.find("gen_3")] = generalize(gfinal,tolerance1);; Feature f = ft.create(values); memorystore.addFeature(f); fs.addFeatures(memorystore.getFeatureReader("poly_county")); } /** * */ private void process() throws Exception { if (lines.size() ==0 ) { throw new Exception("polygon has no edges"); } Polygonizer polyizer = new Polygonizer(); polyizer.add(lines); Collection builtpolys = polyizer.getPolygons(); if (polyizer.getCutEdges().size() != 0) { throw new Exception("polygon has cut edges"); } if (polyizer.getDangles().size() != 0) { throw new Exception("polygon has dandgle edges"); } if (polyizer.getInvalidRingLines().size() != 0) { throw new Exception("polygon has invalid edges"); // System.out.println("poly has invalid edges "+polyid_long); } resultPolygon = builtpolys; } private boolean alreadyThere(Geometry g) { Iterator it = lines.iterator(); while (it.hasNext()) { Geometry lineg = (Geometry) it.next(); if (lineg.equalsExact(g)) return true; else if (equalsExactBackwards(lineg,g)) return true; } return false; } /** * reverse direction of points in a line */ LineString reverse(LineString l) { List clist = Arrays.asList(l.getCoordinates() ); Collections.reverse( clist ); return l.getFactory().createLineString( (Coordinate[]) clist.toArray(new Coordinate[1] ) ); } /** * @param lineg * @param g * @return */ private boolean equalsExactBackwards(Geometry lineg, Geometry g) { if (lineg.getNumPoints() != g.getNumPoints()) return false; return reverse( (LineString) g).equalsExact(lineg); } }