0001: /*
0002: * Geotools2 - OpenSource mapping toolkit
0003: * http://geotools.org
0004: * (C) 2002-2006, Geotools Project Managment Committee (PMC)
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation;
0009: * version 2.1 of the License.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: *
0016: */
0017: package org.geotools.arcsde.data;
0018:
0019: import java.util.ArrayList;
0020: import java.util.HashMap;
0021: import java.util.List;
0022: import java.util.Map;
0023: import java.util.logging.Level;
0024: import java.util.logging.Logger;
0025:
0026: import org.geotools.data.DataSourceException;
0027:
0028: import com.esri.sde.sdk.client.SDEPoint;
0029: import com.esri.sde.sdk.client.SeCoordinateReference;
0030: import com.esri.sde.sdk.client.SeException;
0031: import com.esri.sde.sdk.client.SeShape;
0032: import com.vividsolutions.jts.geom.Coordinate;
0033: import com.vividsolutions.jts.geom.Geometry;
0034: import com.vividsolutions.jts.geom.GeometryCollection;
0035: import com.vividsolutions.jts.geom.GeometryFactory;
0036: import com.vividsolutions.jts.geom.LineString;
0037: import com.vividsolutions.jts.geom.LinearRing;
0038: import com.vividsolutions.jts.geom.MultiLineString;
0039: import com.vividsolutions.jts.geom.MultiPoint;
0040: import com.vividsolutions.jts.geom.MultiPolygon;
0041: import com.vividsolutions.jts.geom.Point;
0042: import com.vividsolutions.jts.geom.Polygon;
0043:
0044: /**
0045: * Creates propper JTS Geometry objects from <code>SeShape</code> objects and
0046: * viceversa.
0047: *
0048: * <p>
0049: * <code>SeShape</code>'s are gathered from an <code>SeRow</code> ArcSDE
0050: * API's result object and holds it's geometry attributes as a three dimensional
0051: * array of <code>double</code> primitives as explained bellow.
0052: * </p>
0053: *
0054: * <p>
0055: * By this way, we avoid the creation of ArcSDE's java implementation of OGC
0056: * geometries for later translation to JTS, avoiding too the dependency on the
0057: * ArcSDE native library wich the geometry package of the ArcSDE Java API
0058: * depends on.
0059: * </p>
0060: *
0061: * <p>
0062: * Given <code>double [][][]coords</code> the meaning of this array is as
0063: * follow:
0064: *
0065: * <ul>
0066: * <li>coords.length reprsents the number of geometries this geometry is
0067: * composed of. In deed, this only applies for multipolygon geometries, for all
0068: * other geometry types, this will be allways <code>1</code></li>
0069: * <li>coords[n] holds the coordinate arrays of the n'th geometry this geometry
0070: * is composed of. Except for multipolygons, this will allways be
0071: * <code>coords[0]</code>.</li>
0072: * <li>coords[n][m] holds the coordinates array for a given geometry. (i.e.
0073: * [0][m] for a multilinestring or [2][m] for a multipolygon composed of 3
0074: * polygons)</li>
0075: * <li>coords[n][m][l] holds the {x1, y1, x2, y2, ...,Xn, Yn} coordinates for a
0076: * given geometry part</li>
0077: * </ul>
0078: * </p>
0079: *
0080: * <p>
0081: * This abstract class will use specialized subclass for constructing the
0082: * propper geometry type
0083: * </p>
0084: *
0085: * @author Gabriel Roldan, Axios Engineering
0086: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/arcsde/datastore/src/main/java/org/geotools/arcsde/data/ArcSDEGeometryBuilder.java $
0087: * @version $Id: ArcSDEGeometryBuilder.java 27863 2007-11-12 20:34:34Z desruisseaux $
0088: */
0089: public abstract class ArcSDEGeometryBuilder {
0090: /** DOCUMENT ME! */
0091: private static final Logger LOGGER = org.geotools.util.logging.Logging
0092: .getLogger(ArcSDEGeometryBuilder.class.getName());
0093:
0094: /** specialized geometry builders classes by it's geometry type */
0095: private static final Map builders = new HashMap();
0096:
0097: /** DOCUMENT ME! */
0098: private static final Map nullGeometries = new HashMap();
0099:
0100: static {
0101: builders.put(Geometry.class, GenericGeometryBuilder
0102: .getInstance());
0103: builders.put(Point.class, PointBuilder.getInstance());
0104: builders.put(MultiPoint.class, MultiPointBuilder.getInstance());
0105: builders.put(LineString.class, LineStringBuilder.getInstance());
0106: builders.put(MultiLineString.class, MultiLineStringBuilder
0107: .getInstance());
0108: builders.put(Polygon.class, PolygonBuilder.getInstance());
0109: builders.put(MultiPolygon.class, MultiPolygonBuilder
0110: .getInstance());
0111:
0112: nullGeometries.put(Geometry.class, new GenericGeometryBuilder()
0113: .getEmpty());
0114: nullGeometries.put(Point.class, new PointBuilder().getEmpty());
0115: nullGeometries.put(MultiPoint.class, new MultiPointBuilder()
0116: .getEmpty());
0117: nullGeometries.put(LineString.class, new LineStringBuilder()
0118: .getEmpty());
0119: nullGeometries.put(MultiLineString.class,
0120: new MultiLineStringBuilder().getEmpty());
0121: nullGeometries.put(Polygon.class, new PolygonBuilder()
0122: .getEmpty());
0123: nullGeometries.put(MultiPolygon.class,
0124: new MultiPolygonBuilder().getEmpty());
0125: }
0126:
0127: /** JTS geometry factory subclasses use to map SeShapes to JTS ones */
0128: protected GeometryFactory factory = new GeometryFactory();
0129:
0130: /**
0131: * Private empty constructor to obligate using this class as factory.
0132: */
0133: private ArcSDEGeometryBuilder() {
0134: // intentionally blank
0135: }
0136:
0137: /**
0138: * Takes an ArcSDE's <code>SeShape</code> and builds a JTS Geometry. The
0139: * geometry type constructed depends on this <code>ArcSDEGeometryBuilder</code>
0140: * specialized subclass
0141: *
0142: * @param shape
0143: * the ESRI's ArcSDE java api shape upon wich to create the new
0144: * JTS geometry
0145: *
0146: * @return the type of JTS Geometry this subclass instance is specialized
0147: * for or an empty geometry of the same class if
0148: * <code>shape.isNil()</code>
0149: *
0150: * @throws SeException
0151: * if it occurs fetching the coordinates array from
0152: * <code>shape</code>
0153: * @throws DataSourceException
0154: * if the
0155: * <code>com.vividsolutions.jts.geom.GeometryFactory</code>
0156: * this builder is backed by can't create the
0157: * <code>com.vividsolutions.jts.geom.Geometry</code> with the
0158: * <code>com.vividsolutions.jts.geom.Coordinate[]</code>
0159: * provided by <code>newGeometry</code>
0160: */
0161: public Geometry construct(SeShape shape) throws SeException,
0162: DataSourceException {
0163: if (shape == null || shape.isNil()) {
0164: return getEmpty();
0165: } else {
0166: return newGeometry(shape.getAllCoords());
0167: }
0168: }
0169:
0170: /**
0171: * Creates the ArcSDE Java API representation of a <code>Geometry</code>
0172: * object in its shape format, suitable to filter expressions as the SDE API
0173: * expects
0174: *
0175: * @param geometry
0176: * the JTS Geometry object to get the SDE representation from
0177: * @param seSrs
0178: * Coordinate Reference System of the underlying
0179: * <code>SeLayer</code> object for wich the
0180: * <code>SeShape</code> is constructed.
0181: *
0182: * @return the <code>SeShape</code> representation of passed
0183: * <code>Geometry</code>
0184: *
0185: * @throws ArcSDEGeometryBuildingException
0186: * DOCUMENT ME!
0187: */
0188: public SeShape constructShape(Geometry geometry,
0189: SeCoordinateReference seSrs)
0190: throws ArcSDEGeometryBuildingException {
0191: SeShape shape = null;
0192:
0193: try {
0194: shape = new SeShape(seSrs);
0195: } catch (SeException ex) {
0196: LOGGER.log(Level.WARNING, ex.getMessage(), ex);
0197: throw new ArcSDEGeometryBuildingException(ex.getSeError()
0198: .getErrDesc()
0199: + ": " + geometry, ex);
0200: }
0201:
0202: if (geometry.isEmpty()) {
0203: return shape;
0204: }
0205:
0206: int numParts;
0207: GeometryCollection gcol = null;
0208:
0209: if (geometry instanceof GeometryCollection) {
0210: gcol = (GeometryCollection) geometry;
0211: } else {
0212: Geometry[] geoms = { geometry };
0213: gcol = new GeometryFactory()
0214: .createGeometryCollection(geoms);
0215: }
0216:
0217: List allPoints = new ArrayList();
0218: numParts = gcol.getNumGeometries();
0219:
0220: int[] partOffsets = new int[numParts];
0221: Geometry geom;
0222: Coordinate[] coords;
0223: Coordinate c;
0224:
0225: for (int currGeom = 0; currGeom < numParts; currGeom++) {
0226: partOffsets[currGeom] = allPoints.size();
0227: geom = gcol.getGeometryN(currGeom);
0228:
0229: coords = geom.getCoordinates();
0230:
0231: for (int i = 0; i < coords.length; i++) {
0232: c = coords[i];
0233: allPoints.add(new SDEPoint(c.x, c.y));
0234: }
0235: }
0236:
0237: SDEPoint[] points = new SDEPoint[allPoints.size()];
0238: allPoints.toArray(points);
0239:
0240: try {
0241: if (geometry instanceof Point || gcol instanceof MultiPoint) {
0242: shape.generatePoint(points.length, points);
0243: } else if (geometry instanceof LineString
0244: || geometry instanceof MultiLineString) {
0245: shape.generateLine(points.length, numParts,
0246: partOffsets, points);
0247: } else {
0248: shape.generatePolygon(points.length, numParts,
0249: partOffsets, points);
0250: }
0251: } catch (SeException e) {
0252: LOGGER
0253: .warning(e.getSeError().getErrDesc() + ":\nGEOM="
0254: + geometry + "\nShape=" + shape + "\nCRS: "
0255: + seSrs);
0256: throw new ArcSDEGeometryBuildingException(e.getSeError()
0257: .getErrDesc(), e);
0258: }
0259:
0260: return shape;
0261: }
0262:
0263: /**
0264: * utility method that <code>ArcSDEGeometryBuilder</code> subclasses use to
0265: * obtain the three dimensional array of double's that forms the body of the
0266: * <code>SeShape</code> structure.
0267: *
0268: * @param jtsGeom
0269: * the source JTS geometry
0270: *
0271: * @return the array of <code>double</code> primitives that represents
0272: * <code>jtsGeom</code> in <code>SeShape</code> format
0273: */
0274: private double[][][] geometryToSdeCoords(Geometry jtsGeom) {
0275: int numParts;
0276: int numSubParts = 1;
0277: double[][][] sdeCoords;
0278:
0279: GeometryCollection gcol = null;
0280:
0281: // to simplify the algorithm, allways use GeometryCollections
0282: // as input geometries
0283: if (jtsGeom instanceof MultiPolygon) {
0284: gcol = (GeometryCollection) jtsGeom;
0285: } else {
0286: Geometry[] geoms = { jtsGeom };
0287:
0288: gcol = new GeometryFactory()
0289: .createGeometryCollection(geoms);
0290: }
0291:
0292: numParts = gcol.getNumGeometries();
0293:
0294: sdeCoords = new double[numParts][0][0];
0295:
0296: for (int i = 0; i < numParts; i++) {
0297: Geometry geom = gcol.getGeometryN(i);
0298:
0299: numSubParts = (geom instanceof Polygon) ? (((Polygon) geom)
0300: .getNumInteriorRing() + 1)
0301: : ((geom instanceof GeometryCollection) ? ((GeometryCollection) geom)
0302: .getNumGeometries()
0303: : 1);
0304:
0305: sdeCoords[i] = new double[numSubParts][0];
0306:
0307: Coordinate[] partCoords = null;
0308:
0309: for (int j = 0; j < numSubParts; j++) {
0310: if (geom instanceof Polygon) {
0311: if (j == 0) {
0312: partCoords = ((Polygon) geom).getExteriorRing()
0313: .getCoordinates();
0314: } else {
0315: partCoords = ((Polygon) geom).getInteriorRingN(
0316: j - 1).getCoordinates();
0317: }
0318: } else if (geom instanceof GeometryCollection) {
0319: partCoords = ((GeometryCollection) geom)
0320: .getGeometryN(j).getCoordinates();
0321: } else {
0322: partCoords = geom.getCoordinates();
0323: }
0324:
0325: sdeCoords[i][j] = toSdeCoords(partCoords);
0326: }
0327: }
0328:
0329: return sdeCoords;
0330: }
0331:
0332: /**
0333: * Creates an array of linear coordinates as <code>SeShape</code> use from
0334: * an array of JTS <code>Coordinate</code> objects
0335: *
0336: * @param coords
0337: * wich coordinate to generate the linear array from
0338: *
0339: * @return the <code>SeShape</code> style coordinate array of a single
0340: * geometry given by its <code>Coordinate</code> array
0341: */
0342: private double[] toSdeCoords(Coordinate[] coords) {
0343: int nCoords = coords.length;
0344: double[] sdeCoords = new double[2 * nCoords];
0345: Coordinate c;
0346:
0347: for (int i = 0, j = 1; i < nCoords; i++, j += 2) {
0348: c = coords[i];
0349: sdeCoords[j - 1] = c.x;
0350: sdeCoords[j] = c.y;
0351: }
0352:
0353: return sdeCoords;
0354: }
0355:
0356: /**
0357: * Builds a JTS Geometry who't type is given by the
0358: * <code>ArcSDEGeometryBuilder</code> subclass instance specialization that
0359: * implements it
0360: *
0361: * @param coords
0362: * <code>SeShape</code>'s coordinate array to build the
0363: * geometry from
0364: *
0365: * @return the JST form of the passed geometry coordinates
0366: *
0367: * @throws DataSourceException
0368: * if an error occurs while creating the JTS Geometry
0369: */
0370: protected abstract Geometry newGeometry(double[][][] coords)
0371: throws DataSourceException;
0372:
0373: /**
0374: * returns an empty JTS geometry who's type is given by the
0375: * <code>ArcSDEGeometryBuilder</code> subclass instance specialization that
0376: * implements it.
0377: *
0378: * <p>
0379: * this method is called in case that <code>SeShape.isNil() == true</code>
0380: * </p>
0381: *
0382: * @return an empty JTS geometry
0383: *
0384: * @throws UnsupportedOperationException
0385: * DOCUMENT ME!
0386: */
0387: protected Geometry getEmpty() {
0388: throw new UnsupportedOperationException(
0389: "this method sholdn't be called directly, it's intended pourpose"
0390: + " is to be implemented by subclasses so they provide propper "
0391: + " null Geometries");
0392: }
0393:
0394: /**
0395: * Builds an array of JTS <code>Coordinate</code> instances that's
0396: * geometrically equals to the <code>SeShape</code> single coordinates
0397: * array passed as argument.
0398: *
0399: * @param coordList
0400: * array of coordinates of a single shape part to build a
0401: * <code>Coordinate</code> from
0402: *
0403: * @return a geometrically equal to <code>coordList</code> array of
0404: * <code>Coordinate</code> instances
0405: */
0406: protected Coordinate[] toCoords(double[] coordList) {
0407: int nCoords = coordList.length / 2;
0408:
0409: Coordinate[] coords = new Coordinate[nCoords];
0410:
0411: for (int i = 0, j = 0; i < nCoords; i++, j++)
0412: coords[i] = new Coordinate(coordList[j], coordList[++j]);
0413:
0414: return coords;
0415: }
0416:
0417: /**
0418: * DOCUMENT ME!
0419: *
0420: * @param coords
0421: * DOCUMENT ME!
0422: *
0423: * @return DOCUMENT ME!
0424: */
0425: protected SDEPoint[] toPointsArray(Coordinate[] coords) {
0426: int nCoords = coords.length;
0427:
0428: SDEPoint[] points = new SDEPoint[nCoords];
0429:
0430: Coordinate c;
0431:
0432: for (int i = 0; i < nCoords; i++) {
0433: c = coords[i];
0434:
0435: points[i] = new SDEPoint(c.x, c.y);
0436: }
0437:
0438: return points;
0439: }
0440:
0441: /**
0442: * Factory method that returns an instance of <code>ArcSDEGeometryBuilder</code>
0443: * specialized in contructing JTS geometries of the JTS Geometry class
0444: * passed as argument. Note that <code>jtsGeometryClass</code> must be one
0445: * of the supported concrete JTS Geometry classes.
0446: *
0447: * @param jtsGeometryClass
0448: *
0449: *
0450: * @throws IllegalArgumentException
0451: * if <code>jtsGeometryClass</code> is not a concrete JTS
0452: * <code>Geometry</code> class (like
0453: * <code>com.vividsolutions.jts.geom.MultiPoint.class</code>
0454: * i.e.)
0455: */
0456: public static ArcSDEGeometryBuilder builderFor(
0457: Class jtsGeometryClass) throws IllegalArgumentException {
0458: ArcSDEGeometryBuilder builder = (ArcSDEGeometryBuilder) builders
0459: .get(jtsGeometryClass);
0460:
0461: if (builder == null) {
0462: String msg = "no geometry builder is defined to construct "
0463: + jtsGeometryClass + " instances.";
0464: throw new IllegalArgumentException(msg);
0465: }
0466:
0467: return builder;
0468: }
0469:
0470: /**
0471: * DOCUMENT ME!
0472: *
0473: * @param geoClass
0474: * DOCUMENT ME!
0475: *
0476: * @return DOCUMENT ME!
0477: *
0478: * @throws NullPointerException
0479: * DOCUMENT ME!
0480: */
0481: public static Geometry defaultValueFor(Class geoClass) {
0482: if (geoClass == null) {
0483: throw new NullPointerException("got null geometry class");
0484: }
0485:
0486: Geometry emptyGeom = (Geometry) nullGeometries.get(geoClass);
0487:
0488: return emptyGeom;
0489: }
0490:
0491: /**
0492: * <code>ArcSDEGeometryBuilder</code> which can create any type of JTS geometry
0493: * from <code>SeShape</code>'s and viceversa
0494: *
0495: * @author Gabriel Roldan, Axios Engineering
0496: * @version $Id: ArcSDEGeometryBuilder.java 27863 2007-11-12 20:34:34Z desruisseaux $
0497: */
0498: private static class GenericGeometryBuilder extends
0499: ArcSDEGeometryBuilder {
0500: /** singleton for generic geometry building */
0501: private static final ArcSDEGeometryBuilder instance = new GenericGeometryBuilder();
0502:
0503: /**
0504: * Returns an instance of this geometry builder. Currently implemented
0505: * as a singleton since it is completely thread safe.
0506: *
0507: * @return the <code>GenericGeometryBuilder</code> singleton.
0508: */
0509: public static ArcSDEGeometryBuilder getInstance() {
0510: return instance;
0511: }
0512:
0513: /**
0514: * DOCUMENT ME!
0515: *
0516: * @return DOCUMENT ME!
0517: */
0518: protected Geometry getEmpty() {
0519: return new PointBuilder().getEmpty();
0520: }
0521:
0522: /**
0523: * DOCUMENT ME!
0524: *
0525: * @param shape
0526: * DOCUMENT ME!
0527: *
0528: * @return DOCUMENT ME!
0529: *
0530: * @throws SeException
0531: * DOCUMENT ME!
0532: * @throws DataSourceException
0533: * DOCUMENT ME!
0534: */
0535: public Geometry construct(SeShape shape) throws SeException,
0536: DataSourceException {
0537: Class realGeomClass = ArcSDEAdapter
0538: .getGeometryTypeFromSeShape(shape);
0539: ArcSDEGeometryBuilder realBuilder = builderFor(realGeomClass);
0540:
0541: return realBuilder.construct(shape);
0542: }
0543:
0544: /**
0545: * DOCUMENT ME!
0546: *
0547: * @param coords
0548: * DOCUMENT ME!
0549: *
0550: * @return DOCUMENT ME!
0551: *
0552: * @throws DataSourceException
0553: * DOCUMENT ME!
0554: * @throws UnsupportedOperationException
0555: * DOCUMENT ME!
0556: */
0557: protected Geometry newGeometry(double[][][] coords)
0558: throws DataSourceException {
0559: throw new UnsupportedOperationException(
0560: "This method should not "
0561: + "be called for this builder. It should be mapped to the "
0562: + "one capable of constructing the actual geometry type");
0563: }
0564: }
0565:
0566: /**
0567: * <code>ArcSDEGeometryBuilder</code> specialized in creating JTS
0568: * <code>Point</code> s from <code>SeShape</code> points and viceversa
0569: *
0570: * @author Gabriel Roldan, Axios Engineering
0571: * @version $Id: ArcSDEGeometryBuilder.java 27863 2007-11-12 20:34:34Z desruisseaux $
0572: */
0573: private static class PointBuilder extends ArcSDEGeometryBuilder {
0574: /** the empty point singleton */
0575: private static Geometry EMPTY;
0576:
0577: /** singleton for point building */
0578: private static final ArcSDEGeometryBuilder instance = new PointBuilder();
0579:
0580: /**
0581: * Returns an instance of this geometry builder for Point geometries.
0582: * Currently implemented as a singleton since it is completely thread
0583: * safe.
0584: *
0585: * @return the <code>PointBuilder</code> singleton.
0586: */
0587: public static ArcSDEGeometryBuilder getInstance() {
0588: return instance;
0589: }
0590:
0591: /**
0592: * DOCUMENT ME!
0593: *
0594: * @return DOCUMENT ME!
0595: */
0596: protected Geometry getEmpty() {
0597: if (EMPTY == null) {
0598: EMPTY = new GeometryFactory()
0599: .createPoint((Coordinate) null);
0600: }
0601:
0602: return EMPTY;
0603: }
0604:
0605: /**
0606: * DOCUMENT ME!
0607: *
0608: * @param coords
0609: * DOCUMENT ME!
0610: *
0611: * @return DOCUMENT ME!
0612: *
0613: * @throws DataSourceException
0614: * DOCUMENT ME!
0615: */
0616: protected Geometry newGeometry(double[][][] coords)
0617: throws DataSourceException {
0618: return super .factory.createPoint(new Coordinate(
0619: coords[0][0][0], coords[0][0][1]));
0620: }
0621: }
0622:
0623: /**
0624: * <code>ArcSDEGeometryBuilder</code> specialized in creating JTS
0625: * <code>MultiPoint</code> s from <code>SeShape</code> multipoints and
0626: * viceversa
0627: *
0628: * @author Gabriel Roldan, Axios Engineering
0629: * @version $Id: ArcSDEGeometryBuilder.java 27863 2007-11-12 20:34:34Z desruisseaux $
0630: */
0631: private static class MultiPointBuilder extends
0632: ArcSDEGeometryBuilder {
0633: /** the empty multipoint singleton */
0634: private static Geometry EMPTY;
0635:
0636: /** singleton for multipoint building */
0637: private static final ArcSDEGeometryBuilder instance = new MultiPointBuilder();
0638:
0639: /**
0640: * Returns an instance of this geometry builder for MultiPoint
0641: * geometries. Currently implemented as a singleton since it is
0642: * completely thread safe.
0643: *
0644: * @return the <code>MultiPointBuilder</code> singleton.
0645: */
0646: public static ArcSDEGeometryBuilder getInstance() {
0647: return instance;
0648: }
0649:
0650: /**
0651: * DOCUMENT ME!
0652: *
0653: * @return DOCUMENT ME!
0654: */
0655: protected Geometry getEmpty() {
0656: if (EMPTY == null) {
0657: EMPTY = new GeometryFactory()
0658: .createMultiPoint((Point[]) null);
0659: }
0660:
0661: return EMPTY;
0662: }
0663:
0664: /**
0665: * DOCUMENT ME!
0666: *
0667: * @param coords
0668: * DOCUMENT ME!
0669: *
0670: * @return DOCUMENT ME!
0671: *
0672: * @throws DataSourceException
0673: * DOCUMENT ME!
0674: */
0675: protected Geometry newGeometry(double[][][] coords)
0676: throws DataSourceException {
0677: int nPoints = coords.length;
0678:
0679: Coordinate[] points = new Coordinate[nPoints];
0680:
0681: for (int i = 0; i < nPoints; i++) {
0682: double x = coords[i][0][0];
0683: double y = coords[i][0][1];
0684: points[i] = new Coordinate(x, y);
0685: }
0686:
0687: return super .factory.createMultiPoint(points);
0688: }
0689: }
0690:
0691: /**
0692: * <code>ArcSDEGeometryBuilder</code> specialized in creating JTS
0693: * <code>LineString</code> s from <code>SeShape</code> linestring and
0694: * viceversa
0695: *
0696: * @author Gabriel Roldan, Axios Engineering
0697: * @version $Id: ArcSDEGeometryBuilder.java 27863 2007-11-12 20:34:34Z desruisseaux $
0698: */
0699: private static class LineStringBuilder extends
0700: ArcSDEGeometryBuilder {
0701: /** the empty linestring singleton */
0702: private static Geometry EMPTY;
0703:
0704: /** DOCUMENT ME! */
0705: private static int numParts = 1; // it's allways 1 for geoms other
0706: // than multipolygons
0707:
0708: /** DOCUMENT ME! */
0709: private static int[] partOffsets = { 0 };
0710:
0711: /** singleton for linestring building */
0712: private static final ArcSDEGeometryBuilder instance = new LineStringBuilder();
0713:
0714: /**
0715: * Returns an instance of this geometry builder for LineString
0716: * geometries. Currently implemented as a singleton since it is
0717: * completely thread safe.
0718: *
0719: * @return the <code>LineStringBuilder</code> singleton.
0720: */
0721: public static ArcSDEGeometryBuilder getInstance() {
0722: return instance;
0723: }
0724:
0725: /**
0726: * DOCUMENT ME!
0727: *
0728: * @return DOCUMENT ME!
0729: */
0730: protected Geometry getEmpty() {
0731: if (EMPTY == null) {
0732: EMPTY = new GeometryFactory()
0733: .createLineString((Coordinate[]) null);
0734: }
0735:
0736: return EMPTY;
0737: }
0738:
0739: /**
0740: * DOCUMENT ME!
0741: *
0742: * @param coords
0743: * DOCUMENT ME!
0744: *
0745: * @return DOCUMENT ME!
0746: *
0747: * @throws DataSourceException
0748: * DOCUMENT ME!
0749: */
0750: protected Geometry newGeometry(double[][][] coords)
0751: throws DataSourceException {
0752: return constructLineString(coords[0][0]);
0753: }
0754:
0755: //
0756: protected LineString constructLineString(double[] linearCoords)
0757: throws DataSourceException {
0758: LineString ls = null;
0759:
0760: Coordinate[] coords = toCoords(linearCoords);
0761:
0762: ls = super .factory.createLineString(coords);
0763:
0764: return ls;
0765: }
0766: }
0767:
0768: /**
0769: * <code>ArcSDEGeometryBuilder</code> specialized in creating JTS
0770: * <code>MultiLineString</code> s from <code>SeShape</code>
0771: * multilinestrings and viceversa
0772: *
0773: * @author Gabriel Roldan, Axios Engineering
0774: * @version $Id: ArcSDEGeometryBuilder.java 27863 2007-11-12 20:34:34Z desruisseaux $
0775: */
0776: private static class MultiLineStringBuilder extends
0777: LineStringBuilder {
0778: /** the empty multilinestring singleton */
0779: private static Geometry EMPTY;
0780:
0781: /** singleton for multilinestring building */
0782: private static final ArcSDEGeometryBuilder instance = new MultiLineStringBuilder();
0783:
0784: /**
0785: * Returns an instance of this geometry builder for MultiLineString
0786: * geometries. Currently implemented as a singleton since it is
0787: * completely thread safe.
0788: *
0789: * @return the <code>MultiLineStringBuilder</code> singleton.
0790: */
0791: public static ArcSDEGeometryBuilder getInstance() {
0792: return instance;
0793: }
0794:
0795: /**
0796: * DOCUMENT ME!
0797: *
0798: * @return DOCUMENT ME!
0799: */
0800: protected Geometry getEmpty() {
0801: if (EMPTY == null) {
0802: EMPTY = new GeometryFactory()
0803: .createMultiLineString(null);
0804: }
0805:
0806: return EMPTY;
0807: }
0808:
0809: /**
0810: * DOCUMENT ME!
0811: *
0812: * @param coords
0813: * DOCUMENT ME!
0814: *
0815: * @return DOCUMENT ME!
0816: *
0817: * @throws DataSourceException
0818: * DOCUMENT ME!
0819: */
0820: protected Geometry newGeometry(double[][][] coords)
0821: throws DataSourceException {
0822: MultiLineString mls = null;
0823:
0824: LineString[] lineStrings = null;
0825:
0826: int nLines = coords.length;
0827:
0828: lineStrings = new LineString[nLines];
0829:
0830: for (int i = 0; i < nLines; i++)
0831: lineStrings[i] = constructLineString(coords[i][0]);
0832:
0833: mls = super .factory.createMultiLineString(lineStrings);
0834:
0835: return mls;
0836: }
0837: }
0838:
0839: /**
0840: * <code>ArcSDEGeometryBuilder</code> specialized in creating JTS
0841: * <code>Polygon</code> s from <code>SeShape</code> polygon and
0842: * viceversa
0843: *
0844: * @author Gabriel Roldan, Axios Engineering
0845: * @version $Id: ArcSDEGeometryBuilder.java 27863 2007-11-12 20:34:34Z desruisseaux $
0846: */
0847: private static class PolygonBuilder extends ArcSDEGeometryBuilder {
0848: /** the empty polygon singleton */
0849: private static Geometry EMPTY;
0850:
0851: /** singleton for polygon building */
0852: private static final ArcSDEGeometryBuilder instance = new PolygonBuilder();
0853:
0854: /**
0855: * Returns an instance of this geometry builder for Polygon geometries.
0856: * Currently implemented as a singleton since it is completely thread
0857: * safe.
0858: *
0859: * @return the <code>PolygonBuilder</code> singleton.
0860: */
0861: public static ArcSDEGeometryBuilder getInstance() {
0862: return instance;
0863: }
0864:
0865: /**
0866: * DOCUMENT ME!
0867: *
0868: * @return DOCUMENT ME!
0869: */
0870: protected Geometry getEmpty() {
0871: if (EMPTY == null) {
0872: EMPTY = new GeometryFactory().createPolygon(null, null);
0873: }
0874:
0875: return EMPTY;
0876: }
0877:
0878: /**
0879: * DOCUMENT ME!
0880: *
0881: * @param coords
0882: *
0883: *
0884: * @throws DataSourceException
0885: */
0886: protected Geometry newGeometry(double[][][] coords)
0887: throws DataSourceException {
0888: return buildPolygon(coords);
0889: }
0890:
0891: /**
0892: * DOCUMENT ME!
0893: *
0894: * @param parts
0895: * DOCUMENT ME!
0896: *
0897: * @return DOCUMENT ME!
0898: */
0899: protected Polygon buildPolygon(double[][][] parts) {
0900: Polygon p = null;
0901:
0902: double[] linearCoordArray = parts[0][0];
0903:
0904: int nHoles = parts.length - 1;
0905:
0906: LinearRing shell = super .factory
0907: .createLinearRing(toCoords(linearCoordArray));
0908:
0909: LinearRing[] holes = new LinearRing[nHoles];
0910:
0911: if (nHoles > 0) {
0912: for (int i = 0; i < nHoles; i++) {
0913: linearCoordArray = parts[i + 1][0];
0914:
0915: holes[i] = super .factory
0916: .createLinearRing(toCoords(linearCoordArray));
0917: }
0918: }
0919:
0920: p = super .factory.createPolygon(shell, holes);
0921:
0922: return p;
0923: }
0924: }
0925:
0926: /**
0927: * <code>ArcSDEGeometryBuilder</code> specialized in creating JTS
0928: * <code>MultiPolygon</code> s from <code>SeShape</code> multipolygons
0929: * and viceversa
0930: *
0931: * @author Gabriel Roldan, Axios Engineering
0932: * @version $Id: ArcSDEGeometryBuilder.java 27863 2007-11-12 20:34:34Z desruisseaux $
0933: */
0934: private static class MultiPolygonBuilder extends PolygonBuilder {
0935: /** the empty multipolygon singleton */
0936: private static Geometry EMPTY;
0937:
0938: /** singleton for multipolygon building */
0939: private static final ArcSDEGeometryBuilder instance = new MultiPolygonBuilder();
0940:
0941: /**
0942: * Returns an instance of this geometry builder for MultiPolygon
0943: * geometries. Currently implemented as a singleton since it is
0944: * completely thread safe.
0945: *
0946: * @return the <code>PointBuilder</code> singleton.
0947: */
0948: public static ArcSDEGeometryBuilder getInstance() {
0949: return instance;
0950: }
0951:
0952: /**
0953: * DOCUMENT ME!
0954: *
0955: * @return an empty multipolygon
0956: */
0957: protected Geometry getEmpty() {
0958: if (EMPTY == null) {
0959: EMPTY = new GeometryFactory().createMultiPolygon(null);
0960: }
0961:
0962: return EMPTY;
0963: }
0964:
0965: /**
0966: * DOCUMENT ME!
0967: *
0968: * @param coords
0969: * the SeShape's multipolygon coordinates array
0970: *
0971: * @return a <code>MultiPolygon</code> constructed based on the SDE
0972: * shape, or the empty geometry if the <code>shape == null ||
0973: * shape.isNil()</code>
0974: *
0975: * @throws DataSourceException
0976: * if it is not possible to obtain the shape's coordinate
0977: * arrays or an exception occurs while building the Geometry
0978: */
0979: protected Geometry newGeometry(double[][][] coords)
0980: throws DataSourceException {
0981: Polygon[] polys = null;
0982:
0983: int numPolys = coords.length;
0984:
0985: polys = new Polygon[numPolys];
0986:
0987: for (int i = 0; i < numPolys; i++) {
0988: try {
0989: polys[i] = buildPolygon(coords[i]);
0990: } catch (Exception ex) {
0991: throw new DataSourceException(ex.getMessage(), ex);
0992: }
0993: }
0994:
0995: MultiPolygon multiPoly = super .factory
0996: .createMultiPolygon(polys);
0997:
0998: return multiPoly;
0999: }
1000:
1001: /**
1002: * DOCUMENT ME!
1003: *
1004: * @param parts
1005: * DOCUMENT ME!
1006: *
1007: * @return DOCUMENT ME!
1008: */
1009: private Polygon buildPolygon(double[][] parts) {
1010: Polygon p = null;
1011:
1012: double[] linearCoordArray = parts[0];
1013:
1014: int nHoles = parts.length - 1;
1015:
1016: LinearRing shell = super .factory
1017: .createLinearRing(toCoords(linearCoordArray));
1018:
1019: LinearRing[] holes = new LinearRing[nHoles];
1020:
1021: if (nHoles > 0) {
1022: for (int i = 0; i < nHoles; i++) {
1023: linearCoordArray = parts[i + 1];
1024:
1025: holes[i] = super.factory
1026: .createLinearRing(toCoords(linearCoordArray));
1027: }
1028: }
1029:
1030: p = super.factory.createPolygon(shell, holes);
1031:
1032: return p;
1033: }
1034: }
1035: }
|