code: private List<PageItemNode> restructurePageItems(List<PageItem> items) {
          List<PageItemNode> pins = items.stream().map(PageItemNode::new).collect(toList());
          for (PageItemNode pinA : pins) {
              for (PageItemNode pinB: pins) {
                  if (pinA != pinB) {
                      if (isInside(pinA.getPageItem().getArea(), pinB.getPageItem().getArea())) {
                          if (pinB.getParent() == pinA) {
                              throw new RuntimeException(format("The following objects have identical areas: %s, %s. Please remove one of the objects", pinA.getPageItem().getName(), pinB.getPageItem().getName()));
                          }
                          pinA.moveToParent(pinB);
                          break;
                      }
                  }
              }
          }
          return pins.stream().filter(pin -> pin.getParent() == null && pin.getChildren().size() > 0).collect(toList());
      }
docs: Orders page items into a tree by their area. Tries to fit one item inside another
  @param items
  @return A list of pins which are root elements (don't have a parent)