Boolean operation in polygons

Hi, wondering if anyone came across a solution to merge/union/intersect polygons?
Not just drawing them with the same fill color, but actually creating a new shape which is a fusion of other arbitrary shapes.
I can do it in Illustrator or Sketch, but how would I go about doing it dynamically in p5?

Thanks!

2 Likes

Welcome to forum.

At least some of them can be achieved with blend modes https://processing.org/reference/blendMode_.html

1 Like

This is a great question! I miss this on core Processing for PShapes very much…

In Processing Java/Python modes you can have it using a library like Geomerative (installing it from the Add Library… panel in the IDE).
But it can be quite some trouble (drawing with its primitives, or importing SVG).

UPDATE: This was originally posted in the Processing category, now it was moved to p5.js.

From the libraries example:

import geomerative.*;

RShape shp1;
RShape shp2;
RShape shp3;
RShape cursorShape;

void setup()
{
  size(400, 400);
  smooth();

  RG.init(this);

  shp1 = RShape.createRing(0, 0, 120, 50);
  shp2 = RShape.createStar(0, 0, 100.0, 80.0, 20);
}

void draw()
{
  background(255);    
  translate(width/2,height/2);

  cursorShape = new RShape(shp2);
  cursorShape.translate(mouseX - width/2, mouseY - height/2);
  
  // Only intersection() does not work for shapes with more than one path
  shp3 = RG.diff( shp1, cursorShape );
  
  strokeWeight( 3 );

  if(mousePressed){
    fill( 220 , 0 , 0 , 30 );
    stroke( 120 , 0 , 0 );
    RG.shape(cursorShape);

    fill( 0 , 220 , 0 , 30 );
    stroke( 0 , 120 , 0 );
    RG.shape(shp1);
  }
  else{
    fill( 220 );
    stroke( 120 );
    RG.shape(shp3);
  }
}

geomerative

1 Like

Interesting answers, I’ve tried both in Processing. Also in Processing createShape has a GROUP which will do it, but the question says “in P5”, are they available, how?

2 Likes

This is a problem of term ambiguity :slight_smile: “P5” used to mean Processing.
Do you mean P5js?

The closest I could find was this: http://haptic-data.com/toxiclibsjs/examples/polygon-clipping-p5

GROUP as far as I understand from reading https://processing.org/reference/createShape_.html does not have any polygon operations :frowning:

@SomeOne: Thanks. Blendmodes are done on the pixel level. I’m looking to build a new shape (eg that I can apply a stroke without the inner parts of the original shapes)

@villares thanks, but I’m looking for a P5.js solution if possible (I’m perhaps in the wrong forum for this?). The toxiclib solution can only do clipping, but I’m actually more interested in a union.

2 Likes

Cheers @mmatty !

We can ask @jeremydouglass to move this to the P5.js category so it will have more views by P5.js savants :smiley:

Maybe someone can adapt this for use with P5: https://github.com/velipso/polybooljs

Maybe someone would like to port from Java or from Python this:

UPDATE: Let’s say I was too optimistic. The code I have chosen to fork doesn’t quite work :frowning: I have to do more research.

1 Like

I’m also interested in being able to intersect polygons using p5js.

My best try was using mask().

https://editor.p5js.org/gvd/sketches/mEl8CBsM3

1 Like

does this have to be shader/openGl based or are other approaches acceptable too?

I was able to use g.js to do boolean operations on vector shapes.

Not sure about the implication of mixing these two libraries in the long term or in more complex situations. The documentation of g.js doesn’t seem to mention creating custom Path objects, but it looks like a typical Canvas/SVG way of drawing paths.

Another library that I know has a strong Vector capability is paper.js

http://paperjs.org/examples/path-intersections/

include the script in index.html

<script src="https://cdn.rawgit.com/nodebox/g.js/master/dist/g.min.js"></script>

sketch.js below.

// import g.js in index.html

function setup() {
  createCanvas(400, 400);
  background(220)

  let pathA = new g.Path()
  pathA.moveTo(20, 20)
  pathA.lineTo(80, 20)
  pathA.lineTo(100, 80)
  pathA.lineTo(60, 80)
  pathA.lineTo(40, 120)
  pathA.closePath()
  pathA.fill = 'yellow'
  pathA.draw(drawingContext)

  let pathB = new g.Path()
  pathB.moveTo(40, 40)
  pathB.lineTo(100, 40)
  pathB.lineTo(140, 60)
  pathB.lineTo(10, 60)
  pathB.closePath()
  pathB.fill = 'orange'
  pathB.draw(drawingContext)

  push()
  translate(150, 0)
  let pathC = g.compound(pathA, pathB, 'union')
  pathC.fill = 'white'
  pathC.stroke = 'black'
  pathC.draw(drawingContext)
  pop()

  push()
  translate(0, 150)
  let pathD = g.compound(pathA, pathB, 'difference')
  pathD.fill = 'white'
  pathD.stroke = 'black'
  pathD.draw(drawingContext)
  pop()

  push()
  translate(150, 150)
  let pathE = g.compound(pathA, pathB, 'intersection')
  pathE.fill = 'white'
  pathE.stroke = 'black'
  pathE.draw(drawingContext)
  pop()
}

Here is the online version of the sketch above:

3 Likes

Woderful!!! Thank you @ErraticGenerator !

Could you use contour for this? I have not tried it but it might work.

https://p5js.org/reference/#/p5/beginContour

Hi there! Thanks, @ErraticGenerator, this is the solution I was looking for.

Many people here propose: “Why don’t use blend mode, masks etc.?” As @mmatty said, this is pixel solutions, but often you need vector graphics, for laser cutting, in my case.

I’m totally surprised that nor Java processing neither p5js do not have built-in support for boolean operations. It’s a classic feature that can be found in any vector graphical editor.

UPD: this solution also works with p5.js-svg, great.

2 Likes

You can try my js/wasm library iOverlay
I must be super fast and stable because it was a main goal in it implementation.

I also wrote a nice article about boolean operations that can be interesting for you.

2 Likes

wow thanks! Looks like impressive work.
3 years later but never tool later I guess