Ir para conteúdo


Revista PROGRAMAR – Edição 46 (Setembro 2014): Download já disponível!

- - - - -

[Resolvido] Ponto dentro de um circulo segmentado


  • Por favor inicie sessão para responder
7 respostas a este tópico

#1 Cybernavigator

Cybernavigator

    Try-Catch User

  • Membro
  • PipPipPipPip
  • 412 mensagens

Publicado 16 de Junho de 2010 - 18:11

Boas, acho que aqui será o melhor sítio para colocar esta dúvida.
Eu tenho um circulo segmentado, e gostava de saber se um ponto está dentro ou fora desse circulo.
Para explicar melhor vou colocar imagens
Imagem Colocada
Isso é o que eu tenho, quando passo o rato na área do donut o que acontece é isto
Imagem Colocada
O segmento fica mais vermelho, mas a área de detecção é o que está a preto mais o que está a vermelho.
A forma como estou a detectar se o ponto está dentro dos limites é a seguinte:

Código :
SE ( (rato.x-centro-x)^2 + (rato.y-centro.y)^2 < raioMaior^2 ) ENTAO

                SE   ( (rato.x-centro-x)^2 + (rato.y-centro.y)^2 > raioMenor^2 )  ENTAO
                         APRESENTA("Dentro dos limites");
                FIM SE

FIM SE
Desta forma eu detecto se está entre o circulo de raio menor e o de raio maior.

Agora o problema está em detectar se está dentro do segmento vermelho. Alguém me sabe ajudar com isto?

Obrigado desde já.

#2 Localhost

Localhost

    Unsigned User

  • Membro
  • PipPipPipPipPipPip
  • 2722 mensagens

Publicado 16 de Junho de 2010 - 18:27

Se souberes a ordenada em que a área vermelha começa podes fazer mais uma verificação que vê se Y é maior que essa ordenada.

#3 Cybernavigator

Cybernavigator

    Try-Catch User

  • Membro
  • PipPipPipPip
  • 412 mensagens

Publicado 16 de Junho de 2010 - 18:38

Ver MensagemLocalhost, em 16 de Junho de 2010 - 18:27, disse:

Se souberes a ordenada em que a área vermelha começa podes fazer mais uma verificação que vê se Y é maior que essa ordenada.
Sim, eu sei onde ele começa, eu percebo o que queres dizer com detectar se está acima dos limites, mas eu queria generalizar a coisa.
Por exemplo, o segmento começa no angulo 0, mas pode começar a 45, acabar em 270, e por aí em diante. Essa solução não me dá grande resultado :S
THX.

#4 Warrior

Warrior

    Unsigned User

  • Moderador
  • PipPipPipPipPipPip
  • 3053 mensagens

Publicado 16 de Junho de 2010 - 18:39

Ver MensagemLocalhost, em 16 de Junho de 2010 - 18:27, disse:

Se souberes a ordenada em que a área vermelha começa podes fazer mais uma verificação que vê se Y é maior que essa ordenada.
Não funciona para segmentos não horizontais.

Tudo depende de como conheces a área a vermelho, mas a forma mais fácil é guardando dois ângulos ao centro e calcular o ângulo ao centro do ponto que queres testar. Tem cuidado porque as contas são módulo 2 PI.

#5 Localhost

Localhost

    Unsigned User

  • Membro
  • PipPipPipPipPipPip
  • 2722 mensagens

Publicado 16 de Junho de 2010 - 18:41

Pensei que o segmento fosse sempre horizontal, desculpa.

#6 Tharis

Tharis

    Unsigned User

  • Membro
  • PipPipPipPipPipPip
  • 2887 mensagens

Publicado 16 de Junho de 2010 - 18:44

A = vértice inferior esquerdo do lado esquerdo da parte vermelha
B = vértice inferior direito do lado direito da parte vermelha

Se o rato estiver à esquerda do centro, verificas se rato.y está por cima da recta definida pelo centro e pelo ponto A.
Se o rato estiver à direita do centro, verificas se rato.y está por cima da recta definida pelo centro e pelo ponto B.

As rectas podem ser escritas na forma y = mx + b, em que m é o declive e é a diferença em YY de dois pontos sobre a diferença em XX dos mesmos dois pontos.

Código :
m1 = (centro.y-A.y)/(centro.x-A.x)
b1 = centro.y - m1 * centro.x

m2 = (centro.y-B.y)/(centro.x-B.x)
b2 = centro.y - m2 * centro.x


SE ( (rato.x-centro-x)^2 + (rato.y-centro.y)^2 < raioMaior^2 ) ENTAO
                SE   ( (rato.x-centro-x)^2 + (rato.y-centro.y)^2 > raioMenor^2 )  ENTAO
                                SE ( rato.x < centro.x AND rato.y > m1 * rato.x + b1) ENTAO
                                                APRESENTA("Dentro dos limites");
                                FIM SE
                                SE ( rato.x > centro.x AND rato.y > m2 * rato.x + b2) ENTAO
                                                APRESENTA("Dentro dos limites");
                                FIM SE
                FIM SE
FIM SE


#7 Cybernavigator

Cybernavigator

    Try-Catch User

  • Membro
  • PipPipPipPip
  • 412 mensagens

Publicado 16 de Junho de 2010 - 19:00

Ver MensagemTharis, em 16 de Junho de 2010 - 18:44, disse:

A = vértice inferior esquerdo do lado esquerdo da parte vermelha
B = vértice inferior direito do lado direito da parte vermelha

Se o rato estiver à esquerda do centro, verificas se rato.y está por cima da recta definida pelo centro e pelo ponto A.
Se o rato estiver à direita do centro, verificas se rato.y está por cima da recta definida pelo centro e pelo ponto B.

As rectas podem ser escritas na forma y = mx + b, em que m é o declive e é a diferença em YY de dois pontos sobre a diferença em XX dos mesmos dois pontos.

Código :
m1 = (centro.y-A.y)/(centro.x-A.x)
b1 = centro.y - m1 * centro.x

m2 = (centro.y-B.y)/(centro.x-B.x)
b2 = centro.y - m2 * centro.x


SE ( (rato.x-centro-x)^2 + (rato.y-centro.y)^2 < raioMaior^2 ) ENTAO
                SE   ( (rato.x-centro-x)^2 + (rato.y-centro.y)^2 > raioMenor^2 )  ENTAO
                                SE ( rato.x < centro.x AND rato.y > m1 * rato.x + b1) ENTAO
                                                APRESENTA("Dentro dos limites");
                                FIM SE
                                SE ( rato.x > centro.x AND rato.y > m2 * rato.x + b2) ENTAO
                                                APRESENTA("Dentro dos limites");
                                FIM SE
                FIM SE
FIM SE

Awesome, agora vem outro problema que é detectar os Vértices mais acima ou mais em baixo.
Mas resolveu muito o problema, obrigadissimo.

#8 Cybernavigator

Cybernavigator

    Try-Catch User

  • Membro
  • PipPipPipPip
  • 412 mensagens

Publicado 16 de Junho de 2010 - 19:06

Bem, agora que vejo bem, não, não funciona lá muito bem, para o exemplo que eu dei funciona minimamente, para o caso de começar em 45º e acabar em 120º já não tem nada a ver.

apliquei da seguinte forma
Código (Objective-C):
NSRect rrect = [self bounds];
        NSPoint center = {rrect.size.width/2, rrect.size.height/2};
        int greaterRadius = (innerRadius > outerRadius) ? innerRadius : outerRadius;
        int lesserRadius = (innerRadius < outerRadius) ? innerRadius : outerRadius;
       
        NSPoint A = {center.x+cos(RADIANS_TO_DEGREES(startingAngle))*lesserRadius ,
                center.y+sin(RADIANS_TO_DEGREES(startingAngle))*lesserRadius};
        NSPoint B = {center.x+cos(RADIANS_TO_DEGREES(endingAngle))*lesserRadius ,
                center.y+sin(RADIANS_TO_DEGREES(endingAngle))*lesserRadius};
       
        int m1 = (center.y-A.y)/(center.x-A.x);
        int b1 = center.y - m1 * center.x;
       
        int m2 = (center.y-B.y)/(center.x-B.x);
        int b2 = center.y - m2 * center.x;
       
       
       
        if ((pow((mouse.x-center.x),2) + pow((mouse.y - center.y),2) < pow(greaterRadius,2)) && (pow((mouse.x-center.x),2) + pow((mouse.y - center.y),2) > pow(lesserRadius,2))){
                if (mouse.x < center.x && mouse.y > m1 * mouse.x + b1) {
                        return 1;
                }
                if (mouse.x > center.x && mouse.y > m2 * mouse.y + b2) {
                        return 1;
                }
        }
       
        return 0;

É a forma correcta para obter o A ou o B? A função RADIAN_TO_DEGREES faz exactamente o contrário :)