docs: @SuppressWarnings({"unchecked", "checkstyle:cyclomaticcomplexity", "checkstyle:npathcomplexity",
  		"checkstyle:nestedifdepth"})
  	private static <P extends GISPrimitive, N extends AbstractGISTreeSetNode<P, N>>
  		boolean addInside(AbstractGISTreeSet<P, N> tree,
  			N insertionNode,
  			P element,
  			GISTreeSetNodeFactory<P, N> builder,
  			boolean enableRearrange) {
  		if (element == null) {
  			return false;
  		}
  		final GeoLocation location = element.getGeoLocation();
  		if (location == null) {
  			return false;
  		}
  
  		N insNode = insertionNode;
  
  		if (insNode == null) {
  			insNode = tree.getTree().getRoot();
  			// The insertion node is the root.
  			if (insNode == null) {
  				if (tree.worldBounds == null) {
  					insNode = builder.newRootNode(element);
  				} else {
  					insNode = builder.newRootNode(
  							element,
  							tree.worldBounds.getMinX(),
  							tree.worldBounds.getMinY(),
  							tree.worldBounds.getWidth(),
  							tree.worldBounds.getHeight());
  				}
  				tree.getTree().setRoot(insNode);
  				tree.updateComponentType(element);
  				return true;
  			}
  		}
  
  		// Go through the tree to retreive the leaf where to put the element
  
  		final boolean isRearrangable = enableRearrange && tree.worldBounds == null;
  
  		while (insNode != null) {
  			if (insNode.isLeaf()) {
  				// The node is a leaf. Add the element inside the node only if
  				// the splitting count is not reached. Otherwise split this node
  				if (insNode.getUserDataCount() >= GISTreeSetConstants.SPLIT_COUNT) {
  					if (isRearrangable && isOutsideNodeBuildingBounds(insNode, location.toBounds2D())) {
  						if (!insNode.addUserData(element)) {
  							return false;
  						}
  						// Make the building bounds of the node larger
  						rearrangeTree(tree, insNode, union(insNode, location.toBounds2D()), builder);
  					} else {
  						// Split the node
  						int classification;
  						final int count = insNode.getChildCount();
  
  						// Prepare the list of elements for each child
  						GeoLocation dataLocation;
  						final List<P>[] collections = (List<P>[]) Array.newInstance(List.class, count);
  
  						int subBranchCount = 0;
  
  						// compute the positions of the data
  						for (final P data : insNode.getAllUserData()) {
  							dataLocation = data.getGeoLocation();
  							classification = GISTreeSetUtil.classifies(insNode, dataLocation);
  							if (collections[classification] == null) {
  								collections[classification] = new LinkedList<>();
  								++subBranchCount;
  							}
  							collections[classification].add(data);
  						}
  
  						classification = GISTreeSetUtil.classifies(insNode, location);
  						if (collections[classification] == null) {
  							collections[classification] = new LinkedList<>();
  							++subBranchCount;
  						}
  						collections[classification].add(element);
  
  						// save the data into the children
  						if (subBranchCount > 1) {
  							for (int region = 0; region < count; ++region) {
  								if (collections[region] != null) {
  									final N newNode = createNode(insNode, IcosepQuadTreeZone.values()[region], builder);
  									assert newNode != null;
  									if (!newNode.addUserData(collections[region])) {
  										return false;
  									}
  									if (!insNode.setChildAt(region, newNode)) {
  										return false;
  									}
  								}
  							}
  							insNode.removeAllUserData();
  						} else if (subBranchCount == 1) {
  							insNode.addUserData(element);
  						}
  
  					}
  					insNode = null;
  				} else {
  					// Insert inside this node, and stop the loop on the tree nodes
  					if (!insNode.addUserData(element)) {
  						return false;
  					}
  					if (isRearrangable && isOutsideNodeBuildingBounds(insNode, location.toBounds2D())) {
  						// Make the building bounds of the node larger
  						rearrangeTree(tree, insNode, union(insNode, location.toBounds2D()), builder);
  					}
  					insNode = null;
  				}
  			} else {
  				// The node is not a leaf. Insert the element inside one of the subtrees
  				final int region = classifies(insNode, location);
  				final N child = insNode.getChildAt(region);
  				if (child == null) {
  					final N newNode = createNode(insNode, IcosepQuadTreeZone.values()[region], builder);
  					insNode.setChildAt(region, newNode);
  					insNode = newNode;
  				} else {
  					insNode = child;
  				}
  			}
  		}
  
  		tree.updateComponentType(element);
  		return true;
  	}