Getting distance of a point in a 2d triangle without calculating perpendicular..

I made this for the lolz. Both methods appear to work just fine. Note the mouse position is slightly off because positions in the frame and panel don’t match exactly due to the menu at the top. Just look at where the cyan dot is.


import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class TrianglePointContains extends JFrame implements MouseMotionListener
{
	private static Vector3f mouseLocation;
	private static Vector3f vertexA;
	private static Vector3f vertexB;
	private static Vector3f vertexC;
	private static TrianglePanel sameSidePanel;
	private static TrianglePanel barycentricPanel;
	
	public TrianglePointContains()
	{
		super("Triangle Point Contains");
		
		//totally arbitrary points
		mouseLocation = new Vector3f(0,0,0);
		vertexA = new Vector3f(200, 50, 0);
		vertexB = new Vector3f(50, 350, 0);
		vertexC = new Vector3f(350, 350, 0);
		
		setLayout(new GridLayout(1,2));
		sameSidePanel = new TrianglePanel( false );
		barycentricPanel = new TrianglePanel( true );
		sameSidePanel.setSize(400,400);
		barycentricPanel.setSize(400,400);
		add(sameSidePanel);
		add(barycentricPanel);
		
		addMouseMotionListener( this );
		
		setSize(800,400);
		setVisible(true);
	}
	
	public static void main(String[] args)
	{
		new TrianglePointContains();
	}
	
	public static boolean isPointInTriangle( boolean barycentric, Vector3f p, Vector3f a, Vector3f b, Vector3f c )
	{
		if ( barycentric )
		{
			Vector3f v0 = c.subtract(a);
			Vector3f v1 = b.subtract(a);
			Vector3f v2 = p.subtract(a);

			float dot00 = v0.dot(v0);
			float dot01 = v0.dot(v1);
			float dot02 = v0.dot(v2);
			float dot11 = v1.dot(v1);
			float dot12 = v1.dot(v2);

			float inverse = 1.0f / (dot00 * dot11 - dot01 * dot01);
			float u = (dot11 * dot02 - dot01 * dot12) * inverse;
			float v = (dot00 * dot12 - dot01 * dot02) * inverse;

			return (u >= 0) && (v >= 0) && (u + v < 1);
		}
		
	    return ( pointsAreOnSameSide(p, a, b, c) && pointsAreOnSameSide(p, b, a, c) && pointsAreOnSameSide(p, c, a, b) );
	}

	private static boolean pointsAreOnSameSide( Vector3f p1, Vector3f p2, Vector3f a, Vector3f b )
	{
	    Vector3f diffba = b.subtract(a);
	    Vector3f diffp1a = p1.subtract(a);
	    Vector3f diffp2a = p2.subtract(a);

	    Vector3f cross1 = diffba.cross(diffp1a);
	    Vector3f cross2 = diffba.cross(diffp2a);

	    return ( cross1.dot( cross2 ) >= 0 );
	}
	
	private static Vector3f getAdjustedMousePosition( boolean barycentric )
	{
		if ( mouseLocation.x >= sameSidePanel.getWidth() )
		{
			return new Vector3f( mouseLocation.x - sameSidePanel.getWidth(), mouseLocation.y, mouseLocation.z );
		}
		return mouseLocation;
	}
	
	public void mouseMoved( MouseEvent e )
	{
		mouseLocation.x = e.getX();
		mouseLocation.y = e.getY();
		repaint();
	}
	
	public void mouseDragged( MouseEvent e )
	{
		mouseLocation.x = e.getX();
		mouseLocation.y = e.getY();
		repaint();
	}
	
	private class TrianglePanel extends JPanel
	{
		private boolean isBarycentric;
		
		public TrianglePanel( boolean barycentric )
		{
			isBarycentric = barycentric;
		}
		
		public void paintComponent( Graphics g )
		{
			super.paintComponent(g);
			
			Vector3f mousePos = getAdjustedMousePosition( isBarycentric );
			boolean containsPoint = isPointInTriangle( isBarycentric, mousePos, vertexA, vertexB, vertexC );
			Polygon p = new Polygon(new int[]{ (int)vertexA.x, (int)vertexB.x, (int)vertexC.x }, new int[] { (int)vertexA.y, (int)vertexB.y, (int)vertexC.y }, 3);
			g.setColor( containsPoint ? Color.RED : Color.GREEN );
			((Graphics2D)g).fill( p );
			g.setColor(Color.BLACK);
			((Graphics2D)g).draw( p );
			
			g.setColor(Color.CYAN);
			g.fillOval( (int)mousePos.x-2, (int)mousePos.y-2, 4, 4 );
		}
	}
	
	private static class Vector3f
	{
		public float x, y, z;
		
		public Vector3f( float setX, float setY, float setZ )
		{
			x = setX;
			y = setY;
			z = setZ;
		}
		
		public float dot( Vector3f other )
		{
			return x * other.x + y * other.y + z * other.z;
		}
		
		public Vector3f cross( Vector3f other )
		{
			return new Vector3f
			(
				(y * other.z) - (other.y * z),
				(z * other.x) - (other.z * x),
				(x * other.y) - (other.x * y)
			);
		}
		
		public Vector3f subtract( Vector3f other )
		{
			return new Vector3f
			(
				x - other.x,
				y - other.y,
				z - other.z
			);
		}
	}
}

Alright so this all started when I asked a question on here, which got answered, but I dunno if the answer is correct yet (though I’m assuming it is, in all honesty) So I haven’t said thank you to Eli yet (You will get it, or at least more replies once I figure out if it works or not).

anyway, I digress. I asked a question on StackOverflow about Getting the distance of a point between two lines and got a answer that said to: “find the straight line that links A and D and get its equation in the form: y = m_1 * x + c_1” So I got no idea how to do this, and the person who gave the answer has stopped replying, so I come to you guys. How do I do that?

Well if you took basic geometry…it’s the usual y=mx+b formula. Just plug it in :wink:

m = slope
b = offset

Isn’t the distance formula this?


distance = sqrt( (x2-x1)^2 + (y2-y1)^2)

Because I’m pretty sure that y=mx+b is a linear equation. (not sure on exact terminology)

Okay, I think I got that down, thanks ra4king.

	public float GetDist(Vector3f one, Vector3f two, Vector3f three, Vector3f p){
		
		
	      Vector3f one_to_point = new Vector3f(0,0,0);
	      Vector3f.sub(p,one,one_to_point);            //Storing vector A->P
	      
	      Vector3f oneToPNorm = new Vector3f(one_to_point);
	      oneToPNorm.normalise();
	     
	      float m = oneToPNorm.y/oneToPNorm.x;
	      float b = oneToPNorm.x/oneToPNorm.y;

Okay,so now the guy just kinda says I can “solve this pair of simultaneous equations to get the point (x,y) that lies at the green circle on your diagram” But doesn’t say how I can do that…

What Geemili said is right, go with it.

If you know two distinct points that are on a line you can calculate the equation of the line. Here’s a site that explains how:

http://www.webmath.com/equline1.html

Once you have the equation of your two lines then you can calculate where they intersect and from there you can solve your original problem.

Alright, I’m trying to make a player walk on a slope. It’s not working, well it is, but there seems to be a shitton of jittering when you walk on the beginning of the slope.

onGround = false;
			Vector3f prevPos = new Vector3f(pos);
			
			if(!jumping && !flying && !hovering) pos.y += fallSpeed + height;
			
			boolean b = false;
			Vector<Tri> tris = model.meshes.get(0).getTrisTouching(pos);
			float minY;
			if(tris.size() > 0) minY = Float.POSITIVE_INFINITY;
			else minY = 0;
			
			for(int i = 0; i < tris.size(); i++){
				Tri q = tris.get(i);
				Normal normal = q.cn;
				if(normal.pos.y <= -0.3f){//asdf
					float dist = Vector3f.dot(pos, normal.pos) - Vector3f.dot(q.center, normal.pos);
					radius = 4;
					
					if(dist < 1){
				    	Vector3f[] quad = model.meshes.get(0).getTriAsArray(q.index - 1);
	
				    	if(prevPos.y + radius <= q.max.y){
				    		//closestPoint = GetClosestPoint(quad[0], quad[2], pos, normal.pos, fallSpeed + height, delta, false);
				    	//	float quadDist = GetDist(quad[0],quad[2], quad[1], pos);
				    		//float quadDist = GetDist2d(new Vector2f(quad[0].x, quad[0].z),new Vector2f(quad[1].x, quad[1].z), new Vector2f(quad[2].x, quad[2].z), new Vector2f(pos.x, pos.z));
				    	//	System.out.println("quadDist:\t" + quadDist);
				    		
				    		if(q.min.y != q.max.y){

				    			float quadDist = getDist(pos, q.v1, q.v2, q.v3);
					    		float sizeChunk = (q.max.y - q.min.y);
					    		float curY = q.min.y + (sizeChunk*quadDist);
					    		
					    		System.out.println("quadDist: " + quadDist);
					    		
					    		if(curY < minY) minY = curY;
				    		}
				    		
				    		else
				    			minY = q.min.y;
				    		
				    		b = true;
					   	}
					}
				}
			}

			if(b){
				onGround = true;
				hovering = false;
				flying = false;
				pos.y = minY - height;
					    		
			}
			
			else{
				pos.y -= height;
			}

And this is getDist

public float getDist( Vector3f p, Vector3f a, Vector3f b, Vector3f c )
	{
	    Vector3f v0 = new Vector3f(0,0,0);
	    Vector3f.sub( c, a, v0 );
	    Vector3f v1 = new Vector3f(0,0,0);
	    Vector3f.sub( b, a, v1);
	    Vector3f v2 = new Vector3f(0,0,0);
	    Vector3f.sub( p, a, v2 );

	    float dot00 = Vector3f.dot(v0, v0);
	    float dot01 = Vector3f.dot(v0, v1);
	    float dot02 = Vector3f.dot(v0, v2);
	    float dot11 = Vector3f.dot(v1, v1);
	    float dot12 = Vector3f.dot(v1, v2);

	    float inverse = 1.0f / (dot00 * dot11 - dot01 * dot01);
	    float u = (dot11 * dot02 - dot01 * dot12) * inverse;
	    float v = (dot00 * dot12 - dot01 * dot02) * inverse;

	    if((u >= 0) && (v >= 0) && (u + v <= 1)) return (float) (Math.sin(u) * Math.cos(v));
	    else return 0;
	}

This is my code for it. Are there any other parts I’ll need to post?

Oh, and here’s the download so you can see how it jitters.
https://dl.dropbox.com/u/28109593/jitter-test.zip

So yeah, this is what I’m trying to do:

Alright, so I’m trying to achieve whats in this image: https://dl.dropbox.com/u/28109593/dotsexample.png

I believe this would be a barycentric coord system, but where the X always equals 1? Basically I need it to only increase/decrease when I move towards/away from the highest point in my triangle. This is the code I got for it so far (Note I’m using the LWJGL library in java).

public float getDist( Vector3f p, Vector3f a, Vector3f b, Vector3f c )
   {
       Vector3f v0 = new Vector3f(0,0,0);
       Vector3f.sub( c, a, v0 );
       Vector3f v1 = new Vector3f(0,0,0);
       Vector3f.sub( b, a, v1);
       Vector3f v2 = new Vector3f(0,0,0);
       Vector3f.sub( p, a, v2 );

       float dot00 = Vector3f.dot(v0, v0);
       float dot01 = Vector3f.dot(v0, v1);
       float dot02 = Vector3f.dot(v0, v2);
       float dot11 = Vector3f.dot(v1, v1);
       float dot12 = Vector3f.dot(v1, v2);

       float inverse = 1.0f / (dot00 * dot11 - dot01 * dot01);
       float u = (dot11 * dot02 - dot01 * dot12) * inverse;
       float v = (dot00 * dot12 - dot01 * dot02) * inverse;

       if((u >= 0) && (v >= 0) && (u + v <= 1)) return (float) (Math.sin(u) * Math.cos(v));
       else return 0;
   }

I guess what I’m asking is: Is there a way to get the distance that a point inside a triangle has travailed from the lowest point the triangle has in space where 1 would be the highest point on the triangle (mosty far away from the lowist) without taking it’s deviating vector into account? I.E. notice that the two red dots on the image have the same coords even though they have different dists from the top’s x?

https://dl.dropbox.com/u/28109593/axisexample.png

Getting distance of a point in a 2d triangle without calculating perpendicular vectors? <-- full topic

Alright, so I’m trying to get the distance of a point in a 2d triangle without calculating perpendicular vectors.

float qd = Vector2f.dot(new Vector2f(pos.x, pos.z), new Vector2f(normal.pos.x, normal.pos.z)) - Vector2f.dot(new Vector2f(q.center.x, q.center.z), new Vector2f(normal.pos.x, normal.pos.z));

That’s the code I’m using. (Note: it’s converting 3f vectors to 2d ones, but you don’t have to worry about that). I need the result of the calculation to be between 0 and 1 I.E. 0.5 or something.

If I’m still not explaining right maybe this will help?

My question is: How do I get the distance of a point in a 2d triangle without calculating perpendicular vector’s distance? I.E. if the tringle is facing up (y = -1) without any tilt I would need the distance in the triangle without any X.

What does “distance of a point” mean? Distance to what? Distance to the closest point on the triangle?

CyanPrime, I warned you on IRC about making a new topic for every little geometry problem you run into. This was your 7th topic or so. It’s now merged into one.

Distance from the top of the triangle?

Still not clear enough. The “top” of the triangle is relative. Think if it in terms of only a point in space and its relation to a triangle in space. Sounds like you want the closest point on the triangle.

OR, if you’re talking something in global space where negative on the global Y axis is always down, then you can cast a ray from the point to the triangle along the Y and get that distance.

Which do you mean?

:clue:

show us the from and to points for both triangles.

Does anyone know of a way I could add a radius to this code for p? Like basically saying “this is true if the triangle is < N dist from the point”

BTW: your isPointInTriangle method might not do what you think it does.

It will return true for points inside an infinitely far stretching volume (confined by the three planes of the triangle).

Are you by any chance simply looking for triangle->sphere collision detection?

Yeah, now you’re asking for something totally different - sphere/circle and triangle collision.

I think that would go something like first testing if the center of the circle is inside the triangle using our previous method (if so, then obviously you have a collision), then by checking to see if the point is within radius distance of any of the sides (if so, we have a collision).

I tried this out with my little script I pasted earlier and it works.


public static boolean isCircleInTriangle( boolean barycentric, Vector3f p, float r, Vector3f a, Vector3f b, Vector3f c)
	{
		//is the point inside the triangle?
		if ( isPointInTriangle(barycentric, p, a, b, c) )
		{
			return true;
		}
		
		//is the point within the radius of any of the line segments?
		float rSquared = r * r;
		if ( getSquaredDistanceToLineSegment( p, a, b ) <= rSquared )
		{
			return true;
		}
		if ( getSquaredDistanceToLineSegment( p, a, c ) <= rSquared )
		{
			return true;
		}
		if ( getSquaredDistanceToLineSegment( p, b, c ) <= rSquared )
		{
			return true;
		}
		
		return false;
	}
	
	private static float getSquaredDistanceToLineSegment( Vector3f p, Vector3f a, Vector3f b )
	{
		Vector3f ab = b.subtract(a);
		Vector3f ap = p.subtract(a);
		
		float dotabap = ab.dot(ap);
		float dotabab = ab.dot(ab);
		
		//if we're closest to a vertex, return the distance to that vertex
		if ( dotabap <= 0.0f )
		{
			return p.squaredDistance(a);
		}
		if ( dotabab <= dotabap )
		{
			return p.squaredDistance(b);
		}
		
		//if not, calculate the distance to the segment
		float ratio = dotabap / dotabab;
		Vector3f nearestPoint = new Vector3f( a.x + ab.x * ratio, a.y + ab.y * ratio, a.z + ab.z * ratio );
		return p.squaredDistance(nearestPoint);
	}