See my context reflection here. It’ll give some background information on why I chose to explore this area.

I messed up and used popStyle instead of popMatrix when translating the ellipses on the z axis.

I had calculated the hue of each point according to its relative position within the array of points that is constantly being added to. This enabled the drawn form, no matter how many points, to always have the full range of the rainbow. Unfortunately, it slowed down so so quickly.

So I just changed the mapping to the mod of 10,000. That being said, sometimes it takes less than 10,000 points for the two rotating circles to complete the radial curve shape.

Mapping the derivative intersections of 0, to the borders of the letter form – essentially taking the z of the point and mapping it to the x of the letters:

Ex: “B”

Some additional inspiration from Aman, & Char – acetate printouts in many many layers of the point cloud, mapping to the color pattern, additional inspiration from Thomas Medicus’s

Special Character 🙂 displayed below:

Changed some of the formulas to allow the points to map and move smoothly and reconnect to stay continuous. Slight patterns of color were adjusted in.

The issue is just that since everything is mapped continuously and evenly through out, the middle bar of the A is missing.

The letter “A”:

The letter ‘C’ above worked a lot better.

I really wanted to strive to get the letter form to be more informed by it’s cycloid method of creation. Simply having a cloud of points doesn’t justify the need to have the cycloid creation within the process.

This is why I wasn’t satisfied with this earlier iteration below:

For the future, what I want to do:

- make the line of the circle disappear when you look at the letter form straight on (Golan’s suggestion)
- stereoscopic view in 3js for google cardboard
- remapping in real-time to different words

```
import geomerative.*;
//import cardboard.*;
// Declare the objects we are going to use, so that they are accesible from setup() and from draw()
RFont f;
RShape grp;
RPoint[] points;
import peasy.*;
PeasyCam cam;
DMachine DM;
float h2;
float w2;
float d2;
float CAPHEIGHT = 300;
// determines the main artboard size (radius)
float ArtboardRadius = 500;
// Animation for starting circles
float Radius1st = floor(random(ArtboardRadius * 0.2, ArtboardRadius * 0.5));
float Radius2nd = floor(random(ArtboardRadius * 0.2, ArtboardRadius * 0.5));
float speedModif1st = floor(random(3)+1);
float speedModif2nd = floor(random(3)+1);
// arm lengths
float armlength = (ArtboardRadius * 1.05) + floor(random(-75, 75));
// beginning location of drawing arm circles and it's speed
float n1, n2;
float nShift = radians(floor(random(45, 135)));
float nSpeed = 0.0005;
// a new layer for the drawing machine
PGraphics fDM;
ArrayList<Starpoint> starArray = new ArrayList<Starpoint>();
IntList inventoryOfEndpointi = new IntList();
int index = 0;
float letterXmax=0;
float pointsArrayIndexOfMax=0;
void setup() {
//fullScreen(PCardboard.STEREO);
inventoryOfEndpointi.append(0);
// VERY IMPORTANT: Allways initialize the library in the setup
RG.init(this);
// Load the font file we want to use (the file must be in the data folder in the sketch floder), with the size 60 and the alignment CENTER
grp = RG.getText("F", "Comfortaa_Bold.ttf", 400, LEFT);
size( 1280, 720, P3D );
d2 = dist(0, 0, w2, h2);
colorMode(HSB, 100);
cam = new PeasyCam(this, 100);
cam.lookAt(650, 300, 0);
cam.setMinimumDistance(50);
cam.setMaximumDistance(1000);
cam.setDistance(800);
cam.setYawRotationMode();
ortho();
smooth();
background(0);
strokeCap(CORNER);
n1 = radians(180);
n2 = n1 + nShift;
DM = new DMachine();
fDM = createGraphics(width, height,P3D);
starArray.add(new Starpoint(width/2, height/2,0));
RG.setPolygonizer(RG.UNIFORMLENGTH);
RG.setPolygonizerLength(1);
points = grp.getPoints();
for(int i=0; i<points.length;i++){//need to map the letter data to the size of the cycloid thingy
points[i].y = points[i].y+120;
}
}
void keyPressed(){
println("float[][] starArray={");
for(int i=0; i<starArray.size();i++){
println("{"+starArray.get(i).x+","+starArray.get(i).y+","+starArray.get(i).z+"},");
}
println("};");
}
float noiseInput = 0;
void draw() {
background(0);
// draw Artboard (BIG CIRCLE)
noFill();
//MAKE THE STROKE OPACITY DISAPPEAR WHEN YOU TURN IT TO THE SIDE
stroke(100);
strokeWeight(1);
ellipse(width/2, height/2, ArtboardRadius*2, ArtboardRadius*2);
// draw Initial Points (Begin Points)
DM.draw1stBeginPoint(n1, Radius1st, speedModif1st);
DM.draw2ndBeginPoint(n2, Radius2nd, speedModif2nd);
DM.CalculateEndPoint(armlength);
float distances = dist(DM.tX, DM.tY, width/2,height/2);//points further out should have z's from the letter that is further away
float zz = 0;//initial z value of all points
stroke(100);
line(DM.tX,DM.tY,0,DM.tX,DM.tY,zz);
int sizeOfArray = starArray.size()%11000;
starArray.add(new Starpoint(DM.tX, DM.tY,sizeOfArray));
for (int i = 1; i < starArray.size()-1; i++) {
Starpoint point = starArray.get(i);
point.render();
if (!(point.hasBeenChecked)){//check if the point is where direction changes drastically if it hasn't already been checked
point.findIfMaxLetter(starArray.get(i-1),starArray.get(i+1),i, noiseInput);
noiseInput+=.0001;
}else if(point.hasBeenChecked && (inventoryOfEndpointi.get(inventoryOfEndpointi.size()-1)>i)){
if(!(point.mapped)){
for(int j=1;j<inventoryOfEndpointi.size();j++){
int indexOfTarget = inventoryOfEndpointi.get(j);
int indexOflastEndpoint = inventoryOfEndpointi.get(j-1);
if((i<indexOfTarget) && (i>indexOflastEndpoint)){
point.mappingToEndpoints(i, starArray.get(indexOfTarget).endZ, indexOfTarget, indexOflastEndpoint, starArray.get(indexOflastEndpoint).endZ) ;//determines the endZ
}
}
}else if(point.mapped){
point.moveTowardsEndZ();
}
}
}
}
class Starpoint {
boolean hasBeenChecked = false;
boolean endCurve = false;
boolean mapped = false;
float x, y, z, endZ;
float hue;
Starpoint(float xx, float yy, int arraySize){
hue = map(arraySize,0,10999,0,100);
x = xx;
y = yy;
z=0;
}
void render(){
pushMatrix();
//color is mapped according to where it is in the array to ensure a rainbow no matter how many points there are
stroke(hue,100,100);
translate(0,0,z);
point(x,y,2);
popMatrix();
}
void moveTowardsEndZ(){
z = 0.99*z+0.01*endZ;
}
void mappingToEndpoints(int currentPointIndex, float targetZ, int targetEndpointindex, int lastEndpointindex, float lastZ){
endZ = map(currentPointIndex,lastEndpointindex,targetEndpointindex,lastZ,targetZ);
mapped = true;
}
void findIfMaxLetter(Starpoint p1,Starpoint p2, int index, float noisy){
if((p1.x>=this.x && p2.x>=this.x)|| (p1.x<=this.x && p2.x<=this.x)||(p1.y>=this.y && p2.y>=this.y)|| (p1.y<=this.y && p2.y<=this.y)){
this.endCurve=true;
this.mapped = true;
addEndCurveIndexValueToGlobalArraylist(index);
//clearly it's an edge, go search for an appropriate z
FloatList inventoryZ = new FloatList();//stores the multiple possible z's for later
for(int j=0; j<points.length; j++){
float ltrY = points[j].y;//they have to match y values generally
if (this.y>ltrY-1+height/2 && this.y<ltrY+height/2){inventoryZ.append(points[j].x);}//if it matches y, add the x value of the letter point as a possible z value
}
inventoryZ.append(0);
addEndCurveIndexValueToGlobalArraylist(index);
//which of the posible z's will it take from the inventory?
//int whichZ = floor(random(0,inventoryZ.size()-1));
int whichZ = floor(map(noise(noisy),0,1,0,inventoryZ.size()));
this.endZ = inventoryZ.get(whichZ);
}else{
float radialDistance = sq(p1.x-width/2)+sq(p1.y-height/2);
float radialDistance1 = sq(this.x-width/2)+sq(this.y-height/2);
if (radialDistance>=radialDistance1){//is it bigger farther away?
//if it is, is the next one smaller?
float radialDistance2 = sq(p2.x-width/2)+sq(p2.y-height/2);
}
}
this.hasBeenChecked = true;
}
}
void addEndCurveIndexValueToGlobalArraylist(int indexValue){
inventoryOfEndpointi.append(indexValue);
}
//////////////////
class DMachine {
float MAxx1, MAyy1;
float MAxx2, MAyy2;
float tX, tY;
float anim;
DMachine() {
anim = 0;
}
void draw1stBeginPoint(float n1_, float Radius1st_, float speedModif1st_) {
float MAx1, MAy1;
MAx1 = width/2 + ArtboardRadius * cos(n1);
MAy1 = height/2 + ArtboardRadius * -sin(n1);
stroke(60);
strokeWeight(1);
fill(0);
ellipse(MAx1, MAy1, Radius1st, Radius1st);
// resets the angle
n1 -= nSpeed;
if (degrees(n1) < 0) {
n1 = radians(360);
}
noStroke();
fill(255);
MAxx1 = MAx1 + cos(anim * speedModif1st) * Radius1st/2;
MAyy1 = MAy1 + sin(anim * speedModif1st) * Radius1st/2;
anim += 0.025;
fill(60);
ellipse(MAxx1, MAyy1, 5, 5);
}
void draw2ndBeginPoint(float n2_, float Radius2nd_, float speedModif2nd) {
float MAx2 = width/2 + ArtboardRadius * cos(n2);
float MAy2 = height/2 + ArtboardRadius * -sin(n2);
stroke(60);
strokeWeight(1);
fill(0);
ellipse(MAx2, MAy2, Radius2nd, Radius2nd);
// resets the angle
n2 -= nSpeed;
if (degrees(n2) < 0) {
n2 = radians(360);
}
noStroke();
fill(255);
MAxx2 = MAx2 + sin(anim * speedModif2nd) * Radius2nd/2;
MAyy2 = MAy2 + cos(anim * speedModif2nd) * Radius2nd/2;
anim += 0.025;
fill(60);
ellipse(MAxx2, MAyy2, 5, 5);
}
void CalculateEndPoint(float armlength_) {
// "crazy" math stuff here
// only look if you dare!
stroke(60);
fill(60);
// distance between the two main points
float a = dist(MAxx1, MAyy1, MAxx2, MAyy2);
line(MAxx1, MAyy1, MAxx2, MAyy2);
// the mid-point
float a2X = lerp(MAxx1, MAxx2, 0.5);
float a2Y = lerp(MAyy1, MAyy2, 0.5);
ellipse(a2X, a2Y, 5, 5);
// The armlength "compensator" aka the triangle height calculator
float fD1 = abs(sq(armlength) - sq(a/2));
float fD2 = sqrt(fD1);
// "compensation" angle
float alpha = asin(abs(MAyy1 - MAyy2) / a);
if (MAyy1 - MAyy2 < 0 && MAxx1 - MAxx2 < 0) {
// works in between "180-270"
// a is \ angle
tX = a2X + fD2 * cos(-PI/2+alpha);
tY = a2Y + fD2 * sin(-PI/2+alpha);
} else if (MAyy1 - MAyy2 < 0 && MAxx1 - MAxx2 > 0) {
// works in between 90-180
// a is / angle
tX = a2X + fD2 * cos(PI/2-alpha);
tY = a2Y + fD2 * sin(PI/2-alpha);
} else if (MAyy1 - MAyy2 > 0 && MAxx1 - MAxx2 > 0) {
// works in between 0-90
// a is \ angle
tX = a2X + fD2 * cos(PI/2+alpha);
tY = a2Y + fD2 * sin(PI/2+alpha);
} else if (MAyy1 - MAyy2 > 0 && MAxx1 - MAxx2 < 0) {
// works in between 270-360
// a is / angle
tX = a2X + fD2 * cos(-PI/2-alpha);
tY = a2Y + fD2 * sin(-PI/2-alpha);
}
// final lines
line(MAxx1, MAyy1, tX, tY);
line(MAxx2, MAyy2, tX, tY);
}
}
```