【问题标题】:rotating coordinate plane for data and text in JavaJava中数据和文本的旋转坐标平面
【发布时间】:2012-03-11 10:23:29
【问题描述】:

我需要:
1.) 移动原点并旋转坐标平面,使 x 值向右移动,y 值从新原点向上移动(在下面的代码中,它需要是内部蓝色矩形的左下角)。这将使我能够在下面的代码中绘制 x,y 坐标对处的点。
2.) 在数据图的 y 轴上绘制 tic 标记的旋转标签。

下面的代码设置了这个问题。它可以工作,除了两个问题:
1.) 以左上角为原点绘制数据点,y 值向下下降
2.) y 轴上的 tic 标记的标签未在屏幕上绘制

谁能告诉我如何修复下面的代码,以便它修复这两个问题并完成上面第一段描述的操作?

代码在以下两个java文件中:

DataGUI.java

import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;

class DataGUI extends JFrame{
DataGUI() {
    super("X,Y Plot");
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setPreferredSize(new Dimension(800, 400));
    this.pack();
    this.setSize(new Dimension(800, 600));
    this.setLocationRelativeTo(null);


    setLayout(new GridLayout());
    ArrayList<Double> myDiffs = new ArrayList<Double>();
            myDiffs.add(25.0);
            myDiffs.add(9.0);
            myDiffs.add(7.0);
            myDiffs.add(16.0);
            myDiffs.add(15.0);
            myDiffs.add(6.0);
            myDiffs.add(2.0);
            myDiffs.add(8.0);
            myDiffs.add(2.0);
            myDiffs.add(27.0);
            myDiffs.add(14.0);
            myDiffs.add(12.0);
            myDiffs.add(19.0);
            myDiffs.add(10.0);
            myDiffs.add(11.0);
            myDiffs.add(8.0);
            myDiffs.add(19.0);
            myDiffs.add(2.0);
            myDiffs.add(16.0);
            myDiffs.add(5.0);
            myDiffs.add(18.0);
            myDiffs.add(23.0);
            myDiffs.add(9.0);
            myDiffs.add(4.0);
            myDiffs.add(8.0);
            myDiffs.add(9.0);
            myDiffs.add(3.0);
            myDiffs.add(3.0);
            myDiffs.add(9.0);
            myDiffs.add(13.0);
            myDiffs.add(17.0);
            myDiffs.add(7.0);
            myDiffs.add(0.0);
            myDiffs.add(2.0);
            myDiffs.add(3.0);
            myDiffs.add(33.0);
            myDiffs.add(23.0);
            myDiffs.add(26.0);
            myDiffs.add(12.0);
            myDiffs.add(12.0);
            myDiffs.add(19.0);
            myDiffs.add(14.0);
            myDiffs.add(9.0);
            myDiffs.add(26.0);
            myDiffs.add(24.0);
            myDiffs.add(13.0);
            myDiffs.add(19.0);
            myDiffs.add(2.0);
            myDiffs.add(7.0);
            myDiffs.add(28.0);
            myDiffs.add(15.0);
            myDiffs.add(2.0);
            myDiffs.add(5.0);
            myDiffs.add(17.0);
            myDiffs.add(2.0);
            myDiffs.add(16.0);
            myDiffs.add(19.0);
            myDiffs.add(2.0);
            myDiffs.add(31.0);
    DataPanel myPP = new DataPanel(myDiffs,this.getHeight(),this.getWidth());
    this.add(myPP);
    this.setVisible(true);// Display the panel.
}
public static void main(String[] args){
    DataGUI myDataGUI = new DataGUI();
    myDataGUI.setVisible(true);
}
}

DataPanel.java (注意:我编辑了下面的代码以包含trashgod的建议,但它仍然不起作用。)

import java.awt.*;
import java.awt.geom.AffineTransform;
import javax.swing.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;

class DataPanel extends JPanel {
Insets ins; // holds the panel's insets
ArrayList<Double> myDiffs;
double maxDiff = Double.NEGATIVE_INFINITY;
double minDiff = Double.POSITIVE_INFINITY;
double maxPlot;

DataPanel(ArrayList<Double> Diffs, int h, int w){
    setOpaque(true);// Ensure that panel is opaque.
    setPreferredSize(new Dimension(w, h));
    setMinimumSize(new Dimension(w, h));
    setMaximumSize(new Dimension(w, h));
    myDiffs = Diffs;
    repaint();
    this.setVisible(true);
}

protected void paintComponent(Graphics g){// Override paintComponent() method.
    super.paintComponent(g);
    //get data about plotting environment and about text
    int height = getHeight();
    int width = getWidth();
    ins = getInsets();
    Graphics2D g2d = (Graphics2D)g;
    FontMetrics fontMetrics = g2d.getFontMetrics();
    String xString = ("x-axis label");
    int xStrWidth = fontMetrics.stringWidth(xString);
    int xStrHeight = fontMetrics.getHeight();
    String yString = "y-axis label";
    int yStrWidth = fontMetrics.stringWidth(yString);
    int yStrHeight = fontMetrics.getHeight();
    String titleString ="Title of Graphic";
    int titleStrWidth = fontMetrics.stringWidth(titleString);
    int titleStrHeight = fontMetrics.getHeight();
    int leftMargin = ins.left;
    //set parameters for inner rectangle
    int hPad=10;
    int vPad = 6;
    int testLeftStartPlotWindow = ins.left+5+(3*yStrHeight);
    int testInnerWidth = width-testLeftStartPlotWindow-ins.right-hPad;
    getMaxMinDiffs();
    getMaxPlotVal();
    double increment = 5.0;
    int numTicks = (int)(maxPlot/increment);//will use numTicks for: remainder, leftStartPlotWindow, innerRectangle+labels+tickmarks
    int remainder = testInnerWidth%numTicks;
    int leftStartPlotWindow = testLeftStartPlotWindow-remainder;
    System.out.println("remainder is: "+remainder);
    int bottomPad = (3*xStrHeight)-vPad;
    int blueTop = ins.bottom+(vPad/2)+titleStrHeight;
    int blueHeight = height-bottomPad-blueTop;
    int blueWidth = blueHeight;
    int blueBottom = blueHeight+blueTop;

    //plot outer rectangle
    g.setColor(Color.red);
    int redWidth = width-leftMargin-1;
    g.drawRect(leftMargin, ins.bottom, redWidth, height-ins.bottom-1);
    //write top label
    g.setColor(Color.black);
    g.drawString(titleString, leftStartPlotWindow+((blueWidth/2)-(titleStrWidth/2)), titleStrHeight);
    // fill, then plot, inner rectangle
    g.setColor(Color.white);
    g.fillRect(leftStartPlotWindow, blueTop, blueWidth, blueHeight);
    g.setColor(Color.blue);
    g.drawRect(leftStartPlotWindow, blueTop, blueWidth, blueHeight);
    //scale the diffs to fit window
    double Scalar = blueWidth/maxPlot;
    ArrayList<Double> scaledDiffs = new ArrayList<Double>();
    for(int e = 0;e<myDiffs.size();e++){scaledDiffs.add(myDiffs.get(e)*Scalar);}
    //plot the scaled Diffs
    AffineTransform at = g2d.getTransform();//save the graphics context's transform
    g2d.translate(leftStartPlotWindow, blueTop);//translate origin to bottom-left corner of blue rectangle
    g2d.scale(1, -1);//invert the y-axis
    for(int w = 0;w<scaledDiffs.size();w++){
        if(w>0){
            double prior = scaledDiffs.get(w-1);
            int priorInt = (int)prior;
            double current = scaledDiffs.get(w);
            int currentInt = (int)current;
            g2d.drawOval(priorInt, currentInt, 4, 4);
        }
    }
    g2d.setTransform(at);//restore the transform for conventional rendering
    //write x-axis label
    g.setColor(Color.red);
    g.drawString(xString, leftStartPlotWindow+((blueWidth/2)-(xStrWidth/2)), height-ins.bottom-vPad);
    //write y-axis label
    g2d.rotate(Math.toRadians(-90), 0, 0);//rotate text 90 degrees counter-clockwise
    g.drawString(yString, -(height/2)-(yStrWidth/2), yStrHeight);
    g2d.rotate(Math.toRadians(+90), 0, 0);//rotate text 90 degrees clockwise
    // draw tick marks on x-axis
    NumberFormat formatter = new DecimalFormat("#0.0");
    double k = (double)blueWidth/(double)numTicks;
    double iteration = 0;
    for(int h=0;h<=numTicks;h++){
        int xval = (int)(h*k);
        g.setColor(Color.red);
        g.drawLine(leftStartPlotWindow+xval, blueBottom+2, leftStartPlotWindow+xval, blueBottom+(xStrHeight/2));//draw tick marks
        g.drawString(formatter.format(iteration),leftStartPlotWindow+xval-(fontMetrics.stringWidth(Double.toString(iteration))/2),blueBottom+(xStrHeight/2)+13);
        iteration+=increment;
    }
    // draw tick marks on y-axis
    iteration = 0;
    for(int h=0;h<=numTicks;h++){
        int yval = (int)(h*k);
        g.setColor(Color.red);
        g.drawLine(leftStartPlotWindow-2, blueBottom-yval, leftStartPlotWindow-(yStrHeight/2), blueBottom-yval);//draw tick marks
        g2d.rotate(Math.toRadians(-90), 0, 0);//rotate text 90 degrees counter-clockwise
        g.drawString(formatter.format(iteration),leftStartPlotWindow-2,blueBottom-(fontMetrics.stringWidth(Double.toString(iteration))/2));
        g2d.rotate(Math.toRadians(+90), 0, 0);//rotate text 90 degrees clockwise
        iteration+=increment;
    }
}
void getMaxMinDiffs(){// get max and min of Diffs
    for(int u = 0;u<myDiffs.size();u++){
        if(myDiffs.get(u)>maxDiff){maxDiff = myDiffs.get(u);}
        if(myDiffs.get(u)<minDiff){minDiff = myDiffs.get(u);}
    }
}
void getMaxPlotVal(){
    maxPlot = maxDiff;
    maxPlot += 1;//make sure maxPlot is bigger than the max data value
    while(maxPlot%5!=0){maxPlot+=1;}//make sure maxPlot is a multiple of 5
}
}

此外,我们非常感谢您提供有关该主题的文章或教程的链接。

【问题讨论】:

  • 与手头的问题无关,但是添加到ArrayList的数据应该保存在数据文件中,而不是在程序中硬编码。
  • @Hovercraft Full Of Eels,是的,我知道。实际上,数据是一些数组操作的结果,比上面的数据集要长得多。但是,我按照上面的方式加载了它,以便该网站上的人们更容易重现它。
  • 考虑List&lt;Double&gt; myDiffs = new ArrayList&lt;Double&gt;(Arrays.asList(25.0, 9.0, 7.0, …))。
  • 我在网上做了一些研究,发现了这个 (youtube.com/watch?v=mZ0qBfEc0fg) 关于仿射变换的教程,还有一些更复杂的教程。这个材料我很难掌握,因为我还没有学过线性代数。但是,如果人们能在出现这种情况时向我展示如何修复我的代码,我想我可以通过分解收到的建议来学习。

标签: java swing plot graphics2d affinetransform


【解决方案1】:

对于有些不完整的答案深表歉意,但这可能会让你的齿轮转动。 Java 以您描述的方式绘制事物:它认为屏幕的左上角为 0、0,并绘制 x 向右增加和 y 向下增加。如果你做出声明的那一行

g2d.drawOval(priorInt, currentInt, 4, 4);

进入

g2d.drawOval(blueWidth - priorInt, blueHeight - currentInt, 4, 4);

它应该为您的第一个问题产生正确的结果。我需要更多关于第二个问题的信息来帮助你解决这个问题。他们是刚刚离开屏幕还是被其他东西吸引了?尝试翻转 +s 和 -s 看看是否可以得到正确的结果。

【讨论】:

  • 感谢您的建议。我进行了更改并尝试运行代码,但它在蓝色矩形之外绘制了一个,这表明它没有正确地重新定位数据点。您可以亲眼看到,如果您使用更改运行代码,蓝色矩形左边缘的左侧有一个数据点,大约是屏幕上方的 70%。这意味着每个点也被错误地绘制,即使它们在蓝色框内。至于 tic 标记标签,它们应该与 x 轴标签类似地放置。 +1 试图提供帮助。
  • 尝试使用 g2d.drawOval (priorInt, -currentInt, 4, 4);我有点盲目,因为我没有运行我建议的代码。很抱歉,但我懒得写 JPanel 包装器 =P。
  • 我唯一能看出你的 y 轴标签绘图代码有问题的是你可能只是在你的红框内绘图。尝试将 g2d.setColor (Color.red) 更改为 g2d.setColor (Color.green)
【解决方案2】:

SineTest 中显示了一种方法。概括地说,

  1. 保存图形上下文的变换。

    Graphics2D g2d = (Graphics2D) g;
    AffineTransform at = g2d.getTransform();
    
  2. 将原点平移到中心。

    g2d.translate(w / 2, h / 2);
    
  3. 反转 y 轴。

    g2d.scale(1, -1);
    
  4. 使用笛卡尔坐标进行渲染。

  5. 恢复常规渲染的变换。

    g2d.setTransform(at);
    

【讨论】:

  • +1 谢谢。我会仔细考虑你的建议。请理解,一段时间以来,我一直在探索翻译、反转、仿射变换等,但它们总是让我感到困惑。当我为一个应用程序弄清楚时,我发现几周后当需要下一个应用程序时我感到困惑。您愿意将您的建议合并到我上面的 DataPanel.java 文件中的工作代码中吗?如果您愿意这样做,我将能够使用 java api 仔细检查您的代码,并更好地了解它是如何工作的。
  • 引用的例子是完整的,它说明了图形变换的一个基本特征——_order counts_。您的范围标记会消失,因为它们已被旋转到视野之外。更多here.
  • 我查看了您的代码和您引用的参考资料。我也做了你建议的改变,但现在它根本没有画出所有的点,只画了一个点。我已经在上面的原始帖子中显示了修改后的代码,包括您的建议,以便可以重新创建当前剩余的问题。您是否愿意向我展示如何修复我上面的修改后的代码,以便它完成我原来的帖子所说的我正在尝试做的事情?谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-25
  • 1970-01-01
  • 2011-01-15
  • 1970-01-01
  • 2013-07-07
相关资源
最近更新 更多