# Trigonometry help--find third point of the triangle

It’s been a few too many years since I took geometry, so I’ve been beating my head against what should be a simple problem .

The goal, illustrated by the test sketch, is to calculate the 3rd point of a triangle, given the coordinates of the first two points and the side lengths. It’s quite close, but the 2 side lengths that are supposed to be constant are not staying constant at certain angles when using the calculated 3rd point.

I went ahead and created a horrible MS paint image to give an illustration of the example:

Thanks!

``````void setup () {
size(400, 400);
}

void draw () {
background(255);
PVector A = new PVector(mouseX, mouseY);
float AC = 100;
PVector B = new PVector(250, 100);
float BC = 100;
float AB = A.dist(B);
PVector C = new PVector();
float theta = acos( (AB*AB + AC*AC - BC*BC) / (2*AB*AC) );
C.x = AC * cos(theta) + A.x;
C.y = AC * sin(theta) + A.y;

line(A.x, A.y, B.x, B.y);
line(A.x, A.y, C.x, C.y);
line(B.x, B.y, C.x, C.y);
}
``````

Look at everything related to inverse cinematics, that’s your subject.

``````
// triangle from two points

// Demonstrator for getting a point C orthogonal
// to the center of a line between points A and B.
// Thanks to amnon.

final color BLACK = color(0);
final color WHITE = color(255);

final color RED   = color(255, 0, 0);
final color GREEN = color(0, 255, 0);
final color BLUE  = color(0, 0, 255);

void setup() {
size(600, 600);
background(WHITE);
}

void draw() {
background(WHITE);

// points A and B
PVector A = new PVector(width/2, height/2);
PVector B = new PVector(mouseX, mouseY);

// connectedPoints(A, B, BLACK);

// the core: get side point C
PVector C = getSidePoint(A, B, 100);   // -100 would make the triangle to the other side

// connectedPoints(C, center, RED);

// draw triangle from ABC
trianglePV(A, B, C);

// highlight its corners
ellipsePV(A, RED);
ellipsePV(B, GREEN);
ellipsePV(C, BLUE);
//
}

// ----------------------------------------------------------------

void trianglePV(PVector pv1, PVector pv2, PVector pv3) {
fill(144); // gray
stroke(BLACK);
triangle( pv1.x, pv1.y,
pv2.x, pv2.y,
pv3.x, pv3.y  );
}

void ellipsePV(PVector pv, color col) {
fill(col);
ellipse(pv.x, pv.y, 10, 10);
}

PVector getSidePoint(PVector A, PVector B,
int distFromLine) {
// the core function of the demonstrator
// thanks to amnon

// difference between A & B
PVector difference = PVector.sub(B, A);
difference.normalize();
difference.mult(distFromLine);
PVector sidePoint = new PVector(-difference.y, difference.x);

// center between A & B
PVector center = getCenter(A, B);
// from relative pos to absolute pos

return sidePoint;
}

// ---------------------------------------------------
// help functions

void connectedPoints(PVector A, PVector B, color myColorStroke) {
// show 2 points A and B and connect them
stroke(myColorStroke);
line(A.x, A.y, B.x, B.y);
ellipse(A.x, A.y, 10, 10);
ellipse(B.x, B.y, 10, 10);
}

PVector getCenter(PVector A, PVector B) {
// returns center point
return PVector.lerp(A, B, 0.5);  // 0.5 defines center
}
//
``````

Did you mean Inverse kinematics
?

Given a triangle:

``````PVector[] tri = new PVector[3];
``````

Then you can use the PVector reference:

to figure out how to solve each part of the problem. Your constraint set, however, is suspicious – you said:

but not all mouse input will satisfy your constraints – for example, a mouse at 0,0 will be more than 200 away from 250, 100, so the two arms cannot be 100 each and reach it. What should happen when you mouse point is invalid, and no 100,00,x triangle exists that can connect to it?

Chrisir solved this problem by making the height of your triangle constant (with the hypotenuse as the base), so that the short arms aren’t always 100, but they are equal.

1 Like

Thanks, @Chrisir this is a much cleaner setup than my example. But, @jeremydouglass is right, this doesn’t exactly solve the problem that I was defining - I’m trying to keep the two known points have a constant side length. I was aware that you can have invalid inputs in my code, but it was just supposed to be an example.

For context, I’m trying to model something like this:

Ah. You may need to update your model before coding it…

In your image, I can see that the two small wheels are bolted on, and it looks like the second wheel slides on an arc slot – while the pen moves freely on the arm join. What are your inputs? Is it a handle that you crank that turns the center wheel?

Ah sorry, this is just an image I pulled from the web. What I meant was I’m trying to simulate something like this in Processing, starting with (what should be) the simple vector math that defines the position of the marker based on the position of the two axles on the left.

Right. But where will your degrees of freedom be? Analysis of motion and what you solve for all depends on some part of the system being able to move…

If all you want is two fixed segments pinned to a point, try the Arm example sketch –

https://processing.org/examples/arm.html

Thanks, that is a useful example. I haven’t thought out possible parameters, but theoretically the math should be the same regardless. You have two segments of fixed length with known starting points attached at their endpoints.

Yes, but that’s just a definition of a triangle – if both endpoints are fixed, there are only two possible places where the fixed-length segments could meet, and in either configuration no motion is possible.

The parameters come in when you decide which of those “known starting points” can move, and how. That introduces equations with constants and variables, which then allows you to solve for the joint – then the math is different depending on the kind of motion.

I’m trying to keep the two known points have a constant side length.

Do you mean the line between the fixed point centerPV and the mouse?

Then this sketch below is for you:

a static triangle rotating towards mouse

(Not what you want I guess)

``````
// triangle from two points - NEW

// https : // discourse.processing.org/t/can-someone-good-with-trigonometry-help-me-out-with-a-small-sketch/9127

// Demonstrator for getting a point C orthogonal
// to the center of a line between points A and B.
// Thanks to amnon.

final color BLACK = color(0);
final color WHITE = color(255);

final color RED   = color(255, 0, 0);
final color GREEN = color(0, 255, 0);
final color BLUE  = color(0, 0, 255);

final float radiusTriangle1 = 220;   // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
float angle= 1.3;

// for the triangle
PVector centerPV; // center RED
PVector pointingTowardsMousePV;  //  pointing towards mouse - Green
PVector thirdCornerPV;   // BLUE

// for the mouse
PVector mousePV;

void setup() {
size(600, 600);
background(WHITE);

// point centerPV
centerPV = new PVector(width/2, height/2);
mousePV = new PVector();
pointingTowardsMousePV = new PVector();
}// setup()

void draw() {
background(WHITE);

// get angle from centerPV to mouse
mousePV.set (mouseX, mouseY);
angle=angleBetweenPV_PV( centerPV, mousePV );

// calc 2nd corner

// calc 3rd corner
// the core: get side point C
thirdCornerPV = getSidePoint(centerPV, pointingTowardsMousePV, 100);   // -100 would make the triangle to the other side

// draw triangle
trianglePV(centerPV, pointingTowardsMousePV, thirdCornerPV);

// highlight its corners
ellipsePV(centerPV, RED);
ellipsePV(pointingTowardsMousePV, GREEN);
ellipsePV(thirdCornerPV, BLUE);
//
} // draw()

// ----------------------------------------------------------------

float angleBetweenPV_PV(PVector a, PVector mousePV) {

// calc angle

// https : // forum.processing.org/two/discussion/10474/find-angle-between-2-points

PVector d = new PVector();

// calc angle
pushMatrix();
translate(a.x, a.y);
// delta
d.x = mousePV.x - a.x;
d.y = mousePV.y - a.y;
// angle
float angle1 = atan2(d.y, d.x);
popMatrix();

return angle1;
}

void trianglePV(PVector pv1, PVector pv2, PVector pv3) {
fill(144); // gray
stroke(BLACK);
triangle( pv1.x, pv1.y,
pv2.x, pv2.y,
pv3.x, pv3.y  );
}

void ellipsePV(PVector pv, color col) {
fill(col);
ellipse(pv.x, pv.y, 10, 10);
}

PVector getSidePoint(PVector A, PVector B,
int distFromLine) {
// the core function of the demonstrator
// thanks to amnon

// difference between A & B
PVector difference = PVector.sub(B, A);
difference.normalize();
difference.mult(distFromLine);
PVector sidePoint = new PVector(-difference.y, difference.x);

// center between A & B
PVector center = getCenter(A, B);
// from relative pos to absolute pos

return sidePoint;
}

// ---------------------------------------------------
// help functions

void connectedPoints(PVector A, PVector B, color myColorStroke) {
// show 2 points A and B and connect them
stroke(myColorStroke);
line(A.x, A.y, B.x, B.y);
ellipse(A.x, A.y, 10, 10);
ellipse(B.x, B.y, 10, 10);
}

PVector getCenter(PVector A, PVector B) {
// returns center point
return PVector.lerp(A, B, 0.5);  // 0.5 defines center
}
``````

in this new version we have indeed a variable distance between fixed point A and mouse and C is found in a way that indeed both sides stay at fixed length 100 (so the height of C varies proportional to the distance between A and mouse)

When the mouse is too far away the triangle becomes a line of course

``````final color BLACK = color(0);
final color WHITE = color(255);

final color RED   = color(255, 0, 0);
final color GREEN = color(0, 255, 0);
final color BLUE  = color(0, 0, 255);

void setup() {
size(600, 600);
background(WHITE);
}

void draw() {
background(WHITE);

// points A and B
PVector A = new PVector(width/2, height/2);
PVector B = new PVector(mouseX, mouseY);

// https : // en.wikipedia.org/wiki/Isosceles_triangle#Height
float lineC = A.dist(B);
float distFromBase= (100*100) - (  lineC*lineC / 4  ) ;
distFromBase=sqrt(distFromBase);

// the core: get side point C
PVector C = getSidePoint(A, B, distFromBase);   // -100 would make the triangle to the other side

// connectedPoints(C, center, RED);

// draw triangle from ABC
trianglePV(A, B, C);

// highlight its corners
ellipsePV(A, RED);
ellipsePV(B, GREEN);
ellipsePV(C, BLUE);

fill(0);
text( A.dist(C),
22, 22);
//
}

// ----------------------------------------------------------------

void trianglePV(PVector pv1, PVector pv2, PVector pv3) {
fill(144); // gray
stroke(BLACK);
triangle( pv1.x, pv1.y,
pv2.x, pv2.y,
pv3.x, pv3.y  );
}

void ellipsePV(PVector pv, color col) {
fill(col);
ellipse(pv.x, pv.y, 10, 10);
}

PVector getSidePoint(PVector A, PVector B,
float distFromLine) {
// the core function of the demonstrator
// thanks to amnon

// difference between A & B
PVector difference = PVector.sub(B, A);
difference.normalize();
difference.mult(distFromLine);
PVector sidePoint = new PVector(-difference.y, difference.x);

// center between A & B
PVector center = getCenter(A, B);
// from relative pos to absolute pos

return sidePoint;
}

// ---------------------------------------------------
// help functions

void connectedPoints(PVector A, PVector B, color myColorStroke) {
// show 2 points A and B and connect them
stroke(myColorStroke);
line(A.x, A.y, B.x, B.y);
ellipse(A.x, A.y, 10, 10);
ellipse(B.x, B.y, 10, 10);
}

PVector getCenter(PVector A, PVector B) {
// returns center point
return PVector.lerp(A, B, 0.5);  // 0.5 defines center
}
//
``````

new version following your 2nd image with the web image of a drawing machine with 2 rotating wheels connected by 2 arms and a blue pen

This calls for a Wheel class…

``````
final color BLACK = color(0);
final color WHITE = color(255);

final color RED   = color(255, 0, 0);
final color GREEN = color(0, 255, 0);
final color BLUE  = color(0, 0, 255);

// WHEEL I
PVector centerPV1=new PVector (200, 300);
float angle1=1.3;
float angleSpeed1=.1;

// WHEEL II
PVector centerPV2=new PVector (300, 320);
float angle2=0;
float angleSpeed2=.021;

// resulting drawing
ArrayList<PVector> list = new ArrayList();

void setup() {
size(600, 600);
background(WHITE);
}

void draw() {
background(WHITE);

// points A and B from WHEELS
PVector A = new PVector(

PVector B = new PVector(

// move WHEELS
angle1+=angleSpeed1;
angle2+=angleSpeed2;

// show WHEELS
noFill();
stroke(BLACK);
ellipse(centerPV1.x, centerPV1.y,
ellipse(centerPV2.x, centerPV2.y,

// CALC
// https : // en.wikipedia.org/wiki/Isosceles_triangle#Height
float lineC = A.dist(B);
float distFromBase= (100*100) - (  lineC*lineC / 4  ) ;
distFromBase=sqrt(distFromBase);

// the core: get side point C
PVector C = getSidePoint(A, B, distFromBase);   // -100 would make the triangle to the other side

// connectedPoints(C, center, RED);

// draw triangle from ABC
trianglePV(A, B, C);

// highlight its corners
ellipsePV(A, RED);
ellipsePV(B, GREEN);
ellipsePV(C, BLUE);

fill(0);
text( A.dist(C),
22, 22);

// show  drawing
for (PVector pv : list) {
stroke(BLUE);
point(pv.x, pv.y);
}
//
}

// ----------------------------------------------------------------

void trianglePV(PVector pv1, PVector pv2, PVector pv3) {
fill(144); // gray
stroke(BLACK);
triangle( pv1.x, pv1.y,
pv2.x, pv2.y,
pv3.x, pv3.y  );
}

void ellipsePV(PVector pv, color col) {
fill(col);
ellipse(pv.x, pv.y, 10, 10);
}

PVector getSidePoint(PVector A, PVector B,
float distFromLine) {
// the core function of the demonstrator
// thanks to amnon

// difference between A & B
PVector difference = PVector.sub(B, A);
difference.normalize();
difference.mult(distFromLine);
PVector sidePoint = new PVector(-difference.y, difference.x);

// center between A & B
PVector center = getCenter(A, B);
// from relative pos to absolute pos

return sidePoint;
}

// ---------------------------------------------------
// help functions

void connectedPoints(PVector A, PVector B, color myColorStroke) {
// show 2 points A and B and connect them
stroke(myColorStroke);
line(A.x, A.y, B.x, B.y);
ellipse(A.x, A.y, 10, 10);
ellipse(B.x, B.y, 10, 10);
}

PVector getCenter(PVector A, PVector B) {
// returns center point
return PVector.lerp(A, B, 0.5);  // 0.5 defines center
}
//
``````

Thank you @Chrisir this is awesome! I need to take some time to make sure I understand the math, but this is exactly what I was looking for.
I’m not sure I understand this line:
`PVector sidePoint = new PVector(-difference.y, difference.x);`

Why is the basis for the third point the difference between A and B with the x and y reversed?

1 Like

I have no idea, as stated this function is made by amnon

Thoughts

you could experiment by leaving out the sign ("`-`") or swapping the x and y.

Since it’s the difference-Vector that we take to get `sidePoint` (which is relative, not absolute) I assume it’s just orthogonal to the difference between vectors A and B (hence x and y swapped). Gut feeling.

Remark I

Remember that sidePoint is based on Vector difference and that we did with it first:

``````   difference.normalize();
difference.mult(distFromLine);
``````

so before deriving `sidePoint` from `difference` we bring difference to the length “`distFromLine`” we want sidePoint to have…

Remark II

Even more interesting might these lines in `draw()` be where I calculate the length of the height towards `C` (the height upon triangles base) and pass this as `distFromBase` to the function `getSidePoint`.

I calculate it based on 100 for both sides. To calculate `distFromBase` in the first place was one of my core ideas. Because `distFromBase` is different (based on 100 and 100) depending on where the mouse is, everything works.

``````  // CALC
float lineC = A.dist(B);
float distFromBase= (100*100) - (  lineC*lineC / 4  ) ;
distFromBase=sqrt(distFromBase);
``````

You could / should make these lines into their own function that you would call like this from `draw()`:

``````  float distFromBase = getHeightUponBaseInIsoscelesTriangle ( A, B, 100 );
``````

Chrisir

orthogonal? yes!

`(x, y) → (-y, x)` is a rotation of 90° counterclockwise around 0,0.

So the code draws a relative vector from A->B, change its length to distFromLine, rotates it by 90 degrees (it is relative, so already logically starts at 0,0), and then add the result to the A-B midpoint – so, from the AB midpoint, to proceeds perpendicularly to distFromLine.

2 Likes