Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
donalm committed Aug 24, 2019
1 parent 75b8071 commit 96a9dd3
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 120 deletions.
176 changes: 71 additions & 105 deletions cuebot/src/main/java/com/imageworks/spcue/util/FrameSet.java
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -49,152 +49,118 @@ 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<Integer> getAll() {
return frameList;
}

private ImmutableList<Integer> parseFrameRange(String frameRange) {
ImmutableList.Builder<Integer> 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<Integer> frames, int zFill) {

private String framesToFrameRanges(ImmutableList<Integer> 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<String> resultBuilder = new ArrayList<String>();
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);

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<Integer> sl = frameList.subList(startFrameIndex, endFrameIndex);

return framesToFrameRanges(sl);
}

/**
* Gets the full numerical sequence.
* @return
*/
public ImmutableList<Integer> getAll() {
return frameList;
}

private ImmutableList<Integer> parseFrameRange(String frameRange) {
ImmutableList.Builder<Integer> builder = ImmutableList.builder();
for (String frameRangeSection : frameRange.split(",")) {
builder.addAll(FrameRange.parseFrameRange(frameRangeSection));
}
return builder.build();
return resultBuilder.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}

0 comments on commit 96a9dd3

Please sign in to comment.