Created
September 26, 2024 03:46
-
-
Save wschutzer/eb8c1ae70c5c611e662027e8f026dc57 to your computer and use it in GitHub Desktop.
sketch_240925b_mobiusring
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import peasy.*; | |
import processing.core.PMatrix3D; | |
PeasyCam cam; | |
boolean recording = true; | |
int frame_size = recording ? 2160 : 800; | |
float fac = frame_size/800.0; | |
int numSegments = 50; // Number of segments along the Möbius ring (higher means smoother) | |
float ringRadius = 200*fac; // Radius of the Möbius ring | |
float ringWidth = 60*fac; // Width of the rectangular cross-section | |
float ringThickness = 60*fac; // Thickness of the rectangular cross-section | |
int FPS = 60; | |
int total_frames = 60*FPS; | |
float t = 0; | |
PFont courier; | |
int n_chars = 10; | |
void settings() | |
{ | |
size(frame_size,frame_size,P3D); | |
smooth(8); | |
} | |
void setup() | |
{ | |
randomSeed(1337); | |
cam = new PeasyCam(this, 500*fac); // Initialize PeasyCam with an initial distance | |
cam.setRotations(-0.66542256, -0.94496423, -3.0573382); | |
cam.pan(40*fac,-10*fac); | |
courier = createFont("Courier New",24*fac,true); | |
// Things are random digits to be drawn on each of the 4 faces of the surface | |
// (actually there are only two faces) | |
things_t = new thing[2*n_chars*numSegments]; | |
things_b = new thing[2*n_chars*numSegments]; | |
things_l = new thing[2*n_chars*numSegments]; | |
things_r = new thing[2*n_chars*numSegments]; | |
float lm = -0.95; | |
for(int j=0; j<numSegments;j++) | |
{ | |
int k = 2*n_chars*j; | |
for(int i=0; i<n_chars; i++) | |
{ | |
things_t[k+i] = new thing(lm+i*0.2, 1); | |
things_t[k+i+n_chars] = new thing(lm+i*0.2, 0); | |
things_l[k+i] = new thing(lm+i*0.2, 1); | |
things_l[k+i+n_chars] = new thing(lm+i*0.2, 0); | |
things_r[k+i] = new thing(lm+i*0.2, 1); | |
things_r[k+i+n_chars] = new thing(lm+i*0.2, 0); | |
things_b[k+i] = new thing(lm+i*0.2, 1); | |
things_b[k+i+n_chars] = new thing(lm+i*0.2, 0); | |
} | |
} | |
} | |
void draw() | |
{ | |
t = (1.0*(frameCount-1)/total_frames) % 1; | |
background(0); | |
pushMatrix(); | |
noStroke();//stroke(128); // Draw lines around the rectangles | |
fill(0); //fill(150*lvl, 200*lvl, 255*lvl); | |
lights(); | |
drawMobiusRing(); | |
popMatrix(); | |
// texts | |
pushMatrix(); | |
float[] rot = cam.getRotations(); | |
rotateX(rot[0]); | |
rotateY(rot[1]); | |
rotateZ(rot[2]); | |
translate(19,0,0); | |
fill(255);stroke(255); | |
textAlign(CENTER, CENTER); | |
textFont(courier); | |
textSize(12*fac); | |
text("@infinitymathart • 2024",0.0*width,0.3*height); | |
popMatrix(); | |
if (recording) | |
{ | |
saveFrame("/Volumes/waldeck/frames/t/frame_####.png"); | |
println(frameCount,"/",total_frames); | |
if (frameCount == total_frames) | |
{ | |
stop(); | |
exit(); | |
} | |
} | |
} | |
// Rendering the Möbius ring using the segment class for each segment | |
// | |
void drawMobiusRing() | |
{ | |
for (int i = 0; i < numSegments; i++) | |
{ | |
float u1 = map(i, 0, numSegments, 0, TWO_PI); // u parameter for current segment | |
float u2 = map(i + 1, 0, numSegments, 0, TWO_PI); // u parameter for next segment | |
// Create ring for u1 and u2 | |
ring f = new ring(u1, u2, 0); | |
f.set_index(i); | |
f.shift(-2*TAU*t); | |
f.draw(); | |
} | |
} | |
// Function to draw the debugging visuals | |
// | |
void drawFaceNormals(ring f) | |
{ | |
pushStyle(); | |
PVector[] centers = {f.tf.p, f.bf.p, f.rf.p, f.lf.p}; | |
PVector[] normals = {f.tf.n, f.bf.n, f.rf.n, f.lf.n}; | |
for (int i = 0; i < centers.length; i++) { | |
PVector center = centers[i]; | |
PVector normalEnd = PVector.add(center, normals[i].copy().mult(30)); // Scale normal for visibility | |
// Draw the normal vector (line) | |
stroke(0,0,255); // White line | |
strokeWeight(1); | |
line(center.x, center.y, center.z, normalEnd.x, normalEnd.y, normalEnd.z); | |
// Draw a green dot at the center of each face | |
stroke(0, 255, 0); | |
strokeWeight(6); | |
point(center.x, center.y, center.z); | |
// Draw a red dot at the end of each normal vector | |
stroke(255, 0, 0); | |
strokeWeight(6); | |
point(normalEnd.x, normalEnd.y, normalEnd.z); | |
} | |
popStyle(); | |
} | |
// Parametric surface of the Möbius strip | |
// | |
PVector s(float u, float v, float r) { | |
float x = r * (1 + v / 2 * cos(u / 2)) * cos(u); | |
float y = r * (1 + v / 2 * cos(u / 2)) * sin(u); | |
float z = r * v / 2 * sin(u / 2); | |
return new PVector(x, y, z); | |
} | |
// Partial derivative with respect to v | |
// | |
PVector dsdv(float u, float v, float r) | |
{ | |
float x = 1.0 / 2 * cos(u / 2) * cos(u); | |
float y = 1.0 / 2 * cos(u / 2) * sin(u); | |
float z = 1.0 / 2 * sin(u / 2); | |
return new PVector(x, y, z); | |
} | |
// Partial derivative with respect to u | |
// | |
PVector dsdu(float u, float v, float r) | |
{ | |
float x = -v / 4 * sin(u / 2) * cos(u) - (1 + v / 2 * cos(u / 2)) * sin(u); | |
float y = -v / 4 * sin(u / 2) * sin(u) + (1 + v / 2 * cos(u / 2)) * cos(u); | |
float z = v / 4 * cos(u / 2); | |
return new PVector(x, y, z); | |
} | |
// Normal vector at the point | |
// | |
PVector normal_vector(float u, float v, float r) { | |
PVector du = dsdu(u, v, r); | |
PVector dv = dsdv(u, v, r); | |
PVector n = dv.cross(du); | |
return n.normalize(); | |
} | |
// System of coordinates at a point on the surface | |
// | |
Coords surfCoords(float u, float v, float r) | |
{ | |
PVector du = dsdu(u,v,r).normalize(); | |
PVector dv = dsdv(u,v,r).normalize(); | |
PVector n = dv.cross(du).normalize(); | |
return new Coords( s(u,v,r), du, dv, n ); | |
} | |
// Coords class to represent the coordinate system at a point on the surface | |
// | |
class Coords { | |
PVector p; // The point on the surface | |
PVector du; // Tangent vector along u | |
PVector dv; // Tangent vector along v | |
PVector n; // Normal vector | |
Coords(PVector p_, PVector du_, PVector dv_, PVector n_) { | |
p = p_.copy(); | |
du = du_.copy(); | |
dv = dv_.copy(); | |
n = n_.copy(); | |
} | |
PMatrix3D basisChange(Coords other) { | |
PMatrix3D inv = other.getBasisMatrix(); | |
inv.invert(); // Get the inverse of the other system's basis | |
PMatrix3D result = getBasisMatrix(); | |
result.apply(inv); // Apply inverse to get change of basis | |
return result; | |
} | |
PMatrix3D getBasisMatrix() { | |
return new PMatrix3D( | |
du.x, dv.x, n.x, 0, | |
du.y, dv.y, n.y, 0, | |
du.z, dv.z, n.z, 0, | |
0, 0, 0, 1 | |
); | |
} | |
} | |
// Surface segment. It consists of 4 lines (top,left,bottom,right) | |
// forming a quadrilateral with center at the point (u, v) | |
// (tipically, v = 0). | |
// | |
class segment { | |
Coords c; // Center and basis of the segment | |
PVector tl; // Top left vertex | |
PVector tr; // Top right vertex | |
PVector bl; // Bottom left vertex | |
PVector br; // Bottom right vertex | |
Coords tf; // Top line coordinate system | |
Coords bf; // Bottom line coordinate system | |
Coords rf; // Right line coordinate system | |
Coords lf; // Left line coordinate system | |
segment(float u, float v) | |
{ | |
// Central coordinate system | |
c = surfCoords(u, v, ringRadius); | |
// Compute the four vertices for the rectangular segment | |
tl = c.p.copy().add(c.dv.copy().mult(-ringWidth / 2)).add(c.n.copy().mult(ringThickness / 2)); | |
tr = c.p.copy().add(c.dv.copy().mult(ringWidth / 2)).add(c.n.copy().mult(ringThickness / 2)); | |
bl = c.p.copy().add(c.dv.copy().mult(-ringWidth / 2)).add(c.n.copy().mult(-ringThickness / 2)); | |
br = c.p.copy().add(c.dv.copy().mult(ringWidth / 2)).add(c.n.copy().mult(-ringThickness / 2)); | |
// Coordinate systems for each face: | |
tf = new Coords(tl.copy().add(tr).mult(0.5), c.du, c.dv, c.n); // Top face | |
bf = new Coords(bl.copy().add(br).mult(0.5), c.du, c.dv.copy().mult(-1), c.n.copy().mult(-1)); // Bottom face | |
rf = new Coords(tr.copy().add(br).mult(0.5), c.du, c.n.copy().mult(-1), c.dv); // Right face | |
lf = new Coords(tl.copy().add(bl).mult(0.5), c.du, c.n.copy(), c.dv.copy().mult(-1)); // Left face | |
} | |
void draw_tl() // Draws the vertex at tl | |
{ | |
vertex(tl.x, tl.y, tl.z); | |
} | |
void draw_tr() | |
{ | |
vertex(tr.x, tr.y, tr.z); | |
} | |
void draw_bl() | |
{ | |
vertex(bl.x, bl.y, bl.z); | |
} | |
void draw_br() | |
{ | |
vertex(br.x, br.y, br.z); | |
} | |
} | |
// Each pair of segments define 4 faces (top,left,bottom,right) which form | |
// a ring. | |
// | |
class ring | |
{ | |
float u1, u2, v; | |
float u_shift; // Shift to be applied to u1 and u2 during animation | |
segment s1; // First segment | |
segment s2; // Next segment | |
Coords tf; // System of coordinates for top face | |
Coords bf; // System of coordinates for bottom face | |
Coords rf; // System of coordinates for right face | |
Coords lf; // System of coordinates for left face | |
int index; | |
ring(float u1_, float u2_, float v_) | |
{ | |
u_shift = 0; | |
index = 0; | |
u1 = u1_; | |
u2 = u2_; | |
v = v_; | |
update_coords(); | |
} | |
void update_coords() | |
{ | |
// Create segment objects for u1 and u2 | |
s1 = new segment(u1+u_shift, v); | |
s2 = new segment(u2+u_shift, v); | |
tf = new Coords(s1.tf.p.copy().add(s2.tf.p).mult(0.5), s1.tf.du.copy().add(s2.tf.du).mult(0.5), s1.tf.dv.copy().add(s2.tf.dv).mult(0.5), s1.tf.n.copy().add(s2.tf.n).mult(0.5)); | |
bf = new Coords(s1.bf.p.copy().add(s2.bf.p).mult(0.5), s1.bf.du.copy().add(s2.bf.du).mult(0.5), s1.bf.dv.copy().add(s2.bf.dv).mult(0.5), s1.bf.n.copy().add(s2.bf.n).mult(0.5)); | |
lf = new Coords(s1.lf.p.copy().add(s2.lf.p).mult(0.5), s1.lf.du.copy().add(s2.lf.du).mult(0.5), s1.lf.dv.copy().add(s2.lf.dv).mult(0.5), s1.lf.n.copy().add(s2.lf.n).mult(0.5)); | |
rf = new Coords(s1.rf.p.copy().add(s2.rf.p).mult(0.5), s1.rf.du.copy().add(s2.rf.du).mult(0.5), s1.rf.dv.copy().add(s2.rf.dv).mult(0.5), s1.rf.n.copy().add(s2.rf.n).mult(0.5)); | |
} | |
void shift(float u_shift_) | |
{ | |
u_shift = u_shift_; | |
update_coords(); | |
} | |
void set_index(int i_) | |
{ | |
index = i_; | |
} | |
// Draws the faces of a ring and things on the faces | |
// | |
void draw() | |
{ | |
// Draw the top and bottom faces of the segment | |
beginShape(QUADS); | |
s1.draw_tl(); | |
s1.draw_bl(); | |
s2.draw_bl(); | |
s2.draw_tl(); | |
endShape(CLOSE); | |
beginShape(QUADS); | |
s1.draw_tr(); | |
s2.draw_tr(); | |
s2.draw_br(); | |
s1.draw_br(); | |
endShape(CLOSE); | |
// Draw the left face (connecting top-left and bottom-left) | |
beginShape(QUADS); | |
s1.draw_tl(); | |
s2.draw_tl(); | |
s2.draw_tr(); | |
s1.draw_tr(); | |
endShape(CLOSE); | |
// Draw the right face (connecting bottom-left and bottom-right) | |
beginShape(QUADS); | |
s1.draw_bl(); | |
s2.draw_bl(); | |
s2.draw_br(); | |
s1.draw_br(); | |
endShape(CLOSE); | |
// Debugging: Draw green dots at the center of each face and red dots at the end of normals | |
//drawFaceNormals(this); | |
/*pushStyle(); | |
stroke(255); | |
strokeWeight(6); | |
PVector v = s_right_face(this, cos(TAU*t), sin(TAU*t)); | |
point(v.x, v.y, v.z); | |
popStyle(); */ | |
// Text things on the faces of the ring | |
pushStyle(); | |
textAlign(LEFT, TOP); // Center the text | |
textSize(10*fac); // Adjust text size as needed | |
fill(255); // Text color | |
//drawTextOnTopFace(this, "TOP FACE", -1, 1); | |
/*String st = "3•14159257"; | |
String st1 = "2•71828182"; | |
float lm = -0.95; | |
for(int i=0;i<st.length();i++) | |
drawTextOnTopFace(this, ""+st.charAt(i), lm+i*0.2, 1); | |
for(int i=0;i<st.length();i++) | |
drawTextOnTopFace(this, ""+st.charAt(i), lm+i*0.2, 0); | |
for(int i=0;i<st.length();i++) | |
drawTextOnBottomFace(this, ""+st.charAt(i), lm+i*0.2, 1); | |
for(int i=0;i<st.length();i++) | |
drawTextOnBottomFace(this, ""+st.charAt(i), lm+i*0.2, 0); | |
for(int i=0;i<st.length();i++) | |
drawTextOnRightFace(this, ""+st1.charAt(i), lm+i*0.2, 1); | |
for(int i=0;i<st.length();i++) | |
drawTextOnRightFace(this, ""+st1.charAt(i), lm+i*0.2, 0); | |
for(int i=0;i<st.length();i++) | |
drawTextOnLeftFace(this, ""+st1.charAt(i), lm+i*0.2, 1); | |
for(int i=0;i<st.length();i++) | |
drawTextOnLeftFace(this, ""+st1.charAt(i), lm+i*0.2, 0); */ | |
for(int i=0;i<2*n_chars;i++) | |
{ | |
thing tg = things_t[2*9*index+i]; | |
if (tg.flipping()) fill(200); else fill(255); | |
drawTextOnTopFace(this, tg.get(), tg.u, tg.v); | |
tg = things_b[2*n_chars*index+i]; | |
if (tg.flipping()) fill(200); else fill(255); | |
drawTextOnBottomFace(this, tg.get(), tg.u, tg.v); | |
tg = things_l[2*n_chars*index+i]; | |
if (tg.flipping()) fill(200); else fill(255); | |
drawTextOnLeftFace(this, tg.get(), tg.u, tg.v); | |
tg = things_r[2*n_chars*index+i]; | |
if (tg.flipping()) fill(200); else fill(255); | |
drawTextOnRightFace(this, tg.get(), tg.u, tg.v); | |
} | |
popStyle(); | |
} | |
} | |
// Parametric function for the top face using bilinear interpolation | |
PVector s_top_face(ring f, float u3, float v3) | |
{ | |
// Interpolate between the four corner points (tl, tr, bl, br) | |
PVector tl = f.s1.tl; // Top-left | |
PVector tr = f.s1.tr; // Top-right | |
PVector bl = f.s2.tl; // Bottom-left | |
PVector br = f.s2.tr; // Bottom-right | |
// Adjust u3 and v3 to range from -1 to 1, making sure the center corresponds to u3 = 0, v3 = 0 | |
float uRatio = (u3 + 1) / 2.0; // Map u3 from [-1,1] to [0,1] | |
float vRatio = (v3 + 1) / 2.0; // Map v3 from [-1,1] to [0,1] | |
// Bilinear interpolation to calculate the point on the surface | |
PVector point = tl.copy().mult((1 - uRatio) * (1 - vRatio)) | |
.add(tr.copy().mult(uRatio * (1 - vRatio))) | |
.add(bl.copy().mult((1 - uRatio) * vRatio)) | |
.add(br.copy().mult(uRatio * vRatio)); | |
return point; | |
} | |
// Parametric function for the bottom face using bilinear interpolation | |
PVector s_bottom_face(ring f, float u3, float v3) { | |
PVector tl = f.s1.bl; // Bottom-left | |
PVector tr = f.s1.br; // Bottom-right | |
PVector bl = f.s2.bl; // Top-left | |
PVector br = f.s2.br; // Top-right | |
float uRatio = (u3 + 1) / 2.0; // Map u3 from [-1,1] to [0,1] | |
float vRatio = (v3 + 1) / 2.0; // Map v3 from [-1,1] to [0,1] | |
PVector point = tl.copy().mult((1 - uRatio) * (1 - vRatio)) | |
.add(tr.copy().mult(uRatio * (1 - vRatio))) | |
.add(bl.copy().mult((1 - uRatio) * vRatio)) | |
.add(br.copy().mult(uRatio * vRatio)); | |
return point; | |
} | |
// Parametric function for the left face using bilinear interpolation | |
PVector s_left_face(ring f, float u3, float v3) { | |
PVector tl = f.s1.tl; // Top-left | |
PVector tr = f.s1.bl; // Top-right | |
PVector bl = f.s2.tl; // Bottom-left | |
PVector br = f.s2.bl; // Bottom-right | |
float uRatio = (u3 + 1) / 2.0; // Map u3 from [-1,1] to [0,1] | |
float vRatio = (v3 + 1) / 2.0; // Map v3 from [-1,1] to [0,1] | |
PVector point = tl.copy().mult((1 - uRatio) * (1 - vRatio)) | |
.add(tr.copy().mult(uRatio * (1 - vRatio))) | |
.add(bl.copy().mult((1 - uRatio) * vRatio)) | |
.add(br.copy().mult(uRatio * vRatio)); | |
return point; | |
} | |
// Parametric function for the right face using bilinear interpolation | |
PVector s_right_face(ring f, float u3, float v3) { | |
PVector tl = f.s1.tr; // Top-left | |
PVector tr = f.s1.br; // Top-right | |
PVector bl = f.s2.tr; // Bottom-left | |
PVector br = f.s2.br; // Bottom-right | |
float uRatio = (u3 + 1) / 2.0; // Map u3 from [-1,1] to [0,1] | |
float vRatio = (v3 + 1) / 2.0; // Map v3 from [-1,1] to [0,1] | |
PVector point = tl.copy().mult((1 - uRatio) * (1 - vRatio)) | |
.add(tr.copy().mult(uRatio * (1 - vRatio))) | |
.add(bl.copy().mult((1 - uRatio) * vRatio)) | |
.add(br.copy().mult(uRatio * vRatio)); | |
return point; | |
} | |
// Function to draw text on the top face | |
void drawTextOnTopFace(ring f, String label, float u, float v) { | |
Coords globalCoords = new Coords( | |
new PVector(0, 0, 0), | |
new PVector(0, 1, 0), | |
new PVector(1, 0, 0), | |
new PVector(0, 0, 1) | |
); // Global coordinate system (identity matrix) | |
// Compute the change of basis matrix | |
PMatrix3D basisChangeMatrix = f.tf.basisChange(globalCoords); | |
// Get the point on the face where to draw | |
PVector center = s_top_face(f, u, -v); | |
// Draw the text on the top face | |
drawTextOnFace(center, basisChangeMatrix, label); | |
} | |
// General function to draw text on a face using basis transformation | |
void drawTextOnFace(PVector position, PMatrix3D basisChangeMatrix, String txt) | |
{ | |
pushMatrix(); // Save the current transformation matrix | |
// Move to the position where the text should be placed | |
translate(position.x, position.y, position.z); | |
// Apply the basis change matrix to align the text correctly | |
applyMatrix(basisChangeMatrix); | |
// Draw the text | |
translate(0,0,fac); // move text up and away from the surface slightly | |
text(txt, 0, 0); // Draw text at the origin | |
popMatrix(); // Restore the original transformation matrix | |
} | |
// Function to draw text on the bottom face | |
void drawTextOnBottomFace(ring f, String label, float u, float v) | |
{ | |
Coords globalCoords = new Coords( | |
new PVector(0, 0, 0), | |
new PVector(0, 1, 0), | |
new PVector(1, 0, 0), | |
new PVector(0, 0, 1) | |
); // Global coordinate system for the bottom face | |
// Compute the change of basis matrix | |
PMatrix3D basisChangeMatrix = f.bf.basisChange(globalCoords); | |
// Get the center of the bottom face | |
PVector center = s_bottom_face(f, -u, -v); | |
// Draw the text on the bottom face | |
drawTextOnFace(center, basisChangeMatrix, label); | |
} | |
// Function to draw text on the left face | |
void drawTextOnLeftFace(ring f, String label, float u, float v) | |
{ | |
Coords globalCoords = new Coords( | |
new PVector(0, 0, 0), | |
new PVector(0, 1, 0), // dv (horizontal) for the left face | |
new PVector(1, 0, 0), // du (vertical) for the left face | |
new PVector(0, 0, 1) | |
); // Global coordinate system for the left face | |
// Compute the change of basis matrix | |
PMatrix3D basisChangeMatrix = f.lf.basisChange(globalCoords); | |
// Get the center of the left face | |
PVector center = s_left_face(f, -u, -v); | |
// Draw the text on the left face | |
drawTextOnFace(center, basisChangeMatrix, label); | |
} | |
// Function to draw text on the right face | |
void drawTextOnRightFace(ring f, String label, float u, float v) | |
{ | |
Coords globalCoords = new Coords( | |
new PVector(0, 0, 0), | |
new PVector(0, 1, 0), // dv (horizontal) for the right face | |
new PVector(1, 0, 0), // du (vertical) for the right face | |
new PVector(0, 0, 1) | |
); // Global coordinate system for the right face | |
// Compute the change of basis matrix | |
PMatrix3D basisChangeMatrix = f.rf.basisChange(globalCoords); | |
// Get the center of the right face | |
PVector center = s_right_face(f, u, -v); | |
// Draw the text on the right face | |
drawTextOnFace(center, basisChangeMatrix, label); | |
} | |
void mousePressed() | |
{ | |
float[] position = cam.getPosition(); | |
println("Position (", position[0], ", ", position[1], ", ", position[2], ")"); | |
float[] rotations = cam.getRotations(); | |
println("Rotations: ", rotations[0], ", ", rotations[1], ", ", rotations[2]); | |
float[] look = cam.getLookAt(); | |
println("Lootat: (", look[0], ", ", look[1], ", ", look[2], ")" ); | |
} | |
class thing | |
{ | |
float u, v; // (u,v) coordinates relative to the surface face | |
char c; // First digit | |
char c1; // Second digit | |
float offset; // Offset at which it begins to flip | |
boolean flips; // Does this thing flip or not? | |
thing(float u_, float v_) | |
{ | |
u = u_; | |
v = v_; | |
c = "0123456789".charAt(int(random(0,9))); | |
c1 = "0123456789".charAt(int(random(0,9))); | |
flips = random(0,1) > 0.6; | |
offset = random(0, 1); | |
} | |
boolean flipping() | |
{ | |
if (flips) | |
{ | |
float tt = (t+offset)%1; | |
if ( (tt > 0.20 && tt < 0.40) || (tt > 0.60 && tt < 0.80 ) ) | |
return true; | |
} | |
return false; | |
} | |
// Returns c, unless it flips and it's time to flip, in which case it returns c1 | |
String get() | |
{ | |
return flipping() ? ""+c1 : ""+c; | |
} | |
} | |
thing[] things_t; | |
thing[] things_b; | |
thing[] things_l; | |
thing[] things_r; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment