public Stream union()

in baremaps-core/src/main/java/org/apache/baremaps/database/algorithm/UnionStream.java [49:111]


  public Stream<Geometry> union() {
    // Use a bitmap to keep track of the geometries that have been visited
    var visited = new Roaring64Bitmap();

    // Create a spatial index of the geometries
    HPRtree tree = new HPRtree();
    for (int i = 0; i < list.size(); i++) {
      tree.insert(list.get(i).getEnvelopeInternal(), i);
    }
    tree.build();

    // Create a stream of geometry unions that are spatially connected
    var stream = IntStream.range(0, list.size()).mapToObj(i -> {
      // Skip the geometries that have already been visited
      if (visited.contains(i)) {
        return null;
      }
      visited.add(i);

      // Initialize an accumulator and a stack to visit neighbors
      var accumulator = new ArrayList<Geometry>();
      var stack = new ArrayDeque<Geometry>();

      // Add the current geometry to the accumulator and the stack
      var g = list.get(i);
      accumulator.add(g);
      stack.push(g);

      // Visit all neighbors that are spatially connected
      while (!stack.isEmpty()) {
        var g1 = stack.pop();
        tree.query(g1.getEnvelopeInternal(), o -> {
          var j = (int) o;
          if (visited.contains(j)) {
            return;
          }
          visited.add(j);
          var g2 = list.get(j);
          try {
            // If the geometries are not spatially disjoint, add them to the accumulator and the
            // stack,
            // so that their neighbors can be visited
            if (g1.intersects(g2)) {
              accumulator.add(g2);
              stack.push(g2);
            }
          } catch (TopologyException e) {
            // This should occur only if the geometries are invalid,
            // or in the case of a bug in JTS.
            logger.warn("Failed to union geometries", e);
            logger.warn("Geometry 1: {}", g1);
            logger.warn("Geometry 2: {}", g2);
          }
        });
      }

      // Union the geometries in the accumulator
      return new UnaryUnionOp(accumulator).union();
    });

    // Filter out the null values
    return stream.filter(Objects::nonNull);
  }