\pgfdeclareshape 的 \anchorborder 交点和位置计算错误

\pgfdeclareshape 的 \anchorborder 交点和位置计算错误

我正在尝试定义一个“标记图标”形状(LIS),它是一个图标(用 pgf 命令绘制,但为简单起见,这里用一个简单的矩形替换),带有一个粘贴在图标上的标签(为简单起见,在这个最小示例中不是这种情况)并且是形状的一部分(边框锚点位于图标和标签的边框)。

通过使用这种形状,我将得到类似于下图的结果;不同之处在于,当标签位于边缘时,边缘将停止在标签的边界处,而不是穿过它。

接近预期结果

上面的图片是通过代码得到的:

\documentclass{article}

\usepackage{tikz}

\begin{document}

\begin{tikzpicture}
  \fill[red] (0,0) circle (1pt);
  \node[draw, label=-90:{Some text}] (node) at (0,0) {};
  \foreach \angle in {0,30,...,330} {
    \node[draw, label=-\angle:{Some text}] (node-\angle) at (\angle:5cm) {};
    \draw (node) -- (node-\angle);
  }
\end{tikzpicture}

\end{document}

使用 LIS 形状,我会写:

\documentclass{article}

\usepackage{tikz}
\usepackage{minimal-shapes}

\begin{document}

\begin{tikzpicture}
  \fill[red] (0,0) circle (1pt);
  \node[lis, align=center] (lis) at (0,0) {Some\\text};
  \foreach \angle in {0,30,...,330} {
    \node[lis, lis label pos=-\angle, align=center] (lis-\angle) at (\angle:4cm) {LIS \\ \angle};
    \draw (lis) -- (lis-\angle);
  }
\end{tikzpicture}

\end{document}

我在文件 minimal-shapes.sty 中定义了 LIS 形状。除了边框锚点的计算之外,一切都运行正常,在计算中,保存的值似乎是错误的,并且文本位置和其他点偏移了 180 度。以下是强调问题的改编形状声明。对于调试,返回的锚点边框始终是图标的边框,但在标签边框上应该有锚点边框的位置绘制了一个小圆圈。

\usepgflibrary{intersections}

\pgfkeyssetvalue{/tikz/lis label pos}{-90}

\newlength{\lis@textWidth} \newlength{\lis@textHeight}

\newcommand{\setTextCenterCoords}[0]{
  %% SIMPLIFIED VERSION
  \pgfmathsetlength{\pgfutil@tempdima}{\wd\pgfnodeparttextbox / 2 + 1.5em}
  \pgfpointpolar{\lis@labelPos}{\pgfutil@tempdima}
}

\pgfdeclareshape{lis}{
  %% DIMENs
  \saveddimen{\textWidth}{
    \pgf@x=\wd\pgfnodeparttextbox
    \ifdim\pgf@x<\pgfshapeminwidth
      \pgf@x=\pgfshapeminwidth
    \fi
  }
  \saveddimen{\textHeight}{\pgf@x=\ht\pgfnodeparttextbox}
  %% MACROs
  \savedmacro{\computeActorDimens}{
    \setlength{\lis@textHeight}{\ht\pgfnodeparttextbox}
    \setlength{\lis@textWidth}{\wd\pgfnodeparttextbox}
  }
  \savedmacro{\lis@labelPos}{
    \pgfmathsetmacro{\lis@labelPos}{Mod((\pgfkeysvalueof{/tikz/lis label pos} + 180), 360) - 180}
    \pgfwarning{Lis label pos: \pgfkeysvalueof{/tikz/lis label pos} -> \lis@labelPos}
  }
  %% SAVEDANCHORs
  \savedanchor{\upperRightIconCorner}{
    \pgfpoint{1em}{1em}
  }
  \savedanchor{\textCenter}{
    \setTextCenterCoords
  }
  \savedanchor{\upperRightTextCorner}{
    \computeActorDimens % Saveddimen do not seem available when declaring saved anchors
    \setTextCenterCoords
    \pgfmathsetlength{\pgf@x}{\pgf@x + (.5 * \lis@textWidth)}
    \pgfmathsetlength{\pgf@y}{\pgf@y + (.5 * \lis@textHeight)}
  }
  %% ANCHORs
  \anchor{center}{\pgfpointorigin}
  \anchor{text}{
    \textCenter
    \pgfmathsetlength{\pgf@x}{\pgf@x - (.5 * \textWidth)}
    \pgfmathsetlength{\pgf@y}{\pgf@y - (.5 * \textHeight)}
  }
  %% BORDER ANCHORs
  \anchorborder{%
    \@tempdima=\pgf@x \@tempdimb=\pgf@y
    %
    %\computeActorDimens
    \textCenter
    \upperRightTextCorner
    \pgfintersectionofpaths{
      \pgfpathmoveto{\pgfpointorigin}\pgfpathlineto{\pgfpoint{\@tempdima}{\@tempdimb}}
      \pgfgetpath\temppath
      %\pgfusepath{stroke}
      \pgfsetpath\temppath
    }{
      \pgfpathrectanglecorners{
        \pgfpointlineattime{-1}{
          \textCenter
        }{
          \upperRightTextCorner
        }
      }{
        \upperRightTextCorner
      }
      \pgfgetpath\temppath
      %\pgfusepath{stroke}
      \pgftext[at=\textCenter]{\footnotesize \lis@labelPos}
      \pgfsetpath\temppath
    }
    %
    \pgfwarning{Nb intersections: \pgfintersectionsolutions}
    %
    \ifnum\pgfintersectionsolutions=0
      \pgfpointborderrectangle{\pgfpoint{\@tempdima}{\@tempdimb}}{\upperRightIconCorner}
    \else
      \pgfintersectionsortbyfirstpath
      \pgfpathcircle{\pgfpointintersectionsolution{\pgfintersectionsolutions}}{3pt}
    \fi
    \pgfpointborderrectangle{\pgfpoint{\@tempdima}{\@tempdimb}}{\upperRightIconCorner}
  }
  %% DRAWINGs
  \backgroundpath{
    %% SIMPLIFIED VERSION
    \upperRightIconCorner \@tempdima=\pgf@x \@tempdimb=\pgf@y
    \pgfpathrectanglecorners{
      \pgfpointlineattime{-1}{\pgfpointorigin}{\pgfpoint{\@tempdima}{\@tempdimb}}
    }{\pgfpoint{\@tempdima}{\@tempdimb}}
    \pgfusepath{stroke}
  }
}

通过上述代码,我得到以下结果:

接近预期结果

对于中心节点来说,它似乎几乎可以正常工作。但外围节点的 \lis@labelPos 值错误(已显示以显示问题)。当应该有交点时,却发现了一个交点(显示为圆圈),但它出现在节点的错误一侧。如果我取消引用第一个“\pgfusepath{stroke}”,线条会朝向图形外部,而不是朝向中心节点(提供给 \anchorborder 的值 \pgf@x 和 \pgf@y 似乎是错误的)。

我不明白发生了什么。有人能帮忙吗?谢谢

答案1

在 \anchorborder 中绘制任何东西似乎都不是一个好主意。应用于 \anchorborder 内容的转换将绘图置于错误的位置。这可能是交集库上的命令与 \anchorborder 不兼容的相同原因。为了解决我的问题,我从“磁带”形状(顺便说一下,其中有一个错误)中获得了一些灵感。生成的代码如下:

\anchorborder{%
  \pgfextract@process\externalpoint{}%
  \ifnum\pdfstrcmp{\lis@iconShape}{rectangle}=0%
    \pgfpointborderrectangle{\externalpoint}{\iconUpperRightOuterCorner}%
  \fi%
  \ifnum\pdfstrcmp{\lis@iconShape}{ellipse}=0%
    \pgfpointborderellipse{\externalpoint}{\iconUpperRightOuterCorner}%
  \fi%
  \lis@tmpX=\pgf@x \lis@tmpY=\pgf@y \pgfmathsetmacro{\lis@tmpLgth}{sqrt( pow(\pgf@x,2) + pow(\pgf@y,2) )}%
  %
  \pgfmathanglebetweenpoints{\pgfpointorigin}{\externalpoint}%
  \pgfmathsetmacro{\lis@externalpointAngle}{\pgfmathresult}%
  %
  \pgfmathsetmacro{\tmpMin}{min(\lis@labelURcornerAngle, \lis@labelULcornerAngle, \lis@labelLLcornerAngle, \lis@labelLRcornerAngle)}%
  \pgfmathsetmacro{\tmpMax}{max(\lis@labelURcornerAngle, \lis@labelULcornerAngle, \lis@labelLLcornerAngle, \lis@labelLRcornerAngle)}%
  \pgfwarning{LIS shape: \lis@externalpointAngle, (\lis@labelURcornerAngle, \lis@labelULcornerAngle, \lis@labelLLcornerAngle, \lis@labelLRcornerAngle) \lis@labelPos, \tmpMin, \tmpMax}%
  \pgfmathsetmacro{\lis@tmpLabelPos}{Mod(\lis@labelPos, 360)}%
  \pgfmathparse{not(and(\tmpMin < \lis@tmpLabelPos , \lis@tmpLabelPos < \tmpMax))}%
  \ifnum\pgfmathresult=1%
    \pgfmathsetmacro{\lis@externalpointAngle}{Mod(\lis@externalpointAngle + 180, 360)}%
    \pgfmathsetmacro{\lis@labelURcornerAngle}{Mod(\lis@labelURcornerAngle + 180, 360)}%
    \pgfmathsetmacro{\lis@labelULcornerAngle}{Mod(\lis@labelULcornerAngle + 180, 360)}%
    \pgfmathsetmacro{\lis@labelLLcornerAngle}{Mod(\lis@labelLLcornerAngle + 180, 360)}%
    \pgfmathsetmacro{\lis@labelLRcornerAngle}{Mod(\lis@labelLRcornerAngle + 180, 360)}%
    \pgfwarning{LIS shape: \lis@externalpointAngle, (\lis@labelURcornerAngle, \lis@labelULcornerAngle, \lis@labelLLcornerAngle, \lis@labelLRcornerAngle) \lis@labelPos}%
  \fi%
  %
  \ifdim\lis@labelURcornerAngle pt<\lis@externalpointAngle pt%
    \ifdim\lis@externalpointAngle pt<\lis@labelULcornerAngle pt%
      \lis@setLabelCenterCoords%
      \pgfmathsetlength{\lis@tmpXa}{\pgf@x + (.5 * \labelOuterWidth)}%
      \pgfmathsetlength{\lis@tmpYa}{\pgf@y + (.5 * \labelOuterHeight)}%
      \lis@setLabelCenterCoords%
      \pgfmathsetlength{\lis@tmpXb}{\pgf@x - (.5 * \labelOuterWidth)}%
      \pgfmathsetlength{\lis@tmpYb}{\pgf@y + (.5 * \labelOuterHeight)}%
      \pgfpointintersectionoflines{\pgfpointorigin}{\externalpoint}{\pgfqpoint{\lis@tmpXa}{\lis@tmpYa}}{\pgfqpoint{\lis@tmpXb}{\lis@tmpYb}}%
      \pgfmathsetmacro{\lis@tmpLgthB}{sqrt( pow(\pgf@x,2) + pow(\pgf@y,2) )}%
      \ifdim\lis@tmpLgthB pt>\lis@tmpLgth pt%
        \lis@tmpX=\pgf@x \lis@tmpY=\pgf@y \pgfmathsetmacro{\lis@tmpLgth}{\lis@tmpLgthB}%
      \fi%
    \fi%
  \fi%
  % 
  \ifdim\lis@labelULcornerAngle pt<\lis@externalpointAngle pt%
    \ifdim\lis@externalpointAngle pt<\lis@labelLLcornerAngle pt%
      \lis@setLabelCenterCoords%
      \pgfmathsetlength{\lis@tmpXa}{\pgf@x - (.5 * \labelOuterWidth)}%
      \pgfmathsetlength{\lis@tmpYa}{\pgf@y + (.5 * \labelOuterHeight)}%
      \lis@setLabelCenterCoords%
      \pgfmathsetlength{\lis@tmpXb}{\pgf@x - (.5 * \labelOuterWidth)}%
      \pgfmathsetlength{\lis@tmpYb}{\pgf@y - (.5 * \labelOuterHeight)}%
      \pgfpointintersectionoflines{\pgfpointorigin}{\externalpoint}{\pgfqpoint{\lis@tmpXa}{\lis@tmpYa}}{\pgfqpoint{\lis@tmpXb}{\lis@tmpYb}}%
      \pgfmathsetmacro{\lis@tmpLgthB}{sqrt( pow(\pgf@x,2) + pow(\pgf@y,2) )}%
      \ifdim\lis@tmpLgthB pt>\lis@tmpLgth pt%
        \lis@tmpX=\pgf@x \lis@tmpY=\pgf@y \pgfmathsetmacro{\lis@tmpLgth}{\lis@tmpLgthB}%
      \fi%
    \fi%
  \fi%
  % 
  \ifdim\lis@labelLLcornerAngle pt<\lis@externalpointAngle pt%
    \ifdim\lis@externalpointAngle pt<\lis@labelLRcornerAngle pt%
      \lis@setLabelCenterCoords%
      \pgfmathsetlength{\lis@tmpXa}{\pgf@x - (.5 * \labelOuterWidth)}%
      \pgfmathsetlength{\lis@tmpYa}{\pgf@y - (.5 * \labelOuterHeight)}%
      \lis@setLabelCenterCoords%
      \pgfmathsetlength{\lis@tmpXb}{\pgf@x + (.5 * \labelOuterWidth)}%
      \pgfmathsetlength{\lis@tmpYb}{\pgf@y - (.5 * \labelOuterHeight)}%
      \pgfpointintersectionoflines{\pgfpointorigin}{\externalpoint}{\pgfqpoint{\lis@tmpXa}{\lis@tmpYa}}{\pgfqpoint{\lis@tmpXb}{\lis@tmpYb}}%
      \pgfmathsetmacro{\lis@tmpLgthB}{sqrt( pow(\pgf@x,2) + pow(\pgf@y,2) )}%
      \ifdim\lis@tmpLgthB pt>\lis@tmpLgth pt%
        \lis@tmpX=\pgf@x \lis@tmpY=\pgf@y \pgfmathsetmacro{\lis@tmpLgth}{\lis@tmpLgthB}%
      \fi%
    \fi%
  \fi%
  % 
  \ifdim\lis@labelLRcornerAngle pt<\lis@externalpointAngle pt%
    \ifdim\lis@externalpointAngle pt<\lis@labelURcornerAngle pt%
      \lis@setLabelCenterCoords%
      \pgfmathsetlength{\lis@tmpXa}{\pgf@x + (.5 * \labelOuterWidth)}%
      \pgfmathsetlength{\lis@tmpYa}{\pgf@y - (.5 * \labelOuterHeight)}%
      \lis@setLabelCenterCoords%
      \pgfmathsetlength{\lis@tmpXb}{\pgf@x + (.5 * \labelOuterWidth)}%
      \pgfmathsetlength{\lis@tmpYb}{\pgf@y + (.5 * \labelOuterHeight)}%
      \pgfpointintersectionoflines{\pgfpointorigin}{\externalpoint}{\pgfqpoint{\lis@tmpXa}{\lis@tmpYa}}{\pgfqpoint{\lis@tmpXb}{\lis@tmpYb}}%
      \pgfmathsetmacro{\lis@tmpLgthB}{sqrt( pow(\pgf@x,2) + pow(\pgf@y,2) )}%
      \ifdim\lis@tmpLgthB pt>\lis@tmpLgth pt%
        \lis@tmpX=\pgf@x \lis@tmpY=\pgf@y \pgfmathsetmacro{\lis@tmpLgth}{\lis@tmpLgthB}%
      \fi%
    \fi%
  \fi%
  % 
  \pgf@x=\lis@tmpX \pgf@y=\lis@tmpY%
}

结果

相关内容