Determining whether a point is inside a square pyramid

Hi monkeys.
I am trying to determine whether a point is inside a square pyramid. I have a square planet and I want to know which face of the planet the player is on. So what I do is for each face in the planet, I get the corners of that face. I then construct 4 triangles using the corner points and the center of the planet. Basically what I do is construct a pyramid in the planet using the center and the 4 corners.
Like this:

For each face of the pyramid I get the cross product of the two corners and then normalize it, and get the dot product of the normalized vector and the player’s physics location. I’m getting weird results, and it doesn’t seem to be working. Can someone look at my code? I don’t have a source of where I got all the equations, it was a result of reading a bunch of forums and lots of googling:

[java]
public int getCurrentFaceOfPlanet(Planet planet)
{
for(int i = 0; i<=5; i++)
{
System.out.println("------------\nFace: “+i+”\n");
PlanetCorner[] corners = planet.getCornersForFace(i);
System.out.println("\nCorner Locations:\n");
System.out.println(corners[0].getWorldTranslation());
System.out.println(corners[1].getWorldTranslation());
System.out.println(corners[2].getWorldTranslation());
System.out.println(corners[3].getWorldTranslation());

		Vector3f P1 = planet.getPlanetNode().getWorldTranslation();
		Vector3f P2 = corners[0].getWorldTranslation();
		Vector3f P3 = corners[1].getWorldTranslation();
		Vector3f P4 = corners[2].getWorldTranslation();
		Vector3f P5 = corners[3].getWorldTranslation();
		
		Vector3f playerP = this.getPhysicsLocation();
		
		Vector3f s1a = P2.subtract(P1);
		Vector3f s1b = P3.subtract(P1);
		Vector3f s1c = s1a.cross(s1b);
		Vector3f s1n = s1c.normalize();
		float s1d = playerP.dot(s1n);
		
		Vector3f s2a = P3.subtract(P1);
		Vector3f s2b = P4.subtract(P1);
		Vector3f s2c = s2a.cross(s2b);
		Vector3f s2n = s2c.normalize();
		float s2d = playerP.dot(s2n);
		
		Vector3f s3a = P4.subtract(P1);
		Vector3f s3b = P5.subtract(P1);
		Vector3f s3c = s3a.cross(s3b);
		Vector3f s3n = s3c.normalize();
		float s3d = playerP.dot(s3n);
		
		Vector3f s4a = P5.subtract(P1);
		Vector3f s4b = P2.subtract(P1);
		Vector3f s4c = s4a.cross(s4b);
		Vector3f s4n = s4c.normalize();
		float s4d = playerP.dot(s4n);
		
		System.out.println("1: "+s1d+" 2: "+s2d+" 3: "+s3d+" 4: "+s4d+"\nPlayer Loc: "+playerP);

	}
	return 0;
}

[/java]

getCornersForFace() returns the corners of that face number in a clockwise order. PlanetNode is at the center of the planet. What am I doing wrong? Sometimes the results for one face are all positive when I try this in 3 different faces, and sometimes negative, etc. The results never seem right. (The return statement is just a temporary placement until I get this working.) If I’m not clear enough let me know. Thanks!

If you calculate the spherical coordinates for a point then it should be easy to determine which “zone” if the sphere they are in. The fact that your sphere is 6 sided makes no real difference.

Going from x,y,z to radians style latitude and longitude is not difficult and then it’s just a matter of checking the range of latitude and longitude. Between -45 and 45, etc…

The nice thing about that approach is that it properly deals with the ambiguous cases of points being above the surface but over corners and stuff. You will always get a valid answer even when the point is “above” two surfaces at once based on planes and normals.

…actually, I’m wrong about the between -45 and 45 thing but still the general approach is sound, I think.

Edit: I should really be working instead of answering posts here… but…

Figure out the polar coordinate for x,z in the x,z plane. This will give you the general horizontal quadrant that your point is in… that really will be between -45 to 45, 45 to 135, etc…

Depending on which quadrant you are in the do another polar coordinate with x,y or z,y depending on whether you are x major or z major in the quadrant. That polar coordinate can also be checked between -45 and 45, etc. because you’ve sliced the world again on the proper axis. These aren’t spherical coordinates it’s double polar coordinates or something but will give you which “side” your point is relative to.

I think I see what you mean. As for the issue with players being above the surface but over the corner, that’s actually not an issue in my case. I want it so when the player crosses over the corner/edge their player is rotated so they are on another face of the planet. So once the player crosses the edge it would think it is on the next face, which in my case is a good thing. I’ll look into your idea and maybe it will work better. I’m still curious why mine didn’t work though :stuck_out_tongue: Thanks!

@PewPewKapowie said: I think I see what you mean. As for the issue with players being above the surface but over the corner, that's actually not an issue in my case. I want it so when the player crosses over the corner/edge their player is rotated so they are on another face of the planet. So once the player crosses the edge it would think it is on the next face, which in my case is a good thing. I'll look into your idea and maybe it will work better. I'm still curious why mine didn't work though :P Thanks!

I didn’t look at yours in detail but a common problem with something like this is making sure the cross products are consistently oriented and stuff. a.cross(b) points in the opposite direction of b.cross(a) so if you aren’t careful you can end up with backwards normals.

Anyway, the mathematically accurate version is simpler (in my opinion) and deals with the edge problem (which you say is unneeded but the solution is free, so…). You may find down the road that you are glad to have dealt with the carved space/edge issues. Presuming you ever animate the “walking over the corner” then you won’t have to do anything special.

Hahah… something just occurred to me as I was simplifying things into just three atan2() calls… and I think removed the need to do the call at all. 45 degree angles are kind of a wonderful thing.

Presuming you have x,y,z relative to the center of the cuboid thing and presuming that you are using standard y-up, z into screen JME/OpenGL conventions…

[java]
if( Math.abs(y) > Math.abs(x) && Math.abs(y) > Math.abs(z) ) {
// on top or bottom, ie: it’s farther up than it is to either side.
// at x == y or z == y you’d be at the 1:1 slope point (45 degrees)
if( y < 0 ) {
// bottom
} else {
// top
}
} else if( Math.abs(x) > Math.abs(z) ) {
if( x < 0 ) {
// “west”
} else {
// “east”
}
} else if( Math.abs(z) > Math.abs(x) ) {
if( z < 0 ) {
// “north”
} else {
// “south”
}
} else {
// you are sitting right on a corner of the
// cube and >= above would avoid this.
}
[/java]

At least it seems right… if I transcribed it right.

1 Like

Oh wow… it works. You just blew my mind, big time.

I tend to overthink things :slight_smile: Thanks!!