Loading...
Logo
Processing Forum

'Filling' the gaps between lines

Answered
  • Need more info
  • Answered
  • Working on it
in General Discussion  •  Other  •  7 months ago  
I'm trying to work out the logic for how I'd accomplish this.

Let's say I've got a couple of lines that intersect, like this:
http://farm9.staticflickr.com/8530/8554745759_ffc2b255fa_o.png

I'd like to then fill in the blank spaces like this:
http://farm9.staticflickr.com/8242/8555855632_c6780cf35f_o.png

I know you're probably thinking I should just draw a triangle and fill it, but I'd like to draw many lines, and have the blank spaces filled at random after they intersect.

Should I just use triangles and try to make them aware of where they are relative to each other? Or is there a more obvious solution I'm overlooking?

Replies(18)

You need to define blank spaces more specifically. Based on the image, I can't see any reason why the top and bottom space couldn't have been filled instead of the left and right. Also, there are four "suggested" lines in that image which are the screen edges (to complete the triangles).

If you had lots of lines creating many spaces, which spaces should be filled, and which ones should not?
Well you could... Hmm.. no.
Or... No, wait.
Uh...
...
Hmm...

I can tell you this much: There is not a more obvious solution you are overlooking. At least not one I can see.

Questions about your "random" lines:
1) Do they always go from the sketch edge to the other edge?
2) Do they always start on the left edge and end on the right edge?

@asimes
The four 'suggested' lines are just two that intersect, but I see what you mean.

If I had an image like this, I'd just want to fill the spaces randomly, the trick is defining them first:
http://farm9.staticflickr.com/8102/8554814905_4fb8274503_o.png

@tfguy44
They will always go from edge-to-edge, yes.
And they will always go from right to left, yes.
Just to make sure we understood "suggested" in the same way... there are two lines that cross (the blue ones). You could think about them as four lines if you wanted to (not what I meant earlier). What I meant by suggested were the horizontal and vertical lines that are the screen edges.

Without those, you have two lines / line segments on a plane and mathematically a plane is infinite. That means you can't test the two blue lines as surrounding an area without the screen edges counting as lines.

All of that only matters if you want to do your area checking with geometric information. Another option could be something like a paint-bucket tool. You pick a random pixel on the screen and flood its neighbors unless the neighbor has the color of one of the lines. This will fill random areas with the same color.
DAMN.
I tried writing a paint-filling method and I get a "YOU'RE DOING TOO MUCH RECURSION!" error.
I need to sleep on this. I'll have a smarter solution tomorrow.
DAMN DAMN DAMN.

Copy code
  1. PGraphics b;
  2. void setup() {
  3.   size(300, 700);
  4.   // Off-screen image for exact boundries.
  5.   b = createGraphics(width, height, P2D);
  6.   // Array of lines.
  7.   PVector[] allLines = new PVector[10];
  8.   // Populate array with random lines.
  9.   for ( int i = 0; i < allLines.length; i++) {
  10.     allLines[i] = new PVector( random(height), random(height), 0 );
  11.   }
  12.   // Draw off-screen image.
  13.   b.beginDraw();
  14.   b.background(0);
  15.   b.stroke(255);
  16.   for ( int i = 0; i < allLines.length; i++) {
  17.     b.line( 0, allLines[i].x, width, allLines[i].y );
  18.   }
  19.   int numSectors = 1;
  20.   for ( int i=0; i < numSectors; i++ ) {
  21.     int x = int(random(width));
  22.     int y = int(random(height));
  23.     fillFrom(x, y);
  24.   }
  25.   b.endDraw();


  26.   image( b.get(), 0, 0 );


  27.   // Draw scene.
  28.   //background(0);
  29.   //stroke(255);
  30.   //smooth();
  31.   //strokeWeight(4);
  32.   //for( int i = 0; i < allLines.length; i++){
  33.   //  line( 0, allLines[i].x, width, allLines[i].y );
  34.   //}
  35.   //
  36. }

  37. void draw() {
  38. } // Do nothing.

  39. void fillFrom( int x, int y ) {
  40.   b.stroke(255, 0, 0);
  41.   b.point( x, y);
  42.   if ( x-1>0 && b.get(x-1, y) == color(0) ) { 
  43.     fillFrom( x-1, y );
  44.   }
  45.   if ( x+1<width && b.get(x+1, y) == color(0) ) { 
  46.     fillFrom( x+1, y );
  47.   }
  48.   if ( y-1>0 && b.get(x, y-1) == color(0) ) { 
  49.     fillFrom( x, y-1 );
  50.   }
  51.   if ( y+1<height && b.get(x, y+1) == color(0) ) { 
  52.     fillFrom( x, y+1 );
  53.   }
  54. }
google 'seed fill' (or 'flood fill')

tfguy's is inefficient, which you can probably tell by the error. you only need to check 3 directions for every point after the start point for instance - you know that the point you've come from is already correct.

alternatively, use your own stack.

@kooogy

A flood fill looks promising. I'll give it a shot!
I'm playing around with pixels[] and get() right now. How exactly do I interpret what it returns to me?

When I pull the pixels from the white part of an image, it returns -1
When I pull the pixels from the black part of an image, it returns -16777216
I wasn't trying for efficiency.

Anyway, the "number" returned by get() is better interpreted as a color.
Print it out as Hexadecimal and use tfguy44's link as reference
You guys are giving me some great suggestions, and I appreciate it!

I'm learning some of these functions, and I'm wondering why my code below doesn't work. It fills the top half of the canvas with white, the bottom half with black, I loop through and change the top to red, the bottom to green, except it fills it all with green instead. My hex filter isn't working:

Copy code
  1. color white = color(255);
  2. color black = color(0);
  3. color r = color(255, 0, 0);
  4. color g = color(0, 255, 0);

  5. size(250, 250);
  6. background(125);
  7. noStroke();

  8. // Fill top half with white
  9. fill(white);
  10. rect(0, 0, 250, 125);

  11. // Fill bottom half with black
  12. fill(black);
  13. rect(0, 125, 250, 250);

  14. loadPixels();


  15. for (int i = 0; i < (width*height); i++) {
  16.   color b = pixels[i];
  17.   // If the pixel color is white, turn it red
  18.   if (hex(b) == "FFFFFFFF") {
  19.     pixels[i] = r;
  20.   }
  21.   // If it's anything other than white, turn it green
  22.   else {
  23.     pixels[i] = g;
  24.   }
  25.   // output.println(hex(b));
  26. }

  27. updatePixels();
I think asimes' suggestion to use hexadecimal was meant in tandem with the link to help you understand the structure of the color variable in Processing. However you don't need to use hex in your code as such. You can just use your pre-defined variables directly...

Adapted Code
Copy code
  1. color white = color(255);
  2. color black = color(0);
  3. color r = color(255, 0, 0);
  4. color g = color(0, 255, 0);
  5.  
  6. size(250, 250);
  7. background(125);
  8. noStroke();
  9.  
  10. // Fill top half with white
  11. fill(white);
  12. rect(0, 0, 250, 125);
  13.  
  14. // Fill bottom half with black
  15. fill(black);
  16. rect(0, 125, 250, 250);
  17.  
  18. loadPixels();
  19. for (int i=0; i<pixels.length; i++) {
  20.   color c = pixels[i];
  21.   if (c == white) {
  22.     pixels[i] = r;
  23.   } else {
  24.     pixels[i] = g;
  25.   }
  26. }
  27. updatePixels();
For what it's worth, here is my attempt...

(press the mouse to restart)

Code Example
Copy code
  1. int numLines = 10;
  2. HashSet <PVector> Q = new HashSet <PVector> ();
  3. HashSet <PVector> Qadd = new HashSet <PVector> ();
  4. color newCol, bgColor = color(0);
  5. boolean done;
  6.  
  7. void setup() {
  8.   size(400, 700);
  9.   drawLines();
  10. }
  11.  
  12. void draw() {
  13.   if (!done) {
  14.     while (!Q.isEmpty()) {
  15.       Qadd.clear();
  16.       loadPixels();
  17.       for (PVector p : Q) {
  18.         int curX = (int) p.x;
  19.         int curY = (int) p.y;
  20.         pixels[curX+curY*width] = newCol;
  21.         addValidXY(curX+1, curY);
  22.         addValidXY(curX-1, curY);
  23.         addValidXY(curX, curY+1);
  24.         addValidXY(curX, curY-1);
  25.       }
  26.       updatePixels();
  27.       Q.clear();
  28.       Q.addAll(Qadd);
  29.     }
  30.     loadPixels();
  31.     for (int i=0; i<pixels.length; i++) {
  32.       if (pixels[i]==bgColor) {
  33.         newCol = color(random(50, 255), random(50, 255), random(50, 255));
  34.         Q.add(new PVector(i%width, i/width));
  35.         return;
  36.       } else if (i==pixels.length-1) {
  37.         done = true;
  38.       }
  39.     }
  40.   }
  41. }
  42.  
  43. void mousePressed() {
  44.   drawLines();
  45. }
  46.  
  47. void drawLines() {
  48.   background(bgColor);
  49.   stroke(255);
  50.   for (int i=0; i<numLines; i++) {
  51.     float y1=random(height);
  52.     float y2=y1+random(-200, 200);
  53.     line(0, y1, width, y2);
  54.   }
  55.   done = false;
  56. }
  57.  
  58. void addValidXY(int x, int y) {
  59.   if ((x < 0 || x >= width) || (y < 0 || y >= height)) return;
  60.   else if (pixels[x+y*width] != bgColor) return;
  61.   else { Qadd.add(new PVector(x, y)); }
  62. }
The problem is on line 25. When comparing strings, you need to use .equals():

Copy code
  1. if ( hex(b).equals("FFFFFFFF") ){

But what you're actually trying to compare at this point is colors, which can be compared directly:

Copy code
  1. if( b == white ){

This is also a lot easier to read!
Thanks guys!
@amnon.owed,

I'm trying to run your method, but I'm getting a "Cannot find a class or type named "HashSet" error.
I'm running the latest beta of Processing, which version did you build that with?
I used Processing 1.5.1 Many default imports have been removed from the latest beta's. Add this line:
Copy code
  1. import java.util.HashSet;
Hello all here on this topic. I just posted my own description of the problem. 


Maybe this gives an input to work out a new way or code in Processing. I wonder that there shall be no function in Processing, like in good old BASIC 20 years ago. 

I solved it many years ago different with an algorithm - as I could not use BASIC on the workstation my art should be shown - as it was Unix. The algorithm was to check each 3rd dot moving from left to right, line by line. When the dot was black I changed this to the "fill"-color and the dot right place of it in case it was black also - and same for the dot on left side if it was black.

I am no programmer any more :( but luckily Alzheimer did not hit me until now. I am looking for a smart-code as I want to publish the recoded art with the code *grins

thank you all.