C lineto: LineTo function (wingdi.h) — Win32 apps

Содержание

d — SVG | MDN

Атрибут d предоставляет определение пути для рисования.

Определение пути — это список команд пути, в которых каждая команда состоит из буквы и некоторых чисел, представляющих параметр команды. Ниже приведены все возможные команды.

Три элемента используют этот атрибут: <path>, <glyph> (en-US), и <missing-glyph> (en-US)

<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <path fill="none" stroke="red"
    d="M 10,30
       A 20,20 0,0,1 50,30
       A 20,20 0,0,1 90,30
       Q 90,60 50,90
       Q 10,60 10,30 z" />
</svg>

Для <path>, d — строка, содержащая ряд команд пути, которые определяют путь, который должен нарисован.(maybe ‘drawn’ not ‘drown’)

Value <string>
Default value
none
Animatable Yes

Warning: Начиная с SVG2 <glyph> (en-US) устарел и не должен использоваться.

Для <glyph> (en-US), d является строкой, содержащей серию команд пути, которые определяют форму контура глифа.

Value <string>
Default value none
Animatable Yes

Сноска: Точка происхождения (координата

0,0) обычно является верхним левым углом контекста. Однако элемент <glyph> (en-US) имеет своё происхождение в левом нижнем углу своего бокса.

Внимание: Начиная с SVG2 <missing-glyph> (en-US) устарел и не должен использоваться.

Для <missing-glyph> (en-US), d является строкой, содержащей серию команд пути, которые определяют форму контура глифа.

Value <string>
Default value none
Animatable Yes

(Path commands)

Команды пути — это команды, объединённые вместе в одну строку и определяющие путь, который нужно нарисовать.  Каждая команда состоит из буквы, следующей за некоторыми числами, которые представляют параметры команды.

SVG определяет 6 типов команд пути для всех 20 команд:

  • MoveTo: M, m
  • LineTo: L, l, H, h, V, v
  • Cubic Bézier Curve: C, c, S, s
  • Quadratic Bézier Curve: Q
    , q, T, t
  • Elliptical Arc Curve: A, a
  • ClosePath: Z, z

Примечание: Команды чувствительны к регистру; команда верхнего регистра указывает свои аргументы как абсолютные позиции, тогда как команда нижнего регистра указывает точки относительно текущей позиции.

Всегда можно указать отрицательное значение в качестве аргумента для команды: отрицательные углы будут вращаться против часовой стрелки, абсолютные позиции x и y будут приниматься за отрицательные координаты, отрицательные относительные значения x будут перемещаться влево, а отрицательные относительные значения y будут двигаться вверх.

Команды перемещения

(MoveTo path commands)

MoveTo инструкции можно рассматривать как собирание чертёжного инструмента и установку его в другом месте. Между предыдущей точкой и указанной точкой нет линии.

Примечание: Хорошей практикой является открытие всех путей с помощью команды moveto, потому что без начального moveto команды будут выполняться с начальной точки, где бы это ни было ранее, что может привести к неопределённому поведению.

Команда Параметры Примечания
M (x, y)+ Движение начала следующего под-пути к координатам  x,y. Любая последующая координатная пара(ы) интерпретируется как параметр(ы) для неявных абсолютных команд LineTo(L) (см. Ниже).
Формула: Pn = {xy}
m (dx, dy)+

Перемещает начало следующего подпути, сдвинув последнюю известную позицию пути на dx вдоль оси x и на dy вдоль оси y. Любая последующая пара координат считается неявной относительной командой LineTo (

l) (см. ниже)
Формула: Pn= {xo + dx, yo + dy}

Examples
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <path fill="none" stroke="red"
    d="M 10,10 h 10
       m  0,10 h 10
       m  0,10 h 10
       M 40,20 h 10
       m  0,10 h 10
       m  0,10 h 10
       m  0,10 h 10
       M 50,50 h 10
       m-20,10 h 10
       m-20,10 h 10
       m-20,10 h 10" />
</svg>

LineTo path commands

LineTo инструкции проводят прямую линию от current point (Po; {x

o, yo}), до end point (Pn; {xn, yn}), на основе указанных параметров. Конечная точка end point (Pn) становится текущей точкой для следующей команды  (Po).

Command Parameters Notes
L (x, y)+

Рисует линию из текущей точки в конечную точку определённую x,y. Любая последующая пара(ы) координат интерпретируется как параметр(ы) для неявной абсолютной команд(ы) LineTo (

L). Формула: Po = Pn = {xy}

l (dx, dy)+ Draw a line from the current point to a point for which coordinates are those of the current point shifted by dx along the x-axis and dy along the y-axis. The current point gets its X and Y coordinates shifted by dx and dy for the next command. All usubsequente pair of coordinates are considered implicite relative LineTo (l) command (see below
).
H x+ Draw a horizontal line from the current point to the new x coordinate (y coordinate stay unchanged). The current point get its x coordinate updated for the next command. All subsequente value are considered an implicite absolute horizontal LineTo (H) command.
h dx+ Draw a horizontal line from the current point to a point shift by dx along the the x-axis (y coordinate stay unchanged). The current point get its X coordinate updated by dx
for the next command. All subsequente value are considered an implicite relative horizontal LineTo (h) command.
V y+ Draw a vertical line from the current point to the new y coordinate (x coordinate stay unchanged). The current point get its y coordinate updated for the next command. All subsequente value are considered an implicite absolute vertical LineTo (V) command.
v dy+ Draw a vertical line from the current point to a point shift by dy
along the y-axis (x coordinate stay unchanged). The current point get its Y coordinate updated by dy for the next command. All subsequente value are considered an implicite relative vertical LineTo (v) command.
Examples
<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
  
  <path fill="none" stroke="red"
        d="M 10,10
           L 90,90
           V 10
           H 50" />

  
  <path fill="none" stroke="red"
        d="M 110,10
           l 80,80
           v -80
           h -40" />
</svg>

Cubic Bézier Curve

Cubic Bézier curves are smooth curve definitions using four points: A starting point, a end point, and two control points to define the curvature.

Command Parameters Notes
C (x1,y1, x2,y2, x,y)+ Draw a Bézier curve from the current point to the coordinate x,y. x1,y1 are the coordinates of the control point at the begining of the curve where x2,y2 are the coordinates of the controle point at the end of the curve. The coordinate x,y become the new current point for the next command. All subsequente triplets of coordinates are considered implicite absolute cubic Bézier curve (C) command.
c (dx1,dy1, dx2,dy2, dx,dy)+ Draw a Bézier curve from the current point to a point for which coordinates are those of the current point shifted by dx along the x-axis and dy along the y-axis. dx1,dy1 are the coordinates of the control point at the beginning of the curve relative to the starting point of the curve and dx2,dy2 are the coordinates of the controle point at the end of the curve relative to the starting point of the curve. The current point gets its X and Y coordinates shifted by dx and dy for the next command. All subsequente triplets of coordinates are considered implicite relative cubic Bézier curve (c) command.
S (x2,y2, x,y)+ Draw a smooth Bézier curve from the current point to the coordinate x,y. x2,y2 are the coordinates of the controle point at the end of the curve. The controle point at the begining of the curve is a reflexion of the controle points at the end of the previous curve command. If the previous command wasn’t a curve, then the coordinate of the controle point at the begining of the curve match those of the curve starting point. The coordinate x,y become the new current point for the next command. All subsequente duo of coordinates are considered implicite absolute smooth cubic Bézier curve (S) command.
s (dx2,dy2, dx,dy)+ Draw a smooth Bézier curve from the current point to a point for which coordinates are those of the current point shifted by dx along the x-axis and dy along the y-axis. dx2,dy2 are the coordinates of the controle point at the end of the curve relative to the starting point of the curve. The controle point at the begining of the curve is a reflexion of the controle points at the end of the previous curve command. If the previous command wasn’t a curve, then the coordinate of the controle point at the begining of the curve match those of the curve starting point. The current point gets its X and Y coordinates shifted by dx and dy for the next command. All subsequente duo of coordinates are considered implicite relative smooth cubic Bézier curve (s) command.
Examples
<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">

  
  <path fill="none" stroke="red"
        d="M 10,90
           C 30,90 25,10 50,10
           S 70,90 90,90" />

  
  <path fill="none" stroke="red"
        d="M 110,90
           c 20,0 15,-80 40,-80
           s 20,80 40,80" />

  
  <g>

    
    <line x1="10" y1="90" x2="30" y2="90" stroke="lightgrey" />
    <circle cx="30" cy="90" r="1.5"/>

    <line x1="50" y1="10" x2="25" y2="10" stroke="lightgrey" />
    <circle cx="25" cy="10" r="1.5"/>

    
    <line x1="50" y1="10" x2="75" y2="10" stroke="lightgrey" stroke-dasharray="2" />
    <circle cx="75" cy="10" r="1.5" fill="lightgrey"/>

    <line x1="90" y1="90" x2="70" y2="90" stroke="lightgrey" />
    <circle cx="70" cy="90" r="1. 5" />

    
    <circle cx="10" cy="90" r="1.5"/>
    <circle cx="50" cy="10" r="1.5"/>
    <circle cx="90" cy="90" r="1.5"/>
  </g>
  <use xlink:href="#ControlPoints" x="100" />
</svg>

Quadratic Bézier Curve

Quadratic Bézier curves are smooth curve definitions using three points: A starting point, a end point, and a control point to define the curvature.

Command Parameters Notes
Q (x1,y1, x,y)+ Draw a Bézier curve from the current point to the coordinate x,y. x1,y1 are the coordinates of the control point for the curve. The coordinate x,y become the new current point for the next command. All subsequente duo of coordinates are considered implicite absolute quadratic Bézier curve (Q) command.
q (dx1,dy1, dx,dy)+ Draw a Bézier curve from the current point to a point for which coordinates are those of the current point shifted by dx along the x-axis and dy along the y-axis. dx1,dy1 are the coordinates of the control point for the curve relative to the starting point of the curve. The current point gets its X and Y coordinates shifted by dx and dy for the next command. All subsequente duo of coordinates are considered implicite relative quadratic Bézier curve (q) command.
T (x,y)+ Draw a smooth Bézier curve from the current point to the coordinate x,y. The controle point for the curve is a reflexion of the controle points at the end of the previous curve command. If the previous command wasn’t a curve, then the coordinate of the controle point at the begining of the curve match those of the curve starting point. The coordinate x,y become the new current point for the next command. All subsequente coordinates are considered implicite absolute smooth quadratic Bézier curve (T) command.
t (dx,dy)+ Draw a smooth Bézier curve from the current point to a point for which coordinates are those of the current point shifted by dx along the x-axis and dy along the y-axis. The controle point for the curve is a reflexion of the controle points at the end of the previous curve command. If the previous command wasn’t a curve, then the coordinate of the controle point at the begining of the curve match those of the curve starting point. The current point gets its X and Y coordinates shifted by dx and dy for the next command. All subsequente coordinates are considered implicite relative smooth quadratic Bézier curve (t) command.
Examples
<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">

  
  <path fill="none" stroke="red"
        d="M 10,50
           Q 25,25 40,50
           t 30,0 30,0 30,0 30,0 30,0" />

  
  <g>
    <polyline points="10,50 25,25 40,50" stroke="rgba(0,0,0,.2)" fill="none" />
    <circle cx="25" cy="25" r="1.5" />

    
    <circle cx="10" cy="50" r="1.5"/>
    <circle cx="40" cy="50" r="1.5"/>

    <g>
      <polyline points="40,50 55,75 70,50" stroke="rgba(0,0,0,.2)" stroke-dasharray="2" fill="none" />
      <circle cx="55" cy="75" r="1.5" fill="lightgrey" />
      <circle cx="70" cy="50" r="1.5" />
    </g>

    <g>
      <polyline points="70,50 85,25 100,50" stroke="rgba(0,0,0,.2)" stroke-dasharray="2" fill="none" />
      <circle cx="85" cy="25" r="1.5" fill="lightgrey" />
      <circle cx="100" cy="50" r="1. 5" />
    </g>

    <use xlink:href="#SmoothQuadraticDown" x="60" />
    <use xlink:href="#SmoothQuadraticUp"   x="60" />
    <use xlink:href="#SmoothQuadraticDown" x="120" />
  </g>
</svg>

Elliptical Arc Curve

Elliptical arc curves are curves define as a portion of an ellipse. It is sometimes easier than Bézier curve to draw highly regular curves.

Command Parameters Notes
A (rx ry angle large-arc-flag sweep-flag x y)+

Draw an Arc curve from the current point to the coordinate x,y. The center of the ellipse used to draw the arc is determine automatically based on the other parameters of the command:

  • rx and ry are the two radii of the ellipse;
  • angle represente a rotation (in degree) of the ellipse relative to the x-axis;
  • large-arc-flag and sweep-flag allows to chose which arc must be drawn as 4 possible arcs can be drawn out of the other parameters.
    • large-arc-flag allows to chose one of the large arc (1) or small arc (0),
    • sweep-flag allows to chose one of the clockwise turning arc (1) or anticlockwise turning arc (0)
The coordinate x,y become the new current point for the next command. All subsequente set of parameters are considered implicite absolute arc curve (A) command.
a (rx ry angle large-arc-flag sweep-flag dx dy)+

Draw an Arc curve from the current point to to a point for which coordinates are those of the current point shifted by dx along the x-axis and dy along the y-axis. The center of the ellipse used to draw the arc is determine automatically based on the other parameters of the command:

  • rx and ry are the two radii of the ellipse;
  • angle represente a rotation (in degree) of the ellipse relative to the x-axis;
  • large-arc-flag and sweep-flag allows to chose which arc must be drawn as 4 possible arcs can be drawn out of the other parameters.
    • large-arc-flag allows to chose one of the large arc (1) or small arc (0),
    • sweep-flag allows to chose one of the clockwise turning arc (1) or anticlockwise turning arc (0)
The current point gets its X and Y coordinates shifted by dx and dy for the next command. All subsequente set of parameters are considered implicite relative arc curve (a) command.
Examples
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">

  
  <path fill="none" stroke="red"
        d="M 6,10
           A 6 4 10 1 0 14,10" />

  <path fill="none" stroke="lime"
        d="M 6,10
           A 6 4 10 1 1 14,10" />

  <path fill="none" stroke="purple"
        d="M 6,10
           A 6 4 10 0 1 14,10" />

  <path fill="none" stroke="pink"
        d="M 6,10
           A 6 4 10 0 0 14,10" />
</svg>

ClosePath

ClosePath instructions draw a straight line from the current position, to the first point in the path.

Command Parameters Notes
Z, z Close the curent subpath by connecting the last point of the path with its initial point. If the two points doesn’t have the same coordinates, a straight line is drawn between those two points.

Note: The appearance of a shape closed with closepath may be different to that of one closed by drawing a line to the origin, using one of the other commands, because the line ends are joined together (according to the stroke-linejoin (en-US) setting), rather than just being placed at the same coordinates.

Examples
<svg viewBox="0 -1 30 11" xmlns="http://www.w3.org/2000/svg">

  
  <path stroke="red"
        d="M 5,1
           l -4,8 8,0" />

  
  <path stroke="red"
        d="M 15,1
           l -4,8 8,0 -4,-8" />

  
  <path stroke="red"
        d="M 25,1
           l -4,8 8,0
           z" />
</svg>

Описание и примеры стандартных функций SVG

Доминирующей причиной появления этого блога стало незаслуженное забвение на целых десять лет языка разметки масштабируемой векторной графики – SVG (Scalable Vector Graphics), входящего в подмножество расширяемого языка разметки XML.
Стандарт SVG 1.0 был принят в качестве спецификации Консорциумом Всемирной паутины (W3C) в сентябре 2001 г. Стандарт SVG 1.1 и его версии SVG mobile profiles (SVG Basic and SVG Tiny) были приняты консорциумом в качестве рекомендации в январе 2003 г.
Сейчас ведутся работы по созданию стандарта SVG 2.0

Основные преимущества формата SVG.

Я не буду долго распространяться о преимуществах векторной графики перед растровой в вебдизайне, замечу лишь, что, однажды созданный, файл в формате SVG одинаково хорошо выглядит без потери качества и на мобильном устройстве и на станционарном мониторе домашнего ПК.
Шапка данного сайта выполнена в формате SVG, попробуйте уменьшить окно браузера до минимальных размеров, картинка на “лету” будет также пропорционально уменьшаться.
SVG – это двухмерная графика и тем не менее это текстовый формат, который можно легко править в блокноте или просто рисовать в векторных редакторах: Incscape , Adobe illustrator, CorelDRAW

Бесконечное полотно документа svg.

Итак, как происходит формирование векторного изображения.
Документ формата SVG – это двухмерный объект, который может иметь бесконечные координаты, как в положительном, так и в отрицательном направлении по осям X и Y. Также документ SVG имеет две области просмотра: viewport – системная область просмотра и viewBox – пользовательская область просмотра, положение которой относительно начала системных координат viewport, может задаваться собственной, пользовательской системой координат. Другими словами окно просмотра viewBox, может быть перемещёно в любое место документа SVG, при этом берется фрагмент изображения под ним, который после процесса согласования между viewBox и viewport, возвращается обратно в системную область просмотра viewport, которую видит пользователь. Используя это свойство можно организовать вертикальную или горизонтальную прокрутку изображения, меняя параметры координат viewBox.

При уменьшении размера пользовательского окна просмотра viewbox можно пропорционально увеличивать фрагмент изображения в системной области просмотра или уменьшать его при увеличении размера viewbox.
Таким образом реализуется эффект лупы. Более подробно эти процессы разобраны в статье: Трансформация изображений SVG при изменении параметров Viewbox.

 

Взаимодействие SVG, XML с HTML, CSS, Jscript

В SVG, как и в HTML можно добавлять ссылки на внешние ресурсы. Но если в HTML одна картинка может служить только для одной внешней ссылки, то в SVG документ можно добавлять сколько угодно внешних ссылок . Картинка кликабельна.
Внутрь HTML страницы легко встраивается код SVG документа или целиком подключается внешний SVG файл. Можно наоборот, внутри SVG файла разместить код HTML внутри тегов foreignObject. Получаются интересные эффекты: Внутри SVG файла находится работающий внешний HTML сайт. К SVG формату можно подключать внешние таблицы стилей CSS 2.0, что позволяет управлять сразу несколькими файлами *.svg. Также вполне допустимо подключение стилей внутри файла *.svg внутри тегов style или использовать внутренние стили непосредственно внутри командных строк фигур и путей.
SVG, как любой основанный на XML формат, позволяет использовать для его обработки таблицы трансформации (XSLT).
Преобразуя XML-данные в SVG с помощью простого XSL, можно получить графическое представление текстовых данных, например визуализировать графики, круговые диаграммы, гистограммы и т.д.

Анимация и интерактивность SVG.

Анимация в SVG осуществляется при помощи языка SMIL (Synchronized Multimedia Integration Language). Также поддерживаются скриптовые языки на основе спецификации ECMAScript — это встраиваемый расширяемый язык программирования.
То есть всё находится в одном месте, внутри документа SVG, поэтому нет необходимости для подключения внешних библиотек.
На каждую отдельную фигуру или на целое изображение можно установить обработчик событий (клик, наведение мышки, нажатие клавиши и т.д), таким образом, пользователь может управлять рисунком. Наведите курсор мышки на кнопку“Start” на примере слева.
По событию mouseover на этой кнопке начнется анимация по команде begin=”startButton. mouseover” – движение цветных шариков по криволинейному пути. Закончится анимация либо через заданные в коде 16 секунд, либо в любой момент по наведению курсора мышки на цветные радиокнопки “Stop”. При этом каждая радиокнопка управляет своим объектом совпадающим по цвету. На рисунке ниже анимация начинается и заканчивается при нажатии клавиши мышки на кнопки GO и STOP. В этом случае работает событие click. Команда на запуск анимации – begin=”gO.click” и соответственно остановка – end=”stop.click”
Следующий пример анимации – плавная отрисовка картинки с нуля до полного изображения.

Уже встроенные в SVG языки программирования позволяют реализовать довольно сложные сценарии анимации. Но, в дополнение к этому есть еще более мощные средства для реализации интерактивности графики и ее анимации – это внешние библиотеки сторонних разработчиков: D3.js, BonsaiJS, Svg.js, Snapsvg.js

Еще примеры анимации ⇛

Недостатки SVG формата

  • С увеличением количества мелких деталей в изображении, быстрее растёт размер файла SVG-данных. Предельный случай — когда изображение представляет собой белый шум. В этом случае SVG не только не даёт никаких преимуществ в размере файла, но даже имеет проигрыш по отношению к растровому формату. На практике, SVG становится невыгоден уже задолго до того, как изображение дойдёт до стадии белого шума.
  • Трудность использования в крупных картографических приложениях из-за того, что для правильного отображения маленькой части изображения документ необходимо прочитать целиком.
  • В настоящее время SVG формат применяется в Интернете сравнительно мало, из-за недостаточной кроссбраузерности. Лучше всего обстоят дела у Mozilla Firefox со встроенным просмотрщиком SVG, так как ее разработчики находятся в рабочей группе Консорциума Всемирной паутины (W3C) по разработке и внедрению стандарта SVG. Хуже всего дела по поддержке формата SVG у Microsoft, которая покинула группу 2003 г. Для Internet Explorer – необходим Adobe SVG Viewer (ASV). С 9 версии IE частично поддерживает функции SVG.
    Браузеры Apple Safari, Google Chrome намного лучше поддерживают SVG, но не полностью, так как SVG – это большая спецификация (вдвое больше HTML 4.01), именно поэтому разработчики браузеров внедряют функции постепенно, от версии к версии. Но абсолютно все разработчики современных браузеров заявляют, что за форматом SVG будущее в области графики вебдизайна.


 

 

UPD. Добавлен новый раздел онлайн генераторы SVG кода path.
следующая: Структура SVG документа ⇛

SVG-path • Про CSS

path — более сложный вариант линии. С его помощью можно нарисовать line, polyline, polygon, circle и rect:

В отличие от polygon, фигура не замыкается сама по себе, но это можно сделать с помощью дополнительного параметра.

Пример фигуры с path:

<svg>
  <symbol>
    <path d="M 10,110 L 10,10 L 40,50 L 70,10 L 100,50 L 130,10 L 130,110 z"
    fill="gold" stroke="orange" stroke-width="5"/>
  </symbol>

  <use xlink:href="#s-crown" x="5" y="7"/>
</svg>

Точки фигуры задаются в атрибуте d. В значении содержатся команды, управляющие направлением и видом линий. Координаты x и y можно разделять запятой или пробелом, но запятая наглядней.

Все команды обозначаются одной буквой, и могут быть записаны в верхнем или нижнем регистре. Верхний регистр обозначает использование абсолютных координат, нижний — относительных.

Примеры ниже демонстрируют разницу между абсолютными и относительными координатами. Различие состоит во второй строке: M 20,20 L 100,150 vs m 20,20 l 100,150.

Команды в нижнем регистре ( m и l) указывают отсчитывать координаты не от верхнего левого угла полотна, а от текущей точки (пример справа):

<svg>
  <path
    stroke="crimson"
    stroke-width="2"
    d="M 20,20 L 80,50
    M 20,20 L 100,150"/>
</svg>
<svg>
  <path
    stroke="skyblue"
    stroke-width="2"
    d="M 20,20 L 80,50
    m 20,20 l 100,150"/>
</svg>

Команды:

M, m

Mmoveto, обозначает начало новой линии — точку, с которой мы начинаем рисовать.

Параметры: x,y.

Команд M в строке может быть несколько, каждая из них будет обозначать начало новой линии:

<svg>
  <path stroke="orange" stroke-width="3"
    d="M 20,20 L150,150
       M 50,20 L180,150"/>
</svg>

Z, z

Zclosepath — замкнуть фигуру, при этом рисуется линия от текущей точки до начальной. Действие этой команды не зависит от регистра, Z и z сработают одинаково.

Параметры: нет.

Z избавляет от необходимости указывать последнюю точку с координатами первой, чтобы закончить фигуру. Кроме того, если замыкать фигуру вручную, может получиться неаккуратный стык:

<svg>
  <path stroke="orange" stroke-width="10" fill="gold"
    d="M 100,20 L 180,160
       L 20,160 L 100,20"/>
</svg>

Вместо последней точки используем Z и получаем аккуратно замкнутую фигуру:

<svg>
  <path stroke="orange" stroke-width="10" fill="gold"
    d="M 100,20 L 180,160
       L 20,160 z"/>
</svg>

L, l

Llineto — рисование линии.

Параметры: x,y.

Следует отметить, что писать L перед каждой точкой не обязательно:

L 80,20 L 20,100 = L 80,20 20,100

Строчки сработают одинаково, но с L удобнее, если код предполагается читать.

<svg>
  <path stroke="green" stroke-width="3" fill="none"
    d="M 20,50
       L 80,20 20,100 150,50 50,150 150,120
       "/>
</svg>

H, h

Hhorizontal lineto — рисование горизонтальной линии.

Параметры: x.

V, v

Vvertical lineto — рисование вертикальной линии.

Параметры: y.

С помощью этих команд очень удобно рисовать прямоугольные фигуры:

<svg>
  <path stroke="lightseagreen" stroke-width="5" fill="turquoise"
    d="M 20,20
       h 160 v 160 h -80 v -80 h -80 z
       "/>
</svg>

Помимо команд для рисования прямых линий, есть несколько команд для рисования кривых. Они достаточно интересные, хотя и несколько сложнее для понимания.

Пунктирная линия в примерах (где возможно) показывает, что получается без команды, задающей кривую. Для меня вспомогательная линия сделала несколько понятнее прицип работы этих команд.

C, c

Ccurveto

Параметры: x1 y1 x2 y2 x y

Абсолютные координаты

C 150,20 150,150 20,150

Относительные координаты

c 150,20 150,150 20,150

S, s

Ssmooth curveto

Параметры: x2 y2 x y

Абсолютные координаты

S 180,100 20,180

Относительные координаты

s 180,100 20,180

Q, q

Qquadratic Bézier curveto

Параметры: x1 y1 x y

Абсолютные координаты

Q 180,100 20,180

Относительные координаты

q 180,100 20,180

T, t

Tsmooth quadratic Bézier curveto

Параметры: x1 y1 x y

Абсолютные координаты

T 60,100 180,20

Относительные координаты

t 60,100 180,20

A, a

Aelliptical arc

Параметры: rx ry x-axis-rotation large-arc-flag sweep-flag x y

Абсолютные координаты

A20,35 0 0,0 170,2

Относительные координаты

a20,35 0 0,0 170,20

Чтобы получить более полное представление о работе этих функций читайте спецификацию.

путей — SVG 2

путей — SVG 2

Содержание

    1. 9.1. Введение
    2. 9.2. Элемент «путь»
    3. 9.3. Данные пути
      1. 9.3.1. Общая информация о данных пути
      2. 9.3.2. Указание данных пути: свойство «d»
      3. 9.3.3. «moveto» команды
      4. 9.3.4. Команда «closepath»
        1. 9.3.4.1. Завершающая сегмент операция закрытия пути
      5. 9.3.5. «lineto» команд
      6. 9.3.6. Кубическая кривая Безье дает команду
      7. 9.3.7. Квадратичная кривая Безье дает команду
      8. 9.3.8. Эллиптическая дуга управляет
      9. 9.3.9. Грамматика данных пути
    4. 9.4. Направленность пути
    5. 9.5. Примечания по реализации
      1. 9.5.1. Параметры эллиптической дуги вне допустимого диапазона
      2. 9.5.2. Отраженные контрольные точки
      3. 9.5.3. Сегменты пути нулевой длины
      4. 9.5.4. Обработка ошибок в данных пути
    6. 9. 6. Расстояние по трассе
      1. 9.6.1. Атрибут pathLength
    7. 9.7. Интерфейсы DOM
      1. 9.7.1. Интерфейс SVGPathElement

9.1. Введение

Путь представляет собой контур фигуры, который можно заливать или погладил. Путь также можно использовать в качестве обтравочного контура для описания анимация или позиционирование текста. Путь может использоваться более чем для одного из эти функции одновременно. (Видеть Серверы заливки, обводки и покраски, Обрезка и маскирование, Анимация (‘animateMotion’), и текст по контуру.)

Путь описывается с использованием концепции текущей точки. В аналогия с рисованием на бумаге, текущая точка может быть думал как расположение ручки. Положение пера могут быть изменены, а контур фигуры (открытый или закрытый) может можно провести перетаскиванием по прямым линиям или кривые.

Пути представляют геометрию контура объекта, определяется в терминах перейти на (установить новую текущую точку), От до (начертить прямую), от до (начертить кривая с использованием кубической кривой Безье), дуга (эллиптическая или дуги окружности) и closepath (замкнуть текущую shape, подключившись к последним командам moveto ). Составные пути (т. Е. Путь с несколькими подпутьями) являются можно разрешить такие эффекты, как «дырки от бублика» в объектах.

В этой главе описываются синтаксис, поведение и DOM. интерфейсы для путей SVG. Различные примечания по реализации для SVG пути можно найти в реализации элемента «path» Заметки.

Путь определяется в SVG с помощью элемента «path».

Все основные формы описаны с точки зрения их эквивалентный путь — это какова их форма как тропинка.(Эквивалентный путь Элемент «path» — это просто сам путь.) Чтобы определить основные формы как эквивалентные пути, определена завершающая сегмент операция замыкания пути, который в настоящее время не может быть представлен в синтаксисе основного пути.

9.2. Элемент «путь»

path

Категории:
Графический элемент, визуализируемый элемент, элемент формы
Модель содержимого:
Любое количество следующих элементов в любом порядке: clipPath, маркер, маска, скрипт, стиль
Атрибуты:
  • атрибутов aria — ‘aria-activedescendant’, ‘aria-atomic’, ‘aria-autocomplete’, ‘aria-busy’, ‘aria-checked’, ‘aria-colcount’, ‘aria-colindex’ , ‘aria-colspan’, ‘aria-controls’, ‘aria-current’, ‘aria -hibitedby’, ‘aria-details’, ‘aria-disabled’, ‘aria-dropeffect’, ‘aria-errormessage’, ‘ aria-extended, aria-flowto, aria-grabbed, aria-haspopup, aria-hidden, aria-invalid, aria-keyshortcuts, aria-label, aria- labelledby ‘,’ aria-level ‘,’ aria-live ‘,’ aria-modal ‘,’ aria-multiline ‘,’ aria-multiselectable ‘,’ aria-Ориентация ‘,’ aria-owns ‘,’ aria-placeholder ‘ , ‘aria-posinset’, ‘aria-press’, ‘aria-readonly’, ‘aria-related’, ‘aria-required’, ‘aria-roledescription’, ‘aria-rowcount’, ‘aria-rowindex’, ‘aria-rowspan’, ‘aria-selected’, ‘aria-setsize’, ‘aria-sort’, ‘aria-valuemax’, ‘aria-valuemin’, ‘aria-valuenow’, ‘aria -valuetext ‘,’ role ‘
  • атрибутов условной обработки -‘ requiredExtensions ‘,’ systemLanguage ‘
  • основных атрибутов -‘ id ‘,’ tabindex ‘,’ lang ‘,’ xml: space ‘,’ class ‘,’ style ‘
  • глобальных атрибутов событий — oncancel, oncanplay, oncanplaythrough, onchange, onclick, onclose, oncuechange, ondblclick, ondrag, ondragend, ondragenter, ondragexit, ondragleave, ondragover, ondragstart, ondrop, ondurationchange, onemptied, onended, onerror, onfocus, oninput, oninvalid, onkeydown ‘,’ onkeypress ‘,’ onkeyup ‘,’ onload ‘,’ onloadeddata ‘,’ onloadedmetadata ‘,’ onloadstart ‘,’ onmousedown ‘,’ onmouseenter ‘,’ onmouseleave ‘,’ onmousemove ‘,’ onmouseout ‘,’ onmouseover ‘, onmouseup, onmousewheel, onpause, onplay, onplaying, onprogress, onratechange, onreset, onresize, onscroll, onseeke d ‘,’ onseeking ‘,’ onselect ‘,’ onshow ‘,’ onstalled ‘,’ onsubmit ‘,’ onsuspend ‘,’ ontimeupdate ‘,’ onggle ‘,’ onvolumechange ‘,’ onwaiting ‘
  • атрибутов событий элемента документа -‘ oncopy ‘,’ oncut ‘,’ onpaste ‘
  • графические атрибуты событий -‘ onfocusin ‘,’ onfocusout ‘
  • атрибуты презентации —
  • ‘ pathLength ‘
Свойства геометрии:
Интерфейсы DOM:
08

Контур формы для элемента «путь» задается с помощью d имущество. См. Данные о пути ниже.

9.3. Данные пути

9.3.1. Общая информация о данных пути

Путь определяется включением «пути» элемент, для которого свойство d указывает данные пути. Данные пути содержат перейти на , линейно на , кривая на (как кубическая, так и квадратичный Безье), arc и closepath инструкции.

Пример треугольника01 указывает путь в форме треугольника. (В M обозначает переход с на , L s обозначают линий до с, а z обозначает ближний путь ().

 

   Пример треугольника01 - простой пример "пути" 
   Путь, изображающий треугольник 
  
  
 

Пример треугольника01

Просмотреть этот пример как SVG (только для браузеров с поддержкой SVG)

Данные пути могут содержать символы новой строки и, следовательно, могут быть разбит на несколько строк для удобства чтения. Новые строки внутри атрибутов в разметке будут нормализованы до пробела символы при разборе.

Синтаксис данных пути краток, чтобы учесть минимальный размер файла и эффективная загрузка, поскольку многие файлы SVG будут преобладать их данные пути. Некоторые из способов, которыми SVG попытки минимизировать размер данных пути следующие:

  • Все инструкции выражаются одним символом (например, moveto выражается как M ).
  • Избыточный пробел и разделители (например, запятые) могут быть устраненным; например, следующее содержит ненужные мест:

    M 100100 L 200200

    Более компактно это можно выразить как:

    M100 100L200 200

  • Буква команды может быть удалена, если идентичная команда в противном случае ему предшествовало бы письмо; например, следующие содержит ненужную вторую команду «L»:

    М 100200 л 200100 л -100-200

    Более компактно это можно выразить как:

    M 100200 L 200100-100-200

  • Для большинства команд есть абсолютные и относительные доступные версии (прописные буквы означают абсолютные координаты, строчные буквы означают относительные координаты).
  • Альтернативные формы от лин до доступны для оптимизировать частные случаи горизонтальных и вертикальных линий (абсолютное и относительное).
  • Альтернативные формы кривой доступны для оптимизировать особые случаи, когда некоторые из контрольных точек на текущем сегменте может быть определена автоматически из контрольные точки на предыдущем сегменте.

Синтаксис данных пути представляет собой префиксную нотацию (т. Е. Команды за которыми следуют параметры).Единственная допустимая десятичная точка — это Юникод U + 0046 FULL STOP («.») Символ (также называемый в Юникоде как PERIOD, точка и десятичная точка) и никаких других разделителей разрешены символы [UNICODE]. (Например, следующее недопустимое числовое значение в потоке данных пути: «13,000,56». Вместо этого скажите: «13000,56».)

Для относительных версий команд все координаты значения относятся к текущей точке в начале команда.

В приведенных ниже таблицах используются следующие обозначения описать синтаксис заданной команды пути:

  • (): группировка параметров
  • +: требуется 1 или несколько заданных параметров

В описании команд пути cpx и cpy представляют координаты текущей точки.

9.3.2. Указание данных пути: свойство «d»

Имя: д
Значение: нет |
Начальное: нет
Применимо к: «путь»
Унаследовано: нет
В процентах: НЕТ
Медиа: визуальный
Вычисленное значение: как указано
Анимация: да

Свойство d используется для определения формы элемента «путь».

Значение none указывает, что нет данные пути для элемента. Для элементов «path» это означает, что элемент не отображает и не влияет на ограничивающую рамку предка элементы контейнера.

Путь состоит из нескольких сегментов, и каждая команда, либо явная или неявно, кроме moveto или closepath, определяет один сегмент пути .

Все координаты и длины, указанные в данных пути, должны рассматриваться как в пользовательских единицах измерения в текущей пользовательской системе координат.

Значение задает форму, используя строку данных пути. Содержание Значение должно соответствовать svg-path Грамматика EBNF определена ниже, и ошибки в строке обрабатываются в соответствии с правила в разделе Обработка ошибок данных пути. Если строка данных пути не содержит допустимых команд, то поведение то же самое, что и значение none.

Для анимации два значения свойства d могут быть только гладко интерполируется, когда строки данных пути содержат та же структура, (т.е. точно такое же количество и типы данных пути команды, расположенные в том же порядке). Если указана анимация и списки команд данных пути имеют разную структуру, тогда значения должны быть интерполированный с помощью дискретный тип анимации.

Если список команд данных пути имеет одинаковую структуру, то каждая параметр для каждой команды данных пути должен быть интерполированный отдельно как вещественные числа. Флаги и логические значения должны быть интерполированы как дроби от нуля до единицы, с учетом любого ненулевого значения быть значением один / истина.

Решено, что «d станет атрибутом презентации (без имени изменить) со строкой данных пути в качестве значения «в Лондон Встреча редакторов.

В следующих разделах перечислены команды, которые можно использовать в строках данных пути. Те что рисовать отрезки прямых линий, включая команды lineto ( л , л , H , H , V и v ) и команды закрытия пути ( Z и z ). Эти три группы команд рисуют кривые:

  • Кубический Команды Безье ( C , c , S и с ).Кубический отрезок Безье определяется по начальной, конечной и двум контрольным точкам.
  • Квадратичный Команды Безье ( Q , q , T и т ). Квадратичный отрезок Безье — это определяется начальной точкой, конечной точкой и одним элементом управления точка.
  • Эллиптический тренажер команды arc ( A и a ). Сегмент эллиптической дуги рисует сегмент эллипса.

9.3.3.

«moveto» управляет

Команды «moveto» ( M или м ) необходимо установить новую начальную точку и новая текущая точка.Эффект такой, как если бы «перо» подняли и переместили в новое место. Сегмент данных пути (если он есть) должен начинаться с «moveto». команда. Последующие команды «moveto» (т. Е. Когда «moveto» не первая команда) представляют собой начало нового подпуть :

Команда Имя Параметры Описание
M (абсолютное)
m (относительное)
moveto (x y) + Начните новый вложенный путь с заданными координатами (x, y). M (верхний регистр) означает, что абсолютное координаты последуют; м (строчные) указывает, что последуют относительные координаты. Если moveto за которыми следуют несколько пар координат, последующие пары рассматриваются как неявные команды lineto. Следовательно, неявный lineto команды будут относительными, если moveto является относительным, и absolute, если moveto является абсолютным. Если относительный ход ( м ) появляется как первый элемент пути, тогда он рассматривается как пара абсолютных координат.В этом случае последующие пары координат рассматриваются как относительные даже если начальное движение интерпретируется как абсолютное движение.

Когда используется относительная команда m , позиция перемещена в ( cpx + x , копий + y ).

9.3.4. Команда

«closepath»

«Ближний путь» ( Z или z ) завершает текущий подпуть, возвращая его в исходную точку. Автоматический от текущей точки к начальной проводится прямая линия текущего подпути. Этот сегмент пути может быть нулевым длина.

Если за «closepath» сразу следует «moveto», то «moveto» определяет начальную точку следующего подпути. Если за «closepath» сразу следует любая другая команда, то следующий подпуть начинается в той же начальной точке, что и текущий подпуть.

Когда подпуть заканчивается «закрытым путем», он отличается по поведению из того, что происходит, когда «вручную» закрывает подпуть через команда «lineto» в способе соединения «штрих-линия» и «штрих-линейный колпачок».С «closepath» конец последнего сегмента подпути «соединяется» с началом начального сегмент подпути, использующий текущее значение «stroke-linejoin». Если вместо этого вы «вручную» закроете подпуть через «lineto» команда, начало первого сегмента и конец последнего сегменты не соединяются, но вместо этого каждый закрывается с помощью текущее значение «stroke-linecap». В конце команды новая текущая точка устанавливается на начальная точка текущего подпути.

Команда Имя Параметры Описание
Z или
z
ближний путь (нет) Закройте текущий подпуть, подключив его обратно к текущему начальная точка подпути (см. выше). Поскольку Z и Z Команды не принимают параметров, они имеют идентичный эффект.

Замкнутый подпуть должен быть закрыт команда «closepath», она «соединяет» первый и последний сегменты пути.Любой другой путь — это открытый подпуть .

Закрытый подпуть отличается по поведению из открытого подпути, конечная координата которого является начальной точкой подпути. Первый и последний сегменты открытого подпути не будут соединены, даже если конечной координатой последнего сегмента пути является начальная точка подпути. Это приведет к первому и последнему сегменты контура ограничиваются текущим значением stroke-linecap вместо соединения с использованием текущего значения stroke-linejoin.

Если за «закрытым путем» сразу следует «moveto», затем «moveto» определяет начальную точку следующий подпуть. Если за «closepath» сразу следует любой другая команда, то следующий подпуть должен начинаться с той же начальной точки как текущий подпуть.

9.3.4.1. Завершающая сегмент операция закрытия пути

Чтобы представить основные формы как эквивалентные пути, должен быть способ закрыть изогнутые формы без введения дополнительного прямолинейного участка (даже если этот сегмент будет иметь нулевую длину).Для этой цели здесь определяется операция закрытия сегмента.

завершение сегмента, закрытие пути операция комбинирует с предыдущей командой пути, с двумя эффектами:

  • Обеспечивает точное совпадение конечной координатной точки предыдущей команды начальная точка текущего подпути.
  • Он соединяет конечную и начальную точки подпути, делая его замкнутым подпутьем.

Завершающие сегменты операции закрытия пути в настоящее время не поддерживаются как команду в синтаксисе данных пути.Рабочая группа предложила такой синтаксис для будущих версий спецификации.

9.3.5.

«lineto» команд

Различные команды «lineto» рисуют прямые линии от текущая точка к новой точке:

Команда Имя Параметры Описание
L (абсолютное)
l (относительное)
линето (x y) + Проведите линию от текущей точки до заданной (x, y) координата, которая становится новой текущей точкой. L (верхний регистр) указывает, что абсолютное координаты последуют; л (строчные буквы) указывает, что последуют относительные координаты. Число пары координат могут быть указаны для рисования ломаной линии. В конце команды новая текущая точка устанавливается на предоставленный окончательный набор координат.
H (абсолютный)
h (относительный)
горизонтальная линия х + Рисует горизонтальную линию от текущей точки. H (верхний регистр) указывает что последуют абсолютные координаты; ч (нижний регистр) указывает, что относительные координаты будут следить. Может быть указано несколько значений x (хотя обычно это не имеет смысла). H или h команда эквивалентна L или l команда с 0 указанным для координаты y. В конце команды новая текущая точка берется из окончательного значения координаты.
V (абсолютное)
v (относительное)
вертикальная линия г + Рисует вертикальную линию от текущей точки. V (верхний регистр) означает, что последуют абсолютные координаты; v (нижний регистр) указывает, что относительные координаты будут следить. Могут быть предоставлены несколько значений y (хотя обычно это не имеет смысла). A В или В команда эквивалентна L или l команда с 0 указанным для координаты x.В конце команды новая текущая точка берется из окончательного значения координаты.

Когда используется относительная команда l , конечная точка линии ( cpx + x , копий + y ).

Когда используется относительная команда h , конечная точка линии — ( cpx + x , копеек ). Это означает что команда h с положительным значением x value рисует горизонтальную линию в направлении положительной оси x.

Когда используется относительная команда v , конечная точка линии — ( cpx , копий + y ).

9.3.6. Кубическая кривая Безье дает команду

Кубические команды Безье следующие:

Команда Имя Параметры Описание
C (абсолютный)
c (относительный)
кривой до (x1 y1 x2 y2 x y) + Рисует кубическую кривую Безье по текущему указать на (x, y), используя (x1, y1) в качестве контрольной точки в начало кривой и (x2, y2) в качестве контрольной точки в конец кривой. C (прописные) указывает, что последуют абсолютные координаты; c (нижний регистр) указывает, что относительный координаты последуют. Несколько наборов координат могут указать, чтобы нарисовать полибезье. В конце команда, новая текущая точка становится последней (x, y) пара координат, используемая в полибезье.
S (абсолютное)
s (относительное)
сокращение / плавная кривая до (x2 y2 x y) + Рисует кубическую кривую Безье по текущему указать на (x, y).Предполагается, что первая контрольная точка отражение второй контрольной точки на предыдущей команду относительно текущей точки. (Если нет предыдущая команда или если предыдущая команда не была C, c, S или s, предположим, что первая контрольная точка совпадает с текущей точкой.) (x2, y2) — второй элемент управления точка (т. е. контрольная точка в конце кривой). S (верхний регистр) означает, что абсолютное координаты последуют; с (строчные буквы) указывает, что последуют относительные координаты.Несколько наборы координат могут быть указаны для рисования полибезье. В конце команды новый текущая точка становится последней используемой парой координат (x, y) в полибезье.

Когда родственник c или s используется команда, каждая из относительных пар координат вычисляется так же, как и в команде m . Например, конечная контрольная точка кривой обе команды: ( cpx + x , копий + y ).

Пример cubic01 показывает некоторые простое использование кубических команд Безье в пути. В пример использует внутреннюю таблицу стилей CSS для назначения стиля характеристики. Обратите внимание, что контрольной точкой для команды «S» является вычисляется автоматически как отражение контрольной точки для предыдущей команды «C» относительно начальной точки Команда «S».

 

   Пример cubic01 - кубические команды Безье в данных пути 
   Изображение, показывающее простой пример данных пути
        используя команды "C" и "S",
        вместе с аннотациями, показывающими контрольные точки
        и конечные точки 
  

  

  
  
  
  
  
  <круг cx = "100" cy = "200" r = "10" />
  <круг cx = "250" cy = "200" r = "10" />
  <круг cx = "400" cy = "200" r = "10" />
  <круг cx = "100" cy = "100" r = "10" />
  <круг cx = "250" cy = "100" r = "10" />
  <круг cx = "400" cy = "300" r = "10" />
  
   M100,200 C100,100 250,100 250,200 
   S400,300 400,200 
 

Пример cubic01

Просмотрите этот пример как SVG (только для браузеров с поддержкой SVG)

На следующем рисунке показано, как кубический Безье кривые меняют свою форму в зависимости от положения контрольные точки. Первые пять примеров иллюстрируют один кубический отрезок пути Безье. Пример внизу справа показана команда «C», за которой следует команда «S».

Просмотр этот пример как SVG (только браузеры с поддержкой SVG)

9.3.7. Квадратичная кривая Безье дает команду

Квадратичные команды Безье следующие:

Команда Имя Параметры Описание
Q (абсолютный)
q (относительный)
квадратичная кривая Безье до (x1 y1 x y) + Строит квадратичную кривую Безье по текущему укажите на (x, y), используя (x1, y1) в качестве контрольной точки. Q (верхний регистр) указывает, что абсолютное координаты последуют; q (строчные буквы) указывает, что последуют относительные координаты. Несколько наборы координат могут быть указаны для рисования полибезье. В конце команды новый текущая точка становится последней используемой парой координат (x, y) в полибезье.
T (абсолютное)
t (относительное)
Сокращение / гладкая квадратичная кривая Безье до (x y) + Строит квадратичную кривую Безье по текущему указать на (x, y).Контрольной точкой считается отражение контрольной точки на предыдущей команде относительно текущей точки. (Если нет предыдущего команда или если предыдущая команда не была Q, q, T или t, предположим, что контрольная точка совпадает с текущей точки.) T (верхний регистр) означает, что последуют абсолютные координаты; т (нижний регистр) указывает, что относительные координаты будут следить. В конце команды новая текущая точка становится последней парой координат (x, y), используемой в полибезье.

Когда родственник q или t используется команда, каждая из относительных пар координат вычисляется так же, как и в команде m . Например, конечная контрольная точка кривой обе команды: ( cpx + x , копий + y ).

Пример quad01 показывает некоторые простое использование квадратичных команд Безье внутри контура. Обратите внимание, что контрольная точка для команды «T» вычисляется автоматически как отражение контрольной точки для предыдущая команда «Q» относительно начальной точки «T» команда.

 

   Пример quad01 - квадратичные команды Безье в данных пути 
   Изображение, показывающее команду "Q" и "T",
        вместе с аннотациями, показывающими контрольные точки
        и конечные точки 
  

  
  
  
    <круг cx = "200" cy = "300" r = "10" />
    
    <круг cx = "1000" cy = "300" r = "10" />
  
  
  
    
    
  
  
 

Пример quad01

Просмотрите этот пример как SVG (только для браузеров с поддержкой SVG)

9.

3.8. Команды эллиптической кривой дуги
SVG 2 Требование: Упростите рисование дуг в синтаксисе пути SVG.
Разрешение: Упростите создание дуг в путях.
Назначение: Чтобы облегчить авторам запись данных пути с дугами вручную.
Владелец: Кэмерон (ACTION-3151)

Команды эллиптической дуги следующие:

Команда Имя Параметры Описание
A (абсолютный)
a (относительный)
эллиптическая дуга (rx ry x-axis-rotation big-arc-flag sweep-flag x г) + Рисует эллиптическую дугу от текущей точки до ( x , y ).Размер и ориентация эллипса определяется двумя радиусами ( RX , Ry ) и x-axis-rotation , которая указывает, как эллипс в целом поворачивается в градусах относительно текущего система координат. Центр ( cx , г. cy ) эллипса вычисляется автоматически, чтобы удовлетворить ограничения, налагаемые другие параметры. флаг с большой дугой и развертка-флаг способствует автоматическому расчеты и помогают определить, как нарисована дуга.

Когда используется относительная команда , конечная точка дуги составляет ( cpx + x , копий + y ).

Пример arcs01 показывает некоторые простое использование команд дуги внутри контура.

 

   Пример arcs01 - команды дуги в данных пути 
   Изображение круговой диаграммы с двумя секторами и
        изображение линии с метками по дуге 
  

  
  

  
 

Пример arcs01

Просмотрите этот пример как SVG (только для браузеров с поддержкой SVG)

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

  • дуга начинается в текущей точке
  • дуга заканчивается в точке ( x , л )
  • эллипс имеет два радиуса ( rx , ry )
  • ось абсцисс эллипса вращается на поворот по оси x градусов относительно оси x текущая система координат.

В большинстве случаев на самом деле есть четыре разные дуги (два разных эллипса, каждый с двумя разными дугами) которые удовлетворяют этим ограничениям. флаг с большой дугой и флаг развертки указывает, какой из четырех дуги нарисованы следующим образом:

  • Из четырех возможных вариантов развертки дуги два будут представлять размах дуги не менее 180 градусов ( «большая дуга»), а два будут представлять длину дуги менее чем или равный 180 градусам («малая дуга»).Если флаг с большой дугой — это ‘1’, затем один из двух будут выбраны более крупные развертки дуги; в противном случае, если флаг с большой дугой — это «0», один из меньших будут выбраны развертки дуги,
  • Если флаг развертки равен «1», то дуга будет быть нарисованным в направлении «положительного угла» (т. е. эллипс формула x = cx + rx * cos (тета) и y = cy + ry * sin (theta) равно оценивается так, что тета начинается под углом, соответствующим текущей точки и увеличивается положительно, пока дуга достигает (x, y)).Значение 0 заставляет дугу рисовать в направление «отрицательный угол» (т. е. тета начинается под углом значение, соответствующее текущей точке, и уменьшается до тех пор, пока дуга достигает (x, y)).

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


 

где «?,?» заменяется на «0,0» «0,1» «1,0» и «1,1» на сгенерируйте четыре возможных случая.

Просмотр этот пример как SVG (только браузеры с поддержкой SVG)

См. Раздел, посвященный параметрам эллиптической дуги, выходящим за пределы допустимого диапазона. для подробных примечаний по реализации для команды эллиптической дуги данных пути.

Приложение «Замечания по реализации» имеет соответствующие формулы для программного обеспечения, которое необходимо преобразовать Обозначение дуги SVG в формате, в котором используются центральные точки и дуги.

9.3.9. Грамматика для данных пути

Данные пути SVG соответствуют следующей грамматике EBNF.

svg_path :: = wsp * moveto? (перейти к drawto_command *)?

drawto_command :: =
    двигаться
    | близкий путь
    | Lineto
    | horizontal_lineto
    | vertical_lineto
    | кривая
    | smooth_curveto
    | quadratic_bezier_curveto
    | smooth_quadratic_bezier_curveto
    | эллиптическая_дуга

moveto :: =
    ("M" | "m") wsp * последовательность_координат

closepath :: =
    ("Z" | "z")

lineto :: =
    ("L" | "l") wsp * последовательность_координат

horizontal_lineto :: =
    ("H" | "h") wsp * последовательность_координат

vertical_lineto :: =
    ("V" | "v") wsp * последовательность_координат

curveto :: =
    ("C" | "c") wsp * curveto_coordinate_sequence

последовательность_координат_кривой :: =
    Coordin_pair_triplet
    | (тройка_координат запятая? последовательность_координат_координат)

smooth_curveto :: =
    ("S" | "s") wsp * smooth_curveto_coordinate_sequence

smooth_curveto_coordinate_sequence :: =
    Coordinate_pair_double
    | (Coordinate_pair_double comma_wsp? smooth_curveto_coordinate_sequence)

quadratic_bezier_curveto :: =
    ("Q" | "q") wsp * quadratic_bezier_curveto_coordinate_sequence

quadratic_bezier_curveto_coordinate_sequence :: =
    Coordinate_pair_double
    | (пара_координат, двойная запятая_wsp? quadratic_bezier_curveto_coordinate_sequence)

smooth_quadratic_bezier_curveto :: =
    ("T" | "t") wsp * последовательность_координат

эллиптическая_дуга :: =
    ("A" | "a") wsp * elliptical_arc_argument_sequence

elliptical_arc_argument_sequence :: =
    elliptical_arc_argument
    | (эллиптическая_дуга_аргумент запятая_всп? эллиптическая_дуга_аргумент_последовательность)

эллиптический_дуговой_аргумент :: =
    число comma_wsp? число comma_wsp? число comma_wsp
    флаг comma_wsp? флаг comma_wsp? Coordin_pair

двойной_координат :: =
    ordin_pair comma_wsp? Coordin_pair

Coordin_pair_triplet :: =
    ordin_pair comma_wsp? Coordin_pair comma_wsp? Coordin_pair

последовательность_пар_координат :: =
    Coordin_pair | (пара_координат, запятая_wsp? последовательность_пар_координат)

последовательность_координат :: =
    координата | (координата запятая? последовательность_координат)

пара_координат :: = координата запятая_wsp? координировать

координата :: = знак? номер

знак :: = "+" | "-"
число :: = ([0-9]) +
flag :: = ("0" | "1")
comma_wsp :: = (wsp + ","? wsp *) | ("," wsp *)
wsp :: = (# x9 | # x20 | #xA | #xC | #xD)
 

Обработка EBNF должна потреблять как можно больше заданного Производство EBNF по мере возможности, останавливаясь в момент, когда встречается персонаж, который больше не удовлетворяет производство.Таким образом, в строке «М 100-200» первая координата для «moveto» потребляет символы «100» и останавливается при встрече со знаком минус, потому что знак минус не может следовать за цифрой при производстве «координаты». В в результате первая координата будет «100», а вторая координата будет «-200».

Аналогично для строки «M 0.6.5» первая координата «moveto» потребляет символы «0,6» и останавливается на встречает вторую десятичную точку, потому что производство «координата» допускает только одну десятичную точку.Результат что первая координата будет «0,6», а вторая координата будет «.5».

Обратите внимание, что EBNF разрешает строку данных пути в d должно быть пустым. Это не ошибка, вместо этого он отключает отображение пути. Отрисовка также отключается, когда свойство d имеет значение none.

Если данные пути не соответствуют грамматике, значит, данные пути ошибочны. (см. Обработка ошибок).

9.4. Направленность пути

Некоторые функции, например ориентация маркеров и формы ограничения строк определяются в терминах направление пути на заданном расстоянии вдоль пути или на начало или конец отдельного сегмента.

Направление пути в указанном расстояние по пути определяется следующим образом:

  • Если заданное расстояние равно нулю, то направление пути равно направление в начале первый сегмент пути.
  • В противном случае, если данное расстояние является длиной пути, то направление пути — это направление в конце пути последний сегмент.
  • В противном случае, если данное расстояние по пути встречается на пути граница сегмента, то направление пути — это направление в начале отрезок на заданном расстоянии, учитывая, что каждый отрезок быть конечной точкой эксклюзивно.

    Это будет «пройти мимо» сегменты нулевой длины и выберите более поздний сегмент, если расстояние находится на границе между двумя сегментами ненулевой длины.

  • В противном случае данное расстояние по пути будет посередине. отрезка пути ненулевой длины. Направление — это просто направление кривой в этой точке. Если точка лежит на разрыве, например куспид в сегменте Безье, то направление не определено; в таком случае, направление между входящим и исходящим направлениями вокруг неоднородности должен быть использован.

Направление в начале сегмента пути определяется следующим образом:

  • Если длина всего пути, которому принадлежит сегмент, равна нулю, то направление в начале сегмента указывает в том же направлении, что и положительная ось абсцисс.
  • В противном случае, если сегмент пути имеет нулевую длину и сегмент не имеют любые предшествующие сегменты ненулевой длины, то направление в начало сегмента такое же, как направление в конце отрезка.
  • В противном случае, если отрезок пути имеет нулевую длину и есть ненулевые сегмент длины, предшествующий этому сегменту, затем направление в начале этот сегмент такой же, как и направление в конце ближайшего предшествующий сегмент ненулевой длины.
  • В противном случае сегмент пути имеет ненулевую длину. Направление на начало сегмента — это просто направление, выходящее из начала сегмента точка.

Направление в конце пути сегмент определяется следующим образом:

  • Если длина всего пути, которому принадлежит сегмент, равна нулю, то направление в конце сегмента указывает в том же направлении, что и положительная ось абсцисс.
  • В противном случае, если сегмент пути имеет нулевую длину и сегмент не есть следующие сегменты ненулевой длины, то направление в конец сегмента совпадает с направление в начале сегмента.
  • В противном случае, если отрезок пути имеет нулевую длину и есть ненулевые сегмент длины, следующий за этим сегментом, затем направление в конце этот сегмент такой же, как и направление в начале ближайшего следующий сегмент ненулевой длины.
  • В противном случае сегмент пути имеет ненулевую длину. Направление на конец сегмента — это просто направление, ведущее к концу сегмента точка.

9,5. Примечания по реализации

Соответствующий пользовательский агент SVG должен реализовывать функции, использующие данные пути. по следующим реквизитам:

9.5.1. Параметры эллиптической дуги вне допустимого диапазона

Для всех параметров эллиптической дуги разрешены произвольные числовые значения. (кроме логических флагов), но пользовательские агенты должны внести следующие корректировки для недопустимых значений при рендеринге кривых или вычислении их геометрии:

  • Если конечная точка ( x , y ) сегмента совпадает с текущей точкой (е.g., конечная точка предыдущего отрезка), тогда это эквивалентно полностью исключению сегмента эллиптической дуги.

  • Если rx или ry равно 0, тогда эта дуга рассматривается как отрезок прямой («lineto»), соединяющий конечные точки.

  • Если rx или ry имеют отрицательные знаки, они опущены; вместо этого используется абсолютное значение.

  • Если rx , ry и x-axis-rotation таковы, что нет решения (в основном, эллипс недостаточно большой, чтобы дотянуться до от текущей точки до новой конечной точки) затем эллипс увеличивается равномерно, пока не будет ровно одно решение (пока эллипс как раз достаточно большой).

    См. Раздел приложения Коррекция радиусов вне допустимого диапазона для математической формулы для этой операции масштабирования.

Это прощающее, но последовательное обращение с выходом за пределы допустимого диапазона values ​​гарантирует, что:

  • Неизбежные приближения, исходящие от компьютера арифметика не может вызвать допустимый набор значений, записанных одним Реализация SVG будет считаться недействительной при чтении другая реализация SVG. В противном случае это было бы проблема для общих граничных случаев, таких как полукруглый дуга.
  • Непрерывная анимация, вызывающая передачу параметров из-за недопустимых значений не проблема. Движение остается непрерывным.

9.5.2. Отраженные контрольные точки

Команды S / s и T / t указывают, что первая контрольная точка данный кубический сегмент Безье вычисляется по формуле отражение последней контрольной точки предыдущего сегмента пути относительно текущей точки. Точная математика выглядит как следует.

Если текущая точка ( curx , cury ) и конечная контрольная точка предыдущего отрезка пути — ( oldx2 , oldy2 ), затем отраженная точка (т.е.е., ( новыйx1 , newy1 ), первая контрольная точка текущего сегмента пути):

(newx1, newy1) = (curx - (oldx2 - curx), cury - (oldy2 - любопытный))
               = (2 * curx - старыйx2, 2 * cury - oldy2)
 

9.5.3. Сегменты пути нулевой длины

Сегменты пути с нулевой длиной недействительны, и повлияет на рендеринг в следующих случаях:

  • Если указатели указаны, то маркер рисуется на каждая применимая вершина, даже если данная вершина является конечная точка отрезка пути нулевой длины и даже если Команды moveto следуют друг за другом.
  • Как указано в Stroke Properties, заглушки должны быть окрашены для подпути нулевой длины, когда stroke-linecap имеет значение круглый или квадратный.

9.5.4. Обработка ошибок в данных пути

Нераспознанное содержимое в потоке данных пути (т. Е. содержимое, не являющееся частью грамматики данных пути) является ошибка. В таком случае необходимо использовать следующие правила обработки ошибок:
  • Общее правило обработки ошибок в данных пути: что пользовательский агент SVG должен отображать элемент «путь» вверх к (но не включая) команду пути, содержащую первая ошибка в спецификации данных пути.Это будет предоставить пользователю или разработчику визуальную подсказку о где ошибка может быть в спецификации данных пути. Это правило сильно препятствует созданию недействительных Данные пути SVG.
  • Если команда данных пути содержит неверный набор параметры, то отображается заданная команда данных пути до последнего правильно определенного сегмента пути включительно, даже если этот сегмент пути является подкомпонентом команда данных составного пути, например «lineto» с несколько пар координат.Например, для пути строка данных ‘M 10,10 L 20,20,30’, есть нечетное количество параметров для команды «L», которая требует четного количество параметров. Пользовательский агент требуется для рисования строка от (10,10) до (20,20), а затем выполнить ошибку отчет с ‘L 20 20’ — последний правильно определенный сегмент спецификации данных пути.
  • По возможности, все пользовательские агенты SVG должны сообщать все ошибки пользователю.

9.6.Расстояние по тропе

Различные операции, включая текст на траектории и анимацию движения и различные инсульты операции, требуют, чтобы пользовательский агент вычислял расстояние по геометрии графического элемента, например «путь».

Существует точная математика для вычисления расстояния вдоль пути, но формулы очень сложные и требуют существенного вычисление. Рекомендуется, чтобы продукты авторинга и пользователь агенты используют алгоритмы, которые дают столь же точные результаты, как возможный; однако, чтобы учесть различия в реализации и чтобы помочь при расчетах расстояний получить результаты, которые приблизительное намерение автора, можно использовать атрибут «pathLength» предоставить авторский расчет общей длины путь, чтобы пользовательский агент мог масштабировать расстояние вдоль пути вычислений по отношению «pathLength» к собственному пользовательскому агенту вычисленное значение для общей длины пути.

Операция «moveto» в элементе «path» определена как нулевая длина. Только различные «lineto», «curveto» и «arcto» команды участвуют в расчетах длины пути.

9.6.1. Атрибут pathLength

Имя Значение Начальное значение Анимационный
длина пути <номер> (нет) да

Авторский расчет полной длины путь в пользовательских единицах.Это значение используется для калибровки собственное расстояние по пути пользовательского агента расчеты с автором. Пользовательский агент будет масштабировать все вычисления расстояния вдоль пути по соотношению «pathLength» пользователю собственное вычисленное значение общей длины пути агента. «PathLength» потенциально влияет вычисления текста по пути, анимация движения и различные инсультные операции.

Нулевое значение допустимо и должно рассматриваться как бесконечный масштабный коэффициент.Значение нуля, масштабируемое бесконечно, должно оставаться нулевым, в то время как любое непроцентное значение больше чем ноль должно стать + Infinity.

Отрицательное значение — ошибка (см. Обработка ошибок).

«pathLength» не влияет на процент расчеты расстояния по траектории.

9.7. DOM интерфейсы

9.7.1. Интерфейс SVGPathElement

Объект SVGPathElement представляет «путь» в DOM.

 [Exposed = Window]
interface  SVGPathElement : SVGGeometryElement {
}; 

% Шейла Шах % ДОКАЗАТЕЛЬСТВО %! % берет 2 точки в векторной форме и находит среднюю точку / findmidpoint {начало 10 слов / B exch def / A exch def [A 0 получить B 0 получить добавить 2 div A 1 получить B 1 получить добавить 2 div] конец} def % занимает стек из 3 2D векторов, 3 точки / mktriangle {начало 16 диктата / C exch def / B exch def / A exch def A 0 получить A 1 получить moveto B 0 получить B 1 получить lineto C 0 получить C 1 получить линето близкий путь конец} def % принимает значения x, y и размер / mkcircle {начало 16 диктата / размер exch def / y exch def / x exch def / N 64 деф / a 0 def a cos size mul x добавить размер sin mul y add moveto N { / a 360 N div добавить def a cos size mul x добавить размер sin mul y add lineto } повторить конец} def % принимает стек из 3 2D векторов, 3 точки % и образует вписанный круг в треугольник с выходом в центр [x y] / mkinscribedcircle {20 dict begin / C exch def / B exch def / A exch def / aa [B 0 получить C 0 получить подписку B 1 получить C 1 получить подп] def / bb [C 0 получить A 0 получить подписку C 1 получить A 1 получить подписку] def / cc [B 0 получить A 0 получить подписку B 1 получить A 1 получить подписку] def / a aa 0 получить 2 опыта aa 1 получить 2 опыта добавить 0.5 exp def / b bb 0 получить 2 опыта bb 1 получить 2 опыта добавить 0,5 опыта определить / c cc 0 получить 2 опыта cc 1 получить 2 опыта добавить 0,5 опыта def / с a b добавить c добавить 2 div def / k s a sub s b sub mul s c sub mul s mul 0.5 exp def / r k s div def % нахождение центра круга / sinA B 1 получить A 1 получить sub c div def / angle sinA dup 2 exp 1 sub neg sqrt atan def / d 1 угол 2 div sin угол 2 div cos div div r mul def [A 0 получить d добавить A 1 получить r добавить] конец} def % принимает 3 вектора, указывает и выводит вектор [xcentre, ycentre, R radius] / mkcircumcircle {20 dict begin / C exch def / B exch def / A exch def / aa [B 0 получить C 0 получить подписку B 1 получить C 1 получить подп] def / bb [C 0 получить A 0 получить подписку C 1 получить A 1 получить подписку] def / cc [B 0 получить A 0 получить подписку B 1 получить A 1 получить подписку] def / a aa 0 получить 2 опыта aa 1 получить 2 опыта добавить 0.5 exp def / b bb 0 получить 2 опыта bb 1 получить 2 опыта добавить 0,5 опыта определить / c cc 0 получить 2 опыта cc 1 получить 2 опыта добавить 0,5 опыта def / k 0,5 b mul B 1 получить A 1 получить sub mul def / R a b mul c mul 4 k mul div def % координаты описанной окружности / x A 0 получить b 2 div добавить def / y R 2 exp b 2 div 2 exp sub 0,5 exp A 1 получить сложить def [x y R] конец} def / Times-Roman findfont 0,15 масштабного шрифта setfont / точка 0,03 по умолчанию % ———————- СТРАНИЦА 11 gsave 100-кратная шкала 2 5.5 перевести 1 72 деления setlinewidth 0,8 сет серый / A [0 0] def / B [1 2] def / C [3 0] def A B C Обводка прямоугольника -0.15 0 переместить (Шоу 1 2 переместить (B) показать 3 0 переместить (C) показать A 0 получить A 1 получить балл mkcircle fill B 0 получить B 1 получить точку mkcircle fill C 0 получить C 1 получить точку mkcircle fill 1 0 0 setrgbcolor % середины сторон / L A B findmidpoint def L 0 получить L 1 получить точку mkcircle fill L 0 получить 0.1 sub L 1 получить moveto (L) показать / M B C findmidpoint def M 0 получить M 1 получить точку mkcircle fill M 0 получить M 1 получить moveto (M) показать / N A C findmidpoint def N 0 получить N 1 получить точку mkcircle fill N 0 получить 0,1 к югу N 1 получить 0.1 переход (N) показать % футов высот / D [1.5625 1.4375] по умолчанию / E [1 0] def / F [0,5625 1,125] по умолчанию 0,8 сет серый A 0 получить A 1 получить moveto D 0 получить D 1 получить линию для хода B 0 получить B 1 получить moveto E 0 получить E 1 получить линию для хода C 0 получить C 1 получить moveto F 0 получить F 1 получить линию до хода 0 1 0 setrgbcolor D 0 получить D 1 получить точку mkcircle fill 0,8 сет серый E 0 получить E 1 получить точку mkcircle fill F 0 получить F 1 получить точку mkcircle fill 0 1 0 setrgbcolor D 0 получить D 1 получить moveto (D) показать 0,8 сет серый E 0 получить E 1 получить 0.1 переход (E) показать F 0 получить 0,1 к югу F 1 перейти к (F) показать / H [1 0,9275] по умолчанию H 0 получить H 1 получить точку mkcircle fill H 0 получить 0,05 sub H 1 получить 0,1 добавить moveto (H) показать % вершин до ортоцентра / P A H findmidpoint def / Q B H findmidpoint def / R C H findmidpoint def 0 0 1 setrgbcolor P 0 получить P 1 получить точку mkcircle fill Q 0 получить Q 1 получить точку mkcircle fill R 0 получить R 1 получить точку mkcircle fill P 0 получить 0.15 sub P 1 получить moveto (P) показать Q 0 получить Q 1 получить 0,05 добавить moveto (Q) показать R 0 получить 0,05 добавить R 1 получить переместить (R) показать 0.9 0,9 0,8 наборrgbcolor P D M mktriangle заливка 0 сет серый L 0 получить L 1 получить moveto M 0 получить M 1 получить lineto R 0 получить R 1 получить lineto P 0 получить P 1 получить lineto близкий путь Инсульт L 0 получить L 1 получить moveto R 0 получить R 1 получить линию до хода M 0 получить M 1 получить moveto P 0 получить P 1 получить линию до хода / Uprime L R findmidpoint def Uprime 0 получить Uprime 1 получить точку mkcircle fill Q 0 получить Q 1 получить moveto R 0 получить R 1 получить lineto N 0 получить N 1 получить линето L 0 получить L 1 получить линето близкий путь Инсульт L 0 получить L 1 получить moveto R 0 получить R 1 получить линию до хода N 0 получить N 1 получить moveto Q 0 получить Q 1 получить линию до хода / Uprime L R findmidpoint def Uprime 0 получить Uprime 1 получить точку mkcircle fill 0 0.6 0.2 setrgbcolor L 0 получить L 1 получить moveto R 0 получить R 1 получить линию до хода Uprime 0 получить 0,2 sub Uprime 1 получить 0,05 добавить ход (U) показать showpage Grestore

Базовая графика — PyX 0.15 Руководство

Введение

Модуль пути позволяет создавать PostScript-подобные пути , которые являются одним основных строительных блоков для создания чертежей. Путь PostScript произвольная форма, состоящая из прямых, дуговых отрезков и кубической кривой Безье кривые. Такой путь не обязательно должен быть соединен, но может также включать несколько отключенные сегменты, которые в дальнейшем будут называться подпутьями .

Todo

пример путей и подпутей (рисунок)

Обычно путь создается путем передачи списка примитивов пути. moveto , lineto , curveto и т. Д. Конструктору путь класс . Например, следующий фрагмент кода определяет путь p , который состоит из прямой линии от точки \ ((0, 0) \) до точка \ ((1, 1) \)

 из импорта pyx *
p = путь.путь (путь.moveto (0, 0), путь.lineto (1, 1))
 

Эквивалентно, можно также использовать предопределенный путь подкласс строка и напишите

 p = path.line (0, 0, 1, 1)
 

Хотя с этим путем уже можно выполнять некоторые геометрические операции (см. следующий раздел), необходим другой объект PyX, чтобы действительно иметь возможность нарисуйте путь, а именно экземпляр класса canvas . Условно, мы используем имя c для этого экземпляра:

Чтобы нарисовать путь на холсте, мы используем метод stroke () холст класс, и.е.,

 с. Ход (п)
c.writeEPSfile ("строка")
 

Для завершения примера мы добавили вызов writeEPSfile () , который записывает содержимое холста в файл line.eps . Обратите внимание, что расширение .eps добавляется автоматически, если еще не присутствует в данном имя файла. Точно так же, если вы хотите вместо этого сгенерировать файл PDF или SVG, используйте

или

c.writeSVGfile («строка»)

В качестве второго примера давайте определим путь, состоящий из более чем одного подпуть:

 крест = путь.путь (path.moveto (0, 0), path.rlineto (1, 1),
                  path.moveto (1, 0), path.rlineto (-1, 1))
 

Первый подпуть — снова прямая линия от \ ((0, 0) \) до \ ((1, 1) \), с той лишь разницей, что теперь мы использовали класс rlinto , чьи аргументы считаются относительными от последней точки пути. Второй moveto instance открывает новый подпуть, начинающийся с точки \ ((1, 0) \) и заканчивающийся на \ ((0, 1) \). Обратите внимание, что хотя обе линии пересекаются в точка \ ((1/2, 1/2) \), они считаются отключенными подпути.Общее правило заключается в том, что каждое вхождение экземпляра moveto к открывает новый подпуть. Этот означает, что если кто-то хочет нарисовать прямоугольник, не следует использовать

 rect1 = path.path (path.moveto (0, 0), path.lineto (0, 1),
                  path.moveto (0, 1), path.lineto (1, 1),
                  path.moveto (1, 1), path.lineto (1, 0),
                  path.moveto (1, 0), path.lineto (0, 0))
 

, который построит прямоугольник из четырех несвязанных подпутей (см.рис. Пример прямоугольника а).В лучшем решении (см. Рис. Пример прямоугольника b) ручка не поднимается между первой и последней точкой:

Пример прямоугольника

Прямоугольник, состоящий из (а) четырех отдельных линий, (б) одного открытого пути и (в) одного замкнутого пути. (d) Заполнение пути всегда автоматически закрывает его.

 rect2 = path.path (path.moveto (0, 0), path.lineto (0, 1),
                  path.lineto (1, 1), path.lineto (1, 0),
                  path.lineto (0, 0))
 

Однако, как видно в левом нижнем углу рис.Пример прямоугольника b, прямоугольник все еще не завершен. Его нужно закрыть, что можно сделать явно, используя для последней прямой прямоугольника (от точки \ ((0, 1) \) обратно в начало координат в \ ((0, 0) \)) ближайший путь директива:

 rect3 = path.path (path.moveto (0, 0), path.lineto (0, 1),
                  path.lineto (1, 1), path.lineto (1, 0),
                  path.closepath ())
 

Директива closepath добавляет прямую линию от текущей точки к первая точка текущего подпути и, кроме того, закрывает подпути, я.е., он соединяет начало и конец отрезка. Это приводит к предполагаемый прямоугольник, показанный на рис. Пример прямоугольника c. Обратите внимание, что заполнение path неявно закрывает каждый открытый подпуть, как показано для одного подпути в Рис. Пример прямоугольника d), который получается из

 c.stroke (rect2, [deco.filled ([color.grey (0.5)])])
 

Здесь мы предоставляем в качестве второго аргумента метода stroke () список, который в настоящее дело состоит только из одного элемента, а именно так называемого декоратор деко.заполнено . Как следует из названия, этот декоратор указывает, что путь не только обводится, но и заливается заданным цветом. Более информация о декораторах, стилях и других атрибутах, которые могут быть переданы как элементы списка можно найти в разд. Атрибуты: стили и украшения. Более подробности о доступных элементах пути можно найти в Разд. Элементы пути.

В заключение этого раздела мы не должны забывать упомянуть, что прямоугольники: конечно, предопределено в PyX, поэтому выше мы могли бы также написать

 rect2 = путь.прямоугольник (0, 0, 1, 1)
 

Здесь первые два аргумента указывают начало прямоугольника, а вторые два аргумента определяют его ширину и высоту соответственно. Больше подробностей по заранее определенным путям мы отсылаем читателя к Разд. Предопределенные пути.

Операции с путями

Часто требуется выполнить геометрические операции с траекторией перед ее размещением. на холсте, поглаживая или заполняя его. Например, можно захотеть пересекать один путь с другим, разделять пути в точках пересечения, а затем соедините сегменты по-новому.PyX поддерживает такие задачи с помощью средствами ряда методов пути, которые мы представим ниже.

Предположим, вы хотите провести радиусы к точкам пересечения окружности с прямая линия. Эту задачу можно выполнить с помощью следующего кода, который приводит к Рис. Пример: пересечение круга с линией, дающей два радиуса

 из импорта pyx *

c = холст.canvas ()

круг = путь.circle (0, 0, 2)
линия = путь.line (-3, 1, 3, 2)
c.stroke (круг, [style.linewidth.Thick])
c.штрих (линия, [style.linewidth.Thick])

isects_circle, isects_line = circle.intersect (линия)
для isect в isects_circle:
    isectx, isecty = circle.at (isect)
    c.stroke (path.line (0, 0, isectx, isecty))

c.writePDFfile ()
 

Пример: пересечение круга с линией, дающей два радиуса

Здесь основные элементы, круг вокруг точки \ ((0, 0) \) с радиусом \ (2 \) и прямая, определены. Затем, пройдя строку , в correct () метод круга , мы получаем кортеж значений параметров точки пересечения.Первый элемент кортежа — это список параметров значения для пути, для которого был вызван метод correct () , второй element — это соответствующий список для пути, переданного в качестве аргумента этому метод. В данном примере нам нужен только один список значений параметров, а именно isects_circle . Используя метод пути at () для получения точки в соответствии со значением параметра, рисуем радиусы для различных точки пересечения.

Еще одна мощная особенность PyX — его способность разделять пути в заданном наборе параметры.Например, чтобы заполнить предыдущий пример, сегмент круга, ограниченного прямой линией (см. рис. Пример: пересечение круга с линией, дающей радиус и сегмент круга), один сначала нужно построить путь, соответствующий контуру этого сегмента. В следующий фрагмент кода дает этот сегмент

 arc1, arc2 = circle.split (isects_circle)
если arc1.arclen () 


 

Пример: пересечение круга с линией, дающей радиусы, и сегмент круга

Здесь мы сначала разбиваем круг с помощью метода split () , передавая список параметров, полученных выше. Поскольку круг замкнут, получается две дуги сегменты. Затем мы используем arclen () , который возвращает длину дуги путь, чтобы найти более короткую из двух дуг. Перед тем, как разделить линию, мы должны учтите, что метод split () принимает только отсортированный список параметры.Наконец, мы соединяем прямую линию и отрезок дуги. Для этого мы используйте оператор << , который не только добавляет пути (которые могут быть выполняется с использованием line2 + arc ), но также присоединяется к последнему подпути line2 и первая из arc . Таким образом, сегмент состоит только из одного подпути и начинка работает как положено.

Важным вопросом при работе с траекториями является используемая параметризация. Внутри PyX использует параметризацию, которая использует интервал длины \ (1 \) для каждого элемента пути.Например, для простого прямого строка, возможные значения параметров варьируются от \ (0 \) до \ (1 \), соответствующие первой и последней точке линии соответственно. Добавление другая прямая линия расширит этот диапазон до максимального значения \ (2 \).

Однако ситуация усложняется, если более сложные объекты, такие как круг задействованы. Тогда можно было бы предположить, что снова значение параметра находится в диапазоне от \ (0 \) до \ (1 \), поскольку предопределенный окружность состоит только из одной дуги вместе с ближним путем элемент.Однако это не так: реальный диапазон намного больше. В причина такого поведения кроется во внутренней обработке пути PyX: Before выполняя любую нетривиальную геометрическую операцию на пути, он будет автоматически преобразовываться в экземпляр класса normpath (см. также разд. путь. Нормальный путь ). Эти сгенерированные таким образом пути уже разделены в своих подпутьях и содержат только прямые линии и сегменты кривой Безье. XXX объясняет параметры normpath и такие вещи, как p.begin (), p.end () - 1,

Более геометрический способ доступа к точке на пути - использовать длину дуги. отрезка пути от первой точки пути до данной точки. Таким образом, все методы пути PyX, которые принимают значение параметра, также позволяют пользователю передавать длина дуги. Например,

 из math import pi

г = 2
pt1 = path.circle (0, 0, r) .at (r * pi)
pt2 = path.circle (0, 0, r) .at (r * 3 * pi / 2)

c.stroke (path.path (path.moveto (* pt1), path.lineto (* pt2)))
 

проведет прямую линию из точки под углом \ (180 \) градусов (в радианах \ (\ pi \)) в другую точку под углом \ (270 \) градусов (в радианах \ (3 \ pi / 2 \)) на окружности радиуса \ (r = 2 \).Однако обратите внимание, что отображение длины дуги в точку вначале обычно прерывисто и конец подпути, и, таким образом, PyX не гарантирует какой-либо конкретный результат для этого граничного случая.

Более подробную информацию о доступных методах пути можно найти в Разд. Путь к классу - пути, подобные PostScript.

Атрибуты: стили и украшения

Атрибуты определяют свойства данного объекта, когда он используется. Обычно есть разные виды атрибутов, которые обычно ортогональны каждому другое, в то время как для одного типа атрибута возможно несколько вариантов.Пример это прокладывание пути. Там ширина и стиль линий - это разные типы атрибуты. Ширина линии может быть тонкой, нормальной, толстой и т. Д., А стиль линий может быть сплошным, штриховым и т. д.

Атрибуты всегда встречаются в списках, переданных как необязательный аргумент ключевого слова в метод или функцию. Обычно атрибуты являются первым аргументом ключевого слова, поэтому один можно просто передать список без указания ключевого слова. Опять же, для пути Например, типичный вызов выглядит как

 c.stroke (path, [style.linewidth.Thick, style.linestyle.dashed])
 

Здесь мы также сталкиваемся с еще одной особенностью системы атрибутов PyX. Для многих атрибуты, полезные значения по умолчанию, хранятся как переменные-члены фактического атрибут. Например, style.linewidth.Thick эквивалентно style.linewidth (0,04, type = "w", unit = "cm") , то есть \ (0,04 \) ширина см (см. раздел «Модуль модуля» для получения дополнительной информации о системе единиц PyX).

Еще одна важная особенность атрибутов PyX - это слияние с атрибутами вызова.Тривиальный пример:

 # следующие две строки эквивалентны
c.stroke (путь, [style.linewidth.Thick, style.linewidth.thin])
c.stroke (путь, [style.linewidth.thin])
 

Здесь атрибут style.linewidth.thin переопределяет предыдущий style.linewidth.Thick объявление. Это особенно важно в более сложные случаи, когда PyX определяет атрибуты по умолчанию для определенной операции. Когда вызывая соответствующие методы со списком атрибутов, этот список добавляется в список значений по умолчанию.Таким образом, пользователь может легко переопределить определенные значения по умолчанию, оставив другие значения по умолчанию нетронутыми. Кроме того, каждый Тип атрибута определяет специальный четкий атрибут, который позволяет выборочно удалить значение по умолчанию. Для обводки пути это выглядит как

 # следующие две строки эквивалентны
c.stroke (путь, [style.linewidth.Thick, style.linewidth.clear])
c.stroke (путь)
 

Атрибут clear также предоставляется базовыми классами различных стилей. Например, стиль .strokestyle.clear очищает все подклассы строкстайла то есть style.linewidth и style.linestyle . Поскольку все атрибуты являются производными от attr.attr , вы можете удалить все значения по умолчанию, используя аттр. Ясно . Обзор наиболее важных типов атрибутов, предоставленных PyX представлен в следующей таблице.

Категория атрибута

описание

примеры

дек.деко

декоратор, указывающий путь путь нарисован

дек. Штрихов , дек. Заполн. , дек. Стрелка , deco.text

style.strokestyle

стиль, используемый для обводки контура

style.linecap , style.linejoin , style.miterlimit , стиль. Дэш , стиль.лайнстайл , style.linewidth , цвет. Цвет

style.fillstyle

стиль, используемый для заполнения пути

цвет. Цвет , узор. Узор

style.filltype

тип заполнения пути

style.fillrule.nonzero_winding (По умолчанию), стиль.fillrule.even_odd

деформатор. Деформатор

операции изменения формы пути

деформер. Циклоида , деформер. Сглаженный

text.textattr

атрибуты, используемые для набора

text.halign , text.valign , text.mathmode , текст.фантом , текст. Размер , text.parbox

trafo.trafo

преобразований, примененных, когда объект рисования

trafo.mirror , trafo.rotate , trafo.scale , г. trafo.slant , г. trafo.translate

Todo

указывает, какие классы в таблице на самом деле являются экземплярами

Обратите внимание, что операции обычно допускают только определенные категории атрибутов.Для пример при обводке контура, текстовые атрибуты не допускаются, а обводка атрибуты и декораторы есть. Некоторые атрибуты могут принадлежать нескольким атрибутам категории, такие как цвета, которые являются атрибутами обводки и заливки.

Наконец, мы обсудим еще одну важную особенность системы атрибутов PyX. Чтобы чтобы обеспечить простую настройку предопределенных атрибутов, можно создать измененный атрибут путем вызова экземпляра атрибута, тем самым указание новых параметров. Типичный пример - изменить способ обведены или заполнены путем создания соответствующего декора .погладил или дек. Заполнено экземпляров. Например, код

 c.stroke (путь, [deco.filled ([color.rgb.green])])
 

рисует путь, залитый зеленым цветом с черным контуром. Здесь дек. Заполнено - это уже экземпляр, который изменен для заливки заданным цветом. Обратите внимание, что эквивалентная версия будет

 c.draw (путь, [deco.stroked, deco.filled ([color.rgb.green])])
 

В частности, вы можете видеть, что deco.stroked уже является атрибутом например, поскольку в противном случае вам не разрешалось передавать его в качестве параметра в метод рисования.Еще один пример, когда полезна модификация декоратора стрелки. Например, следующий код рисует наконечник стрелки с дополнительным острый угол (по сравнению со значением по умолчанию \ (45 \) градусов):

 c.stroke (path, [deco.earrow (angle = 30)])
 

Todo

изменяемые атрибуты

PostScript

PostScript


Что такое PostScript и как его создать? PostScript - это стековый язык, используемый многими принтерами.Принтеры имеют встроенные компьютеры, которые переводят язык PostScript в печатную продукцию. А Программа PostScript - это текстовый файл (как и программа на C ++). Вы напишете C ++ программа, создающая программу PostScript! Используйте операторы cout для распечатайте программу PostScript на экране. Затем используйте перенаправление, чтобы вывести его на файл, например "htree> picture.ps".

Есть ли хорошие ссылки на PostScript? Да, отъезд А Первое руководство по PostScript.Для тех из вас, кто хотел бы иметь больше подробности, PostScript Справочное руководство по языку предоставляет почти полную документацию.

Как просмотреть и распечатать файл PostScript? Чтобы напечатать Файл PostScript с именем picture.ps, используйте команду Unix "lpr picture.ps ". Принтер поймет, что это программа PostScript, не просто обычный текстовый файл. Перед печатью убедитесь, что ваш PostScript программа исправно работает при просмотре. Команда Unix "gs picture.пс " "скомпилирует" программу и настроит X-окно для ее просмотра. Вы не можете сделать это через сеанс Telnet.

Как просмотреть и распечатать файл PostScript на ПК или Mac? Вы можно загрузить AFPL Ghostscript и программу просмотра PostScript GSview через http://www.cs.wisc.edu/~ghost

Как добавить комментарии в мою программу PostScript? % в PostScript аналогичен // в C ++. Увидев%, остальная часть строки игнорируется.Есть одно исключение - первая строка Программа PostScript должна начинаться с% !.

Не могли бы вы описать команды PostScript для рисования графики? Здесь являются одними из самых распространенных.

  • %! каждая программа PostScript начинается с этих двух символов
  • x y moveto перемещает черепаху в (x, y) без рисования - это начинает новый путь.
  • u v rmoveto если текущая точка (x, y), изменить текущую точку на (x + u, y + v) ничего не рисуя - это запускает новый подпуть.
  • x y linto перемещает черепаху из текущей точки в (x, y), добавляя отрезок прямой к текущему пути.
  • u v rlin to , если текущая точка (x, y), переместите черепаху в (x + u, y + v) и добавьте к пути отрезок прямой.
  • closepath добавляет отрезок прямой, соединяющий текущую точку к начальной точке текущего пути (обычно к самой последней точке указанный в moveto), тем самым "закрывая" текущий путь.В следующий фрагмент PostScript строит путь в форме треугольника.
     256 0 переместить на 512 512 строк на 0 512 строк на закрытый путь
     
  • штрих рисует линию (некоторой толщины) вокруг текущего пути. Обратите внимание, что обводка уничтожает текущий путь, поэтому, чтобы начать рисовать новый путь после штриха вам нужно использовать команду типа moveto установить новый текущий путь. Следующий фрагмент PostScript рисует треугольник.
     256 0 переместить до 512 512 линий до 0 512 линий до хода с близкой траекторией
     
  • fill закрашивает всю область, ограниченную текущим путем (используя текущий цвет). Как и обводка, заливка съедает текущую дорожка. Следующий фрагмент PostScript рисует закрашенный ромб.
     256 0 переместить
    512 256 линето
    256 512 линето
      0 256 линето
    256 0 строк для заполнения
     
  • showpage выводит страницу из принтера.
  • x y w h прямоугольник нарисуйте прямоугольник шириной w, высотой h и ниже левая конечная точка (x, y).
  • x y w h rectfill начертите сплошной прямоугольник шириной w, высотой h и нижняя левая конечная точка (x, y).
  • x setlinewidth изменить толщину линии по умолчанию, используемую штрихом, на Икс.
  • x setgray изменяет цвет пера на оттенок серого x, где x находится между 0 и 1 (0 = черный, 1 = белый).
  • r g b setrgbcolor изменяет цвет пера черепахи на красно-зелено-синий color (r, g, b), где r, g, b - значения от 0 до 1.
  • h s b sethsbcolor изменяет цвет пера черепахи на цветовой тон-насыщенность-яркость (h, s, b), где h, s, b - значения между 0 и 1.
  • d повернуть изменяет ориентацию черепахи d градусов против часовой стрелки. Предупреждение: любые команды рисования (включая moveto) теперь по отношению к новой ориентации.Следующий PostScript фрагмент рисует пятиугольник.
     128 128 переместить
    256 0 rlinto 72 повернуть
    256 0 rlinto 72 повернуть
    256 0 rlinto 72 повернуть
    256 0 rlinto 72 повернуть
    256 0 rlinto 72 повернуть
    Инсульт
     
    Последний "72 оборота" не влияет на прорисовку пятиугольник, но это гарантирует, что ориентация черепахи после рисования пятиугольник идентичен тому, когда он был запущен (чистое изменение на 360 градусов).
  • Масштаб a b масштабирует (умножает) все координаты x на a и все y-координаты на b. Нормально иметь отрицательный результат a или b.
  • x y перевести изменить исходную точку в (x, y) - 50 50 перевести часто используется для предотвращения отрисовки чего-либо в самом нижнем левом углу поле страницы
  • x1 y1 x2 y2 x3 y3 curveto добавляет кривую Безье к текущему путь от текущей точки, скажем (x, y), до (x3, y3) с использованием (x1, y1) и (x2, y2) как "кубические контрольные точки Безье"
  • x y r ang1 ang2 arc добавляет дугу окружности к текущему пути - дуга имеет радиус r, с центром в (x, y) и идет против часовой стрелки из ang1 градусов до ang2 градусов.Следующий фрагмент PostScript рисует диск радиуса 100 с центром в точке (256, 256).
     256 256 100 0 Заливка дуги 360
     
  • N {. . . } repeat повторяет операторы, разделенные фигурными скобками N раз
  • / любое имя {. . . } определяет любое имя как синоним операторы, ограниченные фигурными скобками. Следующее определяет функцию pt так что x y r pt впоследствии будет рисовать сплошной круг (в текущий цвет) с центром в точке (x, y) радиуса r.
     / pt {0 360 arc fill} def
     
  • Какая единица измерения используется в системе координат PostScript? Автор по умолчанию одна единица - 1/72 дюйма. На странице 8,5 x 11 левый нижний угол - это (0,0), а верхний правый угол - (612,792).

    Какие стандартные цвета в формате rgb? Красный, зеленый и синие - это (1,0,0), (0,1,0) и (0,0,1) соответственно. Черный - (0,0,0), белый есть (1,1,1).Голубой, пурпурный и желтый - это (0,1,1), (1,0,1) и (1,1,0), соответственно. Вот цвет палитра в PostScript.

    Как нарисовать один контур, имеющий несколько цветов? Вы не могу. Каждый путь в PostScript должен быть нарисован одного цвета. Значит тебе нужно разбейте свой путь на части и раскрасьте каждый по отдельности. Это может быть выполняется отдельными командами moveto и lineto. Если ты используя относительные координаты (например, с помощью rlineto), тогда вы можете не знать (или хотите вычислить), куда двигаться, чтобы начать следующий путь.В этом случае используйте команда currentpoint, чтобы поместить текущую точку в стек и используйте его, чтобы начать следующий путь. Ниже показан равносторонний треугольник в красный, зеленый и синий.

     0440 moveto
    1 0 0 setrgbcolor 512 0 rlinto текущая точка хода moveto -120 rotate
    0 1 0 setrgbcolor 512 0 rlinto текущая точка хода moveto -120 rotate
    0 0 1 setrgbcolor 512 0 rlinto штрих
     

    Как сделать простой PS

    Как сделать простой PS

    Это краткое руководство по простейшим командам PostScript.Ты можешь либо создайте файл PostScript вручную, используя любой текстовый редактор, либо другое скорее всего, вы напишете программу, которая выводит PostScript.

    Шаг первый - первая строка файла

    В верхней части вашего PostScript-файла должно быть написано:

    %! PS

    Это сообщает принтеру, что это файл PostScript, а не обычный текст. ПРИМЕЧАНИЕ: некоторые программы MS-DOS, которые создают файлы PostScript поместит контрольный символ перед %! PS символы. Это приводит к тому, что весь файл интерпретируется как простой текст. большинством принтеров на базе UNIX.Если у вас возникла проблема с печатью файла, сделанного программой MS-DOS проверьте, есть ли там символ control-D, и если да, удалите его. ПЕРВЫЙ символов принтер видит ДОЛЖЕН быть %! PS.


    Шаг второй - масштабирование страницы

    PostScript обычно использует единицы «точки» для размещения графики на страница. Мне удобнее работать с сантиметрами. Я получил следующий фрагмент кода PostScript из общедоступной программы под названием "GLE", который, как мне кажется, доступен на любом большом ftp-сайте; Я рекомендую эта графическая программа.Изучив вывод PostScript этого В программе я собрал следующий фрагмент кода PostScript:

    матрица currentmatrix / originmat exch def / umatrix {originmat matrix concatmatrix setmatrix} def [28.3465 0 0 28.3465 10,5 100,0] матрица

    По сути, это масштабирует страницу так, чтобы теперь все следующие команды будут работать так, как если бы сантиметр является основной единицей длины. Это поместит (0,0) в нижний левый угол страницы и (21,24) рядом с вверху справа на странице.

    Если вы этого не сделаете, то (0,0) будет нижним левым углом страницы и (612 792) - это верхний правый угол страницы (если вы используете 8 1/2 дюйм на лист бумаги 11 дюймов). Это единицы PostScript по умолчанию; 72 из них с точностью до дюйма. 28,3465 в сантиметр, поэтому числа выше в последней строке кода PostScript.


    Шаг третий - проведите линию

    Создание линий на странице состоит из нескольких частей. Первоначально вы устанавливаете ширина линии. Затем перейдите к началу строки; затем перейдите к различные точки, через которые должна быть проведена линия; затем установите цвет линии; наконец, скажите PostScript провести черту.

    Это сгенерирует код, похожий на следующий:

    0,1 комплект ширины линии 2 2 newpath moveto 3 3 линето 3 4 линето 2 4 линии 0 сет серый Инсульт

    Это дает картинку, которая выглядит следующим образом:

    Команды довольно понятны. Команда "штрих" на end - это то, что сообщает PostScript, что нужно нарисовать линию; без этого Команда PostScript ничего не печатает. (Это пригодится позже, если вы хотите создать фигуру и заполнить ее, но не рисовать контур.) Значок "0 setgray "указывает строку , черная, ; для белого в линиях используется «1 сетгрей», а в серых линиях используется число от 0 до 1.

    Каждая точка соединяется с предыдущей прямой линией, поэтому рисуйте изогнутые линии, вам нужно указать много точек на линии. Обычно я считаю, что указывать новые точки каждые 0,02 см или около того - это идеально. хорошо и будет создавать плавные кривые.

    Если вы хотите привязать последнюю точку к первой, используйте команду "closepath" в конце описания строки:

    0.1 комплект в ширину 2 2 newpath moveto 3 3 линето 3 4 линето 2 4 линии близкий путь 0 сет серый Инсульт


    Шаг четвертый - доработать файл

    Когда вы рисуете линию, она на самом деле не рисуется в PostScript помните, пока у вас не будет команды "штрих". Аналогично, страница PostScript фактически не печатается, пока вы не получите команду "showpage". Поместите это в конец вашего PostScript-файла.

    Таким образом, полный файл PostScript выглядит так:

    %! PS матрица currentmatrix / originmat exch def / umatrix {originmat matrix concatmatrix setmatrix} def [28.3465 0 0 28,3465 10,5 100,0] матрица 0,1 комплект ширины линии 2 2 newpath moveto 3 3 линето 3 4 линето 2 4 линии близкий путь 0 сет серый Инсульт showpage

    Щелкните здесь, если хотите получить копию этого PostScript файл.


    Шаг пятый - рисование множества линий

    Если вы хотите нарисовать на странице много линий, просто повторите приведенное выше процесс. Команда "newpath" сообщает PostScript, что вы начинаете новый линия.Если вы просто используете "moveto" без "newpath", он подумает, что вы рисование той же линии, хотя следующая точка на линии не подключен к последней точке. ("moveto" берет ручку и положить его в другое место; "lineto" перемещает перо, пока оно на странице.) Если вы не используете "newpath", вы можете использовать один Команда "stroke", чтобы нарисовать сразу все линии на вашей странице:

    0,1 комплект ширины линии 2 2 newpath moveto 3 3 линето 3 4 линето 2 4 линии 5 3 переместить 6 4 линето 7 2 переместить 8 4 линето 0 сет серый Инсульт

    Обычно вы хотите начинать каждую строку отдельно, поэтому обычно используйте "newpath moveto" каждый раз, когда вы начинаете новую строку.Это меньше важно, когда вы просто рисуете простые линии, но имеет более важное последствия, когда вы начинаете заполнять нарисованные полигоны. Обратите внимание, что команда "stroke" действует так же, как "newpath"; PostScript использует штрих, чтобы нарисовать линию, а затем забыть об этом.

    Если вы хотите, чтобы все линии были одного цвета, вы можете просто указать цвет один раз в самом начале файла.


    Шаг шестой - сжатие файла

    Чтобы уменьшить размер файла PostScript, вы, вероятно, захотите создать несколько простых одно- или двухбуквенных псевдонимов для некоторых общих команд.Например, если вы собираетесь сделать картинку с 300 000 мелких прямые линии (что-то, что я сделал для некоторых своих фотографий) гораздо проще использовать однобуквенные команды вместо того, чтобы говорить "новый путь moveto "300 000 раз.

    В верхней части вашего PostScript-файла после строки%! PS вы можете начать определение некоторых простых команд. Для рисования линий вам понадобится следующие команды:

    / m {newpath moveto} привязать def / l {lineto} bind def / cp {closepath} привязка def / s {stroke} bind def / sg {setgray} привязка def

    «Bind def» определяет псевдоним; фраза в {фигурных скобках} - это определение, а сам псевдоним - это буква (буквы), следующие за / символ.Таким образом, если вы используете "m" в своем PostScript-файле, это фактически означает "newpath moveto". Таким образом, окончательная версия файла PostScript будет выглядеть нравиться:

    %! PS / m {newpath moveto} привязать def / l {lineto} bind def / cp {closepath} привязка def / s {stroke} bind def / sg {setgray} привязка def матрица currentmatrix / originmat exch def / umatrix {originmat matrix concatmatrix setmatrix} def [28.3465 0 0 28.3465 10,5 100,0] матрица 0,1 комплект ширины линии 2 2 мес. 3 3 л 3 4 л 2 4 л cp 0 сг s showpage

    Щелкните здесь, если хотите получить копию этого PostScript файл.


    Заключительные слова мудрости

    Как и большинство компьютерных языков сегодня, PostScript не волнует, что вы делаете. с пробелами (пробелы, новые строки, пустые строки, табуляции и т. д.). Положи их как хотите.

    В общем, нет причин не изменять масштаб страницы каждые когда вы создаете новый файл PostScript, а также создание псевдонимы. Я просто копирую один и тот же фрагмент кода PostScript в каждый C пишу программу, которая должна выводить PostScript.

    Если вы посмотрите некоторые из моих программ, вы можете увидеть кое-что еще на начало и конец файла; это лишнее и ненужный (но не вызывает никаких проблем). Итак, если вы видите примеры в некоторые из моих программ, которые немного отличаются от того, что я объяснил выше, не паникуйте; Я ничего не упустил из вышеперечисленного объяснение.

    Технически, я полагаю, что псевдонимы на самом деле называются процедурой. определения ».

    Вы сейчас в хорошей форме; вы можете многое сделать, просто рисуя линии! Если вы хотите узнать больше, нажмите "Дополнительные команды PostScript" ниже, чтобы больше информации о простых командах PostScript: использование цвета, рисование круги, заполняющие нарисованные вами фигуры.

    Дополнительные команды PostScript

    Ссылки ...


    Текущий адрес:
    Эрик Р. Уикс,
    недели (кружок a) Physics.emory.edu
    , Физический факультет
    Университет Эмори,
    Атланта, Джорджия, 30322-2430,
    ,
    .

    # ---------------------------------------------- ------------------------------- # Copyright (c) 2017, Николя П. Ружье. Все права защищены. # # Распространение и использование в исходной и двоичной формах, с или без # модификация, разрешены при соблюдении следующих условий: # №1.При повторном распространении исходного кода должно сохраняться указанное выше уведомление об авторских правах, это # список условий и следующий отказ от ответственности. # 2. При повторном распространении в двоичной форме должно воспроизводиться указанное выше уведомление об авторских правах, # этот список условий и следующий отказ от ответственности в документации # и / или другие материалы, поставляемые с распространением. # # ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ ВЛАДЕЛЬЦАМИ АВТОРСКИХ ПРАВ И СОСТАВЛЯМИ «КАК ЕСТЬ» И # ЛЮБЫЕ ЯВНЫЕ ИЛИ ПОДРАЗУМЕВАЕМЫЕ ГАРАНТИИ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАясь, ПОДРАЗУМЕВАЕМЫЕ # ГАРАНТИИ КОММЕРЧЕСКОЙ ЦЕННОСТИ И ПРИГОДНОСТИ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ ЯВЛЯЮТСЯ # ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ.НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ ВЛАДЕЛЕЦ АВТОРСКИХ ПРАВ ИЛИ СОСТАВНИКИ НЕ НЕСЕТ ОТВЕТСТВЕННОСТИ ЗА # ЛЮБЫЕ ПРЯМЫЕ, КОСВЕННЫЕ, СЛУЧАЙНЫЕ, ОСОБЫЕ, ПРИМЕРНЫЕ ИЛИ КОСВЕННЫЕ УБЫТКИ # (ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ЗАКУПКИ ТОВАРОВ ИЛИ УСЛУГ ЗАМЕНЫ; # ПОТЕРЯ ИСПОЛЬЗОВАНИЯ, ДАННЫХ ИЛИ ПРИБЫЛИ; ИЛИ ПЕРЕРЫВ ДЕЯТЕЛЬНОСТИ) ОДНАКО ВЫЗВАННЫ # ПО ЛЮБОМУ ТЕОРИИ ОТВЕТСТВЕННОСТИ, ЛИБО ПО ДОГОВОРУ, СТРОГОЙ ОТВЕТСТВЕННОСТИ ИЛИ ИНОСТРАННОСТИ # (ВКЛЮЧАЯ НЕБРЕЖНОСТЬ ИЛИ ИНОЕ), ВОЗНИКАЮЩИЕ ЛЮБОЙ СПОСОБОМ ИСПОЛЬЗОВАНИЯ ЭТОГО # ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ, ДАЖЕ ПРИ СООБЩЕНИИ О ВОЗМОЖНОСТИ ТАКОГО ПОВРЕЖДЕНИЯ.# ------------------------------------------------- ---------------------------- импорт ре импорт Безье импортировать numpy как np из lxml import etree from matplotlib.path Путь импорта MOVETO = 1 LINETO = 2 КРИВАЯ4 = 3 КРИВАЯ3 = 4 ЗАКРЫТЬ = 5 def get (имя файла, имя): "" " Прочитать заданный элемент из файла SVG "" " корень = etree.parse (имя файла) .getroot () return root.xpath ("// * [@ id = '% s']"% name) [0] .get ("d") def путь (имя файла, имя): "" " Чтение и преобразование команды пути SVG в представление пути "" " путь = получить (имя файла, имя) verts, codes = convert (путь) вершины, коды = мозаика (вершины, коды) вернуть верты, коды def convert (путь): "" " Анализируйте и преобразуйте команду пути SVG в представление пути Параметры ---------- путь: строка Допустимая команда пути SVG "" " # Сначала разделяем токены внутри пути токены = [] КОМАНДЫ = набор ('MmZzLlHhVvCcSsQqTtAa') COMMAND_RE = re.компилировать ("([MmZzLlHhVvCcSsQqTtAa])") FLOAT_RE = re.compile ("[- +]? [0-9] * \.? [0-9] + (?: [EE] [- +]? [0-9] +)?") для x в COMMAND_RE.split (путь): если x в КОМАНДАХ: tokens.append (x) для токена в FLOAT_RE.findall (x): tokens.append (float (токен)) # Затем обрабатываем и конвертируем команды # (Обратите внимание, что не все команды были реализованы) commands = {'M': [MOVETO, 2], 'm': [MOVETO, 2], 'L': [LINETO, 2], 'l': [LINETO, 2], # 'V': [Путь.ЛИНЕТО, 1], # 'v': [Path.LINETO, 1], # 'H': [Path.LINETO, 1], # 'h': [Path.LINETO, 1], 'C': [CURVE4, 6], 'c': [CURVE4, 6], # 'S': [Path.CURVE4, 4], # 's': [Path.CURVE4, 4], 'Q': [CURVE3, 4], 'q': [КРИВАЯ3, 4], # 'T': [Path.CURVE3, 2], # 't': [Path.CURVE3, 2], # 'A': [Нет, 7], # 'a': [Нет, 7], 'Z': [ЗАКРЫТЬ, 0], 'z': [ЗАКРЫТЬ, 0]} индекс = 0 коды, verts = [], [] last_vertice = np.массив ([[0, 0]]) а индекс 0: vertices = np.array (tokens [index: index + n]). reshape (n // 2,2) если last_command.islower (): вершины + = last_vertice last_vertice = вершины [-1] коды.extend ([код,] * len (вершины)) verts.extend (vertices.tolist ()) индекс + = n еще: code.append (код) verts.append (last_vertice.tolist ()) # 'M / m' следует за несколькими вершинами означает неявное 'L / l' для # последующие вершины если last_command == 'm': last_command, code = 'l', ЛИНЕТО elif last_command == 'M': last_command, code = 'L', ЛИНЕТО вернуть нп.массив (верт.), коды def tesselate (верты, коды): "" " Создайте мозаику для пути matplotlib с заданными вершинами и кодами. Параметры ---------- вершины: array_like Массив с плавающей запятой `` (n, 2) '' или последовательность пар, представляющих вершины пути. коды: array_like Целые числа массива длиной n, представляющие коды пути. "" " tesselated_verts = [] tesselated_codes = [] индекс = 0 в то время как индекс

    Рисование точек и линий

    Рисование точек и линий

    В первой главе я обсуждал, как интерфейс графических устройств Windows использует драйверы устройств для устройств вывода графики, подключенных к вашему компьютеру.Теоретически все, что требуется драйверу графического устройства для рисования, - это функция SetPixel и функция GetPixel . Все остальное можно было обрабатывать с помощью подпрограмм более высокого уровня, реализованных в модуле GDI. Для рисования линии, например, просто требуется, чтобы GDI многократно вызывал подпрограмму SetPixel , корректируя координаты x и y соответствующим образом.

    На самом деле вы действительно можете сделать практически любой рисунок, который вам нужен, используя только функции SetPixel и GetPixel .Вы также можете создать аккуратную и хорошо структурированную систему программирования графики поверх этих функций. Единственная проблема - производительность. Функция, которая находится на расстоянии нескольких вызовов от каждой функции SetPixel , будет очень медленной. Для графической системы гораздо эффективнее выполнять рисование линий и другие сложные графические операции на уровне драйвера устройства, который может иметь собственный оптимизированный код для выполнения операций. Более того, некоторые платы видеоадаптеров содержат графические сопроцессоры, которые позволяют самому видеооборудованию рисовать цифры.

    Настройка пикселей

    Несмотря на то, что Windows GPI включает функции SetPixel и GetPixel , они обычно не используются. В этой книге функция SetPixel используется только в программе CONNECT в главе 7, а функция GetPixel используется только в программе WHATCLR в главе 8. Тем не менее, они предоставляют удобное место для начала изучения графики. .

    Функция SetPixel устанавливает пиксель с заданными координатами x и y для определенного цвета:

    SetPixel (hdc, x, y, crColor);
     

    Как и в любой функции рисования, первый аргумент - это дескриптор контекста устройства.Второй и третий аргументы указывают положение координат. В основном вы получите контекст устройства для клиентской области вашего окна, а x и y будут относиться к левому верхнему углу этой клиентской области. Последний аргумент имеет тип COLORREF, чтобы указать цвет. Если цвет, который вы указываете в функции, не может быть реализован на видеодисплее, функция устанавливает для пикселя ближайший чистый цвет без сэмплирования и возвращает это значение из функции.

    Функция GetPixel возвращает цвет пикселя в указанной координатной позиции:

    crColor = GetPixel (hdc, x, y);
     

    Прямые линии

    Windows может рисовать прямые, эллиптические линии (изогнутые линии на окружности эллипса) и сплайны Безье.Windows 98 поддерживает семь функций рисования линий:

    • LineTo Рисует прямую линию.
    • Polyline and PolylineTo Нарисуйте серию соединенных прямых линий.
    • PolyPolyline Рисует несколько полилиний.
    • Дуга Рисует эллиптические линии.
    • PolyBezier и PolyBezierTo Рисуют сплайны Безье.

    Кроме того, Windows NT поддерживает еще три функции рисования линий:

    • ArcTo и AngleArc Нарисуйте эллиптические линии.
    • PolyDraw Рисует серию соединенных прямых линий и сплайнов Безье.

    Эти три функции не поддерживаются в Windows 98.

    Позже в этой главе я также буду обсуждать некоторые функции, которые рисуют линии, но также заполняют замкнутую область внутри нарисованной ими фигуры. Эти функции

    • Прямоугольник Рисует прямоугольник.
    • Эллипс Рисует эллипс.
    • RoundRect Рисует прямоугольник со скругленными углами.
    • Pie Рисует часть эллипса, которая выглядит как кусок пирога.
    • Хорда Рисует часть эллипса, образованного хордой.

    Пять атрибутов контекста устройства влияют на внешний вид линий, которые вы рисуете с помощью этих функций: текущее положение пера (только для LineTo , PolylineTo , PolyBezierTo и ArcTo ), перо, фоновый режим, цвет фона и режим рисования.

    Чтобы нарисовать прямую линию, необходимо вызвать две функции. Первая функция указывает точку, в которой начинается линия, а вторая функция определяет конечную точку линии:

    MoveToEx (hdc, xBeg, yBeg, NULL);
    LineTo (hdc, xEnd, yEnd);
     

    MoveToEx на самом деле ничего не рисует; вместо этого он устанавливает атрибут контекста устройства, известный как «текущая позиция». Затем функция LineTo рисует прямую линию от текущей позиции до точки, указанной в функции LineTo .Текущая позиция - это просто отправная точка для нескольких других функций GDI. В контексте устройства по умолчанию текущая позиция изначально установлена ​​в точку (0, 0). Если вы вызываете LineTo без предварительной установки текущей позиции, он рисует линию, начинающуюся в верхнем левом углу клиентской области.

    Краткое историческое примечание: в 16-битных версиях Windows функция установки текущей позиции была MoveTo . У этой функции было всего три аргумента - дескриптор контекста устройства и координаты x и y.Функция вернула предыдущую текущую позицию, упакованную как два 16-битных значения в 32-битную длину без знака. Однако в 32-битных версиях Windows координаты являются 32-битными значениями. Поскольку 32-битные версии C не определяют 64-битный интегральный тип данных, это изменение означало, что MoveTo больше не мог указывать предыдущую текущую позицию в своем возвращаемом значении. Хотя возвращаемое значение MoveTo почти никогда не использовалось в реальном программировании, потребовалась новая функция, и это была MoveToEx .

    Последний аргумент MoveToEx - это указатель на структуру POINT. При возврате из функции поля x и y структуры POINT укажут предыдущую текущую позицию. Если вам не нужна эта информация (что почти всегда так), вы можете просто установить последний аргумент в NULL, как в примере, показанном выше.

    А теперь предостережение: хотя значения координат в Windows 98 кажутся 32-битными значениями, используются только младшие 16 бит.Значения координат фактически ограничены от -32 768 до 32 767. В Windows NT используются полные 32-битные значения.

    Если вам когда-нибудь понадобится текущая позиция, вы можете получить ее, позвонив по телефону

    GetCurrentPositionEx (HDC, & pt);
     

    , где pt - структура ТОЧКИ.

    Следующий код рисует сетку в клиентской области окна, разделяя линии на 100 пикселей, начиная с левого верхнего угла.Предполагается, что переменная hwnd является дескриптором окна, hdc - дескриптором контекста устройства, а x и y - целые числа:

    GetClientRect (hwnd, & rect);
    для (x = 0; x 
    
     

    Хотя кажется неприятным быть вынужденным использовать две функции для рисования одной линии, текущая позиция удобна, когда вы хотите нарисовать серию соединенных линий. Например, вы можете определить массив из 5 точек (10 значений), которые определяют контур прямоугольника:

    ТОЧКА apt [5] = {100, 100, 200, 100, 200, 200, 100, 200, 100, 100};
     

    Обратите внимание, что последняя точка совпадает с первой.Теперь вам нужно использовать только MoveToEx для первой точки и LineTo для последующих точек:

    MoveToEx (hdc, apt [0] .x, apt [0] .y, NULL);
    
    для (я = 1; я <5; я ++)
         LineTo (hdc, apt [i] .x, apt [i] .y);
     

    Поскольку LineTo рисует от текущей позиции до (но не включая) точки в функции LineTo , никакие координаты не записываются дважды этим кодом. Хотя перезапись точек не является проблемой для видеодисплея, она может плохо выглядеть на плоттере или в некоторых режимах рисования, которые я расскажу позже в этой главе.

    Если у вас есть массив точек, которые вы хотите соединить линиями, вы можете проще рисовать линии с помощью функции Полилиния . Этот оператор рисует тот же прямоугольник, что и в приведенном выше коде:

    Ломаная линия (hdc, apt, 5);
     

    Последний аргумент - количество баллов. Мы также могли бы представить это значение как sizeof (apt) / sizeof (POINT) . Полилиния оказывает такое же влияние на рисование, что и исходный MoveToEx , за которым следует несколько функций LineTo .Однако полилиния не использует и не изменяет текущую позицию. PolylineTo немного отличается. Эта функция использует текущую позицию в качестве начальной точки и устанавливает текущую позицию в конец последней нарисованной линии. Приведенный ниже код рисует тот же прямоугольник, что и последний, показанный выше:

    MoveToEx (hdc, apt [0] .x, apt [0] .y, NULL);
    PolylineTo (hdc, apt + 1, 4);
     

    Хотя вы можете использовать Polyline и PolylineTo , чтобы нарисовать всего несколько линий, эти функции наиболее полезны, когда вам нужно нарисовать сложную кривую.Вы делаете это, используя сотни или даже тысячи очень коротких строк. Если они достаточно короткие и их достаточно, вместе они будут выглядеть кривой. Например, предположим, что вам нужно нарисовать синусоидальную волну. Программа SINEWAVE на рис. 5-6 показывает, как это сделать.

    Рисунок 5-6. Программа SINEWAVE.

    SINEWAVE.C

    / * -----------------------------------------
       SINEWAVE.C - Синусоидальная волна с использованием ломаной линии
                     (c) Чарльз Петцольд, 1998 г.
      ----------------------------------------- * /
    
    #include 
    #include 
    
    #define NUM 1000
    #define TWOPI (2 * 3,14159)
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)
    {
         статический TCHAR szAppName [] = ТЕКСТ ("SineWave");
         HWND hwnd;
         MSG msg;
         WNDCLASS wndclass;
         
         wndclass.style = CS_HREDRAW | CS_VREDRAW;
         wndclass.lpfnWndProc = WndProc;
         wndclass.cbClsExtra = 0;
         wndclass.cbWndExtra = 0;
         wndclass.hInstance = hInstance;
         wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
         wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
         wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
         wndclass.lpszMenuName = NULL;
         wndclass.lpszClassName = szAppName;
              
         если (! RegisterClass (& wndclass))
         {
              MessageBox (NULL, TEXT («Программа требует Windows NT!»),
                          szAppName, MB_ICONERROR);
              возврат 0;
         }
         
         hwnd = CreateWindow (szAppName, TEXT («Синусоидальная волна с использованием ломаной линии»),
                              WS_OVERLAPPEDWINDOW,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              NULL, NULL, hInstance, NULL);
    
         ShowWindow (hwnd, iCmdShow);
         UpdateWindow (hwnd);
         
         while (GetMessage (& msg, NULL, 0, 0))
         {
              TranslateMessage (& сообщение);
              DispatchMessage (& сообщение);
         }
         вернуть сообщение.wParam;
    }
    
    LRESULT CALLBACK WndProc (HWND hwnd, сообщение UINT, WPARAM wParam, LPARAM lParam)
    {
         статический int cxClient, cyClient;
         HDC hdc;
         int i;
         PAINTSTRUCT ps;
         POINT apt [NUM];
         
         переключатель (сообщение)
         {
         case WM_SIZE:
              cxClient = LOWORD (lParam);
              cyClient = HIWORD (lParam);
              возврат 0;
              
         case WM_PAINT:
              hdc = BeginPaint (hwnd, & ps);
              
              MoveToEx (hdc, 0, cyClient / 2, NULL);
              LineTo (hdc, cxClient, cyClient / 2);
              
              для (я = 0; я <ЧИСЛО; я ++)
              {
                   кв [я].х = я * cxClient / ЧИСЛО;
                   apt [i] .y = (int) (cyClient / 2 * (1 - sin (TWOPI * i / NUM)));
              }
              
              Ломаная линия (hdc, apt, NUM);
              возврат 0;
              
         case WM_DESTROY:
              PostQuitMessage (0);
              возврат 0;
         }
         вернуть DefWindowProc (hwnd, message, wParam, lParam);
    }
     

    Программа имеет массив из 1000 структур POINT. Поскольку цикл для увеличивается с 0 до 999, поля x структуры POINT устанавливаются на постепенное увеличение значений от 0 до cxClient .Программа устанавливает для полей и структуры POINT значения синусоидальной кривой для одного цикла и увеличенные, чтобы заполнить клиентскую область. Вся кривая строится с помощью одного вызова Polyline . Поскольку функция Polyline реализована на уровне драйвера устройства, она выполняется быстрее, чем вызов LineTo 1000 раз. Результаты показаны на Рисунке 5-7.

    Рисунок 5-7. Дисплей SINEWAVE.

    Функции ограничивающей рамки

    Далее я хочу обсудить функцию Arc , которая рисует эллиптическую кривую.Однако функция Arc не имеет особого смысла без предварительного обсуждения функции Ellipse , а функция Ellipse не имеет особого смысла без предварительного обсуждения функции Rectangle , и если я обсуждаю Ellipse и Rectangle , я мог бы также обсудить RoundRect , Chord и Pie .

    Проблема в том, что функции Rectangle , Ellipse , RoundRect , Chord и Pie не являются строго функциями рисования линий.Да, функции рисуют линии, но они также заполняют замкнутую область текущей кистью для заполнения области. По умолчанию эта кисть сплошного белого цвета, поэтому может быть неочевидно, что эти функции делают больше, чем просто рисуют линии, когда вы впервые начинаете экспериментировать с ними. Эти функции действительно относятся к более позднему разделу «Рисование заполненных областей», но я все равно буду обсуждать их здесь.

    Функции, которые я перечислил выше, схожи в том, что они построены из прямоугольного ограничивающего прямоугольника.«Вы определяете координаты прямоугольника, охватывающего объект - ограничивающего прямоугольника - и Windows рисует объект внутри этого прямоугольника.

    Самая простая из этих функций рисует прямоугольник:

    Прямоугольник (hdc, xLeft, yTop, xRight, yBottom);
     

    Точка ( xLeft , yTop ) - это верхний левый угол прямоугольника, а ( xRight , yBottom ) - нижний правый угол. Рисунок, построенный с использованием функции Rectangle , показан на рисунке 5-8.Стороны прямоугольника всегда параллельны горизонтальной и вертикальной сторонам дисплея.

    Рисунок 5-8. Фигура, нарисованная с помощью функции Прямоугольник .

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

    Рассмотрим вызов функции

    Прямоугольник (HDC, 1, 1, 5, 4);
     

    Я упоминал выше, что Windows рисует фигуру в «ограничивающей рамке». Вы можете думать об отображении как о сетке, где каждый пиксель находится внутри ячейки сетки. На сетке рисуется воображаемый ограничивающий прямоугольник, а затем внутри этого ограничивающего прямоугольника рисуется прямоугольник. Вот как будет нарисована фигура:

    Область, разделяющая прямоугольник сверху и слева от клиентской области, имеет ширину 1 пиксель.

    Как я упоминал ранее, Прямоугольник - это не просто функция рисования линий. GDI также заполняет замкнутую область. Однако, поскольку по умолчанию область заполнена белым, может быть не сразу очевидно, что GDI заполняет область.

    Как только вы научитесь рисовать прямоугольник, вы также научитесь рисовать эллипс, потому что он использует те же аргументы:

    Эллипс (hdc, xLeft, yTop, xRight, yBottom);
     

    Фигура, нарисованная с использованием функции Ellipse , показана (с воображаемой ограничивающей рамкой) на рисунке 5-9.

    Рисунок 5-9. Рисунок, нарисованный с помощью функции Ellipse .

    Функция рисования прямоугольников со скругленными углами использует ту же ограничивающую рамку, что и функции Rectangle и Ellipse , но включает еще два аргумента:

    RoundRect (hdc, xLeft, yTop, xRight, yBottom,
               xCornerEllipse, yCornerEllipse);
     

    Рисунок, построенный с использованием этой функции, показан на Рисунке 5-10.

    Рисунок 5-10. Рисунок, нарисованный с помощью функции RoundRect .

    Windows использует маленький эллипс для рисования закругленных углов. Ширина этого эллипса составляет xCornerEllipse , а высота - yCornerEllipse . Представьте себе, что Windows разбивает этот маленький эллипс на четыре квадранта и использует по одному квадранту для каждого из четырех углов. Закругление углов более заметно при больших значениях xCornerEllipse и yCornerEllipse .Если xCornerEllipse равно разнице между xLeft и xRight , а yCornerEllipse равно разнице между yTop и yBottom , тогда функция RoundRect будет рисовать функцию ellipse .

    Прямоугольник с закругленными углами на рис. 5-10 был нарисован с использованием размеров углового эллипса, рассчитанных по формулам ниже.

    xCornerEllipse = (xRight - xLeft) / 4;
    yCornerEllipse = (yBottom- yTop) / 4;
     

    Это простой подход, но результаты, по общему признанию, выглядят не совсем правильными, потому что закругление углов более выражено вдоль большего размера прямоугольника.Чтобы решить эту проблему, вы, вероятно, захотите сделать xCornerEllipse равным yCornerEllipse в реальных размерах.

    Функции Arc , Chord и Pie принимают одинаковые аргументы:

    Arc (hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);
    Аккорд (hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);
    Круговая диаграмма (hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);
     

    Линия, нарисованная с использованием функции Arc , показана на рисунке 5-11; Рисунки, построенные с использованием функций Chord и Pie , показаны на рисунках 5-12 и 5-13.Windows использует воображаемую линию для соединения ( xStart , yStart ) с центром эллипса. В точке, в которой эта линия пересекает эллипс, Windows начинает рисовать дугу против часовой стрелки по окружности эллипса. Windows также использует воображаемую линию для соединения ( xEnd , yEnd ) с центром эллипса. В точке, в которой эта линия пересекает эллипс, Windows прекращает рисовать дугу.

    Рисунок 5-11. Линия, нарисованная с использованием функции Arc .

    Рисунок 5-12. Рисунок, нарисованный с использованием функции Chord .

    Рисунок 5-13. Рисунок, нарисованный с помощью функции Pie .

    Для функции Arc Windows завершена, поскольку дуга представляет собой эллиптическую линию, а не заполненную область. Для функции Chord Windows соединяет конечные точки дуги.Для функции Pie Windows соединяет каждую конечную точку дуги с центром эллипса. Внутренние части фигурок аккорда и кругового клина заполняются текущей кистью.

    Вы можете задаться вопросом об использовании начальной и конечной позиций в функциях Arc , Chord и Pie . Почему бы просто не указать начальную и конечную точки на окружности эллипса? Что ж, вы можете, но вам нужно выяснить, что это за точки.Метод Windows выполняет свою работу, не требуя такой точности.

    Программа LINEDEMO, показанная на рис. 5-14, рисует прямоугольник, эллипс, прямоугольник со скругленными углами и две линии, но не в таком порядке. Программа демонстрирует, что эти функции, определяющие закрытые области, действительно заполняют их, потому что линии скрыты за эллипсом. Результаты показаны на Рисунке 5-15.

    Рисунок 5-14. Программа LINEDEMO.

    LINEDEMO.C

     / * ----------------------------------------------- ---
       LINEDEMO.C - Демонстрационная программа рисования линий
                     (c) Чарльз Петцольд, 1998 г.
      -------------------------------------------------- * /
    
    #include 
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)
    {
         статический TCHAR szAppName [] = ТЕКСТ ("LineDemo");
         HWND hwnd;
         MSG msg;
         WNDCLASS wndclass;
         
         wndclass.style = CS_HREDRAW | CS_VREDRAW;
         wndclass.lpfnWndProc = WndProc;
         wndclass.cbClsExtra = 0;
         wndclass.cbWndExtra = 0;
         wndclass.hInstance = hInstance;
         wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
         wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
         wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
         wndclass.lpszMenuName = NULL;
         wndclass.lpszClassName = szAppName;
         
         если (! RegisterClass (& wndclass))
         {
              MessageBox (NULL, TEXT («Программа требует Windows NT!»),
                          szAppName, MB_ICONERROR);
              возврат 0;
         }
         
         hwnd = CreateWindow (szAppName, TEXT («Демонстрация строки»),
                              WS_OVERLAPPEDWINDOW,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              NULL, NULL, hInstance, NULL);
         
         ShowWindow (hwnd, iCmdShow);
         UpdateWindow (hwnd);
         
         while (GetMessage (& msg, NULL, 0, 0))
         {
              TranslateMessage (& сообщение);
              DispatchMessage (& сообщение);
         }
         вернуть сообщение.wParam;
    }
    
    LRESULT CALLBACK WndProc (HWND hwnd, сообщение UINT, WPARAM wParam, LPARAM lParam)
    {
         статический int cxClient, cyClient;
         HDC hdc;
         PAINTSTRUCT ps;
         
         переключатель (сообщение)
         {
         case WM_SIZE:
              cxClient = LOWORD (lParam);
              cyClient = HIWORD (lParam);
              возврат 0;
              
         case WM_PAINT:
              hdc = BeginPaint (hwnd, & ps);
              
              Прямоугольник (hdc, cxClient / 8, cyClient / 8,
                         7 * cxClient / 8, 7 * cyClient / 8);
              
              MoveToEx (hdc, 0, 0, NULL);
              LineTo (hdc, cxClient, cyClient);
              
              MoveToEx (hdc, 0, cyClient, NULL);
              LineTo (hdc, cxClient, 0);
              
              Эллипс (hdc, cxClient / 8, cyClient / 8,
                         7 * cxClient / 8, 7 * cyClient / 8);
              
              RoundRect (HDC, cxClient / 4, cyClient / 4,
                         3 * cxClient / 4, 3 * cyClient / 4,
                             cxClient / 4, cyClient / 4);
              
              EndPaint (hwnd, & ps);
              возврат 0;
              
         case WM_DESTROY:
              PostQuitMessage (0);
              возврат 0;
         }
         вернуть DefWindowProc (hwnd, message, wParam, lParam);
    }
     

    Рисунок 5-15. Дисплей LINEDEMO.

    Сплайны Безье

    Слово «шлиц» когда-то относилось к куску гибкого дерева, резины или металла, который использовался для рисования кривых на листе бумаги. Например, если у вас есть несколько разрозненных точек графика и вы хотите провести кривую между ними (для интерполяции или экстраполяции), вы сначала отметите точки на миллиметровой бумаге. Затем вы прикрепляете сплайн к точкам и карандашом рисуете кривую вдоль сплайна, изгибающегося вокруг точек.

    В наше время, конечно же, сплайны - это математические формулы. Они бывают разных видов, но сплайн Безье стал наиболее популярным в программировании компьютерной графики. Это сравнительно недавнее дополнение к арсеналу графических инструментов, доступных на уровне операционной системы, и его источник маловероятен: в 1960-х годах автомобильная компания Renault отказалась от ручного проектирования кузовов автомобилей (в котором использовалась глина). к компьютерному дизайну. Требовались математические инструменты, и Пьер Безье придумал набор формул, которые оказались полезными для этой работы.

    С тех пор двумерная форма сплайна Безье зарекомендовала себя как наиболее полезная кривая (после прямой линии и эллипса) для компьютерной графики. В PostScript сплайн Безье используется для всех кривых - даже эллиптические линии аппроксимируются по Безье. Кривые Безье также используются для определения контуров символов шрифтов PostScript. (TrueType использует более простую и быструю форму сплайна.)

    Одиночный двумерный сплайн Безье определяется четырьмя точками - двумя конечными точками и двумя контрольными точками.Концы кривой закреплены в двух конечных точках. Контрольные точки действуют как «магниты», отводя кривую от прямой линии между двумя конечными точками. Лучше всего это проиллюстрировано интерактивной программой BEZIER, показанной на Рисунке 5-16.

    Рисунок 5-16. Программа BEZIER.

    BEZIER.C

     / * ---------------------------------------
       BEZIER.C - Демо Сплайнов Безье
                   (c) Чарльз Петцольд, 1998 г.
      --------------------------------------- * /
    
    #include 
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)
    {
         статический TCHAR szAppName [] = ТЕКСТ ("Безье");
         HWND hwnd;
         MSG msg;
         WNDCLASS wndclass;
         wndclass.style = CS_HREDRAW | CS_VREDRAW;
         wndclass.lpfnWndProc = WndProc;
         wndclass.cbClsExtra = 0;
         wndclass.cbWndExtra = 0;
         wndclass.hInstance = hInstance;
         wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
         wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
         wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
         wndclass.lpszMenuName = NULL;
         wndclass.lpszClassName = szAppName;
         
         если (! RegisterClass (& wndclass))
         {
              MessageBox (NULL, TEXT («Программа требует Windows NT!»),
                          szAppName, MB_ICONERROR);
              возврат 0;
         }
         
         hwnd = CreateWindow (szAppName, ТЕКСТ ("Сплайны Безье"),
                              WS_OVERLAPPEDWINDOW,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              NULL, NULL, hInstance, NULL);
         
         ShowWindow (hwnd, iCmdShow);
         UpdateWindow (hwnd);
         
         while (GetMessage (& msg, NULL, 0, 0))
         {
              TranslateMessage (& сообщение);
              DispatchMessage (& сообщение);
         }
         вернуть сообщение.wParam;
    }
    
    void DrawBezier (HDC hdc, POINT apt [])
    {
         PolyBezier (HDC, кв, 4);
         
         MoveToEx (hdc, apt [0] .x, apt [0] .y, NULL);
         LineTo (hdc, apt [1] .x, apt [1] .y);
         
         MoveToEx (hdc, apt [2] .x, apt [2] .y, NULL);
         LineTo (hdc, apt [3] .x, apt [3] .y);
    }
    
    LRESULT CALLBACK WndProc (HWND hwnd, сообщение UINT, WPARAM wParam, LPARAM lParam)
    {
         статическая ТОЧКА apt [4];
         HDC hdc;
         int cxClient, cyClient;
         PAINTSTRUCT ps;
         
         переключатель (сообщение)
         {
         case WM_SIZE:
              cxClient = LOWORD (lParam);
              cyClient = HIWORD (lParam);
              
              кв [0].х = cxClient / 4;
              apt [0] .y = cyClient / 2;
              
              apt [1] .x = cxClient / 2;
              apt [1] .y = cyClient / 4;
              
              apt [2] .x = cxClient / 2;
              apt [2] .y = 3 * cyClient / 4;
              
              apt [3] .x = 3 * cxClient / 4;
              apt [3] .y = cyClient / 2;
              
              возврат 0;
    
         case WM_LBUTTONDOWN:
         case WM_RBUTTONDOWN:
         case WM_MOUSEMOVE:
              если (wParam & MK_LBUTTON || wParam & MK_RBUTTON)
              {
                   hdc = GetDC (hwnd);
                   
                   SelectObject (hdc, GetStockObject (WHITE_PEN));
                   DrawBezier (HDC, APT);
                   
                   если (wParam & MK_LBUTTON)
                   {
                        кв [1].x = LOWORD (lParam);
                        apt [1] .y = HIWORD (lParam);
                   }
                   
                   если (wParam & MK_RBUTTON)
                   {
                        apt [2] .x = LOWORD (lParam);
                        apt [2] .y = HIWORD (lParam);
                   }
                   
                   SelectObject (hdc, GetStockObject (BLACK_PEN));
                   DrawBezier (HDC, APT);
                   ReleaseDC (hwnd, hdc);
              }
              возврат 0;
              
         case WM_PAINT:
              InvalidateRect (hwnd, NULL, TRUE);
              
              hdc = BeginPaint (hwnd, & ps);
              
              DrawBezier (HDC, APT);
              
              EndPaint (hwnd, & ps);
              возврат 0;
              
         case WM_DESTROY:
              PostQuitMessage (0);
              возврат 0;
         }
         вернуть DefWindowProc (hwnd, message, wParam, lParam);
    }
     

    Поскольку эта программа использует некоторую логику обработки мыши, о которой мы не узнаем до главы 7, я не буду обсуждать ее внутреннюю работу (которая, тем не менее, может быть очевидной).Вместо этого вы можете использовать программу для экспериментов с манипулированием сплайнами Безье. В этой программе две конечные точки установлены на полпути вниз по клиентской области и ¼ и пути по клиентской области. Двумя контрольными точками можно управлять: первая - нажатием левой кнопки мыши и перемещением мыши, вторая - нажатием правой кнопки мыши и перемещением мыши. На Рис. 5-17 показан типичный дисплей.

    Помимо самого сплайна Безье, программа также рисует прямую линию от первой контрольной точки до первой конечной точки (также называемой начальной точкой) слева и от второй контрольной точки до конечной точки справа. .

    Шлицы Безье считаются полезными при компьютерном проектировании из-за нескольких характеристик. Во-первых, немного попрактиковавшись, вы обычно можете преобразовать кривую во что-то, близкое к желаемой форме.

    Рисунок 5-17. Дисплей BEZIER.

    Во-вторых, шпонка Безье очень хорошо контролируется. В некоторых сплайнах кривая не проходит ни через одну из точек, определяющих кривую.Сплайн Безье всегда закреплен в двух конечных точках. (Это одно из предположений, которое используется для вывода формул Безье.) Кроме того, некоторые формы сплайнов имеют особенности, в которых кривая уходит в бесконечность. В компьютерных дизайнерских работах это редко бывает желательно. Кривая Безье никогда этого не делает; действительно, он всегда ограничен четырехсторонним многоугольником (называемым «выпуклой оболочкой»), который образован соединением конечных и контрольных точек.

    В-третьих, еще одна характеристика сплайна Безье включает взаимосвязь между конечными и контрольными точками.Кривая всегда касательна и направлена ​​в том же направлении, что и прямая линия от начальной точки до первой контрольной точки. (Это наглядно проиллюстрировано программой Безье.) Кроме того, кривая всегда касается и имеет то же направление, что и прямая линия, проведенная от второй контрольной точки до конечной точки. Это два других предположения, использованных для вывода формул Безье.

    В-четвертых, шлицы Безье часто эстетичны. Я знаю, что это субъективный критерий, но я не единственный, кто так думает.

    До 32-разрядных версий Windows вам нужно было создать свой собственный Безье сплайны с использованием функции Polyline . Вам также потребуются знания о следующих параметрические уравнения для сплайна Безье. Начальная точка (x 0 , y 0 ), а конечной точкой является (x 3 , y 3 ). Две контрольные точки: (x 1 , y 1 ) и (x 2 , y 2 ).Кривая построена для значений т от 0 до 1:

    x (t) = (1 - t) 3 x 0 + 3t (1 - t) 2 x 1 + 3t 2 (1 - t) x 2 + t 3 x 3

    y (t) = (1 - t) 3 y 0 + 3t (1 - т) 2 л 1 + 3т 2 (1 - t) y 2 + t 3 y 3

    Вам не нужно знать эти формулы в Windows 98.Чтобы нарисовать один или несколько связанных сплайнов Безье, вы просто вызываете

    PolyBezier (HDC, APT, iCount);
     

    или

    PolyBezierTo (HDC, APT, iCount);
     

    В обоих случаях apt представляет собой массив структур POINT. В PolyBezier первые четыре точки указывают (в этом порядке) начальную точку, первую контрольную точку, вторую контрольную точку и конечную точку первой кривой Безье. Для каждой последующей кривой Безье требуется только три дополнительные точки, потому что начальная точка второй кривой Безье совпадает с конечной точкой первой кривой Безье и так далее.Аргумент iCount всегда равен одному плюс трехкратному количеству соединенных кривых, которые вы рисуете.

    Функция PolyBezierTo использует текущую позицию для первой начальной точки. Для первого и каждого последующего сплайна Безье требуется всего три точки. Когда функция возвращается, текущая позиция устанавливается на последнюю конечную точку.

    Одно примечание: когда вы рисуете серию соединенных сплайнов Безье, точка соединения будет гладкой, только если вторая контрольная точка первого Безье, конечная точка первого Безье (которая также является начальной точкой второго Безье), а первая контрольная точка второй Безье коллинеарна; то есть они лежат на одной прямой.

    Использование стандартных ручек

    Когда вы вызываете любую из функций рисования линий, которые я обсуждал в этом разделе, Windows использует «перо», выбранное в данный момент в контексте устройства, для рисования линии. Перо определяет цвет, ширину и стиль линии, которая может быть сплошной, пунктирной или пунктирной. Перо в контексте устройства по умолчанию называется BLACK_PEN. Это перо рисует сплошную черную линию шириной в один пиксель. BLACK_PEN - одно из трех «стандартных ручек», предоставляемых Windows.Два других - WHITE_PEN и NULL_PEN. NULL_PEN - перо, которое не рисует. Вы также можете создать свои собственные ручки.

    В программах Windows вы обращаетесь к перьям с помощью ручки. Заголовочный файл Windows WINDEF.H определяет тип HPEN, дескриптор пера. Вы можете определить переменную (например, hPen ), используя это определение типа:

    HPEN hPen;
     

    Вы получите дескриптор одного из стандартных перьев, позвонив по номеру GetStockObject .Например, предположим, что вы хотите использовать стандартную ручку WHITE_PEN. У вас получится такая ручка пера:

    hPen = GetStockObject (WHITE_PEN);
     

    Теперь вы должны «выбрать» это перо в контексте устройства:

    SelectObject (hdc, hPen);
     

    Теперь текущим пером является белое перо. После этого вызова любые нарисованные вами линии будут использовать WHITE_PEN до тех пор, пока вы не выберете другое перо в контексте устройства или не отпустите дескриптор контекста устройства.

    Вместо того, чтобы явно определять переменную hPen , вы можете вместо этого объединить вызовы GetStockObject и SelectObject в одном операторе:

    SelectObject (hdc, GetStockObject (WHITE_PEN));
     

    Если вы затем захотите вернуться к использованию BLACK_PEN, вы можете получить дескриптор этого стандартного объекта и выбрать его в контексте устройства одним оператором:

    SelectObject (hdc, GetStockObject (BLACK_PEN));
     

    SelectObject возвращает дескриптор пера, который был ранее выбран в контексте устройства.Если вы начнете с нового контекста устройства и вызовете

    hPen = SelectObject (hdc, GetStockobject (WHITE_PEN));
     

    , текущее перо в контексте устройства будет WHITE_PEN, а переменная hPen будет дескриптором BLACK_PEN. Затем вы можете выбрать BLACK_PEN в контексте устройства, вызвав

    SelectObject (hdc, hPen);
     

    Создание, выбор и удаление перьев

    Хотя перья, определенные как стандартные объекты, безусловно, удобны, вы можете использовать только одно сплошное черное перо, сплошное белое перо или вообще не использовать перо.Если вы хотите стать более красивым, вы должны создать свои собственные ручки.

    Вот общая процедура: вы создаете «логическое перо», которое является просто описанием пера, с помощью функции CreatePen или CreatePenIndirect . Эти функции возвращают дескриптор логического пера. Вы выбираете перо в контексте устройства, вызывая SelectObject . Затем вы можете рисовать линии этим новым пером. В любое время в контексте устройства можно выбрать только одно перо.После освобождения контекста устройства (или после выбора другого пера в контексте устройства) вы можете удалить созданное вами логическое перо, вызвав DeleteObject . Когда вы это сделаете, дескриптор пера больше не действителен.

    Логическое перо - это «объект GDI», один из шести объектов GDI, которые может создать программа. Остальные пять - это кисти, растровые изображения, области, шрифты и палитры. За исключением палитр, все эти объекты выбираются в контексте устройства с помощью SelectObject .

    Три правила регулируют использование объектов GDI, таких как перья:

    • В конечном итоге вам следует удалить все созданные вами объекты GDI.
    • Не удаляйте объекты GDI, пока они выбраны в допустимом контексте устройства.
    • Не удалять стоковые объекты.

    Это небезосновательные правила, но иногда они могут быть немного сложными. Мы рассмотрим несколько примеров, чтобы понять, как работают правила.

    Общий синтаксис функции CreatePen выглядит следующим образом:

    hPen = CreatePen (iPenStyle, iWidth, crColor);
     

    Аргумент iPenStyle определяет, рисует ли перо сплошную линию или линию, состоящую из точек или тире. Аргументом может быть один из следующих идентификаторов, определенных в WINGDI.H. На рис. 5-18 показан вид линий, создаваемых каждым стилем.

    Рисунок 5-18. Семь стилей пера.

    Для стилей PS_SOLID, PS_NULL и PS_INSIDEFRAME аргумент iWidth - это ширина пера. Значение 0 iWidth указывает Windows использовать один пиксель для ширины пера. Стандартные ручки имеют ширину 1 пиксель. Если вы укажете стиль пера с пунктиром или пунктиром с физической шириной больше 1, Windows будет использовать сплошное перо.

    Аргумент crColor для CreatePen - это значение COLORREF, определяющее цвет пера.Для всех стилей пера, кроме PS_INSIDEFRAME, когда вы выбираете перо в контексте устройства, Windows преобразует цвет в ближайший чистый цвет, который устройство может отображать. PS_INSIDEFRAME - единственный стиль пера, который может использовать смешанный цвет, и то только тогда, когда ширина больше 1.

    Стиль PS_INSIDEFRAME имеет еще одну особенность при использовании с функциями, определяющими заполненную область. Для всех стилей пера, кроме PS_INSIDEFRAME, если перо, используемое для рисования контура, имеет ширину более 1 пикселя, то перо центрируется на границе, так что часть линии может выходить за пределы ограничивающей рамки.Для стиля пера PS_INSIDEFRAME вся линия рисуется внутри ограничивающей рамки.

    Вы также можете создать перо, настроив структуру типа LOGPEN («логическое перо») и вызвав CreatePenIndirect . Если ваша программа использует много разных перьев, которые вы инициализируете в исходном коде, этот метод, вероятно, более эффективен.

    Чтобы использовать CreatePenIndirect , сначала вы определяете структуру типа LOGPEN:

    LOGPEN logpen;
     

    Эта структура состоит из трех членов: lopnStyle (целое число без знака или UINT) - стиль пера, lopnWidth (структура POINT) - ширина пера в логических единицах и lopnColor (COLORREF) - цвет пера.Windows использует только поле x структуры lopnWidth для установки ширины пера; он игнорирует поле и .

    Вы создаете перо, передавая адрес структуры в CreatePenIndirect :

    hPen = CreatePenIndirect (& logpen);
     

    Обратите внимание, что для функций CreatePen и CreatePenIndirect не требуется дескриптор контекста устройства. Эти функции создают логические ручки, которые не связаны с контекстом устройства, пока вы не вызовете SelectObject .Вы можете использовать одно и то же логическое перо для нескольких разных устройств, таких как экран и принтер.

    Вот один из способов создания, выбора и удаления перьев. Предположим, ваша программа использует три пера: черное перо шириной 1, красное перо шириной 3 и перо с черными точками. Сначала вы можете определить статические переменные для хранения дескрипторов этих перьев:

    статический HPEN hPen1, hPen2, hPen3;
     

    Во время обработки WM_CREATE вы можете создать три пера:

    hPen1 = CreatePen (PS_SOLID, 1, 0);
    hPen2 = CreatePen (PS_SOLID, 3, RGB (255, 0, 0));
    hPen3 = CreatePen (PS_DOT, 0, 0);
     

    Во время обработки WM_PAINT (или в любой другой раз, когда у вас есть действительный дескриптор контекста устройства), вы можете выбрать одно из этих перьев в контексте устройства и рисовать с его помощью:

    SelectObject (hdc, hPen2);
      [функции рисования линий] 
    SelectObject (hdc, hPen1);
      [функции рисования линий] 
     

    Во время обработки WM_DESTROY вы можете удалить три созданных вами пера:

    DeleteObject (hPen1);
    DeleteObject (hPen2);
    DeleteObject (hPen3);
     

    Это наиболее простой способ создания выделения и удаления перьев, но, очевидно, ваша программа должна знать, какие перья потребуются.Вместо этого вы можете создавать перья во время каждого сообщения WM_PAINT и удалять их после вызова EndPaint . (Вы можете удалить их перед вызовом EndPaint , но вы должны быть осторожны, чтобы не удалить перо, выбранное в данный момент в контексте устройства.)

    Возможно, вы захотите создать перья на лету и объединить вызовы CreatePen и SelectObject в одном операторе:

    SelectObject (hdc, CreatePen (PS_DASH, 0, RGB (255, 0, 0)));
     

    Теперь, когда вы рисуете линии, вы будете использовать красную пунктирную ручку.Когда вы закончите рисовать красные пунктирные линии, вы можете удалить перо. Ой! Как удалить перо, если ручка пера не сохранена? Напомним, что SelectObject возвращает дескриптор пера, ранее выбранного в контексте устройства. Это означает, что вы можете удалить перо, выбрав стандартный BLACK_PEN в контексте устройства и удалив значение, возвращенное из SelectObject :

    DeleteObject (SelectObject (hdc, GetStockObject (BLACK_PEN)));
     

    Вот еще способ.Когда вы выбираете перо во вновь созданном контексте устройства, сохраните дескриптор пера, который возвращает SelectObject :

    hPen = SelectObject (hdc, CreatePen (PS_DASH, 0, RGB (255, 0, 0)));
     

    Что такое hPen ? Если это первый вызов SelectObject , который вы сделали после получения контекста устройства, hPen является дескриптором стандартного объекта BLACK_PEN. Теперь вы можете выбрать это перо в контексте устройства и удалить созданное перо (дескриптор, возвращенный этим вторым вызовом SelectObject ) одним оператором:

    DeleteObject (SelectObject (hdc, hPen));
     

    Если у вас есть дескриптор пера, вы можете получить значения полей структуры LOGPEN, вызвав GetObject :

    GetObject (hPen, sizeof (LOGPEN), (LPVOID) & logpen);
     

    Если вам нужен дескриптор пера, выбранный в данный момент в контексте устройства, вызовите

    hPen = GetCurrentObject (hdc, OBJ_PEN);
     

    Я расскажу о другой функции создания пера, ExtCreatePen , в главе 17.

    Заполнение пробелов

    Использование пунктирных и штриховых перьев вызывает вопрос: что происходит с промежутками между точками и тире? Что вы хотите?

    Цвет промежутков зависит от двух атрибутов контекста устройства - режима фона и цвета фона. Фоновый режим по умолчанию - OPAQUE, что означает, что Windows заполняет промежутки цветом фона, который по умолчанию белый. Это согласуется с WHITE_BRUSH, который многие программы используют в классе окна для стирания фона окна.

    Вы можете изменить цвет фона, который Windows использует для заполнения пробелов, вызвав

    SetBkColor (hdc, crColor);
     

    Как и аргумент crColor , используемый для цвета пера, Windows преобразует этот цвет фона в чистый цвет. Вы можете получить текущий цвет фона, определенный в контексте устройства, вызвав GetBkColor .

    Вы также можете запретить Windows заполнять пробелы, изменив фоновый режим на ПРОЗРАЧНЫЙ:

    SetBkMode (hdc, ПРОЗРАЧНЫЙ);
     

    Windows тогда проигнорирует цвет фона и не заполнит пробелы.Вы можете получить текущий фоновый режим (ПРОЗРАЧНЫЙ или НЕПРЫВНЫЙ), позвонив по номеру GetBkMode .

    Режимы рисования

    Внешний вид линий, нарисованных на дисплее, также зависит от режима рисования, определенного в контексте устройства. Представьте, что вы рисуете линию, цвет которой зависит не только от цвета пера, но и от цвета области отображения, в которой нарисована линия. Представьте себе способ, которым вы могли бы использовать одно перо, чтобы нарисовать черную линию на белой поверхности и белую линию на черной поверхности, не зная, какого цвета эта поверхность.Может ли такая установка быть вам полезна? Это стало возможным благодаря режиму рисования.

    Когда Windows использует перо для рисования линии, она фактически выполняет побитовую логическую операцию между пикселями пера и пикселями целевой поверхности отображения, где пиксели определяют цвет пера и поверхности отображения. Выполнение побитовой логической операции с пикселями называется «растровой операцией» или «ROP». Поскольку рисование линии включает только два пиксельных шаблона (перо и место назначения), логическая операция называется «двоичной растровой операцией» или «ROP2».«Windows определяет 16 кодов ROP2, которые указывают, как Windows комбинирует пиксели пера и пиксели назначения. В контексте устройства по умолчанию режим рисования определяется как R2_COPYPEN, что означает, что Windows просто копирует пиксели пера в место назначения, и вот как мы обычно думаем о ручках.Есть 15 других кодов ROP2.

    Откуда берутся эти 16 различных кодов ROP2? Для наглядности предположим, что монохромная система использует 1 бит на пиксель. Цвет назначения (цвет клиентской области окна) может быть либо черным (который мы представим нулевым пикселем), либо белым (представлен одним пикселем).Перо также может быть черным или белым. Существует четыре комбинации использования черного или белого пера для рисования в черном или белом месте: белое перо на белом месте, белое перо на черном месте, черное перо на белом месте и черное перо на белом. черный пункт назначения.

    Какого цвета будет конечный объект после рисования пером? Одна из возможностей состоит в том, что линия всегда отображается как черная, независимо от цвета пера или цвета назначения. Этот режим рисования обозначается кодом ROP2 R2_BLACK.Другая возможность состоит в том, что линия рисуется как черная, за исключением случаев, когда и ручка, и место назначения черные, и в этом случае линия рисуется как белая. Хотя это может показаться немного странным, у Windows есть для этого название. Режим рисования называется R2_NOTMERGEPEN. Windows выполняет побитовую операцию ИЛИ над целевыми пикселями и пикселями пера, а затем инвертирует результат.

    В таблице ниже показаны все 16 режимов рисования ROP2. В таблице показано, как сочетаются цвета пера (P) и назначения (D) для получения результата.В столбце «Логическая операция» используется нотация C, чтобы показать, как объединяются пиксели назначения и пиксели пера.

    Ручка (P):

    Пункт назначения (D):

    1 1 0 0

    1 0 1 0

    Логическая операция Режим рисования
    Результатов: 0 0 0 0 0 R2_BLACK
    0 0 0 1 ~ (P ¦ D) R2_NOTMERGEPEN
    0 0 1 0 ~ P&D R2_MASKNOTPEN
    0 0 1 1 ~ P R2_NOTCOPYPEN
    0 1 0 0 P&D R2_MASKPENNOT
    0 1 0 1 ~ D R2_NOT
    0 1 1 0 P ^ D R2_XORPEN
    0 1 1 1 ~ (P&D) R2_NOTMASKPEN
    1 0 0 0 P&D R2_MASKPEN
    1 0 0 1 ~ (P ^ D) R2_NOTXORPEN
    1 0 1 0 D R2_NOP
    1 0 1 1 ~ P ¦ D R2_MERGENOTPEN
    1 1 0 0 -П, R2_COPYPEN (по умолчанию)
    1 1 0 1 P ¦ ~ D R2_MERGEPENNOT
    1 1 1 0 P ¦ D R2_MERGEPEN
    1 1 1 1 1 R2_ БЕЛЫЙ

    Вы можете установить новый режим рисования для контекста устройства, вызвав

    SetROP2 (hdc, iDrawMode);
     

    Аргумент iDrawMode - это одно из значений, перечисленных в столбце «Режим рисования» таблицы.Вы можете получить текущий режим рисования, используя функцию:

    iDrawMode = GetROP2 (hdc);
     

    Контекст устройства по умолчанию - R2_COPYPEN, который просто передает цвет пера в место назначения. В режиме R2_NOTCOPYPEN отображается белый цвет, если цвет пера черный, и черный, если цвет пера белый. В режиме R2_BLACK всегда отображается черный цвет, независимо от цвета пера или фона. Аналогично, в режиме R2_WHITE всегда отображается белый цвет. Режим R2_NOP - это «без операции»."Это оставляет пункт назначения неизменным.

    Мы изучали режим рисования в контексте монохромной системы. Однако большинство систем - цветные. В цветовых системах Windows выполняет побитовые операции режима рисования для каждого цветового бита пера и целевых пикселей и снова использует 16 кодов ROP2, описанных в предыдущей таблице. Режим рисования R2_NOT всегда инвертирует целевой цвет для определения цвета линии, независимо от цвета пера.Например, линия, проведенная в голубом месте назначения, будет пурпурной.

    Оставить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *