--- edit: fixed a bug in my code --
hey!
i love tfguy's solution, i think it's already relly good, but i couldn't help but attempt it too...
i've used the bresenham algorithm, that is the algorithm used to draw lines on a computer.
so basically i'm following the test-ray while it is being drawn,
and soon as it would overwrite a black pixel i made the algorithm cancel and return the coordinates.
here's some code:
- float angle = PI/2;
- int rayLength = 300;
- int rayColor = color( 255, 0, 0 );
- boolean drawRays = true;
- int N = 30;
- PVector wallPoints[] = new PVector[N];
- void setup() {
- size(500, 500);
- ellipseMode(CENTER);
- rectMode(CENTER);
- }
- void draw() {
- background(128);
- fill(255, 255, 0);
- stroke( 0 );
- strokeWeight( 2 );
- ellipse( width/2.0, height/2.0, 300, 300);
- fill( 0, 255, 255 );
- ellipse( width/2.0, height/2.0+200, 300, 300);
- rect(width/2.0, height/6.0, 20, 80);
- if( mousePressed ){
- angle -=0.01;
- angle%=TWO_PI;
- }
-
- // how many intersections do we want to test?
-
- // TO MAKE THINGS MORE FANCY:
- // let's do the line checking a few times in a loop
- for( int i = 0; i < N; i++ ){
- float alpha = angle + i*TWO_PI/N;
- // draw a line from the current mouse coordinates with some direction "alpha"
- wallPoints[i] = findWall( mouseX, mouseY, (int)(mouseX+rayLength*cos(alpha)), (int)(mouseY+rayLength*sin(alpha)) );
- }
-
- // draw them later, otherwise we might draw over the edge and then we
- // can't detect it anymore
- for( int i = 0; i < N; i++ ){
- if( wallPoints[i] != null ){
- noFill();
- stroke( 0, 255, 0 );
- ellipse( wallPoints[i].x, wallPoints[i].y, 10, 10 );
-
- // this would be the distance:
- // println( "Distance is currently: " + wallPoints[i].dist( new PVector( mouseX, mouseY ) ) );
- }
- }
-
- }
-
- // bresenham java implementation adapted from the "drawLine" method from
- // http://onyx.boisestate.edu/~tcole/cs498/spr04/ammeraal/Bresenham.java
- // this attempty to draw a line between two points.
- // as soon as it hits a black pixel it stops and returns the coordinates.
- PVector findWall(int xP, int yP, int xQ, int yQ)
- { int x = xP, y = yP, D = 0, HX = xQ - xP, HY = yQ - yP,
- c, M, xInc = 1, yInc = 1;
-
- // do we start on a wall?
- if( get( xP, yP ) == color( 0, 0, 0 ) ) return new PVector( xP, yP );
-
- if (HX < 0){xInc = -1; HX = -HX;}
- if (HY < 0){yInc = -1; HY = -HY;}
- if (HY <= HX)
- { c = 2 * HX; M = 2 * HY;
- for (;;)
- {
- if( (xP!=x || yP!=y) &&get( x, y ) == color( 0, 0, 0 ) ) return new PVector( x, y );
- // disable this if you don't want to draw the trace
- if( drawRays ) set( x, y, rayColor );
- if (x == xQ) break;
- x += xInc;
- D += M;
- if (D > HX){y += yInc; D -= c;}
- }
- }
- else
- { c = 2 * HY; M = 2 * HX;
- for (;;)
- {
- if( (xP!=x || yP!=y) &&get( x, y ) == color( 0, 0, 0 ) ) return new PVector( x, y );
- // disable if you don't want to draw the trace
- if( drawRays ) set(x, y, rayColor);
- if (y == yQ) break;
- y += yInc;
- D += M;
- if (D > HY){x += xInc; D -= c;}
- }
- }
-
- // nothing found?
- return null;
- }
btw:
you'll notice this code has two problems:
1. your wall needs to be at least 2px thick, otherwise the algorithm might "slip by" a wall
2. as soon as you start drawing where the ray hits you might end up painting over the wall,
and the next wall check has found a way to slip by.
both should be quite easy to work around,
the first by drawing a 2px wall, the second by simply not drawing any results until you've made
all your wall checks ...
good luck with your project!
best, hansi.