Source Code Cross Referenced for PolygonHandler.java in  » GIS » GeoTools-2.4.1 » org » geotools » data » shapefile » shp » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.data.shapefile.shp 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2002-2006, Geotools Project Managment Committee (PMC)
005:         *    (C) 2002, Centre for Computational Geography
006:         *
007:         *    This library is free software; you can redistribute it and/or
008:         *    modify it under the terms of the GNU Lesser General Public
009:         *    License as published by the Free Software Foundation; either
010:         *    version 2.1 of the License, or (at your option) any later version.
011:         *
012:         *    This library is distributed in the hope that it will be useful,
013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         *    Lesser General Public License for more details.
016:         */
017:        package org.geotools.data.shapefile.shp;
018:
019:        import java.nio.ByteBuffer;
020:        import java.util.ArrayList;
021:        import java.util.List;
022:        import java.util.logging.Logger;
023:
024:        import com.vividsolutions.jts.algorithm.CGAlgorithms;
025:        import com.vividsolutions.jts.algorithm.RobustCGAlgorithms;
026:        import com.vividsolutions.jts.geom.Coordinate;
027:        import com.vividsolutions.jts.geom.Envelope;
028:        import com.vividsolutions.jts.geom.Geometry;
029:        import com.vividsolutions.jts.geom.GeometryFactory;
030:        import com.vividsolutions.jts.geom.LinearRing;
031:        import com.vividsolutions.jts.geom.MultiPolygon;
032:        import com.vividsolutions.jts.geom.Polygon;
033:
034:        /**
035:         * Wrapper for a Shapefile polygon.
036:         * @author aaime
037:         * @author Ian Schneider
038:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/plugin/shapefile/src/main/java/org/geotools/data/shapefile/shp/PolygonHandler.java $
039:         * @version $Id: PolygonHandler.java 27862 2007-11-12 19:51:19Z desruisseaux $
040:         */
041:        public class PolygonHandler implements  ShapeHandler {
042:            GeometryFactory geometryFactory = new GeometryFactory();
043:            RobustCGAlgorithms cga = new RobustCGAlgorithms();
044:
045:            final ShapeType shapeType;
046:
047:            public PolygonHandler() {
048:                shapeType = ShapeType.POLYGON;
049:            }
050:
051:            public PolygonHandler(ShapeType type) throws ShapefileException {
052:                if ((type != ShapeType.POLYGON) && (type != ShapeType.POLYGONM)
053:                        && (type != ShapeType.POLYGONZ)) {
054:                    throw new ShapefileException(
055:                            "PolygonHandler constructor - expected type to be 5, 15, or 25.");
056:                }
057:
058:                shapeType = type;
059:            }
060:
061:            //returns true if testPoint is a point in the pointList list.
062:            boolean pointInList(Coordinate testPoint, Coordinate[] pointList) {
063:                Coordinate p;
064:
065:                for (int t = pointList.length - 1; t >= 0; t--) {
066:                    p = pointList[t];
067:
068:                    if ((testPoint.x == p.x)
069:                            && (testPoint.y == p.y)
070:                            && ((testPoint.z == p.z) || (!(testPoint.z == testPoint.z))) //nan test; x!=x iff x is nan
071:                    ) {
072:                        return true;
073:                    }
074:                }
075:
076:                return false;
077:            }
078:
079:            public ShapeType getShapeType() {
080:                return shapeType;
081:            }
082:
083:            public int getLength(Object geometry) {
084:                MultiPolygon multi;
085:
086:                if (geometry instanceof  MultiPolygon) {
087:                    multi = (MultiPolygon) geometry;
088:                } else {
089:                    multi = geometryFactory
090:                            .createMultiPolygon(new Polygon[] { (Polygon) geometry });
091:                }
092:
093:                int nrings = 0;
094:
095:                for (int t = 0; t < multi.getNumGeometries(); t++) {
096:                    Polygon p;
097:                    p = (Polygon) multi.getGeometryN(t);
098:                    nrings = nrings + 1 + p.getNumInteriorRing();
099:                }
100:
101:                int npoints = multi.getNumPoints();
102:                int length;
103:
104:                if (shapeType == ShapeType.POLYGONZ) {
105:                    length = 44 + (4 * nrings) + (16 * npoints) + (8 * npoints)
106:                            + 16 + (8 * npoints) + 16;
107:                } else if (shapeType == ShapeType.POLYGONM) {
108:                    length = 44 + (4 * nrings) + (16 * npoints) + (8 * npoints)
109:                            + 16;
110:                } else if (shapeType == ShapeType.POLYGON) {
111:                    length = 44 + (4 * nrings) + (16 * npoints);
112:                } else {
113:                    throw new IllegalStateException(
114:                            "Expected ShapeType of Polygon, got " + shapeType);
115:                }
116:                return length;
117:            }
118:
119:            public Object read(ByteBuffer buffer, ShapeType type) {
120:                if (type == ShapeType.NULL) {
121:                    return createNull();
122:                }
123:                //bounds
124:                buffer.position(buffer.position() + 4 * 8);
125:
126:                int[] partOffsets;
127:
128:                int numParts = buffer.getInt();
129:                int numPoints = buffer.getInt();
130:
131:                partOffsets = new int[numParts];
132:
133:                for (int i = 0; i < numParts; i++) {
134:                    partOffsets[i] = buffer.getInt();
135:                }
136:
137:                ArrayList shells = new ArrayList();
138:                ArrayList holes = new ArrayList();
139:                Coordinate[] coords = readCoordinates(buffer, numPoints);
140:
141:                if (shapeType == ShapeType.POLYGONZ) {
142:                    //z
143:                    buffer.position(buffer.position() + 2 * 8);
144:
145:                    for (int t = 0; t < numPoints; t++) {
146:                        coords[t].z = buffer.getDouble();
147:                    }
148:                }
149:
150:                int offset = 0;
151:                int start;
152:                int finish;
153:                int length;
154:
155:                for (int part = 0; part < numParts; part++) {
156:                    start = partOffsets[part];
157:
158:                    if (part == (numParts - 1)) {
159:                        finish = numPoints;
160:                    } else {
161:                        finish = partOffsets[part + 1];
162:                    }
163:
164:                    length = finish - start;
165:
166:                    // Use the progressive CCW algorithm.
167:                    // basically the area algorithm for polygons
168:                    // which also tells us vertex order based upon the
169:                    // sign of the area.
170:                    Coordinate[] points = new Coordinate[length];
171:                    //double area = 0;
172:                    //int sx = offset;
173:                    for (int i = 0; i < length; i++) {
174:                        points[i] = coords[offset++];
175:                        //int j = sx + (i + 1) % length;
176:                        //area += points[i].x * coords[j].y;
177:                        //area -= points[i].y * coords[j].x;
178:                    }
179:                    //area = -area / 2;
180:                    //REVISIT: polyons with only 1 or 2 points are not polygons - geometryFactory will bomb so we skip if we find one.
181:                    if (points.length == 0 || points.length > 3) {
182:                        LinearRing ring = geometryFactory
183:                                .createLinearRing(points);
184:
185:                        if (CGAlgorithms.isCCW(points)) {
186:                            // counter-clockwise
187:                            holes.add(ring);
188:                        } else {
189:                            // clockwise
190:                            shells.add(ring);
191:                        }
192:                    }
193:                }
194:
195:                // quick optimization: if there's only one shell no need to check
196:                // for holes inclusion
197:                if (shells.size() == 1) {
198:                    return createMulti((LinearRing) shells.get(0), holes);
199:                }
200:                // if for some reason, there is only one hole, we just reverse it and carry on.
201:                else if (holes.size() == 1 && shells.size() == 0) {
202:                    org.geotools.util.logging.Logging.getLogger(
203:                            "org.geotools.data.shapefile").warning(
204:                            "only one hole in this polygon record");
205:                    return createMulti(JTSUtilities
206:                            .reverseRing((LinearRing) holes.get(0)));
207:                } else {
208:
209:                    // build an association between shells and holes
210:                    final ArrayList holesForShells = assignHolesToShells(
211:                            shells, holes);
212:
213:                    Geometry g = buildGeometries(shells, holes, holesForShells);
214:
215:                    return g;
216:                }
217:            }
218:
219:            /**
220:             * @param buffer
221:             * @param numPoints
222:             */
223:            private Coordinate[] readCoordinates(final ByteBuffer buffer,
224:                    final int numPoints) {
225:                Coordinate[] coords = new Coordinate[numPoints];
226:
227:                for (int t = 0; t < numPoints; t++) {
228:                    coords[t] = new Coordinate(buffer.getDouble(), buffer
229:                            .getDouble());
230:                }
231:
232:                return coords;
233:            }
234:
235:            /**
236:             * @param shells
237:             * @param holes
238:             * @param holesForShells
239:             */
240:            private Geometry buildGeometries(final List shells,
241:                    final List holes, final List holesForShells) {
242:                Polygon[] polygons;
243:
244:                // if we have shells, lets use them
245:                if (shells.size() > 0) {
246:                    polygons = new Polygon[shells.size()];
247:                    // oh, this is a bad record with only holes
248:                } else {
249:                    polygons = new Polygon[holes.size()];
250:                }
251:
252:                // this will do nothing for the "only holes case"
253:                for (int i = 0; i < shells.size(); i++) {
254:                    polygons[i] = geometryFactory.createPolygon(
255:                            (LinearRing) shells.get(i),
256:                            (LinearRing[]) ((ArrayList) holesForShells.get(i))
257:                                    .toArray(new LinearRing[0]));
258:                }
259:
260:                // this will take care of the "only holes case"
261:                // we just reverse each hole
262:                if (shells.size() == 0) {
263:                    for (int i = 0, ii = holes.size(); i < ii; i++) {
264:                        LinearRing hole = (LinearRing) holes.get(i);
265:                        polygons[i] = geometryFactory.createPolygon(
266:                                JTSUtilities.reverseRing(hole),
267:                                new LinearRing[0]);
268:                    }
269:                }
270:
271:                Geometry g = geometryFactory.createMultiPolygon(polygons);
272:
273:                return g;
274:            }
275:
276:            /** 
277:             * <b>Package private for testing</b>
278:             * @param shells
279:             * @param holes
280:             */
281:            ArrayList assignHolesToShells(final ArrayList shells,
282:                    final ArrayList holes) {
283:                ArrayList holesForShells = new ArrayList(shells.size());
284:                for (int i = 0; i < shells.size(); i++) {
285:                    holesForShells.add(new ArrayList());
286:                }
287:
288:                //find homes
289:                for (int i = 0; i < holes.size(); i++) {
290:                    LinearRing testRing = (LinearRing) holes.get(i);
291:                    LinearRing minShell = null;
292:                    Envelope minEnv = null;
293:                    Envelope testEnv = testRing.getEnvelopeInternal();
294:                    Coordinate testPt = testRing.getCoordinateN(0);
295:                    LinearRing tryRing;
296:
297:                    for (int j = 0; j < shells.size(); j++) {
298:                        tryRing = (LinearRing) shells.get(j);
299:
300:                        Envelope tryEnv = tryRing.getEnvelopeInternal();
301:                        if (minShell != null) {
302:                            minEnv = minShell.getEnvelopeInternal();
303:                        }
304:
305:                        boolean isContained = false;
306:                        Coordinate[] coordList = tryRing.getCoordinates();
307:
308:                        if (tryEnv.contains(testEnv)
309:                                && (CGAlgorithms.isPointInRing(testPt,
310:                                        coordList) || (pointInList(testPt,
311:                                        coordList)))) {
312:                            isContained = true;
313:                        }
314:
315:                        // check if this new containing ring is smaller than the current minimum ring
316:                        if (isContained) {
317:                            if ((minShell == null) || minEnv.contains(tryEnv)) {
318:                                minShell = tryRing;
319:                            }
320:                        }
321:                    }
322:
323:                    if (minShell == null) {
324:                        org.geotools.util.logging.Logging
325:                                .getLogger("org.geotools.data.shapefile")
326:                                .warning(
327:                                        "polygon found with a hole thats not inside a shell");
328:                        // now reverse this bad "hole" and turn it into a shell
329:                        shells.add(JTSUtilities.reverseRing(testRing));
330:                        holesForShells.add(new ArrayList());
331:                    } else {
332:                        ((ArrayList) holesForShells.get(shells
333:                                .indexOf(minShell))).add(testRing);
334:                    }
335:                }
336:
337:                return holesForShells;
338:            }
339:
340:            private MultiPolygon createMulti(LinearRing single) {
341:                return createMulti(single, java.util.Collections.EMPTY_LIST);
342:            }
343:
344:            private MultiPolygon createMulti(LinearRing single, List holes) {
345:                return geometryFactory
346:                        .createMultiPolygon(new Polygon[] { geometryFactory
347:                                .createPolygon(single, (LinearRing[]) holes
348:                                        .toArray(new LinearRing[holes.size()])) });
349:            }
350:
351:            private MultiPolygon createNull() {
352:                return geometryFactory.createMultiPolygon(null);
353:            }
354:
355:            public void write(ByteBuffer buffer, Object geometry) {
356:                MultiPolygon multi;
357:
358:                if (geometry instanceof  MultiPolygon) {
359:                    multi = (MultiPolygon) geometry;
360:                } else {
361:                    multi = geometryFactory
362:                            .createMultiPolygon(new Polygon[] { (Polygon) geometry });
363:                }
364:
365:                Envelope box = multi.getEnvelopeInternal();
366:                buffer.putDouble(box.getMinX());
367:                buffer.putDouble(box.getMinY());
368:                buffer.putDouble(box.getMaxX());
369:                buffer.putDouble(box.getMaxY());
370:
371:                //need to find the total number of rings and points
372:                int nrings = 0;
373:
374:                for (int t = 0; t < multi.getNumGeometries(); t++) {
375:                    Polygon p;
376:                    p = (Polygon) multi.getGeometryN(t);
377:                    nrings = nrings + 1 + p.getNumInteriorRing();
378:                }
379:
380:                int u = 0;
381:                int[] pointsPerRing = new int[nrings];
382:
383:                for (int t = 0; t < multi.getNumGeometries(); t++) {
384:                    Polygon p;
385:                    p = (Polygon) multi.getGeometryN(t);
386:                    pointsPerRing[u] = p.getExteriorRing().getNumPoints();
387:                    u++;
388:
389:                    for (int v = 0; v < p.getNumInteriorRing(); v++) {
390:                        pointsPerRing[u] = p.getInteriorRingN(v).getNumPoints();
391:                        u++;
392:                    }
393:                }
394:
395:                int npoints = multi.getNumPoints();
396:
397:                buffer.putInt(nrings);
398:                buffer.putInt(npoints);
399:
400:                int count = 0;
401:
402:                for (int t = 0; t < nrings; t++) {
403:                    buffer.putInt(count);
404:                    count = count + pointsPerRing[t];
405:                }
406:
407:                //write out points here!
408:                Coordinate[] coords = multi.getCoordinates();
409:
410:                for (int t = 0; t < coords.length; t++) {
411:                    buffer.putDouble(coords[t].x);
412:                    buffer.putDouble(coords[t].y);
413:                }
414:
415:                if (shapeType == ShapeType.POLYGONZ) {
416:                    //z
417:                    double[] zExtreame = JTSUtilities.zMinMax(multi
418:                            .getCoordinates());
419:
420:                    if (Double.isNaN(zExtreame[0])) {
421:                        buffer.putDouble(0.0);
422:                        buffer.putDouble(0.0);
423:                    } else {
424:                        buffer.putDouble(zExtreame[0]);
425:                        buffer.putDouble(zExtreame[1]);
426:                    }
427:
428:                    for (int t = 0; t < npoints; t++) {
429:                        double z = coords[t].z;
430:
431:                        if (Double.isNaN(z)) {
432:                            buffer.putDouble(0.0);
433:                        } else {
434:                            buffer.putDouble(z);
435:                        }
436:                    }
437:                }
438:
439:                if (shapeType == ShapeType.POLYGONM
440:                        || shapeType == ShapeType.POLYGONZ) {
441:                    //m
442:                    buffer.putDouble(-10E40);
443:                    buffer.putDouble(-10E40);
444:
445:                    for (int t = 0; t < npoints; t++) {
446:                        buffer.putDouble(-10E40);
447:                    }
448:                }
449:            }
450:
451:        }
452:
453:        /*
454:         * $Log: PolygonHandler.java,v $
455:         * Revision 1.9  2004/02/17 18:10:23  ianschneider
456:         * changed to use GeometryFactory for Geometry creation
457:         *
458:         * Revision 1.8  2003/07/24 19:10:02  ianschneider
459:         * *** empty log message ***
460:         *
461:         * Revision 1.7  2003/07/24 18:32:10  ianschneider
462:         * more test updates, fixed Z type writing
463:         *
464:         * Revision 1.6  2003/07/23 23:41:09  ianschneider
465:         * more testing updates
466:         *
467:         * Revision 1.5  2003/07/23 00:59:59  ianschneider
468:         * Lots of PMD fix ups
469:         *
470:         * Revision 1.4  2003/07/21 21:15:29  jmacgill
471:         * small fix for shapefiles with an invalid hole (only 1 or 2 points)
472:         *
473:         * Revision 1.3  2003/05/19 21:38:55  jmacgill
474:         * refactored read method to break it up a little
475:         *
476:         * Revision 1.2  2003/05/19 20:51:30  ianschneider
477:         * removed System.out print statements
478:         *
479:         * Revision 1.1  2003/05/14 17:51:21  ianschneider
480:         * migrated packages
481:         *
482:         * Revision 1.3  2003/04/30 23:19:46  ianschneider
483:         * Added construction of multi geometries for default return values, even if only one geometry.
484:         * This could have effects through system.
485:         *
486:         * Revision 1.2  2003/03/30 20:21:09  ianschneider
487:         * Moved buffer branch to main
488:         *
489:         * Revision 1.1.2.5  2003/03/29 22:30:09  ianschneider
490:         * For case of hole without shell - reverse hole, add to shell list
491:         *
492:         * Revision 1.1.2.4  2003/03/26 19:30:30  ianschneider
493:         * Made hack to reverse polygon records if they contains only holes
494:         *
495:         * Revision 1.1.2.3  2003/03/12 15:30:18  ianschneider
496:         * made ShapeType final for handlers - once they're created, it won't change.
497:         *
498:         * Revision 1.1.2.2  2003/03/07 00:36:41  ianschneider
499:         *
500:         * Added back the additional ShapeType parameter in ShapeHandler.read. ShapeHandler's need
501:         * return their own special "null" shape if needed. Fixed the ShapefileReader to not throw
502:         * exceptions for "null" shapes. Fixed ShapefileReader to accomodate junk after the last valid
503:         * record. The theory goes, if the shape number is proper, that is, one greater than the
504:         * previous, we consider that a valid record and attempt to read it. I suppose, by chance, the
505:         * junk could coincide with the next record number. Stupid ESRI. Fixed some record-length
506:         * calculations which resulted in writing of bad shapefiles.
507:         *
508:         * Revision 1.1.2.1  2003/03/06 01:16:34  ianschneider
509:         *
510:         * The initial changes for moving to java.nio. Added some documentation and improved
511:         * exception handling. Works for reading, may work for writing as of now.
512:         *
513:         * Revision 1.1  2003/02/27 22:35:50  aaime
514:         * New shapefile module, initial commit
515:         *
516:         * Revision 1.2  2003/01/22 18:31:05  jaquino
517:         * Enh: Make About Box configurable
518:         *
519:         * Revision 1.2  2002/09/09 20:46:22  dblasby
520:         * Removed LEDatastream refs and replaced with EndianData[in/out]putstream
521:         *
522:         * Revision 1.1  2002/08/27 21:04:58  dblasby
523:         * orginal
524:         *
525:         * Revision 1.3  2002/03/05 10:51:01  andyt
526:         * removed use of factory from write method
527:         *
528:         * Revision 1.2  2002/03/05 10:23:59  jmacgill
529:         * made sure geometries were created using the factory methods
530:         *
531:         * Revision 1.1  2002/02/28 00:38:50  jmacgill
532:         * Renamed files to more intuitve names
533:         *
534:         * Revision 1.4  2002/02/13 00:23:53  jmacgill
535:         * First semi working JTS version of Shapefile code
536:         *
537:         * Revision 1.3  2002/02/11 18:44:22  jmacgill
538:         * replaced geometry constructions with calls to geometryFactory.createX methods
539:         *
540:         * Revision 1.2  2002/02/11 18:28:41  jmacgill
541:         * rewrote to have static read and write methods
542:         *
543:         * Revision 1.1  2002/02/11 16:54:43  jmacgill
544:         * added shapefile code and directories
545:         *
546:         */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.