Regards!
UColorTool colors;
float hueOffs;
void initColors() {
colors=new UColorTool();
// start by creating lots of colors
colors.addGradient(5,10,"FF0099","FF0033");
colors.addGradient(5,10,"FFFF00","FF3300");
colors.addGradient(5,10,"00FFFF","00496A");
colors.addGradient(5,10,"293236","00496A");
colors.addGradient(5,10,"166A00","44FC12");
colors.addGradient(5,10,"FFFFFF","CCFFFF");
colors.generateColors(10,40);
// force a limited selection from that large palette
int cc[]=new int[6];//min(colors.n,(int)random(6,20))];
for(int i=1; i<cc.length-1; i++) {
cc[i]=colors.getRandomColor();
// cc[i]=colors.adjustHue(cc[i],hueOffs);
}
cc[0]=color(255);
// set colors to that limited palette
colors.colors=cc;
colors.n=cc.length;
doRecolor=true;
}
// initializes triangle surface in one of two configurations
public void reinit() {
initColors();
f=new ArrayList<Poly>();
((Toggle)gui.cp.controller("doCrack")).setState(false);
// n = # of points around circumference
// vl.length = # of "rings"
float n=(int)random(3,9)*6;
UVertexList vl[]=UVertexList.getVertexLists((int)random(3,9));
// radial offset controlled by a sin() function
float sineOffs=random(0.05,0.1)*(float)height;
// # of phases the sin() offset goes through
float sinePhases=(int)random(2,10);
// n+=sinePhases*3;
// calculate concentric vertex lists, with a sin() offset
for(int i=0; i<n; i++) {
for(int j=0; j<vl.length; j++) {
float a=map(i,0,n-1,0,TWO_PI);
float h=map(j,0,vl.length-1,0.2,1);
h*=height;
h+=(sin(a*sinePhases)*sineOffs);
vl[j].add(new UVec3(h,0,0).
rotate(a).add(width/2,height/2));
if(i==n-1) vl[j].close();
}
}
UGeometry geo=new UGeometry();
geo.noDuplicates();
// center triangle fan
geo.triangleFan(vl[0],true,false);
// quadstrip all the rings
geo.quadStrip(vl);
// create Poly instances from all the resulting UFaces
for(int i=0; i<geo.faceNum; i++) {
UVec3 vv[]=geo.face[i].v;
f.add(new Poly(vv[0],vv[1],vv[2]));
}
}
void crack() {
ArrayList<Poly> ff=new ArrayList<Poly>();
Poly pp;
randomCrack=
((Toggle)gui.cp.controller("randomCrack")).getState();
if(randomCrack) {
int id=(int)(sq(random(1))*(float)f.size());
if(random(100)>60) id=(int)random(f.size()/4);
pp=f.get(id);
}
else // crack in sequence, oldest first
pp=f.get(0);
// subdivide triangle to produce new triangles
Poly p[]=pp.subdivide();
// remove old triangle from arraylist
f.remove(pp);
// add the new triangles to arraylist
for (int i=0; i<p.length; i++) {
UVec3 pv[]=p[i].v;
int outCnt=0;
// check if all three vertices are outside canvas
for(int j=0; j<3; j++)
if((pv[j].x<-50 || pv[j].x>width+50)
|| (pv[j].y<-50 || pv[j].y>height+50)) outCnt++;
if(outCnt<3) f.add(p[i]);
else println("Poly rejected: "+UUtil.toString(pv));
}
}
class Poly {
UVec3 v[];
int col;
Poly(UVec3 v1, UVec3 v2, UVec3 v3) {
v=new UVec3[3];
v[0]=v1;
v[1]=v2;
v[2]=v3;
initColors();
}
public void initColors() {
col=colors.getRandomColor();
// if(random(100)>75)
col=colors.adjustBrightness(col,
(random(100)>66 ? random(0.5,0.8) : random(1.5,2)));
}
public void draw() {
fill(col);
if(brightness(col)<100) stroke(255,200);
else stroke(0,200);
noStroke();
beginShape(TRIANGLES);
vertex(v[0].x, v[0].y);
vertex(v[1].x, v[1].y);
vertex(v[2].x, v[2].y);
endShape();
}
// calculate random point in triangle, tending towards the
// center of the triangle surface
public UVec3 calcRandomPoint() {
UVec3 vv=UVec3.interpolate(v[1], v[2], UUtil.rnd.random(0.33f, 0.66f));
vv=UVec3.interpolate(v[0], vv, UUtil.rnd.random(0.33f, 0.66f));
return vv;
}
// subdivide Poly by calculating a random point in the triangle
// face and using it to produce three new Poly instances
public Poly[] subdivide() {
UVec3 vv,vv2,vv3;
Poly p[];
// random center point
if(subdiv==0) {
p=new Poly[3];
vv=calcRandomPoint();
p[0]=new Poly(v[0], vv, v[1]);
p[1]=new Poly(v[1], v[2], vv);
p[2]=new Poly(v[2], v[0], vv);
return p;
}
// mid-edge subdivision rule
if(subdiv==1) {
p=new Poly[4];
int id=0;
float randOffs=0.1;
vv=UVec3.interpolate(v[id],v[((id++)+1)%3],
random(-1,1)*randOffs+0.5); // mid-point offset
vv2=UVec3.interpolate(v[id],v[((id++)+1)%3],
random(-1,1)*randOffs+0.5); // mid-point offset
vv3=UVec3.interpolate(v[id],v[(id+1)%3],
random(-1,1)*randOffs+0.5); // mid-point offset
p[0]=new Poly(v[0], vv, vv3);
p[1]=new Poly(vv,v[1], vv2);
p[2]=new Poly(v[2], vv2, vv3);
p[3]=new Poly(vv, vv2, vv3);
return p;
}
// halving strategy
int id=(int)random(3);
vv=UVec3.interpolate(v[id],v[(id+1)%3],0.5);
p=new Poly[2];
p[0]=new Poly(v[id], vv, v[(id+2)%3]);
p[1]=new Poly(v[(id+1)%3], v[(id+2)%3], vv);
// p[2]=new Poly(v[2], v[0], vv);
return p;
}
}
import processing.pdf.*;
/**
* UCracking01.pde - Marius Watz, 2012
* http://workshop.evolutionzone.com
*
* Cracking (aka subdivision) of triangular geometry. Uses
* ArrayList to efficiently handle storage of new triangles
* while removing old ones after they've been subdivided.
*
* The starting shape is built using a UGeometry instance
* built from an array of vertex lists. UFace instances are
* extracted and used to initialize the custom Poly class,
* allowing us to construct a complex starting form.
*/
import controlP5.*;
import java.util.ArrayList;
import unlekker.modelbuilder.*;
import unlekker.util.*;
public ArrayList<Poly> f;
public boolean doCrack,doSave;
public boolean randomCrack=false,doRecolor;
public USimpleGUI gui;
String filename;
public int subdiv=0;
public void setup() {
size(600, 600,P2D);
gui=new USimpleGUI(this);
gui.addButton("reinit");
gui.addRadioButton("subdivType",
new String[] {"type 1","type 2","type 3"},100);
gui.addButton("initColors");
gui.addToggle("doCrack",doCrack); // toggle continuous cracking
gui.addToggle("randomCrack",randomCrack); // crack at random?
reinit();
smooth();
}
public void draw() {
background(0);
if (doCrack)
// crack 20 times if randomCrac==false, 40 times if true
for(int i=0; i<20+(randomCrack ? 20 : 0); i++) crack();
// handle recoloring
if(doRecolor && f!=null) {
for(Poly pp:f) pp.initColors();
doRecolor=false;
}
for (Poly pp:f) pp.draw();
if(doSave) {
saveFrame(
UIO.getIncrementalFilename(
this.getClass().getSimpleName()+" ###.png",
sketchPath));
doSave=false;
}
else
gui.draw();
}
void controlEvent(ControlEvent ev) {
// handle ControlGroup event for the radio buttons
if(ev.isGroup()) {
for(int i=0;i<ev.group().arrayValue().length;i++) {
if(ev.group().arrayValue()[i]>0) subdiv=i;
}
}
}
public void keyPressed() {
// CTRL-A == initColors();
if(keyEvent.isControlDown() && keyCode==KeyEvent.VK_A) initColors();
if(!online && key=='s') doSave=true;
}
public void mousePressed() {
if(!gui.isMouseOver()) crack();
}
Cracking (aka subdivision) of triangular geometry. Uses ArrayList to efficiently handle storage of new triangles while removing old ones after they've been subdivided.
This version builds starting shape using a UGeometry instance built from an array of vertex lists. UFace instances are extracted and used to initialize the custom Poly class, allowing us to construct a complex starting form.
Other subdivision implementations:
http://ncodescripting.blogspot.be/2010/06/subdivision.html
http://formativecomplexity.blogspot.com/2012/02/aranda-lasch-seattle-public-library.html