2
votes

I am trying to do a theoretically simple effect. For example, I have two white circles bouncing around the window. When they intersect, I want the parts of the circle which are intersecting to be black while the rest of the circles remain white, like this:

two intersecting disks, with intersection being black and everything else being white

Is there a way to do this?

So far I have this:

for(int i = 0; i < balls.length; i++)
{
    balls[i].move();
    for(int j = 0; j < balls.length; j++)
    {
        if(i != j && balls[i].intersect(balls[j]) && !changed[i] && !changed[j])
        {
            balls[j].swapColor();
            changed[j] = true;
        }
        else
            changed[j] = false;
    }
    balls[i].display();
}

but it turns the circles entirely to black when they intersect, whereas I only want the intersection itself to change.


edit: I tried using blend() with two 200x200 pngs, magenta and red to better see the blending work. The blend() parameters don't seem to help with positioning the circles correctly, however.

void setup() {
  size(300, 300);
  background(255);
}

void draw() {  
  PImage img = loadImage("circle.png");
  PImage img2 = loadImage("circle2.png");

  img.blend(img2,0,0,200,200,10,10,200,200,DIFFERENCE);
  image(img,0,0);
  image(img2,50,50);
}

gives me this:

two circles overlapping in Processing

5
Processing which is Java-basedel.steve.o
Java and JavaScript are totally different languages. I think you're talking about JavaScript, not Java.Pointy
Are you sure you mean Java? Can you show what you've tried? This question is very incomplete.Hovercraft Full Of Eels
+1 to fight the downvotes by people who seemingly can't be bothered to find out what Processing is . . .ruakh
another +1 from me as well :) For those unfamiliar with Processing check the tag or in short: a minimal IDE+"language" which originally is a Java library that wraps a lot of handy media related functionalities. There's also a JavaScript port called Processing.js. With the latest Processing IDE you can swap "Modes" meaning you can either publish: for desktops: (Java application or applet), for the browser(JavaScript), for Android(more Java :))George Profenza

5 Answers

3
votes

Here give this a try. It's the blend approach using two PGraphics, instead of PImages. A simple example. EDIT: There is a strange artifact in upper corner of base ellipse when they overlap though, don't now why... I'm looking for, If i find I'll post it here. EDIT2: it seems to be related to the antialias, if you skip smooth() the artifact is gone...

PGraphics c;
PGraphics d;
void setup() {
  size(300, 300);
  background(255);
  c = createGraphics(width, height, JAVA2D);
  d = createGraphics(width, height, JAVA2D);
  c.beginDraw();
  c.smooth();
  c.endDraw();
  d.beginDraw();
  d.smooth();
  d.endDraw();
}

void draw() {  
  background(255);
  c.beginDraw();
  c.background(0, 0);
  c.fill(255);
  c.stroke(0);
  c.ellipse(mouseX, mouseY, 30, 30);
  c.endDraw();

  d.beginDraw();
  d.background(0, 0);
  d.fill(255);
  d.stroke(0);
  d.ellipse(width/2, height/2, 30, 30);
  d.endDraw();
  d.blend(c, 0, 0, width, height, 0, 0, width, height, DIFFERENCE);
  image(d, 0, 0);
}
2
votes

Unfortunately I can't provide a runnable sample now, but for the visual effect you can use the blend() function (probably on the DIFFERENCE mode).

You can draw an ellipse into a PImage using createGraphics btw.

1
votes

I thought of an amusing way to do this. Create a new sketch with the following code and move your mouse around within the canvas.

void setup() {
  size(600,600);
}

void draw() {
  background(0);

  int c1x = width/2;
  int c1y = height/2;
  int c2x = mouseX;
  int c2y = mouseY;

  int d = 100;

  boolean intersect = false;
  if(dist(c1x, c1y, c2x, c2y) < d) intersect = true;

  fill(255);
  stroke(0);
  ellipse(c1x, c1y, d, d);
  ellipse(c2x, c2y, d, d);
  noFill();
  ellipse(c1x, c1y, d, d);

  stroke(0, 0, 255);
  line(c1x, c1y, c2x, c2y);

  stroke(255, 0, 0);
  if(intersect) stroke(0, 255, 0);
  rectMode(CORNERS);
  int mx = (c1x+c2x)/2;
  int my = (c1y+c2y)/2;
  int r = d/2;
  rect(mx-r, my-r, mx+r, my+r); 

  if(intersect) {
    for(int j = my-r; j <= my+r; j++) {
      for(int i = mx-r; i <= mx+r; i++) {
        if(dist(i, j, c1x, c1y) <= r && dist(i, j, c2x, c2y) <= r) {
          stroke(0);
          point(i, j);
        } 
      }
    }   
  }
}

This is a dirty mock-up showing the concept. I know the center points of the two circles. I imagine a square with a width and height equal to the diameter of the circles, and I center that square at the midpoint between the two circles. When the circles collide, I check each pixel within that square, and if the pixel is within both circles, I draw a point there.

I simplified by having the circles with identical diameter, but it's trivial to modify it for variable diameters.

Screenshot of circle intersection fill

Obviously you don't have to draw the green square and blue line, those are there just for reference.

0
votes

they intersect if distance between their centers is smaller than sum of their radius

0
votes

This would be dark ellipses with a white intersection and background and is quick and dirty but works.

with a white background:

background(255);

call something like this:

  blendMode(SUBTRACT);
  fill(0);
  ball1.display();
  fill(255);
  ball2.display();

If you want to take a look at the math behind it check out this link. I think you also might be able to do this with a library like toxiclibs.geom.