Recursive reflectance in ray tracer not working - java

for some reason in my ray tracer if I try to limit the number of recursive calls in my ray tracer my reflectance doesn't work.
Here is my reflectance code:
public static int recursionLevel;
public int maxRecursionLevel;
public Colour shade(Intersection intersection, ArrayList<Light> lights, Ray incidenceRay) {
recursionLevel++;
if(recursionLevel<maxRecursionLevel){
Vector3D reflectedDirection = incidenceRay.direction.subtractNormal(intersection.normal.multiply(2).multiply(incidenceRay.direction.dot(intersection.normal)));
Ray reflectiveRay = new Ray(intersection.point, reflectedDirection);
double min = Double.MAX_VALUE;
Colour tempColour = new Colour();
for(int i = 0; i<RayTracer.world.worldObjects.size(); i++){
Intersection reflectiveRayIntersection = RayTracer.world.worldObjects.get(i).intersect(reflectiveRay);
if (reflectiveRayIntersection != null && reflectiveRayIntersection.distance<min){
min = reflectiveRayIntersection.distance;
recursionLevel++;
tempColour = RayTracer.world.worldObjects.get(i).material.shade(reflectiveRayIntersection, lights, reflectiveRay);
recursionLevel--;
}
}
return tempColour;
}else{
return new Colour(1.0f,1.0f,1.0f);
}
}
If I get rid of the if statement it works, though I run out of memory if I place too many reflective objects. I'm not sure what could be causing this.

The problem is that you're using recursionLevel as global state, but it really should be local state. Also, with every recursive call to shade(), you're incrementing it twice and only decrementing it once. I would refactor your code as follows:
Delete the recursionLevel global
Add a recursionLevel parameter to your shade() method
Keep your if(recursionLevel < maxRecursionLevel) check
Remove the recursionLevel increments and decrements around the recursive call to shade()
Modify the recursive call to shade() such that it calls shade(..., recursionLevel + 1)

Related

ConcurrentModificationException with 2 Iterators and one ArrayList [duplicate]

This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 5 years ago.
I have a quick question that involves one ArrayList, 2 Iterators, and some nested for loops. Im trying to make a bit of a gravity engine using multiple gravity wells pulling on each other and moving around. To do this, Iv made an ArrayList of these gravity wells, all randomly places on the screen with a random size. Here it is for reference.
for(int i = 0; i < amount; i++){ // makes all
int mass = rand.nextInt(45,65);
int locX = rand.nextInt(50, getWidth()-100);
int locY = rand.nextInt(50, getHeight()-100);
Color cColor = rand.nextColor();
if(mass%8==0){
mass = rand.nextInt(25,35);
}
else if(mass%7==0){
mass = rand.nextInt(75,85);
}
Body body = new Body((double)locX,(double)locY,mass);
body.setFilled(true);
body.setColor(Color.WHITE);
body.setFillColor(cColor);
add(body);
bodys.add(body);
}
bodys is the name of the ArrayList containing everything. So my real problem comes to the Iterators. Heres the code thats giving me trouble:
public void move(){
Iterator<Body> eIter = bodys.iterator();
while(eIter.hasNext()){ // finding the thing we edit
Body edit = eIter.next();
int addX = 0, addY = 0;
int totalX = 0, totalY = 0;
double ex = edit.getX(), ey = edit.getY();
double eMass = edit.getMass(), eSize = edit.getHeight();
double eMoveX = edit.getMoveX(), eMoveY = edit.getMoveY();
int placeInArrayEdit = bodys.indexOf(edit);
Iterator<Body> fIter = bodys.iterator();
while(fIter.hasNext()){ // iterating through the force pulling the edit body
Body force = fIter.next(); /// ConcurrentModificationException is thrown
int placeInArrayForce = bodys.indexOf(force);
if(placeInArrayForce != placeInArrayEdit){ // making sure the 2 bodys arent the same
double fx = force.getX(), fy = force.getY();
double fMass = force.getMass();
double fMoveX = force.getMoveX(), fMoveY = force.getMoveY();
double difX = (ex-fx);
double difY = (ey-fy);
double distX = distanceP(ex, fx);
double distY = distanceP(ey, fy);
double vecX = (difX/distX);
double vecY = (difY/distY);
if(distance(fx,ex,fy,ey) <= eSize/3){ // if they are colliding
if(eMass >= fMass){
remove(edit);
edit.addMass((int)(fMass));
eIter.remove(); // problem
}
if(eMass < fMass){
remove(force);
force.addMass((int)(eMass));
fIter.remove();
}
}
double grav = (eMass/fMass);
grav -= (grav*.50);
addX -= (vecX/grav)/2; // this determines movement which means i
addY -= (vecY/grav)/2; // need to edit this with fMass
}
edit.setVelX(addX/(eMass + (eMass*.75)));
edit.setVelY(addY/(eMass + (eMass*.75)));
edit.addMoveX(edit.getVelX());
edit.addMoveY(edit.getVelY());
edit.move(edit.getMoveX(),edit.getMoveY());
}
}
}
The code above is moving the gravity wells and testing for collision. The problem is that ConcurrentModificationException is thrown where iv commented it to be thrown.
Iv spent about an hour or so looking around for a solution and nothing iv tried has worked. The code works up until the wells actually hit each other, then the error is thrown. Is there a way to avoid this error while still testing for collision like this, or is my code just too broken?
Thanks for all the help! Please let me know if you need anything clarified as this is my first question on StackOverflow
See javadoc of ArrayList:
The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
So, you have 2 iterators: eIter for the outer loop, and fIter for the inner loop.
When you call eIter.remove(), fIter will go bad.
When you call fIter.remove(), eIter will go bad.
(If you had called bodys.remove(index), both would go bad.)
Either way, one of the iterators will be stale, and will throw ConcurrentModificationException when you call next().
Also, when you call eIter.remove(), you don't break out of the inner loop, so you run the risk of trying to do it again in another iteration of the inner loop.
In short, you need to find another way, e.g. using indexes and get(index) calls, or something like that.

Finding local minimum of minima

I have a list of double values (distances between point p0 and a point list L) and I'm looking for their minimum. Then I'm changing the list (which now contains distances between point p1 and the point list L) and compute this new minimum.
I repeat this until the new minimum is bigger than the minimum at the previous step.
In pseudo Java code:
double minDistanceTotal = Double.MAX_VALUE;
double minDistanceCurrent = ?????;
while (minDistanceCurrent < minDistanceTotal) {
Point curPoint = ... // take another point p0, p1, p2...
// compute current minimum distance
for (Point otherPoint : pointList) {
double curDistance = distance(curPoint, otherPoint);
if (curDistance < minDistanceCurrent) {
minDistanceCurrent = curDistance;
}
}
// compare it to the total minimum distance
if (minDistanceCurrent < minDistanceTotal) {
... // do something
minDistanceTotal = minDistanceCurrent;
}
}
My problem now is that I'm not sure about how to initialize minDistanceCurrent. First I tried Double.MAX_VALUE - 1, but then the while-loop isn't executed at all.
After checked the Java API to find the actual value of Double.MAX_VALUE which is 0x1.fffffffffffffP+1023. So I tried 0x1.ffffffffffffeP+1023 as the value for minDistanceCurrent, which seems to work.
But I'm not sure if this is really the second highest double value in Java.
So, what's the value I should initialize minDistanceCurrent with? Or is there some different approach to get what I want that I missed?
EDIT: After the answer of #resueman, I realized a flaw in the code. The check of current minimum and total minimum can just be done after a new current minimum is computed and not before (as it is in the condition of the while loop).
The problem was fixed using the following code:
double minDistanceTotal = Double.MAX_VALUE;
double minDistanceCurrent = Double.MAX_VALUE;
while (true) {
Point curPoint = ... // take another point
// compute current minimum distance
for (Point otherPoint : pointList) {
double curDistance = distance(curPoint, otherPoint);
if (curDistance < minDistanceCurrent) {
minDistanceCurrent = curDistance;
}
}
// compare it to the total minimum distance
if (minDistanceCurrent < minDistanceTotal) {
... // do something
minDistanceTotal = minDistanceCurrent;
} else {
break;
}
}
An alternative would be while(!pointList.isEmpty()) to avoid an infinite loop when the list is empty.
It looks like you only want to break out of the loop after this block of code is called
if (minDistanceCurrent < minDistanceTotal) {
... // do something
minDistanceTotal = minDistanceCurrent;
}
If that's the case, then I'd suggest changing your while loop to either while(true) and putting a break in the if statement, or making it while(minDistanceTotal != minDistanceCurrent)
If I'm not wrong, your loop will execute just once. Either the distances calculated by the 'distance' method are lower than MAX_VALUE or overflow the double. In any case, your last 'if' will set current and total distances equal, hence getting you out of the loop. I doubt this is what you really want.
Probably you want just to make minDistanceTotal = minDistanceCurrent just at beginning of the loop, and probably you want to use BigDecimal instead of double to avoid overflowing and inaccurate calculations, but I can't really say as I don't get the idea behind your algorithm.
Summarizing:
Be careful on how you calculate distances inside your "distance(curPoint, otherPoint)", in particular consider overflowing effects. Maybe use BigDecimal instead of Double.
Get ride of the last if and change it for whatever you really need to do.
Hope it helps somehow.

Java depth-first recursive function

Im writing a recursive function in Java (graph theory) to get all paths in a 4x4 table, beginning at a random starting point. Possible directions are horizontal, vertical & diagonal, but I have a requirement that the same location cannot be visited twice.
The script works fine so far, I get a lot of combinations. The problem is that in the for loop of the function, when there is more than one possible way, then I get wrong results in the second and following loops because the boolean[] tempvisited is not getting back to his old values.
I hope there is someone, that may understand my English and my problem too. Here is my code so far:
// here I define a constant input of values:
String letters = "1548987425461854"
// This matrix shows all possible directions from every startpoint in the matrix:
// from the second value, you may get to the following locations: 1,3,5,6 and 7
private int[][] matrix = {
{1,4,5},
{0,2,4,5,6},
{1,3,5,6,7},
{2,6,7},
{0,1,5,8,9},
{0,1,2,4,6,8,9,10},
{1,2,3,5,7,9,10,11},
{2,3,6,10,11},
{4,5,9,12,13},
{4,5,6,8,10,12,13,14},
{5,6,7,9,11,13,14,15},
{6,7,10,14,15},
{8,9,13},
{8,9,10,12,14},
{9,10,11,13,15},
{10,11,14}
};
// Here begins the recursive function
public List<Combination> depthFirst(int vertex, boolean[] visited, Combination zeichen, List<Combination> combis){
// A temporary list of booleans to mark every value position visited or not
boolean[] tempvisited = new boolean[16];
// combis is the whole list of ways, zeichen is just the actual combination
zeichen.name = zeichen.name + this.letters.charAt(vertex);
combis.add(zeichen.name);
//marks actual value as visited
visited[vertex] = true;
for(int i = 0; i < 16; i++){
tempvisited[i] = visited[i];
}//end for
// going to next possible locations
for (int i = 0; i < this.matrix[vertex].length; i++) {
if (!visited[this.matrix[vertex][i]]) {
combis = depthFirst(this.matrix[vertex][i], tempvisited, zeichen, combis);
}//end if
}//end for
return combis;
}
You have the right idea with tempvisited, making a copy. But you're doing so in the wrong place.
You're setting visited[vertex] = true, which means that the visited you passed in is changing. What you want is for visited to never change. Make a copy of it, and make your changes to that copy.
Also, I notice that you use the same zeichen every time. So if you have a path 3 steps long, your combis list with be 3 copies of the same zeichen. That seems incorrect.
You set visited[vertex] to true before the first for loop; you could reset it to false just before you return. If every call undoes the change it did (directly), then every call will return with visited back to its state when that call was made. No tempvisited needed.
Take a look to this other recursive solution (pseudocode) for the Depth First Search (DFS).
void search(Node root) {
if (root == null) return;
visit(root);
root.visited = true;
foreach (Node n in root.adjacent) {
if (n.visited == false)
search(n);
}
}
Actually you don't need a copy of the visited array. Mark the node as visited right before the reccurrent call of depthFirst and then "unmark" it right after the call. Something like:
for (int i = 0; i < this.matrix[vertex].length; i++) {
if (!visited[this.matrix[vertex][i]]) {
visited[this.matrix[vertex][i]] = true;
combis = depthFirst(this.matrix[vertex][i], tempvisited, zeichen, combis);
visited[this.matrix[vertex][i]] = false;
}//end if
}//end for

Adding Polygon points from Line2D values

I have a small block of code that is reading Line2D values from an array called lineList (in a different class) and storing them in the new array called list. from here I have been trying to convert all of the line values into Polygon points (a point for each x, y coordinate of a line end).
so far I have it working but its not working for the very first point of the first line in the array (that's what I suspect it is) that is added and I am having trouble finding a solution to this as I have tried including this in the first if statement.
I will greatly appreciate any help that anyone is able to provide for me on this.
Below is the code I am using for adding the points from the Line2D values:
Polygon p = new Polygon();
ArrayList<Line2D> list = new ArrayList<Line2D>();
Color pixel;
boolean firstTime = true;
list = segmentation.getLineList();
//loop through lineList and add all x and y coordinates to relative x and y arrays
for(int i = 0; i < list.size(); i++) {
if(firstTime == true){
Line2D line = list.get(i);
Point2D startPoint = line.getP1();
Point2D endPoint = line.getP2();
int startX = (int) startPoint.getX();
int startY = (int) startPoint.getY();
int endX = (int) endPoint.getX();
int endY = (int) endPoint.getY();
p.addPoint(p.xpoints[i] = startX, p.ypoints[i] = startY);
p.addPoint(p.xpoints[i] = endX, p.ypoints[i] = endY);
startPoint = null;
endPoint = null;
line = null;
firstTime = false;
}
else {
Line2D line = list.get(i);
Point2D endPoint = line.getP2();
int endX = (int) endPoint.getX();
int endY = (int) endPoint.getY();
p.addPoint(p.xpoints[i] = endX, p.ypoints[i] = endY);
endPoint = null;
line = null;
}
}
Below is an example of the first point (lower most point) not being included in the polygon points.
Seems like a lot of duplicated code to me. Before we try any more debugging, let's refactor the code and make it simpler to understand and debug.
Refactoring
The first bit of code we can pull out is the code to add a point to the Polygon. Here's the new method.
protected void addPoint(Polygon p, Point2D point) {
int x = (int) point.getX();
int y = (int) point.getY();
p.addPoint(x, y);
}
Now, I didn't get to this in one refactoring. I first pulled out the end point code, because it was identical. After reflecting on the code some more, I generalized it so I could use it for the start point code.
When I first saw this line of code
p.addPoint(p.xpoints[i] = startX, p.ypoints[i] = startY);
I thought, WTF? I'd never seen anyone set values in a method call. In a where clause, sure.
After about 5 minutes of thought, I realized that the Polygon class internal values were being set after the execution of the addPoint method. While this might be useful with some other method call, it's not necessary here. The method call can be simplified to
p.addPoint(x, y);
Java developers, if you need yet another reason for making your class variables non-public, this is a real good one. Keeps people from setting your class variables after you've set them in your setter method.
Priming Read
We can get rid of the first time switch, and a lot of code, if we use a little known algorithm called the priming read.
Most for loops have the input statement as the first statement in the loop. The for (String s : stringList) construction of a loop hides the fact that the input statement is the first statement in the loop.
But sometimes, you have a method where you need a priming read. This method is one of those times.
In pseudo code, a priming read works like this.
Read input
for loop
process input
read input
end loop
process last input
By using a priming read, I was able to greatly simplify the createPolygon method.
Any Cobol programmer reading this thought, "Yep, the priming read."
Java programmers, keep this priming read idea in your mind. You won't use it that often, but as you see, it greatly reduces the amount of code you need in certain cases.
Refactored Code
public Polygon createPolygon(Segmentation segmentation) {
Polygon p = new Polygon();
List<Line2D> list = segmentation.getLineList();
if (list.size() < 2) return p;
Line2D line = list.get(0);
addPoint(p, line.getP1());
// loop through lineList and add all x and y coordinates to relative x
// and y arrays
for (int i = 1; i < list.size(); i++) {
addPoint(p, line.getP2());
line = list.get(i);
}
addPoint(p, line.getP2());
return p;
}
protected void addPoint(Polygon p, Point2D point) {
int x = (int) point.getX();
int y = (int) point.getY();
p.addPoint(x, y);
}
I did two additional things to the code.
I added a test for less than 2 lines. Basically, it takes at least 2 lines to create a triangle (polygon). There was no point executing the method for 1 line or zero lines.
I changed the ArrayList reference to List. In Java, it's better to use an interface over a concrete class. Since the only List method we're using in the code is the get method, we can use the interface. The advantage to using the interface is that the createPolygon method doesn't care whether or not the getLineList method returns an ArrayList, a LinkedList, or a custom class that implements List. This makes future modifications easier.

How to detect an infinite loop in a recursive call?

I have a function that is recursively calling itself, and i want to detect and terminate if goes into an infinite loop, i.e - getting called for the same problem again. What is the easiest way to do that?
EDIT: This is the function, and it will get called recursively with different values of x and y. i want to terminate if in a recursive call, the value of the pair (x,y) is repeated.
int fromPos(int [] arr, int x, int y)
One way is to pass a depth variable from one call to the next, incrementing it each time your function calls itself. Check that depth doesn't grow larger than some particular threshold. Example:
int fromPos(int [] arr, int x, int y)
{
return fromPos(arr, x, y, 0);
}
int fromPos(int [] arr, int x, int y, int depth)
{
assert(depth < 10000);
// Do stuff
if (condition)
return fromPos(arr, x+1, y+1, depth + 1);
else
return 0;
}
If the function is purely functional, i.e. it has no state or side effects, then you could keep a Set of the arguments (edit: seeing your edit, you would keep a Set of pairs of (x,y) ) that it has been called with, and every time just check if the current argument is in the set. That way, you can detect a cycle if you run into it pretty quickly. But if the argument space is big and it takes a long time to get to a repeat, you may run out of your memory before you detect a cycle. In general, of course, you can't do it because this is the halting problem.
You will need to find a work-around, because as you've asked it, there is no general solution. See the Halting problem for more info.
An easy way would be to implement one of the following:
Pass the previous value and the new value to the recursive call and make your first step a check to see if they're the same - this is possibly your recursive case.
Pass a variable to indicate the number of times the function has been called, and arbitrarily limit the number of times it can be called.
You can only detect the most trivial ones using program analysis. The best you can do is to add guards in your particular circumstance and pass a depth level context. It is nearly impossible to detect the general case and differentiate legitimate use of recursive algorithms.
You can either use overloading for a consistent signature (this is the better method), or you can use a static variable:
int someFunc(int foo)
{
static recursionDepth = 0;
recursionDepth++;
if (recursionDepth > 10000)
{
recurisonDepth = 0;
return -1;
}
if (foo < 1000)
someFunc(foo + 3);
recursionDepth = 0;
return foo;
}
John Kugelman's answer with overloading is better beacuse it's thread safe, while static variables are not.
Billy3
Looks like you might be working on a 2D array. If you've got an extra bit to spare in the values of the array, you can use it as a flag. Check it, and terminate the recursion if the flag has been set. Then set it before continuing on.
If you don't have a bit to spare in the values, you can always make it an array of objects instead.
If you want to keep your method signature, you could keep a couple of sets to record old values of x and y.
static Set<Integer> xs;
static Set<Integer> ys;//Initialize this!
static int n=0;//keeps the count function calls.
int fromPos(int [] arr, int x, int y){
int newX= getX(x);
int newY= getY(y);
n++;
if ((!xs.add(Integer.valueOf(newX)) && !ys.add(Integer.valueOf(newY))){
assert(n<threshold); //threshold defined elsewhere.
fromPos(arr,newx,newy);
}
}
IMHO Only loops can go into an infinite loop.
If your method has too many level of recursion the JVM will throw a StackOverflowError. You can trap this error with a try/catch block and do whatever you plan to do when this condition occurs.
A recursive function terminates in case a condition is fulfilled.
Examples:
The result of a function is 0 or is 1
The maximum number of calls is reached
The result is lower/greater than the input value
In your case the condition is ([x0,y0] == [xN,yN]) OR ([x1,y1] == [xN,yN]) OR ([xN-1,yN-1] == [xN,yN])
0, 1, ...N are the indexes of the pairs
Thus you need a container(vector, list, map) to store all previous pairs and compare them to the current pair.
First use mvn findbugs:gui to open a gui which point to the line where this error is present.
I also faced the same problem and I solved it by adding a boolean variable in the loop verification.
Code before ->
for (local = 0; local < heightOfDiv; local = local + 200) { // Line under Error
tileInfo = appender.append(tileInfo).append(local).toString();
while (true) {
try {
tileInfo = appender.append(tileInfo).append(getTheTextOfTheElement(getTheXpathOfTile(incr))).toString();
incr++;
} catch (Exception e) {
incr = 1;
tileInfo = appender.append(tileInfo).append("/n").toString();
}
}
To Solve this problem, I just added a boolean variable and set it to false in the catch block. Check it down
for (local = 0; local < heightOfDiv; local = local + 200) {
tileInfo = appender.append(tileInfo).append(local).toString();
boolean terminationStatus = true;
while (terminationStatus) {
try {
tileInfo = appender.append(tileInfo).append(getTheTextOfTheElement(getTheXpathOfTile(incr))).toString();
incr++;
} catch (Exception e) {
incr = 1;
tileInfo = appender.append(tileInfo).append("/n").toString();
terminationStatus = false;
}
}
This is how i Solved this problem.
Hope this will help. :)

Categories