Как найти углы граней разностороннего тетраэдра по длинам ребер

Я пишу программу на C для определения вершины тетраэдра по заданным длинам всех его ребер. Тетраэдр имеет равностороннее основание и разносторонние стороны. Чтобы завершить формулу, мне нужен способ получить угол между гранью и равносторонним основанием. Я знаю высоту высоты одной из граней, и как только я смогу получить угол между гранью и основанием, я могу повернуть высоту на этот угол и получить положение вершины.

У меня 0 идей, с чего начать вычисление формулы угла (см. тета ниже) и как перевести ее в C.

Я знаю длины отрезков, выделенных желтым, и пытаюсь найти угол B, выделенный синим I  знаю длины отрезков, выделенных желтым, и пытаюсь найти угол B, выделенный синим

Вот мой код:

#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;

}

person theideasmith    schedule 28.12.2014    source источник
comment
поскольку вы отредактировали вопрос, вы должны четко добавить список того, что у вас есть в вашем распоряжении (поскольку существует много разных возможных входов, которые дают желаемый результат)   -  person CoffeDeveloper    schedule 28.12.2014
comment
Вы не можете получить этот угол, учитывая только длины. Вам нужно знать позиции (я предполагаю, что они у вас есть, поскольку вы можете вычислять длины, но это был бы другой вопрос, требующий другого ответа)   -  person CoffeDeveloper    schedule 28.12.2014


Ответы (2)


ИСПОЛЬЗОВАНИЕ ТРИГОНОМЕТРИИ

  1. Вычислите длины высот HA и HD по их соответствующим сторонам от сторон .

  2. Вычислите угол AHD по формуле косинуса.

ИСПОЛЬЗОВАНИЕ АНАЛИТИЧЕСКОЙ ГЕОМЕТРИИ

  1. Спроецируйте A ортогонально на BC, чтобы получить H: BH = ((AB.BC)/BC²). BC (жирным шрифтом выделены векторы)

  2. Вычислите угол из cos AHD = AH.HD/||AH||.||HD||

person Yves Daoust    schedule 29.12.2014

ОТВЕТ, ОСНОВАННЫЙ НА ИЗМЕНЕННЫЙ ВОПРОС:

Этот ответ основан на том, что вы процитировали на своей картинке. Угол, отмеченный синим, — это угол между сегментом AH (относительно вашего изображения) и плоскостью (я не вижу вашей системы координат, поэтому предполагаю, что это плоскость XZ)

//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())  
                 )
               );
}

Если этого ответа недостаточно, поскольку он верен для вашего текущего вопроса, вам лучше задать новый вопрос.


СТАРЫЙ ОТВЕТ:

Вы не точны:

высота одной из граней

оба могут означать высоту тетраэдра или длину линий, которые разрезают пополам грани, начиная с верхней вершины.

Если ты знаешь:

  • Высота тетраэдра (отрезок AH)
  • Длина одного из ребер, лежащих в основании (отрезок СВ)

Тогда вы знаете, что существует треугольник A (вершина)-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);
}

Теперь вам нужно знать угол треугольника ABC в A(pex). у вас уже есть CB, AB и 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);
}

Справочное изображение:

Тетраэдр с отмеченными вершинами и точками


Если ты знаешь:

  • Длина линий, которые разрезают грани пополам, начиная с верхней вершины (H'A)
  • Длина одного из ребер, лежащих в основании (CB, где H' принадлежит CB)

Формула проще: вы начинаете с Height и CB и пропускаете только 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);
}

В обоих случаях вам не нужно знать положение вершин (при условии, что основание равностороннее и представляет собой треугольник), если они вам нужны по определенной причине, просто перепишите вопрос на что-то более конкретное.

А это версия Тетраэдера в формате ASCII-Art, так что вы можете документировать свой код:

/**

              A
            / |\
          /   |  \
        /     |    \
      /       |      \
    /         |    ___ \
  / _____---  | H      /
  B ---___            /
          ---___     /
        H'      ----C
*/     
person CoffeDeveloper    schedule 28.12.2014
comment
запустив приведенный выше код для обычного тетраэдра, вы увидите, что угол равен 60 °, что вы и ожидаете. - person CoffeDeveloper; 28.12.2014
comment
Это при условии, что я знаю AH. Я знаю только длины ребер. - person theideasmith; 28.12.2014
comment
тогда вы разместили неправильную картинку, угол, отмеченный синим цветом, по-видимому, является углом между одним из краев и горизонтальной плоскостью. Вы НЕ МОЖЕТЕ знать этот угол, если у вас есть только длины. потому что длины между разными объектами не зависят от вращения (я утверждаю, что это невозможно). Поскольку на этот раз на вопрос дан ответ (и правила сайта не разрешают редактировать вопрос для изменения смысла, теоретически вы должны принять мой ответ и опубликовать новый вопрос с вашей реальной проблемой, если, конечно, ваша проблема может быть решена, предположим, вы собираетесь цитировать синим под другим углом) - person CoffeDeveloper; 28.12.2014