how to get closest edge normal?

Official forum for the Chipmunk2D Physics Library.
Post Reply
Joseph39
Posts: 10
Joined: Mon Dec 07, 2015 1:50 am
Contact:

how to get closest edge normal?

Post by Joseph39 »

i know there is a way to get the closest point on the surface of a shape to a specific point inside it using cpPointQueryInfo

but is there an easy way to get the closest edge normal to a point inside a cpshape?
Joseph39
Posts: 10
Joined: Mon Dec 07, 2015 1:50 am
Contact:

Re: how to get closest edge normal?

Post by Joseph39 »

i managed to find a couple of good solutions for my problem after a good night sleep!!
what i needed to find is the closest edge normal to a point inside a cpshape?

so in turn the real question is how to find the closest edge to a point? and from there getting the normal is the easy part

since we can get the nearest point to the surface from cpPointQueryInfo using cpShapePointQuery()

and since the nearest point to the surface lies by default on the closest edge then all what we have to do is get the segment that the point is lying on by iterating thru each pair of vertices (face) and check if the nearest point is on the current pair of vertices (face) being iterated. and if it is then we have our closest edge and all what is left to do is get the normal!

and to check if our nearest point to the surface is lieing on a segment i used this method:

Code: Select all

// check if point p is on segment ab
static bool onSegment(const Point& a, const Point& b, const Point& p)
{
	if (p.x <= std::max(a.x, b.x) && p.x >= std::min(a.x, b.x) &&
		p.y <= std::max(a.y, b.y) && p.y >= std::min(a.y, b.y))
		return true;
	return false;
}
in total this is how it should look like

Code: Select all

// get transformed vertices
int count = cpPolyShapeGetCount(shape);
cpVect* verts = new cpVect[count];
for(int i=0;i<count;++i) 
	verts[i] = cpBodyLocalToWorld(body, cpPolyShapeGetVert(shape, i));

// p is our point which is inside the the shape
cpVect p = cpv(x, y);

cpPointQueryInfo info;
cpShapePointQuery(cpshape, p, &info);

// this point is on the closest surface
cpVect closestPoint = info.point;

// iterate thru each pair of vertices (face)
cpVect closestEdgeNormal;
for (int i = 0; i < count; i++)
{
	int next = i + 1 < count ? i + 1 : 0;
	cpVect a = verts[i];
	cpVect b = verts[next];
	
	if (onSegment(a, b, closestPoint))
	{
		// get perpendicular vector then normalize
		closestEdgeNormal = cpvnormalize(cpvperp(cpvsub(a, b)));
		
		//no point in continuing once we found our normal
		break;
	}

}

delete[] verts;
another approach which doesn't use a nearest point on surface would be to find the shortest distance to a particular edge using the dot product like this:

Code: Select all

cpVect closestEdgeNormal;
float shortestDistance = FLT_MAX;
for (int i = 0; i < count; i++)
{
	// project the vertex position relative to the position inside onto the edge's normal to find the distance
	int next = i + 1 < count ? i + 1 : 0;
	cpVect a = verts[i];
	cpVect b = verts[next];
	
	cpVect currentNormal = cpvnormalize(cpvperp(cpvsub(a, b)));
	
	float distance = cpvdot(currentNormal, cpvsub(a, p))
	if (distance < shortestDistance)
	{
		// store the shortest distance
		shortestDistance = distance;
		
		closestEdgeNormal = currentNormal;
	}
}
// only after the loop ends (all faces looped) then we can get our closest edge normal.
Post Reply

Who is online

Users browsing this forum: No registered users and 6 guests