001: /*
002: * The JTS Topology Suite is a collection of Java classes that
003: * implement the fundamental operations required to validate a given
004: * geo-spatial data set to a known topological specification.
005: *
006: * Copyright (C) 2001 Vivid Solutions
007: *
008: * This library is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU Lesser General Public
010: * License as published by the Free Software Foundation; either
011: * version 2.1 of the License, or (at your option) any later version.
012: *
013: * This library is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public
019: * License along with this library; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021: *
022: * For more information, contact:
023: *
024: * Vivid Solutions
025: * Suite #1A
026: * 2328 Government Street
027: * Victoria BC V8T 5G5
028: * Canada
029: *
030: * (250)385-6040
031: * www.vividsolutions.com
032: */
033: /*
034: * Geotools2 - OpenSource mapping toolkit
035: * http://geotools.org
036: * (C) 2003, Geotools Project Managment Committee (PMC)
037: *
038: * This library is free software; you can redistribute it and/or
039: * modify it under the terms of the GNU Lesser General Public
040: * License as published by the Free Software Foundation;
041: * version 2.1 of the License.
042: *
043: * This library is distributed in the hope that it will be useful,
044: * but WITHOUT ANY WARRANTY; without even the implied warranty of
045: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
046: * Lesser General Public License for more details.
047: *
048: */
049: package com.vividsolutions.jts.io.oracle;
050:
051: import java.sql.SQLException;
052: import java.util.*;
053:
054: import com.vividsolutions.jts.algorithm.CGAlgorithms;
055: import com.vividsolutions.jts.geom.*;
056:
057: import oracle.jdbc.OracleConnection;
058: import oracle.sql.*;
059:
060: /**
061: *
062: * Translates a JTS Geometry into an Oracle STRUCT representing an MDSYS.GEOMETRY object.
063: *
064: * A connection to an oracle instance with access to the definition of the MDSYS.GEOMETRY
065: * object is required by the oracle driver.
066: *
067: * @version 9i
068: * @author David Zwiers, Vivid Solutions.
069: */
070: public class OraWriter {
071: private OracleConnection connection;
072: private int dimension = 2;
073: private int srid = Constants.SRID_NULL;
074:
075: private String DATATYPE = "MDSYS.SDO_GEOMETRY";
076:
077: /**
078: * Initialize the Oracle MDSYS.GEOMETRY Encoder with a valid oracle connection.
079: *
080: * The connection should have sufficient priveledges to view the description of the MDSYS.GEOMETRY type.
081: *
082: * The dimension is set to 2
083: *
084: * @param con
085: */
086: public OraWriter(OracleConnection con) {
087: this .connection = con;
088: }
089:
090: /**
091: * Initialize the Oracle MDSYS.GEOMETRY Encoder with a valid oracle connection.
092: *
093: * The connection should have sufficient priveledges to view the description of the MDSYS.GEOMETRY type.
094: *
095: * @param con
096: * @param dimension
097: */
098: public OraWriter(OracleConnection con, int dimension) {
099: this .connection = con;
100: this .dimension = dimension;
101: }
102:
103: /**
104: * Provides the oppotunity to force all geometries written using this writter to be written using the
105: * specified srid. This is useful in two cases: 1) when you do not want the geometry's srid to be
106: * over-written or 2) when you want to ensure an entire layer is always written using a constant srid.
107: *
108: * @param srid
109: */
110: public void setSRID(int srid) {
111: this .srid = srid;
112: }
113:
114: /**
115: * This routine will translate the JTS Geometry into an Oracle MDSYS.GEOMETRY STRUCT.
116: *
117: * Although invalid geometries may be encoded, and inserted into an Oracle DB, this is
118: * not recomended. It is the responsibility of the user to ensure the geometry is valid
119: * prior to calling this method. The user should also ensure the the geometry's SRID
120: * field contains the correct value, if an SRID is desired. An incorrect SRID value may
121: * cause index exceptions during an insert or update.
122: *
123: * When a null Geometry is passed in, a non-null, empty STRUCT is returned. Therefore,
124: * inserting the the result of calling this method directly into a table will never result
125: * in null insertions.
126: * (March 2006)
127: *
128: * To pass a NULL Geometry into an oracle geometry parameter using jdbc, use
129: * java.sql.CallableStatement.setNull(index,java.sql.Types.STRUCT,"MDSYS.SDO_GEOMETRY")
130: * (April 2006)
131: *
132: * @param geom JTS Geometry to encode
133: * @return Oracle MDSYS.GEOMETRY STRUCT
134: * @throws SQLException
135: */
136: public STRUCT write(Geometry geom) throws SQLException {
137:
138: // this line may be problematic ... for v9i and later
139: // need to revisit.
140:
141: // was this ... does not work for 9i
142: // if( geom == null) return toSTRUCT( null, DATATYPE );
143:
144: //works fro 9i
145: if (geom == null)
146: return toSTRUCT(new Datum[5], DATATYPE);
147:
148: // does not work for 9i
149: // if( geom == null) return null;
150:
151: //empty geom
152: if (geom.isEmpty() || geom.getCoordinate() == null)
153: return toSTRUCT(new Datum[5], DATATYPE);
154:
155: int gtype = gType(geom);
156: NUMBER SDO_GTYPE = new NUMBER(gtype);
157:
158: //int srid = geom.getFactory().getSRID();
159: int srid = this .srid == Constants.SRID_NULL ? geom.getSRID()
160: : this .srid;
161: NUMBER SDO_SRID = srid == Constants.SRID_NULL ? null
162: : new NUMBER(srid);
163:
164: double[] point = point(geom);
165:
166: STRUCT SDO_POINT;
167:
168: ARRAY SDO_ELEM_INFO;
169: ARRAY SDO_ORDINATES;
170:
171: if (point == null) {
172: int elemInfo[] = elemInfo(geom, gtype);
173:
174: List list = new ArrayList();
175: coordinates(list, geom);
176:
177: int dim = gtype / 1000;
178: int lrs = (gtype - dim * 1000) / 100;
179: int len = dim + lrs; // size per coordinate
180: double[] ordinates = new double[list.size() * len];
181:
182: int k = 0;
183: for (int i = 0; i < list.size() && k < ordinates.length; i++) {
184: int j = 0;
185: double[] ords = (double[]) list.get(i);
186: for (; j < len && j < ords.length; j++) {
187: ordinates[k++] = ords[j];
188: }
189: for (; j < len; j++) { // mostly safety
190: ordinates[k++] = Double.NaN;
191: }
192: }
193:
194: list = null;
195:
196: SDO_POINT = null;
197: SDO_ELEM_INFO = toARRAY(elemInfo,
198: "MDSYS.SDO_ELEM_INFO_ARRAY");
199: SDO_ORDINATES = toARRAY(ordinates,
200: "MDSYS.SDO_ORDINATE_ARRAY");
201: } else { // Point Optimization
202: Datum data[] = new Datum[] { toNUMBER(point[0]),
203: toNUMBER(point[1]), toNUMBER(point[2]), };
204: SDO_POINT = toSTRUCT(data, "MDSYS.SDO_POINT_TYPE");
205: SDO_ELEM_INFO = null;
206: SDO_ORDINATES = null;
207: }
208: Datum attributes[] = new Datum[] { SDO_GTYPE, SDO_SRID,
209: SDO_POINT, SDO_ELEM_INFO, SDO_ORDINATES };
210: return toSTRUCT(attributes, DATATYPE);
211: }
212:
213: /**
214: * Encode Geometry as described by GTYPE and ELEM_INFO
215: *
216: * @param list Flat list of Double
217: * @param geom Geometry
218: *
219: * @throws IllegalArgumentException If geometry cannot be encoded
220: */
221: private void coordinates(List list, Geometry geom) {
222: switch (template(geom)) {
223:
224: case Constants.SDO_GTEMPLATE.POINT:
225: addCoordinates(list, ((Point) geom).getCoordinateSequence());
226: return;
227: case Constants.SDO_GTEMPLATE.LINE:
228: addCoordinates(list, ((LineString) geom)
229: .getCoordinateSequence());
230: return;
231: case Constants.SDO_GTEMPLATE.POLYGON:
232: switch (elemInfoInterpretation(geom,
233: Constants.SDO_ETYPE.POLYGON_EXTERIOR)) {
234: case 3:
235: Envelope e = geom.getEnvelopeInternal();
236: list.add(new double[] { e.getMinX(), e.getMinY() });
237: list.add(new double[] { e.getMaxX(), e.getMaxY() });
238: return;
239: case 1:
240: Polygon polygon = (Polygon) geom;
241: int holes = polygon.getNumInteriorRing();
242:
243: // check outer ring's direction
244: CoordinateSequence ring = polygon.getExteriorRing()
245: .getCoordinateSequence();
246: if (!CGAlgorithms.isCCW(ring.toCoordinateArray())) {
247: ring = reverse(polygon.getFactory()
248: .getCoordinateSequenceFactory(), ring);
249: }
250: addCoordinates(list, ring);
251:
252: for (int i = 0; i < holes; i++) {
253: // check inner ring's direction
254: ring = polygon.getInteriorRingN(i)
255: .getCoordinateSequence();
256: if (CGAlgorithms.isCCW(ring.toCoordinateArray())) {
257: ring = reverse(polygon.getFactory()
258: .getCoordinateSequenceFactory(), ring);
259: }
260:
261: addCoordinates(list, ring);
262: }
263: return;
264: }
265: break; // interpretations 2,4 not supported
266: case Constants.SDO_GTEMPLATE.MULTIPOINT:
267: case Constants.SDO_GTEMPLATE.MULTILINE:
268: case Constants.SDO_GTEMPLATE.MULTIPOLYGON:
269: case Constants.SDO_GTEMPLATE.COLLECTION:
270: for (int i = 0; i < geom.getNumGeometries(); i++) {
271: coordinates(list, geom.getGeometryN(i));
272: }
273: return;
274: }
275:
276: throw new IllegalArgumentException(
277: "Cannot encode JTS "
278: + geom.getGeometryType()
279: + " as "
280: + "SDO_ORDINATRES (Limitied to Point, Line, Polygon, "
281: + "GeometryCollection, MultiPoint, MultiLineString and MultiPolygon)");
282: }
283:
284: /**
285: * Adds a double array to list.
286: *
287: * <p>
288: * The double array will contain all the ordinates in the Coordiante
289: * sequence.
290: * </p>
291: *
292: * @param list
293: * @param sequence
294: */
295: private static void addCoordinates(List list,
296: CoordinateSequence sequence) {
297: Coordinate coord = null;
298: for (int i = 0; i < sequence.size(); i++) {
299: coord = sequence.getCoordinate(i);
300: if (coord.z == Double.NaN)
301: list.add(new double[] { coord.x, coord.y });
302: else
303: list.add(new double[] { coord.x, coord.y, coord.z });
304: }
305: }
306:
307: /**
308: * Return SDO_ELEM_INFO array for geometry
309: *
310: * <pre><code><b>
311: * # Name Meaning</b>
312: * 0 SDO_STARTING_OFFSET Offsets start at one
313: * 1 SDO_ETYPE Describes how ordinates are ordered
314: * 2 SDO_INTERPRETATION SDO_ETYPE: 4, 1005, or 2005
315: * Number of triplets involved in compound geometry
316: *
317: * SDO_ETYPE: 1, 2, 1003, or 2003
318: * Describes ordering of ordinates in geometry
319: * </code></pre>
320: *
321: * <p>
322: * For compound elements (SDO_ETYPE values 4 and 5) the last element of one
323: * is the first element of the next.
324: * </p>
325: *
326: * @param geom Geometry being represented
327: *
328: * @return Descriptionof Ordinates representation
329: */
330: private int[] elemInfo(Geometry geom, int gtype) {
331: List list = new LinkedList();
332:
333: elemInfo(list, geom, 1, gtype);
334:
335: int[] array = new int[list.size()];
336: int offset = 0;
337:
338: for (Iterator i = list.iterator(); i.hasNext(); offset++) {
339: array[offset] = ((Number) i.next()).intValue();
340: }
341:
342: return array;
343: }
344:
345: /**
346: * Add to SDO_ELEM_INFO list for geometry and GTYPE.
347: *
348: * @param elemInfoList List used to gather SDO_ELEM_INFO
349: * @param geom Geometry to encode
350: * @param sOffSet Starting offset in SDO_ORDINATES
351: *
352: * @throws IllegalArgumentException If geom cannot be encoded by ElemInfo
353: */
354: private void elemInfo(List elemInfoList, Geometry geom,
355: int sOffSet, int gtype) {
356:
357: switch (gtype - (gtype / 100) * 100) { // removes right two digits
358: case Constants.SDO_GTEMPLATE.POINT:
359: addInt(elemInfoList, sOffSet);
360: addInt(elemInfoList, Constants.SDO_ETYPE.POINT);
361: addInt(elemInfoList, 1); // INTERPRETATION single point
362:
363: return;
364:
365: case Constants.SDO_GTEMPLATE.MULTIPOINT:
366: MultiPoint points = (MultiPoint) geom;
367:
368: addInt(elemInfoList, sOffSet);
369: addInt(elemInfoList, Constants.SDO_ETYPE.POINT);
370: addInt(elemInfoList, elemInfoInterpretation(points,
371: Constants.SDO_ETYPE.POINT));
372:
373: return;
374:
375: case Constants.SDO_GTEMPLATE.LINE:
376: addInt(elemInfoList, sOffSet);
377: addInt(elemInfoList, Constants.SDO_ETYPE.LINE);
378: addInt(elemInfoList, 1); // INTERPRETATION straight edges
379:
380: return;
381:
382: case Constants.SDO_GTEMPLATE.MULTILINE:
383: MultiLineString lines = (MultiLineString) geom;
384: LineString line;
385: int offset = sOffSet;
386: int dim = gtype / 1000;
387: int len = dim + (gtype - dim * 1000) / 100;
388:
389: for (int i = 0; i < lines.getNumGeometries(); i++) {
390: line = (LineString) lines.getGeometryN(i);
391: addInt(elemInfoList, offset);
392: addInt(elemInfoList, Constants.SDO_ETYPE.LINE);
393: addInt(elemInfoList, 1); // INTERPRETATION straight edges
394: offset += (line.getNumPoints() * len);
395: }
396:
397: return;
398:
399: case Constants.SDO_GTEMPLATE.POLYGON:
400: Polygon polygon = (Polygon) geom;
401: int holes = polygon.getNumInteriorRing();
402:
403: if (holes == 0) {
404: addInt(elemInfoList, sOffSet);
405: addInt(elemInfoList, elemInfoEType(polygon));
406: addInt(elemInfoList, elemInfoInterpretation(polygon,
407: Constants.SDO_ETYPE.POLYGON_EXTERIOR));
408: return;
409: }
410:
411: dim = gtype / 1000;
412: len = dim + (gtype - dim * 1000) / 100;
413: offset = sOffSet;
414: LineString ring;
415:
416: ring = polygon.getExteriorRing();
417: addInt(elemInfoList, offset);
418: addInt(elemInfoList, elemInfoEType(polygon));
419: addInt(elemInfoList, elemInfoInterpretation(polygon,
420: Constants.SDO_ETYPE.POLYGON_EXTERIOR));
421: offset += (ring.getNumPoints() * len);
422:
423: for (int i = 1; i <= holes; i++) {
424: ring = polygon.getInteriorRingN(i - 1);
425: addInt(elemInfoList, offset);
426: addInt(elemInfoList,
427: Constants.SDO_ETYPE.POLYGON_INTERIOR);
428: addInt(elemInfoList, elemInfoInterpretation(ring,
429: Constants.SDO_ETYPE.POLYGON_INTERIOR));
430: offset += (ring.getNumPoints() * len);
431: }
432:
433: return;
434:
435: case Constants.SDO_GTEMPLATE.MULTIPOLYGON:
436: MultiPolygon polys = (MultiPolygon) geom;
437: Polygon poly;
438: offset = sOffSet;
439:
440: dim = gtype / 1000;
441: len = dim + (gtype - dim * 1000) / 100;
442:
443: for (int i = 0; i < polys.getNumGeometries(); i++) {
444: poly = (Polygon) polys.getGeometryN(i);
445: elemInfo(elemInfoList, poly, offset, gType(poly));
446: if (isRectangle(poly)) {
447: offset += (2 * len);
448: } else {
449: offset += (poly.getNumPoints() * len);
450: }
451: }
452:
453: return;
454:
455: case Constants.SDO_GTEMPLATE.COLLECTION:
456: GeometryCollection geoms = (GeometryCollection) geom;
457: offset = sOffSet;
458: dim = gtype / 1000;
459: len = dim + (gtype - dim * 1000) / 100;
460:
461: for (int i = 0; i < geoms.getNumGeometries(); i++) {
462: geom = geoms.getGeometryN(i);
463: elemInfo(elemInfoList, geom, offset, gtype);
464: if (geom instanceof Polygon
465: && isRectangle((Polygon) geom)) {
466: offset += (2 * len);
467: } else {
468: offset += (geom.getNumPoints() * len);
469: }
470: }
471:
472: return;
473: }
474:
475: throw new IllegalArgumentException(
476: "Cannot encode JTS "
477: + geom.getGeometryType()
478: + " as SDO_ELEM_INFO "
479: + "(Limitied to Point, Line, Polygon, GeometryCollection, MultiPoint,"
480: + " MultiLineString and MultiPolygon)");
481: }
482:
483: private void addInt(List list, int i) {
484: list.add(new Integer(i));
485: }
486:
487: /**
488: * We need to check if a <code>polygon</code> a rectangle so we can produce
489: * the correct encoding.
490: *
491: * Rectangles are only supported without a SRID!
492: *
493: * @param polygon
494: *
495: * @return <code>true</code> if polygon is SRID==0 and a rectangle
496: */
497: private boolean isRectangle(Polygon polygon) {
498: if (polygon.getFactory().getSRID() != Constants.SRID_NULL) {
499: // Rectangles only valid in CAD applications
500: // that do not have an SRID system
501: //
502: return false;
503: }
504:
505: if (lrs(polygon) != 0) {
506: // cannot support LRS on a rectangle
507: return false;
508: }
509:
510: Coordinate[] coords = polygon.getCoordinates();
511:
512: if (coords.length != 5) {
513: return false;
514: }
515:
516: if ((coords[0] == null) || (coords[1] == null)
517: || (coords[2] == null) || (coords[3] == null)) {
518: return false;
519: }
520:
521: if (!coords[0].equals2D(coords[4])) {
522: return false;
523: }
524:
525: double x1 = coords[0].x;
526: double y1 = coords[0].y;
527: double x2 = coords[1].x;
528: double y2 = coords[1].y;
529: double x3 = coords[2].x;
530: double y3 = coords[2].y;
531: double x4 = coords[3].x;
532: double y4 = coords[3].y;
533:
534: if ((x1 == x4) && (y1 == y2) && (x3 == x2) && (y3 == y4)) {
535: // 1+-----+2
536: // | |
537: // 4+-----+3
538: return true;
539: }
540:
541: if ((x1 == x2) && (y1 == y4) && (x3 == x4) && (y3 == y2)) {
542: // 2+-----+3
543: // | |
544: // 1+-----+4
545: return true;
546: }
547:
548: return false;
549: }
550:
551: /**
552: * Produce <code>SDO_ETYPE</code> for geometry description as stored in the
553: * <code>SDO_ELEM_INFO</code>.
554: *
555: * <p>
556: * Describes how Ordinates are ordered:
557: * </p>
558: * <pre><code><b>
559: * Value Elements Meaning</b>
560: * 0 Custom Geometry (like spline)
561: * 1 simple Point (or Points)
562: * 2 simple Line (or Lines)
563: * 3 polygon ring of unknown order (discouraged update to 1003 or 2003)
564: * 1003 simple polygon ring (1 exterior counterclockwise order)
565: * 2003 simple polygon ring (2 interior clockwise order)
566: * 4 compound series defines a linestring
567: * 5 compound series defines a polygon ring of unknown order (discouraged)
568: * 1005 compound series defines exterior polygon ring (counterclockwise order)
569: * 2005 compound series defines interior polygon ring (clockwise order)
570: * </code></pre>
571: *
572: * @param geom Geometry being represented
573: *
574: * @return Descriptionof Ordinates representation
575: *
576: * @throws IllegalArgumentException
577: */
578: private int elemInfoEType(Geometry geom) {
579: switch (template(geom)) {
580:
581: case Constants.SDO_GTEMPLATE.POINT:
582: return Constants.SDO_ETYPE.POINT;
583:
584: case Constants.SDO_GTEMPLATE.LINE:
585: return Constants.SDO_ETYPE.LINE;
586:
587: case Constants.SDO_GTEMPLATE.POLYGON:
588: // jts convention
589: return Constants.SDO_ETYPE.POLYGON_EXTERIOR; // cc order
590:
591: default:
592:
593: // should never happen!
594: throw new IllegalArgumentException(
595: "Unknown encoding of SDO_GTEMPLATE");
596: }
597: }
598:
599: /**
600: * Allows specification of <code>INTERPRETATION</code> used to interpret
601: * <code>geom</code>.
602: *
603: * @param geom Geometry to encode
604: * @param etype ETYPE value requiring an INTERPREATION
605: *
606: * @return INTERPRETATION ELEM_INFO entry for geom given etype
607: *
608: * @throws IllegalArgumentException If asked to encode a curve
609: */
610: private int elemInfoInterpretation(Geometry geom, int etype) {
611: switch (etype) {
612:
613: case Constants.SDO_ETYPE.POINT:
614:
615: if (geom instanceof Point) {
616: return 1;
617: }
618:
619: if (geom instanceof MultiPoint) {
620: return ((MultiPoint) geom).getNumGeometries();
621: }
622:
623: break;
624:
625: case Constants.SDO_ETYPE.LINE:
626: // always straight for jts
627: return 1;
628:
629: case Constants.SDO_ETYPE.POLYGON:
630: case Constants.SDO_ETYPE.POLYGON_EXTERIOR:
631: case Constants.SDO_ETYPE.POLYGON_INTERIOR:
632:
633: if (geom instanceof Polygon) {
634: Polygon polygon = (Polygon) geom;
635: // always straight for jts
636: if (isRectangle(polygon)) {
637: return 3;
638: }
639: }
640:
641: return 1;
642: }
643:
644: throw new IllegalArgumentException(
645: "Cannot encode JTS "
646: + geom.getGeometryType()
647: + " as "
648: + "SDO_INTERPRETATION (Limitied to Point, Line, Polygon, "
649: + "GeometryCollection, MultiPoint, MultiLineString and MultiPolygon)");
650: }
651:
652: /**
653: * Return SDO_POINT_TYPE for geometry
654: *
655: * Will return non null for Point objects. <code>null</code> is returned
656: * for all non point objects.
657:
658: * You cannot use this with LRS Coordiantes
659: * Subclasses may wish to repress this method and force Points to be
660: * represented using SDO_ORDINATES.
661: *
662: * @param geom
663: *
664: * @return double[]
665: */
666: private double[] point(Geometry geom) {
667: if (geom instanceof Point && (lrs(geom) == 0)) {
668: Point point = (Point) geom;
669: Coordinate coord = point.getCoordinate();
670:
671: return new double[] { coord.x, coord.y, coord.z };
672: }
673:
674: // SDO_POINT_TYPE only used for non LRS Points
675: return null;
676: }
677:
678: /**
679: * Produce SDO_GTEMPLATE representing provided Geometry.
680: *
681: * <p>
682: * Encoding of Geometry type and dimension.
683: * </p>
684: *
685: * <p>
686: * SDO_GTEMPLATE defined as for digits <code>[d][l][tt]</code>:
687: * </p>
688: *
689: * @param geom
690: *
691: * @return SDO_GTEMPLATE
692: */
693: private int gType(Geometry geom) {
694: int d = dimension(geom) * 1000;
695: int l = lrs(geom) * 100;
696: int tt = template(geom);
697:
698: return d + l + tt;
699: }
700:
701: /**
702: * Return dimensions as defined by SDO_GTEMPLATE (either 2,3 or 4).
703: *
704: *
705: * @param geom
706: *
707: * @return num dimensions
708: */
709: private int dimension(Geometry geom) {
710: int d = Double.isNaN(geom.getCoordinate().z) ? 2 : 3;
711: return d < dimension ? d : dimension;
712: }
713:
714: /**
715: * Return LRS as defined by SDO_GTEMPLATE (either 3,4 or 0).
716: *
717: * @param geom
718: *
719: * @return <code>0</code>
720: */
721: private int lrs(Geometry geom) {
722: // when measures are supported this may change
723: // until then ...
724: return 0;
725: }
726:
727: /**
728: * Return TT as defined by SDO_GTEMPLATE (represents geometry type).
729: *
730: * @see Constants.SDO_GTEMPLATE
731: *
732: * @param geom
733: *
734: * @return template code
735: */
736: private int template(Geometry geom) {
737: if (geom == null) {
738: return -1; // UNKNOWN
739: } else if (geom instanceof Point) {
740: return Constants.SDO_GTEMPLATE.POINT;
741: } else if (geom instanceof LineString) {
742: return Constants.SDO_GTEMPLATE.LINE;
743: } else if (geom instanceof Polygon) {
744: return Constants.SDO_GTEMPLATE.POLYGON;
745: } else if (geom instanceof MultiPoint) {
746: return Constants.SDO_GTEMPLATE.MULTIPOINT;
747: } else if (geom instanceof MultiLineString) {
748: return Constants.SDO_GTEMPLATE.MULTILINE;
749: } else if (geom instanceof MultiPolygon) {
750: return Constants.SDO_GTEMPLATE.MULTIPOLYGON;
751: } else if (geom instanceof GeometryCollection) {
752: return Constants.SDO_GTEMPLATE.COLLECTION;
753: }
754:
755: throw new IllegalArgumentException(
756: "Cannot encode JTS "
757: + geom.getGeometryType()
758: + " as SDO_GTEMPLATE "
759: + "(Limitied to Point, Line, Polygon, GeometryCollection, MultiPoint,"
760: + " MultiLineString and MultiPolygon)");
761: }
762:
763: /** Convience method for STRUCT construction. */
764: private STRUCT toSTRUCT(Datum attributes[], String dataType)
765: throws SQLException {
766: if (dataType.startsWith("*.")) {
767: dataType = "DRA." + dataType.substring(2);//TODO here
768: }
769: StructDescriptor descriptor = StructDescriptor
770: .createDescriptor(dataType, connection);
771:
772: return new STRUCT(descriptor, connection, attributes);
773: }
774:
775: /**
776: * Convience method for ARRAY construction.
777: * <p>
778: * Compare and contrast with toORDINATE - which treats <code>Double.NaN</code>
779: * as<code>NULL</code></p>
780: */
781: private ARRAY toARRAY(double doubles[], String dataType)
782: throws SQLException {
783: ArrayDescriptor descriptor = ArrayDescriptor.createDescriptor(
784: dataType, connection);
785:
786: return new ARRAY(descriptor, connection, doubles);
787: }
788:
789: /**
790: * Convience method for ARRAY construction.
791: */
792: private ARRAY toARRAY(int ints[], String dataType)
793: throws SQLException {
794: ArrayDescriptor descriptor = ArrayDescriptor.createDescriptor(
795: dataType, connection);
796:
797: return new ARRAY(descriptor, connection, ints);
798: }
799:
800: /**
801: * Convience method for NUMBER construction.
802: * <p>
803: * Double.NaN is represented as <code>NULL</code> to agree
804: * with JTS use.</p>
805: */
806: private NUMBER toNUMBER(double number) throws SQLException {
807: if (Double.isNaN(number)) {
808: return null;
809: }
810: return new NUMBER(number);
811: }
812:
813: /**
814: * reverses the coordinate order
815: *
816: * @param factory
817: * @param sequence
818: *
819: * @return CoordinateSequence reversed sequence
820: */
821: private CoordinateSequence reverse(
822: CoordinateSequenceFactory factory,
823: CoordinateSequence sequence) {
824: CoordinateList list = new CoordinateList(sequence
825: .toCoordinateArray());
826: Collections.reverse(list);
827: return factory.create(list.toCoordinateArray());
828: }
829:
830: /**
831: * @param dimension The dimension to set.
832: */
833: public void setDimension(int dimension) {
834: this.dimension = dimension;
835: }
836: }
|