Skip to content

Commit 59eed63

Browse files
committed
Revise Nesting
NestedPosition is always constructed via NestedGrid factory methods. Added methods to determine the pixel coordinates corresponding to a NestedPosition. Cleaned up unused code and comments.
1 parent 1dc5871 commit 59eed63

3 files changed

Lines changed: 126 additions & 61 deletions

File tree

src/main/java/org/janelia/saalfeldlab/n5/shard/DatasetAccess.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ static <T extends NestedPosition> Collection<List<T>> groupInnerPositions(final
5656
if (nestedPosition.level() == outerLevel)
5757
outerNestedPosition = nestedPosition;
5858
else
59-
outerNestedPosition = new NestedPosition(grid, nestedPosition.absolute(0), outerLevel);
59+
outerNestedPosition = grid.nestedPosition(nestedPosition.absolute(outerLevel), outerLevel);
6060

6161

6262
final List<T> blocks = blocksPerShard.computeIfAbsent(outerNestedPosition, it -> new ArrayList<>());

src/main/java/org/janelia/saalfeldlab/n5/shard/DefaultDatasetAccess.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public NestedGrid getGrid() {
3333

3434
@Override
3535
public DataBlock<T> readBlock(final PositionValueAccess kva, final long[] gridPosition) throws N5IOException {
36-
final NestedPosition position = new NestedPosition(grid, gridPosition);
36+
final NestedPosition position = grid.nestedPosition(gridPosition);
3737
return readBlockRecursive(kva.get(position.key()), position, grid.numLevels() - 1);
3838
}
3939

@@ -62,7 +62,7 @@ public List<DataBlock<T>> readBlocks(PositionValueAccess pva, List<long[]> posit
6262
return positions.stream().map(it -> readBlock(pva, it)).collect(Collectors.toList());
6363
}
6464

65-
final List<NestedPosition> blockPositions = positions.stream().map(it -> new NestedPosition(grid, it)).collect(Collectors.toList());
65+
final List<NestedPosition> blockPositions = positions.stream().map(grid::nestedPosition).collect(Collectors.toList());
6666

6767
final int outermostLevel = grid.numLevels() - 1;
6868
final Collection<List<NestedPosition>> blocksPerOutermostShard = groupInnerPositions(grid, blockPositions, outermostLevel);
@@ -141,7 +141,7 @@ private List<DataBlock<T>> readShardRecursive(
141141

142142
@Override
143143
public void writeBlock(final PositionValueAccess pva, final DataBlock<T> dataBlock) throws N5IOException {
144-
final NestedPosition position = new NestedPosition(grid, dataBlock.getGridPosition());
144+
final NestedPosition position = grid.nestedPosition(dataBlock.getGridPosition());
145145
final long[] key = position.key();
146146

147147
final ReadData existingData = getExistingReadData(pva, key);
@@ -255,7 +255,7 @@ private ReadData writeShardRecursive(
255255

256256
@Override
257257
public boolean deleteBlock(final PositionValueAccess kva, final long[] gridPosition) throws N5IOException {
258-
final NestedPosition position = new NestedPosition(grid, gridPosition);
258+
final NestedPosition position = grid.nestedPosition(gridPosition);
259259
final long[] key = position.key();
260260
if (grid.numLevels() == 1) {
261261
// for non-sharded dataset, don't bother getting the value, just remove the key.

src/main/java/org/janelia/saalfeldlab/n5/shard/Nesting.java

Lines changed: 121 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,25 @@
33

44
import java.util.ArrayList;
55

6-
// TODO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7-
//
8-
// [ ] NestedGrid
9-
// [ ] validation in constructor
10-
// [ ] test for that validation
11-
// [ ] javadoc
12-
//
13-
// [ ] NestedPosition interface
14-
// [+] LazyNestedPosition class
15-
// [+] fields: NestedGrid, long[] position, int level
16-
// [+] construct with source level 0
17-
// [+] minimal abs/rel access methods
18-
// [+] toString()
19-
// [-] extract NestedPosition interface
20-
// ==> postpone until necessary
21-
// [ ] equals / hashcode
22-
// [ ] should we have prefix()? suffix()? head()? tail()?
23-
// [+] Implement Comparable so that we can sort and aggregate for N5Reader.readBlocks(...).
24-
// For nested = {X,Y,Z} compare by Z, then Y, then X.
25-
// For X = {x,y,z} compare by z, then y, then x. (flattening order)
26-
//
27-
// TODO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28-
296
import java.util.Arrays;
307
import java.util.List;
318

329
import org.janelia.saalfeldlab.n5.util.GridIterator;
3310

3411
public class Nesting {
3512

36-
public static void main(String[] args) {
37-
final int[][] blockSizes = {{1,1,1}, {3,2,2}, {6,4,4}, {24,24,24}};
38-
final NestedGrid grid = new NestedGrid(blockSizes);
39-
final NestedPosition pos = new NestedPosition(grid, new long[] {38, 7, 129});
40-
System.out.println("pos = " + pos);
41-
System.out.println("key = " + Arrays.toString(pos.key()));
42-
}
43-
4413
public static class NestedPosition implements Comparable<NestedPosition> {
4514

4615
private final NestedGrid grid;
4716
private final long[] position;
4817
private final int level;
4918

50-
public NestedPosition(final NestedGrid grid, final long[] position, final int level) {
19+
protected NestedPosition(final NestedGrid grid, final long[] position, final int level) {
5120
this.grid = grid;
5221
this.position = position;
5322
this.level = level;
5423
}
5524

56-
public NestedPosition(final NestedGrid grid, final long[] position) {
57-
this(grid, position, 0);
58-
}
59-
6025
/**
6126
* Get the nesting level of this position.
6227
* <p>
@@ -84,7 +49,18 @@ public int numDimensions() {
8449
* @return relative grid position
8550
*/
8651
public long[] relative(final int level) {
87-
return grid.relativePosition(position, level);
52+
return grid.relativePosition(position, this.level, level);
53+
}
54+
55+
/**
56+
* Get the relative grid position at this positions {@link #level()},
57+
* that is, relative offset within containing the {@code (level+1)}
58+
* element.
59+
*
60+
* @return relative grid position
61+
*/
62+
public long[] relative() {
63+
return relative(level());
8864
}
8965

9066
/**
@@ -96,13 +72,17 @@ public long[] relative(final int level) {
9672
* @return absolute grid position
9773
*/
9874
public long[] absolute(final int level) {
99-
return grid.absolutePosition(position, level);
75+
return grid.absolutePosition(position, this.level, level);
10076
}
10177

10278
public long[] key() {
10379
return relative(grid.numLevels() - 1);
10480
}
10581

82+
public long[] pixelPosition() {
83+
return grid.pixelPosition(position, level);
84+
}
85+
10686
@Override
10787
public String toString() {
10888
StringBuilder sb = new StringBuilder();
@@ -117,7 +97,8 @@ public String toString() {
11797
return sb.toString();
11898
}
11999

120-
@Override public int compareTo(NestedPosition o) {
100+
@Override
101+
public int compareTo(NestedPosition o) {
121102

122103
final int dimensionInequality = Integer.compare(numDimensions(), o.numDimensions());
123104
if (dimensionInequality != 0)
@@ -127,13 +108,10 @@ public String toString() {
127108
if (levelInequality != 0)
128109
return levelInequality;
129110

130-
final long[] otherAbsPos = o.absolute(level);
131-
final long[] absPos = absolute(level);
132-
133-
for (int i = absPos.length - 1; i >= 0; --i) {
134-
final long diff = absPos[i] - otherAbsPos[i];
111+
for (int i = position.length - 1; i >= 0; --i) {
112+
final long diff = position[i] - o.position[i];
135113
if (diff != 0)
136-
return (int)diff;
114+
return (int) diff;
137115
}
138116

139117
return 0;
@@ -156,6 +134,52 @@ public String toString() {
156134
*/
157135
public static class NestedGrid {
158136

137+
/**
138+
* Create a {@code NestedPosition} at the specified nesting {@code
139+
* level} grid {@code position}.
140+
* <p>
141+
* Note that {@code position} is in units of grid elements at {@code
142+
* level}. Positions with {@code level=0} refer to the DataBlock grid,
143+
* positions with {@code level=1} refer to first-level Shard grid, and
144+
* so on.
145+
* <p>
146+
* The returned {@code NestedPosition} will have
147+
* {@link NestedPosition#level() level()==level}.
148+
*
149+
* @param position
150+
* position at {@code level}
151+
* @param level
152+
* nesting level of {@code position}
153+
*
154+
* @return a NestedPosition representation of the specified grid position and nesting level
155+
*/
156+
public NestedPosition nestedPosition(final long[] position, final int level) {
157+
return new NestedPosition(this, position, level);
158+
}
159+
160+
/**
161+
* Create a {@code NestedPosition} at the specified block grid {@code
162+
* position} (that is, at nesting level 0).
163+
* <p>
164+
* Note that {@code position} is in units of DataBlocks.
165+
* <p>
166+
* The returned {@code NestedPosition} will have
167+
* {@link NestedPosition#level() level()==0}.
168+
*
169+
* @param position
170+
* position at level 0 (block grid)
171+
*
172+
* @return a NestedPosition representation of the specified block grid position
173+
*/
174+
public NestedPosition nestedPosition(final long[] position) {
175+
return nestedPosition(position, 0);
176+
}
177+
178+
179+
180+
181+
182+
159183
private final int numLevels;
160184

161185
private final int numDimensions;
@@ -249,6 +273,46 @@ public int[] getBlockSize(final int level) {
249273
return blockSizes[level];
250274
}
251275

276+
/**
277+
* Computes the pixel position for the given {@code sourcePos} grid
278+
* position at {@code sourceLevel}.
279+
*
280+
* @param sourcePos
281+
* a grid position at {@code sourceLevel}
282+
* @param sourceLevel
283+
* nesting level of {@code sourcePos}
284+
* @param targetPos
285+
* the pixel position will be stored here
286+
*/
287+
public void pixelPosition(
288+
final long[] sourcePos,
289+
final int sourceLevel,
290+
final long[] targetPos) {
291+
final int[] s = blockSizes[sourceLevel];
292+
for (int d = 0; d < numDimensions; ++d) {
293+
targetPos[d] = sourcePos[d] * s[d];
294+
}
295+
}
296+
297+
/**
298+
* Get the pixel position for the given {@code sourcePos} grid position
299+
* at {@code sourceLevel}.
300+
*
301+
* @param sourcePos
302+
* a grid position at {@code sourceLevel}
303+
* @param sourceLevel
304+
* nesting level of {@code sourcePos}
305+
*
306+
* @return the pixel position
307+
*/
308+
public long[] pixelPosition(
309+
final long[] sourcePos,
310+
final int sourceLevel) {
311+
final long[] targetPos = new long[numDimensions];
312+
pixelPosition(sourcePos, sourceLevel, targetPos);
313+
return targetPos;
314+
}
315+
252316
/**
253317
* Computes the absolute {@code targetPos} grid position at {@code
254318
* targetLevel} for the given {@code sourcePos} grid position at {@code
@@ -296,6 +360,9 @@ public long[] absolutePosition(
296360
final long[] sourcePos,
297361
final int sourceLevel,
298362
final int targetLevel) {
363+
if (sourceLevel == targetLevel) {
364+
return sourcePos;
365+
}
299366
final long[] targetPos = new long[numDimensions];
300367
absolutePosition(sourcePos, sourceLevel, targetPos, targetLevel);
301368
return targetPos;
@@ -381,10 +448,6 @@ public int[] relativeBlockSize(final int level) {
381448
return relativeToAdjacent[level];
382449
}
383450

384-
public int[] absoluteBlockSize(final int level) {
385-
return relativeToBase[level];
386-
}
387-
388451
/**
389452
* Given a block position at a particular level, returns a list of
390453
* positions of all sub-blocks at a particular subLevel.
@@ -400,22 +463,24 @@ public int[] absoluteBlockSize(final int level) {
400463
* the nesting sub-level of positions to return
401464
* @return the sub-block positions
402465
*/
466+
// TODO: rename to positionsInSubGrid
403467
public List<long[]> positionInSubGrid(long[] position, int level, int subLevel) {
404468

405-
final long[] subPosition = new long[numDimensions()];
406-
absolutePosition(position, level, subPosition, subLevel);
469+
// find the starting (subLevel grid) coordinates corresponding to the
470+
// first subLevel block in the element at the given level and position
471+
final long[] subPosition = absolutePosition(position, level, subLevel);
407472

408-
final int[] numElementsInSubGrid = absoluteBlockSize(numLevels() - 1);
409-
final GridIterator git = new GridIterator(GridIterator.int2long(numElementsInSubGrid), subPosition);
473+
// find the dimensions (number of subLevel blocks in one level block, along each dimension)
474+
final long[] one = new long[numDimensions];
475+
Arrays.fill(one, 1);
476+
final long[] dimensions = absolutePosition(one, level, subLevel);
410477

411-
// TODO return NestedPositions instead?
478+
final GridIterator git = new GridIterator(dimensions, subPosition);
412479
final ArrayList<long[]> positions = new ArrayList<>();
413480
while (git.hasNext())
414481
positions.add(git.next().clone());
415482

416483
return positions;
417484
}
418-
419485
}
420-
421486
}

0 commit comments

Comments
 (0)