GeoLatte / geolatte-geom

A geometry model that conforms to the OGC Simple Features for SQL specification.
Other
134 stars 63 forks source link

Oracle Polygon encoder decoder do not return the original polygon. #36

Closed securityLast closed 8 years ago

securityLast commented 8 years ago

I setup a Junit test that incoded a simple polygon the decoded it. Then checked that they matched. It failed on polygons using the oracle decoders.

maesenka commented 8 years ago

Can you share these tests?

securityLast commented 8 years ago

import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse;

import javax.xml.bind.DatatypeConverter;

import org.geolatte.geom.ByteBuffer; import org.geolatte.geom.G2D; import org.geolatte.geom.Geometry; import org.geolatte.geom.codec.Wkt; import org.geolatte.geom.codec.Wkt.Dialect; import org.geolatte.geom.codec.WktDecoder; import org.geolatte.geom.codec.db.oracle.SDOGeometry; import org.geolatte.geom.codec.db.sqlserver.Decoders; import org.geolatte.geom.codec.db.sqlserver.Encoders; import org.geolatte.geom.crs.CoordinateReferenceSystem; import org.geolatte.geom.crs.CrsRegistry; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory;

public class LocationTest {

private static CoordinateReferenceSystem<G2D> crs = CrsRegistry.getGeographicCoordinateReferenceSystemForEPSG(4326);

/** The logger. */
protected static Logger logger = LoggerFactory
        .getLogger(LocationTest.class.getName());

final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();

@Test
public void geometryOraclePolygonTest() {
    String wkt1 = "SRID=4326;POLYGON((10.689 -25.092, 34.595 -20.170, 38.814 -35.639, 13.502 -39.155, 10.689 -25.092))";
    Geometry<?> orig = wktToGeometry(wkt1, crs);
    Geometry<?> coded = null;
    SDOGeometry sqlencode = org.geolatte.geom.codec.db.oracle.Encoders.encode(orig);
    try {
        coded = org.geolatte.geom.codec.db.oracle.Decoders.decode(sqlencode);
        logger.info(coded.toString());
    } catch (Exception e) {
        logger.error("DECODE FAILED! " + e.getMessage());
        assertFalse(true);
    }
    assertEquals(orig.toString(), coded.toString());
}

@Test
public void geometryOracleLineTest() {
    String wkt1 = "SRID=4326;LINESTRING(10.689 -25.092, 34.595 -20.170)";
    Geometry<?> orig = wktToGeometry(wkt1, crs);
    Geometry<?> coded = null;
    SDOGeometry sqlencode = org.geolatte.geom.codec.db.oracle.Encoders.encode(orig);
    try {
        coded = org.geolatte.geom.codec.db.oracle.Decoders.decode(sqlencode);
        logger.info(coded.toString());
    } catch (Exception e) {
        logger.error("DECODE FAILED! " + e.getMessage());
        assertFalse(true);
    }
    assertEquals(orig.toString(), coded.toString());
}

@Test
public void geometrySQLServerPolygonTest() {
    String wkt1 = "SRID=4326;POLYGON((10.689 -25.092, 34.595 -20.170, 38.814 -35.639, 13.502 -39.155, 10.689 -25.092))";
    Geometry<?> orig = wktToGeometry(wkt1, crs);
    Geometry<?> coded = null;
    byte[] ssg = Encoders.encode(orig);
    try {
        coded = Decoders.decode(ssg);
        logger.info(coded.toString());
    } catch (Exception e) {
        e.printStackTrace();
        assertFalse(true);
    }
    assertEquals(orig, coded);
}

@Test
public void geometrySQLServerPointTest() {
    String wkt1 = "SRID=4326;POINT(10.689 -25.092)";
    Geometry<?> orig = wktToGeometry(wkt1, crs);
    Geometry<?> coded = null;
    byte[] ssg = Encoders.encode(orig);
    try {
        coded = Decoders.decode(ssg);
        logger.info(coded.toString());
    } catch (Exception e) {
        e.printStackTrace();
        assertFalse(true);
    }
    assertEquals(orig, coded);
}

@Test
public void geometrySQLServerLineTest() {
    String wkt1 = "SRID=4326;LINESTRING(10.689 -25.092, 34.595 -20.170)";
    Geometry<?> orig = wktToGeometry(wkt1, crs);
    Geometry<?> coded = null;
    byte[] ssg = Encoders.encode(orig);
    try {
        coded = Decoders.decode(ssg);
        logger.info(coded.toString());
    } catch (Exception e) {
        e.printStackTrace();
        assertFalse(true);
    }
    assertEquals(orig, coded);
}

@Test
public void geometrySQLServerMultiPolygonTest() {
    String wkt1 = "SRID=4326;MULTIPOLYGON(((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20)))";
    Geometry<?> orig = wktToGeometry(wkt1, crs);
    Geometry<?> coded = null;
    byte[] ssg = Encoders.encode(orig);
    try {
        coded = Decoders.decode(ssg);
        logger.info(coded.toString());
    } catch (Exception e) {
        e.printStackTrace();
        assertFalse(true);
    }
    assertEquals(orig, coded);
}

@Test
public void geometryPostgreSQLPolygonTest() {
    String wkt1 = "SRID=4326;POLYGON((10.689 -25.092, 34.595 -20.170, 38.814 -35.639, 13.502 -39.155, 10.689 -25.092))";
    Geometry<?> orig = wktToGeometry(wkt1, crs);
    logger.info(orig.toString());
    Geometry<?> coded = null;
    ByteBuffer wkb = org.geolatte.geom.codec.Wkb.toWkb(orig);
    try {
        coded = org.geolatte.geom.codec.Wkb.fromWkb(wkb);
        logger.info(coded.toString());
    } catch (Exception e) {
        logger.error("DECODE FAILED! " + e.getMessage());
        assertFalse(true);
    }
    assertEquals(orig, coded);
}

@Test
public void geometryPostgreSQLMultiPolygonTest() {
    String wkt1 = "SRID=4326;MULTIPOLYGON(((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20)))";
    Geometry<?> orig = wktToGeometry(wkt1, crs);
    logger.info(orig.toString());
    Geometry<?> coded = null;
    ByteBuffer wkb = org.geolatte.geom.codec.Wkb.toWkb(orig);
    try {
        coded = org.geolatte.geom.codec.Wkb.fromWkb(wkb);
        logger.info(coded.toString());
    } catch (Exception e) {
        logger.error("DECODE FAILED! " + e.getMessage());
        assertFalse(true);
    }
    assertEquals(orig, coded);
}

@Test
public void decodeSQLGeometeryTest() {
    try {
        byte[] sqlencode = hexStringToByteArray("E6100000010C4703780B24B855C061C3D32B65093540");        
        Geometry<?> coded = Decoders.decode(sqlencode);
        logger.info(coded.toString());
    } catch(Exception e) {
        logger.error("decodeSSQLGeometryTest failed!", e);
        assertFalse(true);
    }

}

@Test
public void checkSQLServerEncodePointTest() {
    try {
        String hexSQLWKB = "E6100000010C4703780B24B855C061C3D32B65093540"; //Point
        byte[] sqlencode = hexStringToByteArray(hexSQLWKB);     
        Geometry<?> coded = Decoders.decode(sqlencode);
        logger.info(coded.toString());
        byte[] codedsql = Encoders.encode(coded);
        String codedStr = bytesToHex(codedsql);
        assertEquals(hexSQLWKB, codedStr);
        logger.info("\n" + hexSQLWKB + "\n" + codedStr);
    } catch(Exception e) {
        logger.error("decodeSSQLGeometryTest failed!", e);
        assertFalse(true);
    }
}

@Test
public void checkSQLServerEncodePolygonTest() {
    try {
        String hexSQLWKB = "00000000010404000000000000000000F03F0000000000000000000000000000F03F000000000000204000000000000018400000000000001040000000000000F03F000000000000000001000000020000000001000000FFFFFFFF0000000003"; //Polygon
        byte[] sqlencode = LocationTest.toByteArray(hexSQLWKB);     
        Geometry<?> coded = Decoders.decode(sqlencode);
        logger.info(coded.toString());
        byte[] codedsql = Encoders.encode(coded);
        String codedStr = LocationTest.toHexString(codedsql);
        assertEquals(hexSQLWKB, codedStr);
        logger.info("\n" + hexSQLWKB + "\n" + codedStr);
    } catch(Exception e) {
        logger.error("decodeSSQLGeometryTest failed!", e);
        assertFalse(true);
    }
}

@Test 
public void hexConverterTest() {
    String hexSQLWKB = "00000000010404000000000000000000F03F0000000000000000000000000000F03F000000000000204000000000000018400000000000001040000000000000F03F000000000000000001000000020000000001000000FFFFFFFF0000000003"; //Polygon
    byte[] stat = LocationTest.toByteArray(hexSQLWKB);
    byte[] func = hexStringToByteArray(hexSQLWKB);
    assertEquals(stat.length, func.length);
    assertEquals(stat[0], 0);
    for(int i = 0; i < stat.length; i++) {
        assertEquals(stat[i], func[i]);
    }

    String str = LocationTest.bytesToHex(stat);
    assertEquals(str, hexSQLWKB);
    logger.info(str);
}

private Geometry<G2D> wktToGeometry(String wktPoint, CoordinateReferenceSystem<G2D> localCrs) {
    Geometry<G2D> geom = null;
    WktDecoder decoder = Wkt.newDecoder(Dialect.POSTGIS_EWKT_1);
    if(wktPoint != null) {
        try {
            geom = (Geometry<G2D>) decoder.decode(wktPoint, localCrs);
            logger.info(geom.toString());
        } catch (Exception e) {
            throw new RuntimeException("Not a WKT string:" + wktPoint);
        }
    }
    return geom;
}

public static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    for (int j = 0; j < bytes.length; j++) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
}

public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                             + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

public static String toHexString(byte[] array) {
    return DatatypeConverter.printHexBinary(array);
}

public static byte[] toByteArray(String s) {
    return DatatypeConverter.parseHexBinary(s);
}

}

maesenka commented 8 years ago

For the Oracle case: it's a feature, not a bug. You'll notice that the difference is that the order of the coordinates has been reversed in the Oracle polygon. The Encoder reverses the order because Oracle expects the outer ring to be in counterclockwise order, and any inner rings in clockwise order.

So I'm closing this one.

securityLast commented 8 years ago

Sorry for flagging it then. I will rework my unit tests to give the correct order.

Thanks for looking into it.

On Tue, Nov 24, 2015 at 3:16 PM, Karel Maesen notifications@github.com wrote:

For the Oracle case: it's a feature, not a bug. You'll notice that the difference is that the order of the coordinates has been reversed in the Oracle polygon. The Encoder reverses the order because Oracle expects the outer ring to be in counterclockwise order, and any inner rings in clockwise order.

So I'm closing this one.

— Reply to this email directly or view it on GitHub https://github.com/GeoLatte/geolatte-geom/issues/36#issuecomment-159392820 .