docs: private E readMultiPatch(int elementIndex, ShapeElementType type) throws IOException {
  		// Ignore the bounds stored inside the file
  		skipBytes(8 * 4);
  
  		// Read the part count
  		final int partCount = readLEInt();
  
  		// Read the point count
  		final int pointCount = readLEInt();
  
  		// Read the parts' indexes
  		final int[] parts = new int[partCount];
  		for (int idxParts = 0; idxParts < partCount; ++idxParts) {
  			parts[idxParts] = readLEInt();
  		}
  
  		// Read the parts' types
  		final ShapeMultiPatchType[] partTypes = new ShapeMultiPatchType[partCount];
  		for (int idxParts = 0; idxParts < partCount; ++idxParts) {
  			partTypes[idxParts] = ShapeMultiPatchType.fromESRIInteger(readLEInt());
  		}
  
  		// Read the points
  		final ESRIPoint[] points = new ESRIPoint[pointCount];
  
  		for (int idxPoints = 0; idxPoints < pointCount; ++idxPoints) {
  			// Read coordinates
  			final double x = fromESRI_x(readLEDouble());
  			final double y = fromESRI_y(readLEDouble());
  
  			// Create point
  			if (!Double.isNaN(x) && !Double.isNaN(y)) {
  				points[idxPoints] = new ESRIPoint(x, y);
  			} else {
  				throw new InvalidNumericValueException(
  						Double.isNaN(x) ? x : y);
  			}
  		} // for i= 0 to numPoints
  
  		// Zmin and Zmax: 2*Double - ignored
  		skipBytes(2 * 8);
  
  		// Z array: numpoints*Double
  		double z;
  		for (int i = 0; i < pointCount; ++i) {
  			z = fromESRI_z(readLEDouble());
  			if (!Double.isNaN(z)) {
  				points[i].setZ(z);
  			}
  		}
  
  		// Mmin and Mmax: 2*Double - ignored
  		skipBytes(2 * 8);
  
  		// M array: numpoints*Double
  		double measure;
  		for (int i = 0; i < pointCount; ++i) {
  			measure = fromESRI_m(readLEDouble());
  			if (!Double.isNaN(measure)) {
  				points[i].setM(measure);
  			}
  		}
  
  		// Create the instance of the element
  		return createMultiPatch(
  				createAttributeCollection(elementIndex),
  				elementIndex,
  				parts,
  				partTypes,
  				points);
  	}