Java2D Sistema de coordernadas não se aplica em todos os casos

Olá JavaBoys,

estou desenvolvendo um aplicativo com a ajuda do Java2D para representar um mapeamento de sensores. Cada sensor tem uma área de cobertura e uma área de comunicação representadas pelo circulo cinza claro (menor) e cinza escuro (maior) nas figuras abaixo, o problema, como vocês podem ver nas figuras é que os dois círculos não ficam em sincronia com seu respectivo sensor. Eu simplemente já tentei de tudo mas ainda não descobri a origem deste problema, o que será?

Para construir o desenho eu me basei na primeira figura, por isso ela está toda certinha, porém na segunda figura (gerada aleatoriamente) os objetos parecem que estão em coordenadas diferentes.

Eu até tenho outra dúvida, mas vamos resolver esta primeiro.

Com certeza é algum problema na lógica.

Posta a parte significativa do código que faz a lógica do desenho.

Heheeh

esqueci do meu código, vou postá-lo. Minhas classes que trabalham com o Java2D são as seguintes:

package Gui.Java2D;

import Logica.AgmPrim;
import Logica.Rede;
import Logica.Sensor;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;

/**
 *
 * @author Maycon
 */
public class painel2D extends javax.swing.JPanel {

    /** Creates new form painel2D */
    public painel2D() {
        initComponents();
        this.setBackground(Color.white); //Altera a cor de fundo
        //this.setSize(10, 10); //Define um tamanho para o painel
    }

    //Este método é invocado para desenhar o Painel
    @Override
    public void paint(Graphics g) {
        super.paint(g);

        //Cria um contexto gráfico com a área restrita dentro do JPanel
        Dimension size = getSize();  
        Graphics2D clip = (Graphics2D) g.create(getInsets().left,
                getInsets().top,
                getWidth() - getInsets().right,
                getHeight() - getInsets().bottom);

        //transforma a tela num plano cartesiano 100x100 com a origem no centro
        //faz com que a imagem seja distorcida proporcionalmente ao redimensionamento da janela
        clip.scale(size.width / 100d, size.height / 100d);
        clip.translate(50, 50);
        clip.scale(1, -1);//Transforma o eixo y em ascendente, ou seja, agora ele soma quando sobre e diminui quando desce

        //Instancia a rede para posicionar os sensores na imagem
        Rede r = Rede.getInstance();

        //Instancia o Agm para posicionar as arestas na imagem
        AgmPrim agm = AgmPrim.getInstance();

        //Pintando as arestas
        //Para todos as arestas presente no algoritimo de Prim
        for (int i = 0; i < agm.numeroDeArestas(); i++) {
            //Se o sensor atual tiver antecedente no AgmPrim
            //Então será desenhada a aresta entre o sensor atual e o seu antecessor
            if(agm.antecessor(i) != -1){
                Sensor atual = r.getSensor(i);
                Sensor antecessor = r.getSensor(agm.antecessor(i));
                Aresta2D a = new Aresta2D(atual.getX(), atual.getY(), antecessor.getX(), antecessor.getY(), agm.peso(i));
                a.paint(clip);
            }
           
        }

        //Pintando os sensores
        //Para todos os sensores da Rede
        for (int i = 0; i < r.getRedeSensores().size(); i++) {
            Sensor2D s = new Sensor2D(r.getSensor(i));
            s.paint(clip);
        }

        //Descarta a cópia do contexto gráfico
        clip.dispose();


    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 570, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 416, Short.MAX_VALUE)
        );
    }// </editor-fold>                        
    // Variables declaration - do not modify                     
    // End of variables declaration                   
}
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Gui.Java2D;

import Logica.Sensor;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;

/**
 *
 * @author Maycon
 */
public class Sensor2D {

    private Sensor sensor;

    public Sensor2D(Sensor s){
        this.sensor = s;
    }

    public void paint(Graphics2D g2d){

        //Cria o contexto no qual o desenho será feito
        Graphics2D g = (Graphics2D) g2d.create();

        if(sensor.isAtivacao())
            ativo(g);
        else
            inativo(g);

        
    }

    public void ativo(Graphics2D g){

        //Tenta aplicar anti-aliasing
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        //Pinta a cor
        if(sensor.getId() == 1)
            g.setColor(Color.red);
        else
            g.setColor(Color.green);

        //Desenha o path do sensor
        g.fill(new Arc2D.Double(sensor.getX(), sensor.getY(), 2, 2, 0, 360, Arc2D.PIE));//Desenha o path
        g.setColor(Color.black);

        //Rotula os sensores com seus respectivos id's
        g.scale(1, -1);
        g.setFont(new Font("SansSerif", Font.PLAIN, 2));
        g.drawString(Integer.toString(sensor.getId()) , (float)sensor.getX(), ((float)-sensor.getY()));
        g.scale(1, -1);

        //Desenha o path da distância de comunicação do sensor
        g.setColor(Color.gray);
        g.setStroke(new BasicStroke(0.1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g.draw(new Ellipse2D.Double(sensor.getX() - 24, sensor.getY() -24, sensor.getComunicacao(), sensor.getComunicacao()));

        //Desenha o path da distância de cobertura do sensor
        g.setColor(Color.lightGray);
        g.setStroke(new BasicStroke(0.1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g.draw(new Ellipse2D.Double(sensor.getX() - 9, sensor.getY() -9, sensor.getCobertura(), sensor.getCobertura()));


        //Descarta a cópia do contexto gráfico
        g.dispose();

    }

    public void inativo(Graphics2D g){

        //Desenha o path do sensor
        g.setColor(Color.lightGray);
        g.fill(new Arc2D.Double(sensor.getX(), sensor.getY(), 2, 2, 0, 360, Arc2D.PIE));//Desenha o path

        //Rotula os sensores com seus respectivos id's
        g.scale(1, -1);
        g.setFont(new Font("SansSerif", Font.PLAIN, 2));
        g.setColor(Color.black);
        g.drawString(Integer.toString(sensor.getId()) , (float)sensor.getX(), ((float)-sensor.getY()));
        g.scale(1, -1);

    }
}
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Gui.Java2D;

import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;

/**
 *
 * @author Maycon
 */
public class Aresta2D {

    private double x1;
    private double y1;
    private double x2;
    private double y2;
    private double peso;

    public Aresta2D(double x1, double y1, double x2, double y2, double peso) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
        this.peso = peso;
    }

    public void paint(Graphics2D g2d) {

        //Cria o contexto no qual o desenho será feito
        Graphics2D g = (Graphics2D) g2d.create();

        //Tenta aplicar anti-aliasing
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        //Desenha uma linha
        g.setStroke(new BasicStroke(0.1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g.draw(new Line2D.Double(this.x1 + 1, this.y1 + 1, this.x2 + 1, this.y2 + 1));
        
        //Descarta a cópia do contexto gráfico
        g.dispose();
    }
}

Exceto pelo fato de que em JPanels você sobrescreve o paintComponent, e não o paint. E que está faltando dar dispose() na sua sua classe do sensor, não vi nenhum erro aparente.

Por que você diz que parecem estar em coordenadas diferentes?

Por que tem essas contas aqui?
sensor.getX() - 24, sensor.getY() -24

Se isso foi um “ajuste” para que a aresta se posicionasse no meio, esse ajuste só funcionará para um tamanho de círculo. O ideal, seria subtrair metado do raio da elipse, que muda de acordo com o caso. Por exemplo, nessa linha:

Seria provavelmente:

float meior = sensor.getComunicacao() / 2.0; g.draw(new Ellipse2D.Double(sensor.getX() - meior, sensor.getY() - meior, sensor.getComunicacao(), sensor.getComunicacao()));

Outra coisa que percebi quando você usa Arc2D e outros métodos que desenham formas quando se faz a tradução de coordenadas de modo que a seta do eixo y aponte para cima (em vez de apontar para baixo, que é o padrão do Java) é que você tem de tomar cuidado com as coordenadas passadas - elas ainda supõem que o eixo de coordenadas aponte para baixo, e isso pode ocasionar resultados inesperados.

Olá,

inseri o dispose() na classe sensor e troquei o paint() pelo paintComponent() no meu jPanel.

Também modifiquei as coordernadas da classe Sensor2D de acordo com o que o ViniGodoy sugeriu e pimba! Problema corrigido com sucesso!!
Muito obrigado a todos.

ViniGodoy, qual é a diferença do método paint() para o paintComponent()???

Minha outra dúvida era para inserir um jComboBox em uma tabela (para que eu possa alterar o estado dos sensores e recriar o desenho em tempo de execução), pois, as soluções que encontrei para isto não foram claras e não cosegui implantá-las. Talvez seja melhor eu abrir outro tópico para solucionar esta dúvida minha?

Segue abaixo a minha classe Sensor2D para mostrar como a mesma ficou após as alterações.

package Gui.Java2D;

import Logica.Sensor;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;

/**
 *
 * @author Maycon
 */
public class Sensor2D {

    private Sensor sensor;

    public Sensor2D(Sensor s){
        this.sensor = s;
    }

    public void paint(Graphics2D g2d){

        //Cria o contexto no qual o desenho será feito
        Graphics2D g = (Graphics2D) g2d.create();

        if(sensor.isAtivacao())
            ativo(g);
        else
            inativo(g);

        //Descarta a cópia do contexto gráfico
        g.dispose();
        
    }

    public void ativo(Graphics2D g){

        //Tenta aplicar anti-aliasing
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        //Pinta a cor
        if(sensor.getId() == 1)
            g.setColor(Color.red);
        else
            g.setColor(Color.green);

        //Desenha o path do sensor
        g.fill(new Arc2D.Double(sensor.getX() - 1, sensor.getY() - 1, 2, 2, 0, 360, Arc2D.PIE));//Desenha o path
        g.setColor(Color.black);

        //Rotula os sensores com seus respectivos id's
        g.scale(1, -1);
        g.setFont(new Font("SansSerif", Font.BOLD, 2));
        g.drawString(Integer.toString(sensor.getId()) , (float)sensor.getX() - 1, ((float)-sensor.getY() - 1));
        g.scale(1, -1);

        //Desenha o path da distância de comunicação do sensor
        double meior = sensor.getComunicacao() / 2.0;
        g.setColor(Color.gray);
        g.setStroke(new BasicStroke(0.1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g.draw(new Ellipse2D.Double(sensor.getX() - meior, sensor.getY() - meior, sensor.getComunicacao(), sensor.getComunicacao()));

        //Desenha o path da distância de cobertura do sensor
        meior = sensor.getCobertura() / 2.0;
        g.setColor(Color.lightGray);
        g.setStroke(new BasicStroke(0.1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g.draw(new Ellipse2D.Double(sensor.getX() - meior, sensor.getY() - meior, sensor.getCobertura(), sensor.getCobertura()));
    }

    public void inativo(Graphics2D g){

        //Desenha o path do sensor
        double meior = sensor.getComunicacao() / 2.0;
        g.setColor(Color.lightGray);
        g.fill(new Arc2D.Double(sensor.getX() - 1, sensor.getY() - 1, 2, 2, 0, 360, Arc2D.PIE));//Desenha o path

        //Rotula os sensores com seus respectivos id's
        g.scale(1, -1);
        g.setFont(new Font("SansSerif", Font.BOLD, 2));
        g.setColor(Color.black);
        g.drawString(Integer.toString(sensor.getId()) , (float)sensor.getX() - 1, ((float)-sensor.getY() - 1));
        g.scale(1, -1);

    }
}