From dcd28fe4f977c1aebf4d74ddafd22fdbf39c73ae Mon Sep 17 00:00:00 2001 From: Mark Craig Date: Thu, 11 May 2017 00:58:05 +0100 Subject: [PATCH] Spirograph generator added, Raspberry Pi GPIO rotary encoders added Draw Spirograph-like shapes within the polargraphcontroller by adjusting some parameters. Using a Raspberry Pi to run polargraphcontroller rotary encoders can be used to adjust the spirograph parameters. --- DisplayMachine.pde | 78 ++++++ README.md | 8 + controlsActions.pde | 53 ++++ controlsSetup.pde | 106 +++++++- polargraphcontroller.pde | 569 ++++++++++++++++++++++++++++++++++++++- tabSetup.pde | 12 + 6 files changed, 823 insertions(+), 3 deletions(-) diff --git a/DisplayMachine.pde b/DisplayMachine.pde index b29b637..3f07c8e 100644 --- a/DisplayMachine.pde +++ b/DisplayMachine.pde @@ -374,6 +374,84 @@ class DisplayMachine extends Machine } } + public void drawForSpiro() + { + // work out the scaling factor. + noStroke(); + // draw machine outline + + // drop shadow + fill(80); + rect(getOutline().getLeft()+DROP_SHADOW_DISTANCE, getOutline().getTop()+DROP_SHADOW_DISTANCE, getOutline().getWidth(), getOutline().getHeight()); + + fill(getMachineColour()); + rect(getOutline().getLeft(), getOutline().getTop(), getOutline().getWidth(), getOutline().getHeight()); + //text("machine " + getDimensionsAsText(getSize()) + " " + getZoomText(), getOutline().getLeft(), getOutline().getTop()); + + if (displayingGuides) + { + // draw some guides + stroke(getGuideColour()); + strokeWeight(1); + // centre line + line(getOutline().getLeft()+(getOutline().getWidth()/2), getOutline().getTop(), + getOutline().getLeft()+(getOutline().getWidth()/2), getOutline().getBottom()); + + // page top line + line(getOutline().getLeft(), getOutline().getTop()+sc(getHomePoint().y), + getOutline().getRight(), getOutline().getTop()+sc(getHomePoint().y)); + } + + // draw page + fill(getPageColour()); + rect(getOutline().getLeft()+sc(getPage().getLeft()), + getOutline().getTop()+sc(getPage().getTop()), + sc(getPage().getWidth()), + sc(getPage().getHeight())); + //text("page " + getDimensionsAsText(getPage()), getOutline().getLeft()+sc(getPage().getLeft()), + //getOutline().getTop()+sc(getPage().getTop())); + fill(0); + //text("offset " + getDimensionsAsText(getPage().getPosition()), + //getOutline().getLeft()+sc(getPage().getLeft()), + //getOutline().getTop()+sc(getPage().getTop())+10); + noFill(); + + // draw home point + noFill(); + strokeWeight(5); + stroke(0, 128); + PVector onScreen = scaleToScreen(inMM(getHomePoint())); + ellipse(onScreen.x, onScreen.y, 15, 15); + strokeWeight(2); + stroke(255); + ellipse(onScreen.x, onScreen.y, 15, 15); + + text("Home point", onScreen.x+ 15, onScreen.y-5); + //text(int(inMM(getHomePoint().x)+0.5) + ", " + int(inMM(getHomePoint().y)+0.5), onScreen.x+ 15, onScreen.y+15); + + + if (displayingGuides + && getOutline().surrounds(getMouseVector()) + && currentMode != MODE_MOVE_IMAGE + && mouseOverControls().isEmpty() + ) + { + drawHangingStrings(); + //drawLineLengthTexts(); + cursor(CROSS); + } + else + { + cursor(ARROW); + } + + if (displayingVector && getVectorShape() != null) + { + displayVectorImage(); + } + } + + // public void displayLiveVideo() // { // // draw actual image, maximum size diff --git a/README.md b/README.md index eb8137d..60d678d 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,11 @@ copies of all the libraries that I use, as well as all the source, and compiled sandy.noble@gmail.com http://www.polargraph.co.uk/ + + +Spirograph functions Copyright Mark Craig 2017 + +GPIO access on Raspberry Pi requires PiJ4 library available from http://pi4j.com/index.html. + +@markcra +http://www.markcra.com/ diff --git a/controlsActions.pde b/controlsActions.pde index 409c737..613297f 100644 --- a/controlsActions.pde +++ b/controlsActions.pde @@ -153,6 +153,59 @@ void numberbox_mode_vectorPathLengthHighPassCutoff(int value) pathLengthHighPassCutoff = value; } +void numberbox_mode_liveBigRadiusValue(int value) +{ + if (value != Radius) + { + Radius = value; + retraceShape = true; + } +} +void numberbox_mode_liveSmallRadiusValue(int value) +{ + if (value != radius) + { + radius = value; + retraceShape = true; + } +} +void numberbox_mode_liveRhoRadiusValue(int value) +{ + if (value != rho) + { + rho = value; + retraceShape = true; + } +} +void numberbox_mode_liveIntervalValue(int value) +{ + if (value != Interval) + { + Interval = value; + retraceShape = true; + } +} +void numberbox_mode_liveMultiplierValue(int value) +{ + if (value != multiplier) + { + multiplier = value; + retraceShape = true; + } +} +void numberbox_mode_liveModeValue(int value) +{ + if (value != mode) + { + mode = value; + retraceShape = true; + } +} +void button_mode_exportSpirograph() +{ + Export(); +} + void button_mode_liveConfirmDraw() { if (captureShape != null) diff --git a/controlsSetup.pde b/controlsSetup.pde index ec7e22a..09f1a47 100644 --- a/controlsSetup.pde +++ b/controlsSetup.pde @@ -131,6 +131,18 @@ Map buildPanels() { tracePanel.setControlSizes(buildControlSizesForPanel(tracePanel)); panels.put(PANEL_NAME_TRACE, tracePanel); + Rectangle panelOutlineSpirograph = new Rectangle(getMainPanelPosition(), + new PVector((DEFAULT_CONTROL_SIZE.x+CONTROL_SPACING.x)*2, panelHeight)); + Panel spirographPanel = new Panel(PANEL_NAME_SPIROGRAPH, panelOutlineSpirograph); + spirographPanel.setOutlineColour(color(200,255,200)); + // get controls + spirographPanel.setResizable(true); + spirographPanel.setControls(getControlsForPanels().get(PANEL_NAME_SPIROGRAPH)); + // get control positions + spirographPanel.setControlPositions(buildControlPositionsForPanel(spirographPanel)); + spirographPanel.setControlSizes(buildControlSizesForPanel(spirographPanel)); + panels.put(PANEL_NAME_SPIROGRAPH, spirographPanel); + Rectangle panelOutlineDetails = new Rectangle(getMainPanelPosition(), new PVector((DEFAULT_CONTROL_SIZE.x+CONTROL_SPACING.x)*2, panelHeight)); Panel detailsPanel = new Panel(PANEL_NAME_DETAILS, panelOutlineDetails); @@ -510,6 +522,54 @@ Map initialiseNumberboxValues(Map map) n.setMax(10); n.setMultiplier(0.1); } + else if (MODE_LIVE_BIG_RADIUS_VALUE.equals(key)) + { + n.setDecimalPrecision(1); + n.setValue(Radius); + n.setMin(1); + n.setMax(255); + n.setMultiplier(1); + } + else if (MODE_LIVE_SMALL_RADIUS_VALUE.equals(key)) + { + n.setDecimalPrecision(1); + n.setValue(radius); + n.setMin(1); + n.setMax(255); + n.setMultiplier(1); + } + else if (MODE_LIVE_RHO_RADIUS_VALUE.equals(key)) + { + n.setDecimalPrecision(1); + n.setValue(rho); + n.setMin(1); + n.setMax(255); + n.setMultiplier(1); + } + else if (MODE_LIVE_INTERVAL_VALUE.equals(key)) + { + n.setDecimalPrecision(1); + n.setValue(Interval); + n.setMin(100); + n.setMax(5000); + n.setMultiplier(1); + } + else if (MODE_LIVE_MULTIPLIER_VALUE.equals(key)) + { + n.setDecimalPrecision(1); + n.setValue(multiplier); + n.setMin(0); + n.setMax(60); + n.setMultiplier(1); + } + else if (MODE_LIVE_MODE_VALUE.equals(key)) + { + n.setDecimalPrecision(1); + n.setValue(mode); + n.setMin(0); + n.setMax(3); + n.setMultiplier(1); + } else if (MODE_LIVE_SIMPLIFICATION_VALUE.equals(key)) { n.setDecimalPrecision(1); @@ -550,7 +610,7 @@ Map initialiseNumberboxValues(Map map) } else if (MODE_CHANGE_POLYGONIZER_LENGTH.equals(key)) { n.setValue(polygonizerLength); - n.setMin(1.0); + n.setMin(1.0); n.setDecimalPrecision(1); n.setMultiplier(0.1); @@ -693,6 +753,7 @@ Map> buildControlsForPanels() map.put(PANEL_NAME_QUEUE, getControllersForControllerNames(getControlNamesForQueuePanel())); map.put(PANEL_NAME_GENERAL, getControllersForControllerNames(getControlNamesForGeneralPanel())); map.put(PANEL_NAME_TRACE, getControllersForControllerNames(getControlNamesForTracePanel())); + map.put(PANEL_NAME_SPIROGRAPH, getControllersForControllerNames(getControlNamesForSpirographPanel())); return map; } @@ -788,7 +849,7 @@ List getControlNamesForRovingPanel() return controlNames; } -List getControlNamesForTracePanel() +List getControlNamesForTracePanel() { List controlNames = new ArrayList(); controlNames.add(MODE_LIVE_BLUR_VALUE); @@ -806,6 +867,31 @@ List getControlNamesForTracePanel() return controlNames; } +List getControlNamesForSpirographPanel() // now spirograph panel +{ + List controlNames = new ArrayList(); + controlNames.add(MODE_LIVE_BIG_RADIUS_VALUE); + controlNames.add(MODE_LIVE_SMALL_RADIUS_VALUE); + controlNames.add(MODE_LIVE_INTERVAL_VALUE); + controlNames.add(MODE_LIVE_RHO_RADIUS_VALUE); + controlNames.add(MODE_LIVE_MULTIPLIER_VALUE); + controlNames.add(MODE_LIVE_MODE_VALUE); + controlNames.add(MODE_EXPORT_SPIROGRAPH); + +//copied from INPUT tab: + //controlNames.add(MODE_LOAD_VECTOR_FILE); + controlNames.add(MODE_RESIZE_VECTOR); + controlNames.add(MODE_MOVE_VECTOR); + controlNames.add(MODE_PEN_LIFT_UP); + controlNames.add(MODE_PEN_LIFT_DOWN); + controlNames.add(MODE_SET_POSITION_HOME); + controlNames.add(MODE_RETURN_TO_HOME); + controlNames.add(MODE_CLEAR_QUEUE); + controlNames.add(MODE_RENDER_VECTORS); + + return controlNames; +} + List getControlNamesForDetailPanel() { List controlNames = new ArrayList(); @@ -1015,6 +1101,14 @@ Map buildControlLabels() result.put(MODE_LIVE_CONFIRM_DRAW, "Draw capture"); result.put(MODE_LIVE_CANCEL_CAPTURE, "Cancel capture"); result.put(MODE_LIVE_ADD_CAPTION, "Add caption"); + + result.put(MODE_LIVE_BIG_RADIUS_VALUE, "Major Radius"); + result.put(MODE_LIVE_SMALL_RADIUS_VALUE, "Minor radius"); + result.put(MODE_LIVE_RHO_RADIUS_VALUE, "Rho"); + result.put(MODE_LIVE_INTERVAL_VALUE, "Interval"); + result.put(MODE_LIVE_MULTIPLIER_VALUE, "Multiplier"); + result.put(MODE_LIVE_MODE_VALUE, "Mode"); + result.put(MODE_EXPORT_SPIROGRAPH, "Export Spirograph"); result.put(MODE_VECTOR_PATH_LENGTH_HIGHPASS_CUTOFF, "Path length cutoff"); result.put(MODE_SHOW_WEBCAM_RAW_VIDEO, "Show video"); @@ -1168,6 +1262,14 @@ Set buildControlNames() result.add(MODE_LIVE_CANCEL_CAPTURE); result.add(MODE_LIVE_ADD_CAPTION); result.add(MODE_VECTOR_PATH_LENGTH_HIGHPASS_CUTOFF); + + result.add(MODE_LIVE_BIG_RADIUS_VALUE); + result.add(MODE_LIVE_SMALL_RADIUS_VALUE); + result.add(MODE_LIVE_RHO_RADIUS_VALUE); + result.add(MODE_LIVE_INTERVAL_VALUE); + result.add(MODE_LIVE_MULTIPLIER_VALUE); + result.add(MODE_LIVE_MODE_VALUE); + result.add(MODE_EXPORT_SPIROGRAPH); result.add(MODE_SHOW_WEBCAM_RAW_VIDEO); result.add(MODE_FLIP_WEBCAM_INPUT); diff --git a/polargraphcontroller.pde b/polargraphcontroller.pde index 3be66f8..790f1de 100644 --- a/polargraphcontroller.pde +++ b/polargraphcontroller.pde @@ -26,7 +26,15 @@ sandy.noble@gmail.com http://www.polargraph.co.uk https://github.com/euphy/polargraphcontroller - + + =================== + Modified by Mark Craig to include Spirograph (replaced Trace tab and butchered some of it's code) + +Spirograph functions Copyright Mark Craig 2017 +GPIO access on Raspberry Pi requires PiJ4 library available from http://pi4j.com/index.html. + +@markcra +http://www.markcra.com/ */ //import processing.video.*; @@ -56,6 +64,24 @@ import java.awt.BorderLayout; import java.lang.reflect.Method; +/* // Comment block the following out for use on non-Raspberry Pi hardware. +// for GPIO rotary encoders & buttons +import com.pi4j.io.gpio.*; +import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent; +import com.pi4j.io.gpio.event.GpioPinListenerDigital; + +import com.pi4j.io.gpio.GpioController; +import com.pi4j.io.gpio.GpioFactory; +import com.pi4j.io.gpio.GpioPinDigitalInput; +import com.pi4j.io.gpio.PinPullResistance; +import com.pi4j.io.gpio.RaspiPin; + +GpioController gpio; +GpioPinDigitalInput button1, input1A, input1B, button2, input2A, input2B, button3, input3A, input3B, button4, input4A, input4B; +GpioPinDigitalInput button5, input5A, input5B, button6, input6A, input6B, button7, input7A, input7B; +// end of comment block for RaspPi +*/ + int majorVersionNo = 2; int minorVersionNo = 4; int buildNo = 2; @@ -330,6 +356,14 @@ static final String MODE_LIVE_CANCEL_CAPTURE = "button_mode_liveClearCapture"; static final String MODE_LIVE_ADD_CAPTION = "button_mode_liveAddCaption"; static final String MODE_LIVE_CONFIRM_DRAW = "button_mode_liveConfirmDraw"; +static final String MODE_LIVE_BIG_RADIUS_VALUE = "numberbox_mode_liveBigRadiusValue"; +static final String MODE_LIVE_SMALL_RADIUS_VALUE = "numberbox_mode_liveSmallRadiusValue"; +static final String MODE_LIVE_RHO_RADIUS_VALUE = "numberbox_mode_liveRhoRadiusValue"; +static final String MODE_LIVE_INTERVAL_VALUE = "numberbox_mode_liveIntervalValue"; +static final String MODE_LIVE_MULTIPLIER_VALUE = "numberbox_mode_liveMultiplierValue"; +static final String MODE_LIVE_MODE_VALUE = "numberbox_mode_liveModeValue"; +static final String MODE_EXPORT_SPIROGRAPH = "button_mode_exportSpirograph"; + static final String MODE_VECTOR_PATH_LENGTH_HIGHPASS_CUTOFF = "numberbox_mode_vectorPathLengthHighPassCutoff"; static final String MODE_SHOW_WEBCAM_RAW_VIDEO = "toggle_mode_showWebcamRawVideo"; static final String MODE_FLIP_WEBCAM_INPUT = "toggle_mode_flipWebcam"; @@ -452,6 +486,8 @@ public static final String TAB_NAME_QUEUE = "tab_queue"; public static final String TAB_LABEL_QUEUE = "Queue"; public static final String TAB_NAME_TRACE = "tab_trace"; public static final String TAB_LABEL_TRACE = "Trace"; +public static final String TAB_NAME_SPIROGRAPH = "tab_spirograph"; +public static final String TAB_LABEL_SPIROGRAPH = "Spirograph"; // Page states public String currentTab = TAB_NAME_INPUT; @@ -462,6 +498,7 @@ public static final String PANEL_NAME_ROVING = "panel_roving"; public static final String PANEL_NAME_DETAILS = "panel_details"; public static final String PANEL_NAME_QUEUE = "panel_queue"; public static final String PANEL_NAME_TRACE = "panel_trace"; +public static final String PANEL_NAME_SPIROGRAPH = "panel_spirograph"; public static final String PANEL_NAME_GENERAL = "panel_general"; @@ -545,6 +582,17 @@ boolean rescaleDisplayMachine = true; int polygonizer = 0; float polygonizerLength = 0.0; +// Global variables for Spirograph. +int mode = 0; // different spirograph drawing methods +int pos_x = 320; // position of spirograph preview on screen +int pos_y = 320; +int radius = 1; // minor radius +int Radius = 171; // major radius +int rho = 53; // pen position on minor radius +int Interval = 516; // how many lines/segments are used +int multiplier = 0; // used in mode 2 + + void setup() { println("Running polargraph controller"); @@ -608,6 +656,8 @@ void setup() useSerialPortConnection = false; } + setupGPIO(); + currentMode = MODE_BEGIN; preLoadCommandQueue(); changeTab(TAB_NAME_INPUT, TAB_NAME_INPUT); @@ -669,6 +719,230 @@ void addEventListeners() ); } +void setupGPIO() { + /* // Comment block the following out for use on non-Raspberry Pi hardware. + gpio = GpioFactory.getInstance(); + button1 = gpio.provisionDigitalInputPin(RaspiPin.GPIO_00, "Pin1", PinPullResistance.PULL_UP); + input1A = gpio.provisionDigitalInputPin(RaspiPin.GPIO_03, "Pin1A", PinPullResistance.PULL_UP); + input1B = gpio.provisionDigitalInputPin(RaspiPin.GPIO_02, "Pin1B", PinPullResistance.PULL_UP); + button2 = gpio.provisionDigitalInputPin(RaspiPin.GPIO_08, "Pin2", PinPullResistance.PULL_UP); + input2A = gpio.provisionDigitalInputPin(RaspiPin.GPIO_09, "Pin2A", PinPullResistance.PULL_UP); + input2B = gpio.provisionDigitalInputPin(RaspiPin.GPIO_07, "Pin2B", PinPullResistance.PULL_UP); + button3 = gpio.provisionDigitalInputPin(RaspiPin.GPIO_13, "Pin3", PinPullResistance.PULL_UP); + input3A = gpio.provisionDigitalInputPin(RaspiPin.GPIO_12, "Pin3A", PinPullResistance.PULL_UP); + input3B = gpio.provisionDigitalInputPin(RaspiPin.GPIO_14, "Pin3B", PinPullResistance.PULL_UP); + button4 = gpio.provisionDigitalInputPin(RaspiPin.GPIO_23, "Pin4", PinPullResistance.PULL_UP); + input4A = gpio.provisionDigitalInputPin(RaspiPin.GPIO_22, "Pin4A", PinPullResistance.PULL_UP); + input4B = gpio.provisionDigitalInputPin(RaspiPin.GPIO_21, "Pin4B", PinPullResistance.PULL_UP); + button5 = gpio.provisionDigitalInputPin(RaspiPin.GPIO_15, "Pin5", PinPullResistance.PULL_UP); + input5A = gpio.provisionDigitalInputPin(RaspiPin.GPIO_16, "Pin5A", PinPullResistance.PULL_UP); + input5B = gpio.provisionDigitalInputPin(RaspiPin.GPIO_01, "Pin5B", PinPullResistance.PULL_UP); + button6 = gpio.provisionDigitalInputPin(RaspiPin.GPIO_04, "Pin6", PinPullResistance.PULL_UP); + input6A = gpio.provisionDigitalInputPin(RaspiPin.GPIO_06, "Pin6A", PinPullResistance.PULL_UP); + input6B = gpio.provisionDigitalInputPin(RaspiPin.GPIO_05, "Pin6B", PinPullResistance.PULL_UP); + button7 = gpio.provisionDigitalInputPin(RaspiPin.GPIO_29, "Pin7", PinPullResistance.PULL_UP); + input7A = gpio.provisionDigitalInputPin(RaspiPin.GPIO_28, "Pin7A", PinPullResistance.PULL_UP); + input7B = gpio.provisionDigitalInputPin(RaspiPin.GPIO_27, "Pin7B", PinPullResistance.PULL_UP); + + button1.addListener(new GpioPinListenerDigital() { // Cancel button: clears the queue, lifts the pen and returns to home position. + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = button1.getState().getValue(); + print("button1.getState().getValue() returned "); + println(a); + if (a == 0) { // rising edge + resetQueue(); + //addToCommandQueue(CMD_PENUP + penLiftUpPosition +",END"); + button_mode_returnToHome(); + } + } + }); + button2.addListener(new GpioPinListenerDigital() { // Export button: Use these spirgraph settings (move it across to polargraph). + int lastA; + + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = button2.getState().getValue(); + if (a == 0) { // rising edge + button_mode_exportSpirograph(); + } + } + }); + button3.addListener(new GpioPinListenerDigital() { // start button + int lastA; + + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = button3.getState().getValue(); + if (a == 0) { // rising edge + sendVectorShapes(); + } + } + }); + button4.addListener(new GpioPinListenerDigital() { // pause/resume queue button + int lastA; + + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = button4.getState().getValue(); + if (a == 0) { // rising edge + commandQueueRunning = !commandQueueRunning; + } + } + }); + button5.addListener(new GpioPinListenerDigital() { // set Home + int lastA; + + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = button5.getState().getValue(); + if (a == 0) { // rising edge + sendSetHomePosition(); + } + } + }); + button6.addListener(new GpioPinListenerDigital() { // reset position to defualt + int lastA; + + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = button6.getState().getValue(); + if (a == 0) { // rising edge + PVector newVecPosition = new PVector(0, 0); + vectorPosition = newVecPosition; + } + } + }); + button7.addListener(new GpioPinListenerDigital() { // reset scale to default + int lastA; + + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = button7.getState().getValue(); + if (a == 0) { // rising edge + cp5.getController(MODE_RESIZE_VECTOR).setValue( 38.6 ); + } + } + }); + + input1A.addListener(new GpioPinListenerDigital() { + int lastA; + + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = input1A.getState().getValue(); + int b = input1B.getState().getValue(); + if (lastA != a) { + int n = (b == a ? -1 : 1); + if (Radius + n > 0 && Radius + n < 1000) { + cp5.getController(MODE_LIVE_BIG_RADIUS_VALUE).setValue( Radius + n ); + } + lastA = a; + } + } + }); + + input2A.addListener(new GpioPinListenerDigital() { + int lastA; + + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = input2A.getState().getValue(); + int b = input2B.getState().getValue(); + if (lastA != a) { + int n = (b == a ? -1 : 1); + if (radius + n > 0 && radius + n < 1000) { + cp5.getController(MODE_LIVE_SMALL_RADIUS_VALUE).setValue( radius + n ); + } + lastA = a; + } + } + }); + input3A.addListener(new GpioPinListenerDigital() { + int lastA; + + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = input3A.getState().getValue(); + int b = input3B.getState().getValue(); + if (lastA != a) { + int n = (b == a ? -1 : 1); + if (rho + n > 0 && rho + n < 1000) { + cp5.getController(MODE_LIVE_RHO_RADIUS_VALUE).setValue( rho + n ); + } + lastA = a; + } + } + }); + + input4A.addListener(new GpioPinListenerDigital() { + int lastA; + + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = input4A.getState().getValue(); + int b = input4B.getState().getValue(); + if (lastA != a) { + int n = (b == a ? -1 : 1); + if (Interval + n > 0 && Interval + n < 1000) { + cp5.getController(MODE_LIVE_INTERVAL_VALUE).setValue( Interval + n ); + } + lastA = a; + } + } + }); + + input5A.addListener(new GpioPinListenerDigital() { // X-position of Vectors + int lastA; + + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = input5A.getState().getValue(); + int b = input5B.getState().getValue(); + if (lastA != a) { + int n = (b == a ? -1 : 1); + PVector push = new PVector(n, 0); + vectorPosition = PVector.add(vectorPosition, push); + lastA = a; + } + } + }); + + input6A.addListener(new GpioPinListenerDigital() { // Y-position of Vectors + int lastA; + + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = input6A.getState().getValue(); + int b = input6B.getState().getValue(); + if (lastA != a) { + int n = (b == a ? -1 : 1); + PVector push = new PVector(0, n); + vectorPosition = PVector.add(vectorPosition, push); + lastA = a; + } + } + }); + + input7A.addListener(new GpioPinListenerDigital() { // Scale of vectors + int lastA; + + @Override + public synchronized void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent arg0) { + int a = input7A.getState().getValue(); + int b = input7B.getState().getValue(); + if (lastA != a) { + int n = (b == a ? -1 : 1); + float scale = vectorScaling; + if (scale + n > 0 && scale + n < 100) { + cp5.getController(MODE_RESIZE_VECTOR).setValue( scale + n ); + } + lastA = a; + } + } + }); + */ // end of comment block for RaspPi +} void preLoadCommandQueue() { @@ -723,6 +997,9 @@ void draw() else if (getCurrentTab() == TAB_NAME_TRACE) { drawTracePage(); } + else if (getCurrentTab() == TAB_NAME_SPIROGRAPH) { + drawSpiroPage(); + } else { drawDetailsPage(); } @@ -936,6 +1213,281 @@ void drawTracePage() // displayGamepadOverlay(); } +void drawSpiroPage() { + strokeWeight(1); + background(100); + noFill(); + stroke(255, 150, 255, 100); + strokeWeight(3); + stroke(150); + noFill(); + + getDisplayMachine().drawForSpiro();//Trace(); + if (true || retraceShape) // displayingImage && getDisplayMachine().imageIsReady() && + { + spirograph(); + //processedLiveImage = trace_processImageForTrace(getDisplayMachine().getImage()); + //colourSeparations = trace_buildSeps(processedLiveImage, sepKeyColour); + //traceShape = trace_traceImage(colourSeparations); + //drawingTraceShape = true; + retraceShape = false; + } + + + + stroke(255, 0, 0); + + for (Panel panel : getPanelsForTab(TAB_NAME_SPIROGRAPH)) + { + panel.draw(); + } + text(propertiesFilename, getPanel(PANEL_NAME_GENERAL).getOutline().getLeft(), getPanel(PANEL_NAME_GENERAL).getOutline().getTop()-7); + + + if (displayingInfoTextOnInputPage) + showText(250,45); + drawStatusText((int)statusTextPosition.x, (int)statusTextPosition.y); + showCommandQueue((int) width-200, 20); + + +// processGamepadInput(); +// +// if (displayGamepadOverlay) +// displayGamepadOverlay(); +} + +void spirograph() { + float theta; + int last_x = (Radius-radius)*1+rho*1; + if (mode != 0) + last_x = (Radius+radius)*1-rho*1; + int last_y = 0; + int x; + int y; + if (radius <= 0) radius = 1; + if (Radius <= 0) Radius = 1; + if (rho <= 0) rho = 1; + if (mode == 0) { // hypotrochoid + for(int i=0; i"; + lineNo++; + data[lineNo] = ""; + lineNo++; + data[lineNo] = ""; + lineNo++; + // Start of XML + data[lineNo] = ""; + lineNo++; + + // hide the settings in plain sight so anyone can recreate the same spirograph from the SVG + data[lineNo] = ""; + lineNo++; + + // Drawing lines + if (mode == 0) { + for(int i=0; i0) { + data[lineNo] += "L "+str(x) + " " + str(y) + " "; + } + else if (i==0) { // first time through we start the path + data[lineNo] = "0) { + data[lineNo] += "L "+str(x) + " " + str(y) + " "; + } + else if (i==0) { // first time through we start the path + data[lineNo] = "0) { + data[lineNo] += "L "+str(x) + " " + str(y) + " "; + } + else if (i==0) { // first time through we start the path + data[lineNo] = "0) { + data[lineNo] += "L "+str(x) + " " + str(y) + " "; + } + else if (i==0) { // first time through we start the path + data[lineNo] = "0) { + data[lineNo] += "L "+str(x) + " " + str(y) + " "; + } + else if (i==0) { // first time through we start the path + data[lineNo] = ""; + lineNo++; + + // Wrap up the file + data[lineNo] = ""; + + // Save to File + // The same file is overwritten by adding the data folder path to saveStrings(). + saveStrings(filepath, data); + println("Export complete."); +} void drawCommandQueuePage() { @@ -1166,6 +1718,21 @@ void loadVectorWithFileChooser() ); } +void loadVectorFromSpirograph() { + // need a hard coded filename and location to load the spirograph. + File file = new File("output.svg"); // doesn't look right to me but can't find any better function. + RShape shape = loadShapeFromFile(file.getPath()); + if (shape != null) + { + setVectorFilename(file.getPath()); + setVectorShape(shape); + } + else + { + println("File not found (" + file.getPath() + ")"); + } +} + class VectorFileFilter extends javax.swing.filechooser.FileFilter { public boolean accept(File file) { diff --git a/tabSetup.pde b/tabSetup.pde index 75e7eca..ff1b8c0 100644 --- a/tabSetup.pde +++ b/tabSetup.pde @@ -61,11 +61,16 @@ Map> buildPanelsForTabs() queuePanels.add(getPanel(PANEL_NAME_QUEUE)); queuePanels.add(getPanel(PANEL_NAME_GENERAL)); + Set spirographPanels = new HashSet(2); + spirographPanels.add(getPanel(PANEL_NAME_SPIROGRAPH)); + spirographPanels.add(getPanel(PANEL_NAME_GENERAL)); + map.put(TAB_NAME_INPUT, inputPanels); map.put(TAB_NAME_ROVING, rovingPanels); map.put(TAB_NAME_TRACE, tracePanels); map.put(TAB_NAME_DETAILS, detailsPanels); map.put(TAB_NAME_QUEUE, queuePanels); + map.put(TAB_NAME_SPIROGRAPH, spirographPanels); return map; } @@ -78,6 +83,7 @@ List buildTabNames() list.add(TAB_NAME_TRACE); list.add(TAB_NAME_DETAILS); list.add(TAB_NAME_QUEUE); + list.add(TAB_NAME_SPIROGRAPH); return list; } @@ -112,6 +118,11 @@ void initTabs() queue.setLabel(TAB_LABEL_QUEUE); queue.activateEvent(true); queue.setId(5); + + Tab spirograph = cp5.getTab(TAB_NAME_SPIROGRAPH); + spirograph.setLabel(TAB_LABEL_SPIROGRAPH); + spirograph.activateEvent(true); + spirograph.setId(6); } public Set buildPanelNames() @@ -123,6 +134,7 @@ public Set buildPanelNames() set.add(PANEL_NAME_DETAILS); set.add(PANEL_NAME_QUEUE); set.add(PANEL_NAME_GENERAL); + set.add(PANEL_NAME_SPIROGRAPH); return set; }