Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Задача на геометрию. Требуется посчитать площадь пересечения. 
V
    Опции темы
maxdiver
Дата 5.12.2011, 19:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 381
Регистрация: 29.1.2008
Где: Саратов

Репутация: 16
Всего: 18



Ладно, я утомился объяснять, ваша взяла. Вот код.
smile

Код
// класс "точка"
struct pt {
    double x, y;
};

// класс "прямая"
struct line {
    double a, b, c;

    // строит прямую по двум точкам
    line (pt p, pt q) {
        a = p.y - q.y;
        b = q.x - p.x;
        c = - a * p.x - b * p.y;
        double z = sqrt (a*a + b*b); // нормируем прямую, для увеличения точности
        a /= z;  b /= z;  c /= z;
    }

    // вычисляет знак точки относительно полуплоскости
    int sign (pt p) const {
        double v = a * p.x + b * p.y + c;
        return abs(v)<1E-9 ? 0 : v>0 ? +1 : -1;
    }
};

// строит многоугольник, аппроксимирующий окружность
vector<pt> build (double x0, double y0, double r) {
    const int N = 1000000; // число точек в многоугольнике (чем больше, тем точнее)
    vector<pt> res (N);
    r *= sqrt (2 * PI / N / sin (2 * PI / N)); // формула для пересчёта радиуса, чтобы площадь многоугольника совпала с площадью круга
    for (int i=0; i<N; ++i) {
        double ang = 2 * PI * i / N;
        res[i].x = x0 + r * cos (ang);
        res[i].y = y0 + r * sin (ang);
    }
    return res;
}

// строит полуплоскость, граница которой проходит через точки a и b, и так, что точка c лежит в этой полуплоскости (т.е. имеет знак "+1" относительно прямой)
line halfplane (pt a, pt b, pt c) {
    line l (a, b);
    if (l.sign (c) == -1) { // если c не попала в полуплоскость, умножим всё на -1, чтобы попала
        l.a *= -1;
        l.b *= -1;
        l.c *= -1;
    }
    return l;
}

// вычисляет определитель матрицы 2x2
double det (double a, double b, double c, double d) {
    return a * d - b * c;
}

// пересекает две прямые
pt intersect (line m, line n) {
    double zn = det (m.a, m.b, n.a, n.b);
    pt res = {
        - det (m.c, m.b, n.c, n.b) / zn,
        - det (m.a, m.c, n.a, n.c) / zn
    };
    return res;
}

// отсекает многоугольник полуплоскостью
vector<pt> cut (vector<pt> p, line l) {
    vector<pt> res;
    for (size_t i=0; i<p.size(); ++i) {
        // рассматриваем текущую точку
        if (l.sign (p[i]) >= 0)
            res.push_back (p[i]);
        // добавляем точку пересечения, если таковая есть
        pt next = p[(i+1)%p.size()];
        if (l.sign (p[i]) * l.sign (next) == -1)
            res.push_back (intersect (l, line (p[i], next)));
    }
    return res;
}

// считает площадь многоугольника
double area (vector<pt> p) {
    double s = 0;
    for (size_t i=0; i<p.size(); ++i) {
        pt next = p[(i+1)%p.size()];
        s += (p[i].x + next.x) * (p[i].y - next.y);
    }
    return abs (s) / 2;
}

// решает задачу - для треугольника (p1,p2,p3) и окружности (x0,y0,r)
double solve (pt p1, pt p2, pt p3, double x0, double y0, double r) {
    vector<pt> p = build (x0, y0, r);
    p = cut (p, halfplane (p1, p2, p3));
    p = cut (p, halfplane (p1, p3, p2));
    p = cut (p, halfplane (p2, p3, p1));
    return area (p);
}


(тут не 30 строчек, но я попытался написать всё как можно подробнее)

Точность - на моих тестах - порядка 15 знаков (хотя, наверное, на хитрых тестах будет похуже работать, но уж 6 знаков будет держать, инфа 100% ).
PM MAIL WWW ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Алгоритмы"

maxim1000

Форум "Алгоритмы" предназначен для обсуждения вопросов, связанных только с алгоритмами и структурами данных, без привязки к конкретному языку программирования и/или программному продукту.


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, maxim1000.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Алгоритмы | Следующая тема »


 




[ Время генерации скрипта: 0.0402 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.