Как настроить желаемые координаты в Graphics2D

Я хочу настроить математическое (где y растет вверх, а не вниз) координатное пространство от (-1, -1) до (+1, +1) и разместить его в окне независимо от размера окна.

Я использую анонимный подкласс JComponent в Java SE 7 и привожу входящий Graphics в paintComponent к Graphics2D, а затем рисую Graphics2D

Но Graphics2D устанавливается в пространстве координат компьютера, которое изменяется в зависимости от размера окна. Как заставить его масштабироваться в соответствии с размером окна и увеличивать Y? Следующая программа должна показать темный квадрат в верхнем правом квадранте.

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;

import javax.swing.JComponent;
import javax.swing.JFrame;

public class G {
  public static void main (String [] args) {
    JFrame frame = new JFrame(G.class.getCanonicalName());
    frame.setUndecorated(true);
    JComponent component = new JComponent() {
      private static final long serialVersionUID = 1L;
      @Override
      protected void paintComponent (Graphics g) {
        super.paintComponent(g);
        paint2D((Graphics2D)g);
      }
      protected void paint2D (Graphics2D g2) {
        g2.draw(new Rectangle2D.Double(0.1, 0.1, 0.9, 0.9));
      }
    };
    frame.add(component);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(400, 400);
    frame.setVisible(true);
  }
}

person necromancer    schedule 14.05.2013    source источник


Ответы (1)


Настройте систему координат по своему усмотрению, используя transform() и translate(). Так:

  1. вы хотите, чтобы начало координат было на (0, высота); Нижняя левая.
  2. то вы хотите перевернуть ось Y.

Пример кода:

AffineTransform tform = AffineTransform.getTranslateInstance( 0, height);
tform.scale( 1, -1);
g2.setTransform( tform);

[Моя отредактированная версия]:

public static void main (String [] args) {
    JFrame frame = new JFrame( G2dTransform_Question.class.getCanonicalName());
    JComponent component = new JComponent() {
        private static final long serialVersionUID = 1L;
        @Override
        protected void paintComponent (Graphics g) {
            super.paintComponent(g);
            paint2D((Graphics2D)g);
        }
        protected void paint2D (Graphics2D g2) {
            AffineTransform tform = AffineTransform.getTranslateInstance( 0, getHeight());
            tform.scale( getWidth(), -getHeight());    // NOTE -- to make 1.0 'full width'.
            g2.setTransform( tform);

            g2.setColor( Color.BLUE);  // NOTE -- so we can *see* something.
            g2.fill( new Rectangle2D.Double(0.1, 0.1, 0.8, 0.8));  // NOTE -- 'fill' works better than 'draw'.
        }
    };

    frame.setLayout( new BorderLayout());    // NOTE -- make the component size to frame.
    frame.add( component, BorderLayout.CENTER);

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(400, 400);
    frame.setVisible(true);
}

[Версия на воздушной подушке]: Спасибо, Ховер!

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;

import javax.swing.JComponent;
import javax.swing.JFrame;

public class G {
  public static final int PREF_W = 400;
  public static final int PREF_H = PREF_W;

public static void main (String [] args) {
    JFrame frame = new JFrame(G.class.getCanonicalName());
    frame.setUndecorated(true);
    JComponent component = new JComponent() {
      private static final long serialVersionUID = 1L;
      @Override
      protected void paintComponent (Graphics g) {
        super.paintComponent(g);
        AffineTransform tform = AffineTransform.getTranslateInstance( 0, getHeight());
        tform.scale( 1, -1);
        Graphics2D g2 = (Graphics2D) g.create();
        g2.setTransform( tform);
        paint2D(g2);
        g2.dispose();
      }
      protected void paint2D (Graphics2D g2) {
        g2.draw(new Rectangle2D.Double(10, 10, 20, 30));
      }

      @Override
      public Dimension getPreferredSize() {
         return new Dimension(PREF_W, PREF_H);
      }
    };
    frame.add(component);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }
}
person Thomas W    schedule 14.05.2013
comment
спасибо, но я не знаю, как это сделать. Должен ли я использовать getWidth() и getHeight(), чтобы интервал [-1,+1] соответствовал каждому измерению? а как перевернуть? я не разбираюсь в матрицах. есть ли способ создать флип-преобразование? или мне дважды повернуть? это, по сути, конкретные методы и аргументы, которые я ищу. - person necromancer; 14.05.2013
comment
спасибо, но это не сработало. раньше я получал крошечную точку в левом верхнем углу, как и ожидалось. теперь ничего ... проголосовали, но не решили проблему отображения прямоугольника в правом верхнем квадранте. - person necromancer; 14.05.2013
comment
` Преобразование AffineTransform = AffineTransform.getTranslateInstance(0, getHeight()); трансформировать.шкала(1, -1); g2.setTransform(преобразование); g2.draw(новый Rectangle2D.Double(+0.1, +0.1, +0.9, +0.9));` - person necromancer; 14.05.2013
comment
Пример добавлен. Томас, вы можете редактировать или исправлять, как считаете нужным. Но это показывает, что ваше предложение работает. Я рекомендую преобразовывать только копии объекта Graphics, чтобы предотвратить побочные эффекты в дальнейшем. Мне также нравится переопределять getPreferredSize(...) как более чистый способ установки моего компонента и, следовательно, размера моего графического интерфейса. 1+ к ответу. - person Hovercraft Full Of Eels; 14.05.2013
comment
вау @HovercraftFullOfEels я тронут. слезы текут по щеке. не потому, что ваш ответ правильный или нет, а потому, что вы дали код, а не руководство! Я попробую ответить сейчас. ‹вытирает, всхлипывает› - person necromancer; 14.05.2013
comment
@HovercraftFullOfEels спасибо за все улучшения в том, как получить g2 и как использовать getPreferredSize. основная часть лучше, но я озадачен, почему, если я рисую прямоугольник размеров (10, 10, 390, 390), видны только нижняя и левая стороны. видимая часть достигает максимума (10, 10, 389, 390) - person necromancer; 14.05.2013
comment
@ThomasW ааа... манна небесная! спасибо - отлично работает! :) - person necromancer; 14.05.2013
comment
@ThomasW, если подумать, когда я изменил 0.8 на 0.9, результат выглядит не так. не беспокойтесь исправить это, если это не беспокоит. я думаю, решит уравнения, чтобы получить преобразования трудным путем. - person necromancer; 14.05.2013
comment
@randomstring - эти вторые два параметра для Rect - это width/height, а не X/Y! - person Thomas W; 14.05.2013
comment
@ThomasW оказывается, что draw сбил меня с толку. fill работает иначе, чем draw. - person necromancer; 14.05.2013
comment
@HovercraftFullOfEels продолжение этого stackoverflow.com/questions/16535904/graphics2d-does-postmodern - person necromancer; 14.05.2013