read method

  1. @override
dynamic read(
  1. LByteBuffer buffer,
  2. ShapeType? type,
  3. bool flatFeature
)
override

Read a geometry from the ByteBuffer. The buffer's position, byteOrder, and limit are set to that which is needed. The record has been read as well as the shape type integer. The handler need not worry about reading unused information as the ShapefileReader will correctly adjust the buffer position after this call.

@param buffer The ByteBuffer to read from. @return A geometry object.

Implementation

@override
dynamic read(LByteBuffer buffer, ShapeType? type, bool flatFeature) {
  if (type == ShapeType.NULL) {
    return createNull();
  }
  // bounds
  buffer.position = buffer.position + 4 * 8;

  int numParts = buffer.getInt32();
  int numPoints = buffer.getInt32();
  int dimensions = (shapeType == ShapeType.POLYGONZ) && !flatFeature ? 3 : 2;

  List<int> partOffsets = List.filled(numParts, 0);

  for (int i = 0; i < numParts; i++) {
    partOffsets[i] = buffer.getInt32();
  }

  List<LinearRing> shells = [];
  List<LinearRing> holes = [];
  CoordinateSequence coords = readCoordinates(buffer, numPoints, dimensions);

  int offset = 0;
  int start;
  int finish;
  int length;

  for (int part = 0; part < numParts; part++) {
    start = partOffsets[part];

    if (part == (numParts - 1)) {
      finish = numPoints;
    } else {
      finish = partOffsets[part + 1];
    }

    length = finish - start;
    int close = 0; // '1' if the ring must be closed, '0' otherwise
    if ((coords.getOrdinate(start, CoordinateSequence.X) !=
            coords.getOrdinate(finish - 1, CoordinateSequence.X)) ||
        (coords.getOrdinate(start, CoordinateSequence.Y) !=
            coords.getOrdinate(finish - 1, CoordinateSequence.Y))) {
      close = 1;
    }
    if (dimensions == 3 && !coords.hasM()) {
      if (coords.getOrdinate(start, CoordinateSequence.Z) !=
          coords.getOrdinate(finish - 1, CoordinateSequence.Z)) {
        close = 1;
      }
    }

    CoordinateSequence csRing;
    if (coords.hasZ()) {
      csRing = Shapeutils.createCSMeas(
          geometryFactory.getCoordinateSequenceFactory(),
          length + close,
          4,
          1);
    } else if (coords.hasM()) {
      csRing = Shapeutils.createCSMeas(
          geometryFactory.getCoordinateSequenceFactory(),
          length + close,
          3,
          1);
    } else {
      csRing = Shapeutils.createCS(
          geometryFactory.getCoordinateSequenceFactory(), length + close, 2);
    }

    // double area = 0;
    // int sx = offset;
    for (int i = 0; i < length; i++) {
      csRing.setOrdinate(i, CoordinateSequence.X,
          coords.getOrdinate(offset, CoordinateSequence.X));
      csRing.setOrdinate(i, CoordinateSequence.Y,
          coords.getOrdinate(offset, CoordinateSequence.Y));
      if (coords.hasZ()) {
        csRing.setOrdinate(i, CoordinateSequence.Z,
            coords.getOrdinate(offset, CoordinateSequence.Z));
      }
      if (coords.hasM()) {
        csRing.setOrdinate(i, CoordinateSequence.M,
            coords.getOrdinate(offset, CoordinateSequence.M));
      }
      offset++;
    }
    if (close == 1) {
      csRing.setOrdinate(length, CoordinateSequence.X,
          coords.getOrdinate(start, CoordinateSequence.X));
      csRing.setOrdinate(length, CoordinateSequence.Y,
          coords.getOrdinate(start, CoordinateSequence.Y));
      if (coords.hasZ()) {
        csRing.setOrdinate(length, CoordinateSequence.Z,
            coords.getOrdinate(start, CoordinateSequence.Z));
      }
      if (coords.hasM()) {
        csRing.setOrdinate(length, CoordinateSequence.M,
            coords.getOrdinate(start, CoordinateSequence.M));
      }
    }
    // REVISIT: polygons with only 1 or 2 points are not polygons -
    // geometryFactory will bomb so we skip if we find one.
    if (csRing.size() == 0 || csRing.size() > 3) {
      LinearRing ring = geometryFactory.createLinearRingSeq(csRing);

      if (Shapeutils.isCCW(csRing)) {
        // counter-clockwise
        holes.add(ring);
      } else {
        // clockwise
        shells.add(ring);
      }
    }
  }

  // quick optimization: if there's only one shell no need to check
  // for holes inclusion
  if (shells.length == 1) {
    return createMultiWithHoles(shells[0], holes);
  }
  // if for some reason, there is only one hole, we just reverse it and
  // carry on.
  else if (holes.length == 1 && shells.isEmpty) {
    return createMulti(holes[0]);
  } else {
    // build an association between shells and holes
    final List<List<LinearRing>> holesForShells =
        assignHolesToShells(shells, holes);

    Geometry g = buildGeometries(shells, holes, holesForShells);

    return g;
  }
}