netlib.narod.ru< Назад | Оглавление | Далее >

Ручное преобразование координат

При желании можно настраивать координаты, передаваемые функциям рисования объекта Graphics, через свойства DpiX и DpiY. Допустим, нужно что-то нарисовать в миллиметровых координатах с плавающей точкой. Для этого потребуется метод, преобразующий миллиметры в пикселы:

  PointF MMConv(Graphics grfx, PointF pointf)
  {
      pointf.X *= grfx.DpiX / 25.4f;
      pointf.Y *= grfx.DpiY / 25.4f;

      return pointf;
  }

Метод получает координаты точек, выраженные в миллиметрах. Путем деления на 25,4 эти координаты преобразуются в дюймы (кстати, это точный пересчет). После умножения результата на разрешение устройства (в точках на дюйм) получается число пикселов.

Проверим наши расчеты, нарисовав 10-сантиметровую линейку.

TenCentimeterRuler.cs

  //---------------------------------------------------
  // TenCentimeterRuler.cs (C) 2001 by Charles Petzold
  //---------------------------------------------------
  using System;
  using System.Drawing;
  using System.Windows.Forms;

  class TenCentimeterRuler: PrintableForm
  {
      public new static void Main()
      {
          Application.Run(new TenCentimeterRuler());
      }
      public TenCentimeterRuler()
      {
          Text = "Ten-Centimeter Ruler";
      }
      protected override void DoPage(Graphics grfx, Color clr, int cx, int cy)
      {
          Pen       pen   = new Pen(clr);
          Brush     brush = new SolidBrush(clr);
          const int xOffset = 10;
          const int yOffset = 10;

          grfx.DrawPolygon(pen, new PointF[] 
              {
                  MMConv(grfx, new PointF(xOffset,       yOffset)),
                  MMConv(grfx, new PointF(xOffset + 100, yOffset)),
                  MMConv(grfx, new PointF(xOffset + 100, yOffset + 10)),
                  MMConv(grfx, new PointF(xOffset,       yOffset + 10))
              });

          StringFormat strfmt = new StringFormat();
          strfmt.Alignment = StringAlignment.Center;

          for (int i = 1; i < 100; i++)
          {
              if (i % 10 == 0)         // Сантиметровые деления
              {
                  grfx.DrawLine(pen, 
                       MMConv(grfx, new PointF(xOffset + i, yOffset)),
                       MMConv(grfx, new PointF(xOffset + i, yOffset + 5)));

                  grfx.DrawString((i/10).ToString(), Font, brush, 
                       MMConv(grfx, new PointF(xOffset + i, yOffset + 5)), 
                       strfmt);
              }
              else if (i % 5 == 0)     // Полусантиметровые деления
              {
                  grfx.DrawLine(pen, 
                       MMConv(grfx, new PointF(xOffset + i, yOffset)),
                       MMConv(grfx, new PointF(xOffset + i, yOffset + 3)));
              }
              else                     // Миллиметровые деления
              {
                  grfx.DrawLine(pen, 
                       MMConv(grfx, new PointF(xOffset + i, yOffset)),
                       MMConv(grfx, new PointF(xOffset + i, yOffset + 2.5f)));
               }
          }
      }
      PointF MMConv(Graphics grfx, PointF pointf)
      {
          pointf.X *= grfx.DpiX / 25.4f;
          pointf.Y *= grfx.DpiY / 25.4f;

          return pointf;
      }
  }

Вот как выглядит эта линейка на экране:


Рис. 7.1.

Кроме рисунка, здесь выводится текст. Почему я был уверен, что размер текста будет правильным? Просто мне было известно, что свойством Font задан шрифт с кеглем около 8 пунктов, высота его символов будет около 3 мм, что примерно соответствует нужному размеру.

Я сделал класс TenCentimeterRuler потомком PrintableForm, чтобы раз и навсегда стало ясно: эта методика не будет работать на принтере. Мой принтер с разрешением 600 dpi печатает эту линейку в шесть раз больше, чем она выглядит на экране.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz