Looking for some help with a pattern generator build using Processing (Processing.org).
I'm trying to generate a pattern with the use of processing like this:
- - - - - - - - - - - - - - - - - - - - - - - - -
Currently I got so far that it creates a pattern like this:
- - - - - - - - - - - - - - - - - - - - - - - - -
This is my code in the build.pde file:
import processing.pdf.*;
HDrawablePool pool;
HColorPool colors;
void setup(){
size(1000,1000);
H.init(this).background(#ffffff);
smooth();
colors = new HColorPool(#111111);
pool = new HDrawablePool(1000);
pool.autoAddToStage()
.add(new HShape("cv_bitter01.svg"))
.add(new HShape("cv_bitter02.svg"))
.add(new HShape("cv_bitter03.svg"))
.add(new HShape("cv_bitter04.svg"))
.add(new HShape("cv_bitter05.svg"))
.add(new HShape("cv_bitter06.svg"))
.add(new HShape("cv_bitter07.svg"))
.add(new HShape("cv_bitter08.svg"))
.add(new HShape("cv_bitter09.svg"))
.add(new HShape("cv_bitter10.svg"))
.layout(
new HGridLayout()
.startX(25)
.startY(25)
.spacing(40,40)
.cols(30)
)
.onCreate(
new HCallback() {
public void run(Object obj) {
HShape d = (HShape) obj;
d
.enableStyle(false)
.strokeJoin(ROUND)
.strokeCap(ROUND)
.strokeWeight(2)
.stroke(#000000)
.rotation( (int)random(-15,15) )
.anchorAt(H.CENTER)
;
d.randomColors(colors.fillOnly());
}
}
)
.requestAll()
;
saveVector();
noLoop();
}
void draw() {
H.drawStage();
}
void saveVector() {
PGraphics tmp = null;
tmp = beginRecord(PDF, "render.pdf");
if (tmp == null) {
H.drawStage();
} else {
H.stage().paintAll(tmp, false, 1); // PGraphics, uses3D, alpha
}
endRecord();
}
HGridLayout
is a rectangular grid.
For the pattern you're after use HHexLayout
instead.
Have a look at the following HHexLayout examples:
Update You can get away with a Hex layout, however, after having a closer look, there will be elements drawn that are offscreen.
The pattern is also known as a diagrid and you could generate it in multiple ways. One basic method is keep offset every other row on the x axis. You can check if a row is even or odd using the remainder of the integer division operation using the modulo(%) operator:
for(int i = 0; i < 10; i++){
if(i % 2 == 0){
println(i, "is even)");
}else{
println(i, "is odd)");
}
}
If you look at the HGridLayout source code you'll notice how the x,y positions are calculated based on the row, column index.
You can make a copy of this class, name it say HDiagrid and on top of the same grid behaviour, add an extra variable to keep track of the extra offset on the x axis to be applied ever other row. In your text annotion the offset is applied to odd rows, so use row % 2 == 1
to check if the current position to calculate is on an odd row, therefore the diagonal grid x offset should be applied.
Here's a basic example, remixing Hype's HGridLayout_001:
import hype.*;
import hype.extended.layout.HGridLayout;
HDrawablePool pool;
void setup() {
size(640,640);
H.init(this).background(#242424);
pool = new HDrawablePool(192);
pool.autoAddToStage()
.add(new HRect(25).rounding(4))
.layout(
new HDiagridLayout()
//new HGridLayout()
.startX(28)
.startY(21)
.spacing(26 * 3, 26)
.cols(8)
)
.onCreate(
new HCallback() {
public void run(Object obj) {
HDrawable d = (HDrawable) obj;
d.noStroke().fill(#ECECEC).anchorAt(H.CENTER);
}
}
)
.requestAll()
;
H.drawStage();
noLoop();
}
void draw() {
}
import hype.HDrawable;
import hype.interfaces.HLayout;
import processing.core.PVector;
// a modified copy of https://github.com/hype/HYPE_Processing/blob/master/src/main/java/hype/extended/layout/HGridLayout.java
public class HDiagridLayout implements HLayout {
private int currentIndex, numCols, numRows;
private float startX, startY, startZ, xSpace, ySpace, zSpace;
// extra property to for diagonal grid horizontal offset
private float diagridOffset;
public HDiagridLayout() {
xSpace = ySpace = zSpace = numCols = 16;
// update horizontal offset
diagridOffset = xSpace * 0.5;
numRows = 0;
}
public HDiagridLayout(int numOfColumns) {
this();
numCols = numOfColumns;
}
public HDiagridLayout(int numOfColumns, int numOfRows) {
this();
numCols = numOfColumns;
numRows = numOfRows;
}
public HDiagridLayout currentIndex(int i) {
currentIndex = i;
return this;
}
public int currentIndex() {
return currentIndex;
}
public HDiagridLayout resetIndex() {
currentIndex = 0;
return this;
}
public HDiagridLayout cols(int numOfColumns) {
numCols = numOfColumns;
return this;
}
public int cols() {
return numCols;
}
public HDiagridLayout rows(int numOfRows) {
numRows = numOfRows;
return this;
}
public int rows() {
return numRows;
}
public PVector startLoc() {
return new PVector(startX, startY, startZ);
}
public HDiagridLayout startLoc(float x, float y) {
startX = x;
startY = y;
startZ = 0;
return this;
}
public HDiagridLayout startLoc(float x, float y, float z) {
startX = x;
startY = y;
startZ = z;
return this;
}
public float startX() {
return startX;
}
public HDiagridLayout startX(float x) {
startX = x;
return this;
}
public float startY() {
return startY;
}
public HDiagridLayout startY(float y) {
startY = y;
return this;
}
public float startZ() {
return startZ;
}
public HDiagridLayout startZ(float z) {
startZ = z;
return this;
}
public PVector spacing() {
return new PVector(xSpace, ySpace, zSpace);
}
public HDiagridLayout spacing(float xSpacing, float ySpacing) {
xSpace = xSpacing;
ySpace = ySpacing;
// update horizontal offset
diagridOffset = xSpace * 0.5;
return this;
}
public HDiagridLayout spacing(float xSpacing, float ySpacing, float zSpacing) {
xSpace = xSpacing;
ySpace = ySpacing;
zSpace = zSpacing;
// update horizontal offset
diagridOffset = xSpace * 0.5;
return this;
}
public float spacingX() {
return xSpace;
}
public HDiagridLayout spacingX(float xSpacing) {
xSpace = xSpacing;
// update horizontal offset
diagridOffset = xSpace * 0.5;
return this;
}
public float spacingY() {
return ySpace;
}
public HDiagridLayout spacingY(float ySpacing) {
ySpace = ySpacing;
return this;
}
public float spacingZ() {
return zSpace;
}
public HDiagridLayout spacingZ(float zSpacing) {
zSpace = zSpacing;
return this;
}
@Override
public PVector getNextPoint() {
int layer = 0;
int row = 0;
int col = currentIndex % numCols;
if (numRows > 0) {
layer = (int) Math.floor( currentIndex / (numCols * numRows) );
row = (int) Math.floor(currentIndex / numCols) - (layer * numRows);
} else {
row = (int) Math.floor(currentIndex / numCols);
}
++currentIndex;
// every other row the x value will be offset by an amount
// on even rows it's 9
float xOffset = 0;
// if the row is odd (remainder of integer division by 2 is 1) (see % operator reference)
if(row % 2 == 1){
// apply the diagonal grid offset
xOffset = diagridOffset;
}
// add xOffset (be it 0 on even rows or not
if (numRows > 0) {
return new PVector(col* xSpace + startX + xOffset, row* ySpace + startY, layer* zSpace + startZ);
} else {
return new PVector(col* xSpace + startX + xOffset, row* ySpace + startY);
}
}
@Override
public void applyTo(HDrawable target) {
target.loc(getNextPoint());
}
}
Which produces this:
Notice in the example above the diagridOffset
is half of spacingX
.
This is just an example: it can be another proportion or it can even be independent of spacingX
. Additionally you can add getter and setter methods (similar to public float spacingX()
and public HDiagridLayout spacingX(float xSpacing)
for example).
Have fun!