private static Geometry readPolys(GeometryFactory geomFactory,
                                      List<Integer> geomCmds,
                                      Vec2d cursor,
                                      RingClassifier ringClassifier) {

        // Guard: must have header
        if(geomCmds.isEmpty()) {
            return null;
        }

        /** Geometry command index */
        int i = 0;

        int cmdHdr;
        int cmdLength;
        GeomCmd cmd;
        List<LinearRing> rings = new ArrayList<>(1);
        CoordinateSequence nextCoordSeq;
        Coordinate nextCoord;

        while(i <= geomCmds.size() - MIN_POLYGON_LEN) {

            // --------------------------------------------
            // Expected: MoveTo command of length 1
            // --------------------------------------------

            // Read command header
            cmdHdr = geomCmds.get(i++);
            cmdLength = GeomCmdHdr.getCmdLength(cmdHdr);
            cmd = GeomCmdHdr.getCmd(cmdHdr);

            // Guard: command type and length
            if(cmd != GeomCmd.MoveTo || cmdLength != 1) {
                break;
            }

            // Update cursor position with relative move
            cursor.add(
                    ZigZag.decode(geomCmds.get(i++)),
                    ZigZag.decode(geomCmds.get(i++))
            );


            // --------------------------------------------
            // Expected: LineTo command of length > 1
            // --------------------------------------------

            // Read command header
            cmdHdr = geomCmds.get(i++);
            cmdLength = GeomCmdHdr.getCmdLength(cmdHdr);
            cmd = GeomCmdHdr.getCmd(cmdHdr);

            // Guard: command type and length
            if(cmd != GeomCmd.LineTo || cmdLength < 2) {
                break;
            }

            // Guard: header data length unsupported by geometry command buffer
            //  (require at least (2 values * 2 params) + (current index 'i') + (1 for ClosePath))
            if((cmdLength * GeomCmd.LineTo.getParamCount()) + i + 1 > geomCmds.size()) {
                break;
            }

            nextCoordSeq = geomFactory.getCoordinateSequenceFactory().create(2 + cmdLength, 2);

            // Set first point from MoveTo command
            nextCoord = nextCoordSeq.getCoordinate(0);
            nextCoord.setOrdinate(0, cursor.x);
            nextCoord.setOrdinate(1, cursor.y);

            // Set remaining points from LineTo command
            for(int lineToIndex = 0; lineToIndex < cmdLength; ++lineToIndex) {

                // Update cursor position with relative line delta
                cursor.add(
                        ZigZag.decode(geomCmds.get(i++)),
                        ZigZag.decode(geomCmds.get(i++))
                );

                nextCoord = nextCoordSeq.getCoordinate(lineToIndex + 1);
                nextCoord.setOrdinate(0, cursor.x);
                nextCoord.setOrdinate(1, cursor.y);
            }


            // --------------------------------------------
            // Expected: ClosePath command of length 1
            // --------------------------------------------

            // Read command header
            cmdHdr = geomCmds.get(i++);
            cmdLength = GeomCmdHdr.getCmdLength(cmdHdr);
            cmd = GeomCmdHdr.getCmd(cmdHdr);

            if(cmd != GeomCmd.ClosePath || cmdLength != 1) {
                break;
            }

            // Set last point from ClosePath command
            nextCoord = nextCoordSeq.getCoordinate(nextCoordSeq.size() - 1);
            nextCoord.setOrdinate(0, nextCoordSeq.getOrdinate(0, 0));
            nextCoord.setOrdinate(1, nextCoordSeq.getOrdinate(0, 1));

            rings.add(geomFactory.createLinearRing(nextCoordSeq));
        }


        // Classify rings
        final List<Polygon> polygons = ringClassifier.classifyRings(rings, geomFactory);
        if(polygons.size() < 1) {
            return null;

        } else if(polygons.size() == 1) {
            return polygons.get(0);

        } else {
            return geomFactory.createMultiPolygon(polygons.toArray(new Polygon[polygons.size()]));
        }
    }
private static Geometry readPolys ( GeometryFactory geomFactory , List < Integer > geomCmds , Vec2d cursor , RingClassifier ringClassifier ) { if ( geomCmds . isEmpty ( ) ) { return null ; } int i = 0 ; int cmdHdr ; int cmdLength ; GeomCmd cmd ; List < LinearRing > rings = new ArrayList < > ( 1 ) ; CoordinateSequence nextCoordSeq ; Coordinate nextCoord ; while ( i <= geomCmds . size ( ) - MIN_POLYGON_LEN ) { cmdHdr = geomCmds . get ( i ++ ) ; cmdLength = GeomCmdHdr . getCmdLength ( cmdHdr ) ; cmd = GeomCmdHdr . getCmd ( cmdHdr ) ; if ( cmd != GeomCmd . MoveTo || cmdLength != 1 ) { break ; } cursor . add ( ZigZag . decode ( geomCmds . get ( i ++ ) ) , ZigZag . decode ( geomCmds . get ( i ++ ) ) ) ; cmdHdr = geomCmds . get ( i ++ ) ; cmdLength = GeomCmdHdr . getCmdLength ( cmdHdr ) ; cmd = GeomCmdHdr . getCmd ( cmdHdr ) ; if ( cmd != GeomCmd . LineTo || cmdLength < 2 ) { break ; } if ( ( cmdLength * GeomCmd . LineTo . getParamCount ( ) ) + i + 1 > geomCmds . size ( ) ) { break ; } nextCoordSeq = geomFactory . getCoordinateSequenceFactory ( ) . create ( 2 + cmdLength , 2 ) ; nextCoord = nextCoordSeq . getCoordinate ( 0 ) ; nextCoord . setOrdinate ( 0 , cursor . x ) ; nextCoord . setOrdinate ( 1 , cursor . y ) ; for ( int lineToIndex = 0 ; lineToIndex < cmdLength ; ++ lineToIndex ) { cursor . add ( ZigZag . decode ( geomCmds . get ( i ++ ) ) , ZigZag . decode ( geomCmds . get ( i ++ ) ) ) ; nextCoord = nextCoordSeq . getCoordinate ( lineToIndex + 1 ) ; nextCoord . setOrdinate ( 0 , cursor . x ) ; nextCoord . setOrdinate ( 1 , cursor . y ) ; } cmdHdr = geomCmds . get ( i ++ ) ; cmdLength = GeomCmdHdr . getCmdLength ( cmdHdr ) ; cmd = GeomCmdHdr . getCmd ( cmdHdr ) ; if ( cmd != GeomCmd . ClosePath || cmdLength != 1 ) { break ; } nextCoord = nextCoordSeq . getCoordinate ( nextCoordSeq . size ( ) - 1 ) ; nextCoord . setOrdinate ( 0 , nextCoordSeq . getOrdinate ( 0 , 0 ) ) ; nextCoord . setOrdinate ( 1 , nextCoordSeq . getOrdinate ( 0 , 1 ) ) ; rings . add ( geomFactory . createLinearRing ( nextCoordSeq ) ) ; } final List < Polygon > polygons = ringClassifier . classifyRings ( rings , geomFactory ) ; if ( polygons . size ( ) < 1 ) { return null ; } else if ( polygons . size ( ) == 1 ) { return polygons . get ( 0 ) ; } else { return geomFactory . createMultiPolygon ( polygons . toArray ( new Polygon [ polygons . size ( ) ] ) ) ; } }
Create {@link Polygon} or {@link MultiPolygon} from MVT geometry drawing commands.

@param geomFactory creates JTS geometry
@param geomCmds contains MVT geometry commands
@param cursor contains current MVT extent position
@param ringClassifier
@return JTS geometry or null on failure