我想创建一些新形状以便与 tiKz 一起使用。我面临的问题是如何访问新创建的形状的边缘。
到目前为止我得到了这个:
\documentclass[paper=a4,11pt,parskip=half,twoside]{scrartcl}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[french]{babel}
\usepackage[pdftex]{graphicx}
\usepackage{tikz}
\usepackage{circuitikz}
\usepackage{pgfplots}
\def\convEl{%
++(-.5,-.5) -- ++(1,0) -- ++(0,1) -- ++(-1,0) -- cycle
}
\def\convEm{%
++(0,0) circle (.5)
}
\def\convMe{%
++(-.5,-.5) -- ++(.5,1) -- ++(.5,-1) -- cycle
}
\def\accEn{%
++(-.5,-.5) -- ++(.5,0) -- ++(0,1) -- ++(-.5,0) -- cycle ++(0,-1) -- ++(.5,1)
}
\begin{document}
\begin{tikzpicture}
\filldraw[draw=red,ultra thick,fill=orange] (0,0) \convEl node (a) {};
\filldraw[draw=red,ultra thick,fill=orange] (2,0) \convEm node (b) {};
\filldraw[draw=red,ultra thick,fill=orange] (4,0) \convMe;
\filldraw[draw=red,ultra thick,fill=orange] (6,0) \accEn;
\end{tikzpicture}
\end{document}
好吧,也许我应该与提供的代码进行比较,使其更精确一些。我想访问形状的特定位置,例如底部中心和每侧 +30°/-30° 以连接箭头。这是预期行为的一个小方案。这就是为什么我需要创建/访问更多锚点的原因。如果我画一个简单的矩形,我可以做到,但要使用我需要的新/特殊形状……
答案1
使用 Spike 的方法肯定是可能的,但要定义的形状非常简单,所以我认为有一种最简单的方法。应该归功于 Jake 的回答如何在 tikz 中产生划掉的矩形?,因为在这里我只是改编了一些东西。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}
\tikzset{
orange square/.style={draw=red,ultra thick, fill=orange,%
minimum width=1cm, minimum height=1cm},%
orange circle/.style={circle,draw=red,ultra thick, fill=orange,minimum width=1cm},%
orange triangle/.style={regular polygon, regular polygon sides=3,%
draw=red,ultra thick, fill=orange,minimum height=1cm},%
orange rectangle/.style={rectangle,draw=red,ultra thick,%
fill=orange,minimum height=1cm,minimum width=0.5cm,append after command={
(\tikzlastnode.north east) edge[draw=red,ultra thick,shorten >=1.75\pgflinewidth,
shorten <=1.75\pgflinewidth,](\tikzlastnode.south west)
}
},%
}
\begin{document}
\begin{tikzpicture}[scale=1.75,transform shape]
\node[orange square] (a) at (0,0){};
\node[orange circle] (b) at (2,0){};
\node[orange triangle] (c) at (4,0){};
\node[orange rectangle] (d) at (6,0){};
\draw[->,>=stealth] (a.south) -- (b.west) (b.north) -- (c.north)-- (d.center);
\end{tikzpicture}
\end{document}
结果:
编辑问题对于更好地理解请求非常有用。在这种情况下,定义一个新的形状可能更好,但这是 Spike 的领域:我为您提供了另一种选择。好的,如果习惯于该calc
库,这可能是一种替代方案。
基本提示是regular polygons
定义也corner
锚定,因此通过以它们为参考,可以访问每个位置而无需定义新的形状。
修改后的示例:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric,calc}
\tikzset{
orange square/.style={regular polygon, regular polygon sides=4,%
draw=red,ultra thick, fill=orange,minimum width=1.5cm},%
orange triangle/.style={regular polygon, regular polygon sides=3,%
draw=red,ultra thick, fill=orange,minimum height=1.5cm},%
}
\begin{document}
\begin{tikzpicture}[scale=1.75,transform shape]
\node[orange square,] (e) at (0,-2){};
\node[orange triangle] (f) at (4,-2.165){};
% Display the anchors
\foreach \anchor/\placement in {corner 1/above, corner 2/above, corner 3/below, corner 4/below}
\draw[shift=(e.\anchor)] plot[mark=x] coordinates{(0,0)}node[\placement] {\tiny\texttt{(e.\anchor)}};
\foreach \anchor/\placement in {corner 1/above, corner 2/below, corner 3/below}
\draw[shift=(f.\anchor)] plot[mark=x] coordinates{(0,0)}node[\placement] {\tiny\texttt{(f.\anchor)}};
% Drawing the arrows
\draw[-latex] ($(e.corner 3)!0.5!(e.corner 4)-(0,1)$)--($(e.corner 3)!0.5!(e.corner 4)$);
\draw[-latex] ($(e.corner 1)!0.2!(e.corner 4)$)--($(f.corner 1)!0.25!(f.corner 2)$);
\draw[-latex] ($(e.corner 1)!0.5!(e.corner 4)$)--($(f.corner 1)!0.525!(f.corner 2)$);
\draw[-latex] ($(e.corner 1)!0.8!(e.corner 4)$)--($(f.corner 1)!0.8!(f.corner 2)$);
\end{tikzpicture}
\end{document}
结果:
答案2
创建新形状并不容易。它需要准确阅读 tikz 手册(第 75.5 节)并掌握一些 TeX 编程技能。顺便说一句,如果我能做到这一点,那么每个人都可以做到。如果您想创建真正的形状,您可以参考上述手册和其他先前的问题(例如如何在 TikZ 中定义机械约束)。
您给出的前三个示例仅使用样式即可实现。第三个可能需要定义,但考虑到它与矩形非常相似,因此并不难:
\documentclass{scrartcl}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric} %needed for the triangle
\makeatletter
\pgfdeclareshape{myrectangle}{% taken and modified from page 631 of the manual
\inheritsavedanchors[from=rectangle] % this is nearly a rectangle
\inheritanchorborder[from=rectangle]
\inheritanchor[from=rectangle]{center}
\inheritanchor[from=rectangle]{north}
\inheritanchor[from=rectangle]{south}
\inheritanchor[from=rectangle]{west}
\inheritanchor[from=rectangle]{east}
% ... and possibly more
\backgroundpath{% this is new
% store lower right in xa/ya and upper right in xb/yb
\southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
\northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
% construct main path
\pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
\pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
\pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@ya}}
\pgfpathclose
% add diagonal
\pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
}
}
\pgfdeclareshape{mytriangle}{%
\inheritsavedanchors[from=circle]
\inheritanchor[from=circle]{center}
\anchor{north}{\centerpoint\advance\pgf@y by\radius}
\anchor{south}{\centerpoint\advance\pgf@y by-\radius}
%etc...
\anchor{west}{%
\centerpoint
\pgf@xa=\radius
% y = -1.5*r*tan(alpha)
\advance\pgf@x by-1\pgf@xa
\advance\pgf@y by-1.5\pgf@xa
}
\anchor{east}{%
\centerpoint
\pgf@xa=\radius
% y = 1.5*r*tan(alpha)
\advance\pgf@x by1\pgf@xa
\advance\pgf@y by-1.5\pgf@xa
}
\anchor{south west}{%
\centerpoint
\pgf@xa=\radius
\advance\pgf@x by-\pgf@xa
\advance\pgf@y by-\pgf@xa
}
\anchor{south east}{%
\centerpoint
\pgf@xa=\radius
\advance\pgf@x by\pgf@xa
\advance\pgf@y by-\pgf@xa
}
\backgroundpath{%
\pgf@x=\radius
\pgfutil@tempdima=\pgf@x%
\pgf@xb=-\pgf@x%
\pgf@yb=-\pgf@x%
\pgf@xc= \pgf@x%
\pgf@yc=-\pgf@x%
\centerpoint
\advance\pgf@xb by\pgf@x
\advance\pgf@yb by\pgf@y
\advance\pgf@xc by\pgf@x
\advance\pgf@yc by\pgf@y
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
\advance\pgf@ya by\radius%
\pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}%
\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}%
\pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}}%
\pgfpathclose%
\advance\pgf@ya by-\radius%
}%
}
\makeatother
% now the styles
\tikzset{orangesquare/.style={draw=red,ultra thick, fill=orange,minimum width=1cm, minimum height=1cm},%
orangecircle/.style={circle,draw=red,ultra thick, fill=orange,minimum width=1cm},%
orangetriangle/.style={regular polygon, regular polygon sides=3,draw=red,ultra thick, fill=orange,minimum height=1cm},%
orangetriangle/.style={mytriangle,draw=red,ultra thick, fill=orange,minimum height=1cm}}
\begin{document}
\begin{tikzpicture}
\node[orangesquare] (a) at (0,0){};
\node[orangecircle] (b) at (2,0){};
\node[orangetriangle] (c) at (4,0){};
\node[orangerectangle] (d) at (6,0){};
\draw[->,>=stealth] (a.south) -- (b.west) (b.north) -- (c.north) -- (d.center);
\end{tikzpicture}
\end{document}
我使用圆形锚点(中心和半径)创建了三角形。如您所见,它与其他形状之间存在差异:最小宽度不考虑线宽。可以修复锚点位置,将其移至形状的外部,但无论如何都需要稍微调整最小尺寸。不幸的是,我不知道如何解决这个问题。也许我会把它作为一个问题发布。
答案3
我提出了另外两种方法来解决所提出的问题。
- 一个是 tikz 的标准功能,
- 另一种是沿着描述图片的路径自动创建可寻址节点的方法。
正如您在评论中所问的那样,我还有一个解决三角形底部对齐问题的建议。
您可以在这里看到结果:
您可以在这里看到代码:
\documentclass [tikz] {standalone}
\usetikzlibrary{decorations.markings}
\usetikzlibrary{shapes.geometric}
\newcounter{mynodes}
\tikzset{
my anchors/.style = {
draw = red
, ultra thick
, fill = orange
, postaction={
/utils/exec=\setcounter{mynodes}{0}
, decorate
, decoration={
markings,
mark=between positions 0 and 1 step 3mm with {
\coordinate (#1 \themynodes);
\node at (#1 \themynodes) {\tiny \themynodes}; \stepcounter{mynodes}
}
}
}
}
, degrees/.style = {
draw = red
, minimum size = 2cm
, ultra thick
, fill = orange
, anchor = south west
}
}
\newlength{\shifiting}
\setlength{\shifiting}{3cm}
\begin{document}
\begin{tikzpicture}[]
\draw [my anchors = circle 1] (1,1) circle (1);
\draw [my anchors = square 1, xshift = \shifiting] (0,0) rectangle (2, 2);
\draw [my anchors = triangle 1, xshift = 2\shifiting] (0,0) -- (1, 2) -- (2,0) -- cycle;
\draw [my anchors = crossed rectangle 1, xshift = 3\shifiting] (1,2) -- (0, 2) -- (0,0) -- (1,0) -- cycle -- (0,0);
\draw (circle 1 12) -- (square 1 14) -- (triangle 1 13) -- (crossed rectangle 1 24);
\node [anchor = south west, minimum size = 2cm] (ref 1) at (0 , 1\shifiting) {};
\node [circle, degrees, anchor = center] (circle 2) at (ref 1) {};
\node [degrees] (square 2) at (\shifiting, \shifiting) {};
\node [anchor = south west, minimum size = 2cm] (ref 2) at (2\shifiting , \shifiting) {};
\node [degrees, isosceles triangle, rotate = 90, anchor = left corner, isosceles triangle stretches] (triangle 2) at (ref 2.south west) {};
\node [degrees, minimum width = 1cm] (crossed rectangle 2) at (3\shifiting, \shifiting) {};
\path [draw = red, ultra thick] (crossed rectangle 2.north east) -- (crossed rectangle 2.south west);
\draw (circle 2.230) -- (square 2.30) -- (triangle 2.-110) -- (crossed rectangle 2.center);
\end{tikzpicture}
\end{document}
希望这可以帮助。
编辑
好吧,从对节点对齐的质疑中,我在这里留下另外两个建议,这在某种程度上引出了对对称性问题的考虑。
第一种方法是在每个多边形的边缘进行分割,但对圆必须进行特殊处理。您可以在这里看到结果:
代码如下:
\documentclass [tikz] {standalone}
\usetikzlibrary{decorations.markings}
\usetikzlibrary{shapes.geometric}
\usetikzlibrary{calc}
\newcounter{mynodes}
% node, begin anchor, end anchor, name
\newcommand{\makepoints}[4]{
\foreach \k in {1, ..., \points}
{
\pgfmathsetmacro{\dist}{\k * (1 / (\points + 1))}
\coordinate (#1 #4 \k) at ($(#1.#2)!\dist!(#1.#3)$);
}
}
% node, begin degree, end degree, name
\newcommand{\makepointsbydegrees}[4]{
\foreach \k in {1, ..., \points}
{
\pgfmathsetmacro{\step}{(abs(#3) - abs(#2)) / (\points + 1)}
\pgfmathsetmacro{\step}{ifthenelse(#2 < 0, -\step,)}
\pgfmathsetmacro{\degree}{#2 + \k * \step}
\coordinate (#1 #4 \k) at (#1.\degree);
}
}
\tikzset{
base/.style = {
draw = red
, line join = round
, line cap = round
, minimum size = 2cm
, ultra thick
, fill = orange
}
, ref/.style = {
, minimum size = 2cm
, anchor = south west
}
}
\newlength{\shifiting}
\setlength{\shifiting}{3cm}
\begin{document}
\begin{tikzpicture}[]
\pgfmathtruncatemacro{\points}{3}
% circle
\node [ref] (ref 1) at (0 , 1\shifiting) {};
\node [base, circle, anchor = center] (circle) at (ref 1) {};
\makepointsbydegrees{circle}{-270}{-450}{right}
% square
\node [ref] (ref 2) at (\shifiting, \shifiting) {};
\node [base] (square) at (ref 2) {};
\makepoints{square}{north east}{south east}{right}
\makepoints{square}{north west}{south west}{left}
% triangle
\node [ref] (ref 3) at (2\shifiting , \shifiting) {};
\node [base, isosceles triangle, rotate = 90, anchor = left corner, isosceles triangle stretches] (triangle) at (ref 3.south west) {};
\makepoints{triangle}{east}{left corner}{left}
\makepoints{triangle}{east}{right corner}{right}
% crossed retangle
\node [ref, minimum width = 1cm] (ref 4) at (3\shifiting, \shifiting) {};
\node [base, minimum width = 1cm] (crossed rectangle) at (ref 4) {};
\path [base, shorten >= 2pt, shorten <= 2pt] (crossed rectangle.north east) -- (crossed rectangle.south west);
\makepoints{crossed rectangle}{north west}{south west}{left}
% lines
\foreach \i in {1, ..., \points}
{
\draw [->] (circle right \i) -- (square left \i);
\draw [->] (square right \i) -- (triangle left \i);
\draw [->] (triangle right \i) -- (crossed rectangle left \i);
}
\end{tikzpicture}
\end{document}
第二种方法带来了完全不同的范例,使用了 Tikz 提供的更多功能,例如through
、matrix
和。在下图中fit
,intersections
您可以看到结果和一些构造线。
代码如下:
\documentclass [tikz] {standalone}
\usetikzlibrary{fit}
\usetikzlibrary{intersections}
\usetikzlibrary{calc}
\usetikzlibrary{matrix}
\usetikzlibrary{through}
% node, begin anchor, end anchor, name
\newcommand{\makepoints}[4]{
\foreach \k in {1, ..., \points}
{
\pgfmathsetmacro{\dist}{\k * (1 / (\points + 1))}
\coordinate (#1 #4 \k) at ($(#1.#2)!\dist!(#1.#3)$);
}
}
% first path, second path, counter
\newcommand{\intersectpoints}[3]{
\path [name intersections = {of = #1 and #2, sort by = #2, name = #3, total = \t}]
\foreach \s in {1, ..., \t} {
node [fill, circle, inner sep = 1.5pt] at (#3-\s) {}
};
}
\tikzset{
base/.style = {
draw = red
, line join = round
, minimum size = 2cm
, ultra thick
, fill = orange
, name path = #1
}
, ref/.style = {
, minimum size = 2cm
, anchor = south west
}
, cr/.style = {
, minimum width = 1cm
, minimum height = 2cm
}
, conexion/.style = {
, ->
, thick
, draw = blue
}
}
\begin{document}
\begin{tikzpicture}[]
% number of reference lines
\pgfmathtruncatemacro{\points}{4}
\matrix (m) [matrix of nodes, nodes in empty cells, nodes = {ref}]
{
& & & & & & \\
};
\node [base = circle] at (m-1-1) [circle through={(m-1-1.east)}] {};
\draw [base = square] (m-1-3.south west) rectangle (m-1-3.north east);
\draw [base = triangle] (m-1-5.south west) -- (m-1-5.south east) -- (m-1-5.north) -- cycle;
\node [draw, cr] (cr) at (m-1-7){};
\draw [base = crossed rectangle] (cr.north east) -- (cr.north west) -- (cr.south west) -- (cr.south east) -- cycle -- (cr.south west);
% reference rectangle fitting all figures
\node [draw, dotted, inner sep = 0pt, fit = (m-1-1) (m-1-7)] (outline) {};
\makepoints{outline}{north west}{south west}{left}
\makepoints{outline}{north east}{south east}{right}
% reference lines through figures
\draw [dotted, name path = path 1] (outline left 1) -- (outline right 1);
\draw [dotted, name path = path 2] (outline left 2) -- (outline right 2);
\draw [dotted, name path = path 3] (outline left 3) -- (outline right 3);
\draw [dotted, name path = path 4] (outline left 4) -- (outline right 4);
% circle points
\intersectpoints{circle}{path 1}{c 1}
\intersectpoints{circle}{path 2}{c 2}
\intersectpoints{circle}{path 3}{c 3}
% square points
\intersectpoints{square}{path 1}{r 1}
\intersectpoints{square}{path 2}{r 2}
\intersectpoints{square}{path 3}{r 3}
% triangle points
\intersectpoints{triangle}{path 1}{t 1}
\intersectpoints{triangle}{path 2}{t 2}
\intersectpoints{triangle}{path 3}{t 3}
% crossed rectangle
\intersectpoints{crossed rectangle}{path 1}{cr 1}
\intersectpoints{crossed rectangle}{path 2}{cr 2}
\intersectpoints{crossed rectangle}{path 3}{cr 3}
% lines between circle and square
\draw [conexion] (c 1-2) -- (r 1-1);
\draw [conexion] (c 2-2) -- (r 2-1);
\draw [conexion] (c 3-2) -- (r 3-1);
% lines between square and triangle
\draw [conexion] (r 1-2) -- (t 1-1);
\draw [conexion] (r 2-2) -- (t 2-1);
\draw [conexion] (r 3-2) -- (t 3-1);
% lines between triangle and crossed rectangle
\draw [conexion] (t 1-2) -- (cr 1-2);
\draw [conexion] (t 2-2) -- (cr 2-2);
\draw [conexion] (t 3-2) -- (cr 3-1);
\end{tikzpicture}
\end{document}
希望你喜欢。