GeoLatte / geolatte-geom

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

Oracle PolygonSdoDecoder should skip unsupported ordinates #169

Open geirsagberg opened 3 months ago

geirsagberg commented 3 months ago

I have an SDO Polygon with some initial ordinates that contain custom metadata:

(2003,82347,null,(1,0,1,10,0,2,11,1003,1,47,2003,1),(0.0,8.0,1.0,45.0,-1.0,100.0,-1.0,0.0,-1.0,0.0,116712.255139103,6939047.36203288,116704.700506065,6939040.6912486,116698.953958519,6939031.50691358,116708.602658342,6939017.54194319,116713.230418604,6939012.18853483,116714.000609768,6939009.16622119,116734.230411832,6939026.8756717,116742.732632141,6939034.48478609,116751.011830927,6939041.97995529,116747.358759767,6939043.6588074,116744.114459277,6939045.84921152,116741.775624066,6939046.18904433,116739.628147685,6939044.55121321,116732.978040147,6939045.10937637,116729.59052832,6939046.05917251,116726.545546915,6939046.34085121,116724.448196814,6939047.56076488,116712.255139103,6939047.36203288,116723.533359264,6939037.81863852,116725.365165851,6939037.32779974,116726.703264627,6939036.19553463,116726.899791358,6939035.47442466,116725.179767819,6939033.29835153,116722.567804377,6939030.66650706,116718.132173834,6939026.77850234,116716.135093639,6939033.71392686,116718.001127453,6939035.94298276,116720.75391878,6939037.37124384,116723.533359264,6939037.81863852))

The first 10 ordinates are not part of the polygon itself.

However, the PolygonSdoDecoder attempts to treat them as part of the polygon. This causes a failure with "Invalid null ring found when attempting to construct polygon".

Here is a suggested pseudocode fix that skips all unsupported elements:

    @Override
    protected <P extends Position> Geometry<P> decode(SDOGType gtype, List<Element> elements, CoordinateReferenceSystem<P> crs) {
        List<Element> supportedElements = elements.filter(x -> x.getElementType() != ElementType.UNSUPPORTED);
        LinearRing[] rings = new LinearRing[supportedElements.size()];

        int idx = 1;
        for(Element element: supportedElements ) {
            if (element.getElementType().isInteriorRing()) {
                rings[idx++] = new LinearRing(element.linearizedPositions(gtype, crs), crs);
            }
            else {
                rings[0] = new LinearRing(element.linearizedPositions(gtype, crs), crs);
            }
        }

        if( !Arrays.stream(rings).allMatch(Objects::nonNull)){
            //only possible when number of exterior rings != 1.
            throw new IllegalStateException("Invalid null ring found when attempting to construct polygon");
        }
        return new Polygon(rings);
    }