Hi. Interesting problem with Vector3f. The hashCode implementation does not adhere to the hash-equals contract to return a unique hash code for different objects. Here is the test cases and a possible solution. As you can see, for (1, 1, 1), (-1, 1, 1) and (1, -1, 1) the same hash is returned. The custom hash function returns a unique hash but it’s more computation.
I would recommend, a) remove the equals and hashCode methods from Vector3f, b) add a documentation that the hash code is not unique or c) use a more complicated algorithm to return the hash code.
PS: it’s not a bug or help request, I shouldn’t use Vector3f in a hash map anyway. It was just a quick and dirty solution for some debugging.
class Vector3fTest {
static test_hashCode() {
Stream.of(
of(new Vector3f(0, 0, 0), 2030264), //
of(new Vector3f(1, 1, 1), -627115336), //
of(new Vector3f(-1, 1, 1), -627115336), //
of(new Vector3f(1, -1, 1), -627115336), //
of(new Vector3f(1, 1, -1), 1520368312), //
)
}
@ParameterizedTest
@MethodSource
void test_hashCode(def v, def expected) {
assert v.hashCode() == expected
}
static test_hashCode_custom() {
Stream.of(
of(new Vector3f(0, 0, 0), 59), //
of(new Vector3f(1, 1, 1), 1098907707), //
of(new Vector3f(-1, 1, 1), 1082130491), //
of(new Vector3f(1, -1, 1), 1065353275), //
of(new Vector3f(1, 1, -1), 1084227643), //
)
}
@ParameterizedTest
@MethodSource
void test_hashCode_custom(def v, def expected) {
assert toHash(v) == expected
}
static int toHash(def v) {
final int PRIME = 59;
int result = 1;
float f = calcN(calcN(v.x, v.y), v.z)
result = (result * PRIME) + (Float.hashCode(f));
return result;
}
static float calcN(float x, float y) {
return (x + y) * (x + y + 1) / 2 + y;
}
}