Author Topic: Picking and 2D Bounds  (Read 4123 times)

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Picking and 2D Bounds
« on: October 23, 2011, 07:22:08 am »
I'm doing picking with the mouse on objects. I'm creating the textured plane like this:
Code: [Select]
     private Object3D createPlane(String textureName) {
Texture texture = TextureManager.getInstance().getTexture(textureName);
Object3D plane = Primitives.getPlane(1, texture.getWidth()/6);
plane.setTransparency(100);
plane.setTexture(textureName);
plane.setSelectable(Object3D.MOUSE_SELECTABLE);
plane.build();
return plane;
     }

Then I'm trying to get 2D bounds as follows:
Code: [Select]
     public Rectangle getBounds2D(Camera theCamera, FrameBuffer buffer) {
if (sourceMesh == null) {
     VertexController controller = new VertexController(this.unitPlane.getMesh());
     sourceMesh = controller.getSourceMesh();
}
SimpleVector p1 = new SimpleVector(sourceMesh[0]), p2 = new SimpleVector(sourceMesh[1]);
SimpleVector p3 = new SimpleVector(sourceMesh[2]), p4 = new SimpleVector(sourceMesh[3]);
p1.matMul(unitPlane.getWorldTransformation());p2.matMul(unitPlane.getWorldTransformation());
p3.matMul(unitPlane.getWorldTransformation());p4.matMul(unitPlane.getWorldTransformation());
p1 = Interact2D.project3D2D(theCamera, buffer, p1);
p2 = Interact2D.project3D2D(theCamera, buffer, p2);
p3 = Interact2D.project3D2D(theCamera, buffer, p3);
p4 = Interact2D.project3D2D(theCamera, buffer, p4);
float x1 = p1.x, x2, y1 = p1.y, y2;
if (x1 != p2.x)
     x2 = p2.x;
else x2 = p3.x;
if (y1 != p2.y)
     y2 = p2.y;
else y2 = p3.y;
System.out.println("X: "+x1 +" Y: "+y1 +" WIDTH : "+((int)Math.abs(x1-x2)) +" HEIGHT: "+(int)Math.abs(y1-y2));
return new Rectangle((int)x1, (int)y1, (int)Math.abs(x1-x2), (int)Math.abs(y1-y2));
     }

The trouble is that only the same two planes are selectable (the others aren't) and x1 is often negative (and it's always the right values for the same two).

I should add that I've rotated all the objects (but not the camera) by -90 degrees around the X axis so that I'm looking down on them from above (the world is on the X/Y plane).
« Last Edit: October 23, 2011, 08:39:21 am by AGP »

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12298
    • View Profile
    • http://www.jpct.net
Re: Picking and 2D Bounds
« Reply #1 on: October 23, 2011, 07:40:44 pm »
It would be easier to use the PolygonManager to get the vertcies transformed into world space. To calculate the bounds in 2D you have to do the same thing that you did to calculate  them in 3D in the other thread. I'm not sure what the two ifs you are using now are supposed to do...

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Picking and 2D Bounds
« Reply #2 on: October 23, 2011, 08:41:48 pm »
No, I know, but in this particular instance I'm not going to rotate anything anymore. So shouldn't it work? And is it weird that it consistently works for two planes, and consistently doesn't for the other four?

The ifs on getBounds2D test for whether the Rectangle has width and height that are non-zero.

Also, how are the polygon IDs arranged? 0-PolygonManager.getMaxPolygonID() ?
« Last Edit: October 23, 2011, 09:18:00 pm by AGP »

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12298
    • View Profile
    • http://www.jpct.net
Re: Picking and 2D Bounds
« Reply #3 on: October 23, 2011, 10:46:00 pm »
Hard to tell, as i've no idea what unitPlane for example is...however, i would simply rewrite this to use the PolygonManager instead (yes, IDs go from 0 to max (exclusive IIRC)) and do a proper min/max-calculation to get a correct bounding box for all cases.

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Picking and 2D Bounds
« Reply #4 on: October 24, 2011, 04:38:39 am »
OK, I wrote this:
Code: [Select]
     public Rectangle newBounds2D(Camera theCamera, FrameBuffer buffer) {
PolygonManager polyManager = unitPlane.getPolygonManager();
SimpleVector[] vertices = new SimpleVector[polyManager.getMaxPolygonID()*3];
int currentPoly = 0;
float minX = Float.MAX_VALUE, minY = Float.MAX_VALUE, minZ = Float.MAX_VALUE;
float maxX = Float.MIN_VALUE, maxY = Float.MIN_VALUE, maxZ = Float.MIN_VALUE;
for (int i = 0; i < vertices.length; i+=3) {
     vertices[i] = polyManager.getTransformedVertex(currentPoly, 0);
     vertices[i+1] = polyManager.getTransformedVertex(currentPoly, 1);
     vertices[i+2] = polyManager.getTransformedVertex(currentPoly++, 2);
     if (minX > vertices[i].x)
minX = vertices[i].x;
     if (minX > vertices[i+1].x)
minX = vertices[i+1].x;
     if (minX > vertices[i+2].x)
minX = vertices[i+2].x;
     if (maxX < vertices[i].x)
maxX = vertices[i].x;
     if (maxX < vertices[i+1].x)
maxX = vertices[i+1].x;
     if (maxX < vertices[i+2].x)
maxX = vertices[i+2].x;
     if (minY > vertices[i].y)
minY = vertices[i].y;
     if (minY > vertices[i+1].y)
minY = vertices[i+1].y;
     if (minY > vertices[i+2].y)
minY = vertices[i+2].y;
     if (maxY < vertices[i].y)
maxY = vertices[i].y;
     if (maxY < vertices[i+1].y)
maxY = vertices[i+1].y;
     if (maxY < vertices[i+2].y)
maxY = vertices[i+2].y;
     if (minZ > vertices[i].z)
minZ = vertices[i].z;
     if (minZ > vertices[i+1].z)
minZ = vertices[i+1].z;
     if (minZ > vertices[i+2].z)
minZ = vertices[i+2].z;
     if (maxZ < vertices[i].z)
maxZ = vertices[i].z;
     if (maxZ < vertices[i+1].z)
maxZ = vertices[i+1].z;
     if (maxZ < vertices[i+2].z)
maxZ = vertices[i+2].z;
}
return getBounds2D(theCamera, buffer, minX, minY, maxX, maxY);
     }
     public Rectangle getBounds2D(Camera theCamera, FrameBuffer buffer, float minX, float minY, float maxX, float maxY) {
SimpleVector minP = Interact2D.project3D2D(theCamera, buffer, new SimpleVector(minX, minY, 0));
SimpleVector maxP = Interact2D.project3D2D(theCamera, buffer, new SimpleVector(maxX, maxY, 0));
return new Rectangle((int)minP.x, (int)minP.y, (int)Math.abs(maxP.x-minP.x), (int)Math.abs(maxP.y-minP.y));
     }

Exact same problem, though.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12298
    • View Profile
    • http://www.jpct.net
Re: Picking and 2D Bounds
« Reply #5 on: October 24, 2011, 06:59:54 am »
What exactly IS the actual problem with this? I didn't really get it so far...

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Picking and 2D Bounds
« Reply #6 on: October 24, 2011, 07:10:41 am »
Try it out. I've sent it to you (chopped as much of it as possible but there's still some fat).

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12298
    • View Profile
    • http://www.jpct.net
Re: Picking and 2D Bounds
« Reply #7 on: October 26, 2011, 07:06:59 am »
For those reading this thread: The wiki/documentation on Interact2D.pickPolygon() got the order in the result array reversed (at least for some parts of the documentation), which caused confusion. The wiki is already fixed, the documentation will be fixed in the next version.

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Picking and 2D Bounds
« Reply #8 on: November 04, 2011, 10:26:47 pm »
PART 2: maxX and maxY seem to both be at the origin, making the bounding box of something built on Cartesian quadrant 2 (relative to the origin) much bigger than it should be.

(By the way, the KeyMapper thing still isn't solved. I'm starting to think it's a Java 7 thing.)

Code: [Select]
     public Rectangle newBounds2D(Camera theCamera, FrameBuffer buffer) {
PolygonManager polyManager = unitPlane.getPolygonManager();
SimpleVector[] vertices = new SimpleVector[polyManager.getMaxPolygonID()*3];
int currentPoly = 0;
float minX = Float.MAX_VALUE, minY = Float.MAX_VALUE, minZ = Float.MAX_VALUE;
float maxX = Float.MIN_VALUE, maxY = Float.MIN_VALUE, maxZ = Float.MIN_VALUE;
for (int i = 0; i < vertices.length; i+=3) {
     vertices[i] = polyManager.getTransformedVertex(currentPoly, 0);
     vertices[i+1] = polyManager.getTransformedVertex(currentPoly, 1);
     vertices[i+2] = polyManager.getTransformedVertex(currentPoly++, 2);
     if (minX > vertices[i].x)
minX = vertices[i].x;
     if (minX > vertices[i+1].x)
minX = vertices[i+1].x;
     if (minX > vertices[i+2].x)
minX = vertices[i+2].x;
     if (maxX < vertices[i].x)
maxX = vertices[i].x;
     if (maxX < vertices[i+1].x)
maxX = vertices[i+1].x;
     if (maxX < vertices[i+2].x)
maxX = vertices[i+2].x;
     if (minY > vertices[i].y)
minY = vertices[i].y;
     if (minY > vertices[i+1].y)
minY = vertices[i+1].y;
     if (minY > vertices[i+2].y)
minY = vertices[i+2].y;
     if (maxY < vertices[i].y)
maxY = vertices[i].y;
     if (maxY < vertices[i+1].y)
maxY = vertices[i+1].y;
     if (maxY < vertices[i+2].y)
maxY = vertices[i+2].y;
     if (minZ > vertices[i].z)
minZ = vertices[i].z;
     if (minZ > vertices[i+1].z)
minZ = vertices[i+1].z;
     if (minZ > vertices[i+2].z)
minZ = vertices[i+2].z;
     if (maxZ < vertices[i].z)
maxZ = vertices[i].z;
     if (maxZ < vertices[i+1].z)
maxZ = vertices[i+1].z;
     if (maxZ < vertices[i+2].z)
maxZ = vertices[i+2].z;
}
return getBounds2D(theCamera, buffer, minX, minY, maxX, maxY);
     }
     public Rectangle getBounds2D(Camera theCamera, FrameBuffer buffer, float minX, float minY, float maxX, float maxY) {
SimpleVector minP = Interact2D.project3D2D(theCamera, buffer, new SimpleVector(minX, minY, -20f));//z=0f
SimpleVector maxP = Interact2D.project3D2D(theCamera, buffer, new SimpleVector(maxX, maxY, -20f));//z=0f
return new Rectangle((int)minP.x, (int)minP.y, (int)Math.abs(maxP.x-minP.x), (int)Math.abs(maxP.y-minP.y));
     }

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12298
    • View Profile
    • http://www.jpct.net
Re: Picking and 2D Bounds
« Reply #9 on: November 04, 2011, 11:15:44 pm »
Maybe because you are actually calculating the box in 3D world space and then project that into 2D. I think the right solution would be to project it into 2D and then calculate the box based on that.

About the KeyMapper...i'm not sure about this. Don't the keyPressed()/keyReleased() methods get called?

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Picking and 2D Bounds
« Reply #10 on: November 05, 2011, 03:06:05 am »
Only keyReleased gets called with key code 0. It's weird.

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Picking and 2D Bounds
« Reply #11 on: November 06, 2011, 09:47:31 pm »
As per your suggestion, I wrote this:
Code: [Select]
     private Point[] get2DVertices(SimpleVector[] vertices3d, Camera theCamera, FrameBuffer buffer) {
Point[] vertices = new Point[vertices3d.length];
for (int i = 0; i < vertices.length; i++) {
     SimpleVector point = Interact2D.project3D2D(theCamera, buffer, vertices3d[i]);
     vertices[i] = new Point((int)(point.x+.5f), (int)(point.y+.5f));
}
return vertices;
     }
     public Rectangle get2DBounds(Camera theCamera, FrameBuffer buffer) {
System.out.println("get2DBounds");
PolygonManager polyManager = unitPlane.getPolygonManager();
SimpleVector[] vertices3d = new SimpleVector[polyManager.getMaxPolygonID()*3];
int currentPoly = 0;
int minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, minZ = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE, maxZ = Integer.MIN_VALUE;
for (int i = 0; i < vertices3d.length; i+=3) {
     vertices3d[i] = polyManager.getTransformedVertex(currentPoly, 0);
     vertices3d[i+1] = polyManager.getTransformedVertex(currentPoly, 1);
     vertices3d[i+2] = polyManager.getTransformedVertex(currentPoly++, 2);
}
Point[] vertices = this.get2DVertices(vertices3d, theCamera, buffer);
for (int i = 0; i < vertices.length; i+=3) {
     if (minX > vertices[i].x)
minX = vertices[i].x;
     if (minX > vertices[i+1].x)
minX = vertices[i+1].x;
     if (minX > vertices[i+2].x)
minX = vertices[i+2].x;
     if (maxX < vertices[i].x)
maxX = vertices[i].x;
     if (maxX < vertices[i+1].x)
maxX = vertices[i+1].x;
     if (maxX < vertices[i+2].x)
maxX = vertices[i+2].x;
     if (minY > vertices[i].y)
minY = vertices[i].y;
     if (minY > vertices[i+1].y)
minY = vertices[i+1].y;
     if (minY > vertices[i+2].y)
minY = vertices[i+2].y;
     if (maxY < vertices[i].y)
maxY = vertices[i].y;
     if (maxY < vertices[i+1].y)
maxY = vertices[i+1].y;
     if (maxY < vertices[i+2].y)
maxY = vertices[i+2].y;
}
return new Rectangle(minX, minY, (int)Math.abs(maxX-minX), (int)Math.abs(maxY-minY));
     }

Now my question is: how expensive is the project3d2d method? Because as it is I'm using it on all the vertices as opposed to just what I had perceived as necessary...

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12298
    • View Profile
    • http://www.jpct.net
Re: Picking and 2D Bounds
« Reply #12 on: November 06, 2011, 10:44:44 pm »
Shouldn't be too expensive (as long as the models aren't too complex). To speed it up a little, you can enable lazy transformation at the beginning of the method and disable it afterwards.
« Last Edit: November 06, 2011, 10:50:12 pm by EgonOlsen »