在Java2D AWT框架中使用世界坐标

问题描述 投票:0回答:1

我在尝试实施世界坐标到设备坐标转换时遇到困难。

基本上我想绘制以下世界坐标:

    // --- World Coordinates
    //
    //                  (xmax,ymax)
    //      ┌────────────────┐
    //      │                │
    //      │                │
    //      │                │
    //      │                │
    //      └────────────────┘
    // (xmin,ymin)
    //
    // (xmin,ymin) = (0, 100)
    // (xmax,ymax) = (1.5, 2.5)

在本书(第31页)之后,我试图实现从世界坐标视口移动到设备坐标视口所需的仿射变换。

    // Introduction to Computer Graphics Using Java 2D and 3D 
    // Frank Klawonn, Ed. Springer 2008
    // Page 31

我准备了一个包含两个测试的测试类,第一个测试类(仅设置int test = 1)测试前两个转换以翻转Y轴(屏幕左上角的原点,而不是左下角)。

测试工作正常,绘制矩形和线条来显示这一点。

Test1

但是,在切换到包含所有预期转换的测试2时,我得到一个空屏幕,结果如下:

    // --- Affine Transform 1 and 2
    //
    //   T(0, h) ◦ S(1,−1)
    //
    // --- Affine Transform 3, 4 and 5
    //   
    //                     ╭ umax − umin   vmax − vmin ╮
    //   T(umin, vmin) ◦ S | ----------- , ----------- | ◦ T(-xmin, -ymin)  
    //                     ╰ xmax − xmin   ymax − ymin ╯
    //

包含Test类的完整源代码:

package com.example.test2;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;

public class Test2 extends Frame {

        Graphics2D          g2d;

        Insets              insFrame;
        Dimension           sizeFrame;

        public Test2() {

            this.setSize(660,540);            
            this.setUndecorated(false);
            this.setVisible(true);

            this.addWindowListener(new WindowAdapter(){  
                public void windowClosing(WindowEvent e) {  
                    dispose();  
                }  
            });

        }

        @Override
        public void paint(Graphics g) {

            g2d = (Graphics2D) g;

            insFrame = this.getInsets();
            sizeFrame = this.getSize();

            //int test = 1;   // Change to test 2 to test the whole transformation
            int test = 2;

            if ( test == 1 ) {

                // AT1 & AT2 Test
                this.setScale(1);
                g2d.setColor(Color.ORANGE);
                Line2D.Double line = new Line2D.Double(0, 0, sizeFrame.width-insFrame.left-insFrame.right-1, sizeFrame.height-insFrame.top-insFrame.bottom);
                g2d.draw(line);
                g2d.setColor(Color.RED);
                g2d.drawRect(0, 0, sizeFrame.width-insFrame.left-insFrame.right-1, sizeFrame.height-insFrame.top-insFrame.bottom-1);

            } else if (test == 2) {

                // AT1, AT2, AT3, AT4 & AT5 Test
                this.setScale(2);
                g2d.setColor(Color.ORANGE);
                Line2D.Double line = new Line2D.Double(0, 1.5, 100, 2.5);
                g2d.draw(line);
                g2d.setColor(Color.RED);
                Rectangle2D.Double rectangle = new Rectangle2D.Double(0, 1.5, 100, 2.5);
                g2d.draw(rectangle);

            }


        };

        // Required affine transforms to move from 
        // World Coordinates Viewport to 
        // Screen Pixel Coordinates Viewport
        //
        // --- Reference textbook:
        //
        // Introduction to Computer Graphics Using Java 2D and 3D 
        // Frank Klawonn, Ed. Springer 2008
        // Page 31
        // 
        // --- Viewports
        //
        // World Coordinates Viewport (xmin,ymin) - (xmax,ymax)
        // Screen Pixel Coordinates Viewport (umin, vmin) - (umax, vmax)
        // 
        // --- World Coordinates
        //
        //                  (xmax,ymax)
        //      ┌────────────────┐
        //      │                │
        //      │                │
        //      │                │
        //      │                │
        //      └────────────────┘
        // (xmin,ymin)
        //
        // (xmin,ymin) = (0, 100)
        // (xmax,ymax) = (1.5, 2.5)
        //
        // --- User coordinates
        //
        //                  (umax,vmax)
        //      ┌────────────────┐
        //      │                │
        //      │                │
        //      │                │
        //      │                │
        //      └────────────────┘
        // (umin,vmin)
        //
        // (umin,vmin) = (inset.left, heightFrame - inset.bottom)
        // (umax,vmax) = (widthFrame - inset.right, inset.top)
        //
        // --- Affine Transform 1 and 2
        //
        //   T(0, h) ◦ S(1,−1)
        //
        // --- Affine Transform 3, 4 and 5
        //   
        //                     ╭ umax − umin   vmax − vmin ╮
        //   T(umin, vmin) ◦ S | ----------- , ----------- | ◦ T(-xmin, -ymin)  
        //                     ╰ xmax − xmin   ymax − ymin ╯
        //
        private void setScale(int test) {

            // World Coordinates
            // (xmin,ymin) = (0, 1.5)
            // (xmax,ymax) = (100, 2.5)
            Double xmin = 0.0;
            Double ymin = 1.5;
            Double xmax = 100.0;
            Double ymax = 2.5;

            // User Coordinates
            // (umin,vmin) = (inset.left, heightFrame - inset.bottom)
            // (umax,vmax) = (widthFrame - inset.right, inset.top)
            int umin = insFrame.left;
            int vmin = (int) (sizeFrame.getHeight() - insFrame.bottom);
            int umax = (int) (sizeFrame.getWidth() - insFrame.right);
            int vmax = insFrame.top;


            if (test == 1) {

                // Affine Transformation 1 and 2
                // T(0, h) ◦ S(1,−1)
                AffineTransform at1 = new AffineTransform();
                at1.setToScale(1,-1);
                AffineTransform at2 = new AffineTransform();
                at2.setToTranslation(insFrame.left, sizeFrame.getHeight() - insFrame.bottom - 1);
                at1.preConcatenate(at2);
                g2d.transform(at1);

            } else if (test == 2) {

                // Affine Transformation 1 and 2
                // T(0, h) ◦ S(1,−1)
                AffineTransform at1 = new AffineTransform();
                at1.setToScale(1,-1);
                AffineTransform at2 = new AffineTransform();
                at2.setToTranslation(insFrame.left, sizeFrame.getHeight() - insFrame.bottom - 1);

                // Affine Transformation 3, 4 and 5
                //                   ╭ umax − umin   vmax − vmin ╮
                // T(umin, vmin) ◦ S | ----------- , ----------- | ◦ T(-xmin, -ymin)  
                //                   ╰ xmax − xmin   ymax − ymin ╯
                AffineTransform at3 = new AffineTransform();
                at3.setToTranslation(umin, vmin);
                AffineTransform at4 = new AffineTransform();
                at4.setToScale(1.0*(umax-umin)/(xmax-xmin), 1.0*(vmax-vmin)/(ymax-ymin));
                AffineTransform at5 = new AffineTransform();
                at5.setToTranslation(-xmin,-ymin);
                at4.preConcatenate(at5);
                at3.preConcatenate(at4);
                at2.preConcatenate(at3);
                at1.preConcatenate(at2);
                g2d.transform(at1);

            }


        }

        public static void main( String[] args ) {
            Test2 window = new Test2();

    }

}
java math awt coordinates java-2d
1个回答
1
投票

我查看了这本书,发现AffineTransform.preConcatenate()的使用令人困惑。我更喜欢使用AffineTransform.concatenate(),因为对我而言,这给了更自然的流动。

让我们看一下第一个例子(转换,然后交换y方向)。

这是你的代码:

    AffineTransform at1 = new AffineTransform();
    at1.setToScale(1,-1);
    AffineTransform at2 = new AffineTransform();
    at2.setToTranslation(insFrame.left, sizeFrame.getHeight() - insFrame.bottom - 1);
    at1.preConcatenate(at2);

使用concatenate,你可以把它写成:

    AffineTransform at1 = new AffineTransform();
    at1.setToTranslation(insFrame.left, sizeFrame.getHeight() - insFrame.bottom - 1);
    AffineTransform at2 = new AffineTransform();
    at2.setToScale(1,-1);
    at1.concatenate(at2);

或者,甚至更短:

    AffineTransform at = new AffineTransform();
    at.translate(insFrame.left, sizeFrame.getHeight() - insFrame.bottom - 1);
    at.scale(1,-1);

您可以在代码中看到直接表示的流程“translate,then scale”。


对于第二个测试,您可以应用相同的方法:

    // Affine Transformation 3, 4 and 5
    //                   ╭ umax − umin   vmax − vmin ╮
    // T(umin, vmin) ◦ S | ----------- , ----------- | ◦ T(-xmin, -ymin)
    //                   ╰ xmax − xmin   ymax − ymin ╯
    AffineTransform at = new AffineTransform();
    at.translate(umin, vmin);
    at.scale((umax-umin)/(xmax-xmin), (vmax-vmin)/(ymax-ymin));
    at.translate(-xmin, -ymin);

请注意:umin, vmin已经表示左下方的屏幕坐标,umax, vmax表示右上方的屏幕坐标,因此不需要额外的平移或y轴翻转!


一些结束说明:

  • Java2D中行的默认宽度是一个缩放单位。通过选择yminymax,一个缩放单元可以填满窗户的整个高度。为了不获得填充矩形,您应该在g2d.setStroke(new BasicStroke(0.0f));调用之前使用g2d.draw()将线宽设置为最小可能值。
  • Rectangle2D.Double()的参数是x, y, w, h,所以你在第二个例子中创建矩形对象的代码应该读取Rectangle2D.Double rectangle = new Rectangle2D.Double(0, 1.5, 100, 1);(高度为2.5,上边框不会在屏幕上显示)。
© www.soinside.com 2019 - 2024. All rights reserved.