Source Code Cross Referenced for SDO.java in  » GIS » GeoTools-2.4.1 » org » geotools » data » oracle » sdo » 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.oracle.sdo 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *    GeoTools - OpenSource mapping toolkit
0003:         *    http://geotools.org
0004:         *    (C) 2003-2006, Geotools Project Managment Committee (PMC)
0005:         *    (C) 2003  Refractions Research Inc.
0006:         *    
0007:         *    This library is free software; you can redistribute it and/or
0008:         *    modify it under the terms of the GNU Lesser General Public
0009:         *    License as published by the Free Software Foundation; either
0010:         *    version 2.1 of the License, or (at your option) any later version.
0011:         *
0012:         *    This library is distributed in the hope that it will be useful,
0013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015:         *    Lesser General Public License for more details.
0016:         *
0017:         *    Refractions Research Inc. Can be found on the web at:
0018:         *    http://www.refractions.net/
0019:         */
0020:        package org.geotools.data.oracle.sdo;
0021:
0022:        import java.lang.reflect.Array;
0023:        import java.text.MessageFormat;
0024:        import java.util.ArrayList;
0025:        import java.util.Iterator;
0026:        import java.util.LinkedList;
0027:        import java.util.List;
0028:        import java.util.logging.Logger;
0029:
0030:        import com.vividsolutions.jts.algorithm.RobustCGAlgorithms;
0031:        import com.vividsolutions.jts.geom.Coordinate;
0032:        import com.vividsolutions.jts.geom.CoordinateSequence;
0033:        import com.vividsolutions.jts.geom.CoordinateSequenceFactory;
0034:        import com.vividsolutions.jts.geom.Envelope;
0035:        import com.vividsolutions.jts.geom.Geometry;
0036:        import com.vividsolutions.jts.geom.GeometryCollection;
0037:        import com.vividsolutions.jts.geom.GeometryFactory;
0038:        import com.vividsolutions.jts.geom.LineString;
0039:        import com.vividsolutions.jts.geom.LinearRing;
0040:        import com.vividsolutions.jts.geom.MultiLineString;
0041:        import com.vividsolutions.jts.geom.MultiPoint;
0042:        import com.vividsolutions.jts.geom.MultiPolygon;
0043:        import com.vividsolutions.jts.geom.Point;
0044:        import com.vividsolutions.jts.geom.Polygon;
0045:
0046:        /**
0047:         * Oracle Spatial Data Object utilities functions.
0048:         * 
0049:         * <p>
0050:         * Provide utility functions for working with JTS Geometries in terms Oracle
0051:         * Spatial Data Objects
0052:         * </p>
0053:         *
0054:         * <p>
0055:         * This class can be used for normal JTS Geometry persistence with little fuss
0056:         * and bother - please see GeometryConverter for an example of this.
0057:         * <p>
0058:         * With a little fuss and bother LRS information can also be handled.
0059:         * Although it is very rare that JTS makes use of such things. 
0060:         * </p>
0061:         * @see <a href="http://otn.oracle.com/pls/db10g/db10g.to_toc?pathname=appdev.101%2Fb10826%2Ftoc.htm&remark=portal+%28Unstructured+data%29">Spatial User's Guide (10.1)</a>
0062:         * @author Jody Garnett, Refractions Reasearch Inc.
0063:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/oracle-spatial/src/main/java/org/geotools/data/oracle/sdo/SDO.java $
0064:         * @version CVS Version
0065:         *
0066:         * @see net.refractions.jspatial.jts
0067:         */
0068:        public final class SDO {
0069:            private static final Logger LOGGER = org.geotools.util.logging.Logging
0070:                    .getLogger("org.geotools.data.oracle.sdo");
0071:            public static final int SRID_NULL = -1;
0072:
0073:            /** Used to test for Counter Clockwise or Clockwise Linear Rings */
0074:            private static RobustCGAlgorithms clock = new RobustCGAlgorithms();
0075:
0076:            // 
0077:            // Encoding Helper Functions
0078:            //
0079:
0080:            /**
0081:             * Produce SDO_GTYPE representing provided Geometry.
0082:             * 
0083:             * <p>
0084:             * Encoding of Geometry type and dimension.
0085:             * </p>
0086:             * 
0087:             * <p>
0088:             * SDO_GTYPE defined as for digits <code>[d][l][tt]</code>:
0089:             * </p>
0090:             * 
0091:             * <ul>
0092:             * <li>
0093:             * <b><code>d</code>:</b> number of dimensions (limited to 2,3, or 4)
0094:             * </li>
0095:             * <li>
0096:             * <b><code>l</code>:</b> measure representation (ordinate 3 or 4) or 0 to
0097:             * represent none/last
0098:             * </li>
0099:             * <li>
0100:             * <b><code>tt:</code></b> See the TT. constants defined in this class
0101:             * </li>
0102:             * </ul>
0103:             * 
0104:             * <p>
0105:             * Definition provided by Oracle Spatial User�s Guide and Reference.
0106:             * </p>
0107:             *
0108:             * @param geom
0109:             *
0110:             */
0111:            public static int gType(Geometry geom) {
0112:                int d = D(geom) * 1000;
0113:                int l = L(geom) * 100;
0114:                int tt = TT(geom);
0115:
0116:                return d + l + tt;
0117:            }
0118:
0119:            /**
0120:             * Return D as defined by SDO_GTYPE (either 2,3 or 4).
0121:             * 
0122:             * <p>
0123:             * For normal JTS Geometry this will be 2 or 3 depending if
0124:             * geom.getCoordinate.z is Double.NaN.
0125:             * </p>
0126:             * 
0127:             * <p>
0128:             * Subclasses may override as required.
0129:             * </p>
0130:             *
0131:             * @param geom
0132:             *
0133:             * @return <code>3</code>
0134:             */
0135:            public static int D(Geometry geom) {
0136:                CoordinateSequenceFactory f = geom.getFactory()
0137:                        .getCoordinateSequenceFactory();
0138:
0139:                if (f instanceof  CoordinateAccessFactory) {
0140:                    return ((CoordinateAccessFactory) f).getDimension();
0141:                } else {
0142:                    //return 3;
0143:                    return Double.isNaN(geom.getCoordinate().z) ? 2 : 3;
0144:                }
0145:            }
0146:
0147:            /**
0148:             * Return L as defined by SDO_GTYPE (either 3,4 or 0).
0149:             * 
0150:             * <p>
0151:             * L represents support for LRS (Liniar Referencing System?). JTS Geometry
0152:             * objects do not support LRS so this will be 0.
0153:             * </p>
0154:             * 
0155:             * <p>
0156:             * Subclasses may override as required.
0157:             * </p>
0158:             *
0159:             * @param geom
0160:             *
0161:             * @return <code>0</code>
0162:             */
0163:            public static int L(Geometry geom) {
0164:                CoordinateSequenceFactory f = geom.getFactory()
0165:                        .getCoordinateSequenceFactory();
0166:
0167:                if (f instanceof  CoordinateAccessFactory) {
0168:                    return ((CoordinateAccessFactory) f).getDimension();
0169:                } else {
0170:                    return 0;
0171:                }
0172:            }
0173:
0174:            /**
0175:             * Return TT as defined by SDO_GTYPE (represents geometry type).
0176:             * 
0177:             * <p>
0178:             * TT is used to represent the type of the JTS Geometry:
0179:             * </p>
0180:             * <pre><code>
0181:             * <b>Value Geometry Type    JTS Geometry</b>
0182:             * 00    UNKNOWN_GEOMETRY null
0183:             * 01    POINT            Point
0184:             * 02    LINE             LineString
0185:             *       CURVE            <i>not supported</i>
0186:             * 03    POLYGON          Polygon
0187:             * 04    COLLECTION       GeometryCollection
0188:             * 05    MULTIPOINT       MultiPoint
0189:             * 06    MULTILINE        MultiLineString
0190:             *       MULTICURVE       <i>not supported</i>
0191:             * 07    MULTIPOLYGON     MultiPolygon
0192:             * </code></pre>
0193:             *
0194:             * @param geom
0195:             *
0196:             * @return <code>TT</code> representing <code>geom</code>
0197:             *
0198:             * @throws IllegalArgumentException If SDO_GTYPE can not be represetned by
0199:             *         JTS
0200:             */
0201:            public static int TT(Geometry geom) {
0202:                if (geom == null) {
0203:                    return TT.UNKNOWN; // UNKNOWN
0204:                } else if (geom instanceof  Point) {
0205:                    return TT.POINT;
0206:                } else if (geom instanceof  LineString) {
0207:                    return TT.LINE;
0208:                } else if (geom instanceof  Polygon) {
0209:                    return TT.POLYGON;
0210:                } else if (geom instanceof  MultiPoint) {
0211:                    return TT.MULTIPOINT;
0212:                } else if (geom instanceof  MultiLineString) {
0213:                    return TT.MULTILINE;
0214:                } else if (geom instanceof  MultiPolygon) {
0215:                    return TT.MULTIPOLYGON;
0216:                } else if (geom instanceof  GeometryCollection) {
0217:                    return TT.COLLECTION;
0218:                }
0219:
0220:                throw new IllegalArgumentException(
0221:                        "Cannot encode JTS "
0222:                                + geom.getGeometryType()
0223:                                + " as SDO_GTYPE "
0224:                                + "(Limitied to Point, Line, Polygon, GeometryCollection, MultiPoint,"
0225:                                + " MultiLineString and MultiPolygon)");
0226:            }
0227:
0228:            /**
0229:             * Returns geometry SRID.
0230:             * 
0231:             * <p>
0232:             * SRID code representing Spatial Reference System. SRID number used must
0233:             * be defined in the Oracle MDSYS.CS_SRS table.
0234:             * </p>
0235:             * 
0236:             * <p>
0237:             * <code>SRID_NULL</code>represents lack of coordinate system.
0238:             * </p>
0239:             *
0240:             * @param geom Geometry SRID Number (JTS14 uses GeometryFactor.getSRID() )
0241:             *
0242:             * @return <code>SRID</code> for provided geom
0243:             */
0244:            public static int SRID(Geometry geom) {
0245:                return geom.getSRID();
0246:            }
0247:
0248:            /**
0249:             * Return SDO_POINT_TYPE for geometry
0250:             * 
0251:             * <p>
0252:             * Will return non null for Point objects. <code>null</code> is returned
0253:             * for all non point objects.
0254:             * </p>
0255:             * 
0256:             * <p>
0257:             * You cannot use this with LRS Coordiantes
0258:             * </p>
0259:             * 
0260:             * <p>
0261:             * Subclasses may wish to repress this method and force Points to be
0262:             * represented using SDO_ORDINATES.
0263:             * </p>
0264:             *
0265:             * @param geom
0266:             *
0267:             */
0268:            public static double[] point(Geometry geom) {
0269:                if (geom instanceof  Point && (L(geom) == 0)) {
0270:                    Point point = (Point) geom;
0271:                    Coordinate coord = point.getCoordinate();
0272:
0273:                    return new double[] { coord.x, coord.y, coord.z };
0274:                }
0275:
0276:                // SDO_POINT_TYPE only used for non LRS Points
0277:                return null;
0278:            }
0279:
0280:            /**
0281:             * Return SDO_ELEM_INFO array for geometry
0282:             * 
0283:             * <p>
0284:             * Describes how to use Ordinates to represent Geometry.
0285:             * </p>
0286:             * <pre><code><b>
0287:             * # Name                Meaning</b>
0288:             * 0 SDO_STARTING_OFFSET Offsets start at one
0289:             * 1 SDO_ETYPE           Describes how ordinates are ordered
0290:             * 2 SDO_INTERPRETATION  SDO_ETYPE: 4, 1005, or 2005
0291:             *                       Number of triplets involved in compound geometry
0292:             *                       
0293:             *                       SDO_ETYPE: 1, 2, 1003, or 2003
0294:             *                       Describes ordering of ordinates in geometry  
0295:             * </code></pre>
0296:             * 
0297:             * <p>
0298:             * For compound elements (SDO_ETYPE values 4 and 5) the last element of one
0299:             * is the first element of the next.
0300:             * </p>
0301:             *
0302:             * @param geom Geometry being represented
0303:             *
0304:             * @return Descriptionof Ordinates representation
0305:             */
0306:            public static int[] elemInfo(Geometry geom) {
0307:                return elemInfo(geom, gType(geom));
0308:            }
0309:
0310:            public static int[] elemInfo(Geometry geom, final int GTYPE) {
0311:                List list = new LinkedList();
0312:                elemInfo(list, geom, 1, GTYPE);
0313:
0314:                return intArray(list);
0315:            }
0316:
0317:            /**
0318:             * Add to SDO_ELEM_INFO list for geometry and GTYPE.
0319:             *
0320:             * @param elemInfoList List used to gather SDO_ELEM_INFO
0321:             * @param geom Geometry to encode
0322:             * @param STARTING_OFFSET Starting offset in SDO_ORDINATES
0323:             * @param GTYPE Encoding of dimension, measures and geometry type
0324:             *
0325:             * @throws IllegalArgumentException If geom cannot be encoded by ElemInfo
0326:             */
0327:            private static void elemInfo(List elemInfoList, Geometry geom,
0328:                    final int STARTING_OFFSET, final int GTYPE) {
0329:                final int tt = TT(geom);
0330:
0331:                switch (tt) {
0332:                case TT.POINT:
0333:                    addElemInfo(elemInfoList, (Point) geom, STARTING_OFFSET);
0334:
0335:                    return;
0336:
0337:                case TT.LINE:
0338:                    addElemInfo(elemInfoList, (LineString) geom,
0339:                            STARTING_OFFSET);
0340:
0341:                    return;
0342:
0343:                case TT.POLYGON:
0344:                    addElemInfo(elemInfoList, (Polygon) geom, STARTING_OFFSET,
0345:                            GTYPE);
0346:
0347:                    return;
0348:
0349:                case TT.MULTIPOINT:
0350:                    addElemInfo(elemInfoList, (MultiPoint) geom,
0351:                            STARTING_OFFSET);
0352:
0353:                    return;
0354:
0355:                case TT.MULTILINE:
0356:                    addElemInfo(elemInfoList, (MultiLineString) geom,
0357:                            STARTING_OFFSET, GTYPE);
0358:
0359:                    return;
0360:
0361:                case TT.MULTIPOLYGON:
0362:                    addElemInfo(elemInfoList, (MultiPolygon) geom,
0363:                            STARTING_OFFSET, GTYPE);
0364:
0365:                    return;
0366:
0367:                case TT.COLLECTION:
0368:                    addElemInfo(elemInfoList, (GeometryCollection) geom,
0369:                            STARTING_OFFSET, GTYPE);
0370:
0371:                    return;
0372:                }
0373:
0374:                throw new IllegalArgumentException(
0375:                        "Cannot encode JTS "
0376:                                + geom.getGeometryType()
0377:                                + " as SDO_ELEM_INFO "
0378:                                + "(Limitied to Point, Line, Polygon, GeometryCollection, MultiPoint,"
0379:                                + " MultiLineString and MultiPolygon)");
0380:            }
0381:
0382:            /**
0383:             * Not often called as POINT_TYPE prefered over ELEMINFO & ORDINATES.
0384:             * 
0385:             * <p>
0386:             * This method is included to allow for multigeometry encoding.
0387:             * </p>
0388:             *
0389:             * @param elemInfoList List containing ELEM_INFO array
0390:             * @param point Point to encode
0391:             * @param STARTING_OFFSET Starting offset in SDO_ORDINATE array
0392:             */
0393:            private static void addElemInfo(List elemInfoList, Point point,
0394:                    final int STARTING_OFFSET) {
0395:                addInt(elemInfoList, STARTING_OFFSET);
0396:                addInt(elemInfoList, ETYPE.POINT);
0397:                addInt(elemInfoList, 1); // INTERPRETATION single point
0398:            }
0399:
0400:            private static void addElemInfo(List elemInfoList, LineString line,
0401:                    final int STARTING_OFFSET) {
0402:                addInt(elemInfoList, STARTING_OFFSET);
0403:                addInt(elemInfoList, ETYPE.LINE);
0404:                addInt(elemInfoList, 1); // INTERPRETATION straight edges        
0405:            }
0406:
0407:            private static void addElemInfo(List elemInfoList, Polygon polygon,
0408:                    final int STARTING_OFFSET, final int GTYPE) {
0409:                final int HOLES = polygon.getNumInteriorRing();
0410:
0411:                if (HOLES == 0) {
0412:                    addInt(elemInfoList, STARTING_OFFSET);
0413:                    addInt(elemInfoList, elemInfoEType(polygon));
0414:                    addInt(elemInfoList, elemInfoInterpretation(polygon,
0415:                            ETYPE.POLYGON_EXTERIOR));
0416:
0417:                    return;
0418:                }
0419:
0420:                int LEN = D(GTYPE) + L(GTYPE);
0421:                int offset = STARTING_OFFSET;
0422:                LineString ring;
0423:
0424:                ring = polygon.getExteriorRing();
0425:                addInt(elemInfoList, offset);
0426:                addInt(elemInfoList, elemInfoEType(polygon));
0427:                addInt(elemInfoList, elemInfoInterpretation(polygon,
0428:                        ETYPE.POLYGON_EXTERIOR));
0429:                offset += (ring.getNumPoints() * LEN);
0430:
0431:                for (int i = 1; i <= HOLES; i++) {
0432:                    ring = polygon.getInteriorRingN(i - 1);
0433:                    addInt(elemInfoList, offset);
0434:                    addInt(elemInfoList, ETYPE.POLYGON_INTERIOR);
0435:                    addInt(elemInfoList, elemInfoInterpretation(ring,
0436:                            ETYPE.POLYGON_INTERIOR));
0437:                    offset += (ring.getNumPoints() * LEN);
0438:                }
0439:            }
0440:
0441:            private static void addElemInfo(List elemInfoList,
0442:                    MultiPoint points, final int STARTING_OFFSET) {
0443:                addInt(elemInfoList, STARTING_OFFSET);
0444:                addInt(elemInfoList, ETYPE.POINT);
0445:                addInt(elemInfoList,
0446:                        elemInfoInterpretation(points, ETYPE.POINT));
0447:            }
0448:
0449:            private static void addElemInfo(List elemInfoList,
0450:                    MultiLineString lines, final int STARTING_OFFSET,
0451:                    final int GTYPE) {
0452:                LineString line;
0453:                int offset = STARTING_OFFSET;
0454:
0455:                int LEN = D(GTYPE) + L(GTYPE);
0456:
0457:                for (int i = 0; i < lines.getNumGeometries(); i++) {
0458:                    line = (LineString) lines.getGeometryN(i);
0459:                    addElemInfo(elemInfoList, line, offset);
0460:                    offset += (line.getNumPoints() * LEN);
0461:                }
0462:            }
0463:
0464:            private static void addElemInfo(List elemInfoList,
0465:                    MultiPolygon polys, final int STARTING_OFFSET,
0466:                    final int GTYPE) {
0467:                Polygon poly;
0468:                int offset = STARTING_OFFSET;
0469:
0470:                int LEN = D(GTYPE) + L(GTYPE);
0471:
0472:                for (int i = 0; i < polys.getNumGeometries(); i++) {
0473:                    poly = (Polygon) polys.getGeometryN(i);
0474:                    addElemInfo(elemInfoList, poly, offset, GTYPE);
0475:                    if (isRectangle(poly)) {
0476:                        offset += (2 * LEN);
0477:                    } else {
0478:                        offset += (poly.getNumPoints() * LEN);
0479:                    }
0480:                }
0481:            }
0482:
0483:            private static void addElemInfo(List elemInfoList,
0484:                    GeometryCollection geoms, final int STARTING_OFFSET,
0485:                    final int GTYPE) {
0486:                Geometry geom;
0487:                int offset = STARTING_OFFSET;
0488:                int LEN = D(GTYPE) + L(GTYPE);
0489:
0490:                for (int i = 0; i < geoms.getNumGeometries(); i++) {
0491:                    geom = geoms.getGeometryN(i);
0492:                    elemInfo(elemInfoList, geom, offset, GTYPE);
0493:                    if (geom instanceof  Polygon && isRectangle((Polygon) geom)) {
0494:                        offset += (2 * LEN);
0495:                    } else {
0496:                        offset += (geom.getNumPoints() * LEN);
0497:                    }
0498:                }
0499:            }
0500:
0501:            /**
0502:             * Adds contents of array to the list as Interger objects
0503:             *
0504:             * @param list List to append the contents of array to
0505:             * @param array Array of ints to append
0506:             */
0507:            private static void addInts(List list, int[] array) {
0508:                for (int i = 0; i < array.length; i++) {
0509:                    list.add(new Integer(array[i]));
0510:                }
0511:            }
0512:
0513:            private static void addInt(List list, int i) {
0514:                list.add(new Integer(i));
0515:            }
0516:
0517:            /**
0518:             * Converts provied list to an int array
0519:             *
0520:             * @param list List to cast to an array type
0521:             * @return array of ints 
0522:             */
0523:            private static int[] intArray(List list) {
0524:                int[] array = new int[list.size()];
0525:                int offset = 0;
0526:
0527:                for (Iterator i = list.iterator(); i.hasNext(); offset++) {
0528:                    array[offset] = ((Number) i.next()).intValue();
0529:                }
0530:
0531:                return array;
0532:            }
0533:
0534:            /**
0535:             * Starting offset used by SDO_ORDINATES as stored in the SDO_ELEM_INFO
0536:             * array.
0537:             * 
0538:             * <p>
0539:             * Starting offsets start from one.
0540:             * </p>
0541:             * 
0542:             * <p>
0543:             * Describes ordinates as part of <code>SDO_ELEM_INFO</code> data type.
0544:             * </p>
0545:             *
0546:             * @param geom
0547:             *
0548:             * @return <code>1</code> for non nested <code>geom</code>
0549:             */
0550:            public static int elemInfoStartingOffset(Geometry geom) {
0551:                return 1;
0552:            }
0553:
0554:            /**
0555:             * Produce <code>SDO_ETYPE</code> for geometry description as stored in the
0556:             * <code>SDO_ELEM_INFO</code>.
0557:             * 
0558:             * <p>
0559:             * Describes how Ordinates are ordered:
0560:             * </p>
0561:             * <pre><code><b>
0562:             * Value Elements Meaning</b>
0563:             *    0           Custom Geometry (like spline) 
0564:             *    1  simple   Point (or Points)
0565:             *    2  simple   Line (or Lines)
0566:             *    3           polygon ring of unknown order (discouraged update to 1003 or 2003)
0567:             * 1003  simple   polygon ring (1 exterior counterclockwise order)
0568:             * 2003  simple   polygon ring (2 interior clockwise order)
0569:             *    4  compound series defines a linestring
0570:             *    5  compound series defines a polygon ring of unknown order (discouraged)
0571:             * 1005  compound series defines exterior polygon ring (counterclockwise order)
0572:             * 2005  compound series defines interior polygon ring (clockwise order)
0573:             * </code></pre>
0574:             * 
0575:             * <p>
0576:             * Keep in mind:
0577:             * </p>
0578:             * 
0579:             * <ul>
0580:             * <li>
0581:             * <code>simple</code> elements are defined by a single triplet entry in
0582:             * the <code>SDO_ELEM_INFO</code> array
0583:             * </li>
0584:             * <li>
0585:             * <code>compound</code> elements are defined by a header triplet, and a
0586:             * series of triplets for the parts. Elements in a compound element share
0587:             * first and last points.
0588:             * </li>
0589:             * <li>
0590:             * We are not allowed to mix 1 digit and 4 digit values for ETYPE and GTYPE
0591:             * in a single geometry
0592:             * </li>
0593:             * </ul>
0594:             * 
0595:             * <p>
0596:             * This whole mess describes ordinates as part of
0597:             * <code>SDO_ELEM_INFO</code> array. data type.
0598:             * </p>
0599:             *
0600:             * @param geom Geometry being represented
0601:             *
0602:             * @return Descriptionof Ordinates representation
0603:             *
0604:             * @throws IllegalArgumentException
0605:             */
0606:            protected static int elemInfoEType(Geometry geom) {
0607:                switch (TT(geom)) {
0608:                case TT.UNKNOWN:
0609:                    return ETYPE.CUSTOM;
0610:
0611:                case TT.POINT:
0612:                    return ETYPE.POINT;
0613:
0614:                case TT.LINE:
0615:                    return ETYPE.LINE;
0616:
0617:                case TT.POLYGON:
0618:                    return isExterior((Polygon) geom) ? ETYPE.POLYGON_EXTERIOR // cc order
0619:                            : ETYPE.POLYGON_INTERIOR; // ccw order
0620:
0621:                default:
0622:
0623:                    // should never happen!
0624:                    throw new IllegalArgumentException(
0625:                            "Unknown encoding of SDO_GTYPE");
0626:                }
0627:            }
0628:
0629:            /**
0630:             * Produce <code>SDO_INTERPRETATION</code> for geometry description as
0631:             * stored in the <code>SDO_ELEM_INFO</code>.
0632:             * 
0633:             * <p>
0634:             * Describes ordinates as part of <code>SDO_ELEM_INFO</code> array.
0635:             * </p>
0636:             * 
0637:             * <ul>
0638:             * <li>
0639:             * <b><code>compound</code> element:</b>(SDO_ETYPE 4, 1005, or 2005)<br>
0640:             * Number of subsequent triplets are part of compound element
0641:             * </li>
0642:             * <li>
0643:             * <b><code>simple</code> element:</b>(SDE_ELEM 1, 2, 1003, or 2003)<br>
0644:             * Code defines how ordinates are interpreted (lines or curves)
0645:             * </li>
0646:             * </ul>
0647:             * 
0648:             * <p>
0649:             * SDO_INTERPRETAION Values: (from Table 2-2 in reference docs)
0650:             * </p>
0651:             * <pre><code><b>
0652:             * SDO_ETYPE Value    Meaning</b>
0653:             * 0         anything Custom Geometry
0654:             * 1         1        Point
0655:             * 1         N > 1    N points
0656:             * 2         1        LineString of straight lines
0657:             * 2         2        LineString connected by circ arcs (start,any,end pt)
0658:             * 1003/2003 1        Polygon Edged with straight lines
0659:             * 1003/2003 2        Polygon Edged with circ arcs (start, any, end pt)
0660:             * 1003/2003 3        Non SRID rectangle defined by (bottomleft,topright pt)
0661:             * 1003/2003 4        Circle defined by three points on circumference
0662:             * 4         N > 1    Compound Line String made of N (ETYPE=2) lines and arcs
0663:             * 1005/2005 N > 1    Polygon defined by (ETYPE=2) lines and arcs
0664:             * 
0665:             *                 
0666:             * </code></pre>
0667:             * 
0668:             * <p>
0669:             * When playing with circular arcs (SDO_INTERPRETATION==2) arcs are defined
0670:             * by three points. A start point, any point on the arc and the end point.
0671:             * The last point of an arc is the start point of the next. When used to
0672:             * describe a polygon (SDO_ETYPE==1003 or 2003) the first and last point
0673:             * must be the same.
0674:             * </p>
0675:             *
0676:             * @param geom
0677:             *
0678:             */
0679:            public static int elemInfoInterpretation(Geometry geom) {
0680:                return elemInfoInterpretation(geom, elemInfoEType(geom));
0681:            }
0682:
0683:            /**
0684:             * Allows specification of <code>INTERPRETATION</code> used to interpret
0685:             * <code>geom</code>.
0686:             * <p>
0687:             * Provides the INTERPRETATION value for the ELEM_INFO triplet
0688:             * of (STARTING_OFFSET, ETYPE, INTERPRETATION).
0689:             * </p>
0690:             * @param geom Geometry to encode
0691:             * @param etype ETYPE value requiring an INTERPREATION
0692:             *
0693:             * @return INTERPRETATION ELEM_INFO entry for geom given etype
0694:             *
0695:             * @throws IllegalArgumentException If asked to encode a curve
0696:             */
0697:            public static int elemInfoInterpretation(Geometry geom,
0698:                    final int etype) {
0699:                switch (etype) {
0700:                case ETYPE.CUSTOM: // customize for your own Geometries
0701:                    break;
0702:
0703:                case ETYPE.POINT:
0704:
0705:                    if (geom instanceof  Point) {
0706:                        return 1;
0707:                    }
0708:
0709:                    if (geom instanceof  MultiPoint) {
0710:                        return ((MultiPoint) geom).getNumGeometries();
0711:                    }
0712:
0713:                    break;
0714:
0715:                case ETYPE.LINE:
0716:
0717:                    if (isCurve((LineString) geom)) {
0718:                        return 2;
0719:                    }
0720:
0721:                    return 1;
0722:
0723:                case ETYPE.POLYGON:
0724:                case ETYPE.POLYGON_EXTERIOR:
0725:                case ETYPE.POLYGON_INTERIOR:
0726:
0727:                    if (geom instanceof  Polygon) {
0728:                        Polygon polygon = (Polygon) geom;
0729:
0730:                        if (isCurve(polygon)) {
0731:                            return 2;
0732:                        }
0733:
0734:                        if (isRectangle(polygon)) {
0735:                            return 3;
0736:                        }
0737:
0738:                        if (isCircle(polygon)) {
0739:                            return 4;
0740:                        }
0741:                    }
0742:
0743:                    return 1;
0744:
0745:                case ETYPE.COMPOUND:
0746:                    throw new IllegalArgumentException(
0747:                            "JTS LineStrings are not composed of curves and lines.");
0748:
0749:                case ETYPE.COMPOUND_POLYGON:
0750:                case ETYPE.COMPOUND_POLYGON_INTERIOR:
0751:                case ETYPE.COMPOUND_POLYGON_EXTERIOR:
0752:                    throw new IllegalArgumentException(
0753:                            "JTS Polygons are not composed of curves and lines.");
0754:                }
0755:
0756:                throw new IllegalArgumentException(
0757:                        "Cannot encode JTS "
0758:                                + geom.getGeometryType()
0759:                                + " as "
0760:                                + "SDO_INTERPRETATION (Limitied to Point, Line, Polygon, "
0761:                                + "GeometryCollection, MultiPoint, MultiLineString and MultiPolygon)");
0762:            }
0763:
0764:            /**
0765:             * Produce <code>SDO_ORDINATES</code> for geometry.
0766:             * 
0767:             * <p>
0768:             * Please see SDO_ETYPE, SDO_INTERPRETATION and SDO_GTYPE for description
0769:             * of how these ordinates are to be interpreted.
0770:             * </p>
0771:             * 
0772:             * <p>
0773:             * Ordinates are ordered by Dimension are non null:
0774:             * </p>
0775:             * 
0776:             * <ul>
0777:             * <li>
0778:             * <p>
0779:             * Two Dimensional:
0780:             * </p>
0781:             * {x1,y1,x2,y2,...}
0782:             * </li>
0783:             * <li>
0784:             * <p>
0785:             * Three Dimensional:
0786:             * </p>
0787:             * {x1,y1,z1,x2,y2,z2,...}
0788:             * </li>
0789:             * </ul>
0790:             * 
0791:             * <p>
0792:             * Spatial will siliently detect and ignore the following:
0793:             * </p>
0794:             * 
0795:             * <ul>
0796:             * <li>
0797:             * d001 point/d005 multipoint elements that are not SDO_ETYPE==1 points
0798:             * </li>
0799:             * <li>
0800:             * d002 lines or curve/d006 multilines or multicurve elements that are not
0801:             * SDO_ETYPE==2 lines or SDO_ETYPE==4 arcs
0802:             * </li>
0803:             * <li>
0804:             * d003 polygon/d007 multipolygon elements that are not SDO_ETYPE==3
0805:             * unordered polygon lines or SDO_ETYPE==5 unorderd compound polygon ring
0806:             * are ignored
0807:             * </li>
0808:             * </ul>
0809:             * 
0810:             * <p>
0811:             * While Oracle is silient on these errors - all other errors will not be
0812:             * detected!
0813:             * </p>
0814:             *
0815:             * @param geom
0816:             *
0817:             */
0818:            public static double[] ordinates(Geometry geom) {
0819:                List list = new ArrayList();
0820:
0821:                coordinates(list, geom);
0822:
0823:                return ordinates(list, geom);
0824:            }
0825:
0826:            public static CoordinateSequence getCS(Geometry geom) {
0827:                CoordinateSequence cs = null;
0828:                switch (TT(geom)) {
0829:                case TT.UNKNOWN:
0830:                    break; // extend with your own custom types
0831:
0832:                case TT.POINT:
0833:                    //addCoordinates(list, (Point) geom);
0834:
0835:                    return cs;
0836:
0837:                case TT.LINE:
0838:                    cs = getLineStringCS((LineString) geom);
0839:
0840:                    return cs;
0841:
0842:                case TT.POLYGON:
0843:                    //addCoordinates(list, (Polygon) geom);
0844:
0845:                    return cs;
0846:
0847:                case TT.COLLECTION:
0848:                    //addCoordinates(list, (GeometryCollection) geom);
0849:
0850:                    return cs;
0851:
0852:                case TT.MULTIPOINT:
0853:                    //addCoordinates(list, (MultiPoint) geom);
0854:
0855:                    return cs;
0856:
0857:                case TT.MULTILINE:
0858:                    //addCoordinates(list, (MultiLineString) geom);
0859:
0860:                    return cs;
0861:
0862:                case TT.MULTIPOLYGON:
0863:                    //addCoordinates(list, (MultiPolygon) geom);
0864:
0865:                    return cs;
0866:                }
0867:
0868:                throw new IllegalArgumentException(
0869:                        "Cannot encode JTS "
0870:                                + geom.getGeometryType()
0871:                                + " as "
0872:                                + "SDO_ORDINATRES (Limitied to Point, Line, Polygon, "
0873:                                + "GeometryCollection, MultiPoint, MultiLineString and MultiPolygon)");
0874:
0875:            }
0876:
0877:            /**
0878:             * getLineStringCS purpose.
0879:             * <p>
0880:             * Description ...
0881:             * </p>
0882:             * @param string
0883:             */
0884:            private static CoordinateSequence getLineStringCS(LineString ls) {
0885:                if (ls.getCoordinateSequence() instanceof  CoordinateAccess) {
0886:                    CoordinateAccess ca = (CoordinateAccess) ls
0887:                            .getCoordinateSequence();
0888:                    return ca;
0889:                } else
0890:                    return null;
0891:            }
0892:
0893:            /**
0894:             * Encode Geometry as described by GTYPE and ELEM_INFO
0895:             * <p>
0896:             * CoordinateSequence & CoordinateAccess wil be used to determine the
0897:             * dimension, and the number of ordinates added.
0898:             * </p>
0899:             * @param list Flat list of Double
0900:             * @param geom Geometry 
0901:             *
0902:             * @throws IllegalArgumentException If geometry cannot be encoded
0903:             */
0904:            public static void coordinates(List list, Geometry geom) {
0905:                switch (TT(geom)) {
0906:                case TT.UNKNOWN:
0907:                    break; // extend with your own custom types
0908:
0909:                case TT.POINT:
0910:                    addCoordinates(list, (Point) geom);
0911:
0912:                    return;
0913:
0914:                case TT.LINE:
0915:                    addCoordinates(list, (LineString) geom);
0916:
0917:                    return;
0918:
0919:                case TT.POLYGON:
0920:                    addCoordinates(list, (Polygon) geom);
0921:
0922:                    return;
0923:
0924:                case TT.COLLECTION:
0925:                    addCoordinates(list, (GeometryCollection) geom);
0926:
0927:                    return;
0928:
0929:                case TT.MULTIPOINT:
0930:                    addCoordinates(list, (MultiPoint) geom);
0931:
0932:                    return;
0933:
0934:                case TT.MULTILINE:
0935:                    addCoordinates(list, (MultiLineString) geom);
0936:
0937:                    return;
0938:
0939:                case TT.MULTIPOLYGON:
0940:                    addCoordinates(list, (MultiPolygon) geom);
0941:
0942:                    return;
0943:                }
0944:
0945:                throw new IllegalArgumentException(
0946:                        "Cannot encode JTS "
0947:                                + geom.getGeometryType()
0948:                                + " as "
0949:                                + "SDO_ORDINATRES (Limitied to Point, Line, Polygon, "
0950:                                + "GeometryCollection, MultiPoint, MultiLineString and MultiPolygon)");
0951:            }
0952:
0953:            /**
0954:             * Adds a double array to list.
0955:             * 
0956:             * <p>
0957:             * The double array will contain all the ordinates in the Coordiante
0958:             * sequence.
0959:             * </p>
0960:             *
0961:             * @param list
0962:             * @param sequence
0963:             */
0964:            private static void addCoordinates(List list,
0965:                    CoordinateSequence sequence) {
0966:                double[] ords;
0967:
0968:                if (sequence instanceof  CoordinateAccess) {
0969:                    CoordinateAccess access = (CoordinateAccess) sequence;
0970:
0971:                    for (int i = 0; i < access.size(); i++) {
0972:                        list.add(ordinateArray(access, i));
0973:                    }
0974:                } else {
0975:                    for (int i = 0; i < sequence.size(); i++) {
0976:                        list.add(ordinateArray(sequence.getCoordinate(i)));
0977:                    }
0978:                }
0979:            }
0980:
0981:            private static double[] ordinateArray(Coordinate coord) {
0982:                return new double[] { coord.x, coord.y, coord.z };
0983:            }
0984:
0985:            private static double[] ordinateArray(CoordinateAccess access,
0986:                    int index) {
0987:                final int D = access.getDimension();
0988:                final int L = access.getNumAttributes();
0989:                final int LEN = D + L;
0990:                double[] ords = new double[LEN];
0991:
0992:                for (int i = 0; i < LEN; i++) {
0993:                    ords[i] = access.getOrdinate(index, i);
0994:                }
0995:
0996:                return ords;
0997:            }
0998:
0999:            /**
1000:             * 
1001:             * ordinateArray purpose.
1002:             * <p>
1003:             * Description ...
1004:             * </p>
1005:             * @param access
1006:             * @param index
1007:             */
1008:            private static double[] doubleOrdinateArray(
1009:                    CoordinateAccess access, int index) {
1010:                final int D = access.getDimension();
1011:                final int L = access.getNumAttributes();
1012:                final int LEN = D + L;
1013:                double[] ords = new double[LEN];
1014:
1015:                for (int i = 0; i < LEN; i++) {
1016:                    ords[i] = access.getOrdinate(index, i);
1017:                }
1018:
1019:                return ords;
1020:            }
1021:
1022:            /**
1023:             * Used with ELEM_INFO <code>( 1, 1, 1)</code>
1024:             *
1025:             * @param list List to add coordiantes to
1026:             * @param point Point to be encoded
1027:             */
1028:            private static void addCoordinates(List list, Point point) {
1029:                addCoordinates(list, point.getCoordinateSequence());
1030:            }
1031:
1032:            /**
1033:             * Used with ELEM_INFO <code>(1, 2, 1)</code>
1034:             *
1035:             * @param list List to add coordiantes to
1036:             * @param line LineString to be encoded
1037:             */
1038:            private static void addCoordinates(List list, LineString line) {
1039:                addCoordinates(list, line.getCoordinateSequence());
1040:            }
1041:
1042:            /**
1043:             * Used to addCoordinates based on polygon encoding.
1044:             * 
1045:             * <p>
1046:             * Elem Info Interpretations supported:
1047:             * 
1048:             * <ul>
1049:             * <li>
1050:             * 3: Rectangle
1051:             * </li>
1052:             * <li>
1053:             * 1: Standard (supports holes)
1054:             * </li>
1055:             * </ul>
1056:             * </p>
1057:             *
1058:             * @param list List to add coordiantes to
1059:             * @param polygon Polygon to be encoded
1060:             */
1061:            private static void addCoordinates(List list, Polygon polygon) {
1062:                switch (elemInfoInterpretation(polygon)) {
1063:                case 4: // circle not supported
1064:                    break;
1065:
1066:                case 3:
1067:                    addCoordinatesInterpretation3(list, polygon);
1068:                    break;
1069:
1070:                case 2: // curve not suppported
1071:                    break;
1072:
1073:                case 1:
1074:                    addCoordinatesInterpretation1(list, polygon);
1075:
1076:                    break;
1077:                }
1078:            }
1079:
1080:            /**
1081:             * Rectangle ordinates for polygon.
1082:             * 
1083:             * <p>
1084:             * You should in sure that the provided <code>polygon</code> is a rectangle
1085:             * using isRectangle( Polygon )
1086:             * </p>
1087:             * 
1088:             * <p></p>
1089:             *
1090:             * @param list List to add coordiantes to
1091:             * @param polygon Polygon to be encoded
1092:             */
1093:            private static void addCoordinatesInterpretation3(List list,
1094:                    Polygon poly) {
1095:                Envelope e = poly.getEnvelopeInternal();
1096:                list.add(new double[] { e.getMinX(), e.getMinY() });
1097:                list.add(new double[] { e.getMaxX(), e.getMaxY() });
1098:            }
1099:
1100:            /**
1101:             * Add ordinates for polygon - with hole support.
1102:             * 
1103:             * <p>
1104:             * Ensure ordinates are added in the correct orientation as External or
1105:             * Internal polygons.
1106:             * </p>
1107:             *
1108:             * @param list List to add coordiantes to
1109:             * @param polygon Polygon to be encoded
1110:             */
1111:            private static void addCoordinatesInterpretation1(List list,
1112:                    Polygon polygon) {
1113:                int holes = polygon.getNumInteriorRing();
1114:
1115:                addCoordinates(list, counterClockWise(polygon.getFactory()
1116:                        .getCoordinateSequenceFactory(), polygon
1117:                        .getExteriorRing().getCoordinateSequence()));
1118:
1119:                for (int i = 0; i < holes; i++) {
1120:                    addCoordinates(list, clockWise(polygon.getFactory()
1121:                            .getCoordinateSequenceFactory(), polygon
1122:                            .getInteriorRingN(i).getCoordinateSequence()));
1123:                }
1124:            }
1125:
1126:            private static void addCoordinates(List list, MultiPoint points) {
1127:                for (int i = 0; i < points.getNumGeometries(); i++) {
1128:                    addCoordinates(list, (Point) points.getGeometryN(i));
1129:                }
1130:            }
1131:
1132:            private static void addCoordinates(List list, MultiLineString lines) {
1133:                for (int i = 0; i < lines.getNumGeometries(); i++) {
1134:                    addCoordinates(list, (LineString) lines.getGeometryN(i));
1135:                }
1136:            }
1137:
1138:            private static void addCoordinates(List list, MultiPolygon polys) {
1139:                for (int i = 0; i < polys.getNumGeometries(); i++) {
1140:                    addCoordinates(list, (Polygon) polys.getGeometryN(i));
1141:                }
1142:            }
1143:
1144:            private static void addCoordinates(List list,
1145:                    GeometryCollection geoms) {
1146:                Geometry geom;
1147:
1148:                for (int i = 0; i < geoms.getNumGeometries(); i++) {
1149:                    geom = geoms.getGeometryN(i);
1150:
1151:                    if (geom instanceof  Point) {
1152:                        addCoordinates(list, (Point) geom);
1153:                    } else if (geom instanceof  LineString) {
1154:                        addCoordinates(list, (LineString) geom);
1155:                    } else if (geom instanceof  Polygon) {
1156:                        addCoordinates(list, (Polygon) geom);
1157:                    } else if (geom instanceof  MultiPoint) {
1158:                        addCoordinates(list, (MultiPoint) geom);
1159:                    } else if (geom instanceof  MultiLineString) {
1160:                        addCoordinates(list, (MultiLineString) geom);
1161:                    } else if (geom instanceof  MultiPolygon) {
1162:                        addCoordinates(list, (MultiPolygon) geom);
1163:                    } else if (geom instanceof  GeometryCollection) {
1164:                        addCoordinates(list, (GeometryCollection) geom);
1165:                    }
1166:                }
1167:            }
1168:
1169:            /**
1170:             * Package up array of requested ordinate, regardless of geometry
1171:             * 
1172:             * <p>
1173:             * Example numbering: for (x y g m) dimension==2, measure==2
1174:             * </p>
1175:             * 
1176:             * <ul>
1177:             * <li>
1178:             * 0: x ordinate array
1179:             * </li>
1180:             * <li>
1181:             * 1: y ordinate array
1182:             * </li>
1183:             * <li>
1184:             * 2: g ordinate array
1185:             * </li>
1186:             * <li>
1187:             * 3: m ordinate array
1188:             * </li>
1189:             * </ul>
1190:             * 
1191:             *
1192:             * @param coords
1193:             * @param ordinate
1194:             *
1195:             */
1196:            public static double[] ordinateArray(CoordinateSequence coords,
1197:                    int ordinate) {
1198:                if (coords instanceof  CoordinateAccess) {
1199:                    CoordinateAccess access = (CoordinateAccess) coords;
1200:
1201:                    return access.toOrdinateArray(ordinate);
1202:                } else {
1203:                    final int LENGTH = coords.size();
1204:                    Coordinate c;
1205:                    double[] array = new double[LENGTH];
1206:
1207:                    if (ordinate == 0) {
1208:                        for (int i = 0; i < LENGTH; i++) {
1209:                            c = coords.getCoordinate(i);
1210:                            array[i] = (c != null) ? c.x : Double.NaN;
1211:                        }
1212:                    } else if (ordinate == 1) {
1213:                        for (int i = 0; i < LENGTH; i++) {
1214:                            c = coords.getCoordinate(i);
1215:                            array[i] = (c != null) ? c.y : Double.NaN;
1216:                        }
1217:                    } else if (ordinate == 2) {
1218:                        for (int i = 0; i < LENGTH; i++) {
1219:                            c = coords.getCoordinate(i);
1220:                            array[i] = (c != null) ? c.z : Double.NaN;
1221:                        }
1222:                    } else {
1223:                        // default to NaN
1224:                        for (int i = 0; i < LENGTH; i++) {
1225:                            array[i] = Double.NaN;
1226:                        }
1227:                    }
1228:
1229:                    return array;
1230:                }
1231:            }
1232:
1233:            /**
1234:             * Ordinate access.
1235:             * 
1236:             * <p>
1237:             * CoordianteAccess is required for additional ordinates.
1238:             * </p>
1239:             * 
1240:             * <p>
1241:             * Ordinate limitied to:
1242:             * </p>
1243:             * 
1244:             * <ul>
1245:             * <li>
1246:             * 0: x ordinate array
1247:             * </li>
1248:             * <li>
1249:             * 1: y ordinate array
1250:             * </li>
1251:             * <li>
1252:             * 2: z ordinate array
1253:             * </li>
1254:             * <li>
1255:             * 3: empty ordinate array
1256:             * </li>
1257:             * </ul>
1258:             * 
1259:             *
1260:             * @param array
1261:             * @param ordinate
1262:             *
1263:             */
1264:            public static double[] ordinateArray(Coordinate[] array,
1265:                    int ordinate) {
1266:                if (array == null) {
1267:                    return null;
1268:                }
1269:
1270:                final int LENGTH = array.length;
1271:                double[] ords = new double[LENGTH];
1272:                Coordinate c;
1273:
1274:                if (ordinate == 0) {
1275:                    for (int i = 0; i < LENGTH; i++) {
1276:                        c = array[i];
1277:                        ords[i] = (c != null) ? c.x : Double.NaN;
1278:                    }
1279:                } else if (ordinate == 1) {
1280:                    for (int i = 0; i < LENGTH; i++) {
1281:                        c = array[i];
1282:                        ords[i] = (c != null) ? c.y : Double.NaN;
1283:                    }
1284:                } else if (ordinate == 2) {
1285:                    for (int i = 0; i < LENGTH; i++) {
1286:                        c = array[i];
1287:                        ords[i] = (c != null) ? c.z : Double.NaN;
1288:                    }
1289:                } else {
1290:                    // default to NaN
1291:                    for (int i = 0; i < LENGTH; i++) {
1292:                        ords[i] = Double.NaN;
1293:                    }
1294:                }
1295:
1296:                return ords;
1297:            }
1298:
1299:            public static double[] ordinateArray(List list, int ordinate) {
1300:                if (list == null) {
1301:                    return null;
1302:                }
1303:
1304:                final int LENGTH = list.size();
1305:                double[] ords = new double[LENGTH];
1306:                Coordinate c;
1307:
1308:                if (ordinate == 0) {
1309:                    for (int i = 0; i < LENGTH; i++) {
1310:                        c = (Coordinate) list.get(i);
1311:                        ords[i] = (c != null) ? c.x : Double.NaN;
1312:                    }
1313:                } else if (ordinate == 1) {
1314:                    for (int i = 0; i < LENGTH; i++) {
1315:                        c = (Coordinate) list.get(i);
1316:                        ords[i] = (c != null) ? c.y : Double.NaN;
1317:                    }
1318:                } else if (ordinate == 2) {
1319:                    for (int i = 0; i < LENGTH; i++) {
1320:                        c = (Coordinate) list.get(i);
1321:                        ords[i] = (c != null) ? c.z : Double.NaN;
1322:                    }
1323:                } else {
1324:                    // default to NaN
1325:                    for (int i = 0; i < LENGTH; i++) {
1326:                        ords[i] = Double.NaN;
1327:                    }
1328:                }
1329:
1330:                return ords;
1331:            }
1332:
1333:            /**
1334:             * Do not use me, I am broken
1335:             * <p>
1336:             * Do not use me, I am broken
1337:             * </p>
1338:             * @deprecated Do not use me, I am broken
1339:             * @param list
1340:             * @param ordinate
1341:             */
1342:            /*
1343:            //TODO: check if I am correct
1344:            public static Object[] attributeArray(List list, int ordinate) {
1345:            	if (list == null) {
1346:            		return null;
1347:            	}
1348:
1349:            	final int LENGTH = list.size();
1350:            	Object[] ords = new Object[LENGTH];
1351:            	Coordinate c;
1352:            	Double d;
1353:            	String s;
1354:
1355:            	if (ordinate == 0) {
1356:            		for (int i = 0; i < LENGTH; i++) {
1357:            			c = (Coordinate) list.get(i);
1358:            			ords[i] = (c != null) ? new Double(c.x) : new Double(Double.NaN);
1359:            		}
1360:            	} else if (ordinate == 1) {
1361:            		for (int i = 0; i < LENGTH; i++) {
1362:            			c = (Coordinate) list.get(i);
1363:            			ords[i] = (c != null) ? new Double(c.y) : new Double(Double.NaN);
1364:            		}
1365:            	} else if (ordinate == 2) {
1366:            		for (int i = 0; i < LENGTH; i++) {
1367:            			c = (Coordinate) list.get(i);
1368:            			ords[i] = (c != null) ? new Double(c.z) : new Double(Double.NaN);
1369:            		}
1370:            	}
1371:            	else if (ordinate == 3) {		//BUG I am broken, do not use me our own Z
1372:            		for (int i = 0; i < LENGTH; i++) {
1373:            			c = (Coordinate) list.get(i);
1374:            			ords[i] = (c != null) ? new Double(Double.NaN) : new Double(Double.NaN);
1375:            		}
1376:            	}
1377:            	else if (ordinate == 4) {		// our own T (a String)
1378:            		for (int i = 0; i < LENGTH; i++) {
1379:            			c = (Coordinate) list.get(i);
1380:            			ords[i] = (c != null) ? new Double(Double.NaN) : new Double(Double.NaN);
1381:            		}
1382:            	}else {
1383:            		// default to NaN
1384:            		for (int i = 0; i < LENGTH; i++) {
1385:            			ords[i] = list.get(i);
1386:            		}
1387:            	}
1388:
1389:            	return ords;
1390:            }
1391:             */
1392:
1393:            /**
1394:             * Package up <code>array</code> in correct manner for <code>geom</code>.
1395:             * 
1396:             * <p>
1397:             * Ordinates are placed into an array based on:
1398:             * </p>
1399:             * 
1400:             * <ul>
1401:             * <li>
1402:             * geometryGTypeD - chooses between 2d and 3d representation
1403:             * </li>
1404:             * <li>
1405:             * geometryGTypeL - number of LRS measures
1406:             * </li>
1407:             * </ul>
1408:             * 
1409:             *
1410:             * @param list
1411:             * @param geom
1412:             *
1413:             */
1414:            public static double[] ordinates(List list, Geometry geom) {
1415:                LOGGER.finest("ordinates D:" + D(geom));
1416:                LOGGER.finest("ordinates L:" + L(geom));
1417:
1418:                if (D(geom) == 3) {
1419:                    return ordinates3d(list, L(geom));
1420:                } else {
1421:                    return ordinates2d(list, L(geom));
1422:                }
1423:            }
1424:
1425:            /**
1426:             * Ordinates (x,y,x1,y1,...) from coordiante list.
1427:             * 
1428:             * <p>
1429:             * No assumptions are made about the order
1430:             * </p>
1431:             *
1432:             * @param list coordinate list
1433:             * @return ordinate array
1434:             */
1435:            public static double[] ordinates2d(List list) {
1436:                final int NUMBER = list.size();
1437:                final int LEN = 2;
1438:                double[] array = new double[NUMBER * LEN];
1439:                double[] ords;
1440:                int offset = 0;
1441:
1442:                for (int i = 0; i < NUMBER; i++) {
1443:                    ords = (double[]) list.get(i);
1444:
1445:                    if (ords != null) {
1446:                        array[offset++] = ords[0];
1447:                        array[offset++] = ords[1];
1448:                    } else {
1449:                        array[offset++] = Double.NaN;
1450:                        array[offset++] = Double.NaN;
1451:                    }
1452:                }
1453:
1454:                return array;
1455:            }
1456:
1457:            /**
1458:             * Ordinates (x,y,z,x2,y2,z2...) from coordiante[] array.
1459:             *
1460:             * @param list List of coordiante
1461:             *
1462:             * @return ordinate array
1463:             */
1464:            public static double[] ordinates3d(List list) {
1465:                final int NUMBER = list.size();
1466:                final int LEN = 3;
1467:                double[] array = new double[NUMBER * LEN];
1468:                double[] ords;
1469:                int offset = 0;
1470:
1471:                for (int i = 0; i < NUMBER; i++) {
1472:                    ords = (double[]) list.get(i);
1473:
1474:                    if (ords != null) {
1475:                        array[offset++] = ords[0];
1476:                        array[offset++] = ords[1];
1477:                        array[offset++] = ords[2];
1478:                    } else {
1479:                        array[offset++] = Double.NaN;
1480:                        array[offset++] = Double.NaN;
1481:                        array[offset++] = Double.NaN;
1482:                    }
1483:                }
1484:
1485:                return array;
1486:            }
1487:
1488:            /**
1489:             * Ordinates (x,y,...id,x2,y2,...) from coordiante[] List.
1490:             *
1491:             * @param list coordiante list
1492:             * @param L Dimension of ordinates required for representation
1493:             *
1494:             * @return ordinate array
1495:             */
1496:            public static double[] ordinates2d(List list, final int L) {
1497:                if (L == 0) {
1498:                    return ordinates2d(list);
1499:                }
1500:
1501:                final int NUMBER = list.size();
1502:                final int LEN = 2 + L;
1503:                double[] array = new double[NUMBER * LEN];
1504:                double[] ords;
1505:
1506:                for (int i = 0; i < NUMBER; i++) {
1507:                    ords = (double[]) list.get(i);
1508:
1509:                    for (int j = 0; j < LEN; j++) {
1510:                        array[(i * LEN) + j] = ords[j];
1511:                    }
1512:                }
1513:
1514:                return array;
1515:            }
1516:
1517:            /**
1518:             * Ordinates (x,y,z,...id,x2,y2,z2...) from coordiante[] array.
1519:             *
1520:             * @param list coordinate array to be represented as ordinates
1521:             * @param L Dimension of ordinates required for representation
1522:             *
1523:             * @return ordinate array
1524:             */
1525:            public static double[] ordinates3d(List list, final int L) {
1526:                if (L == 0) {
1527:                    return ordinates3d(list);
1528:                }
1529:
1530:                final int NUMBER = list.size();
1531:                final int LEN = 3 + L;
1532:                double[] array = new double[NUMBER * LEN];
1533:                double[] ords;
1534:
1535:                for (int i = 0; i < NUMBER; i++) {
1536:                    ords = (double[]) list.get(i);
1537:
1538:                    for (int j = 0; j < LEN; j++) {
1539:                        array[(i * LEN) + j] = ords[j];
1540:                    }
1541:                }
1542:
1543:                return array;
1544:            }
1545:
1546:            /**
1547:             * Ensure Ring of Coordinates are in a counter clockwise order.
1548:             * 
1549:             * <p>
1550:             * If the Coordiante need to be reversed a copy will be returned.
1551:             * </p>
1552:             *
1553:             * @param factory Factory to used to reverse CoordianteSequence
1554:             * @param ring Ring of Coordinates
1555:             *
1556:             * @return coords in a CCW order
1557:             */
1558:            public static CoordinateSequence counterClockWise(
1559:                    CoordinateSequenceFactory factory, CoordinateSequence ring) {
1560:                if (clock.isCCW(ring.toCoordinateArray())) {
1561:                    return ring;
1562:                }
1563:
1564:                return Coordinates.reverse(factory, ring);
1565:            }
1566:
1567:            /**
1568:             * Ensure Ring of Coordinates are in a clockwise order.
1569:             * 
1570:             * <p>
1571:             * If the Coordiante need to be reversed a copy will be returned.
1572:             * </p>
1573:             *
1574:             * @param factory Factory used to reverse CoordianteSequence
1575:             * @param ring Ring of Coordinates
1576:             *
1577:             * @return coords in a CW order
1578:             */
1579:            private static CoordinateSequence clockWise(
1580:                    CoordinateSequenceFactory factory, CoordinateSequence ring) {
1581:                if (!clock.isCCW(ring.toCoordinateArray())) {
1582:                    return ring;
1583:                }
1584:                return Coordinates.reverse(factory, ring);
1585:            }
1586:
1587:            /**
1588:             * Reverse the clockwise orientation of the ring of Coordiantes.
1589:             *
1590:             * @param ring Ring of Coordinates
1591:             *
1592:             * @return coords Copy of <code>ring</code> in reversed order
1593:             */
1594:            private static Coordinate[] reverse(Coordinate[] ring) {
1595:                int length = ring.length;
1596:                Coordinate[] reverse = new Coordinate[length];
1597:
1598:                for (int i = 0; i < length; i++) {
1599:                    reverse[i] = ring[length - i - 1];
1600:                }
1601:                return reverse;
1602:            }
1603:
1604:            // Utility Functions
1605:            //
1606:            //
1607:
1608:            /**
1609:             * Will need to tell if we are encoding a Polygon Exterior or Interior so
1610:             * we can produce the correct encoding.
1611:             *
1612:             * @param poly Polygon to check
1613:             *
1614:             * @return <code>true</code> as we expect PolygonExteriors to be passed in
1615:             */
1616:            private static boolean isExterior(Polygon poly) {
1617:                return true; // JTS polygons are always exterior
1618:            }
1619:
1620:            /**
1621:             * We need to check if a <code>polygon</code> a cicle so we can produce the
1622:             * correct encoding.
1623:             *
1624:             * @param polygon
1625:             *
1626:             * @return <code>true</code> if polygon is a circle
1627:             */
1628:            private static boolean isCircle(Polygon polygon) {
1629:                return false; // JTS does not do cicles
1630:            }
1631:
1632:            /**
1633:             * We need to check if a <code>polygon</code> a rectangle so we can produce
1634:             * the correct encoding.
1635:             * 
1636:             * <p>
1637:             * Rectangles are only supported without a SRID!
1638:             * </p>
1639:             *
1640:             * @param polygon
1641:             *
1642:             * @return <code>true</code> if polygon is SRID==0 and a rectangle
1643:             */
1644:            private static boolean isRectangle(Polygon polygon) {
1645:                if (polygon.getFactory().getSRID() != SRID_NULL) {
1646:                    // Rectangles only valid in CAD applications
1647:                    // that do not have an SRID system
1648:                    //
1649:                    return false;
1650:                }
1651:
1652:                if (L(polygon) != 0) {
1653:                    // cannot support LRS on a rectangle
1654:                    return false;
1655:                }
1656:
1657:                Coordinate[] coords = polygon.getCoordinates();
1658:
1659:                if (coords.length != 5) {
1660:                    return false;
1661:                }
1662:
1663:                if ((coords[0] == null) || (coords[1] == null)
1664:                        || (coords[2] == null) || (coords[3] == null)) {
1665:                    return false;
1666:                }
1667:
1668:                if (!coords[0].equals2D(coords[4])) {
1669:                    return false;
1670:                }
1671:
1672:                double x1 = coords[0].x;
1673:                double y1 = coords[0].y;
1674:                double x2 = coords[1].x;
1675:                double y2 = coords[1].y;
1676:                double x3 = coords[2].x;
1677:                double y3 = coords[2].y;
1678:                double x4 = coords[3].x;
1679:                double y4 = coords[3].y;
1680:
1681:                if ((x1 == x4) && (y1 == y2) && (x3 == x2) && (y3 == y4)) {
1682:                    // 1+-----+2
1683:                    //  |     |
1684:                    // 4+-----+3
1685:                    return true;
1686:                }
1687:
1688:                if ((x1 == x2) && (y1 == y4) && (x3 == x4) && (y3 == y2)) {
1689:                    // 2+-----+3
1690:                    //  |     |
1691:                    // 1+-----+4
1692:                    return true;
1693:                }
1694:
1695:                return false;
1696:            }
1697:
1698:            /**
1699:             * We need to check if a <code>polygon</code> is defined with curves so we
1700:             * can produce the correct encoding.
1701:             * 
1702:             * <p></p>
1703:             *
1704:             * @param polygon
1705:             *
1706:             * @return <code>false</code> as JTS does not support curves
1707:             */
1708:            private static boolean isCurve(Polygon polygon) {
1709:                return false;
1710:            }
1711:
1712:            /**
1713:             * We need to check if a <code>lineString</code> is defined with curves so
1714:             * we can produce the correct encoding.
1715:             * 
1716:             * <p></p>
1717:             *
1718:             * @param lineString
1719:             *
1720:             * @return <code>false</code> as JTS does not support curves
1721:             */
1722:            private static boolean isCurve(LineString lineString) {
1723:                return false;
1724:            }
1725:
1726:            // Decoding Helper Functions
1727:            //
1728:            //
1729:            /**
1730:             * Returns a range from a CoordinateList, based on ELEM_INFO triplets.
1731:             *
1732:             * @param factory Factory used for JTS 
1733:             * @param coords Coordinates
1734:             * @param GTYPE Encoding of <b>D</b>imension, <b>L</b>RS and <b>TT</b>ype
1735:             * @param elemInfo
1736:             * @param triplet
1737:             *
1738:             */
1739:            private static CoordinateSequence subList(
1740:                    CoordinateSequenceFactory factory,
1741:                    CoordinateSequence coords, int GTYPE, int[] elemInfo,
1742:                    int triplet) {
1743:
1744:                final int STARTING_OFFSET = STARTING_OFFSET(elemInfo, triplet);
1745:                final int ENDING_OFFSET = STARTING_OFFSET(elemInfo, triplet + 1); // -1 for end
1746:
1747:                if ((STARTING_OFFSET == 1) && (ENDING_OFFSET == -1)) {
1748:                    // Use all Cordiantes
1749:                    return coords;
1750:                }
1751:                final int LEN = D(GTYPE) + L(GTYPE);
1752:
1753:                int start = (STARTING_OFFSET - 1) / LEN;
1754:                int end = (ENDING_OFFSET != -1) ? ((ENDING_OFFSET - 1) / LEN)
1755:                        : coords.size();
1756:
1757:                return subList(factory, coords, start, end);
1758:            }
1759:
1760:            /**
1761:             * Version of List.subList() that returns a CoordinateSequence.
1762:             * 
1763:             * <p>
1764:             * Returns from start (inclusive) to end (exlusive):
1765:             * </p>
1766:             * 
1767:             * <p>
1768:             * Math speak: <code>[start,end)</code>
1769:             * </p>
1770:             *
1771:             * @param factory Manages CoordinateSequences for JTS
1772:             * @param coords coords to sublist
1773:             * @param start starting offset
1774:             * @param end upper bound of sublist 
1775:             *
1776:             * @return CoordianteSequence
1777:             */
1778:            private static CoordinateSequence subList(
1779:                    CoordinateSequenceFactory factory,
1780:                    CoordinateSequence coords, int start, int end) {
1781:                if ((start == 0) && (end == coords.size())) {
1782:                    return coords;
1783:                }
1784:
1785:                return Coordinates.subList(factory, coords, start, end);
1786:            }
1787:
1788:            private static LinearRing[] toInteriorRingArray(List list) {
1789:                return (LinearRing[]) toArray(list, LinearRing.class);
1790:
1791:                /*
1792:                   if( list == null ) return null;
1793:                   LinearRing array[] = new LinearRing[ list.size() ];
1794:                   int index=0;
1795:                   for( Iterator i=list.iterator(); i.hasNext(); index++ )
1796:                   {
1797:                       array[ index ] = (LinearRing) i.next();
1798:                   }
1799:                   return array;
1800:                 */
1801:            }
1802:
1803:            private static LineString[] toLineStringArray(List list) {
1804:                return (LineString[]) toArray(list, LineString.class);
1805:
1806:                /*
1807:                   if( list == null ) return null;
1808:                   LineString array[] = new LineString[ list.size() ];
1809:                   int index=0;
1810:                   for( Iterator i=list.iterator(); i.hasNext(); index++ )
1811:                   {
1812:                       array[ index ] = (LineString) i.next();
1813:                   }
1814:                   return array;
1815:                 */
1816:            }
1817:
1818:            private static Polygon[] toPolygonArray(List list) {
1819:                return (Polygon[]) toArray(list, Polygon.class);
1820:            }
1821:
1822:            private static Geometry[] toGeometryArray(List list) {
1823:                return (Geometry[]) toArray(list, Geometry.class);
1824:            }
1825:
1826:            /**
1827:             * Useful function for converting to typed arrays for JTS API.
1828:             * 
1829:             * <p>
1830:             * Example:
1831:             * </p>
1832:             * <pre><code>
1833:             * new MultiPoint( toArray( list, Coordiante.class ) );
1834:             * </code></pre>
1835:             *
1836:             * @param list
1837:             * @param type
1838:             *
1839:             */
1840:            private static Object toArray(List list, Class type) {
1841:                if (list == null) {
1842:                    return null;
1843:                }
1844:
1845:                Object array = Array.newInstance(type, list.size());
1846:                int index = 0;
1847:
1848:                for (Iterator i = list.iterator(); i.hasNext(); index++) {
1849:                    Array.set(array, index, i.next());
1850:                }
1851:
1852:                return array;
1853:            }
1854:
1855:            /**
1856:             * Access D (for dimension) as encoded in GTYPE
1857:             *
1858:             * @param GTYPE DOCUMENT ME!
1859:             *
1860:             * @return DOCUMENT ME!
1861:             */
1862:            public static int D(final int GTYPE) {
1863:                return GTYPE / 1000;
1864:            }
1865:
1866:            /**
1867:             * Access L (for LRS) as encoded in GTYPE
1868:             *
1869:             * @param GTYPE DOCUMENT ME!
1870:             *
1871:             * @return DOCUMENT ME!
1872:             */
1873:            public static int L(final int GTYPE) {
1874:                return (GTYPE - (D(GTYPE) * 1000)) / 100;
1875:            }
1876:
1877:            /**
1878:             * Access TT (for geometry type) as encoded in GTYPE
1879:             *
1880:             * @param GTYPE DOCUMENT ME!
1881:             *
1882:             * @return DOCUMENT ME!
1883:             */
1884:            public static int TT(final int GTYPE) {
1885:                return GTYPE - (D(GTYPE) * 1000) - (L(GTYPE) * 100);
1886:            }
1887:
1888:            /**
1889:             * Access STARTING_OFFSET from elemInfo, or -1 if not available.
1890:             * 
1891:             * <p></p>
1892:             *
1893:             * @param elemInfo DOCUMENT ME!
1894:             * @param triplet DOCUMENT ME!
1895:             *
1896:             * @return DOCUMENT ME!
1897:             */
1898:            private static int STARTING_OFFSET(int[] elemInfo, int triplet) {
1899:                if (((triplet * 3) + 0) >= elemInfo.length) {
1900:                    return -1;
1901:                }
1902:
1903:                return elemInfo[(triplet * 3) + 0];
1904:            }
1905:
1906:            /**
1907:             * A version of assert that indicates range pre/post condition.
1908:             * <p>
1909:             * Works like assert exception IllegalArgumentException is thrown indicating this
1910:             * is a required check.
1911:             * </p>
1912:             * <p>
1913:             * Example phrased as a positive statement of the requirement to be met:
1914:             * <pre><code>
1915:             * ensure( "STARTING_OFFSET {1} must indicate a valid ordinate between {0} and {2}.
1916:             * </code></pre>
1917:             * </p>
1918:             * @param condition MessageFormat pattern - positive statement of requirement
1919:             * @param min minimum acceptable value ({0} in message format)
1920:             * @param actual value supplied ({1} in message format)
1921:             * @param max maximum acceptable value ({2} in message format)
1922:             * @throws IllegalArgumentException unless min <= actual <= max
1923:             */
1924:            private static void ensure(String condition, int min, int actual,
1925:                    int max) {
1926:                if (!(min <= actual && actual <= max)) {
1927:                    String msg = MessageFormat.format(condition, new Object[] {
1928:                            new Integer(min), new Integer(actual),
1929:                            new Integer(max) });
1930:                    throw new IllegalArgumentException(msg);
1931:                }
1932:            }
1933:
1934:            /**
1935:             * A version of assert that indicates range pre/post condition.
1936:             * <p>
1937:             * Works like assert exception IllegalArgumentException is thrown indicating this
1938:             * is a required check.
1939:             * </p>
1940:             * <p>
1941:             * Example phrased as a positive statement of the requirement to be met:
1942:             * <pre><code>
1943:             * ensure( "INTERPRETATION {0} must be on of {1}.
1944:             * </code></pre>
1945:             * </p>
1946:             * @param condition MessageFormat pattern - positive statement of requirement
1947:             * @param actual value supplied ({0} in message format)
1948:             * @param set Array of acceptable values ({1} in message format)
1949:             * @throws IllegalArgumentException unless actual is a member of set
1950:             */
1951:            private static void ensure(String condition, int actual, int[] set) {
1952:                if (set == null)
1953:                    return; // don't apparently care
1954:                for (int i = 0; i < set.length; i++) {
1955:                    if (set[i] == actual)
1956:                        return; // found it
1957:                }
1958:                StringBuffer array = new StringBuffer();
1959:                for (int i = 0; i < set.length; i++) {
1960:                    array.append(set[i]);
1961:                    if (i < set.length) {
1962:                        array.append(",");
1963:                    }
1964:                }
1965:                String msg = MessageFormat.format(condition, new Object[] {
1966:                        new Integer(actual), array });
1967:                throw new IllegalArgumentException(msg);
1968:            }
1969:
1970:            /** Returns the "length" of the ordinate array used for the
1971:             * CoordianteSequence, GTYPE is used to determine the dimension.
1972:             * <p>
1973:             * This is most often used to check the STARTING_OFFSET value to ensure
1974:             * that is falls within allowable bounds.
1975:             * </p>
1976:             * <p>
1977:             * Example:<pre><code>
1978:             * if (!(STARTING_OFFSET >= 1) ||
1979:             *     !(STARTING_OFFSET <= ordinateSize( coords, GTYPE ))){
1980:             *     throw new IllegalArgumentException(
1981:             *         "ELEM_INFO STARTING_OFFSET "+STARTING_OFFSET+ 
1982:             *         "inconsistent with COORDINATES length "+size( coords, GTYPE ) );
1983:             * } 
1984:             * </code></pre>
1985:             * </p>
1986:             * @param coords
1987:             * @param GTYPE
1988:             */
1989:            private static int ordinateSize(CoordinateSequence coords, int GTYPE) {
1990:                if (coords == null) {
1991:                    return 0;
1992:                }
1993:                return coords.size() * D(GTYPE);
1994:            }
1995:
1996:            /**
1997:             * ETYPE access for the elemInfo triplet indicated.
1998:             * <p>
1999:             * @see ETYPE for an indication of possible values
2000:             * 
2001:             * @param elemInfo
2002:             * @param triplet
2003:             * @return ETYPE for indicated triplet
2004:             */
2005:            private static int ETYPE(int[] elemInfo, int triplet) {
2006:                if (((triplet * 3) + 1) >= elemInfo.length) {
2007:                    return -1;
2008:                }
2009:
2010:                return elemInfo[(triplet * 3) + 1];
2011:            }
2012:
2013:            private static int INTERPRETATION(int[] elemInfo, int triplet) {
2014:                if (((triplet * 3) + 2) >= elemInfo.length) {
2015:                    return -1;
2016:                }
2017:
2018:                return elemInfo[(triplet * 3) + 2];
2019:            }
2020:
2021:            /**
2022:             * Coordiantes from <code>(x,y,x2,y2,...)</code> ordinates.
2023:             *
2024:             * @param ordinates DOCUMENT ME!
2025:             *
2026:             * @return DOCUMENT ME!
2027:             */
2028:            public static Coordinate[] asCoordinates(double[] ordinates) {
2029:                return asCoordiantes(ordinates, 2);
2030:            }
2031:
2032:            /**
2033:             * Coordiantes from a <code>(x,y,i3..,id,x2,y2...)</code> ordinates.
2034:             *
2035:             * @param ordinates DOCUMENT ME!
2036:             * @param d DOCUMENT ME!
2037:             *
2038:             * @return DOCUMENT ME!
2039:             */
2040:            public static Coordinate[] asCoordiantes(double[] ordinates, int d) {
2041:                int length = ordinates.length / d;
2042:                Coordinate[] coords = new Coordinate[length];
2043:
2044:                for (int i = 0; i < length; i++) {
2045:                    coords[i] = new Coordinate(ordinates[i * d],
2046:                            ordinates[(i * d) + 1]);
2047:                }
2048:
2049:                return coords;
2050:            }
2051:
2052:            /**
2053:             * Construct CoordinateList as described by GTYPE.
2054:             * 
2055:             * <p>
2056:             * GTYPE encodes the following information:
2057:             * 
2058:             * <ul>
2059:             * <li>
2060:             * D: Dimension of ordinates
2061:             * </li>
2062:             * <li>
2063:             * L: Dimension of LRS measures
2064:             * </li>
2065:             * </ul>
2066:             * </p>
2067:             * 
2068:             * <p>
2069:             * The number of ordinates per coordinate are taken to be L+D, and the
2070:             * number of ordinates should be a multiple of this value.
2071:             * </p>
2072:             * 
2073:             * <p>
2074:             * In the Special case of GTYPE 2001 and a three ordinates are interpreted
2075:             * as a single Coordinate rather than an error.
2076:             * </p>
2077:             *
2078:             * @param f CoordinateSequenceFactory used to encode ordiantes for JTS 
2079:             * @param GTYPE Encoding of <b>D</b>imension, <b>L</b>RS and <b>TT</b>ype
2080:             * @param ordinates
2081:             *
2082:             *
2083:             * @throws IllegalArgumentException DOCUMENT ME!
2084:             */
2085:            public static CoordinateSequence coordinates(
2086:                    CoordinateSequenceFactory f, final int GTYPE,
2087:                    double[] ordinates) {
2088:                if ((ordinates == null) || (ordinates.length == 0)) {
2089:                    return f.create(new Coordinate[0]);
2090:                }
2091:
2092:                final int D = SDO.D(GTYPE);
2093:                final int L = SDO.L(GTYPE);
2094:                final int TT = SDO.TT(GTYPE);
2095:
2096:                //      POINT_TYPE Special Case
2097:                //
2098:                if ((D == 2) && (L == 0) && (TT == 01)
2099:                        && (ordinates.length == 3)) {
2100:                    return f.create(new Coordinate[] { new Coordinate(
2101:                            ordinates[0], ordinates[1], ordinates[2]), });
2102:                }
2103:
2104:                final int LEN = D + L;
2105:
2106:                if ((ordinates.length % LEN) != 0) {
2107:                    throw new IllegalArgumentException("Dimension D:" + D
2108:                            + " and L:" + L + " denote Coordiantes " + "of "
2109:                            + LEN + " ordinates. This cannot be resolved with"
2110:                            + "an ordinate array of length " + ordinates.length);
2111:                }
2112:
2113:                final int LENGTH = ordinates.length / LEN;
2114:
2115:                OrdinateList x = new OrdinateList(ordinates, 0, LEN);
2116:                OrdinateList y = new OrdinateList(ordinates, 1, LEN);
2117:                OrdinateList z = null;
2118:
2119:                if (D == 3) {
2120:                    z = new OrdinateList(ordinates, 2, LEN);
2121:                }
2122:
2123:                if (L != 0) {
2124:                    OrdinateList[] m = new OrdinateList[L];
2125:
2126:                    for (int i = 0; i < L; i++) {
2127:                        m[i] = new OrdinateList(ordinates, D + i, LEN);
2128:                    }
2129:
2130:                    return coordiantes(f, x, y, z, m);
2131:                } else {
2132:                    return coordiantes(f, x, y, z);
2133:                }
2134:            }
2135:
2136:            /**
2137:             * Construct CoordinateSequence with no LRS measures.
2138:             * 
2139:             * <p>
2140:             * To produce two dimension Coordiantes pass in <code>null</code> for z
2141:             * </p>
2142:             *
2143:             * @param f DOCUMENT ME!
2144:             * @param x DOCUMENT ME!
2145:             * @param y DOCUMENT ME!
2146:             * @param z DOCUMENT ME!
2147:             *
2148:             * @return DOCUMENT ME!
2149:             */
2150:            public static CoordinateSequence coordiantes(
2151:                    CoordinateSequenceFactory f, OrdinateList x,
2152:                    OrdinateList y, OrdinateList z) {
2153:                final int LENGTH = x.size();
2154:                Coordinate[] array = new Coordinate[LENGTH];
2155:
2156:                if (z != null) {
2157:                    for (int i = 0; i < LENGTH; i++) {
2158:                        array[i] = new Coordinate(x.getDouble(i), y
2159:                                .getDouble(i), z.getDouble(i));
2160:                    }
2161:                } else {
2162:                    for (int i = 0; i < LENGTH; i++) {
2163:                        array[i] = new Coordinate(x.getDouble(i), y
2164:                                .getDouble(i));
2165:                    }
2166:                }
2167:
2168:                return f.create(array);
2169:            }
2170:
2171:            /**
2172:             * Construct CoordinateSequence with no LRS measures.
2173:             * 
2174:             * <p>
2175:             * To produce two dimension Coordiantes pass in <code>null</code> for z
2176:             * </p>
2177:             *
2178:             * @param f DOCUMENT ME!
2179:             * @param x DOCUMENT ME!
2180:             * @param y DOCUMENT ME!
2181:             * @param z DOCUMENT ME!
2182:             *
2183:             * @return DOCUMENT ME!
2184:             */
2185:            public static CoordinateSequence coordiantes(
2186:                    CoordinateSequenceFactory f, AttributeList x,
2187:                    AttributeList y, AttributeList z) {
2188:                final int LENGTH = x.size();
2189:                Coordinate[] array = new Coordinate[LENGTH];
2190:
2191:                if (z != null) {
2192:                    for (int i = 0; i < LENGTH; i++) {
2193:                        array[i] = new Coordinate(x.getDouble(i), y
2194:                                .getDouble(i), z.getDouble(i));
2195:                    }
2196:                } else {
2197:                    for (int i = 0; i < LENGTH; i++) {
2198:                        array[i] = new Coordinate(x.getDouble(i), y
2199:                                .getDouble(i));
2200:                    }
2201:                }
2202:
2203:                return f.create(array);
2204:            }
2205:
2206:            /**
2207:             * Construct SpatialCoordiantes, with LRS measure information.
2208:             * 
2209:             * <p>
2210:             * To produce two dimension Coordiantes pass in <code>null</code> for z
2211:             * </p>
2212:             *
2213:             * @param f DOCUMENT ME!
2214:             * @param x x-ordinates
2215:             * @param y y-ordinates
2216:             * @param z z-ordinates, <code>null</code> for 2D
2217:             * @param m column major measure information
2218:             *
2219:             * @return DOCUMENT ME!
2220:             */
2221:            public static CoordinateSequence coordiantes(
2222:                    CoordinateSequenceFactory f, OrdinateList x,
2223:                    OrdinateList y, OrdinateList z, OrdinateList[] m) {
2224:                final int D = (z != null) ? 3 : 2;
2225:                final int L = (m != null) ? m.length : 0;
2226:
2227:                if (f instanceof  CoordinateAccess && (L != 0)) {
2228:                    CoordinateAccessFactory factory = (CoordinateAccessFactory) f;
2229:                    double[][] xyz = new double[D][];
2230:                    double[][] measures = new double[L][];
2231:
2232:                    xyz[0] = x.toDoubleArray();
2233:                    xyz[1] = y.toDoubleArray();
2234:
2235:                    if (D == 3) {
2236:                        xyz[2] = z.toDoubleArray();
2237:                    }
2238:
2239:                    for (int i = 0; i < L; i++) {
2240:                        measures[i] = m[i].toDoubleArray();
2241:                    }
2242:
2243:                    return factory.create(xyz, measures);
2244:                } else {
2245:                    return coordiantes(f, x, y, z);
2246:                }
2247:            }
2248:
2249:            /**
2250:             * Construct SpatialCoordiantes, with LRS measure information.
2251:             * 
2252:             * <p>
2253:             * To produce two dimension Coordiantes pass in <code>null</code> for z
2254:             * </p>
2255:             *
2256:             * @param f DOCUMENT ME!
2257:             * @param x x-ordinates
2258:             * @param y y-ordinates
2259:             * @param z z-ordinates, <code>null</code> for 2D
2260:             * @param m column major measure information
2261:             *
2262:             * @return DOCUMENT ME!
2263:             */
2264:            public static CoordinateSequence coordiantes(
2265:                    CoordinateSequenceFactory f, AttributeList x,
2266:                    AttributeList y, AttributeList z, AttributeList[] m) {
2267:                final int D = (z != null) ? 3 : 2;
2268:                final int L = (m != null) ? m.length : 0;
2269:
2270:                if (f instanceof  CoordinateAccess && (L != 0)) {
2271:                    CoordinateAccessFactory factory = (CoordinateAccessFactory) f;
2272:                    double[][] xyz = new double[D][];
2273:                    Object[] measures = new Object[L];
2274:
2275:                    xyz[0] = x.toDoubleArray();
2276:                    xyz[1] = y.toDoubleArray();
2277:
2278:                    if (D == 3) {
2279:                        xyz[2] = z.toDoubleArray();
2280:                    }
2281:
2282:                    for (int i = 0; i < L; i++) {
2283:                        measures[i] = m[i].toObjectArray();
2284:                    }
2285:
2286:                    return factory.create(xyz, measures);
2287:                } else {
2288:                    return coordiantes(f, x, y, z);
2289:                }
2290:            }
2291:
2292:            /**
2293:             * Decode geometry from provided SDO encoded information.
2294:             * 
2295:             * <p></p>
2296:             *
2297:             * @param gf Used to construct returned Geometry
2298:             * @param GTYPE SDO_GTYPE represents dimension, LRS, and geometry type
2299:             * @param SRID SDO_SRID represents Spatial Reference System
2300:             * @param point
2301:             * @param elemInfo
2302:             * @param ordinates
2303:             *
2304:             * @return Geometry as encoded
2305:             */
2306:            public static Geometry create(GeometryFactory gf, final int GTYPE,
2307:                    final int SRID, double[] point, int[] elemInfo,
2308:                    double[] ordinates) {
2309:                final int L = SDO.L(GTYPE);
2310:                final int TT = SDO.TT(GTYPE);
2311:                double[] list;
2312:                double[][] lists;
2313:
2314:                CoordinateSequence coords;
2315:
2316:                if ((L == 0) && (TT == 01) && (point != null)
2317:                        && (elemInfo == null)) {
2318:                    // Single Point Type Optimization
2319:                    coords = SDO.coordinates(gf.getCoordinateSequenceFactory(),
2320:                            GTYPE, point);
2321:                    elemInfo = new int[] { 1, ETYPE.POINT, 1 };
2322:                } else {
2323:                    coords = SDO.coordinates(gf.getCoordinateSequenceFactory(),
2324:                            GTYPE, ordinates);
2325:                }
2326:
2327:                return create(gf, GTYPE, SRID, elemInfo, 0, coords, -1);
2328:            }
2329:
2330:            /**
2331:             * Consturct geometry with SDO encoded information over a CoordinateList.
2332:             * 
2333:             * <p>
2334:             * Helpful when dealing construction Geometries with your own Coordiante
2335:             * Types. The dimensionality specified in GTYPE will be used to interpret
2336:             * the offsets in elemInfo.
2337:             * </p>
2338:             *
2339:             * @param gf
2340:             * @param GTYPE Encoding of <b>D</b>imension, <b>L</b>RS and <b>TT</b>ype
2341:             * @param SRID
2342:             * @param elemInfo
2343:             * @param triplet DOCUMENT ME!
2344:             * @param coords
2345:             * @param N Number of triplets (-1 for unknown/don't care)
2346:             *
2347:             * @return Geometry as encoded, or null w/ log if it cannot be represented via JTS
2348:             */
2349:            public static Geometry create(GeometryFactory gf, final int GTYPE,
2350:                    final int SRID, final int[] elemInfo, final int triplet,
2351:                    CoordinateSequence coords, final int N) {
2352:                switch (SDO.TT(GTYPE)) {
2353:                case TT.POINT:
2354:                    return createPoint(gf, GTYPE, SRID, elemInfo, triplet,
2355:                            coords);
2356:
2357:                case TT.LINE:
2358:                    return createLine(gf, GTYPE, SRID, elemInfo, triplet,
2359:                            coords);
2360:
2361:                case TT.POLYGON:
2362:                    return createPolygon(gf, GTYPE, SRID, elemInfo, triplet,
2363:                            coords);
2364:
2365:                case TT.MULTIPOINT:
2366:                    return createMultiPoint(gf, GTYPE, SRID, elemInfo, triplet,
2367:                            coords);
2368:
2369:                case TT.MULTILINE:
2370:                    return createMultiLine(gf, GTYPE, SRID, elemInfo, triplet,
2371:                            coords, N);
2372:
2373:                case TT.MULTIPOLYGON:
2374:                    return createMultiPolygon(gf, GTYPE, SRID, elemInfo,
2375:                            triplet, coords, N);
2376:
2377:                case TT.COLLECTION:
2378:                    return createCollection(gf, GTYPE, SRID, elemInfo, triplet,
2379:                            coords, N);
2380:
2381:                case TT.UNKNOWN:
2382:                default:
2383:                    LOGGER
2384:                            .warning("Cannot represent provided SDO STRUCT (GTYPE ="
2385:                                    + GTYPE + ") using JTS Geometry");
2386:                    return null;
2387:                }
2388:            }
2389:
2390:            /**
2391:             * Create Point as encoded.
2392:             *
2393:             * @param gf
2394:             * @param GTYPE Encoding of <b>D</b>imension, <b>L</b>RS and <b>TT</b>ype
2395:             * @param SRID
2396:             * @param elemInfo
2397:             * @param element
2398:             * @param coords
2399:             *
2400:             * @return Point
2401:             */
2402:            private static Point createPoint(GeometryFactory gf,
2403:                    final int GTYPE, final int SRID, final int[] elemInfo,
2404:                    final int element, CoordinateSequence coords) {
2405:                final int STARTING_OFFSET = STARTING_OFFSET(elemInfo, element);
2406:                final int etype = ETYPE(elemInfo, element);
2407:                final int INTERPRETATION = INTERPRETATION(elemInfo, element);
2408:
2409:                if (!(STARTING_OFFSET >= 1)
2410:                        || !(STARTING_OFFSET <= coords.size()))
2411:                    throw new IllegalArgumentException(
2412:                            "ELEM_INFO STARTING_OFFSET " + STARTING_OFFSET
2413:                                    + " inconsistent with ORDINATES length "
2414:                                    + coords.size());
2415:                if (etype != ETYPE.POINT)
2416:                    throw new IllegalArgumentException("ETYPE " + etype
2417:                            + " inconsistent with expected POINT");
2418:                if (INTERPRETATION != 1) {
2419:                    LOGGER
2420:                            .warning("Could not create JTS Point with INTERPRETATION "
2421:                                    + INTERPRETATION
2422:                                    + " - we only expect 1 for a single point");
2423:                    return null;
2424:                }
2425:
2426:                Point point = new Point(subList(gf
2427:                        .getCoordinateSequenceFactory(), coords, GTYPE,
2428:                        elemInfo, element), gf);
2429:
2430:                //Point point = gf.createPoint( coords.getCoordinate( index ) );
2431:                point.setSRID(SRID);
2432:
2433:                return point;
2434:            }
2435:
2436:            /**
2437:             * Create LineString as encoded.
2438:             *
2439:             * @param gf
2440:             * @param GTYPE Encoding of <b>D</b>imension, <b>L</b>RS and <b>TT</b>ype
2441:             * @param SRID
2442:             * @param elemInfo
2443:             * @param triplet
2444:             * @param coords
2445:             *
2446:             *
2447:             * @throws IllegalArgumentException If asked to create a curve
2448:             */
2449:            private static LineString createLine(GeometryFactory gf,
2450:                    final int GTYPE, final int SRID, final int[] elemInfo,
2451:                    final int triplet, CoordinateSequence coords) {
2452:                final int STARTING_OFFSET = STARTING_OFFSET(elemInfo, triplet);
2453:                final int etype = ETYPE(elemInfo, triplet);
2454:                final int INTERPRETATION = INTERPRETATION(elemInfo, triplet);
2455:
2456:                if (etype != ETYPE.LINE)
2457:                    return null;
2458:                if (INTERPRETATION != 1) {
2459:                    LOGGER
2460:                            .warning("Could not create JTS LineString with INTERPRETATION "
2461:                                    + INTERPRETATION
2462:                                    + " - we can only support 1 for straight edges");
2463:                    return null;
2464:                }
2465:
2466:                if (INTERPRETATION != 1) {
2467:                    // May be INTERPRETATION == 2 for curves
2468:                    throw new IllegalArgumentException(
2469:                            "ELEM_INFO INTERPRETAION "
2470:                                    + INTERPRETATION
2471:                                    + " not supported"
2472:                                    + "by JTS LineString.  Straight edges"
2473:                                    + "( ELEM_INFO INTERPRETAION 1) is supported");
2474:                }
2475:
2476:                LineString line = new LineString(subList(gf
2477:                        .getCoordinateSequenceFactory(), coords, GTYPE,
2478:                        elemInfo, triplet), gf);
2479:                line.setSRID(SRID);
2480:
2481:                return line;
2482:            }
2483:
2484:            /**
2485:             * Create Polygon as encoded.
2486:             * 
2487:             * <p>
2488:             * Encoded as a one or more triplets in elemInfo:
2489:             * </p>
2490:             * 
2491:             * <ul>
2492:             * <li>
2493:             * Exterior Polygon Ring: first triplet:
2494:             * 
2495:             * <ul>
2496:             * <li>
2497:             * STARTING_OFFSET: position in ordinal ordinate array
2498:             * </li>
2499:             * <li>
2500:             * ETYPE: 1003 (exterior) or 3 (polygon w/ counter clockwise ordinates)
2501:             * </li>
2502:             * <li>
2503:             * INTERPRETATION: 1 for strait edges, 3 for rectanlge
2504:             * </li>
2505:             * </ul>
2506:             * 
2507:             * </li>
2508:             * <li>
2509:             * Interior Polygon Ring(s): remaining triplets:
2510:             * 
2511:             * <ul>
2512:             * <li>
2513:             * STARTING_OFFSET: position in ordinal ordinate array
2514:             * </li>
2515:             * <li>
2516:             * ETYPE: 2003 (interior) or 3 (polygon w/ clockWise ordinates)
2517:             * </li>
2518:             * <li>
2519:             * INTERPRETATION: 1 for strait edges, 3 for rectanlge
2520:             * </li>
2521:             * </ul>
2522:             * 
2523:             * </li>
2524:             * </ul>
2525:             * 
2526:             * <p>
2527:             * The polygon encoding will process subsequent 2003, or 3 triples with
2528:             * clockwise ordering as interior holes.
2529:             * </p>
2530:             * 
2531:             * <p>
2532:             * A subsequent triplet of any other type marks the end of the polygon.
2533:             * </p>
2534:             * 
2535:             * <p>
2536:             * The dimensionality of GTYPE will be used to transalte the
2537:             * <code>STARTING_OFFSET</code> provided by elemInfo into an index into
2538:             * <code>coords</code>.
2539:             * </p>
2540:             *
2541:             * @param gf Used to construct polygon
2542:             * @param GTYPE Encoding of <b>D</b>imension, <b>L</b>RS and <b>TT</b>ype
2543:             * @param SRID Spatial Reference System
2544:             * @param elemInfo Interpretation of coords
2545:             * @param triplet Triplet in elemInfo to process as a Polygon
2546:             * @param coords Coordinates to interpret using elemInfo
2547:             *
2548:             * @return Polygon as encoded by elemInfo, or null when faced with and
2549:             *         encoding that can not be captured by JTS
2550:             * @throws IllegalArgumentException When faced with an invalid SDO encoding
2551:             */
2552:            private static Polygon createPolygon(GeometryFactory gf,
2553:                    final int GTYPE, final int SRID, final int[] elemInfo,
2554:                    final int triplet, CoordinateSequence coords)
2555:                    throws IllegalArgumentException {
2556:                final int STARTING_OFFSET = STARTING_OFFSET(elemInfo, triplet);
2557:                final int eTYPE = ETYPE(elemInfo, triplet);
2558:                final int INTERPRETATION = INTERPRETATION(elemInfo, triplet);
2559:
2560:                ensure(
2561:                        "ELEM_INFO STARTING_OFFSET {1} must be in the range {0}..{1} of COORDINATES",
2562:                        1, STARTING_OFFSET, ordinateSize(coords, GTYPE));
2563:                if (!(1 <= STARTING_OFFSET && STARTING_OFFSET <= ordinateSize(
2564:                        coords, GTYPE))) {
2565:                    throw new IllegalArgumentException(
2566:                            "ELEM_INFO STARTING_OFFSET " + STARTING_OFFSET
2567:                                    + "inconsistent with COORDINATES length "
2568:                                    + ordinateSize(coords, GTYPE));
2569:                }
2570:                ensure(
2571:                        "ETYPE {0} must be expected POLYGON or POLYGON_EXTERIOR (one of {1})",
2572:                        eTYPE, new int[] { ETYPE.POLYGON,
2573:                                ETYPE.POLYGON_EXTERIOR });
2574:                if (!(eTYPE == ETYPE.POLYGON)
2575:                        && !(eTYPE == ETYPE.POLYGON_EXTERIOR)) {
2576:                    throw new IllegalArgumentException(
2577:                            "ETYPE "
2578:                                    + eTYPE
2579:                                    + " inconsistent with expected POLYGON or POLYGON_EXTERIOR");
2580:                }
2581:                if (!(INTERPRETATION == 1) && !(INTERPRETATION == 3)) {
2582:                    LOGGER
2583:                            .warning("Could not create JTS Polygon with INTERPRETATION "
2584:                                    + INTERPRETATION
2585:                                    + " - we can only support 1 for straight edges, and 3 for rectangle");
2586:                    return null;
2587:                }
2588:
2589:                LinearRing exteriorRing = createLinearRing(gf, GTYPE, SRID,
2590:                        elemInfo, triplet, coords);
2591:
2592:                List rings = new LinkedList();
2593:                int etype;
2594:                HOLES: for (int i = triplet + 1; (etype = ETYPE(elemInfo, i)) != -1; i++) {
2595:                    if (etype == ETYPE.POLYGON_INTERIOR) {
2596:                        rings.add(createLinearRing(gf, GTYPE, SRID, elemInfo,
2597:                                i, coords));
2598:                    } else if (etype == ETYPE.POLYGON) { // nead to test Clockwiseness of Ring to see if it is
2599:                        // interior or not - (use POLYGON_INTERIOR to avoid pain)
2600:
2601:                        LinearRing ring = createLinearRing(gf, GTYPE, SRID,
2602:                                elemInfo, i, coords);
2603:
2604:                        if (clock.isCCW(ring.getCoordinates())) { // it is an Interior Hole
2605:                            rings.add(ring);
2606:                        } else { // it is the next Polygon! - get out of here
2607:
2608:                            break HOLES;
2609:                        }
2610:                    } else { // not a LinearRing - get out of here
2611:
2612:                        break HOLES;
2613:                    }
2614:                }
2615:
2616:                Polygon poly = gf.createPolygon(exteriorRing,
2617:                        toInteriorRingArray(rings));
2618:                poly.setSRID(SRID);
2619:
2620:                return poly;
2621:            }
2622:
2623:            /**
2624:             * Create Linear Ring for exterior/interior polygon ELEM_INFO triplets.
2625:             * 
2626:             * <p>
2627:             * Encoded as a single triplet in elemInfo:
2628:             * </p>
2629:             * 
2630:             * <ul>
2631:             * <li>
2632:             * STARTING_OFFSET: position in ordinal ordinate array
2633:             * </li>
2634:             * <li>
2635:             * ETYPE: 1003 (exterior) or 2003 (interior) or 3 (unknown order)
2636:             * </li>
2637:             * <li>
2638:             * INTERPRETATION: 1 for strait edges, 3 for rectanlge
2639:             * </li>
2640:             * </ul>
2641:             * 
2642:             * <p>
2643:             * The dimensionality of GTYPE will be used to transalte the
2644:             * <code>STARTING_OFFSET</code> provided by elemInfo into an index into
2645:             * <code>coords</code>.
2646:             * </p>
2647:             *
2648:             * @param gf
2649:             * @param GTYPE Encoding of <b>D</b>imension, <b>L</b>RS and <b>TT</b>ype
2650:             * @param SRID
2651:             * @param elemInfo
2652:             * @param triplet
2653:             * @param coords
2654:             *
2655:             * @return LinearRing
2656:             *
2657:             * @throws IllegalArgumentException If circle, or curve is requested
2658:             */
2659:            private static LinearRing createLinearRing(GeometryFactory gf,
2660:                    final int GTYPE, final int SRID, final int[] elemInfo,
2661:                    final int triplet, CoordinateSequence coords) {
2662:
2663:                final int STARTING_OFFSET = STARTING_OFFSET(elemInfo, triplet);
2664:                final int eTYPE = ETYPE(elemInfo, triplet);
2665:                final int INTERPRETATION = INTERPRETATION(elemInfo, triplet);
2666:                final int LENGTH = coords.size() * D(GTYPE);
2667:
2668:                if (!(STARTING_OFFSET >= 1) || !(STARTING_OFFSET <= LENGTH))
2669:                    throw new IllegalArgumentException(
2670:                            "ELEM_INFO STARTING_OFFSET " + STARTING_OFFSET
2671:                                    + " inconsistent with ORDINATES length "
2672:                                    + coords.size());
2673:                if (!(eTYPE == ETYPE.POLYGON)
2674:                        && !(eTYPE == ETYPE.POLYGON_EXTERIOR)
2675:                        && !(eTYPE == ETYPE.POLYGON_INTERIOR)) {
2676:                    throw new IllegalArgumentException(
2677:                            "ETYPE "
2678:                                    + eTYPE
2679:                                    + " inconsistent with expected POLYGON, POLYGON_EXTERIOR or POLYGON_INTERIOR");
2680:                }
2681:                if (!(INTERPRETATION == 1) && !(INTERPRETATION == 3)) {
2682:                    LOGGER
2683:                            .warning("Could not create LinearRing with INTERPRETATION "
2684:                                    + INTERPRETATION
2685:                                    + " - we can only support 1 for straight edges");
2686:                    return null;
2687:                }
2688:                LinearRing ring;
2689:
2690:                if (INTERPRETATION == 1) {
2691:                    ring = gf.createLinearRing(subList(gf
2692:                            .getCoordinateSequenceFactory(), coords, GTYPE,
2693:                            elemInfo, triplet));
2694:                } else if (INTERPRETATION == 3) {
2695:                    // rectangle does not maintain measures
2696:                    //
2697:                    CoordinateSequence ext = subList(gf
2698:                            .getCoordinateSequenceFactory(), coords, GTYPE,
2699:                            elemInfo, triplet);
2700:                    Coordinate min = ext.getCoordinate(0);
2701:                    Coordinate max = ext.getCoordinate(1);
2702:                    ring = gf.createLinearRing(new Coordinate[] { min,
2703:                            new Coordinate(max.x, min.y), max,
2704:                            new Coordinate(min.x, max.y), min });
2705:                } else {
2706:                    // May be INTERPRETATION == 2 for curves, or 4 for circle
2707:                    //
2708:                    throw new IllegalArgumentException(
2709:                            "ELEM_INFO INTERPRETAION "
2710:                                    + elemInfo[2]
2711:                                    + " not supported"
2712:                                    + "for JTS Polygon Linear Rings."
2713:                                    + "ELEM_INFO INTERPRETAION 1 and 3 are supported");
2714:                }
2715:
2716:                ring.setSRID(SRID);
2717:
2718:                return ring;
2719:            }
2720:
2721:            /**
2722:             * Create MultiPoint as encoded by elemInfo.
2723:             * 
2724:             * <p>
2725:             * Encoded as a single triplet in elemInfo:
2726:             * </p>
2727:             * 
2728:             * <ul>
2729:             * <li>
2730:             * STARTING_OFFSET: position in ordinal ordinate array
2731:             * </li>
2732:             * <li>
2733:             * ETYPE: 1 for Point
2734:             * </li>
2735:             * <li>
2736:             * INTERPRETATION: number of points
2737:             * </li>
2738:             * </ul>
2739:             * 
2740:             *
2741:             * @param gf Used to construct polygon
2742:             * @param GTYPE Encoding of <b>D</b>imension, <b>L</b>RS and <b>TT</b>ype
2743:             * @param SRID Spatial Reference System
2744:             * @param elemInfo Interpretation of coords
2745:             * @param triplet Triplet in elemInfo to process as a Polygon
2746:             * @param coords Coordinates to interpret using elemInfo
2747:             *
2748:             */
2749:            private static MultiPoint createMultiPoint(GeometryFactory gf,
2750:                    final int GTYPE, final int SRID, final int[] elemInfo,
2751:                    final int triplet, CoordinateSequence coords) {
2752:                final int STARTING_OFFSET = STARTING_OFFSET(elemInfo, triplet);
2753:                final int eTYPE = ETYPE(elemInfo, triplet);
2754:                final int INTERPRETATION = INTERPRETATION(elemInfo, triplet);
2755:
2756:                if (!(STARTING_OFFSET >= 1)
2757:                        || !(STARTING_OFFSET <= coords.size()))
2758:                    throw new IllegalArgumentException(
2759:                            "ELEM_INFO STARTING_OFFSET " + STARTING_OFFSET
2760:                                    + " inconsistent with ORDINATES length "
2761:                                    + coords.size());
2762:                if (!(eTYPE == ETYPE.POINT))
2763:                    throw new IllegalArgumentException("ETYPE " + eTYPE
2764:                            + " inconsistent with expected POINT");
2765:                //CH- changed to >= 1, for GEOS-437, Jody and I looked at docs
2766:                //and multipoint is a superset of point, so it should be fine,
2767:                //for cases when there is just one point.  Bart is testing.
2768:                if (!(INTERPRETATION >= 1)) {
2769:                    LOGGER
2770:                            .warning("Could not create MultiPoint with INTERPRETATION "
2771:                                    + INTERPRETATION
2772:                                    + " - representing the number of points");
2773:                    return null;
2774:                }
2775:
2776:                final int LEN = D(GTYPE) + L(GTYPE);
2777:
2778:                int start = (STARTING_OFFSET - 1) / LEN;
2779:                int end = start + INTERPRETATION;
2780:
2781:                MultiPoint points = gf.createMultiPoint(subList(gf
2782:                        .getCoordinateSequenceFactory(), coords, start, end));
2783:                points.setSRID(SRID);
2784:
2785:                return points;
2786:            }
2787:
2788:            /**
2789:             * Create MultiLineString as encoded by elemInfo.
2790:             * 
2791:             * <p>
2792:             * Encoded as a series line of triplets in elemInfo:
2793:             * </p>
2794:             * 
2795:             * <ul>
2796:             * <li>
2797:             * STARTING_OFFSET: position in ordinal ordinate array
2798:             * </li>
2799:             * <li>
2800:             * ETYPE: 2 for Line
2801:             * </li>
2802:             * <li>
2803:             * INTERPRETATION: 1 for straight edges
2804:             * </li>
2805:             * </ul>
2806:             * 
2807:             * <p></p>
2808:             *
2809:             * @param gf Used to construct MultiLineString
2810:             * @param GTYPE Encoding of <b>D</b>imension, <b>L</b>RS and <b>TT</b>ype
2811:             * @param SRID Spatial Reference System
2812:             * @param elemInfo Interpretation of coords
2813:             * @param triplet Triplet in elemInfo to process as a Polygon
2814:             * @param coords Coordinates to interpret using elemInfo
2815:             * @param N Number of triplets (or -1 for rest)
2816:             *
2817:             */
2818:            private static MultiLineString createMultiLine(GeometryFactory gf,
2819:                    final int GTYPE, final int SRID, final int[] elemInfo,
2820:                    final int triplet, CoordinateSequence coords, final int N) {
2821:                final int STARTING_OFFSET = STARTING_OFFSET(elemInfo, triplet);
2822:                final int eTYPE = ETYPE(elemInfo, triplet);
2823:                final int INTERPRETATION = INTERPRETATION(elemInfo, triplet);
2824:
2825:                final int LENGTH = coords.size() * D(GTYPE);
2826:
2827:                if (!(STARTING_OFFSET >= 1) || !(STARTING_OFFSET <= LENGTH))
2828:                    throw new IllegalArgumentException(
2829:                            "ELEM_INFO STARTING_OFFSET " + STARTING_OFFSET
2830:                                    + " inconsistent with ORDINATES length "
2831:                                    + coords.size());
2832:                if (!(eTYPE == ETYPE.LINE))
2833:                    throw new IllegalArgumentException("ETYPE " + eTYPE
2834:                            + " inconsistent with expected LINE");
2835:                if (!(INTERPRETATION == 1)) {
2836:                    // we cannot represent INTERPRETATION > 1 
2837:                    LOGGER
2838:                            .warning("Could not create MultiLineString with INTERPRETATION "
2839:                                    + INTERPRETATION
2840:                                    + " - we can only represent 1 for straight edges");
2841:                    return null;
2842:                }
2843:
2844:                final int LEN = D(GTYPE) + L(GTYPE);
2845:                final int endTriplet = (N != -1) ? (triplet + N)
2846:                        : (elemInfo.length / 3);
2847:
2848:                List list = new LinkedList();
2849:                int etype;
2850:                LINES: // bad bad gotos jody
2851:                for (int i = triplet; (i < endTriplet)
2852:                        && ((etype = ETYPE(elemInfo, i)) != -1); i++) {
2853:                    if (etype == ETYPE.LINE) {
2854:                        list.add(createLine(gf, GTYPE, SRID, elemInfo, i,
2855:                                coords));
2856:                    } else { // not a LinearString - get out of here
2857:
2858:                        break LINES; // goto LINES
2859:                    }
2860:                }
2861:
2862:                MultiLineString lines = gf
2863:                        .createMultiLineString(toLineStringArray(list));
2864:                lines.setSRID(SRID);
2865:
2866:                return lines;
2867:            }
2868:
2869:            /**
2870:             * Create MultiPolygon as encoded by elemInfo.
2871:             * 
2872:             * <p>
2873:             * Encoded as a series polygon triplets in elemInfo:
2874:             * </p>
2875:             * 
2876:             * <ul>
2877:             * <li>
2878:             * STARTING_OFFSET: position in ordinal ordinate array
2879:             * </li>
2880:             * <li>
2881:             * ETYPE: 2003 or 3 for Polygon
2882:             * </li>
2883:             * <li>
2884:             * INTERPRETATION: 1 for straight edges, 3 for rectangle
2885:             * </li>
2886:             * </ul>
2887:             * 
2888:             * <p></p>
2889:             *
2890:             * @param gf Used to construct MultiLineString
2891:             * @param GTYPE Encoding of <b>D</b>imension, <b>L</b>RS and <b>TT</b>ype
2892:             * @param SRID Spatial Reference System
2893:             * @param elemInfo Interpretation of coords
2894:             * @param triplet Triplet in elemInfo to process as a Polygon
2895:             * @param coords Coordinates to interpret using elemInfo
2896:             * @param N Number of triplets (or -1 for rest)
2897:             *
2898:             */
2899:            private static MultiPolygon createMultiPolygon(GeometryFactory gf,
2900:                    final int GTYPE, final int SRID, final int[] elemInfo,
2901:                    final int triplet, CoordinateSequence coords, final int N) {
2902:                final int STARTING_OFFSET = STARTING_OFFSET(elemInfo, triplet);
2903:                final int eTYPE = ETYPE(elemInfo, triplet);
2904:                final int INTERPRETATION = INTERPRETATION(elemInfo, triplet);
2905:                final int LENGTH = coords.size() * D(GTYPE);
2906:
2907:                if (!(STARTING_OFFSET >= 1) || !(STARTING_OFFSET <= LENGTH))
2908:                    throw new IllegalArgumentException(
2909:                            "ELEM_INFO STARTING_OFFSET " + STARTING_OFFSET
2910:                                    + " inconsistent with ORDINATES length "
2911:                                    + coords.size());
2912:                if (!(eTYPE == ETYPE.POLYGON)
2913:                        && !(eTYPE == ETYPE.POLYGON_EXTERIOR))
2914:                    throw new IllegalArgumentException(
2915:                            "ETYPE "
2916:                                    + eTYPE
2917:                                    + " inconsistent with expected POLYGON or POLYGON_EXTERIOR");
2918:                if (INTERPRETATION != 1 && INTERPRETATION != 3) {
2919:                    LOGGER
2920:                            .warning("Could not create MultiPolygon with INTERPRETATION "
2921:                                    + INTERPRETATION
2922:                                    + " - we can only represent 1 for straight edges, or 3 for rectangle");
2923:                    return null;
2924:                }
2925:                final int LEN = D(GTYPE) + L(GTYPE);
2926:                final int endTriplet = (N != -1) ? (triplet + N)
2927:                        : ((elemInfo.length / 3) + 1);
2928:
2929:                List list = new LinkedList();
2930:                int etype;
2931:                POLYGONS: for (int i = triplet; (i < endTriplet)
2932:                        && ((etype = ETYPE(elemInfo, i)) != -1); i++) {
2933:                    if ((etype == ETYPE.POLYGON)
2934:                            || (etype == ETYPE.POLYGON_EXTERIOR)) {
2935:                        Polygon poly = createPolygon(gf, GTYPE, SRID, elemInfo,
2936:                                i, coords);
2937:                        i += poly.getNumInteriorRing(); // skip interior rings
2938:                        list.add(poly);
2939:                    } else { // not a Polygon - get out here
2940:
2941:                        break POLYGONS;
2942:                    }
2943:                }
2944:
2945:                MultiPolygon polys = gf
2946:                        .createMultiPolygon(toPolygonArray(list));
2947:                polys.setSRID(SRID);
2948:
2949:                return polys;
2950:            }
2951:
2952:            /**
2953:             * Create MultiPolygon as encoded by elemInfo.
2954:             * 
2955:             * <p>
2956:             * Encoded as a series polygon triplets in elemInfo:
2957:             * </p>
2958:             * 
2959:             * <ul>
2960:             * <li>
2961:             * STARTING_OFFSET: position in ordinal ordinate array
2962:             * </li>
2963:             * <li>
2964:             * ETYPE: 2003 or 3 for Polygon
2965:             * </li>
2966:             * <li>
2967:             * INTERPRETATION: 1 for straight edges, 2 for rectangle
2968:             * </li>
2969:             * </ul>
2970:             * 
2971:             * <p></p>
2972:             *
2973:             * TODO: Confirm that createCollection is not getting cut&paste mistakes from polygonCollection
2974:             * 
2975:             * @param gf Used to construct MultiLineString
2976:             * @param GTYPE Encoding of <b>D</b>imension, <b>L</b>RS and <b>TT</b>ype
2977:             * @param SRID Spatial Reference System
2978:             * @param elemInfo Interpretation of coords
2979:             * @param triplet Triplet in elemInfo to process as a Polygon
2980:             * @param coords Coordinates to interpret using elemInfo
2981:             * @param N Number of triplets (or -1 for rest)
2982:             *
2983:             * @return GeometryCollection
2984:             *
2985:             * @throws IllegalArgumentException DWhen faced with an encoding error
2986:             */
2987:            private static GeometryCollection createCollection(
2988:                    GeometryFactory gf, final int GTYPE, final int SRID,
2989:                    final int[] elemInfo, final int triplet,
2990:                    CoordinateSequence coords, final int N) {
2991:                final int STARTING_OFFSET = STARTING_OFFSET(elemInfo, triplet);
2992:                final int eTYPE = ETYPE(elemInfo, triplet);
2993:                final int INTERPRETATION = INTERPRETATION(elemInfo, triplet);
2994:
2995:                final int LENGTH = coords.size() * D(GTYPE);
2996:
2997:                if (!(STARTING_OFFSET >= 1) || !(STARTING_OFFSET <= LENGTH))
2998:                    throw new IllegalArgumentException(
2999:                            "ELEM_INFO STARTING_OFFSET " + STARTING_OFFSET
3000:                                    + " inconsistent with ORDINATES length "
3001:                                    + coords.size());
3002:
3003:                final int LEN = D(GTYPE) + L(GTYPE);
3004:                final int endTriplet = (N != -1) ? (triplet + N)
3005:                        : ((elemInfo.length / 3) + 1);
3006:
3007:                List list = new LinkedList();
3008:                int etype;
3009:                int interpretation;
3010:                Geometry geom;
3011:
3012:                GEOMETRYS: for (int i = triplet; i < endTriplet; i++) {
3013:                    etype = ETYPE(elemInfo, i);
3014:                    interpretation = INTERPRETATION(elemInfo, i);
3015:
3016:                    switch (etype) {
3017:                    case -1:
3018:                        break GEOMETRYS; // We are the of the list - get out of here
3019:
3020:                    case ETYPE.POINT:
3021:
3022:                        if (interpretation == 1) {
3023:                            geom = createPoint(gf, GTYPE, SRID, elemInfo, i,
3024:                                    coords);
3025:                        } else if (interpretation > 1) {
3026:                            geom = createMultiPoint(gf, GTYPE, SRID, elemInfo,
3027:                                    i, coords);
3028:                        } else {
3029:                            throw new IllegalArgumentException(
3030:                                    "ETYPE.POINT requires INTERPRETATION >= 1");
3031:                        }
3032:
3033:                        break;
3034:
3035:                    case ETYPE.LINE:
3036:                        geom = createLine(gf, GTYPE, SRID, elemInfo, i, coords);
3037:
3038:                        break;
3039:
3040:                    case ETYPE.POLYGON:
3041:                    case ETYPE.POLYGON_EXTERIOR:
3042:                        geom = createPolygon(gf, GTYPE, SRID, elemInfo, i,
3043:                                coords);
3044:                        i += ((Polygon) geom).getNumInteriorRing();
3045:
3046:                        break;
3047:
3048:                    case ETYPE.POLYGON_INTERIOR:
3049:                        throw new IllegalArgumentException(
3050:                                "ETYPE 2003 (Polygon Interior) no expected in a GeometryCollection"
3051:                                        + "(2003 is used to represent polygon holes, in a 1003 polygon exterior)");
3052:
3053:                    case ETYPE.CUSTOM:
3054:                    case ETYPE.COMPOUND:
3055:                    case ETYPE.COMPOUND_POLYGON:
3056:                    case ETYPE.COMPOUND_POLYGON_EXTERIOR:
3057:                    case ETYPE.COMPOUND_POLYGON_INTERIOR:
3058:                    default:
3059:                        throw new IllegalArgumentException(
3060:                                "ETYPE "
3061:                                        + etype
3062:                                        + " not representable as a JTS Geometry."
3063:                                        + "(Custom and Compound Straight and Curved Geometries not supported)");
3064:                    }
3065:
3066:                    list.add(geom);
3067:                }
3068:
3069:                GeometryCollection geoms = gf
3070:                        .createGeometryCollection(toGeometryArray(list));
3071:                geoms.setSRID(SRID);
3072:
3073:                return geoms;
3074:            }
3075:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.