Ray collision bug(?)

Hello,

i got a reccurent intermitent bug coming from a comparison

is this jme related problem or java ? i can’t tell

around getCollision

Code:
CollisionResults res = new CollisionResults(); int n=rootNode.collideWith(new Ray(o, dir),res); for(int i=0;i<n;i++) if(res.getCollision(i).getDistance()<=maxDist) <------------------- error { ...

juil. 02, 2012 9:12:18 PM com.jme3.app.Application handleError
Grave: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.ComparableTimSort.mergeLo(ComparableTimSort.java:714)
at java.util.ComparableTimSort.mergeAt(ComparableTimSort.java:451)
at java.util.ComparableTimSort.mergeCollapse(ComparableTimSort.java:376)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:182)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:146)
at java.util.Arrays.sort(Arrays.java:472)
at java.util.Collections.sort(Collections.java:155)
at com.jme3.collision.CollisionResults.getCollision(CollisionResults.java:106)
1 Like

Which jme3 version you use?, nightly? latest stable or older? Maybee try a upgrade, since I use jdk7 and never got this error with rays.

Code:
Area: API: Utilities

Synopsis: Updated sort behavior for Arrays and Collections may throw an IllegalArgumentException

Description: The sorting algorithm used by java.util.Arrays.sort and (indirectly) by java.util.Collections.sort has been replaced. The new sort implementation may throw an IllegalArgumentException if it detects a Comparable that violates the Comparable contract. The previous implementation silently ignored such a situation. If the previous behavior is desired, you can use the new system property, java.util.Arrays.useLegacyMergeSort, to restore previous mergesort behavior.

Nature of Incompatibility: behavioral

RFE: 6804124

yes latest

i have just done the 4 latest plugins update too :frowning:

Well untill a real solution is found just add that run parameter in the rfe above, might work.

This sorting issuse seems to pop up randomly and yes I think its a bug in some java version too.

Spotted here.

Since I’m testing stuff with procedural meshes and hadn’t got that problem before, I assume it’s due to my particular mesh; perhaps points are too distant from each other? Or maybe, singe my triangles are a real big mess, there is a limit problem somewhere.



I think it may originate in the sort done on the collision results [java]Collections.sort(results);[/java] eventhough the class CollisionResults doesn’t implement Comparable…

@carpentier-ch said:
Spotted here.
Since I'm testing stuff with procedural meshes and hadn't got that problem before, I assume it's due to my particular mesh; perhaps points are too distant from each other? Or maybe, singe my triangles are a real big mess, there is a limit problem somewhere.

I think it may originate in the sort done on the collision results [java]Collections.sort(results);[/java] eventhough the class CollisionResults doesn't implement Comparable...


It's CollisionResult (note: without the s) that is being sorted... and it DOES implement Comparable.

The only thing I can think is that the sorting doesn't like the fact that compareTo() returns 0 for objects that are not actual equal. This would be relatively easy to fix, if so. Though I think the JDK is being kind of stupid on this one.

Actually, I'm wondering if it's really because the comparison is done on floats. Something is tickling my brain that NaNs act funny in comparisons and may be inconsistent. For example if a = NaN and b = NaN then a < b and b < a or something... which would really mess up that comparable method. If it's true... I don't remember for sure but like I said something is tickling in there.

Perhaps before your call you can use getCollisionDirect(int index) to iterator and print all of the collisions since it avoids the sort. Then we can see if there are some odd NaNs or Infinities in there when this exception happens.

Okay, I’ll check that. Hope your hunch is right!

Hohoho. No need to go that far.



[java]public int compareTo(CollisionResult other) {

if (distance < other.distance)

return -1;

else if (distance > other.distance)

return 1;

else

return 0;

}[/java]

in class CollisionResult.



It does indeed not respect the contract : “The implementor must also ensure that the relation is transitive: (x.compareTo(y)>0 && y.compareTo(z)>0) implies x.compareTo(z)>0.”



Fix: replace by the following:

[java]

public int compareTo(CollisionResult other) {

return Float.compare(distance - other.distance);

}

[/java]



EDIT: which, actually, deals with the NaNs, so I assume you are right.

Double-EDIT-Mega-Combo: Aaaaand we have a winner: [java](NaN, NaN, NaN)[/java]

@carpentier-ch said:
It does indeed not respect the contract : "The implementor must also ensure that the relation is transitive: (x.compareTo(y)>0 && y.compareTo(z)>0) implies x.compareTo(z)>0."


This part is what I didn't understand. For normal floats the contract looks intact to me.

The other solution you posted is the one I might have used. Generally compareTo() is setup so that you can return this.value - other.value... but for float it's more complicated. Fortunately, Float has already provided a nice method.

I will point out that I think you mean Float.compare( distance, other.distance ).... you used subtraction instead.
1 Like

Hmmm… My bad, it does indeed respect the contract. Sorry, this “return 1 or -1” thing tseems too much like aa kludge to me :stuck_out_tongue:



And yes, I meant Float.compare( distance, other.distance ).



Problem solved (But not my mesh! Darn dual contouring!)

Thanks, a fix was committed using Float.compare(). This means NaNs will appear as the farthest CollisionResults and the exception will not be raised on Java 7.

Thanks a lot :slight_smile:

i have a question:

why collisionResult.getDistance() returns Nan ?

shouldn’t it just return null as a collision result or not include it ?

primitives (float) can’t be set to null only references can

For certain types of collisions like mesh vs. bounding volume, there might not be a distance. Many of the algorithms we use for collisions do not provide penetration distance for a triangle vs volume collision.