shapeInExtents = mQueryExtents.contains(path[2], path[3]);
shapeInExtents = (mQueryExtents.outcode(path[2], path[3]) == 0);
	public Row fetch() throws MapyrusException	{		int recordNumber;		int recordLength;		double x, y, lastX, lastY, xMin, yMin, xMax, yMax;		double fieldValue;		int i, shapeType;		int nBytes, nParts, nPoints, partIndex, pathIndex;		boolean shapeInExtents = false;		Row row;		double path[] = null;		try		{			/*			 * Keep reading until we get a shape inside the extents or we reach			 * the end of the file.			 */			row = new Row();			while (!shapeInExtents && mBytesRead < mShapeFileLength)			{				/*				 * Read header for next shape.  Convert record length to byte length.				 */				recordNumber = mShapeStream.readInt();				recordLength = mShapeStream.readInt() * 2;				shapeType = readLittleEndianInt(mShapeStream);				nBytes = 4;				if (mShapeFileType == POINT || mShapeFileType == POINT_Z ||					mShapeFileType == POINT_M)				{					/*					 * Read point coordinates, see if they are inside					 * query extents.  Skip Z and Measure values for 3D shapes.					 */					path = new double[4];					path[0] = 4;					path[1] = PathIterator.SEG_MOVETO;										path[2] = readLittleEndianDouble(mShapeStream);					path[3] = readLittleEndianDouble(mShapeStream);					nBytes += 16;					shapeInExtents = mQueryExtents.contains(path[2], path[3]);				}				else if (mShapeFileType == POLYLINE || mShapeFileType == POLYGON ||					mShapeFileType == POLYLINE_Z || mShapeFileType == POLYGON_Z ||					mShapeFileType == POLYLINE_M || mShapeFileType == POLYGON_M ||					mShapeFileType == MULTIPATCH)				{					/*					 * Read bounding box of polyline or polygon.					 * Find if it intersects with query extents.					 */					xMin = readLittleEndianDouble(mShapeStream);					yMin = readLittleEndianDouble(mShapeStream);					xMax = readLittleEndianDouble(mShapeStream);					yMax = readLittleEndianDouble(mShapeStream);					nBytes += 4 * 8;					shapeInExtents = mQueryExtents.intersects(xMin, yMin, xMax - xMin, yMax - yMin);					if (shapeInExtents)					{						/*						 * Read polyline or polygon coordinates.						 */						nParts = readLittleEndianInt(mShapeStream);						nPoints = readLittleEndianInt(mShapeStream);						nBytes += 2 * 4;						int []parts = new int[nParts];						for (i = 0; i < nParts; i++)							parts[i] = readLittleEndianInt(mShapeStream);						nBytes += nParts * 4;						/*						 * Skip part type information in multi-patch files.						 */						if (mShapeFileType == MULTIPATCH)						{							mShapeStream.skipBytes(nParts * 4);							nBytes += nParts * 4;						}						path = new double[nPoints * 3 + 1];						partIndex = 0;						pathIndex = 1;						lastX = lastY = Double.MAX_VALUE;						for (i = 0; i < nPoints; i++)						{							/*							 * Add next coordinates, as either a moveto or lineto.							 */							x = readLittleEndianDouble(mShapeStream);							y = readLittleEndianDouble(mShapeStream);							nBytes += 2 * 8;							if (partIndex < nParts && parts[partIndex] == i)							{								path[pathIndex] = PathIterator.SEG_MOVETO;								partIndex++;							}							else if (x == lastX && y == lastY)							{								/*								 * Skip duplicate points.								 */								continue;							}							else							{								path[pathIndex] = PathIterator.SEG_LINETO;							}															path[pathIndex + 1] = lastX = x;							path[pathIndex + 2] = lastY = y;							pathIndex += 3;						}						path[0] = pathIndex;					}					else					{						/*						 * Shape is outside query extents, skip it.						 */					}				}				else if (mShapeFileType == MULTIPOINT || mShapeFileType == MULTIPOINT_Z ||					mShapeFileType == MULTIPOINT_M)				{					/*					 * Read bounding box of points.					 * Find if it intersects with query extents.					 */					xMin = readLittleEndianDouble(mShapeStream);					yMin = readLittleEndianDouble(mShapeStream);					xMax = readLittleEndianDouble(mShapeStream);					yMax = readLittleEndianDouble(mShapeStream);					nBytes += 4 * 8;					shapeInExtents = mQueryExtents.intersects(xMin, yMin, xMax - xMin, yMax - yMin);					if (shapeInExtents)					{						nPoints = readLittleEndianInt(mShapeStream);						nBytes += 4;						/*						 * Read each of the points and add them to the path.						 */						path = new double[nPoints * 3 + 1];												pathIndex = 1;											for (i = 0; i < nPoints; i++)						{							path[pathIndex] = PathIterator.SEG_MOVETO;							path[pathIndex + 1] = readLittleEndianDouble(mShapeStream);							path[pathIndex + 2] = readLittleEndianDouble(mShapeStream);							pathIndex += 3;							nBytes += 16;						}						path[0] = pathIndex;					}				}				/*				 * Skip until end of this record in shape file.				 */						if (nBytes < recordLength)					mShapeStream.skipBytes(recordLength - nBytes);				mBytesRead += recordLength + 8;				/*				 * If user wants any attribute fields then read them for this shape.				 * Don't bother unpacking them if we are skipping this shape.				 */				if (mNDBFFieldsToFetch > 0)				{					mDBFStream.read(mDBFRecord);					while (mDBFRecord[0] == DBF_DELETED_RECORD)					{						/*						 * Skip deleted records.						 */						mDBFStream.read(mDBFRecord);					}				}				if (shapeInExtents)				{					if (mNDBFFieldsToFetch > 0)					{						int recordOffset = 1;						for (i = 0; i < mDBFFieldTypes.length; i++)						{							Argument arg = null;								/*							 * Only unpack fields that user asked for.							 */							if (((Boolean)mDBFFieldsToFetch.get(i)).booleanValue())							{								if (mDBFFieldTypes[i] == DBF_CHARACTER ||									mDBFFieldTypes[i] == DBF_DATE)								{									arg = new Argument(Argument.STRING,										unpackString(mDBFRecord, recordOffset,										mDBFFieldLengths[i]));								}								else if (mDBFFieldTypes[i] == DBF_NUMBER ||									mDBFFieldTypes[i] == DBF_FLOATING)								{									String s = unpackString(mDBFRecord,										recordOffset, mDBFFieldLengths[i]);									try									{										fieldValue = Double.parseDouble(s);									}									catch (NumberFormatException e)									{										fieldValue = 0.0;									}									arg = new Argument(fieldValue);								}								else if (mDBFFieldTypes[i] == DBF_LOGICAL)								{									switch ((char)mDBFRecord[recordOffset])									{										case 'y':										case 'Y':										case 'T':										case 't':											arg = Argument.numericOne;											break;										default:											arg = Argument.numericZero;											break;									}								}								row.add(arg);							}								recordOffset += mDBFFieldLengths[i];						}					}					/*					 * Add geometry as final field.					 */					row.add(new Argument(path));				}			}		}		catch (IOException e)		{			throw new MapyrusException(e.getMessage());		}		/*		 * Return next row, or null if we did not find one.		 */		if (shapeInExtents)			return(row);		else			return(null);	}