How to determine closest point on plane vs aabb

Started by
7 comments, last by Dirk Gregorius 8 years, 7 months ago
Hi there,

how do i determine the closest point from a plane to a axis aligned box in 2D?
The plane does already have the normal which may not be not axis-aligned.

I know how to do the closest point against plane, against box, against circle, against line segment but not this one.
Also i know the concept of using the minkowski sum, but this wont work in this case either sad.png

In my current state i cant find a solution, even though i am sure that its easy.

Does anyone have some tips for me?

Thanks in advance,
Final
Advertisement

how do i determine the closest point from a plane to a axis aligned box in 2D?


I was with you until "in 2D". Can you explain what you want, as precisely as possible?

how do i determine the closest point from a plane to a axis aligned box in 2D?


I was with you until "in 2D". Can you explain what you want, as precisely as possible?


In case the plane are not axis aligned, it seems that the edge which are closest to the plane are the closest one...

plane_aabb.png

And when plane are axis aligned:

plane_aabb_2.png
If the AABB is always axis aligned (which, by definition, it is), then all you have to do is use your plane's normal to determine which faces/edges/vertices to test.

If the normal has exactly three nonzero components, then test against the two corresponding vertices.
If the normal has exactly two nonzero components, then test against the two parallel edges (using two components of either vertex of that edge).
If the normal has exactly one nonzero component, then test against the two parallel faces (using one component of any vertex of that face).
Else, explode in a massive ball of fire.

If you only want to find faces/edges/vertices with normals pointing towards your plane, then you only have to test one feature instead of two. If you're treating your plane as double-sided, then you test the near and far features (the features on the opposite sides of the box).

If the AABB is always axis aligned (which, by definition, it is), then all you have to do is use your plane's normal to determine which faces/edges/vertices to test.

If the normal has exactly three nonzero components, then test against the two corresponding vertices.
If the normal has exactly two nonzero components, then test against the two parallel edges (using two components of either vertex of that edge).
If the normal has exactly one nonzero component, then test against the two parallel faces (using one component of any vertex of that face).
Else, explode in a massive ball of fire.

If you only want to find faces/edges/vertices with normals pointing towards your plane, then you only have to test one feature instead of two. If you're treating your plane as double-sided, then you test the near and far features (the features on the opposite sides of the box).

What wait? This seems like SAT... i just need to project all 4 box vertices to the normal and use the vertices which projection are the nearest...

And using this vertex to get the closest point are just like point vs plane...

In the other case i must first check if the plane are axis aligned with the box, then i just can use the box center and its extend... hmm... yeah this may work.

Oh wait, there is a easier way - if two vertices have the same projected distance then its axis aligned. So basically all boils down to projection...

Thanks!!!

And here my resulting code - Thanks for that hint!


		Vec2f[] vertices = new Vec2f[4];
		vertices[0] = new Vec2f(bodyB.pos.x + box.radius.x, bodyB.pos.y + box.radius.y);
		vertices[1] = new Vec2f(bodyB.pos.x - box.radius.x, bodyB.pos.y + box.radius.y);
		vertices[2] = new Vec2f(bodyB.pos.x - box.radius.x, bodyB.pos.y - box.radius.y);
		vertices[3] = new Vec2f(bodyB.pos.x + box.radius.x, bodyB.pos.y - box.radius.y);
		Vec2f nearestVertexA = vertices[0];
		Vec2f nearestVertexB = null;
		float nearestDistance = nearestVertexA.dot(normal);
		boolean axisAligned = false;
		for (int i = 1; i < vertices.length; i++) {
			Vec2f v = vertices[i];
			float p = v.dot(normal);
			if (p < nearestDistance) {
				nearestDistance = p;
				nearestVertexA = v;
			} else if (p == nearestDistance) {
				nearestVertexB = v;
				axisAligned = true;
			}
		}
		
		Vec2f planePoint = plane.getPoint();
		Vec2f distanceToPlane = new Vec2f(nearestVertexA).sub(planePoint);
		float projDistance = distanceToPlane.dot(normal);
		Vec2f closestPoint = new Vec2f();

		if (axisAligned) {
			float projRadius = Math.abs(box.radius.dot(normal));
			float d = projRadius + projDistance;
			closestPoint.set(bodyB.pos).addMultScalar(normal, -d);
		} else {
			closestPoint.set(nearestVertexA).addMultScalar(normal, -projDistance);
		}

Just get the support point on the box in the negative direction of the plane normal. This will give you both the closest point and penetration

Just get the support point on the box in the negative direction of the plane normal. This will give you both the closest point and penetration

Using support points seems to be exactly the same as projecting the vertices against the normal, but searching for the greatest distance instead. Plugging in a negative normal into that gives me the exact same result i have right now -> the vertex with the smallest distance...

I dont see any difference...

I don't understand why you want to return the projected center in case the plane is axis aligned. The vertices should be equally good. Here is how I would break this up. Maybe it helps.


Vector3 ClosestPointOnPlane( Bounds3 aabb, Plane plane )
{
    Vector3 support = aabb->Support( -plane.m_Normal );
    return plane.Project( support );
}

Vector3 Bounds3::Support( Vector3 v )
{
    Vector support;
    support.x = v.x < 0 ? m_Min.x : m_Max.x;
    support.x = v.y < 0 ? m_Min.y : m_Max.y;
    support.x = v.z < 0 ? m_Min.z : m_Max.z;

    return support;
}

Vector Plane::Project( Vector3 p )
{
    float distance = dot( m_Normal, p ) - m_Offset;
    return p - distance * m_Normal;
}

This topic is closed to new replies.

Advertisement