Рассчитать треугольник от площади и углов - PullRequest
1 голос
/ 20 июля 2010

Я пытаюсь вычислить базу треугольников по Району и углам.Если угол-B равен 90 °, то формула работает, но в моем случае угол может составлять от 0,1 ° до 179,8 °.Формула предполагает, что угол равен 90, поэтому я подумал, что может быть что-то скрытое, что могло бы работать для самого угла.Вот формула:

альтернативный текст http://i25.tinypic.com/jj33gx.png альтернативный текст http://i31.tinypic.com/2mmijkm.png

Формула в коде будет выглядеть так:

Height = sqrt((2 * Area) / (tan(Angle-A)));

Я ищудля второй половины формулы.Будет ли следующая часть формулы примерно такой:

cos(sin(AngleB))

Ответы [ 6 ]

6 голосов
/ 20 июля 2010

Цики ответ правильный, но я бы хотел уточнить, как он получается.

Мы начнем с углов и площади, как известно.Я собираюсь использовать метки на схеме ОП для этого объяснения.

Сначала у нас есть основная истина, что площадь треугольника равна половине произведения его основания и высоты: Area = base * height / 2.Мы хотим иметь возможность определить соотношение между основанием и высотой, чтобы мы могли уменьшить это уравнение до одного неизвестного и решить для основания.

Еще одна важная вещь, которую нужно знать, это то, что высота треугольника пропорциональна стороне-А: height = Side-A * sin(Angle-B).Таким образом, знание стороны-A даст нам высоту.

Теперь нам нужно установить связь между стороной-A и стороной-C (основанием).Наиболее подходящим правилом здесь является закон синуса: Side-A/sin(A) = Side-C/sin(C).Мы перестроим это уравнение, чтобы найти сторону A в терминах стороны C: Side-A = Side-C * sin(A)/sin(C).

Теперь мы можем вставить этот результат в уравнение высоты, чтобы получить формулу для высоты в терминах стороны Cтолько: height = Side-C * sin(A) * sin(B) / sin(C)

Используя Side-C в качестве базы в уравнении площади, теперь мы можем найти площадь только в виде Side-C: Area = Side-C^2 * sin(A) * sin(B) / 2sin(C)

Затем переупорядочитьэто уравнение, чтобы найти сторону-C с точки зрения области:

Side-C = SQRT(2 * Area * sin(C) / (sin(B) * (sin(A)))

И это дает вам одну сторону.Это можно повторить, чтобы найти другие стороны, или вы можете использовать другой подход, чтобы найти другие стороны, знающие эту.

5 голосов
/ 20 июля 2010

Хорошо, новая попытка: если мои вычисления верны, сторона B равна sqrt (2 * площадь * sin (угол-B) / (sin (угол-A) * sin (угол-C))

Так как Площадь = 1/2 * A * B * sin (c) = 1/2 * C * B * sin (a) = 1/2 * A * C * sin (b) мы получаем:

A = 2 * area / (B * sin (c)) и, используя это, мы получаем:

C = sin (c) * B / sin (b), и когда мы помещаем это обратно в уравнение площади, мы получаем:

B = sqrt (2 * площадь * sin (угол-B) / (sin (угол-A) * sin (угол-C))

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

1 голос
/ 20 июля 2010

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

Прочитайте это, и это должно быть само за себя.

Создайте модуль Python, который решает треугольники, применяя теоремы sin и cosin.

Модуль получает в качестве параметров некоторые значения треугольника и, если возможно, возвращает значения всех его углов и длины сторон.

Параметры принимаются как dict, и его следует вызывать как автономный из командной строки.

from __future__ import division
import sys, logging
from math import radians, degrees, acos, cos, sin, sqrt, asin

class InconsistentDataError(TypeError):
    pass


class InsufficientDataError(TypeError):
    pass


class NonUpdatable(dict):
    """Dictionary whose items can be set only once."""
    def __setitem__(self, i, y):
        if self.get(i, None):
            raise InconsistentDataError()
        super(NonUpdatable, self).__setitem__(i, y)


def get_known_sides(**kwarg):
    """Filter from the input elements the Side elements."""
    return dict([i for i in kwarg.iteritems() if i[0].isupper()])

def get_known_angles(**kwarg):
    """Filter from the input elements the Angle elements."""
    return dict([i for i in kwarg.iteritems() if i[0].islower()])

def get_opposite_angle(C, B, A):
    """
    Get the angle corresponding to C.

    Keyword arguments:
    A -- right side of the angle (real number > 0)
    B -- left side of the angle (real number > 0)
    C -- side opposite to the angle (real number > 0)

    Returns:
    angle opposite to C
    """
    return degrees(acos((A**2 + B**2 - C**2) / (2 * A * B)))

def get_side(A, B, c):
    """
    Calculate the Side corresponding to the Angle c.

    Keyword arguments:
    A -- left side of C (real number > 0)
    B -- right side of C (real number > 0)
    c -- angle opposite to side C (real number)

    Returns:
    side C, opposite to c
    """
    return sqrt(A**2 + B**2 - 2*A*B*cos(radians(c)))

def get_overlapping_angle(known_angles, known_sides):
    """
    Calculate the Angle of a known side, knowing the angle to another known side.

    Keyword arguments:
    known_angles -- (dict of angles)
    known_sides -- (dict of sides)

    Returns:
    angle of the known side, to which there is no known angle
    """
    a = (set([i.lower() for i in known_sides.iterkeys()]) - 
            set([i.lower() for i in known_angles.iterkeys()])).pop()

    b = (set([i.lower() for i in known_sides.iterkeys()]) & 
            set([i.lower() for i in known_angles.iterkeys()])).pop()

    y = (known_sides[a.upper()]/known_sides[b.upper()]) * sin(radians(known_angles[b.lower()]))
    if y > 1: y = 1 #Rounding error fix --- y = 1.000000000001; asin(y) -> Exception
    return {a.lower(): degrees(asin(y))}

def get_angles(A, B, C):
    """
    Calculate all the angles, given the length of all the sides.

    Keyword arguments:
    A -- side A (real number > 0)
    B -- side B (real number > 0)
    C -- side C (real number > 0)

    Returns:
    dict of angles
    """
    sides = {"A":A,"B":B,"C":C}
    _sides = sides.keys()
    angles = {}

    for side in sides.keys():
        angles[side.lower()] = get_opposite_angle(
                                    sides[_sides[0]], 
                                    sides[_sides[1]], 
                                    sides[_sides[2]])
        _sides.append(_sides.pop(0))

    return angles

def get_triangle_values(**kwargs):
    """Calculate the missing values of a triangle based on the known values."""
    known_params = kwargs
    angles = NonUpdatable({
        "a":0, 
        "b":0, 
        "c":0,
    })
    sides = NonUpdatable({
        "A":0, 
        "B":0, 
        "C":0,
    })

    if len(known_params) < 3:
        raise InsufficientDataError("Three parameters are needed to calculate triangle's values.")

    if str(known_params.keys()).islower():
        raise TypeError("At least one length needed.")

    known_sides = NonUpdatable(get_known_sides(**known_params))
    sides.update(known_sides)
    known_angles = NonUpdatable(get_known_angles(**known_params))
    angles.update(known_angles)

    if len(known_angles) == 3 and sum(known_angles.itervalues()) != 180:
        raise InconsistentDataError("One of the sides is too long.")

    if len(known_sides) == 3:
        x=[side for side in known_sides.itervalues() if (sum(known_sides.itervalues()) - side) < side]
        if len(x):
            raise InconsistentDataError("One of the sides is too long.")

        for angle, value in get_angles(**known_sides).iteritems(): 
            # Done this way to force exception when overwriting a 
            # user input angle, otherwise it would be a simple assignment.
            # >>> angles = get_angles(**known_sides)
            # This means inconsistent input data.
            angles[angle] = value

    else: # There are angles given and not enough sides.
        if len(known_angles) > 1:
            #2 angles given. Get last angle and calculate missing sides
            for angle, val in angles.iteritems():
                if val == 0:
                    angles[angle] = 180. - sum(angles.itervalues())

            known_sides = known_sides.items()
            for side, length in sides.iteritems():
                if length == 0:
                    sides[side] = known_sides[0][1] / \
                        sin(radians(angles[known_sides[0][0].lower()])) * \
                        sin(radians(angles[side.lower()]))

        else:
            unknown_side = (set(sides.keys()) - set(known_sides.keys())).pop()

            chars = [ord(i.lower()) for i in known_params.iterkeys()]
            chars.sort()

            if chars[0] < chars[1] < chars[2]:
                sides[unknown_side] = get_side(known_sides.values()[0], known_sides.values()[1], known_angles[unknown_side.lower()])
                angles = get_angles(**sides)

            else:
                known_angles.update(get_overlapping_angle(known_angles, known_sides))
                angles.update(known_angles)

                for angle, val in angles.iteritems():
                    if val == 0:
                        angles[angle] = 180. - sum(angles.itervalues())

                sides[unknown_side] = get_side(known_sides.values()[0], known_sides.values()[1], angles[unknown_side.lower()])

    angles.update(sides)
    return angles

if __name__ == "__main__":
    try:
        values = get_triangle_values( **eval(sys.argv[1], {}, {}) )
    except IndexError, e:
        values = get_triangle_values(A=10,B=10,C=10)
    except InsufficientDataError, e:
        print "Not enough data!"
        exit(1)
    except InconsistentDataError, e:
        print "Data is inconsistent!"
        exit(1)

    print values

A, B и C - длины сторон, a, b и c - углы, поэтому c - угол, противоположный стороне C.

Тесты

0 голосов
/ 20 июля 2010

Формула, которую вы даете для Стороны-A, кажется правильной, ЕСЛИ треугольник равнобедренный, т. Е. Угол-B = Угол-C (вы получаете это, используя закон синусов и формулу синусов для области). Если это не равнобедренный, вам, кажется, нужно знать другие углы; общая формула:

Side-A = sqrt(2*Area*sin(Angle-A)/(sin(Angle-B)*sin(Angle-C)))

Конечно, я сделал это в своей голове, так что проверь математику;)

Редактировать: Хорошо, исправлена ​​формула после регистрации на бумаге.

0 голосов
/ 20 июля 2010

Как насчет расчета длин двух сторон треугольника, где третьему размеру присваивается длина 1 (с использованием закона синусов для углов, с этой стороной назначена длина 1),затем масштабируйте треугольник, пока его площадь не совпадет с областью, которая у вас есть?Тогда вы можете рассчитать высоту довольно легко.http://en.wikipedia.org/wiki/Triangle_area#Using_trigonometry

0 голосов
/ 20 июля 2010

Если я не ошибаюсь, длина стороны x между двумя углами a и b должна быть следующей.

         ________________
        /  2A       2A
x =    / ------ + ------
     \/  tan(a)   tan(b)

Таким образом, для расчета стороны-C вы, но в углах-A и угле-B.

(Теперь дважды проверил - кажется, это правильно.)

...