【问题标题】:Java - Draw a ruler (line with tick marks at 90 degree angle)Java - 绘制尺子(带有 90 度角刻度线的线)
【发布时间】:2011-03-30 03:22:25
【问题描述】:

我正在使用 Java AWT 在面板上画线(Line2DGraphics2D.drawLine()),我想知道如何画一条带刻度线的线,类似于:

|----|----|----|----|----|

我提前知道要在哪些位置绘制刻度。

线条可以在任何位置,因此必须以相对于线条本身的角度绘制刻度。

我的基本几何和在 Java 中应用它的能力令我失望。 :)

【问题讨论】:

  • 您想在任意方向上绘制“标尺”线吗?刻度线是固定间隔的,还是您希望它们出现在 0%、33%、66%、100% 时?
  • 请参阅下面的图形说明。刻度线将以任意间距均匀分布。 (IE:我需要一个解决方案,我可以分割一条线并在每个线段沿其长度绘制任意数量的这些刻度)
  • 告诉我你对我的回答的看法。

标签: java swing graphics awt computational-geometry


【解决方案1】:

我建议你

  1. 实现从左到右绘制简单水平标尺的标尺绘制方法
  2. 使用Math.atan2 找出所需的角度。
  3. 在调用标尺绘图方法之前应用带有平移和旋转的AffineTransform

这是一个完整的测试程序。 (Graphics.create方法用于创建原始图形对象的副本,所以我们不会把原始变换弄乱。)

import java.awt.*;

public class RulerExample {

    public static void main(String args[]) {
        JFrame f = new JFrame();
        f.add(new JComponent() {

            private final double TICK_DIST = 20;

            void drawRuler(Graphics g1, int x1, int y1, int x2, int y2) {
                Graphics2D g = (Graphics2D) g1.create();

                double dx = x2 - x1, dy = y2 - y1;
                double len = Math.sqrt(dx*dx + dy*dy);
                AffineTransform at = AffineTransform.getTranslateInstance(x1, y1);
                at.concatenate(AffineTransform.getRotateInstance(Math.atan2(dy, dx)));
                g.transform(at);

                // Draw horizontal ruler starting in (0, 0)
                g.drawLine(0, 0, (int) len, 0);
                for (double i = 0; i < len; i += TICK_DIST)
                    g.drawLine((int) i, -3, (int) i, 3);
            }

            public void paintComponent(Graphics g) {
                drawRuler(g, 10, 30, 300, 150);
                drawRuler(g, 300, 150, 100, 100);
                drawRuler(g, 100, 100, 120, 350);
                drawRuler(g, 50, 350, 350, 50);
            }
        });

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

请注意,您可以在刻度上方轻松绘制数字。 drawString 调用将经历相同的转换,并沿线很好地“倾斜”。

【讨论】:

  • 有趣,我相信 'AffineTransform' 是我正在寻找的关键字。 Google 使用非常相似的组件制作了本教程:glyphic.com/transform/applet/1intro.html 现在我只需要了解如何将其应用于我的问题。
  • 您通过首先平移(移动)到所需的起点,然后旋转所需的角度(atan2(dy, dx))来应用它。将这两个转换与 AffineTransform.concatenate 结合起来。
  • 看起来不错。我需要让自己更熟悉 Transform 的东西。
【解决方案2】:

注意事项:

  • 垂直线的斜率为 -1/oldslope。
  • 为了支持任何方向的线,您需要参数化地进行
  • 因此,您在原始行中有 dy 和 dx,这意味着 newdx=dy; newdy=-1*dx
  • 如果 &lt;dx, dy&gt; 是单位向量(sqrt(dx*dx+dy+dy)==1dx==cos(theta); dy=sin(theta) 用于某些 theta),那么您只需要知道刻度线之间的距离。
  • sx, sy 是你的起点 x 和 y
  • length 是行的长度
  • seglength 是短划线的长度
  • dx,dy 是原线的斜率
  • newdx, newdy 是(上面计算的)交叉线的斜率

因此,

  1. &lt;sx,sy&gt;(开始x,y)到&lt;sx+dx*length,sy+dy*length&gt;画一条线
  2. &lt;sx+dx*i-newdx*seglength/2,sy+dy*i-newdy*seglength/2&gt;&lt;sx+dx*i+newdx*seglength/2,sy+dy*i+newdy*seglength/2&gt; 画一组线(for(i=0;i

【讨论】:

  • 我非常喜欢这个答案,因为它试图解释几何。不幸的是,我很难理解它。我插入了你描述的公式,我得到了 newdy 和 newdx 的非常奇怪的结果。 (负值远远超出面板上的坐标范围)同样,我的几何学充其量只是基本的,但我想知道该公式是否适用于笛卡尔坐标系。 Java 的坐标将 0,0 放在面板的左上角。
【解决方案3】:

我希望你知道矩阵乘法。为了旋转一条线,您需要通过旋转矩阵将其倍增。 (我无法画出合适的矩阵,但假设两条线没有分开)

|x'| = |cos(an) -sin(an)| |x|

|y`| = |sin(an)  cos(an)| |y|

旧点是 x,y,新点是 x',y'。让我们通过一个例子来说明,假设你有一条从 (0,0) 到 (0,1) 的垂直线,现在你想将它旋转 90 度。 (0,0) 将保持为零,所以让我们看看 (0,1) 会发生什么

|x'| = |cos(90) -sin(90)| |0|

|y`| = |sin(90)  cos(90)| |1|

==

|1 0| |0|

|0 1| |1|

==

| 1*0 + 0*1|

| 0*0 + 1*1|

== |0|

   |1|

您会像预期的那样到达水平线(0,0),(0,1)

希望对你有帮助,
罗尼

【讨论】:

    猜你喜欢
    • 2022-11-14
    • 1970-01-01
    • 2019-06-12
    • 2017-10-21
    • 1970-01-01
    • 2019-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多