Skip to content

Latest commit

 

History

History
496 lines (365 loc) · 15.5 KB

Circulos.md

File metadata and controls

496 lines (365 loc) · 15.5 KB

Circulos

Um círculo é o conjunto de pontos equidistantes de um ponto C. A distância de um ponto do círculo ao seu centro C é denominada raio r do círculo.

Representação de círculos

Conforme sua definição, um círculo pode ser representado através de um ponto C e um raio r.

// Definição da classe Point

class Circle {
public:
        Point C;
        double r;

        Circle(const Point& Cv = Point(0, 0), double rv = 1.0) : C(Cv), r(rv) {}
};

A equação do círculo pode ser deduzida a partir da expressão d(P, C) = r, onde P = (x, y) é um ponto do círculo, C = (x0, y0) é o centro do círculo e r é o raio. A equação final é dada a seguir.

Equação do Círculo

Esta equação é útil para resolver vários problemas envolvendo círculos, como o problema de determinar se um ponto está dentro, fora ou sobre um círculo, como veremos a seguir.

Relação entre círculos e pontos

Dado um ponto P e um círculo de centro C e raio r, uma (e apenas uma) das três afirmações abaixo será verdadeira:

  1. P está dentro do círculo;
  2. P está sobre o círculo;
  3. P está fora do círculo.

Para determinar qual é a relação válida, basta computar a distância entre o ponto P e o centro C do círculo: caso esta distância seja menor, igual ou maior que r, P estará dentro, sobre e fora do círculo, respectivamente.

// Definição da classe Point

class Circle {
public:

    // Membros e construtores

    typedef enum { IN, OUT, ON } PointPosition;

    PointPosition position(const Point& P) const
    {
        auto d = P.distance(C);

        return equals(d, r) ? ON : (d < r ? IN : OUT);
    }
};

Perímetro e Área

Tanto o cálculo do perímetro quanto da área de um círculo envolvem o uso da constante PI. Caso o problema não informe o valor a ser utilizado, há duas maneira de proceder para determinar o valor desta constante. A primeira é utilizar o valor definido na linguagem Python, que pode ser obtido com o script abaixo.

from math import *

print pi

O valor resultante, 3.141592653589793, está correto nas suas 15 casas decimais. Outra forma é utilizar a função acos da biblioteca de matemática padrão do C/C++.

#include <cmath>

const double PI = 2.0 * acos(0.0);

O valor obtido coincide com aquele fornecido pelo script Python.

O perímetro (circunferência) é o comprimento do contorno do círculo, e é igual a PI vezes o seu diâmetro, sendo o diâmetro o dobro do raio do círculo.

// Definição do valor de PI

class Circle {
public:

    // Membros e construtores

    double perimeter() const
    {
        return 2.0 * PI * r;
    }
};

O valor da área delimitada pelo círculo é igual a PI vezes o quadrado do raio do círculo.

// Definição do valor de PI

class Circle {
public:

    // Membros e construtores

    double area() const
    {
        return PI * r * r;
    }
};

Arcos e cordas

Um arco de um círculo corresponde a uma seção conectada da circunferência. O comprimento do arco pode ser determinado através do ângulo central a (definido pela união dos dois pontos extremos do arco entre si e com o centro do círculo) através do produto do perímetro P e a razão entre a e 2PI (caso a esteja em radianos). A simplificação desta razão nos leva a a*r.

// Definição do valor de PI

class Circle {
public:

    // Membros e construtores
    // Perímetro e área

    double arc(double a) const
    {
        return a * r;
    }
};

Uma corda corresponde a qualquer segmento de reta cujos pontos extremos estão sob o círculo. O diâmetro é a maior dentre todas as cordas possíveis de um círculo. Conhecidos o raio r e o ângulo central a do arco definido pela corda, o comprimento L da corda pode ser determinado através da Lei dos Cossenos (L = sqrt(2 * r * r * (1 - cos(a)) ou pela Trigonometria (L = 2 * r * sin(a/2)).

// Definição do valor de PI

class Circle {
public:

    // Membros e construtores
    // Perímetro e área

    double chord(double a) const
    {
        return 2 * r * sin(a/2);
    }
};

Setores e Segmentos

Um setor de um círculo é a área delimitada por um arco. Assim como no caso do arco, a área do setor será a fração da área total correspondente ao ângulo central a do arco que delimita o setor. A simplificação desta fração nos leva a ar²/2.

// Definição do valor de PI

class Circle {
public:

    // Membros e construtores
    // Perímetro e área

    double sector(double a) const
    {
        return a * r * r / 2.0;
    }
};

Um segmento de um círculo, associado a um ângulo central a, corresponde à área resultante da diferença entre o setor delimitado por a e do triângulo resultante do segmentos de reta que unem os extremos dos arcos ao centro do círculo e os extremos entre si (a corda). A área deste triângulo pode ser determinada pela Fórmula de Heron (semiperímetro).

class Circle {
public:

    // Membros e construtores
    // Setor e corda

    double segment(double a) const
    {
        auto c = chord(a);
        auto s = (r + r + c)/2.0;                   // Semiperímetro
        auto T = sqrt(s*(s - r)*(s - r)*(s - c));   // Área do triângulo

        return sector(a) - T;
    }
};

Considerando que T é um triângulo com base igual a corda e altura igual a rcos(a/2), chegamos a expressão fechada para o segmento: ar²(a - sen a)/2.

class Circle {
public:

    // Membros e construtores
    // Setor e corda

    double segment(double a) const
    {
        return r*r*(a - sin(a))/2.0;
    }
};

Construção de círculos a partir de pontos

É possível identificar o(s) círculo(s) que interceptam um conjunto de N pontos dados.

No caso de N = 1, existem infinitos círculos (com infinitos raios possíveis) que passam por um ponto. O caso N = 2 se torna mais interessante se o raio r também for dado de antemão. Dados dois pontos P e Q e o um raio r, os cenários possíveis são:

  1. P = Q: esta situação é idêntica ao caso N = 1;
  2. dist(P, Q) = 2r: se a distância entre os dois pontos dados é igual ao diâmetro do círculo, existe um único círculo de raio r que passa por P e Q. O centro deste círculo será o ponto médio do segmento PQ;
  3. dist(P, Q) > 2r: neste caso, nenhum círculo de r pode passar por ambos pontos simultaneamente
  4. dist(P, Q) < 2r: neste caso, exatamente dois círculos passam por P e Q com raio r. O código abaixo, adaptado do livro Competitive Programming 3, permite identificar um destes círculos. O outro pode ser encontrado invertendo os parâmetros (passar Q como primeiro e P como segundo parâmetro).
// Definição da class Point

class Circle {
public:
    // Membros e construtores

    static bool
    from2PointsAndRadius(const Point& P, const Point& Q, double r, Circle& c)
    {
        double d2 = (P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y);
        double det = r * r / d2 - 0.25;

        if (det < 0.0)
            return false;

        double h = sqrt(det);

        auto x = (P.x + Q.x) * 0.5 + (P.y - Q.y) * h;
        auto y = (P.y + Q.y) * 0.5 + (Q.x - P.x) * h;

        c = Circle(Point(x, y), r);

        return true;
    }
}

O método retorna falso se a distância entre os pontos é menor que o diâmetro. Nos demais casos, o círculo c, passado por referência, contém o centro e o raio de um círculo que intercepta ambos P e Q.

Para o caso N = 3 há uma interessante relação: se os pontos P, Q, R não são colineares, a equação do círculo que passa por estes três pontos pode ser expressa pelo determinante abaixo.

Equação do círculo que passa por 3 pontos

Este determinante também pode ser utilizado para determinar se 4 pontos são cocirculares, substituindo as coordenadas do quarto ponto nas variáveis da primeira linha.

Contudo, a implementação desta determinante não é trivial, uma vez que é preciso recorrer a cofatores, e o resultado final não fica na forma canônica, de onde são extraídas as informações sobre o raio e o centro.

Uma outra abordagem é observar que a distância entre os três pontos e o centro do círculo são iguais e, das relações d(P, C) = d(Q, C), d(P, C) = d(R, C), encontrar um sistema linear em relação as coordenadas do centro. Determinado o centro, o raio será a distância entre qualquer um dos pontos e o centro.

// Definição da classe Point e Circle

Circle circle_from_3_points(const Point& P, const Point& Q, const Point& R)
{
    auto a = 2*(Q.x - P.x);
    auto b = 2*(Q.y - P.y);
    auto c = 2*(R.x - P.x);
    auto d = 2*(R.y - P.y);

    auto det = a*d - b*c;

    // Pontos colineares
    if (equals(det, 0))
        return Circle();

    auto k1 = (Q.x*Q.x + Q.y*Q.y) - (P.x*P.x + P.y*P.y);
    auto k2 = (R.x*R.x + R.y*R.y) - (P.x*P.x + P.y*P.y);

    auto cx = (k1*d - k2*b)/det;
    auto cy = (a*k2 - c*k1)/det;

    Point C(cx, cy);
    auto r = C.distance(P);

    return Circle(C, r);
}

Interseção entre dois círculos

Dados dois círculos com centros C1, C2 e raios r1, r2, existem cinco cenários possíveis para suas interseções. Seja d a distância entre os pontos C1 e C2. Então

  1. se d > r1 + r2, então os círculos não se interceptam;
  2. se d < |r1 - r2|, então também não há interseção, pois um dos círculos (o de menor raio) está contido no outro (o de maior raio);
  3. se d == 0 e r1 == r2, então os círculos são idênticos: há infinitos pontos de interseção;
  4. se d == r1 + r2, os círculos se interceptam em um único ponto;
  5. nos demais casos, há dois pontos na interseção entre os círculos.

Se C1 = (x1, y1) e C2 = (x2, y2), então as coordenadas dos pontos de interseção P1 e P2 são dadas pelas expressões abaixo.

Interseção entre dois círculos

// Definição das classes Point e Circle

#define INF -1

using pp = pair<Point, Point>;
using ipp = pair<int, pp>;

ipp intersection(const Circle& c1, const Circle& c2)
{
    double d = c1.C.distance(c2.C);

    if (d > c1.r + c2.r or d < fabs(c1.r - c2.r))
        return ipp(0, pp(Point(), Point()));

    if (equals(d, 0) and equals(c1.r, c2.r))
        return ipp(INF, pp(Point(), Point()));

    auto a = (c1.r * c1.r - c2.r * c2.r + d * d)/(2 * d);
    auto h = sqrt(c1.r * c1.r - a * a);

    auto x = c1.C.x + (a/d)*(c2.C.x - c1.C.x);
    auto y = c1.C.y + (a/d)*(c2.C.y - c1.C.y);

    auto P = Point(x, y);

    x = P.x + (h/d)*(c2.C.y - c1.C.y);
    y = P.y - (h/d)*(c2.C.x - c1.C.x);
    auto P1 = Point(x, y);

    x = P.x - (h/d)*(c2.C.y - c1.C.y);
    y = P.y + (h/d)*(c2.C.x - c1.C.x);

    auto P2 = Point(x, y);

    return ipp(equals(d, c1.r + c2.r) ? 1 : 2, pp(P1, P2));
}

Interseção entre círculos e retas

Uma reta que passa pelos pontos P1 e P2 pode ser representada, na forma paramétrica, pela expressão vetorial P = P1 + u(P2 - P1), onde u é uma variável real. Assim, a coordenada x de P é dada por x = x1 + u(x2 - x1); de forma semelhante, a coordenada y de P é dada por y = y1 + u(y2 - y1).

Se estas coordenadas forem levadas para a equação do círculo de centro C e raio r (isto é, (x - Cx)² + (y - Cy)² = r²), obtemos o polinômio quadrático au² + bu + c = 0, onde

Coeficientes da interseção entre círculo e reta

O discriminante D (delta) desta equação caracteriza as possíveis interseções:

  1. se D < 0, não há interseção entre o círculo e a reta;
  2. se D == 0, há um único ponto de interseção (a reta é tangente ao círculo);
  3. se D > 0, há dois pontos distintos de interseção.
// Definição das classes Point e Circle

// Interseção entre o círculo c e a reta que passa por P e Q
ipp intersection(const Circle& c, const Point& P, const Point& Q)
{
    auto a = pow(Q.x - P.x, 2.0) + pow(Q.y - P.y, 2.0);
    auto b = 2*((Q.x - P.x) * (P.x - c.C.x) + (Q.y - P.y) * (P.y - c.C.y));
    auto d = pow(c.C.x, 2.0) + pow(c.C.y, 2.0) + pow(P.x, 2.0) + pow(P.y, 2.0)
        + 2*(c.C.x * P.x + c.C.y * P.y);

    auto D = b * b - 4 * a * d;

    if (D < 0)
        return ipp(0, pp(Point(), Point()));
    else if (equals(D, 0))
    {
        auto u = -b/(2*a);

        auto x = P.x + u*(Q.x - P.x);
        auto y = P.y + u*(Q.y - P.y);

        return ipp(1, pp(Point(x, y), Point()));
    }

    auto u = (-b + sqrt(D))/(2*a);

    auto x = P.x + u*(Q.x - P.x);
    auto y = P.y + u*(Q.y - P.y);

    auto P1 = Point(x, y);

    u = (-b - sqrt(D))/(2*a);

    x = P.x + u*(Q.x - P.x);
    y = P.y + u*(Q.y - P.y);

    auto P2 = Point(x, y);

    return ipp(2, pp(P1, P2));
}

Exercícios

  1. Codeforces
    1. 2C - Commentator Problem
  2. UVA
    1. 190 - Circle Through Three Points
    2. 438 - The Circumference of the Circle
    3. 10005 - Packing Polygons
    4. 10209 - Is This Integration?
    5. 10221 - Satellites
    6. 10563 - Geometry Paradox
    7. 10589 - Area
    8. 10678 - The Grazing Cow
    9. 12578 - 10:6:2

Referências

HALIM, Steve; HALIM, Felix. Competitive Programming 3, Lulu, 2013.

BOURKE, Paul. Intersection of two circles. Acesso em 06/08/2016.

QC.EDU.HK. Equation of circle passing through 3 givem points. Acesso em 18/08/2016.

Stack Exchange. Mathematics: Get the equation of a circle when given 3 points. Acesso em 18/08/2016.