diff --git a/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNode.java b/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNode.java index 82402c197..f0e954bb0 100644 --- a/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNode.java +++ b/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNode.java @@ -3,6 +3,9 @@ package com.seibel.lod.core.util.objects.quadTree; import com.seibel.lod.core.logging.DhLoggerBuilder; import com.seibel.lod.core.pos.DhSectionPos; import com.seibel.lod.core.util.LodUtil; +import com.seibel.lod.core.util.objects.quadTree.iterators.QuadNodeDirectChildIterator; +import com.seibel.lod.core.util.objects.quadTree.iterators.QuadNodeDirectChildPosIterator; +import com.seibel.lod.core.util.objects.quadTree.iterators.QuadTreeNodeIterator; import org.apache.logging.log4j.Logger; import java.util.Iterator; @@ -119,19 +122,35 @@ public class QuadNode * @throws IllegalArgumentException if childSectionPos has the wrong detail level or is outside the bounds of this node * @return the node at the given position */ - public T getValue(DhSectionPos sectionPos) throws IllegalArgumentException { return this.getOrSetValue(sectionPos, false, null); } + public QuadNode getNode(DhSectionPos sectionPos) throws IllegalArgumentException { return this.getOrSetValue(sectionPos, false, null); } + /** * @param sectionPos must be 1 detail level lower than this node's detail level * @throws IllegalArgumentException if childSectionPos has the wrong detail level or is outside the bounds of this node - * @return the node at the given position before the new node was set + * @return the value at the given position before the new value was set */ - public T setValue(DhSectionPos sectionPos, T newValue) throws IllegalArgumentException { return this.getOrSetValue(sectionPos, true, newValue); } + public T setValue(DhSectionPos sectionPos, T newValue) throws IllegalArgumentException + { + QuadNode previousNode = this.getNode(sectionPos); + if (previousNode != null) + { + T previousValue = previousNode.value; + previousNode.value = newValue; + return previousValue; + } + else + { + this.getOrSetValue(sectionPos, true, newValue); + return null; + } + } + /** * @param inputSectionPos must be 1 detail level lower than this node's detail level * @throws IllegalArgumentException if childSectionPos has the wrong detail level or is outside the bounds of this * @return the node at the given position before the new node was set (if the new node should be set) */ - private T getOrSetValue(DhSectionPos inputSectionPos, boolean replaceValue, T newValue) throws IllegalArgumentException + private QuadNode getOrSetValue(DhSectionPos inputSectionPos, boolean replaceValue, T newValue) throws IllegalArgumentException { // debug validation @@ -162,12 +181,11 @@ public class QuadNode if (inputSectionPos.sectionDetailLevel == this.sectionPos.sectionDetailLevel) { // this node is the requested position - T returnValue = this.value; if (replaceValue) { this.value = newValue; } - return returnValue; + return this; } else { @@ -248,11 +266,12 @@ public class QuadNode // iterators // //===========// - public Iterator> getNodeIterator() { return new QuadNodeIterator<>(this, false); } - public Iterator> getLeafNodeIterator() { return new QuadNodeIterator<>(this, true); } + public Iterator> getNodeIterator() { return new QuadTreeNodeIterator<>(this, false); } + public Iterator> getLeafNodeIterator() { return new QuadTreeNodeIterator<>(this, true); } - public Iterator> getDirectChildNodeIterator() { return new QuadNodeDirectChildNodeIterator<>(this); } - public Iterator getDirectChildPosIterator() { return new QuadNodeDirectChildPosIterator<>(this); } + /** positions can point to null children */ + public Iterator getChildPosIterator() { return new QuadNodeDirectChildPosIterator<>(this); } + public Iterator> getChildNodeIterator() { return new QuadNodeDirectChildIterator<>(this); } diff --git a/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadTree.java b/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadTree.java index 4562ee79b..b91fffc81 100644 --- a/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadTree.java +++ b/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadTree.java @@ -71,12 +71,28 @@ public class QuadTree // getters and setters // //=====================// - /** @return the value at the given section position */ - public final T get(DhSectionPos pos) throws IndexOutOfBoundsException { return this.getOrSet(pos, false, null); } - /** @return the value that was previously in the given position, null if nothing */ - public final T set(DhSectionPos pos, T value) throws IndexOutOfBoundsException { return this.getOrSet(pos, true, value); } + /** @return the node at the given section position */ + public final QuadNode getNode(DhSectionPos pos) throws IndexOutOfBoundsException { return this.getOrSetNode(pos, false, null); } + /** @return the value at the given section position */ + public final T getValue(DhSectionPos pos) throws IndexOutOfBoundsException + { + QuadNode node = this.getNode(pos); + if (node != null) + { + return node.value; + } + return null; + } - protected final T getOrSet(DhSectionPos pos, boolean setNewValue, T newValue) throws IndexOutOfBoundsException + /** @return the value that was previously in the given position, null if nothing */ + public final T setValue(DhSectionPos pos, T value) throws IndexOutOfBoundsException + { + T previousValue = this.getValue(pos); + this.getOrSetNode(pos, true, value); + return previousValue; + } + + protected final QuadNode getOrSetNode(DhSectionPos pos, boolean setNewValue, T newValue) throws IndexOutOfBoundsException { if (this.isSectionPosInBounds(pos)) { @@ -103,12 +119,12 @@ public class QuadTree } - T returnValue = topQuadNode.getValue(pos); + QuadNode returnNode = topQuadNode.getNode(pos); if (setNewValue) { topQuadNode.setValue(pos, newValue); } - return returnValue; + return returnNode; } else { @@ -166,7 +182,7 @@ public class QuadTree DhSectionPos childPos = pos.getChildByIndex(i); if (this.isSectionPosInBounds(childPos)) { - T value = this.get(childPos); + T value = this.getValue(childPos); if (includeNullValues || value != null) { childCount++; @@ -183,7 +199,7 @@ public class QuadTree // iterators // //===========// - public Iterator> rootNodeIterator() { return new QuadTreeRootNodeIterator(); } + /** can include null nodes */ public Iterator rootNodePosIterator() { return new QuadTreeRootPosIterator(true); } public Iterator> nodeIterator() { return new QuadTreeNodeIterator(false); } @@ -309,7 +325,8 @@ public class QuadTree } - return this.iteratorPosQueue.poll(); + DhSectionPos sectionPos = this.iteratorPosQueue.poll(); + return sectionPos; } @@ -321,40 +338,9 @@ public class QuadTree public void forEachRemaining(Consumer action) { Iterator.super.forEachRemaining(action); } } - private class QuadTreeRootNodeIterator implements Iterator> - { - private final QuadTreeRootPosIterator rootPosIterator; - - public QuadTreeRootNodeIterator() - { - this.rootPosIterator = new QuadTreeRootPosIterator(false); - } - - - - @Override - public boolean hasNext() { return this.rootPosIterator.hasNext(); } - - @Override - public QuadNode next() - { - DhSectionPos pos = this.rootPosIterator.next(); - return QuadTree.this.topRingList.get(pos.sectionX, pos.sectionZ); - } - - - /** Unimplemented */ - @Override - public void remove() { throw new UnsupportedOperationException("remove"); } - - @Override - public void forEachRemaining(Consumer> action) { Iterator.super.forEachRemaining(action); } - - } - private class QuadTreeNodeIterator implements Iterator> { - private final QuadTreeRootNodeIterator rootNodeIterator; + private final QuadTreeRootPosIterator rootNodeIterator; private Iterator> currentNodeIterator; private final boolean onlyReturnLeaves; @@ -362,28 +348,56 @@ public class QuadTree public QuadTreeNodeIterator(boolean onlyReturnLeaves) { - this.rootNodeIterator = new QuadTreeRootNodeIterator(); + this.rootNodeIterator = new QuadTreeRootPosIterator(false); this.onlyReturnLeaves = onlyReturnLeaves; } @Override - public boolean hasNext() { return this.rootNodeIterator.hasNext() || this.currentNodeIterator.hasNext(); } + public boolean hasNext() + { + if (!this.rootNodeIterator.hasNext() && this.currentNodeIterator != null && !this.currentNodeIterator.hasNext()) + { + return false; + } + + + if (this.currentNodeIterator == null || !this.currentNodeIterator.hasNext()) + { + this.currentNodeIterator = this.getNextChildNodeIterator(); + } + return this.currentNodeIterator != null && this.currentNodeIterator.hasNext(); + } @Override public QuadNode next() { - if (this.currentNodeIterator == null) + if (this.currentNodeIterator == null || !this.currentNodeIterator.hasNext()) { - QuadNode rootNode = this.rootNodeIterator.next(); - this.currentNodeIterator = this.onlyReturnLeaves ? rootNode.getLeafNodeIterator() : rootNode.getNodeIterator(); + this.currentNodeIterator = this.getNextChildNodeIterator(); } return this.currentNodeIterator.next(); } + /** @return null if no new iterator could be found */ + private Iterator> getNextChildNodeIterator() + { + Iterator> nodeIterator = null; + while((nodeIterator == null || !nodeIterator.hasNext()) && this.rootNodeIterator.hasNext()) + { + DhSectionPos sectionPos = this.rootNodeIterator.next(); + QuadNode rootNode = QuadTree.this.getNode(sectionPos); + if (rootNode != null) + { + nodeIterator = this.onlyReturnLeaves ? rootNode.getLeafNodeIterator() : rootNode.getNodeIterator(); + } + } + return nodeIterator; + } + /** Unimplemented */ @Override diff --git a/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNodeChildIndexIterator.java b/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/iterators/QuadNodeChildIndexIterator.java similarity index 82% rename from core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNodeChildIndexIterator.java rename to core/src/main/java/com/seibel/lod/core/util/objects/quadTree/iterators/QuadNodeChildIndexIterator.java index d1f7adbee..6cb66787b 100644 --- a/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNodeChildIndexIterator.java +++ b/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/iterators/QuadNodeChildIndexIterator.java @@ -1,4 +1,6 @@ -package com.seibel.lod.core.util.objects.quadTree; +package com.seibel.lod.core.util.objects.quadTree.iterators; + +import com.seibel.lod.core.util.objects.quadTree.QuadNode; import java.util.Iterator; import java.util.LinkedList; @@ -23,6 +25,7 @@ public class QuadNodeChildIndexIterator implements Iterator // add index to queue if either not null or we want to return null values as well if (returnNullChildPos || parentNode.getChildByIndex(i) != null) { + // TODO is it possible that a child could be outside the parent QuadTree's radius? this.iteratorQueue.add(i); } } @@ -42,8 +45,8 @@ public class QuadNodeChildIndexIterator implements Iterator throw new NoSuchElementException(); } - - return this.iteratorQueue.poll(); + Integer index = this.iteratorQueue.poll(); + return index; } diff --git a/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNodeDirectChildNodeIterator.java b/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/iterators/QuadNodeDirectChildIterator.java similarity index 68% rename from core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNodeDirectChildNodeIterator.java rename to core/src/main/java/com/seibel/lod/core/util/objects/quadTree/iterators/QuadNodeDirectChildIterator.java index bb54de35b..b5049724c 100644 --- a/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNodeDirectChildNodeIterator.java +++ b/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/iterators/QuadNodeDirectChildIterator.java @@ -1,16 +1,19 @@ -package com.seibel.lod.core.util.objects.quadTree; +package com.seibel.lod.core.util.objects.quadTree.iterators; + +import com.seibel.lod.core.pos.DhSectionPos; +import com.seibel.lod.core.util.objects.quadTree.QuadNode; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.function.Consumer; -public class QuadNodeDirectChildNodeIterator implements Iterator> +public class QuadNodeDirectChildIterator implements Iterator> { private final QuadNodeChildIndexIterator childIndexIterator; private final QuadNode parentNode; - public QuadNodeDirectChildNodeIterator(QuadNode parentNode) + public QuadNodeDirectChildIterator(QuadNode parentNode) { this.parentNode = parentNode; this.childIndexIterator = new QuadNodeChildIndexIterator<>(this.parentNode, false); @@ -31,7 +34,8 @@ public class QuadNodeDirectChildNodeIterator implements Iterator> int childIndex = this.childIndexIterator.next(); - return this.parentNode.getChildByIndex(childIndex); + QuadNode node = this.parentNode.getChildByIndex(childIndex); + return node; } diff --git a/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNodeDirectChildPosIterator.java b/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/iterators/QuadNodeDirectChildPosIterator.java similarity index 82% rename from core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNodeDirectChildPosIterator.java rename to core/src/main/java/com/seibel/lod/core/util/objects/quadTree/iterators/QuadNodeDirectChildPosIterator.java index 7565501cb..c304d1769 100644 --- a/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNodeDirectChildPosIterator.java +++ b/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/iterators/QuadNodeDirectChildPosIterator.java @@ -1,6 +1,7 @@ -package com.seibel.lod.core.util.objects.quadTree; +package com.seibel.lod.core.util.objects.quadTree.iterators; import com.seibel.lod.core.pos.DhSectionPos; +import com.seibel.lod.core.util.objects.quadTree.QuadNode; import java.util.Iterator; import java.util.NoSuchElementException; @@ -33,7 +34,8 @@ public class QuadNodeDirectChildPosIterator implements Iterator int childIndex = this.childIndexIterator.next(); - return this.parentNode.sectionPos.getChildByIndex(childIndex); + DhSectionPos sectionPos = this.parentNode.sectionPos.getChildByIndex(childIndex); + return sectionPos; } @@ -44,4 +46,4 @@ public class QuadNodeDirectChildPosIterator implements Iterator @Override public void forEachRemaining(Consumer action) { Iterator.super.forEachRemaining(action); } -} +} \ No newline at end of file diff --git a/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNodeIterator.java b/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/iterators/QuadTreeNodeIterator.java similarity index 91% rename from core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNodeIterator.java rename to core/src/main/java/com/seibel/lod/core/util/objects/quadTree/iterators/QuadTreeNodeIterator.java index 2e3624e15..61a4adfcb 100644 --- a/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/QuadNodeIterator.java +++ b/core/src/main/java/com/seibel/lod/core/util/objects/quadTree/iterators/QuadTreeNodeIterator.java @@ -1,4 +1,6 @@ -package com.seibel.lod.core.util.objects.quadTree; +package com.seibel.lod.core.util.objects.quadTree.iterators; + +import com.seibel.lod.core.util.objects.quadTree.QuadNode; import java.util.Iterator; import java.util.LinkedList; @@ -6,7 +8,7 @@ import java.util.NoSuchElementException; import java.util.Queue; import java.util.function.Consumer; -class QuadNodeIterator implements Iterator> +public class QuadTreeNodeIterator implements Iterator> { /** lowest numerical value, inclusive */ private final byte highestDetailLevel; @@ -20,7 +22,7 @@ class QuadNodeIterator implements Iterator> - public QuadNodeIterator(QuadNode rootNode, boolean onlyReturnLeafValues) + public QuadTreeNodeIterator(QuadNode rootNode, boolean onlyReturnLeafValues) { this.onlyReturnLeafValues = onlyReturnLeafValues; // TODO the naming conversion for these are flipped in a lot of places @@ -104,6 +106,7 @@ class QuadNodeIterator implements Iterator> Queue> parentNodes = new LinkedList<>(this.validNodesForDetailLevel); this.validNodesForDetailLevel.clear(); + // populate the list of nodes for this level for (QuadNode parentNode : parentNodes) { for (int i = 0; i < 4; i++) diff --git a/core/src/test/java/tests/QuadTreeTest.java b/core/src/test/java/tests/QuadTreeTest.java index c03719014..a12dd942e 100644 --- a/core/src/test/java/tests/QuadTreeTest.java +++ b/core/src/test/java/tests/QuadTreeTest.java @@ -277,11 +277,14 @@ public class QuadTreeTest // root nodes int rootNodeCount = 0; - Iterator> rootNodeIterator = tree.rootNodeIterator(); - while (rootNodeIterator.hasNext()) + Iterator rootNodePosIterator = tree.rootNodePosIterator(); + while (rootNodePosIterator.hasNext()) { - QuadNode rootNode = rootNodeIterator.next(); - rootNodeCount++; + QuadNode rootNode = tree.getNode(rootNodePosIterator.next()); + if (rootNode != null) + { + rootNodeCount++; + } } Assert.assertEquals("incorrect root count", 1, rootNodeCount); @@ -391,25 +394,31 @@ public class QuadTreeTest // confirm the root node were added int rootNodeCount = 0; - Iterator> rootNodeIterator = tree.rootNodeIterator(); - while (rootNodeIterator.hasNext()) + Iterator rootNodePosIterator = tree.rootNodePosIterator(); + while (rootNodePosIterator.hasNext()) { - rootNodeIterator.next(); - rootNodeCount++; + QuadNode rootNode = tree.getNode(rootNodePosIterator.next()); + if (rootNode != null) + { + rootNodeCount++; + } } Assert.assertEquals("incorrect root count", 1, rootNodeCount); // attempt to get and remove, each node in the tree int rootNodePosCount = 0; - Iterator rootNodePosIterator = tree.rootNodePosIterator(); + rootNodePosIterator = tree.rootNodePosIterator(); while (rootNodePosIterator.hasNext()) { DhSectionPos rootNodePos = rootNodePosIterator.next(); - - testGet(tree, rootNodePos, 0); - testSet(tree, rootNodePos, null); - - rootNodePosCount++; + QuadNode rootNode = tree.getNode(rootNodePos); + if (rootNode != null) + { + testGet(tree, rootNodePos, 0); + testSet(tree, rootNodePos, null); + + rootNodePosCount++; + } } Assert.assertEquals("incorrect root count", 1, rootNodePosCount); @@ -441,17 +450,20 @@ public class QuadTreeTest Iterator rootNodePosIterator = tree.rootNodePosIterator(); while (rootNodePosIterator.hasNext()) { - DhSectionPos sectionPos = rootNodePosIterator.next(); - testSet(tree, sectionPos, 0); + testSet(tree, rootNodePosIterator.next(), 0); } + // 4 root nodes should be added int rootNodeCount = 0; - Iterator> rootNodeIterator = tree.rootNodeIterator(); - while (rootNodeIterator.hasNext()) + rootNodePosIterator = tree.rootNodePosIterator(); + while (rootNodePosIterator.hasNext()) { - QuadNode rootNode = rootNodeIterator.next(); - rootNodeCount++; + QuadNode rootNode = tree.getNode(rootNodePosIterator.next()); + if (rootNode != null) + { + rootNodeCount++; + } } Assert.assertEquals("incorrect root count", expectedRootNodeCount, rootNodeCount); } @@ -472,11 +484,14 @@ public class QuadTreeTest testSet(tree, new DhSectionPos(tree.treeMaxDetailLevel, 1, 1), -1, IndexOutOfBoundsException.class); int rootNodeCount = 0; - Iterator> rootNodeIterator = tree.rootNodeIterator(); + Iterator rootNodeIterator = tree.rootNodePosIterator(); while (rootNodeIterator.hasNext()) { - QuadNode rootNode = rootNodeIterator.next(); - rootNodeCount++; + QuadNode rootNode = tree.getNode(rootNodeIterator.next()); + if (rootNode != null) + { + rootNodeCount++; + } } Assert.assertEquals("incorrect leaf value sum", 1, rootNodeCount); @@ -508,11 +523,14 @@ public class QuadTreeTest int rootNodeCount = 0; - Iterator> rootNodeIterator = tree.rootNodeIterator(); + Iterator rootNodeIterator = tree.rootNodePosIterator(); while (rootNodeIterator.hasNext()) { - QuadNode rootNode = rootNodeIterator.next(); - rootNodeCount++; + QuadNode rootNode = tree.getNode(rootNodeIterator.next()); + if (rootNode != null) + { + rootNodeCount++; + } } Assert.assertEquals("incorrect leaf value sum", 4, rootNodeCount); @@ -550,26 +568,37 @@ public class QuadTreeTest // create the root node testSet(tree, new DhSectionPos((byte)10, 0, 0), 1); - // recurse down the tree + + AtomicInteger minimumDetailLevelReachedRef = new AtomicInteger(tree.treeMaxDetailLevel); - Iterator> rootNodeIterator = tree.rootNodeIterator(); - while (rootNodeIterator.hasNext()) + + // recurse down the tree + Iterator rootNodePosIterator = tree.rootNodePosIterator(); + while (rootNodePosIterator.hasNext()) { - QuadNode rootNode = rootNodeIterator.next(); - Iterator rootNodeDirectChildPosIterator = rootNode.getDirectChildPosIterator(); - while (rootNodeDirectChildPosIterator.hasNext()) + DhSectionPos sectionPos = rootNodePosIterator.next(); + QuadNode rootNode = tree.getNode(sectionPos); + if (rootNode != null) { - DhSectionPos sectionPos = rootNodeDirectChildPosIterator.next(); + // fill in the root node's direct children + Iterator childPosIterator = rootNode.getChildPosIterator(); + while (childPosIterator.hasNext()) + { + DhSectionPos rootChildPos = childPosIterator.next(); + rootNode.setValue(rootChildPos, 0); + } - // all sections will be null - rootNode.setValue(sectionPos, 0); - } - - Iterator> rootNodeDirectChildIterator = rootNode.getDirectChildNodeIterator(); - while (rootNodeDirectChildIterator.hasNext()) - { - QuadNode quadNode = rootNodeDirectChildIterator.next(); - recursivelyCreateNodeChildren(quadNode, tree.treeMinDetailLevel, minimumDetailLevelReachedRef); + + + // recursively create child nodes down to the minimum detail level + Iterator> ChildIterator = rootNode.getChildNodeIterator(); + while (ChildIterator.hasNext()) + { + QuadNode childNode = ChildIterator.next(); + Assert.assertNotNull(childNode); // TODO is this correct? + + recursivelyCreateNodeChildren(childNode, tree.treeMinDetailLevel, minimumDetailLevelReachedRef); + } } } @@ -584,19 +613,20 @@ public class QuadTreeTest // fill in the null children - Iterator directChildPosIterator = node.getDirectChildPosIterator(); - while (directChildPosIterator.hasNext()) + Iterator directChildIterator = node.getChildPosIterator(); + while (directChildIterator.hasNext()) { - node.setValue(directChildPosIterator.next(), 0); + node.setValue(directChildIterator.next(), 0); childNodesCreated = true; } // attempt to recurse down these new children - Iterator> directChildIterator = node.getDirectChildNodeIterator(); + directChildIterator = node.getChildPosIterator(); while (directChildIterator.hasNext()) { - QuadNode childNode = directChildIterator.next(); + DhSectionPos sectionPos = directChildIterator.next(); + QuadNode childNode = node.getNode(sectionPos); Assert.assertTrue("Child node recurred too low. Min detail level: "+minDetailLevel+", node detail level: "+childNode.sectionPos.sectionDetailLevel, childNode.sectionPos.sectionDetailLevel >= minDetailLevel); recursivelyCreateNodeChildren(childNode, minDetailLevel, minimumDetailLevelReachedRef); @@ -628,15 +658,15 @@ public class QuadTreeTest public void quadNodeChildPositionIndexTest() { QuadNode rootNode = new QuadNode<>(new DhSectionPos((byte)10, 0, 0), (byte)0); - Iterator directChildIterator = rootNode.getDirectChildPosIterator(); - while (directChildIterator.hasNext()) + Iterator directChildPosIterator = rootNode.getChildPosIterator(); + while (directChildPosIterator.hasNext()) { - DhSectionPos sectionPos = directChildIterator.next(); + DhSectionPos sectionPos = directChildPosIterator.next(); Assert.assertNotEquals("Root node pos shouldn't be included in direct child pos iteration", sectionPos, rootNode.sectionPos); rootNode.setValue(sectionPos, 1); } - Assert.assertEquals("node not filled", rootNode.getChildValueCount(), 4); + Assert.assertEquals("node not filled", 4, rootNode.getChildValueCount()); for (int i = 0; i < 4; i++) @@ -648,6 +678,53 @@ public class QuadTreeTest } + @Test + public void quadNodeChildPositionOutOfBoundsTest() + { + int treeWidthInBlocks = 64; + QuadTree tree = new QuadTree<>(treeWidthInBlocks, new DhBlockPos2D(-2, 0), (byte)0); + + + + // center root node + DhSectionPos centerNodePos = new DhSectionPos((byte)1, 0, 0); + + // create node + tree.setValue(centerNodePos, 0); + QuadNode centerRootNode = tree.getNode(centerNodePos); + Assert.assertNotNull(centerRootNode); + + // child pos in bounds of the tree + Iterator childPosIterator = centerRootNode.getChildPosIterator(); + while (childPosIterator.hasNext()) + { + DhSectionPos childPos = childPosIterator.next(); + centerRootNode.setValue(childPos, 1); + } + Assert.assertEquals("center node not filled", 4, centerRootNode.getChildValueCount()); + + + + // edge root node + DhSectionPos offsetNodePos = new DhSectionPos((byte)1, -17, -16); + + // create node + tree.setValue(offsetNodePos, 0); + QuadNode offsetRootNode = tree.getNode(offsetNodePos); + Assert.assertNotNull(offsetRootNode); + + // child pos in bounds of the tree + childPosIterator = offsetRootNode.getChildPosIterator(); + while (childPosIterator.hasNext()) + { + DhSectionPos childPos = childPosIterator.next(); + offsetRootNode.setValue(childPos, 1); + } + // TODO James thought this shouldn't work for all 4 nodes, but he must've thought wrong. + Assert.assertEquals("offset should only contain some children.", 4, offsetRootNode.getChildValueCount()); + + } + // this is here for quickly testing the toString method, it should never fail @Test public void toStringTest() @@ -675,7 +752,7 @@ public class QuadTreeTest // set try { - Integer previousValue = tree.set(pos, setValue); + Integer previousValue = tree.setValue(pos, setValue); } catch (Exception e) { @@ -696,7 +773,7 @@ public class QuadTreeTest { try { - Integer getResult = tree.get(pos); + Integer getResult = tree.getValue(pos); Assert.assertEquals("get failed "+pos, getValue, getResult); } catch (Exception e) @@ -734,11 +811,11 @@ public class QuadTreeTest private static class MediumTestTree extends AbstractTestTreeParams { public int getWidthInBlocks() { return 1024; } - } private static class TinyTestTree extends AbstractTestTreeParams { + // top detail level = 6 public int getWidthInBlocks() { return 32; } }