Java - Нарисуйте линейку (линия с отметками под углом 90 градусов) - PullRequest
7 голосов
/ 15 августа 2010

Я использую Java AWT для рисования линий на панели (Line2D и Graphics2D.drawLine()), и мне интересно, как я могу нарисовать линию с отметками, как:

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

Я знаю позиции, на которых хотел бы заранее поставить галочки.

Линии могут быть в любом положении, поэтому отметки должны быть нарисованы под углом, относящимся к самой линии.

Моя базовая геометрия и способность применять ее в Java меня не подводят. :)

Ответы [ 3 ]

13 голосов
/ 15 августа 2010

Я предлагаю вам

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

enter image description here

Примечание,что вы могли бы так же легко нарисовать цифры над галочками.DrawString-вызовы прошли бы то же преобразование и были бы приятно «наклонены» вдоль линии.

1 голос
/ 15 августа 2010

Надеюсь, вы знаете умножение матриц. Чтобы повернуть линию, нужно умножить ее на матрицу вращения. (Я не могу нарисовать правильную матрицу, но предполагаю, что обе линии не разделены)

|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), как и следовало ожидать.

Надеюсь, это поможет,
Рони

1 голос
/ 15 августа 2010

Вещи, которые нужно отметить:

  • Перпендикулярная линия имеет наклон -1 / старый наклон.
  • Чтобы поддерживать линии в любом направлении, вам нужно сделать это параметрически
  • Таким образом, у вас есть dy и dx через исходную строку, что означает, что newdx=dy; newdy=-1*dx.
  • Если он у вас такой, что <dx, dy> является единичным вектором (sqrt(dx*dx+dy+dy)==1 или dx==cos(theta); dy=sin(theta) для некоторой тэты), вам просто нужно знать, как далеко друг от друга вы хотите поставить отметки.
  • sx, sy - ваш старт x и y
  • длина - длина линии
  • длина сегмента - длина тире
  • dx, dy - наклоны исходной линии
  • newdx, newdy - это (рассчитанные выше) наклоны перекрестных линий

Таким образом,

  1. Нарисуйте линию от <sx,sy> (начало x, y) до <sx+dx*length,sy+dy*length>
  2. Нарисуйте набор линий (для (i = 0; i <= длина; i + = интервал) от <code><sx+dx*i-newdx*seglength/2,sy+dy*i-newdy*seglength/2> до <sx+dx*i+newdx*seglength/2,sy+dy*i+newdy*seglength/2>
...