0

So I have a base shape I am beginning to work with, which is just a regular polygon shape from shapes.geometric. How do I create a grid of anchors within this shape? I know that it is just math + pgf I need to work through, and a simple thing eventually, unless I am wrong about how I need to go about movement and placement with a shape I've created. Its mostly about setting up my limited understanding of math through an understanding of pgf, any input appreciated.

\pgfdeclareshape{rootHex}{
    \savedmacro\sides{%
        \pgfmathtruncatemacro\sides{6}%
    }
    \savedmacro\anglestep{%
        \pgfmathdivide{360}{\sides}%
        \let\anglestep\pgfmathresult%
    }
    \savedmacro\calculateradii{%
        %
        % Get the node dimensions.
        %
        \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/inner xsep}}%
        \advance\pgf@x.5\wd\pgfnodeparttextbox%
        \pgfmathsetlength\pgf@y{\pgfkeysvalueof{/pgf/inner ysep}}%
        \advance\pgf@y.5\ht\pgfnodeparttextbox%
        \advance\pgf@y.5\dp\pgfnodeparttextbox%
        \ifdim\pgf@y>\pgf@x%
            \pgf@x\pgf@y%
        \fi%
        %
        % Calculate i, the incircle radius 
        %
        \pgf@x1.41421\pgf@x%
        %
        % Calculate r, the polygon radius
        %
        % r = i / cos(360 / s / 2)
        %
        % (s = polygon sides)
        %
        \pgfmathdivide{180}{\sides}%
        \pgfmathsec@{\pgfmathresult}%
        \pgf@x\pgfmathresult\pgf@x%
        %
        % Accommodate the minimum width/height.
        %
        \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/minimum width}}%
        \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/minimum height}}%
        \ifdim\pgf@ya>\pgf@xa%
            \pgf@xa\pgf@ya%
        \fi%
        \ifdim\pgf@x<.5\pgf@xa%
            \pgf@x.5\pgf@xa%
        \fi%
        \edef\radius{\the\pgf@x}%
        %
        % Now calculate the anchor radius from the outer sep.
        %
        \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}%
        \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}%
        \ifdim\pgf@ya>\pgf@xa%
            \pgf@xa\pgf@ya%
        \fi
        %
        % Take into account the miter length.
        %
        % m = o / sin (90 - (360 / s / 2))
        %
        % (o = outer sep, s = sides)
        %
        \pgfmathdivide{180}{\sides}%
        \pgfmathsubtract@{90}{\pgfmathresult}%
        \pgfmathcosec@{\pgfmathresult}%
        \advance\pgf@x\pgfmathresult\pgf@xa%
        \edef\anchorradius{\the\pgf@x}%
        %
        % Save both radii.
        %
        \addtosavedmacro{\radius}%
        \addtosavedmacro{\anchorradius}%
    }
    \savedmacro\startangle{%
        \pgfmathdivide{360}{\sides}%
        \let\anglestep\pgfmathresult%
        \pgfmathtruncatemacro\sides{\sides}%
        \pgfmathdivide@{\anglestep}{2}%
        \pgfmathsubtract@{90}{\pgfmathresult}%
        \pgfmathadd{\pgfmathresult}{\pgfkeysvalueof{/pgf/shape border rotate}}%
        \let\startangle\pgfmathresult%
    }
    %
    % Saved anchors.
    %
    \savedanchor{\centerpoint}{%
        \pgf@x.5\wd\pgfnodeparttextbox%
        \pgf@y.5\ht\pgfnodeparttextbox%
        \advance\pgf@y-.5\dp\pgfnodeparttextbox%
    }%
    \savedanchor{\midpoint}{%
        \pgf@x.5\wd\pgfnodeparttextbox%
        \pgfmathsetlength\pgf@y{+.5ex}%
    }%  
    %
    % Other anchors.
    %
    \anchor{center}{\centerpoint}%
    \anchor{mid}{\midpoint}%
    \anchor{base}{\centerpoint\pgf@y=0pt}%
    \anchor{north}{%
        \calculateradii%
        \csname pgf@anchor@rootHex@border\endcsname{\pgfqpoint{0pt}{\anchorradius}}}%
    \anchor{south}{%
        \calculateradii%
        \csname pgf@anchor@rootHex@border\endcsname{\pgfqpoint{0pt}{-\anchorradius}}}%
    \anchor{east}{%
        \calculateradii%
        \csname pgf@anchor@rootHex@border\endcsname{\pgfqpoint{\anchorradius}{0pt}}}%
    \anchor{west}{%
        \calculateradii%
        \csname pgf@anchor@rootHex@border\endcsname{\pgfqpoint{-\anchorradius}{0pt}}}%
    \anchor{north east}{%
        \calculateradii%
        \csname pgf@anchor@rootHex@border\endcsname{\pgfqpoint{\anchorradius}{\anchorradius}}}%
    \anchor{north west}{%
        \calculateradii%
        \csname pgf@anchor@rootHex@border\endcsname{\pgfqpoint{-\anchorradius}{\anchorradius}}}%
    \anchor{south east}{%
        \calculateradii%
        \csname pgf@anchor@rootHex@border\endcsname{\pgfqpoint{\anchorradius}{-\anchorradius}}}%
    \anchor{south west}{%
        \calculateradii%
        \csname pgf@anchor@rootHex@border\endcsname{\pgfqpoint{-\anchorradius}{-\anchorradius}}}%   
    %
    % Background path.
    %
    \backgroundpath{%
        \calculateradii%
        \pgfpathmoveto{%
            \pgfpointadd{\centerpoint}{\pgfqpointpolar{\startangle}{\radius}}%
        }%
        \let\angle\startangle%
        \pgfmathloop%
            \ifnum\pgfmathcounter=\sides\relax% 
                \pgfpathclose%
            \else%
                \pgfmathadd@{\angle}{\anglestep}%
                \let\angle\pgfmathresult%
                \pgfpathlineto{%
                    \pgfpointadd{\centerpoint}{\pgfqpointpolar{\angle}{\radius}}%
                }%
        \repeatpgfmathloop% 
    }%
    \anchorborder{%
        %
        % Save x and y.
        %
        \edef\externalx{\the\pgf@x}%
        \edef\externaly{\the\pgf@y}%
        %
        % Adjust the location of the external 
        % point relative to \centerpoint.
        %
        \centerpoint%
        \pgf@xa\externalx\relax%
        \pgf@ya\externaly\relax%
        \advance\pgf@xa\pgf@x%
        \advance\pgf@ya\pgf@y%
        \edef\externalx{\the\pgf@xa}%
        \edef\externaly{\the\pgf@ya}%
        %
        % Get the angle of the external point to the \centerpoint.
        %
        \pgfmathanglebetweenpoints{\centerpoint}{\pgfqpoint{\externalx}{\externaly}}%
        %
        % Locate the appropriate sides on the polygon border...
        %
        \pgfmathsubtract@{\pgfmathresult}{\startangle}%
        \ifdim\pgfmathresult pt<0pt\relax%
            \pgfmathadd@{\pgfmathresult}{360}%
        \fi%
        \pgfmathdivide@{\pgfmathresult}{\anglestep}%
        \pgfmathfloor@{\pgfmathresult}%
        \pgfmathmultiply@{\pgfmathresult}{\anglestep}%
        \pgfmathadd@{\pgfmathresult}{\startangle}%
        \let\firstangle\pgfmathresult%
        \pgfmathadd@{\pgfmathresult}{\anglestep}%
        \let\secondangle\pgfmathresult%
        \calculateradii%
        %
        % ...and thus, the point on the polygon border.
        %
        \pgfpointintersectionoflines{\centerpoint}{\pgfpoint{+\externalx}{+\externaly}}%
            {%
                \pgfpointadd{\centerpoint}%
                    {\pgfqpointpolar{+\firstangle}{+\anchorradius}}%
                }%  
                {%
                    \pgfpointadd{\centerpoint}%
                        {\pgfqpointpolar{+\secondangle}{+\anchorradius}}%
                }%  
    }
    %
    % More hackery for when the rootHex is positioned using 
    % a `corner <n+1>' or `side <n+1>' anchor, where n is the maximum 
    % number of sides of any previously drawn rootHex.
    %
    \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@rootHex\endcsname{%
        \c@pgf@counta\sides\relax%
        \pgfmathloop%
            \ifnum\c@pgf@counta>0\relax%
                \pgfutil@ifundefined{pgf@anchor@rootHex@corner\space\the\c@pgf@counta}{%
                %
                % ...(manually \xdef as \gdef is normally used by \anchor)...
                %
                \expandafter\xdef\csname pgf@anchor@rootHex@corner\space\the\c@pgf@counta\endcsname{%
                    \noexpand\calculateradii%
                    \noexpand\pgfmathsubtract@{\the\c@pgf@counta}{1}%
                    \noexpand\pgfmathmultiply@{\noexpand\pgfmathresult}{\noexpand\anglestep}%
                    \noexpand\pgfmathadd@{\noexpand\pgfmathresult}{\noexpand\startangle}%
                    \noexpand\let\noexpand\angle\noexpand\pgfmathresult%
                    \noexpand\pgfpointadd{\noexpand\centerpoint}%
                        {\noexpand\pgfqpointpolar{\noexpand\angle}{\noexpand\anchorradius}}%
                }%
                \expandafter\xdef\csname pgf@anchor@rootHex@side\space\the\c@pgf@counta\endcsname{%
                    \noexpand\calculateradii%
                    \noexpand\pgfmathsubtract@{\the\c@pgf@counta}{1}%
                    \noexpand\pgfmathmultiply@{\noexpand\pgfmathresult}{\noexpand\anglestep}%
                    \noexpand\pgfmathadd@{\noexpand\pgfmathresult}{\noexpand\startangle}%
                    \noexpand\let\noexpand\firstangle\noexpand\pgfmathresult%
                    \noexpand\pgfmathadd@{\noexpand\pgfmathresult}{\noexpand\anglestep}%
                    \noexpand\let\noexpand\secondangle\noexpand\pgfmathresult%
                    \noexpand\pgfpointlineattime{0.5}%
                        {\noexpand\pgfpointadd{\noexpand\centerpoint}%
                            {\noexpand\pgfqpointpolar{\noexpand\firstangle}{\noexpand\anchorradius}}}%
                        {\noexpand\pgfpointadd{\noexpand\centerpoint}%
                            {\noexpand\pgfqpointpolar{\noexpand\secondangle}{\noexpand\anchorradius}}}%
                }%
            }{\c@pgf@counta0\relax}% 
            \advance\c@pgf@counta-1\relax%
        \repeatpgfmathloop% 
    }%
}

EDIT:

for clarity, I want to specify (regular, not saved) anchors along the edges and within the space of the shape, not just the edges. I'm guessing I need to travel along some polar coordinate thing I create and add anchors where I want, but 2d cartesian x,y would suffice for for my current (perhaps imagined) needs. enter image description here

  • 1
    what exactly is it you want to achieve? – Dux Mar 7 '16 at 16:40
  • Take a look at page 600, all regular polygon shapes already have a.corner i and a.side i anchors (a is node's name, and i is a number between 1 and regular polygon sides) which point to every polygon corner o midpoints in segments. What else do you need? – Ignasi Mar 7 '16 at 17:06
  • For clarity, see image. I want to create referencable anchors along all edge & corners, as well as a number of interior points within the shape. – blueblank Mar 7 '16 at 17:19
2

If you don't want to use all these anchors for node placement and only like a coordinate system. You don't need anchors defined in \pgfdeclareshape, a perpendicular coordinate system with corner and side anchors could be enough.

enter image description here

\documentclass[border=2mm,tikz]{standalone}
\usetikzlibrary{positioning, shapes.geometric}

\begin{document}
\begin{tikzpicture}[
    hex/.style={regular polygon,
      regular polygon sides=6,
      minimum size=10mm,
      inner sep=0mm,
      outer sep=0mm,
      rotate=0,
        draw
    }
]
\node[hex] (A) {};
\node[hex, above right=.5cm of A] (B) {};
\foreach \j in {A,B}{
    \foreach \i in {1,2,...,6}{
        \fill[red] (\j.corner \i) circle(1pt);
        \fill[red] (\j.side \i) circle(1pt);
    }
    \foreach \i in {corner 2, side 1, corner 1}
        \fill[red] (\j.side 2-|\j.\i) circle(1pt);
    \foreach \i in {side 2, corner 2, side 1, corner 1, side 6}
        \fill[red] (\j.corner 3-|\j.\i) circle(1pt);
    \foreach \i in {corner 2, side 1, corner 1}
        \fill[red] (\j.side 3-|\j.\i) circle(1pt);
    }
\draw (A.corner 3-|A.corner 2) to[out=10,in=120] (B.side 3-|B.corner 5);
\end{tikzpicture}
\end{document}
  • The anchors will be for node placement within a shape, not references between shapes. Interesting to see, and yes I am still working through a lot of just basic placement issues. – blueblank Mar 7 '16 at 19:27
  • what does the "-|" mean exactly – blueblank Mar 7 '16 at 19:31
  • @blueblank These non anchors can be used for node placement within a shape. A-|B means intersection point between horizontal line from A and vertical line from B. Without specific anchor, A means A.center. You can use -| or |- which means intersection between vertical and horizontal. – Ignasi Mar 7 '16 at 19:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.