From 1061fcd7e2151fa8e94f176c8375c117a82254cf Mon Sep 17 00:00:00 2001 From: Donal McMullan Date: Wed, 3 Jul 2019 16:24:56 +0100 Subject: [PATCH] Add a FrameSet.getChunk method and substitute its result into frame commands. #104 --- .../dispatcher/DispatchSupportService.java | 6 + .../com/imageworks/spcue/util/FrameSet.java | 138 ++++++++++++++++++ .../spcue/test/util/FrameSetTests.java | 51 +++++++ 3 files changed, 195 insertions(+) diff --git a/cuebot/src/main/java/com/imageworks/spcue/dispatcher/DispatchSupportService.java b/cuebot/src/main/java/com/imageworks/spcue/dispatcher/DispatchSupportService.java index 3f035ab4c..d50e85278 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/dispatcher/DispatchSupportService.java +++ b/cuebot/src/main/java/com/imageworks/spcue/dispatcher/DispatchSupportService.java @@ -59,6 +59,7 @@ import com.imageworks.spcue.rqd.RqdClient; import com.imageworks.spcue.service.BookingManager; import com.imageworks.spcue.service.DependManager; +import com.imageworks.spcue.util.FrameSet; @Transactional(propagation = Propagation.REQUIRED) public class DispatchSupportService implements DispatchSupport { @@ -346,6 +347,10 @@ public RunFrame prepareRqdRunFrame(VirtualProc proc, DispatchFrame frame) { int frameNumber = Integer.valueOf(frame.name.substring(0,frame.name.indexOf("-"))); String zFrameNumber = String.format("%04d", frameNumber); + FrameSet fs = new FrameSet(frame.range); + int startFrameIndex = fs.index(frameNumber); + String frameSpec = fs.getChunk(startFrameIndex, frame.chunkSize); + return RunFrame.newBuilder() .setShot(frame.shot) .setShow(frame.show) @@ -386,6 +391,7 @@ public RunFrame prepareRqdRunFrame(VirtualProc proc, DispatchFrame frame) { .replaceAll("#IFRAME#", String.valueOf(frameNumber)) .replaceAll("#LAYER#", frame.layerName) .replaceAll("#JOB#", frame.jobName) + .replaceAll("#FRAMESPEC#", frameSpec) .replaceAll("#FRAME#", frame.name)) .build(); } 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 b2d520940..79afc58c0 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/util/FrameSet.java +++ b/cuebot/src/main/java/com/imageworks/spcue/util/FrameSet.java @@ -1,6 +1,10 @@ package com.imageworks.spcue.util; +import java.util.ArrayList; +import java.lang.StringBuilder; import com.google.common.collect.ImmutableList; +import com.google.common.base.Strings; +import com.imageworks.spcue.SpcueRuntimeException; /** * Represents an ordered sequence of FrameRanges. @@ -44,6 +48,140 @@ public int index(int idx) { return frameList.indexOf(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 + */ + 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); + } + } + + /** + * 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 + */ + private String pad(int number, int width){ + return Strings.padStart(String.valueOf(number), width, '0'); + } + + /** + * 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' + */ + private String framesToFrameRanges(ImmutableList frames) { + return framesToFrameRanges(frames, 0); + } + + /** + * 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' + */ + private String framesToFrameRanges(ImmutableList frames, int zFill) { + + int l = frames.size(); + if (l == 0) { + return ""; + } else if (l == 1) { + return pad(frames.get(0), zFill); + } + + ArrayList resultBuilder = new ArrayList(); + + int curr_count = 1; + int curr_stride = 0; + int new_stride = 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; + } + new_stride = curr_frame - last_frame; + if (curr_stride == new_stride) { + 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; + curr_start = last_frame; + last_frame = curr_frame; + continue; + } else { + resultBuilder.add(buildFrangePart(curr_start, last_frame, curr_stride, zFill)); + curr_stride = 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)); + } else { + resultBuilder.add(buildFrangePart(curr_start, curr_frame, curr_stride, zFill)); + } + + 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 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 f4cbe8469..5241cd902 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 @@ -36,4 +36,55 @@ public void testIndex() { assertEquals(5, result.index(6)); assertEquals(-1, result.index(22)); } + + @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); + } + + @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); + } + + @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); + } + + @Test + public void testFramesToFrameRanges03() { + + FrameSet result = new FrameSet("1-100x3"); + + String b = result.getChunk(9, 3); + assertEquals("28-34x3", b); + } + + @Test + public void testFramesToFrameRanges04() { + + FrameSet result = new FrameSet("1-100"); + + String b = result.getChunk(9, 3); + assertEquals("10-12", b); + } }