Очень часто нам нужно рисовать точки. У каждого из нас есть свой любимый метод делать это.
Что твое ?
Используете ли вы узлы, рисунки, отметки, ... ? В стиле ?
Некоторые фоны
В руководстве tikz/pgf это очень часто делается с помощью \tikz\fill circle (2pt);
.
В примере ключа /tikz/insert path
мы видим этот код
\tikz [c/.style={insert path={circle[radius=2pt]}}]
\draw (0,0) -- (1,1) [c] -- (3,2) [c];
Также есть пример дляобработчик ключей /.pic
(стр.255) для создания такого же заполненного круга.
Преимущество этих методов в их простоте, но они не подходят мне по следующим причинам:
- Внешний вид точки зависит от действия команды контура (рисовать, заполнять, ...).
em
При масштабировании изображения ширина линии (и размер шрифта) не масштабируются, но масштабируются точки (это можно легко обойти , например, указав размер ).- Когда вы рисуете линию после того, как нарисовали точку, линия рисуется поверх точки.
И более ...
Что я ищу
Вот список вещей, которые я хотел бы иметь возможность делать, используя только одно определение «точки» (или более одного определения, но с единым синтаксисом).
Для каждого требования я дал тест, который нужно пройти с ожидаемым результатом. В тесте вы можете заменить "point" на ваш любимый синтаксис.
1) Точки должны быть правильно масштабированы. И для меня не ясно, должен ли размер быть пропорционален ширине линии или размеру шрифта. Вероятно, лучше всего задать размер с помощью ширины линии, а затем при необходимости (см. пункт 3)) установить размер, em
если мы хотим совместимости масштабирования шрифта. Что вы думаете?
\begin{tikzpicture}
\foreach[count=\i] \w in {ultra thin, thin, ultra thick} {
\draw[yshift=-\i em, \w] (0,0) -- (.5,0) "point" -- (1,0);
}
\foreach[count=\i] \s in {.2, .5, 1} {
\draw[xshift=1.5cm, yshift=-\i em, scale=\s] (0,0) -- (.5,0) "point" -- (1,0);
}
\end{tikzpicture}
2) Мы должны иметь возможность легко стилизовать точки. Например, мы должны иметь возможность сказать что-то вроде "нарисуй толстую красную точку".
(см. следующий пункт для теста)
3) Draw, fill и opacity точек могут быть установлены в, inherit
в этом случае эти параметры наследуются от scope/path. Но только draw должен быть установлен inherit
по умолчанию, другие значения по умолчанию (по личному вкусу) должны быть fill=white и opacity=1.
\begin{tikzpicture}[scale=2, very thick]
\filldraw[draw opacity=.5, draw=red, fill opacity=.3, densely dotted]
(0,0) "point" -- (.5,0) "ultra thick point filled in green" -- (.5,.5) "point with inherited draw, fill and opacity" -- cycle;
\end{tikzpicture}
4) Точке можно легко присвоить имя на месте ее использования, coordinate
и если точка нарисована с node
именем, то оно должно указывать на центр узла, а не на сам узел.
\begin{tikzpicture}
\draw[very thick] (0,1) "point" -- (1,0) "thick point filled in green with name=A";
\draw[ultra thick, purple] (0,0) "point" -- (A);
\end{tikzpicture}
5) Точки можно использовать в любой ситуации, где мы обычно можем использовать другую команду для их рисования. Это уже проиллюстрировано предыдущими примерами, но было бы неплохо, если бы мы могли использовать их с \node at
и \coordinate at
(что не очевидно, потому что at
не меняют текущую координату).
(см. следующий пункт для теста)
6) Точки рисуются поверх любой линии (на переднем плане).
\begin{tikzpicture}
\node[left] {A} at (0,1) "ultra thick point";
\coordinate["thick point"] (B) at (1,0);
\draw (A) -- (B);
\end{tikzpicture}
7) Решение не должно быть хакерским, чтобы определение «точки» было (надеюсь) совместимо с будущими версиями tikz.
Каково мое личное неполное решение?
Я опубликую это как ответ.
решение1
Метод 1(используя узел)
\tikzset{
every point/.style = {circle, inner sep={.75\pgflinewidth}, opacity=1, draw, solid, fill=white},
point/.style={insert path={node[every point, #1]{}}}, point/.default={},
point name/.style = {insert path={coordinate (#1)}},
}
и кое-что еще:
\tikzset{
colored point/.style = {point={fill=#1}},
inherit/.style = {point/.style={insert path={node[circle, inner sep={.75\pgflinewidth}, draw, fill, #1]{}}}}
}
Удовлетворяет 1.
Удовлетворяет 2 с таким стилем
[point={fill=red, very thick}]
Частично удовлетворяет 3. Я не знаю, как определить
draw opacity=inherit
илиfill=inherit
. Я определяю новый стильinherit
, который переопределит всеpoint
, удаливopacity=1
иfill=white
, но это уродливо ;).Частично удовлетворяет 4: вы можете использовать
point name=A
. Я бы хотел иметь возможность использовать кавычки, чтобы сказать что-то вроде,[point={red, "A"}]
но я не знаю, как это сделать.Почти удовлетворяет 5: мы можем поставить [точку] почти где угодно, например
(A) [point]
, илиnode[point, above]{A}
, илиcoordinate[point](A)
. Но нельзя использовать с\coordinate at
или\node at
(за исключением случаев, когда вы повторяетесь вот так\coordinate (A) at (1,1) (A) [point];
)НЕУДАЧНОна 6. Я знаю, чтоесть хакерское решение поместить узел на слой, но это противоречит 7).
Удовлетворяет 7.
Полный код всех тестов и результат
\documentclass[varwidth,border=50]{standalone}
\usepackage{tikz}
% not clear how to use layers with this method
\pgfdeclarelayer{background}
\pgfdeclarelayer{foreground}
\pgfsetlayers{background,main,foreground}
\tikzset{
every point/.style = {circle, inner sep={.75\pgflinewidth}, opacity=1, draw, solid, fill=white},
point/.style={insert path={node[every point, #1]{}}}, point/.default={},
colored point/.style = {point={fill=#1}},
point name/.style = {insert path={coordinate (#1)}},
inherit/.style = {point/.style={insert path={node[circle, inner sep={.75\pgflinewidth}, draw, fill, #1]{}}}}
}
\begin{document}
\begin{itemize}
% ---------------------------------
\item Test 1 : ok.\\[1em]
\begin{tikzpicture}
\foreach[count=\i] \w in {ultra thin, thin, ultra thick} {
\draw[yshift=-\i em, \w] (0,0) -- (.5,0) [point] -- (1,0);
}
\foreach[count=\i] \s in {.2, .5, 1} {
\draw[xshift=1.5cm, yshift=-\i em, scale=\s] (0,0) -- (.5,0) [point] -- (1,0);
}
\end{tikzpicture}
% ---------------------------------
\item Test 2 : ok.
% ---------------------------------
\item Test 3 : partialy ok, there is no good \texttt{inherit}.\\
\begin{tikzpicture}[scale=2, very thick]
\filldraw[draw opacity=.5, draw=red, fill opacity=.3, densely dotted]
(0,0) [point] -- (.5,0) [point={ultra thick, fill=green}] -- (.5,.5) [inherit, point] -- cycle;
\end{tikzpicture}
% ---------------------------------
\item Test 4 : almost ok (using \texttt{point name})\\
\begin{tikzpicture}
\draw[very thick] (0,1) [point] -- (1,0) [point={thick, fill=green, point name=A}];
\draw[ultra thick, purple] (0,0) [point] -- (A);
\end{tikzpicture}
% ---------------------------------
\item Test 5 : almost ok.
% ---------------------------------
\item Test 6 : fails ! (visible in test 4 too)\\
\begin{tikzpicture}
\coordinate (A) at (0,1) (A) node[point=ultra thick, left] {A};
\coordinate (B) at (1,0) (B) [thick, point];
\draw (A) -- (B);
\end{tikzpicture}
\end{itemize}
\end{document}
Метод 2(используя картинку)
\pgfdeclarelayer{background}
\pgfdeclarelayer{foreground}
\pgfsetlayers{background,main,foreground}
\tikzset{
every point/.style = {radius={\pgflinewidth}, opacity=1, draw, solid, fill=white},
pt/.pic = {
\begin{pgfonlayer}{foreground}
\path[every point, #1] circle;
\end{pgfonlayer}
},
point/.style={insert path={pic{pt={#1}}}}, point/.default={},
point name/.style = {insert path={coordinate (#1)}}
}
НЕУДАЧНОна 1. Я не знаю как наследовать стили от path к pic. Есть ли какой-то стиль типа
current path style
?Удовлетворяет 2. То же, что и метод I.
НЕУДАЧНОна 3. Мы можем стилизовать как в методе I, но поскольку (1) не выполняется, (3) не выполняется.
Частично удовлетворяет 4. То же, что и метод I.
НЕУДАЧНОна 5: так как естьошибка в 'pic'мы не можем использовать узел после него в PGF 3.0. Когда эта ошибка будет исправлена, этот метод будет эквивалентен первому в этом тесте.
Удовлетворяет 6. Это главный интерес данного метода.
Удовлетворяет 7.
Полный код всех тестов и результат
\documentclass[varwidth,border=50]{standalone}
\usepackage{tikz}
\pgfdeclarelayer{background}
\pgfdeclarelayer{foreground}
\pgfsetlayers{background,main,foreground}
\tikzset{
every point/.style = {radius={\pgflinewidth}, opacity=1, draw, solid, fill=white},
pt/.pic = {
\begin{pgfonlayer}{foreground}
\path[every point, #1] circle;
\end{pgfonlayer}
},
point/.style={insert path={pic{pt={#1}}}}, point/.default={},
colored point/.style = {point={fill=#1}},
point name/.style = {insert path={coordinate (#1)}}
}
\begin{document}
\begin{itemize}
\item Test 1 : fails for sizing from path width, scale is ok.\\[1em]
\begin{tikzpicture}
\foreach[count=\i] \w in {ultra thin, thin, ultra thick} {
\draw[yshift=-\i em, \w] (0,0) -- (.5,0) [point] -- (1,0);
}
\foreach[count=\i] \s in {.2, .5, 1} {
\draw[xshift=1.5cm, yshift=-\i em, scale=\s] (0,0) -- (.5,0) [point] -- (1,0);
}
\end{tikzpicture}
\item Test 2 : partialy ok, there is no \texttt{inherit} (at all).
\item Test 3 : fails ! Can't inherit style from path.\\
\begin{tikzpicture}[scale=2, very thick, densely dotted]
\filldraw[draw opacity=.5, draw=red, fill opacity=.3]
(0,0) [point] -- (.5,0) [point={ultra thick, fill=green}] -- (.5,.5) [point] -- cycle;
\end{tikzpicture}
\item Test 4 : almost ok (using \texttt{point name})\\
\begin{tikzpicture}
\draw[very thick] (0,1) [point] -- (1,0) [point={thick, fill=green, point name=A}];
\draw[ultra thick, purple] (0,0) [point] -- (A);
\end{tikzpicture}
\item Test 5 : fails ! (can't put node after [point] )
\item Test 6 : ok.\\
\begin{tikzpicture}
\path (0,1) node[left] {A} coordinate (A) [point=ultra thick];
\coordinate (B) at (1,0) (B) [thick, point];
\draw (A) -- (B);
\end{tikzpicture}
\end{itemize}
\end{document}
решение2
Примечание:Я создал небольшую библиотеку tikz на основе этого ответа и назвал ее так
nicepoints
, она доступна наGitHub.
Наконец, у меня есть метод рисования точек, которые удовлетворяют всем критериям (немного по-другому для наследования цвета) и даже больше.
Прежде чем дать вам полное решение, давайте начнем с начала истории.
Самый простой способ
Я только что понял, что, вероятно, лучший способ выразить свою точку зрения — это использовать «точку» .
:
\tikz\draw[very thin,red] (0,0) -- node{.} (1,0);
Цвет наследуется очень полезным образом, я думаю. Цвет точки совпадает с цветом текста.
\tikz\draw[very thin,red,text=violet] (0,0) -- node{.} node[above]{A} (1,0);
Но такие точки слишком малы для более толстых линий.
\tikz\draw[very thick,red,text=violet] (0,0) -- node{.} (1,0);
Мы можем масштабировать его с помощью line width
и автоматизировать все это, создав стиль.
\tikzset{point/.style={insert path={ node[scale=2.5*sqrt(\pgflinewidth)]{.} }}}
\tikz\draw[very thick,red,text=violet] (0,0) -- node[point,above]{A} (1,0);
Выбор sqrt
- дело вкуса: таким образом, для более тонких линий точки не слишком маленькие, а для более толстых - не слишком толстые. Фактически, таким образом, поверхность точки пропорциональна ширине линии.
Более сложные моменты
А если мы хотим заполнить точку, мы можем просто нарисовать еще одну точку поменьше поверх первой:
\tikzset{
outer dot/.style = {scale=2.5*sqrt(\pgflinewidth)},
inner dot/.style = {scale=sqrt(\pgflinewidth),#1},inner dot/.default={white},
point/.style={insert path={ node[outer dot]{.} node[inner dot=#1]{.}}}
}
\tikz\draw[very thick,blue] (0,0) -- node[point]{} (1,0) [point=red];
Проблема, которая пока не решена, заключается в том, что линии, проведенные после точки, могут перекрывать ее следующим образом:
\begin{tikzpicture}[scale=2]
\draw[very thick,blue] (0,0) -- node[point]{} (1,0) [point=red];
\draw[red] (0,0) -- node[point]{} (1,.2);
\draw[very thick] (0,.2) -- (1,0);
\end{tikzpicture}
Решение
Мы хотим поместить точку на верхний слой, таким образом, чтобы любая линия, проведенная после нее, оставалась под точкой. Для этого мы можем использовать , pgfonlayer
но есть две трудности:
Не так уж много способов автоматически вставить
pgfonlayer
. Мы можем использовать некоторые хаки (но я этого не хочу). Мы можем использоватьpic
, но в этом случае нам придется исправить ошибку TikZ 3.0.0, если мы хотим иметь возможность использовать узлы после точки. И третий вариант, который я знаю, — использоватьpath picture
.
Вот тут есть одна хитрость: если мы что-то нарисуем внутриpath picture
, изменив слой, рисунок не будет обрезан, поскольку обрезка будет применена к исходному слою.Когда мы меняем слой, "почти" все сбрасывается: толщина линии, цвета рисования и заливки, непрозрачность. Но я был приятно удивлен, когда писалэтот вопрос, что цвет текста и непрозрачность не сбрасываются при смене слоя. Поэтому единственное, о чем нам нужно позаботиться, это
line width
. Но это не так уж и сложно, потому что в нашем распоряжении естьpgflinewidth
то, что мы можем сохранить до смены слоя и использовать на новом слое.
Вот «нецитированная» версия ответа на первоначальный вопрос:
\pgfdeclarelayer{points}
\pgfsetlayers{main,points}
\tikzset{
set point size/.code={\pgfmathsetmacro{\pointsize}{sqrt(\pgflinewidth)}},
point size/.style={set point size/.prefix style={line width=#1}},
every dot/.style = {inner sep=0, outer sep=0,font=},
outer dot/.style = {every dot, scale=2.5*\pointsize},
inner dot/.style = {every dot, scale=\pointsize, text=#1}, inner dot/.default={white},
point fill/.style = {inner dot/.default={#1}},
point coordinate/.style={insert path={coordinate(#1)}},
point/.style={insert path={
node[inner sep=0, overlay, every point/.try, #1, set point size,
path picture={
\begin{pgfonlayer}{points}
\node[outer dot]{.} node[inner dot]{.};
\end{pgfonlayer}
}
]{}
}
}
}
И еще один тест:
\begin{tikzpicture}[scale=2]
\draw[blue] (0,0)[point] -- node[thick,point={name=A},below]{$A$} (1,0) [point=red];
\draw[red] (0,0) -- node[point]{} (1,.2) [point=thick];
\draw[very thick] (0,.2)[point={point coordinate=B, label=$B$}] -- (1,0);
\draw[green] (A)--(B);
\end{tikzpicture}
Как ...
- Как использовать
point
стиль?- просто как
(1,1) [point]
, - или внутри другого узла, подобного этому
node[point,below]{$A$}
.
- просто как
- Как поставить точку в середине сегмента?Мы не можем использовать
-- [point]
синтаксис, но мы можем:- поместите внутрь еще один узел, как этот
-- node[point]{}
- или после окончания сегмента, вот так
--(1,1)[point=midway]
- поместите внутрь еще один узел, как этот
- Как установить
draw
цвет точки?Как будто мы задаем цвет текста всех узлов.- Если цвет задан на пути таким образом,
\path[red] ...
то он наследуется точками на пути (поскольку в этом случае цвет текста также задан).
\tikz\draw[red] (0,0. -- (1,0) [point=midway];
- Если мы зададим только цвет отрисовки/заливки на контуре/области, но не цвет текста, то точки по умолчанию будут черными (как и текст).
\tikz\path[draw=red] (0,0) -- (1,0) [point=midway];
- Мы можем указать цвет точки, как в следующем примере:
- Если цвет задан на пути таким образом,
\begin{tikzpicture}[масштаб=2] \draw[fill=синий!14] (0,0) [точка] -- (1,0) [точка=синий] -- узел[красный,точка,левый]{красная точка и текст} (1,1) узел[точка,выше,красный]{только красный текст} -- (0,1) узел[точка=красная,ниже]{только красная точка}; \end{tikzpicture}
- Как установить
fill
цвет точки?С помощьюpoint fill
ключа.- Если мы хотим установить его для всех точек на пути, мы можем сделать
\path[point fill=red] ...
- Если мы хотим установить его для одной точки, мы можем сделать
[point={point fill=red}]
.
- Если мы хотим установить его для всех точек на пути, мы можем сделать
\tikz\path[ультратолстый, красный, точечная заливка=синий] (0,0) [точка] (.5,0) [точка={заливка точки=зеленый}] (1,0) [точка];
- Как установить размер точки?Точка наследует свой размер от ширины линии контура.
- Чтобы изменить его на одну точку, мы можем использовать,
[point=very thick]
например, - Чтобы установить его для всех точек в области видимости независимо от ширины линии, мы можем использовать,
point size=.8pt
например,
- Чтобы изменить его на одну точку, мы можем использовать,
И наконец, мы можем использовать every point
для установки стиля точки по умолчанию.
Дополнительные материалы: цитируемые баллы
Если мы хотим иметь возможность сказать point="A"
и установить координаты (A)
и отобразить текст $A$
рядом с точкой, мы можем использовать библиотеку quotes
.
Вот полный код для этих quoted
точек.
\usetikzlibrary{quotes}
\pgfdeclarelayer{points}
\pgfsetlayers{main,points}
\tikzset{
set point size/.code={\pgfmathsetmacro{\pointsize}{sqrt(\pgflinewidth)}},
point size/.style={set point size/.prefix style={line width=#1}},
every dot/.style = {inner sep=0, outer sep=0,font=},
outer dot/.style = {every dot, scale=2.5*\pointsize},
inner dot/.style = {every dot, scale=\pointsize, text=#1}, inner dot/.default={white},
point fill/.style = {inner dot/.default={#1}},
point coordinate/.style={insert path={coordinate(#1)}},
quotes mean point/.style={'/.style={empty label/.style={node contents=}},
node quotes mean/.try={point coordinate=##1,
label={[direction shorthands, every label quotes/.try, ##2,
node contents=\ensuremath{##1}, empty label/.try]}}},
point/.style={quotes mean point, insert path={
node[inner sep=0, overlay, every point/.try, #1, set point size,
path picture={
\begin{pgfonlayer}{points}
\node[outer dot]{.} node[inner dot]{.};
\end{pgfonlayer}
}]{}
}
}
}
Как использовать цитируемые пункты
- Когда вы говорите
[point="B"red]
, сначала вставляется , а затем используетсяcoordinate(B)
эквивалент .label={[red]$B$}
- Если вы используете
[point="B"']
(с'
), то$B$
не отображается (добавляется пустая метка), аcoordinate(B)
вставляется. - Если нам нужна только метка без координат, мы можем использовать
[point={label=$B$}]
илиnode[point,above]{$B$}
.
Давайте закончим этот краткий ответ примером использования «цитируемых пунктов»:
\begin{tikzpicture}[scale=2]
\draw[fill=yellow!30,very thick]
(0,0) [point="A"] -- (1,0) [point={"B"',blue}]
-- node[red,point="C"left]{} (1,1) [point="D"{above,red}]
-- (0,1) [point={red,"E"}];
\draw[thick,purple] (E) -- (B) to[bend right] (D) edge[bend right] (C) [point=near start];
\end{tikzpicture}
ОБНОВЛЯТЬ:Мы можем определить \point
так
\def\point[#1] at (#2){\path (#2) [point={#1}]}
и затем используйте его вот так:
\point["A"below] at (1,1);
ОБНОВЛЕНИЕ 2:После комментариев PaulGaborit я добавил every dot
стиль, который сбрасывает шрифт. Таким образом, если мы используем шрифт с точкой, которая не находится в центре узла, у нас есть два варианта:
- сделать шрифт «точка» стандартным шрифтом,
- или сделайте небольшой сдвиг (в em), чтобы поместить его в центр.
Например, мы можем поместить:
\tikzset{
every dot/.style={inner sep=0, outer sep=0,
node font=\usefont{T1}{lmr}{m}{n}\fontsize{10pt}{0pt}\selectfont}
}