Java - Draw a ruler (line with tick marks at 90 degree angle)

故事扮演 提交于 2019-11-29 04:27:01

I suggest you

  1. implement a ruler-drawing-method that draws a simple horizontal ruler from left to right
  2. Figure out the desired angle using Math.atan2.
  3. Apply an AffineTransform with translation and rotation before invoking the ruler-drawing-method.

Here is a complete test-program. (The Graphics.create method is used to create a copy of the original graphics object, so we don't mess up the original transform.)

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);
    }
}

Note, that you could just as easily draw numbers above the ticks. The drawString-calls would go through the same transformation and get nicely "tilted" along the line.

Things that need noting:

  • A perpendicular line has a slope of -1/oldslope.
  • In order to support lines in any direction, you need to do it parametrically
  • Thus, you have dy and dx across the original line, which means that newdx=dy; newdy=-1*dx.
  • If you have it such that <dx, dy> is a unit vector (sqrt(dx*dx+dy+dy)==1, or dx==cos(theta); dy=sin(theta) for some theta), you then just need to know how far apart you want the tick marks.
  • sx, sy are your start x and y
  • length is the length of the line
  • seglength is the length of the dashes
  • dx, dy is the slopes of the original line
  • newdx, newdy are the (calculated above) slopes of the cross lines

Thus,

  1. Draw a line from <sx,sy> (start x,y) to <sx+dx*length,sy+dy*length>
  2. Draw a set of lines (for(i=0;i<=length;i+=interval) from <sx+dx*i-newdx*seglength/2,sy+dy*i-newdy*seglength/2> to <sx+dx*i+newdx*seglength/2,sy+dy*i+newdy*seglength/2>
roni

I hope you know matrix multiplication. In order to rotate a line you need to multiple it by rotation matrix. (I coudln't draw a proper matrix but assume both line are not separated)

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

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

The old points are x,y and the new is x',y'. Let us illustrate by an example, lets say you have a vertical line from (0,0) to (0,1), now you want to rotate it by 90 degrees. (0,0) will remain zero so lets just see what happens to (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|

you get to horizontal line (0,0),(0,1) like you would expect.

Hope it helps,
Roni

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!