diff --git a/cuebot/src/main/java/com/imageworks/spcue/util/FrameSet.java b/cuebot/src/main/java/com/imageworks/spcue/util/FrameSet.java index 79afc58c0..b27a3159c 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/util/FrameSet.java +++ b/cuebot/src/main/java/com/imageworks/spcue/util/FrameSet.java @@ -1,10 +1,10 @@ package com.imageworks.spcue.util; +import java.lang.IllegalArgumentException; import java.util.ArrayList; -import java.lang.StringBuilder; +import java.util.StringJoiner; import com.google.common.collect.ImmutableList; import com.google.common.base.Strings; -import com.imageworks.spcue.SpcueRuntimeException; /** * Represents an ordered sequence of FrameRanges. @@ -49,66 +49,84 @@ public int index(int idx) { } /** - * Return a string representation of a subset of a frame range. - * - * This approach was adapted from https://pypi.org/project/Fileseq/ - * @param startFrame Start frame - * @param endFrame End frame - * @param stride The step between frames - * @param zFill Left pad each frame ID with zeroes to make it this width. - * @return String representation of the frame range, e.g. 1-1001x3 + * Gets the full numerical sequence. + * @return */ - private String buildFrangePart(int startFrame, int endFrame, int stride, int zFill) { - String padStart = pad(startFrame, zFill); - String padStop = pad(endFrame, zFill); - if (startFrame == endFrame) { - return padStart; - } else if (stride == 1) { - return String.format("%s-%s", padStart, padStop); - } else { - return String.format("%s-%sx%d", padStart, padStop, stride); + public ImmutableList getAll() { + return frameList; + } + + private ImmutableList parseFrameRange(String frameRange) { + ImmutableList.Builder builder = ImmutableList.builder(); + for (String frameRangeSection : frameRange.split(",")) { + builder.addAll(FrameRange.parseFrameRange(frameRangeSection)); } + return builder.build(); } /** - * Left pad 'number' with zeroes to make it 'width' characters wide. - * @param number An integer to pad - * @param width The required width of the resulting String. - * @return A left-padded string, e.g 0047 + * Return a sub-FrameSet object starting at startFrame with max chunkSize members + * @param startFrameIndex Index of frame to start at; not the frame itself + * @param chunkSize Max number of frames per chunk + * @return String representation of the chunk, e.g. 1-1001x3 */ - private String pad(int number, int width){ - return Strings.padStart(String.valueOf(number), width, '0'); + public String getChunk(int startFrameIndex, int chunkSize) { + if (frameList.size() <= startFrameIndex || startFrameIndex < 0) { + String sf = String.valueOf(startFrameIndex); + String sz = String.valueOf(frameList.size() - 1); + throw new IllegalArgumentException("startFrameIndex " + sf + " is not in range 0-" + sz); + } + if (chunkSize == 1) { + // Chunksize of 1 so the FrameSet is just the startFrame + return String.valueOf(frameList.get(startFrameIndex)); + } + int finalFrameIndex = frameList.size() - 1; + int endFrameIndex = startFrameIndex + chunkSize; + if (endFrameIndex > finalFrameIndex) { + // We don't have enough frames, so return the remaining frames. + endFrameIndex = finalFrameIndex; + } + + return framesToFrameRanges(frameList.subList(startFrameIndex, endFrameIndex)); } /** - * Return a String representation of a frame range based on a list of literal integer frame IDs. - * @param frames A list of integers representing frame IDs, - * @return A representation of a frameset, e.g. '1-10,12-100x2' + * Return a string representation of a subset of a frame range. + * + * This approach was adapted from https://pypi.org/project/Fileseq/ + * @param startFrame Start frame + * @param endFrame End frame + * @param step The step between frames + * @return String representation of the frame range, e.g. 1-1001x3 */ - private String framesToFrameRanges(ImmutableList frames) { - return framesToFrameRanges(frames, 0); + private String buildFrangePart(int startFrame, int endFrame, int step) { + if (startFrame == endFrame) { + return String.valueOf(startFrame); + } else if (step == 1) { + return String.format("%d-%d", startFrame, endFrame); + } else { + return String.format("%d-%dx%d", startFrame, endFrame, step); + } } /** * Return a String representation of a frame range based on a list of literal integer frame IDs. - * @param frames A list of integers representing frame IDs, - * @param zFill The required width of each left-padded frame ID, e.g. 4 if ID '1' should become '0001' - * @return A representation of a frameset, e.g. '1-10,12-100x2' + * @param frames List of integers representing frame IDs, + * @return String representation of a frameset, e.g. '1-10,12-100x2' */ - private String framesToFrameRanges(ImmutableList frames, int zFill) { - + private String framesToFrameRanges(ImmutableList frames) { int l = frames.size(); if (l == 0) { return ""; } else if (l == 1) { - return pad(frames.get(0), zFill); + return String.valueOf(frames.get(0)); } - ArrayList resultBuilder = new ArrayList(); + StringJoiner resultBuilder = new StringJoiner(","); int curr_count = 1; - int curr_stride = 0; - int new_stride = 0; + int curr_step = 0; + int new_step = 0; int curr_start = frames.get(0); int curr_frame = frames.get(0); int last_frame = frames.get(0); @@ -116,85 +134,33 @@ private String framesToFrameRanges(ImmutableList frames, int zFill) { for (int i = 1; i < frames.size(); i++) { curr_frame = frames.get(i); - if (curr_stride == 0) { - curr_stride = curr_frame - curr_start; + if (curr_step == 0) { + curr_step = curr_frame - curr_start; } - new_stride = curr_frame - last_frame; - if (curr_stride == new_stride) { + new_step = curr_frame - last_frame; + if (curr_step == new_step) { last_frame = curr_frame; curr_count += 1; - continue; - } else if (curr_count == 2 && curr_stride != 1) { - resultBuilder.add(pad(curr_start, zFill)); - curr_stride = 0; + } else if (curr_count == 2 && curr_step != 1) { + resultBuilder.add(String.valueOf(curr_start)); + curr_step = 0; curr_start = last_frame; last_frame = curr_frame; - continue; } else { - resultBuilder.add(buildFrangePart(curr_start, last_frame, curr_stride, zFill)); - curr_stride = 0; + resultBuilder.add(buildFrangePart(curr_start, last_frame, curr_step)); + curr_step = 0; curr_start = curr_frame; last_frame = curr_frame; curr_count = 1; - continue; } } - if (curr_count == 2 && curr_stride != 1) { - resultBuilder.add(pad(curr_start, zFill)); - resultBuilder.add(pad(curr_frame, zFill)); + if (curr_count == 2 && curr_step != 1) { + resultBuilder.add(String.valueOf(curr_start)); + resultBuilder.add(String.valueOf(curr_frame)); } else { - resultBuilder.add(buildFrangePart(curr_start, curr_frame, curr_stride, zFill)); + resultBuilder.add(buildFrangePart(curr_start, curr_frame, curr_step)); } - StringBuilder sb = new StringBuilder(); - l = resultBuilder.size()-1; - for (int j = 0; j < l; j++) { - sb.append(resultBuilder.get(j)).append(","); - } - sb.append(resultBuilder.get(l)); - return sb.toString(); - } - - /** - * Return a sub-FrameSet object starting at startFrame with max chunkSize members - * @param idx - * @return FrameSet - */ - public String getChunk(int startFrameIndex, int chunkSize) { - if (frameList.size() <= startFrameIndex || startFrameIndex < 0) { - String sf = String.valueOf(startFrameIndex); - String sz = String.valueOf(frameList.size() - 1); - throw new SpcueRuntimeException("startFrameIndex " + sf + " is not in range 0-" + sz); - } - if (chunkSize == 1) { - // Chunksize of 1 so the FrameSet is just the startFrame - return String.valueOf(frameList.get(startFrameIndex)); - } - int finalFrameIndex = frameList.size() - 1; - int endFrameIndex = startFrameIndex + chunkSize; - if (endFrameIndex > finalFrameIndex) { - // We don't have enough frames, so return the remaining frames. - endFrameIndex = finalFrameIndex; - } - - ImmutableList sl = frameList.subList(startFrameIndex, endFrameIndex); - - return framesToFrameRanges(sl); - } - - /** - * Gets the full numerical sequence. - * @return - */ - public ImmutableList getAll() { - return frameList; - } - - private ImmutableList parseFrameRange(String frameRange) { - ImmutableList.Builder builder = ImmutableList.builder(); - for (String frameRangeSection : frameRange.split(",")) { - builder.addAll(FrameRange.parseFrameRange(frameRangeSection)); - } - return builder.build(); + return resultBuilder.toString(); } } diff --git a/cuebot/src/test/java/com/imageworks/spcue/test/util/FrameSetTests.java b/cuebot/src/test/java/com/imageworks/spcue/test/util/FrameSetTests.java index 5241cd902..3b5d616b1 100644 --- a/cuebot/src/test/java/com/imageworks/spcue/test/util/FrameSetTests.java +++ b/cuebot/src/test/java/com/imageworks/spcue/test/util/FrameSetTests.java @@ -39,52 +39,42 @@ public void testIndex() { @Test public void testFramesToFrameRanges00() { - FrameSet result = new FrameSet("1-10x2,11-100x20,103-108"); // int[] intArray = {1, 3, 5, 7, 9, 11, 31, 51, 71, 91, 103, 104, 105, 106, 107, 108}; - String b = result.getChunk(5, 5); - assertEquals("11-91x20", b); + assertEquals("11-91x20", result.getChunk(5, 5)); } @Test public void testFramesToFrameRanges01() { - FrameSet result = new FrameSet("1-10x2,11-100x20,103-108"); // int[] intArray = {1, 3, 5, 7, 9, 11, 31, 51, 71, 91, 103, 104, 105, 106, 107, 108}; - String b = result.getChunk(2, 5); - assertEquals("5-11x2,31", b); + assertEquals("5-11x2,31", result.getChunk(2, 5)); } @Test public void testFramesToFrameRanges02() { - FrameSet result = new FrameSet("1-10x2,11-100x20,103-108"); // int[] intArray = {1, 3, 5, 7, 9, 11, 31, 51, 71, 91, 103, 104, 105, 106, 107, 108}; - String b = result.getChunk(9, 3); - assertEquals("91,103,104", b); + assertEquals("91,103,104", result.getChunk(9, 3)); } @Test public void testFramesToFrameRanges03() { - FrameSet result = new FrameSet("1-100x3"); - String b = result.getChunk(9, 3); - assertEquals("28-34x3", b); + assertEquals("28-34x3", result.getChunk(9, 3)); } @Test public void testFramesToFrameRanges04() { - FrameSet result = new FrameSet("1-100"); - String b = result.getChunk(9, 3); - assertEquals("10-12", b); + assertEquals("10-12", result.getChunk(9, 3)); } }