Store Item color value for every pixel p5js - p5.js

I made a grid where i can draw every pixel using the get and store function
and now I want to store also the color value every time I change the color from the color picker. Right now all the cells on the grid are affected when I choose a color instead of staying in e.g. red when I choose red and stay red when I choose green.
Below is the code:
let sizewidth = 17
let sizeheight = 17
function setup() {
createCanvas(sizewidth*30, sizeheight*30);
col = createColorPicker('#000000');
}
function draw() {
background(255);
for(y = 0; y < sizeheight; y++){
for(x = 0; x < sizewidth; x++){
if(getItem(x + ":" + y) == null){
storeItem(x + ":" + y, false)
}
if(getItem(x + ":" + y) == true){
fill(col.color());
}
rect(x*30, y*30, 30, 30)
noFill()
}
}
}
function mouseClicked(){
for(y = 0; y < sizeheight; y++){
for(x = 0; x < sizewidth; x++){
if(mouseX < x*30+30 && mouseX > x*30 && mouseY < y*30+30 && mouseY > y*30){
storeItem(x + ":" + y, true)
}
}
}
}
function keyTyped(){
if(key == "c"){
clearStorage()
}
}

I think that you can store the color data instead of boolean value, like this:
let sizewidth = 17
let sizeheight = 17
function setup() {
clearStorage() // clearing the previous boolean data (can be deleted later)
createCanvas(sizewidth*30, sizeheight*30);
col = createColorPicker('#000000');
}
function draw() {
background(255);
for(y = 0; y < sizeheight; y++){
for(x = 0; x < sizewidth; x++){
if(getItem(x + ":" + y) == null){
storeItem(x + ":" + y, [255,255,255]) // filling all white
}
else {
let c = getItem(x + ":" + y); // getting color
fill(c[0],c[1],c[2]); // fill cell with the color
}
rect(x*30, y*30, 30, 30)
noFill()
}
}
}
function mouseClicked(){
for(y = 0; y < sizeheight; y++){
for(x = 0; x < sizewidth; x++){
if(mouseX < x*30+30 && mouseX > x*30 && mouseY < y*30+30 && mouseY > y*30){
let c = col.color();
storeItem(x + ":" + y, [red(c),green(c),blue(c)]); // storing the color
}
}
}
}
function keyTyped(){
if(key == "c"){
clearStorage()
}
}

Related

processing error (It looks like you're mixing "active" and "static" modes.)

It looks like you're mixing "active" and "static" modes. I want to play two figures different direction. I am a beginner and need help in understanding what to do wiht the error.
int x,y;
int diam;
int xdir;
int z,r;
int zdir;
int extent;
void setup(){
size(600, 400);
x = 300;
y = 100;
diam = 30;
xdir = +4;
fill(#000000);
z = 300;
r = 300;
zdir = -4;
extent = 30;
}
void draw(){
background(200);
ellipse(x, y, diam, diam);
x = x + xdir;
if (x + diam/2 > 600){
xdir = xdir * -1;
fill(#e81919);
}
else if (x - diam/2 < 0 ){
xdir = xdir * -1;
fill(#00f22e);
}
}
square (z, r, extent);
z = z + zdir;
if (z + 30 > 600 || z - 30 < 0){
zdir = zdir * -1;
fill(#00f22e);
}
}
You've got an extra curly brace after else if (){}. Should look like this:
void draw() {
background(200);
ellipse(x, y, diam, diam);
x = x + xdir;
if (x + diam/2 > 600) {
xdir = xdir * -1;
fill(#e81919);
} else if (x - diam/2 < 0 ) {
xdir = xdir * -1;
fill(#00f22e);
}
square (z, r, extent);
z = z + zdir;
if (z + 30 > 600 || z - 30 < 0) {
zdir = zdir * -1;
fill(#00f22e);
}
}

How does recursive division to generate maze work? [duplicate]

I am currently developing a random maze generator that stores the maze in a 2-dimensional array called grid. This will then be used later on to generate a real 3D maze that the user can then walk through.
After doing some research, I attempted to create this maze generator using the recursive division algorithm, however due to the nature of the format of the maze, this isn't really working for me.
From what I understand, the recursive division method does not treat walls as cells.
For instance, my grid would look like this:
a b c d e f g h
1 - - - - - - - -
2 | | | | |
3 | | |
4 | - - | - |
5 | | | |
6 | - | - |
7 x |
8 - - - - - - - -
The point that I'm trying to get across here is that the grid I am trying to create will be represented something like this:
w w w w w w w w
w w w w w
w w w
w w w w w w
w w w w
w w w w w
g w
w w w w w w w w
Where 'w' is a wall and 'g' is the entrance/exit. So walls are placed into the grid, e.g. grid[1][2] == 'w'
The problem with the recursive division algorithm is that walls are not treated as members of the cell. All of the 'cells' would essentially contain whitespace and the walls would be placed around them.
So when I tried to implement this algorithm in my situation, I ended up with a result like this: (the black squares are walls, the white squares are empty, and the red square is the entrance)
My JSFiddle is located here.
Essentially the user will start at the red square and have to go through the maze and find keys that will open the door (which is the red square) to escape, so all of the whitespace in the maze would have to be accessible.
Does anyone have any ideas on how I can rewrite this algorithm to make sure that there is always a path from the red square to any other space in the maze? Ideally, the path would never be more than one square wide.
Code:
var grid;
function generate(dimensions, numDoors) {
//numDoors is unused right now
grid = new Array();
for (var i = 0; i < dimensions; i++) {
grid[i] = new Array();
for (var j = 0; j < dimensions; j++) {
grid[i][j] = "";
}
}
addOuterWalls();
var ent = addEntrance();
addInnerWalls(true, 1, grid.length - 2, 1, grid.length - 2, ent);
}
function addOuterWalls() {
for (var i = 0; i < grid.length; i++) {
if (i == 0 || i == (grid.length - 1)) {
for (var j = 0; j < grid.length; j++) {
grid[i][j] = "w";
}
} else {
grid[i][0] = "w";
grid[i][grid.length - 1] = "w";
}
}
}
function addEntrance() {
var x = randomNumber(1, grid.length - 1);
grid[grid.length - 1][x] = "g";
return x;
}
function addInnerWalls(h, minX, maxX, minY, maxY, gate) {
if (h) {
if (maxX - minX < 2) {
return;
}
var y = randomNumber(minY, maxY);
addHWall(minX, maxX, y);
addInnerWalls(!h, minX, maxX, minY, y-1, gate);
addInnerWalls(!h, minX, maxX, y + 1, maxY, gate);
} else {
if (maxY - minY < 2) {
return;
}
var x = randomNumber(minX, maxX);
addVWall(minY, maxY, x);
addInnerWalls(!h, minX, x-1, minY, maxY, gate);
addInnerWalls(!h, x + 1, maxX, minY, maxY, gate);
}
}
function addHWall(minX, maxX, y) {
var hole = randomNumber(minX, maxX);
for (var i = minX; i <= maxX; i++) {
if (i == hole) grid[y][i] = "";
else grid[y][i] = "w";
}
}
function addVWall(minY, maxY, x) {
var hole = randomNumber(minY, maxY);
for (var i = minY; i <= maxY; i++) {
if (i == hole) grid[i][x] = "";
else grid[i][x] = "w";
}
}
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function display() {
document.getElementById("cnt").innerHTML = "";
for (var i = 0; i < grid.length; i++) {
var output = "<div>";
for (var j = 0; j < grid.length; j++) {
output += "<b " + grid[i][j] + "></b>";
}
output += "</div>";
document.getElementById("cnt").innerHTML += output;
}
}
generate(30, 1, 1);
display();
Put walls only in even cells, and doors in odd cells, and make "dimensions" odd.
http://jsfiddle.net/tPm3s/1/
Code:
var grid;
function generate(dimensions, numDoors) {
grid = new Array();
for (var i = 0; i < dimensions; i++) {
grid[i] = new Array();
for (var j = 0; j < dimensions; j++) {
grid[i][j] = "";
}
}
addOuterWalls();
var ent = addEntrance();
addInnerWalls(true, 1, grid.length - 2, 1, grid.length - 2, ent);
}
function addOuterWalls() {
for (var i = 0; i < grid.length; i++) {
if (i == 0 || i == (grid.length - 1)) {
for (var j = 0; j < grid.length; j++) {
grid[i][j] = "w";
}
} else {
grid[i][0] = "w";
grid[i][grid.length - 1] = "w";
}
}
}
function addEntrance() {
var x = randomNumber(1, grid.length - 1);
grid[grid.length - 1][x] = "g";
return x;
}
function addInnerWalls(h, minX, maxX, minY, maxY, gate) {
if (h) {
if (maxX - minX < 2) {
return;
}
var y = Math.floor(randomNumber(minY, maxY)/2)*2;
addHWall(minX, maxX, y);
addInnerWalls(!h, minX, maxX, minY, y-1, gate);
addInnerWalls(!h, minX, maxX, y + 1, maxY, gate);
} else {
if (maxY - minY < 2) {
return;
}
var x = Math.floor(randomNumber(minX, maxX)/2)*2;
addVWall(minY, maxY, x);
addInnerWalls(!h, minX, x-1, minY, maxY, gate);
addInnerWalls(!h, x + 1, maxX, minY, maxY, gate);
}
}
function addHWall(minX, maxX, y) {
var hole = Math.floor(randomNumber(minX, maxX)/2)*2+1;
for (var i = minX; i <= maxX; i++) {
if (i == hole) grid[y][i] = "";
else grid[y][i] = "w";
}
}
function addVWall(minY, maxY, x) {
var hole = Math.floor(randomNumber(minY, maxY)/2)*2+1;
for (var i = minY; i <= maxY; i++) {
if (i == hole) grid[i][x] = "";
else grid[i][x] = "w";
}
}
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function display() {
document.getElementById("cnt").innerHTML = "";
for (var i = 0; i < grid.length; i++) {
var output = "<div>";
for (var j = 0; j < grid.length; j++) {
output += "<b " + grid[i][j] + "></b>";
}
output += "</div>";
document.getElementById("cnt").innerHTML += output;
}
}
generate(31, 1, 1);
display();

How to simplify shapes for triangulation with three.js and jsclipper

I try to display geometry which is constructed by constructpath commands like moveto lineto beziercurveto in Three.js.
Therefore I create a THREE.ShapePath(); and execute the command toShapes(isClockwise).
After this I use THREE.ExtrudeBufferGeometry to create the 3D shape.
Unfortunately the shapes are sometimes really complex and are not created correctly which means they are distorted.
Using libtess as triangulation library solves some issues. But I have still distorted geometry.
Now I want to use jsclipper to simplify the shapes prior triangulation.
I modified three.js in such way:
in the method addShape in ExtrudeBufferGeometry I have added:
$.each(vertices, function(index, item) {
vertices[index]['X'] = vertices[index]['x'];
vertices[index]['Y'] = vertices[index]['y'];
delete vertices[index]['x'];
delete vertices[index]['y'];
});
if (holes[0]) {
for (i = 0; i < holes.length; i++ ) {
$.each(holes[i], function(index, item) {
holes[i][index]['X'] = holes[i][index]['x'];
holes[i][index]['Y'] = holes[i][index]['y'];
delete holes[i][index]['x'];
delete holes[i][index]['y'];
});
}
}
var scale = 100;
ClipperLib.JS.ScaleUpPaths([vertices], scale);
if (holes[0]) {
ClipperLib.JS.ScaleUpPaths(holes, scale);
}
vertices = ClipperLib.Clipper.SimplifyPolygons([vertices], ClipperLib.PolyFillType.pftNonZero);
// or ClipperLib.PolyFillType.pftEvenOdd
if (holes[0]) {
holes = ClipperLib.Clipper.SimplifyPolygons(holes, ClipperLib.PolyFillType.pftNonZero);
// or ClipperLib.PolyFillType.pftEvenOdd
}
// var cleandelta = 0.1; // 0.1 should be the appropriate delta in different cases
// vertices = ClipperLib.Clipper.CleanPolygons([vertices], cleandelta * scale);
// if (holes[0]) {
// holes = ClipperLib.Clipper.CleanPolygons(holes, cleandelta * scale);
// }
ClipperLib.JS.ScaleDownPaths(vertices, scale);
if (holes[0]) {
ClipperLib.JS.ScaleDownPaths(holes, scale);
}
for (i = 0; i < vertices.length; i++ ) {
$.each(vertices[i], function(index, item) {
vertices[i][index]['x'] = vertices[i][index]['X'];
vertices[i][index]['y'] = vertices[i][index]['Y'];
delete vertices[i][index]['X'];
delete vertices[i][index]['Y'];
});
}
if (holes[0]) {
for (i = 0; i < holes.length; i++ ) {
$.each(holes[i], function(index, item) {
holes[i][index]['x'] = holes[i][index]['X'];
holes[i][index]['y'] = holes[i][index]['Y'];
delete holes[i][index]['X'];
delete holes[i][index]['Y'];
});
}
}
Now I can see that the vertices are "reduced".
But var faces = ShapeUtils.triangulateShape( vertices, holes ); doesn't generate faces for some examples anymore.
Please can one help how to simplify the shapes correctly?
A bit hard to figure out what the problem is actually. Clipper (also when using SimplifyPolygons or SimplifyPolygon) can only produce weakly-simple polygons, which means that there can be pseudo-duplicate points: although sequential coordinates are quaranteed to be not indentical, some of the next points can share the same coordinate. Also a coordinate can be on the line between two points.
After simplifying (or any other boolean operation) you could make a cleaning step using Offsetting with a small negative value: https://sourceforge.net/p/jsclipper/wiki/documentation/#clipperlibclipperoffsetexecute.
This possibly removes all of the pseudo-duplicate points.
I have made also a float version of Clipper (http://jsclipper.sourceforge.net/6.4.2.2_fpoint/). It is extensively tested, but because Angus Johnson, the author of the original C# Clipper (of which JS-version is ported from), has thought that using floats causes robustness problems although according to my tests the are no such, the original C# float version does not exists. The float version is simpler to use and you can try there a small negative offset: eg. -0.001 or -0.01.
You could also give a try to PolyTree or ExPolygons (https://sourceforge.net/p/jsclipper/wiki/ExPolygons%20and%20PolyTree%206/). ExPolygons can be used to get holes and contours and PolyTree can be used to get the full parent-child-relationship of holes and contours.
The last resort is a broken-pen-nib -function. It detects all pseudo-duplicate points and make a broken-pen-nib -effect to them, so that the result is free of any duplicates. The attached images shows what this effect means using large nib-effect-value to make the effect meaning clearer. Three.js polygon triangulation fails in pseudo duplicate points. There are a discussion https://github.com/mrdoob/three.js/issues/3386 of this subject.
// Make polygons to simple by making "a broken pen tip" effect on each semi-adjacent (duplicate) vertex
// ORIGPOLY can be a contour
// or exPolygon structure
function BreakPenNibs(ORIGPOLY, dist, scale)
{
if (!dist || dist < 0) return;
var sqrt = Math.sqrt;
var allpoints = {}, point = {};
var key = "";
var currX = 0.0,
currY = 0.0;
var prevX = 0.0,
prevY = 0.0;
var nextX = 0.0,
nextY;
var x = 0.0,
y = 0.0,
length = 0.0,
i = 0,
duplcount = 0,
j = 0;
var prev_i = 0,
next_i = 0,
last_i;
var extra_vertices = new Array(100),
moved_vertices = new Array(100);
// Get first all duplicates
var duplicates = new Array(100),
indexi = "",
indexstr = "",
arraystr = "",
polys, outer, holes;
if (ORIGPOLY instanceof Array)
{
outer = ORIGPOLY;
}
else if (ORIGPOLY.outer instanceof Array)
{
outer = ORIGPOLY.outer;
}
else return;
if (ORIGPOLY.holes instanceof Array) holes = ORIGPOLY.holes;
else holes = [];
polys = [outer].concat(holes);
var polys_length = polys.length;
// Get first max lenght of arrays
var max_index_len = 0;
var arr_len;
i = polys_length;
while (i--)
{
arr_len = polys[i].length;
if (arr_len > max_index_len) max_index_len = arr_len;
}
max_index_len = max_index_len.toString().length;
var max_polys_length = polys_length.toString().length;
var poly;
j = polys_length;
var scaling = scale/10;
while (j--)
{
poly = polys[j];
ilen = poly.length;
i = ilen;
while (i--)
{
point = poly[i];
//key = Math.round(point.X) + ":" + Math.round(point.Y);
key = (Math.round(point.X / scaling) * scaling)
+ ":" + (Math.round(point.Y / scaling) * scaling);
indexi = allpoints[key];
if (typeof (indexi) != "undefined")
{
// first found duplicate
duplicates[duplcount] = indexi;
duplcount++;
arraystr = j.toString();
while (arraystr.length < max_polys_length) arraystr = "0" + arraystr;
indexstr = i.toString();
while (indexstr.length < max_index_len) indexstr = "0" + indexstr;
duplicates[duplcount] = arraystr + "." + indexstr;
duplcount++;
}
arraystr = j.toString();
while (arraystr.length < max_polys_length) arraystr = "0" + arraystr;
indexstr = i.toString();
while (indexstr.length < max_index_len) indexstr = "0" + indexstr;
allpoints[key] = arraystr + "." + indexstr;
}
}
if (!duplcount) return;
duplicates.length = duplcount;
duplicates.sort();
//console.log(JSON.stringify(duplicates));
var splitted, poly_index = 0,
nth_dupl = 0;
var prev_poly_index = -1;
poly_index = 0;
for (j = 0; j < duplcount; j++)
{
splitted = duplicates[j].split(".");
poly_index = parseInt(splitted[0], 10);
if (poly_index != prev_poly_index) nth_dupl = 0;
else nth_dupl++;
i = parseInt(splitted[1], 10);
poly = polys[poly_index];
len = poly.length;
if (poly[0].X === poly[len - 1].X &&
poly[0].Y === poly[len - 1].Y)
{
last_i = len - 2;
}
else
{
last_i = len - 1;
}
point = poly[i];
// Calculate "broken pen tip" effect
// for current point by finding
// a coordinate at a distance dist
// along the edge between current and
// previous point
// This is inlined to maximize speed
currX = point.X;
currY = point.Y;
if (i === 0) prev_i = last_i; // last element in array
else prev_i = i - 1;
prevX = poly[prev_i].X;
prevY = poly[prev_i].Y;
x=0;y=0;
if (!point.Collinear)
{
length = sqrt((-currX + prevX) * (-currX + prevX) + (currY - prevY) * (currY - prevY));
//console.log(length);
x = currX - (dist * (currX - prevX)) / length;
y = currY - (dist * (currY - prevY)) / length;
}
// save the found (calculated) point
moved_vertices[j] = {
X: x,
Y: y,
Collinear:point.Collinear,
index: i,
poly_index: poly_index
};
// "broken nib effect" for next point also
if (i == len - 1) next_i = 0;
else next_i = i + 1;
nextX = poly[next_i].X;
nextY = poly[next_i].Y;
x=0;y=0;
if (!point.Collinear)
{
length = sqrt((-currX + nextX) * (-currX + nextX) + (currY - nextY) * (currY - nextY));
x = currX - (dist * (currX - nextX)) / length;
y = currY - (dist * (currY - nextY)) / length;
}
// save the found (calculated) point
extra_vertices[j] = {
X: x,
Y: y,
Collinear:point.Collinear,
index: i + nth_dupl,
poly_index: poly_index
};
prev_poly_index = poly_index;
}
moved_vertices.length = extra_vertices.length = duplcount;
//console.log("MOVED:" + JSON.stringify(moved_vertices));
//console.log("EXTRA:" + JSON.stringify(extra_vertices));
// Update moved coordinates
i = duplcount;
var point2;
while (i--)
{
point = moved_vertices[i];
x = point.X;
y = point.Y;
// Faster than isNaN: http://jsperf.com/isnan-alternatives
if (x != x || x == Infinity || x == -Infinity) continue;
if (y != y || y == Infinity || y == -Infinity) continue;
point2 = polys[point.poly_index][point.index];
point2.X = point.X;
point2.Y = point.Y;
point2.Collinear = point.Collinear;
}
// Add an extra vertex
// This is needed to remain the angle of the next edge
for (i = 0; i < duplcount; i++)
{
point = extra_vertices[i];
x = point.X;
y = point.Y;
// Faster than isNaN: http://jsperf.com/isnan-alternatives
if (x != x || x == Infinity || x == -Infinity) continue;
if (y != y || y == Infinity || y == -Infinity) continue;
polys[point.poly_index].splice(point.index + 1, 0,
{
X: point.X,
Y: point.Y,
Collinear: point.Collinear
});
}
// Remove collinear points
// and for some reason coming
// sequential duplicates
// TODO: check why seq. duplicates becomes
j = polys.length;
var prev_point = null;
while (j--)
{
poly = polys[j];
ilen = poly.length;
i = ilen;
while (i--)
{
point = poly[i];
if(prev_point!=null && point.X == prev_point.X && point.Y == prev_point.Y) poly.splice(i, 1);
else
if(point.Collinear) poly.splice(i, 1);
prev_point = point;
}
}
//console.log(JSON.stringify(polys));
// because original array is modified, no need to return anything
}
var BreakPenNipsOfExPolygons = function (exPolygons, dist, scale)
{
var i = 0,
j = 0,
ilen = exPolygons.length,
jlen = 0;
for (; i < ilen; i++)
{
//if(i!=4) continue;
BreakPenNibs(exPolygons[i], dist, scale);
}
};

How to convert rectangle selection to circle(in grid)

I apply function on small portion of rectangular 2d grid. The code looks like this -
for(int x = startX; x < endX; ++x)
{
for(int y = startY; y < endY; ++y)
{
Function(grid[x+y*stride]);
}
}
Now I want circle shape instead rectangular shape to apply the same function, but forgot how :S please help
Looks like this is enought for me
bool isInside(int circle_x, int circle_y, int rad, int x, int y)
{
// Compare radius of circle with distance of its center from
// given point
if ((x - circle_x)*(x - circle_x) +
(y - circle_y)*(y - circle_y) <= rad*rad)
return true;
else
return false;
}
for(int x = startX; x < endX; ++x)
{
for(int y = startY; y < endY; ++y)
{
if(isInside(centerX,centerY,Radius,x,y))
{
Function(grid[x+y*stride]);
}
}
}

I made a processing program that generates a mandelbrot set but don't know how to effectively implement a zoom method

I'm not sure if it is possible in processing but I would like to be able to zoom in on the fractal without it being extremely laggy and buggy. What I currently have is:
int maxIter = 100;
float zoom = 1;
float x0 = width/2;
float y0 = height/2;
void setup(){
size(500,300);
noStroke();
smooth();
}
void draw(){
translate(x0, y0);
scale(zoom);
for(float Py = 0; Py < height; Py++){
for(float Px = 0; Px < width; Px++){
// scale pixel coordinates to Mandelbrot scale
float w = width;
float h = height;
float xScaled = (Px * (3.5/w)) - 2.5;
float yScaled = (Py * (2/h)) - 1;
float x = 0;
float y = 0;
int iter = 0;
while( x*x + y*y < 2*2 && iter < maxIter){
float tempX = x*x - y*y + xScaled;
y = 2*x*y + yScaled;
x = tempX;
iter += 1;
}
// color pixels
color c;
c = pickColor(iter);
rect(Px, Py,1,1);
fill(c);
}
}
}
// pick color based on time pixel took to escape (number of iterations through loop)
color pickColor(int iters){
color b = color(0,0,0);
if(iters == maxIter) return b;
int l = 1;
color[] colors = new color[maxIter];
for(int i = 0; i < colors.length; i++){
switch(l){
case 1 : colors[i] = color(255,0,0); break;
case 2 : colors[i] = color(0,0,255); break;
case 3 : colors[i] = color(0,255,0); break;
}
if(l == 1 || l == 2) l++;
else if(l == 3) l = 1;
else l--;
}
return colors[iters];
}
// allow zooming in and out
void mouseWheel(MouseEvent event){
float direction = event.getCount();
if(direction < 0) zoom += .02;
if(direction > 0) zoom -= .02;
}
// allow dragging back and forth to change view
void mouseDragged(){
x0+= mouseX-pmouseX;
y0+= mouseY-pmouseY;
}
but it doesn't work very well. It works alright at the size and max iteration I have it set to now (but still not well) and is completely unusable at larger sizes or higher maximum iterations.
The G4P library has an example that does exactly this. Download the library and go to the G4P_MandelBrot example. The example can be found online here.
Hope this helps!

Resources