Aqui está um quebra-cabeça de geometria enganosamente desafiador para você!
Dado um círculo A
e n
outros círculos B[n]
, encontre a área total contida dentro dela e A
que não esteja em nenhum círculo de B
.
Seu código deve ser o mais curto possível.
Entrada
Sua entrada deve conter as seguintes informações:
- Um número de ponto flutuante para representar o raio do círculo
A
. - Uma lista de números de ponto flutuante para representar os raios dos círculos
B
. - Uma lista dos centros de círculos em
B
. Seu programa pode esperar os centros em coordenadas polares ou cartesianas. - Opcionalmente, você pode receber o número
n
de círculos em B. Esta entrada não é necessária.
Deve-se assumir que o centro do círculo A
é a origem, ou seja, o ponto (0, 0)
.
É garantido que há dois círculos em B
são idênticos, mas é não garantida que: todos os círculos de B
intersecção A
, todos os centros de B
estão fora A
, ou há dois círculos em B
cruzam entre si. Verifique se sua solução pode lidar com vários casos extremos.
Você pode receber entrada em qualquer ordem e na forma de entrada de texto (por meio de stdin ou equivalente do seu idioma), parâmetros de função ou argumentos da linha de comando.
Se você optar por receber entrada de texto, deve haver delimitadores ASCII imprimíveis de um ou dois caracteres entre as partes da entrada.
Resultado
Seu programa ou função deve gerar um único número de ponto flutuante representando a área total que A
não está dentro de nenhum dos círculos de B
. Suas respostas devem ter precisão de pelo menos três números significativos para todos os casos de teste.
Aplicam-se as regras gerais de código-golfe .
Sua solução não deve contar com pontos de amostragem dentro dos círculos para determinar uma área.
Os incorporados que localizam automaticamente interseções de círculos, localizam áreas dentro de interseções de círculos ou resolvem esse problema imediatamente não são permitidos.
Casos de teste
Em cada imagem, o círculo A
é destacado em azul, com círculos B
destacados em verde e preto preenchido. A área que deve ser retornada é preenchida em vermelho.
(Agradecimentos especiais a Rainer P. por verificar minhas soluções)
Caso de teste 1:
A = {x: 0, y: 0, rad: 50}
B[0] = {x: 0, y: 0, rad: 100}
Result: 0.00
Caso de teste 2:
A = {x: 0, y: 0, rad: 100.000000}
B[0] = {x: 100.000000, y: 0.000000, rad: 50.000000}
B[1] = {x: 30.901699, y: -95.105652, rad: 50.000000}
B[2] = {x: -80.901699, y: -58.778525, rad: 50.000000}
B[3] = {x: -80.901699, y: 58.778525, rad: 50.000000}
B[4] = {x: 30.901699, y: 95.105652, rad: 50.000000}
Result: 1.3878e+04
Caso de teste 3:
A = {x: 0, y: 0, rad: 138}
B[0] = {x: 100, y: 0, rad: 100}
B[1] = {x: -50, y: -86, rad: 100}
B[2] = {x: -93, y: 135, rad: 50}
Result: 1.8969e+04
Caso de teste 4:
A = {x: 0, y: 0, rad: 121.593585}
B[0] = {x: 81.000000, y: 107.000000, rad: 59.841457}
B[1] = {x: -152.000000, y: -147.000000, rad: 50.000000}
B[2] = {x: 43.000000, y: -127.000000, rad: 105.118980}
B[3] = {x: 0.000000, y: -72.000000, rad: 57.870545}
B[4] = {x: -97.000000, y: -81.000000, rad: 98.488578}
B[5] = {x: -72.000000, y: 116.000000, rad: 66.468037}
B[6] = {x: 2.000000, y: 51.000000, rad: 50.000000}
Result: 1.1264e+04
Caso de teste 5:
A = {x: 0, y: 0, rad: 121.605921}
B[0] = {x: 0.000000, y: -293.000000, rad: 250.000000}
B[1] = {x: 0.000000, y: -56.000000, rad: 78.230429}
B[2] = {x: 0.000000, y: -102.000000, rad: 100.000000}
Result: 2.6742e+04
Leitura sugerida:
Ademais, MP "Área de sobreposição comum de três círculos". Outubro de 2006. Web. http://dspace.dsto.defence.gov.au/dspace/bitstream/1947/4551/4/DSTO-TN-0722.PR.pdf .
fonte
B
contenha outro. Pode valer a pena acrescentar isso.1.8970e+04
.B[0] - A intersection: 20653.659515
,B[1] - A intersection: 20757.824115
,B[1] - B[0] intersection: 1841.847766
,B[2] - A intersection: 1289.164541
, que produz18969.69009
como resposta.Respostas:
Python 2, 631 bytes
Quebras de linha precedidas por
\
são de fácil leitura e não são contadas na pontuação.Lê a entrada através de STDIN como uma lista de
(center, radius)
pares, ondecenter
é um número complexo no formulárioX+Yj
. O primeiro círculo na lista é A (cujo centro não tem que estar na origem), e do resto da lista é B . Imprime o resultado em STDOUT.Exemplo
Explicação
Essa é uma variação (mais longa e muito mais feia: P) da minha solução para o desafio Área de um polígono de auto-interseção de Martin Büttner . Ele usa o mesmo truque de dividir o problema em pedaços pequenos o suficiente, para os quais se torna mais gerenciável.
Encontramos os pontos de interseção entre todos os pares de círculos (considerando A e os círculos em B ) e passamos uma linha vertical por cada um deles. Além disso, passamos todas as linhas verticais tangentes a qualquer um dos círculos. Nós jogar fora todas as linhas que não se cruzam A , de modo que todas as linhas restantes são entre as tangentes esquerdo e direito de uma .
Estamos procurando a área da interseção de A e a união dos círculos em B - a área vermelha escura na ilustração acima. Esta é a área que temos que subtrair de A para obter o resultado.
Entre cada par de linhas verticais consecutivas, essa área pode ser dividida em um conjunto de trapézios verticais (ou triângulos ou segmentos de linha, como casos especiais de trapézios), com um segmento de arco "excessivo" próximo a cada perna. O fato de passarmos tantas linhas verticais quanto garantimos que a área delimitada não é realmente mais complicada do que isso, pois, caso contrário, teria que haver um ponto adicional de interseção e, portanto, uma linha vertical adicional, entre as duas linhas em questão.
Para encontrar esses trapézios e segmentos de arco, para cada par de linhas verticais consecutivas, encontramos os segmentos de arco de cada um dos círculos que se encontram adequadamente entre essas duas linhas (é claro, alguns círculos podem não ter segmento de arco entre um determinado par de linhas .) Na ilustração abaixo, esses são os seis segmentos de arco amarelo (claro e escuro), ao considerar as duas linhas verticais vermelhas. Observe que, como passamos todas as linhas verticais tangentes aos círculos, se um círculo possui um segmento de arco entre as duas linhas, ele cruza necessariamente as duas linhas, o que simplifica o restante do algoritmo.
Nem todos esses arcos são relevantes; estamos interessados apenas nos que estão no limite da interseção entre A e a união de B . Para encontrá-los, classificamos os arcos de cima para baixo (observe que os arcos podem não se cruzar adequadamente, pois isso implicaria a existência de outra linha vertical entre os dois que estamos considerando e, portanto, faz sentido conversar sobre um arco arbitrário estar acima ou abaixo de qualquer outro.)
Atravessamos os arcos, em ordem, mantendo a contagem do número de círculos B em que estamos atualmente, n . Se n mudar de 0 para 1 enquanto estivermos dentro de A , ou se estivermos no arco superior de A enquanto n for diferente de zero, o arco atual corresponderá a uma perna de um trapézio. Se n mudar de 1 para 0 enquanto estivermos no interior for diferente de zero, o arco atual corresponderá à outra perna do mesmo trapézio. Quando encontramos um par de arcos (os dois arcos amarelos brilhantes na ilustração acima), calculamos a área do trapézio correspondente e dos dois segmentos de arco e o adicionamos à área total a ser subtraída de A , ou se estivermos no arco inferior de A enquanto n um .
O cálculo da área de A , bem como das áreas dos trapézios, é bastante simples. A área de cada segmento do arco é a área do setor circular correspondente, menos a área do triângulo cujos vértices são os dois pontos finais do segmento do arco e o centro do círculo correspondente.
fonte