docs: private static <P extends GISPrimitive, N extends AbstractGISTreeSetNode<P, N>>
  		N rearrangeTree(AbstractGISTreeSet<P, N> tree, N node, Rectangle2afp<?, ?, ?, ?, ?, ?> desiredBounds,
  				GISTreeSetNodeFactory<P, N> builder) {
  		// Search for the node that completely contains the desired area
  		N topNode = node.getParentNode();
  		while (topNode != null && isOutsideNodeBuildingBounds(topNode, desiredBounds)) {
  			topNode = topNode.getParentNode();
  		}
  
  		final Rectangle2afp<?, ?, ?, ?, ?, ?> dr;
  		if (topNode == null) {
  			// Node node found, the entire tree should be rebuilt
  			topNode = tree.getTree().getRoot();
  			if (topNode == null) {
  				throw new IllegalStateException();
  			}
  			dr = union(topNode, desiredBounds);
  		} else {
  			dr = getNormalizedNodeBuildingBounds(topNode, desiredBounds);
  		}
  
  		// Build a new subtree
  		final N parent = topNode.getParentNode();
  		final Iterator<P> dataIterator = new PrefixDataDepthFirstTreeIterator<>(topNode);
  		final N newTopNode = builder.newNode(
  				topNode.getZone(),
  				dr.getMinX(), dr.getMinY(), dr.getWidth(), dr.getHeight());
  		while (dataIterator.hasNext()) {
  			if (!addInside(tree, newTopNode, dataIterator.next(), builder, false)) {
  				throw new IllegalStateException();
  			}
  		}
  
  		// Replace rearranged subtree by the new one
  		if (parent != null) {
  			parent.setChildAt(topNode.getZone().ordinal(), newTopNode);
  			return parent;
  		}
  		tree.getTree().setRoot(newTopNode);
  		return newTopNode;
  	}