Java-Gaming.org Hi !
Featured games (90)
games approved by the League of Dukes
Games in Showcase (798)
Games in Android Showcase (234)
games submitted by our members
Games in WIP (865)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  HashMap issues...  (Read 5943 times)
0 Members and 1 Guest are viewing this topic.
Offline Archive
« Posted 2015-05-25 21:33:28 »

What I'm Trying To Do:

Loop through all triangles {
    if there is an intensity value assigned to the vertex in the HashMap already {
        set the vertex's intensity to the already calculated intensity
    } else {
        calculate the intensity and set it to the vertex
        pair up the vertex and the intensity and add it to the HashMap
    }
}

Therefore using this logic, I should have to only calculate the intensity of the vertex only once.

However, the body of the "if there is an intensity value assigned to the vertex in the HashMap already" statement never gets called because it never is null.

When I print out all the keys and values in the HashMap, I get repeated keys.

Anyone know the issue?

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
   private strictfp void calculateLight(int ambientIntensity, int intensity, Vector source) {
      Map<Vector, Integer> calculated = new HashMap<Vector, Integer>();
      for (Triangle tri : triangles) {
         
         Vector n = tri.normal();

         if (calculated.get(tri.v1) != null) {
            tri.i1 = calculated.get(tri.v1);
         } else {
            tri.i1 = calcIntensity(n, tri.v1, source, intensity, ambientIntensity);
            calculated.put(tri.v1, tri.i1);
         }

         if (calculated.get(tri.v2) != null) {
            tri.i1 = calculated.get(tri.v2);
         } else {
            tri.i2 = calcIntensity(n, tri.v2, source, intensity, ambientIntensity);
            calculated.put(tri.v2, tri.i2);
         }
         
         if (calculated.get(tri.v3) != null) {
            tri.i1 = calculated.get(tri.v3);
         } else {
            tri.i3 = calcIntensity(n, tri.v3, source, intensity, ambientIntensity);
            calculated.put(tri.v3, tri.i3);
         }
         
      }
      Iterator<Vector> keySetIterator = calculated.keySet().iterator();

      while (keySetIterator.hasNext()) {
         Vector key = keySetIterator.next();
         System.out.println("key: " + key + " value: " + calculated.get(key));
      }

   }

Offline BurntPizza

« JGO Bitwise Duke »


Medals: 486
Exp: 7 years



« Reply #1 - Posted 2015-05-25 21:37:25 »

Man that's the first time I've seen strictfp actually being used.

You probably aren't [correctly] overriding equals() and/or hashCode() for Vector.
Offline Archive
« Reply #2 - Posted 2015-05-25 21:43:32 »

This is my Vector equals method.

1  
2  
3  
4  
5  
6  
7  
   @Override
   public boolean equals(Object obj) {
      float epsilon = 0.0001f;
      Vector vec = (Vector) obj;
      return Math.abs(vec.x - x) < epsilon && Math.abs(vec.y - y) < epsilon && Math.abs(vec.z - z) < epsilon;
   }
   


And does hashCode need to be overridden to check for equality? I've never overridden it.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline KudoDEV

JGO Ninja


Medals: 79
Exp: 6 years


Game Dev Hobbyist


« Reply #3 - Posted 2015-05-25 21:46:12 »

And does hashCode need to be overridden to check for equality? I've never overridden it.

Yes I believe so try this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
 @Override
    public int hashCode() {
        int hash = 7;
        hash = 59 * hash + Float.floatToIntBits(this.x);
        hash = 59 * hash + Float.floatToIntBits(this.y);
        hash = 59 * hash + Float.floatToIntBits(this.z);
        return hash;
    }

   
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Vector3f other = (Vector3f) obj;
        return Float.floatToIntBits(this.x) == Float.floatToIntBits(other.x)
                && Float.floatToIntBits(this.y) == Float.floatToIntBits(other.y)
                && Float.floatToIntBits(this.z) == Float.floatToIntBits(other.z);
    }


Edit: cleaned looked ugly.

Offline BurntPizza

« JGO Bitwise Duke »


Medals: 486
Exp: 7 years



« Reply #4 - Posted 2015-05-25 21:46:31 »

Well it is a HashMap, isn't it?  Pointing

But as a general rule: http://stackoverflow.com/a/2707554

Quote
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
Offline Archive
« Reply #5 - Posted 2015-05-25 21:51:18 »

Ahh, okay, thank you BurntPizza and thank you KudoDEV.

Offline Roquen

JGO Kernel


Medals: 518



« Reply #6 - Posted 2015-05-26 08:12:36 »

The strictfp does nothing here.
Offline Archive
« Reply #7 - Posted 2015-05-26 22:39:23 »

Yeah I know that, this method used to be completely different, full of floating point algorithms and such. I just copy and pasted the method and rewrote the contents within it to try out this HashMap idea I had.

Offline basil_

« JGO Bitwise Duke »


Medals: 418
Exp: 13 years



« Reply #8 - Posted 2015-05-28 14:42:39 »

I also use hashmaps of vectors alot, looks like this :

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
@Override public int hashCode()
{
  // long hash = 1;
  int hash = 1;

  // trunc(); // truncating a vector is useful sometimes (for normals or colours)

  hash = hash*31 + floatToIntBits(x);
  hash = hash*31 + floatToIntBits(y);
  hash = hash*31 + floatToIntBits(z);

  // return(int)( hash ^ ( hash>>32 )); // uncomment this and the first line to use 64bit hash
  return hash;                          // 32bit hash is 'good enough' most time
}


float-to-int-bits can cause a little headache with
0.0f
and
-0.0f
:

1  
2  
3  
4  
public static int floatToIntBits(final float f)
{
  return f == 0.0f ? 0 : Float.floatToIntBits(f);
}


trunc can look like this, if you need it. precision like
0.00001f
works fine :

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
public final vec3d trunc(final float precision)
{
  x = roundTo(x,precision);
  y = roundTo(y,precision);
  z = roundTo(z,precision);

  return this;
}

public static float roundTo(final float x, final float precision)
{
  return floor(x/precision + 0.5f)*precision;
}

public static int floor(final float v)
{
  return v >= 0 ? (int)v : (int)v - 1;
}


the equals method, again my prefered flavour :

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
@Override public boolean equals(final Object v)
{
  try
  {
    return equals((vec3d)v);
  }
  catch(final ClassCastException ignored)
  {
    return false;
  }
}

public final boolean equals(final vec3d v)
{
  try
  {
    return equals(x,v.x) && equals(y,v.y) && equals(z,v.z);
  }
  catch(final NullPointerException ignored)
  {
    return false;
  }
}

public static boolean equals(final float a,final float b)
{
  return Math.abs(a - b) < FLOAT_ERROR;
}


i use a fixed
FLOAT_ERROR
around 4 * machine epsilon, which is good enough. more correct would be an error scaled with a and b.

http://en.wikipedia.org/wiki/IEEE_floating_point
http://en.wikipedia.org/wiki/File:IEEE754.png

http://en.wikipedia.org/wiki/Machine_epsilon

compute machine eps can be done like this :
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
static
{
  float eps = 1.0f;

  do
  {
    eps = eps*0.5f;
  }
  while(eps + 1 > 1);

  MACHINE_EPS = eps;
}


then i just use
FLOAT_ERROR = MACHINE_EPS*4.01f;
when comparing two floats, cos' i'm lazy.

o/
Offline Riven
Administrator

« JGO Overlord »


Medals: 1369
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #9 - Posted 2015-05-28 15:54:04 »

Instead of burdening Vec3.hashCode() and Vec3.equals() with error-margins, I think that for your use case it's much better to transform the original data that is loaded from a model file, prior to shoving it into a HashMap.

1  
2  
3  
Vec3 vec = new Vec3(parseFloat(x), parseFloat(y), parseFloat(z));

vec.trunc(0.001f); // 1mm resolution


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
class Vec3 {
   // ...

   public boolean equals(Vec3 that) {
      return (this.x == that.x) && (this.y == that.y) && (this.z == that.z);
   }

   @Override
   public int hashCode() {
      int hash = 1;
      hash = hash*31 + floatToIntBits(x);
      hash = hash*31 + floatToIntBits(y);
      hash = hash*31 + floatToIntBits(z);
      return hash;
   }
}



Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings!
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Roquen

JGO Kernel


Medals: 518



« Reply #10 - Posted 2015-05-29 08:09:04 »

As an aside:  putting vertices into a hashmap (in general) seems like a really bad idea.

Otherwise...some points:

If you do, then having constant precision through the domain is probably better than direct FP (multiply by constant and covert to integer).

You'll probably get better results using a modern hashing function than old school (the smaller the size of the map, the lesser the importance)

1  
2  
3  
4  
public static int floatToIntBits(final float f)
{
   Float.floatToIntBits(f+0.f); // adding zero flushes any negative zeroes.
}


With IEEE compliance, you never need to compute the epsilon.
Offline Riven
Administrator

« JGO Overlord »


Medals: 1369
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #11 - Posted 2015-05-29 08:23:52 »

As an aside:  putting vertices into a hashmap (in general) seems like a really bad idea.

It's useful to do deduplication. Like finding (almost) matching vertex-attributes, for when you're indexing your vertex-data.
HashMap<VertexAttr, Integer>


I use it as 'an algorithm', as opposed to (meaningful) storage of data.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings!
Offline Roquen

JGO Kernel


Medals: 518



« Reply #12 - Posted 2015-05-29 11:00:12 »

Yeah that's an example.
Offline basil_

« JGO Bitwise Duke »


Medals: 418
Exp: 13 years



« Reply #13 - Posted 2015-05-29 14:37:26 »

@Roquen thanks for the
Float.floatToIntBits(f+0.f)
neg-zero trick Smiley

got a side-note too : i use http://fastutil.di.unimi.it/ alot, they provide all kinds of hashmaps. the interesting part is, some of them allow us to provide an implementation of equality and hashcodes to the hashmap.

means, with that we can turn the whole thing around and tell the hashmap how to compute hashcodes/equals and not code it into the objects stored. in the end it's the same.
Offline Riven
Administrator

« JGO Overlord »


Medals: 1369
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #14 - Posted 2015-05-29 20:45:47 »

That's indeed the obvious way to go.

It's just like the Comparable interface is a massive design flaw. Use Comparators, already! There is more than one way to order things, and natural order only really applies for numbers, not even strings (see: case sensitiveness).

Burdening every single class with the responsibility to make it usable for a rather specific datastructure is so backwards that it's amazing it hasn't been at least made pluggable in the Collection API.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings!
Pages: [1]
  ignore  |  Print  
 
 

 
Riven (35 views)
2019-09-04 15:33:17

hadezbladez (3999 views)
2018-11-16 13:46:03

hadezbladez (1448 views)
2018-11-16 13:41:33

hadezbladez (4011 views)
2018-11-16 13:35:35

hadezbladez (772 views)
2018-11-16 13:32:03

EgonOlsen (4088 views)
2018-06-10 19:43:48

EgonOlsen (4666 views)
2018-06-10 19:43:44

EgonOlsen (2756 views)
2018-06-10 19:43:20

DesertCoockie (3648 views)
2018-05-13 18:23:11

nelsongames (3852 views)
2018-04-24 18:15:36
Java Gaming Resources
by philfrei
2019-05-14 16:15:13

Deployment and Packaging
by philfrei
2019-05-08 15:15:36

Deployment and Packaging
by philfrei
2019-05-08 15:13:34

Deployment and Packaging
by philfrei
2019-02-17 20:25:53

Deployment and Packaging
by mudlee
2018-08-22 18:09:50

Java Gaming Resources
by gouessej
2018-08-22 08:19:41

Deployment and Packaging
by gouessej
2018-08-22 08:04:08

Deployment and Packaging
by gouessej
2018-08-22 08:03:45
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!