So -
Single curve vertical toolpath extrusion is already impossible.
But then they successfully connected.
Without any infill or supports.

Great OBDF department show at AUArts last night!
Lots I could write about but I especially loved this celestial clock a student made, a steel ball bearing endlessly rotating about its equater, powered by what I presume to be a magnet on the inside of the device, invisible rolling it around and around as if it were a second-hand on a clock. Very creative, and a cool hidden-mechanism idea I'd love to incorporate into future projects.
Lotta problems, still working through it, gotta separate these and more fully implement and test each stage:
/*
* Stage 1: Image (.png) → Raw Binary Data (.bin)
*
* Converts the image pixel data into raw binary and saves as a .bin file.
*/
PImage img;
String binaryFile = "output-1.bin";
void setup() {
size(512, 512);
img = loadImage("input.png");
img.resize(width, height);
byte[] bytes = new byte[img.pixels.length * 4];
img.loadPixels();
for (int i = 0; i < img.pixels.length; i++) {
color c = img.pixels[i];
bytes[i * 4] = (byte) red(c);
bytes[i * 4 + 1] = (byte) green(c);
bytes[i * 4 + 2] = (byte) blue(c);
bytes[i * 4 + 3] = (byte) alpha(c);
}
saveBytes(binaryFile, bytes);
println("Stage 1 complete: "+binaryFile);
exit();
}
/*
* Stage 2: Binary Data (.bin) → Soundwave (.wav)
*
* Interprets binary data as waveform amplitude values and generates a .wav file.
*/
import processing.sound.*;
String binaryInput = "output-1.bin";
String wavFile = "output-2.wav";
void setup() {
byte[] data = loadBytes(binaryInput);
AudioSample sample = new AudioSample(this, data.length, 44100);
for (int i = 0; i < data.length; i++) {
sample.write(i, (data[i] / 128.0) - 1.0);
}
sample.save(wavFile);
println("Stage 2 complete: "+wavFile);
exit();
}
/*
* Stage 3: Soundwave (.wav) → 3D Mesh (.obj)
*
* Uses waveform amplitude data to generate a 3D mesh and saves it as .obj.
*/
import peasy.*;
import wblut.hemesh.*;
String wavInput = "output-2.wav";
String objFile = "output-3.obj";
void setup() {
float[] waveform = loadSoundWave(wavInput);
HE_Mesh mesh = new HE_Mesh(new HEC_Grid().setU(100).setV(100).setUSize(200).setVSize(200));
for (int i = 0; i < waveform.length; i++) {
mesh.getVertex(i).setZ(waveform[i] * 50);
}
HET_Export.saveToOBJ(mesh, objFile);
println("Stage 3 complete: "+objFile);
exit();
}
/*
* Stage 4: 3D Mesh (.obj) → Vector Drawing (.svg)
*
* Flattens the 3D mesh into 2D and saves it as an .svg file.
*/
import processing.svg.*;
String objInput = "output-3.obj";
String svgFile = "output-4.svg";
void setup() {
PShape mesh2D = loadShape(objInput);
size(800, 800);
beginRecord(SVG, svgFile);
shape(mesh2D, 0, 0, width, height);
endRecord();
println("Stage 4 complete: "+svgFile);
exit();
}
/*
* Stage 5: Vector Drawing (.svg) → Plaintext Coordinates (.txt)
*
* Extracts x, y coordinates from the .svg and saves them as a .txt file.
*/
String svgInput = "output-4.svg";
String txtFile = "output-5.txt";
void setup() {
PShape svg = loadShape(svgInput);
String coords = "";
for (int i = 0; i < svg.getChildCount(); i++) {
PShape child = svg.getChild(i);
for (int j = 0; j < child.getVertexCount(); j++) {
float x = child.getVertexX(j);
float y = child.getVertexY(j);
coords += x + "," + y + "\n";
}
}
saveStrings(txtFile, split(coords, "\n"));
println("Stage 5 complete: "+txtFile);
exit();
}
/*
* Stage 6: Plaintext Coordinates (.txt) → Color Palette (.aco)
*
* Converts x, y coordinates into RGB color values and saves as an .aco color palette file.
*/
String txtInput = "output-5.txt";
String acoFile = "output-6.aco";
void setup() {
String[] coords = loadStrings(txtInput);
color[] palette = new color[coords.length];
for (int i = 0; i < coords.length; i++) {
String[] parts = split(coords[i], ",");
float x = float(parts[0]) % 255;
float y = float(parts[1]) % 255;
palette[i] = color(x, y, (x + y) % 255);
}
saveACO(acoFile, palette);
println("Stage 6 complete: "+acoFile);
exit();
}
/*
* Stage 7: Color Palette (.aco) → Encoded Image (.tiff)
*
* Uses the color palette to create a new image and saves it as a .tiff file.
*/
String acoInput = "output-6.aco";
String tiffFile = "output-7.tiff";
void setup() {
color[] palette = loadACO(acoInput);
PImage img = createImage(512, 512, RGB);
img.loadPixels();
for (int i = 0; i < img.pixels.length; i++) {
img.pixels[i] = palette[i % palette.length];
}
img.updatePixels();
img.save(tiffFile);
println("Stage 7 complete: "+tiffFile);
exit();
}
/*
* Stage 8: Encoded Image (.tiff) → Raw Hex Data (.hex)
*
* Converts image pixel data into raw hexadecimal values.
*/
String tiffInput = "output-7.tiff";
String hexFile = "output-8.hex";
void setup() {
PImage img = loadImage(tiffInput);
img.loadPixels();
String hexData = "";
for (int i = 0; i < img.pixels.length; i++) {
hexData += hex(img.pixels[i], 6) + "\n";
}
saveStrings(hexFile, split(hexData, "\n"));
println("Stage 8 complete: "+hexFile);
exit();
}
/*
* Stage 9: Raw Hex Data (.hex) → Glitched Audio (.wav)
*
* Uses the hex data as raw audio waveform values.
*/
String hexInput = "output-8.hex";
String glitchWav = "output-9.wav";
void setup() {
String[] hexData = loadStrings(hexInput);
AudioSample sample = new AudioSample(this, hexData.length, 44100);
for (int i = 0; i < hexData.length; i++) {
float val = unhex(hexData[i]) / 255.0 * 2.0 - 1.0;
sample.write(i, val);
}
sample.save(glitchWav);
println("Stage 9 complete: "+glitchWav);
exit();
}
/*
* Stage 10: Glitched Audio (.wav) → Reconstructed Image (.png)
*
* Interprets audio data as pixel values and reconstructs a new image.
*/
String wavInput = "output-9.wav";
String finalPng = "output-10.png";
void setup() {
float[] audioData = loadSoundWave(wavInput);
PImage img = createImage(512, 512, RGB);
img.loadPixels();
for (int i = 0; i < img.pixels.length; i++) {
float val = audioData[i % audioData.length] * 255.0;
img.pixels[i] = color(val);
}
img.updatePixels();
img.save(finalPng);
println("Stage 10 complete: "+finalPng);
exit();
}
Singularly combining photography, traditional cyanotype printing processes, 3d printing, and digital maniuplation - to create singlular obj...