Skip to content Skip to sidebar Skip to footer

Is It Possible To Make Canvas With Background With Lines Or Canvas That Isn't A Rectangle?

I'm trying to make this one https://massmoca.org/event/walldrawing340/ in Javascript code, using p5.js, but I have no clue how to fill these shapes with lines. Is there any other

Solution 1:

If you don't need actual line coordinates (for plotting for example), I'd just make most out of createGraphics() to easily render shapes and lines into (taking advantage of the fact that get() returns a p5.Image) and p5.Image's mask() function.

Here's a basic example:

functionsetup() {
  createCanvas(600, 300);
  
  let w = 300;
  let h = 150;
  let spacing = 12;
  let strokeWidth = 1;
  
  constBLUE   = color('#005398');
  constYELLOW = color('#f9db44');
  constRED    = color('#dc1215');
  
  bg = getLinesRect(w, h, RED, BLUE, spacing, strokeWidth, true);
  fg = getLinesRect(w, h, RED, YELLOW, spacing, strokeWidth, false);
  mask = getCircleMask(w, h, w * 0.5, h * 0.5, 100, 0);
  
  image(bg, 0, 0);
  image(fg, w, 0);
  // render opaque mask (for visualisation only), mask() requires alpha channelimage(getCircleMask(w, h, w * 0.5, h * 0.5, 100, 255),0, h);
  
  // apply mask
  fg.mask(mask);
  // render bg + masked fgimage(bg, w, h);
  image(fg, w, h);
  
  // text labelsnoStroke();
  fill(255);
  text("bg layer", 9, 12);
  text("fg layer", w + 9, 12);
  text("mask", 9, h + 12);
  text("bg + masked fg", w + 9, h + 12);
}

functiongetLinesRect(w, h, bg, fg, spacing, strokeWidth, isHorizontal){
  let rect = createGraphics(w, h);
  rect.background(bg);
  rect.stroke(fg);
  rect.strokeWeight(strokeWidth);
  
  if(isHorizontal){
    for(let y = 0 ; y < h; y += spacing){
      rect.line(0, y + strokeWidth, w, y + strokeWidth);
    } 
  }else{
    for(let x = 0 ; x < w; x += spacing){
      rect.line(x + strokeWidth, 0, x + strokeWidth, h);
    }
  }
  // convert from p5.Graphics to p5.Imagereturn rect.get();
}

functiongetCircleMask(w, h, cx, cy, cs, opacity){
  let mask = createGraphics(w, h);
  // make background transparent (alpha is used for masking)
  mask.background(0, opacity);
  mask.noStroke();
  mask.fill(255);
  mask.circle(cx, cy, cs);
  // convert p5.Graphics to p5.Imagereturn mask.get();
}
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>

3 coloured composition with horizontal lined background and vertical lined foreground, applying a circular mask to the foreground

You can apply the same logic for the rest of the shapes:

functionsetup() {
  createCanvas(1620, 590);
  
  let compWidth  = 500;
  let compHeight = 250;
  let compSpacing= 30;
  
  let lineWeight = 1.5;
  let lineSpacing = 12;
  
  constBLUE   = color('#005398');
  constYELLOW = color('#f9db44');
  constRED    = color('#dc1215');
  
  // yellow square
  circleMask   = getCircleMask(compWidth, compHeight, compWidth * 0.5, compHeight * 0.5, 210);
  redCircle    = getComposition(compWidth, compHeight, RED, 
                                                    BLUE,
                                                    YELLOW,
                                                    lineSpacing, lineWeight, circleMask);
  
  
  // red box
  boxMask      = getRectMask(compWidth, compHeight, (compWidth - 100) * 0.5, 20, 100, 210);
  redBox       = getComposition(compWidth, compHeight, RED, 
                                                    YELLOW,
                                                    BLUE,
                                                    lineSpacing, lineWeight, boxMask);
  
  
  // yellow square
  squareMask   = getRectMask(compWidth, compHeight, 144, 20, 210, 210);
  yellowSquare = getComposition(compWidth, compHeight, YELLOW, 
                                                    RED,
                                                    BLUE,
                                                    lineSpacing, lineWeight, squareMask);
                                                    
  // yellow trapeze
  trapezeMask   = getQuadMask(compWidth, compHeight, 200, 25, 200 + 115, 25,
                                                     150 + 220, 220, 150, 220);
  yellowTrapeze = getComposition(compWidth, compHeight, YELLOW, 
                                                    BLUE,
                                                    RED,
                                                    lineSpacing, lineWeight, trapezeMask);
                                                    
  // blue triangle
  triangleMask   = getTriangleMask(compWidth, compHeight, compWidth * 0.5, 25,
                                                     150 + 220, 220, 150, 220);
  blueTriangle   = getComposition(compWidth, compHeight, BLUE, 
                                                    YELLOW,
                                                    RED,
                                                    lineSpacing, lineWeight, triangleMask);
                                                    
  // blue parallelogram
  parallelogramMask = getQuadMask(compWidth, compHeight, 200, 25, 200 + 145, 25,
                                                         150 + 145, 220, 150, 220);
  blueParallelogram = getComposition(compWidth, compHeight, BLUE, 
                                                    RED,
                                                    YELLOW,
                                                    lineSpacing, lineWeight, parallelogramMask);
  
  // render compositionsimage(redCircle, compSpacing, compSpacing);
  image(redBox, compSpacing, compSpacing + (compHeight + compSpacing));
  
  
  image(yellowSquare, compSpacing + (compWidth + compSpacing), compSpacing);
  image(yellowTrapeze, compSpacing + (compWidth + compSpacing), compSpacing + (compHeight + compSpacing));
  
  image(blueTriangle, compSpacing + (compWidth + compSpacing) * 2, compSpacing);
  image(blueParallelogram, compSpacing + (compWidth + compSpacing) * 2, compSpacing + (compHeight + compSpacing));
  
}

functiongetComposition(w, h, bgFill, bgStroke, fgStroke, spacing, strokeWidth, mask){
  let comp = createGraphics(w, h);
  
  bg = getLinesRect(w, h, bgFill, bgStroke, spacing, strokeWidth, true);
  fg = getLinesRect(w, h, bgFill, fgStroke, spacing, strokeWidth, false);
  // apply mask
  fg.mask(mask);
  // render to final output
  comp.image(bg, 0, 0);
  comp.image(fg, 0, 0);
  
  return comp;
}

functiongetRectMask(w, h, rx, ry, rw, rh){
  let mask = createGraphics(w, h);
  // make background transparent (alpha is used for masking)
  mask.background(0,0);
  mask.noStroke();
  mask.fill(255);
  mask.rect(rx, ry, rw, rh);
  // convert p5.Graphics to p5.Imagereturn mask.get();
}

functiongetCircleMask(w, h, cx, cy, cs){
  let mask = createGraphics(w, h);
  // make background transparent (alpha is used for masking)
  mask.background(0,0);
  mask.noStroke();
  mask.fill(255);
  mask.circle(cx, cy, cs);
  // convert p5.Graphics to p5.Imagereturn mask.get();
}

functiongetQuadMask(w, h, x1, y1, x2, y2, x3, y3, x4, y4){
  let mask = createGraphics(w, h);
  // make background transparent (alpha is used for masking)
  mask.background(0,0);
  mask.noStroke();
  mask.fill(255);
  mask.quad(x1, y1, x2, y2, x3, y3, x4, y4);
  // convert p5.Graphics to p5.Imagereturn mask.get();
}

functiongetTriangleMask(w, h, x1, y1, x2, y2, x3, y3){
  let mask = createGraphics(w, h);
  // make background transparent (alpha is used for masking)
  mask.background(0,0);
  mask.noStroke();
  mask.fill(255);
  mask.triangle(x1, y1, x2, y2, x3, y3);
  // convert p5.Graphics to p5.Imagereturn mask.get();
}

functiongetLinesRect(w, h, bg, fg, spacing, strokeWidth, isHorizontal){
  let rect = createGraphics(w, h);
  rect.background(bg);
  rect.stroke(fg);
  rect.strokeWeight(strokeWidth);
  
  if(isHorizontal){
    for(let y = 0 ; y < h; y += spacing){
      rect.line(0, y + strokeWidth, w, y + strokeWidth);
    } 
  }else{
    for(let x = 0 ; x < w; x += spacing){
      rect.line(x + strokeWidth, 0, x + strokeWidth, h);
    }
  }
  // convert from p5.Graphics to p5.Imagereturn rect.get();
}
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>

rough reproduction of Soll Lewitt's Wall Drawing 340

Probably both rectangles and the triangle could've been drawn using getQuadMask() making good use of coordinates.

Note that I've just eye balled the shapes a bit so they're not going to be perfect, but it should be easy to tweak. Bare in mind the placement of the mask will have an effect of on how the vertical lines will align.

There are probably other ways to get the same visual effect. For example, using texture() and textureWrap(REPEAT) with beginShape()/endShape(), using pixels for each line and checking intersections before changing direction and colours, etc.

In terms of generating lines for plotting I would start with horizontal lines, doing line to convex polygon intersection to determine where to stop the horizontal lines and start vertical lines. @AgniusVasiliauskas's answer(+1) is good for that approach.

Freya Holmér has a pretty nice visual explanation for the test.

Solution 2:

You need linear algebra stuff, basically noticing how vertical line starting/ending Y coordinate changes in relation to line's X coordinate. And of course a lot of experimenting until you get something usable. Something like :

var w = 600
    h = 600
    sp = 15var slides = [fcircle, fsquare, ftriangle, ftrapezoid, fparallelogram];

var active = 0;

var ms;

functionblines(){
  stroke(0);
  for (var i=0; i < h; i+=sp) {
    line(0,i,w,i);
  }
}

functionvertlines(calcline) {
   for (var x=w/2-w/4+sp; x < w/2+w/4; x+=sp) {
       var pnts = calcline(x);
       line(pnts[0],pnts[1],pnts[2],pnts[3]);
   }
}

functionfcircle() {
   // cut backgroundnoStroke();
   circle(w/2, h/2, w/2);
   stroke('red');
   // draw figure lineslet calc = function (x){
      var sx = x-w/2;
      var sy = h/2;
      var ey = h/2;
      sy += 137*sin(2.5+x/135);
      ey -= 137*sin(2.5+x/135);
      return [x,sy,x,ey];
   }
   vertlines(calc);
}

functionfsquare() {
   // cut backgroundnoStroke();
   quad(w/2-w/4, h/2-h/4, w/2+w/4, h/2-h/4,
        w/2+w/4, h/2+h/4, w/2-w/4, h/2+h/4);  
   stroke('red');
   // draw figure lineslet calc = function (x){
      return [x,h/2-h/4,x,h/2+h/4];
   }
   vertlines(calc);
}

functionftriangle() {
   // cut backgroundnoStroke();
   quad(w/2, h/2-h/4, w/2+w/4, h/2+h/4,
        w/2-w/4, h/2+h/4, w/2, h/2-h/4);  
  stroke('red');
   // draw figure lineslet calc = function (x){
      var inpx = x > w/2 ? w-x : x;
      var ys = h/2+h/4;
      ys += -(0.3*inpx*log(inpx)-220);
      return [x,ys,x,h/2+h/4];
   }
   vertlines(calc);
}

functionftrapezoid() {
   // cut backgroundnoStroke();
   quad(w/2-w/10, h/2-h/4, w/2+w/10, h/2-h/4,
        w/2+w/4, h/2+h/4, w/2-w/4, h/2+h/4);  
   stroke('red');
   // draw figure lineslet calc = function (x){
      var inpx = x > w/2 ? w-x : x;
      var ys = h/2+h/4;
      ys += -(0.55*inpx*log(inpx)-420);
      if (x >= w/2-w/10 && x <= w/2+w/10) {
         ys=h/2-h/4;
      }
      return [x,ys,x,h/2+h/4];
   }
   vertlines(calc);
}

functionfparallelogram() {
   // cut backgroundnoStroke();
   quad(w/2-w/10, h/2-h/4, w/2+w/7, h/2-h/4,
        w/2, h/2+h/4, w/2-w/4, h/2+h/4);  
   stroke('red');
   // draw figure lineslet calc = function (x){
      // guard conditionif (x > w/2+w/7)
         return [0,0,0,0];
      var inpx = x > w/2 ? w-x : x;
      var ys = h/2+h/4;
      ys += -(0.55*inpx*log(inpx)-420);
      var ye=h/2+h/4if (x >= w/2-w/10) {
         ys=h/2-h/4;
      }
      if (x > w/2) {
         ye = h/2+h/4;
         ye += 0.50*inpx*log(inpx)-870;
      }
      return [x,ys,x,ye];
   }
   vertlines(calc);
}

functionsetup() {
  ms = millis();
  createCanvas(w, h);
}

functiondraw() {
   if (millis() - ms > 2000) {
      ms = millis();
      active++;
      if (active > slides.length-1)
         active = 0;
   }
   background('#D6EAF8');
   fill('#D6EAF8');
   blines();
   slides[active]();
}

Slideshow DEMO

Solution 3:

I have a way to do some of the shapes, but I am not sure about others. One way you could do it is if you know where every point on the outline of the shape is, you could just use a for loop and connect every other point from the top and bottom using the line or rect function. This would be relatively easy with shapes like squares and parallelograms, but I am not sure what functions could be used to get this for the points of a circle or trapezoid.

See more here: https://www.openprocessing.org/sketch/745383

Post a Comment for "Is It Possible To Make Canvas With Background With Lines Or Canvas That Isn't A Rectangle?"