brainbaking/content/wiki/code/java/oraclegeometry.md

6.7 KiB

+++ title = "oraclegeometry" draft = false tags = [ "", "Users", "jefklak", "Downloads", "pages", "code", "java", "oraclegeometry" ] date = "2013-03-12" +++

Oracle Geometries

SDO_GEOMETRY Mappen in de DB

Via Hibernate: met een UserType implementatie

    public Object nullSafeGet(ResultSet resultSet, String[] strings, Object o) throws HibernateException, SQLException {
        STRUCT geometry = (STRUCT) resultSet.getObject(strings[0]);

        if (resultSet.wasNull() || geometry ###### null) {
            return null;
        }
        return new Geometry(JGeometry.load(geometry));
    }

    /**
     * setNull(i, Types.OTHER or Types.STRUCT) results in "unknown column type" exceptions!
     */
    public void nullSafeSet(PreparedStatement preparedStatement, Object o, int i) throws HibernateException, SQLException {
        if (o ###### null) {
            preparedStatement.setNull(i, Types.STRUCT, OracleSpatialDialect.MSYS + "." + OracleSpatialDialect.SDO_GEOM_TYPE_COLUMN);
        } else {
            if (o instanceof Geometry) {
                Connection oracleConnection = ((DelegatingConnection) preparedStatement.getConnection()).getInnermostDelegate();
                STRUCT struct = JGeometry.store(((Geometry) o).getInnerGeometry(), oracleConnection);
                preparedStatement.setObject(i, struct);
            }
        }
    }

Merk op dat de store() method op JGeometry effectief een oracle connectie object nodig heeft (harde cast gebeurt in de implementatie). een struct object kan dan omgevormd worden naar JGeometry (te downloaden: sdoapi jar, Oracle Spatial Java API). Het Geometry object is iets dat hierrond gewrapped is. Dit heeft een aantal voordelen:

  1. Afscheiden spatial api dependency rest van de code
  2. Makkelijk converteren van SDO_GEOMETRY('...') String waarde naar object en omgekeerd

############= Van String naar Object en omgekeerd ############=

public class Geometry implements Cloneable, Serializable {

	private static final String MDSYS_POINT_TYPE = "MDSYS.SDO_POINT_TYPE";
	private static final String MDSYS_ORDINATE_ARR = "MDSYS.SDO_ORDINATE_ARRAY";
	private static final String MDSYS_ELEMENT_ARR = "MDSYS.SDO_ELEM_INFO_ARRAY";
	private static final String MDSYS_GEOM = "MDSYS.SDO_GEOMETRY";

	final static int SRID = 327680;

	private final JGeometry geometry;

	public Geometry() {
		this.geometry = null;
	}

	public Geometry(String sdoGeometry) throws GeometryConversionException {
		try {
			this.geometry = disassembleSdoGeometry(sdoGeometry);
		} catch (Exception disassemblingEx) {
			throw new GeometryConversionException(disassemblingEx);
		}
	}

	public Geometry(JGeometry jGeometry) {
		this.geometry = jGeometry;
	}

	public JGeometry getInnerGeometry() {
		return geometry;
	}

	@Override
	public String toString() {
		return toSDOGeometryString();
	}

	private JGeometry disassembleSdoGeometry(String sdoGeometry) {
		return new JGeometry(retrieveGeometryType(sdoGeometry), //
				retrieveSRID(sdoGeometry), //
				retrievePointTypeX(sdoGeometry), //
				retrievePointTypeY(sdoGeometry), //
				retrievePointTypeZ(sdoGeometry), //
				retrieveElemInfo(sdoGeometry), //
				retrieveOrdinatesArray(sdoGeometry) //
		);
	}

	private int retrieveGeometryType(String sdoGeometry) {
		String geometryType = StringUtils.substringBetween(sdoGeometry, "(", ",");
		return Integer.parseInt(geometryType.trim());
	}

	private int retrieveSRID(String sdoGeometry) {
		String sridString = StringUtils.substringBetween(sdoGeometry, ",", ",");
		return Integer.parseInt(sridString.trim());
	}

	private double retrievePointTypeX(String sdoGeometry) {
		return retrievePointTypes(sdoGeometry)[0];
	}

	private double retrievePointTypeY(String sdoGeometry) {
		return retrievePointTypes(sdoGeometry)[1];
	}

	private double retrievePointTypeZ(String sdoGeometry) {
		return retrievePointTypes(sdoGeometry)[2];
	}

	private double[] retrievePointTypes(String sdoGeometry) {
		double[] result = new double[3];
		String pointTypesAsString = StringUtils.substringBetween(sdoGeometry, MDSYS_POINT_TYPE + "(", ")");
		if (pointTypesAsString != null) {
			result = toDoubleArray(pointTypesAsString);
		}
		return result;
	}

	private int[] retrieveElemInfo(String sdoGeometry) {
		String elemInfoArray = StringUtils.substringBetween(sdoGeometry, MDSYS_ELEMENT_ARR + "(", ")");
		return toIntArray(elemInfoArray);
	}

	private double[] retrieveOrdinatesArray(String sdoGeometry) {
		String ordinatesArray = StringUtils.substringBetween(sdoGeometry, MDSYS_ORDINATE_ARR + "(", ")");
		return toDoubleArray(ordinatesArray);
	}

	public String toSDOGeometryString() {
		if (geometry ###### null)
			return null;

		StringBuilder string = new StringBuilder(MDSYS_GEOM + "(");
		string.append(getGeometryType() + ",");
		string.append(geometry.getSRID() + ",");

		if (geometry.getPoint() ###### null) {
			string.append("null,");
		} else {
			string.append(MDSYS_POINT_TYPE);
			string.append(toStringDoubleArray(geometry.getPoint()));
			string.append(",");
		}

		if (geometry.getElemInfo() ###### null) {
			string.append("null,");
		} else {
			string.append(MDSYS_ELEMENT_ARR);
			string.append(toStringIntArray(geometry.getElemInfo()));
			string.append(",");
		}

		if (geometry.getOrdinatesArray() ###### null) {
			string.append("null");
		} else {
			string.append(MDSYS_ORDINATE_ARR);
			string.append(toStringDoubleArray(geometry.getOrdinatesArray()));
		}
		return string.append(")").toString();
	}

	private int getGeometryType() {
		return (geometry.getDimensions() * 1000 + geometry.getType());
	}

	@Override
	public Object clone() {
		return (geometry ###### null ? new Geometry() : new Geometry((JGeometry) geometry.clone()));
	}

	@Override
	public int hashCode() {
		return (geometry ###### null ? 0 : geometry.hashCode());
	}

	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof Geometry))
			return false;
		JGeometry other = ((Geometry) obj).geometry;

		return new EqualsBuilder().append(geometry, other).isEquals();
	}

############= Joins uitvoeren ############=

Een Join kan uitgevoerd worden met een Oracle Geometry functie in de database: SDO_GEOM.SDO_UNION. Die voegt twee SDO_GEOMETRY objecten samen tot een maar er is ook nog metadata nodig dat ergens anders zit:

SELECT SDO_GEOM.SDO_UNION(?, diminfo, ?, diminfo) FROM ALL_SDO_GEOM_METADATA WHERE owner ###### ? and table_name  ?

NULL is toegelaten dus het is zo eenvoudig om een recursieve method aan te maken.

Opgelet Het is nodig om de voorgaande SQL in een PreparedStatement te steken indien de geometrie coördinaten +1.000 items bevatten. Zelfs in SQL Developer gaat dit niet. Foutboodschap dan: ORA-00939: too many arguments for function