How to find the angles of the faces of a scalene tetrahedron given lengths of edges

515 Views Asked by At

I'm writing a program in C to determine the apex of a tetrahedron given the given the lengths of all its edges. The tetrahedron has an equilateral base and scalene sides. In order to complete the formula, I need a way of getting the angle between a face and the equilateral base. I know the height of the altitude of one of the faces, and once I can get the angle between a face and the base, I can rotate the height by that angle and get the position of the apex.

I have 0 idea where to begin figuring out the formula for the angle(see theta below), and how to translate it into C.

I know the lengths of the segments in yellow and am trying to find angle B in blue I know the lengths of the segments in yellow and am trying to find angle B in blue

Here's my code so far:

#include <math.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

typedef struct {
  float x;
  float y;
  float z;
} Point;

typedef struct {
  float edgeA, edgeB, edgeC;
  float legA, legB, legC;
  Point vertexBaseA, vertexBaseB, vertexBaseC;
  Point apex;
} scaleneTetrahedron;

Point p(float x,float y) {
    Point pt; pt.x = x; pt.y = y; pt.z =0;return pt;
}

Point pZ(float x, float y, float z) {
      Point pt; pt.x = x; pt.y = y;pt.z =z; return pt;
}

void printPoint(char *identifier, Point p){
  printf("(%s: %f, %f, %f)\n",identifier, p.x,p.y,p.z);
}

void printFloat(float n) {
  printf("%f",n);
}

scaleneTetrahedron sT_Hedron(float lengthsEdges[3],float lengthsLegs[3],Point vertexBases[3]) {
  scaleneTetrahedron h;
  h.edgeA = lengthsEdges[0], h.edgeB = lengthsEdges[2], h.edgeC = lengthsEdges[2];
  h.legA = lengthsLegs[0], h.legB = lengthsLegs[1],h.legC = lengthsLegs[2];
  h.vertexBaseA = vertexBases[0], h.vertexBaseB = vertexBases[1], h.vertexBaseC = vertexBases[2];
  return h;
}

#define rt(n) (sqrt(n))
float SQUARE(float n) {return n*n;}
float PERP(float slope) { return 1/slope * -1;}
float Rad_To_Deg(float angle) {return angle*57.29577951f;}

#define ANGLE_FOR(rangX,rangY)      ( Rad_To_Deg(atan2(rangX,rangY))     )

float DISTANCE(Point v1, Point v2){
  return sqrtf(SQUARE(v1.x-v2.x) + SQUARE(v1.y-v2.y));

}

float WIDTH(float leg1,float leg2,float base){
  float ret = ((SQUARE(leg1) - SQUARE(leg2)) + SQUARE(base)) / (2 * base);
  printf("Ret is:%f\n",ret);
  return ret;
}

float HEIGHT(float width,float leg1){
  float ret = sqrtf(SQUARE(leg1) - SQUARE(width));
  return ret;
}

float slopeFor(Point A, Point B) {
  return (B.y-A.y) / (B.x - A.x);
}

float yInterceptFor(float slope, Point A) {
  return (A.y - (slope * A.x));
}

float map(float range1_A, float range1_B, float range2_A, float range2_B, float value) {
    float  inMin = range1_A;
    float  inMax = range1_B;

    float  outMin = range2_A;
    float  outMax = range2_B;

    float input = value;
    float output = outMin + (outMax - outMin) * (input - inMin) / (inMax - inMin);

    return output;
}

Point XYAltitude(float leg1, float leg2, float base) {

  float width = WIDTH(leg1,leg2,base); 
  float height = HEIGHT(width,leg1);
  return p(width, height);
}

Point APEX_OF(scaleneTetrahedron shape) {
  Point altitude1 = XYAltitude(shape.legA,shape.legB, shape.edgeA);//Getting the x position of the altitude of faceA and the height of the altitude. 
  printPoint("Altitude face:",altitude1);
  float 
  x = altitude1.x,
  baseX1 = x,
  baseX2 = x,
  baseY1 = 0,
  baseY2 = 10
  ; 

  float slopeBase = slopeFor(shape.vertexBaseC, shape.vertexBaseB), yIntBase = yInterceptFor(slopeBase,shape.vertexBaseB);
  printf("slope is:%f ,yint is:%f, point of intersection:%f\n",slopeBase,yIntBase, (slopeBase * x)+yIntBase);
  Point intersectionBase = p(x, (slopeBase * x) + yIntBase);


  printPoint("IntersectionBase:",intersectionBase);

  float zIntersectionBase = (slopeBase * x) + yIntBase;//it is "y" because we are switching from a topdown to a side view
  float zHypotenuse = (shape.edgeC* intersectionBase.y)/shape.vertexBaseC.y; //THIS IS THROWING OFF THE MEASUREMENT: sqrtf(SQUARE(zIntersectionBase) + SQUARE(altitude1.y));
  Point zAltitude   = XYAltitude(altitude1.y,zHypotenuse,zIntersectionBase);
  float theta       = Rad_To_Deg(atan2(zAltitude.x,zAltitude.y));//Here's where I am having trouble.
  float y = Rad_To_Deg(sin(theta)) * altitude1.x;
  float z = Rad_To_Deg(cos(theta)) * altitude1.x;
  printFloat(theta);
  Point rtd;
  rtd.x = x;
  rtd.z = y; //Only now did I learn that z and y are swapped in 3D. But, this is no problem due to abstraction. 
  rtd.y = z;

  return rtd;
}

int main(int argc, const char *argv[]){
  // srand(time(NULL));   

  Point vertexA  = p(0,0); 
  Point vertexB  = p(3,0.f);
  Point vertexC  = p(1.5,2.6); 
  Point apex =   pZ(1.5,0.87,2.45);

  float baseA = DISTANCE(vertexA,vertexB);
  float baseB = DISTANCE(vertexB,vertexC);
  float baseC = DISTANCE(vertexC,vertexA);
  float legA  = DISTANCE(vertexA,apex);
  float legB  = DISTANCE(vertexB,apex);
  float legC  = DISTANCE(vertexC,apex);

  scaleneTetrahedron toSend;
  toSend.edgeA = baseA;
  toSend.edgeB = baseB;
  toSend.edgeC = baseC;

  toSend.legA = legA; 
  toSend.legB = legB;
  toSend.legC = legC;

  toSend.vertexBaseA = vertexA;
  toSend.vertexBaseB = vertexB;
  toSend.vertexBaseC = vertexC;
  printPoint("APEX:",APEX_OF(toSend));

  return 0;

}
2

There are 2 best solutions below

0
On BEST ANSWER

USING TRIGONOMETRY

  1. Compute the lengths of the altitudes HA and HD in their respective face from the sides.

  2. Compute the angle AHD by the cosine formula.

USING ANALYTICAL GEOMETRY

  1. Project A orthogonally onto BC to get H: BH = ((AB.BC)/BC²).BC (bold are vectors)

  2. Compute the angle from cos AHD = AH.HD/||AH||.||HD||

3
On

ANSWER BASED ON EDITED QUESTION:

This answer is based on what you quoted on your picture. The angle you marked in blue is the angle between segment AH (referenced to your picture) and the plane (I don't see your coordinate system so I assume that's the XZ plane)

//I use Point instead of Vector3, semantically no difference here
//but it is wrong conceptually.
Point getUpVector(){
     Point Up;
     Up.y = 1.0f;
     Up.x = Up.z = 0.0f;
     return Up;
}

Point getOrigin(){
    Point O;
    Up.x=Up.y=Up.z=0.0f;
    return O;         
}

Point getDirection(Point P1, Point P2){
    Point P3;
    P3.x = P1.x-P2.x; P3.y = P1.y-P2.y; P3.z = P1.z-P2.z;
    return P3;
}

double dotProduct(Point A, Point B){
    return A.x*B.x + A.y*B.y + A.z*B.z;
}


double distanceOfPoints(Point P1, Point P2){
    double x = P1.x - P2.x;
    double y = P1.y - P2.y;
    double z = P1.z - P2.z;
    return sqrt(x*x + y*y + z*z);
}

Point normalize(Point A){
    double L =  distanceOfPoints(A,GetOrigin());
    A.x/= L; A.y/=L; A.z/=L;
    return A;
}

//the function you have to call requires to know coordinates of points H and A
// it is impossible to compute that angle using only distances, because distances
// are indpendent of rotation while that angle requires to know the rotation..!!
double angleOnThePlane(Point H, Point A){
    Point D = getDirection(H,A);
    P = normalize(D);
    return asin( dotProduct(P,getUpVector())/
                 (distanceOfPoints(getUpVector,getOrigin()) +
                  distanceOfPoints(P,getOrigin())  
                 )
               );
}

If this answer is not enough, since is correct for your current question, you'd better ask a new question.


OLD ANSWER:

You are not precise:

height of one of the faces

may both mean the height of the tetrahedron, or the length of the lines that cut in half the faces starting from the top vertex.

If you know:

  • Height of the tetrahedron (segment AH)
  • Lenght of one of the edges lying in the base (segment CB)

Then you know there is a triangle A (Apex)-C-H

//since the base is equilateral you can compute CH with:
double computeCH(double CB){
    return CB*sqrt(3.0)/3.0
}

//the missing edge is then CA, you need pitagora this time:
double computeCA(double CB, double AH){
    double CH = computeCH(CB);
    return sqrt(AH*AH+CH*CH);
}

Now, you need to know the angle of the triangle ABC in the A(pex). you already have CB,AB and AC.

//just compute the height of the triangle ABC
double computeHeight(double CB, double AB){
    return sqrt(AB*AB - 0.25*CB*CB);
}

//then angle is trivial
double computeAngle(double Height, double AB){
    return 2.0*acos(Height/AB);
}

Reference Image:

A Tetrahedron with some vertices and points marked


If you know:

  • Length of the lines that cut in half the faces starting from the top vertex (H'A)
  • Lenght of one of the edges lying in the base (CB where H' belongs to CB)

The formula is more simple, basically you start with Height and CB and you miss just AB

double computeAB(double Height, double CB){
    return sqrt( CB*CB*0.25 + Height*Height);
}

//just need to compute the angle now
double computeAngle(double Height, double AB){
    return 2.0*acos(Height/AB);
}

In both cases you don't need to know vertices positions (assuming base is equilateral and is a triangle), if you need them for a particular reason, then just re-write the question to something more specific.

And this is the ASCII-Art version of the Tetraheder so you can document your code:

/**

              A
            / |\
          /   |  \
        /     |    \
      /       |      \
    /         |    ___ \
  / _____---  | H      /
  B ---___            /
          ---___     /
        H'      ----C
*/